Merge branch 'master' into doc-refactor-2

This commit is contained in:
Bituvo 2024-04-03 22:14:38 -04:00
commit 3337cc2091
612 changed files with 121627 additions and 10194 deletions

3
.gitattributes vendored
View File

@ -1,2 +1,5 @@
# Forces all files which git considers text files to use LF line endings
* text=auto eol=lf
*.cpp diff=cpp
*.h diff=cpp

View File

@ -8,6 +8,8 @@ on:
- 'lib/**.cpp'
- 'src/**.[ch]'
- 'src/**.cpp'
- 'irr/**.[ch]'
- 'irr/**.cpp'
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- 'android/**'

View File

@ -8,6 +8,8 @@ on:
- 'lib/**.cpp'
- 'src/**.[ch]'
- 'src/**.cpp'
- 'irr/**.[ch]'
- 'irr/**.cpp'
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- 'util/ci/**'

89
.github/workflows/docker_image.yml vendored Normal file
View File

@ -0,0 +1,89 @@
---
name: docker_image
# https://docs.github.com/en/actions/publishing-packages/publishing-docker-images
# https://docs.docker.com/build/ci/github-actions/multi-platform
# https://github.com/opencontainers/image-spec/blob/main/annotations.md
on:
push:
branches: [ "master" ]
# Publish semver tags as releases.
tags: [ "*.*.*" ]
pull_request:
# Build docker image on pull requests. (but do not publish)
paths:
- 'lib/**.[ch]'
- 'lib/**.cpp'
- 'src/**.[ch]'
- 'src/**.cpp'
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- 'util/ci/**'
- 'misc/irrlichtmt_tag.txt'
- 'Dockerfile'
- '.dockerignore'
- '.github/workflows/docker_image.yml'
workflow_dispatch:
env:
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3.0.0
# Login against the Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v5.5.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
labels: |
org.opencontainers.image.title=Minetest
org.opencontainers.image.vendor=Minetest
org.opencontainers.image.licenses=LGPL-2.1-only
# Build and push Docker image
# https://github.com/docker/build-push-action
# No arm support for now. Require cross-compilation support in Dockerfile to not use QEMU.
- name: Build and push Docker image
uses: docker/build-push-action@v5.1.0
with:
context: .
platforms: linux/amd64
push: ${{ github.event_name != 'pull_request' }}
load: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Test Docker Image
run: |
docker run --rm $(cut -d, -f1 <<<"$DOCKER_METADATA_OUTPUT_TAGS") minetestserver --version
shell: bash

View File

@ -8,10 +8,11 @@ on:
- 'lib/**.cpp'
- 'src/**.[ch]'
- 'src/**.cpp'
- 'irr/**.[ch]'
- 'irr/**.cpp'
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- 'util/ci/**'
- 'misc/irrlichtmt_tag.txt'
- 'Dockerfile'
- '.dockerignore'
- '.github/workflows/linux.yml'
@ -24,7 +25,6 @@ on:
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- 'util/ci/**'
- 'misc/irrlichtmt_tag.txt'
- 'Dockerfile'
- '.dockerignore'
- '.github/workflows/linux.yml'
@ -108,7 +108,7 @@ jobs:
- name: Install deps
run: |
source ./util/ci/common.sh
install_linux_deps clang-14 gdb
install_linux_deps clang-14 lldb
- name: Build
run: |
@ -151,13 +151,3 @@ jobs:
- name: Test
run: |
./bin/minetestserver --run-unittests
docker:
name: "Docker image"
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Build docker image
run: |
docker build . -t minetest:latest
docker run --rm minetest:latest /usr/local/bin/minetestserver --version

View File

@ -14,24 +14,24 @@ on:
- '.github/workflows/**.yml'
jobs:
# Note that the integration tests are also run build.yml, but only when C++ code is changed.
# Note that the integration tests are also run in build.yml, but only when C++ code is changed.
integration_tests:
name: "Compile and run multiplayer tests"
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install deps
run: |
source ./util/ci/common.sh
install_linux_deps clang-10 gdb libluajit-5.1-dev
install_linux_deps clang gdb libluajit-5.1-dev
- name: Build
run: |
./util/ci/build.sh
env:
CC: clang-10
CXX: clang++-10
CMAKE_FLAGS: "-DENABLE_GETTEXT=0 -DBUILD_SERVER=0"
CC: clang
CXX: clang++
CMAKE_FLAGS: "-DENABLE_GETTEXT=0 -DBUILD_SERVER=0 -DBUILD_UNITTESTS=0"
- name: Integration test + devtest
run: |

View File

@ -16,8 +16,8 @@ on:
jobs:
build:
runs-on: ubuntu-22.04
if: github.repository == 'minetest/minetest'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

View File

@ -8,6 +8,8 @@ on:
- 'lib/**.cpp'
- 'src/**.[ch]'
- 'src/**.cpp'
- 'irr/**.[ch]'
- 'irr/**.cpp'
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- '.github/workflows/macos.yml'
@ -33,7 +35,6 @@ jobs:
- name: Build
run: |
git clone https://github.com/minetest/irrlicht lib/irrlichtmt --depth 1 -b $(cat misc/irrlichtmt_tag.txt)
mkdir build
cd build
cmake .. \

View File

@ -8,10 +8,11 @@ on:
- 'lib/**.cpp'
- 'src/**.[ch]'
- 'src/**.cpp'
- 'irr/**.[ch]'
- 'irr/**.cpp'
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- 'util/buildbot/**'
- 'misc/irrlichtmt_tag.txt'
- 'misc/*.manifest'
- '.github/workflows/windows.yml'
pull_request:
@ -23,7 +24,6 @@ on:
- '**/CMakeLists.txt'
- 'cmake/Modules/**'
- 'util/buildbot/**'
- 'misc/irrlichtmt_tag.txt'
- 'misc/*.manifest'
- '.github/workflows/windows.yml'
@ -97,11 +97,6 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Checkout IrrlichtMt
run: |
$ref = @(Get-Content misc\irrlichtmt_tag.txt)
git clone https://github.com/minetest/irrlicht lib\irrlichtmt --depth 1 -b $ref[0]
- name: Restore from cache and run vcpkg
uses: lukka/run-vcpkg@v7
with:

3
.gitignore vendored
View File

