Add MultiCraft changes in src
This commit is contained in:
parent
fda3932c16
commit
b6dbd3fc7a
@ -8,22 +8,26 @@ else()
|
||||
endif()
|
||||
|
||||
# This can be read from ${PROJECT_NAME} after project() is called
|
||||
project(minetest)
|
||||
set(PROJECT_NAME_CAPITALIZED "Minetest")
|
||||
project(multicraft)
|
||||
set(PROJECT_NAME_CAPITALIZED "MultiCraft")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
set(GCC_MINIMUM_VERSION "5.1")
|
||||
set(CLANG_MINIMUM_VERSION "3.5")
|
||||
|
||||
# Also remember to set PROTOCOL_VERSION in network/networkprotocol.h when releasing
|
||||
set(VERSION_MAJOR 5)
|
||||
set(VERSION_MINOR 5)
|
||||
set(VERSION_PATCH 0)
|
||||
set(VERSION_MAJOR 2)
|
||||
set(VERSION_MINOR 0)
|
||||
set(VERSION_PATCH 4)
|
||||
set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string")
|
||||
|
||||
# Change to false for releases
|
||||
set(DEVELOPMENT_BUILD FALSE)
|
||||
|
||||
set(ENABLE_UPDATE_CHECKER (NOT ${DEVELOPMENT_BUILD}) CACHE BOOL
|
||||
"Whether to enable update checks by default")
|
||||
|
||||
set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
|
||||
if(VERSION_EXTRA)
|
||||
set(VERSION_STRING "${VERSION_STRING}-${VERSION_EXTRA}")
|
||||
@ -50,7 +54,7 @@ set(RUN_IN_PLACE ${DEFAULT_RUN_IN_PLACE} CACHE BOOL
|
||||
|
||||
set(BUILD_CLIENT TRUE CACHE BOOL "Build client")
|
||||
set(BUILD_SERVER FALSE CACHE BOOL "Build server")
|
||||
set(BUILD_UNITTESTS TRUE CACHE BOOL "Build unittests")
|
||||
set(BUILD_UNITTESTS FALSE CACHE BOOL "Build unittests")
|
||||
|
||||
set(WARN_ALL TRUE CACHE BOOL "Enable -Wall for Release build")
|
||||
|
||||
@ -186,16 +190,15 @@ install(FILES "doc/client_lua_api.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "doc/menu_lua_api.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "doc/texture_packs.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "doc/world_format.txt" DESTINATION "${DOCDIR}" COMPONENT "Docs")
|
||||
install(FILES "minetest.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
|
||||
install(FILES "multicraft.conf.example" DESTINATION "${EXAMPLE_CONF_DIR}")
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
install(FILES "doc/minetest.6" "doc/minetestserver.6" DESTINATION "${MANDIR}/man6")
|
||||
install(FILES "misc/net.minetest.minetest.desktop" DESTINATION "${XDG_APPS_DIR}")
|
||||
install(FILES "misc/net.minetest.minetest.appdata.xml" DESTINATION "${APPDATADIR}")
|
||||
install(FILES "misc/minetest.svg" DESTINATION "${ICONDIR}/hicolor/scalable/apps")
|
||||
install(FILES "misc/minetest-xorg-icon-128.png"
|
||||
install(FILES "misc/multicraft-xorg-icon-128.png"
|
||||
DESTINATION "${ICONDIR}/hicolor/128x128/apps"
|
||||
RENAME "minetest.png")
|
||||
RENAME "multicraft.png")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
@ -207,6 +210,9 @@ endif()
|
||||
find_package(GMP REQUIRED)
|
||||
find_package(Json REQUIRED)
|
||||
find_package(Lua REQUIRED)
|
||||
add_subdirectory(lib/luautf8)
|
||||
add_subdirectory(lib/luachacha)
|
||||
|
||||
if(NOT USE_LUAJIT)
|
||||
set(LUA_BIT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/bitop)
|
||||
set(LUA_BIT_LIBRARY bitop)
|
||||
@ -284,7 +290,7 @@ if(WIN32)
|
||||
set(CPACK_CREATE_DESKTOP_LINKS ${PROJECT_NAME})
|
||||
set(CPACK_PACKAGING_INSTALL_PREFIX "/${PROJECT_NAME_CAPITALIZED}")
|
||||
|
||||
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/minetest-icon.ico")
|
||||
set(CPACK_WIX_PRODUCT_ICON "${CMAKE_CURRENT_SOURCE_DIR}/misc/multicraft-icon.ico")
|
||||
# Supported languages can be found at
|
||||
# http://wixtoolset.org/documentation/manual/v3/wixui/wixui_localization.html
|
||||
#set(CPACK_WIX_CULTURES "ar-SA,bg-BG,ca-ES,hr-HR,cs-CZ,da-DK,nl-NL,en-US,et-EE,fi-FI,fr-FR,de-DE")
|
||||
|
2
lib/luachacha/CMakeLists.txt
Normal file
2
lib/luachacha/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
add_library(luachacha STATIC chacha.c lchacha.c)
|
||||
target_include_directories(luachacha PUBLIC ${LUA_INCLUDE_DIR})
|
210
lib/luachacha/chacha.c
Normal file
210
lib/luachacha/chacha.c
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
chacha-merged.c version 20080118
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include "ecrypt-sync.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#define ROTATE(v,c) (ROTL32(v,c))
|
||||
#define XOR(v,w) ((v) ^ (w))
|
||||
#define PLUS(v,w) (U32V((v) + (w)))
|
||||
#define PLUSONE(v) (PLUS((v),1))
|
||||
|
||||
#define QUARTERROUND(a,b,c,d) \
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a),16); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c),12); \
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
|
||||
|
||||
void ECRYPT_init(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static const char sigma[16] = "expand 32-byte k";
|
||||
static const char tau[16] = "expand 16-byte k";
|
||||
|
||||
void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
|
||||
{
|
||||
const char *constants;
|
||||
|
||||
x->input[4] = U8TO32_LITTLE(k + 0);
|
||||
x->input[5] = U8TO32_LITTLE(k + 4);
|
||||
x->input[6] = U8TO32_LITTLE(k + 8);
|
||||
x->input[7] = U8TO32_LITTLE(k + 12);
|
||||
if (kbits == 256) { /* recommended */
|
||||
k += 16;
|
||||
constants = sigma;
|
||||
} else { /* kbits == 128 */
|
||||
constants = tau;
|
||||
}
|
||||
x->input[8] = U8TO32_LITTLE(k + 0);
|
||||
x->input[9] = U8TO32_LITTLE(k + 4);
|
||||
x->input[10] = U8TO32_LITTLE(k + 8);
|
||||
x->input[11] = U8TO32_LITTLE(k + 12);
|
||||
x->input[0] = U8TO32_LITTLE(constants + 0);
|
||||
x->input[1] = U8TO32_LITTLE(constants + 4);
|
||||
x->input[2] = U8TO32_LITTLE(constants + 8);
|
||||
x->input[3] = U8TO32_LITTLE(constants + 12);
|
||||
}
|
||||
|
||||
void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv,const u8* counter)
|
||||
{
|
||||
x->input[12] = (counter == NULL) ? 0 : U8TO32_LITTLE(counter + 0);
|
||||
x->input[13] = (counter == NULL) ? 0 : U8TO32_LITTLE(counter + 4);
|
||||
x->input[14] = U8TO32_LITTLE(iv + 0);
|
||||
x->input[15] = U8TO32_LITTLE(iv + 4);
|
||||
}
|
||||
|
||||
void ECRYPT_IETF_ivsetup(ECRYPT_ctx *x,const u8 *iv,const u8* counter)
|
||||
{
|
||||
x->input[12] = (counter == NULL) ? 0 : U8TO32_LITTLE(counter);
|
||||
x->input[13] = U8TO32_LITTLE(iv + 0);
|
||||
x->input[14] = U8TO32_LITTLE(iv + 4);
|
||||
x->input[15] = U8TO32_LITTLE(iv + 8);
|
||||
}
|
||||
|
||||
void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes,int rounds)
|
||||
{
|
||||
u32 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15;
|
||||
u32 j0, j1, j2, j3, j4, j5, j6, j7, j8, j9, j10, j11, j12, j13, j14, j15;
|
||||
u8 *ctarget;
|
||||
u8 tmp[64];
|
||||
int i;
|
||||
|
||||
if (!bytes) return;
|
||||
|
||||
j0 = x->input[0];
|
||||
j1 = x->input[1];
|
||||
j2 = x->input[2];
|
||||
j3 = x->input[3];
|
||||
j4 = x->input[4];
|
||||
j5 = x->input[5];
|
||||
j6 = x->input[6];
|
||||
j7 = x->input[7];
|
||||
j8 = x->input[8];
|
||||
j9 = x->input[9];
|
||||
j10 = x->input[10];
|
||||
j11 = x->input[11];
|
||||
j12 = x->input[12];
|
||||
j13 = x->input[13];
|
||||
j14 = x->input[14];
|
||||
j15 = x->input[15];
|
||||
|
||||
for (;;) {
|
||||
if (bytes < 64) {
|
||||
for (i = 0;i < bytes;++i) tmp[i] = m[i];
|
||||
m = tmp;
|
||||
ctarget = c;
|
||||
c = tmp;
|
||||
}
|
||||
x0 = j0;
|
||||
x1 = j1;
|
||||
x2 = j2;
|
||||
x3 = j3;
|
||||
x4 = j4;
|
||||
x5 = j5;
|
||||
x6 = j6;
|
||||
x7 = j7;
|
||||
x8 = j8;
|
||||
x9 = j9;
|
||||
x10 = j10;
|
||||
x11 = j11;
|
||||
x12 = j12;
|
||||
x13 = j13;
|
||||
x14 = j14;
|
||||
x15 = j15;
|
||||
for (i = rounds;i > 0;i -= 2) {
|
||||
QUARTERROUND( x0, x4, x8,x12)
|
||||
QUARTERROUND( x1, x5, x9,x13)
|
||||
QUARTERROUND( x2, x6,x10,x14)
|
||||
QUARTERROUND( x3, x7,x11,x15)
|
||||
QUARTERROUND( x0, x5,x10,x15)
|
||||
QUARTERROUND( x1, x6,x11,x12)
|
||||
QUARTERROUND( x2, x7, x8,x13)
|
||||
QUARTERROUND( x3, x4, x9,x14)
|
||||
}
|
||||
x0 = PLUS(x0,j0);
|
||||
x1 = PLUS(x1,j1);
|
||||
x2 = PLUS(x2,j2);
|
||||
x3 = PLUS(x3,j3);
|
||||
x4 = PLUS(x4,j4);
|
||||
x5 = PLUS(x5,j5);
|
||||
x6 = PLUS(x6,j6);
|
||||
x7 = PLUS(x7,j7);
|
||||
x8 = PLUS(x8,j8);
|
||||
x9 = PLUS(x9,j9);
|
||||
x10 = PLUS(x10,j10);
|
||||
x11 = PLUS(x11,j11);
|
||||
x12 = PLUS(x12,j12);
|
||||
x13 = PLUS(x13,j13);
|
||||
x14 = PLUS(x14,j14);
|
||||
x15 = PLUS(x15,j15);
|
||||
|
||||
x0 = XOR(x0,U8TO32_LITTLE(m + 0));
|
||||
x1 = XOR(x1,U8TO32_LITTLE(m + 4));
|
||||
x2 = XOR(x2,U8TO32_LITTLE(m + 8));
|
||||
x3 = XOR(x3,U8TO32_LITTLE(m + 12));
|
||||
x4 = XOR(x4,U8TO32_LITTLE(m + 16));
|
||||
x5 = XOR(x5,U8TO32_LITTLE(m + 20));
|
||||
x6 = XOR(x6,U8TO32_LITTLE(m + 24));
|
||||
x7 = XOR(x7,U8TO32_LITTLE(m + 28));
|
||||
x8 = XOR(x8,U8TO32_LITTLE(m + 32));
|
||||
x9 = XOR(x9,U8TO32_LITTLE(m + 36));
|
||||
x10 = XOR(x10,U8TO32_LITTLE(m + 40));
|
||||
x11 = XOR(x11,U8TO32_LITTLE(m + 44));
|
||||
x12 = XOR(x12,U8TO32_LITTLE(m + 48));
|
||||
x13 = XOR(x13,U8TO32_LITTLE(m + 52));
|
||||
x14 = XOR(x14,U8TO32_LITTLE(m + 56));
|
||||
x15 = XOR(x15,U8TO32_LITTLE(m + 60));
|
||||
|
||||
j12 = PLUSONE(j12);
|
||||
if (!j12) {
|
||||
j13 = PLUSONE(j13);
|
||||
/* stopping at 2^70 bytes per nonce is user's responsibility */
|
||||
}
|
||||
|
||||
U32TO8_LITTLE(c + 0,x0);
|
||||
U32TO8_LITTLE(c + 4,x1);
|
||||
U32TO8_LITTLE(c + 8,x2);
|
||||
U32TO8_LITTLE(c + 12,x3);
|
||||
U32TO8_LITTLE(c + 16,x4);
|
||||
U32TO8_LITTLE(c + 20,x5);
|
||||
U32TO8_LITTLE(c + 24,x6);
|
||||
U32TO8_LITTLE(c + 28,x7);
|
||||
U32TO8_LITTLE(c + 32,x8);
|
||||
U32TO8_LITTLE(c + 36,x9);
|
||||
U32TO8_LITTLE(c + 40,x10);
|
||||
U32TO8_LITTLE(c + 44,x11);
|
||||
U32TO8_LITTLE(c + 48,x12);
|
||||
U32TO8_LITTLE(c + 52,x13);
|
||||
U32TO8_LITTLE(c + 56,x14);
|
||||
U32TO8_LITTLE(c + 60,x15);
|
||||
|
||||
if (bytes <= 64) {
|
||||
if (bytes < 64) {
|
||||
for (i = 0;i < bytes;++i) ctarget[i] = c[i];
|
||||
}
|
||||
x->input[12] = j12;
|
||||
x->input[13] = j13;
|
||||
return;
|
||||
}
|
||||
bytes -= 64;
|
||||
c += 64;
|
||||
m += 64;
|
||||
}
|
||||
}
|
||||
|
||||
void ECRYPT_decrypt_bytes(ECRYPT_ctx *x,const u8 *c,u8 *m,u32 bytes)
|
||||
{
|
||||
ECRYPT_encrypt_bytes(x,c,m,bytes,8);
|
||||
}
|
||||
|
||||
void ECRYPT_keystream_bytes(ECRYPT_ctx *x,u8 *stream,u32 bytes)
|
||||
{
|
||||
u32 i;
|
||||
for (i = 0;i < bytes;++i) stream[i] = 0;
|
||||
ECRYPT_encrypt_bytes(x,stream,stream,bytes,8);
|
||||
}
|
272
lib/luachacha/ecrypt-config.h
Normal file
272
lib/luachacha/ecrypt-config.h
Normal file
@ -0,0 +1,272 @@
|
||||
/* ecrypt-config.h */
|
||||
|
||||
/* *** Normally, it should not be necessary to edit this file. *** */
|
||||
|
||||
#ifndef ECRYPT_CONFIG
|
||||
#define ECRYPT_CONFIG
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Guess the endianness of the target architecture. */
|
||||
|
||||
/*
|
||||
* The LITTLE endian machines:
|
||||
*/
|
||||
#if defined(__ultrix) /* Older MIPS */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(__alpha) /* Alpha */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(i386) /* x86 (gcc) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(__i386) /* x86 (gcc) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(_M_IX86) /* x86 (MSC, Borland) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(_MSC_VER) /* x86 (surely MSC) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
#elif defined(__INTEL_COMPILER) /* x86 (surely Intel compiler icl.exe) */
|
||||
#define ECRYPT_LITTLE_ENDIAN
|
||||
|
||||
/*
|
||||
* The BIG endian machines:
|
||||
*/
|
||||
#elif defined(sun) /* Newer Sparc's */
|
||||
#define ECRYPT_BIG_ENDIAN
|
||||
#elif defined(__ppc__) /* PowerPC */
|
||||
#define ECRYPT_BIG_ENDIAN
|
||||
|
||||
/*
|
||||
* Finally machines with UNKNOWN endianness:
|
||||
*/
|
||||
#elif defined (_AIX) /* RS6000 */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#elif defined(__hpux) /* HP-PA */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#elif defined(__aux) /* 68K */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#elif defined(__dgux) /* 88K (but P6 in latest boxes) */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#elif defined(__sgi) /* Newer MIPS */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#else /* Any other processor */
|
||||
#define ECRYPT_UNKNOWN
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit
|
||||
* integers.
|
||||
*
|
||||
* Note: to enable 64-bit types on 32-bit compilers, it might be
|
||||
* necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc
|
||||
* -std=c99).
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* --- check char --- */
|
||||
|
||||
#if (UCHAR_MAX / 0xFU > 0xFU)
|
||||
#ifndef I8T
|
||||
#define I8T char
|
||||
#define U8C(v) (v##U)
|
||||
|
||||
#if (UCHAR_MAX == 0xFFU)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if (UCHAR_MAX / 0xFFU > 0xFFU)
|
||||
#ifndef I16T
|
||||
#define I16T char
|
||||
#define U16C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if (UCHAR_MAX / 0xFFFFU > 0xFFFFU)
|
||||
#ifndef I32T
|
||||
#define I32T char
|
||||
#define U32C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if (UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
|
||||
#ifndef I64T
|
||||
#define I64T char
|
||||
#define U64C(v) (v##U)
|
||||
#define ECRYPT_NATIVE64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* --- check short --- */
|
||||
|
||||
#if (USHRT_MAX / 0xFU > 0xFU)
|
||||
#ifndef I8T
|
||||
#define I8T short
|
||||
#define U8C(v) (v##U)
|
||||
|
||||
#if (USHRT_MAX == 0xFFU)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if (USHRT_MAX / 0xFFU > 0xFFU)
|
||||
#ifndef I16T
|
||||
#define I16T short
|
||||
#define U16C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if (USHRT_MAX / 0xFFFFU > 0xFFFFU)
|
||||
#ifndef I32T
|
||||
#define I32T short
|
||||
#define U32C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if (USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
|
||||
#ifndef I64T
|
||||
#define I64T short
|
||||
#define U64C(v) (v##U)
|
||||
#define ECRYPT_NATIVE64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* --- check int --- */
|
||||
|
||||
#if (UINT_MAX / 0xFU > 0xFU)
|
||||
#ifndef I8T
|
||||
#define I8T int
|
||||
#define U8C(v) (v##U)
|
||||
|
||||
#if (ULONG_MAX == 0xFFU)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if (UINT_MAX / 0xFFU > 0xFFU)
|
||||
#ifndef I16T
|
||||
#define I16T int
|
||||
#define U16C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if (UINT_MAX / 0xFFFFU > 0xFFFFU)
|
||||
#ifndef I32T
|
||||
#define I32T int
|
||||
#define U32C(v) (v##U)
|
||||
#endif
|
||||
|
||||
#if (UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
|
||||
#ifndef I64T
|
||||
#define I64T int
|
||||
#define U64C(v) (v##U)
|
||||
#define ECRYPT_NATIVE64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* --- check long --- */
|
||||
|
||||
#if (ULONG_MAX / 0xFUL > 0xFUL)
|
||||
#ifndef I8T
|
||||
#define I8T long
|
||||
#define U8C(v) (v##UL)
|
||||
|
||||
#if (ULONG_MAX == 0xFFUL)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if (ULONG_MAX / 0xFFUL > 0xFFUL)
|
||||
#ifndef I16T
|
||||
#define I16T long
|
||||
#define U16C(v) (v##UL)
|
||||
#endif
|
||||
|
||||
#if (ULONG_MAX / 0xFFFFUL > 0xFFFFUL)
|
||||
#ifndef I32T
|
||||
#define I32T long
|
||||
#define U32C(v) (v##UL)
|
||||
#endif
|
||||
|
||||
#if (ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL)
|
||||
#ifndef I64T
|
||||
#define I64T long
|
||||
#define U64C(v) (v##UL)
|
||||
#define ECRYPT_NATIVE64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* --- check long long --- */
|
||||
|
||||
#ifdef ULLONG_MAX
|
||||
|
||||
#if (ULLONG_MAX / 0xFULL > 0xFULL)
|
||||
#ifndef I8T
|
||||
#define I8T long long
|
||||
#define U8C(v) (v##ULL)
|
||||
|
||||
#if (ULLONG_MAX == 0xFFULL)
|
||||
#define ECRYPT_I8T_IS_BYTE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if (ULLONG_MAX / 0xFFULL > 0xFFULL)
|
||||
#ifndef I16T
|
||||
#define I16T long long
|
||||
#define U16C(v) (v##ULL)
|
||||
#endif
|
||||
|
||||
#if (ULLONG_MAX / 0xFFFFULL > 0xFFFFULL)
|
||||
#ifndef I32T
|
||||
#define I32T long long
|
||||
#define U32C(v) (v##ULL)
|
||||
#endif
|
||||
|
||||
#if (ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL)
|
||||
#ifndef I64T
|
||||
#define I64T long long
|
||||
#define U64C(v) (v##ULL)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* --- check __int64 --- */
|
||||
|
||||
#ifdef _UI64_MAX
|
||||
|
||||
#ifndef I64T
|
||||
#if (_UI64_MAX / 0xFFFFFFFFui64 > 0xFFFFFFFFui64)
|
||||
#define I64T __int64
|
||||
#define U64C(v) (v##ui64)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
46
lib/luachacha/ecrypt-machine.h
Normal file
46
lib/luachacha/ecrypt-machine.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* ecrypt-machine.h */
|
||||
|
||||
/*
|
||||
* This file is included by 'ecrypt-portable.h'. It allows to override
|
||||
* the default macros for specific platforms. Please carefully check
|
||||
* the machine code generated by your compiler (with optimisations
|
||||
* turned on) before deciding to edit this file.
|
||||
*/
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#if (defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT))
|
||||
|
||||
#define ECRYPT_MACHINE_ROT
|
||||
|
||||
#if (defined(WIN32) && defined(_MSC_VER))
|
||||
|
||||
#undef ROTL32
|
||||
#undef ROTR32
|
||||
#undef ROTL64
|
||||
#undef ROTR64
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ROTL32(v, n) _lrotl(v, n)
|
||||
#define ROTR32(v, n) _lrotr(v, n)
|
||||
#define ROTL64(v, n) _rotl64(v, n)
|
||||
#define ROTR64(v, n) _rotr64(v, n)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#if (defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP))
|
||||
|
||||
#define ECRYPT_MACHINE_SWAP
|
||||
|
||||
/*
|
||||
* If you want to overwrite the default swap macros, put it here. And so on.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
303
lib/luachacha/ecrypt-portable.h
Normal file
303
lib/luachacha/ecrypt-portable.h
Normal file
@ -0,0 +1,303 @@
|
||||
/* ecrypt-portable.h */
|
||||
|
||||
/*
|
||||
* WARNING: the conversions defined below are implemented as macros,
|
||||
* and should be used carefully. They should NOT be used with
|
||||
* parameters which perform some action. E.g., the following two lines
|
||||
* are not equivalent:
|
||||
*
|
||||
* 1) ++x; y = ROTL32(x, n);
|
||||
* 2) y = ROTL32(++x, n);
|
||||
*/
|
||||
|
||||
/*
|
||||
* *** Please do not edit this file. ***
|
||||
*
|
||||
* The default macros can be overridden for specific architectures by
|
||||
* editing 'ecrypt-machine.h'.
|
||||
*/
|
||||
|
||||
#ifndef ECRYPT_PORTABLE
|
||||
#define ECRYPT_PORTABLE
|
||||
|
||||
#include "ecrypt-config.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* The following types are defined (if available):
|
||||
*
|
||||
* u8: unsigned integer type, at least 8 bits
|
||||
* u16: unsigned integer type, at least 16 bits
|
||||
* u32: unsigned integer type, at least 32 bits
|
||||
* u64: unsigned integer type, at least 64 bits
|
||||
*
|
||||
* s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64
|
||||
*
|
||||
* The selection of minimum-width integer types is taken care of by
|
||||
* 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit
|
||||
* compilers, it might be necessary to switch from ISO C90 mode to ISO
|
||||
* C99 mode (e.g., gcc -std=c99).
|
||||
*/
|
||||
|
||||
#ifdef I8T
|
||||
typedef signed I8T s8;
|
||||
typedef unsigned I8T u8;
|
||||
#endif
|
||||
|
||||
#ifdef I16T
|
||||
typedef signed I16T s16;
|
||||
typedef unsigned I16T u16;
|
||||
#endif
|
||||
|
||||
#ifdef I32T
|
||||
typedef signed I32T s32;
|
||||
typedef unsigned I32T u32;
|
||||
#endif
|
||||
|
||||
#ifdef I64T
|
||||
typedef signed I64T s64;
|
||||
typedef unsigned I64T u64;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The following macros are used to obtain exact-width results.
|
||||
*/
|
||||
|
||||
#define U8V(v) ((u8)(v) & U8C(0xFF))
|
||||
#define U16V(v) ((u16)(v) & U16C(0xFFFF))
|
||||
#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
|
||||
#define U64V(v) ((u64)(v) & U64C(0xFFFFFFFFFFFFFFFF))
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* The following macros return words with their bits rotated over n
|
||||
* positions to the left/right.
|
||||
*/
|
||||
|
||||
#define ECRYPT_DEFAULT_ROT
|
||||
|
||||
#define ROTL8(v, n) \
|
||||
(U8V((v) << (n)) | ((v) >> (8 - (n))))
|
||||
|
||||
#define ROTL16(v, n) \
|
||||
(U16V((v) << (n)) | ((v) >> (16 - (n))))
|
||||
|
||||
#define ROTL32(v, n) \
|
||||
(U32V((v) << (n)) | ((v) >> (32 - (n))))
|
||||
|
||||
#define ROTL64(v, n) \
|
||||
(U64V((v) << (n)) | ((v) >> (64 - (n))))
|
||||
|
||||
#define ROTR8(v, n) ROTL8(v, 8 - (n))
|
||||
#define ROTR16(v, n) ROTL16(v, 16 - (n))
|
||||
#define ROTR32(v, n) ROTL32(v, 32 - (n))
|
||||
#define ROTR64(v, n) ROTL64(v, 64 - (n))
|
||||
|
||||
#include "ecrypt-machine.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* The following macros return a word with bytes in reverse order.
|
||||
*/
|
||||
|
||||
#define ECRYPT_DEFAULT_SWAP
|
||||
|
||||
#define SWAP16(v) \
|
||||
ROTL16(v, 8)
|
||||
|
||||
#define SWAP32(v) \
|
||||
((ROTL32(v, 8) & U32C(0x00FF00FF)) | \
|
||||
(ROTL32(v, 24) & U32C(0xFF00FF00)))
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define SWAP64(v) \
|
||||
((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | \
|
||||
(ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \
|
||||
(ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | \
|
||||
(ROTL64(v, 56) & U64C(0xFF000000FF000000)))
|
||||
#else
|
||||
#define SWAP64(v) \
|
||||
(((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32)))
|
||||
#endif
|
||||
|
||||
#include "ecrypt-machine.h"
|
||||
|
||||
#define ECRYPT_DEFAULT_WTOW
|
||||
|
||||
#ifdef ECRYPT_LITTLE_ENDIAN
|
||||
#define U16TO16_LITTLE(v) (v)
|
||||
#define U32TO32_LITTLE(v) (v)
|
||||
#define U64TO64_LITTLE(v) (v)
|
||||
|
||||
#define U16TO16_BIG(v) SWAP16(v)
|
||||
#define U32TO32_BIG(v) SWAP32(v)
|
||||
#define U64TO64_BIG(v) SWAP64(v)
|
||||
#endif
|
||||
|
||||
#ifdef ECRYPT_BIG_ENDIAN
|
||||
#define U16TO16_LITTLE(v) SWAP16(v)
|
||||
#define U32TO32_LITTLE(v) SWAP32(v)
|
||||
#define U64TO64_LITTLE(v) SWAP64(v)
|
||||
|
||||
#define U16TO16_BIG(v) (v)
|
||||
#define U32TO32_BIG(v) (v)
|
||||
#define U64TO64_BIG(v) (v)
|
||||
#endif
|
||||
|
||||
#include "ecrypt-machine.h"
|
||||
|
||||
/*
|
||||
* The following macros load words from an array of bytes with
|
||||
* different types of endianness, and vice versa.
|
||||
*/
|
||||
|
||||
#define ECRYPT_DEFAULT_BTOW
|
||||
|
||||
#if (!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE))
|
||||
|
||||
#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0])
|
||||
#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0])
|
||||
#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0])
|
||||
|
||||
#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0])
|
||||
#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0])
|
||||
#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0])
|
||||
|
||||
#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v))
|
||||
#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v))
|
||||
#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v))
|
||||
|
||||
#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v))
|
||||
#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v))
|
||||
#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v))
|
||||
|
||||
#else
|
||||
|
||||
#define U8TO16_LITTLE(p) \
|
||||
(((u16)((p)[0]) ) | \
|
||||
((u16)((p)[1]) << 8))
|
||||
|
||||
#define U8TO32_LITTLE(p) \
|
||||
(((u32)((p)[0]) ) | \
|
||||
((u32)((p)[1]) << 8) | \
|
||||
((u32)((p)[2]) << 16) | \
|
||||
((u32)((p)[3]) << 24))
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define U8TO64_LITTLE(p) \
|
||||
(((u64)((p)[0]) ) | \
|
||||
((u64)((p)[1]) << 8) | \
|
||||
((u64)((p)[2]) << 16) | \
|
||||
((u64)((p)[3]) << 24) | \
|
||||
((u64)((p)[4]) << 32) | \
|
||||
((u64)((p)[5]) << 40) | \
|
||||
((u64)((p)[6]) << 48) | \
|
||||
((u64)((p)[7]) << 56))
|
||||
#else
|
||||
#define U8TO64_LITTLE(p) \
|
||||
((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32))
|
||||
#endif
|
||||
|
||||
#define U8TO16_BIG(p) \
|
||||
(((u16)((p)[0]) << 8) | \
|
||||
((u16)((p)[1]) ))
|
||||
|
||||
#define U8TO32_BIG(p) \
|
||||
(((u32)((p)[0]) << 24) | \
|
||||
((u32)((p)[1]) << 16) | \
|
||||
((u32)((p)[2]) << 8) | \
|
||||
((u32)((p)[3]) ))
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define U8TO64_BIG(p) \
|
||||
(((u64)((p)[0]) << 56) | \
|
||||
((u64)((p)[1]) << 48) | \
|
||||
((u64)((p)[2]) << 40) | \
|
||||
((u64)((p)[3]) << 32) | \
|
||||
((u64)((p)[4]) << 24) | \
|
||||
((u64)((p)[5]) << 16) | \
|
||||
((u64)((p)[6]) << 8) | \
|
||||
((u64)((p)[7]) ))
|
||||
#else
|
||||
#define U8TO64_BIG(p) \
|
||||
(((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4))
|
||||
#endif
|
||||
|
||||
#define U16TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) ); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
} while (0)
|
||||
|
||||
#define U32TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) ); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
(p)[2] = U8V((v) >> 16); \
|
||||
(p)[3] = U8V((v) >> 24); \
|
||||
} while (0)
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define U64TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) ); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
(p)[2] = U8V((v) >> 16); \
|
||||
(p)[3] = U8V((v) >> 24); \
|
||||
(p)[4] = U8V((v) >> 32); \
|
||||
(p)[5] = U8V((v) >> 40); \
|
||||
(p)[6] = U8V((v) >> 48); \
|
||||
(p)[7] = U8V((v) >> 56); \
|
||||
} while (0)
|
||||
#else
|
||||
#define U64TO8_LITTLE(p, v) \
|
||||
do { \
|
||||
U32TO8_LITTLE((p), U32V((v) )); \
|
||||
U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define U16TO8_BIG(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) ); \
|
||||
(p)[1] = U8V((v) >> 8); \
|
||||
} while (0)
|
||||
|
||||
#define U32TO8_BIG(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) >> 24); \
|
||||
(p)[1] = U8V((v) >> 16); \
|
||||
(p)[2] = U8V((v) >> 8); \
|
||||
(p)[3] = U8V((v) ); \
|
||||
} while (0)
|
||||
|
||||
#ifdef ECRYPT_NATIVE64
|
||||
#define U64TO8_BIG(p, v) \
|
||||
do { \
|
||||
(p)[0] = U8V((v) >> 56); \
|
||||
(p)[1] = U8V((v) >> 48); \
|
||||
(p)[2] = U8V((v) >> 40); \
|
||||
(p)[3] = U8V((v) >> 32); \
|
||||
(p)[4] = U8V((v) >> 24); \
|
||||
(p)[5] = U8V((v) >> 16); \
|
||||
(p)[6] = U8V((v) >> 8); \
|
||||
(p)[7] = U8V((v) ); \
|
||||
} while (0)
|
||||
#else
|
||||
#define U64TO8_BIG(p, v) \
|
||||
do { \
|
||||
U32TO8_BIG((p), U32V((v) >> 32)); \
|
||||
U32TO8_BIG((p) + 4, U32V((v) )); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include "ecrypt-machine.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
290
lib/luachacha/ecrypt-sync.h
Normal file
290
lib/luachacha/ecrypt-sync.h
Normal file
@ -0,0 +1,290 @@
|
||||
/* ecrypt-sync.h */
|
||||
|
||||
/*
|
||||
* Header file for synchronous stream ciphers without authentication
|
||||
* mechanism.
|
||||
*
|
||||
* *** Please only edit parts marked with "[edit]". ***
|
||||
*/
|
||||
|
||||
#ifndef ECRYPT_SYNC
|
||||
#define ECRYPT_SYNC
|
||||
|
||||
#include "ecrypt-portable.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Cipher parameters */
|
||||
|
||||
/*
|
||||
* The name of your cipher.
|
||||
*/
|
||||
#define ECRYPT_NAME "ChaCha8"
|
||||
#define ECRYPT_PROFILE "_____"
|
||||
|
||||
/*
|
||||
* Specify which key and IV sizes are supported by your cipher. A user
|
||||
* should be able to enumerate the supported sizes by running the
|
||||
* following code:
|
||||
*
|
||||
* for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i)
|
||||
* {
|
||||
* keysize = ECRYPT_KEYSIZE(i);
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* All sizes are in bits.
|
||||
*/
|
||||
|
||||
#define ECRYPT_MAXKEYSIZE 256 /* [edit] */
|
||||
#define ECRYPT_KEYSIZE(i) (128 + (i)*128) /* [edit] */
|
||||
|
||||
#define ECRYPT_MAXIVSIZE 64 /* [edit] */
|
||||
#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Data structures */
|
||||
|
||||
/*
|
||||
* ECRYPT_ctx is the structure containing the representation of the
|
||||
* internal state of your cipher.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 input[16]; /* could be compressed */
|
||||
/*
|
||||
* [edit]
|
||||
*
|
||||
* Put here all state variable needed during the encryption process.
|
||||
*/
|
||||
} ECRYPT_ctx;
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Mandatory functions */
|
||||
|
||||
/*
|
||||
* Key and message independent initialization. This function will be
|
||||
* called once when the program starts (e.g., to build expanded S-box
|
||||
* tables).
|
||||
*/
|
||||
void ECRYPT_init();
|
||||
|
||||
/*
|
||||
* Key setup. It is the user's responsibility to select the values of
|
||||
* keysize and ivsize from the set of supported values specified
|
||||
* above.
|
||||
*/
|
||||
void ECRYPT_keysetup(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* key,
|
||||
u32 keysize, /* Key size in bits. */
|
||||
u32 ivsize); /* IV size in bits. */
|
||||
|
||||
/*
|
||||
* IV setup. After having called ECRYPT_keysetup(), the user is
|
||||
* allowed to call ECRYPT_ivsetup() different times in order to
|
||||
* encrypt/decrypt different messages with the same key but different
|
||||
* IV's.
|
||||
*/
|
||||
void ECRYPT_ivsetup(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* iv,
|
||||
const u8* counter);
|
||||
|
||||
/*
|
||||
* IV setup for the IETF version of ChaCha (RFC 7539)
|
||||
*/
|
||||
void ECRYPT_IETF_ivsetup(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* iv,
|
||||
const u8* counter);
|
||||
|
||||
/*
|
||||
* Encryption/decryption of arbitrary length messages.
|
||||
*
|
||||
* For efficiency reasons, the API provides two types of
|
||||
* encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function
|
||||
* (declared here) encrypts byte strings of arbitrary length, while
|
||||
* the ECRYPT_encrypt_blocks() function (defined later) only accepts
|
||||
* lengths which are multiples of ECRYPT_BLOCKLENGTH.
|
||||
*
|
||||
* The user is allowed to make multiple calls to
|
||||
* ECRYPT_encrypt_blocks() to incrementally encrypt a long message,
|
||||
* but he is NOT allowed to make additional encryption calls once he
|
||||
* has called ECRYPT_encrypt_bytes() (unless he starts a new message
|
||||
* of course). For example, this sequence of calls is acceptable:
|
||||
*
|
||||
* ECRYPT_keysetup();
|
||||
*
|
||||
* ECRYPT_ivsetup();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
* ECRYPT_encrypt_bytes();
|
||||
*
|
||||
* ECRYPT_ivsetup();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
*
|
||||
* ECRYPT_ivsetup();
|
||||
* ECRYPT_encrypt_bytes();
|
||||
*
|
||||
* The following sequence is not:
|
||||
*
|
||||
* ECRYPT_keysetup();
|
||||
* ECRYPT_ivsetup();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
* ECRYPT_encrypt_bytes();
|
||||
* ECRYPT_encrypt_blocks();
|
||||
*/
|
||||
|
||||
void ECRYPT_encrypt_bytes(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* plaintext,
|
||||
u8* ciphertext,
|
||||
u32 msglen, /* Message length in bytes. */
|
||||
int rounds
|
||||
);
|
||||
|
||||
void ECRYPT_decrypt_bytes(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* ciphertext,
|
||||
u8* plaintext,
|
||||
u32 msglen); /* Message length in bytes. */
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Optional features */
|
||||
|
||||
/*
|
||||
* For testing purposes it can sometimes be useful to have a function
|
||||
* which immediately generates keystream without having to provide it
|
||||
* with a zero plaintext. If your cipher cannot provide this function
|
||||
* (e.g., because it is not strictly a synchronous cipher), please
|
||||
* reset the ECRYPT_GENERATES_KEYSTREAM flag.
|
||||
*/
|
||||
|
||||
#define ECRYPT_GENERATES_KEYSTREAM
|
||||
#ifdef ECRYPT_GENERATES_KEYSTREAM
|
||||
|
||||
void ECRYPT_keystream_bytes(
|
||||
ECRYPT_ctx* ctx,
|
||||
u8* keystream,
|
||||
u32 length); /* Length of keystream in bytes. */
|
||||
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Optional optimizations */
|
||||
|
||||
/*
|
||||
* By default, the functions in this section are implemented using
|
||||
* calls to functions declared above. However, you might want to
|
||||
* implement them differently for performance reasons.
|
||||
*/
|
||||
|
||||
/*
|
||||
* All-in-one encryption/decryption of (short) packets.
|
||||
*
|
||||
* The default definitions of these functions can be found in
|
||||
* "ecrypt-sync.c". If you want to implement them differently, please
|
||||
* undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag.
|
||||
*/
|
||||
#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */
|
||||
|
||||
void ECRYPT_encrypt_packet(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* iv,
|
||||
const u8* plaintext,
|
||||
u8* ciphertext,
|
||||
u32 msglen);
|
||||
|
||||
void ECRYPT_decrypt_packet(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* iv,
|
||||
const u8* ciphertext,
|
||||
u8* plaintext,
|
||||
u32 msglen);
|
||||
|
||||
/*
|
||||
* Encryption/decryption of blocks.
|
||||
*
|
||||
* By default, these functions are defined as macros. If you want to
|
||||
* provide a different implementation, please undef the
|
||||
* ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions
|
||||
* declared below.
|
||||
*/
|
||||
|
||||
#define ECRYPT_BLOCKLENGTH 64 /* [edit] */
|
||||
|
||||
#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */
|
||||
#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS
|
||||
|
||||
#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \
|
||||
ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, \
|
||||
(blocks) * ECRYPT_BLOCKLENGTH)
|
||||
|
||||
#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \
|
||||
ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, \
|
||||
(blocks) * ECRYPT_BLOCKLENGTH)
|
||||
|
||||
#ifdef ECRYPT_GENERATES_KEYSTREAM
|
||||
|
||||
#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \
|
||||
ECRYPT_keystream_bytes(ctx, keystream, \
|
||||
(blocks) * ECRYPT_BLOCKLENGTH)
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
void ECRYPT_encrypt_blocks(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* plaintext,
|
||||
u8* ciphertext,
|
||||
u32 blocks); /* Message length in blocks. */
|
||||
|
||||
void ECRYPT_decrypt_blocks(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* ciphertext,
|
||||
u8* plaintext,
|
||||
u32 blocks); /* Message length in blocks. */
|
||||
|
||||
#ifdef ECRYPT_GENERATES_KEYSTREAM
|
||||
|
||||
void ECRYPT_keystream_blocks(
|
||||
ECRYPT_ctx* ctx,
|
||||
const u8* keystream,
|
||||
u32 blocks); /* Keystream length in blocks. */
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If your cipher can be implemented in different ways, you can use
|
||||
* the ECRYPT_VARIANT parameter to allow the user to choose between
|
||||
* them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please
|
||||
* only use this possibility if you really think it could make a
|
||||
* significant difference and keep the number of variants
|
||||
* (ECRYPT_MAXVARIANT) as small as possible (definitely not more than
|
||||
* 10). Note also that all variants should have exactly the same
|
||||
* external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.).
|
||||
*/
|
||||
#define ECRYPT_MAXVARIANT 1 /* [edit] */
|
||||
|
||||
#ifndef ECRYPT_VARIANT
|
||||
#define ECRYPT_VARIANT 1
|
||||
#endif
|
||||
|
||||
#if (ECRYPT_VARIANT > ECRYPT_MAXVARIANT)
|
||||
#error this variant does not exist
|
||||
#endif
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#endif
|
79
lib/luachacha/lchacha.c
Normal file
79
lib/luachacha/lchacha.c
Normal file
@ -0,0 +1,79 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
#include <lualib.h>
|
||||
|
||||
#include "ecrypt-sync.h"
|
||||
|
||||
#if LUA_VERSION_NUM == 501
|
||||
#define l_setfuncs(L, funcs) luaL_register(L, NULL, funcs)
|
||||
#else
|
||||
#define l_setfuncs(L, funcs) luaL_setfuncs(L, funcs, 0)
|
||||
#endif
|
||||
|
||||
static int chacha_generic_crypt(lua_State *L, bool is_ietf)
|
||||
{
|
||||
ECRYPT_ctx ctx;
|
||||
const char *key, *iv, *plaintext, *counter;
|
||||
char *ciphertext;
|
||||
size_t keysize, ivsize, msglen, countersize;
|
||||
|
||||
int rounds = luaL_checkinteger(L, 1);
|
||||
|
||||
/* IETF only normalizes ChaCha 20. */
|
||||
if (rounds != 20 && (is_ietf || (rounds % 2 != 0)))
|
||||
return luaL_error(L, "invalid number of rounds: %d", rounds);
|
||||
|
||||
luaL_checktype(L, 2, LUA_TSTRING);
|
||||
luaL_checktype(L, 3, LUA_TSTRING);
|
||||
luaL_checktype(L, 4, LUA_TSTRING);
|
||||
|
||||
key = lua_tolstring(L, 2, &keysize);
|
||||
iv = lua_tolstring(L, 3, &ivsize);
|
||||
plaintext = lua_tolstring(L, 4, &msglen);
|
||||
counter = luaL_optlstring(L, 5, NULL, &countersize);
|
||||
|
||||
if (ivsize != (is_ietf ? 12 : 8))
|
||||
return luaL_error(L, "invalid IV size: %dB", (int)ivsize);
|
||||
|
||||
if (keysize != 32 && (is_ietf || keysize != 16))
|
||||
return luaL_error(L, "invalid key size: %dB", (int)keysize);
|
||||
|
||||
if (counter && countersize != (is_ietf ? 4 : 8))
|
||||
return luaL_error(L, "invalid counter size: %dB", (int)countersize);
|
||||
|
||||
if (msglen == 0) { lua_pushlstring(L, "", 0); return 1; }
|
||||
|
||||
ciphertext = malloc(msglen);
|
||||
if (!ciphertext) return luaL_error(L, "OOM");
|
||||
|
||||
/* keysize and ivsize are in bits */
|
||||
ECRYPT_keysetup(&ctx, (u8*)key, 8 * keysize, 8 * ivsize);
|
||||
if (is_ietf) ECRYPT_IETF_ivsetup(&ctx, (u8*)iv, (u8*)counter);
|
||||
else ECRYPT_ivsetup(&ctx, (u8*)iv, (u8*)counter);
|
||||
ECRYPT_encrypt_bytes(&ctx, (u8*)plaintext, (u8*)ciphertext, msglen, rounds);
|
||||
|
||||
lua_pushlstring(L, ciphertext, msglen);
|
||||
free(ciphertext);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int chacha_ref_crypt(lua_State *L)
|
||||
{ return chacha_generic_crypt(L, false); }
|
||||
|
||||
static int chacha_ietf_crypt(lua_State *L)
|
||||
{ return chacha_generic_crypt(L, true); }
|
||||
|
||||
int luaopen_chacha(lua_State *L)
|
||||
{
|
||||
struct luaL_Reg l[] = {
|
||||
{ "ref_crypt", chacha_ref_crypt },
|
||||
{ "ietf_crypt", chacha_ietf_crypt },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
lua_newtable(L);
|
||||
l_setfuncs(L, l);
|
||||
return 1;
|
||||
}
|
2
lib/luautf8/CMakeLists.txt
Normal file
2
lib/luautf8/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
add_library(luautf8 STATIC lutf8lib.c)
|
||||
target_include_directories(luautf8 PUBLIC ${LUA_INCLUDE_DIR})
|
1300
lib/luautf8/lutf8lib.c
Normal file
1300
lib/luautf8/lutf8lib.c
Normal file
File diff suppressed because it is too large
Load Diff
3753
lib/luautf8/unidata.h
Normal file
3753
lib/luautf8/unidata.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
project(minetest)
|
||||
project(multicraft)
|
||||
|
||||
INCLUDE(CheckIncludeFiles)
|
||||
INCLUDE(CheckLibraryExists)
|
||||
@ -32,12 +32,17 @@ if(NOT (BUILD_CLIENT OR BUILD_SERVER))
|
||||
endif()
|
||||
|
||||
option(USE_SDL "Use SDL2 for window management" FALSE)
|
||||
option(USE_STATIC_BUILD "Link additional libraries needed for static build" FALSE)
|
||||
|
||||
if(USE_SDL)
|
||||
if(NOT USE_STATIC_BUILD)
|
||||
find_package(SDL2)
|
||||
else()
|
||||
set(SDL2_FOUND TRUE)
|
||||
endif()
|
||||
if (SDL2_FOUND)
|
||||
message(STATUS "SDL2 found.")
|
||||
include_directories(${SDL2_INCLUDEDIR})
|
||||
include_directories(${SDL2_INCLUDE_DIR})
|
||||
else()
|
||||
message(FATAL_ERROR "SDL2 not found.")
|
||||
endif()
|
||||
@ -193,6 +198,8 @@ if(ENABLE_LEVELDB)
|
||||
endif()
|
||||
endif(ENABLE_LEVELDB)
|
||||
|
||||
option(ENABLE_SQLITE "Enable SQLite backend" TRUE)
|
||||
set(USE_SQLITE TRUE)
|
||||
|
||||
OPTION(ENABLE_REDIS "Enable Redis backend" TRUE)
|
||||
set(USE_REDIS FALSE)
|
||||
@ -556,6 +563,8 @@ if(BUILD_CLIENT)
|
||||
${FREETYPE_LIBRARY}
|
||||
${PLATFORM_LIBS}
|
||||
${SDL2_LIBRARIES}
|
||||
luautf8
|
||||
luachacha
|
||||
)
|
||||
if(NOT USE_LUAJIT)
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES
|
||||
@ -565,6 +574,21 @@ if(BUILD_CLIENT)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(USE_SDL)
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
${SDL2_LIBRARIES}
|
||||
)
|
||||
if(USE_STATIC_BUILD AND WIN32)
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
winmm
|
||||
imm32
|
||||
setupapi
|
||||
opengl32
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
if(ENABLE_GLES)
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
@ -582,12 +606,23 @@ if(BUILD_CLIENT)
|
||||
${PROJECT_NAME}
|
||||
${GETTEXT_LIBRARY}
|
||||
)
|
||||
if(USE_STATIC_BUILD)
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
${GETTEXT_ICONV_LIBRARY}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
if(USE_CURL)
|
||||
target_link_libraries(
|
||||
${PROJECT_NAME}
|
||||
${CURL_LIBRARY}
|
||||
)
|
||||
if(USE_STATIC_BUILD)
|
||||
if(WIN32)
|
||||
target_link_libraries(${PROJECT_NAME} bcrypt crypt32 ws2_32)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
if(FREETYPE_PKGCONFIG_FOUND)
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
@ -634,6 +669,8 @@ if(BUILD_SERVER)
|
||||
${LUA_BIT_LIBRARY}
|
||||
${GMP_LIBRARY}
|
||||
${PLATFORM_LIBS}
|
||||
luautf8
|
||||
luachacha
|
||||
)
|
||||
set_target_properties(${PROJECT_NAME}server PROPERTIES
|
||||
COMPILE_DEFINITIONS "SERVER")
|
||||
@ -901,7 +938,7 @@ if(BUILD_CLIENT)
|
||||
if(USE_GETTEXT)
|
||||
foreach(LOCALE ${GETTEXT_USED_LOCALES})
|
||||
set_mo_paths(MO_BUILD_PATH MO_DEST_PATH ${LOCALE})
|
||||
set(MO_BUILD_PATH "${MO_BUILD_PATH}/${PROJECT_NAME}.mo")
|
||||
set(MO_BUILD_PATH "${MO_BUILD_PATH}/minetest.mo")
|
||||
install(FILES ${MO_BUILD_PATH} DESTINATION ${MO_DEST_PATH})
|
||||
endforeach()
|
||||
endif()
|
||||
@ -918,9 +955,9 @@ if (USE_GETTEXT)
|
||||
set(MO_FILES)
|
||||
|
||||
foreach(LOCALE ${GETTEXT_USED_LOCALES})
|
||||
set(PO_FILE_PATH "${GETTEXT_PO_PATH}/${LOCALE}/${PROJECT_NAME}.po")
|
||||
set(PO_FILE_PATH "${GETTEXT_PO_PATH}/${LOCALE}/minetest.po")
|
||||
set_mo_paths(MO_BUILD_PATH MO_DEST_PATH ${LOCALE})
|
||||
set(MO_FILE_PATH "${MO_BUILD_PATH}/${PROJECT_NAME}.mo")
|
||||
set(MO_FILE_PATH "${MO_BUILD_PATH}/minetest.mo")
|
||||
|
||||
add_custom_command(OUTPUT ${MO_BUILD_PATH}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${MO_BUILD_PATH}
|
||||
|
@ -44,15 +44,18 @@ enum ActiveObjectType {
|
||||
|
||||
struct ActiveObjectMessage
|
||||
{
|
||||
ActiveObjectMessage(u16 id_, bool reliable_=true, const std::string &data_ = "") :
|
||||
ActiveObjectMessage(u16 id_, bool reliable_ = true,
|
||||
const std::string &data_ = "", const std::string legacy_ = "") :
|
||||
id(id_),
|
||||
reliable(reliable_),
|
||||
datastring(data_)
|
||||
datastring(data_),
|
||||
legacystring(legacy_)
|
||||
{}
|
||||
|
||||
u16 id;
|
||||
bool reliable;
|
||||
std::string datastring;
|
||||
std::string legacystring;
|
||||
};
|
||||
|
||||
enum ActiveObjectCommand {
|
||||
|
@ -19,8 +19,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IrrCompileConfig.h"
|
||||
|
||||
#include "util/string.h"
|
||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||
#include "threading/sdl_thread.h"
|
||||
#else
|
||||
#include "threading/thread.h"
|
||||
#endif
|
||||
#include "exceptions.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
33
src/chat.cpp
33
src/chat.cpp
@ -35,6 +35,7 @@ ChatBuffer::ChatBuffer(u32 scrollback):
|
||||
if (m_scrollback == 0)
|
||||
m_scrollback = 1;
|
||||
m_empty_formatted_line.first = true;
|
||||
m_empty_formatted_line.line_index = 0;
|
||||
|
||||
m_cache_clickable_chat_weblinks = false;
|
||||
// Curses mode cannot access g_settings here
|
||||
@ -52,8 +53,9 @@ void ChatBuffer::addLine(const std::wstring &name, const std::wstring &text)
|
||||
{
|
||||
m_lines_modified = true;
|
||||
|
||||
ChatLine line(name, text);
|
||||
ChatLine line(name, text, m_current_line_index);
|
||||
m_unformatted.push_back(line);
|
||||
m_current_line_index++;
|
||||
|
||||
if (m_rows > 0) {
|
||||
// m_formatted is valid and must be kept valid
|
||||
@ -73,6 +75,7 @@ void ChatBuffer::clear()
|
||||
{
|
||||
m_unformatted.clear();
|
||||
m_formatted.clear();
|
||||
m_current_line_index = 0;
|
||||
m_scroll = 0;
|
||||
m_lines_modified = true;
|
||||
}
|
||||
@ -127,6 +130,8 @@ void ChatBuffer::deleteOldest(u32 count)
|
||||
m_scroll = getBottomScrollPos();
|
||||
else
|
||||
scrollAbsolute(m_scroll - del_formatted);
|
||||
|
||||
m_del_formatted += del_formatted;
|
||||
}
|
||||
|
||||
void ChatBuffer::deleteByAge(f32 maxAge)
|
||||
@ -272,6 +277,7 @@ u32 ChatBuffer::formatChatLine(const ChatLine& line, u32 cols,
|
||||
//EnrichedString line_text(line.text);
|
||||
|
||||
next_line.first = true;
|
||||
next_line.line_index = line.line_index;
|
||||
// Set/use forced newline after the last frag in each line
|
||||
bool mark_newline = false;
|
||||
|
||||
@ -461,6 +467,7 @@ void ChatPrompt::input(wchar_t ch)
|
||||
clampView();
|
||||
m_nick_completion_start = 0;
|
||||
m_nick_completion_end = 0;
|
||||
m_line_modified = true;
|
||||
}
|
||||
|
||||
void ChatPrompt::input(const std::wstring &str)
|
||||
@ -470,6 +477,7 @@ void ChatPrompt::input(const std::wstring &str)
|
||||
clampView();
|
||||
m_nick_completion_start = 0;
|
||||
m_nick_completion_end = 0;
|
||||
m_line_modified = true;
|
||||
}
|
||||
|
||||
void ChatPrompt::addToHistory(const std::wstring &line)
|
||||
@ -494,6 +502,7 @@ void ChatPrompt::clear()
|
||||
m_cursor = 0;
|
||||
m_nick_completion_start = 0;
|
||||
m_nick_completion_end = 0;
|
||||
m_line_modified = true;
|
||||
}
|
||||
|
||||
std::wstring ChatPrompt::replace(const std::wstring &line)
|
||||
@ -504,6 +513,7 @@ std::wstring ChatPrompt::replace(const std::wstring &line)
|
||||
clampView();
|
||||
m_nick_completion_start = 0;
|
||||
m_nick_completion_end = 0;
|
||||
m_line_modified = true;
|
||||
return old_line;
|
||||
}
|
||||
|
||||
@ -605,6 +615,7 @@ void ChatPrompt::nickCompletion(const std::list<std::string>& names, bool backwa
|
||||
clampView();
|
||||
m_nick_completion_start = prefix_start;
|
||||
m_nick_completion_end = prefix_end;
|
||||
m_line_modified = true;
|
||||
}
|
||||
|
||||
void ChatPrompt::reformat(u32 cols)
|
||||
@ -686,6 +697,7 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
|
||||
m_line.erase(m_cursor, abs(new_cursor - old_cursor));
|
||||
}
|
||||
m_cursor_len = 0;
|
||||
m_line_modified = true;
|
||||
break;
|
||||
case CURSOROP_SELECT:
|
||||
if (scope == CURSOROP_SCOPE_LINE) {
|
||||
@ -705,6 +717,25 @@ void ChatPrompt::cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope sco
|
||||
m_nick_completion_end = 0;
|
||||
}
|
||||
|
||||
void ChatPrompt::setCursorPos(int cursor_pos)
|
||||
{
|
||||
s32 length = m_line.size();
|
||||
m_cursor = MYMAX(MYMIN(cursor_pos, length), 0);
|
||||
m_cursor_len = 0;
|
||||
|
||||
clampView();
|
||||
|
||||
m_nick_completion_start = 0;
|
||||
m_nick_completion_end = 0;
|
||||
}
|
||||
|
||||
void ChatPrompt::setViewPosition(int view)
|
||||
{
|
||||
m_view = view;
|
||||
|
||||
clampView();
|
||||
}
|
||||
|
||||
void ChatPrompt::clampView()
|
||||
{
|
||||
s32 length = m_line.size();
|
||||
|
51
src/chat.h
51
src/chat.h
@ -37,16 +37,22 @@ struct ChatLine
|
||||
EnrichedString name;
|
||||
// message text
|
||||
EnrichedString text;
|
||||
// Line index in ChatLine buffer
|
||||
int line_index;
|
||||
|
||||
ChatLine(const std::wstring &a_name, const std::wstring &a_text):
|
||||
ChatLine(const std::wstring &a_name, const std::wstring &a_text,
|
||||
int a_line_index):
|
||||
name(a_name),
|
||||
text(a_text)
|
||||
text(a_text),
|
||||
line_index(a_line_index)
|
||||
{
|
||||
}
|
||||
|
||||
ChatLine(const EnrichedString &a_name, const EnrichedString &a_text):
|
||||
ChatLine(const EnrichedString &a_name, const EnrichedString &a_text,
|
||||
int a_line_index):
|
||||
name(a_name),
|
||||
text(a_text)
|
||||
text(a_text),
|
||||
line_index(a_line_index)
|
||||
{
|
||||
}
|
||||
};
|
||||
@ -69,6 +75,8 @@ struct ChatFormattedLine
|
||||
std::vector<ChatFormattedFragment> fragments;
|
||||
// true if first line of one formatted ChatLine
|
||||
bool first;
|
||||
// Line index in ChatLine buffer
|
||||
int line_index;
|
||||
};
|
||||
|
||||
class ChatBuffer
|
||||
@ -118,6 +126,12 @@ public:
|
||||
bool getLinesModified() const { return m_lines_modified; }
|
||||
void resetLinesModified() { m_lines_modified = false; }
|
||||
|
||||
s32 getScrollPos() { return m_scroll; }
|
||||
u32 getColsCount() { return m_cols; }
|
||||
|
||||
u32 getDelFormatted() const { return m_del_formatted; }
|
||||
void resetDelFormatted() { m_del_formatted = 0; }
|
||||
|
||||
// Format a chat line for the given number of columns.
|
||||
// Appends the formatted lines to the destination array and
|
||||
// returns the number of formatted lines.
|
||||
@ -126,7 +140,6 @@ public:
|
||||
|
||||
void resize(u32 scrollback);
|
||||
|
||||
protected:
|
||||
s32 getTopScrollPos() const;
|
||||
s32 getBottomScrollPos() const;
|
||||
|
||||
@ -147,15 +160,20 @@ private:
|
||||
// Empty formatted line, for error returns
|
||||
ChatFormattedLine m_empty_formatted_line;
|
||||
|
||||
// Enable clickable chat weblinks
|
||||
bool m_cache_clickable_chat_weblinks;
|
||||
// Color of clickable chat weblinks
|
||||
irr::video::SColor m_cache_chat_weblink_color;
|
||||
|
||||
// Whether the lines were modified since last markLinesUnchanged()
|
||||
// Is always set to true when m_unformatted is modified, because that's what
|
||||
// determines the output of getLineCount() and getLine()
|
||||
bool m_lines_modified = true;
|
||||
|
||||
// How many formatted lines have been deleted
|
||||
u32 m_del_formatted = 0;
|
||||
|
||||
int m_current_line_index = 0;
|
||||
|
||||
// Enable clickable chat weblinks
|
||||
bool m_cache_clickable_chat_weblinks;
|
||||
// Color of clickable chat weblinks
|
||||
irr::video::SColor m_cache_chat_weblink_color;
|
||||
};
|
||||
|
||||
class ChatPrompt
|
||||
@ -197,6 +215,8 @@ public:
|
||||
std::wstring getVisiblePortion() const;
|
||||
// Get cursor position (relative to visible portion). -1 if invalid
|
||||
s32 getVisibleCursorPosition() const;
|
||||
// Get view position (absolute value)
|
||||
s32 getViewPosition() const { return m_view; }
|
||||
// Get length of cursor selection
|
||||
s32 getCursorLength() const { return m_cursor_len; }
|
||||
|
||||
@ -232,6 +252,14 @@ public:
|
||||
// deletes the word to the left of the cursor.
|
||||
void cursorOperation(CursorOp op, CursorOpDir dir, CursorOpScope scope);
|
||||
|
||||
void setCursorPos(int cursor_pos);
|
||||
void setViewPosition(int view);
|
||||
|
||||
// Functions for keeping track of whether the line was modified by any
|
||||
// preceding operations
|
||||
bool getLineModified() const { return m_line_modified; }
|
||||
void resetLineModified() { m_line_modified = false; }
|
||||
|
||||
protected:
|
||||
// set m_view to ensure that 0 <= m_view <= m_cursor < m_view + m_cols
|
||||
// if line can be fully shown, set m_view to zero
|
||||
@ -263,6 +291,9 @@ private:
|
||||
s32 m_nick_completion_start = 0;
|
||||
// Last nick completion start (index into m_line)
|
||||
s32 m_nick_completion_end = 0;
|
||||
|
||||
// True if line was modified
|
||||
bool m_line_modified = true;
|
||||
};
|
||||
|
||||
class ChatBackend
|
||||
|
@ -595,12 +595,11 @@ void Camera::updateViewingRange()
|
||||
m_cameranode->setNearValue(0.1f * BS);
|
||||
#endif
|
||||
|
||||
m_draw_control.wanted_range = std::fmin(adjustDist(viewing_range, getFovMax()), 4000);
|
||||
if (m_draw_control.range_all) {
|
||||
m_cameranode->setFarValue(100000.0);
|
||||
return;
|
||||
}
|
||||
m_cameranode->setFarValue((viewing_range < 2000) ? 2000 * BS : viewing_range * BS);
|
||||
if (m_draw_control.extended_range)
|
||||
viewing_range *= 3;
|
||||
viewing_range = std::fmin(adjustDist(viewing_range, getFovMax()), 4000);
|
||||
m_draw_control.wanted_range = viewing_range;
|
||||
m_cameranode->setFarValue(m_draw_control.range_all ? 100000.0 : std::max(2000.0f, viewing_range) * BS);
|
||||
}
|
||||
|
||||
void Camera::setDigging(s32 button)
|
||||
@ -609,16 +608,21 @@ void Camera::setDigging(s32 button)
|
||||
m_digging_button = button;
|
||||
}
|
||||
|
||||
void Camera::wield(const ItemStack &item)
|
||||
void Camera::wield(const ItemStack &item, const bool no_change_anim)
|
||||
{
|
||||
if (item.name != m_wield_item_next.name ||
|
||||
item.metadata != m_wield_item_next.metadata) {
|
||||
m_wield_item_next = item;
|
||||
if (m_wield_change_timer > 0)
|
||||
if (no_change_anim) {
|
||||
// Change items immediately
|
||||
m_wieldnode->setItem(item, m_client);
|
||||
m_wield_change_timer = 0.125f;
|
||||
} else if (m_wield_change_timer > 0) {
|
||||
m_wield_change_timer = -m_wield_change_timer;
|
||||
else if (m_wield_change_timer == 0)
|
||||
} else if (m_wield_change_timer == 0) {
|
||||
m_wield_change_timer = -0.001;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::drawWieldedTool(irr::core::matrix4* translation)
|
||||
|
@ -150,7 +150,7 @@ public:
|
||||
void setDigging(s32 button);
|
||||
|
||||
// Replace the wielded item mesh
|
||||
void wield(const ItemStack &item);
|
||||
void wield(const ItemStack &item, const bool no_change_anim);
|
||||
|
||||
// Draw the wielded tool.
|
||||
// This has to happen *after* the main scene is drawn.
|
||||
|
@ -51,7 +51,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "clientmedia.h"
|
||||
#include "version.h"
|
||||
#include "database/database-files.h"
|
||||
#if USE_SQLITE
|
||||
#include "database/database-sqlite3.h"
|
||||
#endif
|
||||
#include "serialization.h"
|
||||
#include "guiscalingfilter.h"
|
||||
#include "script/scripting_client.h"
|
||||
@ -139,6 +141,9 @@ Client::Client(
|
||||
}
|
||||
|
||||
m_cache_save_interval = g_settings->getU16("server_map_save_interval");
|
||||
m_round_screen = g_settings->getU16("round_screen");
|
||||
m_hud_scaling = g_settings->getFloat("hud_scaling");
|
||||
m_inv_item_anim_enabled = g_settings->getBool("inventory_items_animations");
|
||||
}
|
||||
|
||||
void Client::migrateModStorage()
|
||||
@ -272,7 +277,7 @@ const std::string &Client::getBuiltinLuaPath()
|
||||
|
||||
const std::string &Client::getClientModsLuaPath()
|
||||
{
|
||||
static const std::string clientmods_dir = porting::path_share + DIR_DELIM + "clientmods";
|
||||
static const std::string clientmods_dir = porting::path_user + DIR_DELIM + "clientmods";
|
||||
return clientmods_dir;
|
||||
}
|
||||
|
||||
@ -294,11 +299,13 @@ void Client::Stop()
|
||||
m_script->on_shutdown();
|
||||
//request all client managed threads to stop
|
||||
m_mesh_update_thread.stop();
|
||||
#if USE_SQLITE
|
||||
// Save local server map
|
||||
if (m_localdb) {
|
||||
infostream << "Local map saving ended." << std::endl;
|
||||
m_localdb->endSave();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_mods_loaded)
|
||||
delete m_script;
|
||||
@ -687,12 +694,14 @@ void Client::step(float dtime)
|
||||
m_mod_storage_database->beginSave();
|
||||
}
|
||||
|
||||
#if USE_SQLITE
|
||||
// Write server map
|
||||
if (m_localdb && m_localdb_save_interval.step(dtime,
|
||||
m_cache_save_interval)) {
|
||||
m_localdb->endSave();
|
||||
m_localdb->beginSave();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Client::loadMedia(const std::string &data, const std::string &filename,
|
||||
@ -852,9 +861,11 @@ void Client::initLocalMapSaving(const Address &address,
|
||||
#undef set_world_path
|
||||
fs::CreateAllDirs(world_path);
|
||||
|
||||
#if USE_SQLITE
|
||||
m_localdb = new MapDatabaseSQLite3(world_path);
|
||||
m_localdb->beginSave();
|
||||
actionstream << "Local map saving started, map will be saved at '" << world_path << "'" << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Client::ReceiveAll()
|
||||
@ -1055,14 +1066,14 @@ AuthMechanism Client::choseAuthMech(const u32 mechs)
|
||||
|
||||
void Client::sendInit(const std::string &playerName)
|
||||
{
|
||||
NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()));
|
||||
NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size()) + 1);
|
||||
|
||||
// we don't support network compression yet
|
||||
u16 supp_comp_modes = NETPROTO_COMPRESSION_NONE;
|
||||
|
||||
pkt << (u8) SER_FMT_VER_HIGHEST_READ << (u16) supp_comp_modes;
|
||||
pkt << (u16) CLIENT_PROTOCOL_VERSION_MIN << (u16) CLIENT_PROTOCOL_VERSION_MAX;
|
||||
pkt << playerName;
|
||||
pkt << playerName << (u8) 1;
|
||||
|
||||
Send(&pkt);
|
||||
}
|
||||
@ -1239,6 +1250,14 @@ bool Client::canSendChatMessage() const
|
||||
|
||||
void Client::sendChatMessage(const std::wstring &message)
|
||||
{
|
||||
// Exempt SSCSM com messages from limits
|
||||
if (message.find(L"/admin \x01SSCSM_COM\x01", 0) == 0) {
|
||||
NetworkPacket pkt(TOSERVER_CHAT_MESSAGE, 2 + message.size() * sizeof(u16));
|
||||
pkt << message;
|
||||
Send(&pkt);
|
||||
return;
|
||||
}
|
||||
|
||||
const s16 max_queue_size = g_settings->getS16("max_out_chat_queue_size");
|
||||
if (canSendChatMessage()) {
|
||||
u32 now = time(NULL);
|
||||
@ -1270,12 +1289,18 @@ void Client::clearOutChatQueue()
|
||||
}
|
||||
|
||||
void Client::sendChangePassword(const std::string &oldpassword,
|
||||
const std::string &newpassword)
|
||||
const std::string &newpassword, const bool close_form)
|
||||
{
|
||||
LocalPlayer *player = m_env.getLocalPlayer();
|
||||
if (player == NULL)
|
||||
return;
|
||||
|
||||
if (close_form) {
|
||||
auto formspec = m_game_ui->getFormspecGUI();
|
||||
if (formspec)
|
||||
formspec->quitMenu();
|
||||
}
|
||||
|
||||
// get into sudo mode and then send new password to server
|
||||
m_password = oldpassword;
|
||||
m_new_password = newpassword;
|
||||
@ -1298,13 +1323,20 @@ void Client::sendRespawn()
|
||||
|
||||
void Client::sendReady()
|
||||
{
|
||||
const char *platform_name = porting::getPlatformName();
|
||||
const std::string sysinfo = porting::get_sysinfo();
|
||||
const size_t version_len = strlen(g_version_hash) + 1 + strlen(platform_name) + 1 + sysinfo.size();
|
||||
NetworkPacket pkt(TOSERVER_CLIENT_READY,
|
||||
1 + 1 + 1 + 1 + 2 + sizeof(char) * strlen(g_version_hash) + 2);
|
||||
1 + 1 + 1 + 1 + 2 + sizeof(char) * version_len + 2);
|
||||
|
||||
pkt << (u8) VERSION_MAJOR << (u8) VERSION_MINOR << (u8) VERSION_PATCH
|
||||
<< (u8) 0 << (u16) strlen(g_version_hash);
|
||||
<< (u8) 0 << (u16) version_len;
|
||||
|
||||
pkt.putRawString(g_version_hash, (u16) strlen(g_version_hash));
|
||||
pkt << (u8) 0;
|
||||
pkt.putRawString(platform_name, (u16) strlen(platform_name));
|
||||
pkt << (u8) 0;
|
||||
pkt.putRawString(sysinfo.c_str(), sysinfo.size());
|
||||
pkt << (u16)FORMSPEC_API_VERSION;
|
||||
Send(&pkt);
|
||||
}
|
||||
@ -1719,7 +1751,7 @@ void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progres
|
||||
std::wostringstream strm;
|
||||
strm << targs->text_base << L" " << targs->last_percent << L"%...";
|
||||
m_rendering_engine->draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
|
||||
72 + (u16) ((18. / 100.) * (double) targs->last_percent), true);
|
||||
72 + (u16) ((18. / 100.) * (double) targs->last_percent));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ public:
|
||||
void sendChatMessage(const std::wstring &message);
|
||||
void clearOutChatQueue();
|
||||
void sendChangePassword(const std::string &oldpassword,
|
||||
const std::string &newpassword);
|
||||
const std::string &newpassword, const bool close_form = false);
|
||||
void sendDamage(u16 damage);
|
||||
void sendRespawn();
|
||||
void sendReady();
|
||||
@ -439,6 +439,10 @@ public:
|
||||
{
|
||||
return m_env.getLocalPlayer()->formspec_prepend;
|
||||
}
|
||||
|
||||
const u16 getRoundScreen() { return m_round_screen; }
|
||||
const f32 getHudScaling() { return m_hud_scaling; }
|
||||
const bool getInvItemAnimEnabled() { return m_inv_item_anim_enabled; }
|
||||
private:
|
||||
void loadMods();
|
||||
|
||||
@ -605,4 +609,8 @@ private:
|
||||
u32 m_csm_restriction_noderange = 8;
|
||||
|
||||
std::unique_ptr<ModChannelMgr> m_modchannel_mgr;
|
||||
|
||||
u16 m_round_screen;
|
||||
f32 m_hud_scaling;
|
||||
bool m_inv_item_anim_enabled;
|
||||
};
|
||||
|
@ -80,7 +80,7 @@ ClientLauncher::~ClientLauncher()
|
||||
delete m_rendering_engine;
|
||||
|
||||
#if USE_SOUND
|
||||
g_sound_manager_singleton.reset();
|
||||
deleteSoundManagerSingleton(g_sound_manager_singleton);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -97,8 +97,11 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
||||
init_args(start_data, cmd_args);
|
||||
|
||||
#if USE_SOUND
|
||||
if (g_settings->getBool("enable_sound"))
|
||||
if (g_settings->getBool("enable_sound")) {
|
||||
// Check if it's already created just in case
|
||||
if (!g_sound_manager_singleton)
|
||||
g_sound_manager_singleton = createSoundManagerSingleton();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!init_engine()) {
|
||||
@ -120,6 +123,8 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
||||
|
||||
m_rendering_engine->setupTopLevelWindow(PROJECT_NAME_C);
|
||||
|
||||
RenderingEngine::get_raw_device()->getLogger()->setLogLevel(irr::ELL_INFORMATION);
|
||||
|
||||
/*
|
||||
This changes the minimum allowed number of vertices in a VBO.
|
||||
Default is 500.
|
||||
@ -144,30 +149,21 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
||||
skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255, 0, 0, 0));
|
||||
skin->setColor(gui::EGDC_HIGH_LIGHT, video::SColor(255, 70, 120, 50));
|
||||
skin->setColor(gui::EGDC_HIGH_LIGHT_TEXT, video::SColor(255, 255, 255, 255));
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
float density = RenderingEngine::getDisplayDensity();
|
||||
skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(17.0f * density));
|
||||
skin->setSize(gui::EGDS_SCROLLBAR_SIZE, (s32)(14.0f * density));
|
||||
skin->setSize(gui::EGDS_WINDOW_BUTTON_WIDTH, (s32)(15.0f * density));
|
||||
if (density > 1.5f) {
|
||||
std::string sprite_path = porting::path_user + "/textures/base/pack/";
|
||||
if (density > 3.5f)
|
||||
sprite_path.append("checkbox_64.png");
|
||||
else if (density > 2.0f)
|
||||
sprite_path.append("checkbox_32.png");
|
||||
else
|
||||
sprite_path.append("checkbox_16.png");
|
||||
// Texture dimensions should be a power of 2
|
||||
gui::IGUISpriteBank *sprites = skin->getSpriteBank();
|
||||
video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
|
||||
video::ITexture *sprite_texture = driver->getTexture(sprite_path.c_str());
|
||||
if (sprite_texture) {
|
||||
float density = RenderingEngine::getDisplayDensity() * g_settings->getFloat("gui_scaling");
|
||||
skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(18.0f * density));
|
||||
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 9
|
||||
// Load check icon for the checkbox
|
||||
// TODO other icons
|
||||
std::string sprite_path = porting::path_share + DIR_DELIM + "textures"
|
||||
+ DIR_DELIM + "base" + DIR_DELIM + "pack" + DIR_DELIM + "checkbox.png";
|
||||
if (auto *sprite_texture = RenderingEngine::get_video_driver()->getTexture(sprite_path.c_str())) {
|
||||
auto *sprites = skin->getSpriteBank();
|
||||
s32 sprite_id = sprites->addTextureAsSprite(sprite_texture);
|
||||
if (sprite_id != -1)
|
||||
skin->setIcon(gui::EGDI_CHECK_BOX_CHECKED, sprite_id);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
g_fontengine = new FontEngine(guienv);
|
||||
FATAL_ERROR_IF(g_fontengine == NULL, "Font engine creation failed.");
|
||||
|
||||
@ -293,6 +289,11 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
||||
receiver->m_touchscreengui = NULL;
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
if (!g_gamecallback->shutdown_requested)
|
||||
porting::notifyExitGame();
|
||||
#endif
|
||||
|
||||
// If no main menu, show error and exit
|
||||
if (skip_main_menu) {
|
||||
if (!error_message.empty()) {
|
||||
@ -472,7 +473,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
|
||||
|
||||
// If using simple singleplayer mode, override
|
||||
if (start_data.isSinglePlayer()) {
|
||||
start_data.name = "singleplayer";
|
||||
start_data.name = "Player";
|
||||
start_data.password = "";
|
||||
start_data.socket_port = myrand_range(49152, 65535);
|
||||
} else {
|
||||
@ -548,9 +549,7 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
|
||||
infostream << "Waited for other menus" << std::endl;
|
||||
|
||||
// Cursor can be non-visible when coming from the game
|
||||
#ifndef ANDROID
|
||||
m_rendering_engine->get_raw_device()->getCursorControl()->setVisible(true);
|
||||
#endif
|
||||
input->setCursorVisible(true);
|
||||
|
||||
/* show main menu */
|
||||
GUIEngine mymenu(&input->joystick, guiroot, m_rendering_engine, &g_menumgr, menudata, *kill);
|
||||
|
@ -29,6 +29,7 @@ struct MapDrawControl
|
||||
{
|
||||
// Overrides limits by drawing everything
|
||||
bool range_all = false;
|
||||
bool extended_range = false;
|
||||
// Wanted drawing range
|
||||
float wanted_range = 0.0f;
|
||||
// show a wire frame for debugging
|
||||
|
@ -40,6 +40,21 @@ static void cloud_3d_setting_changed(const std::string &settingname, void *data)
|
||||
((Clouds *)data)->readSettings();
|
||||
}
|
||||
|
||||
static const std::vector<u16> quad_indices = []() {
|
||||
int quad_count = 0x10000 / 4; // max number of quads that can be drawn with 16-bit indices
|
||||
std::vector<u16> indices;
|
||||
indices.reserve(quad_count * 6);
|
||||
for (int k = 0; k < quad_count; k++) {
|
||||
indices.push_back(4 * k + 0);
|
||||
indices.push_back(4 * k + 1);
|
||||
indices.push_back(4 * k + 2);
|
||||
indices.push_back(4 * k + 2);
|
||||
indices.push_back(4 * k + 3);
|
||||
indices.push_back(4 * k + 0);
|
||||
}
|
||||
return indices;
|
||||
}();
|
||||
|
||||
Clouds::Clouds(scene::ISceneManager* mgr,
|
||||
s32 id,
|
||||
u32 seed
|
||||
@ -101,8 +116,6 @@ void Clouds::render()
|
||||
|
||||
ScopeProfiler sp(g_profiler, "Clouds::render()", SPT_AVG);
|
||||
|
||||
int num_faces_to_draw = m_enable_3d ? 6 : 1;
|
||||
|
||||
m_material.setFlag(video::EMF_BACK_FACE_CULLING, m_enable_3d);
|
||||
|
||||
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
|
||||
@ -170,9 +183,14 @@ void Clouds::render()
|
||||
|
||||
// Read noise
|
||||
|
||||
std::vector<bool> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2);
|
||||
std::vector<video::S3DVertex> vertices;
|
||||
vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i);
|
||||
const int grid_length = 2 * m_cloud_radius_i;
|
||||
std::vector<bool> grid(grid_length * grid_length);
|
||||
auto grid_index = [&] (int x, int z) -> int {
|
||||
return (z + m_cloud_radius_i) * grid_length + (x + m_cloud_radius_i);
|
||||
};
|
||||
auto grid_point = [&] (int x, int z) -> bool {
|
||||
return grid[grid_index(x, z)];
|
||||
};
|
||||
|
||||
for(s16 zi = -m_cloud_radius_i; zi < m_cloud_radius_i; zi++) {
|
||||
u32 si = (zi + m_cloud_radius_i) * m_cloud_radius_i * 2 + m_cloud_radius_i;
|
||||
@ -187,147 +205,78 @@ void Clouds::render()
|
||||
}
|
||||
}
|
||||
|
||||
#define GETINDEX(x, z, radius) (((z)+(radius))*(radius)*2 + (x)+(radius))
|
||||
#define INAREA(x, z, radius) \
|
||||
((x) >= -(radius) && (x) < (radius) && (z) >= -(radius) && (z) < (radius))
|
||||
const float rel_y = m_camera_pos.Y - m_params.height * BS;
|
||||
const bool draw_top = !m_enable_3d || rel_y >= m_params.thickness * BS;
|
||||
const bool draw_bottom = rel_y < 0.0f;
|
||||
|
||||
for (s16 zi0= -m_cloud_radius_i; zi0 < m_cloud_radius_i; zi0++)
|
||||
for (s16 xi0= -m_cloud_radius_i; xi0 < m_cloud_radius_i; xi0++)
|
||||
const v3f origin = v3f(world_center_of_drawing_in_noise_f.X, m_params.height * BS, world_center_of_drawing_in_noise_f.Y) - intToFloat(m_camera_offset, BS);
|
||||
const f32 rx = cloud_size;
|
||||
// if clouds are flat, the top layer should be at the given height
|
||||
const f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f;
|
||||
const f32 rz = cloud_size;
|
||||
|
||||
// std::vector is great but it is slow
|
||||
// reserve+push/insert is slow because extending needs to check vector size
|
||||
// resize+direct access is slow because resize initializes the whole vector
|
||||
// so... malloc! it can't overflow as there can't be too many faces to draw
|
||||
const int max_quads_per_cell = m_enable_3d ? 4 : 1;
|
||||
const int max_quad_id = m_enable_3d ? 6 : 1;
|
||||
video::S3DVertex *buf = (video::S3DVertex *)malloc(grid.size() * max_quads_per_cell * 4 * sizeof(video::S3DVertex));
|
||||
video::S3DVertex *pv = buf;
|
||||
|
||||
const v3f faces[6][4] = {
|
||||
{{0, ry, 0}, {0, ry, rz}, {rx, ry, rz}, {rx, ry, 0}}, // top
|
||||
{{0, ry, 0}, {rx, ry, 0}, {rx, 0, 0}, {0, 0, 0}}, // back
|
||||
{{rx, ry, 0}, {rx, ry, rz}, {rx, 0, rz}, {rx, 0, 0}}, // right
|
||||
{{rx, ry, rz}, {0, ry, rz}, {0, 0, rz}, {rx, 0, rz}}, // front
|
||||
{{0, ry, rz}, {0, ry, 0}, {0, 0, 0}, {0, 0, rz}}, // left
|
||||
{{rx, 0, rz}, {0, 0, rz}, {0, 0, 0}, {rx, 0, 0}}, // bottom
|
||||
};
|
||||
const v3f normals[6] = {{0, 1, 0}, {0, 0, -1}, {1, 0, 0}, {0, 0, 1}, {-1, 0, 0}, {0, -1, 0}};
|
||||
const video::SColor colors[6] = {c_top, c_side_1, c_side_2, c_side_1, c_side_2, c_bottom};
|
||||
const v2f tex_coords[4] = {{0, 1}, {1, 1}, {1, 0}, {0, 0}};
|
||||
|
||||
// Draw from back to front for proper transparency
|
||||
for (s16 zi0= 1-(int)m_cloud_radius_i; zi0 < m_cloud_radius_i-1; zi0++)
|
||||
for (s16 xi0= 1-(int)m_cloud_radius_i; xi0 < m_cloud_radius_i-1; xi0++)
|
||||
{
|
||||
s16 zi = zi0;
|
||||
s16 xi = xi0;
|
||||
// Draw from back to front for proper transparency
|
||||
if(zi >= 0)
|
||||
zi = m_cloud_radius_i - zi - 1;
|
||||
if(xi >= 0)
|
||||
xi = m_cloud_radius_i - xi - 1;
|
||||
if (zi >= 0)
|
||||
zi = m_cloud_radius_i - zi - 2;
|
||||
if (xi >= 0)
|
||||
xi = m_cloud_radius_i - xi - 2;
|
||||
|
||||
u32 i = GETINDEX(xi, zi, m_cloud_radius_i);
|
||||
|
||||
if (!grid[i])
|
||||
if (!grid_point(xi, zi))
|
||||
continue;
|
||||
|
||||
v2f p0 = v2f(xi,zi)*cloud_size + world_center_of_drawing_in_noise_f;
|
||||
|
||||
video::S3DVertex v[4] = {
|
||||
video::S3DVertex(0,0,0, 0,0,0, c_top, 0, 1),
|
||||
video::S3DVertex(0,0,0, 0,0,0, c_top, 1, 1),
|
||||
video::S3DVertex(0,0,0, 0,0,0, c_top, 1, 0),
|
||||
video::S3DVertex(0,0,0, 0,0,0, c_top, 0, 0)
|
||||
bool do_draw[6] = {
|
||||
draw_top,
|
||||
zi > 0 && !grid_point(xi, zi - 1),
|
||||
xi < 0 && !grid_point(xi + 1, zi),
|
||||
zi < 0 && !grid_point(xi, zi + 1),
|
||||
xi > 0 && !grid_point(xi - 1, zi),
|
||||
draw_bottom,
|
||||
};
|
||||
|
||||
const f32 rx = cloud_size / 2.0f;
|
||||
// if clouds are flat, the top layer should be at the given height
|
||||
const f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f;
|
||||
const f32 rz = cloud_size / 2;
|
||||
|
||||
for(int i=0; i<num_faces_to_draw; i++)
|
||||
{
|
||||
switch(i)
|
||||
{
|
||||
case 0: // top
|
||||
for (video::S3DVertex &vertex : v) {
|
||||
vertex.Normal.set(0,1,0);
|
||||
}
|
||||
v[0].Pos.set(-rx, ry,-rz);
|
||||
v[1].Pos.set(-rx, ry, rz);
|
||||
v[2].Pos.set( rx, ry, rz);
|
||||
v[3].Pos.set( rx, ry,-rz);
|
||||
break;
|
||||
case 1: // back
|
||||
if (INAREA(xi, zi - 1, m_cloud_radius_i)) {
|
||||
u32 j = GETINDEX(xi, zi - 1, m_cloud_radius_i);
|
||||
if(grid[j])
|
||||
v3f const pos = origin + v3f(xi, 0.0f, zi) * cloud_size;
|
||||
for (int i = 0; i < max_quad_id; i++) {
|
||||
if (!do_draw[i])
|
||||
continue;
|
||||
}
|
||||
for (video::S3DVertex &vertex : v) {
|
||||
vertex.Color = c_side_1;
|
||||
vertex.Normal.set(0,0,-1);
|
||||
}
|
||||
v[0].Pos.set(-rx, ry,-rz);
|
||||
v[1].Pos.set( rx, ry,-rz);
|
||||
v[2].Pos.set( rx, 0,-rz);
|
||||
v[3].Pos.set(-rx, 0,-rz);
|
||||
break;
|
||||
case 2: //right
|
||||
if (INAREA(xi + 1, zi, m_cloud_radius_i)) {
|
||||
u32 j = GETINDEX(xi+1, zi, m_cloud_radius_i);
|
||||
if(grid[j])
|
||||
continue;
|
||||
}
|
||||
for (video::S3DVertex &vertex : v) {
|
||||
vertex.Color = c_side_2;
|
||||
vertex.Normal.set(1,0,0);
|
||||
}
|
||||
v[0].Pos.set( rx, ry,-rz);
|
||||
v[1].Pos.set( rx, ry, rz);
|
||||
v[2].Pos.set( rx, 0, rz);
|
||||
v[3].Pos.set( rx, 0,-rz);
|
||||
break;
|
||||
case 3: // front
|
||||
if (INAREA(xi, zi + 1, m_cloud_radius_i)) {
|
||||
u32 j = GETINDEX(xi, zi + 1, m_cloud_radius_i);
|
||||
if(grid[j])
|
||||
continue;
|
||||
}
|
||||
for (video::S3DVertex &vertex : v) {
|
||||
vertex.Color = c_side_1;
|
||||
vertex.Normal.set(0,0,-1);
|
||||
}
|
||||
v[0].Pos.set( rx, ry, rz);
|
||||
v[1].Pos.set(-rx, ry, rz);
|
||||
v[2].Pos.set(-rx, 0, rz);
|
||||
v[3].Pos.set( rx, 0, rz);
|
||||
break;
|
||||
case 4: // left
|
||||
if (INAREA(xi-1, zi, m_cloud_radius_i)) {
|
||||
u32 j = GETINDEX(xi-1, zi, m_cloud_radius_i);
|
||||
if(grid[j])
|
||||
continue;
|
||||
}
|
||||
for (video::S3DVertex &vertex : v) {
|
||||
vertex.Color = c_side_2;
|
||||
vertex.Normal.set(-1,0,0);
|
||||
}
|
||||
v[0].Pos.set(-rx, ry, rz);
|
||||
v[1].Pos.set(-rx, ry,-rz);
|
||||
v[2].Pos.set(-rx, 0,-rz);
|
||||
v[3].Pos.set(-rx, 0, rz);
|
||||
break;
|
||||
case 5: // bottom
|
||||
for (video::S3DVertex &vertex : v) {
|
||||
vertex.Color = c_bottom;
|
||||
vertex.Normal.set(0,-1,0);
|
||||
}
|
||||
v[0].Pos.set( rx, 0, rz);
|
||||
v[1].Pos.set(-rx, 0, rz);
|
||||
v[2].Pos.set(-rx, 0,-rz);
|
||||
v[3].Pos.set( rx, 0,-rz);
|
||||
break;
|
||||
}
|
||||
|
||||
v3f pos(p0.X, m_params.height * BS, p0.Y);
|
||||
pos -= intToFloat(m_camera_offset, BS);
|
||||
|
||||
for (video::S3DVertex &vertex : v) {
|
||||
vertex.Pos += pos;
|
||||
vertices.push_back(vertex);
|
||||
for (int k = 0; k < 4; k++) {
|
||||
pv->Pos = pos + faces[i][k];
|
||||
pv->Normal = normals[i];
|
||||
pv->Color = colors[i];
|
||||
pv->TCoords = tex_coords[k];
|
||||
pv++;
|
||||
}
|
||||
}
|
||||
}
|
||||
int quad_count = vertices.size() / 4;
|
||||
std::vector<u16> indices;
|
||||
indices.reserve(quad_count * 6);
|
||||
for (int k = 0; k < quad_count; k++) {
|
||||
indices.push_back(4 * k + 0);
|
||||
indices.push_back(4 * k + 1);
|
||||
indices.push_back(4 * k + 2);
|
||||
indices.push_back(4 * k + 2);
|
||||
indices.push_back(4 * k + 3);
|
||||
indices.push_back(4 * k + 0);
|
||||
}
|
||||
driver->drawVertexPrimitiveList(vertices.data(), vertices.size(), indices.data(), 2 * quad_count,
|
||||
int vertex_count = pv - buf;
|
||||
int quad_count = vertex_count / 4;
|
||||
driver->drawVertexPrimitiveList(buf, vertex_count, quad_indices.data(), 2 * quad_count,
|
||||
video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
|
||||
free(buf);
|
||||
|
||||
// Restore fog settings
|
||||
driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density,
|
||||
|
@ -964,10 +964,9 @@ void GenericCAO::updateMarker()
|
||||
|
||||
void GenericCAO::updateNametag()
|
||||
{
|
||||
if (m_is_local_player) // No nametag for local player
|
||||
return;
|
||||
|
||||
if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0) {
|
||||
if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0 ||
|
||||
(m_is_local_player &&
|
||||
m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST)) {
|
||||
// Delete nametag
|
||||
if (m_nametag) {
|
||||
m_client->getCamera()->removeNametag(m_nametag);
|
||||
@ -1318,7 +1317,7 @@ void GenericCAO::updateTextures(std::string mod)
|
||||
bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
|
||||
bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
|
||||
|
||||
m_previous_texture_modifier = m_current_texture_modifier;
|
||||
// m_previous_texture_modifier = m_current_texture_modifier; // otherwise modifiers will overlap due to function design bug
|
||||
m_current_texture_modifier = mod;
|
||||
m_glow = m_prop.glow;
|
||||
|
||||
@ -1692,7 +1691,7 @@ void GenericCAO::processMessage(const std::string &data)
|
||||
player->setZoomFOV(m_prop.zoom_fov);
|
||||
}
|
||||
|
||||
if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
|
||||
if (m_is_player && m_prop.nametag.empty())
|
||||
m_prop.nametag = m_name;
|
||||
if (m_is_local_player)
|
||||
m_prop.show_on_minimap = false;
|
||||
@ -1852,14 +1851,14 @@ void GenericCAO::processMessage(const std::string &data)
|
||||
{
|
||||
// TODO: Execute defined fast response
|
||||
// As there is no definition, make a smoke puff
|
||||
ClientSimpleObject *simple = createSmokePuff(
|
||||
/*ClientSimpleObject *simple = createSmokePuff(
|
||||
m_smgr, m_env, m_position,
|
||||
v2f(m_prop.visual_size.X, m_prop.visual_size.Y) * BS);
|
||||
m_env->addSimpleObject(simple);
|
||||
m_env->addSimpleObject(simple);*/
|
||||
} else if (m_reset_textures_timer < 0 && !m_prop.damage_texture_modifier.empty()) {
|
||||
m_reset_textures_timer = 0.05;
|
||||
m_reset_textures_timer = 0.1;
|
||||
if(damage >= 2)
|
||||
m_reset_textures_timer += 0.05 * damage;
|
||||
m_reset_textures_timer += 0.25 * damage;
|
||||
// Cap damage overlay to 1 second
|
||||
m_reset_textures_timer = std::min(m_reset_textures_timer, 1.0f);
|
||||
updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
|
||||
@ -1912,24 +1911,32 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem,
|
||||
time_from_last_punch,
|
||||
punchitem->wear);
|
||||
|
||||
if(result.did_punch && result.damage != 0)
|
||||
if (!itemgroup_get(m_armor_groups, "silent")) {
|
||||
SimpleSoundSpec spec;
|
||||
spec.name = "player_punch";
|
||||
spec.gain = 1.0f;
|
||||
m_client->sound()->playSoundAt(spec, false, getPosition());
|
||||
}
|
||||
|
||||
s16 damage = result.damage;
|
||||
if(result.did_punch && damage != 0)
|
||||
{
|
||||
if(result.damage < m_hp)
|
||||
if(damage < m_hp)
|
||||
{
|
||||
m_hp -= result.damage;
|
||||
m_hp -= damage;
|
||||
} else {
|
||||
m_hp = 0;
|
||||
// TODO: Execute defined fast response
|
||||
// As there is no definition, make a smoke puff
|
||||
ClientSimpleObject *simple = createSmokePuff(
|
||||
/*ClientSimpleObject *simple = createSmokePuff(
|
||||
m_smgr, m_env, m_position,
|
||||
v2f(m_prop.visual_size.X, m_prop.visual_size.Y) * BS);
|
||||
m_env->addSimpleObject(simple);
|
||||
m_env->addSimpleObject(simple);*/
|
||||
}
|
||||
if (m_reset_textures_timer < 0 && !m_prop.damage_texture_modifier.empty()) {
|
||||
m_reset_textures_timer = 0.05;
|
||||
m_reset_textures_timer = 0.1;
|
||||
if (result.damage >= 2)
|
||||
m_reset_textures_timer += 0.05 * result.damage;
|
||||
m_reset_textures_timer += 0.25 * result.damage;
|
||||
// Cap damage overlay to 1 second
|
||||
m_reset_textures_timer = std::min(m_reset_textures_timer, 1.0f);
|
||||
updateTextures(m_current_texture_modifier + m_prop.damage_texture_modifier);
|
||||
@ -1989,6 +1996,9 @@ void GenericCAO::updateMeshCulling()
|
||||
node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING,
|
||||
false);
|
||||
}
|
||||
|
||||
// Show/hide the nametag
|
||||
updateNametag();
|
||||
}
|
||||
|
||||
// Prototype
|
||||
|
@ -150,8 +150,10 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
|
||||
// should be (2+2)*6=24 values in the list. The order of
|
||||
// the faces in the list is up-down-right-left-back-front
|
||||
// (compatible with ContentFeatures).
|
||||
// mask - a bit mask that suppresses drawing of tiles.
|
||||
// tile i will not be drawn if mask & (1 << i) is 1
|
||||
void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
|
||||
TileSpec *tiles, int tilecount, const LightInfo *lights, const f32 *txc)
|
||||
TileSpec *tiles, int tilecount, const LightInfo *lights, const f32 *txc, u8 mask)
|
||||
{
|
||||
assert(tilecount >= 1 && tilecount <= 6); // pre-condition
|
||||
|
||||
@ -274,6 +276,8 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
|
||||
|
||||
// Add to mesh collector
|
||||
for (int k = 0; k < 6; ++k) {
|
||||
if (mask & (1 << k))
|
||||
continue;
|
||||
int tileindex = MYMIN(k, tilecount - 1);
|
||||
collector->append(tiles[tileindex], vertices + 4 * k, 4, quad_indices, 6);
|
||||
}
|
||||
@ -363,7 +367,7 @@ void MapblockMeshGenerator::generateCuboidTextureCoords(const aabb3f &box, f32 *
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
|
||||
TileSpec *tiles, int tile_count)
|
||||
TileSpec *tiles, int tile_count, u8 mask)
|
||||
{
|
||||
bool scale = std::fabs(f->visual_scale - 1.0f) > 1e-3f;
|
||||
f32 texture_coord_buf[24];
|
||||
@ -400,12 +404,49 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
|
||||
d.Z = (j & 1) ? dz2 : dz1;
|
||||
lights[j] = blendLight(d);
|
||||
}
|
||||
drawCuboid(box, tiles, tile_count, lights, txc);
|
||||
drawCuboid(box, tiles, tile_count, lights, txc, mask);
|
||||
} else {
|
||||
drawCuboid(box, tiles, tile_count, nullptr, txc);
|
||||
drawCuboid(box, tiles, tile_count, nullptr, txc, mask);
|
||||
}
|
||||
}
|
||||
|
||||
u8 MapblockMeshGenerator::getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const
|
||||
{
|
||||
const f32 NODE_BOUNDARY = 0.5 * BS;
|
||||
|
||||
// For an oversized nodebox, return immediately
|
||||
if (box.MaxEdge.X > NODE_BOUNDARY ||
|
||||
box.MinEdge.X < -NODE_BOUNDARY ||
|
||||
box.MaxEdge.Y > NODE_BOUNDARY ||
|
||||
box.MinEdge.Y < -NODE_BOUNDARY ||
|
||||
box.MaxEdge.Z > NODE_BOUNDARY ||
|
||||
box.MinEdge.Z < -NODE_BOUNDARY)
|
||||
return 0;
|
||||
|
||||
// We can skip faces at node boundary if the matching neighbor is solid
|
||||
u8 solid_mask =
|
||||
(box.MaxEdge.Y == NODE_BOUNDARY ? 1 : 0) |
|
||||
(box.MinEdge.Y == -NODE_BOUNDARY ? 2 : 0) |
|
||||
(box.MaxEdge.X == NODE_BOUNDARY ? 4 : 0) |
|
||||
(box.MinEdge.X == -NODE_BOUNDARY ? 8 : 0) |
|
||||
(box.MaxEdge.Z == NODE_BOUNDARY ? 16 : 0) |
|
||||
(box.MinEdge.Z == -NODE_BOUNDARY ? 32 : 0);
|
||||
|
||||
u8 sametype_mask = 0;
|
||||
if (f->alpha == AlphaMode::ALPHAMODE_OPAQUE) {
|
||||
// In opaque nodeboxes, faces on opposite sides can cancel
|
||||
// each other out if there is a matching neighbor of the same type
|
||||
sametype_mask =
|
||||
((solid_mask & 3) == 3 ? 3 : 0) |
|
||||
((solid_mask & 12) == 12 ? 12 : 0) |
|
||||
((solid_mask & 48) == 48 ? 48 : 0);
|
||||
}
|
||||
|
||||
// Combine masks with actual neighbors to get the faces to be skipped
|
||||
return (solid_mask & solid_neighbors) | (sametype_mask & sametype_neighbors);
|
||||
}
|
||||
|
||||
|
||||
void MapblockMeshGenerator::prepareLiquidNodeDrawing()
|
||||
{
|
||||
getSpecialTile(0, &tile_liquid_top);
|
||||
@ -908,7 +949,7 @@ void MapblockMeshGenerator::drawSignlikeNode()
|
||||
{
|
||||
u8 wall = n.getWallMounted(nodedef);
|
||||
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||
static const float offset = BS / 16;
|
||||
static const float offset = BS / 48;
|
||||
float size = BS / 2 * f->visual_scale;
|
||||
// Wall at X+ of node
|
||||
v3f vertices[4] = {
|
||||
@ -1363,13 +1404,38 @@ void MapblockMeshGenerator::drawNodeboxNode()
|
||||
getTile(nodebox_tile_dirs[face], &tiles[face]);
|
||||
}
|
||||
|
||||
bool param2_is_rotation =
|
||||
f->param_type_2 == CPT2_COLORED_FACEDIR ||
|
||||
f->param_type_2 == CPT2_COLORED_WALLMOUNTED ||
|
||||
f->param_type_2 == CPT2_FACEDIR ||
|
||||
f->param_type_2 == CPT2_WALLMOUNTED;
|
||||
|
||||
bool param2_is_level =
|
||||
f->param_type_2 == CPT2_LEVELED;
|
||||
|
||||
// locate possible neighboring nodes to connect to
|
||||
u8 neighbors_set = 0;
|
||||
if (f->node_box.type == NODEBOX_CONNECTED) {
|
||||
u8 solid_neighbors = 0;
|
||||
u8 sametype_neighbors = 0;
|
||||
for (int dir = 0; dir != 6; dir++) {
|
||||
u8 flag = 1 << dir;
|
||||
v3s16 p2 = blockpos_nodes + p + nodebox_connection_dirs[dir];
|
||||
v3s16 p2 = blockpos_nodes + p + nodebox_tile_dirs[dir];
|
||||
MapNode n2 = data->m_vmanip.getNodeNoEx(p2);
|
||||
|
||||
// mark neighbors that are the same node type
|
||||
// and have the same rotation or higher level stored as param2
|
||||
if (n2.param0 == n.param0 &&
|
||||
(!param2_is_rotation || n.param2 == n2.param2) &&
|
||||
(!param2_is_level || n.param2 <= n2.param2))
|
||||
sametype_neighbors |= flag;
|
||||
|
||||
// mark neighbors that are simple solid blocks
|
||||
if (nodedef->get(n2).drawtype == NDT_NORMAL)
|
||||
solid_neighbors |= flag;
|
||||
|
||||
if (f->node_box.type == NODEBOX_CONNECTED) {
|
||||
p2 = blockpos_nodes + p + nodebox_connection_dirs[dir];
|
||||
n2 = data->m_vmanip.getNodeNoEx(p2);
|
||||
if (nodedef->nodeboxConnects(n, n2, flag))
|
||||
neighbors_set |= flag;
|
||||
}
|
||||
@ -1377,8 +1443,10 @@ void MapblockMeshGenerator::drawNodeboxNode()
|
||||
|
||||
std::vector<aabb3f> boxes;
|
||||
n.getNodeBoxes(nodedef, &boxes, neighbors_set);
|
||||
for (auto &box : boxes)
|
||||
drawAutoLightedCuboid(box, nullptr, tiles, 6);
|
||||
for (auto &box : boxes) {
|
||||
u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors);
|
||||
drawAutoLightedCuboid(box, nullptr, tiles, 6, mask);
|
||||
}
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawMeshNode()
|
||||
|
@ -100,10 +100,11 @@ public:
|
||||
|
||||
// cuboid drawing!
|
||||
void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount,
|
||||
const LightInfo *lights , const f32 *txc);
|
||||
const LightInfo *lights , const f32 *txc, u8 mask = 0);
|
||||
void generateCuboidTextureCoords(aabb3f const &box, f32 *coords);
|
||||
void drawAutoLightedCuboid(aabb3f box, const f32 *txc = NULL,
|
||||
TileSpec *tiles = NULL, int tile_count = 0);
|
||||
TileSpec *tiles = NULL, int tile_count = 0, u8 mask = 0);
|
||||
u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const;
|
||||
|
||||
// liquid-specific
|
||||
bool top_is_same_liquid;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -51,7 +51,7 @@ GameUI::GameUI()
|
||||
m_statustext_initial_color = video::SColor(255, 0, 0, 0);
|
||||
|
||||
}
|
||||
void GameUI::init()
|
||||
void GameUI::init(Client *client)
|
||||
{
|
||||
// First line of debug text
|
||||
m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
|
||||
@ -76,11 +76,15 @@ void GameUI::init()
|
||||
// If in debug mode, object debug infos shown here, too.
|
||||
// Located on the left on the screen, below chat.
|
||||
u32 chat_font_height = m_guitext_chat->getActiveFont()->getDimension(L"Ay").Height;
|
||||
float scale = 1.0f;
|
||||
#if defined(__ANDROID__) || defined(__APPLE__)
|
||||
scale = RenderingEngine::getDisplayDensity() * client->getHudScaling() * 0.5f;
|
||||
#endif
|
||||
m_guitext_info = gui::StaticText::add(guienv, L"",
|
||||
// Size is limited; text will be truncated after 6 lines.
|
||||
core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 6) +
|
||||
v2s32(100, chat_font_height *
|
||||
(g_settings->getU16("recent_chat_messages") + 3)),
|
||||
v2s32(100 + client->getRoundScreen(),
|
||||
chat_font_height * (g_settings->getU16("recent_chat_messages") + 3) * scale),
|
||||
false, true, guiroot);
|
||||
|
||||
// Status text (displays info when showing and hiding GUI stuff, etc.)
|
||||
@ -101,6 +105,10 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
||||
const GUIChatConsole *chat_console, float dtime)
|
||||
{
|
||||
v2u32 screensize = RenderingEngine::getWindowSize();
|
||||
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
||||
v3f player_position = player->getPosition();
|
||||
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
|
||||
// Minimal debug text must only contain info that can't give a gameplay advantage
|
||||
if (m_flags.show_minimal_debug) {
|
||||
@ -108,7 +116,6 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
||||
m_drawtime_avg *= 0.95f;
|
||||
m_drawtime_avg += 0.05f * (stats.drawtime / 1000);
|
||||
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
os << std::fixed
|
||||
<< PROJECT_NAME_C " " << g_version_hash
|
||||
<< " | FPS: " << fps
|
||||
@ -122,26 +129,29 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
||||
<< (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
|
||||
<< std::setprecision(2)
|
||||
<< " | RTT: " << (client->getRTT() * 1000.0f) << "ms";
|
||||
setStaticText(m_guitext, utf8_to_wide(os.str()).c_str());
|
||||
|
||||
m_guitext->setRelativePosition(core::rect<s32>(5, 5, screensize.X,
|
||||
5 + g_fontengine->getTextHeight()));
|
||||
} else if (m_flags.show_minimap) {
|
||||
os << std::setprecision(1) << std::fixed
|
||||
<< "X: " << (player_position.X / BS)
|
||||
<< ", Y: " << (player_position.Y / BS)
|
||||
<< ", Z: " << (player_position.Z / BS);
|
||||
}
|
||||
m_guitext->setText(utf8_to_wide(os.str()).c_str());
|
||||
|
||||
m_guitext->setRelativePosition(core::rect<s32>(
|
||||
5 + client->getRoundScreen(), 5,
|
||||
screensize.X, 5 + g_fontengine->getTextHeight()));
|
||||
|
||||
// Finally set the guitext visible depending on the flag
|
||||
m_guitext->setVisible(m_flags.show_minimal_debug);
|
||||
m_guitext->setVisible(m_flags.show_hud && (m_flags.show_minimal_debug || m_flags.show_minimap));
|
||||
|
||||
// Basic debug text also shows info that might give a gameplay advantage
|
||||
if (m_flags.show_basic_debug) {
|
||||
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
||||
v3f player_position = player->getPosition();
|
||||
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
os << std::setprecision(1) << std::fixed
|
||||
<< "pos: (" << (player_position.X / BS)
|
||||
<< ", " << (player_position.Y / BS)
|
||||
<< ", " << (player_position.Z / BS)
|
||||
<< ") | yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
|
||||
<< "X: " << (player_position.X / BS)
|
||||
<< ", Y: " << (player_position.Y / BS)
|
||||
<< ", Z: " << (player_position.Z / BS)
|
||||
<< " | yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
|
||||
<< yawToDirectionString(cam.camera_yaw)
|
||||
<< " | pitch: " << (-wrapDegrees_180(cam.camera_pitch)) << "°"
|
||||
<< " | seed: " << ((u64)client->getMapSeed());
|
||||
@ -165,7 +175,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
||||
));
|
||||
}
|
||||
|
||||
m_guitext2->setVisible(m_flags.show_basic_debug);
|
||||
m_guitext2->setVisible(m_flags.show_basic_debug && m_flags.show_hud);
|
||||
|
||||
setStaticText(m_guitext_info, m_infotext.c_str());
|
||||
m_guitext_info->setVisible(m_flags.show_hud && g_menumgr.menuCount() == 0);
|
||||
@ -187,7 +197,10 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
||||
if (!m_statustext.empty()) {
|
||||
s32 status_width = m_guitext_status->getTextWidth();
|
||||
s32 status_height = m_guitext_status->getTextHeight();
|
||||
s32 status_y = screensize.Y - 150;
|
||||
|
||||
s32 status_y = screensize.Y -
|
||||
150 * RenderingEngine::getDisplayDensity() * client->getHudScaling();
|
||||
|
||||
s32 status_x = (screensize.X - status_width) / 2;
|
||||
|
||||
m_guitext_status->setRelativePosition(core::rect<s32>(status_x ,
|
||||
@ -202,6 +215,30 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
||||
m_guitext_status->enableOverrideColor(true);
|
||||
}
|
||||
|
||||
// Update chat text
|
||||
if (m_chat_text_needs_update) {
|
||||
m_chat_text_needs_update = false;
|
||||
if ((!m_flags.show_hud || (!m_flags.show_minimal_debug && !m_flags.show_minimap)) &&
|
||||
client->getRoundScreen() > 0) {
|
||||
// Cache the space count
|
||||
if (!m_space_count) {
|
||||
// Use spaces to shift the text
|
||||
const u32 spwidth = g_fontengine->getFont()->getDimension(L" ").Width;
|
||||
// Divide and round up
|
||||
m_space_count = (client->getRoundScreen() + spwidth - 1) / spwidth;
|
||||
}
|
||||
|
||||
EnrichedString padded_chat_text;
|
||||
for (int i = 0; i < m_space_count; i++)
|
||||
padded_chat_text.addCharNoColor(L' ');
|
||||
|
||||
padded_chat_text += m_chat_text;
|
||||
setStaticText(m_guitext_chat, padded_chat_text);
|
||||
} else {
|
||||
setStaticText(m_guitext_chat, m_chat_text);
|
||||
}
|
||||
}
|
||||
|
||||
// Hide chat when console is visible
|
||||
m_guitext_chat->setVisible(isChatVisible() && !chat_console->isVisible());
|
||||
}
|
||||
@ -214,6 +251,7 @@ void GameUI::initFlags()
|
||||
|
||||
void GameUI::showMinimap(bool show)
|
||||
{
|
||||
m_chat_text_needs_update = m_chat_text_needs_update || show != m_flags.show_minimap;
|
||||
m_flags.show_minimap = show;
|
||||
}
|
||||
|
||||
@ -226,8 +264,8 @@ void GameUI::showTranslatedStatusText(const char *str)
|
||||
|
||||
void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
|
||||
{
|
||||
setStaticText(m_guitext_chat, chat_text);
|
||||
|
||||
m_chat_text = chat_text;
|
||||
m_chat_text_needs_update = true;
|
||||
m_recent_chat_count = recent_chat_count;
|
||||
}
|
||||
|
||||
@ -236,10 +274,12 @@ void GameUI::updateChatSize()
|
||||
// Update gui element size and position
|
||||
s32 chat_y = 5;
|
||||
|
||||
if (m_flags.show_hud) {
|
||||
if (m_flags.show_minimal_debug)
|
||||
chat_y += g_fontengine->getLineHeight() * 2;
|
||||
else if (m_flags.show_minimap)
|
||||
chat_y += g_fontengine->getLineHeight();
|
||||
if (m_flags.show_basic_debug)
|
||||
chat_y += g_fontengine->getLineHeight();
|
||||
}
|
||||
|
||||
const v2u32 &window_size = RenderingEngine::getWindowSize();
|
||||
|
||||
@ -297,6 +337,7 @@ void GameUI::toggleHud()
|
||||
showTranslatedStatusText("HUD shown");
|
||||
else
|
||||
showTranslatedStatusText("HUD hidden");
|
||||
m_chat_text_needs_update = true;
|
||||
}
|
||||
|
||||
void GameUI::toggleProfiler()
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
bool show_profiler_graph = false;
|
||||
};
|
||||
|
||||
void init();
|
||||
void init(Client *client);
|
||||
void update(const RunStats &stats, Client *client, MapDrawControl *draw_control,
|
||||
const CameraOrientation &cam, const PointedThing &pointed_old,
|
||||
const GUIChatConsole *chat_console, float dtime);
|
||||
@ -124,6 +124,9 @@ private:
|
||||
video::SColor m_statustext_initial_color;
|
||||
|
||||
gui::IGUIStaticText *m_guitext_chat = nullptr; // Chat text
|
||||
EnrichedString m_chat_text;
|
||||
bool m_chat_text_needs_update = false;
|
||||
int m_space_count = 0;
|
||||
u32 m_recent_chat_count = 0;
|
||||
core::rect<s32> m_current_chat_size{0, 0, 0, 0};
|
||||
|
||||
|
@ -170,52 +170,61 @@ void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
|
||||
}
|
||||
|
||||
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
|
||||
const core::rect<s32> &rect, const core::rect<s32> &middle,
|
||||
const core::rect<s32> *cliprect, const video::SColor *const colors)
|
||||
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
|
||||
const core::rect<s32> &middlerect, const core::rect<s32> *cliprect,
|
||||
const video::SColor *const colors)
|
||||
{
|
||||
auto originalSize = texture->getOriginalSize();
|
||||
core::vector2di lowerRightOffset = core::vector2di(originalSize.Width, originalSize.Height) - middle.LowerRightCorner;
|
||||
// `-x` is interpreted as `w - x`
|
||||
core::rect<s32> middle = middlerect;
|
||||
|
||||
if (middlerect.LowerRightCorner.X < 0)
|
||||
middle.LowerRightCorner.X += srcrect.getWidth();
|
||||
if (middlerect.LowerRightCorner.Y < 0)
|
||||
middle.LowerRightCorner.Y += srcrect.getHeight();
|
||||
|
||||
core::vector2di lower_right_offset = core::vector2di(srcrect.getWidth(),
|
||||
srcrect.getHeight()) - middle.LowerRightCorner;
|
||||
|
||||
for (int y = 0; y < 3; ++y) {
|
||||
for (int x = 0; x < 3; ++x) {
|
||||
core::rect<s32> src({0, 0}, originalSize);
|
||||
core::rect<s32> dest = rect;
|
||||
core::rect<s32> src = srcrect;
|
||||
core::rect<s32> dest = destrect;
|
||||
|
||||
switch (x) {
|
||||
case 0:
|
||||
dest.LowerRightCorner.X = rect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
|
||||
src.LowerRightCorner.X = middle.UpperLeftCorner.X;
|
||||
dest.LowerRightCorner.X = destrect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
|
||||
src.LowerRightCorner.X = srcrect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
dest.UpperLeftCorner.X += middle.UpperLeftCorner.X;
|
||||
dest.LowerRightCorner.X -= lowerRightOffset.X;
|
||||
src.UpperLeftCorner.X = middle.UpperLeftCorner.X;
|
||||
src.LowerRightCorner.X = middle.LowerRightCorner.X;
|
||||
dest.LowerRightCorner.X -= lower_right_offset.X;
|
||||
src.UpperLeftCorner.X += middle.UpperLeftCorner.X;
|
||||
src.LowerRightCorner.X -= lower_right_offset.X;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
dest.UpperLeftCorner.X = rect.LowerRightCorner.X - lowerRightOffset.X;
|
||||
src.UpperLeftCorner.X = middle.LowerRightCorner.X;
|
||||
dest.UpperLeftCorner.X = destrect.LowerRightCorner.X - lower_right_offset.X;
|
||||
src.UpperLeftCorner.X = srcrect.LowerRightCorner.X - lower_right_offset.X;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (y) {
|
||||
case 0:
|
||||
dest.LowerRightCorner.Y = rect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
|
||||
src.LowerRightCorner.Y = middle.UpperLeftCorner.Y;
|
||||
dest.LowerRightCorner.Y = destrect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
|
||||
src.LowerRightCorner.Y = srcrect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
dest.UpperLeftCorner.Y += middle.UpperLeftCorner.Y;
|
||||
dest.LowerRightCorner.Y -= lowerRightOffset.Y;
|
||||
src.UpperLeftCorner.Y = middle.UpperLeftCorner.Y;
|
||||
src.LowerRightCorner.Y = middle.LowerRightCorner.Y;
|
||||
dest.LowerRightCorner.Y -= lower_right_offset.Y;
|
||||
src.UpperLeftCorner.Y += middle.UpperLeftCorner.Y;
|
||||
src.LowerRightCorner.Y -= lower_right_offset.Y;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
dest.UpperLeftCorner.Y = rect.LowerRightCorner.Y - lowerRightOffset.Y;
|
||||
src.UpperLeftCorner.Y = middle.LowerRightCorner.Y;
|
||||
dest.UpperLeftCorner.Y = destrect.LowerRightCorner.Y - lower_right_offset.Y;
|
||||
src.UpperLeftCorner.Y = srcrect.LowerRightCorner.Y - lower_right_offset.Y;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -46,13 +46,13 @@ video::ITexture *guiScalingImageButton(video::IVideoDriver *driver, video::IText
|
||||
*/
|
||||
void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
|
||||
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
|
||||
const core::rect<s32> *cliprect = 0, const video::SColor *const colors = 0,
|
||||
bool usealpha = false);
|
||||
const core::rect<s32> *cliprect = nullptr,
|
||||
const video::SColor *const colors = nullptr, bool usealpha = false);
|
||||
|
||||
/*
|
||||
* 9-slice / segment drawing
|
||||
*/
|
||||
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
|
||||
const core::rect<s32> &rect, const core::rect<s32> &middle,
|
||||
const core::rect<s32> *cliprect = nullptr,
|
||||
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
|
||||
const core::rect<s32> &middlerect, const core::rect<s32> *cliprect = nullptr,
|
||||
const video::SColor *const colors = nullptr);
|
||||
|
@ -44,8 +44,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "gui/touchscreengui.h"
|
||||
#endif
|
||||
|
||||
#define OBJECT_CROSSHAIR_LINE_SIZE 8
|
||||
#define CROSSHAIR_LINE_SIZE 10
|
||||
#define OBJECT_CROSSHAIR_LINE_SIZE 16
|
||||
#define CROSSHAIR_LINE_SIZE 16
|
||||
|
||||
Hud::Hud(Client *client, LocalPlayer *player,
|
||||
Inventory *inventory)
|
||||
@ -61,6 +61,7 @@ Hud::Hud(Client *client, LocalPlayer *player,
|
||||
RenderingEngine::getDisplayDensity() + 0.5f);
|
||||
m_hotbar_imagesize *= m_hud_scaling;
|
||||
m_padding = m_hotbar_imagesize / 12;
|
||||
m_hud_move_upwards = g_settings->getU16("hud_move_upwards");
|
||||
|
||||
for (auto &hbar_color : hbar_colors)
|
||||
hbar_color = video::SColor(255, 255, 255, 255);
|
||||
@ -109,7 +110,7 @@ Hud::Hud(Client *client, LocalPlayer *player,
|
||||
|
||||
if (m_mode == HIGHLIGHT_BOX) {
|
||||
m_selection_material.Thickness =
|
||||
rangelim(g_settings->getS16("selectionbox_width"), 1, 5);
|
||||
rangelim(g_settings->getS16("selectionbox_width"), 1, 6);
|
||||
} else if (m_mode == HIGHLIGHT_HALO) {
|
||||
m_selection_material.setTexture(0, tsrc->getTextureForMesh("halo.png"));
|
||||
m_selection_material.setFlag(video::EMF_BACK_FACE_CULLING, true);
|
||||
@ -360,10 +361,12 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
|
||||
floor(e->pos.Y * (float) m_screensize.Y + 0.5));
|
||||
switch (e->type) {
|
||||
case HUD_ELEM_TEXT: {
|
||||
unsigned int font_size = g_fontengine->getDefaultFontSize();
|
||||
float font_size = g_fontengine->getDefaultFontSize();
|
||||
|
||||
if (e->size.X > 0)
|
||||
font_size *= e->size.X;
|
||||
else if (e->size.Y > 0)
|
||||
font_size = MYMAX(font_size * (float) e->size.Y / 100, 1.0f);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// The text size on Android is not proportional with the actual scaling
|
||||
@ -448,14 +451,19 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
|
||||
const video::SColor color(255, 255, 255, 255);
|
||||
const video::SColor colors[] = {color, color, color, color};
|
||||
core::dimension2di imgsize(texture->getOriginalSize());
|
||||
v2s32 dstsize(imgsize.Width * e->scale.X * m_scale_factor,
|
||||
imgsize.Height * e->scale.Y * m_scale_factor);
|
||||
v2s32 dstsize(imgsize.Width * e->scale.X,
|
||||
imgsize.Height * e->scale.Y);
|
||||
if (e->scale.X < 0)
|
||||
dstsize.X = m_screensize.X * (e->scale.X * -0.01);
|
||||
if (e->scale.Y < 0)
|
||||
dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
|
||||
dstsize.X *= m_scale_factor;
|
||||
dstsize.Y *= m_scale_factor;
|
||||
v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
|
||||
(e->align.Y - 1.0) * dstsize.Y / 2);
|
||||
|
||||
if ((dstsize.Y + pos.Y + offset.Y + e->offset.Y * m_scale_factor) > m_displaycenter.Y)
|
||||
offset.Y -= m_hud_move_upwards;
|
||||
core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
|
||||
rect += pos + offset + v2s32(e->offset.X * m_scale_factor,
|
||||
e->offset.Y * m_scale_factor);
|
||||
@ -619,19 +627,19 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
|
||||
}
|
||||
|
||||
core::dimension2di srcd(stat_texture->getOriginalSize());
|
||||
core::dimension2di srcd_bg = stat_texture_bg ? core::dimension2di(stat_texture_bg->getOriginalSize()) : srcd;
|
||||
core::dimension2di dstd;
|
||||
if (size == v2s32()) {
|
||||
dstd = srcd;
|
||||
dstd.Height *= m_scale_factor;
|
||||
dstd.Width *= m_scale_factor;
|
||||
offset.X *= m_scale_factor;
|
||||
offset.Y *= m_scale_factor;
|
||||
} else {
|
||||
dstd.Height = size.Y * m_scale_factor;
|
||||
dstd.Width = size.X * m_scale_factor;
|
||||
}
|
||||
|
||||
offset.X *= m_scale_factor;
|
||||
offset.Y *= m_scale_factor;
|
||||
}
|
||||
|
||||
v2s32 p = pos;
|
||||
if (corner & HUD_CORNER_LOWER)
|
||||
@ -639,6 +647,9 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
|
||||
|
||||
p += offset;
|
||||
|
||||
if ((pos.Y + offset.Y) > m_displaycenter.Y)
|
||||
p.Y -= m_hud_move_upwards;
|
||||
|
||||
v2s32 steppos;
|
||||
switch (drawdir) {
|
||||
case HUD_DIR_RIGHT_LEFT:
|
||||
@ -680,7 +691,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
|
||||
// Need to draw halves: Calculate rectangles
|
||||
srchalfrect = calculate_clipping_rect(srcd, steppos);
|
||||
dsthalfrect = calculate_clipping_rect(dstd, steppos);
|
||||
srchalfrect2 = calculate_clipping_rect(srcd, steppos * -1);
|
||||
srchalfrect2 = calculate_clipping_rect(srcd_bg, steppos * -1);
|
||||
dsthalfrect2 = calculate_clipping_rect(dstd, steppos * -1);
|
||||
}
|
||||
|
||||
@ -719,7 +730,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
|
||||
else
|
||||
start_offset = count / 2;
|
||||
for (s32 i = start_offset; i < maxcount / 2; i++) {
|
||||
core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
|
||||
core::rect<s32> srcrect(0, 0, srcd_bg.Width, srcd_bg.Height);
|
||||
core::rect<s32> dstrect(0, 0, dstd.Width, dstd.Height);
|
||||
|
||||
dstrect += p;
|
||||
@ -731,7 +742,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
|
||||
|
||||
if (maxcount % 2 == 1) {
|
||||
draw2DImageFilterScaled(driver, stat_texture_bg,
|
||||
dsthalfrect + p, srchalfrect,
|
||||
dsthalfrect + p, calculate_clipping_rect(srcd_bg, steppos),
|
||||
NULL, colors, true);
|
||||
}
|
||||
}
|
||||
@ -750,7 +761,8 @@ void Hud::drawHotbar(u16 playeritem) {
|
||||
|
||||
s32 hotbar_itemcount = player->hud_hotbar_itemcount;
|
||||
s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
|
||||
v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
|
||||
v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 2.4);
|
||||
pos.Y -= m_hud_move_upwards;
|
||||
|
||||
const v2u32 &window_size = RenderingEngine::getWindowSize();
|
||||
if ((float) width / (float) window_size.X <=
|
||||
@ -777,43 +789,49 @@ void Hud::drawHotbar(u16 playeritem) {
|
||||
void Hud::drawCrosshair()
|
||||
{
|
||||
if (pointing_at_object) {
|
||||
int obj_crosshair_size = (int) (OBJECT_CROSSHAIR_LINE_SIZE * m_scale_factor);
|
||||
if (use_object_crosshair_image) {
|
||||
video::ITexture *object_crosshair = tsrc->getTexture("object_crosshair.png");
|
||||
v2u32 size = object_crosshair->getOriginalSize();
|
||||
v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
|
||||
m_displaycenter.Y - (size.Y / 2));
|
||||
driver->draw2DImage(object_crosshair, lsize,
|
||||
core::rect<s32>(0, 0, size.X, size.Y),
|
||||
nullptr, crosshair_argb, true);
|
||||
core::rect<s32> rect(m_displaycenter.X - obj_crosshair_size,
|
||||
m_displaycenter.Y - obj_crosshair_size,
|
||||
m_displaycenter.X + obj_crosshair_size,
|
||||
m_displaycenter.Y + obj_crosshair_size);
|
||||
video::SColor crosshair_color[] = {crosshair_argb, crosshair_argb,
|
||||
crosshair_argb, crosshair_argb};
|
||||
draw2DImageFilterScaled(driver, object_crosshair, rect,
|
||||
core::rect<s32>({0, 0}, object_crosshair->getOriginalSize()),
|
||||
nullptr, crosshair_color, true);
|
||||
} else {
|
||||
driver->draw2DLine(
|
||||
m_displaycenter - v2s32(OBJECT_CROSSHAIR_LINE_SIZE,
|
||||
OBJECT_CROSSHAIR_LINE_SIZE),
|
||||
m_displaycenter + v2s32(OBJECT_CROSSHAIR_LINE_SIZE,
|
||||
OBJECT_CROSSHAIR_LINE_SIZE), crosshair_argb);
|
||||
m_displaycenter - v2s32(obj_crosshair_size, obj_crosshair_size),
|
||||
m_displaycenter + v2s32(obj_crosshair_size, obj_crosshair_size),
|
||||
crosshair_argb);
|
||||
driver->draw2DLine(
|
||||
m_displaycenter + v2s32(OBJECT_CROSSHAIR_LINE_SIZE,
|
||||
-OBJECT_CROSSHAIR_LINE_SIZE),
|
||||
m_displaycenter + v2s32(-OBJECT_CROSSHAIR_LINE_SIZE,
|
||||
OBJECT_CROSSHAIR_LINE_SIZE), crosshair_argb);
|
||||
m_displaycenter + v2s32(obj_crosshair_size, -obj_crosshair_size),
|
||||
m_displaycenter + v2s32(-obj_crosshair_size, obj_crosshair_size),
|
||||
crosshair_argb);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int crosshair_size = (int) (CROSSHAIR_LINE_SIZE * m_scale_factor);
|
||||
if (use_crosshair_image) {
|
||||
video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
|
||||
v2u32 size = crosshair->getOriginalSize();
|
||||
v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
|
||||
m_displaycenter.Y - (size.Y / 2));
|
||||
driver->draw2DImage(crosshair, lsize,
|
||||
core::rect<s32>(0, 0, size.X, size.Y),
|
||||
nullptr, crosshair_argb, true);
|
||||
core::rect<s32> rect(m_displaycenter.X - crosshair_size,
|
||||
m_displaycenter.Y - crosshair_size,
|
||||
m_displaycenter.X + crosshair_size,
|
||||
m_displaycenter.Y + crosshair_size);
|
||||
video::SColor crosshair_color[] = {crosshair_argb, crosshair_argb,
|
||||
crosshair_argb, crosshair_argb};
|
||||
draw2DImageFilterScaled(driver, crosshair, rect,
|
||||
core::rect<s32>({0, 0}, crosshair->getOriginalSize()),
|
||||
nullptr, crosshair_color, true);
|
||||
} else {
|
||||
driver->draw2DLine(m_displaycenter - v2s32(CROSSHAIR_LINE_SIZE, 0),
|
||||
m_displaycenter + v2s32(CROSSHAIR_LINE_SIZE, 0), crosshair_argb);
|
||||
driver->draw2DLine(m_displaycenter - v2s32(0, CROSSHAIR_LINE_SIZE),
|
||||
m_displaycenter + v2s32(0, CROSSHAIR_LINE_SIZE), crosshair_argb);
|
||||
driver->draw2DLine(m_displaycenter - v2s32(crosshair_size, 0),
|
||||
m_displaycenter + v2s32(crosshair_size, 0), crosshair_argb);
|
||||
driver->draw2DLine(m_displaycenter - v2s32(0, crosshair_size),
|
||||
m_displaycenter + v2s32(0, crosshair_size), crosshair_argb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,6 +120,7 @@ private:
|
||||
v2s32 m_displaycenter;
|
||||
s32 m_hotbar_imagesize; // Takes hud_scaling into account, updated by resizeHotbar()
|
||||
s32 m_padding; // Takes hud_scaling into account, updated by resizeHotbar()
|
||||
s32 m_hud_move_upwards;
|
||||
video::SColor hbar_colors[4];
|
||||
|
||||
std::vector<aabb3f> m_selection_boxes;
|
||||
|
@ -20,8 +20,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "util/numeric.h"
|
||||
#include "inputhandler.h"
|
||||
#include "gui/guiChatConsole.h"
|
||||
#include "gui/mainmenumanager.h"
|
||||
#include "hud.h"
|
||||
#include "settings.h"
|
||||
|
||||
#ifdef __IOS__
|
||||
#include "porting_ios.h"
|
||||
extern "C" void external_pause_game();
|
||||
#endif
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
void KeyCache::populate_nonchanging()
|
||||
{
|
||||
@ -98,13 +109,57 @@ void KeyCache::populate()
|
||||
|
||||
bool MyEventReceiver::OnEvent(const SEvent &event)
|
||||
{
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
if (event.EventType == irr::EET_SDL_CONTROLLER_BUTTON_EVENT ||
|
||||
event.EventType == irr::EET_SDL_CONTROLLER_AXIS_EVENT) {
|
||||
if (g_settings->getBool("enable_joysticks")) {
|
||||
sdl_game_controller->translateEvent(event);
|
||||
input->setCursorVisible(sdl_game_controller->isCursorVisible());
|
||||
}
|
||||
} else if ((event.EventType == irr::EET_MOUSE_INPUT_EVENT &&
|
||||
event.MouseInput.Event == irr::EMIE_MOUSE_MOVED) ||
|
||||
event.EventType == irr::EET_TOUCH_INPUT_EVENT) {
|
||||
if (!sdl_game_controller->isFakeEvent() &&
|
||||
sdl_game_controller->isActive()) {
|
||||
sdl_game_controller->setActive(false);
|
||||
input->setCursorVisible(sdl_game_controller->isCursorVisible());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (event.EventType == irr::EET_TOUCH_INPUT_EVENT) {
|
||||
TouchScreenGUI::setActive(true);
|
||||
if (m_touchscreengui && !isMenuActive())
|
||||
m_touchscreengui->show();
|
||||
} else if ((event.EventType == irr::EET_MOUSE_INPUT_EVENT &&
|
||||
event.MouseInput.Event == irr::EMIE_MOUSE_MOVED) ||
|
||||
sdl_game_controller->isActive()) {
|
||||
TouchScreenGUI::setActive(false);
|
||||
if (m_touchscreengui && !isMenuActive())
|
||||
m_touchscreengui->hide();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
if (event.EventType == irr::EET_SDL_CONTROLLER_BUTTON_EVENT)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
GUIChatConsole* chat_console = GUIChatConsole::getChatConsole();
|
||||
if (chat_console && chat_console->isOpen()) {
|
||||
bool result = chat_console->preprocessEvent(event);
|
||||
if (result)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
React to nothing here if a menu is active
|
||||
*/
|
||||
if (isMenuActive()) {
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (m_touchscreengui) {
|
||||
m_touchscreengui->Toggle(false);
|
||||
m_touchscreengui->hide();
|
||||
}
|
||||
#endif
|
||||
return g_menumgr.preprocessEvent(event);
|
||||
@ -137,6 +192,15 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef __IOS__
|
||||
} else if (event.EventType == irr::EET_APPLICATION_EVENT) {
|
||||
int AppEvent = event.ApplicationEvent.EventType;
|
||||
ioswrap_events(AppEvent);
|
||||
if (AppEvent == irr::EAET_WILL_PAUSE)
|
||||
external_pause_game();
|
||||
return true;
|
||||
#endif
|
||||
|
||||
} else if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
|
||||
// joystick may be nullptr if game is launched with '--random-input' parameter
|
||||
return joystick && joystick->handleEvent(event.JoystickEvent);
|
||||
@ -191,8 +255,10 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
|
||||
LL_NONE, // ELL_NONE
|
||||
};
|
||||
assert(event.LogEvent.Level < ARRLEN(irr_loglev_conv));
|
||||
#ifndef NDEBUG
|
||||
g_logger.log(irr_loglev_conv[event.LogEvent.Level],
|
||||
std::string("Irrlicht: ") + event.LogEvent.Text);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
/* always return false in order to continue processing events */
|
||||
|
@ -197,6 +197,11 @@ public:
|
||||
|
||||
JoystickController *joystick = nullptr;
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
SDLGameController* sdl_game_controller = nullptr;
|
||||
InputHandler* input = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
TouchScreenGUI *m_touchscreengui;
|
||||
#endif
|
||||
@ -264,8 +269,13 @@ public:
|
||||
|
||||
virtual void clear() {}
|
||||
|
||||
virtual void setCursorVisible(bool visible) {};
|
||||
|
||||
JoystickController joystick;
|
||||
KeyCache keycache;
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
SDLGameController sdl_game_controller;
|
||||
#endif
|
||||
};
|
||||
/*
|
||||
Separated input handler
|
||||
@ -277,6 +287,10 @@ public:
|
||||
RealInputHandler(MyEventReceiver *receiver) : m_receiver(receiver)
|
||||
{
|
||||
m_receiver->joystick = &joystick;
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
m_receiver->sdl_game_controller = &sdl_game_controller;
|
||||
m_receiver->input = this;
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ~RealInputHandler()
|
||||
@ -389,6 +403,22 @@ public:
|
||||
return m_receiver->getMouseWheel();
|
||||
}
|
||||
|
||||
virtual void setCursorVisible(bool visible)
|
||||
{
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
sdl_game_controller.setCursorVisible(visible);
|
||||
|
||||
if (sdl_game_controller.isActive())
|
||||
visible = false;
|
||||
#endif
|
||||
IrrlichtDevice *device = RenderingEngine::get_raw_device();
|
||||
|
||||
if (device->getCursorControl()) {
|
||||
if (visible != device->getCursorControl()->isVisible())
|
||||
device->getCursorControl()->setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
joystick.clear();
|
||||
|
@ -20,9 +20,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "joystick_controller.h"
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "keys.h"
|
||||
#include "keycode.h"
|
||||
#include "gui/mainmenumanager.h"
|
||||
#include "settings.h"
|
||||
#include "gettime.h"
|
||||
#include "porting.h"
|
||||
#include "renderingengine.h"
|
||||
#include "util/string.h"
|
||||
|
||||
bool JoystickButtonCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
|
||||
@ -326,3 +329,352 @@ float JoystickController::getMovementSpeed()
|
||||
speed = 1.0f;
|
||||
return speed;
|
||||
}
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
bool SDLGameController::m_active = false;
|
||||
bool SDLGameController::m_cursor_visible = false;
|
||||
|
||||
void SDLGameController::handleMouseMovement(int x, int y)
|
||||
{
|
||||
IrrlichtDevice* device = RenderingEngine::get_raw_device();
|
||||
|
||||
bool changed = false;
|
||||
|
||||
u32 current_time = device->getTimer()->getRealTime();
|
||||
v2s32 mouse_pos = device->getCursorControl()->getPosition();
|
||||
int deadzone = g_settings->getU16("joystick_deadzone");
|
||||
|
||||
if (x > deadzone || x < -deadzone) {
|
||||
s32 dt = current_time - m_mouse_time;
|
||||
|
||||
mouse_pos.X += (x * dt / 30000);
|
||||
if (mouse_pos.X < 0)
|
||||
mouse_pos.X = 0;
|
||||
if (mouse_pos.X > device->getVideoDriver()->getScreenSize().Width)
|
||||
mouse_pos.X = device->getVideoDriver()->getScreenSize().Width;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (y > deadzone || y < -deadzone) {
|
||||
s32 dt = current_time - m_mouse_time;
|
||||
|
||||
mouse_pos.Y += (y * dt / 30000);
|
||||
if (mouse_pos.Y < 0)
|
||||
mouse_pos.Y = 0;
|
||||
if (mouse_pos.Y > device->getVideoDriver()->getScreenSize().Height)
|
||||
mouse_pos.Y = device->getVideoDriver()->getScreenSize().Height;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
SEvent translated_event;
|
||||
translated_event.EventType = irr::EET_MOUSE_INPUT_EVENT;
|
||||
translated_event.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
|
||||
translated_event.MouseInput.X = mouse_pos.X;
|
||||
translated_event.MouseInput.Y = mouse_pos.Y;
|
||||
translated_event.MouseInput.Control = false;
|
||||
translated_event.MouseInput.Shift = false;
|
||||
translated_event.MouseInput.ButtonStates = m_button_states;
|
||||
|
||||
sendEvent(translated_event);
|
||||
device->getCursorControl()->setPosition(mouse_pos.X, mouse_pos.Y);
|
||||
}
|
||||
|
||||
m_mouse_time = current_time;
|
||||
}
|
||||
|
||||
void SDLGameController::handleTriggerLeft(s16 value)
|
||||
{
|
||||
IrrlichtDevice* device = RenderingEngine::get_raw_device();
|
||||
|
||||
int deadzone = g_settings->getU16("joystick_deadzone");
|
||||
|
||||
SEvent translated_event;
|
||||
translated_event.EventType = irr::EET_KEY_INPUT_EVENT;
|
||||
translated_event.KeyInput.Char = 0;
|
||||
translated_event.KeyInput.Key = getKeySetting("keymap_hotbar_previous").getKeyCode();
|
||||
translated_event.KeyInput.Shift = false;
|
||||
translated_event.KeyInput.Control = false;
|
||||
|
||||
if (value <= deadzone && m_trigger_left_value > deadzone) {
|
||||
translated_event.KeyInput.PressedDown = false;
|
||||
sendEvent(translated_event);
|
||||
} else if (value > deadzone && m_trigger_left_value <= deadzone) {
|
||||
translated_event.KeyInput.PressedDown = true;
|
||||
sendEvent(translated_event);
|
||||
}
|
||||
|
||||
m_trigger_left_value = value;
|
||||
}
|
||||
|
||||
void SDLGameController::handleTriggerRight(s16 value)
|
||||
{
|
||||
IrrlichtDevice* device = RenderingEngine::get_raw_device();
|
||||
|
||||
int deadzone = g_settings->getU16("joystick_deadzone");
|
||||
|
||||
SEvent translated_event;
|
||||
translated_event.EventType = irr::EET_KEY_INPUT_EVENT;
|
||||
translated_event.KeyInput.Char = 0;
|
||||
translated_event.KeyInput.Key = getKeySetting("keymap_hotbar_next").getKeyCode();
|
||||
translated_event.KeyInput.Shift = false;
|
||||
translated_event.KeyInput.Control = false;
|
||||
|
||||
if (value <= deadzone && m_trigger_right_value > deadzone) {
|
||||
translated_event.KeyInput.PressedDown = false;
|
||||
sendEvent(translated_event);
|
||||
} else if (value > deadzone && m_trigger_right_value <= deadzone) {
|
||||
translated_event.KeyInput.PressedDown = true;
|
||||
sendEvent(translated_event);
|
||||
}
|
||||
|
||||
m_trigger_right_value = value;
|
||||
}
|
||||
|
||||
void SDLGameController::handleMouseClickLeft(bool pressed)
|
||||
{
|
||||
IrrlichtDevice* device = RenderingEngine::get_raw_device();
|
||||
|
||||
v2s32 mouse_pos = device->getCursorControl()->getPosition();
|
||||
|
||||
if (pressed)
|
||||
m_button_states |= irr::EMBSM_LEFT;
|
||||
else
|
||||
m_button_states &= ~irr::EMBSM_LEFT;
|
||||
|
||||
SEvent translated_event;
|
||||
translated_event.EventType = irr::EET_MOUSE_INPUT_EVENT;
|
||||
translated_event.MouseInput.Event = pressed ? irr::EMIE_LMOUSE_PRESSED_DOWN : irr::EMIE_LMOUSE_LEFT_UP;
|
||||
translated_event.MouseInput.X = mouse_pos.X;
|
||||
translated_event.MouseInput.Y = mouse_pos.Y;
|
||||
translated_event.MouseInput.Control = false;
|
||||
translated_event.MouseInput.Shift = false;
|
||||
translated_event.MouseInput.ButtonStates = m_button_states;
|
||||
|
||||
sendEvent(translated_event);
|
||||
}
|
||||
|
||||
void SDLGameController::handleMouseClickRight(bool pressed)
|
||||
{
|
||||
IrrlichtDevice* device = RenderingEngine::get_raw_device();
|
||||
|
||||
v2s32 mouse_pos = device->getCursorControl()->getPosition();
|
||||
|
||||
if (pressed)
|
||||
m_button_states |= irr::EMBSM_RIGHT;
|
||||
else
|
||||
m_button_states &= ~irr::EMBSM_RIGHT;
|
||||
|
||||
SEvent translated_event;
|
||||
translated_event.EventType = irr::EET_MOUSE_INPUT_EVENT;
|
||||
translated_event.MouseInput.Event = pressed ? irr::EMIE_RMOUSE_PRESSED_DOWN : irr::EMIE_RMOUSE_LEFT_UP;
|
||||
translated_event.MouseInput.X = mouse_pos.X;
|
||||
translated_event.MouseInput.Y = mouse_pos.Y;
|
||||
translated_event.MouseInput.Control = false;
|
||||
translated_event.MouseInput.Shift = false;
|
||||
translated_event.MouseInput.ButtonStates = m_button_states;
|
||||
|
||||
sendEvent(translated_event);
|
||||
}
|
||||
|
||||
void SDLGameController::handleButton(const SEvent &event)
|
||||
{
|
||||
irr::EKEY_CODE key = KEY_UNKNOWN;
|
||||
|
||||
switch (event.SDLControllerButtonEvent.Button) {
|
||||
case SDL_CONTROLLER_BUTTON_A:
|
||||
key = getKeySetting("keymap_jump").getKeyCode();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_B:
|
||||
key = getKeySetting("keymap_sneak").getKeyCode();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_X:
|
||||
key = getKeySetting("keymap_special1").getKeyCode();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_Y:
|
||||
key = getKeySetting("keymap_minimap").getKeyCode();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_BACK:
|
||||
key = getKeySetting("keymap_chat").getKeyCode();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_GUIDE:
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_START:
|
||||
key = KEY_ESCAPE;
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
|
||||
key = getKeySetting("keymap_camera_mode").getKeyCode();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
|
||||
key = KEY_LBUTTON;
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
|
||||
key = KEY_LBUTTON;
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
|
||||
key = KEY_RBUTTON;
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
||||
key = getKeySetting("keymap_rangeselect").getKeyCode();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||
key = getKeySetting("keymap_drop").getKeyCode();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||
key = KEY_ESCAPE;
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||
key = getKeySetting("keymap_inventory").getKeyCode();
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_MISC1:
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE1:
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE2:
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE3:
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE4:
|
||||
case SDL_CONTROLLER_BUTTON_TOUCHPAD:
|
||||
break;
|
||||
}
|
||||
|
||||
if (key != KEY_UNKNOWN) {
|
||||
SEvent translated_event;
|
||||
translated_event.EventType = irr::EET_KEY_INPUT_EVENT;
|
||||
translated_event.KeyInput.Char = 0;
|
||||
translated_event.KeyInput.Key = key;
|
||||
translated_event.KeyInput.PressedDown = event.SDLControllerButtonEvent.Pressed;
|
||||
translated_event.KeyInput.Shift = false;
|
||||
translated_event.KeyInput.Control = false;
|
||||
|
||||
sendEvent(translated_event);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLGameController::handleButtonInMenu(const SEvent &event)
|
||||
{
|
||||
irr::EKEY_CODE key = KEY_UNKNOWN;
|
||||
|
||||
// Just used game mapping for escape key for now
|
||||
switch (event.SDLControllerButtonEvent.Button) {
|
||||
case SDL_CONTROLLER_BUTTON_A:
|
||||
case SDL_CONTROLLER_BUTTON_B:
|
||||
case SDL_CONTROLLER_BUTTON_X:
|
||||
case SDL_CONTROLLER_BUTTON_Y:
|
||||
case SDL_CONTROLLER_BUTTON_BACK:
|
||||
case SDL_CONTROLLER_BUTTON_GUIDE:
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_START:
|
||||
key = KEY_ESCAPE;
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
|
||||
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
|
||||
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||
key = KEY_ESCAPE;
|
||||
break;
|
||||
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||
case SDL_CONTROLLER_BUTTON_MISC1:
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE1:
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE2:
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE3:
|
||||
case SDL_CONTROLLER_BUTTON_PADDLE4:
|
||||
case SDL_CONTROLLER_BUTTON_TOUCHPAD:
|
||||
break;
|
||||
}
|
||||
|
||||
if (key != KEY_UNKNOWN) {
|
||||
SEvent translated_event;
|
||||
translated_event.EventType = irr::EET_KEY_INPUT_EVENT;
|
||||
translated_event.KeyInput.Char = 0;
|
||||
translated_event.KeyInput.Key = key;
|
||||
translated_event.KeyInput.PressedDown = event.SDLControllerButtonEvent.Pressed;
|
||||
translated_event.KeyInput.Shift = false;
|
||||
translated_event.KeyInput.Control = false;
|
||||
|
||||
sendEvent(translated_event);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLGameController::handlePlayerMovement(int x, int y)
|
||||
{
|
||||
int deadzone = g_settings->getU16("joystick_deadzone");
|
||||
|
||||
m_move_sideward = x;
|
||||
if (m_move_sideward < deadzone && m_move_sideward > -deadzone)
|
||||
m_move_sideward = 0;
|
||||
else
|
||||
m_active = true;
|
||||
|
||||
m_move_forward = y;
|
||||
if (m_move_forward < deadzone && m_move_forward > -deadzone)
|
||||
m_move_forward = 0;
|
||||
else
|
||||
m_active = true;
|
||||
}
|
||||
|
||||
void SDLGameController::handleCameraOrientation(int x, int y)
|
||||
{
|
||||
int deadzone = g_settings->getU16("joystick_deadzone");
|
||||
|
||||
m_camera_yaw = x;
|
||||
if (m_camera_yaw < deadzone && m_camera_yaw > -deadzone)
|
||||
m_camera_yaw = 0;
|
||||
else
|
||||
m_active = true;
|
||||
|
||||
m_camera_pitch = y;
|
||||
if (m_camera_pitch < deadzone && m_camera_pitch > -deadzone)
|
||||
m_camera_pitch = 0;
|
||||
else
|
||||
m_active = true;
|
||||
}
|
||||
|
||||
void SDLGameController::sendEvent(const SEvent &event)
|
||||
{
|
||||
m_active = true;
|
||||
m_is_fake_event = true;
|
||||
IrrlichtDevice* device = RenderingEngine::get_raw_device();
|
||||
device->postEventFromUser(event);
|
||||
m_is_fake_event = false;
|
||||
}
|
||||
|
||||
void SDLGameController::translateEvent(const SEvent &event)
|
||||
{
|
||||
if (event.EventType == irr::EET_SDL_CONTROLLER_BUTTON_EVENT) {
|
||||
if (isMenuActive()) {
|
||||
if (event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSTICK ||
|
||||
event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
||||
handleMouseClickLeft(event.SDLControllerButtonEvent.Pressed);
|
||||
} else if (event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
||||
handleMouseClickRight(event.SDLControllerButtonEvent.Pressed);
|
||||
} else {
|
||||
handleButtonInMenu(event);
|
||||
}
|
||||
} else {
|
||||
if (event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_RIGHTSTICK ||
|
||||
event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
||||
handleMouseClickLeft(event.SDLControllerButtonEvent.Pressed);
|
||||
} else if (event.SDLControllerButtonEvent.Button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
|
||||
handleMouseClickRight(event.SDLControllerButtonEvent.Pressed);
|
||||
} else {
|
||||
handleButton(event);
|
||||
}
|
||||
}
|
||||
} else if (event.EventType == irr::EET_SDL_CONTROLLER_AXIS_EVENT) {
|
||||
const s16* value = event.SDLControllerAxisEvent.Value;
|
||||
|
||||
if (isMenuActive()) {
|
||||
handleMouseMovement(value[SDL_CONTROLLER_AXIS_LEFTX], value[SDL_CONTROLLER_AXIS_LEFTY]);
|
||||
} else {
|
||||
handleTriggerLeft(value[SDL_CONTROLLER_AXIS_TRIGGERLEFT]);
|
||||
handleTriggerRight(value[SDL_CONTROLLER_AXIS_TRIGGERRIGHT]);
|
||||
handlePlayerMovement(value[SDL_CONTROLLER_AXIS_LEFTX], value[SDL_CONTROLLER_AXIS_LEFTY]);
|
||||
handleCameraOrientation(value[SDL_CONTROLLER_AXIS_RIGHTX], value[SDL_CONTROLLER_AXIS_RIGHTY]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -170,3 +170,47 @@ private:
|
||||
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_keys_pressed;
|
||||
std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_keys_released;
|
||||
};
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
class SDLGameController
|
||||
{
|
||||
private:
|
||||
void handleMouseMovement(int x, int y);
|
||||
void handleTriggerLeft(s16 value);
|
||||
void handleTriggerRight(s16 value);
|
||||
void handleMouseClickLeft(bool pressed);
|
||||
void handleMouseClickRight(bool pressed);
|
||||
void handleButton(const SEvent &event);
|
||||
void handleButtonInMenu(const SEvent &event);
|
||||
void handlePlayerMovement(int x, int y);
|
||||
void handleCameraOrientation(int x, int y);
|
||||
void sendEvent(const SEvent &event);
|
||||
|
||||
int m_button_states = 0;
|
||||
u32 m_mouse_time = 0;
|
||||
s16 m_trigger_left_value = 0;
|
||||
s16 m_trigger_right_value = 0;
|
||||
s16 m_move_sideward = 0;
|
||||
s16 m_move_forward = 0;
|
||||
s16 m_camera_yaw = 0;
|
||||
s16 m_camera_pitch = 0;
|
||||
|
||||
static bool m_active;
|
||||
static bool m_cursor_visible;
|
||||
bool m_is_fake_event = false;
|
||||
|
||||
public:
|
||||
void translateEvent(const SEvent &event);
|
||||
|
||||
s16 getMoveSideward() { return m_move_sideward; }
|
||||
s16 getMoveForward() { return m_move_forward; }
|
||||
s16 getCameraYaw() { return m_camera_yaw; }
|
||||
s16 getCameraPitch() { return m_camera_pitch; }
|
||||
|
||||
void setActive(bool value) { m_active = value; }
|
||||
static bool isActive() { return m_active; }
|
||||
void setCursorVisible(bool visible) { m_cursor_visible = visible; }
|
||||
static bool isCursorVisible() { return m_cursor_visible; }
|
||||
bool isFakeEvent() { return m_is_fake_event; }
|
||||
};
|
||||
#endif
|
||||
|
@ -44,6 +44,8 @@ public:
|
||||
const char *sym() const;
|
||||
const char *name() const;
|
||||
|
||||
irr::EKEY_CODE getKeyCode() { return Key; }
|
||||
|
||||
protected:
|
||||
static bool valid_kcode(irr::EKEY_CODE k)
|
||||
{
|
||||
|
@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "map.h"
|
||||
#include "client.h"
|
||||
#include "content_cao.h"
|
||||
#include "client/joystick_controller.h"
|
||||
#include "gui/touchscreengui.h"
|
||||
|
||||
/*
|
||||
LocalPlayer
|
||||
@ -172,11 +174,13 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
if (!collision_info || collision_info->empty())
|
||||
m_standing_node = floatToInt(m_position, BS);
|
||||
|
||||
#if 0
|
||||
// Temporary option for old move code
|
||||
if (!physics_override_new_move) {
|
||||
old_move(dtime, env, pos_max_d, collision_info);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Map *map = &env->getMap();
|
||||
const NodeDefManager *nodemgr = m_client->ndef();
|
||||
@ -292,6 +296,11 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
float player_stepheight = (m_cao == nullptr) ? 0.0f :
|
||||
(touching_ground ? m_cao->getStepHeight() : (0.2f * BS));
|
||||
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (TouchScreenGUI::isActive() && touching_ground)
|
||||
player_stepheight += (0.6f * BS);
|
||||
#endif
|
||||
|
||||
v3f accel_f;
|
||||
const v3f initial_position = position;
|
||||
const v3f initial_speed = m_speed;
|
||||
@ -423,7 +432,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
m_client->getEventManager()->put(new SimpleTriggerEvent(MtEvent::PLAYER_REGAIN_GROUND));
|
||||
|
||||
// Set camera impact value to be used for view bobbing
|
||||
camera_impact = getSpeed().Y * -1;
|
||||
camera_impact = -initial_speed.Y;
|
||||
}
|
||||
|
||||
{
|
||||
@ -627,6 +636,18 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
|
||||
|
||||
speedH *= control.movement_speed; /* Apply analog input */
|
||||
|
||||
if (!free_move && !in_liquid && !in_liquid_stable && !getParent() && (physics_override_speed != 0)) {
|
||||
if (!m_sneak_offset && control.sneak) {
|
||||
eye_offset_first.Y -= 3.0f;
|
||||
eye_offset_third.Y -= 3.0f;
|
||||
m_sneak_offset = true;
|
||||
} else if (m_sneak_offset && !control.sneak) {
|
||||
eye_offset_first.Y += 3.0f;
|
||||
eye_offset_third.Y += 3.0f;
|
||||
m_sneak_offset = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Acceleration increase
|
||||
f32 incH = 0.0f; // Horizontal (X, Z)
|
||||
f32 incV = 0.0f; // Vertical (Y)
|
||||
@ -646,11 +667,18 @@ void LocalPlayer::applyControl(float dtime, Environment *env)
|
||||
}
|
||||
|
||||
float slip_factor = 1.0f;
|
||||
if (!free_move && !in_liquid && !in_liquid_stable)
|
||||
float speed_factor = 1.0f;
|
||||
if (!free_move && !in_liquid && !in_liquid_stable) {
|
||||
slip_factor = getSlipFactor(env, speedH);
|
||||
speed_factor = getSpeedFactor(env);
|
||||
}
|
||||
|
||||
// Don't sink when swimming in pitch mode
|
||||
if (pitch_move && in_liquid) {
|
||||
// Apply speed factor
|
||||
speedH *= speed_factor;
|
||||
speedV *= speed_factor;
|
||||
|
||||
// Don't sink when swimming
|
||||
if (in_liquid) {
|
||||
v3f controlSpeed = speedH + speedV;
|
||||
if (controlSpeed.getLength() > 0.01f)
|
||||
swimming_pitch = true;
|
||||
@ -751,6 +779,7 @@ void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H,
|
||||
m_speed += d;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Temporary option for old move code
|
||||
void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
std::vector<CollisionInfo> *collision_info)
|
||||
@ -888,6 +917,11 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
// TODO: This shouldn't be hardcoded but decided by the server
|
||||
float player_stepheight = touching_ground ? (BS * 0.6f) : (BS * 0.2f);
|
||||
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (TouchScreenGUI::isActive())
|
||||
player_stepheight += (0.6 * BS);
|
||||
#endif
|
||||
|
||||
v3f accel_f;
|
||||
const v3f initial_position = position;
|
||||
const v3f initial_speed = m_speed;
|
||||
@ -953,7 +987,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
std::fabs(player_p2df.Y - node_p2df.Y));
|
||||
|
||||
if (distance_f > min_distance_f ||
|
||||
max_axis_distance_f > 0.5f * BS + sneak_max + 0.1f * BS)
|
||||
max_axis_distance_f > 0.5f * BS + sneak_max + 0.05f * BS)
|
||||
continue;
|
||||
|
||||
// The node to be sneaked on has to be walkable
|
||||
@ -1065,6 +1099,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d,
|
||||
// Autojump
|
||||
handleAutojump(dtime, env, result, initial_position, initial_speed, pos_max_d);
|
||||
}
|
||||
#endif
|
||||
|
||||
float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
|
||||
{
|
||||
@ -1085,12 +1120,53 @@ float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float LocalPlayer::getSpeedFactor(Environment *env)
|
||||
{
|
||||
int speed_below = 0, speed_above = 0;
|
||||
v3s16 pos = getStandingNodePos();
|
||||
const NodeDefManager *nodemgr = env->getGameDef()->ndef();
|
||||
Map *map = &env->getMap();
|
||||
|
||||
const ContentFeatures &f = nodemgr->get(map->getNode(pos));
|
||||
if (f.walkable)
|
||||
speed_below = itemgroup_get(f.groups, "speed");
|
||||
|
||||
const ContentFeatures &f2 = nodemgr->get(map->getNode(
|
||||
pos + v3s16(0, 1, 0)));
|
||||
speed_above = itemgroup_get(f2.groups, "speed");
|
||||
|
||||
if (speed_above == 0) {
|
||||
const ContentFeatures &f3 = nodemgr->get(map->getNode(
|
||||
pos + v3s16(0, 2, 0)));
|
||||
speed_above = itemgroup_get(f3.groups, "speed");
|
||||
}
|
||||
|
||||
int speed = speed_below + speed_above;
|
||||
if (speed != 0)
|
||||
return core::clamp(1.0f + f32(speed) / 100.f, 0.01f, 10.f);
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
void LocalPlayer::handleAutojump(f32 dtime, Environment *env,
|
||||
const collisionMoveResult &result, const v3f &initial_position,
|
||||
const v3f &initial_speed, f32 pos_max_d)
|
||||
{
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
// Touchscreen uses player_stepheight for autojump
|
||||
if (TouchScreenGUI::isActive())
|
||||
return;
|
||||
#endif
|
||||
|
||||
PlayerSettings &player_settings = getPlayerSettings();
|
||||
if (!player_settings.autojump)
|
||||
bool autojump_enabled = player_settings.autojump;
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
// Force autojump on gamepad
|
||||
autojump_enabled |= SDLGameController::isActive();
|
||||
#endif
|
||||
|
||||
if (!autojump_enabled)
|
||||
return;
|
||||
|
||||
if (m_autojump)
|
||||
|
@ -163,6 +163,7 @@ private:
|
||||
const f32 max_increase_V, const bool use_pitch);
|
||||
bool updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max);
|
||||
float getSlipFactor(Environment *env, const v3f &speedH);
|
||||
float getSpeedFactor(Environment *env);
|
||||
void handleAutojump(f32 dtime, Environment *env,
|
||||
const collisionMoveResult &result,
|
||||
const v3f &position_before_move, const v3f &speed_before_move,
|
||||
@ -179,6 +180,7 @@ private:
|
||||
// Whether a "sneak ladder" structure is detected at the players pos
|
||||
// see detectSneakLadder() in the .cpp for more info (always false if disabled)
|
||||
bool m_sneak_ladder_detected = false;
|
||||
bool m_sneak_offset = false;
|
||||
|
||||
// ***** Variables for temporary option of the old move code *****
|
||||
// Stores the max player uplift by m_sneak_node
|
||||
|
@ -1162,9 +1162,6 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
|
||||
material.MaterialType = m_shdrsrc->getShaderInfo(
|
||||
p.layer.shader_id).material;
|
||||
p.layer.applyMaterialOptionsWithShaders(material);
|
||||
if (p.layer.normal_texture)
|
||||
material.setTexture(1, p.layer.normal_texture);
|
||||
material.setTexture(2, p.layer.flags_texture);
|
||||
} else {
|
||||
p.layer.applyMaterialOptions(material);
|
||||
}
|
||||
@ -1267,12 +1264,6 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack,
|
||||
|
||||
const FrameSpec &animation_frame = (*tile.frames)[frame];
|
||||
buf->getMaterial().setTexture(0, animation_frame.texture);
|
||||
if (m_enable_shaders) {
|
||||
if (animation_frame.normal_texture)
|
||||
buf->getMaterial().setTexture(1,
|
||||
animation_frame.normal_texture);
|
||||
buf->getMaterial().setTexture(2, animation_frame.flags_texture);
|
||||
}
|
||||
}
|
||||
|
||||
// Day-night transition
|
||||
|
@ -193,12 +193,18 @@ Minimap::Minimap(Client *client)
|
||||
|
||||
// Initialize minimap modes
|
||||
addMode(MINIMAP_TYPE_OFF);
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
addMode(MINIMAP_TYPE_SURFACE, 256);
|
||||
addMode(MINIMAP_TYPE_SURFACE, 128);
|
||||
#endif
|
||||
addMode(MINIMAP_TYPE_SURFACE, 64);
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
addMode(MINIMAP_TYPE_RADAR, 512);
|
||||
addMode(MINIMAP_TYPE_RADAR, 256);
|
||||
addMode(MINIMAP_TYPE_RADAR, 128);
|
||||
#else
|
||||
addMode(MINIMAP_TYPE_RADAR, 64);
|
||||
#endif
|
||||
|
||||
// Initialize minimap data
|
||||
data = new MinimapData;
|
||||
@ -356,6 +362,9 @@ void Minimap::addMode(MinimapModeDef mode)
|
||||
porting::mt_snprintf(label_buf, sizeof(label_buf),
|
||||
mode.label.c_str(), zoom);
|
||||
mode.label = label_buf;
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
mode.label = mode.label.substr(0, mode.label.find(", "));
|
||||
#endif
|
||||
}
|
||||
|
||||
m_modes.push_back(mode);
|
||||
@ -458,7 +467,7 @@ void Minimap::blitMinimapPixelsToImageSurface(
|
||||
|
||||
map_image->setPixel(x, data->mode.map_size - z - 1, tilecolor);
|
||||
|
||||
u32 h = mmpixel->height;
|
||||
const u32 h = 255; // full bright
|
||||
heightmap_image->setPixel(x,data->mode.map_size - z - 1,
|
||||
video::SColor(255, h, h, h));
|
||||
}
|
||||
@ -518,8 +527,13 @@ video::ITexture *Minimap::getMinimapTexture()
|
||||
if (minimap_mask) {
|
||||
for (s16 y = 0; y < MINIMAP_MAX_SY; y++)
|
||||
for (s16 x = 0; x < MINIMAP_MAX_SX; x++) {
|
||||
const video::SColor &mask_col = minimap_mask->getPixel(x, y);
|
||||
video::SColor mask_col = minimap_mask->getPixel(x, y);
|
||||
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 9
|
||||
// Irrlicht 1.9 has some problem with alpha
|
||||
if (mask_col.getRed() != 255)
|
||||
#else
|
||||
if (!mask_col.getAlpha())
|
||||
#endif
|
||||
minimap_image->setPixel(x, y, video::SColor(0,0,0,0));
|
||||
}
|
||||
}
|
||||
@ -579,10 +593,11 @@ void Minimap::drawMinimap()
|
||||
// Non hud managed minimap drawing (legacy minimap)
|
||||
v2u32 screensize = RenderingEngine::getWindowSize();
|
||||
const u32 size = 0.25 * screensize.Y;
|
||||
const u32 padding = 10 * RenderingEngine::getDisplayDensity();
|
||||
|
||||
drawMinimap(core::rect<s32>(
|
||||
screensize.X - size - 10, 10,
|
||||
screensize.X - 10, size + 10));
|
||||
screensize.X - size - padding, padding,
|
||||
screensize.X - padding, size + padding));
|
||||
}
|
||||
|
||||
void Minimap::drawMinimap(core::rect<s32> rect) {
|
||||
@ -611,7 +626,7 @@ void Minimap::drawMinimap(core::rect<s32> rect) {
|
||||
material.setFlag(video::EMF_TRILINEAR_FILTER, true);
|
||||
material.Lighting = false;
|
||||
material.TextureLayer[0].Texture = minimap_texture;
|
||||
material.TextureLayer[1].Texture = data->heightmap_texture;
|
||||
material.TextureLayer[1].Texture = data->mode.type == MINIMAP_TYPE_RADAR ? 0 : data->heightmap_texture;
|
||||
|
||||
if (m_enable_shaders && data->mode.type == MINIMAP_TYPE_SURFACE) {
|
||||
u16 sid = m_shdrsrc->getShader("minimap_shader", TILE_MATERIAL_ALPHA);
|
||||
|
@ -76,6 +76,7 @@ Particle::Particle(
|
||||
m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
|
||||
m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
|
||||
m_material.setFlag(video::EMF_FOG_ENABLE, true);
|
||||
m_material.setFlag(video::EMF_ZWRITE_ENABLE, false);
|
||||
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
m_material.setTexture(0, texture);
|
||||
m_texpos = texpos;
|
||||
|
@ -32,7 +32,7 @@ void RenderingCoreAnaglyph::setupMaterial(int color_mask)
|
||||
video::SOverrideMaterial &mat = driver->getOverrideMaterial();
|
||||
mat.reset();
|
||||
mat.Material.ColorMask = color_mask;
|
||||
mat.EnableFlags = video::EMF_COLOR_MASK;
|
||||
mat.EnableFlags |= video::EMF_COLOR_MASK;
|
||||
mat.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID |
|
||||
scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT |
|
||||
scene::ESNRP_SHADOW;
|
||||
|
@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
*/
|
||||
|
||||
#include <IrrlichtDevice.h>
|
||||
#include "filesys.h"
|
||||
#include "fontengine.h"
|
||||
#include "client.h"
|
||||
#include "clouds.h"
|
||||
@ -37,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "../gui/guiSkin.h"
|
||||
|
||||
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__) && \
|
||||
!defined(SERVER) && !defined(__HAIKU__)
|
||||
!defined(SERVER) && !defined(__HAIKU__) && !defined(__IOS__)
|
||||
#define XORG_USED
|
||||
#endif
|
||||
#ifdef XORG_USED
|
||||
@ -56,8 +57,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include <winuser.h>
|
||||
#endif
|
||||
|
||||
#if ENABLE_GLES
|
||||
#include "filesys.h"
|
||||
#ifdef __ANDROID__
|
||||
#include "defaultsettings.h"
|
||||
#endif
|
||||
|
||||
RenderingEngine *RenderingEngine::s_singleton = nullptr;
|
||||
@ -91,8 +92,13 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
|
||||
|
||||
// Resolution selection
|
||||
bool fullscreen = g_settings->getBool("fullscreen");
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
u16 screen_w = 0;
|
||||
u16 screen_h = 0;
|
||||
#else
|
||||
u16 screen_w = g_settings->getU16("screen_w");
|
||||
u16 screen_h = g_settings->getU16("screen_h");
|
||||
#endif
|
||||
|
||||
// bpp, fsaa, vsync
|
||||
bool vsync = g_settings->getBool("vsync");
|
||||
@ -132,9 +138,6 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
|
||||
params.Vsync = vsync;
|
||||
params.EventReceiver = receiver;
|
||||
params.HighPrecisionFPU = true;
|
||||
#ifdef __ANDROID__
|
||||
params.PrivateData = porting::app_global;
|
||||
#endif
|
||||
#if ENABLE_GLES
|
||||
// there is no standardized path for these on desktop
|
||||
std::string rel_path = std::string("client") + DIR_DELIM
|
||||
@ -151,6 +154,13 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
|
||||
gui::EGST_WINDOWS_METALLIC, driver);
|
||||
m_device->getGUIEnvironment()->setSkin(skin);
|
||||
skin->drop();
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Apply settings according to screen size
|
||||
// We can get real screen size only after device initialization finished
|
||||
if (m_device)
|
||||
set_default_settings();
|
||||
#endif
|
||||
}
|
||||
|
||||
RenderingEngine::~RenderingEngine()
|
||||
@ -464,6 +474,14 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
|
||||
gui::IGUIEnvironment *guienv, ITextureSource *tsrc, float dtime,
|
||||
int percent, bool clouds)
|
||||
{
|
||||
#ifdef __IOS__
|
||||
if (m_device->isWindowMinimized())
|
||||
return;
|
||||
#else
|
||||
if (!m_device->isWindowFocused())
|
||||
return;
|
||||
#endif
|
||||
|
||||
v2u32 screensize = getWindowSize();
|
||||
|
||||
v2s32 textsize(g_fontengine->getTextWidth(text), g_fontengine->getLineHeight());
|
||||
@ -481,31 +499,50 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
|
||||
get_video_driver()->beginScene(
|
||||
true, true, video::SColor(255, 140, 186, 250));
|
||||
g_menucloudsmgr->drawAll();
|
||||
} else
|
||||
} else {
|
||||
get_video_driver()->beginScene(true, true, video::SColor(255, 0, 0, 0));
|
||||
video::ITexture *background_image = tsrc->getTexture("bg.png");
|
||||
|
||||
v2u32 screensize = driver->getScreenSize();
|
||||
get_video_driver()->draw2DImage(background_image,
|
||||
irr::core::rect<s32>(0, 0, screensize.X * 4, screensize.Y * 4),
|
||||
irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
|
||||
}
|
||||
|
||||
// draw progress bar
|
||||
if ((percent >= 0) && (percent <= 100)) {
|
||||
video::ITexture *progress_img = tsrc->getTexture("progress_bar.png");
|
||||
std::string texture_path = porting::path_share + DIR_DELIM + "textures"
|
||||
+ DIR_DELIM + "base" + DIR_DELIM + "pack" + DIR_DELIM;
|
||||
video::ITexture *progress_img =
|
||||
driver->getTexture((texture_path + "progress_bar.png").c_str());
|
||||
video::ITexture *progress_img_bg =
|
||||
tsrc->getTexture("progress_bar_bg.png");
|
||||
driver->getTexture((texture_path + "progress_bar_bg.png").c_str());
|
||||
video::ITexture *progress_img_fg =
|
||||
driver->getTexture((texture_path + "progress_bar_fg.png").c_str());
|
||||
|
||||
if (progress_img && progress_img_bg) {
|
||||
#ifndef __ANDROID__
|
||||
if (progress_img && progress_img_bg && progress_img_fg) {
|
||||
const core::dimension2d<u32> &img_size =
|
||||
progress_img_bg->getSize();
|
||||
u32 imgW = rangelim(img_size.Width, 200, 600);
|
||||
u32 imgH = rangelim(img_size.Height, 24, 72);
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
float density = RenderingEngine::getDisplayDensity();
|
||||
float gui_scaling = g_settings->getFloat("gui_scaling");
|
||||
float scale = density * gui_scaling;
|
||||
u32 imgW = rangelim(img_size.Width, 256, 1024) * scale;
|
||||
u32 imgH = rangelim(img_size.Height, 32, 128) * scale;
|
||||
#else
|
||||
const core::dimension2d<u32> img_size(256, 48);
|
||||
float imgRatio = (float)img_size.Height / img_size.Width;
|
||||
u32 imgW = screensize.X / 2.2f;
|
||||
u32 imgH = floor(imgW * imgRatio);
|
||||
float imgRatio = (float) img_size.Height / img_size.Width;
|
||||
u32 imgW = screensize.X / 2;
|
||||
if (!hasNPotSupport()) {
|
||||
imgW = npot2(imgW);
|
||||
if (imgW > (screensize.X * 0.7) && imgW >= 1024)
|
||||
imgW /= 2;
|
||||
}
|
||||
u32 imgH = imgW * imgRatio;
|
||||
#endif
|
||||
v2s32 img_pos((screensize.X - imgW) / 2,
|
||||
(screensize.Y - imgH) / 2);
|
||||
|
||||
draw2DImageFilterScaled(get_video_driver(), progress_img_bg,
|
||||
draw2DImageFilterScaled(driver, progress_img_bg,
|
||||
core::rect<s32>(img_pos.X, img_pos.Y,
|
||||
img_pos.X + imgW,
|
||||
img_pos.Y + imgH),
|
||||
@ -513,7 +550,19 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
|
||||
img_size.Height),
|
||||
0, 0, true);
|
||||
|
||||
draw2DImageFilterScaled(get_video_driver(), progress_img,
|
||||
const video::SColor color(255, 255 - percent * 2, percent * 2, 25);
|
||||
const video::SColor colors[] = {color, color, color, color};
|
||||
|
||||
draw2DImageFilterScaled(driver, progress_img_fg,
|
||||
core::rect<s32>(img_pos.X, img_pos.Y,
|
||||
img_pos.X + (percent * imgW) / 100,
|
||||
img_pos.Y + imgH),
|
||||
core::rect<s32>(0, 0,
|
||||
(percent * img_size.Width) / 100,
|
||||
img_size.Height),
|
||||
0, colors, true);
|
||||
|
||||
draw2DImageFilterScaled(driver, progress_img,
|
||||
core::rect<s32>(img_pos.X, img_pos.Y,
|
||||
img_pos.X + (percent * imgW) / 100,
|
||||
img_pos.Y + imgH),
|
||||
@ -525,7 +574,7 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
|
||||
}
|
||||
|
||||
guienv->drawAll();
|
||||
get_video_driver()->endScene();
|
||||
driver->endScene();
|
||||
guitext->remove();
|
||||
}
|
||||
|
||||
@ -533,7 +582,7 @@ void RenderingEngine::draw_load_screen(const std::wstring &text,
|
||||
Draws the menu scene including (optional) cloud background.
|
||||
*/
|
||||
void RenderingEngine::draw_menu_scene(gui::IGUIEnvironment *guienv,
|
||||
float dtime, bool clouds)
|
||||
ITextureSource *tsrc, float dtime, bool clouds)
|
||||
{
|
||||
bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
|
||||
if (cloud_menu_background) {
|
||||
@ -542,8 +591,15 @@ void RenderingEngine::draw_menu_scene(gui::IGUIEnvironment *guienv,
|
||||
get_video_driver()->beginScene(
|
||||
true, true, video::SColor(255, 140, 186, 250));
|
||||
g_menucloudsmgr->drawAll();
|
||||
} else
|
||||
} else {
|
||||
get_video_driver()->beginScene(true, true, video::SColor(255, 0, 0, 0));
|
||||
video::ITexture *background_image = tsrc->getTexture("bg.png");
|
||||
|
||||
v2u32 screensize = driver->getScreenSize();
|
||||
get_video_driver()->draw2DImage(background_image,
|
||||
irr::core::rect<s32>(0, 0, screensize.X * 4, screensize.Y * 4),
|
||||
irr::core::rect<s32>(0, 0, screensize.X, screensize.Y), 0, 0, false);
|
||||
}
|
||||
|
||||
guienv->drawAll();
|
||||
get_video_driver()->endScene();
|
||||
@ -598,7 +654,7 @@ const VideoDriverInfo &RenderingEngine::getVideoDriverInfo(irr::video::E_DRIVER_
|
||||
return driver_info_map.at((int)type);
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
#if defined(XORG_USED)
|
||||
|
||||
static float calcDisplayDensity(irr::video::IVideoDriver *driver)
|
||||
@ -695,14 +751,30 @@ v2u32 RenderingEngine::getDisplaySize()
|
||||
return deskres;
|
||||
}
|
||||
|
||||
#else // __ANDROID__
|
||||
#else // __ANDROID__/__IOS__
|
||||
float RenderingEngine::getDisplayDensity()
|
||||
{
|
||||
return porting::getDisplayDensity();
|
||||
static const float density = porting::getDisplayDensity();
|
||||
return density;
|
||||
}
|
||||
|
||||
v2u32 RenderingEngine::getDisplaySize()
|
||||
{
|
||||
return porting::getDisplaySize();
|
||||
const RenderingEngine *engine = RenderingEngine::get_instance();
|
||||
if (engine == nullptr)
|
||||
return v2u32(0, 0);
|
||||
return engine->getWindowSize();
|
||||
}
|
||||
#endif // __ANDROID__/__IOS__
|
||||
|
||||
bool RenderingEngine::isHighDpi()
|
||||
{
|
||||
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
|
||||
return g_settings->getFloat("screen_dpi") / 72.0f >= 2;
|
||||
#elif defined(__IOS__)
|
||||
float density = RenderingEngine::getDisplayDensity();
|
||||
return g_settings->getBool("device_is_tablet") ? (density >= 2) : (density >= 3);
|
||||
#else
|
||||
return RenderingEngine::getDisplayDensity() >= 3;
|
||||
#endif
|
||||
}
|
||||
#endif // __ANDROID__
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
static const VideoDriverInfo &getVideoDriverInfo(irr::video::E_DRIVER_TYPE type);
|
||||
static float getDisplayDensity();
|
||||
static v2u32 getDisplaySize();
|
||||
static bool isHighDpi();
|
||||
|
||||
bool setupTopLevelWindow(const std::string &name);
|
||||
void setupTopLevelXorgWindow(const std::string &name);
|
||||
@ -106,9 +107,11 @@ public:
|
||||
|
||||
void draw_load_screen(const std::wstring &text,
|
||||
gui::IGUIEnvironment *guienv, ITextureSource *tsrc,
|
||||
float dtime = 0, int percent = 0, bool clouds = true);
|
||||
float dtime = 0, int percent = 0, bool clouds = false);
|
||||
|
||||
void draw_menu_scene(gui::IGUIEnvironment *guienv, float dtime, bool clouds);
|
||||
void draw_menu_scene(
|
||||
gui::IGUIEnvironment *guienv, ITextureSource *tsrc,
|
||||
float dtime, bool clouds = false);
|
||||
void draw_scene(video::SColor skycolor, bool show_hud,
|
||||
bool show_minimap, bool draw_wield_tool, bool draw_crosshair);
|
||||
|
||||
|
@ -40,7 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "client/tile.h"
|
||||
#include "config.h"
|
||||
|
||||
#if ENABLE_GLES
|
||||
#if ENABLE_GLES && !defined(__APPLE__)
|
||||
#ifdef _IRR_COMPILE_WITH_OGLES1_
|
||||
#include <GLES/gl.h>
|
||||
#else
|
||||
@ -49,7 +49,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#else
|
||||
#ifndef __APPLE__
|
||||
#include <GL/gl.h>
|
||||
#else
|
||||
#elif !defined(__IOS__)
|
||||
#define GL_SILENCE_DEPRECATION
|
||||
#include <OpenGL/gl.h>
|
||||
#endif
|
||||
@ -240,8 +240,6 @@ class MainShaderConstantSetter : public IShaderConstantSetter
|
||||
CachedVertexShaderSetting<float, 16> m_world_view;
|
||||
// Texture matrix
|
||||
CachedVertexShaderSetting<float, 16> m_texture;
|
||||
// Normal matrix
|
||||
CachedVertexShaderSetting<float, 9> m_normal;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@ -251,7 +249,6 @@ public:
|
||||
#if ENABLE_GLES
|
||||
, m_world_view("mWorldView")
|
||||
, m_texture("mTexture")
|
||||
, m_normal("mNormal")
|
||||
#endif
|
||||
, m_shadow_view_proj("m_ShadowViewProj")
|
||||
, m_light_direction("v_LightDirection")
|
||||
@ -286,16 +283,6 @@ public:
|
||||
core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
|
||||
m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
|
||||
m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
|
||||
|
||||
core::matrix4 normal;
|
||||
worldView.getTransposed(normal);
|
||||
sanity_check(normal.makeInverse());
|
||||
float m[9] = {
|
||||
normal[0], normal[1], normal[2],
|
||||
normal[4], normal[5], normal[6],
|
||||
normal[8], normal[9], normal[10],
|
||||
};
|
||||
m_normal.set(m, services);
|
||||
#endif
|
||||
|
||||
// Set uniforms for Shadow shader
|
||||
@ -633,7 +620,6 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||
uniform highp mat4 mWorldView;
|
||||
uniform highp mat4 mWorldViewProj;
|
||||
uniform mediump mat4 mTexture;
|
||||
uniform mediump mat3 mNormal;
|
||||
|
||||
attribute highp vec4 inVertexPosition;
|
||||
attribute lowp vec4 inVertexColor;
|
||||
@ -656,7 +642,6 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||
#define mWorldView gl_ModelViewMatrix
|
||||
#define mWorldViewProj gl_ModelViewProjectionMatrix
|
||||
#define mTexture (gl_TextureMatrix[0])
|
||||
#define mNormal gl_NormalMatrix
|
||||
|
||||
#define inVertexPosition gl_Vertex
|
||||
#define inVertexColor gl_Color
|
||||
@ -668,7 +653,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
||||
}
|
||||
|
||||
bool use_discard = use_gles;
|
||||
#ifdef __unix__
|
||||
#if defined(__unix__) && !defined(__APPLE__)
|
||||
// For renderers that should use discard instead of GL_ALPHA_TEST
|
||||
const char* gl_renderer = (const char*)glGetString(GL_RENDERER);
|
||||
if (strstr(gl_renderer, "GC7000"))
|
||||
|
@ -237,7 +237,7 @@ void Sky::render()
|
||||
}
|
||||
|
||||
// Draw far cloudy fog thing blended with skycolor
|
||||
if (m_visible) {
|
||||
/*if (m_visible) {
|
||||
driver->setMaterial(m_materials[1]);
|
||||
for (u32 j = 0; j < 4; j++) {
|
||||
vertices[0] = video::S3DVertex(-1, -0.02, -1, 0, 0, 1, m_bgcolor, t, t);
|
||||
@ -260,7 +260,7 @@ void Sky::render()
|
||||
}
|
||||
driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// Draw stars before sun and moon to be behind them
|
||||
if (m_star_params.visible)
|
||||
@ -813,7 +813,7 @@ void Sky::updateStars()
|
||||
|
||||
video::SColor fallback_color = m_star_params.starcolor; // used on GLES 2 “without shaders”
|
||||
PcgRandom rgen(m_seed);
|
||||
float d = (0.006 / 2) * m_star_params.scale;
|
||||
float d = (0.003 / 2) * m_star_params.scale;
|
||||
for (u16 i = 0; i < m_star_params.count; i++) {
|
||||
v3f r = v3f(
|
||||
rgen.range(-10000, 10000),
|
||||
|
@ -50,7 +50,7 @@ with this program; ifnot, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#define BUFFER_SIZE 30000
|
||||
|
||||
std::shared_ptr<SoundManagerSingleton> g_sound_manager_singleton;
|
||||
SoundManagerSingleton* g_sound_manager_singleton = nullptr;
|
||||
|
||||
typedef std::unique_ptr<ALCdevice, void (*)(ALCdevice *p)> unique_ptr_alcdevice;
|
||||
typedef std::unique_ptr<ALCcontext, void(*)(ALCcontext *p)> unique_ptr_alccontext;
|
||||
@ -707,15 +707,22 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<SoundManagerSingleton> createSoundManagerSingleton()
|
||||
SoundManagerSingleton* createSoundManagerSingleton()
|
||||
{
|
||||
auto smg = std::make_shared<SoundManagerSingleton>();
|
||||
auto smg = new SoundManagerSingleton();
|
||||
if (!smg->init()) {
|
||||
smg.reset();
|
||||
delete smg;
|
||||
smg = nullptr;
|
||||
}
|
||||
return smg;
|
||||
}
|
||||
|
||||
void deleteSoundManagerSingleton(SoundManagerSingleton* smg)
|
||||
{
|
||||
delete smg;
|
||||
smg = nullptr;
|
||||
}
|
||||
|
||||
ISoundManager *createOpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher)
|
||||
{
|
||||
return new OpenALSoundManager(smg, fetcher);
|
||||
|
@ -24,8 +24,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "sound.h"
|
||||
|
||||
class SoundManagerSingleton;
|
||||
extern std::shared_ptr<SoundManagerSingleton> g_sound_manager_singleton;
|
||||
extern SoundManagerSingleton* g_sound_manager_singleton;
|
||||
|
||||
std::shared_ptr<SoundManagerSingleton> createSoundManagerSingleton();
|
||||
SoundManagerSingleton* createSoundManagerSingleton();
|
||||
void deleteSoundManagerSingleton(SoundManagerSingleton* smg);
|
||||
ISoundManager *createOpenALSoundManager(
|
||||
SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher);
|
||||
|
@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
A cache from texture name to texture path
|
||||
*/
|
||||
MutexedMap<std::string, std::string> g_texturename_to_path_cache;
|
||||
bool g_disable_texture_packs = false;
|
||||
|
||||
/*
|
||||
Replaces the filename extension.
|
||||
@ -1023,14 +1024,9 @@ video::IImage *Align2Npot2(video::IImage *image,
|
||||
unsigned int height = npot2(dim.Height);
|
||||
unsigned int width = npot2(dim.Width);
|
||||
|
||||
if (dim.Height == height && dim.Width == width)
|
||||
if (dim.Width == width)
|
||||
return image;
|
||||
|
||||
if (dim.Height > height)
|
||||
height *= 2;
|
||||
if (dim.Width > width)
|
||||
width *= 2;
|
||||
|
||||
video::IImage *targetimage =
|
||||
driver->createImage(video::ECF_A8R8G8B8,
|
||||
core::dimension2d<u32>(width, height));
|
||||
@ -1040,7 +1036,15 @@ video::IImage *Align2Npot2(video::IImage *image,
|
||||
image->drop();
|
||||
return targetimage;
|
||||
}
|
||||
|
||||
#else
|
||||
bool hasNPotSupport()
|
||||
{
|
||||
#ifdef __IOS__
|
||||
return true; // Irrlicht cares about it on iOS
|
||||
#endif
|
||||
static const std::string &driverstring = g_settings->get("video_driver");
|
||||
return (driverstring != "ogles1"); // gles3 has NPot Support and used instead of gles2
|
||||
}
|
||||
#endif
|
||||
|
||||
static std::string unescape_string(const std::string &str, const char esc = '\\')
|
||||
@ -1215,8 +1219,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
|
||||
It is an image with a number of cracking stages
|
||||
horizontally tiled.
|
||||
*/
|
||||
#ifndef HAVE_TOUCHSCREENGUI
|
||||
video::IImage *img_crack = m_sourcecache.getOrLoad(
|
||||
"crack_anylength.png");
|
||||
#else
|
||||
video::IImage *img_crack = m_sourcecache.getOrLoad(
|
||||
"crack_anylength_touch.png");
|
||||
#endif
|
||||
|
||||
if (img_crack) {
|
||||
draw_crack(img_crack, baseimg,
|
||||
@ -2332,5 +2341,13 @@ video::ITexture *TextureSource::getShaderFlagsTexture(bool normalmap_present)
|
||||
|
||||
std::vector<std::string> getTextureDirs()
|
||||
{
|
||||
if (g_disable_texture_packs)
|
||||
return {};
|
||||
return fs::GetRecursiveDirs(g_settings->get("texture_path"));
|
||||
}
|
||||
|
||||
|
||||
void setDisableTexturePacks(const bool disable_texture_packs)
|
||||
{
|
||||
g_disable_texture_packs = disable_texture_packs;
|
||||
}
|
||||
|
@ -175,8 +175,6 @@ struct FrameSpec
|
||||
|
||||
u32 texture_id = 0;
|
||||
video::ITexture *texture = nullptr;
|
||||
video::ITexture *normal_texture = nullptr;
|
||||
video::ITexture *flags_texture = nullptr;
|
||||
};
|
||||
|
||||
#define MAX_TILE_LAYERS 2
|
||||
@ -262,11 +260,8 @@ struct TileLayer
|
||||
// Ordered for size, please do not reorder
|
||||
|
||||
video::ITexture *texture = nullptr;
|
||||
video::ITexture *normal_texture = nullptr;
|
||||
video::ITexture *flags_texture = nullptr;
|
||||
|
||||
u32 shader_id = 0;
|
||||
|
||||
u32 texture_id = 0;
|
||||
|
||||
u16 animation_frame_length_ms = 0;
|
||||
@ -326,3 +321,5 @@ struct TileSpec
|
||||
};
|
||||
|
||||
std::vector<std::string> getTextureDirs();
|
||||
|
||||
void setDisableTexturePacks(const bool disable_texture_packs);
|
||||
|
@ -41,6 +41,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#define MIN_EXTRUSION_MESH_RESOLUTION 16
|
||||
#define MAX_EXTRUSION_MESH_RESOLUTION 512
|
||||
|
||||
/*!
|
||||
* Applies overlays, textures and materials to the given mesh and
|
||||
* extracts tile colors for colorization.
|
||||
* \param colors returns the colors of the mesh buffers in the mesh.
|
||||
*/
|
||||
static void postProcessCubeMesh(scene::SMesh *mesh, const ContentFeatures &f,
|
||||
IShaderSource *shader_source, std::string const &shader_name,
|
||||
std::vector<ItemPartColor> *colors);
|
||||
|
||||
|
||||
static scene::IMesh *createExtrusionMesh(int resolution_x, int resolution_y)
|
||||
{
|
||||
const f32 r = 0.5;
|
||||
@ -237,18 +247,6 @@ WieldMeshSceneNode::~WieldMeshSceneNode()
|
||||
g_extrusion_mesh_cache = nullptr;
|
||||
}
|
||||
|
||||
void WieldMeshSceneNode::setCube(const ContentFeatures &f,
|
||||
v3f wield_scale)
|
||||
{
|
||||
scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
|
||||
scene::SMesh *copy = cloneMesh(cubemesh);
|
||||
cubemesh->drop();
|
||||
postProcessNodeMesh(copy, f, false, true, &m_material_type, &m_colors, true);
|
||||
changeToMesh(copy);
|
||||
copy->drop();
|
||||
m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR);
|
||||
}
|
||||
|
||||
void WieldMeshSceneNode::setExtruded(const std::string &imagename,
|
||||
const std::string &overlay_name, v3f wield_scale, ITextureSource *tsrc,
|
||||
u8 num_frames)
|
||||
@ -310,7 +308,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
|
||||
}
|
||||
|
||||
static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
|
||||
std::vector<ItemPartColor> *colors, const ContentFeatures &f)
|
||||
std::vector<ItemPartColor> *colors, const ContentFeatures &f, std::string const shader_name = {})
|
||||
{
|
||||
MeshMakeData mesh_make_data(client, false);
|
||||
MeshCollector collector;
|
||||
@ -333,6 +331,7 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
|
||||
}
|
||||
gen.renderSingle(n.getContent(), n.getParam2());
|
||||
|
||||
IShaderSource *shader_source = shader_name.empty() ? nullptr : client->getShaderSource();
|
||||
colors->clear();
|
||||
scene::SMesh *mesh = new scene::SMesh();
|
||||
for (auto &prebuffers : collector.prebuffers)
|
||||
@ -340,14 +339,20 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
|
||||
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
|
||||
const FrameSpec &frame = (*p.layer.frames)[0];
|
||||
p.layer.texture = frame.texture;
|
||||
p.layer.normal_texture = frame.normal_texture;
|
||||
}
|
||||
for (video::S3DVertex &v : p.vertices) {
|
||||
v.Color.setAlpha(255);
|
||||
}
|
||||
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
buf->Material.setTexture(0, p.layer.texture);
|
||||
if (!shader_name.empty()) {
|
||||
auto shader_id = shader_source->getShader(shader_name, (MaterialType)p.layer.material_type, f.drawtype);
|
||||
buf->Material.MaterialType = shader_source->getShaderInfo(shader_id).material;
|
||||
p.layer.applyMaterialOptionsWithShaders(buf->Material);
|
||||
} else {
|
||||
p.layer.applyMaterialOptions(buf->Material);
|
||||
}
|
||||
buf->Material.MaterialTypeParam = 0.0f;
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->append(&p.vertices[0], p.vertices.size(),
|
||||
&p.indices[0], p.indices.size());
|
||||
@ -430,15 +435,22 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
|
||||
}
|
||||
case NDT_NORMAL:
|
||||
case NDT_ALLFACES:
|
||||
case NDT_LIQUID:
|
||||
setCube(f, def.wield_scale);
|
||||
case NDT_LIQUID: {
|
||||
scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
|
||||
scene::SMesh *copy = cloneMesh(cubemesh);
|
||||
cubemesh->drop();
|
||||
postProcessCubeMesh(copy, f, shdrsrc, "object_shader", &m_colors);
|
||||
changeToMesh(copy);
|
||||
copy->drop();
|
||||
m_meshnode->setScale(def.wield_scale * WIELD_SCALE_FACTOR);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Render non-trivial drawtypes like the actual node
|
||||
MapNode n(id);
|
||||
n.setParam2(def.place_param2);
|
||||
|
||||
mesh = createSpecialNodeMesh(client, n, &m_colors, f);
|
||||
mesh = createSpecialNodeMesh(client, id, &m_colors, f, "object_shader");
|
||||
changeToMesh(mesh);
|
||||
mesh->drop();
|
||||
m_meshnode->setScale(
|
||||
@ -451,8 +463,6 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
|
||||
u32 material_count = m_meshnode->getMaterialCount();
|
||||
for (u32 i = 0; i < material_count; ++i) {
|
||||
video::SMaterial &material = m_meshnode->getMaterial(i);
|
||||
material.MaterialType = m_material_type;
|
||||
material.MaterialTypeParam = 0.5f;
|
||||
material.setFlag(video::EMF_BACK_FACE_CULLING, cull_backface);
|
||||
material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
|
||||
material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
|
||||
@ -546,6 +556,7 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
|
||||
m_shadow->addNodeToShadowList(m_meshnode);
|
||||
}
|
||||
|
||||
// Only used for inventory images
|
||||
void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
|
||||
{
|
||||
ITextureSource *tsrc = client->getTextureSource();
|
||||
@ -593,8 +604,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
|
||||
} else
|
||||
scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
|
||||
// add overlays
|
||||
postProcessNodeMesh(mesh, f, false, false, nullptr,
|
||||
&result->buffer_colors, true);
|
||||
postProcessCubeMesh(mesh, f, nullptr, {}, &result->buffer_colors);
|
||||
if (f.drawtype == NDT_ALLFACES)
|
||||
scaleMesh(mesh, v3f(f.visual_scale));
|
||||
break;
|
||||
@ -692,9 +702,9 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
|
||||
bool use_shaders, bool set_material, const video::E_MATERIAL_TYPE *mattype,
|
||||
std::vector<ItemPartColor> *colors, bool apply_scale)
|
||||
static void postProcessCubeMesh(scene::SMesh *mesh, const ContentFeatures &f,
|
||||
IShaderSource *shader_source, std::string const &shader_name,
|
||||
std::vector<ItemPartColor> *colors)
|
||||
{
|
||||
u32 mc = mesh->getMeshBufferCount();
|
||||
// Allocate colors for existing buffers
|
||||
@ -721,28 +731,21 @@ void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
|
||||
(*colors)[i] = ItemPartColor(layer->has_color, layer->color);
|
||||
}
|
||||
video::SMaterial &material = buf->getMaterial();
|
||||
if (set_material)
|
||||
if (shader_source && !shader_name.empty()) {
|
||||
auto shader_id = shader_source->getShader(shader_name, (MaterialType)layer->material_type, NDT_ALLFACES);
|
||||
material.MaterialType = shader_source->getShaderInfo(shader_id).material;
|
||||
layer->applyMaterialOptionsWithShaders(material);
|
||||
} else {
|
||||
layer->applyMaterialOptions(material);
|
||||
if (mattype) {
|
||||
material.MaterialType = *mattype;
|
||||
}
|
||||
material.MaterialTypeParam = 0.0f;
|
||||
if (layer->animation_frame_count > 1) {
|
||||
const FrameSpec &animation_frame = (*layer->frames)[0];
|
||||
material.setTexture(0, animation_frame.texture);
|
||||
} else {
|
||||
material.setTexture(0, layer->texture);
|
||||
}
|
||||
if (use_shaders) {
|
||||
if (layer->normal_texture) {
|
||||
if (layer->animation_frame_count > 1) {
|
||||
const FrameSpec &animation_frame = (*layer->frames)[0];
|
||||
material.setTexture(1, animation_frame.normal_texture);
|
||||
} else
|
||||
material.setTexture(1, layer->normal_texture);
|
||||
}
|
||||
material.setTexture(2, layer->flags_texture);
|
||||
}
|
||||
if (apply_scale && tile->world_aligned) {
|
||||
if (tile->world_aligned) {
|
||||
u32 n = buf->getVertexCount();
|
||||
for (u32 k = 0; k != n; ++k)
|
||||
buf->getTCoords(k) /= layer->scale;
|
||||
|
@ -133,14 +133,3 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);
|
||||
|
||||
scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename,
|
||||
const std::string &overlay_name);
|
||||
|
||||
/*!
|
||||
* Applies overlays, textures and optionally materials to the given mesh and
|
||||
* extracts tile colors for colorization.
|
||||
* \param mattype overrides the buffer's material type, but can also
|
||||
* be NULL to leave the original material.
|
||||
* \param colors returns the colors of the mesh buffers in the mesh.
|
||||
*/
|
||||
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, bool use_shaders,
|
||||
bool set_material, const video::E_MATERIAL_TYPE *mattype,
|
||||
std::vector<ItemPartColor> *colors, bool apply_scale = false);
|
||||
|
@ -472,20 +472,14 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
|
||||
{
|
||||
case CSE_AuthAccept:
|
||||
m_state = CS_AwaitingInit2;
|
||||
if (chosen_mech == AUTH_MECHANISM_SRP ||
|
||||
chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
|
||||
srp_verifier_delete((SRPVerifier *) auth_data);
|
||||
chosen_mech = AUTH_MECHANISM_NONE;
|
||||
resetChosenMech();
|
||||
break;
|
||||
case CSE_Disconnect:
|
||||
m_state = CS_Disconnecting;
|
||||
break;
|
||||
case CSE_SetDenied:
|
||||
m_state = CS_Denied;
|
||||
if (chosen_mech == AUTH_MECHANISM_SRP ||
|
||||
chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
|
||||
srp_verifier_delete((SRPVerifier *) auth_data);
|
||||
chosen_mech = AUTH_MECHANISM_NONE;
|
||||
resetChosenMech();
|
||||
break;
|
||||
default:
|
||||
myerror << "HelloSent: Invalid client state transition! " << event;
|
||||
@ -561,9 +555,7 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
|
||||
break;
|
||||
case CSE_SudoSuccess:
|
||||
m_state = CS_SudoMode;
|
||||
if (chosen_mech == AUTH_MECHANISM_SRP)
|
||||
srp_verifier_delete((SRPVerifier *) auth_data);
|
||||
chosen_mech = AUTH_MECHANISM_NONE;
|
||||
resetChosenMech();
|
||||
break;
|
||||
/* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
|
||||
default:
|
||||
@ -596,6 +588,15 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteClient::resetChosenMech()
|
||||
{
|
||||
if (auth_data) {
|
||||
srp_verifier_delete((SRPVerifier *) auth_data);
|
||||
auth_data = nullptr;
|
||||
}
|
||||
chosen_mech = AUTH_MECHANISM_NONE;
|
||||
}
|
||||
|
||||
u64 RemoteClient::uptime() const
|
||||
{
|
||||
return porting::getTimeS() - m_connection_time;
|
||||
@ -714,6 +715,59 @@ void ClientInterface::sendToAll(NetworkPacket *pkt)
|
||||
}
|
||||
}
|
||||
|
||||
void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt,
|
||||
u16 min_proto_ver)
|
||||
{
|
||||
RecursiveMutexAutoLock clientslock(m_clients_mutex);
|
||||
for (auto &client_it : m_clients) {
|
||||
RemoteClient *client = client_it.second;
|
||||
NetworkPacket *pkt_to_send = nullptr;
|
||||
|
||||
if (client->net_proto_version >= min_proto_ver) {
|
||||
pkt_to_send = pkt;
|
||||
} else if (client->net_proto_version != 0) {
|
||||
pkt_to_send = legacypkt;
|
||||
} else {
|
||||
// This will happen if a client is connecting when sendToAllCompat
|
||||
// is called, this can safely be ignored.
|
||||
continue;
|
||||
}
|
||||
|
||||
m_con->Send(client->peer_id,
|
||||
clientCommandFactoryTable[pkt_to_send->getCommand()].channel,
|
||||
pkt_to_send,
|
||||
clientCommandFactoryTable[pkt_to_send->getCommand()].reliable);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientInterface::oldSendToAll(NetworkPacket *pkt)
|
||||
{
|
||||
RecursiveMutexAutoLock clientslock(m_clients_mutex);
|
||||
for (auto &client_it : m_clients) {
|
||||
RemoteClient *client = client_it.second;
|
||||
|
||||
if (client->net_proto_version != 0 && client->net_proto_version < 37) {
|
||||
m_con->Send(client->peer_id,
|
||||
clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
|
||||
clientCommandFactoryTable[pkt->getCommand()].reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientInterface::newSendToAll(NetworkPacket *pkt)
|
||||
{
|
||||
RecursiveMutexAutoLock clientslock(m_clients_mutex);
|
||||
for (auto &client_it : m_clients) {
|
||||
RemoteClient *client = client_it.second;
|
||||
|
||||
if (client->net_proto_version > 36) {
|
||||
m_con->Send(client->peer_id,
|
||||
clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
|
||||
clientCommandFactoryTable[pkt->getCommand()].reliable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
|
||||
{
|
||||
RecursiveMutexAutoLock clientslock(m_clients_mutex);
|
||||
|
@ -242,6 +242,8 @@ public:
|
||||
u32 allowed_auth_mechs = 0;
|
||||
u32 allowed_sudo_mechs = 0;
|
||||
|
||||
void resetChosenMech();
|
||||
|
||||
bool isSudoMechAllowed(AuthMechanism mech)
|
||||
{ return allowed_sudo_mechs & mech; }
|
||||
bool isMechAllowed(AuthMechanism mech)
|
||||
@ -332,7 +334,15 @@ public:
|
||||
m_version_major = major;
|
||||
m_version_minor = minor;
|
||||
m_version_patch = patch;
|
||||
m_full_version = full;
|
||||
m_full_version = full.c_str();
|
||||
const size_t pos = full.find('\x00');
|
||||
if (pos != std::string::npos) {
|
||||
m_platform = full.substr(pos + 1).c_str();
|
||||
|
||||
const size_t pos2 = full.find('\x00', pos + 1);
|
||||
if (pos2 != std::string::npos)
|
||||
m_sysinfo = full.substr(pos2 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* read version information */
|
||||
@ -341,6 +351,9 @@ public:
|
||||
u8 getPatch() const { return m_version_patch; }
|
||||
const std::string &getFullVer() const { return m_full_version; }
|
||||
|
||||
const std::string &getPlatform() const { return m_platform; }
|
||||
const std::string &getSysInfo() const { return m_sysinfo; }
|
||||
|
||||
void setLangCode(const std::string &code) { m_lang_code = code; }
|
||||
const std::string &getLangCode() const { return m_lang_code; }
|
||||
|
||||
@ -426,6 +439,8 @@ private:
|
||||
u8 m_version_patch = 0;
|
||||
|
||||
std::string m_full_version = "unknown";
|
||||
std::string m_platform = "unknown";
|
||||
std::string m_sysinfo = "unknown";
|
||||
|
||||
u16 m_deployed_compression = 0;
|
||||
|
||||
@ -465,6 +480,9 @@ public:
|
||||
|
||||
/* send to all clients */
|
||||
void sendToAll(NetworkPacket *pkt);
|
||||
void sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt, u16 min_proto_ver);
|
||||
void oldSendToAll(NetworkPacket *pkt);
|
||||
void newSendToAll(NetworkPacket *pkt);
|
||||
|
||||
/* delete a client */
|
||||
void DeleteClient(session_t peer_id);
|
||||
|
@ -15,11 +15,14 @@
|
||||
#define BUILD_TYPE "@CMAKE_BUILD_TYPE@"
|
||||
#define ICON_DIR "@ICONDIR@"
|
||||
#cmakedefine01 RUN_IN_PLACE
|
||||
#cmakedefine01 DEVELOPMENT_BUILD
|
||||
#cmakedefine01 ENABLE_UPDATE_CHECKER
|
||||
#cmakedefine01 USE_GETTEXT
|
||||
#cmakedefine01 USE_CURL
|
||||
#cmakedefine01 USE_SOUND
|
||||
#cmakedefine01 USE_CURSES
|
||||
#cmakedefine01 USE_LEVELDB
|
||||
#cmakedefine01 USE_SQLITE
|
||||
#cmakedefine01 USE_LUAJIT
|
||||
#cmakedefine01 USE_POSTGRESQL
|
||||
#cmakedefine01 USE_PROMETHEUS
|
||||
|
@ -11,10 +11,11 @@
|
||||
|
||||
#if defined USE_CMAKE_CONFIG_H
|
||||
#include "cmake_config.h"
|
||||
#elif defined (__ANDROID__)
|
||||
#define PROJECT_NAME "minetest"
|
||||
#define PROJECT_NAME_C "Minetest"
|
||||
#elif defined(__ANDROID__) || defined(__APPLE__)
|
||||
#define PROJECT_NAME "multicraft"
|
||||
#define PROJECT_NAME_C "MultiCraft"
|
||||
#define STATIC_SHAREDIR ""
|
||||
#define ENABLE_UPDATE_CHECKER 1
|
||||
#define VERSION_STRING STR(VERSION_MAJOR) "." STR(VERSION_MINOR) "." STR(VERSION_PATCH) STR(VERSION_EXTRA)
|
||||
#ifdef NDEBUG
|
||||
#define BUILD_TYPE "Release"
|
||||
|
@ -110,4 +110,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
GUI related things
|
||||
*/
|
||||
|
||||
#define TTF_DEFAULT_FONT_SIZE (16)
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
#define TTF_DEFAULT_FONT_SIZE (13)
|
||||
#else
|
||||
#define TTF_DEFAULT_FONT_SIZE (18)
|
||||
#endif
|
||||
|
69
src/content/packages.cpp
Normal file
69
src/content/packages.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
Minetest
|
||||
Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 3.0 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "content/packages.h"
|
||||
#include "log.h"
|
||||
#include "filesys.h"
|
||||
#include "porting.h"
|
||||
#include "settings.h"
|
||||
#include "content/mods.h"
|
||||
#include "content/subgames.h"
|
||||
|
||||
std::string Package::getDownloadURL(const std::string &baseURL) const
|
||||
{
|
||||
return baseURL + "/packages/" + author + "/" + name + "/releases/" +
|
||||
std::to_string(release) + "/download/";
|
||||
}
|
||||
|
||||
#if USE_CURL
|
||||
std::vector<Package> getPackagesFromURL(const std::string &url)
|
||||
{
|
||||
std::vector<std::string> extra_headers;
|
||||
extra_headers.emplace_back("Accept: application/json");
|
||||
|
||||
Json::Value json = fetchJsonValue(url, &extra_headers);
|
||||
if (!json.isArray()) {
|
||||
errorstream << "Invalid JSON download " << std::endl;
|
||||
return std::vector<Package>();
|
||||
}
|
||||
|
||||
std::vector<Package> packages;
|
||||
|
||||
// Note: `unsigned int` is required to index JSON
|
||||
for (unsigned int i = 0; i < json.size(); ++i) {
|
||||
Package package;
|
||||
|
||||
package.author = json[i]["author"].asString();
|
||||
package.name = json[i]["name"].asString();
|
||||
package.title = json[i]["title"].asString();
|
||||
package.type = json[i]["type"].asString();
|
||||
package.shortDesc = json[i]["shortDesc"].asString();
|
||||
package.release = json[i]["release"].asInt();
|
||||
if (json[i].isMember("thumbnail"))
|
||||
package.thumbnail = json[i]["thumbnail"].asString();
|
||||
|
||||
if (package.valid())
|
||||
packages.push_back(package);
|
||||
else
|
||||
errorstream << "Invalid package at " << i << std::endl;
|
||||
}
|
||||
|
||||
return packages;
|
||||
}
|
||||
#endif
|
52
src/content/packages.h
Normal file
52
src/content/packages.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Minetest
|
||||
Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 3.0 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "config.h"
|
||||
#include "convert_json.h"
|
||||
#include "irrlichttypes.h"
|
||||
|
||||
struct Package
|
||||
{
|
||||
std::string author;
|
||||
std::string name; // Technical name
|
||||
std::string title;
|
||||
std::string type; // One of "mod", "game", or "txp"
|
||||
|
||||
std::string shortDesc;
|
||||
u32 release;
|
||||
std::string thumbnail;
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return !(author.empty() || name.empty() || title.empty() ||
|
||||
type.empty() || release <= 0);
|
||||
}
|
||||
|
||||
std::string getDownloadURL(const std::string &baseURL) const;
|
||||
};
|
||||
|
||||
#if USE_CURL
|
||||
std::vector<Package> getPackagesFromURL(const std::string &url);
|
||||
#else
|
||||
inline std::vector<Package> getPackagesFromURL(const std::string &url)
|
||||
{
|
||||
return std::vector<Package>();
|
||||
}
|
||||
#endif
|
@ -37,9 +37,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
namespace
|
||||
{
|
||||
|
||||
bool getGameMinetestConfig(const std::string &game_path, Settings &conf)
|
||||
bool getGameMinetestConfig(
|
||||
const std::string &game_path, Settings &conf, const std::string &file)
|
||||
{
|
||||
std::string conf_path = game_path + DIR_DELIM + "minetest.conf";
|
||||
std::string conf_path = game_path + DIR_DELIM + file;
|
||||
return conf.readConfigFile(conf_path.c_str());
|
||||
}
|
||||
|
||||
@ -136,13 +137,17 @@ SubgameSpec findSubgame(const std::string &id)
|
||||
if (conf.exists("release"))
|
||||
game_release = conf.getS32("release");
|
||||
|
||||
bool moddable = true;
|
||||
if (conf.exists("moddable"))
|
||||
moddable = conf.getBool("moddable");
|
||||
|
||||
std::string menuicon_path;
|
||||
#ifndef SERVER
|
||||
menuicon_path = getImagePath(
|
||||
game_path + DIR_DELIM + "menu" + DIR_DELIM + "icon.png");
|
||||
#endif
|
||||
return SubgameSpec(id, game_path, gamemod_path, mods_paths, game_name,
|
||||
menuicon_path, game_author, game_release);
|
||||
menuicon_path, game_author, game_release, moddable);
|
||||
}
|
||||
|
||||
SubgameSpec findWorldSubgame(const std::string &world_path)
|
||||
@ -341,7 +346,8 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
|
||||
game_settings = Settings::createLayer(SL_GAME);
|
||||
}
|
||||
|
||||
getGameMinetestConfig(gamespec.path, *game_settings);
|
||||
getGameMinetestConfig(gamespec.path, *game_settings, "minetest.conf");
|
||||
getGameMinetestConfig(gamespec.path, *game_settings, "multicraft.conf");
|
||||
game_settings->removeSecureSettings();
|
||||
|
||||
infostream << "Initializing world at " << final_path << std::endl;
|
||||
@ -355,10 +361,17 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
|
||||
|
||||
conf.set("world_name", name);
|
||||
conf.set("gameid", gamespec.id);
|
||||
#if !defined(__ANDROID__) && !defined(__APPLE__)
|
||||
conf.set("backend", "sqlite3");
|
||||
conf.set("player_backend", "sqlite3");
|
||||
conf.set("auth_backend", "sqlite3");
|
||||
conf.set("mod_storage_backend", "sqlite3");
|
||||
#else
|
||||
conf.set("backend", "leveldb");
|
||||
conf.set("player_backend", "leveldb");
|
||||
conf.set("auth_backend", "leveldb");
|
||||
conf.set("mod_storage_backend", "leveldb");
|
||||
#endif
|
||||
conf.setBool("creative_mode", g_settings->getBool("creative_mode"));
|
||||
conf.setBool("enable_damage", g_settings->getBool("enable_damage"));
|
||||
|
||||
|
@ -35,6 +35,7 @@ struct SubgameSpec
|
||||
std::string gamemods_path;
|
||||
std::set<std::string> addon_mods_paths;
|
||||
std::string menuicon_path;
|
||||
bool moddable;
|
||||
|
||||
SubgameSpec(const std::string &id = "", const std::string &path = "",
|
||||
const std::string &gamemods_path = "",
|
||||
@ -42,11 +43,12 @@ struct SubgameSpec
|
||||
std::set<std::string>(),
|
||||
const std::string &name = "",
|
||||
const std::string &menuicon_path = "",
|
||||
const std::string &author = "", int release = 0) :
|
||||
const std::string &author = "", int release = 0,
|
||||
const bool moddable = true) :
|
||||
id(id),
|
||||
name(name), author(author), release(release), path(path),
|
||||
gamemods_path(gamemods_path), addon_mods_paths(addon_mods_paths),
|
||||
menuicon_path(menuicon_path)
|
||||
menuicon_path(menuicon_path), moddable(moddable)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,14 @@ void sanity_check_fn(const char *assertion, const char *file,
|
||||
errorstream << file << ":" << line << ": " << function
|
||||
<< ": An engine assumption '" << assertion << "' failed." << std::endl;
|
||||
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
std::string capture = "An engine assumption failed: \"" + std::string(assertion) +
|
||||
"\" in file: " + std::string(file) + ":" + std::to_string(line) +
|
||||
" (" + std::string(function) + ")";
|
||||
porting::finishGame(capture);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void fatal_error_fn(const char *msg, const char *file,
|
||||
@ -71,7 +78,14 @@ void fatal_error_fn(const char *msg, const char *file,
|
||||
errorstream << file << ":" << line << ": " << function
|
||||
<< ": A fatal error occurred: " << msg << std::endl;
|
||||
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
std::string capture = "A fatal error occurred: \"" + std::string(msg) +
|
||||
"\" in file: " + std::string(file) + ":" + std::to_string(line) +
|
||||
" (" + std::string(function) + ")";
|
||||
porting::finishGame(capture);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -23,24 +23,37 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "filesys.h"
|
||||
#include "config.h"
|
||||
#include "constants.h"
|
||||
#include "porting.h"
|
||||
#include "mapgen/mapgen.h" // Mapgen::setDefaultSettings
|
||||
#include "util/string.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include "client/renderingengine.h"
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifdef __IOS__
|
||||
#import "SDVersion.h"
|
||||
#else
|
||||
#import <AppKit/AppKit.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void set_default_settings()
|
||||
{
|
||||
Settings *settings = Settings::createLayer(SL_DEFAULTS);
|
||||
Settings *settings = Settings::getLayer(SL_DEFAULTS);
|
||||
if (settings == nullptr)
|
||||
settings = Settings::createLayer(SL_DEFAULTS);
|
||||
|
||||
// Client and server
|
||||
settings->setDefault("language", "");
|
||||
settings->setDefault("name", "");
|
||||
settings->setDefault("bind_address", "");
|
||||
settings->setDefault("serverlist_url", "servers.minetest.net");
|
||||
settings->setDefault("serverlist_url", "servers.multicraft.world");
|
||||
|
||||
// Client
|
||||
settings->setDefault("address", "");
|
||||
settings->setDefault("enable_sound", "true");
|
||||
settings->setDefault("sound_volume", "0.8");
|
||||
settings->setDefault("sound_volume", "1.0");
|
||||
settings->setDefault("mute_sound", "false");
|
||||
settings->setDefault("enable_mesh_cache", "false");
|
||||
settings->setDefault("mesh_generation_interval", "0");
|
||||
@ -61,9 +74,9 @@ void set_default_settings()
|
||||
settings->setDefault("curl_file_download_timeout", "300000");
|
||||
settings->setDefault("curl_verify_cert", "true");
|
||||
settings->setDefault("enable_remote_media_server", "true");
|
||||
settings->setDefault("enable_client_modding", "false");
|
||||
settings->setDefault("enable_client_modding", "true");
|
||||
settings->setDefault("max_out_chat_queue_size", "20");
|
||||
settings->setDefault("pause_on_lost_focus", "false");
|
||||
settings->setDefault("pause_on_lost_focus", "true");
|
||||
settings->setDefault("enable_register_confirmation", "true");
|
||||
settings->setDefault("clickable_chat_weblinks", "false");
|
||||
settings->setDefault("chat_weblink_color", "#8888FF");
|
||||
@ -176,7 +189,7 @@ void set_default_settings()
|
||||
settings->setDefault("near_plane", "0.1");
|
||||
#endif
|
||||
settings->setDefault("screen_w", "1024");
|
||||
settings->setDefault("screen_h", "600");
|
||||
settings->setDefault("screen_h", "768");
|
||||
settings->setDefault("autosave_screensize", "true");
|
||||
settings->setDefault("fullscreen", "false");
|
||||
settings->setDefault("vsync", "false");
|
||||
@ -207,12 +220,13 @@ void set_default_settings()
|
||||
settings->setDefault("cinematic_camera_smoothing", "0.7");
|
||||
settings->setDefault("enable_clouds", "true");
|
||||
settings->setDefault("view_bobbing_amount", "1.0");
|
||||
settings->setDefault("fall_bobbing_amount", "0.03");
|
||||
settings->setDefault("fall_bobbing_amount", "1.0");
|
||||
settings->setDefault("enable_3d_clouds", "true");
|
||||
settings->setDefault("cloud_radius", "12");
|
||||
settings->setDefault("menu_clouds", "true");
|
||||
settings->setDefault("opaque_water", "false");
|
||||
settings->setDefault("console_height", "0.6");
|
||||
settings->setDefault("console_message_height", "0.25");
|
||||
settings->setDefault("console_color", "(0,0,0)");
|
||||
settings->setDefault("console_alpha", "200");
|
||||
settings->setDefault("formspec_fullscreen_bg_color", "(0,0,0)");
|
||||
@ -220,21 +234,24 @@ void set_default_settings()
|
||||
settings->setDefault("formspec_default_bg_color", "(0,0,0)");
|
||||
settings->setDefault("formspec_default_bg_opacity", "140");
|
||||
settings->setDefault("selectionbox_color", "(0,0,0)");
|
||||
settings->setDefault("selectionbox_width", "2");
|
||||
settings->setDefault("selectionbox_width", "4");
|
||||
settings->setDefault("node_highlighting", "box");
|
||||
settings->setDefault("crosshair_color", "(255,255,255)");
|
||||
settings->setDefault("crosshair_alpha", "255");
|
||||
settings->setDefault("recent_chat_messages", "6");
|
||||
settings->setDefault("recent_chat_messages", "10");
|
||||
settings->setDefault("hud_scaling", "1.0");
|
||||
settings->setDefault("gui_scaling", "1.0");
|
||||
settings->setDefault("gui_scaling_filter", "false");
|
||||
settings->setDefault("gui_scaling_filter_txr2img", "true");
|
||||
settings->setDefault("desynchronize_mapblock_texture_animation", "true");
|
||||
settings->setDefault("hud_hotbar_max_width", "1.0");
|
||||
settings->setDefault("hud_move_upwards", "0");
|
||||
settings->setDefault("round_screen", "0");
|
||||
settings->setDefault("enable_local_map_saving", "false");
|
||||
settings->setDefault("show_entity_selectionbox", "false");
|
||||
settings->setDefault("transparency_sorting", "true");
|
||||
settings->setDefault("texture_clean_transparent", "false");
|
||||
settings->setDefault("texture_min_size", "64");
|
||||
settings->setDefault("texture_min_size", "0");
|
||||
settings->setDefault("ambient_occlusion_gamma", "1.8");
|
||||
#if ENABLE_GLES
|
||||
settings->setDefault("enable_shaders", "false");
|
||||
@ -243,11 +260,11 @@ void set_default_settings()
|
||||
#endif
|
||||
settings->setDefault("enable_particles", "true");
|
||||
settings->setDefault("arm_inertia", "true");
|
||||
settings->setDefault("show_nametag_backgrounds", "true");
|
||||
settings->setDefault("show_nametag_backgrounds", "false");
|
||||
|
||||
settings->setDefault("enable_minimap", "true");
|
||||
settings->setDefault("minimap_shape_round", "true");
|
||||
settings->setDefault("minimap_double_scan_height", "true");
|
||||
settings->setDefault("minimap_double_scan_height", "false");
|
||||
|
||||
// Effects
|
||||
settings->setDefault("directional_colored_fog", "true");
|
||||
@ -286,39 +303,53 @@ void set_default_settings()
|
||||
settings->setDefault("aux1_descends", "false");
|
||||
settings->setDefault("doubletap_jump", "false");
|
||||
settings->setDefault("always_fly_fast", "true");
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
settings->setDefault("autojump", "true");
|
||||
#else
|
||||
settings->setDefault("autojump", "false");
|
||||
#endif
|
||||
settings->setDefault("continuous_forward", "false");
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
settings->setDefault("enable_joysticks", "true");
|
||||
#else
|
||||
settings->setDefault("enable_joysticks", "false");
|
||||
#endif
|
||||
settings->setDefault("joystick_id", "0");
|
||||
settings->setDefault("joystick_type", "");
|
||||
settings->setDefault("repeat_joystick_button_time", "0.17");
|
||||
settings->setDefault("joystick_frustum_sensitivity", "170");
|
||||
settings->setDefault("joystick_deadzone", "2048");
|
||||
settings->setDefault("joystick_deadzone", "4096");
|
||||
|
||||
// Main menu
|
||||
settings->setDefault("main_menu_path", "");
|
||||
settings->setDefault("serverlist_file", "favoriteservers.json");
|
||||
|
||||
// General font settings
|
||||
std::string MultiCraftFont = porting::getDataPath("fonts" DIR_DELIM "MultiCraftFont.ttf");
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(__APPLE__)
|
||||
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "Arimo-Regular.ttf"));
|
||||
settings->setDefault("font_path_italic", porting::getDataPath("fonts" DIR_DELIM "Arimo-Italic.ttf"));
|
||||
settings->setDefault("font_path_bold", porting::getDataPath("fonts" DIR_DELIM "Arimo-Bold.ttf"));
|
||||
settings->setDefault("font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "Arimo-BoldItalic.ttf"));
|
||||
#else
|
||||
settings->setDefault("font_path", MultiCraftFont);
|
||||
settings->setDefault("font_path_italic", MultiCraftFont);
|
||||
settings->setDefault("font_path_bold", MultiCraftFont);
|
||||
settings->setDefault("font_path_bold_italic", MultiCraftFont);
|
||||
#endif
|
||||
settings->setDefault("font_bold", "false");
|
||||
settings->setDefault("font_italic", "false");
|
||||
settings->setDefault("font_shadow", "1");
|
||||
settings->setDefault("font_shadow_alpha", "127");
|
||||
settings->setDefault("font_size_divisible_by", "1");
|
||||
settings->setDefault("mono_font_path", porting::getDataPath("fonts" DIR_DELIM "Cousine-Regular.ttf"));
|
||||
settings->setDefault("mono_font_path_italic", porting::getDataPath("fonts" DIR_DELIM "Cousine-Italic.ttf"));
|
||||
settings->setDefault("mono_font_path_bold", porting::getDataPath("fonts" DIR_DELIM "Cousine-Bold.ttf"));
|
||||
settings->setDefault("mono_font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "Cousine-BoldItalic.ttf"));
|
||||
settings->setDefault("mono_font_path", MultiCraftFont);
|
||||
settings->setDefault("mono_font_path_italic", MultiCraftFont);
|
||||
settings->setDefault("mono_font_path_bold", MultiCraftFont);
|
||||
settings->setDefault("mono_font_path_bold_italic", MultiCraftFont);
|
||||
settings->setDefault("mono_font_size_divisible_by", "1");
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(__APPLE__)
|
||||
settings->setDefault("fallback_font_path", porting::getDataPath("fonts" DIR_DELIM "DroidSansFallbackFull.ttf"));
|
||||
#else
|
||||
settings->setDefault("fallback_font_path", MultiCraftFont);
|
||||
#endif
|
||||
|
||||
std::string font_size_str = std::to_string(TTF_DEFAULT_FONT_SIZE);
|
||||
settings->setDefault("font_size", font_size_str);
|
||||
@ -326,7 +357,7 @@ void set_default_settings()
|
||||
settings->setDefault("chat_font_size", "0"); // Default "font_size"
|
||||
|
||||
// ContentDB
|
||||
settings->setDefault("contentdb_url", "https://content.minetest.net");
|
||||
settings->setDefault("contentdb_url", "https://content.multicraft.world");
|
||||
settings->setDefault("contentdb_max_concurrent_downloads", "3");
|
||||
|
||||
#ifdef __ANDROID__
|
||||
@ -335,10 +366,20 @@ void set_default_settings()
|
||||
settings->setDefault("contentdb_flag_blacklist", "nonfree, desktop_default");
|
||||
#endif
|
||||
|
||||
settings->setDefault("update_information_url", "https://updates.multicraft.world/app.json");
|
||||
#if ENABLE_UPDATE_CHECKER
|
||||
settings->setDefault("update_last_checked", "");
|
||||
#else
|
||||
settings->setDefault("update_last_checked", "disabled");
|
||||
#endif
|
||||
|
||||
// Server
|
||||
settings->setDefault("compat_player_model", "character.b3d,3d_armor_character.b3d,skinsdb_3d_armor_character_5.b3d");
|
||||
settings->setDefault("compat_send_original_model", "true");
|
||||
settings->setDefault("disable_texture_packs", "false");
|
||||
settings->setDefault("disable_escape_sequences", "false");
|
||||
settings->setDefault("strip_color_codes", "false");
|
||||
settings->setDefault("strip_color_codes", "true");
|
||||
settings->setDefault("announce_mt", "true");
|
||||
#if USE_PROMETHEUS
|
||||
settings->setDefault("prometheus_listener_address", "127.0.0.1:30000");
|
||||
#endif
|
||||
@ -347,13 +388,14 @@ void set_default_settings()
|
||||
settings->setDefault("enable_ipv6", "true");
|
||||
settings->setDefault("ipv6_server", "false");
|
||||
settings->setDefault("max_packets_per_iteration","1024");
|
||||
settings->setDefault("port", "30000");
|
||||
settings->setDefault("port", "40000");
|
||||
settings->setDefault("enable_protocol_compat", "true");
|
||||
settings->setDefault("strict_protocol_version_checking", "false");
|
||||
settings->setDefault("player_transfer_distance", "0");
|
||||
settings->setDefault("max_simultaneous_block_sends_per_client", "40");
|
||||
settings->setDefault("time_send_interval", "5");
|
||||
|
||||
settings->setDefault("default_game", "minetest");
|
||||
settings->setDefault("default_game", "default");
|
||||
settings->setDefault("motd", "");
|
||||
settings->setDefault("max_users", "15");
|
||||
settings->setDefault("creative_mode", "false");
|
||||
@ -361,7 +403,7 @@ void set_default_settings()
|
||||
settings->setDefault("default_password", "");
|
||||
settings->setDefault("default_privs", "interact, shout");
|
||||
settings->setDefault("enable_pvp", "true");
|
||||
settings->setDefault("enable_mod_channels", "false");
|
||||
settings->setDefault("enable_mod_channels", "true");
|
||||
settings->setDefault("disallow_empty_password", "false");
|
||||
settings->setDefault("disable_anticheat", "false");
|
||||
settings->setDefault("enable_rollback_recording", "false");
|
||||
@ -371,7 +413,7 @@ void set_default_settings()
|
||||
settings->setDefault("kick_msg_crash", "This server has experienced an internal error. You will now be disconnected.");
|
||||
settings->setDefault("ask_reconnect_on_crash", "false");
|
||||
|
||||
settings->setDefault("chat_message_format", "<@name> @message");
|
||||
settings->setDefault("chat_message_format", "@name: @message");
|
||||
settings->setDefault("profiler_print_interval", "0");
|
||||
settings->setDefault("active_object_send_range_blocks", "8");
|
||||
settings->setDefault("active_block_range", "4");
|
||||
@ -380,7 +422,7 @@ void set_default_settings()
|
||||
settings->setDefault("max_block_send_distance", "12");
|
||||
settings->setDefault("block_send_optimize_distance", "4");
|
||||
settings->setDefault("server_side_occlusion_culling", "true");
|
||||
settings->setDefault("csm_restriction_flags", "62");
|
||||
settings->setDefault("csm_restriction_flags", "60");
|
||||
settings->setDefault("csm_restriction_noderange", "0");
|
||||
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
|
||||
settings->setDefault("time_speed", "72");
|
||||
@ -389,7 +431,7 @@ void set_default_settings()
|
||||
settings->setDefault("max_objects_per_block", "64");
|
||||
settings->setDefault("server_map_save_interval", "5.3");
|
||||
settings->setDefault("chat_message_max_size", "500");
|
||||
settings->setDefault("chat_message_limit_per_10sec", "8.0");
|
||||
settings->setDefault("chat_message_limit_per_10sec", "5.0");
|
||||
settings->setDefault("chat_message_limit_trigger_kick", "50");
|
||||
settings->setDefault("sqlite_synchronous", "2");
|
||||
settings->setDefault("map_compression_level_disk", "-1");
|
||||
@ -402,13 +444,14 @@ void set_default_settings()
|
||||
settings->setDefault("nodetimer_interval", "0.2");
|
||||
settings->setDefault("ignore_world_load_errors", "false");
|
||||
settings->setDefault("remote_media", "");
|
||||
settings->setDefault("debug_log_level", "action");
|
||||
settings->setDefault("debug_log_level", "warning");
|
||||
settings->setDefault("debug_log_size_max", "50");
|
||||
settings->setDefault("chat_log_level", "error");
|
||||
settings->setDefault("emergequeue_limit_total", "1024");
|
||||
settings->setDefault("emergequeue_limit_diskonly", "128");
|
||||
settings->setDefault("emergequeue_limit_generate", "128");
|
||||
settings->setDefault("num_emerge_threads", "1");
|
||||
settings->setDefault("log_mod_memory_usage_on_load", "false");
|
||||
settings->setDefault("secure.enable_security", "true");
|
||||
settings->setDefault("secure.trusted_mods", "");
|
||||
settings->setDefault("secure.http_mods", "");
|
||||
@ -416,7 +459,7 @@ void set_default_settings()
|
||||
// Physics
|
||||
settings->setDefault("movement_acceleration_default", "3");
|
||||
settings->setDefault("movement_acceleration_air", "2");
|
||||
settings->setDefault("movement_acceleration_fast", "10");
|
||||
settings->setDefault("movement_acceleration_fast", "20");
|
||||
settings->setDefault("movement_speed_walk", "4");
|
||||
settings->setDefault("movement_speed_crouch", "1.35");
|
||||
settings->setDefault("movement_speed_fast", "20");
|
||||
@ -424,7 +467,7 @@ void set_default_settings()
|
||||
settings->setDefault("movement_speed_jump", "6.5");
|
||||
settings->setDefault("movement_liquid_fluidity", "1");
|
||||
settings->setDefault("movement_liquid_fluidity_smooth", "0.5");
|
||||
settings->setDefault("movement_liquid_sink", "10");
|
||||
settings->setDefault("movement_liquid_sink", "20");
|
||||
settings->setDefault("movement_gravity", "9.81");
|
||||
|
||||
// Liquids
|
||||
@ -433,7 +476,7 @@ void set_default_settings()
|
||||
settings->setDefault("liquid_update", "1.0");
|
||||
|
||||
// Mapgen
|
||||
settings->setDefault("mg_name", "v7");
|
||||
settings->setDefault("mg_name", "v7p");
|
||||
settings->setDefault("water_level", "1");
|
||||
settings->setDefault("mapgen_limit", "31007");
|
||||
settings->setDefault("chunksize", "5");
|
||||
@ -453,60 +496,249 @@ void set_default_settings()
|
||||
settings->setDefault("screen_dpi", "72");
|
||||
settings->setDefault("display_density_factor", "1");
|
||||
|
||||
settings->setDefault("device_is_tablet", "false");
|
||||
|
||||
// Altered settings for macOS
|
||||
#if defined(__MACH__) && defined(__APPLE__)
|
||||
settings->setDefault("keymap_sneak", "KEY_SHIFT");
|
||||
settings->setDefault("fps_max", "0");
|
||||
#if defined(__MACH__) && defined(__APPLE__) && !defined(__IOS__)
|
||||
settings->setDefault("screen_w", "0");
|
||||
settings->setDefault("screen_h", "0");
|
||||
settings->setDefault("keymap_camera_mode", "KEY_KEY_C");
|
||||
settings->setDefault("vsync", "true");
|
||||
|
||||
int ScaleFactor = (int) [NSScreen mainScreen].backingScaleFactor;
|
||||
settings->setDefault("screen_dpi", std::to_string(ScaleFactor * 72));
|
||||
if (ScaleFactor >= 2) {
|
||||
settings->setDefault("hud_scaling", "1.5");
|
||||
} else {
|
||||
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE - 2));
|
||||
settings->setDefault("hud_scaling", "1.25");
|
||||
settings->setDefault("gui_scaling", "1.5");
|
||||
}
|
||||
|
||||
// Shaders work but may reduce performance on iGPU
|
||||
settings->setDefault("enable_shaders", "false");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
settings->setDefault("touchtarget", "true");
|
||||
settings->setDefault("touchscreen_threshold","20");
|
||||
settings->setDefault("fixed_virtual_joystick", "false");
|
||||
settings->setDefault("touchscreen_threshold", "20");
|
||||
settings->setDefault("touch_sensitivity", "0.2");
|
||||
settings->setDefault("fixed_virtual_joystick", "true");
|
||||
settings->setDefault("virtual_joystick_triggers_aux1", "false");
|
||||
settings->setDefault("fast_move", "true");
|
||||
#endif
|
||||
// Altered settings for Android
|
||||
#ifdef __ANDROID__
|
||||
settings->setDefault("screen_w", "0");
|
||||
settings->setDefault("screen_h", "0");
|
||||
|
||||
// Mobile Platform
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
settings->setDefault("fullscreen", "true");
|
||||
settings->setDefault("smooth_lighting", "false");
|
||||
settings->setDefault("performance_tradeoffs", "true");
|
||||
settings->setDefault("max_simultaneous_block_sends_per_client", "10");
|
||||
settings->setDefault("emergequeue_limit_diskonly", "16");
|
||||
settings->setDefault("emergequeue_limit_generate", "16");
|
||||
settings->setDefault("max_block_generate_distance", "5");
|
||||
settings->setDefault("enable_3d_clouds", "false");
|
||||
settings->setDefault("curl_verify_cert", "false");
|
||||
settings->setDefault("max_objects_per_block", "16");
|
||||
settings->setDefault("doubletap_jump", "true");
|
||||
settings->setDefault("gui_scaling_filter_txr2img", "false");
|
||||
settings->setDefault("autosave_screensize", "false");
|
||||
settings->setDefault("recent_chat_messages", "6");
|
||||
|
||||
// Set the optimal settings depending on the memory size [Android] | model [iOS]
|
||||
#ifdef __ANDROID__
|
||||
float memoryMax = porting::getTotalSystemMemory();
|
||||
|
||||
if (memoryMax < 2) {
|
||||
// minimal settings for less than 2GB RAM
|
||||
#elif __IOS__
|
||||
if (false) {
|
||||
// obsolete
|
||||
#endif
|
||||
settings->setDefault("client_unload_unused_data_timeout", "60");
|
||||
settings->setDefault("client_mapblock_limit", "50");
|
||||
settings->setDefault("fps_max", "30");
|
||||
settings->setDefault("fps_max_unfocused", "10");
|
||||
settings->setDefault("max_objects_per_block", "20");
|
||||
settings->setDefault("sqlite_synchronous", "1");
|
||||
settings->setDefault("map_compression_level_disk", "-1");
|
||||
settings->setDefault("map_compression_level_net", "-1");
|
||||
settings->setDefault("server_map_save_interval", "15");
|
||||
settings->setDefault("client_mapblock_limit", "1000");
|
||||
settings->setDefault("viewing_range", "30");
|
||||
settings->setDefault("smooth_lighting", "false");
|
||||
settings->setDefault("enable_3d_clouds", "false");
|
||||
settings->setDefault("active_object_send_range_blocks", "1");
|
||||
settings->setDefault("active_block_range", "1");
|
||||
settings->setDefault("dedicated_server_step", "0.2");
|
||||
settings->setDefault("abm_interval", "3.0");
|
||||
settings->setDefault("chunksize", "3");
|
||||
settings->setDefault("max_block_generate_distance", "1");
|
||||
settings->setDefault("arm_inertia", "false");
|
||||
#ifdef __ANDROID__
|
||||
} else if (memoryMax >= 2 && memoryMax < 4) {
|
||||
// low settings for 2-4GB RAM
|
||||
#elif __IOS__
|
||||
} else if (!IOS_VERSION_AVAILABLE("13.0")) {
|
||||
// low settings
|
||||
#endif
|
||||
settings->setDefault("client_unload_unused_data_timeout", "120");
|
||||
settings->setDefault("client_mapblock_limit", "200");
|
||||
settings->setDefault("fps_max", "35");
|
||||
settings->setDefault("fps_max_unfocused", "10");
|
||||
settings->setDefault("viewing_range", "40");
|
||||
settings->setDefault("smooth_lighting", "false");
|
||||
settings->setDefault("active_object_send_range_blocks", "1");
|
||||
settings->setDefault("active_block_range", "2");
|
||||
settings->setDefault("viewing_range", "50");
|
||||
settings->setDefault("leaves_style", "simple");
|
||||
settings->setDefault("curl_verify_cert","false");
|
||||
settings->setDefault("dedicated_server_step", "0.2");
|
||||
settings->setDefault("abm_interval", "2.0");
|
||||
settings->setDefault("chunksize", "3");
|
||||
settings->setDefault("max_block_generate_distance", "2");
|
||||
settings->setDefault("arm_inertia", "false");
|
||||
#ifdef __ANDROID__
|
||||
} else if (memoryMax >= 4 && memoryMax < 6) {
|
||||
// medium settings for 4.1-6GB RAM
|
||||
#elif __IOS__
|
||||
} else if (([SDVersion deviceVersion] == iPhone6S) || ([SDVersion deviceVersion] == iPhone6SPlus) || ([SDVersion deviceVersion] == iPhoneSE) ||
|
||||
([SDVersion deviceVersion] == iPhone7) || ([SDVersion deviceVersion] == iPhone7Plus) ||
|
||||
([SDVersion deviceVersion] == iPadMini4) || ([SDVersion deviceVersion] == iPadAir2) || ([SDVersion deviceVersion] == iPad5))
|
||||
{
|
||||
// medium settings
|
||||
#endif
|
||||
settings->setDefault("client_unload_unused_data_timeout", "180");
|
||||
settings->setDefault("client_mapblock_limit", "300");
|
||||
settings->setDefault("fps_max", "35");
|
||||
settings->setDefault("viewing_range", "60");
|
||||
settings->setDefault("active_object_send_range_blocks", "2");
|
||||
settings->setDefault("active_block_range", "2");
|
||||
settings->setDefault("max_block_generate_distance", "3");
|
||||
} else {
|
||||
// high settings
|
||||
settings->setDefault("client_mapblock_limit", "500");
|
||||
settings->setDefault("viewing_range", "125");
|
||||
settings->setDefault("active_object_send_range_blocks", "4");
|
||||
settings->setDefault("max_block_generate_distance", "5");
|
||||
|
||||
// Apply settings according to screen size
|
||||
float x_inches = (float) porting::getDisplaySize().X /
|
||||
(160.f * porting::getDisplayDensity());
|
||||
|
||||
if (x_inches < 3.7f) {
|
||||
settings->setDefault("hud_scaling", "0.6");
|
||||
settings->setDefault("font_size", "14");
|
||||
settings->setDefault("mono_font_size", "14");
|
||||
} else if (x_inches < 4.5f) {
|
||||
settings->setDefault("hud_scaling", "0.7");
|
||||
settings->setDefault("font_size", "14");
|
||||
settings->setDefault("mono_font_size", "14");
|
||||
} else if (x_inches < 6.0f) {
|
||||
settings->setDefault("hud_scaling", "0.85");
|
||||
settings->setDefault("font_size", "14");
|
||||
settings->setDefault("mono_font_size", "14");
|
||||
// enable visual shader effects
|
||||
settings->setDefault("enable_waving_water", "true");
|
||||
settings->setDefault("enable_waving_leaves", "true");
|
||||
settings->setDefault("enable_waving_plants", "true");
|
||||
}
|
||||
// Tablets >= 6.0 use non-Android defaults for these settings
|
||||
|
||||
// Android Settings
|
||||
#ifdef __ANDROID__
|
||||
// Switch to olges2 with shaders on powerful Android devices
|
||||
if (memoryMax >= 6) {
|
||||
settings->setDefault("video_driver", "ogles2");
|
||||
settings->setDefault("enable_shaders", "true");
|
||||
} else {
|
||||
settings->setDefault("video_driver", "ogles1");
|
||||
settings->setDefault("enable_shaders", "false");
|
||||
}
|
||||
|
||||
v2u32 window_size = RenderingEngine::getDisplaySize();
|
||||
if (window_size.X > 0) {
|
||||
float x_inches = window_size.X / (160.f * RenderingEngine::getDisplayDensity());
|
||||
if (x_inches <= 3.7) {
|
||||
// small 4" phones
|
||||
g_settings->setDefault("hud_scaling", "0.55");
|
||||
g_settings->setDefault("touch_sensitivity", "0.3");
|
||||
} else if (x_inches > 3.7 && x_inches <= 4.5) {
|
||||
// medium phones
|
||||
g_settings->setDefault("hud_scaling", "0.6");
|
||||
g_settings->setDefault("selectionbox_width", "6");
|
||||
} else if (x_inches > 4.5 && x_inches <= 5.5) {
|
||||
// large 6" phones
|
||||
g_settings->setDefault("hud_scaling", "0.7");
|
||||
g_settings->setDefault("selectionbox_width", "6");
|
||||
} else if (x_inches > 5.5 && x_inches <= 6.5) {
|
||||
// 7" tablets
|
||||
g_settings->setDefault("hud_scaling", "0.9");
|
||||
g_settings->setDefault("selectionbox_width", "6");
|
||||
} else if (x_inches >= 7.0) {
|
||||
settings->setDefault("device_is_tablet", "true");
|
||||
settings->setDefault("recent_chat_messages", "8");
|
||||
settings->setDefault("console_message_height", "0.4");
|
||||
}
|
||||
|
||||
if (x_inches <= 4.5) {
|
||||
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE - 1));
|
||||
} else if (x_inches >= 7.0) {
|
||||
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE + 1));
|
||||
}
|
||||
|
||||
// Settings for the Rounded or Cutout Screen
|
||||
int RoundScreen = porting::getRoundScreen();
|
||||
if (RoundScreen > 0)
|
||||
settings->setDefault("round_screen", std::to_string(RoundScreen));
|
||||
}
|
||||
#endif // Android
|
||||
|
||||
// iOS Settings
|
||||
#ifdef __IOS__
|
||||
// Switch to olges2 with shaders in new iOS versions
|
||||
if (IOS_VERSION_AVAILABLE("13.0")) {
|
||||
settings->setDefault("video_driver", "ogles2");
|
||||
settings->setDefault("enable_shaders", "true");
|
||||
} else {
|
||||
settings->setDefault("video_driver", "ogles1");
|
||||
settings->setDefault("enable_shaders", "false");
|
||||
}
|
||||
|
||||
settings->setDefault("debug_log_level", "none");
|
||||
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
settings->setDefault("device_is_tablet", "true");
|
||||
settings->setDefault("recent_chat_messages", "8");
|
||||
settings->setDefault("console_message_height", "0.4");
|
||||
}
|
||||
|
||||
// Set the size of the elements depending on the screen size
|
||||
if SDVersion4Inch {
|
||||
// 4" iPhone and iPod Touch
|
||||
settings->setDefault("hud_scaling", "0.55");
|
||||
settings->setDefault("touch_sensitivity", "0.33");
|
||||
} else if SDVersion4and7Inch {
|
||||
// 4.7" iPhone
|
||||
settings->setDefault("hud_scaling", "0.6");
|
||||
settings->setDefault("touch_sensitivity", "0.27");
|
||||
} else if SDVersion5and5Inch {
|
||||
// 5.5" iPhone Plus
|
||||
settings->setDefault("hud_scaling", "0.65");
|
||||
settings->setDefault("touch_sensitivity", "0.3");
|
||||
} else if (SDVersion5and8Inch || SDVersion6and1Inch) {
|
||||
// 5.8" and 6.1" iPhones
|
||||
settings->setDefault("hud_scaling", "0.8");
|
||||
settings->setDefault("touch_sensitivity", "0.35");
|
||||
settings->setDefault("selectionbox_width", "6");
|
||||
} else if SDVersion6and5Inch {
|
||||
// 6.5" iPhone
|
||||
settings->setDefault("hud_scaling", "0.85");
|
||||
settings->setDefault("touch_sensitivity", "0.35");
|
||||
settings->setDefault("selectionbox_width", "6");
|
||||
} else if SDVersion7and9Inch {
|
||||
// iPad mini
|
||||
settings->setDefault("hud_scaling", "0.9");
|
||||
settings->setDefault("touch_sensitivity", "0.25");
|
||||
settings->setDefault("selectionbox_width", "6");
|
||||
} else if SDVersion8and3Inch {
|
||||
settings->setDefault("touch_sensitivity", "0.25");
|
||||
settings->setDefault("selectionbox_width", "6");
|
||||
} else {
|
||||
// iPad
|
||||
settings->setDefault("touch_sensitivity", "0.3");
|
||||
settings->setDefault("selectionbox_width", "6");
|
||||
}
|
||||
|
||||
if SDVersion4Inch {
|
||||
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE - 2));
|
||||
} else if (SDVersion4and7Inch || SDVersion5and5Inch) {
|
||||
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE - 1));
|
||||
} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && !SDVersion7and9Inch) {
|
||||
settings->setDefault("font_size", std::to_string(TTF_DEFAULT_FONT_SIZE + 1));
|
||||
}
|
||||
|
||||
// Settings for the Rounded Screen and Home Bar
|
||||
if SDVersionRoundScreen {
|
||||
int upwards = 25, round = 40;
|
||||
if SDVersioniPhone12Series {
|
||||
upwards = 20, round = 90;
|
||||
} else if SDVersion8and3Inch {
|
||||
upwards = 15, round = 20;
|
||||
}
|
||||
|
||||
settings->setDefault("hud_move_upwards", std::to_string(upwards));
|
||||
settings->setDefault("round_screen", std::to_string(round));
|
||||
}
|
||||
#endif // iOS
|
||||
#endif
|
||||
}
|
||||
|
@ -316,12 +316,13 @@ bool IsDirDelimiter(char c)
|
||||
|
||||
bool RecursiveDelete(const std::string &path)
|
||||
{
|
||||
infostream<<"Removing \""<<path<<"\""<<std::endl;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
Execute the 'rm' command directly, by fork() and execve()
|
||||
*/
|
||||
|
||||
infostream<<"Removing \""<<path<<"\""<<std::endl;
|
||||
|
||||
pid_t child_pid = fork();
|
||||
|
||||
if(child_pid == 0)
|
||||
@ -356,6 +357,28 @@ bool RecursiveDelete(const std::string &path)
|
||||
}while(tpid != child_pid);
|
||||
return (child_status == 0);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
Executing fork() and execve() is unsafe and unavailable on some platforms
|
||||
*/
|
||||
|
||||
bool success = true;
|
||||
std::vector<std::string> paths;
|
||||
paths.push_back(path);
|
||||
fs::GetRecursiveSubPaths(path, paths, true, {});
|
||||
|
||||
// Go backwards to successfully delete the output of GetRecursiveSubPaths
|
||||
for (int i = paths.size() - 1; i >= 0; i--) {
|
||||
const std::string &p = paths[i];
|
||||
bool did = DeleteSingleFileOrEmptyDirectory(p);
|
||||
if (!did) {
|
||||
errorstream << "Failed to delete " << p << std::endl;
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DeleteSingleFileOrEmptyDirectory(const std::string &path)
|
||||
@ -387,7 +410,7 @@ std::string TempPath()
|
||||
configuration hardcodes mkstemp("/tmp/lua_XXXXXX").
|
||||
*/
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__APPLE__)
|
||||
return porting::path_cache;
|
||||
#else
|
||||
return DIR_DELIM "tmp";
|
||||
@ -796,7 +819,8 @@ bool safeWriteToFile(const std::string &path, const std::string &content)
|
||||
}
|
||||
|
||||
#ifndef SERVER
|
||||
bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string &destination)
|
||||
bool extractZipFile(io::IFileSystem *fs, const char *filename,
|
||||
const std::string &destination, const char *password, std::string *errorMessage)
|
||||
{
|
||||
// Be careful here not to touch the global file hierarchy in Irrlicht
|
||||
// since this function needs to be thread-safe!
|
||||
@ -814,6 +838,13 @@ bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string
|
||||
}
|
||||
|
||||
irr_ptr<io::IFileArchive> opened_zip(zip_loader->createArchive(filename, false, false));
|
||||
if (opened_zip.get() == nullptr) {
|
||||
if (errorMessage != nullptr)
|
||||
*errorMessage = "failed to open zip file";
|
||||
return false;
|
||||
}
|
||||
|
||||
opened_zip->Password = core::stringc(password);
|
||||
const io::IFileList* files_in_zip = opened_zip->getFileList();
|
||||
|
||||
for (u32 i = 0; i < files_in_zip->getFileCount(); i++) {
|
||||
@ -829,6 +860,14 @@ bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string
|
||||
|
||||
irr_ptr<io::IReadFile> toread(opened_zip->createAndOpenFile(i));
|
||||
|
||||
if (toread.get() == nullptr) {
|
||||
// Wrong password
|
||||
fs->removeFileArchive(fs->getFileArchiveCount()-1);
|
||||
if (errorMessage != nullptr)
|
||||
*errorMessage = "invalid password";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::ofstream os(fullpath.c_str(), std::ios::binary);
|
||||
if (!os.good())
|
||||
return false;
|
||||
|
@ -138,7 +138,9 @@ const char *GetFilenameFromPath(const char *path);
|
||||
bool safeWriteToFile(const std::string &path, const std::string &content);
|
||||
|
||||
#ifndef SERVER
|
||||
bool extractZipFile(irr::io::IFileSystem *fs, const char *filename, const std::string &destination);
|
||||
bool extractZipFile(irr::io::IFileSystem *fs, const char *filename,
|
||||
const std::string &destination, const char *password = "",
|
||||
std::string *errorMessage = nullptr);
|
||||
#endif
|
||||
|
||||
bool ReadFile(const std::string &path, std::string &out);
|
||||
|
@ -24,6 +24,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "gettext.h"
|
||||
#include "util/string.h"
|
||||
#include "log.h"
|
||||
#include "porting.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
#if USE_GETTEXT && defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
@ -131,6 +136,10 @@ void init_gettext(const char *path, const std::string &configured_language,
|
||||
setenv("LANG", configured_language.c_str(), 1);
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) || defined(__APPLE__)
|
||||
setenv("LANG", configured_language.c_str(), 1);
|
||||
#endif
|
||||
|
||||
// Reload locale with changed environment
|
||||
setlocale(LC_ALL, "");
|
||||
#elif defined(_MSC_VER)
|
||||
@ -207,6 +216,20 @@ void init_gettext(const char *path, const std::string &configured_language,
|
||||
}
|
||||
else {
|
||||
/* set current system default locale */
|
||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||
SDL_Locale* locale = SDL_GetPreferredLocales();
|
||||
|
||||
if (locale) {
|
||||
if (locale[0].language) {
|
||||
char lang[3] = {0};
|
||||
strncpy(lang, locale[0].language, 2);
|
||||
SDL_setenv("LANG", lang, 1);
|
||||
SDL_setenv("LANGUAGE", lang, 1);
|
||||
}
|
||||
|
||||
SDL_free(locale);
|
||||
}
|
||||
#endif
|
||||
setlocale(LC_ALL, "");
|
||||
}
|
||||
|
||||
@ -221,7 +244,7 @@ void init_gettext(const char *path, const std::string &configured_language,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
std::string name = lowercase(PROJECT_NAME);
|
||||
std::string name = "minetest";;
|
||||
infostream << "Gettext: domainname=\"" << name
|
||||
<< "\" path=\"" << path << "\"" << std::endl;
|
||||
|
||||
|
@ -19,7 +19,6 @@ set(gui_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiInventoryList.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiItemImage.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiKeyChangeMenu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiPasswordChange.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiPathSelectMenu.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiScene.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp
|
||||
|
@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "client/tile.h" // ITextureSource
|
||||
#include "client/fontengine.h"
|
||||
#include "client/renderingengine.h"
|
||||
#include "debug.h"
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "util/string.h"
|
||||
@ -45,6 +46,7 @@ public:
|
||||
BGIMG_PRESSED, // Note: Deprecated property
|
||||
FGIMG,
|
||||
FGIMG_HOVERED, // Note: Deprecated property
|
||||
FGIMG_MIDDLE,
|
||||
FGIMG_PRESSED, // Note: Deprecated property
|
||||
ALPHA,
|
||||
CONTENT_OFFSET,
|
||||
@ -57,6 +59,12 @@ public:
|
||||
SOUND,
|
||||
SPACING,
|
||||
SIZE,
|
||||
SCROLLBAR_BGIMG,
|
||||
SCROLLBAR_THUMB_IMG,
|
||||
SCROLLBAR_UP_IMG,
|
||||
SCROLLBAR_DOWN_IMG,
|
||||
SCROLLBAR_THUMB_TOP_IMG,
|
||||
SCROLLBAR_THUMB_BOTTOM_IMG,
|
||||
NUM_PROPERTIES,
|
||||
NONE
|
||||
};
|
||||
@ -69,6 +77,32 @@ public:
|
||||
STATE_INVALID = 1 << 3,
|
||||
};
|
||||
|
||||
// Used in guiConfirmRegistration.cpp, guiKeyChangeMenu.cpp and guiVolumeChange.h
|
||||
static std::array<StyleSpec, NUM_STATES> getButtonStyle(const std::string texture_path = "", std::string color = "") {
|
||||
std::array<StyleSpec, NUM_STATES> ret;
|
||||
color = color != "" ? "_" + color : "";
|
||||
|
||||
const bool high_dpi = RenderingEngine::isHighDpi();
|
||||
const std::string x2 = high_dpi ? ".x2" : "";
|
||||
StyleSpec btn_spec;
|
||||
btn_spec.set(BGIMG, texture_path + "gui/gui_button" + color + x2 + ".png");
|
||||
btn_spec.set(BGIMG_MIDDLE, high_dpi ? "48" : "32");
|
||||
btn_spec.set(BORDER, "false");
|
||||
btn_spec.set(PADDING, high_dpi ? "-30" : "-20");
|
||||
|
||||
ret[STATE_DEFAULT] = btn_spec;
|
||||
|
||||
StyleSpec hovered_spec;
|
||||
hovered_spec.set(BGIMG, texture_path + "gui/gui_button" + color + "_hovered" + x2 + ".png");
|
||||
ret[STATE_HOVERED] = hovered_spec;
|
||||
|
||||
StyleSpec pressed_spec;
|
||||
pressed_spec.set(BGIMG, texture_path + "gui/gui_button" + color + "_pressed" + x2 + ".png");
|
||||
ret[STATE_PRESSED] = pressed_spec;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<bool, NUM_PROPERTIES> property_set{};
|
||||
std::array<std::string, NUM_PROPERTIES> properties;
|
||||
@ -101,6 +135,8 @@ public:
|
||||
return FGIMG;
|
||||
} else if (name == "fgimg_hovered") {
|
||||
return FGIMG_HOVERED;
|
||||
} else if (name == "fgimg_middle") {
|
||||
return FGIMG_MIDDLE;
|
||||
} else if (name == "fgimg_pressed") {
|
||||
return FGIMG_PRESSED;
|
||||
} else if (name == "alpha") {
|
||||
@ -125,6 +161,18 @@ public:
|
||||
return SPACING;
|
||||
} else if (name == "size") {
|
||||
return SIZE;
|
||||
} else if (name == "scrollbar_bgimg") {
|
||||
return SCROLLBAR_BGIMG;
|
||||
} else if (name == "scrollbar_thumb_img") {
|
||||
return SCROLLBAR_THUMB_IMG;
|
||||
} else if (name == "scrollbar_up_img") {
|
||||
return SCROLLBAR_UP_IMG;
|
||||
} else if (name == "scrollbar_down_img") {
|
||||
return SCROLLBAR_DOWN_IMG;
|
||||
} else if (name == "scrollbar_thumb_top_img") {
|
||||
return SCROLLBAR_THUMB_TOP_IMG;
|
||||
} else if (name == "scrollbar_thumb_bottom_img") {
|
||||
return SCROLLBAR_THUMB_BOTTOM_IMG;
|
||||
} else {
|
||||
return NONE;
|
||||
}
|
||||
@ -176,9 +224,14 @@ public:
|
||||
{
|
||||
StyleSpec temp = styles[StyleSpec::STATE_DEFAULT];
|
||||
temp.state_map = state;
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
// always render pressed as hovered on touchscreen
|
||||
if (state & STATE_PRESSED)
|
||||
state = State(state | STATE_HOVERED);
|
||||
#endif
|
||||
for (int i = StyleSpec::STATE_DEFAULT + 1; i <= state; i++) {
|
||||
if ((state & i) != 0) {
|
||||
temp = temp | styles[i];
|
||||
temp |= styles[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,40 +9,37 @@
|
||||
#include <vector>
|
||||
|
||||
GUIAnimatedImage::GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
|
||||
s32 id, const core::rect<s32> &rectangle, const std::string &texture_name,
|
||||
s32 frame_count, s32 frame_duration, ISimpleTextureSource *tsrc) :
|
||||
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle), m_tsrc(tsrc)
|
||||
s32 id, const core::rect<s32> &rectangle) :
|
||||
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle)
|
||||
{
|
||||
m_texture = m_tsrc->getTexture(texture_name);
|
||||
|
||||
m_frame_count = std::max(frame_count, 1);
|
||||
m_frame_duration = std::max(frame_duration, 0);
|
||||
|
||||
if (m_texture != nullptr) {
|
||||
core::dimension2d<u32> size = m_texture->getOriginalSize();
|
||||
if (size.Height < (u64)m_frame_count)
|
||||
m_frame_count = size.Height;
|
||||
} else {
|
||||
// No need to step an animation if we have nothing to draw
|
||||
m_frame_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void GUIAnimatedImage::draw()
|
||||
{
|
||||
// Render the current frame
|
||||
if (m_texture != nullptr) {
|
||||
if (m_texture == nullptr)
|
||||
return;
|
||||
|
||||
video::IVideoDriver *driver = Environment->getVideoDriver();
|
||||
|
||||
const video::SColor color(255, 255, 255, 255);
|
||||
const video::SColor colors[] = {color, color, color, color};
|
||||
|
||||
core::dimension2d<u32> size = m_texture->getOriginalSize();
|
||||
|
||||
if ((u32)m_frame_count > size.Height)
|
||||
m_frame_count = size.Height;
|
||||
if (m_frame_idx >= m_frame_count)
|
||||
m_frame_idx = m_frame_count - 1;
|
||||
|
||||
size.Height /= m_frame_count;
|
||||
|
||||
draw2DImageFilterScaled(driver, m_texture, AbsoluteRect,
|
||||
core::rect<s32>(core::position2d<s32>(0, size.Height * m_frame_idx), size),
|
||||
NoClip ? nullptr : &AbsoluteClippingRect, colors, true);
|
||||
core::rect<s32> rect(core::position2d<s32>(0, size.Height * m_frame_idx), size);
|
||||
core::rect<s32> *cliprect = NoClip ? nullptr : &AbsoluteClippingRect;
|
||||
|
||||
if (m_middle.getArea() == 0) {
|
||||
const video::SColor color(255, 255, 255, 255);
|
||||
const video::SColor colors[] = {color, color, color, color};
|
||||
draw2DImageFilterScaled(driver, m_texture, AbsoluteRect, rect, cliprect,
|
||||
colors, true);
|
||||
} else {
|
||||
draw2DImage9Slice(driver, m_texture, AbsoluteRect, rect, m_middle, cliprect);
|
||||
}
|
||||
|
||||
// Step the animation
|
||||
@ -55,7 +52,7 @@ void GUIAnimatedImage::draw()
|
||||
m_global_time = new_global_time;
|
||||
|
||||
// Advance by the number of elapsed frames, looping if necessary
|
||||
m_frame_idx += u32(m_frame_time / m_frame_duration);
|
||||
m_frame_idx += (u32)(m_frame_time / m_frame_duration);
|
||||
m_frame_idx %= m_frame_count;
|
||||
|
||||
// If 1 or more frames have elapsed, reset the frame time counter with
|
||||
@ -63,11 +60,3 @@ void GUIAnimatedImage::draw()
|
||||
m_frame_time %= m_frame_duration;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GUIAnimatedImage::setFrameIndex(s32 frame)
|
||||
{
|
||||
s32 idx = std::max(frame, 0);
|
||||
if (idx > 0 && idx < m_frame_count)
|
||||
m_frame_idx = idx;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
class ISimpleTextureSource;
|
||||
@ -8,21 +9,33 @@ class ISimpleTextureSource;
|
||||
class GUIAnimatedImage : public gui::IGUIElement {
|
||||
public:
|
||||
GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
|
||||
s32 id, const core::rect<s32> &rectangle, const std::string &texture_name,
|
||||
s32 frame_count, s32 frame_duration, ISimpleTextureSource *tsrc);
|
||||
s32 id, const core::rect<s32> &rectangle);
|
||||
|
||||
virtual void draw() override;
|
||||
|
||||
void setFrameIndex(s32 frame);
|
||||
void setTexture(video::ITexture *texture) { m_texture = texture; };
|
||||
video::ITexture *getTexture() const { return m_texture; };
|
||||
|
||||
void setMiddleRect(const core::rect<s32> &middle) { m_middle = middle; };
|
||||
core::rect<s32> getMiddleRect() const { return m_middle; };
|
||||
|
||||
void setFrameDuration(u64 duration) { m_frame_duration = duration; };
|
||||
u64 getFrameDuration() const { return m_frame_duration; };
|
||||
|
||||
void setFrameCount(s32 count) { m_frame_count = std::max(count, 1); };
|
||||
s32 getFrameCount() const { return m_frame_count; };
|
||||
|
||||
void setFrameIndex(s32 frame) { m_frame_idx = std::max(frame, 0); };
|
||||
s32 getFrameIndex() const { return m_frame_idx; };
|
||||
|
||||
private:
|
||||
ISimpleTextureSource *m_tsrc;
|
||||
|
||||
video::ITexture *m_texture = nullptr;
|
||||
|
||||
u64 m_global_time = 0;
|
||||
s32 m_frame_idx = 0;
|
||||
s32 m_frame_count = 1;
|
||||
u64 m_frame_duration = 1;
|
||||
u64 m_frame_duration = 0;
|
||||
u64 m_frame_time = 0;
|
||||
|
||||
core::rect<s32> m_middle;
|
||||
};
|
||||
|
@ -48,21 +48,15 @@ void GUIBackgroundImage::draw()
|
||||
|
||||
video::IVideoDriver *driver = Environment->getVideoDriver();
|
||||
|
||||
core::rect<s32> srcrect(core::position2d<s32>(0, 0),
|
||||
core::dimension2di(texture->getOriginalSize()));
|
||||
|
||||
if (m_middle.getArea() == 0) {
|
||||
const video::SColor color(255, 255, 255, 255);
|
||||
const video::SColor colors[] = {color, color, color, color};
|
||||
draw2DImageFilterScaled(driver, texture, rect,
|
||||
core::rect<s32>(core::position2d<s32>(0, 0),
|
||||
core::dimension2di(texture->getOriginalSize())),
|
||||
nullptr, colors, true);
|
||||
draw2DImageFilterScaled(driver, texture, rect, srcrect, nullptr, colors, true);
|
||||
} else {
|
||||
core::rect<s32> middle = m_middle;
|
||||
// `-x` is interpreted as `w - x`
|
||||
if (middle.LowerRightCorner.X < 0)
|
||||
middle.LowerRightCorner.X += texture->getOriginalSize().Width;
|
||||
if (middle.LowerRightCorner.Y < 0)
|
||||
middle.LowerRightCorner.Y += texture->getOriginalSize().Height;
|
||||
draw2DImage9Slice(driver, texture, rect, middle);
|
||||
draw2DImage9Slice(driver, texture, rect, srcrect, m_middle);
|
||||
}
|
||||
|
||||
IGUIElement::draw();
|
||||
|
@ -320,15 +320,9 @@ void GUIButton::draw()
|
||||
sourceRect, &AbsoluteClippingRect,
|
||||
image_colors, UseAlphaChannel);
|
||||
} else {
|
||||
core::rect<s32> middle = BgMiddle;
|
||||
// `-x` is interpreted as `w - x`
|
||||
if (middle.LowerRightCorner.X < 0)
|
||||
middle.LowerRightCorner.X += texture->getOriginalSize().Width;
|
||||
if (middle.LowerRightCorner.Y < 0)
|
||||
middle.LowerRightCorner.Y += texture->getOriginalSize().Height;
|
||||
draw2DImage9Slice(driver, texture,
|
||||
ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
|
||||
middle, &AbsoluteClippingRect, image_colors);
|
||||
sourceRect, BgMiddle, &AbsoluteClippingRect, image_colors);
|
||||
}
|
||||
// END PATCH
|
||||
}
|
||||
@ -509,7 +503,12 @@ video::SColor GUIButton::getOverrideColor() const
|
||||
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
|
||||
video::SColor GUIButton::getActiveColor() const
|
||||
{
|
||||
return video::SColor(0,0,0,0); // unused?
|
||||
if (OverrideColorEnabled)
|
||||
return OverrideColor;
|
||||
IGUISkin* skin = Environment->getSkin();
|
||||
if (skin)
|
||||
return skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT);
|
||||
return OverrideColor;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -32,15 +32,15 @@ using namespace gui;
|
||||
GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment,
|
||||
gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle,
|
||||
ISimpleTextureSource *tsrc, bool noclip)
|
||||
: GUIButton (environment, parent, id, rectangle, tsrc, noclip)
|
||||
: GUIButton(environment, parent, id, rectangle, tsrc, noclip)
|
||||
{
|
||||
m_image = Environment->addImage(
|
||||
core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), this);
|
||||
m_image->setScaleImage(isScalingImage());
|
||||
GUIButton::setScaleImage(true);
|
||||
m_image = new GUIAnimatedImage(environment, this, id, rectangle);
|
||||
sendToBack(m_image);
|
||||
}
|
||||
|
||||
void GUIButtonImage::setForegroundImage(video::ITexture *image)
|
||||
void GUIButtonImage::setForegroundImage(video::ITexture *image,
|
||||
const core::rect<s32> &middle)
|
||||
{
|
||||
if (image == m_foreground_image)
|
||||
return;
|
||||
@ -52,11 +52,12 @@ void GUIButtonImage::setForegroundImage(video::ITexture *image)
|
||||
m_foreground_image->drop();
|
||||
|
||||
m_foreground_image = image;
|
||||
m_image->setImage(image);
|
||||
m_image->setTexture(image);
|
||||
m_image->setMiddleRect(middle);
|
||||
}
|
||||
|
||||
//! Set element properties from a StyleSpec
|
||||
void GUIButtonImage::setFromStyle(const StyleSpec& style)
|
||||
void GUIButtonImage::setFromStyle(const StyleSpec &style)
|
||||
{
|
||||
GUIButton::setFromStyle(style);
|
||||
|
||||
@ -67,19 +68,13 @@ void GUIButtonImage::setFromStyle(const StyleSpec& style)
|
||||
getTextureSource());
|
||||
|
||||
setForegroundImage(guiScalingImageButton(driver, texture,
|
||||
AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));
|
||||
setScaleImage(true);
|
||||
AbsoluteRect.getWidth(), AbsoluteRect.getHeight()),
|
||||
style.getRect(StyleSpec::FGIMG_MIDDLE, m_image->getMiddleRect()));
|
||||
} else {
|
||||
setForegroundImage(nullptr);
|
||||
setForegroundImage();
|
||||
}
|
||||
}
|
||||
|
||||
void GUIButtonImage::setScaleImage(bool scaleImage)
|
||||
{
|
||||
GUIButton::setScaleImage(scaleImage);
|
||||
m_image->setScaleImage(scaleImage);
|
||||
}
|
||||
|
||||
GUIButtonImage *GUIButtonImage::addButton(IGUIEnvironment *environment,
|
||||
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
|
||||
IGUIElement *parent, s32 id, const wchar_t *text,
|
||||
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "guiButton.h"
|
||||
#include "IGUIButton.h"
|
||||
#include "guiAnimatedImage.h"
|
||||
|
||||
using namespace irr;
|
||||
|
||||
@ -32,12 +33,11 @@ public:
|
||||
s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
|
||||
bool noclip = false);
|
||||
|
||||
void setForegroundImage(video::ITexture *image = nullptr);
|
||||
void setForegroundImage(video::ITexture *image = nullptr,
|
||||
const core::rect<s32> &middle = core::rect<s32>());
|
||||
|
||||
//! Set element properties from a StyleSpec
|
||||
virtual void setFromStyle(const StyleSpec& style) override;
|
||||
|
||||
virtual void setScaleImage(bool scaleImage=true) override;
|
||||
virtual void setFromStyle(const StyleSpec &style) override;
|
||||
|
||||
//! Do not drop returned handle
|
||||
static GUIButtonImage *addButton(gui::IGUIEnvironment *environment,
|
||||
@ -47,5 +47,5 @@ public:
|
||||
|
||||
private:
|
||||
video::ITexture *m_foreground_image = nullptr;
|
||||
gui::IGUIImage *m_image;
|
||||
GUIAnimatedImage *m_image;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,99 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "modalMenu.h"
|
||||
#include "chat.h"
|
||||
#include "config.h"
|
||||
#include "guiScrollBar.h"
|
||||
|
||||
struct ChatSelection
|
||||
{
|
||||
enum SelectionType {
|
||||
SELECTION_NONE,
|
||||
SELECTION_HISTORY,
|
||||
SELECTION_PROMPT
|
||||
};
|
||||
|
||||
ChatSelection() : selection_type(SELECTION_NONE), scroll(0), row(0),
|
||||
line_index(0), line(0), fragment(0), character(0), x_max(false) {};
|
||||
|
||||
void reset() {
|
||||
selection_type = SELECTION_NONE;
|
||||
scroll = 0;
|
||||
row = 0;
|
||||
line_index = 0;
|
||||
line = 0;
|
||||
fragment = 0;
|
||||
character = 0;
|
||||
x_max = false;
|
||||
}
|
||||
|
||||
bool operator== (const ChatSelection &other) const {
|
||||
if (selection_type == SELECTION_HISTORY &&
|
||||
other.selection_type == SELECTION_HISTORY) {
|
||||
return (row + scroll == other.row + other.scroll &&
|
||||
line_index == other.line_index &&
|
||||
line == other.line &&
|
||||
fragment == other.fragment &&
|
||||
character == other.character &&
|
||||
x_max == other.x_max);
|
||||
|
||||
} else {
|
||||
return (scroll + character == other.scroll + other.character &&
|
||||
x_max == other.x_max);
|
||||
}
|
||||
}
|
||||
|
||||
bool operator< (const ChatSelection &other) const {
|
||||
if (selection_type == SELECTION_HISTORY &&
|
||||
other.selection_type == SELECTION_HISTORY) {
|
||||
if (row + scroll != other.row + other.scroll)
|
||||
return (row + scroll < other.row + other.scroll);
|
||||
if (line_index != other.line_index)
|
||||
return (line_index < other.line_index);
|
||||
if (line != other.line)
|
||||
return (line < other.line);
|
||||
if (fragment != other.fragment)
|
||||
return (fragment < other.fragment);
|
||||
if (character != other.character)
|
||||
return (character < other.character);
|
||||
if (x_max != other.x_max)
|
||||
return (x_max < other.x_max);
|
||||
|
||||
return false;
|
||||
|
||||
} else {
|
||||
if (scroll + character != other.scroll + other.character)
|
||||
return (scroll + character < other.scroll + other.character);
|
||||
if (x_max != other.x_max)
|
||||
return (x_max < other.x_max);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator> (const ChatSelection &other) {
|
||||
return other < *this;
|
||||
}
|
||||
|
||||
bool operator<= (const ChatSelection &other) {
|
||||
return !(*this > other);
|
||||
}
|
||||
|
||||
bool operator>= (const ChatSelection &other) {
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
bool operator!= (const ChatSelection &other) const {
|
||||
return !this->operator==(other);
|
||||
}
|
||||
|
||||
SelectionType selection_type;
|
||||
int scroll;
|
||||
int row;
|
||||
int line_index;
|
||||
unsigned int line;
|
||||
unsigned int fragment;
|
||||
unsigned int character;
|
||||
bool x_max;
|
||||
};
|
||||
|
||||
class Client;
|
||||
|
||||
@ -50,8 +143,6 @@ public:
|
||||
// Close the console, equivalent to openConsole(0).
|
||||
// This doesn't close immediately but initiates an animation.
|
||||
void closeConsole();
|
||||
// Close the console immediately, without animation.
|
||||
void closeConsoleAtOnce();
|
||||
// Set whether to close the console after the user presses enter.
|
||||
void setCloseOnEnter(bool close) { m_close_on_enter = close; }
|
||||
|
||||
@ -74,6 +165,21 @@ public:
|
||||
|
||||
virtual bool acceptsIME() { return true; }
|
||||
|
||||
bool hasFocus();
|
||||
|
||||
bool convertToMouseEvent(
|
||||
SEvent &mouse_event, SEvent touch_event) const noexcept;
|
||||
|
||||
bool preprocessEvent(SEvent event);
|
||||
|
||||
bool getAndroidChatOpen() { return m_android_chat_open; }
|
||||
void setAndroidChatOpen(bool value) { m_android_chat_open = value; }
|
||||
|
||||
void onLinesModified();
|
||||
void onPromptModified();
|
||||
|
||||
static GUIChatConsole* getChatConsole() { return m_chat_console; }
|
||||
|
||||
private:
|
||||
void reformatConsole();
|
||||
void recalculateConsolePosition();
|
||||
@ -87,7 +193,19 @@ private:
|
||||
// If clicked fragment has a web url, send it to the system default web browser
|
||||
void middleClick(s32 col, s32 row);
|
||||
|
||||
ChatSelection getCursorPos(s32 x, s32 y);
|
||||
ChatSelection getPromptCursorPos(s32 x, s32 y);
|
||||
ChatSelection getCurrentPromptCursorPos();
|
||||
irr::core::stringc getSelectedText();
|
||||
irr::core::stringc getPromptSelectedText();
|
||||
void movePromptCursor(s32 x, s32 y);
|
||||
void deletePromptSelection();
|
||||
void createVScrollBar();
|
||||
void updateVScrollBar(bool force_update = false, bool move_bottom = false);
|
||||
|
||||
private:
|
||||
static GUIChatConsole* m_chat_console;
|
||||
|
||||
ChatBackend* m_chat_backend;
|
||||
Client* m_client;
|
||||
IMenuManager* m_menumgr;
|
||||
@ -134,4 +252,17 @@ private:
|
||||
bool m_cache_clickable_chat_weblinks;
|
||||
// Track if a ctrl key is currently held down
|
||||
bool m_is_ctrl_down;
|
||||
|
||||
ChatSelection m_mark_begin;
|
||||
ChatSelection m_mark_end;
|
||||
bool m_history_marking = false;
|
||||
bool m_prompt_marking = false;
|
||||
bool m_long_press = false;
|
||||
ChatSelection m_cursor_press_pos;
|
||||
|
||||
u32 m_scrollbar_width = 0;
|
||||
GUIScrollBar *m_vscrollbar = nullptr;
|
||||
s32 m_bottom_scroll_pos = 0;
|
||||
|
||||
bool m_android_chat_open = false;
|
||||
};
|
||||
|
@ -20,7 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "guiConfirmRegistration.h"
|
||||
#include "client/client.h"
|
||||
#include "filesys.h"
|
||||
#include "guiBackgroundImage.h"
|
||||
#include "guiButton.h"
|
||||
#include "guiEditBoxWithScrollbar.h"
|
||||
#include <IGUICheckBox.h>
|
||||
#include <IGUIButton.h>
|
||||
#include <IGUIStaticText.h>
|
||||
@ -32,6 +35,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "client/renderingengine.h"
|
||||
#endif
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
#include "gettext.h"
|
||||
|
||||
// Continuing from guiPasswordChange.cpp
|
||||
@ -40,6 +47,8 @@ const int ID_confirm = 263;
|
||||
const int ID_intotext = 264;
|
||||
const int ID_cancel = 265;
|
||||
const int ID_message = 266;
|
||||
const int ID_background = 267;
|
||||
const int ID_confirmPasswordBg = 268;
|
||||
|
||||
GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
|
||||
gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client,
|
||||
@ -52,11 +61,21 @@ GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
m_touchscreen_visible = false;
|
||||
#endif
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||
if (porting::hasRealKeyboard())
|
||||
SDL_StartTextInput();
|
||||
#endif
|
||||
}
|
||||
|
||||
GUIConfirmRegistration::~GUIConfirmRegistration()
|
||||
{
|
||||
removeChildren();
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||
if (porting::hasRealKeyboard() && SDL_IsTextInputActive())
|
||||
SDL_StopTextInput();
|
||||
#endif
|
||||
}
|
||||
|
||||
void GUIConfirmRegistration::removeChildren()
|
||||
@ -77,11 +96,13 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
|
||||
/*
|
||||
Calculate new sizes and positions
|
||||
*/
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
const float s = m_gui_scale * RenderingEngine::getDisplayDensity() / 2;
|
||||
float s = MYMIN(screensize.X / 600.f, screensize.Y / 360.f);
|
||||
#if HAVE_TOUCHSCREENGUI
|
||||
s *= g_settings->getBool("device_is_tablet") ? 0.7f : 0.8f;
|
||||
#else
|
||||
const float s = m_gui_scale;
|
||||
s *= 0.5f;
|
||||
#endif
|
||||
|
||||
DesiredRect = core::rect<s32>(
|
||||
screensize.X / 2 - 600 * s / 2,
|
||||
screensize.Y / 2 - 360 * s / 2,
|
||||
@ -98,11 +119,21 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
|
||||
/*
|
||||
Add stuff
|
||||
*/
|
||||
s32 ypos = 30 * s;
|
||||
|
||||
// Background image
|
||||
{
|
||||
const std::string texture = "bg_common.png";
|
||||
const core::rect<s32> rect(0, 0, 0, 0);
|
||||
const core::rect<s32> middle(40, 40, -40, -40);
|
||||
new GUIBackgroundImage(Environment, this, ID_background, rect,
|
||||
texture, middle, m_tsrc, true);
|
||||
}
|
||||
|
||||
s32 ypos = 20 * s;
|
||||
{
|
||||
core::rect<s32> rect2(0, 0, 540 * s, 180 * s);
|
||||
rect2 += topleft_client + v2s32(30 * s, ypos);
|
||||
static const std::string info_text_template = strgettext(
|
||||
const std::string info_text_template = strgettext(
|
||||
"You are about to join this server with the name \"%s\" for the "
|
||||
"first time.\n"
|
||||
"If you proceed, a new account using your credentials will be "
|
||||
@ -122,40 +153,54 @@ void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
|
||||
e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_CENTER);
|
||||
}
|
||||
|
||||
ypos += 200 * s;
|
||||
{
|
||||
core::rect<s32> rect2(0, 0, 540 * s, 30 * s);
|
||||
rect2 += topleft_client + v2s32(30 * s, ypos);
|
||||
gui::IGUIEditBox *e = Environment->addEditBox(m_pass_confirm.c_str(),
|
||||
rect2, true, this, ID_confirmPassword);
|
||||
e->setPasswordBox(true);
|
||||
Environment->setFocus(e);
|
||||
}
|
||||
|
||||
ypos += 50 * s;
|
||||
{
|
||||
core::rect<s32> rect2(0, 0, 230 * s, 35 * s);
|
||||
rect2 = rect2 + v2s32(size.X / 2 - 220 * s, ypos);
|
||||
text = wgettext("Register and Join");
|
||||
GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_confirm, text);
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect2(0, 0, 120 * s, 35 * s);
|
||||
rect2 = rect2 + v2s32(size.X / 2 + 70 * s, ypos);
|
||||
text = wgettext("Cancel");
|
||||
GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_cancel, text);
|
||||
delete[] text;
|
||||
}
|
||||
ypos += 140 * s;
|
||||
{
|
||||
core::rect<s32> rect2(0, 0, 500 * s, 40 * s);
|
||||
rect2 += topleft_client + v2s32(30 * s, ypos + 40 * s);
|
||||
rect2 += topleft_client + v2s32(30 * s, ypos + 45 * s);
|
||||
text = wgettext("Passwords do not match!");
|
||||
IGUIElement *e = Environment->addStaticText(
|
||||
text, rect2, false, true, this, ID_message);
|
||||
e->setVisible(false);
|
||||
delete[] text;
|
||||
}
|
||||
|
||||
ypos += 75 * s;
|
||||
{
|
||||
core::rect<s32> rect2(0, 0, 540 * s, 40 * s);
|
||||
rect2 += topleft_client + v2s32(30 * s, ypos);
|
||||
|
||||
core::rect<s32> bg_middle(10, 10, -10, -10);
|
||||
new GUIBackgroundImage(Environment, this, ID_confirmPasswordBg,
|
||||
rect2, "field_bg.png", bg_middle, m_tsrc, false);
|
||||
|
||||
rect2.UpperLeftCorner.X += 5 * s;
|
||||
rect2.LowerRightCorner.X -= 5 * s;
|
||||
|
||||
gui::IGUIEditBox *e = Environment->addEditBox(m_pass_confirm.c_str(),
|
||||
rect2, true, this, ID_confirmPassword);
|
||||
e->setDrawBorder(false);
|
||||
e->setDrawBackground(false);
|
||||
e->setPasswordBox(true);
|
||||
Environment->setFocus(e);
|
||||
}
|
||||
|
||||
ypos += 60 * s;
|
||||
{
|
||||
core::rect<s32> rect2(0, 0, 300 * s, 40 * s);
|
||||
rect2 = rect2 + v2s32(size.X / 2 - 250 * s, ypos);
|
||||
text = wgettext("Register and Join");
|
||||
GUIButton *e = GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_confirm, text);
|
||||
e->setStyles(StyleSpec::getButtonStyle("", "green"));
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect2(0, 0, 140 * s, 40 * s);
|
||||
rect2 = rect2 + v2s32(size.X / 2 + 110 * s, ypos);
|
||||
text = wgettext("Cancel");
|
||||
GUIButton *e = GUIButton::addButton(Environment, rect2, m_tsrc, this, ID_cancel, text);
|
||||
e->setStyles(StyleSpec::getButtonStyle());
|
||||
delete[] text;
|
||||
}
|
||||
}
|
||||
|
||||
void GUIConfirmRegistration::drawMenu()
|
||||
@ -163,13 +208,9 @@ void GUIConfirmRegistration::drawMenu()
|
||||
gui::IGUISkin *skin = Environment->getSkin();
|
||||
if (!skin)
|
||||
return;
|
||||
video::IVideoDriver *driver = Environment->getVideoDriver();
|
||||
|
||||
video::SColor bgcolor(140, 0, 0, 0);
|
||||
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
|
||||
|
||||
gui::IGUIElement::draw();
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
getAndroidUIInput();
|
||||
#endif
|
||||
}
|
||||
@ -257,10 +298,10 @@ bool GUIConfirmRegistration::OnEvent(const SEvent &event)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
bool GUIConfirmRegistration::getAndroidUIInput()
|
||||
{
|
||||
if (!hasAndroidUIInput() || m_jni_field_name != "password")
|
||||
if (m_jni_field_name.empty() || m_jni_field_name != "password")
|
||||
return false;
|
||||
|
||||
// still waiting
|
||||
|
@ -51,13 +51,16 @@ public:
|
||||
bool processInput();
|
||||
|
||||
bool OnEvent(const SEvent &event);
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
bool getAndroidUIInput();
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::wstring getLabelByID(s32 id) { return L""; }
|
||||
std::string getNameByID(s32 id) { return "password"; }
|
||||
std::string getNameByID(s32 id)
|
||||
{
|
||||
return id == 262 ? "password" : ""; // 262 is ID_confirmPassword
|
||||
}
|
||||
|
||||
Client *m_client = nullptr;
|
||||
const std::string &m_playername;
|
||||
@ -65,4 +68,5 @@ private:
|
||||
bool *m_aborted = nullptr;
|
||||
std::wstring m_pass_confirm = L"";
|
||||
ISimpleTextureSource *m_tsrc;
|
||||
video::SColor m_fullscreen_bgcolor;
|
||||
};
|
||||
|
@ -25,8 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "IGUIFont.h"
|
||||
|
||||
#include "porting.h"
|
||||
#include "touchscreengui.h"
|
||||
#include "util/string.h"
|
||||
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
GUIEditBox::~GUIEditBox()
|
||||
{
|
||||
if (m_override_font)
|
||||
@ -178,6 +183,8 @@ void GUIEditBox::setTextMarkers(s32 begin, s32 end)
|
||||
if (begin != m_mark_begin || end != m_mark_end) {
|
||||
m_mark_begin = begin;
|
||||
m_mark_end = end;
|
||||
m_real_mark_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
|
||||
m_real_mark_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
|
||||
sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED);
|
||||
}
|
||||
}
|
||||
@ -204,12 +211,28 @@ bool GUIEditBox::OnEvent(const SEvent &event)
|
||||
switch (event.EventType) {
|
||||
case EET_GUI_EVENT:
|
||||
if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) {
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (!TouchScreenGUI::isActive())
|
||||
#endif
|
||||
if (event.GUIEvent.Caller == this) {
|
||||
m_mouse_marking = false;
|
||||
setTextMarkers(0, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
case EET_SDL_TEXT_EVENT:
|
||||
if (event.SDLTextEvent.Type == irr::ESDLET_TEXTINPUT) {
|
||||
core::stringw text =
|
||||
utf8_to_stringw(event.SDLTextEvent.Text);
|
||||
|
||||
for (size_t i = 0; i < text.size(); i++)
|
||||
inputChar(text[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case EET_KEY_INPUT_EVENT:
|
||||
if (processKey(event))
|
||||
return true;
|
||||
@ -240,11 +263,21 @@ bool GUIEditBox::processKey(const SEvent &event)
|
||||
s32 new_mark_begin = m_mark_begin;
|
||||
s32 new_mark_end = m_mark_end;
|
||||
|
||||
// On Windows right alt simulates additional control press/release events.
|
||||
// It causes unexpected bahavior, for example right alt + A would clear text
|
||||
// in the edit box. At least for SDL we can easily check if alt key is
|
||||
// pressed
|
||||
bool altPressed = false;
|
||||
#if defined(_IRR_COMPILE_WITH_SDL_DEVICE_)
|
||||
SDL_Keymod keymod = SDL_GetModState();
|
||||
altPressed = keymod & KMOD_ALT;
|
||||
#endif
|
||||
|
||||
// control shortcut handling
|
||||
if (event.KeyInput.Control) {
|
||||
if (event.KeyInput.Control && !altPressed) {
|
||||
|
||||
// german backlash '\' entered with control + '?'
|
||||
if (event.KeyInput.Char == '\\') {
|
||||
if (m_writable && event.KeyInput.Char == '\\') {
|
||||
inputChar(event.KeyInput.Char);
|
||||
return true;
|
||||
}
|
||||
@ -259,10 +292,14 @@ bool GUIEditBox::processKey(const SEvent &event)
|
||||
onKeyControlC(event);
|
||||
break;
|
||||
case KEY_KEY_X:
|
||||
text_changed = onKeyControlX(event, new_mark_begin, new_mark_end);
|
||||
if (m_writable)
|
||||
text_changed = onKeyControlX(
|
||||
event, new_mark_begin, new_mark_end);
|
||||
break;
|
||||
case KEY_KEY_V:
|
||||
text_changed = onKeyControlV(event, new_mark_begin, new_mark_end);
|
||||
if (m_writable)
|
||||
text_changed = onKeyControlV(
|
||||
event, new_mark_begin, new_mark_end);
|
||||
break;
|
||||
case KEY_HOME:
|
||||
// move/highlight to start of text
|
||||
@ -288,6 +325,26 @@ bool GUIEditBox::processKey(const SEvent &event)
|
||||
new_mark_end = 0;
|
||||
}
|
||||
break;
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
case EET_TOUCH_INPUT_EVENT:
|
||||
if (event.TouchInput.Event == irr::ETIE_PRESSED_LONG) {
|
||||
if (!m_mouse_marking) {
|
||||
m_long_press = true;
|
||||
bool success = onKeyControlC(event);
|
||||
#ifdef __ANDROID__
|
||||
if (success)
|
||||
SDL_AndroidShowToast(
|
||||
"Copied to clipboard", 2,
|
||||
-1, 0, 0);
|
||||
#elif __IOS__
|
||||
if (success)
|
||||
porting::showToast("Copied to clipboard");
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -336,6 +393,7 @@ bool GUIEditBox::processKey(const SEvent &event)
|
||||
m_blink_start_time = porting::getTimeMs();
|
||||
} break;
|
||||
case KEY_RETURN:
|
||||
if (m_writable) {
|
||||
if (m_multiline) {
|
||||
inputChar(L'\n');
|
||||
} else {
|
||||
@ -343,6 +401,8 @@ bool GUIEditBox::processKey(const SEvent &event)
|
||||
sendGuiEvent(EGET_EDITBOX_ENTER);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
if (event.KeyInput.Shift) {
|
||||
if (m_cursor_pos > 0) {
|
||||
@ -388,11 +448,15 @@ bool GUIEditBox::processKey(const SEvent &event)
|
||||
}
|
||||
break;
|
||||
case KEY_BACK:
|
||||
text_changed = onKeyBack(event, new_mark_begin, new_mark_end);
|
||||
if (m_writable)
|
||||
text_changed = onKeyBack(
|
||||
event, new_mark_begin, new_mark_end);
|
||||
break;
|
||||
|
||||
case KEY_DELETE:
|
||||
text_changed = onKeyDelete(event, new_mark_begin, new_mark_end);
|
||||
if (m_writable)
|
||||
text_changed = onKeyDelete(
|
||||
event, new_mark_begin, new_mark_end);
|
||||
break;
|
||||
|
||||
case KEY_ESCAPE:
|
||||
@ -426,10 +490,12 @@ bool GUIEditBox::processKey(const SEvent &event)
|
||||
return false;
|
||||
|
||||
default:
|
||||
if (m_writable) {
|
||||
inputChar(event.KeyInput.Char);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set new text markers
|
||||
setTextMarkers(new_mark_begin, new_mark_end);
|
||||
@ -450,8 +516,7 @@ bool GUIEditBox::onKeyUp(const SEvent &event, s32 &mark_begin, s32 &mark_end)
|
||||
// clang-format off
|
||||
if (m_multiline || (m_word_wrap && m_broken_text.size() > 1)) {
|
||||
s32 lineNo = getLineFromPos(m_cursor_pos);
|
||||
s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos :
|
||||
(m_mark_begin > m_mark_end ? m_mark_begin : m_mark_end);
|
||||
s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos : m_real_mark_begin;
|
||||
if (lineNo > 0) {
|
||||
s32 cp = m_cursor_pos - m_broken_text_positions[lineNo];
|
||||
if ((s32)m_broken_text[lineNo - 1].size() < cp) {
|
||||
@ -482,8 +547,7 @@ bool GUIEditBox::onKeyDown(const SEvent &event, s32 &mark_begin, s32 &mark_end)
|
||||
// clang-format off
|
||||
if (m_multiline || (m_word_wrap && m_broken_text.size() > 1)) {
|
||||
s32 lineNo = getLineFromPos(m_cursor_pos);
|
||||
s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos :
|
||||
(m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end);
|
||||
s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos : m_real_mark_begin;
|
||||
if (lineNo < (s32)m_broken_text.size() - 1) {
|
||||
s32 cp = m_cursor_pos - m_broken_text_positions[lineNo];
|
||||
if ((s32)m_broken_text[lineNo + 1].size() < cp) {
|
||||
@ -509,17 +573,16 @@ bool GUIEditBox::onKeyDown(const SEvent &event, s32 &mark_begin, s32 &mark_end)
|
||||
return false;
|
||||
}
|
||||
|
||||
void GUIEditBox::onKeyControlC(const SEvent &event)
|
||||
bool GUIEditBox::onKeyControlC(const SEvent &event)
|
||||
{
|
||||
// copy to clipboard
|
||||
if (m_passwordbox || !m_operator || m_mark_begin == m_mark_end)
|
||||
return;
|
||||
return false;
|
||||
|
||||
const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
|
||||
const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
|
||||
|
||||
std::string s = stringw_to_utf8(Text.subString(realmbgn, realmend - realmbgn));
|
||||
std::string s = stringw_to_utf8(Text.subString(
|
||||
m_real_mark_begin, m_real_mark_end - m_real_mark_begin));
|
||||
m_operator->copyToClipboard(s.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GUIEditBox::onKeyControlX(const SEvent &event, s32 &mark_begin, s32 &mark_end)
|
||||
@ -533,18 +596,15 @@ bool GUIEditBox::onKeyControlX(const SEvent &event, s32 &mark_begin, s32 &mark_e
|
||||
if (m_passwordbox || !m_operator || m_mark_begin == m_mark_end)
|
||||
return false;
|
||||
|
||||
const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
|
||||
const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
|
||||
|
||||
// Now remove from box if enabled
|
||||
if (isEnabled()) {
|
||||
// delete
|
||||
core::stringw s;
|
||||
s = Text.subString(0, realmbgn);
|
||||
s.append(Text.subString(realmend, Text.size() - realmend));
|
||||
s = Text.subString(0, m_real_mark_begin);
|
||||
s.append(Text.subString(m_real_mark_end, Text.size() - m_real_mark_end));
|
||||
Text = s;
|
||||
|
||||
m_cursor_pos = realmbgn;
|
||||
m_cursor_pos = m_real_mark_begin;
|
||||
mark_begin = 0;
|
||||
mark_end = 0;
|
||||
return true;
|
||||
@ -562,9 +622,6 @@ bool GUIEditBox::onKeyControlV(const SEvent &event, s32 &mark_begin, s32 &mark_e
|
||||
if (!m_operator)
|
||||
return false;
|
||||
|
||||
const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
|
||||
const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
|
||||
|
||||
// add new character
|
||||
if (const c8 *p = m_operator->getTextFromClipboard()) {
|
||||
core::stringw inserted_text = utf8_to_stringw(p);
|
||||
@ -582,13 +639,14 @@ bool GUIEditBox::onKeyControlV(const SEvent &event, s32 &mark_begin, s32 &mark_e
|
||||
} else {
|
||||
// replace text
|
||||
|
||||
core::stringw s = Text.subString(0, realmbgn);
|
||||
core::stringw s = Text.subString(0, m_real_mark_begin);
|
||||
s.append(inserted_text);
|
||||
s.append(Text.subString(realmend, Text.size() - realmend));
|
||||
s.append(Text.subString(
|
||||
m_real_mark_end, Text.size() - m_real_mark_end));
|
||||
|
||||
if (!m_max || s.size() <= m_max) {
|
||||
Text = s;
|
||||
m_cursor_pos = realmbgn + inserted_text.size();
|
||||
m_cursor_pos = m_real_mark_begin + inserted_text.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -607,16 +665,11 @@ bool GUIEditBox::onKeyBack(const SEvent &event, s32 &mark_begin, s32 &mark_end)
|
||||
|
||||
if (m_mark_begin != m_mark_end) {
|
||||
// delete marked text
|
||||
const s32 realmbgn =
|
||||
m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
|
||||
const s32 realmend =
|
||||
m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
|
||||
|
||||
s = Text.subString(0, realmbgn);
|
||||
s.append(Text.subString(realmend, Text.size() - realmend));
|
||||
s = Text.subString(0, m_real_mark_begin);
|
||||
s.append(Text.subString(m_real_mark_end, Text.size() - m_real_mark_end));
|
||||
Text = s;
|
||||
|
||||
m_cursor_pos = realmbgn;
|
||||
m_cursor_pos = m_real_mark_begin;
|
||||
} else {
|
||||
// delete text behind cursor
|
||||
if (m_cursor_pos > 0)
|
||||
@ -645,16 +698,11 @@ bool GUIEditBox::onKeyDelete(const SEvent &event, s32 &mark_begin, s32 &mark_end
|
||||
|
||||
if (m_mark_begin != m_mark_end) {
|
||||
// delete marked text
|
||||
const s32 realmbgn =
|
||||
m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
|
||||
const s32 realmend =
|
||||
m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
|
||||
|
||||
s = Text.subString(0, realmbgn);
|
||||
s.append(Text.subString(realmend, Text.size() - realmend));
|
||||
s = Text.subString(0, m_real_mark_begin);
|
||||
s.append(Text.subString(m_real_mark_end, Text.size() - m_real_mark_end));
|
||||
Text = s;
|
||||
|
||||
m_cursor_pos = realmbgn;
|
||||
m_cursor_pos = m_real_mark_begin;
|
||||
} else {
|
||||
// delete text before cursor
|
||||
s = Text.subString(0, m_cursor_pos);
|
||||
@ -690,14 +738,11 @@ void GUIEditBox::inputString(const core::stringw &str)
|
||||
core::stringw s;
|
||||
if (m_mark_begin != m_mark_end) {
|
||||
// replace marked text
|
||||
s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
|
||||
s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
|
||||
|
||||
s = Text.subString(0, real_begin);
|
||||
s = Text.subString(0, m_real_mark_begin);
|
||||
s.append(str);
|
||||
s.append(Text.subString(real_end, Text.size() - real_end));
|
||||
s.append(Text.subString(m_real_mark_end, Text.size() - m_real_mark_end));
|
||||
Text = s;
|
||||
m_cursor_pos = real_begin + len;
|
||||
m_cursor_pos = m_real_mark_begin + 1;
|
||||
} else {
|
||||
// append string
|
||||
s = Text.subString(0, m_cursor_pos);
|
||||
@ -720,56 +765,106 @@ void GUIEditBox::inputString(const core::stringw &str)
|
||||
bool GUIEditBox::processMouse(const SEvent &event)
|
||||
{
|
||||
switch (event.MouseInput.Event) {
|
||||
case irr::EMIE_LMOUSE_LEFT_UP:
|
||||
if (Environment->hasFocus(this)) {
|
||||
m_cursor_pos = getCursorPos(
|
||||
event.MouseInput.X, event.MouseInput.Y);
|
||||
if (m_mouse_marking) {
|
||||
setTextMarkers(m_mark_begin, m_cursor_pos);
|
||||
case irr::EMIE_LMOUSE_LEFT_UP: {
|
||||
s32 cursor_pos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
// Remove text markers for short tap in one place
|
||||
if (TouchScreenGUI::isActive() && !m_long_press &&
|
||||
m_cursor_press_pos == cursor_pos &&
|
||||
Environment->hasFocus(this)) {
|
||||
setTextMarkers(cursor_pos, cursor_pos);
|
||||
}
|
||||
#endif
|
||||
m_cursor_press_pos = -1;
|
||||
m_long_press = false;
|
||||
if (Environment->hasFocus(this)) {
|
||||
m_cursor_pos = cursor_pos;
|
||||
m_mouse_marking = false;
|
||||
calculateScrollPos();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case irr::EMIE_MOUSE_MOVED: {
|
||||
s32 cursor_pos = getCursorPos(event.MouseInput.X, event.MouseInput.Y);
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
// Start text marking when cursor was moved, so that user doesn't want
|
||||
// to copy text.
|
||||
if (TouchScreenGUI::isActive() && !m_long_press && !m_mouse_marking &&
|
||||
m_cursor_press_pos != -1 &&
|
||||
cursor_pos != m_cursor_press_pos &&
|
||||
Environment->hasFocus(this)) {
|
||||
m_mouse_marking = true;
|
||||
|
||||
int mark_length = m_real_mark_end - m_real_mark_begin;
|
||||
|
||||
if (mark_length > 2 &&
|
||||
std::abs(m_cursor_press_pos - m_mark_begin) < 3)
|
||||
setTextMarkers(m_mark_end, m_cursor_press_pos);
|
||||
else if (mark_length > 2 &&
|
||||
std::abs(m_cursor_press_pos - m_mark_end) < 3)
|
||||
setTextMarkers(m_mark_begin, m_cursor_press_pos);
|
||||
else
|
||||
setTextMarkers(m_cursor_press_pos, m_cursor_press_pos);
|
||||
}
|
||||
#endif
|
||||
if (m_mouse_marking) {
|
||||
m_cursor_pos = getCursorPos(
|
||||
event.MouseInput.X, event.MouseInput.Y);
|
||||
m_cursor_pos = cursor_pos;
|
||||
setTextMarkers(m_mark_begin, m_cursor_pos);
|
||||
calculateScrollPos();
|
||||
return true;
|
||||
}
|
||||
} break;
|
||||
case EMIE_LMOUSE_PRESSED_DOWN:
|
||||
case EMIE_LMOUSE_PRESSED_DOWN: {
|
||||
m_long_press = false;
|
||||
|
||||
if (!Environment->hasFocus(this)) {
|
||||
m_blink_start_time = porting::getTimeMs();
|
||||
m_mouse_marking = true;
|
||||
m_cursor_pos = getCursorPos(
|
||||
event.MouseInput.X, event.MouseInput.Y);
|
||||
m_cursor_press_pos = m_cursor_pos;
|
||||
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (!TouchScreenGUI::isActive() ||
|
||||
m_cursor_pos < m_real_mark_begin ||
|
||||
m_cursor_pos > m_real_mark_end) {
|
||||
#endif
|
||||
m_mouse_marking = true;
|
||||
setTextMarkers(m_cursor_pos, m_cursor_pos);
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
}
|
||||
#endif
|
||||
calculateScrollPos();
|
||||
return true;
|
||||
} else {
|
||||
if (!AbsoluteClippingRect.isPointInside(core::position2d<s32>(
|
||||
event.MouseInput.X, event.MouseInput.Y))) {
|
||||
m_cursor_press_pos = -1;
|
||||
return false;
|
||||
} else {
|
||||
// move cursor
|
||||
m_cursor_pos = getCursorPos(
|
||||
event.MouseInput.X, event.MouseInput.Y);
|
||||
m_cursor_press_pos = m_cursor_pos;
|
||||
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (!TouchScreenGUI::isActive() ||
|
||||
m_cursor_pos < m_real_mark_begin ||
|
||||
m_cursor_pos > m_real_mark_end) {
|
||||
#endif
|
||||
s32 newMarkBegin = m_mark_begin;
|
||||
if (!m_mouse_marking)
|
||||
newMarkBegin = m_cursor_pos;
|
||||
|
||||
m_mouse_marking = true;
|
||||
setTextMarkers(newMarkBegin, m_cursor_pos);
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
}
|
||||
#endif
|
||||
calculateScrollPos();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case EMIE_MOUSE_WHEEL:
|
||||
if (m_vscrollbar && m_vscrollbar->isVisible()) {
|
||||
s32 pos = m_vscrollbar->getPos();
|
||||
|
@ -132,6 +132,13 @@ public:
|
||||
|
||||
virtual bool acceptsIME() { return isEnabled() && m_writable; };
|
||||
|
||||
//! Sets the scrollbar texture
|
||||
void setScrollbarStyle(const StyleSpec &style, ISimpleTextureSource *tsrc)
|
||||
{
|
||||
if (m_vscrollbar != nullptr)
|
||||
m_vscrollbar->setStyle(style, tsrc);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void breakText() = 0;
|
||||
|
||||
@ -179,6 +186,7 @@ protected:
|
||||
|
||||
u32 m_blink_start_time = 0;
|
||||
s32 m_cursor_pos = 0;
|
||||
s32 m_cursor_press_pos = 0;
|
||||
s32 m_hscroll_pos = 0;
|
||||
s32 m_vscroll_pos = 0; // scroll position in characters
|
||||
u32 m_max = 0;
|
||||
@ -190,9 +198,12 @@ protected:
|
||||
bool m_writable;
|
||||
|
||||
bool m_mouse_marking = false;
|
||||
bool m_long_press = false;
|
||||
|
||||
s32 m_mark_begin = 0;
|
||||
s32 m_mark_end = 0;
|
||||
s32 m_real_mark_begin = 0;
|
||||
s32 m_real_mark_end = 0;
|
||||
|
||||
gui::IGUIFont *m_last_break_font = nullptr;
|
||||
IOSOperator *m_operator = nullptr;
|
||||
@ -207,7 +218,7 @@ private:
|
||||
|
||||
bool onKeyUp(const SEvent &event, s32 &mark_begin, s32 &mark_end);
|
||||
bool onKeyDown(const SEvent &event, s32 &mark_begin, s32 &mark_end);
|
||||
void onKeyControlC(const SEvent &event);
|
||||
bool onKeyControlC(const SEvent &event);
|
||||
bool onKeyControlX(const SEvent &event, s32 &mark_begin, s32 &mark_end);
|
||||
bool onKeyControlV(const SEvent &event, s32 &mark_begin, s32 &mark_end);
|
||||
bool onKeyBack(const SEvent &event, s32 &mark_begin, s32 &mark_end);
|
||||
|
@ -83,6 +83,7 @@ void GUIEditBoxWithScrollBar::draw()
|
||||
return;
|
||||
|
||||
const bool focus = Environment->hasFocus(this);
|
||||
const bool scollbar_focus = Environment->hasFocus(m_vscrollbar);
|
||||
|
||||
IGUISkin* skin = Environment->getSkin();
|
||||
if (!skin)
|
||||
@ -94,6 +95,10 @@ void GUIEditBoxWithScrollBar::draw()
|
||||
default_bg_color = m_writable ? skin->getColor(EGDC_WINDOW) : video::SColor(0);
|
||||
bg_color = m_bg_color_used ? m_bg_color : default_bg_color;
|
||||
|
||||
if (IsEnabled && m_writable) {
|
||||
bg_color = focus ? skin->getColor(EGDC_FOCUSED_EDITABLE) : skin->getColor(EGDC_EDITABLE);
|
||||
}
|
||||
|
||||
if (!m_border && m_background) {
|
||||
skin->draw2DRectangle(this, bg_color, AbsoluteRect, &AbsoluteClippingRect);
|
||||
}
|
||||
@ -134,10 +139,8 @@ void GUIEditBoxWithScrollBar::draw()
|
||||
|
||||
// get mark position
|
||||
const bool ml = (!m_passwordbox && (m_word_wrap || m_multiline));
|
||||
const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
|
||||
const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
|
||||
const s32 hline_start = ml ? getLineFromPos(realmbgn) : 0;
|
||||
const s32 hline_count = ml ? getLineFromPos(realmend) - hline_start + 1 : 1;
|
||||
const s32 hline_start = ml ? getLineFromPos(m_real_mark_begin) : 0;
|
||||
const s32 hline_count = ml ? getLineFromPos(m_real_mark_end) - hline_start + 1 : 1;
|
||||
const s32 line_count = ml ? m_broken_text.size() : 1;
|
||||
|
||||
// Save the override color information.
|
||||
@ -187,26 +190,26 @@ void GUIEditBoxWithScrollBar::draw()
|
||||
false, true, &local_clip_rect);
|
||||
|
||||
// draw mark and marked text
|
||||
if (focus && m_mark_begin != m_mark_end && i >= hline_start && i < hline_start + hline_count) {
|
||||
if ((focus || scollbar_focus) && m_mark_begin != m_mark_end && i >= hline_start && i < hline_start + hline_count) {
|
||||
|
||||
s32 mbegin = 0, mend = 0;
|
||||
s32 lineStartPos = 0, lineEndPos = txt_line->size();
|
||||
|
||||
if (i == hline_start) {
|
||||
// highlight start is on this line
|
||||
s = txt_line->subString(0, realmbgn - start_pos);
|
||||
s = txt_line->subString(0, m_real_mark_begin - start_pos);
|
||||
mbegin = font->getDimension(s.c_str()).Width;
|
||||
|
||||
// deal with kerning
|
||||
mbegin += font->getKerningWidth(
|
||||
&((*txt_line)[realmbgn - start_pos]),
|
||||
realmbgn - start_pos > 0 ? &((*txt_line)[realmbgn - start_pos - 1]) : 0);
|
||||
&((*txt_line)[m_real_mark_begin - start_pos]),
|
||||
m_real_mark_begin - start_pos > 0 ? &((*txt_line)[m_real_mark_begin - start_pos - 1]) : 0);
|
||||
|
||||
lineStartPos = realmbgn - start_pos;
|
||||
lineStartPos = m_real_mark_begin - start_pos;
|
||||
}
|
||||
if (i == hline_start + hline_count - 1) {
|
||||
// highlight end is on this line
|
||||
s2 = txt_line->subString(0, realmend - start_pos);
|
||||
s2 = txt_line->subString(0, m_real_mark_end - start_pos);
|
||||
mend = font->getDimension(s2.c_str()).Width;
|
||||
lineEndPos = (s32)s2.size();
|
||||
} else {
|
||||
|
@ -38,6 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "client/fontengine.h"
|
||||
#include "client/guiscalingfilter.h"
|
||||
#include "irrlicht_changes/static_text.h"
|
||||
#include "translation.h"
|
||||
|
||||
#if ENABLE_GLES
|
||||
#include "client/tile.h"
|
||||
@ -47,7 +48,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
/******************************************************************************/
|
||||
void TextDestGuiEngine::gotText(const StringMap &fields)
|
||||
{
|
||||
try {
|
||||
m_engine->getScriptIface()->handleMainMenuButtons(fields);
|
||||
} catch (LuaError &e) {
|
||||
m_engine->handleMainMenuLuaError(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@ -76,6 +81,9 @@ video::ITexture *MenuTextureSource::getTexture(const std::string &name, u32 *id)
|
||||
return NULL;
|
||||
|
||||
#if ENABLE_GLES
|
||||
if (hasNPotSupport())
|
||||
return m_driver->getTexture(name.c_str());
|
||||
|
||||
video::ITexture *retval = m_driver->findTexture(name.c_str());
|
||||
if (retval)
|
||||
return retval;
|
||||
@ -84,10 +92,12 @@ video::ITexture *MenuTextureSource::getTexture(const std::string &name, u32 *id)
|
||||
if (!image)
|
||||
return NULL;
|
||||
|
||||
image = Align2Npot2(image, m_driver);
|
||||
retval = m_driver->addTexture(name.c_str(), image);
|
||||
// Verified by the profiler - it reduces memory usage!
|
||||
video::IImage *newimage = Align2Npot2(image, m_driver);
|
||||
retval = m_driver->addTexture(name.c_str(), newimage);
|
||||
image = NULL;
|
||||
m_to_delete.insert(name);
|
||||
image->drop();
|
||||
newimage->drop();
|
||||
return retval;
|
||||
#else
|
||||
return m_driver->getTexture(name.c_str());
|
||||
@ -151,8 +161,8 @@ GUIEngine::GUIEngine(JoystickController *joystick,
|
||||
//create soundmanager
|
||||
MenuMusicFetcher soundfetcher;
|
||||
#if USE_SOUND
|
||||
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get())
|
||||
m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(), &soundfetcher);
|
||||
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton)
|
||||
m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton, &soundfetcher);
|
||||
#endif
|
||||
if (!m_sound_manager)
|
||||
m_sound_manager = &dummySoundManager;
|
||||
@ -191,6 +201,12 @@ GUIEngine::GUIEngine(JoystickController *joystick,
|
||||
|
||||
infostream << "GUIEngine: Initializing Lua" << std::endl;
|
||||
|
||||
// Translate the error message before clearing g_client_translations
|
||||
if (!m_data->script_data.errormessage.empty())
|
||||
m_data->script_data.errormessage = wide_to_utf8(translate_string(
|
||||
utf8_to_wide(m_data->script_data.errormessage)));
|
||||
|
||||
g_client_translations->clear();
|
||||
m_script = new MainMenuScripting(this);
|
||||
|
||||
try {
|
||||
@ -204,8 +220,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
|
||||
|
||||
run();
|
||||
} catch (LuaError &e) {
|
||||
errorstream << "Main menu error: " << e.what() << std::endl;
|
||||
m_data->script_data.errormessage = e.what();
|
||||
handleMainMenuLuaError(e.what());
|
||||
}
|
||||
|
||||
m_menu->quitMenu();
|
||||
@ -213,6 +228,18 @@ GUIEngine::GUIEngine(JoystickController *joystick,
|
||||
m_menu = NULL;
|
||||
}
|
||||
|
||||
void GUIEngine::handleMainMenuLuaError(const char* errmsg) {
|
||||
errorstream << "Main menu error: " << errmsg << std::endl;
|
||||
m_data->script_data.errormessage = errmsg;
|
||||
#ifdef __ANDROID__
|
||||
porting::handleError("Main menu error", errmsg);
|
||||
#endif
|
||||
|
||||
// Make the menu quit. Since an error message has been set this won't
|
||||
// actually start the game.
|
||||
m_startgame = true;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
bool GUIEngine::loadMainMenuScript()
|
||||
{
|
||||
@ -231,6 +258,9 @@ bool GUIEngine::loadMainMenuScript()
|
||||
} catch (const ModError &e) {
|
||||
errorstream << "GUIEngine: execution of menu script failed: "
|
||||
<< e.what() << std::endl;
|
||||
#ifdef __ANDROID__
|
||||
porting::handleError("Main menu load error", e.what());
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -269,6 +299,16 @@ void GUIEngine::run()
|
||||
}
|
||||
|
||||
while (m_rendering_engine->run() && (!m_startgame) && (!m_kill)) {
|
||||
IrrlichtDevice *device = m_rendering_engine->get_raw_device();
|
||||
#ifdef __IOS__
|
||||
if (device->isWindowMinimized())
|
||||
#else
|
||||
if (!device->isWindowFocused())
|
||||
#endif
|
||||
{
|
||||
sleep_ms(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
const irr::core::dimension2d<u32> ¤t_screen_size =
|
||||
m_rendering_engine->get_video_driver()->getScreenSize();
|
||||
@ -306,7 +346,6 @@ void GUIEngine::run()
|
||||
|
||||
driver->endScene();
|
||||
|
||||
IrrlichtDevice *device = m_rendering_engine->get_raw_device();
|
||||
u32 frametime_min = 1000 / (device->isWindowFocused()
|
||||
? g_settings->getFloat("fps_max")
|
||||
: g_settings->getFloat("fps_max_unfocused"));
|
||||
@ -317,7 +356,7 @@ void GUIEngine::run()
|
||||
|
||||
m_script->step();
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
m_menu->getAndroidUIInput();
|
||||
#endif
|
||||
}
|
||||
@ -499,19 +538,28 @@ void GUIEngine::drawHeader(video::IVideoDriver *driver)
|
||||
v2s32 splashsize(((f32)texture->getOriginalSize().Width) * mult,
|
||||
((f32)texture->getOriginalSize().Height) * mult);
|
||||
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
// Don't draw the header if there isn't enough room
|
||||
s32 free_space = (((s32)screensize.Height)-320)/2;
|
||||
|
||||
if (free_space > splashsize.Y) {
|
||||
if (free_space <= splashsize.Y)
|
||||
return;
|
||||
|
||||
core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
|
||||
splashrect += v2s32((screensize.Width/2)-(splashsize.X/2),
|
||||
((free_space/2)-splashsize.Y/2)+10);
|
||||
((free_space/2)-splashsize.Y/2));
|
||||
#else
|
||||
core::rect<s32> splashrect(0, 0, splashsize.X, splashsize.Y);
|
||||
splashrect += v2s32((screensize.Width/2)-(splashsize.X/2), 0);
|
||||
|
||||
if (g_settings->getBool("device_is_tablet"))
|
||||
splashrect += v2s32(0, splashsize.Y/4);
|
||||
#endif
|
||||
|
||||
draw2DImageFilterScaled(driver, texture, splashrect,
|
||||
core::rect<s32>(core::position2d<s32>(0,0),
|
||||
core::dimension2di(texture->getOriginalSize())),
|
||||
NULL, NULL, true);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@ -614,7 +662,7 @@ void GUIEngine::updateTopLeftTextSize()
|
||||
{
|
||||
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(m_toplefttext.c_str()),
|
||||
g_fontengine->getTextHeight());
|
||||
rect += v2s32(4, 0);
|
||||
rect += v2s32(5 + g_settings->getU16("round_screen"), 0);
|
||||
|
||||
m_irr_toplefttext->remove();
|
||||
m_irr_toplefttext = gui::StaticText::add(m_rendering_engine->get_gui_env(),
|
||||
|
@ -159,6 +159,8 @@ public:
|
||||
/** default destructor */
|
||||
virtual ~GUIEngine();
|
||||
|
||||
void handleMainMenuLuaError(const char* errmsg);
|
||||
|
||||
/**
|
||||
* return MainMenuScripting interface
|
||||
*/
|
||||
|
@ -67,6 +67,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "guiScrollContainer.h"
|
||||
#include "guiHyperText.h"
|
||||
#include "guiScene.h"
|
||||
#include "touchscreengui.h"
|
||||
|
||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
#define MY_CHECKPOS(a,b) \
|
||||
if (v_pos.size() != 2) { \
|
||||
@ -217,6 +222,10 @@ void GUIFormSpecMenu::setInitialFocus()
|
||||
if (it->getType() == gui::EGUIET_EDIT_BOX
|
||||
&& it->getText()[0] == 0) {
|
||||
Environment->setFocus(it);
|
||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||
if (porting::hasRealKeyboard())
|
||||
SDL_StartTextInput();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -225,6 +234,10 @@ void GUIFormSpecMenu::setInitialFocus()
|
||||
for (gui::IGUIElement *it : children) {
|
||||
if (it->getType() == gui::EGUIET_EDIT_BOX) {
|
||||
Environment->setFocus(it);
|
||||
#ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
|
||||
if (porting::hasRealKeyboard())
|
||||
SDL_StartTextInput();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -534,10 +547,15 @@ void GUIFormSpecMenu::parseList(parserData *data, const std::string &element)
|
||||
pos.X + (geom.X - 1) * slot_spacing.X + slot_size.X,
|
||||
pos.Y + (geom.Y - 1) * slot_spacing.Y + slot_size.Y);
|
||||
|
||||
video::ITexture *bgimg = style.getTexture(StyleSpec::BGIMG, m_tsrc, nullptr);
|
||||
video::ITexture *bgimg_hovered = style.getTexture(StyleSpec::BGIMG_HOVERED, m_tsrc, nullptr);
|
||||
video::ITexture *bgimg_pressed = style.getTexture(StyleSpec::BGIMG_PRESSED, m_tsrc, nullptr);
|
||||
core::rect<s32> bgimg_middle = style.getRect(StyleSpec::BGIMG_MIDDLE, core::rect<s32>());
|
||||
|
||||
GUIInventoryList *e = new GUIInventoryList(Environment, data->current_parent,
|
||||
spec.fid, rect, m_invmgr, loc, listname, geom, start_i,
|
||||
v2s32(slot_size.X, slot_size.Y), slot_spacing, this,
|
||||
data->inventorylist_options, m_font);
|
||||
v2s32(slot_size.X, slot_size.Y), slot_spacing, bgimg, bgimg_hovered,
|
||||
bgimg_pressed, bgimg_middle, this, data->inventorylist_options, m_font);
|
||||
|
||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
|
||||
|
||||
@ -665,6 +683,10 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen
|
||||
std::vector<std::string> v_geom = split(parts[1],',');
|
||||
std::string name = parts[3];
|
||||
std::string value = parts[4];
|
||||
std::vector<std::string> textures;
|
||||
|
||||
if (parts.size() == 6)
|
||||
textures = split(parts[5], ',');
|
||||
|
||||
MY_CHECKPOS("scrollbar",0);
|
||||
MY_CHECKGEOM("scrollbar",1);
|
||||
@ -720,6 +742,18 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen
|
||||
|
||||
e->setPageSize(scrollbar_size * (max - min + 1) / data->scrollbar_options.thumb_size);
|
||||
|
||||
std::vector<video::ITexture *> itextures;
|
||||
|
||||
if (textures.empty()) {
|
||||
// Fall back to the scrollbar textures specified in style[]
|
||||
e->setStyle(style, m_tsrc);
|
||||
} else {
|
||||
for (u32 i = 0; i < textures.size(); ++i)
|
||||
itextures.push_back(m_tsrc->getTexture(textures[i]));
|
||||
|
||||
e->setTextures(itextures);
|
||||
}
|
||||
|
||||
if (spec.fname == m_focused_element) {
|
||||
Environment->setFocus(e);
|
||||
}
|
||||
@ -784,38 +818,50 @@ void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string
|
||||
void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
|
||||
{
|
||||
std::vector<std::string> parts;
|
||||
if (!precheckElement("image", element, 2, 3, parts))
|
||||
if (!precheckElement("image", element, 2, 4, parts))
|
||||
return;
|
||||
|
||||
if (parts.size() >= 3) {
|
||||
std::vector<std::string> v_pos = split(parts[0],',');
|
||||
std::vector<std::string> v_geom = split(parts[1],',');
|
||||
std::string name = unescape_string(parts[2]);
|
||||
size_t offset = parts.size() >= 3;
|
||||
|
||||
std::vector<std::string> v_pos = split(parts[0],',');
|
||||
MY_CHECKPOS("image", 0);
|
||||
|
||||
std::vector<std::string> v_geom;
|
||||
if (parts.size() >= 3) {
|
||||
v_geom = split(parts[1],',');
|
||||
MY_CHECKGEOM("image", 1);
|
||||
}
|
||||
|
||||
std::string name = unescape_string(parts[1 + offset]);
|
||||
video::ITexture *texture = m_tsrc->getTexture(name);
|
||||
|
||||
v2s32 pos;
|
||||
v2s32 geom;
|
||||
|
||||
if (parts.size() < 3) {
|
||||
if (texture != nullptr) {
|
||||
core::dimension2du dim = texture->getOriginalSize();
|
||||
geom.X = dim.Width;
|
||||
geom.Y = dim.Height;
|
||||
} else {
|
||||
geom = v2s32(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (data->real_coordinates) {
|
||||
pos = getRealCoordinateBasePos(v_pos);
|
||||
if (parts.size() >= 3)
|
||||
geom = getRealCoordinateGeometry(v_geom);
|
||||
} else {
|
||||
pos = getElementBasePos(&v_pos);
|
||||
if (parts.size() >= 3) {
|
||||
geom.X = stof(v_geom[0]) * (float)imgsize.X;
|
||||
geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data->explicit_size)
|
||||
warningstream<<"invalid use of image without a size[] element"<<std::endl;
|
||||
|
||||
video::ITexture *texture = m_tsrc->getTexture(name);
|
||||
if (!texture) {
|
||||
errorstream << "GUIFormSpecMenu::parseImage() Unable to load texture:"
|
||||
<< std::endl << "\t" << name << std::endl;
|
||||
return;
|
||||
}
|
||||
warningstream << "Invalid use of image without a size[] element" << std::endl;
|
||||
|
||||
FieldSpec spec(
|
||||
name,
|
||||
@ -824,61 +870,47 @@ void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
|
||||
258 + m_fields.size(),
|
||||
1
|
||||
);
|
||||
core::rect<s32> rect(pos, pos + geom);
|
||||
gui::IGUIImage *e = Environment->addImage(rect, data->current_parent,
|
||||
spec.fid, 0, true);
|
||||
e->setImage(texture);
|
||||
e->setScaleImage(true);
|
||||
auto style = getDefaultStyleForElement("image", spec.fname);
|
||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
|
||||
m_fields.push_back(spec);
|
||||
|
||||
// images should let events through
|
||||
e->grab();
|
||||
m_clickthrough_elements.push_back(e);
|
||||
return;
|
||||
core::rect<s32> rect = core::rect<s32>(pos, pos + geom);
|
||||
|
||||
core::rect<s32> middle;
|
||||
if (parts.size() >= 4)
|
||||
parseMiddleRect(parts[3], &middle);
|
||||
|
||||
// Temporary fix for issue #12581 in 5.6.0.
|
||||
// Use legacy image when not rendering 9-slice image because GUIAnimatedImage
|
||||
// uses NNAA filter which causes visual artifacts when image uses alpha blending.
|
||||
|
||||
gui::IGUIElement *e;
|
||||
if (middle.getArea() > 0) {
|
||||
GUIAnimatedImage *image = new GUIAnimatedImage(Environment, data->current_parent,
|
||||
spec.fid, rect);
|
||||
|
||||
image->setTexture(texture);
|
||||
image->setMiddleRect(middle);
|
||||
e = image;
|
||||
}
|
||||
else {
|
||||
gui::IGUIImage *image = Environment->addImage(rect, data->current_parent, spec.fid, nullptr, true);
|
||||
image->setImage(texture);
|
||||
image->setScaleImage(true);
|
||||
image->grab(); // compensate for drop in addImage
|
||||
e = image;
|
||||
}
|
||||
|
||||
// Else: 2 arguments in "parts"
|
||||
|
||||
std::vector<std::string> v_pos = split(parts[0],',');
|
||||
std::string name = unescape_string(parts[1]);
|
||||
|
||||
MY_CHECKPOS("image", 0);
|
||||
|
||||
v2s32 pos = getElementBasePos(&v_pos);
|
||||
|
||||
if (!data->explicit_size)
|
||||
warningstream<<"invalid use of image without a size[] element"<<std::endl;
|
||||
|
||||
video::ITexture *texture = m_tsrc->getTexture(name);
|
||||
if (!texture) {
|
||||
errorstream << "GUIFormSpecMenu::parseImage() Unable to load texture:"
|
||||
<< std::endl << "\t" << name << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
FieldSpec spec(
|
||||
name,
|
||||
L"",
|
||||
L"",
|
||||
258 + m_fields.size()
|
||||
);
|
||||
gui::IGUIImage *e = Environment->addImage(texture, pos, true,
|
||||
data->current_parent, spec.fid, 0);
|
||||
auto style = getDefaultStyleForElement("image", spec.fname);
|
||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
|
||||
m_fields.push_back(spec);
|
||||
|
||||
// images should let events through
|
||||
e->grab();
|
||||
// Animated images should let events through
|
||||
m_clickthrough_elements.push_back(e);
|
||||
|
||||
m_fields.push_back(spec);
|
||||
}
|
||||
|
||||
void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &element)
|
||||
{
|
||||
std::vector<std::string> parts;
|
||||
if (!precheckElement("animated_image", element, 6, 7, parts))
|
||||
if (!precheckElement("animated_image", element, 6, 8, parts))
|
||||
return;
|
||||
|
||||
std::vector<std::string> v_pos = split(parts[0], ',');
|
||||
@ -904,7 +936,8 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
|
||||
}
|
||||
|
||||
if (!data->explicit_size)
|
||||
warningstream << "Invalid use of animated_image without a size[] element" << std::endl;
|
||||
warningstream << "Invalid use of animated_image without a size[] element"
|
||||
<< std::endl;
|
||||
|
||||
FieldSpec spec(
|
||||
name,
|
||||
@ -917,9 +950,17 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
|
||||
|
||||
core::rect<s32> rect = core::rect<s32>(pos, pos + geom);
|
||||
|
||||
GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent, spec.fid,
|
||||
rect, texture_name, frame_count, frame_duration, m_tsrc);
|
||||
core::rect<s32> middle;
|
||||
if (parts.size() >= 8)
|
||||
parseMiddleRect(parts[7], &middle);
|
||||
|
||||
GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent,
|
||||
spec.fid, rect);
|
||||
|
||||
e->setTexture(m_tsrc->getTexture(texture_name));
|
||||
e->setMiddleRect(middle);
|
||||
e->setFrameDuration(frame_duration);
|
||||
e->setFrameCount(frame_count);
|
||||
if (parts.size() >= 7)
|
||||
e->setFrameIndex(stoi(parts[6]) - 1);
|
||||
|
||||
@ -1044,6 +1085,35 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
|
||||
m_fields.push_back(spec);
|
||||
}
|
||||
|
||||
bool GUIFormSpecMenu::parseMiddleRect(const std::string &value, core::rect<s32> *parsed_rect)
|
||||
{
|
||||
core::rect<s32> rect;
|
||||
std::vector<std::string> v_rect = split(value, ',');
|
||||
|
||||
if (v_rect.size() == 1) {
|
||||
s32 x = stoi(v_rect[0]);
|
||||
rect.UpperLeftCorner = core::vector2di(x, x);
|
||||
rect.LowerRightCorner = core::vector2di(-x, -x);
|
||||
} else if (v_rect.size() == 2) {
|
||||
s32 x = stoi(v_rect[0]);
|
||||
s32 y = stoi(v_rect[1]);
|
||||
rect.UpperLeftCorner = core::vector2di(x, y);
|
||||
rect.LowerRightCorner = core::vector2di(-x, -y);
|
||||
// `-x` is interpreted as `w - x`
|
||||
} else if (v_rect.size() == 4) {
|
||||
rect.UpperLeftCorner = core::vector2di(stoi(v_rect[0]), stoi(v_rect[1]));
|
||||
rect.LowerRightCorner = core::vector2di(stoi(v_rect[2]), stoi(v_rect[3]));
|
||||
} else {
|
||||
warningstream << "Invalid rectangle string format: \"" << value
|
||||
<< "\"" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
*parsed_rect = rect;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &element)
|
||||
{
|
||||
std::vector<std::string> parts;
|
||||
@ -1085,25 +1155,8 @@ void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &eleme
|
||||
}
|
||||
|
||||
core::rect<s32> middle;
|
||||
if (parts.size() >= 5) {
|
||||
std::vector<std::string> v_middle = split(parts[4], ',');
|
||||
if (v_middle.size() == 1) {
|
||||
s32 x = stoi(v_middle[0]);
|
||||
middle.UpperLeftCorner = core::vector2di(x, x);
|
||||
middle.LowerRightCorner = core::vector2di(-x, -x);
|
||||
} else if (v_middle.size() == 2) {
|
||||
s32 x = stoi(v_middle[0]);
|
||||
s32 y = stoi(v_middle[1]);
|
||||
middle.UpperLeftCorner = core::vector2di(x, y);
|
||||
middle.LowerRightCorner = core::vector2di(-x, -y);
|
||||
// `-x` is interpreted as `w - x`
|
||||
} else if (v_middle.size() == 4) {
|
||||
middle.UpperLeftCorner = core::vector2di(stoi(v_middle[0]), stoi(v_middle[1]));
|
||||
middle.LowerRightCorner = core::vector2di(stoi(v_middle[2]), stoi(v_middle[3]));
|
||||
} else {
|
||||
warningstream << "Invalid rectangle given to middle param of background[] element" << std::endl;
|
||||
}
|
||||
}
|
||||
if (parts.size() >= 5)
|
||||
parseMiddleRect(parts[4], &middle);
|
||||
|
||||
if (!data->explicit_size && !clip)
|
||||
warningstream << "invalid use of unclipped background without a size[] element" << std::endl;
|
||||
@ -1233,8 +1286,7 @@ void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element)
|
||||
e->setSelected(stoi(str_initial_selection));
|
||||
|
||||
auto style = getDefaultStyleForElement("table", name);
|
||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
|
||||
e->setOverrideFont(style.getFont());
|
||||
e->setStyle(style);
|
||||
|
||||
m_tables.emplace_back(spec, e);
|
||||
m_fields.push_back(spec);
|
||||
@ -1307,8 +1359,7 @@ void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element
|
||||
e->setSelected(stoi(str_initial_selection));
|
||||
|
||||
auto style = getDefaultStyleForElement("textlist", name);
|
||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
|
||||
e->setOverrideFont(style.getFont());
|
||||
e->setStyle(style);
|
||||
|
||||
m_tables.emplace_back(spec, e);
|
||||
m_fields.push_back(spec);
|
||||
@ -1414,6 +1465,10 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
|
||||
std::vector<std::string> v_geom = split(parts[1],',');
|
||||
std::string name = parts[2];
|
||||
std::string label = parts[3];
|
||||
std::string default_val;
|
||||
|
||||
if (parts.size() > 4)
|
||||
default_val = parts[4];
|
||||
|
||||
MY_CHECKPOS("pwdfield",0);
|
||||
MY_CHECKGEOM("pwdfield",1);
|
||||
@ -1437,19 +1492,23 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
|
||||
|
||||
core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X+geom.X, pos.Y+geom.Y);
|
||||
|
||||
if (m_form_src && !default_val.empty())
|
||||
default_val = m_form_src->resolveText(default_val);
|
||||
|
||||
std::wstring wlabel = translate_string(utf8_to_wide(unescape_string(label)));
|
||||
std::wstring wpassword = utf8_to_wide(unescape_string(default_val));
|
||||
|
||||
FieldSpec spec(
|
||||
name,
|
||||
wlabel,
|
||||
L"",
|
||||
wpassword,
|
||||
258 + m_fields.size(),
|
||||
0,
|
||||
ECI_IBEAM
|
||||
);
|
||||
|
||||
spec.send = true;
|
||||
gui::IGUIEditBox *e = Environment->addEditBox(0, rect, true,
|
||||
gui::IGUIEditBox *e = Environment->addEditBox(wpassword.c_str(), rect, true,
|
||||
data->current_parent, spec.fid);
|
||||
|
||||
if (spec.fname == m_focused_element) {
|
||||
@ -1470,6 +1529,9 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element
|
||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
|
||||
e->setDrawBorder(style.getBool(StyleSpec::BORDER, true));
|
||||
e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF)));
|
||||
if (style.get(StyleSpec::BGCOLOR, "") == "transparent") {
|
||||
e->setDrawBackground(false);
|
||||
}
|
||||
e->setOverrideFont(style.getFont());
|
||||
|
||||
irr::SEvent evt;
|
||||
@ -1506,10 +1568,12 @@ void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec,
|
||||
spec.flabel.swap(spec.fdefault);
|
||||
}
|
||||
|
||||
GUIEditBox *box = nullptr;
|
||||
gui::IGUIEditBox *e = nullptr;
|
||||
if (is_multiline) {
|
||||
e = new GUIEditBoxWithScrollBar(spec.fdefault.c_str(), true, Environment,
|
||||
data->current_parent, spec.fid, rect, is_editable, true);
|
||||
box = new GUIEditBoxWithScrollBar(spec.fdefault.c_str(), true, Environment,
|
||||
data->current_parent, spec.fid, rect, is_editable, !is_editable);
|
||||
e = box;
|
||||
} else if (is_editable) {
|
||||
e = Environment->addEditBox(spec.fdefault.c_str(), rect, true,
|
||||
data->current_parent, spec.fid);
|
||||
@ -1543,6 +1607,8 @@ void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec,
|
||||
e->setDrawBorder(border);
|
||||
e->setDrawBackground(border);
|
||||
e->setOverrideFont(style.getFont());
|
||||
if (box != nullptr)
|
||||
box->setScrollbarStyle(style, m_tsrc);
|
||||
|
||||
e->drop();
|
||||
}
|
||||
@ -1566,6 +1632,8 @@ void GUIFormSpecMenu::parseSimpleField(parserData *data,
|
||||
std::string label = parts[1];
|
||||
std::string default_val = parts[2];
|
||||
|
||||
bool is_dynamic = (name.length() > 0 && name[0] == 'D');
|
||||
|
||||
core::rect<s32> rect;
|
||||
|
||||
if (data->explicit_size)
|
||||
@ -1596,6 +1664,8 @@ void GUIFormSpecMenu::parseSimpleField(parserData *data,
|
||||
ECI_IBEAM
|
||||
);
|
||||
|
||||
spec.is_dynamic = is_dynamic;
|
||||
|
||||
createTextField(data, spec, rect, false);
|
||||
|
||||
m_fields.push_back(spec);
|
||||
@ -1612,6 +1682,8 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>&
|
||||
std::string label = parts[3];
|
||||
std::string default_val = parts[4];
|
||||
|
||||
bool is_dynamic = (name.length() > 0 && name[0] == 'D');
|
||||
|
||||
MY_CHECKPOS(type,0);
|
||||
MY_CHECKGEOM(type,1);
|
||||
|
||||
@ -1660,6 +1732,8 @@ void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>&
|
||||
ECI_IBEAM
|
||||
);
|
||||
|
||||
spec.is_dynamic = is_dynamic;
|
||||
|
||||
createTextField(data, spec, rect, type == "textarea");
|
||||
|
||||
// Note: Before 5.2.0 "parts.size() >= 6" resulted in a
|
||||
@ -1733,7 +1807,7 @@ void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &elemen
|
||||
spec.sound = style.get(StyleSpec::Property::SOUND, "");
|
||||
|
||||
GUIHyperText *e = new GUIHyperText(spec.flabel.c_str(), Environment,
|
||||
data->current_parent, spec.fid, rect, m_client, m_tsrc);
|
||||
data->current_parent, spec.fid, rect, m_client, m_tsrc, style);
|
||||
e->drop();
|
||||
|
||||
m_fields.push_back(spec);
|
||||
@ -3247,10 +3321,34 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
double fitx_imgsize;
|
||||
double fity_imgsize;
|
||||
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
v2f padded_screensize(
|
||||
mydata.screensize.X,
|
||||
mydata.screensize.Y
|
||||
);
|
||||
|
||||
// Try and find a tabheader[] element in the formspec
|
||||
for (unsigned int j = i; j < elements.size(); j++) {
|
||||
// This could use split() but since we don't parse parameters
|
||||
// here it's probably faster to use find().
|
||||
const size_t pos = elements[j].find('[');
|
||||
if (pos == std::string::npos)
|
||||
continue;
|
||||
|
||||
// If we find a tabheader then decrease padded_screensize.Y and
|
||||
// stop searching through the formspec.
|
||||
const std::string element_type = trim(elements[j].substr(0, pos));
|
||||
if (element_type == "tabheader") {
|
||||
padded_screensize.Y *= 0.9f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
v2f padded_screensize(
|
||||
mydata.screensize.X * (1.0f - mydata.padding.X * 2.0f),
|
||||
mydata.screensize.Y * (1.0f - mydata.padding.Y * 2.0f)
|
||||
);
|
||||
#endif
|
||||
|
||||
if (mydata.real_coordinates) {
|
||||
fitx_imgsize = padded_screensize.X / mydata.invsize.X;
|
||||
@ -3271,6 +3369,10 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
// In Android, the preferred imgsize should be larger to accommodate the
|
||||
// smaller screensize.
|
||||
double prefer_imgsize = min_screen_dim / 10 * gui_scaling;
|
||||
|
||||
// Try to fit 13 coordinates on large tablets.
|
||||
if (g_settings->getBool("device_is_tablet"))
|
||||
prefer_imgsize = min_screen_dim / 13 * gui_scaling;
|
||||
#else
|
||||
// Desktop computers have more space, so try to fit 15 coordinates.
|
||||
double prefer_imgsize = min_screen_dim / 15 * gui_scaling;
|
||||
@ -3476,10 +3578,10 @@ void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator fro
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
bool GUIFormSpecMenu::getAndroidUIInput()
|
||||
{
|
||||
if (!hasAndroidUIInput())
|
||||
if (m_jni_field_name.empty())
|
||||
return false;
|
||||
|
||||
// still waiting
|
||||
@ -3500,6 +3602,17 @@ bool GUIFormSpecMenu::getAndroidUIInput()
|
||||
|
||||
std::string text = porting::getInputDialogValue();
|
||||
((gui::IGUIEditBox *)element)->setText(utf8_to_wide(text).c_str());
|
||||
|
||||
// Create event
|
||||
gui::IGUIElement *focus = Environment->getFocus();
|
||||
if (focus) {
|
||||
SEvent e;
|
||||
e.EventType = EET_GUI_EVENT;
|
||||
e.GUIEvent.Caller = focus;
|
||||
e.GUIEvent.Element = 0;
|
||||
e.GUIEvent.EventType = gui::EGET_EDITBOX_CHANGED;
|
||||
element->OnEvent(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -3631,9 +3744,12 @@ void GUIFormSpecMenu::drawMenu()
|
||||
}
|
||||
|
||||
/* TODO find way to show tooltips on touchscreen */
|
||||
#ifndef HAVE_TOUCHSCREENGUI
|
||||
m_pointer = RenderingEngine::get_raw_device()->getCursorControl()->getPosition();
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (!TouchScreenGUI::isActive())
|
||||
#endif
|
||||
{
|
||||
m_pointer = RenderingEngine::get_raw_device()->getCursorControl()->getPosition();
|
||||
}
|
||||
|
||||
/*
|
||||
Draw fields/buttons tooltips and update the mouse cursor
|
||||
@ -3641,11 +3757,9 @@ void GUIFormSpecMenu::drawMenu()
|
||||
gui::IGUIElement *hovered =
|
||||
Environment->getRootGUIElement()->getElementFromPoint(m_pointer);
|
||||
|
||||
#ifndef HAVE_TOUCHSCREENGUI
|
||||
gui::ICursorControl *cursor_control = RenderingEngine::get_raw_device()->
|
||||
getCursorControl();
|
||||
gui::ECURSOR_ICON current_cursor_icon = cursor_control->getActiveIcon();
|
||||
#endif
|
||||
bool hovered_element_found = false;
|
||||
|
||||
if (hovered != NULL) {
|
||||
@ -3681,11 +3795,9 @@ void GUIFormSpecMenu::drawMenu()
|
||||
m_tooltips[field.fname].bgcolor);
|
||||
}
|
||||
|
||||
#ifndef HAVE_TOUCHSCREENGUI
|
||||
if (field.ftype != f_HyperText && // Handled directly in guiHyperText
|
||||
current_cursor_icon != field.fcursor_icon)
|
||||
cursor_control->setActiveIcon(field.fcursor_icon);
|
||||
#endif
|
||||
|
||||
hovered_element_found = true;
|
||||
|
||||
@ -3696,10 +3808,8 @@ void GUIFormSpecMenu::drawMenu()
|
||||
|
||||
if (!hovered_element_found) {
|
||||
// no element is hovered
|
||||
#ifndef HAVE_TOUCHSCREENGUI
|
||||
if (current_cursor_icon != ECI_NORMAL)
|
||||
cursor_control->setActiveIcon(ECI_NORMAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
m_tooltip_element->draw();
|
||||
@ -3731,14 +3841,12 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text,
|
||||
int tooltip_offset_x = m_btn_height;
|
||||
int tooltip_offset_y = m_btn_height;
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (TouchScreenGUI::isActive()) {
|
||||
tooltip_offset_x *= 3;
|
||||
tooltip_offset_y = 0;
|
||||
if (m_pointer.X > (s32)screenSize.X / 2)
|
||||
tooltip_offset_x = -(tooltip_offset_x + tooltip_width);
|
||||
|
||||
// Hide tooltip after ETIE_LEFT_UP
|
||||
if (m_pointer.X == 0)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Calculate and set the tooltip position
|
||||
@ -4081,6 +4189,15 @@ enum ButtonEventType : u8
|
||||
BET_OTHER
|
||||
};
|
||||
|
||||
void GUIFormSpecMenu::clearSelection()
|
||||
{
|
||||
m_selected_swap.clear();
|
||||
delete m_selected_item;
|
||||
m_selected_item = nullptr;
|
||||
m_selected_amount = 0;
|
||||
m_selected_dragging = false;
|
||||
}
|
||||
|
||||
bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||
{
|
||||
if (event.EventType==EET_KEY_INPUT_EVENT) {
|
||||
@ -4290,8 +4407,14 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||
move_amount = 1;
|
||||
else if (button == BET_MIDDLE)
|
||||
move_amount = MYMIN(m_selected_amount, 10);
|
||||
else if (button == BET_LEFT)
|
||||
else if (button == BET_LEFT) {
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
if (g_touchscreengui && g_touchscreengui->isActive() && s.listname == "craft")
|
||||
move_amount = 1;
|
||||
else
|
||||
#endif
|
||||
move_amount = m_selected_amount;
|
||||
}
|
||||
// else wheeldown
|
||||
|
||||
if (identical) {
|
||||
@ -4515,6 +4638,9 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||
if (event.EventType == EET_GUI_EVENT) {
|
||||
if (event.GUIEvent.EventType == gui::EGET_TAB_CHANGED
|
||||
&& isVisible()) {
|
||||
// reset selection
|
||||
clearSelection();
|
||||
|
||||
// find the element that was clicked
|
||||
for (GUIFormSpecMenu::FieldSpec &s : m_fields) {
|
||||
if ((s.ftype == f_TabHeader) &&
|
||||
@ -4541,8 +4667,10 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||
(event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED) ||
|
||||
(event.GUIEvent.EventType == gui::EGET_COMBO_BOX_CHANGED) ||
|
||||
(event.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED)) {
|
||||
s32 caller_id = event.GUIEvent.Caller->getID();
|
||||
// reset selection
|
||||
clearSelection();
|
||||
|
||||
s32 caller_id = event.GUIEvent.Caller->getID();
|
||||
if (caller_id == 257) {
|
||||
if (m_allowclose) {
|
||||
acceptInput(quit_mode_accept);
|
||||
@ -4651,14 +4779,19 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||
}
|
||||
}
|
||||
|
||||
if (event.GUIEvent.EventType == gui::EGET_TABLE_CHANGED) {
|
||||
if (event.GUIEvent.EventType == gui::EGET_TABLE_CHANGED ||
|
||||
event.GUIEvent.EventType == gui::EGET_EDITBOX_CHANGED) {
|
||||
// reset selection
|
||||
clearSelection();
|
||||
|
||||
int current_id = event.GUIEvent.Caller->getID();
|
||||
if (current_id > 257) {
|
||||
// find the element that was clicked
|
||||
// find the element that was clicked or changed
|
||||
for (GUIFormSpecMenu::FieldSpec &s : m_fields) {
|
||||
// if it's a table, set the send field
|
||||
// so lua knows which table was changed
|
||||
if ((s.ftype == f_Table) && (s.fid == current_id)) {
|
||||
if ((s.ftype == f_Table && s.fid == current_id) ||
|
||||
(s.ftype == f_Unknown && s.is_dynamic && s.fid == current_id)) {
|
||||
s.send = true;
|
||||
acceptInput();
|
||||
s.send=false;
|
||||
|
@ -113,6 +113,7 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
ftype(f_Unknown),
|
||||
is_exit(false),
|
||||
priority(priority),
|
||||
is_dynamic(false),
|
||||
fcursor_icon(cursor_icon)
|
||||
{
|
||||
}
|
||||
@ -126,6 +127,7 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
bool is_exit;
|
||||
// Draw priority for formspec version < 3
|
||||
int priority;
|
||||
bool is_dynamic;
|
||||
core::rect<s32> rect;
|
||||
gui::ECURSOR_ICON fcursor_icon;
|
||||
std::string sound;
|
||||
@ -257,6 +259,7 @@ public:
|
||||
|
||||
void acceptInput(FormspecQuitMode quitmode=quit_mode_no);
|
||||
bool preprocessEvent(const SEvent& event);
|
||||
void clearSelection();
|
||||
bool OnEvent(const SEvent& event);
|
||||
bool doPause;
|
||||
bool pausesGame() { return doPause; }
|
||||
@ -264,7 +267,7 @@ public:
|
||||
GUITable* getTable(const std::string &tablename);
|
||||
std::vector<std::string>* getDropDownValues(const std::string &name);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#if defined(__ANDROID__) || defined(__IOS__)
|
||||
bool getAndroidUIInput();
|
||||
#endif
|
||||
|
||||
@ -456,6 +459,8 @@ private:
|
||||
void parseSetFocus(const std::string &element);
|
||||
void parseModel(parserData *data, const std::string &element);
|
||||
|
||||
bool parseMiddleRect(const std::string &value, core::rect<s32> *parsed_rect);
|
||||
|
||||
void tryClose();
|
||||
|
||||
void showTooltip(const std::wstring &text, const irr::video::SColor &color,
|
||||
|
@ -990,7 +990,7 @@ void TextDrawer::draw(const core::rect<s32> &clip_rect,
|
||||
//! constructor
|
||||
GUIHyperText::GUIHyperText(const wchar_t *text, IGUIEnvironment *environment,
|
||||
IGUIElement *parent, s32 id, const core::rect<s32> &rectangle,
|
||||
Client *client, ISimpleTextureSource *tsrc) :
|
||||
Client *client, ISimpleTextureSource *tsrc, const StyleSpec &style) :
|
||||
IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle),
|
||||
m_client(client), m_vscrollbar(nullptr),
|
||||
m_drawer(text, client, environment, tsrc), m_text_scrollpos(0, 0)
|
||||
@ -1012,6 +1012,7 @@ GUIHyperText::GUIHyperText(const wchar_t *text, IGUIEnvironment *environment,
|
||||
|
||||
m_vscrollbar = new GUIScrollBar(Environment, this, -1, rect, false, true);
|
||||
m_vscrollbar->setVisible(false);
|
||||
m_vscrollbar->setStyle(style, tsrc);
|
||||
}
|
||||
|
||||
//! destructor
|
||||
|
@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "StyleSpec.h"
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
@ -202,7 +203,7 @@ public:
|
||||
GUIHyperText(const wchar_t *text, gui::IGUIEnvironment *environment,
|
||||
gui::IGUIElement *parent, s32 id,
|
||||
const core::rect<s32> &rectangle, Client *client,
|
||||
ISimpleTextureSource *tsrc);
|
||||
ISimpleTextureSource *tsrc, const StyleSpec &style);
|
||||
|
||||
//! destructor
|
||||
virtual ~GUIHyperText();
|
||||
|
@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "guiInventoryList.h"
|
||||
#include "guiFormSpecMenu.h"
|
||||
#include "client/guiscalingfilter.h"
|
||||
#include "client/hud.h"
|
||||
#include "client/client.h"
|
||||
|
||||
@ -33,6 +34,10 @@ GUIInventoryList::GUIInventoryList(gui::IGUIEnvironment *env,
|
||||
const s32 start_item_i,
|
||||
const v2s32 &slot_size,
|
||||
const v2f32 &slot_spacing,
|
||||
video::ITexture* slotbg_n_texture,
|
||||
video::ITexture* slotbg_h_texture,
|
||||
video::ITexture* slotbg_p_texture,
|
||||
const core::rect<s32> &slotbg_middle,
|
||||
GUIFormSpecMenu *fs_menu,
|
||||
const Options &options,
|
||||
gui::IGUIFont *font) :
|
||||
@ -44,10 +49,15 @@ GUIInventoryList::GUIInventoryList(gui::IGUIEnvironment *env,
|
||||
m_start_item_i(start_item_i),
|
||||
m_slot_size(slot_size),
|
||||
m_slot_spacing(slot_spacing),
|
||||
m_slotbg_n_texture(slotbg_n_texture),
|
||||
m_slotbg_h_texture(slotbg_h_texture),
|
||||
m_slotbg_p_texture(slotbg_p_texture),
|
||||
m_slotbg_middle(slotbg_middle),
|
||||
m_fs_menu(fs_menu),
|
||||
m_options(options),
|
||||
m_font(font),
|
||||
m_hovered_i(-1),
|
||||
m_pressed(false),
|
||||
m_already_warned(false)
|
||||
{
|
||||
}
|
||||
@ -109,6 +119,27 @@ void GUIInventoryList::draw()
|
||||
(hovering ? IT_ROT_HOVERED : IT_ROT_NONE);
|
||||
|
||||
// layer 0
|
||||
if (m_slotbg_n_texture) {
|
||||
video::ITexture *texture = m_slotbg_n_texture;
|
||||
if (hovering) {
|
||||
if (m_pressed && m_slotbg_p_texture)
|
||||
texture = m_slotbg_p_texture;
|
||||
else if (m_slotbg_h_texture)
|
||||
texture = m_slotbg_h_texture;
|
||||
}
|
||||
|
||||
core::rect<s32> srcrect(core::position2d<s32>(0, 0),
|
||||
core::dimension2di(texture->getOriginalSize()));
|
||||
if (m_slotbg_middle.getArea() == 0) {
|
||||
const video::SColor color(255, 255, 255, 255);
|
||||
const video::SColor colors[] = {color, color, color, color};
|
||||
draw2DImageFilterScaled(driver, texture, rect, srcrect,
|
||||
&AbsoluteClippingRect, colors, true);
|
||||
} else {
|
||||
draw2DImage9Slice(driver, texture, rect, srcrect, m_slotbg_middle,
|
||||
&AbsoluteClippingRect);
|
||||
}
|
||||
} else {
|
||||
if (hovering) {
|
||||
driver->draw2DRectangle(m_options.slotbg_h, rect, &AbsoluteClippingRect);
|
||||
} else {
|
||||
@ -138,6 +169,7 @@ void GUIInventoryList::draw()
|
||||
core::rect<s32>(v2s32(x2, y1),
|
||||
v2s32(x2 + border, y2)), clipping_rect_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// layer 1
|
||||
if (selected)
|
||||
@ -173,8 +205,15 @@ bool GUIInventoryList::OnEvent(const SEvent &event)
|
||||
|
||||
m_hovered_i = getItemIndexAtPos(v2s32(event.MouseInput.X, event.MouseInput.Y));
|
||||
|
||||
if (m_hovered_i != -1)
|
||||
if (m_hovered_i != -1) {
|
||||
if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
|
||||
m_pressed = true;
|
||||
else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
|
||||
m_pressed = false;
|
||||
return IGUIElement::OnEvent(event);
|
||||
}
|
||||
|
||||
m_pressed = false;
|
||||
|
||||
// no item slot at pos of mouse event => allow clicking through
|
||||
// find the element that would be hovered if this inventorylist was invisible
|
||||
|
@ -69,6 +69,10 @@ public:
|
||||
const s32 start_item_i,
|
||||
const v2s32 &slot_size,
|
||||
const v2f32 &slot_spacing,
|
||||
video::ITexture* slotbg_n_texture,
|
||||
video::ITexture* slotbg_h_texture,
|
||||
video::ITexture* slotbg_p_texture,
|
||||
const core::rect<s32> &slotbg_middle,
|
||||
GUIFormSpecMenu *fs_menu,
|
||||
const Options &options,
|
||||
gui::IGUIFont *font);
|
||||
@ -117,6 +121,12 @@ private:
|
||||
// specifies how large the space between slots is (space between is spacing-size)
|
||||
const v2f32 m_slot_spacing;
|
||||
|
||||
// Slot textures
|
||||
video::ITexture* m_slotbg_n_texture;
|
||||
video::ITexture* m_slotbg_h_texture;
|
||||
video::ITexture* m_slotbg_p_texture;
|
||||
core::rect<s32> m_slotbg_middle;
|
||||
|
||||
// the GUIFormSpecMenu can have an item selected and co.
|
||||
GUIFormSpecMenu *m_fs_menu;
|
||||
|
||||
@ -128,6 +138,9 @@ private:
|
||||
// the index of the hovered item; -1 if no item is hovered
|
||||
s32 m_hovered_i;
|
||||
|
||||
// Whether the hovered item is being pressed
|
||||
bool m_pressed;
|
||||
|
||||
// we do not want to write a warning on every draw
|
||||
bool m_already_warned;
|
||||
};
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "guiKeyChangeMenu.h"
|
||||
#include "debug.h"
|
||||
#include "guiBackgroundImage.h"
|
||||
#include "guiButton.h"
|
||||
#include "serialization.h"
|
||||
#include <string>
|
||||
@ -29,10 +30,14 @@
|
||||
#include <IGUIButton.h>
|
||||
#include <IGUIStaticText.h>
|
||||
#include <IGUIFont.h>
|
||||
#include "filesys.h"
|
||||
#include "porting.h"
|
||||
#include "settings.h"
|
||||
#include "StyleSpec.h"
|
||||
#include <algorithm>
|
||||
|
||||
#include "mainmenumanager.h" // for g_gamecallback
|
||||
#include "client/renderingengine.h"
|
||||
|
||||
#define KMaxButtonPerColumns 12
|
||||
|
||||
@ -41,6 +46,7 @@ extern MainGameCallback *g_gamecallback;
|
||||
enum
|
||||
{
|
||||
GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
|
||||
GUI_ID_BACKGROUND_IMG,
|
||||
// buttons
|
||||
GUI_ID_KEY_FORWARD_BUTTON,
|
||||
GUI_ID_KEY_BACKWARD_BUTTON,
|
||||
@ -84,11 +90,21 @@ enum
|
||||
|
||||
GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent, s32 id, IMenuManager *menumgr,
|
||||
ISimpleTextureSource *tsrc) :
|
||||
ISimpleTextureSource *tsrc, bool main_menu) :
|
||||
GUIModalMenu(env, parent, id, menumgr),
|
||||
m_tsrc(tsrc)
|
||||
m_tsrc(tsrc),
|
||||
m_main_menu(main_menu)
|
||||
{
|
||||
init_keys();
|
||||
|
||||
if (m_main_menu) return;
|
||||
v3f formspec_bgcolor = g_settings->getV3F("formspec_fullscreen_bg_color");
|
||||
m_fullscreen_bgcolor = video::SColor(
|
||||
(u8) MYMIN(MYMAX(g_settings->getS32("formspec_fullscreen_bg_opacity"), 0), 255),
|
||||
MYMIN(MYMAX(myround(formspec_bgcolor.X), 0), 255),
|
||||
MYMIN(MYMAX(myround(formspec_bgcolor.Y), 0), 255),
|
||||
MYMIN(MYMAX(myround(formspec_bgcolor.Z), 0), 255)
|
||||
);
|
||||
}
|
||||
|
||||
GUIKeyChangeMenu::~GUIKeyChangeMenu()
|
||||
@ -120,7 +136,20 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
||||
{
|
||||
removeChildren();
|
||||
|
||||
const float s = m_gui_scale;
|
||||
float s = MYMIN(screensize.X / 835.f, screensize.Y / 430.f);
|
||||
#if HAVE_TOUCHSCREENGUI
|
||||
s *= g_settings->getBool("device_is_tablet") ? 0.8f : 0.9f;
|
||||
#else
|
||||
s *= 0.75f;
|
||||
#endif
|
||||
|
||||
// Make sure the GUI will fit on the screen
|
||||
// The change keys GUI is 835x430 pixels (with a scaling of 1)
|
||||
if (835 * s > screensize.X)
|
||||
s = screensize.X / 835.f;
|
||||
if (430 * s > screensize.Y)
|
||||
s = screensize.Y / 430.f;
|
||||
|
||||
DesiredRect = core::rect<s32>(
|
||||
screensize.X / 2 - 835 * s / 2,
|
||||
screensize.Y / 2 - 430 * s / 2,
|
||||
@ -132,11 +161,29 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
||||
v2s32 size = DesiredRect.getSize();
|
||||
v2s32 topleft(0, 0);
|
||||
|
||||
std::string texture_path = "";
|
||||
if (m_main_menu)
|
||||
texture_path = porting::path_share + DIR_DELIM "textures" DIR_DELIM
|
||||
"base" DIR_DELIM "pack" DIR_DELIM;
|
||||
|
||||
// Background image
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 600 * s, 40 * s);
|
||||
rect += topleft + v2s32(25 * s, 3 * s);
|
||||
const std::string texture = texture_path + "bg_common.png";
|
||||
const core::rect<s32> rect(0, 0, 0, 0);
|
||||
const core::rect<s32> middle(40, 40, -40, -40);
|
||||
new GUIBackgroundImage(Environment, this, GUI_ID_BACKGROUND_IMG, rect,
|
||||
texture, middle, m_tsrc, true);
|
||||
}
|
||||
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 795 * s, 50 * s);
|
||||
rect += topleft + v2s32(25 * s, 10 * s);
|
||||
//gui::IGUIStaticText *t =
|
||||
const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from minetest.conf)");
|
||||
#if !defined(__ANDROID__) && !defined(__IOS__)
|
||||
const wchar_t *text = wgettext("Keybindings. (If this menu screws up, remove stuff from multicraft.conf)");
|
||||
#else
|
||||
const wchar_t *text = wgettext("Change Keys");
|
||||
#endif
|
||||
Environment->addStaticText(text,
|
||||
rect, false, true, this, -1);
|
||||
delete[] text;
|
||||
@ -174,7 +221,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
||||
{
|
||||
s32 option_x = offset.X;
|
||||
s32 option_y = offset.Y + 5 * s;
|
||||
u32 option_w = 180 * s;
|
||||
u32 option_w = 300 * s;
|
||||
{
|
||||
core::rect<s32> rect(0, 0, option_w, 30 * s);
|
||||
rect += topleft + v2s32(option_x, option_y);
|
||||
@ -189,7 +236,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
||||
{
|
||||
s32 option_x = offset.X;
|
||||
s32 option_y = offset.Y + 5 * s;
|
||||
u32 option_w = 280 * s;
|
||||
u32 option_w = 300 * s;
|
||||
{
|
||||
core::rect<s32> rect(0, 0, option_w, 30 * s);
|
||||
rect += topleft + v2s32(option_x, option_y);
|
||||
@ -204,7 +251,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
||||
{
|
||||
s32 option_x = offset.X;
|
||||
s32 option_y = offset.Y + 5 * s;
|
||||
u32 option_w = 280;
|
||||
u32 option_w = 300 * s;
|
||||
{
|
||||
core::rect<s32> rect(0, 0, option_w, 30 * s);
|
||||
rect += topleft + v2s32(option_x, option_y);
|
||||
@ -216,18 +263,23 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
|
||||
offset += v2s32(0, 25);
|
||||
}
|
||||
|
||||
const std::array<StyleSpec, StyleSpec::NUM_STATES> styles =
|
||||
StyleSpec::getButtonStyle(texture_path);
|
||||
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
|
||||
rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s);
|
||||
core::rect<s32> rect(0, 0, 150 * s, 35 * s);
|
||||
rect += topleft + v2s32(size.X / 2 - 165 * s, size.Y - 50 * s);
|
||||
const wchar_t *text = wgettext("Save");
|
||||
GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
|
||||
GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_BACK_BUTTON, text);
|
||||
e->setStyles(styles);
|
||||
delete[] text;
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 100 * s, 30 * s);
|
||||
rect += topleft + v2s32(size.X / 2 + 5 * s, size.Y - 40 * s);
|
||||
core::rect<s32> rect(0, 0, 150 * s, 35 * s);
|
||||
rect += topleft + v2s32(size.X / 2 + 15 * s, size.Y - 50 * s);
|
||||
const wchar_t *text = wgettext("Cancel");
|
||||
GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
|
||||
GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc, this, GUI_ID_ABORT_BUTTON, text);
|
||||
e->setStyles(styles);
|
||||
delete[] text;
|
||||
}
|
||||
}
|
||||
@ -237,10 +289,13 @@ void GUIKeyChangeMenu::drawMenu()
|
||||
gui::IGUISkin* skin = Environment->getSkin();
|
||||
if (!skin)
|
||||
return;
|
||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||
|
||||
video::SColor bgcolor(140, 0, 0, 0);
|
||||
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
|
||||
if (!m_main_menu) {
|
||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||
v2u32 screenSize = driver->getScreenSize();
|
||||
core::rect<s32> allbg(0, 0, screenSize.X, screenSize.Y);
|
||||
driver->draw2DRectangle(m_fullscreen_bgcolor, allbg, &allbg);
|
||||
}
|
||||
|
||||
gui::IGUIElement::draw();
|
||||
}
|
||||
@ -277,6 +332,9 @@ bool GUIKeyChangeMenu::acceptInput()
|
||||
|
||||
g_gamecallback->signalKeyConfigChange();
|
||||
|
||||
if (!g_settings_path.empty())
|
||||
g_settings->updateConfigFile(g_settings_path.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -296,7 +354,7 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
|
||||
if (event.EventType == EET_KEY_INPUT_EVENT && active_key
|
||||
&& event.KeyInput.PressedDown) {
|
||||
|
||||
bool prefer_character = shift_down;
|
||||
bool prefer_character = shift_down && event.KeyInput.Char != 0;
|
||||
KeyPress kp(event.KeyInput, prefer_character);
|
||||
|
||||
if (event.KeyInput.Key == irr::KEY_DELETE)
|
||||
@ -355,6 +413,13 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
|
||||
&& event.KeyInput.Key == irr::KEY_ESCAPE) {
|
||||
quitMenu();
|
||||
return true;
|
||||
} else if (event.EventType == EET_KEY_INPUT_EVENT &&
|
||||
!event.KeyInput.PressedDown) {
|
||||
if (shift_down && !event.KeyInput.Shift) {
|
||||
shift_down = false;
|
||||
active_key = nullptr;
|
||||
return true;
|
||||
}
|
||||
} else if (event.EventType == EET_GUI_EVENT) {
|
||||
if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
|
||||
&& isVisible())
|
||||
|
@ -43,7 +43,8 @@ class GUIKeyChangeMenu : public GUIModalMenu
|
||||
{
|
||||
public:
|
||||
GUIKeyChangeMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
|
||||
IMenuManager *menumgr, ISimpleTextureSource *tsrc);
|
||||
IMenuManager *menumgr, ISimpleTextureSource *tsrc,
|
||||
bool main_menu = false);
|
||||
~GUIKeyChangeMenu();
|
||||
|
||||
void removeChildren();
|
||||
@ -77,4 +78,7 @@ private:
|
||||
gui::IGUIStaticText *key_used_text = nullptr;
|
||||
std::vector<key_setting *> key_settings;
|
||||
ISimpleTextureSource *m_tsrc;
|
||||
bool m_main_menu = false;
|
||||
|
||||
video::SColor m_fullscreen_bgcolor;
|
||||
};
|
||||
|
@ -12,16 +12,18 @@ the arrow buttons where there is insufficient space.
|
||||
|
||||
#include "guiScrollBar.h"
|
||||
#include <IGUIButton.h>
|
||||
#include <IGUISkin.h>
|
||||
#include <IGUIImage.h>
|
||||
|
||||
GUIScrollBar::GUIScrollBar(IGUIEnvironment *environment, IGUIElement *parent, s32 id,
|
||||
core::rect<s32> rectangle, bool horizontal, bool auto_scale) :
|
||||
IGUIElement(EGUIET_ELEMENT, environment, parent, id, rectangle),
|
||||
up_button(nullptr), down_button(nullptr), is_dragging(false),
|
||||
is_horizontal(horizontal), is_auto_scaling(auto_scale),
|
||||
dragged_by_slider(false), tray_clicked(false), scroll_pos(0),
|
||||
draw_center(0), thumb_size(0), min_pos(0), max_pos(100), small_step(10),
|
||||
large_step(50), drag_offset(0), page_size(100), border_size(0)
|
||||
up_button(nullptr), down_button(nullptr), bg_image(nullptr),
|
||||
slider_image(nullptr), slider_top_image(nullptr),
|
||||
slider_bottom_image(nullptr), is_dragging(false), is_horizontal(horizontal),
|
||||
is_auto_scaling(auto_scale), dragged_by_slider(false),
|
||||
tray_clicked(false), scroll_pos(0), draw_center(0), thumb_size(0),
|
||||
min_pos(0), max_pos(100), small_step(10), large_step(50),
|
||||
drag_offset(0), page_size(100), border_size(0)
|
||||
{
|
||||
refreshControls();
|
||||
setNotClipped(false);
|
||||
@ -193,6 +195,14 @@ bool GUIScrollBar::OnEvent(const SEvent &event)
|
||||
return IGUIElement::OnEvent(event);
|
||||
}
|
||||
|
||||
gui::IGUIImage* GUIScrollBar::addImage(const core::rect<s32> &rect, video::ITexture *texture)
|
||||
{
|
||||
gui::IGUIImage *e = Environment->addImage(rect, this);
|
||||
e->setImage(texture);
|
||||
e->setScaleImage(true);
|
||||
return e;
|
||||
}
|
||||
|
||||
void GUIScrollBar::draw()
|
||||
{
|
||||
if (!IsVisible)
|
||||
@ -208,10 +218,26 @@ void GUIScrollBar::draw()
|
||||
refreshControls();
|
||||
|
||||
slider_rect = AbsoluteRect;
|
||||
skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR), slider_rect,
|
||||
&AbsoluteClippingRect);
|
||||
|
||||
if (core::isnotzero(range())) {
|
||||
if (m_textures.size() >= 1) {
|
||||
s32 w = RelativeRect.getWidth();
|
||||
s32 h = RelativeRect.getHeight();
|
||||
core::rect<s32> rect{0, w, w, h - w};
|
||||
|
||||
if (is_horizontal)
|
||||
rect = {h, 0, w - h, h};
|
||||
|
||||
if (!bg_image)
|
||||
bg_image = addImage(rect, m_textures[0]);
|
||||
else
|
||||
bg_image->setRelativePosition(rect);
|
||||
} else {
|
||||
skin->draw2DRectangle(this, skin->getColor(EGDC_SCROLLBAR),
|
||||
slider_rect, &AbsoluteClippingRect);
|
||||
}
|
||||
|
||||
// Always show scrollbar thumb
|
||||
//if (core::isnotzero(range())) {
|
||||
if (is_horizontal) {
|
||||
slider_rect.UpperLeftCorner.X = AbsoluteRect.UpperLeftCorner.X +
|
||||
draw_center - thumb_size / 2;
|
||||
@ -223,8 +249,42 @@ void GUIScrollBar::draw()
|
||||
slider_rect.LowerRightCorner.Y =
|
||||
slider_rect.UpperLeftCorner.Y + thumb_size;
|
||||
}
|
||||
|
||||
if (m_textures.size() >= 2) {
|
||||
s32 w = slider_rect.getWidth();
|
||||
s32 h = slider_rect.getHeight();
|
||||
core::rect<s32> rect{0, draw_center - (h / 2), w, draw_center + h - (h / 2)};
|
||||
|
||||
if (is_horizontal)
|
||||
rect = {draw_center - (w / 2), 0, draw_center + w - (w / 2), h};
|
||||
|
||||
if (!slider_image)
|
||||
slider_image = addImage(rect, m_textures[1]);
|
||||
else
|
||||
slider_image->setRelativePosition(rect);
|
||||
|
||||
// Add top and bottom images if required
|
||||
// TODO: Horizontal scrollbars
|
||||
if (m_textures.size() >= 6 && !is_horizontal) {
|
||||
core::rect<s32> top_rect = rect;
|
||||
top_rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + w / 2;
|
||||
if (!slider_top_image)
|
||||
slider_top_image = addImage(top_rect, m_textures[4]);
|
||||
else
|
||||
slider_top_image->setRelativePosition(top_rect);
|
||||
|
||||
core::rect<s32> bottom_rect = rect;
|
||||
bottom_rect.UpperLeftCorner.Y = rect.LowerRightCorner.Y - w / 2;
|
||||
if (!slider_bottom_image)
|
||||
slider_bottom_image = addImage(bottom_rect, m_textures[5]);
|
||||
else
|
||||
slider_bottom_image->setRelativePosition(bottom_rect);
|
||||
}
|
||||
} else {
|
||||
skin->draw3DButtonPaneStandard(this, slider_rect, &AbsoluteClippingRect);
|
||||
}
|
||||
//}
|
||||
|
||||
IGUIElement::draw();
|
||||
}
|
||||
|
||||
@ -327,6 +387,34 @@ s32 GUIScrollBar::getPos() const
|
||||
return scroll_pos;
|
||||
}
|
||||
|
||||
void GUIScrollBar::setTextures(const std::vector<video::ITexture *> &textures)
|
||||
{
|
||||
m_textures = textures;
|
||||
refreshControls();
|
||||
};
|
||||
|
||||
void GUIScrollBar::setStyle(const StyleSpec &style, ISimpleTextureSource *tsrc)
|
||||
{
|
||||
if (style.isNotDefault(StyleSpec::SCROLLBAR_BGIMG) &&
|
||||
style.isNotDefault(StyleSpec::SCROLLBAR_THUMB_IMG) &&
|
||||
style.isNotDefault(StyleSpec::SCROLLBAR_UP_IMG) &&
|
||||
style.isNotDefault(StyleSpec::SCROLLBAR_DOWN_IMG)) {
|
||||
arrow_visibility = ArrowVisibility::SHOW;
|
||||
std::vector<video::ITexture *> textures = {
|
||||
style.getTexture(StyleSpec::SCROLLBAR_BGIMG, tsrc),
|
||||
style.getTexture(StyleSpec::SCROLLBAR_THUMB_IMG, tsrc),
|
||||
style.getTexture(StyleSpec::SCROLLBAR_UP_IMG, tsrc),
|
||||
style.getTexture(StyleSpec::SCROLLBAR_DOWN_IMG, tsrc)
|
||||
};
|
||||
if (style.isNotDefault(StyleSpec::SCROLLBAR_THUMB_TOP_IMG) &&
|
||||
style.isNotDefault(StyleSpec::SCROLLBAR_THUMB_BOTTOM_IMG)) {
|
||||
textures.push_back(style.getTexture(StyleSpec::SCROLLBAR_THUMB_TOP_IMG, tsrc));
|
||||
textures.push_back(style.getTexture(StyleSpec::SCROLLBAR_THUMB_BOTTOM_IMG, tsrc));
|
||||
}
|
||||
setTextures(textures);
|
||||
}
|
||||
}
|
||||
|
||||
void GUIScrollBar::refreshControls()
|
||||
{
|
||||
IGUISkin *skin = Environment->getSkin();
|
||||
@ -342,13 +430,21 @@ void GUIScrollBar::refreshControls()
|
||||
if (is_horizontal) {
|
||||
s32 h = RelativeRect.getHeight();
|
||||
border_size = RelativeRect.getWidth() < h * 4 ? 0 : h;
|
||||
|
||||
if (!up_button) {
|
||||
up_button = Environment->addButton(
|
||||
core::rect<s32>(0, 0, h, h), this);
|
||||
up_button->setSubElement(true);
|
||||
up_button->setTabStop(false);
|
||||
}
|
||||
if (sprites) {
|
||||
|
||||
if (m_textures.size() >= 3) {
|
||||
up_button->setImage(m_textures[2]);
|
||||
up_button->setScaleImage(true);
|
||||
up_button->setDrawBorder(false);
|
||||
up_button->setUseAlphaChannel(true);
|
||||
up_button->setSpriteBank(nullptr);
|
||||
} else if (sprites) {
|
||||
up_button->setSpriteBank(sprites);
|
||||
up_button->setSprite(EGBS_BUTTON_UP,
|
||||
s32(skin->getIcon(EGDI_CURSOR_LEFT)),
|
||||
@ -360,6 +456,7 @@ void GUIScrollBar::refreshControls()
|
||||
up_button->setRelativePosition(core::rect<s32>(0, 0, h, h));
|
||||
up_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT,
|
||||
EGUIA_LOWERRIGHT);
|
||||
|
||||
if (!down_button) {
|
||||
down_button = Environment->addButton(
|
||||
core::rect<s32>(RelativeRect.getWidth() - h, 0,
|
||||
@ -368,7 +465,14 @@ void GUIScrollBar::refreshControls()
|
||||
down_button->setSubElement(true);
|
||||
down_button->setTabStop(false);
|
||||
}
|
||||
if (sprites) {
|
||||
|
||||
if (m_textures.size() >= 4) {
|
||||
down_button->setImage(m_textures[3]);
|
||||
down_button->setScaleImage(true);
|
||||
down_button->setDrawBorder(false);
|
||||
down_button->setUseAlphaChannel(true);
|
||||
down_button->setSpriteBank(nullptr);
|
||||
} else if (sprites) {
|
||||
down_button->setSpriteBank(sprites);
|
||||
down_button->setSprite(EGBS_BUTTON_UP,
|
||||
s32(skin->getIcon(EGDI_CURSOR_RIGHT)),
|
||||
@ -377,6 +481,7 @@ void GUIScrollBar::refreshControls()
|
||||
s32(skin->getIcon(EGDI_CURSOR_RIGHT)),
|
||||
current_icon_color);
|
||||
}
|
||||
|
||||
down_button->setRelativePosition(
|
||||
core::rect<s32>(RelativeRect.getWidth() - h, 0,
|
||||
RelativeRect.getWidth(), h));
|
||||
@ -384,14 +489,23 @@ void GUIScrollBar::refreshControls()
|
||||
EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
|
||||
} else {
|
||||
s32 w = RelativeRect.getWidth();
|
||||
border_size = RelativeRect.getHeight() < w * 4 ? 0 : w;
|
||||
s32 h = RelativeRect.getHeight();
|
||||
border_size = h < w * 4 ? 0 : w;
|
||||
|
||||
if (!up_button) {
|
||||
up_button = Environment->addButton(
|
||||
core::rect<s32>(0, 0, w, w), this);
|
||||
up_button->setSubElement(true);
|
||||
up_button->setTabStop(false);
|
||||
}
|
||||
if (sprites) {
|
||||
|
||||
if (m_textures.size() >= 3) {
|
||||
up_button->setImage(m_textures[2]);
|
||||
up_button->setScaleImage(true);
|
||||
up_button->setDrawBorder(false);
|
||||
up_button->setUseAlphaChannel(true);
|
||||
up_button->setSpriteBank(nullptr);
|
||||
} else if (sprites) {
|
||||
up_button->setSpriteBank(sprites);
|
||||
up_button->setSprite(EGBS_BUTTON_UP,
|
||||
s32(skin->getIcon(EGDI_CURSOR_UP)),
|
||||
@ -403,15 +517,21 @@ void GUIScrollBar::refreshControls()
|
||||
up_button->setRelativePosition(core::rect<s32>(0, 0, w, w));
|
||||
up_button->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT,
|
||||
EGUIA_UPPERLEFT, EGUIA_UPPERLEFT);
|
||||
|
||||
if (!down_button) {
|
||||
down_button = Environment->addButton(
|
||||
core::rect<s32>(0, RelativeRect.getHeight() - w,
|
||||
w, RelativeRect.getHeight()),
|
||||
this);
|
||||
core::rect<s32>(0, 0, w, w), this);
|
||||
down_button->setSubElement(true);
|
||||
down_button->setTabStop(false);
|
||||
}
|
||||
if (sprites) {
|
||||
|
||||
if (m_textures.size() >= 4) {
|
||||
down_button->setImage(m_textures[3]);
|
||||
down_button->setScaleImage(true);
|
||||
down_button->setDrawBorder(false);
|
||||
down_button->setUseAlphaChannel(true);
|
||||
down_button->setSpriteBank(nullptr);
|
||||
} else if (sprites) {
|
||||
down_button->setSpriteBank(sprites);
|
||||
down_button->setSprite(EGBS_BUTTON_UP,
|
||||
s32(skin->getIcon(EGDI_CURSOR_DOWN)),
|
||||
|
@ -12,7 +12,10 @@ the arrow buttons where there is insufficient space.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "guiAnimatedImage.h"
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "StyleSpec.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace irr;
|
||||
using namespace gui;
|
||||
@ -39,6 +42,7 @@ public:
|
||||
s32 getLargeStep() const { return large_step; }
|
||||
s32 getSmallStep() const { return small_step; }
|
||||
s32 getPos() const;
|
||||
s32 getPageSize() const { return page_size; }
|
||||
|
||||
void setMax(const s32 &max);
|
||||
void setMin(const s32 &min);
|
||||
@ -47,14 +51,21 @@ public:
|
||||
void setPos(const s32 &pos);
|
||||
void setPageSize(const s32 &size);
|
||||
void setArrowsVisible(ArrowVisibility visible);
|
||||
void setTextures(const std::vector<video::ITexture *> &textures);
|
||||
void setStyle(const StyleSpec &style, ISimpleTextureSource *tsrc);
|
||||
|
||||
private:
|
||||
void refreshControls();
|
||||
s32 getPosFromMousePos(const core::position2di &p) const;
|
||||
f32 range() const { return f32(max_pos - min_pos); }
|
||||
gui::IGUIImage *addImage(const core::rect<s32> &rect, video::ITexture *texture);
|
||||
|
||||
IGUIButton *up_button;
|
||||
IGUIButton *down_button;
|
||||
gui::IGUIImage *bg_image;
|
||||
gui::IGUIImage *slider_image;
|
||||
gui::IGUIImage *slider_top_image;
|
||||
gui::IGUIImage *slider_bottom_image;
|
||||
ArrowVisibility arrow_visibility = DEFAULT;
|
||||
bool is_dragging;
|
||||
bool is_horizontal;
|
||||
@ -72,6 +83,9 @@ private:
|
||||
s32 page_size;
|
||||
s32 border_size;
|
||||
|
||||
std::vector<video::ITexture *> m_textures;
|
||||
core::rect<s32> m_texture_middle;
|
||||
|
||||
core::rect<s32> slider_rect;
|
||||
video::SColor current_icon_color;
|
||||
};
|
||||
|
@ -29,7 +29,7 @@ GUISkin::GUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver)
|
||||
{
|
||||
Colors[EGDC_3D_DARK_SHADOW] = video::SColor(101,50,50,50);
|
||||
Colors[EGDC_3D_SHADOW] = video::SColor(101,130,130,130);
|
||||
Colors[EGDC_3D_FACE] = video::SColor(220,100,100,100);
|
||||
Colors[EGDC_3D_FACE] = video::SColor(101,210,210,210);
|
||||
Colors[EGDC_3D_HIGH_LIGHT] = video::SColor(101,255,255,255);
|
||||
Colors[EGDC_3D_LIGHT] = video::SColor(101,210,210,210);
|
||||
Colors[EGDC_ACTIVE_BORDER] = video::SColor(101,16,14,115);
|
||||
@ -1003,6 +1003,16 @@ void GUISkin::drawColoredIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon,
|
||||
colors = Colors;
|
||||
|
||||
bool gray = element && !element->isEnabled();
|
||||
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 9
|
||||
if (icon == EGDI_CHECK_BOX_CHECKED) {
|
||||
// Scale checkbox check specifically
|
||||
int radius = getSize(EGDS_CHECK_BOX_WIDTH) * .38;
|
||||
core::recti rect{position.X - radius, position.Y - radius, position.X + radius, position.Y + radius};
|
||||
SpriteBank->draw2DSprite(Icons[icon], rect, 0,
|
||||
&colors[gray ? EGDC_GRAY_WINDOW_SYMBOL : EGDC_WINDOW_SYMBOL], currenttime - starttime, loop);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
SpriteBank->draw2DSprite(Icons[icon], position, clip,
|
||||
colors[gray? EGDC_GRAY_WINDOW_SYMBOL : EGDC_WINDOW_SYMBOL], starttime, currenttime, loop, true);
|
||||
}
|
||||
|
@ -77,14 +77,12 @@ GUITable::GUITable(gui::IGUIEnvironment *env,
|
||||
setTabStop(true);
|
||||
setTabOrder(-1);
|
||||
updateAbsolutePosition();
|
||||
#ifdef HAVE_TOUCHSCREENGUI
|
||||
float density = 1; // dp scaling is applied by the skin
|
||||
#else
|
||||
float density = RenderingEngine::getDisplayDensity();
|
||||
#endif
|
||||
float gui_scaling = g_settings->getFloat("gui_scaling");
|
||||
scale = density * gui_scaling;
|
||||
core::rect<s32> relative_rect = m_scrollbar->getRelativePosition();
|
||||
s32 width = (relative_rect.getWidth() / (2.0 / 3.0)) * density *
|
||||
g_settings->getFloat("gui_scaling");
|
||||
s32 width = (relative_rect.getWidth() / (2.0 / 3.0)) *
|
||||
gui_scaling;
|
||||
m_scrollbar->setRelativePosition(core::rect<s32>(
|
||||
relative_rect.LowerRightCorner.X-width,relative_rect.UpperLeftCorner.Y,
|
||||
relative_rect.LowerRightCorner.X,relative_rect.LowerRightCorner.Y
|
||||
@ -387,7 +385,7 @@ void GUITable::setTable(const TableOptions &options,
|
||||
image = m_images[row->content_index];
|
||||
|
||||
// Get content width and update xmax
|
||||
row->content_width = image ? image->getOriginalSize().Width : 0;
|
||||
row->content_width = image ? image->getOriginalSize().Width * scale : 0;
|
||||
row->content_width = MYMAX(row->content_width, width);
|
||||
s32 row_xmax = row->x + padding + row->content_width;
|
||||
xmax = MYMAX(xmax, row_xmax);
|
||||
@ -759,17 +757,21 @@ void GUITable::drawCell(const Cell *cell, video::SColor color,
|
||||
core::rect<s32> source_rect(
|
||||
core::position2d<s32>(0, 0),
|
||||
image->getOriginalSize());
|
||||
s32 imgh = source_rect.LowerRightCorner.Y;
|
||||
s32 imgh = source_rect.LowerRightCorner.Y * scale;
|
||||
s32 rowh = row_rect.getHeight();
|
||||
if (imgh < rowh)
|
||||
dest_pos.Y += (rowh - imgh) / 2;
|
||||
else
|
||||
source_rect.LowerRightCorner.Y = rowh;
|
||||
|
||||
video::SColor color(255, 255, 255, 255);
|
||||
video::SColor colors[] = {color, color, color, color};
|
||||
|
||||
driver->draw2DImage(image, dest_pos, source_rect,
|
||||
&client_clip, color, true);
|
||||
core::rect<s32> image_pos(dest_pos.X, dest_pos.Y,
|
||||
dest_pos.X + (image->getOriginalSize().Width * scale),
|
||||
dest_pos.Y + (image->getOriginalSize().Height * scale));
|
||||
|
||||
draw2DImageFilterScaled(driver, image, image_pos, source_rect,
|
||||
&client_clip, colors, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "guiScrollBar.h"
|
||||
#include "StyleSpec.h"
|
||||
|
||||
class ISimpleTextureSource;
|
||||
|
||||
@ -147,6 +148,14 @@ public:
|
||||
/* Irrlicht event handler */
|
||||
virtual bool OnEvent(const SEvent &event);
|
||||
|
||||
/* Set scrollbar texture */
|
||||
void setStyle(const StyleSpec &style)
|
||||
{
|
||||
setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
|
||||
setOverrideFont(style.getFont());
|
||||
m_scrollbar->setStyle(style, m_tsrc);
|
||||
}
|
||||
|
||||
protected:
|
||||
enum ColumnType {
|
||||
COLUMN_TYPE_TEXT,
|
||||
@ -207,6 +216,8 @@ protected:
|
||||
gui::IGUIFont *m_font = nullptr;
|
||||
GUIScrollBar *m_scrollbar = nullptr;
|
||||
|
||||
float scale;
|
||||
|
||||
// Allocated strings and images
|
||||
std::vector<core::stringw> m_strings;
|
||||
std::vector<video::ITexture*> m_images;
|
||||
|
@ -19,18 +19,22 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include "guiVolumeChange.h"
|
||||
#include "debug.h"
|
||||
#include "guiBackgroundImage.h"
|
||||
#include "guiButton.h"
|
||||
#include "guiScrollBar.h"
|
||||
#include "serialization.h"
|
||||
#include <string>
|
||||
#include <IGUICheckBox.h>
|
||||
#include <IGUIButton.h>
|
||||
#include <IGUIScrollBar.h>
|
||||
#include <IGUIStaticText.h>
|
||||
#include <IGUIFont.h>
|
||||
#include "settings.h"
|
||||
#include "StyleSpec.h"
|
||||
|
||||
#include "gettext.h"
|
||||
#include "client/renderingengine.h"
|
||||
|
||||
const int ID_backgroundImage = 262;
|
||||
const int ID_soundText = 263;
|
||||
const int ID_soundExitButton = 264;
|
||||
const int ID_soundSlider = 265;
|
||||
@ -43,6 +47,13 @@ GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env,
|
||||
GUIModalMenu(env, parent, id, menumgr),
|
||||
m_tsrc(tsrc)
|
||||
{
|
||||
v3f formspec_bgcolor = g_settings->getV3F("formspec_fullscreen_bg_color");
|
||||
m_fullscreen_bgcolor = video::SColor(
|
||||
(u8) MYMIN(MYMAX(g_settings->getS32("formspec_fullscreen_bg_opacity"), 0), 255),
|
||||
MYMIN(MYMAX(myround(formspec_bgcolor.X), 0), 255),
|
||||
MYMIN(MYMAX(myround(formspec_bgcolor.Y), 0), 255),
|
||||
MYMIN(MYMAX(myround(formspec_bgcolor.Z), 0), 255)
|
||||
);
|
||||
}
|
||||
|
||||
GUIVolumeChange::~GUIVolumeChange()
|
||||
@ -52,6 +63,9 @@ GUIVolumeChange::~GUIVolumeChange()
|
||||
|
||||
void GUIVolumeChange::removeChildren()
|
||||
{
|
||||
if (gui::IGUIElement *e = getElementFromId(ID_backgroundImage))
|
||||
e->remove();
|
||||
|
||||
if (gui::IGUIElement *e = getElementFromId(ID_soundText))
|
||||
e->remove();
|
||||
|
||||
@ -74,12 +88,18 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
|
||||
/*
|
||||
Calculate new sizes and positions
|
||||
*/
|
||||
const float s = m_gui_scale;
|
||||
float s = MYMIN(screensize.X / 380.f, screensize.Y / 180.f);
|
||||
#if HAVE_TOUCHSCREENGUI
|
||||
s *= g_settings->getBool("device_is_tablet") ? 0.4f : 0.5f;
|
||||
#else
|
||||
s *= 0.35f;
|
||||
#endif
|
||||
|
||||
DesiredRect = core::rect<s32>(
|
||||
screensize.X / 2 - 380 * s / 2,
|
||||
screensize.Y / 2 - 200 * s / 2,
|
||||
screensize.Y / 2 - 180 * s / 2,
|
||||
screensize.X / 2 + 380 * s / 2,
|
||||
screensize.Y / 2 + 200 * s / 2
|
||||
screensize.Y / 2 + 180 * s / 2 // 200
|
||||
);
|
||||
recalculateAbsolutePosition(false);
|
||||
|
||||
@ -90,8 +110,15 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
|
||||
Add stuff
|
||||
*/
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 160 * s, 20 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 80 * s, size.Y / 2 - 70 * s);
|
||||
const std::string texture = "bg_common.png";
|
||||
const core::rect<s32> rect(0, 0, 0, 0);
|
||||
const core::rect<s32> middle(40, 40, -40, -40);
|
||||
new GUIBackgroundImage(Environment, this, ID_backgroundImage, rect,
|
||||
texture, middle, m_tsrc, true);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 320 * s, 25 * s);
|
||||
rect = rect + v2s32(30 * s, size.Y / 2 - 35 * s); // 55
|
||||
|
||||
wchar_t text[100];
|
||||
const wchar_t *str = wgettext("Sound Volume: %d%%");
|
||||
@ -103,28 +130,38 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize)
|
||||
true, this, ID_soundText);
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 80 * s, 30 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 80 * s / 2, size.Y / 2 + 55 * s);
|
||||
core::rect<s32> rect(0, 0, 80 * s, 35 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 40 * s, size.Y / 2 + 35 * s); // 45
|
||||
const wchar_t *text = wgettext("Exit");
|
||||
GUIButton::addButton(Environment, rect, m_tsrc, this, ID_soundExitButton, text);
|
||||
GUIButton *e = GUIButton::addButton(Environment, rect, m_tsrc, this,
|
||||
ID_soundExitButton, text);
|
||||
delete[] text;
|
||||
|
||||
e->setStyles(StyleSpec::getButtonStyle());
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 300 * s, 20 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 150 * s, size.Y / 2);
|
||||
gui::IGUIScrollBar *e = Environment->addScrollBar(true,
|
||||
rect, this, ID_soundSlider);
|
||||
core::rect<s32> rect(0, 0, 320 * s, 30 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 160 * s, size.Y / 2 - 12 * s); // 30
|
||||
GUIScrollBar *e = new GUIScrollBar(Environment, this,
|
||||
ID_soundSlider, rect, true, false);
|
||||
e->setMax(100);
|
||||
e->setPos(volume);
|
||||
e->setArrowsVisible(GUIScrollBar::ArrowVisibility::SHOW);
|
||||
e->setTextures({
|
||||
m_tsrc->getTexture("gui/scrollbar_horiz_bg.png"),
|
||||
m_tsrc->getTexture("gui/scrollbar_slider.png"),
|
||||
m_tsrc->getTexture("gui/scrollbar_minus.png"),
|
||||
m_tsrc->getTexture("gui/scrollbar_plus.png"),
|
||||
});
|
||||
}
|
||||
{
|
||||
core::rect<s32> rect(0, 0, 160 * s, 20 * s);
|
||||
rect = rect + v2s32(size.X / 2 - 80 * s, size.Y / 2 - 35 * s);
|
||||
/*{
|
||||
core::rect<s32> rect(0, 0, 150 * s, 25 * s);
|
||||
rect = rect + v2s32(30 * s, size.Y / 2 + 5 * s);
|
||||
const wchar_t *text = wgettext("Muted");
|
||||
Environment->addCheckBox(g_settings->getBool("mute_sound"), rect, this,
|
||||
ID_soundMuteButton, text);
|
||||
delete[] text;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void GUIVolumeChange::drawMenu()
|
||||
@ -133,25 +170,35 @@ void GUIVolumeChange::drawMenu()
|
||||
if (!skin)
|
||||
return;
|
||||
video::IVideoDriver* driver = Environment->getVideoDriver();
|
||||
video::SColor bgcolor(140, 0, 0, 0);
|
||||
driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
|
||||
|
||||
v2u32 screenSize = driver->getScreenSize();
|
||||
core::rect<s32> allbg(0, 0, screenSize.X, screenSize.Y);
|
||||
driver->draw2DRectangle(m_fullscreen_bgcolor, allbg, &allbg);
|
||||
|
||||
gui::IGUIElement::draw();
|
||||
}
|
||||
|
||||
void GUIVolumeChange::saveSettingsAndQuit()
|
||||
{
|
||||
if (!g_settings_path.empty())
|
||||
g_settings->updateConfigFile(g_settings_path.c_str());
|
||||
quitMenu();
|
||||
}
|
||||
|
||||
bool GUIVolumeChange::OnEvent(const SEvent& event)
|
||||
{
|
||||
if (event.EventType == EET_KEY_INPUT_EVENT) {
|
||||
if (event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown) {
|
||||
quitMenu();
|
||||
saveSettingsAndQuit();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.KeyInput.Key == KEY_RETURN && event.KeyInput.PressedDown) {
|
||||
quitMenu();
|
||||
saveSettingsAndQuit();
|
||||
return true;
|
||||
}
|
||||
} else if (event.EventType == EET_GUI_EVENT) {
|
||||
if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED) {
|
||||
/*if (event.GUIEvent.EventType == gui::EGET_CHECKBOX_CHANGED) {
|
||||
gui::IGUIElement *e = getElementFromId(ID_soundMuteButton);
|
||||
if (e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) {
|
||||
g_settings->setBool("mute_sound", ((gui::IGUICheckBox*)e)->isChecked());
|
||||
@ -159,11 +206,11 @@ bool GUIVolumeChange::OnEvent(const SEvent& event)
|
||||
|
||||
Environment->setFocus(this);
|
||||
return true;
|
||||
}
|
||||
}*/
|
||||
|
||||
if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED) {
|
||||
if (event.GUIEvent.Caller->getID() == ID_soundExitButton) {
|
||||
quitMenu();
|
||||
saveSettingsAndQuit();
|
||||
return true;
|
||||
}
|
||||
Environment->setFocus(this);
|
||||
@ -180,9 +227,13 @@ bool GUIVolumeChange::OnEvent(const SEvent& event)
|
||||
}
|
||||
if (event.GUIEvent.EventType == gui::EGET_SCROLL_BAR_CHANGED) {
|
||||
if (event.GUIEvent.Caller->getID() == ID_soundSlider) {
|
||||
s32 pos = ((gui::IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
|
||||
s32 pos = ((GUIScrollBar*)event.GUIEvent.Caller)->getPos();
|
||||
g_settings->setFloat("sound_volume", (float) pos / 100);
|
||||
|
||||
// unmute sound when changing the volume
|
||||
if (g_settings->getBool("mute_sound"))
|
||||
g_settings->setBool("mute_sound", false);
|
||||
|
||||
gui::IGUIElement *e = getElementFromId(ID_soundText);
|
||||
wchar_t text[100];
|
||||
const wchar_t *str = wgettext("Sound Volume: %d%%");
|
||||
|
@ -50,5 +50,8 @@ protected:
|
||||
std::string getNameByID(s32 id) { return ""; }
|
||||
|
||||
private:
|
||||
void saveSettingsAndQuit();
|
||||
|
||||
ISimpleTextureSource *m_tsrc;
|
||||
video::SColor m_fullscreen_bgcolor;
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user