Merge branch 'master' of https://github.com/minetest/minetest
This commit is contained in:
commit
3ff3103e98
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -230,7 +230,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
repository: minetest/irrlicht
|
repository: minetest/irrlicht
|
||||||
path: lib/irrlichtmt/
|
path: lib/irrlichtmt/
|
||||||
ref: "1.9.0mt5"
|
ref: "1.9.0mt6"
|
||||||
|
|
||||||
- name: Restore from cache and run vcpkg
|
- name: Restore from cache and run vcpkg
|
||||||
uses: lukka/run-vcpkg@v7
|
uses: lukka/run-vcpkg@v7
|
||||||
|
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
@ -22,7 +22,7 @@ on:
|
|||||||
- '.github/workflows/macos.yml'
|
- '.github/workflows/macos.yml'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
IRRLICHT_TAG: 1.9.0mt5
|
IRRLICHT_TAG: 1.9.0mt6
|
||||||
MINETEST_GAME_REPO: https://github.com/minetest/minetest_game.git
|
MINETEST_GAME_REPO: https://github.com/minetest/minetest_game.git
|
||||||
MINETEST_GAME_BRANCH: master
|
MINETEST_GAME_BRANCH: master
|
||||||
MINETEST_GAME_NAME: minetest_game
|
MINETEST_GAME_NAME: minetest_game
|
||||||
|
@ -9,7 +9,7 @@ stages:
|
|||||||
- deploy
|
- deploy
|
||||||
|
|
||||||
variables:
|
variables:
|
||||||
IRRLICHT_TAG: "1.9.0mt5"
|
IRRLICHT_TAG: "1.9.0mt6"
|
||||||
MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git"
|
MINETEST_GAME_REPO: "https://github.com/minetest/minetest_game.git"
|
||||||
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
|
CONTAINER_IMAGE: registry.gitlab.com/$CI_PROJECT_PATH
|
||||||
|
|
||||||
|
@ -63,6 +63,9 @@ Zughy:
|
|||||||
|
|
||||||
appgurueu:
|
appgurueu:
|
||||||
textures/base/pack/server_incompatible.png
|
textures/base/pack/server_incompatible.png
|
||||||
|
|
||||||
|
erlehmann, Warr1024, rollerozxa:
|
||||||
|
textures/base/pack/no_screenshot.png
|
||||||
|
|
||||||
License of Minetest source code
|
License of Minetest source code
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
@ -34,10 +34,14 @@ import android.widget.Button;
|
|||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import androidx.annotation.Keep;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
// Native code finds these methods by name (see porting_android.cpp).
|
||||||
|
// This annotation prevents the minifier/Proguard from mangling them.
|
||||||
|
@Keep
|
||||||
public class GameActivity extends NativeActivity {
|
public class GameActivity extends NativeActivity {
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("c++_shared");
|
System.loadLibrary("c++_shared");
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
LOCAL_PATH := $(call my-dir)/..
|
LOCAL_PATH := $(call my-dir)/..
|
||||||
|
|
||||||
#LOCAL_ADDRESS_SANITIZER:=true
|
#LOCAL_ADDRESS_SANITIZER:=true
|
||||||
|
#USE_BUILTIN_LUA:=true
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := Curl
|
LOCAL_MODULE := Curl
|
||||||
@ -42,11 +43,15 @@ LOCAL_MODULE := Irrlicht
|
|||||||
LOCAL_SRC_FILES := deps/$(APP_ABI)/Irrlicht/libIrrlichtMt.a
|
LOCAL_SRC_FILES := deps/$(APP_ABI)/Irrlicht/libIrrlichtMt.a
|
||||||
include $(PREBUILT_STATIC_LIBRARY)
|
include $(PREBUILT_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
ifndef USE_BUILTIN_LUA
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := LuaJIT
|
LOCAL_MODULE := LuaJIT
|
||||||
LOCAL_SRC_FILES := deps/$(APP_ABI)/LuaJIT/libluajit.a
|
LOCAL_SRC_FILES := deps/$(APP_ABI)/LuaJIT/libluajit.a
|
||||||
include $(PREBUILT_STATIC_LIBRARY)
|
include $(PREBUILT_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := OpenAL
|
LOCAL_MODULE := OpenAL
|
||||||
LOCAL_SRC_FILES := deps/$(APP_ABI)/OpenAL-Soft/libopenal.a
|
LOCAL_SRC_FILES := deps/$(APP_ABI)/OpenAL-Soft/libopenal.a
|
||||||
@ -92,7 +97,6 @@ LOCAL_CFLAGS += \
|
|||||||
-DUSE_CURL=1 \
|
-DUSE_CURL=1 \
|
||||||
-DUSE_SOUND=1 \
|
-DUSE_SOUND=1 \
|
||||||
-DUSE_LEVELDB=0 \
|
-DUSE_LEVELDB=0 \
|
||||||
-DUSE_LUAJIT=1 \
|
|
||||||
-DUSE_GETTEXT=1 \
|
-DUSE_GETTEXT=1 \
|
||||||
-DVERSION_MAJOR=${versionMajor} \
|
-DVERSION_MAJOR=${versionMajor} \
|
||||||
-DVERSION_MINOR=${versionMinor} \
|
-DVERSION_MINOR=${versionMinor} \
|
||||||
@ -100,6 +104,12 @@ LOCAL_CFLAGS += \
|
|||||||
-DVERSION_EXTRA=${versionExtra} \
|
-DVERSION_EXTRA=${versionExtra} \
|
||||||
$(GPROF_DEF)
|
$(GPROF_DEF)
|
||||||
|
|
||||||
|
ifdef USE_BUILTIN_LUA
|
||||||
|
LOCAL_CFLAGS += -DUSE_LUAJIT=0
|
||||||
|
else
|
||||||
|
LOCAL_CFLAGS += -DUSE_LUAJIT=1
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef NDEBUG
|
ifdef NDEBUG
|
||||||
LOCAL_CFLAGS += -DNDEBUG=1
|
LOCAL_CFLAGS += -DNDEBUG=1
|
||||||
endif
|
endif
|
||||||
@ -120,12 +130,19 @@ LOCAL_C_INCLUDES := \
|
|||||||
deps/$(APP_ABI)/Irrlicht/include \
|
deps/$(APP_ABI)/Irrlicht/include \
|
||||||
deps/$(APP_ABI)/Gettext/include \
|
deps/$(APP_ABI)/Gettext/include \
|
||||||
deps/$(APP_ABI)/Iconv/include \
|
deps/$(APP_ABI)/Iconv/include \
|
||||||
deps/$(APP_ABI)/LuaJIT/include \
|
|
||||||
deps/$(APP_ABI)/OpenAL-Soft/include \
|
deps/$(APP_ABI)/OpenAL-Soft/include \
|
||||||
deps/$(APP_ABI)/SQLite/include \
|
deps/$(APP_ABI)/SQLite/include \
|
||||||
deps/$(APP_ABI)/Vorbis/include \
|
deps/$(APP_ABI)/Vorbis/include \
|
||||||
deps/$(APP_ABI)/Zstd/include
|
deps/$(APP_ABI)/Zstd/include
|
||||||
|
|
||||||
|
ifdef USE_BUILTIN_LUA
|
||||||
|
LOCAL_C_INCLUDES += \
|
||||||
|
../../lib/lua/src \
|
||||||
|
../../lib/bitop
|
||||||
|
else
|
||||||
|
LOCAL_C_INCLUDES += deps/$(APP_ABI)/LuaJIT/include
|
||||||
|
endif
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
$(wildcard ../../src/client/*.cpp) \
|
$(wildcard ../../src/client/*.cpp) \
|
||||||
$(wildcard ../../src/client/*/*.cpp) \
|
$(wildcard ../../src/client/*/*.cpp) \
|
||||||
@ -207,6 +224,41 @@ LOCAL_SRC_FILES := \
|
|||||||
../../src/voxel.cpp \
|
../../src/voxel.cpp \
|
||||||
../../src/voxelalgorithms.cpp
|
../../src/voxelalgorithms.cpp
|
||||||
|
|
||||||
|
# Built-in Lua
|
||||||
|
ifdef USE_BUILTIN_LUA
|
||||||
|
LOCAL_SRC_FILES += \
|
||||||
|
../../lib/lua/src/lapi.c \
|
||||||
|
../../lib/lua/src/lauxlib.c \
|
||||||
|
../../lib/lua/src/lbaselib.c \
|
||||||
|
../../lib/lua/src/lcode.c \
|
||||||
|
../../lib/lua/src/ldblib.c \
|
||||||
|
../../lib/lua/src/ldebug.c \
|
||||||
|
../../lib/lua/src/ldo.c \
|
||||||
|
../../lib/lua/src/ldump.c \
|
||||||
|
../../lib/lua/src/lfunc.c \
|
||||||
|
../../lib/lua/src/lgc.c \
|
||||||
|
../../lib/lua/src/linit.c \
|
||||||
|
../../lib/lua/src/liolib.c \
|
||||||
|
../../lib/lua/src/llex.c \
|
||||||
|
../../lib/lua/src/lmathlib.c \
|
||||||
|
../../lib/lua/src/lmem.c \
|
||||||
|
../../lib/lua/src/loadlib.c \
|
||||||
|
../../lib/lua/src/lobject.c \
|
||||||
|
../../lib/lua/src/lopcodes.c \
|
||||||
|
../../lib/lua/src/loslib.c \
|
||||||
|
../../lib/lua/src/lparser.c \
|
||||||
|
../../lib/lua/src/lstate.c \
|
||||||
|
../../lib/lua/src/lstring.c \
|
||||||
|
../../lib/lua/src/lstrlib.c \
|
||||||
|
../../lib/lua/src/ltable.c \
|
||||||
|
../../lib/lua/src/ltablib.c \
|
||||||
|
../../lib/lua/src/ltm.c \
|
||||||
|
../../lib/lua/src/lundump.c \
|
||||||
|
../../lib/lua/src/lvm.c \
|
||||||
|
../../lib/lua/src/lzio.c \
|
||||||
|
../../lib/bitop/bit.c
|
||||||
|
endif
|
||||||
|
|
||||||
# GMP
|
# GMP
|
||||||
LOCAL_SRC_FILES += ../../lib/gmp/mini-gmp.c
|
LOCAL_SRC_FILES += ../../lib/gmp/mini-gmp.c
|
||||||
|
|
||||||
@ -218,12 +270,14 @@ LOCAL_STATIC_LIBRARIES += \
|
|||||||
Freetype \
|
Freetype \
|
||||||
Iconv libcharset \
|
Iconv libcharset \
|
||||||
Irrlicht \
|
Irrlicht \
|
||||||
LuaJIT \
|
|
||||||
OpenAL \
|
OpenAL \
|
||||||
Gettext \
|
Gettext \
|
||||||
SQLite3 \
|
SQLite3 \
|
||||||
Vorbis libvorbisfile libogg \
|
Vorbis libvorbisfile libogg \
|
||||||
Zstd
|
Zstd
|
||||||
|
ifndef USE_BUILTIN_LUA
|
||||||
|
LOCAL_STATIC_LIBRARIES += LuaJIT
|
||||||
|
endif
|
||||||
LOCAL_STATIC_LIBRARIES += android_native_app_glue $(PROFILER_LIBS)
|
LOCAL_STATIC_LIBRARIES += android_native_app_glue $(PROFILER_LIBS)
|
||||||
|
|
||||||
LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES
|
LOCAL_LDLIBS := -lEGL -lGLESv1_CM -lGLESv2 -landroid -lOpenSLES
|
||||||
|
@ -151,11 +151,9 @@ local function start_install(package, reason)
|
|||||||
|
|
||||||
if conf_path then
|
if conf_path then
|
||||||
local conf = Settings(conf_path)
|
local conf = Settings(conf_path)
|
||||||
if name_is_title then
|
conf:set("title", package.title)
|
||||||
conf:set("name", package.title)
|
if not name_is_title then
|
||||||
else
|
conf:set("name", package.name)
|
||||||
conf:set("title", package.title)
|
|
||||||
conf:set("name", package.name)
|
|
||||||
end
|
end
|
||||||
if not conf:get("description") then
|
if not conf:get("description") then
|
||||||
conf:set("description", package.short_description)
|
conf:set("description", package.short_description)
|
||||||
@ -360,7 +358,7 @@ function install_dialog.get_formspec()
|
|||||||
selected_game_idx = i
|
selected_game_idx = i
|
||||||
end
|
end
|
||||||
|
|
||||||
games[i] = core.formspec_escape(games[i].name)
|
games[i] = core.formspec_escape(games[i].title)
|
||||||
end
|
end
|
||||||
|
|
||||||
local selected_game = pkgmgr.games[selected_game_idx]
|
local selected_game = pkgmgr.games[selected_game_idx]
|
||||||
@ -410,7 +408,7 @@ function install_dialog.get_formspec()
|
|||||||
"container[0.375,0.70]",
|
"container[0.375,0.70]",
|
||||||
|
|
||||||
"label[0,0.25;", fgettext("Base Game:"), "]",
|
"label[0,0.25;", fgettext("Base Game:"), "]",
|
||||||
"dropdown[2,0;4.25,0.5;gameid;", table.concat(games, ","), ";", selected_game_idx, "]",
|
"dropdown[2,0;4.25,0.5;selected_game;", table.concat(games, ","), ";", selected_game_idx, "]",
|
||||||
|
|
||||||
"label[0,0.8;", fgettext("Dependencies:"), "]",
|
"label[0,0.8;", fgettext("Dependencies:"), "]",
|
||||||
|
|
||||||
@ -461,9 +459,9 @@ function install_dialog.handle_submit(this, fields)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
if fields.gameid then
|
if fields.selected_game then
|
||||||
for _, game in pairs(pkgmgr.games) do
|
for _, game in pairs(pkgmgr.games) do
|
||||||
if game.name == fields.gameid then
|
if game.title == fields.selected_game then
|
||||||
core.settings:set("menu_last_game", game.id)
|
core.settings:set("menu_last_game", game.id)
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
@ -646,6 +646,8 @@ function pkgmgr.install_dir(type, path, basename, targetpath)
|
|||||||
else
|
else
|
||||||
targetpath = core.get_gamepath() .. DIR_DELIM .. basename
|
targetpath = core.get_gamepath() .. DIR_DELIM .. basename
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
error("basefolder didn't return a recognised type, this shouldn't happen")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Copy it
|
-- Copy it
|
||||||
@ -739,7 +741,7 @@ function pkgmgr.preparemodlist(data)
|
|||||||
retval[#retval + 1] = {
|
retval[#retval + 1] = {
|
||||||
type = "game",
|
type = "game",
|
||||||
is_game_content = true,
|
is_game_content = true,
|
||||||
name = fgettext("$1 mods", gamespec.name),
|
name = fgettext("$1 mods", gamespec.title),
|
||||||
path = gamespec.path
|
path = gamespec.path
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@ -924,10 +926,10 @@ end
|
|||||||
function pkgmgr.gamelist()
|
function pkgmgr.gamelist()
|
||||||
local retval = ""
|
local retval = ""
|
||||||
if #pkgmgr.games > 0 then
|
if #pkgmgr.games > 0 then
|
||||||
retval = retval .. core.formspec_escape(pkgmgr.games[1].name)
|
retval = retval .. core.formspec_escape(pkgmgr.games[1].title)
|
||||||
|
|
||||||
for i=2,#pkgmgr.games,1 do
|
for i=2,#pkgmgr.games,1 do
|
||||||
retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].name)
|
retval = retval .. "," .. core.formspec_escape(pkgmgr.games[i].title)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return retval
|
return retval
|
||||||
|
@ -88,7 +88,7 @@ if enable_gamebar then
|
|||||||
|
|
||||||
local image = nil
|
local image = nil
|
||||||
local text = nil
|
local text = nil
|
||||||
local tooltip = core.formspec_escape(game.name)
|
local tooltip = core.formspec_escape(game.title)
|
||||||
|
|
||||||
if (game.menuicon_path or "") ~= "" then
|
if (game.menuicon_path or "") ~= "" then
|
||||||
image = core.formspec_escape(game.menuicon_path)
|
image = core.formspec_escape(game.menuicon_path)
|
||||||
|
@ -643,8 +643,8 @@ shadow_update_frames (Map shadows update frames) int 8 1 16
|
|||||||
|
|
||||||
# Set the soft shadow radius size.
|
# Set the soft shadow radius size.
|
||||||
# Lower values mean sharper shadows, bigger values mean softer shadows.
|
# Lower values mean sharper shadows, bigger values mean softer shadows.
|
||||||
# Minimum value: 1.0; maximum value: 10.0
|
# Minimum value: 1.0; maximum value: 15.0
|
||||||
shadow_soft_radius (Soft shadow radius) float 1.0 1.0 10.0
|
shadow_soft_radius (Soft shadow radius) float 5.0 1.0 15.0
|
||||||
|
|
||||||
# Set the tilt of Sun/Moon orbit in degrees.
|
# Set the tilt of Sun/Moon orbit in degrees.
|
||||||
# Value of 0 means no tilt / vertical orbit.
|
# Value of 0 means no tilt / vertical orbit.
|
||||||
|
@ -25,6 +25,7 @@ uniform float animationTimer;
|
|||||||
varying float cosLight;
|
varying float cosLight;
|
||||||
varying float f_normal_length;
|
varying float f_normal_length;
|
||||||
varying vec3 shadow_position;
|
varying vec3 shadow_position;
|
||||||
|
varying float perspective_factor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -116,23 +117,16 @@ float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance
|
|||||||
|
|
||||||
|
|
||||||
#if SHADOW_FILTER == 2
|
#if SHADOW_FILTER == 2
|
||||||
#define PCFBOUND 3.5
|
#define PCFBOUND 2.0 // 5x5
|
||||||
#define PCFSAMPLES 64.0
|
#define PCFSAMPLES 25
|
||||||
#elif SHADOW_FILTER == 1
|
#elif SHADOW_FILTER == 1
|
||||||
#define PCFBOUND 1.5
|
#define PCFBOUND 1.0 // 3x3
|
||||||
#if defined(POISSON_FILTER)
|
#define PCFSAMPLES 9
|
||||||
#define PCFSAMPLES 32.0
|
|
||||||
#else
|
|
||||||
#define PCFSAMPLES 16.0
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#define PCFBOUND 0.0
|
#define PCFBOUND 0.0
|
||||||
#if defined(POISSON_FILTER)
|
#define PCFSAMPLES 1
|
||||||
#define PCFSAMPLES 4.0
|
|
||||||
#else
|
|
||||||
#define PCFSAMPLES 1.0
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef COLORED_SHADOWS
|
#ifdef COLORED_SHADOWS
|
||||||
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
@ -149,59 +143,31 @@ float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDis
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float getBaseLength(vec2 smTexCoord)
|
#define BASEFILTERRADIUS 1.0
|
||||||
{
|
|
||||||
float l = length(2.0 * smTexCoord.xy - 1.0 - CameraPos.xy); // length in texture coords
|
|
||||||
return xyPerspectiveBias1 / (1.0 / l - xyPerspectiveBias0); // return to undistorted coords
|
|
||||||
}
|
|
||||||
|
|
||||||
float getDeltaPerspectiveFactor(float l)
|
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
return 0.04 * pow(512.0 / f_textureresolution, 0.4) / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10
|
|
||||||
}
|
|
||||||
|
|
||||||
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
|
|
||||||
{
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
|
||||||
float perspectiveFactor;
|
|
||||||
|
|
||||||
// Return fast if sharp shadows are requested
|
// Return fast if sharp shadows are requested
|
||||||
if (PCFBOUND == 0.0)
|
if (PCFBOUND == 0.0 || SOFTSHADOWRADIUS <= 0.0)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
if (SOFTSHADOWRADIUS <= 1.0) {
|
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
|
|
||||||
return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 clampedpos;
|
vec2 clampedpos;
|
||||||
float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5);
|
|
||||||
float y, x;
|
float y, x;
|
||||||
float depth = 0.0;
|
float depth = getHardShadowDepth(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
float pointDepth;
|
// A factor from 0 to 1 to reduce blurring of short shadows
|
||||||
float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier;
|
float sharpness_factor = 1.0;
|
||||||
|
// conversion factor from shadow depth to blur radius
|
||||||
|
float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0;
|
||||||
|
if (depth > 0.0 && f_normal_length > 0.0)
|
||||||
|
// 5 is empirical factor that controls how fast shadow loses sharpness
|
||||||
|
sharpness_factor = clamp(5 * depth * depth_to_blur, 0.0, 1.0);
|
||||||
|
depth = 0.0;
|
||||||
|
|
||||||
float bound = clamp(PCFBOUND * (1 - baseLength), 0.0, PCFBOUND);
|
float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor
|
||||||
int n = 0;
|
* f_textureresolution / 2.0 / f_shadowfar;
|
||||||
|
float world_radius = 0.2; // shadow blur radius in world float coordinates, e.g. 0.2 = 0.02 of one node
|
||||||
|
|
||||||
for (y = -bound; y <= bound; y += 1.0)
|
return max(BASEFILTERRADIUS * f_textureresolution / 4096.0, sharpness_factor * world_radius * world_to_texture * SOFTSHADOWRADIUS);
|
||||||
for (x = -bound; x <= bound; x += 1.0) {
|
|
||||||
clampedpos = vec2(x,y);
|
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * maxRadius);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * maxRadius * perspectiveFactor + smTexCoord.xy;
|
|
||||||
|
|
||||||
pointDepth = getHardShadowDepth(shadowsampler, clampedpos.xy, realDistance);
|
|
||||||
if (pointDepth > -0.01) {
|
|
||||||
depth += pointDepth;
|
|
||||||
n += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
depth = depth / n;
|
|
||||||
depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001;
|
|
||||||
|
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
|
|
||||||
return max(length(smTexCoord.xy) * 2 * 2048 / f_textureresolution / pow(perspectiveFactor, 3), depth * maxRadius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef POISSON_FILTER
|
#ifdef POISSON_FILTER
|
||||||
@ -276,26 +242,23 @@ const vec2[64] poissonDisk = vec2[64](
|
|||||||
|
|
||||||
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
vec2 clampedpos;
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
|
||||||
vec4 visibility = vec4(0.0);
|
|
||||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
|
|
||||||
if (radius < 0.1) {
|
if (radius < 0.1) {
|
||||||
// we are in the middle of even brightness, no need for filtering
|
// we are in the middle of even brightness, no need for filtering
|
||||||
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
vec2 clampedpos;
|
||||||
float perspectiveFactor;
|
vec4 visibility = vec4(0.0);
|
||||||
|
float scale_factor = radius / f_textureresolution;
|
||||||
|
|
||||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
|
||||||
int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
|
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
|
||||||
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
||||||
int end_offset = int(samples) + init_offset;
|
int end_offset = int(samples) + init_offset;
|
||||||
|
|
||||||
for (int x = init_offset; x < end_offset; x++) {
|
for (int x = init_offset; x < end_offset; x++) {
|
||||||
clampedpos = poissonDisk[x];
|
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
|
|
||||||
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,26 +269,23 @@ vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance
|
|||||||
|
|
||||||
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
vec2 clampedpos;
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
|
||||||
float visibility = 0.0;
|
|
||||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
|
|
||||||
if (radius < 0.1) {
|
if (radius < 0.1) {
|
||||||
// we are in the middle of even brightness, no need for filtering
|
// we are in the middle of even brightness, no need for filtering
|
||||||
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
vec2 clampedpos;
|
||||||
float perspectiveFactor;
|
float visibility = 0.0;
|
||||||
|
float scale_factor = radius / f_textureresolution;
|
||||||
|
|
||||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
|
||||||
int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
|
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
|
||||||
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
||||||
int end_offset = int(samples) + init_offset;
|
int end_offset = int(samples) + init_offset;
|
||||||
|
|
||||||
for (int x = init_offset; x < end_offset; x++) {
|
for (int x = init_offset; x < end_offset; x++) {
|
||||||
clampedpos = poissonDisk[x];
|
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
|
|
||||||
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,65 +301,57 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|||||||
|
|
||||||
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
vec2 clampedpos;
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
|
||||||
vec4 visibility = vec4(0.0);
|
|
||||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
|
|
||||||
if (radius < 0.1) {
|
if (radius < 0.1) {
|
||||||
// we are in the middle of even brightness, no need for filtering
|
// we are in the middle of even brightness, no need for filtering
|
||||||
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
vec2 clampedpos;
|
||||||
float perspectiveFactor;
|
vec4 visibility = vec4(0.0);
|
||||||
|
float x, y;
|
||||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
|
||||||
float y, x;
|
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
|
||||||
float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
|
float scale_factor = radius / bound / f_textureresolution;
|
||||||
int n = 0;
|
float n = 0.0;
|
||||||
|
|
||||||
// basic PCF filter
|
// basic PCF filter
|
||||||
for (y = -bound; y <= bound; y += 1.0)
|
for (y = -bound; y <= bound; y += 1.0)
|
||||||
for (x = -bound; x <= bound; x += 1.0) {
|
for (x = -bound; x <= bound; x += 1.0) {
|
||||||
clampedpos = vec2(x,y); // screen offset
|
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
|
|
||||||
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
||||||
n += 1;
|
n += 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return visibility / n;
|
return visibility / max(n, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
vec2 clampedpos;
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
|
||||||
float visibility = 0.0;
|
|
||||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
|
|
||||||
if (radius < 0.1) {
|
if (radius < 0.1) {
|
||||||
// we are in the middle of even brightness, no need for filtering
|
// we are in the middle of even brightness, no need for filtering
|
||||||
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
vec2 clampedpos;
|
||||||
float perspectiveFactor;
|
float visibility = 0.0;
|
||||||
|
float x, y;
|
||||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
|
||||||
float y, x;
|
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
|
||||||
float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
|
float scale_factor = radius / bound / f_textureresolution;
|
||||||
int n = 0;
|
float n = 0.0;
|
||||||
|
|
||||||
// basic PCF filter
|
// basic PCF filter
|
||||||
for (y = -bound; y <= bound; y += 1.0)
|
for (y = -bound; y <= bound; y += 1.0)
|
||||||
for (x = -bound; x <= bound; x += 1.0) {
|
for (x = -bound; x <= bound; x += 1.0) {
|
||||||
clampedpos = vec2(x,y); // screen offset
|
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
|
|
||||||
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
||||||
n += 1;
|
n += 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return visibility / n;
|
return visibility / max(n, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -39,6 +39,7 @@ centroid varying vec2 varTexCoord;
|
|||||||
varying float adj_shadow_strength;
|
varying float adj_shadow_strength;
|
||||||
varying float f_normal_length;
|
varying float f_normal_length;
|
||||||
varying vec3 shadow_position;
|
varying vec3 shadow_position;
|
||||||
|
varying float perspective_factor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -253,6 +254,7 @@ void main(void)
|
|||||||
|
|
||||||
shadow_position = applyPerspectiveDistortion(m_ShadowViewProj * mWorld * (inVertexPosition + vec4(normalOffsetScale * nNormal, 0.0))).xyz;
|
shadow_position = applyPerspectiveDistortion(m_ShadowViewProj * mWorld * (inVertexPosition + vec4(normalOffsetScale * nNormal, 0.0))).xyz;
|
||||||
shadow_position.z -= z_bias;
|
shadow_position.z -= z_bias;
|
||||||
|
perspective_factor = pFactor;
|
||||||
|
|
||||||
if (f_timeofday < 0.2) {
|
if (f_timeofday < 0.2) {
|
||||||
adj_shadow_strength = f_shadow_strength * 0.5 *
|
adj_shadow_strength = f_shadow_strength * 0.5 *
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
uniform sampler2D baseTexture;
|
uniform sampler2D baseTexture;
|
||||||
|
|
||||||
uniform vec4 emissiveColor;
|
|
||||||
uniform vec3 dayLight;
|
uniform vec3 dayLight;
|
||||||
uniform vec4 skyBgColor;
|
uniform vec4 skyBgColor;
|
||||||
uniform float fogDistance;
|
uniform float fogDistance;
|
||||||
@ -26,6 +25,7 @@ uniform float animationTimer;
|
|||||||
varying float cosLight;
|
varying float cosLight;
|
||||||
varying float f_normal_length;
|
varying float f_normal_length;
|
||||||
varying vec3 shadow_position;
|
varying vec3 shadow_position;
|
||||||
|
varying float perspective_factor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -119,23 +119,16 @@ float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance
|
|||||||
|
|
||||||
|
|
||||||
#if SHADOW_FILTER == 2
|
#if SHADOW_FILTER == 2
|
||||||
#define PCFBOUND 3.5
|
#define PCFBOUND 2.0 // 5x5
|
||||||
#define PCFSAMPLES 64.0
|
#define PCFSAMPLES 25
|
||||||
#elif SHADOW_FILTER == 1
|
#elif SHADOW_FILTER == 1
|
||||||
#define PCFBOUND 1.5
|
#define PCFBOUND 1.0 // 3x3
|
||||||
#if defined(POISSON_FILTER)
|
#define PCFSAMPLES 9
|
||||||
#define PCFSAMPLES 32.0
|
|
||||||
#else
|
|
||||||
#define PCFSAMPLES 16.0
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#define PCFBOUND 0.0
|
#define PCFBOUND 0.0
|
||||||
#if defined(POISSON_FILTER)
|
#define PCFSAMPLES 1
|
||||||
#define PCFSAMPLES 4.0
|
|
||||||
#else
|
|
||||||
#define PCFSAMPLES 1.0
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef COLORED_SHADOWS
|
#ifdef COLORED_SHADOWS
|
||||||
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
@ -152,59 +145,31 @@ float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDis
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float getBaseLength(vec2 smTexCoord)
|
#define BASEFILTERRADIUS 1.0
|
||||||
{
|
|
||||||
float l = length(2.0 * smTexCoord.xy - 1.0 - CameraPos.xy); // length in texture coords
|
|
||||||
return xyPerspectiveBias1 / (1.0 / l - xyPerspectiveBias0); // return to undistorted coords
|
|
||||||
}
|
|
||||||
|
|
||||||
float getDeltaPerspectiveFactor(float l)
|
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
return 0.04 * pow(512.0 / f_textureresolution, 0.4) / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10
|
|
||||||
}
|
|
||||||
|
|
||||||
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
|
|
||||||
{
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
|
||||||
float perspectiveFactor;
|
|
||||||
|
|
||||||
// Return fast if sharp shadows are requested
|
// Return fast if sharp shadows are requested
|
||||||
if (PCFBOUND == 0.0)
|
if (PCFBOUND == 0.0 || SOFTSHADOWRADIUS <= 0.0)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
|
||||||
if (SOFTSHADOWRADIUS <= 1.0) {
|
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
|
|
||||||
return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 clampedpos;
|
vec2 clampedpos;
|
||||||
float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5);
|
|
||||||
float y, x;
|
float y, x;
|
||||||
float depth = 0.0;
|
float depth = getHardShadowDepth(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
float pointDepth;
|
// A factor from 0 to 1 to reduce blurring of short shadows
|
||||||
float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier;
|
float sharpness_factor = 1.0;
|
||||||
|
// conversion factor from shadow depth to blur radius
|
||||||
|
float depth_to_blur = f_shadowfar / SOFTSHADOWRADIUS / xyPerspectiveBias0;
|
||||||
|
if (depth > 0.0 && f_normal_length > 0.0)
|
||||||
|
// 5 is empirical factor that controls how fast shadow loses sharpness
|
||||||
|
sharpness_factor = clamp(5 * depth * depth_to_blur, 0.0, 1.0);
|
||||||
|
depth = 0.0;
|
||||||
|
|
||||||
float bound = clamp(PCFBOUND * (1 - baseLength), 0.0, PCFBOUND);
|
float world_to_texture = xyPerspectiveBias1 / perspective_factor / perspective_factor
|
||||||
int n = 0;
|
* f_textureresolution / 2.0 / f_shadowfar;
|
||||||
|
float world_radius = 0.2; // shadow blur radius in world float coordinates, e.g. 0.2 = 0.02 of one node
|
||||||
|
|
||||||
for (y = -bound; y <= bound; y += 1.0)
|
return max(BASEFILTERRADIUS * f_textureresolution / 4096.0, sharpness_factor * world_radius * world_to_texture * SOFTSHADOWRADIUS);
|
||||||
for (x = -bound; x <= bound; x += 1.0) {
|
|
||||||
clampedpos = vec2(x,y);
|
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * maxRadius);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * maxRadius * perspectiveFactor + smTexCoord.xy;
|
|
||||||
|
|
||||||
pointDepth = getHardShadowDepth(shadowsampler, clampedpos.xy, realDistance);
|
|
||||||
if (pointDepth > -0.01) {
|
|
||||||
depth += pointDepth;
|
|
||||||
n += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
depth = depth / n;
|
|
||||||
depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001;
|
|
||||||
|
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
|
|
||||||
return max(length(smTexCoord.xy) * 2 * 2048 / f_textureresolution / pow(perspectiveFactor, 3), depth * maxRadius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef POISSON_FILTER
|
#ifdef POISSON_FILTER
|
||||||
@ -279,26 +244,23 @@ const vec2[64] poissonDisk = vec2[64](
|
|||||||
|
|
||||||
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
vec2 clampedpos;
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
|
||||||
vec4 visibility = vec4(0.0);
|
|
||||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
|
|
||||||
if (radius < 0.1) {
|
if (radius < 0.1) {
|
||||||
// we are in the middle of even brightness, no need for filtering
|
// we are in the middle of even brightness, no need for filtering
|
||||||
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
vec2 clampedpos;
|
||||||
float perspectiveFactor;
|
vec4 visibility = vec4(0.0);
|
||||||
|
float scale_factor = radius / f_textureresolution;
|
||||||
|
|
||||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
|
||||||
int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
|
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
|
||||||
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
||||||
int end_offset = int(samples) + init_offset;
|
int end_offset = int(samples) + init_offset;
|
||||||
|
|
||||||
for (int x = init_offset; x < end_offset; x++) {
|
for (int x = init_offset; x < end_offset; x++) {
|
||||||
clampedpos = poissonDisk[x];
|
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
|
|
||||||
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,26 +271,23 @@ vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance
|
|||||||
|
|
||||||
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
vec2 clampedpos;
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
|
||||||
float visibility = 0.0;
|
|
||||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
|
|
||||||
if (radius < 0.1) {
|
if (radius < 0.1) {
|
||||||
// we are in the middle of even brightness, no need for filtering
|
// we are in the middle of even brightness, no need for filtering
|
||||||
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
vec2 clampedpos;
|
||||||
float perspectiveFactor;
|
float visibility = 0.0;
|
||||||
|
float scale_factor = radius / f_textureresolution;
|
||||||
|
|
||||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
int samples = (1 + 1 * int(SOFTSHADOWRADIUS > 1.0)) * PCFSAMPLES; // scale max samples for the soft shadows
|
||||||
int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
|
samples = int(clamp(pow(4.0 * radius + 1.0, 2.0), 1.0, float(samples)));
|
||||||
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
||||||
int end_offset = int(samples) + init_offset;
|
int end_offset = int(samples) + init_offset;
|
||||||
|
|
||||||
for (int x = init_offset; x < end_offset; x++) {
|
for (int x = init_offset; x < end_offset; x++) {
|
||||||
clampedpos = poissonDisk[x];
|
clampedpos = poissonDisk[x] * scale_factor + smTexCoord.xy;
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
|
|
||||||
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,65 +303,57 @@ float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|||||||
|
|
||||||
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
vec2 clampedpos;
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
|
||||||
vec4 visibility = vec4(0.0);
|
|
||||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
|
|
||||||
if (radius < 0.1) {
|
if (radius < 0.1) {
|
||||||
// we are in the middle of even brightness, no need for filtering
|
// we are in the middle of even brightness, no need for filtering
|
||||||
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
vec2 clampedpos;
|
||||||
float perspectiveFactor;
|
vec4 visibility = vec4(0.0);
|
||||||
|
float x, y;
|
||||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
|
||||||
float y, x;
|
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
|
||||||
float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
|
float scale_factor = radius / bound / f_textureresolution;
|
||||||
int n = 0;
|
float n = 0.0;
|
||||||
|
|
||||||
// basic PCF filter
|
// basic PCF filter
|
||||||
for (y = -bound; y <= bound; y += 1.0)
|
for (y = -bound; y <= bound; y += 1.0)
|
||||||
for (x = -bound; x <= bound; x += 1.0) {
|
for (x = -bound; x <= bound; x += 1.0) {
|
||||||
clampedpos = vec2(x,y); // screen offset
|
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
|
|
||||||
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
||||||
n += 1;
|
n += 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return visibility / n;
|
return visibility / max(n, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
||||||
{
|
{
|
||||||
vec2 clampedpos;
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance);
|
||||||
float visibility = 0.0;
|
|
||||||
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
|
|
||||||
if (radius < 0.1) {
|
if (radius < 0.1) {
|
||||||
// we are in the middle of even brightness, no need for filtering
|
// we are in the middle of even brightness, no need for filtering
|
||||||
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
float baseLength = getBaseLength(smTexCoord);
|
vec2 clampedpos;
|
||||||
float perspectiveFactor;
|
float visibility = 0.0;
|
||||||
|
float x, y;
|
||||||
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
float bound = (1 + 0.5 * int(SOFTSHADOWRADIUS > 1.0)) * PCFBOUND; // scale max bound for soft shadows
|
||||||
float y, x;
|
bound = clamp(0.5 * (4.0 * radius - 1.0), 0.5, bound);
|
||||||
float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
|
float scale_factor = radius / bound / f_textureresolution;
|
||||||
int n = 0;
|
float n = 0.0;
|
||||||
|
|
||||||
// basic PCF filter
|
// basic PCF filter
|
||||||
for (y = -bound; y <= bound; y += 1.0)
|
for (y = -bound; y <= bound; y += 1.0)
|
||||||
for (x = -bound; x <= bound; x += 1.0) {
|
for (x = -bound; x <= bound; x += 1.0) {
|
||||||
clampedpos = vec2(x,y); // screen offset
|
clampedpos = vec2(x,y) * scale_factor + smTexCoord.xy;
|
||||||
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
|
|
||||||
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
|
|
||||||
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
||||||
n += 1;
|
n += 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return visibility / n;
|
return visibility / max(n, 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -489,7 +440,6 @@ void main(void)
|
|||||||
shadow_color = visibility.gba;
|
shadow_color = visibility.gba;
|
||||||
#else
|
#else
|
||||||
if (cosLight > 0.0 || f_normal_length < 1e-3)
|
if (cosLight > 0.0 || f_normal_length < 1e-3)
|
||||||
if (cosLight > 0.0)
|
|
||||||
shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
|
shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
|
||||||
else
|
else
|
||||||
shadow_int = 1.0;
|
shadow_int = 1.0;
|
||||||
@ -540,6 +490,6 @@ void main(void)
|
|||||||
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
||||||
col = mix(skyBgColor, col, clarity);
|
col = mix(skyBgColor, col, clarity);
|
||||||
col = vec4(col.rgb, base.a);
|
col = vec4(col.rgb, base.a);
|
||||||
|
|
||||||
gl_FragColor = col;
|
gl_FragColor = col;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ centroid varying vec2 varTexCoord;
|
|||||||
varying float adj_shadow_strength;
|
varying float adj_shadow_strength;
|
||||||
varying float f_normal_length;
|
varying float f_normal_length;
|
||||||
varying vec3 shadow_position;
|
varying vec3 shadow_position;
|
||||||
|
varying float perspective_factor;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
varying vec3 eyeVec;
|
varying vec3 eyeVec;
|
||||||
@ -162,6 +163,7 @@ void main(void)
|
|||||||
|
|
||||||
shadow_position = applyPerspectiveDistortion(m_ShadowViewProj * mWorld * (inVertexPosition + vec4(normalOffsetScale * nNormal, 0.0))).xyz;
|
shadow_position = applyPerspectiveDistortion(m_ShadowViewProj * mWorld * (inVertexPosition + vec4(normalOffsetScale * nNormal, 0.0))).xyz;
|
||||||
shadow_position.z -= z_bias;
|
shadow_position.z -= z_bias;
|
||||||
|
perspective_factor = pFactor;
|
||||||
|
|
||||||
if (f_timeofday < 0.2) {
|
if (f_timeofday < 0.2) {
|
||||||
adj_shadow_strength = f_shadow_strength * 0.5 *
|
adj_shadow_strength = f_shadow_strength * 0.5 *
|
||||||
|
@ -62,7 +62,8 @@ Where `<gameid>` is unique to each game.
|
|||||||
The game directory can contain the following files:
|
The game directory can contain the following files:
|
||||||
|
|
||||||
* `game.conf`, with the following keys:
|
* `game.conf`, with the following keys:
|
||||||
* `name`: Required, a human readable title to address the game, e.g. `name = Minetest`.
|
* `title`: Required, a human-readable title to address the game, e.g. `title = Minetest Game`.
|
||||||
|
* `name`: (Deprecated) same as title.
|
||||||
* `description`: Short description to be shown in the content tab
|
* `description`: Short description to be shown in the content tab
|
||||||
* `allowed_mapgens = <comma-separated mapgens>`
|
* `allowed_mapgens = <comma-separated mapgens>`
|
||||||
e.g. `allowed_mapgens = v5,v6,flat`
|
e.g. `allowed_mapgens = v5,v6,flat`
|
||||||
|
@ -246,13 +246,14 @@ Package - content which is downloadable from the content db, may or may not be i
|
|||||||
* core.get_texturepath() (possible in async calls)
|
* core.get_texturepath() (possible in async calls)
|
||||||
* returns path to default textures
|
* returns path to default textures
|
||||||
* core.get_game(index)
|
* core.get_game(index)
|
||||||
|
* `name` in return value is deprecated, use `title` instead.
|
||||||
* returns:
|
* returns:
|
||||||
|
|
||||||
{
|
{
|
||||||
id = <id>,
|
id = <id>,
|
||||||
path = <full path to game>,
|
path = <full path to game>,
|
||||||
gamemods_path = <path>,
|
gamemods_path = <path>,
|
||||||
name = <name of game>,
|
title = <title of game>,
|
||||||
menuicon_path = <full path to menuicon>,
|
menuicon_path = <full path to menuicon>,
|
||||||
author = "author",
|
author = "author",
|
||||||
DEPRECATED:
|
DEPRECATED:
|
||||||
@ -264,8 +265,9 @@ Package - content which is downloadable from the content db, may or may not be i
|
|||||||
* returns
|
* returns
|
||||||
|
|
||||||
{
|
{
|
||||||
name = "name of content",
|
name = "technical_id",
|
||||||
type = "mod" or "modpack" or "game" or "txp",
|
type = "mod" or "modpack" or "game" or "txp",
|
||||||
|
title = "Human readable title",
|
||||||
description = "description",
|
description = "description",
|
||||||
author = "author",
|
author = "author",
|
||||||
path = "path/to/content",
|
path = "path/to/content",
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
name = Development Test
|
title = Development Test
|
||||||
description = Testing environment to help with testing the engine features of Minetest. It can also be helpful in mod development.
|
description = Testing environment to help with testing the engine features of Minetest. It can also be helpful in mod development.
|
||||||
|
@ -164,8 +164,13 @@ static int traversetable (global_State *g, Table *h) {
|
|||||||
markobject(g, h->metatable);
|
markobject(g, h->metatable);
|
||||||
mode = gfasttm(g, h->metatable, TM_MODE);
|
mode = gfasttm(g, h->metatable, TM_MODE);
|
||||||
if (mode && ttisstring(mode)) { /* is there a weak mode? */
|
if (mode && ttisstring(mode)) { /* is there a weak mode? */
|
||||||
weakkey = (strchr(svalue(mode), 'k') != NULL);
|
// Android's 'FORTIFY libc' calls __builtin_object_size on the argument of strchr.
|
||||||
weakvalue = (strchr(svalue(mode), 'v') != NULL);
|
// This produces an incorrect size for the expression `svalue(mode)`, causing
|
||||||
|
// an assertion. By placing it in a temporary, __builtin_object_size returns
|
||||||
|
// -1 (for unknown size) which functions correctly.
|
||||||
|
const char *tmp = svalue(mode);
|
||||||
|
weakkey = (strchr(tmp, 'k') != NULL);
|
||||||
|
weakvalue = (strchr(tmp, 'v') != NULL);
|
||||||
if (weakkey || weakvalue) { /* is really weak? */
|
if (weakkey || weakvalue) { /* is really weak? */
|
||||||
h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
|
h->marked &= ~(KEYWEAK | VALUEWEAK); /* clear bits */
|
||||||
h->marked |= cast_byte((weakkey << KEYWEAKBIT) |
|
h->marked |= cast_byte((weakkey << KEYWEAKBIT) |
|
||||||
|
@ -48,7 +48,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
Camera::Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine):
|
Camera::Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine):
|
||||||
m_draw_control(draw_control),
|
m_draw_control(draw_control),
|
||||||
m_client(client)
|
m_client(client),
|
||||||
|
m_player_light_color(0xFFFFFFFF)
|
||||||
{
|
{
|
||||||
auto smgr = rendering_engine->get_scene_manager();
|
auto smgr = rendering_engine->get_scene_manager();
|
||||||
// note: making the camera node a child of the player node
|
// note: making the camera node a child of the player node
|
||||||
@ -154,8 +155,10 @@ void Camera::step(f32 dtime)
|
|||||||
bool was_under_zero = m_wield_change_timer < 0;
|
bool was_under_zero = m_wield_change_timer < 0;
|
||||||
m_wield_change_timer = MYMIN(m_wield_change_timer + dtime, 0.125);
|
m_wield_change_timer = MYMIN(m_wield_change_timer + dtime, 0.125);
|
||||||
|
|
||||||
if (m_wield_change_timer >= 0 && was_under_zero)
|
if (m_wield_change_timer >= 0 && was_under_zero) {
|
||||||
m_wieldnode->setItem(m_wield_item_next, m_client);
|
m_wieldnode->setItem(m_wield_item_next, m_client);
|
||||||
|
m_wieldnode->setNodeLightColor(m_player_light_color);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_view_bobbing_state != 0)
|
if (m_view_bobbing_state != 0)
|
||||||
{
|
{
|
||||||
@ -556,7 +559,8 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 tool_reload_ratio)
|
|||||||
m_wieldnode->setPosition(wield_position);
|
m_wieldnode->setPosition(wield_position);
|
||||||
m_wieldnode->setRotation(wield_rotation);
|
m_wieldnode->setRotation(wield_rotation);
|
||||||
|
|
||||||
m_wieldnode->setNodeLightColor(player->light_color);
|
m_player_light_color = player->light_color;
|
||||||
|
m_wieldnode->setNodeLightColor(m_player_light_color);
|
||||||
|
|
||||||
// Set render distance
|
// Set render distance
|
||||||
updateViewingRange();
|
updateViewingRange();
|
||||||
|
@ -291,4 +291,7 @@ private:
|
|||||||
|
|
||||||
std::list<Nametag *> m_nametags;
|
std::list<Nametag *> m_nametags;
|
||||||
bool m_show_nametag_backgrounds;
|
bool m_show_nametag_backgrounds;
|
||||||
|
|
||||||
|
// Last known light color of the player
|
||||||
|
video::SColor m_player_light_color;
|
||||||
};
|
};
|
||||||
|
@ -789,16 +789,18 @@ void Client::peerAdded(con::Peer *peer)
|
|||||||
infostream << "Client::peerAdded(): peer->id="
|
infostream << "Client::peerAdded(): peer->id="
|
||||||
<< peer->id << std::endl;
|
<< peer->id << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::deletingPeer(con::Peer *peer, bool timeout)
|
void Client::deletingPeer(con::Peer *peer, bool timeout)
|
||||||
{
|
{
|
||||||
infostream << "Client::deletingPeer(): "
|
infostream << "Client::deletingPeer(): "
|
||||||
"Server Peer is getting deleted "
|
"Server Peer is getting deleted "
|
||||||
<< "(timeout=" << timeout << ")" << std::endl;
|
<< "(timeout=" << timeout << ")" << std::endl;
|
||||||
|
|
||||||
if (timeout) {
|
m_access_denied = true;
|
||||||
m_access_denied = true;
|
if (timeout)
|
||||||
m_access_denied_reason = gettext("Connection timed out.");
|
m_access_denied_reason = gettext("Connection timed out.");
|
||||||
}
|
else
|
||||||
|
m_access_denied_reason = gettext("Connection aborted (protocol error?).");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -304,6 +304,7 @@ void ClientEnvironment::step(float dtime)
|
|||||||
node_at_lplayer = m_map->getNode(p);
|
node_at_lplayer = m_map->getNode(p);
|
||||||
|
|
||||||
u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef());
|
u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef());
|
||||||
|
lplayer->light_color = encode_light(light, 0); // this transfers light.alpha
|
||||||
final_color_blend(&lplayer->light_color, light, day_night_ratio);
|
final_color_blend(&lplayer->light_color, light, day_night_ratio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,15 +449,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
drawcall_count += draw_order.size();
|
drawcall_count += draw_order.size();
|
||||||
|
|
||||||
for (auto &descriptor : draw_order) {
|
for (auto &descriptor : draw_order) {
|
||||||
scene::IMeshBuffer *buf;
|
scene::IMeshBuffer *buf = descriptor.getBuffer();
|
||||||
|
|
||||||
if (descriptor.m_use_partial_buffer) {
|
|
||||||
descriptor.m_partial_buffer->beforeDraw();
|
|
||||||
buf = descriptor.m_partial_buffer->getBuffer();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buf = descriptor.m_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check and abort if the machine is swapping a lot
|
// Check and abort if the machine is swapping a lot
|
||||||
if (draw.getTimerTime() > 2000) {
|
if (draw.getTimerTime() > 2000) {
|
||||||
@ -489,6 +481,8 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
// Do not enable filter on shadow texture to avoid visual artifacts
|
// Do not enable filter on shadow texture to avoid visual artifacts
|
||||||
// with colored shadows.
|
// with colored shadows.
|
||||||
// Filtering is done in shader code anyway
|
// Filtering is done in shader code anyway
|
||||||
|
layer.BilinearFilter = false;
|
||||||
|
layer.AnisotropicFilter = false;
|
||||||
layer.TrilinearFilter = false;
|
layer.TrilinearFilter = false;
|
||||||
}
|
}
|
||||||
driver->setMaterial(material);
|
driver->setMaterial(material);
|
||||||
@ -499,7 +493,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
|
|||||||
m.setTranslation(block_wpos - offset);
|
m.setTranslation(block_wpos - offset);
|
||||||
|
|
||||||
driver->setTransform(video::ETS_WORLD, m);
|
driver->setTransform(video::ETS_WORLD, m);
|
||||||
driver->drawMeshBuffer(buf);
|
descriptor.draw(driver);
|
||||||
vertex_count += buf->getIndexCount();
|
vertex_count += buf->getIndexCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -810,15 +804,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
|||||||
drawcall_count += draw_order.size();
|
drawcall_count += draw_order.size();
|
||||||
|
|
||||||
for (auto &descriptor : draw_order) {
|
for (auto &descriptor : draw_order) {
|
||||||
scene::IMeshBuffer *buf;
|
scene::IMeshBuffer *buf = descriptor.getBuffer();
|
||||||
|
|
||||||
if (descriptor.m_use_partial_buffer) {
|
|
||||||
descriptor.m_partial_buffer->beforeDraw();
|
|
||||||
buf = descriptor.m_partial_buffer->getBuffer();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
buf = descriptor.m_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check and abort if the machine is swapping a lot
|
// Check and abort if the machine is swapping a lot
|
||||||
if (draw.getTimerTime() > 1000) {
|
if (draw.getTimerTime() > 1000) {
|
||||||
@ -843,7 +829,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver,
|
|||||||
m.setTranslation(block_wpos - offset);
|
m.setTranslation(block_wpos - offset);
|
||||||
|
|
||||||
driver->setTransform(video::ETS_WORLD, m);
|
driver->setTransform(video::ETS_WORLD, m);
|
||||||
driver->drawMeshBuffer(buf);
|
descriptor.draw(driver);
|
||||||
vertex_count += buf->getIndexCount();
|
vertex_count += buf->getIndexCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -964,3 +950,18 @@ void ClientMap::updateTransparentMeshBuffers()
|
|||||||
m_needs_update_transparent_meshes = false;
|
m_needs_update_transparent_meshes = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scene::IMeshBuffer* ClientMap::DrawDescriptor::getBuffer()
|
||||||
|
{
|
||||||
|
return m_use_partial_buffer ? m_partial_buffer->getBuffer() : m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientMap::DrawDescriptor::draw(video::IVideoDriver* driver)
|
||||||
|
{
|
||||||
|
if (m_use_partial_buffer) {
|
||||||
|
m_partial_buffer->beforeDraw();
|
||||||
|
driver->drawMeshBuffer(m_partial_buffer->getBuffer());
|
||||||
|
m_partial_buffer->afterDraw();
|
||||||
|
} else {
|
||||||
|
driver->drawMeshBuffer(m_buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -174,6 +174,9 @@ private:
|
|||||||
DrawDescriptor(v3s16 pos, const PartialMeshBuffer *buffer) :
|
DrawDescriptor(v3s16 pos, const PartialMeshBuffer *buffer) :
|
||||||
m_pos(pos), m_partial_buffer(buffer), m_reuse_material(false), m_use_partial_buffer(true)
|
m_pos(pos), m_partial_buffer(buffer), m_reuse_material(false), m_use_partial_buffer(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
scene::IMeshBuffer* getBuffer();
|
||||||
|
void draw(video::IVideoDriver* driver);
|
||||||
};
|
};
|
||||||
|
|
||||||
Client *m_client;
|
Client *m_client;
|
||||||
|
@ -920,12 +920,8 @@ void GenericCAO::setNodeLight(const video::SColor &light_color)
|
|||||||
if (m_prop.visual == "upright_sprite") {
|
if (m_prop.visual == "upright_sprite") {
|
||||||
if (!m_meshnode)
|
if (!m_meshnode)
|
||||||
return;
|
return;
|
||||||
|
for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i)
|
||||||
scene::IMesh *mesh = m_meshnode->getMesh();
|
m_meshnode->getMaterial(i).EmissiveColor = light_color;
|
||||||
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
|
|
||||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
|
||||||
buf->getMaterial().EmissiveColor = light_color;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
scene::ISceneNode *node = getSceneNode();
|
scene::ISceneNode *node = getSceneNode();
|
||||||
if (!node)
|
if (!node)
|
||||||
|
@ -1204,15 +1204,16 @@ void MapBlockBspTree::traverse(s32 node, v3f viewpoint, std::vector<s32> &output
|
|||||||
void PartialMeshBuffer::beforeDraw() const
|
void PartialMeshBuffer::beforeDraw() const
|
||||||
{
|
{
|
||||||
// Patch the indexes in the mesh buffer before draw
|
// Patch the indexes in the mesh buffer before draw
|
||||||
|
m_buffer->Indices = std::move(m_vertex_indexes);
|
||||||
m_buffer->Indices.clear();
|
|
||||||
if (!m_vertex_indexes.empty()) {
|
|
||||||
for (auto index : m_vertex_indexes)
|
|
||||||
m_buffer->Indices.push_back(index);
|
|
||||||
}
|
|
||||||
m_buffer->setDirty(scene::EBT_INDEX);
|
m_buffer->setDirty(scene::EBT_INDEX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PartialMeshBuffer::afterDraw() const
|
||||||
|
{
|
||||||
|
// Take the data back
|
||||||
|
m_vertex_indexes = std::move(m_buffer->Indices.steal());
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MapBlockMesh
|
MapBlockMesh
|
||||||
*/
|
*/
|
||||||
@ -1582,7 +1583,7 @@ void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos)
|
|||||||
const auto &t = m_transparent_triangles[i];
|
const auto &t = m_transparent_triangles[i];
|
||||||
if (current_buffer != t.buffer) {
|
if (current_buffer != t.buffer) {
|
||||||
if (current_buffer) {
|
if (current_buffer) {
|
||||||
m_transparent_buffers.emplace_back(current_buffer, current_strain);
|
m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain));
|
||||||
current_strain.clear();
|
current_strain.clear();
|
||||||
}
|
}
|
||||||
current_buffer = t.buffer;
|
current_buffer = t.buffer;
|
||||||
@ -1593,7 +1594,7 @@ void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!current_strain.empty())
|
if (!current_strain.empty())
|
||||||
m_transparent_buffers.emplace_back(current_buffer, current_strain);
|
m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapBlockMesh::consolidateTransparentBuffers()
|
void MapBlockMesh::consolidateTransparentBuffers()
|
||||||
@ -1607,7 +1608,7 @@ void MapBlockMesh::consolidateTransparentBuffers()
|
|||||||
for (const auto &t : m_transparent_triangles) {
|
for (const auto &t : m_transparent_triangles) {
|
||||||
if (current_buffer != t.buffer) {
|
if (current_buffer != t.buffer) {
|
||||||
if (current_buffer != nullptr) {
|
if (current_buffer != nullptr) {
|
||||||
this->m_transparent_buffers.emplace_back(current_buffer, current_strain);
|
this->m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain));
|
||||||
current_strain.clear();
|
current_strain.clear();
|
||||||
}
|
}
|
||||||
current_buffer = t.buffer;
|
current_buffer = t.buffer;
|
||||||
@ -1618,7 +1619,7 @@ void MapBlockMesh::consolidateTransparentBuffers()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!current_strain.empty()) {
|
if (!current_strain.empty()) {
|
||||||
this->m_transparent_buffers.emplace_back(current_buffer, current_strain);
|
this->m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,20 +140,31 @@ private:
|
|||||||
s32 root = -1; // index of the root node
|
s32 root = -1; // index of the root node
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PartialMeshBuffer
|
||||||
|
*
|
||||||
|
* Attach alternate `Indices` to an existing mesh buffer, to make it possible to use different
|
||||||
|
* indices with the same vertex buffer.
|
||||||
|
*
|
||||||
|
* Irrlicht does not currently support this: `CMeshBuffer` ties together a single vertex buffer
|
||||||
|
* and a single index buffer. There's no way to share these between mesh buffers.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class PartialMeshBuffer
|
class PartialMeshBuffer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PartialMeshBuffer(scene::SMeshBuffer *buffer, const std::vector<u16> &vertex_indexes) :
|
PartialMeshBuffer(scene::SMeshBuffer *buffer, std::vector<u16> &&vertex_indexes) :
|
||||||
m_buffer(buffer), m_vertex_indexes(vertex_indexes)
|
m_buffer(buffer), m_vertex_indexes(std::move(vertex_indexes))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
scene::IMeshBuffer *getBuffer() const { return m_buffer; }
|
scene::IMeshBuffer *getBuffer() const { return m_buffer; }
|
||||||
const std::vector<u16> &getVertexIndexes() const { return m_vertex_indexes; }
|
const std::vector<u16> &getVertexIndexes() const { return m_vertex_indexes; }
|
||||||
|
|
||||||
void beforeDraw() const;
|
void beforeDraw() const;
|
||||||
|
void afterDraw() const;
|
||||||
private:
|
private:
|
||||||
scene::SMeshBuffer *m_buffer;
|
scene::SMeshBuffer *m_buffer;
|
||||||
std::vector<u16> m_vertex_indexes;
|
mutable std::vector<u16> m_vertex_indexes;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -771,6 +771,8 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
|||||||
shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n";
|
shaders_header << "#define SOFTSHADOWRADIUS " << shadow_soft_radius << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shaders_header << "#line 0\n"; // reset the line counter for meaningful diagnostics
|
||||||
|
|
||||||
std::string common_header = shaders_header.str();
|
std::string common_header = shaders_header.str();
|
||||||
|
|
||||||
std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl");
|
std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl");
|
||||||
|
@ -670,6 +670,7 @@ std::string ShadowRenderer::readShaderFile(const std::string &path)
|
|||||||
std::string prefix;
|
std::string prefix;
|
||||||
if (m_shadow_map_colored)
|
if (m_shadow_map_colored)
|
||||||
prefix.append("#define COLORED_SHADOWS 1\n");
|
prefix.append("#define COLORED_SHADOWS 1\n");
|
||||||
|
prefix.append("#line 0\n");
|
||||||
|
|
||||||
std::string content;
|
std::string content;
|
||||||
fs::ReadFile(path, content);
|
fs::ReadFile(path, content);
|
||||||
|
@ -96,7 +96,12 @@ void parseContentInfo(ContentSpec &spec)
|
|||||||
|
|
||||||
Settings conf;
|
Settings conf;
|
||||||
if (!conf_path.empty() && conf.readConfigFile(conf_path.c_str())) {
|
if (!conf_path.empty() && conf.readConfigFile(conf_path.c_str())) {
|
||||||
if (conf.exists("name"))
|
if (conf.exists("title"))
|
||||||
|
spec.title = conf.get("title");
|
||||||
|
else if (spec.type == "game" && conf.exists("name"))
|
||||||
|
spec.title = conf.get("name");
|
||||||
|
|
||||||
|
if (spec.type != "game" && conf.exists("name"))
|
||||||
spec.name = conf.get("name");
|
spec.name = conf.get("name");
|
||||||
|
|
||||||
if (conf.exists("description"))
|
if (conf.exists("description"))
|
||||||
|
@ -27,7 +27,14 @@ struct ContentSpec
|
|||||||
std::string type;
|
std::string type;
|
||||||
std::string author;
|
std::string author;
|
||||||
u32 release = 0;
|
u32 release = 0;
|
||||||
|
|
||||||
|
/// Technical name / Id
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
|
/// Human-readable title
|
||||||
|
std::string title;
|
||||||
|
|
||||||
|
/// Short description
|
||||||
std::string desc;
|
std::string desc;
|
||||||
std::string path;
|
std::string path;
|
||||||
};
|
};
|
||||||
|
@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <common/c_internal.h>
|
||||||
#include "content/subgames.h"
|
#include "content/subgames.h"
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
@ -45,6 +46,25 @@ bool getGameMinetestConfig(const std::string &game_path, Settings &conf)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SubgameSpec::checkAndLog() const
|
||||||
|
{
|
||||||
|
// Log deprecation messages
|
||||||
|
auto handling_mode = get_deprecated_handling_mode();
|
||||||
|
if (!deprecation_msgs.empty() && handling_mode != DeprecatedHandlingMode::Ignore) {
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "Game " << title << " at " << path << ":" << std::endl;
|
||||||
|
for (auto msg : deprecation_msgs)
|
||||||
|
os << "\t" << msg << std::endl;
|
||||||
|
|
||||||
|
if (handling_mode == DeprecatedHandlingMode::Error)
|
||||||
|
throw ModError(os.str());
|
||||||
|
else
|
||||||
|
warningstream << os.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct GameFindPath
|
struct GameFindPath
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
@ -121,11 +141,13 @@ SubgameSpec findSubgame(const std::string &id)
|
|||||||
Settings conf;
|
Settings conf;
|
||||||
conf.readConfigFile(conf_path.c_str());
|
conf.readConfigFile(conf_path.c_str());
|
||||||
|
|
||||||
std::string game_name;
|
std::string game_title;
|
||||||
if (conf.exists("name"))
|
if (conf.exists("title"))
|
||||||
game_name = conf.get("name");
|
game_title = conf.get("title");
|
||||||
|
else if (conf.exists("name"))
|
||||||
|
game_title = conf.get("name");
|
||||||
else
|
else
|
||||||
game_name = id;
|
game_title = id;
|
||||||
|
|
||||||
std::string game_author;
|
std::string game_author;
|
||||||
if (conf.exists("author"))
|
if (conf.exists("author"))
|
||||||
@ -140,8 +162,14 @@ SubgameSpec findSubgame(const std::string &id)
|
|||||||
menuicon_path = getImagePath(
|
menuicon_path = getImagePath(
|
||||||
game_path + DIR_DELIM + "menu" + DIR_DELIM + "icon.png");
|
game_path + DIR_DELIM + "menu" + DIR_DELIM + "icon.png");
|
||||||
#endif
|
#endif
|
||||||
return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name,
|
|
||||||
|
SubgameSpec spec(id, game_path, gamemod_path, mods_paths, game_title,
|
||||||
menuicon_path, game_author, game_release);
|
menuicon_path, game_author, game_release);
|
||||||
|
|
||||||
|
if (conf.exists("name") && !conf.exists("title"))
|
||||||
|
spec.deprecation_msgs.push_back("\"name\" setting in game.conf is deprecated, please use \"title\" instead");
|
||||||
|
|
||||||
|
return spec;
|
||||||
}
|
}
|
||||||
|
|
||||||
SubgameSpec findWorldSubgame(const std::string &world_path)
|
SubgameSpec findWorldSubgame(const std::string &world_path)
|
||||||
@ -159,10 +187,12 @@ SubgameSpec findWorldSubgame(const std::string &world_path)
|
|||||||
std::string conf_path = world_gamepath + DIR_DELIM + "game.conf";
|
std::string conf_path = world_gamepath + DIR_DELIM + "game.conf";
|
||||||
conf.readConfigFile(conf_path.c_str());
|
conf.readConfigFile(conf_path.c_str());
|
||||||
|
|
||||||
if (conf.exists("name"))
|
if (conf.exists("title"))
|
||||||
gamespec.name = conf.get("name");
|
gamespec.title = conf.get("title");
|
||||||
|
else if (conf.exists("name"))
|
||||||
|
gamespec.title = conf.get("name");
|
||||||
else
|
else
|
||||||
gamespec.name = world_gameid;
|
gamespec.title = world_gameid;
|
||||||
|
|
||||||
return gamespec;
|
return gamespec;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ class Settings;
|
|||||||
struct SubgameSpec
|
struct SubgameSpec
|
||||||
{
|
{
|
||||||
std::string id;
|
std::string id;
|
||||||
std::string name;
|
std::string title;
|
||||||
std::string author;
|
std::string author;
|
||||||
int release;
|
int release;
|
||||||
std::string path;
|
std::string path;
|
||||||
@ -41,20 +41,24 @@ struct SubgameSpec
|
|||||||
std::unordered_map<std::string, std::string> addon_mods_paths;
|
std::unordered_map<std::string, std::string> addon_mods_paths;
|
||||||
std::string menuicon_path;
|
std::string menuicon_path;
|
||||||
|
|
||||||
|
// For logging purposes
|
||||||
|
std::vector<const char *> deprecation_msgs;
|
||||||
|
|
||||||
SubgameSpec(const std::string &id = "", const std::string &path = "",
|
SubgameSpec(const std::string &id = "", const std::string &path = "",
|
||||||
const std::string &gamemods_path = "",
|
const std::string &gamemods_path = "",
|
||||||
const std::unordered_map<std::string, std::string> &addon_mods_paths = {},
|
const std::unordered_map<std::string, std::string> &addon_mods_paths = {},
|
||||||
const std::string &name = "",
|
const std::string &title = "",
|
||||||
const std::string &menuicon_path = "",
|
const std::string &menuicon_path = "",
|
||||||
const std::string &author = "", int release = 0) :
|
const std::string &author = "", int release = 0) :
|
||||||
id(id),
|
id(id),
|
||||||
name(name), author(author), release(release), path(path),
|
title(title), author(author), release(release), path(path),
|
||||||
gamemods_path(gamemods_path), addon_mods_paths(addon_mods_paths),
|
gamemods_path(gamemods_path), addon_mods_paths(addon_mods_paths),
|
||||||
menuicon_path(menuicon_path)
|
menuicon_path(menuicon_path)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isValid() const { return (!id.empty() && !path.empty()); }
|
bool isValid() const { return (!id.empty() && !path.empty()); }
|
||||||
|
void checkAndLog() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
SubgameSpec findSubgame(const std::string &id);
|
SubgameSpec findSubgame(const std::string &id);
|
||||||
|
@ -344,7 +344,7 @@ void set_default_settings()
|
|||||||
settings->setDefault("shadow_filters", "1");
|
settings->setDefault("shadow_filters", "1");
|
||||||
settings->setDefault("shadow_poisson_filter", "true");
|
settings->setDefault("shadow_poisson_filter", "true");
|
||||||
settings->setDefault("shadow_update_frames", "8");
|
settings->setDefault("shadow_update_frames", "8");
|
||||||
settings->setDefault("shadow_soft_radius", "1.0");
|
settings->setDefault("shadow_soft_radius", "5.0");
|
||||||
settings->setDefault("shadow_sky_body_orbit_tilt", "0.0");
|
settings->setDefault("shadow_sky_body_orbit_tilt", "0.0");
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
|
@ -54,25 +54,10 @@ GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
GUIConfirmRegistration::~GUIConfirmRegistration()
|
|
||||||
{
|
|
||||||
removeChildren();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GUIConfirmRegistration::removeChildren()
|
|
||||||
{
|
|
||||||
const core::list<gui::IGUIElement *> &children = getChildren();
|
|
||||||
core::list<gui::IGUIElement *> children_copy;
|
|
||||||
for (gui::IGUIElement *i : children)
|
|
||||||
children_copy.push_back(i);
|
|
||||||
for (gui::IGUIElement *i : children_copy)
|
|
||||||
i->remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
|
void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
|
||||||
{
|
{
|
||||||
acceptInput();
|
acceptInput();
|
||||||
removeChildren();
|
removeAllChildren();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate new sizes and positions
|
Calculate new sizes and positions
|
||||||
|
@ -34,9 +34,6 @@ public:
|
|||||||
s32 id, IMenuManager *menumgr, Client *client,
|
s32 id, IMenuManager *menumgr, Client *client,
|
||||||
const std::string &playername, const std::string &password,
|
const std::string &playername, const std::string &password,
|
||||||
bool *aborted, ISimpleTextureSource *tsrc);
|
bool *aborted, ISimpleTextureSource *tsrc);
|
||||||
~GUIConfirmRegistration();
|
|
||||||
|
|
||||||
void removeChildren();
|
|
||||||
/*
|
/*
|
||||||
Remove and re-add (or reposition) stuff
|
Remove and re-add (or reposition) stuff
|
||||||
*/
|
*/
|
||||||
|
@ -127,7 +127,8 @@ GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick,
|
|||||||
|
|
||||||
GUIFormSpecMenu::~GUIFormSpecMenu()
|
GUIFormSpecMenu::~GUIFormSpecMenu()
|
||||||
{
|
{
|
||||||
removeChildren();
|
removeAllChildren();
|
||||||
|
removeTooltip();
|
||||||
|
|
||||||
for (auto &table_it : m_tables)
|
for (auto &table_it : m_tables)
|
||||||
table_it.second->drop();
|
table_it.second->drop();
|
||||||
@ -174,14 +175,8 @@ void GUIFormSpecMenu::create(GUIFormSpecMenu *&cur_formspec, Client *client,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::removeChildren()
|
void GUIFormSpecMenu::removeTooltip()
|
||||||
{
|
{
|
||||||
const core::list<gui::IGUIElement*> &children = getChildren();
|
|
||||||
|
|
||||||
while (!children.empty()) {
|
|
||||||
(*children.getLast())->remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_tooltip_element) {
|
if (m_tooltip_element) {
|
||||||
m_tooltip_element->remove();
|
m_tooltip_element->remove();
|
||||||
m_tooltip_element->drop();
|
m_tooltip_element->drop();
|
||||||
@ -199,16 +194,7 @@ void GUIFormSpecMenu::setInitialFocus()
|
|||||||
// 5. first focusable (not statictext, not tabheader)
|
// 5. first focusable (not statictext, not tabheader)
|
||||||
// 6. first child element
|
// 6. first child element
|
||||||
|
|
||||||
core::list<gui::IGUIElement*> children = getChildren();
|
const auto& children = getChildren();
|
||||||
|
|
||||||
// in case "children" contains any NULL elements, remove them
|
|
||||||
for (core::list<gui::IGUIElement*>::Iterator it = children.begin();
|
|
||||||
it != children.end();) {
|
|
||||||
if (*it)
|
|
||||||
++it;
|
|
||||||
else
|
|
||||||
it = children.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. first empty editbox
|
// 1. first empty editbox
|
||||||
for (gui::IGUIElement *it : children) {
|
for (gui::IGUIElement *it : children) {
|
||||||
@ -236,8 +222,7 @@ void GUIFormSpecMenu::setInitialFocus()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 4. last button
|
// 4. last button
|
||||||
for (core::list<gui::IGUIElement*>::Iterator it = children.getLast();
|
for (auto it = children.rbegin(); it != children.rend(); ++it) {
|
||||||
it != children.end(); --it) {
|
|
||||||
if ((*it)->getType() == gui::EGUIET_BUTTON) {
|
if ((*it)->getType() == gui::EGUIET_BUTTON) {
|
||||||
Environment->setFocus(*it);
|
Environment->setFocus(*it);
|
||||||
return;
|
return;
|
||||||
@ -257,7 +242,7 @@ void GUIFormSpecMenu::setInitialFocus()
|
|||||||
if (children.empty())
|
if (children.empty())
|
||||||
Environment->setFocus(this);
|
Environment->setFocus(this);
|
||||||
else
|
else
|
||||||
Environment->setFocus(*(children.begin()));
|
Environment->setFocus(children.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
GUITable* GUIFormSpecMenu::getTable(const std::string &tablename)
|
GUITable* GUIFormSpecMenu::getTable(const std::string &tablename)
|
||||||
@ -3045,7 +3030,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove children
|
// Remove children
|
||||||
removeChildren();
|
removeAllChildren();
|
||||||
|
removeTooltip();
|
||||||
|
|
||||||
for (auto &table_it : m_tables)
|
for (auto &table_it : m_tables)
|
||||||
table_it.second->drop();
|
table_it.second->drop();
|
||||||
@ -3341,7 +3327,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||||||
pos_offset = v2f32();
|
pos_offset = v2f32();
|
||||||
|
|
||||||
// used for formspec versions < 3
|
// used for formspec versions < 3
|
||||||
core::list<IGUIElement *>::Iterator legacy_sort_start = Children.getLast();
|
std::list<IGUIElement *>::iterator legacy_sort_start = std::prev(Children.end()); // last element
|
||||||
|
|
||||||
if (enable_prepends) {
|
if (enable_prepends) {
|
||||||
// Backup the coordinates so that prepends can use the coordinates of choice.
|
// Backup the coordinates so that prepends can use the coordinates of choice.
|
||||||
@ -3356,7 +3342,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||||||
// legacy sorting for formspec versions < 3
|
// legacy sorting for formspec versions < 3
|
||||||
if (m_formspec_version >= 3)
|
if (m_formspec_version >= 3)
|
||||||
// prepends do not need to be reordered
|
// prepends do not need to be reordered
|
||||||
legacy_sort_start = Children.getLast();
|
legacy_sort_start = std::prev(Children.end()); // last element
|
||||||
else if (version_backup >= 3)
|
else if (version_backup >= 3)
|
||||||
// only prepends elements have to be reordered
|
// only prepends elements have to be reordered
|
||||||
legacySortElements(legacy_sort_start);
|
legacySortElements(legacy_sort_start);
|
||||||
@ -3437,7 +3423,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator from)
|
void GUIFormSpecMenu::legacySortElements(std::list<IGUIElement *>::iterator from)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Draw order for formspec_version <= 2:
|
Draw order for formspec_version <= 2:
|
||||||
@ -3454,17 +3440,16 @@ void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator fro
|
|||||||
if (from == Children.end())
|
if (from == Children.end())
|
||||||
from = Children.begin();
|
from = Children.begin();
|
||||||
else
|
else
|
||||||
from++;
|
++from;
|
||||||
|
|
||||||
core::list<IGUIElement *>::Iterator to = Children.end();
|
std::list<IGUIElement *>::iterator to = Children.end();
|
||||||
// 1: Copy into a sortable container
|
// 1: Copy into a sortable container
|
||||||
std::vector<IGUIElement *> elements;
|
std::vector<IGUIElement *> elements(from, to);
|
||||||
for (auto it = from; it != to; ++it)
|
|
||||||
elements.emplace_back(*it);
|
|
||||||
|
|
||||||
// 2: Sort the container
|
// 2: Sort the container
|
||||||
std::stable_sort(elements.begin(), elements.end(),
|
std::stable_sort(elements.begin(), elements.end(),
|
||||||
[this] (const IGUIElement *a, const IGUIElement *b) -> bool {
|
[this] (const IGUIElement *a, const IGUIElement *b) -> bool {
|
||||||
|
// TODO: getSpecByID is a linear search. It should made O(1), or cached here.
|
||||||
const FieldSpec *spec_a = getSpecByID(a->getID());
|
const FieldSpec *spec_a = getSpecByID(a->getID());
|
||||||
const FieldSpec *spec_b = getSpecByID(b->getID());
|
const FieldSpec *spec_b = getSpecByID(b->getID());
|
||||||
return spec_a && spec_b &&
|
return spec_a && spec_b &&
|
||||||
@ -3472,10 +3457,7 @@ void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator fro
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 3: Re-assign the pointers
|
// 3: Re-assign the pointers
|
||||||
for (auto e : elements) {
|
reorderChildren(from, to, elements);
|
||||||
*from = e;
|
|
||||||
from++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
@ -3600,12 +3582,11 @@ void GUIFormSpecMenu::drawMenu()
|
|||||||
/*
|
/*
|
||||||
This is where all the drawing happens.
|
This is where all the drawing happens.
|
||||||
*/
|
*/
|
||||||
core::list<IGUIElement*>::Iterator it = Children.begin();
|
for (auto child : Children)
|
||||||
for (; it != Children.end(); ++it)
|
if (child->isNotClipped() ||
|
||||||
if ((*it)->isNotClipped() ||
|
|
||||||
AbsoluteClippingRect.isRectCollided(
|
AbsoluteClippingRect.isRectCollided(
|
||||||
(*it)->getAbsolutePosition()))
|
child->getAbsolutePosition()))
|
||||||
(*it)->draw();
|
child->draw();
|
||||||
|
|
||||||
for (gui::IGUIElement *e : m_clickthrough_elements)
|
for (gui::IGUIElement *e : m_clickthrough_elements)
|
||||||
e->setVisible(false);
|
e->setVisible(false);
|
||||||
|
@ -212,7 +212,7 @@ public:
|
|||||||
m_lockscreensize = basescreensize;
|
m_lockscreensize = basescreensize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeChildren();
|
void removeTooltip();
|
||||||
void setInitialFocus();
|
void setInitialFocus();
|
||||||
|
|
||||||
void setFocus(const std::string &elementname)
|
void setFocus(const std::string &elementname)
|
||||||
@ -467,7 +467,7 @@ private:
|
|||||||
* types were drawn before others.
|
* types were drawn before others.
|
||||||
* This function sorts the elements in the old order for backwards compatibility.
|
* This function sorts the elements in the old order for backwards compatibility.
|
||||||
*/
|
*/
|
||||||
void legacySortElements(core::list<IGUIElement *>::Iterator from);
|
void legacySortElements(std::list<IGUIElement *>::iterator from);
|
||||||
|
|
||||||
int m_btn_height;
|
int m_btn_height;
|
||||||
gui::IGUIFont *m_font = nullptr;
|
gui::IGUIFont *m_font = nullptr;
|
||||||
|
@ -103,7 +103,8 @@ GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
|
|||||||
|
|
||||||
GUIKeyChangeMenu::~GUIKeyChangeMenu()
|
GUIKeyChangeMenu::~GUIKeyChangeMenu()
|
||||||
{
|
{
|
||||||
removeChildren();
|
removeAllChildren();
|
||||||
|
key_used_text = nullptr;
|
||||||
|
|
||||||
for (key_setting *ks : key_settings) {
|
for (key_setting *ks : key_settings) {
|
||||||
delete[] ks->button_name;
|
delete[] ks->button_name;
|
||||||
@ -112,23 +113,10 @@ GUIKeyChangeMenu::~GUIKeyChangeMenu()
|
|||||||
key_settings.clear();
|
key_settings.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIKeyChangeMenu::removeChildren()
|
|
||||||
{
|
|
||||||
const core::list<gui::IGUIElement*> &children = getChildren();
|
|
||||||
core::list<gui::IGUIElement*> children_copy;
|
|
||||||
for (gui::IGUIElement*i : children) {
|
|
||||||
children_copy.push_back(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (gui::IGUIElement *i : children_copy) {
|
|
||||||
i->remove();
|
|
||||||
}
|
|
||||||
key_used_text = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
||||||
{
|
{
|
||||||
removeChildren();
|
removeAllChildren();
|
||||||
|
key_used_text = nullptr;
|
||||||
|
|
||||||
const float s = m_gui_scale;
|
const float s = m_gui_scale;
|
||||||
DesiredRect = core::rect<s32>(
|
DesiredRect = core::rect<s32>(
|
||||||
|
@ -46,7 +46,6 @@ public:
|
|||||||
IMenuManager *menumgr, ISimpleTextureSource *tsrc);
|
IMenuManager *menumgr, ISimpleTextureSource *tsrc);
|
||||||
~GUIKeyChangeMenu();
|
~GUIKeyChangeMenu();
|
||||||
|
|
||||||
void removeChildren();
|
|
||||||
/*
|
/*
|
||||||
Remove and re-add (or reposition) stuff
|
Remove and re-add (or reposition) stuff
|
||||||
*/
|
*/
|
||||||
|
@ -51,23 +51,6 @@ GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GUIPasswordChange::~GUIPasswordChange()
|
|
||||||
{
|
|
||||||
removeChildren();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GUIPasswordChange::removeChildren()
|
|
||||||
{
|
|
||||||
const core::list<gui::IGUIElement *> &children = getChildren();
|
|
||||||
core::list<gui::IGUIElement *> children_copy;
|
|
||||||
for (gui::IGUIElement *i : children) {
|
|
||||||
children_copy.push_back(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (gui::IGUIElement *i : children_copy) {
|
|
||||||
i->remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void GUIPasswordChange::regenerateGui(v2u32 screensize)
|
void GUIPasswordChange::regenerateGui(v2u32 screensize)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -78,7 +61,7 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
|
|||||||
/*
|
/*
|
||||||
Remove stuff
|
Remove stuff
|
||||||
*/
|
*/
|
||||||
removeChildren();
|
removeAllChildren();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate new sizes and positions
|
Calculate new sizes and positions
|
||||||
|
@ -31,9 +31,7 @@ public:
|
|||||||
GUIPasswordChange(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
|
GUIPasswordChange(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
|
||||||
IMenuManager *menumgr, Client *client,
|
IMenuManager *menumgr, Client *client,
|
||||||
ISimpleTextureSource *tsrc);
|
ISimpleTextureSource *tsrc);
|
||||||
~GUIPasswordChange();
|
|
||||||
|
|
||||||
void removeChildren();
|
|
||||||
/*
|
/*
|
||||||
Remove and re-add (or reposition) stuff
|
Remove and re-add (or reposition) stuff
|
||||||
*/
|
*/
|
||||||
|
@ -32,13 +32,12 @@ GUIFileSelectMenu::GUIFileSelectMenu(gui::IGUIEnvironment* env,
|
|||||||
|
|
||||||
GUIFileSelectMenu::~GUIFileSelectMenu()
|
GUIFileSelectMenu::~GUIFileSelectMenu()
|
||||||
{
|
{
|
||||||
removeChildren();
|
|
||||||
setlocale(LC_NUMERIC, "C");
|
setlocale(LC_NUMERIC, "C");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFileSelectMenu::regenerateGui(v2u32 screensize)
|
void GUIFileSelectMenu::regenerateGui(v2u32 screensize)
|
||||||
{
|
{
|
||||||
removeChildren();
|
removeAllChildren();
|
||||||
m_fileOpenDialog = 0;
|
m_fileOpenDialog = 0;
|
||||||
|
|
||||||
core::dimension2du size(600 * m_gui_scale, 400 * m_gui_scale);
|
core::dimension2du size(600 * m_gui_scale, 400 * m_gui_scale);
|
||||||
|
@ -59,12 +59,11 @@ bool GUIScrollContainer::OnEvent(const SEvent &event)
|
|||||||
void GUIScrollContainer::draw()
|
void GUIScrollContainer::draw()
|
||||||
{
|
{
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
core::list<IGUIElement *>::Iterator it = Children.begin();
|
for (auto child : Children)
|
||||||
for (; it != Children.end(); ++it)
|
if (child->isNotClipped() ||
|
||||||
if ((*it)->isNotClipped() ||
|
|
||||||
AbsoluteClippingRect.isRectCollided(
|
AbsoluteClippingRect.isRectCollided(
|
||||||
(*it)->getAbsolutePosition()))
|
child->getAbsolutePosition()))
|
||||||
(*it)->draw();
|
child->draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,32 +45,12 @@ GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GUIVolumeChange::~GUIVolumeChange()
|
|
||||||
{
|
|
||||||
removeChildren();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GUIVolumeChange::removeChildren()
|
|
||||||
{
|
|
||||||
if (gui::IGUIElement *e = getElementFromId(ID_soundText))
|
|
||||||
e->remove();
|
|
||||||
|
|
||||||
if (gui::IGUIElement *e = getElementFromId(ID_soundExitButton))
|
|
||||||
e->remove();
|
|
||||||
|
|
||||||
if (gui::IGUIElement *e = getElementFromId(ID_soundSlider))
|
|
||||||
e->remove();
|
|
||||||
|
|
||||||
if (gui::IGUIElement *e = getElementFromId(ID_soundMuteButton))
|
|
||||||
e->remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GUIVolumeChange::regenerateGui(v2u32 screensize)
|
void GUIVolumeChange::regenerateGui(v2u32 screensize)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Remove stuff
|
Remove stuff
|
||||||
*/
|
*/
|
||||||
removeChildren();
|
removeAllChildren();
|
||||||
/*
|
/*
|
||||||
Calculate new sizes and positions
|
Calculate new sizes and positions
|
||||||
*/
|
*/
|
||||||
|
@ -31,9 +31,6 @@ public:
|
|||||||
GUIVolumeChange(gui::IGUIEnvironment* env,
|
GUIVolumeChange(gui::IGUIEnvironment* env,
|
||||||
gui::IGUIElement* parent, s32 id,
|
gui::IGUIElement* parent, s32 id,
|
||||||
IMenuManager *menumgr, ISimpleTextureSource *tsrc);
|
IMenuManager *menumgr, ISimpleTextureSource *tsrc);
|
||||||
~GUIVolumeChange();
|
|
||||||
|
|
||||||
void removeChildren();
|
|
||||||
/*
|
/*
|
||||||
Remove and re-add (or reposition) stuff
|
Remove and re-add (or reposition) stuff
|
||||||
*/
|
*/
|
||||||
|
@ -64,10 +64,6 @@ public:
|
|||||||
// Remove all entries if there are duplicates
|
// Remove all entries if there are duplicates
|
||||||
m_stack.remove(menu);
|
m_stack.remove(menu);
|
||||||
|
|
||||||
/*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast();
|
|
||||||
assert(*i == menu);
|
|
||||||
m_stack.erase(i);*/
|
|
||||||
|
|
||||||
if(!m_stack.empty())
|
if(!m_stack.empty())
|
||||||
m_stack.back()->setVisible(true);
|
m_stack.back()->setVisible(true);
|
||||||
}
|
}
|
||||||
|
@ -108,19 +108,6 @@ void GUIModalMenu::quitMenu()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIModalMenu::removeChildren()
|
|
||||||
{
|
|
||||||
const core::list<gui::IGUIElement *> &children = getChildren();
|
|
||||||
core::list<gui::IGUIElement *> children_copy;
|
|
||||||
for (gui::IGUIElement *i : children) {
|
|
||||||
children_copy.push_back(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (gui::IGUIElement *i : children_copy) {
|
|
||||||
i->remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
bool GUIModalMenu::DoubleClickDetection(const SEvent &event)
|
bool GUIModalMenu::DoubleClickDetection(const SEvent &event)
|
||||||
{
|
{
|
||||||
|
@ -47,7 +47,6 @@ public:
|
|||||||
bool canTakeFocus(gui::IGUIElement *e);
|
bool canTakeFocus(gui::IGUIElement *e);
|
||||||
void draw();
|
void draw();
|
||||||
void quitMenu();
|
void quitMenu();
|
||||||
void removeChildren();
|
|
||||||
|
|
||||||
virtual void regenerateGui(v2u32 screensize) = 0;
|
virtual void regenerateGui(v2u32 screensize) = 0;
|
||||||
virtual void drawMenu() = 0;
|
virtual void drawMenu() = 0;
|
||||||
|
@ -292,9 +292,6 @@ shadow_offset(0), shadow_alpha(0), fallback(0)
|
|||||||
Driver->grab();
|
Driver->grab();
|
||||||
|
|
||||||
setInvisibleCharacters(L" ");
|
setInvisibleCharacters(L" ");
|
||||||
|
|
||||||
// Glyphs aren't reference counted, so don't try to delete them when we free the array.
|
|
||||||
Glyphs.set_free_when_destroyed(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antialias, const bool transparency)
|
bool CGUITTFont::load(const io::path& filename, const u32 size, const bool antialias, const bool transparency)
|
||||||
@ -411,8 +408,7 @@ CGUITTFont::~CGUITTFont()
|
|||||||
{
|
{
|
||||||
// Delete the glyphs and glyph pages.
|
// Delete the glyphs and glyph pages.
|
||||||
reset_images();
|
reset_images();
|
||||||
CGUITTAssistDelete::Delete(Glyphs);
|
Glyphs.clear();
|
||||||
//Glyphs.clear();
|
|
||||||
|
|
||||||
// We aren't using this face anymore.
|
// We aren't using this face anymore.
|
||||||
auto n = c_faces.find(filename);
|
auto n = c_faces.find(filename);
|
||||||
@ -675,6 +671,8 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
|
|||||||
update_glyph_pages();
|
update_glyph_pages();
|
||||||
auto it = Render_Map.begin();
|
auto it = Render_Map.begin();
|
||||||
auto ie = Render_Map.end();
|
auto ie = Render_Map.end();
|
||||||
|
core::array<core::vector2di> tmp_positions;
|
||||||
|
core::array<core::recti> tmp_source_rects;
|
||||||
while (it != ie)
|
while (it != ie)
|
||||||
{
|
{
|
||||||
CGUITTGlyphPage* page = it->second;
|
CGUITTGlyphPage* page = it->second;
|
||||||
@ -696,10 +694,8 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
|
|||||||
do
|
do
|
||||||
++i;
|
++i;
|
||||||
while (i < page->render_positions.size() && page->render_colors[i] == colprev);
|
while (i < page->render_positions.size() && page->render_colors[i] == colprev);
|
||||||
core::array<core::vector2di> tmp_positions;
|
tmp_positions.set_data(&page->render_positions[ibegin], i - ibegin);
|
||||||
core::array<core::recti> tmp_source_rects;
|
tmp_source_rects.set_data(&page->render_source_rects[ibegin], i - ibegin);
|
||||||
tmp_positions.set_pointer(&page->render_positions[ibegin], i - ibegin, false, false); // no copy
|
|
||||||
tmp_source_rects.set_pointer(&page->render_source_rects[ibegin], i - ibegin, false, false);
|
|
||||||
--i;
|
--i;
|
||||||
|
|
||||||
if (!use_transparency)
|
if (!use_transparency)
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <irrUString.h>
|
#include <irrUString.h>
|
||||||
#include "util/enriched_string.h"
|
#include "util/enriched_string.h"
|
||||||
|
#include "util/basic_macros.h"
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
namespace irr
|
namespace irr
|
||||||
@ -46,23 +47,34 @@ namespace gui
|
|||||||
struct SGUITTFace;
|
struct SGUITTFace;
|
||||||
class CGUITTFont;
|
class CGUITTFont;
|
||||||
|
|
||||||
//! Class to assist in deleting glyphs.
|
|
||||||
class CGUITTAssistDelete
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template <class T, typename TAlloc>
|
|
||||||
static void Delete(core::array<T, TAlloc>& a)
|
|
||||||
{
|
|
||||||
TAlloc allocator;
|
|
||||||
allocator.deallocate(a.pointer());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Structure representing a single TrueType glyph.
|
//! Structure representing a single TrueType glyph.
|
||||||
struct SGUITTGlyph
|
struct SGUITTGlyph
|
||||||
{
|
{
|
||||||
//! Constructor.
|
//! Constructor.
|
||||||
SGUITTGlyph() : isLoaded(false), glyph_page(0), surface(0), parent(0) {}
|
SGUITTGlyph() :
|
||||||
|
isLoaded(false),
|
||||||
|
glyph_page(0),
|
||||||
|
source_rect(),
|
||||||
|
offset(),
|
||||||
|
advance(),
|
||||||
|
surface(0),
|
||||||
|
parent(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
DISABLE_CLASS_COPY(SGUITTGlyph);
|
||||||
|
|
||||||
|
//! This class would be trivially copyable except for the reference count on `surface`.
|
||||||
|
SGUITTGlyph(SGUITTGlyph &&other) :
|
||||||
|
isLoaded(other.isLoaded),
|
||||||
|
glyph_page(other.glyph_page),
|
||||||
|
source_rect(other.source_rect),
|
||||||
|
offset(other.offset),
|
||||||
|
advance(other.advance),
|
||||||
|
surface(other.surface),
|
||||||
|
parent(other.parent)
|
||||||
|
{
|
||||||
|
other.surface = 0;
|
||||||
|
}
|
||||||
|
|
||||||
//! Destructor.
|
//! Destructor.
|
||||||
~SGUITTGlyph() { unload(); }
|
~SGUITTGlyph() { unload(); }
|
||||||
|
@ -304,7 +304,11 @@ int ModApiMainMenu::l_get_games(lua_State *L)
|
|||||||
lua_settable(L, top_lvl2);
|
lua_settable(L, top_lvl2);
|
||||||
|
|
||||||
lua_pushstring(L, "name");
|
lua_pushstring(L, "name");
|
||||||
lua_pushstring(L, game.name.c_str());
|
lua_pushstring(L, game.title.c_str());
|
||||||
|
lua_settable(L, top_lvl2);
|
||||||
|
|
||||||
|
lua_pushstring(L, "title");
|
||||||
|
lua_pushstring(L, game.title.c_str());
|
||||||
lua_settable(L, top_lvl2);
|
lua_settable(L, top_lvl2);
|
||||||
|
|
||||||
lua_pushstring(L, "author");
|
lua_pushstring(L, "author");
|
||||||
@ -356,6 +360,11 @@ int ModApiMainMenu::l_get_content_info(lua_State *L)
|
|||||||
lua_pushstring(L, spec.author.c_str());
|
lua_pushstring(L, spec.author.c_str());
|
||||||
lua_setfield(L, -2, "author");
|
lua_setfield(L, -2, "author");
|
||||||
|
|
||||||
|
if (!spec.title.empty()) {
|
||||||
|
lua_pushstring(L, spec.title.c_str());
|
||||||
|
lua_setfield(L, -2, "title");
|
||||||
|
}
|
||||||
|
|
||||||
lua_pushinteger(L, spec.release);
|
lua_pushinteger(L, spec.release);
|
||||||
lua_setfield(L, -2, "release");
|
lua_setfield(L, -2, "release");
|
||||||
|
|
||||||
|
@ -440,6 +440,7 @@ void Server::init()
|
|||||||
|
|
||||||
m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
|
m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
|
||||||
|
|
||||||
|
m_gamespec.checkAndLog();
|
||||||
m_modmgr->loadMods(m_script);
|
m_modmgr->loadMods(m_script);
|
||||||
|
|
||||||
// Read Textures and calculate sha1 sums
|
// Read Textures and calculate sha1 sums
|
||||||
@ -3109,7 +3110,7 @@ std::string Server::getStatusString()
|
|||||||
// Version
|
// Version
|
||||||
os << "version: " << g_version_string;
|
os << "version: " << g_version_string;
|
||||||
// Game
|
// Game
|
||||||
os << " | game: " << (m_gamespec.name.empty() ? m_gamespec.id : m_gamespec.name);
|
os << " | game: " << (m_gamespec.title.empty() ? m_gamespec.id : m_gamespec.title);
|
||||||
// Uptime
|
// Uptime
|
||||||
os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
|
os << " | uptime: " << duration_to_string((int) m_uptime_counter->get());
|
||||||
// Max lag estimate
|
// Max lag estimate
|
||||||
|
@ -362,7 +362,7 @@ struct TestMapBlock: public TestBase
|
|||||||
|
|
||||||
MapNode node;
|
MapNode node;
|
||||||
bool position_valid;
|
bool position_valid;
|
||||||
core::list<v3s16> validity_exceptions;
|
std::list<v3s16> validity_exceptions;
|
||||||
|
|
||||||
TC()
|
TC()
|
||||||
{
|
{
|
||||||
@ -373,7 +373,7 @@ struct TestMapBlock: public TestBase
|
|||||||
{
|
{
|
||||||
//return position_valid ^ (p==position_valid_exception);
|
//return position_valid ^ (p==position_valid_exception);
|
||||||
bool exception = false;
|
bool exception = false;
|
||||||
for(core::list<v3s16>::Iterator i=validity_exceptions.begin();
|
for(std::list<v3s16>::iterator i=validity_exceptions.begin();
|
||||||
i != validity_exceptions.end(); i++)
|
i != validity_exceptions.end(); i++)
|
||||||
{
|
{
|
||||||
if(p == *i)
|
if(p == *i)
|
||||||
|
@ -80,7 +80,7 @@ class TestFailedException : public std::exception {
|
|||||||
<< #expected << std::endl \
|
<< #expected << std::endl \
|
||||||
<< " at " << fs::GetFilenameFromPath(__FILE__) << ":" \
|
<< " at " << fs::GetFilenameFromPath(__FILE__) << ":" \
|
||||||
<< __LINE__ << std::endl \
|
<< __LINE__ << std::endl \
|
||||||
<< " actual: " << a << std::endl << " expected: " \
|
<< " actual : " << a << std::endl << " expected: " \
|
||||||
<< e << std::endl; \
|
<< e << std::endl; \
|
||||||
throw TestFailedException(); \
|
throw TestFailedException(); \
|
||||||
} \
|
} \
|
||||||
|
@ -169,23 +169,50 @@ void TestSerialization::testDeSerializeLongString()
|
|||||||
|
|
||||||
void TestSerialization::testSerializeJsonString()
|
void TestSerialization::testSerializeJsonString()
|
||||||
{
|
{
|
||||||
|
std::istringstream is(std::ios::binary);
|
||||||
|
const auto reset_is = [&] (const std::string &s) {
|
||||||
|
is.clear();
|
||||||
|
is.str(s);
|
||||||
|
};
|
||||||
|
const auto assert_at_eof = [] (std::istream &is) {
|
||||||
|
is.get();
|
||||||
|
UASSERT(is.eof());
|
||||||
|
};
|
||||||
|
|
||||||
// Test blank string
|
// Test blank string
|
||||||
UASSERT(serializeJsonString("") == "\"\"");
|
UASSERTEQ(std::string, serializeJsonString(""), "\"\"");
|
||||||
|
reset_is("\"\"");
|
||||||
|
UASSERTEQ(std::string, deSerializeJsonString(is), "");
|
||||||
|
assert_at_eof(is);
|
||||||
|
|
||||||
// Test basic string
|
// Test basic string
|
||||||
UASSERT(serializeJsonString("Hello world!") == "\"Hello world!\"");
|
UASSERTEQ(std::string, serializeJsonString("Hello world!"), "\"Hello world!\"");
|
||||||
|
reset_is("\"Hello world!\"");
|
||||||
|
UASSERTEQ(std::string, deSerializeJsonString(is), "Hello world!");
|
||||||
|
assert_at_eof(is);
|
||||||
|
|
||||||
// MSVC fails when directly using "\\\\"
|
// Test optional serialization
|
||||||
std::string backslash = "\\";
|
const std::pair<const char*, const char*> test_pairs[] = {
|
||||||
UASSERT(serializeJsonString(teststring2) ==
|
{ "abc", "abc" },
|
||||||
mkstr("\"") +
|
{ "x y z", "\"x y z\"" },
|
||||||
|
{ "\"", "\"\\\"\"" },
|
||||||
|
};
|
||||||
|
for (auto it : test_pairs) {
|
||||||
|
UASSERTEQ(std::string, serializeJsonStringIfNeeded(it.first), it.second);
|
||||||
|
reset_is(it.second);
|
||||||
|
UASSERTEQ(std::string, deSerializeJsonStringIfNeeded(is), it.first);
|
||||||
|
assert_at_eof(is);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test all byte values
|
||||||
|
const std::string bs = "\\"; // MSVC fails when directly using "\\\\"
|
||||||
|
const std::string expected = mkstr("\"") +
|
||||||
"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007" +
|
"\\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007" +
|
||||||
"\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f" +
|
"\\b\\t\\n\\u000b\\f\\r\\u000e\\u000f" +
|
||||||
"\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" +
|
"\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017" +
|
||||||
"\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f" +
|
"\\u0018\\u0019\\u001a\\u001b\\u001c\\u001d\\u001e\\u001f" +
|
||||||
" !\\\"" + teststring2.substr(0x23, 0x2f-0x23) +
|
" !\\\"" + teststring2.substr(0x23, 0x5c-0x23) +
|
||||||
"\\/" + teststring2.substr(0x30, 0x5c-0x30) +
|
bs + bs + teststring2.substr(0x5d, 0x7f-0x5d) + "\\u007f" +
|
||||||
backslash + backslash + teststring2.substr(0x5d, 0x7f-0x5d) + "\\u007f" +
|
|
||||||
"\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087" +
|
"\\u0080\\u0081\\u0082\\u0083\\u0084\\u0085\\u0086\\u0087" +
|
||||||
"\\u0088\\u0089\\u008a\\u008b\\u008c\\u008d\\u008e\\u008f" +
|
"\\u0088\\u0089\\u008a\\u008b\\u008c\\u008d\\u008e\\u008f" +
|
||||||
"\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" +
|
"\\u0090\\u0091\\u0092\\u0093\\u0094\\u0095\\u0096\\u0097" +
|
||||||
@ -202,14 +229,31 @@ void TestSerialization::testSerializeJsonString()
|
|||||||
"\\u00e8\\u00e9\\u00ea\\u00eb\\u00ec\\u00ed\\u00ee\\u00ef" +
|
"\\u00e8\\u00e9\\u00ea\\u00eb\\u00ec\\u00ed\\u00ee\\u00ef" +
|
||||||
"\\u00f0\\u00f1\\u00f2\\u00f3\\u00f4\\u00f5\\u00f6\\u00f7" +
|
"\\u00f0\\u00f1\\u00f2\\u00f3\\u00f4\\u00f5\\u00f6\\u00f7" +
|
||||||
"\\u00f8\\u00f9\\u00fa\\u00fb\\u00fc\\u00fd\\u00fe\\u00ff" +
|
"\\u00f8\\u00f9\\u00fa\\u00fb\\u00fc\\u00fd\\u00fe\\u00ff" +
|
||||||
"\"");
|
"\"";
|
||||||
|
std::string serialized = serializeJsonString(teststring2);
|
||||||
|
UASSERTEQ(std::string, serialized, expected);
|
||||||
|
|
||||||
// Test deserialize
|
reset_is(serialized);
|
||||||
std::istringstream is(serializeJsonString(teststring2), std::ios::binary);
|
UASSERTEQ(std::string, deSerializeJsonString(is), teststring2);
|
||||||
UASSERT(deSerializeJsonString(is) == teststring2);
|
UASSERT(!is.eof()); // should have stopped at " so eof must not be set yet
|
||||||
UASSERT(!is.eof());
|
assert_at_eof(is);
|
||||||
is.get();
|
|
||||||
UASSERT(is.eof());
|
// Test that deserialization leaves rest of stream alone
|
||||||
|
std::string tmp;
|
||||||
|
reset_is("\"foo\"bar");
|
||||||
|
UASSERTEQ(std::string, deSerializeJsonString(is), "foo");
|
||||||
|
std::getline(is, tmp, '\0');
|
||||||
|
UASSERTEQ(std::string, tmp, "bar");
|
||||||
|
|
||||||
|
reset_is("\"x y z\"bar");
|
||||||
|
UASSERTEQ(std::string, deSerializeJsonStringIfNeeded(is), "x y z");
|
||||||
|
std::getline(is, tmp, '\0');
|
||||||
|
UASSERTEQ(std::string, tmp, "bar");
|
||||||
|
|
||||||
|
reset_is("foo bar");
|
||||||
|
UASSERTEQ(std::string, deSerializeJsonStringIfNeeded(is), "foo");
|
||||||
|
std::getline(is, tmp, '\0');
|
||||||
|
UASSERTEQ(std::string, tmp, " bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,15 +18,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "serialize.h"
|
#include "serialize.h"
|
||||||
#include "pointer.h"
|
|
||||||
#include "porting.h"
|
#include "porting.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
#include "util/hex.h"
|
||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "irrlichttypes.h"
|
#include "irrlichttypes.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <cassert>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
FloatType g_serialize_f32_type = FLOATTYPE_UNKNOWN;
|
FloatType g_serialize_f32_type = FLOATTYPE_UNKNOWN;
|
||||||
|
|
||||||
@ -120,121 +119,148 @@ std::string deSerializeString32(std::istream &is)
|
|||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
//// JSON
|
//// JSON-like strings
|
||||||
////
|
////
|
||||||
|
|
||||||
std::string serializeJsonString(const std::string &plain)
|
std::string serializeJsonString(const std::string &plain)
|
||||||
{
|
{
|
||||||
std::ostringstream os(std::ios::binary);
|
std::string tmp;
|
||||||
os << "\"";
|
|
||||||
|
tmp.reserve(plain.size() + 2);
|
||||||
|
tmp.push_back('"');
|
||||||
|
|
||||||
for (char c : plain) {
|
for (char c : plain) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '"':
|
case '"':
|
||||||
os << "\\\"";
|
tmp.append("\\\"");
|
||||||
break;
|
break;
|
||||||
case '\\':
|
case '\\':
|
||||||
os << "\\\\";
|
tmp.append("\\\\");
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
os << "\\/";
|
|
||||||
break;
|
break;
|
||||||
case '\b':
|
case '\b':
|
||||||
os << "\\b";
|
tmp.append("\\b");
|
||||||
break;
|
break;
|
||||||
case '\f':
|
case '\f':
|
||||||
os << "\\f";
|
tmp.append("\\f");
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
os << "\\n";
|
tmp.append("\\n");
|
||||||
break;
|
break;
|
||||||
case '\r':
|
case '\r':
|
||||||
os << "\\r";
|
tmp.append("\\r");
|
||||||
break;
|
break;
|
||||||
case '\t':
|
case '\t':
|
||||||
os << "\\t";
|
tmp.append("\\t");
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
if (c >= 32 && c <= 126) {
|
if (c >= 32 && c <= 126) {
|
||||||
os << c;
|
tmp.push_back(c);
|
||||||
} else {
|
} else {
|
||||||
u32 cnum = (u8)c;
|
// We pretend that Unicode codepoints map to bytes (they don't)
|
||||||
os << "\\u" << std::hex << std::setw(4)
|
u8 cnum = static_cast<u8>(c);
|
||||||
<< std::setfill('0') << cnum;
|
tmp.append("\\u00");
|
||||||
|
tmp.push_back(hex_chars[cnum >> 4]);
|
||||||
|
tmp.push_back(hex_chars[cnum & 0xf]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
os << "\"";
|
tmp.push_back('"');
|
||||||
return os.str();
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void deSerializeJsonString(std::string &s)
|
||||||
|
{
|
||||||
|
assert(s.size() >= 2);
|
||||||
|
assert(s.front() == '"' && s.back() == '"');
|
||||||
|
|
||||||
|
size_t w = 0; // write index
|
||||||
|
size_t i = 1; // read index
|
||||||
|
const size_t len = s.size() - 1; // string length with trailing quote removed
|
||||||
|
|
||||||
|
while (i < len) {
|
||||||
|
char c = s[i++];
|
||||||
|
assert(c != '"');
|
||||||
|
|
||||||
|
if (c != '\\') {
|
||||||
|
s[w++] = c;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i >= len)
|
||||||
|
throw SerializationError("JSON string ended prematurely");
|
||||||
|
char c2 = s[i++];
|
||||||
|
switch (c2) {
|
||||||
|
case 'b':
|
||||||
|
s[w++] = '\b';
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
s[w++] = '\f';
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
s[w++] = '\n';
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
s[w++] = '\r';
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
s[w++] = '\t';
|
||||||
|
break;
|
||||||
|
case 'u': {
|
||||||
|
if (i + 3 >= len)
|
||||||
|
throw SerializationError("JSON string ended prematurely");
|
||||||
|
unsigned char v[4] = {};
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
hex_digit_decode(s[i+j], v[j]);
|
||||||
|
i += 4;
|
||||||
|
u32 hexnumber = (v[0] << 12) | (v[1] << 8) | (v[2] << 4) | v[3];
|
||||||
|
// Note that this does not work for anything other than ASCII
|
||||||
|
// but these functions do not actually interact with real JSON input.
|
||||||
|
s[w++] = (int) hexnumber;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
s[w++] = c2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(w <= i && i <= len);
|
||||||
|
// Truncate string to current write index
|
||||||
|
s.resize(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string deSerializeJsonString(std::istream &is)
|
std::string deSerializeJsonString(std::istream &is)
|
||||||
{
|
{
|
||||||
std::ostringstream os(std::ios::binary);
|
std::string tmp;
|
||||||
char c, c2;
|
char c;
|
||||||
|
bool was_backslash = false;
|
||||||
|
|
||||||
// Parse initial doublequote
|
// Parse initial doublequote
|
||||||
is >> c;
|
c = is.get();
|
||||||
if (c != '"')
|
if (c != '"')
|
||||||
throw SerializationError("JSON string must start with doublequote");
|
throw SerializationError("JSON string must start with doublequote");
|
||||||
|
tmp.push_back(c);
|
||||||
|
|
||||||
// Parse characters
|
// Grab the entire json string
|
||||||
for (;;) {
|
for (;;) {
|
||||||
c = is.get();
|
c = is.get();
|
||||||
if (is.eof())
|
if (is.eof())
|
||||||
throw SerializationError("JSON string ended prematurely");
|
throw SerializationError("JSON string ended prematurely");
|
||||||
|
|
||||||
if (c == '"') {
|
tmp.push_back(c);
|
||||||
return os.str();
|
if (was_backslash)
|
||||||
}
|
was_backslash = false;
|
||||||
|
else if (c == '\\')
|
||||||
if (c == '\\') {
|
was_backslash = true;
|
||||||
c2 = is.get();
|
else if (c == '"')
|
||||||
if (is.eof())
|
break; // found end of string
|
||||||
throw SerializationError("JSON string ended prematurely");
|
|
||||||
switch (c2) {
|
|
||||||
case 'b':
|
|
||||||
os << '\b';
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
os << '\f';
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
os << '\n';
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
os << '\r';
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
os << '\t';
|
|
||||||
break;
|
|
||||||
case 'u': {
|
|
||||||
int hexnumber;
|
|
||||||
char hexdigits[4 + 1];
|
|
||||||
|
|
||||||
is.read(hexdigits, 4);
|
|
||||||
if (is.eof())
|
|
||||||
throw SerializationError("JSON string ended prematurely");
|
|
||||||
hexdigits[4] = 0;
|
|
||||||
|
|
||||||
std::istringstream tmp_is(hexdigits, std::ios::binary);
|
|
||||||
tmp_is >> std::hex >> hexnumber;
|
|
||||||
os << (char)hexnumber;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
os << c2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
os << c;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return os.str();
|
deSerializeJsonString(tmp);
|
||||||
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string serializeJsonStringIfNeeded(const std::string &s)
|
std::string serializeJsonStringIfNeeded(const std::string &s)
|
||||||
@ -248,41 +274,21 @@ std::string serializeJsonStringIfNeeded(const std::string &s)
|
|||||||
|
|
||||||
std::string deSerializeJsonStringIfNeeded(std::istream &is)
|
std::string deSerializeJsonStringIfNeeded(std::istream &is)
|
||||||
{
|
{
|
||||||
std::stringstream tmp_os(std::ios_base::binary | std::ios_base::in | std::ios_base::out);
|
// Check for initial quote
|
||||||
bool expect_initial_quote = true;
|
char c = is.peek();
|
||||||
bool is_json = false;
|
if (is.eof())
|
||||||
bool was_backslash = false;
|
return "";
|
||||||
for (;;) {
|
|
||||||
char c = is.get();
|
|
||||||
if (is.eof())
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (expect_initial_quote && c == '"') {
|
if (c == '"') {
|
||||||
tmp_os << c;
|
// json string: defer to the right implementation
|
||||||
is_json = true;
|
return deSerializeJsonString(is);
|
||||||
} else if(is_json) {
|
|
||||||
tmp_os << c;
|
|
||||||
if (was_backslash)
|
|
||||||
was_backslash = false;
|
|
||||||
else if (c == '\\')
|
|
||||||
was_backslash = true;
|
|
||||||
else if (c == '"')
|
|
||||||
break; // Found end of string
|
|
||||||
} else {
|
|
||||||
if (c == ' ') {
|
|
||||||
// Found end of word
|
|
||||||
is.unget();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp_os << c;
|
|
||||||
}
|
|
||||||
expect_initial_quote = false;
|
|
||||||
}
|
|
||||||
if (is_json) {
|
|
||||||
return deSerializeJsonString(tmp_os);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmp_os.str();
|
// not a json string:
|
||||||
|
std::string tmp;
|
||||||
|
std::getline(is, tmp, ' ');
|
||||||
|
if (!is.eof())
|
||||||
|
is.unget(); // we hit a space, put it back
|
||||||
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 2.0 KiB |
@ -47,7 +47,7 @@ done
|
|||||||
echo "The compiler runtime DLLs could not be found, they might be missing in the final package."
|
echo "The compiler runtime DLLs could not be found, they might be missing in the final package."
|
||||||
|
|
||||||
# Get stuff
|
# Get stuff
|
||||||
irrlicht_version=1.9.0mt5
|
irrlicht_version=1.9.0mt6
|
||||||
ogg_version=1.3.5
|
ogg_version=1.3.5
|
||||||
openal_version=1.21.1
|
openal_version=1.21.1
|
||||||
vorbis_version=1.3.7
|
vorbis_version=1.3.7
|
||||||
|
@ -47,7 +47,7 @@ done
|
|||||||
echo "The compiler runtime DLLs could not be found, they might be missing in the final package."
|
echo "The compiler runtime DLLs could not be found, they might be missing in the final package."
|
||||||
|
|
||||||
# Get stuff
|
# Get stuff
|
||||||
irrlicht_version=1.9.0mt5
|
irrlicht_version=1.9.0mt6
|
||||||
ogg_version=1.3.5
|
ogg_version=1.3.5
|
||||||
openal_version=1.21.1
|
openal_version=1.21.1
|
||||||
vorbis_version=1.3.7
|
vorbis_version=1.3.7
|
||||||
|
@ -13,7 +13,7 @@ install_linux_deps() {
|
|||||||
shift
|
shift
|
||||||
pkgs+=(libirrlicht-dev)
|
pkgs+=(libirrlicht-dev)
|
||||||
else
|
else
|
||||||
wget "https://github.com/minetest/irrlicht/releases/download/1.9.0mt5/ubuntu-bionic.tar.gz"
|
wget "https://github.com/minetest/irrlicht/releases/download/1.9.0mt6/ubuntu-bionic.tar.gz"
|
||||||
sudo tar -xaf ubuntu-bionic.tar.gz -C /usr/local
|
sudo tar -xaf ubuntu-bionic.tar.gz -C /usr/local
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user