@ -64,6 +64,7 @@ AppDir
/clientmods/*
!/clientmods/preview/
/client/mod_storage/
/mod_data
## Configuration/log files
minetest.conf
@ -118,7 +119,7 @@ compile_commands.json
*.sln
.vs/
# Optional user provided library folder
# Old irrlichtmt. Still ignored to make bisecting easier.
lib/irrlichtmt
# Generated mod storage database

View File

@ -91,27 +91,12 @@ if(ANDROID)
endif()
set(IRRLICHTMT_BUILD_DIR "" CACHE PATH "Path to IrrlichtMt build directory.")
if(ANDROID)
# currently manually provided
elseif(NOT "${IRRLICHTMT_BUILD_DIR}" STREQUAL "")
find_package(IrrlichtMt QUIET
PATHS "${IRRLICHTMT_BUILD_DIR}"
NO_DEFAULT_PATH
)
if(NOT TARGET IrrlichtMt::IrrlichtMt)
# find_package() searches certain subdirectories. ${PATH}/cmake is not
# the only one, but it is the one where IrrlichtMt is supposed to export
# IrrlichtMtConfig.cmake
message(FATAL_ERROR "Could not find IrrlichtMtConfig.cmake in ${IRRLICHTMT_BUILD_DIR}/cmake.")
endif()
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib/irrlichtmt")
message(STATUS "Using user-provided IrrlichtMt at subdirectory 'lib/irrlichtmt'")
if(TRUE)
message(STATUS "Using imported IrrlichtMt at subdirectory 'irr'")
if(BUILD_CLIENT)
# tell IrrlichtMt to create a static library
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared library" FORCE)
add_subdirectory(lib/irrlichtmt EXCLUDE_FROM_ALL)
add_subdirectory(irr EXCLUDE_FROM_ALL)
unset(BUILD_SHARED_LIBS CACHE)
if(NOT TARGET IrrlichtMt)
@ -120,44 +105,7 @@ elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/lib/irrlichtmt")
else()
add_library(IrrlichtMt::IrrlichtMt INTERFACE IMPORTED)
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/irrlichtmt/include")
endif()
else()
find_package(IrrlichtMt QUIET)
if(NOT TARGET IrrlichtMt::IrrlichtMt)
string(CONCAT explanation_msg
"You must install IrrlichMt as described in docs/compiling/\n")
if(BUILD_CLIENT)
message(FATAL_ERROR "IrrlichtMt is required to build the client, but it was not found.\n${explanation_msg}")
endif()
include(MinetestFindIrrlichtHeaders)
if(NOT IRRLICHT_INCLUDE_DIR)
message(FATAL_ERROR "IrrlichtMt headers are required to build the server, but none found.\n${explanation_msg}")
endif()
message(STATUS "Found IrrlichtMt headers: ${IRRLICHT_INCLUDE_DIR}")
add_library(IrrlichtMt::IrrlichtMt INTERFACE IMPORTED)
# Note that we can't use target_include_directories() since that doesn't work for IMPORTED targets before CMake 3.11
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${IRRLICHT_INCLUDE_DIR}")
endif()
endif()
if(ANDROID)
# skipped for now
elseif(BUILD_CLIENT AND TARGET IrrlichtMt::IrrlichtMt)
# retrieve version somehow
if(NOT IrrlichtMt_VERSION)
get_target_property(IrrlichtMt_VERSION IrrlichtMt VERSION)
endif()
message(STATUS "Found IrrlichtMt ${IrrlichtMt_VERSION}")
set(TARGET_VER_S 1.9.0mt15)
string(REPLACE "mt" "." TARGET_VER ${TARGET_VER_S})
if(IrrlichtMt_VERSION VERSION_LESS ${TARGET_VER})
message(FATAL_ERROR "At least IrrlichtMt ${TARGET_VER_S} is required to build")
elseif(NOT DEVELOPMENT_BUILD AND IrrlichtMt_VERSION VERSION_GREATER ${TARGET_VER})
message(FATAL_ERROR "IrrlichtMt ${TARGET_VER_S} is required to build")
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/irr/include")
endif()
endif()

View File

@ -1,7 +1,6 @@
ARG DOCKER_IMAGE=alpine:3.19
FROM $DOCKER_IMAGE AS dev
ENV IRRLICHT_VERSION master
ENV SPATIALINDEX_VERSION master
ENV LUAJIT_VERSION v2.1
@ -30,9 +29,7 @@ RUN git clone --recursive https://github.com/jupp0r/prometheus-cpp && \
git clone --recursive https://luajit.org/git/luajit.git -b ${LUAJIT_VERSION} && \
cd luajit && \
make amalg && make install && \
cd /usr/src/ && \
git clone --depth=1 https://github.com/minetest/irrlicht -b ${IRRLICHT_VERSION} && \
cp -r irrlicht/include /usr/include/irrlichtmt
cd /usr/src/
FROM dev as builder
@ -48,6 +45,7 @@ COPY lib /usr/src/minetest/lib
COPY misc /usr/src/minetest/misc
COPY po /usr/src/minetest/po
COPY src /usr/src/minetest/src
COPY irr /usr/src/minetest/irr
COPY textures /usr/src/minetest/textures
WORKDIR /usr/src/minetest

View File

@ -108,9 +108,9 @@ Use `--help`
## Docker
* [Developing minetestserver with Docker](doc/developing/docker.md)
- [Developing minetestserver with Docker](doc/developing/docker.md)
We provide a Dockerfile that can be used to build the server.
- [Running a server with Docker](doc/docker_server.md)
## Version Scheme

View File

@ -75,7 +75,7 @@ task prepareAssets() {
from "${projRoot}/client/shaders" into "${assetsFolder}/client/shaders"
}
copy {
from "../native/deps/armeabi-v7a/Irrlicht/Shaders" into "${assetsFolder}/client/shaders/Irrlicht"
from "${projRoot}/irr/media/Shaders" into "${assetsFolder}/client/shaders/Irrlicht"
}
copy {
from "${projRoot}/fonts" include "*.ttf" into "${assetsFolder}/fonts"
@ -108,6 +108,10 @@ task prepareAssets() {
preBuild.dependsOn zipAssets
prepareAssets.dependsOn ':native:getDeps'
clean {
delete new File("src/main/assets", "Minetest.zip")
}
// Map for the version code that gives each ABI a value.
import com.android.build.OutputFile

View File

@ -10,7 +10,7 @@ project.ext.set("versionCode", 46) // Android Version Code
// each APK must have a larger `versionCode` than the previous
buildscript {
ext.ndk_version = '25.2.9519653'
ext.ndk_version = '26.2.11394342'
repositories {
google()
mavenCentral()

Binary file not shown.

View File

@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip

295
android/gradlew vendored
View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -17,78 +17,111 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -97,92 +130,120 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
command -v java >/dev/null || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
JAVACMD=java
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

100
android/gradlew.bat vendored
View File

@ -1,100 +0,0 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -43,19 +43,25 @@ android {
}
// get precompiled deps
task downloadDeps(type: Download) {
def depsDir = new File(buildDir.parent, 'deps')
def depsZip = new File(buildDir, 'deps.zip')
def depsDir = new File(buildDir.parent, 'deps')
if (new File(depsDir, 'armeabi-v7a').exists()) {
task getDeps {
doLast { logger.lifecycle('Using existing deps from {}', depsDir) }
}
} else {
task downloadDeps(type: Download) {
def depsZip = new File(buildDir, 'deps.zip')
src 'https://github.com/minetest/minetest_android_deps/releases/download/latest/deps.zip'
dest depsZip
overwrite false
src 'https://github.com/minetest/minetest_android_deps/releases/download/latest/deps-lite.zip'
dest depsZip
overwrite false
task getDeps(dependsOn: downloadDeps, type: Copy) {
depsDir.mkdir()
from zipTree(depsZip)
into depsDir
doFirst { logger.lifecycle('Extracting to {}', depsDir) }
task getDeps(dependsOn: downloadDeps, type: Copy) {
depsDir.mkdir()
from zipTree(depsZip)
into depsDir
doFirst { logger.lifecycle('Extracting to {}', depsDir) }
}
}
}

View File

@ -0,0 +1,13 @@
-- Registered metatables, used by the C++ packer
local known_metatables = {}
function core.register_async_metatable(name, mt)
assert(type(name) == "string", ("attempt to use %s value as metatable name"):format(type(name)))
assert(type(mt) == "table", ("attempt to register a %s value as metatable"):format(type(mt)))
assert(known_metatables[name] == nil or known_metatables[name] == mt,
("attempt to override metatable %s"):format(name))
known_metatables[name] = mt
known_metatables[mt] = name
end
core.known_metatables = known_metatables
core.register_async_metatable("__builtin:vector", vector.metatable)

View File

@ -31,11 +31,6 @@ function core.get_node(pos)
return core.vmanip:get_node_at(pos)
end
function core.get_node_or_nil(pos)
local node = core.vmanip:get_node_at(pos)
return node.name ~= "ignore" and node
end
function core.get_perlin(seed, octaves, persist, spread)
local params
if type(seed) == "table" then

View File

@ -37,6 +37,8 @@ core.features = {
blocking_pointability_type = true,
dynamic_add_media_startup = true,
dynamic_add_media_filepath = true,
lsystem_decoration_type = true,
item_meta_range = true,
}
function core.has_feature(arg)

View File

@ -18,6 +18,7 @@ if core.settings:get_bool("profiler.load") then
end
dofile(commonpath .. "after.lua")
dofile(commonpath .. "metatable.lua")
dofile(commonpath .. "mod_storage.lua")
dofile(gamepath .. "item_entity.lua")
dofile(gamepath .. "deprecated.lua")

View File

@ -736,3 +736,22 @@ core.noneitemdef_default = { -- This is used for the hand and unknown items
on_drop = nil,
on_use = nil,
}
--
-- get_node implementation
--
local get_node_raw = core.get_node_raw
core.get_node_raw = nil
function core.get_node(pos)
local content, param1, param2 = get_node_raw(pos.x, pos.y, pos.z)
return {name = core.get_name_from_content_id(content), param1 = param1, param2 = param2}
end
function core.get_node_or_nil(pos)
local content, param1, param2, pos_ok = get_node_raw(pos.x, pos.y, pos.z)
return pos_ok and
{name = core.get_name_from_content_id(content), param1 = param1, param2 = param2}
or nil
end

View File

@ -0,0 +1,84 @@
-- Table to keep track of callback executions
-- [i + 0] = count of expected patterns of index (i + 1)
-- [i + 1] = pattern to check
local PATTERN_NORMAL = { 4, "allow_%w", 2, "on_take", 1, "on_put", 1 }
local PATTERN_SWAP = { 8, "allow_%w", 4, "on_take", 2, "on_put", 2 }
local exec_listing = {} -- List of logged callbacks (e.g. "on_take", "allow_put")
-- Checks whether the logged callbacks equal the expected pattern
core.__helper_check_callbacks = function(expect_swap)
local exec_pattern = expect_swap and PATTERN_SWAP or PATTERN_NORMAL
local ok = #exec_listing == exec_pattern[1]
if ok then
local list_index = 1
for i = 2, #exec_pattern, 2 do
for n = 1, exec_pattern[i + 1] do
-- Match the list for "n" occurrences of the wanted callback name pattern
ok = exec_listing[list_index]:find(exec_pattern[i])
list_index = list_index + 1
if not ok then break end
end
if not ok then break end
end
end
if not ok then
print("Execution order mismatch!")
print("Expected patterns: ", dump(exec_pattern))
print("Got list: ", dump(exec_listing))
end
exec_listing = {}
return ok
end
-- Uncomment the other line for easier callback debugging
local log = function(...) end
--local log = print
minetest.register_allow_player_inventory_action(function(_, action, inv, info)
log("\tallow " .. action, info.count or info.stack:to_string())
if action == "move" then
-- testMoveFillStack
return info.count
end
if action == "take" or action == "put" then
assert(not info.stack:is_empty(), "Stack empty in: " .. action)
-- testMoveUnallowed
-- testSwapFromUnallowed
-- testSwapToUnallowed
if info.stack:get_name() == "default:takeput_deny" then
return 0
end
-- testMovePartial
if info.stack:get_name() == "default:takeput_max_5" then
return 5
end
-- testCallbacks
if info.stack:get_name():find("default:takeput_cb_%d") then
-- Log callback as executed
table.insert(exec_listing, "allow_" .. action)
return -- Unlimited
end
end
return -- Unlimited
end)
minetest.register_on_player_inventory_action(function(_, action, inv, info)
log("\ton " .. action, info.count or info.stack:to_string())
if action == "take" or action == "put" then
assert(not info.stack:is_empty(), action)
if info.stack:get_name():find("default:takeput_cb_%d") then
-- Log callback as executed
table.insert(exec_listing, "on_" .. action)
return
end
end
end)

View File

@ -63,6 +63,7 @@ elseif INIT == "mainmenu" then
elseif INIT == "async" then
dofile(asyncpath .. "mainmenu.lua")
elseif INIT == "async_game" then
dofile(commonpath .. "metatable.lua")
dofile(asyncpath .. "game.lua")
elseif INIT == "client" then
dofile(scriptdir .. "client" .. DIR_DELIM .. "init.lua")

View File

@ -18,6 +18,26 @@
-- Global menu data
menudata = {}
-- located in user cache path, for remembering this like e.g. last update check
cache_settings = Settings(core.get_cache_path() .. DIR_DELIM .. "common.conf")
--- Checks if the given key contains a timestamp less than a certain age.
--- Pair this with a call to `cache_settings:set(key, tostring(os.time()))`
--- after successfully refreshing the cache.
--- @param key Name of entry in cache_settings
--- @param max_age Age to check against, in seconds
--- @return true if the max age is not reached
function check_cache_age(key, max_age)
local time_now = os.time()
local time_checked = tonumber(cache_settings:get(key)) or 0
return time_now - time_checked < max_age
end
function core.on_before_close()
-- called before the menu is closed, either exit or to join a game
cache_settings:write()
end
-- Local cached values
local min_supp_proto, max_supp_proto
@ -27,6 +47,16 @@ function common_update_cached_supp_proto()
end
common_update_cached_supp_proto()
-- Other global functions
function core.sound_stop(handle, ...)
return handle:stop(...)
end
function os.tmpname()
error('do not use') -- instead: core.get_temp_path()
end
-- Menu helper functions
local function render_client_count(n)
@ -140,11 +170,6 @@ function render_serverlist_row(spec)
return table.concat(details, ",")
end
---------------------------------------------------------------------------------
os.tmpname = function()
error('do not use') -- instead use core.get_temp_path()
end
--------------------------------------------------------------------------------
function menu_render_worldlist()
local retval = {}

View File

@ -26,13 +26,23 @@ if not core.get_http_api then
end
assert(core.create_dir(core.get_cache_path() .. DIR_DELIM .. "cdb"))
local cache_file_path = core.get_cache_path() .. DIR_DELIM .. "cdb" .. DIR_DELIM .. "updates.json"
local has_fetched = false
local latest_releases
do
local tmp = core.get_once("cdb_latest_releases")
if tmp then
latest_releases = core.deserialize(tmp, true)
has_fetched = latest_releases ~= nil
if check_cache_age("cdb_updates_last_checked", 3 * 3600) then
local f = io.open(cache_file_path, "r")
local data = ""
if f then
data = f:read("*a")
f:close()
end
data = data ~= "" and core.parse_json(data) or nil
if type(data) == "table" then
latest_releases = data
has_fetched = true
end
end
end
@ -97,7 +107,8 @@ local function fetch()
return
end
latest_releases = lowercase_keys(releases)
core.set_once("cdb_latest_releases", core.serialize(latest_releases))
core.safe_file_write(cache_file_path, core.write_json(latest_releases))
cache_settings:set("cdb_updates_last_checked", tostring(os.time()))
if update_detector.get_count() > 0 then
local maintab = ui.find_by_name("maintab")

View File

@ -15,15 +15,30 @@
--with this program; if not, write to the Free Software Foundation, Inc.,
--51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
---- IMPORTANT ----
-- This whole file can be removed after a while.
-- It was only directly useful for upgrades from 5.7.0 to 5.8.0, but
-- maybe some odd fellow directly upgrades from 5.6.1 to 5.9.0 in the future...
-- see <https://github.com/minetest/minetest/pull/13850> in case it's not obvious
---- ----
local SETTING_NAME = "no_mtg_notification"
function check_reinstall_mtg()
if core.settings:get_bool("no_mtg_notification") then
-- used to be in minetest.conf
if core.settings:get_bool(SETTING_NAME) then
cache_settings:set_bool(SETTING_NAME, true)
core.settings:remove(SETTING_NAME)
end
if cache_settings:get_bool(SETTING_NAME) then
return
end
local games = core.get_games()
for _, game in ipairs(games) do
if game.id == "minetest" then
core.settings:set_bool("no_mtg_notification", true)
cache_settings:set_bool(SETTING_NAME, true)
return
end
end
@ -37,7 +52,7 @@ function check_reinstall_mtg()
end
end
if not mtg_world_found then
core.settings:set_bool("no_mtg_notification", true)
cache_settings:set_bool(SETTING_NAME, true)
return
end
@ -87,7 +102,7 @@ local function buttonhandler(this, fields)
end
if fields.dismiss then
core.settings:set_bool("no_mtg_notification", true)
cache_settings:set_bool("no_mtg_notification", true)
this:delete()
return true
end

View File

@ -51,12 +51,13 @@ end
local function version_info_buttonhandler(this, fields)
if fields.version_check_remind then
-- Erase last known, user will be reminded again at next check
core.settings:set("update_last_known", "")
cache_settings:set("update_last_known", "")
this:delete()
return true
end
if fields.version_check_never then
core.settings:set("update_last_checked", "disabled")
-- clear checked URL
core.settings:set("update_information_url", "")
this:delete()
return true
end
@ -116,7 +117,7 @@ local function on_version_info_received(json)
return
end
local known_update = tonumber(core.settings:get("update_last_known")) or 0
local known_update = tonumber(cache_settings:get("update_last_known")) or 0
-- Format: MMNNPPP (Major, Minor, Patch)
local new_number = type(json.latest) == "table" and json.latest.version_code
@ -135,7 +136,7 @@ local function on_version_info_received(json)
return
end
core.settings:set("update_last_known", tostring(new_number))
cache_settings:set("update_last_known", tostring(new_number))
-- Show version info dialog (once)
maintab:hide()
@ -149,20 +150,20 @@ end
function check_new_version()
local url = core.settings:get("update_information_url")
if core.settings:get("update_last_checked") == "disabled" or
url == "" then
if url == "" then
-- Never show any updates
return
end
local time_now = os.time()
local time_checked = tonumber(core.settings:get("update_last_checked")) or 0
if time_now - time_checked < 2 * 24 * 3600 then
-- Check interval of 2 entire days
-- every 2 days
if check_cache_age("update_last_checked", 2 * 24 * 3600) then
return
end
cache_settings:set("update_last_checked", tostring(os.time()))
core.settings:set("update_last_checked", tostring(time_now))
-- Clean old leftovers (this can be removed after 5.9.0 or so)
core.settings:remove("update_last_checked")
core.settings:remove("update_last_known")
core.handle_async(function(params)
local http = core.get_http_api()

View File

@ -28,8 +28,6 @@ local basepath = core.get_builtin_path()
defaulttexturedir = core.get_texturepath_share() .. DIR_DELIM .. "base" ..
DIR_DELIM .. "pack" .. DIR_DELIM
dofile(menupath .. DIR_DELIM .. "misc.lua")
dofile(basepath .. "common" .. DIR_DELIM .. "filterlist.lua")
dofile(basepath .. "fstk" .. DIR_DELIM .. "buttonbar.lua")
dofile(basepath .. "fstk" .. DIR_DELIM .. "dialog.lua")

View File

@ -1,6 +0,0 @@
-- old non-method sound function
function core.sound_stop(handle, ...)
return handle:stop(...)
end

View File

@ -17,7 +17,7 @@
serverlistmgr = {
-- continent code we detected for ourselves
my_continent = core.get_once("continent"),
my_continent = nil,
-- list of locally favorites servers
favorites = nil,
@ -26,6 +26,15 @@ serverlistmgr = {
servers = nil,
}
do
if check_cache_age("geoip_last_checked", 3600) then
local tmp = cache_settings:get("geoip") or ""
if tmp:match("^[A-Z][A-Z]$") then
serverlistmgr.my_continent = tmp
end
end
end
--------------------------------------------------------------------------------
-- Efficient data structure for normalizing arbitrary scores attached to objects
-- e.g. {{"a", 3.14}, {"b", 3.14}, {"c", 20}, {"d", 0}}
@ -112,6 +121,22 @@ local public_downloading = false
local geoip_downloading = false
--------------------------------------------------------------------------------
local function fetch_geoip()
local http = core.get_http_api()
local url = core.settings:get("serverlist_url") .. "/geoip"
local response = http.fetch_sync({ url = url })
if not response.succeeded then
return
end
local retval = core.parse_json(response.data)
if type(retval) ~= "table" then
return
end
return type(retval.continent) == "string" and retval.continent
end
function serverlistmgr.sync()
if not serverlistmgr.servers then
serverlistmgr.servers = {{
@ -129,37 +154,23 @@ function serverlistmgr.sync()
return
end
-- only fetched once per MT instance
if not serverlistmgr.my_continent and not geoip_downloading then
geoip_downloading = true
core.handle_async(
function(param)
local http = core.get_http_api()
local url = core.settings:get("serverlist_url") .. "/geoip"
local response = http.fetch_sync({ url = url })
if not response.succeeded then
return
end
local retval = core.parse_json(response.data)
return retval and type(retval.continent) == "string" and retval.continent
end,
nil,
function(result)
geoip_downloading = false
if not result then
return
end
serverlistmgr.my_continent = result
core.set_once("continent", result)
-- reorder list if we already have it
if serverlistmgr.servers then
serverlistmgr.servers = order_server_list(serverlistmgr.servers)
core.event_handler("Refresh")
end
core.handle_async(fetch_geoip, nil, function(result)
geoip_downloading = false
if not result then
return
end
)
serverlistmgr.my_continent = result
cache_settings:set("geoip", result)
cache_settings:set("geoip_last_checked", tostring(os.time()))
-- re-sort list if applicable
if serverlistmgr.servers then
serverlistmgr.servers = order_server_list(serverlistmgr.servers)
core.event_handler("Refresh")
end
end)
end
if public_downloading then
@ -167,6 +178,7 @@ function serverlistmgr.sync()
end
public_downloading = true
-- note: this isn't cached because it's way too dynamic
core.handle_async(
function(param)
local http = core.get_http_api()

View File

@ -158,7 +158,7 @@ return {
"style[label_button;border=false]" ..
"button[0.1,3.4;5.3,0.5;label_button;" ..
core.formspec_escape(version.project .. " " .. version.string) .. "]" ..
"button[1.5,4.1;2.5,0.8;homepage;minetest.net]" ..
"button_url[1.5,4.1;2.5,0.8;homepage;minetest.net;https://www.minetest.net/]" ..
"hypertext[5.5,0.25;9.75,6.6;credits;" .. minetest.formspec_escape(hypertext) .. "]"
-- Render information
@ -188,10 +188,6 @@ return {
end,
cbf_button_handler = function(this, fields, name, tabdata)
if fields.homepage then
core.open_url("https://www.minetest.net")
end
if fields.share_debug then
local path = core.get_user_path() .. DIR_DELIM .. "debug.txt"
core.share_file(path)

View File

@ -1,5 +1,6 @@
_G.core = {get_once = function(_) end}
_G.core = {}
_G.unpack = table.unpack
_G.check_cache_age = function() return false end
_G.serverlistmgr = {}
dofile("builtin/common/vector.lua")

View File

@ -114,7 +114,11 @@ always_fly_fast (Always fly fast) bool true
# the place button.
#
# Requires: keyboard_mouse
repeat_place_time (Place repetition interval) float 0.25 0.16 2
repeat_place_time (Place repetition interval) float 0.25 0.15 2.0
# The minimum time in seconds it takes between digging nodes when holding
# the dig button.
repeat_dig_time (Dig repetition interval) float 0.15 0.15 2.0
# Automatically jump up single-node obstacles.
autojump (Automatic jumping) bool false
@ -153,16 +157,21 @@ invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false
# Requires: !android
enable_touch (Enable touchscreen) bool true
# The length in pixels it takes for touchscreen interaction to start.
#
# Requires: touchscreen_gui
touchscreen_threshold (Touchscreen threshold) int 20 0 100
# Touchscreen sensitivity multiplier.
#
# Requires: touchscreen_gui
touchscreen_sensitivity (Touchscreen sensitivity) float 0.2 0.001 10.0
# The length in pixels after which a touch interaction is considered movement.
#
# Requires: touchscreen_gui
touchscreen_threshold (Movement threshold) int 20 0 100
# The delay in milliseconds after which a touch interaction is considered a long tap.
#
# Requires: touchscreen_gui
touch_long_tap_delay (Threshold for long taps) int 400 100 1000
# Use crosshair to select object instead of whole screen.
# If enabled, a crosshair will be shown and will be used for selecting object.
#
@ -181,6 +190,19 @@ fixed_virtual_joystick (Fixed virtual joystick) bool false
# Requires: touchscreen_gui
virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
# The gesture for for punching players/entities.
# This can be overridden by games and mods.
#
# * short_tap
# Easy to use and well-known from other games that shall not be named.
#
# * long_tap
# Known from the classic Minetest mobile controls.
# Combat is more or less impossible.
#
# Requires: touchscreen_gui
touch_punch_gesture (Punch gesture) enum short_tap short_tap,long_tap
[Graphics and Audio]
@ -772,6 +794,7 @@ serverlist_url (Serverlist URL) string servers.minetest.net
enable_split_login_register (Enable split login/register) bool true
# URL to JSON file which provides information about the newest Minetest release
# If this is empty the engine will never check for updates.
update_information_url (Update information URL) string https://www.minetest.net/release_info.json
[*Server]
@ -1816,10 +1839,6 @@ video_driver (Video driver) enum ,opengl,opengl3,ogles1,ogles2
# Use this to limit the performance impact of transparency depth sorting
transparency_sorting_distance (Transparency Sorting Distance) int 16 0 128
# Enable vertex buffer objects.
# This should greatly improve graphics performance.
enable_vbo (VBO) bool true
# Radius of cloud area stated in number of 64 node cloud squares.
# Values larger than 26 will start to produce sharp cutoffs at cloud area corners.
cloud_radius (Cloud radius) int 12 1 62
@ -2291,20 +2310,6 @@ show_advanced (Show advanced settings) bool false
# Changing this setting requires a restart.
enable_sound (Sound) bool true
# Unix timestamp (integer) of when the client last checked for an update
# Set this value to "disabled" to never check for updates.
update_last_checked (Last update check) string
# Version number which was last seen during an update check.
#
# Representation: MMMIIIPPP, where M=Major, I=Minor, P=Patch
# Ex: 5.5.0 is 005005000
update_last_known (Last known version update) int 0
# If this is set to true, the user will never (again) be shown the
# "reinstall Minetest Game" notification.
no_mtg_notification (Don't show "reinstall Minetest Game" notification) bool false
# Key for moving the player forward.
keymap_forward (Forward key) key KEY_KEY_W

1
client/shaders/Irrlicht Symbolic link
View File

@ -0,0 +1 @@
../../irr/media/Shaders

View File

@ -0,0 +1,17 @@
uniform vec4 fogColor;
uniform float fogDistance;
uniform float fogShadingParameter;
varying vec3 eyeVec;
varying lowp vec4 varColor;
void main(void)
{
vec4 col = varColor;
float clarity = clamp(fogShadingParameter
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
col.rgb = mix(fogColor.rgb, col.rgb, clarity);
gl_FragColor = col;
}

View File

@ -0,0 +1,21 @@
uniform vec4 emissiveColor;
varying lowp vec4 varColor;
varying vec3 eyeVec;
void main(void)
{
gl_Position = mWorldViewProj * inVertexPosition;
#ifdef GL_ES
vec4 color = inVertexColor.bgra;
#else
vec4 color = inVertexColor;
#endif
color *= emissiveColor;
varColor = color;
eyeVec = -(mWorldView * inVertexPosition).xyz;
}

View File

@ -1,6 +1,6 @@
uniform vec4 starColor;
uniform vec4 emissiveColor;
void main(void)
{
gl_FragColor = starColor;
gl_FragColor = emissiveColor;
}

View File

@ -1,31 +1,27 @@
set(DEPS "${CMAKE_SOURCE_DIR}/android/native/deps/${ANDROID_ABI}")
add_library(IrrlichtMt::IrrlichtMt STATIC IMPORTED)
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${DEPS}/Irrlicht/include)
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
IMPORTED_LOCATION ${DEPS}/Irrlicht/libIrrlichtMt.a)
set_target_properties(IrrlichtMt::IrrlichtMt PROPERTIES
INTERFACE_LINK_LIBRARIES "EGL;GLESv1_CM;GLESv2;${DEPS}/Irrlicht/libpng.a;${DEPS}/Irrlicht/libjpeg.a")
set(CURL_INCLUDE_DIR ${DEPS}/Curl/include)
set(CURL_LIBRARY ${DEPS}/Curl/libcurl.a;${DEPS}/Curl/libmbedcrypto.a;${DEPS}/Curl/libmbedtls.a;${DEPS}/Curl/libmbedx509.a)
set(FREETYPE_INCLUDE_DIR_ft2build ${DEPS}/Freetype/include/freetype2)
set(FREETYPE_INCLUDE_DIR_freetype2 ${FREETYPE_INCLUDE_DIR_ft2build}/freetype)
set(FREETYPE_INCLUDE_DIR_ft2build ${DEPS}/Freetype/include/freetype2)
set(FREETYPE_LIBRARY ${DEPS}/Freetype/libfreetype.a)
set(GETTEXT_INCLUDE_DIR ${DEPS}/Gettext/include;${DEPS}/Iconv/include)
set(GETTEXT_LIBRARY ${DEPS}/Gettext/libintl.a)
set(ICONV_LIBRARY ${DEPS}/Iconv/libiconv.a;${DEPS}/Iconv/libcharset.a)
set(JPEG_INCLUDE_DIR ${DEPS}/JPEG/include)
set(JPEG_LIBRARY ${DEPS}/JPEG/libjpeg.a)
set(LUA_INCLUDE_DIR ${DEPS}/LuaJIT/include)
set(LUA_LIBRARY ${DEPS}/LuaJIT/libluajit.a)
set(OGG_INCLUDE_DIR ${DEPS}/Vorbis/include)
set(OGG_LIBRARY ${DEPS}/Vorbis/libogg.a)
set(OPENAL_INCLUDE_DIR ${DEPS}/OpenAL-Soft/include)
set(OPENAL_LIBRARY ${DEPS}/OpenAL-Soft/libopenal.a;OpenSLES)
set(PNG_LIBRARY ${DEPS}/PNG/libpng.a)
set(PNG_PNG_INCLUDE_DIR ${DEPS}/PNG/include)
set(SQLITE3_INCLUDE_DIR ${DEPS}/SQLite/include)
set(SQLITE3_LIBRARY ${DEPS}/SQLite/libsqlite3.a)
set(VORBIS_INCLUDE_DIR ${DEPS}/Vorbis/include)
set(VORBISFILE_LIBRARY ${DEPS}/Vorbis/libvorbisfile.a)
set(VORBIS_LIBRARY ${DEPS}/Vorbis/libvorbis.a)
set(VORBISFILE_LIBRARY ${DEPS}/Vorbis/libvorbisfile.a)
set(ZSTD_INCLUDE_DIR ${DEPS}/Zstd/include)
set(ZSTD_LIBRARY ${DEPS}/Zstd/libzstd.a)

View File

@ -1,18 +0,0 @@
# Locate IrrlichtMt headers on system.
find_path(IRRLICHT_INCLUDE_DIR NAMES irrlicht.h
DOC "Path to the directory with IrrlichtMt includes"
PATHS
/usr/local/include/irrlichtmt
/usr/include/irrlichtmt
/system/develop/headers/irrlichtmt #Haiku
PATH_SUFFIXES "include/irrlichtmt"
)
# Handholding for users
if(IRRLICHT_INCLUDE_DIR AND (NOT IS_DIRECTORY "${IRRLICHT_INCLUDE_DIR}" OR
NOT EXISTS "${IRRLICHT_INCLUDE_DIR}/irrlicht.h"))
message(WARNING "IRRLICHT_INCLUDE_DIR was set to ${IRRLICHT_INCLUDE_DIR} "
"but irrlicht.h does not exist inside. The path will not be used.")
unset(IRRLICHT_INCLUDE_DIR CACHE)
endif()

View File

@ -54,8 +54,6 @@ Library specific options:
GETTEXT_LIBRARY - Optional/platform-dependent with gettext; path to libintl.so/libintl.dll.a
GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe
ICONV_LIBRARY - Optional/platform-dependent; path to libiconv.so/libiconv.dylib
IRRLICHT_DLL - Only on Windows; path to IrrlichtMt.dll
IRRLICHT_INCLUDE_DIR - Directory that contains IrrCompileConfig.h (usable for server build only)
LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h
LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a
LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll

View File

@ -2,47 +2,47 @@
## Dependencies
| Dependency | Version | Commentary |
| ---------- | ------- | -------------------------------------------------------------------- |
| GCC | 7.5+ | or Clang 7.0.1+ |
| CMake | 3.5+ | |
| Dependency | Version | Commentary |
| ---------- | ------- | ---------- |
| GCC | 7.5+ | or Clang 7.0.1+ |
| CMake | 3.5+ | |
| IrrlichtMt | - | Custom version of Irrlicht, see https://github.com/minetest/irrlicht |
| libjpeg | - | (via IrrlichtMt) |
| libpng | - | (via IrrlichtMt) |
| SDL | 2.x | (via IrrlichtMt) |
| Freetype | 2.0+ | |
| SQLite3 | 3+ | |
| Zlib | - | |
| Zstd | 1.0+ | |
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
| GMP | 5.0.0+ | Bundled mini-GMP is used if not present |
| JsonCPP | 1.0.0+ | Bundled JsonCPP is used if not present |
| Curl | 7.56.0+ | Optional |
| gettext | - | Optional |
| libjpeg | - | |
| libpng | - | |
| SDL | 2.x | |
| Freetype | 2.0+ | |
| SQLite3 | 3+ | |
| Zlib | - | |
| Zstd | 1.0+ | |
| LuaJIT | 2.0+ | Bundled Lua 5.1 is used if not present |
| GMP | 5.0.0+ | Bundled mini-GMP is used if not present |
| JsonCPP | 1.0.0+ | Bundled JsonCPP is used if not present |
| Curl | 7.56.0+ | Optional |
| gettext | - | Optional |
For Debian/Ubuntu users:
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext libsdl2-dev
sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext libsdl2-dev
For Fedora users:
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libXi-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext SDL2-devel
sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext SDL2-devel
For openSUSE users:
sudo zypper install gcc cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libXi-devel libvorbis-devel freetype2-devel SDL2-devel
sudo zypper install gcc cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libvorbis-devel freetype2-devel SDL2-devel
For Arch users:
sudo pacman -S --needed base-devel libcurl-gnutls cmake libxi libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2
sudo pacman -S --needed base-devel libcurl-gnutls cmake libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2
For Alpine users:
sudo apk add build-base cmake libpng-dev jpeg-dev libxi-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext sdl2-dev
sudo apk add build-base cmake libpng-dev jpeg-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext sdl2-dev
For Void users:
sudo xbps-install cmake libpng-devel jpeg-devel libXi-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel libzstd-devel gettext SDL2-devel
sudo xbps-install cmake libpng-devel jpeg-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel libzstd-devel gettext SDL2-devel
## Download
@ -73,24 +73,12 @@ Download source (this is the URL to the latest of source repository, which might
git clone --depth 1 https://github.com/minetest/minetest.git
cd minetest
Download IrrlichtMt to `lib/irrlichtmt`, it will be used to satisfy the IrrlichtMt dependency that way:
git clone --depth 1 --branch "$(cat misc/irrlichtmt_tag.txt)" https://github.com/minetest/irrlicht.git lib/irrlichtmt
Download source, without using Git:
wget https://github.com/minetest/minetest/archive/master.tar.gz
tar xf master.tar.gz
cd minetest-master
Download IrrlichtMt, without using Git:
cd lib/
wget https://github.com/minetest/irrlicht/archive/master.tar.gz
tar xf master.tar.gz
mv irrlicht-master irrlichtmt
cd ..
## Build
Build a version that runs directly from the source directory:
@ -109,13 +97,3 @@ Run it:
* You can disable the client build by specifying `-DBUILD_CLIENT=FALSE`.
* You can select between Release and Debug build by `-DCMAKE_BUILD_TYPE=<Debug or Release>`.
* Debug build is slower, but gives much more useful output in a debugger.
* If you build a bare server you don't need to compile IrrlichtMt, just the headers suffice.
* In that case use `-DIRRLICHT_INCLUDE_DIR=/some/where/irrlichtmt/include`.
* Minetest will use the IrrlichtMt package that is found first, given by the following order:
1. Specified `IRRLICHTMT_BUILD_DIR` CMake variable
2. `${PROJECT_SOURCE_DIR}/lib/irrlichtmt` (if existent)
3. Installation of IrrlichtMt in the system-specific library paths
4. For server builds with disabled `BUILD_CLIENT` variable, the headers from `IRRLICHT_INCLUDE_DIR` will be used.
> [!NOTE]
> Changing the IrrlichtMt build directory (includes system installs) requires regenerating the CMake cache (`rm CMakeCache.txt`)

View File

@ -19,12 +19,6 @@ git clone --depth 1 https://github.com/minetest/minetest.git
cd minetest
```
Download Minetest's fork of Irrlicht:
```bash
git clone --depth 1 --branch "$(cat misc/irrlichtmt_tag.txt)" https://github.com/minetest/irrlicht.git lib/irrlichtmt
```
## Build
```bash

View File

@ -17,12 +17,6 @@ After you successfully built vcpkg you can easily install the required libraries
vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp gettext sdl2 --triplet x64-windows
```
* **Don't forget about IrrlichtMt.** The easiest way is to clone it to `lib/irrlichtmt`:
```bat
for /F %i in (misc\irrlichtmt_tag.txt) do git clone --depth 1 --branch %i https://github.com/minetest/irrlicht.git lib\irrlichtmt
```
* `curl` is optional, but required to read the serverlist, `curl[winssl]` is required to use the content store.
* `openal-soft`, `libvorbis` and `libogg` are optional, but required to use sound.
* `luajit` is optional, it replaces the integrated Lua interpreter with a faster just-in-time interpreter.

View File

@ -15,6 +15,7 @@ Notable pages:
## In This Folder
* [Developing minetestserver with Docker](docker.md)
* [Android Tips & Tricks](android.md)
* [Miscellaneous](misc.md)
## IRC

63
doc/developing/android.md Normal file
View File

@ -0,0 +1,63 @@
# Android tips & tricks
## Sign the Android APK from CI
The [Github Actions Workflow](https://github.com/minetest/minetest/actions?query=workflow%3Aandroid+event%3Apush)
automatically produces an APK for each architecture.
Before installing them onto a device they however need to be signed.
This requires an installation of the Android SDK and `adb`.
```bash
.../android-sdk/build-tools/30.0.3/apksigner sign --ks ~/.android/debug.keystore \
app-arm64-v8a-release-unsigned.apk
# Enter 'android' (without quotes) when asked for a password
```
Note that the `debug.keystore` will not exist if you have never compiled an
Android app on your system (probably).
After that installing it will work:
```bash
adb install -r -d ./app-arm64-v8a-release-unsigned.apk
```
## How to get debug output from Minetest on Android
In case debug.txt isn't enough (e.g. when debugging a crash), you can get debug
output using logcat:
`adb logcat -s 'Minetest:*' '*:F'`
Note that you can do this even *after* the app has crashed,
since Android keeps an internal buffer.
A segmentation fault for example looks like this:
```
01-10 17:20:22.215 19308 20560 F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 20560 (MinetestNativeT), pid 19308 (netest.minetest)
01-10 17:20:22.287 20576 20576 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-10 17:20:22.287 20576 20576 F DEBUG : Build fingerprint: '...'
01-10 17:20:22.287 20576 20576 F DEBUG : Revision: '4'
01-10 17:20:22.287 20576 20576 F DEBUG : ABI: 'arm64'
01-10 17:20:22.288 20576 20576 F DEBUG : Timestamp: 2024-01-10 17:20:22+0100
01-10 17:20:22.288 20576 20576 F DEBUG : pid: 19308, tid: 20560, name: MinetestNativeT >>> net.minetest.minetest <<<
01-10 17:20:22.288 20576 20576 F DEBUG : uid: 10385
01-10 17:20:22.288 20576 20576 F DEBUG : signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
[ ... more information follows ... ]
```
If you want get rid of previous output you can do that with `adb logcat -c`.
## I edited builtin, shaders, ... but nothing changed. Help!
You're probably hitting two problems:
* the build system only generates assets once
* the app only re-extracts assets when the version changes
Force regenerating the assets: `./gradlew app:clean`
Erase the app's memory of which version was installed: `adb shell run-as net.minetest.minetest rm shared_prefs/MinetestSettings.xml`
If this doesn't work you can also uninstall it using `adb shell pm uninstall net.minetest.minetest`. You will obviously lose your data.
Then build and install as normal and your changes should be applied.

View File

@ -1,51 +1,5 @@
# Miscellaneous
## Sign the Android APK from CI
The [Github Actions Workflow](https://github.com/minetest/minetest/actions?query=workflow%3Aandroid+event%3Apush)
automatically produces an APK for each architecture.
Before installing them onto a device they however need to be signed.
This requires an installation of the Android SDK and `adb`.
```bash
.../android-sdk/build-tools/30.0.3/apksigner sign --ks ~/.android/debug.keystore \
app-arm64-v8a-release-unsigned.apk
# Enter 'android' (without quotes) when asked for a password
```
Note that the `debug.keystore` will not exist if you have never compiled an
Android app on your system (probably).
After that installing it will work:
```bash
adb install -r -d ./app-arm64-v8a-release-unsigned.apk
```
## How to get debug output from Minetest on Android
In case debug.txt isn't enough (e.g. when debugging a crash), you can get debug
output using logcat:
`adb logcat -s 'Minetest:*' '*:F'`
Note that you can do this even *after* the app has crashed,
since Android keeps an internal buffer.
A segmentation fault for example looks like this:
```
01-10 17:20:22.215 19308 20560 F libc : Fatal signal 6 (SIGABRT), code -1 (SI_QUEUE) in tid 20560 (MinetestNativeT), pid 19308 (netest.minetest)
01-10 17:20:22.287 20576 20576 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
01-10 17:20:22.287 20576 20576 F DEBUG : Build fingerprint: '...'
01-10 17:20:22.287 20576 20576 F DEBUG : Revision: '4'
01-10 17:20:22.287 20576 20576 F DEBUG : ABI: 'arm64'
01-10 17:20:22.288 20576 20576 F DEBUG : Timestamp: 2024-01-10 17:20:22+0100
01-10 17:20:22.288 20576 20576 F DEBUG : pid: 19308, tid: 20560, name: MinetestNativeT >>> net.minetest.minetest <<<
01-10 17:20:22.288 20576 20576 F DEBUG : uid: 10385
01-10 17:20:22.288 20576 20576 F DEBUG : signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
[ ... more information follows ... ]
```
## Profiling Minetest on Linux
We will be using a tool called "perf", which you can get by installing `perf` or `linux-perf` or `linux-tools-common`.

46
doc/docker_server.md Normal file
View File

@ -0,0 +1,46 @@
# Docker Server
We provide Minetest server Docker images using the GitHub container registry.
Images are built on each commit and available using the following tag scheme:
* `ghcr.io/minetest/minetest:master` (latest build)
* `ghcr.io/minetest/minetest:<tag>` (specific Git tag)
* `ghcr.io/minetest/minetest:latest` (latest Git tag, which is the stable release)
See [here](https://github.com/minetest/minetest/pkgs/container/minetest) for all available tags.
For a quick test you can easily run:
```shell
docker run ghcr.io/minetest/minetest:master
```
To use it in a production environment, you should use volumes bound to the Docker host to persist data and modify the configuration:
```shell
docker create -v /home/minetest/data/:/var/lib/minetest/ -v /home/minetest/conf/:/etc/minetest/ ghcr.io/minetest/minetest:master
```
You may also want to use [Docker Compose](https://docs.docker.com/compose):
```yaml
---
version: "2"
services:
minetest_server:
image: ghcr.io/minetest/minetest:master
restart: always
networks:
- default
volumes:
- /home/minetest/data/:/var/lib/minetest/
- /home/minetest/conf/:/etc/minetest/
ports:
- "30000:30000/udp"
- "127.0.0.1:30000:30000/tcp"
```
Data will be written to `/home/minetest/data` on the host, and configuration will be read from `/home/minetest/conf/minetest.conf`.
**Note:** If you don't understand the previous commands please read the [official Docker documentation](https://docs.docker.com) before use.

View File

@ -652,8 +652,9 @@ The mask is applied using binary AND.
#### `[sheet:<w>x<h>:<x>,<y>`
Retrieves a tile at position x,y from the base image
which it assumes to be a tilesheet with dimensions w,h.
Retrieves a tile at position x, y (in tiles, 0-indexed)
from the base image, which it assumes to be a tilesheet
with dimensions w, h (in tiles).
#### `[colorize:<color>:<ratio>`
@ -1085,6 +1086,7 @@ Table used to specify how a sound is played:
-- its end in `-start_time` seconds.
-- It is unspecified what happens if `loop` is false and `start_time` is
-- smaller than minus the sound's length.
-- Available since feature `sound_params_start_time`.
loop = false,
@ -1098,6 +1100,21 @@ Table used to specify how a sound is played:
-- Attach the sound to an object.
-- Can't be used together with `pos`.
-- For backward compatibility, sounds continue playing at the last location
-- of the object if an object is removed (for example if an entity dies).
-- It is not recommended to rely on this.
-- For death sounds, prefer playing a positional sound instead.
-- If you want to stop a sound when an entity dies or is deactivated,
-- store the handle and call `minetest.sound_stop` in `on_die` / `on_deactivate`.
-- Ephemeral sounds are entirely unaffected by the object being removed
-- or leaving the active object range.
-- Non-ephemeral sounds stop playing on clients if objects leave
-- the active object range; they should start playing again if objects
--- come back into range (but due to a known bug, they don't yet).
to_player = name,
-- Only play for this player.
-- Can't be used together with `exclude_player`.
@ -1382,8 +1399,7 @@ Look for examples in `games/devtest` or `games/minetest_game`.
* `liquid`
* The cubic source node for a liquid.
* Faces bordering to the same node are never rendered.
* Connects to node specified in `liquid_alternative_flowing`.
* You *must* set `liquid_alternative_source` to the node's own name.
* Connects to node specified in `liquid_alternative_flowing` if specified.
* Use `backface_culling = false` for the tiles you want to make
visible when inside the node.
* `flowingliquid`
@ -2499,6 +2515,8 @@ Some of the values in the key-value store are handled specially:
0 = default, 1 = left / up, 2 = middle, 3 = right / down
The default currently is the same as right/down.
Example: 6 = 2 + 1*4 = middle,up
* `range`: Overrides the pointing range
Example: `meta:set_float("range", 4.2)`
Example:
@ -2965,6 +2983,16 @@ background elements are drawn before all other elements.
centered on `H`. With the new coordinate system, `H` will modify the height.
* `label` is the text on the button
### `button_url[<X>,<Y>;<W>,<H>;<name>;<label>;<url>]`
* Clickable button. When clicked, fields will be sent and the user will be given the
option to open the URL in a browser.
* With the old coordinate system, buttons are a set height, but will be vertically
centered on `H`. With the new coordinate system, `H` will modify the height.
* To make this into an `image_button`, you can use formspec styling.
* `label` is the text on the button.
* `url` must be a valid web URL, starting with `http://` or `https://`.
### `image_button[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]`
* `texture name` is the filename of an image
@ -2991,6 +3019,11 @@ background elements are drawn before all other elements.
* When clicked, fields will be sent and the form will quit.
* Same as `button` in all other respects.
### `button_url_exit[<X>,<Y>;<W>,<H>;<name>;<label>;<url>]`
* When clicked, fields will be sent and the form will quit.
* Same as `button_url` in all other respects.
### `image_button_exit[<X>,<Y>;<W>,<H>;<texture name>;<name>;<label>]`
* When clicked, fields will be sent and the form will quit.
@ -3482,11 +3515,13 @@ Changes the style of the text.
Sets global style.
Global only styles:
* `background`: Text background, a `colorspec` or `none`.
* `margin`: Page margins in pixel.
* `valign`: Text vertical alignment (`top`, `middle`, `bottom`).
Inheriting styles (affects child elements):
* `color`: Default text color. Given color is a `colorspec`.
* `hovercolor`: Color of <action> tags when mouse is over.
* `size`: Default text size.
@ -3500,6 +3535,7 @@ tags appear.
`<tag name=... color=... hovercolor=... font=... size=...>`
Defines or redefines tag style. This can be used to define new tags.
* `name`: Name of the tag to define or change.
* `color`: Text color. Given color is a `colorspec`.
* `hovercolor`: Text color when element hovered (only for `action` tags). Given color is a `colorspec`.
@ -3532,6 +3568,7 @@ Other tags can be added using `<tag ...>` tag.
Make that text a clickable text triggering an action.
* `name`: Name of the action (mandatory).
* `url`: URL to open when the action is triggered (optional).
When clicked, the formspec is send to the server. The value of the text field
sent to `on_player_receive_fields` will be "action:" concatenated to the action
@ -3585,6 +3622,18 @@ X, Y and Z being angles around each three axes. Works only if
* Is not created automatically, use `InvRef:set_size`
* Is only used to enhance the empty hand's tool capabilities
## ItemStack transaction order
This list describes the situation for non-empty ItemStacks in both slots
that cannot be stacked at all, hence triggering an ItemStack swap operation.
Put/take callbacks on empty ItemStack are not executed.
1. The "allow take" and "allow put" callbacks are each run once for the source
and destination inventory.
2. The allowed ItemStacks are exchanged.
3. The "on take" callbacks are run for the source and destination inventories
4. The "on put" callbacks are run for the source and destination inventories
# Colors
@ -4005,25 +4054,31 @@ Two functions are provided to translate strings: `minetest.translate` and
avoid clashes with other mods.
This function must be given a number of arguments equal to the number of
arguments the translated string expects.
Arguments are literal strings -- they will not be translated, so if you want
them to be, they need to come as outputs of `minetest.translate` as well.
Arguments are literal strings -- they will not be translated.
For instance, suppose we want to translate "@1 Wool" with "@1" being replaced
by the translation of "Red". We can do the following:
For instance, suppose we want to greet players when they join. We can do the
following:
```lua
local S = minetest.get_translator()
S("@1 Wool", S("Red"))
```
```lua
local S = minetest.get_translator("hello")
minetest.register_on_joinplayer(function(player)
local name = player:get_player_name()
minetest.chat_send_player(name, S("Hello @1, how are you today?", name))
end)
```
This will be displayed as "Red Wool" on old clients and on clients that do
not have localization enabled. However, if we have for instance a translation
file named `wool.fr.tr` containing the following:
When someone called "CoolGuy" joins the game with an old client or a client
that does not have localization enabled, they will see `Hello CoolGuy, how are
you today?`
@1 Wool=Laine @1
Red=Rouge
However, if we have for instance a translation file named `hello.de.tr`
containing the following:
this will be displayed as "Laine Rouge" on clients with a French locale.
# textdomain: hello
Hello @1, how are you today?=Hallo @1, wie geht es dir heute?
and CoolGuy has set a German locale, they will see `Hallo CoolGuy, wie geht es
dir heute?`
## Operations on Translated Strings
@ -4450,6 +4505,11 @@ Can specify a probability of a node randomly appearing when placed.
This decoration type is intended to be used for multi-node sized discrete
structures, such as trees, cave spikes, rocks, and so on.
## `lsystem`
Generates a L-system tree at the position where the decoration is placed.
Uses the same L-system as `minetest.spawn_tree`, but is faster than using it manually.
The `treedef` field in the decoration definition is used for the tree definition.
# Schematics
@ -5187,6 +5247,12 @@ Minetest includes the following settings to control behavior of privileges:
* `minetest.get_worldpath()`: returns e.g. `"/home/user/.minetest/world"`
* Useful for storing custom data
* `minetest.get_mod_data_path()`: returns e.g. `"/home/user/.minetest/mod_data/mymod"`
* Useful for storing custom data *independently of worlds*.
* Must be called during mod load time.
* Can read or write to this directory at any time.
* It's possible that multiple Minetest instances are running at the same
time, which may lead to corruption if you are not careful.
* `minetest.is_singleplayer()`
* `minetest.features`: Table containing API feature flags
@ -5278,6 +5344,10 @@ Minetest includes the following settings to control behavior of privileges:
dynamic_add_media_startup = true,
-- dynamic_add_media supports `filename` and `filedata` parameters (5.9.0)
dynamic_add_media_filepath = true,
-- L-system decoration type (5.9.0)
lsystem_decoration_type = true,
-- Overrideable pointing range using the itemstack meta key `"range"` (5.9.0)
item_meta_range = true,
}
```
@ -5883,6 +5953,7 @@ handler.
returns `{name="ignore", param1=0, param2=0}` for unloaded areas.
* `minetest.get_node_or_nil(pos)`
* Same as `get_node` but returns `nil` for unloaded areas.
* Note that areas may still contain "ignore" despite being loaded.
* `minetest.get_node_light(pos[, timeofday])`
* Gets the light value at the given position. Note that the light value
"inside" the node at the given position is returned, so you usually want
@ -5928,7 +5999,7 @@ handler.
* `minetest.add_entity(pos, name, [staticdata])`: Spawn Lua-defined entity at
position.
* Returns `ObjectRef`, or `nil` if failed
* Entities with `static_save = true` can be added also
* Entities with `static_save = true` can be added also
to unloaded and non-generated blocks.
* `minetest.add_item(pos, item)`: Spawn item
* Returns `ObjectRef`, or `nil` if failed
@ -6120,13 +6191,16 @@ handler.
* Returns the position of the blocking node when `false`
* `pos1`: First position
* `pos2`: Second position
* `minetest.raycast(pos1, pos2, objects, liquids)`: returns `Raycast`
* `minetest.raycast(pos1, pos2, objects, liquids, pointabilities)`: returns `Raycast`
* Creates a `Raycast` object.
* `pos1`: start of the ray
* `pos2`: end of the ray
* `objects`: if false, only nodes will be returned. Default is `true`.
* `liquids`: if false, liquid nodes (`liquidtype ~= "none"`) won't be
returned. Default is `false`.
returned. Default is `false`.
* `pointabilities`: Allows overriding the `pointable` property of
nodes and objects. Uses the same format as the `pointabilities` property
of item definitions. Default is `nil`.
* `minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)`
* returns table containing path that can be walked on
* returns a table of 3D points representing a path from `pos1` to `pos2` or
@ -6503,6 +6577,18 @@ This allows you easy interoperability for delegating work to jobs.
* Register a path to a Lua file to be imported when an async environment
is initialized. You can use this to preload code which you can then call
later using `minetest.handle_async()`.
* `minetest.register_async_metatable(name, mt)`:
* Register a metatable that should be preserved when data is transferred
between the main thread and the async environment.
* `name` is a string that identifies the metatable. It is recommended to
follow the `modname:name` convention for this identifier.
* `mt` is the metatable to register.
* Note that it is allowed to register the same metatable under multiple
names, but it is not allowed to register multiple metatables under the
same name.
* You must register the metatable in both the main environment
and the async environment for this mechanism to work.
### List of APIs Available in an Async Environment
@ -6528,6 +6614,7 @@ Class instances that can be transferred between environments:
Functions:
* Standalone helpers such as logging, filesystem, encoding,
hashing or compression APIs
* `minetest.register_async_metatable` (see above)
Variables:
* `minetest.settings`
@ -7143,9 +7230,45 @@ You can use the gennotify mechanism to transfer this information.
All callbacks registered with [Global callback registration functions] are added
to corresponding `minetest.registered_*` tables.
For historical reasons, the use of an -s suffix in these names is inconsistent.
* `minetest.registered_on_chat_messages`
* `minetest.registered_on_chatcommands`
* `minetest.registered_globalsteps`
* `minetest.registered_on_punchnodes`
* `minetest.registered_on_placenodes`
* `minetest.registered_on_dignodes`
* `minetest.registered_on_generateds`
* `minetest.registered_on_newplayers`
* `minetest.registered_on_dieplayers`
* `minetest.registered_on_respawnplayers`
* `minetest.registered_on_prejoinplayers`
* `minetest.registered_on_joinplayers`
* `minetest.registered_on_leaveplayers`
* `minetest.registered_on_player_receive_fields`
* `minetest.registered_on_cheats`
* `minetest.registered_on_crafts`
* `minetest.registered_craft_predicts`
* `minetest.registered_on_item_eats`
* `minetest.registered_on_item_pickups`
* `minetest.registered_on_punchplayers`
* `minetest.registered_on_authplayers`
* `minetest.registered_on_player_inventory_actions`
* `minetest.registered_allow_player_inventory_actions`
* `minetest.registered_on_rightclickplayers`
* `minetest.registered_on_mods_loaded`
* `minetest.registered_on_shutdown`
* `minetest.registered_on_protection_violation`
* `minetest.registered_on_priv_grant`
* `minetest.registered_on_priv_revoke`
* `minetest.registered_can_bypass_userlimit`
* `minetest.registered_on_modchannel_message`
* `minetest.registered_on_liquid_transformed`
* `minetest.registered_on_mapblocks_changed`
# Class Reference
# Class reference
Sorted alphabetically.
@ -7765,10 +7888,14 @@ child will follow movement and rotation of that bone.
* Second column: subject looking to the left
* Third column: subject backing the camera
* Fourth column: subject looking to the right
* Fifth column: subject viewed from above
* Sixth column: subject viewed from below
* `get_entity_name()`: (**Deprecated**: Will be removed in a future version, use the field `self.name` instead)
* `get_luaentity()`
* Fifth column: subject viewed from above
* Sixth column: subject viewed from below
* `get_luaentity()`:
* Returns the object's associated luaentity table, if there is one
* Otherwise returns `nil` (e.g. for players)
* `get_entity_name()`:
* **Deprecated**: Will be removed in a future version,
use `:get_luaentity().name` instead.
#### Player Only (No-Op for Other Objects)
@ -8473,7 +8600,8 @@ Player properties need to be saved manually.
-- "mesh" uses the defined mesh model.
-- "wielditem" is used for dropped items.
-- (see builtin/game/item_entity.lua).
-- For this use 'wield_item = itemname' (Deprecated: 'textures = {itemname}').
-- For this use 'wield_item = itemname'.
-- Setting 'textures = {itemname}' has the same effect, but is deprecated.
-- If the item has a 'wield_image' the object will be an extrusion of
-- that, otherwise:
-- If 'itemname' is a cubic node or nodebox the object will appear
@ -8500,8 +8628,8 @@ Player properties need to be saved manually.
-- "cube" uses 6 textures just like a node, but all 6 must be defined.
-- "sprite" uses 1 texture.
-- "upright_sprite" uses 2 textures: {front, back}.
-- "wielditem" expects 'textures = {itemname}' (see 'visual' above).
-- "mesh" requires one texture for each mesh buffer/material (in order)
-- Deprecated usage of "wielditem" expects 'textures = {itemname}' (see 'visual' above).
colors = {},
-- Number of required colors depends on visual
@ -8817,6 +8945,7 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
range = 4.0,
-- Range of node and object pointing that is possible with this item held
-- Can be overridden with itemstack meta.
liquids_pointable = false,
-- If true, item can point to all liquid nodes (`liquidtype ~= "none"`),
@ -8830,9 +8959,9 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
objects = {
["modname:entityname"] = true,
["group:ghosty"] = true, -- (an armor group)
}
},
},
-- Contains lists to override the `pointable` property of pointed nodes and objects.
-- Contains lists to override the `pointable` property of nodes and objects.
-- The index can be a node/entity name or a group with the prefix `"group:"`.
-- (For objects `armor_groups` are used and for players the entity name is irrelevant.)
-- If multiple fields fit, the following priority order is applied:
@ -8897,19 +9026,20 @@ Used by `minetest.register_node`, `minetest.register_craftitem`, and
-- Otherwise should be name of node which the client immediately places
-- upon digging. Server will always update with actual result shortly.
touch_interaction = {
-- Only affects touchscreen clients.
-- Defines the meaning of short and long taps with the item in hand.
-- The fields in this table have two valid values:
-- * "long_dig_short_place" (long tap = dig, short tap = place)
-- * "short_dig_long_place" (short tap = dig, long tap = place)
-- The field to be used is selected according to the current
-- `pointed_thing`.
pointed_nothing = "long_dig_short_place",
pointed_node = "long_dig_short_place",
pointed_object = "short_dig_long_place",
touch_interaction = <TouchInteractionMode> OR {
pointed_nothing = <TouchInteractionMode>,
pointed_node = <TouchInteractionMode>,
pointed_object = <TouchInteractionMode>,
},
-- Only affects touchscreen clients.
-- Defines the meaning of short and long taps with the item in hand.
-- If specified as a table, the field to be used is selected according to
-- the current `pointed_thing`.
-- There are three possible TouchInteractionMode values:
-- * "user" (meaning depends on client-side settings)
-- * "long_dig_short_place" (long tap = dig, short tap = place)
-- * "short_dig_long_place" (short tap = dig, long tap = place)
-- The default value is "user".
sound = {
-- Definition of item sounds to be played at various events.
@ -9121,10 +9251,8 @@ Used by `minetest.register_node`.
-- flowing version (`liquid_alternative_flowing`) and
-- source version (`liquid_alternative_source`) of a liquid.
--
-- Specifically, these fields are required if any of these is true:
-- * `liquidtype ~= "none" or
-- * `drawtype == "liquid" or
-- * `drawtype == "flowingliquid"
-- Specifically, these fields are required if `liquidtype ~= "none"` or
-- `drawtype == "flowingliquid"`.
--
-- Liquids consist of up to two nodes: source and flowing.
--
@ -9988,7 +10116,7 @@ See [Decoration types]. Used by `minetest.register_decoration`.
```lua
{
deco_type = "simple",
-- Type. "simple" or "schematic" supported
-- Type. "simple", "schematic" or "lsystem" supported
place_on = "default:dirt_with_grass",
-- Node (or list of nodes) that the decoration can be placed on
@ -10141,6 +10269,12 @@ See [Decoration types]. Used by `minetest.register_decoration`.
-- Effect is inverted for "all_ceilings" decorations.
-- Ignored by 'y_min', 'y_max' and 'spawn_by' checks, which always refer
-- to the 'place_on' node.
----- L-system-type parameters
treedef = {},
-- Same as for `minetest.spawn_tree`.
-- See section [L-system trees] for more details.
}
```

View File

@ -53,10 +53,6 @@ The "gamedata" table is read when calling `core.start()`. It should contain:
* Android only. Shares file using the share popup
* `core.get_version()` (possible in async calls)
* returns current core version
* `core.set_once(key, value)`:
* save a string value that persists even if menu is closed
* `core.get_once(key)`:
* get a string value saved by above function, or `nil`

View File

@ -71,6 +71,22 @@ minetest.register_chatcommand("bench_content2name", {
end,
})
local function get_positions_cube(ppos)
local pos_list = {}
local i = 1
for x=2,100 do
for y=2,100 do
for z=2,100 do
pos_list[i] = ppos:offset(x, y, z)
i = i + 1
end
end
end
return pos_list
end
minetest.register_chatcommand("bench_bulk_set_node", {
params = "",
description = "Benchmark: Bulk-set 99×99×99 stone nodes",
@ -79,25 +95,15 @@ minetest.register_chatcommand("bench_bulk_set_node", {
if not player then
return false, "No player."
end
local pos_list = {}
local ppos = player:get_pos()
local i = 1
for x=2,100 do
for y=2,100 do
for z=2,100 do
pos_list[i] = {x=ppos.x + x,y = ppos.y + y,z = ppos.z + z}
i = i + 1
end
end
end
local pos_list = get_positions_cube(player:get_pos())
minetest.chat_send_player(name, "Benchmarking minetest.bulk_set_node. Warming up ...");
minetest.chat_send_player(name, "Benchmarking minetest.bulk_set_node. Warming up ...")
-- warm up with stone to prevent having different callbacks
-- due to different node topology
minetest.bulk_set_node(pos_list, {name = "mapgen_stone"})
minetest.chat_send_player(name, "Warming up finished, now benchmarking ...");
minetest.chat_send_player(name, "Warming up finished, now benchmarking ...")
local start_time = minetest.get_us_time()
for i=1,#pos_list do
@ -114,4 +120,37 @@ minetest.register_chatcommand("bench_bulk_set_node", {
end,
})
minetest.register_chatcommand("bench_bulk_get_node", {
params = "",
description = "Benchmark: Bulk-get 99×99×99 nodes",
func = function(name, param)
local player = minetest.get_player_by_name(name)
if not player then
return false, "No player."
end
local pos_list = get_positions_cube(player:get_pos())
local function bench()
local start_time = minetest.get_us_time()
for i=1,#pos_list do
local n = minetest.get_node(pos_list[i])
-- Make sure the name lookup is never optimized away.
-- Table allocation might still be omitted. But only accessing
-- the name of a node is a common pattern anyways.
if n.name == "benchmarks:nonexistent_node" then
error("should never happen")
end
end
return minetest.get_us_time() - start_time
end
minetest.chat_send_player(name, "Benchmarking minetest.get_node. Warming up ...")
bench()
minetest.chat_send_player(name, "Warming up finished, now benchmarking ...")
local result_us = bench()
local msg = string.format("Benchmark results: minetest.get_node loop 1: %.2f ms",
result_us / 1000)
return true, msg
end,
})

View File

@ -29,12 +29,16 @@ minetest.register_node("chest:chest", {
return inv:is_empty("main")
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
print_to_everything("Chest: ".. player:get_player_name() .. " triggered 'allow put' event for " .. stack:to_string())
return stack:get_count()
print_to_everything("Chest: ".. player:get_player_name() .. " triggered 'allow put' (10) event for " .. stack:to_string())
return 10
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
print_to_everything("Chest: ".. player:get_player_name() .. " triggered 'allow take' event for " .. stack:to_string())
return stack:get_count()
print_to_everything("Chest: ".. player:get_player_name() .. " triggered 'allow take' (20) event for " .. stack:to_string())
return 20
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
print_to_everything("Chest: ".. player:get_player_name() .. " triggered 'allow move' (30) event")
return 30
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
print_to_everything("Chest: ".. player:get_player_name() .. " put " .. stack:to_string())
@ -42,4 +46,7 @@ minetest.register_node("chest:chest", {
on_metadata_inventory_take = function(pos, listname, index, stack, player)
print_to_everything("Chest: ".. player:get_player_name() .. " took " .. stack:to_string())
end,
on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
print_to_everything("Chest: ".. player:get_player_name() .. " moved " .. count)
end,
})

View File

@ -1,12 +1,15 @@
local color = minetest.colorize
-- \208\176 is a cyrillic small a
local unsafe_url = minetest.formspec_escape("https://u:p@wikipedi\208\176.org:1233/heIIoll?a=b#c")
local clip_fs = [[
style_type[label,button,image_button,item_image_button,
tabheader,scrollbar,table,animated_image
,field,textarea,checkbox,dropdown;noclip=%c]
label[0,0;A clipping test]
button[0,1;3,0.8;clip_button;A clipping test]
button_url[0,1;3,0.8;clip_button;A clipping test;]] .. unsafe_url .. [[]
image_button[0,2;3,0.8;testformspec_button_image.png;clip_image_button;A clipping test]
item_image_button[0,3;3,0.8;testformspec:item;clip_item_image_button;A clipping test]
tabheader[0,4.7;3,0.63;clip_tabheader;Clip,Test,Text,Tabs;1;false;false]
@ -92,6 +95,7 @@ This is a normal text.
<t_green>color=green</t_green>
Action: <action name=color><t_green>color=green</t_green></action>
Action: <action name=hovercolor><t_hover>hovercolor=yellow</t_hover></action>
Action URL: <action name=open url=https://example.com/?a=b#c>open URL</action>
<t_size>size=24</t_size>
<t_mono>font=mono</t_mono>
<t_multi>color=green font=mono size=24</t_multi>
@ -145,7 +149,7 @@ local hypertext_fs = "hypertext[0,0;11,9;hypertext;"..minetest.formspec_escape(h
local style_fs = [[
style[one_btn1;bgcolor=red;textcolor=yellow;bgcolor_hovered=orange;
bgcolor_pressed=purple]
button[0,0;2.5,0.8;one_btn1;Button]
button_url_exit[0,0;2.5,0.8;one_btn1;Button;]] .. unsafe_url .. [[]
style[one_btn2;border=false;textcolor=cyan] ]]..
"button[0,1.05;2.5,0.8;one_btn2;Text " .. color("#FF0", "Yellow") .. [[]

View File

@ -90,3 +90,18 @@ minetest.register_craftitem("testitems:image_meta", {
return itemstack
end,
})
minetest.register_craftitem("testitems:telescope_stick", {
description = S("Telescope Stick (Increases range on use.)"),
inventory_image = "testitems_telescope_stick.png",
on_use = function(itemstack, player)
local meta = itemstack:get_meta()
local range = meta:get_float("range") + 1.2
if range > 10 then
range = 0
end
meta:set_float("range", range)
minetest.chat_send_player(player:get_player_name(), "Telescope Stick range set to "..range)
return itemstack
end,
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

View File

@ -33,6 +33,25 @@ minetest.register_node("testnodes:anim", {
groups = { dig_immediate = 2 },
})
minetest.register_node("testnodes:fill_positioning", {
description = S("Fill Modifier Test Node") .. "\n" ..
S("The node should have the same look as " ..
"testnodes:fill_positioning_reference."),
drawtype = "glasslike",
paramtype = "light",
tiles = {"[fill:16x16:#ffffff^[fill:6x6:1,1:#00ffdc" ..
"^[fill:6x6:1,9:#00ffdc^[fill:6x6:9,1:#00ffdc^[fill:6x6:9,9:#00ffdc"},
groups = {dig_immediate = 3},
})
minetest.register_node("testnodes:fill_positioning_reference", {
description = S("Fill Modifier Test Node Reference"),
drawtype = "glasslike",
paramtype = "light",
tiles = {"testnodes_fill_positioning_reference.png"},
groups = {dig_immediate = 3},
})
-- Node texture transparency test
local alphas = { 64, 128, 191 }
@ -69,6 +88,19 @@ for a=1,#alphas do
})
end
minetest.register_node("testnodes:alpha_compositing", {
description = S("Alpha Compositing Test Node") .. "\n" ..
S("A regular grid should be visible where each cell contains two " ..
"texels with the same colour.") .. "\n" ..
S("Alpha compositing is gamma-incorrect for backwards compatibility."),
drawtype = "glasslike",
paramtype = "light",
tiles = {"testnodes_alpha_compositing_bottom.png^" ..
"testnodes_alpha_compositing_top.png"},
use_texture_alpha = "blend",
groups = {dig_immediate = 3},
})
-- Generate PNG textures
local function mandelbrot(w, h, iterations)

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

View File

@ -53,7 +53,7 @@ local test_object = {
end,
sunlight_propagates = true,
is_ground_content = false,
light_source = 0,
pos = vector.new(-1, -2, -3),
}
local function test_object_passing()
@ -166,3 +166,44 @@ local function test_userdata_passing2(cb, _, pos)
end, vm, pos)
end
unittests.register("test_userdata_passing2", test_userdata_passing2, {map=true, async=true})
local function test_async_metatable_override()
assert(pcall(core.register_async_metatable, "__builtin:vector", vector.metatable),
"Metatable name aliasing throws an error when it should be allowed")
assert(not pcall(core.register_async_metatable, "__builtin:vector", {}),
"Illegal metatable overriding allowed")
end
unittests.register("test_async_metatable_override", test_async_metatable_override)
local function test_async_metatable_registration(cb)
local custom_metatable = {}
core.register_async_metatable("unittests:custom_metatable", custom_metatable)
core.handle_async(function(x)
-- unittests.custom_metatable is registered in inside_async_env.lua
return getmetatable(x) == unittests.custom_metatable, x
end, function(metatable_preserved_async, table_after_roundtrip)
if not metatable_preserved_async then
return cb("Custom metatable not preserved (main -> async)")
end
if getmetatable(table_after_roundtrip) ~= custom_metatable then
return cb("Custom metable not preserved (after roundtrip)")
end
cb()
end, setmetatable({}, custom_metatable))
end
unittests.register("test_async_metatable_registration", test_async_metatable_registration, {async=true})
local function test_vector_preserve(cb)
local vec = vector.new(1, 2, 3)
core.handle_async(function(x)
return x[1]
end, function(ret)
if ret ~= vec then -- fails if metatable was not preserved
return cb("Vector value mismatch")
end
cb()
end, {vec})
end
unittests.register("test_async_vector", test_vector_preserve, {async=true})

View File

@ -108,9 +108,9 @@ local function wait_for_player(callback)
end)
end
local function wait_for_map(player, callback)
local function wait_for_map(pos, callback)
local function check()
if core.get_node_or_nil(player:get_pos()) ~= nil then
if core.get_node(pos).name ~= "ignore" then
callback()
else
core.after(0, check)
@ -119,8 +119,8 @@ local function wait_for_map(player, callback)
check()
end
-- This runs in a coroutine so it uses await()
function unittests.run_all()
-- This runs in a coroutine so it uses await().
local counters = { time = 0, total = 0, passed = 0 }
-- Run standalone tests first
@ -143,10 +143,11 @@ function unittests.run_all()
end
-- Wait for the world to generate/load, run tests that require map access
local pos = player:get_pos():round():offset(0, 5, 0)
core.forceload_block(pos, true, -1)
await(function(cb)
wait_for_map(player, cb)
wait_for_map(pos, cb)
end)
local pos = vector.round(player:get_pos())
for idx = 1, #unittests.list do
local def = unittests.list[idx]
if not def.done then
@ -182,6 +183,7 @@ dofile(modpath .. "/get_version.lua")
dofile(modpath .. "/itemstack_equals.lua")
dofile(modpath .. "/content_ids.lua")
dofile(modpath .. "/metadata.lua")
dofile(modpath .. "/raycast.lua")
--------------

View File

@ -2,6 +2,9 @@ unittests = {}
core.log("info", "Hello World")
unittests.custom_metatable = {}
core.register_async_metatable("unittests:custom_metatable", unittests.custom_metatable)
local function do_tests()
assert(core == minetest)
-- stuff that should not be here

View File

@ -99,17 +99,24 @@ local function test_clear_meta(_, pos)
end
unittests.register("test_clear_meta", test_clear_meta, {map=true})
local on_punch_called
minetest.register_on_punchnode(function()
local on_punch_called, on_place_called
core.register_on_placenode(function()
on_place_called = true
end)
core.register_on_punchnode(function()
on_punch_called = true
end)
unittests.register("test_punch_node", function(_, pos)
minetest.place_node(pos, {name="basenodes:dirt"})
local function test_node_callbacks(_, pos)
on_place_called = false
on_punch_called = false
minetest.punch_node(pos)
minetest.remove_node(pos)
-- currently failing: assert(on_punch_called)
end, {map=true})
core.place_node(pos, {name="basenodes:dirt"})
assert(on_place_called, "on_place not called")
core.punch_node(pos)
assert(on_punch_called, "on_punch not called")
core.remove_node(pos)
end
unittests.register("test_node_callbacks", test_node_callbacks, {map=true})
local function test_hashing()
local input = "hello\000world"

View File

@ -0,0 +1,36 @@
local function raycast_with_pointabilities(start_pos, end_pos, pointabilities)
local ray = core.raycast(start_pos, end_pos, nil, nil, pointabilities)
for hit in ray do
if hit.type == "node" then
return hit.under
end
end
return nil
end
local function test_raycast_pointabilities(player, pos1)
local pos2 = pos1:offset(0, 0, 1)
local pos3 = pos1:offset(0, 0, 2)
local oldnode1 = core.get_node(pos1)
local oldnode2 = core.get_node(pos2)
local oldnode3 = core.get_node(pos3)
core.swap_node(pos1, {name = "air"})
core.swap_node(pos2, {name = "testnodes:not_pointable"})
core.swap_node(pos3, {name = "testnodes:pointable"})
local p = nil
assert(raycast_with_pointabilities(pos1, pos3, p) == pos3)
p = core.registered_items["testtools:blocked_pointing_staff"].pointabilities
assert(raycast_with_pointabilities(pos1, pos3, p) == nil)
p = core.registered_items["testtools:ultimate_pointing_staff"].pointabilities
assert(raycast_with_pointabilities(pos1, pos3, p) == pos2)
core.swap_node(pos1, oldnode1)
core.swap_node(pos2, oldnode2)
core.swap_node(pos3, oldnode3)
end
unittests.register("test_raycast_pointabilities", test_raycast_pointabilities, {map=true})

10
irr/.editorconfig Executable file
View File

@ -0,0 +1,10 @@
root = true
[*]
charset = utf-8
[*.{cpp,h,txt,cmake,fsh,vsh}]
indent_size = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true

310
irr/.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,310 @@
name: build
# build on c/cpp changes or workflow changes
on:
- push
- pull_request
jobs:
linux-gl:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Install deps
run: |
sudo apt-get update
sudo apt-get install g++ cmake libxi-dev libgl1-mesa-dev libpng-dev libjpeg-dev zlib1g-dev -qyy
- name: Build
run: |
cmake . -DUSE_SDL2=OFF
make VERBOSE=1 -j2
- name: Test
run: |
ctest --output-on-failure
- name: Package
run: |
make DESTDIR=$PWD/_install install
tar -c -I "gzip -9" -f irrlicht-linux.tar.gz -C ./_install/usr/local .
- uses: actions/upload-artifact@v4
with:
name: irrlicht-linux
path: ./irrlicht-linux.tar.gz
linux-gles:
# Xvfb test is broken on 20.04 for unknown reasons (not our bug)
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install deps
run: |
sudo apt-get update
sudo apt-get install g++ cmake libxi-dev libgles2-mesa-dev libpng-dev libjpeg-dev zlib1g-dev xvfb -qyy
- name: Build
run: |
cmake . -DBUILD_EXAMPLES=1 -DUSE_SDL2=OFF -DENABLE_OPENGL=OFF -DENABLE_GLES2=ON
make -j2
- name: Test (headless)
run: |
cd bin/Linux
./AutomatedTest null
- name: Test (Xvfb)
run: |
cd bin/Linux
LIBGL_ALWAYS_SOFTWARE=true xvfb-run ./AutomatedTest ogles2
linux-sdl:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Install deps
run: |
sudo apt-get update
sudo apt-get install g++ cmake libsdl2-dev libpng-dev libjpeg-dev zlib1g-dev -qyy
- name: Build
run: |
cmake . -DBUILD_EXAMPLES=1 -DUSE_SDL2=ON -DCMAKE_BUILD_TYPE=Debug
make -j2
- name: Test (headless)
run: |
cd bin/Linux
./AutomatedTest null
linux-sdl-gl3:
# Xvfb test is broken on 20.04 for unknown reasons (not our bug)
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Install deps
run: |
sudo apt-get update
sudo apt-get install g++ cmake libsdl2-dev libpng-dev libjpeg-dev zlib1g-dev xvfb -qyy
- name: Build
run: |
cmake . -DBUILD_EXAMPLES=1 -DUSE_SDL2=ON -DENABLE_OPENGL=OFF -DENABLE_OPENGL3=ON
make -j2
- name: Test (headless)
run: |
cd bin/Linux
./AutomatedTest null
- name: Test (Xvfb)
run: |
cd bin/Linux
LIBGL_ALWAYS_SOFTWARE=true xvfb-run ./AutomatedTest opengl3
linux-sdl-gles2:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Install deps
run: |
sudo apt-get update
sudo apt-get install g++ cmake libsdl2-dev libpng-dev libjpeg-dev zlib1g-dev xvfb -qyy
- name: Build
run: |
cmake . -DBUILD_EXAMPLES=1 -DUSE_SDL2=ON -DENABLE_OPENGL=OFF -DENABLE_GLES2=ON
make -j2
- name: Test (headless)
run: |
cd bin/Linux
./AutomatedTest null
- name: Test (Xvfb)
run: |
cd bin/Linux
LIBGL_ALWAYS_SOFTWARE=true xvfb-run ./AutomatedTest ogles2
mingw:
name: "MinGW ${{matrix.config.variant}}${{matrix.config.extras}}"
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
config:
- {variant: win32, arch: i686}
- {variant: win64, arch: x86_64}
- {variant: win32, arch: i686, extras: "-sdl"}
- {variant: win64, arch: x86_64, extras: "-sdl"}
steps:
- uses: actions/checkout@v4
- name: Install compiler
run: |
sudo apt-get update && sudo apt-get install cmake -qyy
./scripts/ci-get-mingw.sh
- name: Build
run: |
./scripts/ci-build-mingw.sh package
env:
CC: ${{matrix.config.arch}}-w64-mingw32-clang
CXX: ${{matrix.config.arch}}-w64-mingw32-clang++
extras: ${{matrix.config.extras}}
- uses: actions/upload-artifact@v4
with:
name: irrlicht-${{matrix.config.variant}}${{matrix.config.extras}}
path: ./irrlicht-${{matrix.config.variant}}${{matrix.config.extras}}.zip
macos:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install deps
run: |
brew update --auto-update
brew install cmake libpng jpeg
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
- name: Build
run: |
cmake . -DCMAKE_FIND_FRAMEWORK=LAST -DBUILD_EXAMPLES=1
make -j3
- name: Test (headless)
run: |
./bin/OSX/AutomatedTest null
macos-sdl:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install deps
run: |
brew update --auto-update
brew install cmake libpng jpeg sdl2
env:
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1
HOMEBREW_NO_INSTALL_CLEANUP: 1
- name: Build
run: |
cmake . -DCMAKE_FIND_FRAMEWORK=LAST -DBUILD_EXAMPLES=1 -DUSE_SDL2=1
make -j3
msvc:
name: VS 2019 ${{ matrix.config.arch }} ${{ matrix.sdl.label }}
runs-on: windows-2019
env:
VCPKG_VERSION: 8eb57355a4ffb410a2e94c07b4dca2dffbee8e50
# 2023.10.19
vcpkg_packages: zlib libpng libjpeg-turbo
strategy:
fail-fast: false
matrix:
config:
-
arch: x86
generator: "-G'Visual Studio 16 2019' -A Win32"
vcpkg_triplet: x86-windows
-
arch: x64
generator: "-G'Visual Studio 16 2019' -A x64"
vcpkg_triplet: x64-windows
sdl:
-
use: FALSE
label: '(no SDL)'
vcpkg_packages: opengl-registry
-
use: TRUE
label: '(with SDL)'
vcpkg_packages: sdl2
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Restore from cache and run vcpkg
uses: lukka/run-vcpkg@v7
with:
vcpkgArguments: ${{env.vcpkg_packages}} ${{matrix.sdl.vcpkg_packages}}
vcpkgDirectory: '${{ github.workspace }}\vcpkg'
appendedCacheKey: ${{ matrix.config.vcpkg_triplet }}
vcpkgGitCommitId: ${{ env.VCPKG_VERSION }}
vcpkgTriplet: ${{ matrix.config.vcpkg_triplet }}
- name: CMake
run: |
cmake ${{matrix.config.generator}} `
-DUSE_SDL2=${{matrix.sdl.use}} `
-DCMAKE_TOOLCHAIN_FILE="${{ github.workspace }}\vcpkg\scripts\buildsystems\vcpkg.cmake" `
-DCMAKE_BUILD_TYPE=Release .
- name: Build
run: cmake --build . --config Release
- name: Create artifact folder
run: |
mkdir artifact/
mkdir artifact/lib/
- name: Move dlls into artifact folder
run: move bin\Win32-VisualStudio\Release\* artifact\lib\
- name: Move includes into artifact folder
run: move include artifact/
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: msvc-${{ matrix.config.arch }}-${{matrix.sdl.use}}
path: artifact/
android:
name: Android ${{ matrix.arch }}
runs-on: ubuntu-20.04
env:
ndk_version: "r25c"
ANDROID_NDK: ${{ github.workspace }}/android-ndk
strategy:
matrix:
arch: [armeabi-v7a, arm64-v8a, x86, x86_64]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install deps
run: |
sudo rm /var/lib/man-db/auto-update
sudo apt-get update
sudo apt-get install -qyy wget unzip zip gcc-multilib make cmake
- name: Cache NDK
id: cache-ndk
uses: actions/cache@v4
with:
key: android-ndk-${{ env.ndk_version }}-linux
path: ${{ env.ANDROID_NDK }}
- name: Install NDK
run: |
wget --progress=bar:force "http://dl.google.com/android/repository/android-ndk-${ndk_version}-linux.zip"
unzip -q "android-ndk-${ndk_version}-linux.zip"
rm "android-ndk-${ndk_version}-linux.zip"
mv "android-ndk-${ndk_version}" "${ANDROID_NDK}"
if: ${{ steps.cache-ndk.outputs.cache-hit != 'true' }}
- name: Build
run: ./scripts/ci-build-android.sh ${{ matrix.arch }}
#- name: Upload Artifact
# uses: actions/upload-artifact@v4
# with:
# name: irrlicht-android-${{ matrix.arch }}
# path: ${{ runner.temp }}/pkg/${{ matrix.arch }}

25
irr/.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
CMakeFiles
CMakeCache.txt
cmake_install.cmake
install_manifest.txt
IrrlichtMtConfig.cmake
IrrlichtMtConfigVersion.cmake
IrrlichtMtTargets.cmake
CTestTestfile.cmake
Makefile
libs/*
*.so*
*.a
*.exe
*.dll
bin/Linux
scripts/gl2ext.h
scripts/glcorearb.h
scripts/glext.h
*.vcxproj*
*.dir/
*.sln
*visualstudio/
# vscode cmake plugin
build/*

82
irr/CMakeLists.txt Normal file
View File

@ -0,0 +1,82 @@
cmake_minimum_required(VERSION 3.12)
set(IRRLICHTMT_REVISION 15)
project(Irrlicht
VERSION 1.9.0.${IRRLICHTMT_REVISION}
LANGUAGES CXX
)
message(STATUS "*** Building IrrlichtMt ${PROJECT_VERSION} ***")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(GNUInstallDirs)
if(ANDROID)
set(sysname Android)
elseif(APPLE)
set(sysname OSX)
elseif(MSVC)
set(sysname Win32-VisualStudio)
elseif(WIN32)
set(sysname Win32-gcc)
else()
set(sysname Linux)
endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib/${sysname})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin/${sysname})
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type: Debug or Release" FORCE)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
enable_testing()
add_subdirectory(src)
add_subdirectory(test)
option(BUILD_EXAMPLES "Build example applications" FALSE)
if(BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
# Export a file that describes the targets that IrrlichtMt creates.
# The file is placed in the location FILE points to, where CMake can easily
# locate it by pointing CMAKE_PREFIX_PATH to this project root.
export(EXPORT IrrlichtMt-export
FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/IrrlichtMtTargets.cmake"
NAMESPACE IrrlichtMt::
)
# Installation of headers.
install(DIRECTORY "${PROJECT_SOURCE_DIR}/include/"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/irrlichtmt"
)
# Installation of CMake target and configuration files.
install(EXPORT IrrlichtMt-export
FILE IrrlichtMtTargets.cmake
NAMESPACE IrrlichtMt::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/IrrlichtMt"
)
include(CMakePackageConfigHelpers)
configure_package_config_file("${PROJECT_SOURCE_DIR}/Config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/IrrlichtMtConfig.cmake"
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/IrrlichtMt"
NO_SET_AND_CHECK_MACRO
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/cmake/IrrlichtMtConfigVersion.cmake"
COMPATIBILITY AnyNewerVersion
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/cmake/IrrlichtMtConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/cmake/IrrlichtMtConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/IrrlichtMt"
)

11
irr/Config.cmake.in Normal file
View File

@ -0,0 +1,11 @@
@PACKAGE_INIT@
include(CMakeFindDependencyMacro)
if(NOT TARGET IrrlichtMt::IrrlichtMt)
# private dependency only explicitly needed with static libs
if(@USE_SDL2@ AND NOT @BUILD_SHARED_LIBS@)
find_dependency(SDL2)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/IrrlichtMtTargets.cmake")
endif()

26
irr/LICENSE Normal file
View File

@ -0,0 +1,26 @@
Copyright (C) 2002-2012 Nikolaus Gebhardt
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Please note that the Irrlicht Engine is based in part on the work of the
Independent JPEG Group, the zlib, libPng and aesGladman. This means that if you use
the Irrlicht Engine in your product, you must acknowledge somewhere in your
documentation that you've used the IJPG code. It would also be nice to mention
that you use the Irrlicht Engine, the zlib, libPng and aesGladman. See the
corresponding license files for further informations. It is also possible to disable
usage of those additional libraries by defines in the IrrCompileConfig.h header and
recompiling the engine.

88
irr/README.md Normal file
View File

@ -0,0 +1,88 @@
IrrlichtMt version 1.9
======================
IrrlichtMt is the 3D engine of [Minetest](https://github.com/minetest).
It is based on the [Irrlicht Engine](https://irrlicht.sourceforge.io/) but is now developed independently.
It is intentionally not compatible to upstream and is planned to be eventually absorbed into Minetest.
Build
-----
The build system is CMake.
The following libraries are required to be installed:
* zlib, libPNG, libJPEG
* OpenGL
* or on mobile: OpenGL ES (can be optionally enabled on desktop too)
* on Unix: X11
* SDL2 (see below)
Aside from standard search options (`ZLIB_INCLUDE_DIR`, `ZLIB_LIBRARY`, ...) the following options are available:
* `BUILD_SHARED_LIBS` (default: `ON`) - Build IrrlichtMt as a shared library
* `BUILD_EXAMPLES` (default: `OFF`) - Build example applications
* `ENABLE_OPENGL` - Enable OpenGL driver
* `ENABLE_OPENGL3` (default: `OFF`) - Enable OpenGL 3+ driver
* `ENABLE_GLES1` - Enable OpenGL ES driver, legacy
* `ENABLE_GLES2` - Enable OpenGL ES 2+ driver
* `USE_SDL2` (default: platform-dependent, usually `ON`) - Use SDL2 instead of older native device code
e.g. on a Linux system you might want to build for local use like this:
git clone https://github.com/minetest/irrlicht
cd irrlicht
cmake . -DBUILD_SHARED_LIBS=OFF
make -j$(nproc)
This will put an IrrlichtMtTargets.cmake file into the cmake directory in the current build directory, and it can then be imported from another project by pointing `find_package()` to the build directory, or by setting the `CMAKE_PREFIX_PATH` variable to that same path.
on Windows system:
It is highly recommended to use vcpkg as package manager.
After you successfully built vcpkg you can easily install the required libraries:
vcpkg install zlib libjpeg-turbo libpng sdl2 --triplet x64-windows
Run the following script in PowerShell:
git clone https://github.com/minetest/irrlicht
cd irrlicht
cmake -B build -G "Visual Studio 17 2022" -A "Win64" -DCMAKE_TOOLCHAIN_FILE=[vcpkg-root]/scripts/buildsystems/vcpkg.cmake -DBUILD_SHARED_LIBS=OFF
cmake --build build --config Release
Platforms
---------
We aim to support these platforms:
* Windows via MinGW
* Linux (GL or GLES)
* macOS
* Android
This doesn't mean other platforms don't work or won't be supported, if you find something that doesn't work contributions are welcome.
License
-------
The license of the Irrlicht Engine is based on the zlib/libpng license and applies to this fork, too.
The Irrlicht Engine License
===========================
Copyright (C) 2002-2012 Nikolaus Gebhardt
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgement in the product documentation would be
appreciated but is not required.
2. Altered source versions must be clearly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

View File

@ -0,0 +1,38 @@
#-------------------------------------------------------------------
# The contents of this file are placed in the public domain. Feel
# free to make use of it in any way you like.
#-------------------------------------------------------------------
# Try to find OpenGL ES 2 and EGL
if(WIN32)
find_path(OPENGLES2_INCLUDE_DIR GLES2/gl2.h)
find_library(OPENGLES2_LIBRARY libGLESv2)
elseif(APPLE)
find_library(OPENGLES2_LIBRARY OpenGLES REQUIRED) # framework
else()
# Unix
find_path(OPENGLES2_INCLUDE_DIR GLES2/gl2.h
PATHS /usr/X11R6/include /usr/include
)
find_library(OPENGLES2_LIBRARY
NAMES GLESv2
PATHS /usr/X11R6/lib /usr/lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OpenGLES2 DEFAULT_MSG OPENGLES2_LIBRARY OPENGLES2_INCLUDE_DIR)
find_path(EGL_INCLUDE_DIR EGL/egl.h
PATHS /usr/X11R6/include /usr/include
)
find_library(EGL_LIBRARY
NAMES EGL
PATHS /usr/X11R6/lib /usr/lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(EGL REQUIRED_VARS EGL_LIBRARY EGL_INCLUDE_DIR NAME_MISMATCHED)
endif()
set(OPENGLES2_LIBRARIES ${OPENGLES2_LIBRARY} ${EGL_LIBRARY})

View File

@ -0,0 +1,154 @@
#include <iostream>
#include <irrlicht.h>
#include "exampleHelper.h"
using namespace irr;
static IrrlichtDevice *device = nullptr;
static int test_fail = 0;
void test_irr_array();
void test_irr_string();
static video::E_DRIVER_TYPE chooseDriver(core::stringc arg_)
{
if (arg_ == "null")
return video::EDT_NULL;
if (arg_ == "ogles1")
return video::EDT_OGLES1;
if (arg_ == "ogles2")
return video::EDT_OGLES2;
if (arg_ == "opengl")
return video::EDT_OPENGL;
if (arg_ == "opengl3")
return video::EDT_OPENGL3;
std::cerr << "Unknown driver type: " << arg_.c_str() << ". Trying OpenGL." << std::endl;
return video::EDT_OPENGL;
}
static inline void check(bool ok, const char *msg)
{
if (!ok) {
test_fail++;
device->getLogger()->log((core::stringc("FAILED TEST: ") + msg).c_str(), ELL_ERROR);
}
}
void run_unit_tests()
{
std::cout << "Running unit tests:" << std::endl;
try {
test_irr_array();
test_irr_string();
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
test_fail++;
}
std::cout << std::endl;
}
int main(int argc, char *argv[])
{
run_unit_tests();
SIrrlichtCreationParameters p;
p.DriverType = chooseDriver(argc > 1 ? argv[1] : "");
p.WindowSize = core::dimension2du(640, 480);
p.Vsync = true;
p.LoggingLevel = ELL_DEBUG;
device = createDeviceEx(p);
if (!device)
return 1;
{
u32 total = 0;
device->getOSOperator()->getSystemMemory(&total, nullptr);
core::stringc message = core::stringc("Total RAM in MiB: ") + core::stringc(total >> 10);
device->getLogger()->log(message.c_str(), ELL_INFORMATION);
check(total > 130 * 1024, "RAM amount");
}
device->setWindowCaption(L"Hello World!");
device->setResizable(true);
video::IVideoDriver *driver = device->getVideoDriver();
scene::ISceneManager *smgr = device->getSceneManager();
gui::IGUIEnvironment *guienv = device->getGUIEnvironment();
guienv->addStaticText(L"sample text", core::rect<s32>(10, 10, 110, 22), false);
gui::IGUIButton *button = guienv->addButton(
core::rect<s32>(10, 30, 110, 30 + 32), 0, -1, L"sample button",
L"sample tooltip");
gui::IGUIEditBox *editbox = guienv->addEditBox(L"",
core::rect<s32>(10, 70, 60, 70 + 16));
const io::path mediaPath = getExampleMediaPath();
auto mesh_file = device->getFileSystem()->createAndOpenFile(mediaPath + "coolguy_opt.x");
check(mesh_file, "mesh file loading");
scene::IAnimatedMesh *mesh = smgr->getMesh(mesh_file);
check(mesh, "mesh loading");
if (mesh_file)
mesh_file->drop();
if (mesh) {
video::ITexture *tex = driver->getTexture(mediaPath + "cooltexture.png");
check(tex, "texture loading");
scene::IAnimatedMeshSceneNode *node = smgr->addAnimatedMeshSceneNode(mesh);
if (node) {
node->forEachMaterial([tex](video::SMaterial &mat) {
mat.Lighting = false;
mat.setTexture(0, tex);
});
node->setFrameLoop(0, 29);
node->setAnimationSpeed(30);
}
}
smgr->addCameraSceneNode(0, core::vector3df(0, 4, 5), core::vector3df(0, 2, 0));
s32 n = 0;
SEvent event;
device->getTimer()->start();
while (device->run()) {
if (device->getTimer()->getTime() >= 1000) {
device->getTimer()->setTime(0);
++n;
if (n == 1) { // Tooltip display
bzero(&event, sizeof(SEvent));
event.EventType = irr::EET_MOUSE_INPUT_EVENT;
event.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
event.MouseInput.X = button->getAbsolutePosition().getCenter().X;
event.MouseInput.Y = button->getAbsolutePosition().getCenter().Y;
device->postEventFromUser(event);
} else if (n == 2) // Text input focus
guienv->setFocus(editbox);
else if (n == 3) { // Keypress for Text input
bzero(&event, sizeof(SEvent));
event.EventType = irr::EET_KEY_INPUT_EVENT;
event.KeyInput.Char = L'a';
event.KeyInput.Key = KEY_KEY_A;
event.KeyInput.PressedDown = true;
device->postEventFromUser(event);
event.KeyInput.PressedDown = false;
device->postEventFromUser(event);
} else
device->closeDevice();
}
driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH,
video::SColor(255, 100, 100, 150));
smgr->drawAll();
guienv->drawAll();
driver->endScene();
}
check(core::stringw(L"a") == editbox->getText(), "EditBox text");
device->getLogger()->log("Done.", ELL_INFORMATION);
device->drop();
return test_fail > 0 ? 1 : 0;
}

View File

@ -0,0 +1,138 @@
#include <irrArray.h>
#include "test_helper.h"
using namespace irr;
using core::array;
static void test_basics()
{
array<int> v;
v.push_back(1); // 1
v.push_front(2); // 2, 1
v.insert(4, 0); // 4, 2, 1
v.insert(3, 1); // 4, 3, 2, 1
v.insert(0, 4); // 4, 3, 2, 1, 0
UASSERTEQ(v.size(), 5);
UASSERTEQ(v[0], 4);
UASSERTEQ(v[1], 3);
UASSERTEQ(v[2], 2);
UASSERTEQ(v[3], 1);
UASSERTEQ(v[4], 0);
array<int> w = v;
UASSERTEQ(w.size(), 5);
UASSERT(w == v);
w.clear();
UASSERTEQ(w.size(), 0);
UASSERTEQ(w.allocated_size(), 0);
UASSERT(w.empty());
w = v;
UASSERTEQ(w.size(), 5);
w.set_used(3);
UASSERTEQ(w.size(), 3);
UASSERTEQ(w[0], 4);
UASSERTEQ(w[1], 3);
UASSERTEQ(w[2], 2);
UASSERTEQ(w.getLast(), 2);
w.set_used(20);
UASSERTEQ(w.size(), 20);
w = v;
w.sort();
UASSERTEQ(w.size(), 5);
UASSERTEQ(w[0], 0);
UASSERTEQ(w[1], 1);
UASSERTEQ(w[2], 2);
UASSERTEQ(w[3], 3);
UASSERTEQ(w[4], 4);
w.erase(0);
UASSERTEQ(w.size(), 4);
UASSERTEQ(w[0], 1);
UASSERTEQ(w[1], 2);
UASSERTEQ(w[2], 3);
UASSERTEQ(w[3], 4);
w.erase(1, 2);
UASSERTEQ(w.size(), 2);
UASSERTEQ(w[0], 1);
UASSERTEQ(w[1], 4);
w.swap(v);
UASSERTEQ(w.size(), 5);
UASSERTEQ(v.size(), 2);
}
static void test_linear_searches()
{
// Populate the array with 0, 1, 2, ..., 100, 100, 99, 98, 97, ..., 0
array<int> arr;
for (int i = 0; i <= 100; i++)
arr.push_back(i);
for (int i = 100; i >= 0; i--)
arr.push_back(i);
s32 end = arr.size() - 1;
for (int i = 0; i <= 100; i++) {
s32 index = arr.linear_reverse_search(i);
UASSERTEQ(index, end - i);
}
for (int i = 0; i <= 100; i++) {
s32 index = arr.linear_search(i);
UASSERTEQ(index, i);
}
}
static void test_binary_searches()
{
const auto &values = {3, 5, 1, 2, 5, 10, 19, 9, 7, 1, 2, 5, 8, 15};
array<int> arr;
for (int value : values) {
arr.push_back(value);
}
// Test the const form first, it uses a linear search without sorting
const array<int> &carr = arr;
UASSERTEQ(carr.binary_search(20), -1);
UASSERTEQ(carr.binary_search(0), -1);
UASSERTEQ(carr.binary_search(1), 2);
// Sorted: 1, 1, 2, 2, 3, 5, 5, 5, 7, 8, 9, 10, 15, 19
UASSERTEQ(arr.binary_search(20), -1);
UASSERTEQ(arr.binary_search(0), -1);
for (int value : values) {
s32 i = arr.binary_search(value);
UASSERTNE(i, -1);
UASSERTEQ(arr[i], value);
}
s32 first, last;
first = arr.binary_search_multi(1, last);
UASSERTEQ(first, 0);
UASSERTEQ(last, 1);
first = arr.binary_search_multi(2, last);
UASSERTEQ(first, 2);
UASSERTEQ(last, 3);
first = arr.binary_search_multi(3, last);
UASSERTEQ(first, 4);
UASSERTEQ(last, 4);
first = arr.binary_search_multi(4, last);
UASSERTEQ(first, -1);
first = arr.binary_search_multi(5, last);
UASSERTEQ(first, 5);
UASSERTEQ(last, 7);
first = arr.binary_search_multi(7, last);
UASSERTEQ(first, 8);
UASSERTEQ(last, 8);
first = arr.binary_search_multi(19, last);
UASSERTEQ(first, 13);
UASSERTEQ(last, 13);
}
void test_irr_array()
{
test_basics();
test_linear_searches();
test_binary_searches();
std::cout << " test_irr_array PASSED" << std::endl;
}

View File

@ -0,0 +1,33 @@
#pragma once
#include <exception>
#include <iostream>
class TestFailedException : public std::exception
{
};
// Asserts the comparison specified by CMP is true, or fails the current unit test
#define UASSERTCMP(CMP, actual, expected) \
do { \
const auto &a = (actual); \
const auto &e = (expected); \
if (!CMP(a, e)) { \
std::cout \
<< "Test assertion failed: " << #actual << " " << #CMP << " " \
<< #expected << std::endl \
<< " at " << __FILE__ << ":" << __LINE__ << std::endl \
<< " actual: " << a << std::endl \
<< " expected: " \
<< e << std::endl; \
throw TestFailedException(); \
} \
} while (0)
#define CMPEQ(a, e) (a == e)
#define CMPTRUE(a, e) (a)
#define CMPNE(a, e) (a != e)
#define UASSERTEQ(actual, expected) UASSERTCMP(CMPEQ, actual, expected)
#define UASSERTNE(actual, nexpected) UASSERTCMP(CMPNE, actual, nexpected)
#define UASSERT(actual) UASSERTCMP(CMPTRUE, actual, true)

View File

@ -0,0 +1,205 @@
#include <irrString.h>
#include <cstring>
#include <clocale>
#include <vector>
#include "test_helper.h"
using namespace irr;
using namespace irr::core;
#define CMPSTR(a, b) (!strcmp(a, b))
#define UASSERTSTR(actual, expected) UASSERTCMP(CMPSTR, actual.c_str(), expected)
static void test_basics()
{
// ctor
stringc s;
UASSERTEQ(s.c_str()[0], '\0');
s = stringc(0.1234567);
UASSERTSTR(s, "0.123457");
s = stringc(0x1p+53);
UASSERTSTR(s, "9007199254740992.000000");
s = stringc(static_cast<int>(-102400));
UASSERTSTR(s, "-102400");
s = stringc(static_cast<unsigned int>(102400));
UASSERTSTR(s, "102400");
s = stringc(static_cast<long>(-1024000));
UASSERTSTR(s, "-1024000");
s = stringc(static_cast<unsigned long>(1024000));
UASSERTSTR(s, "1024000");
s = stringc("YESno", 3);
UASSERTSTR(s, "YES");
s = stringc(L"test", 4);
UASSERTSTR(s, "test");
s = stringc("Hello World!");
UASSERTSTR(s, "Hello World!");
// operator=
s = stringw(L"abcdef");
UASSERTSTR(s, "abcdef");
s = L"abcdef";
UASSERTSTR(s, "abcdef");
s = static_cast<const char *>(nullptr);
UASSERTSTR(s, "");
// operator+
s = s + stringc("foo");
UASSERTSTR(s, "foo");
s = s + L"bar";
UASSERTSTR(s, "foobar");
// the rest
s = "f";
UASSERTEQ(s[0], 'f');
const auto &sref = s;
UASSERTEQ(sref[0], 'f');
UASSERT(sref == "f");
UASSERT(sref == stringc("f"));
s = "a";
UASSERT(sref < stringc("aa"));
UASSERT(sref < stringc("b"));
UASSERT(stringc("Z") < sref);
UASSERT(!(sref < stringc("a")));
UASSERT(sref.lower_ignore_case("AA"));
UASSERT(sref.lower_ignore_case("B"));
UASSERT(!sref.lower_ignore_case("A"));
s = "dog";
UASSERT(sref != "cat");
UASSERT(sref != stringc("cat"));
}
static void test_methods()
{
stringc s;
const auto &sref = s;
s = "irrlicht";
UASSERTEQ(sref.size(), 8);
UASSERT(!sref.empty());
s.clear();
UASSERTEQ(sref.size(), 0);
UASSERT(sref.empty());
UASSERT(sref[0] == 0);
s = "\tAz#`";
s.make_lower();
UASSERTSTR(s, "\taz#`");
s.make_upper();
UASSERTSTR(s, "\tAZ#`");
UASSERT(sref.equals_ignore_case("\taz#`"));
UASSERT(sref.equals_substring_ignore_case("Z#`", 2));
s = "irrlicht";
UASSERT(sref.equalsn(stringc("irr"), 3));
UASSERT(sref.equalsn("irr", 3));
s = "fo";
s.append('o');
UASSERTSTR(s, "foo");
s.append("bar", 1);
UASSERTSTR(s, "foob");
s.append("ar", 999999);
UASSERTSTR(s, "foobar");
s = "nyan";
s.append(stringc("cat"));
UASSERTSTR(s, "nyancat");
s.append(stringc("sam"), 1);
UASSERTSTR(s, "nyancats");
s = "fbar";
s.insert(1, "ooXX", 2);
UASSERTSTR(s, "foobar");
UASSERTEQ(sref.findFirst('o'), 1);
UASSERTEQ(sref.findFirst('X'), -1);
UASSERTEQ(sref.findFirstChar("abff", 2), 3);
UASSERTEQ(sref.findFirstCharNotInList("fobb", 2), 3);
UASSERTEQ(sref.findLast('o'), 2);
UASSERTEQ(sref.findLast('X'), -1);
UASSERTEQ(sref.findLastChar("abrr", 2), 4);
UASSERTEQ(sref.findLastCharNotInList("rabb", 2), 3);
UASSERTEQ(sref.findNext('o', 2), 2);
UASSERTEQ(sref.findLast('o', 1), 1);
s = "ob-oob";
UASSERTEQ(sref.find("ob", 1), 4);
UASSERTEQ(sref.find("ob"), 0);
UASSERTEQ(sref.find("?"), -1);
s = "HOMEOWNER";
stringc s2 = sref.subString(2, 4);
UASSERTSTR(s2, "MEOW");
s2 = sref.subString(2, 4, true);
UASSERTSTR(s2, "meow");
s = "land";
s.replace('l', 's');
UASSERTSTR(s, "sand");
s = ">dog<";
s.replace("dog", "cat");
UASSERTSTR(s, ">cat<");
s.replace("cat", "horse");
UASSERTSTR(s, ">horse<");
s.replace("horse", "gnu");
UASSERTSTR(s, ">gnu<");
s = " h e l p ";
s.remove(' ');
UASSERTSTR(s, "help");
s.remove("el");
UASSERTSTR(s, "hp");
s = "irrlicht";
s.removeChars("it");
UASSERTSTR(s, "rrlch");
s = "\r\nfoo bar ";
s.trim();
UASSERTSTR(s, "foo bar");
s = "foxo";
s.erase(2);
UASSERTSTR(s, "foo");
s = "a";
s.append('\0');
s.append('b');
UASSERTEQ(s.size(), 3);
s.validate();
UASSERTEQ(s.size(), 1);
UASSERTEQ(s.lastChar(), 'a');
std::vector<stringc> res;
s = "a,,b,c";
s.split(res, ",aa", 1, true, false);
UASSERTEQ(res.size(), 3);
UASSERTSTR(res[0], "a");
UASSERTSTR(res[2], "c");
res.clear();
s.split(res, ",", 1, false, true);
UASSERTEQ(res.size(), 7);
UASSERTSTR(res[0], "a");
UASSERTSTR(res[2], "");
for (int i = 0; i < 3; i++)
UASSERTSTR(res[2 * i + 1], ",");
}
static void test_conv()
{
// locale-independent
stringw out;
utf8ToWString(out, "†††");
UASSERTEQ(out.size(), 3);
for (int i = 0; i < 3; i++)
UASSERTEQ(static_cast<u16>(out[i]), 0x2020);
stringc out2;
wStringToUTF8(out2, L"†††");
UASSERTEQ(out2.size(), 9);
for (int i = 0; i < 3; i++) {
UASSERTEQ(static_cast<u8>(out2[3 * i]), 0xe2);
UASSERTEQ(static_cast<u8>(out2[3 * i + 1]), 0x80);
UASSERTEQ(static_cast<u8>(out2[3 * i + 2]), 0xa0);
}
// locale-dependent
if (!setlocale(LC_CTYPE, "C.UTF-8"))
setlocale(LC_CTYPE, "UTF-8"); // macOS
stringw out3;
multibyteToWString(out3, "†††");
UASSERTEQ(out3.size(), 3);
for (int i = 0; i < 3; i++)
UASSERTEQ(static_cast<u16>(out3[i]), 0x2020);
}
void test_irr_string()
{
test_basics();
test_methods();
test_conv();
std::cout << " test_irr_string PASSED" << std::endl;
}

View File

@ -0,0 +1,17 @@
set(IRREXAMPLES
# removed
)
if(UNIX)
list(APPEND IRREXAMPLES AutomatedTest)
endif()
foreach(exname IN ITEMS ${IRREXAMPLES})
file(GLOB sources "${CMAKE_CURRENT_SOURCE_DIR}/${exname}/*.cpp")
add_executable(${exname} ${sources})
target_include_directories(${exname} PRIVATE
${CMAKE_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/${exname}
)
target_link_libraries(${exname} IrrlichtMt)
endforeach()

274
irr/include/CMeshBuffer.h Normal file
View File

@ -0,0 +1,274 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "irrArray.h"
#include "IMeshBuffer.h"
namespace irr
{
namespace scene
{
//! Template implementation of the IMeshBuffer interface
template <class T>
class CMeshBuffer : public IMeshBuffer
{
public:
//! Default constructor for empty meshbuffer
CMeshBuffer() :
ChangedID_Vertex(1), ChangedID_Index(1), MappingHint_Vertex(EHM_NEVER), MappingHint_Index(EHM_NEVER), HWBuffer(NULL), PrimitiveType(EPT_TRIANGLES)
{
#ifdef _DEBUG
setDebugName("CMeshBuffer");
#endif
}
//! Get material of this meshbuffer
/** \return Material of this buffer */
const video::SMaterial &getMaterial() const override
{
return Material;
}
//! Get material of this meshbuffer
/** \return Material of this buffer */
video::SMaterial &getMaterial() override
{
return Material;
}
//! Get pointer to vertices
/** \return Pointer to vertices. */
const void *getVertices() const override
{
return Vertices.const_pointer();
}
//! Get pointer to vertices
/** \return Pointer to vertices. */
void *getVertices() override
{
return Vertices.pointer();
}
//! Get number of vertices
/** \return Number of vertices. */
u32 getVertexCount() const override
{
return Vertices.size();
}
//! Get type of index data which is stored in this meshbuffer.
/** \return Index type of this buffer. */
video::E_INDEX_TYPE getIndexType() const override
{
return video::EIT_16BIT;
}
//! Get pointer to indices
/** \return Pointer to indices. */
const u16 *getIndices() const override
{
return Indices.const_pointer();
}
//! Get pointer to indices
/** \return Pointer to indices. */
u16 *getIndices() override
{
return Indices.pointer();
}
//! Get number of indices
/** \return Number of indices. */
u32 getIndexCount() const override
{
return Indices.size();
}
//! Get the axis aligned bounding box
/** \return Axis aligned bounding box of this buffer. */
const core::aabbox3d<f32> &getBoundingBox() const override
{
return BoundingBox;
}
//! Set the axis aligned bounding box
/** \param box New axis aligned bounding box for this buffer. */
//! set user axis aligned bounding box
void setBoundingBox(const core::aabbox3df &box) override
{
BoundingBox = box;
}
//! Recalculate the bounding box.
/** should be called if the mesh changed. */
void recalculateBoundingBox() override
{
if (!Vertices.empty()) {
BoundingBox.reset(Vertices[0].Pos);
const irr::u32 vsize = Vertices.size();
for (u32 i = 1; i < vsize; ++i)
BoundingBox.addInternalPoint(Vertices[i].Pos);
} else
BoundingBox.reset(0, 0, 0);
}
//! Get type of vertex data stored in this buffer.
/** \return Type of vertex data. */
video::E_VERTEX_TYPE getVertexType() const override
{
return T::getType();
}
//! returns position of vertex i
const core::vector3df &getPosition(u32 i) const override
{
return Vertices[i].Pos;
}
//! returns position of vertex i
core::vector3df &getPosition(u32 i) override
{
return Vertices[i].Pos;
}
//! returns normal of vertex i
const core::vector3df &getNormal(u32 i) const override
{
return Vertices[i].Normal;
}
//! returns normal of vertex i
core::vector3df &getNormal(u32 i) override
{
return Vertices[i].Normal;
}
//! returns texture coord of vertex i
const core::vector2df &getTCoords(u32 i) const override
{
return Vertices[i].TCoords;
}
//! returns texture coord of vertex i
core::vector2df &getTCoords(u32 i) override
{
return Vertices[i].TCoords;
}
//! Append the vertices and indices to the current buffer
/** Only works for compatible types, i.e. either the same type
or the main buffer is of standard type. Otherwise, behavior is
undefined.
*/
void append(const void *const vertices, u32 numVertices, const u16 *const indices, u32 numIndices) override
{
if (vertices == getVertices())
return;
const u32 vertexCount = getVertexCount();
u32 i;
Vertices.reallocate(vertexCount + numVertices);
for (i = 0; i < numVertices; ++i) {
Vertices.push_back(static_cast<const T *>(vertices)[i]);
BoundingBox.addInternalPoint(static_cast<const T *>(vertices)[i].Pos);
}
Indices.reallocate(getIndexCount() + numIndices);
for (i = 0; i < numIndices; ++i) {
Indices.push_back(indices[i] + vertexCount);
}
}
//! get the current hardware mapping hint
E_HARDWARE_MAPPING getHardwareMappingHint_Vertex() const override
{
return MappingHint_Vertex;
}
//! get the current hardware mapping hint
E_HARDWARE_MAPPING getHardwareMappingHint_Index() const override
{
return MappingHint_Index;
}
//! set the hardware mapping hint, for driver
void setHardwareMappingHint(E_HARDWARE_MAPPING NewMappingHint, E_BUFFER_TYPE Buffer = EBT_VERTEX_AND_INDEX) override
{
if (Buffer == EBT_VERTEX_AND_INDEX || Buffer == EBT_VERTEX)
MappingHint_Vertex = NewMappingHint;
if (Buffer == EBT_VERTEX_AND_INDEX || Buffer == EBT_INDEX)
MappingHint_Index = NewMappingHint;
}
//! Describe what kind of primitive geometry is used by the meshbuffer
void setPrimitiveType(E_PRIMITIVE_TYPE type) override
{
PrimitiveType = type;
}
//! Get the kind of primitive geometry which is used by the meshbuffer
E_PRIMITIVE_TYPE getPrimitiveType() const override
{
return PrimitiveType;
}
//! flags the mesh as changed, reloads hardware buffers
void setDirty(E_BUFFER_TYPE Buffer = EBT_VERTEX_AND_INDEX) override
{
if (Buffer == EBT_VERTEX_AND_INDEX || Buffer == EBT_VERTEX)
++ChangedID_Vertex;
if (Buffer == EBT_VERTEX_AND_INDEX || Buffer == EBT_INDEX)
++ChangedID_Index;
}
//! Get the currently used ID for identification of changes.
/** This shouldn't be used for anything outside the VideoDriver. */
u32 getChangedID_Vertex() const override { return ChangedID_Vertex; }
//! Get the currently used ID for identification of changes.
/** This shouldn't be used for anything outside the VideoDriver. */
u32 getChangedID_Index() const override { return ChangedID_Index; }
void setHWBuffer(void *ptr) const override
{
HWBuffer = ptr;
}
void *getHWBuffer() const override
{
return HWBuffer;
}
u32 ChangedID_Vertex;
u32 ChangedID_Index;
//! hardware mapping hint
E_HARDWARE_MAPPING MappingHint_Vertex;
E_HARDWARE_MAPPING MappingHint_Index;
mutable void *HWBuffer;
//! Material for this meshbuffer.
video::SMaterial Material;
//! Vertices of this buffer
core::array<T> Vertices;
//! Indices into the vertices of this buffer.
core::array<u16> Indices;
//! Bounding box of this meshbuffer.
core::aabbox3d<f32> BoundingBox;
//! Primitive type used for rendering (triangles, lines, ...)
E_PRIMITIVE_TYPE PrimitiveType;
};
//! Standard meshbuffer
typedef CMeshBuffer<video::S3DVertex> SMeshBuffer;
//! Meshbuffer with two texture coords per vertex, e.g. for lightmaps
typedef CMeshBuffer<video::S3DVertex2TCoords> SMeshBufferLightMap;
//! Meshbuffer with vertices having tangents stored, e.g. for normal mapping
typedef CMeshBuffer<video::S3DVertexTangents> SMeshBufferTangents;
} // end namespace scene
} // end namespace irr

32
irr/include/EAttributes.h Normal file
View File

@ -0,0 +1,32 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
namespace irr
{
namespace io
{
//! Types of attributes available for IAttributes
enum E_ATTRIBUTE_TYPE
{
// integer attribute
EAT_INT = 0,
// float attribute
EAT_FLOAT,
// boolean attribute
EAT_BOOL,
// known attribute type count
EAT_COUNT,
// unknown attribute
EAT_UNKNOWN
};
} // end namespace io
} // end namespace irr

View File

@ -0,0 +1,35 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "irrTypes.h"
namespace irr
{
namespace scene
{
//! An enumeration for all types of automatic culling for built-in scene nodes
enum E_CULLING_TYPE
{
EAC_OFF = 0,
EAC_BOX = 1,
EAC_FRUSTUM_BOX = 2,
EAC_FRUSTUM_SPHERE = 4,
EAC_OCC_QUERY = 8
};
//! Names for culling type
const c8 *const AutomaticCullingNames[] = {
"false",
"box", // camera box against node box
"frustum_box", // camera frustum against node box
"frustum_sphere", // camera frustum against node sphere
"occ_query", // occlusion query
0,
};
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,41 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
namespace irr
{
namespace scene
{
//! An enumeration for all types of debug data for built-in scene nodes (flags)
enum E_DEBUG_SCENE_TYPE
{
//! No Debug Data ( Default )
EDS_OFF = 0,
//! Show Bounding Boxes of SceneNode
EDS_BBOX = 1,
//! Show Vertex Normals
EDS_NORMALS = 2,
//! Shows Skeleton/Tags
EDS_SKELETON = 4,
//! Overlays Mesh Wireframe
EDS_MESH_WIRE_OVERLAY = 8,
//! Show Bounding Boxes of all MeshBuffers
EDS_BBOX_BUFFERS = 32,
//! EDS_BBOX | EDS_BBOX_BUFFERS
EDS_BBOX_ALL = EDS_BBOX | EDS_BBOX_BUFFERS,
//! Show all debug infos
EDS_FULL = 0xffffffff
};
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,46 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
namespace irr
{
//! An enum for the different device types supported by the Irrlicht Engine.
enum E_DEVICE_TYPE
{
//! A device native to Microsoft Windows
/** This device uses the Win32 API and works in all versions of Windows. */
EIDT_WIN32,
//! A device native to Unix style operating systems.
/** This device uses the X11 windowing system and works in Linux, Solaris, FreeBSD, OSX and
other operating systems which support X11. */
EIDT_X11,
//! A device native to Mac OSX
/** This device uses Apple's Cocoa API and works in Mac OSX 10.2 and above. */
EIDT_OSX,
//! A device which uses Simple DirectMedia Layer
/** The SDL device works under all platforms supported by SDL but first must be compiled
in by setting the USE_SDL2 CMake option to ON */
EIDT_SDL,
//! This selection allows Irrlicht to choose the best device from the ones available.
/** If this selection is chosen then Irrlicht will try to use the IrrlichtDevice native
to your operating system. If this is unavailable then the X11, SDL and then console device
will be tried. This ensures that Irrlicht will run even if your platform is unsupported,
although it may not be able to render anything. */
EIDT_BEST,
//! A device for Android platforms
/** Best used with embedded devices and mobile systems.
Does not need X11 or other graphical subsystems.
May support hw-acceleration via OpenGL-ES */
EIDT_ANDROID,
};
} // end namespace irr

View File

@ -0,0 +1,137 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
namespace irr
{
namespace video
{
//! enumeration for querying features of the video driver.
enum E_VIDEO_DRIVER_FEATURE
{
//! Is driver able to render to a surface?
EVDF_RENDER_TO_TARGET = 0,
//! Is hardware transform and lighting supported?
EVDF_HARDWARE_TL,
//! Are multiple textures per material possible?
EVDF_MULTITEXTURE,
//! Is driver able to render with a bilinear filter applied?
EVDF_BILINEAR_FILTER,
//! Can the driver handle mip maps?
EVDF_MIP_MAP,
//! Can the driver update mip maps automatically?
EVDF_MIP_MAP_AUTO_UPDATE,
//! Are stencilbuffers switched on and does the device support stencil buffers?
EVDF_STENCIL_BUFFER,
//! Is Vertex Shader 1.1 supported?
EVDF_VERTEX_SHADER_1_1,
//! Is Vertex Shader 2.0 supported?
EVDF_VERTEX_SHADER_2_0,
//! Is Vertex Shader 3.0 supported?
EVDF_VERTEX_SHADER_3_0,
//! Is Pixel Shader 1.1 supported?
EVDF_PIXEL_SHADER_1_1,
//! Is Pixel Shader 1.2 supported?
EVDF_PIXEL_SHADER_1_2,
//! Is Pixel Shader 1.3 supported?
EVDF_PIXEL_SHADER_1_3,
//! Is Pixel Shader 1.4 supported?
EVDF_PIXEL_SHADER_1_4,
//! Is Pixel Shader 2.0 supported?
EVDF_PIXEL_SHADER_2_0,
//! Is Pixel Shader 3.0 supported?
EVDF_PIXEL_SHADER_3_0,
//! Are ARB vertex programs v1.0 supported?
EVDF_ARB_VERTEX_PROGRAM_1,
//! Are ARB fragment programs v1.0 supported?
EVDF_ARB_FRAGMENT_PROGRAM_1,
//! Is GLSL supported?
EVDF_ARB_GLSL,
//! Is HLSL supported?
EVDF_HLSL,
//! Are non-square textures supported?
EVDF_TEXTURE_NSQUARE,
//! Are non-power-of-two textures supported?
EVDF_TEXTURE_NPOT,
//! Are framebuffer objects supported?
EVDF_FRAMEBUFFER_OBJECT,
//! Are vertex buffer objects supported?
EVDF_VERTEX_BUFFER_OBJECT,
//! Supports Alpha To Coverage
EVDF_ALPHA_TO_COVERAGE,
//! Supports Color masks (disabling color planes in output)
EVDF_COLOR_MASK,
//! Supports multiple render targets at once
EVDF_MULTIPLE_RENDER_TARGETS,
//! Supports separate blend settings for multiple render targets
EVDF_MRT_BLEND,
//! Supports separate color masks for multiple render targets
EVDF_MRT_COLOR_MASK,
//! Supports separate blend functions for multiple render targets
EVDF_MRT_BLEND_FUNC,
//! Supports geometry shaders
EVDF_GEOMETRY_SHADER,
//! Supports occlusion queries
EVDF_OCCLUSION_QUERY,
//! Supports polygon offset/depth bias for avoiding z-fighting
EVDF_POLYGON_OFFSET,
//! Support for different blend functions. Without, only ADD is available
EVDF_BLEND_OPERATIONS,
//! Support for separate blending for RGB and Alpha.
EVDF_BLEND_SEPARATE,
//! Support for texture coord transformation via texture matrix
EVDF_TEXTURE_MATRIX,
//! Support for cube map textures.
EVDF_TEXTURE_CUBEMAP,
//! Support for filtering across different faces of the cubemap
EVDF_TEXTURE_CUBEMAP_SEAMLESS,
//! Support for clamping vertices beyond far-plane to depth instead of capping them.
EVDF_DEPTH_CLAMP,
//! Only used for counting the elements of this enum
EVDF_COUNT
};
} // end namespace video
} // end namespace irr

View File

@ -0,0 +1,44 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "irrTypes.h"
namespace irr
{
namespace video
{
//! An enum for all types of drivers the Irrlicht Engine supports.
enum E_DRIVER_TYPE
{
//! Null driver, useful for applications to run the engine without visualization.
/** The null device is able to load textures, but does not
render and display any graphics. */
EDT_NULL,
//! OpenGL device, available on most platforms.
/** Performs hardware accelerated rendering of 3D and 2D
primitives. */
EDT_OPENGL,
//! OpenGL-ES 1.x driver, for embedded and mobile systems
EDT_OGLES1,
//! OpenGL-ES 2.x driver, for embedded and mobile systems
/** Supports shaders etc. */
EDT_OGLES2,
//! WebGL1 friendly subset of OpenGL-ES 2.x driver for Emscripten
EDT_WEBGL1,
EDT_OPENGL3,
//! No driver, just for counting the elements
EDT_COUNT
};
} // end namespace video
} // end namespace irr

34
irr/include/EFocusFlags.h Normal file
View File

@ -0,0 +1,34 @@
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
namespace irr
{
namespace gui
{
//! Bitflags for defining the the focus behavior of the gui
// (all names start with SET as we might add REMOVE flags later to control that behavior as well)
enum EFOCUS_FLAG
{
//! When set the focus changes when the left mouse-button got clicked while over an element
EFF_SET_ON_LMOUSE_DOWN = 0x1,
//! When set the focus changes when the right mouse-button got clicked while over an element
//! Note that elements usually don't care about right-click and that won't change with this flag
//! This is mostly to allow taking away focus from elements with right-mouse additionally.
EFF_SET_ON_RMOUSE_DOWN = 0x2,
//! When set the focus changes when the mouse-cursor is over an element
EFF_SET_ON_MOUSE_OVER = 0x4,
//! When set the focus can be changed with TAB-key combinations.
EFF_SET_ON_TAB = 0x8,
//! When set it's possible to set the focus to disabled elements.
EFF_CAN_FOCUS_DISABLED = 0x16
};
} // namespace gui
} // namespace irr

View File

@ -0,0 +1,35 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "irrTypes.h"
namespace irr
{
namespace gui
{
enum EGUI_ALIGNMENT
{
//! Aligned to parent's top or left side (default)
EGUIA_UPPERLEFT = 0,
//! Aligned to parent's bottom or right side
EGUIA_LOWERRIGHT,
//! Aligned to the center of parent
EGUIA_CENTER,
//! Stretched to fit parent
EGUIA_SCALE
};
//! Names for alignments
const c8 *const GUIAlignmentNames[] = {
"upperLeft",
"lowerRight",
"center",
"scale",
0,
};
} // namespace gui
} // namespace irr

View File

@ -0,0 +1,133 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "irrTypes.h"
namespace irr
{
namespace gui
{
//! List of all basic Irrlicht GUI elements.
/** An IGUIElement returns this when calling IGUIElement::getType(); */
enum EGUI_ELEMENT_TYPE
{
//! A button (IGUIButton)
EGUIET_BUTTON = 0,
//! A check box (IGUICheckBox)
EGUIET_CHECK_BOX,
//! A combo box (IGUIComboBox)
EGUIET_COMBO_BOX,
//! A context menu (IGUIContextMenu)
EGUIET_CONTEXT_MENU,
//! A menu (IGUIMenu)
EGUIET_MENU,
//! An edit box (IGUIEditBox)
EGUIET_EDIT_BOX,
//! A file open dialog (IGUIFileOpenDialog)
EGUIET_FILE_OPEN_DIALOG,
//! A color select open dialog (IGUIColorSelectDialog)
EGUIET_COLOR_SELECT_DIALOG,
//! A in/out fader (IGUIInOutFader)
EGUIET_IN_OUT_FADER,
//! An image (IGUIImage)
EGUIET_IMAGE,
//! A list box (IGUIListBox)
EGUIET_LIST_BOX,
//! A mesh viewer (IGUIMeshViewer)
EGUIET_MESH_VIEWER,
//! A message box (IGUIWindow)
EGUIET_MESSAGE_BOX,
//! A modal screen
EGUIET_MODAL_SCREEN,
//! A scroll bar (IGUIScrollBar)
EGUIET_SCROLL_BAR,
//! A spin box (IGUISpinBox)
EGUIET_SPIN_BOX,
//! A static text (IGUIStaticText)
EGUIET_STATIC_TEXT,
//! A tab (IGUITab)
EGUIET_TAB,
//! A tab control
EGUIET_TAB_CONTROL,
//! A Table
EGUIET_TABLE,
//! A tool bar (IGUIToolBar)
EGUIET_TOOL_BAR,
//! A Tree View
EGUIET_TREE_VIEW,
//! A window
EGUIET_WINDOW,
//! Unknown type.
EGUIET_ELEMENT,
//! The root of the GUI
EGUIET_ROOT,
//! Not an element, amount of elements in there
EGUIET_COUNT,
//! This enum is never used, it only forces the compiler to compile this enumeration to 32 bit.
EGUIET_FORCE_32_BIT = 0x7fffffff
};
//! Names for built-in element types
const c8 *const GUIElementTypeNames[] = {
"button",
"checkBox",
"comboBox",
"contextMenu",
"menu",
"editBox",
"fileOpenDialog",
"colorSelectDialog",
"inOutFader",
"image",
"listBox",
"meshViewer",
"messageBox",
"modalScreen",
"scrollBar",
"spinBox",
"staticText",
"tab",
"tabControl",
"table",
"toolBar",
"treeview",
"window",
"element",
"root",
"profiler",
0,
};
} // end namespace gui
} // end namespace irr

View File

@ -0,0 +1,40 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
namespace irr
{
namespace scene
{
enum E_HARDWARE_MAPPING
{
//! Don't store on the hardware
EHM_NEVER = 0,
//! Rarely changed, usually stored completely on the hardware
EHM_STATIC,
//! Sometimes changed, driver optimized placement
EHM_DYNAMIC,
//! Always changed, cache optimizing on the GPU
EHM_STREAM
};
enum E_BUFFER_TYPE
{
//! Does not change anything
EBT_NONE = 0,
//! Change the vertex mapping
EBT_VERTEX,
//! Change the index mapping
EBT_INDEX,
//! Change both vertex and index mapping to the same value
EBT_VERTEX_AND_INDEX
};
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,82 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
namespace irr
{
namespace video
{
//! Material properties
enum E_MATERIAL_PROP
{
//! Corresponds to SMaterial::Wireframe.
EMP_WIREFRAME = 0x1,
//! Corresponds to SMaterial::PointCloud.
EMP_POINTCLOUD = 0x2,
//! Corresponds to SMaterial::GouraudShading.
EMP_GOURAUD_SHADING = 0x4,
//! Corresponds to SMaterial::Lighting.
EMP_LIGHTING = 0x8,
//! Corresponds to SMaterial::ZBuffer.
EMP_ZBUFFER = 0x10,
//! Corresponds to SMaterial::ZWriteEnable.
EMP_ZWRITE_ENABLE = 0x20,
//! Corresponds to SMaterial::BackfaceCulling.
EMP_BACK_FACE_CULLING = 0x40,
//! Corresponds to SMaterial::FrontfaceCulling.
EMP_FRONT_FACE_CULLING = 0x80,
//! Corresponds to SMaterialLayer::MinFilter.
EMP_MIN_FILTER = 0x100,
//! Corresponds to SMaterialLayer::MagFilter.
EMP_MAG_FILTER = 0x200,
//! Corresponds to SMaterialLayer::AnisotropicFilter.
EMP_ANISOTROPIC_FILTER = 0x400,
//! Corresponds to SMaterial::FogEnable.
EMP_FOG_ENABLE = 0x800,
//! Corresponds to SMaterial::NormalizeNormals.
EMP_NORMALIZE_NORMALS = 0x1000,
//! Corresponds to SMaterialLayer::TextureWrapU, TextureWrapV and
//! TextureWrapW.
EMP_TEXTURE_WRAP = 0x2000,
//! Corresponds to SMaterial::AntiAliasing.
EMP_ANTI_ALIASING = 0x4000,
//! Corresponds to SMaterial::ColorMask.
EMP_COLOR_MASK = 0x8000,
//! Corresponds to SMaterial::ColorMaterial.
EMP_COLOR_MATERIAL = 0x10000,
//! Corresponds to SMaterial::UseMipMaps.
EMP_USE_MIP_MAPS = 0x20000,
//! Corresponds to SMaterial::BlendOperation.
EMP_BLEND_OPERATION = 0x40000,
//! Corresponds to SMaterial::PolygonOffsetFactor, PolygonOffsetDirection,
//! PolygonOffsetDepthBias and PolygonOffsetSlopeScale.
EMP_POLYGON_OFFSET = 0x80000,
//! Corresponds to SMaterial::BlendFactor.
EMP_BLEND_FACTOR = 0x100000,
};
} // end namespace video
} // end namespace irr

View File

@ -0,0 +1,74 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "irrTypes.h"
namespace irr
{
namespace video
{
//! Abstracted and easy to use fixed function/programmable pipeline material modes.
enum E_MATERIAL_TYPE
{
//! Standard solid material.
/** Only first texture is used, which is supposed to be the
diffuse material. */
EMT_SOLID = 0,
//! Makes the material transparent based on the texture alpha channel.
/** The final color is blended together from the destination
color and the texture color, using the alpha channel value as
blend factor. Only first texture is used. If you are using
this material with small textures, it is a good idea to load
the texture in 32 bit mode
(video::IVideoDriver::setTextureCreationFlag()). Also, an alpha
ref is used, which can be manipulated using
SMaterial::MaterialTypeParam. This value controls how sharp the
edges become when going from a transparent to a solid spot on
the texture. */
EMT_TRANSPARENT_ALPHA_CHANNEL,
//! Makes the material transparent based on the texture alpha channel.
/** If the alpha channel value is greater than 127, a
pixel is written to the target, otherwise not. This
material does not use alpha blending and is a lot faster
than EMT_TRANSPARENT_ALPHA_CHANNEL. It is ideal for drawing
stuff like leaves of plants, because the borders are not
blurry but sharp. Only first texture is used. If you are
using this material with small textures and 3d object, it
is a good idea to load the texture in 32 bit mode
(video::IVideoDriver::setTextureCreationFlag()). */
EMT_TRANSPARENT_ALPHA_CHANNEL_REF,
//! Makes the material transparent based on the vertex alpha value.
EMT_TRANSPARENT_VERTEX_ALPHA,
//! BlendFunc = source * sourceFactor + dest * destFactor ( E_BLEND_FUNC )
/** Using only first texture. Generic blending method.
The blend function is set to SMaterial::MaterialTypeParam with
pack_textureBlendFunc (for 2D) or pack_textureBlendFuncSeparate (for 3D). */
EMT_ONETEXTURE_BLEND,
//! This value is not used. It only forces this enumeration to compile to 32 bit.
EMT_FORCE_32BIT = 0x7fffffff
};
//! Array holding the built in material type names
const char *const sBuiltInMaterialTypeNames[] = {
"solid",
"trans_alphach",
"trans_alphach_ref",
"trans_vertex_alpha",
"onetexture_blend",
0,
};
constexpr u32 numBuiltInMaterials =
sizeof(sBuiltInMaterialTypeNames) / sizeof(char *) - 1;
} // end namespace video
} // end namespace irr

View File

@ -0,0 +1,43 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
namespace irr
{
namespace scene
{
//! Enumeration for all primitive types there are.
enum E_PRIMITIVE_TYPE
{
//! All vertices are non-connected points.
EPT_POINTS = 0,
//! All vertices form a single connected line.
EPT_LINE_STRIP,
//! Just as LINE_STRIP, but the last and the first vertex is also connected.
EPT_LINE_LOOP,
//! Every two vertices are connected creating n/2 lines.
EPT_LINES,
//! After the first two vertices each vertex defines a new triangle.
//! Always the two last and the new one form a new triangle.
EPT_TRIANGLE_STRIP,
//! After the first two vertices each vertex defines a new triangle.
//! All around the common first vertex.
EPT_TRIANGLE_FAN,
//! Explicitly set all vertices for each triangle.
EPT_TRIANGLES,
//! The single vertices are expanded to quad billboards on the GPU.
EPT_POINT_SPRITES
};
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,30 @@
// Copyright (C) Michael Zeilfelder
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "irrTypes.h"
namespace irr
{
namespace io
{
//! An enumeration for different class types implementing IReadFile
enum EREAD_FILE_TYPE
{
//! CReadFile
ERFT_READ_FILE = MAKE_IRR_ID('r', 'e', 'a', 'd'),
//! CMemoryReadFile
ERFT_MEMORY_READ_FILE = MAKE_IRR_ID('r', 'm', 'e', 'm'),
//! CLimitReadFile
ERFT_LIMIT_READ_FILE = MAKE_IRR_ID('r', 'l', 'i', 'm'),
//! Unknown type
EFIT_UNKNOWN = MAKE_IRR_ID('u', 'n', 'k', 'n')
};
} // end namespace io
} // end namespace irr

View File

@ -0,0 +1,49 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "irrTypes.h"
namespace irr
{
namespace scene
{
//! An enumeration for all types of built-in scene nodes
/** A scene node type is represented by a four character code
such as 'cube' or 'mesh' instead of simple numbers, to avoid
name clashes with external scene nodes.*/
enum ESCENE_NODE_TYPE
{
//! of type CSceneManager (note that ISceneManager is not(!) an ISceneNode)
ESNT_SCENE_MANAGER = MAKE_IRR_ID('s', 'm', 'n', 'g'),
//! Mesh Scene Node
ESNT_MESH = MAKE_IRR_ID('m', 'e', 's', 'h'),
//! Empty Scene Node
ESNT_EMPTY = MAKE_IRR_ID('e', 'm', 't', 'y'),
//! Dummy Transformation Scene Node
ESNT_DUMMY_TRANSFORMATION = MAKE_IRR_ID('d', 'm', 'm', 'y'),
//! Camera Scene Node
ESNT_CAMERA = MAKE_IRR_ID('c', 'a', 'm', '_'),
//! Billboard Scene Node
ESNT_BILLBOARD = MAKE_IRR_ID('b', 'i', 'l', 'l'),
//! Animated Mesh Scene Node
ESNT_ANIMATED_MESH = MAKE_IRR_ID('a', 'm', 's', 'h'),
//! Unknown scene node
ESNT_UNKNOWN = MAKE_IRR_ID('u', 'n', 'k', 'n'),
//! Will match with any scene node when checking types
ESNT_ANY = MAKE_IRR_ID('a', 'n', 'y', '_')
};
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,85 @@
#pragma once
#include "irrTypes.h"
namespace irr
{
namespace video
{
//! Compile target enumeration for the addHighLevelShaderMaterial() method.
enum E_VERTEX_SHADER_TYPE
{
EVST_VS_1_1 = 0,
EVST_VS_2_0,
EVST_VS_2_a,
EVST_VS_3_0,
EVST_VS_4_0,
EVST_VS_4_1,
EVST_VS_5_0,
//! This is not a type, but a value indicating how much types there are.
EVST_COUNT
};
//! Names for all vertex shader types, each entry corresponds to a E_VERTEX_SHADER_TYPE entry.
const c8 *const VERTEX_SHADER_TYPE_NAMES[] = {
"vs_1_1",
"vs_2_0",
"vs_2_a",
"vs_3_0",
"vs_4_0",
"vs_4_1",
"vs_5_0",
0};
//! Compile target enumeration for the addHighLevelShaderMaterial() method.
enum E_PIXEL_SHADER_TYPE
{
EPST_PS_1_1 = 0,
EPST_PS_1_2,
EPST_PS_1_3,
EPST_PS_1_4,
EPST_PS_2_0,
EPST_PS_2_a,
EPST_PS_2_b,
EPST_PS_3_0,
EPST_PS_4_0,
EPST_PS_4_1,
EPST_PS_5_0,
//! This is not a type, but a value indicating how much types there are.
EPST_COUNT
};
//! Names for all pixel shader types, each entry corresponds to a E_PIXEL_SHADER_TYPE entry.
const c8 *const PIXEL_SHADER_TYPE_NAMES[] = {
"ps_1_1",
"ps_1_2",
"ps_1_3",
"ps_1_4",
"ps_2_0",
"ps_2_a",
"ps_2_b",
"ps_3_0",
"ps_4_0",
"ps_4_1",
"ps_5_0",
0};
//! Enum for supported geometry shader types
enum E_GEOMETRY_SHADER_TYPE
{
EGST_GS_4_0 = 0,
//! This is not a type, but a value indicating how much types there are.
EGST_COUNT
};
//! String names for supported geometry shader types
const c8 *const GEOMETRY_SHADER_TYPE_NAMES[] = {
"gs_4_0",
0};
} // end namespace video
} // end namespace irr

View File

@ -0,0 +1,34 @@
#pragma once
namespace irr
{
namespace video
{
//! Enumeration for all vertex attributes there are.
enum E_VERTEX_ATTRIBUTES
{
EVA_POSITION = 0,
EVA_NORMAL,
EVA_COLOR,
EVA_TCOORD0,
EVA_TCOORD1,
EVA_TANGENT,
EVA_BINORMAL,
EVA_COUNT
};
//! Array holding the built in vertex attribute names
const char *const sBuiltInVertexAttributeNames[] = {
"inVertexPosition",
"inVertexNormal",
"inVertexColor",
"inTexCoord0",
"inTexCoord1",
"inVertexTangent",
"inVertexBinormal",
0,
};
} // end namespace video
} // end namespace irr

View File

@ -0,0 +1,69 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "aabbox3d.h"
#include "IMesh.h"
namespace irr
{
namespace scene
{
//! Interface for an animated mesh.
/** There are already simple implementations of this interface available so
you don't have to implement this interface on your own if you need to:
You might want to use irr::scene::SAnimatedMesh, irr::scene::SMesh,
irr::scene::SMeshBuffer etc. */
class IAnimatedMesh : public IMesh
{
public:
//! Gets the frame count of the animated mesh.
/** Note that the play-time is usually getFrameCount()-1 as it stops as soon as the last frame-key is reached.
\return The amount of frames. If the amount is 1,
it is a static, non animated mesh. */
virtual u32 getFrameCount() const = 0;
//! Gets the animation speed of the animated mesh.
/** \return The number of frames per second to play the
animation with by default. If the amount is 0,
it is a static, non animated mesh. */
virtual f32 getAnimationSpeed() const = 0;
//! Sets the animation speed of the animated mesh.
/** \param fps Number of frames per second to play the
animation with by default. If the amount is 0,
it is not animated. The actual speed is set in the
scene node the mesh is instantiated in.*/
virtual void setAnimationSpeed(f32 fps) = 0;
//! Returns the IMesh interface for a frame.
/** \param frame: Frame number as zero based index. The maximum
frame number is getFrameCount() - 1;
\param detailLevel: Level of detail. 0 is the lowest, 255 the
highest level of detail. Most meshes will ignore the detail level.
\param startFrameLoop: Because some animated meshes (.MD2) are
blended between 2 static frames, and maybe animated in a loop,
the startFrameLoop and the endFrameLoop have to be defined, to
prevent the animation to be blended between frames which are
outside of this loop.
If startFrameLoop and endFrameLoop are both -1, they are ignored.
\param endFrameLoop: see startFrameLoop.
\return Returns the animated mesh based on a detail level. */
virtual IMesh *getMesh(s32 frame, s32 detailLevel = 255, s32 startFrameLoop = -1, s32 endFrameLoop = -1) = 0;
//! Returns the type of the animated mesh.
/** In most cases it is not necessary to use this method.
This is useful for making a safe downcast. For example,
if getMeshType() returns EAMT_MD2 it's safe to cast the
IAnimatedMesh to IAnimatedMeshMD2.
\returns Type of the mesh. */
E_ANIMATED_MESH_TYPE getMeshType() const override
{
return EAMT_UNKNOWN;
}
};
} // end namespace scene
} // end namespace irr

View File

@ -0,0 +1,169 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "ISceneNode.h"
#include "IBoneSceneNode.h"
#include "IAnimatedMesh.h"
namespace irr
{
namespace scene
{
enum E_JOINT_UPDATE_ON_RENDER
{
//! do nothing
EJUOR_NONE = 0,
//! get joints positions from the mesh (for attached nodes, etc)
EJUOR_READ,
//! control joint positions in the mesh (eg. ragdolls, or set the animation from animateJoints() )
EJUOR_CONTROL
};
class IAnimatedMeshSceneNode;
//! Callback interface for catching events of ended animations.
/** Implement this interface and use
IAnimatedMeshSceneNode::setAnimationEndCallback to be able to
be notified if an animation playback has ended.
**/
class IAnimationEndCallBack : public virtual IReferenceCounted
{
public:
//! Will be called when the animation playback has ended.
/** See IAnimatedMeshSceneNode::setAnimationEndCallback for
more information.
\param node: Node of which the animation has ended. */
virtual void OnAnimationEnd(IAnimatedMeshSceneNode *node) = 0;
};
//! Scene node capable of displaying an animated mesh.
class IAnimatedMeshSceneNode : public ISceneNode
{
public:
//! Constructor
IAnimatedMeshSceneNode(ISceneNode *parent, ISceneManager *mgr, s32 id,
const core::vector3df &position = core::vector3df(0, 0, 0),
const core::vector3df &rotation = core::vector3df(0, 0, 0),
const core::vector3df &scale = core::vector3df(1.0f, 1.0f, 1.0f)) :
ISceneNode(parent, mgr, id, position, rotation, scale) {}
//! Destructor
virtual ~IAnimatedMeshSceneNode() {}
//! Sets the current frame number.
/** From now on the animation is played from this frame.
\param frame: Number of the frame to let the animation be started from.
The frame number must be a valid frame number of the IMesh used by this
scene node. Set IAnimatedMesh::getMesh() for details. */
virtual void setCurrentFrame(f32 frame) = 0;
//! Sets the frame numbers between the animation is looped.
/** The default is 0 to getFrameCount()-1 of the mesh.
Number of played frames is end-start.
It interpolates toward the last frame but stops when it is reached.
It does not interpolate back to start even when looping.
Looping animations should ensure last and first frame-key are identical.
\param begin: Start frame number of the loop.
\param end: End frame number of the loop.
\return True if successful, false if not. */
virtual bool setFrameLoop(s32 begin, s32 end) = 0;
//! Sets the speed with which the animation is played.
/** \param framesPerSecond: Frames per second played. */
virtual void setAnimationSpeed(f32 framesPerSecond) = 0;
//! Gets the speed with which the animation is played.
/** \return Frames per second played. */
virtual f32 getAnimationSpeed() const = 0;
//! Get a pointer to a joint in the mesh (if the mesh is a bone based mesh).
/** With this method it is possible to attach scene nodes to
joints for example possible to attach a weapon to the left hand
of an animated model. This example shows how:
\code
ISceneNode* hand =
yourAnimatedMeshSceneNode->getJointNode("LeftHand");
hand->addChild(weaponSceneNode);
\endcode
Please note that the joint returned by this method may not exist
before this call and the joints in the node were created by it.
\param jointName: Name of the joint.
\return Pointer to the scene node which represents the joint
with the specified name. Returns 0 if the contained mesh is not
an skinned mesh or the name of the joint could not be found. */
virtual IBoneSceneNode *getJointNode(const c8 *jointName) = 0;
//! same as getJointNode(const c8* jointName), but based on id
virtual IBoneSceneNode *getJointNode(u32 jointID) = 0;
//! Gets joint count.
/** \return Amount of joints in the mesh. */
virtual u32 getJointCount() const = 0;
//! Returns the currently displayed frame number.
virtual f32 getFrameNr() const = 0;
//! Returns the current start frame number.
virtual s32 getStartFrame() const = 0;
//! Returns the current end frame number.
virtual s32 getEndFrame() const = 0;
//! Sets looping mode which is on by default.
/** If set to false, animations will not be played looped. */
virtual void setLoopMode(bool playAnimationLooped) = 0;
//! returns the current loop mode
/** When true the animations are played looped */
virtual bool getLoopMode() const = 0;
//! Sets a callback interface which will be called if an animation playback has ended.
/** Set this to 0 to disable the callback again.
Please note that this will only be called when in non looped
mode, see IAnimatedMeshSceneNode::setLoopMode(). */
virtual void setAnimationEndCallback(IAnimationEndCallBack *callback = 0) = 0;
//! Sets if the scene node should not copy the materials of the mesh but use them in a read only style.
/** In this way it is possible to change the materials a mesh
causing all mesh scene nodes referencing this mesh to change
too. */
virtual void setReadOnlyMaterials(bool readonly) = 0;
//! Returns if the scene node should not copy the materials of the mesh but use them in a read only style
virtual bool isReadOnlyMaterials() const = 0;
//! Sets a new mesh
virtual void setMesh(IAnimatedMesh *mesh) = 0;
//! Returns the current mesh
virtual IAnimatedMesh *getMesh(void) = 0;
//! Set how the joints should be updated on render
virtual void setJointMode(E_JOINT_UPDATE_ON_RENDER mode) = 0;
//! Sets the transition time in seconds
/** Note: This needs to enable joints, and setJointmode set to
EJUOR_CONTROL. You must call animateJoints(), or the mesh will
not animate. */
virtual void setTransitionTime(f32 Time) = 0;
//! animates the joints in the mesh based on the current frame.
/** Also takes in to account transitions. */
virtual void animateJoints(bool CalculateAbsolutePositions = true) = 0;
//! render mesh ignoring its transformation.
/** Culling is unaffected. */
virtual void setRenderFromIdentity(bool On) = 0;
//! Creates a clone of this scene node and its children.
/** \param newParent An optional new parent.
\param newManager An optional new scene manager.
\return The newly created clone of this node. */
virtual ISceneNode *clone(ISceneNode *newParent = 0, ISceneManager *newManager = 0) = 0;
};
} // end namespace scene
} // end namespace irr

Some files were not shown because too many files have changed in this diff Show More