diff --git a/CMakeLists.txt b/CMakeLists.txt index c97cde148..fea33f0ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ # This file is part of Noggit3, licensed under GNU General Public License (version 3). -cmake_minimum_required(VERSION 3.3) +cmake_minimum_required(VERSION 3.18) cmake_policy (SET CMP0057 NEW) # "Support new IN_LIST if() operator." -set (CMAKE_CXX_STANDARD 14) +set (CMAKE_CXX_STANDARD 17) set (CMAKE_CXX_STANDARD_REQUIRED ON) # Project name @@ -73,11 +73,22 @@ add_global_compiler_flag_if_supported (-Werror=mismatched-tags) add_global_compiler_flag_if_supported (-Wno-multichar) # declaration of 'identifier' hides previous: + +#add_noggit_compiler_flag_if_supported (/we4456) # local declaration +#add_noggit_compiler_flag_if_supported (/we4457) # function parameter +#add_noggit_compiler_flag_if_supported (/we4458) # class members +#add_noggit_compiler_flag_if_supported (/we4459) # global declaration +#add_noggit_compiler_flag_if_supported (-Werror=shadow) + +# better exception handling for visual studio, particularly for the asynchronous stuff +add_global_compiler_flag_if_supported (/EHa) +# multi core building for visual studio +add_global_compiler_flag_if_supported (/MP) #add_noggit_compiler_flag_if_supported (/we4456) # local declaration add_noggit_compiler_flag_if_supported (/we4457) # function parameter add_noggit_compiler_flag_if_supported (/we4458) # class members add_noggit_compiler_flag_if_supported (/we4459) # global declaration -add_noggit_compiler_flag_if_supported (-Werror=shadow) +#add_noggit_compiler_flag_if_supported (-Werror=shadow) if( NOGGIT_ALL_WARNINGS ) MESSAGE( STATUS "Spilling out mass warnings." ) @@ -89,11 +100,6 @@ if( NOGGIT_ALL_WARNINGS ) add_noggit_compiler_flag_if_supported (/Wall) endif( NOGGIT_ALL_WARNINGS ) -# better exception handling for visual studio, particularly for the asynchronous stuff -add_global_compiler_flag_if_supported (/EHa) -# multi core building for visual studio -add_global_compiler_flag_if_supported (/MP) - add_global_compiler_flag_if_supported_config (/Ob2 Release RelWithDebInfo) # inline any suitable functions add_global_compiler_flag_if_supported_config (/Oi Release RelWithDebInfo) # enable intrasic functions add_global_compiler_flag_if_supported_config (/Ot Release RelWithDebInfo) # favor fast code @@ -130,7 +136,6 @@ endif() FIND_PACKAGE( OpenGL REQUIRED ) FIND_PACKAGE( Boost 1.60 COMPONENTS thread filesystem system unit_test_framework REQUIRED ) -FIND_PACKAGE( stormlib REQUIRED ) find_package (Qt5 COMPONENTS Widgets OpenGL OpenGLExtensions) if (USE_SQL) @@ -190,6 +195,10 @@ elseif (WIN32) set(ResFiles media/res.rc) endif() +option (NOGGIT_WITH_SCRIPTING "Enable scripting support?" ON) + +include_directories ("${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/tmp") + # And do the job. INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/src" ) @@ -378,6 +387,52 @@ set ( math_headers src/math/vector_4d.hpp ) +set ( scripting_sources + src/noggit/scripting/script_object.cpp + src/noggit/scripting/script_standard_brush.cpp + src/noggit/scripting/script_tex.cpp + src/noggit/scripting/script_brush.cpp + src/noggit/scripting/script_global.cpp + src/noggit/scripting/script_chunk.cpp + src/noggit/scripting/script_context.cpp + src/noggit/scripting/script_filesystem.cpp + src/noggit/scripting/script_image.cpp + src/noggit/scripting/script_math.cpp + src/noggit/scripting/script_model.cpp + src/noggit/scripting/script_noise.cpp + src/noggit/scripting/script_random.cpp + src/noggit/scripting/script_selection.cpp + src/noggit/scripting/script_vert-script_texture_index.ipp + src/noggit/scripting/script_vert.cpp + src/noggit/scripting/scripting_tool.cpp + src/noggit/scripting/script_profiles.cpp + src/noggit/scripting/script_settings.cpp + src/noggit/scripting/script_exception.cpp + src/noggit/scripting/script_procedures.cpp + ) + +set ( scripting_headers + src/noggit/scripting/script_object.hpp + src/noggit/scripting/script_standard_brush.hpp + src/noggit/scripting/script_tex.hpp + src/noggit/scripting/script_filesystem.hpp + src/noggit/scripting/script_global.hpp + src/noggit/scripting/script_noise.hpp + src/noggit/scripting/script_chunk.hpp + src/noggit/scripting/script_model.hpp + src/noggit/scripting/script_vert.hpp + src/noggit/scripting/script_random.hpp + src/noggit/scripting/script_selection.hpp + src/noggit/scripting/scripting_tool.hpp + src/noggit/scripting/script_context.hpp + src/noggit/scripting/script_brush.hpp + src/noggit/scripting/script_image.hpp + src/noggit/scripting/script_math.hpp + src/noggit/scripting/script_profiles.hpp + src/noggit/scripting/script_settings.hpp + src/noggit/scripting/script_procedures.hpp + ) + set ( opengl_headers src/opengl/context.hpp src/opengl/primitives.hpp @@ -449,6 +504,9 @@ source_group("external" FILES ${external_sources} ${external_headers}) source_group("os" FILES ${os_sources} ${os_headers}) source_group("util" FILES ${util_sources}) source_group("glsl" FILES ${shaders}) +if (NOGGIT_WITH_SCRIPTING) + source_group ("scripting" FILES ${scripting_sources} ${scripting_headers}) +endif() qt5_add_resources (compiled_resource_files "resources/resources.qrc") @@ -477,9 +535,13 @@ ADD_EXECUTABLE ( noggit ) target_compile_options (noggit PRIVATE ${NOGGIT_CXX_FLAGS}) +if (NOGGIT_WITH_SCRIPTING) + target_sources (noggit PRIVATE ${scripting_sources} ${scripting_headers}) + add_compile_definitions (NOGGIT_HAS_SCRIPTING) +endif() + TARGET_LINK_LIBRARIES (noggit ${OPENGL_LIBRARIES} - stormlib::stormlib Boost::thread Boost::filesystem Boost::system @@ -648,3 +710,93 @@ target_compile_definitions (math-matrix_4x4.test PRIVATE "-DBOOST_TEST_MODULE=\" target_compile_options (math-matrix_4x4.test PRIVATE ${NOGGIT_CXX_FLAGS}) target_link_libraries (math-matrix_4x4.test Boost::unit_test_framework noggit::math) add_test (NAME math-matrix_4x4 COMMAND $) + +include (FetchContent) + +# Dependency: StormLib + +FetchContent_Declare (storm + GIT_REPOSITORY https://github.com/ladislav-zezula/StormLib.git + GIT_TAG 60c2dd0fa16d3506722e25fee9b6fa4082b0c1e5 +) +FetchContent_GetProperties (storm) +if (NOT storm_POPULATED) + message (STATUS "Installing StormLib...") + FetchContent_Populate (storm) +endif() +add_subdirectory (${storm_SOURCE_DIR} ${storm_BINARY_DIR} EXCLUDE_FROM_ALL) +set (storm_warning_disable_flags "") +add_local_compiler_flag_if_supported (-Wno-implicit-function-declaration storm_warning_disable_flags) +target_compile_options (storm PRIVATE ${storm_warning_disable_flags}) + +target_link_libraries (noggit + storm +) + +if (NOGGIT_WITH_SCRIPTING) + # Dependency: json.hpp + FetchContent_Declare (json + GIT_REPOSITORY https://github.com/ArthurSonzogni/nlohmann_json_cmake_fetchcontent + GIT_TAG v3.9.1 + ) + FetchContent_GetProperties (json) + if (NOT json_POPULATED) + message (STATUS "Installing json.hpp...") + FetchContent_Populate (json) + endif() + add_subdirectory (${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL) + + # Dependency: lodepng + FetchContent_Declare (lodepng + GIT_REPOSITORY https://github.com/lvandeve/lodepng.git + GIT_TAG 7fdcc96a5e5864eee72911c3ca79b1d9f0d12292 + ) + FetchContent_GetProperties (lodepng) + if (NOT lodepng_POPULATED) + message (STATUS "Installing lodepng...") + FetchContent_Populate (lodepng) + endif() + add_library (lodepng "${lodepng_SOURCE_DIR}/lodepng.cpp") + target_include_directories (lodepng SYSTEM PUBLIC ${lodepng_SOURCE_DIR}) + + # Dependency: FastNoise2 + FetchContent_Declare (fastnoise2 + GIT_REPOSITORY https://github.com/tswow/FastNoise2.git + GIT_TAG v0.0.1-heightmap + PATCH_COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/deps/patch_fastnoise2.cmake" + UPDATE_DISCONNECTED true + ) + FetchContent_GetProperties (fastnoise2) + if (NOT fastnoise2_POPULATED) + message (STATUS "Installing FastNoise2... (big repo, large download)") + FetchContent_Populate (fastnoise2) + endif() + add_subdirectory (${fastnoise2_SOURCE_DIR} ${fastnoise2_BINARY_DIR} EXCLUDE_FROM_ALL) + + # Dependency: Lua + find_package (Lua REQUIRED) + add_library (Lua-Lua INTERFACE) + add_library (Lua::Lua ALIAS Lua-Lua) + target_link_libraries (Lua-Lua INTERFACE ${LUA_LIBRARIES}) + target_include_directories (Lua-Lua INTERFACE ${LUA_INCLUDE_DIR}) + + # Dependency: sol2 + FetchContent_Declare (sol2 + GIT_REPOSITORY https://github.com/tswow/sol2 + GIT_TAG b9c83d5ecf6bc9503dc66779f2395dc32dffb1e5 + ) + FetchContent_MakeAvailable (sol2) + # sol2::sol2 neither links lua nor sets include directories as system so will clobber us with + # loads of warnings, sadly. It also wants to be install(EXPORT)ed which is not what we want. + add_library (sane-sol2 INTERFACE) + add_library (sol2::sane ALIAS sane-sol2) + target_link_libraries (sane-sol2 INTERFACE Lua::Lua) + target_include_directories (sane-sol2 SYSTEM INTERFACE "${sol2_SOURCE_DIR}/include") + + target_link_libraries (noggit + lodepng + FastNoise + nlohmann_json::nlohmann_json + sol2::sane + ) +endif() diff --git a/README.md b/README.md index 78ad908f3..0b7bb381a 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,14 @@ the COPYING file. # DISCORD # You can follow Noggit's development and get the latest build here: https://discord.gg/UbdFHyM +# SCRIPTING # +Noggit can be scripted using the Lua (5.1) programming language. See the [scripting documentation](scripts/docs/README.md). + # BUILDING # This project requires CMake to be built. It also requires the following libraries: * OpenGL -* StormLib (by Ladislav Zezula) * Boost * Qt 5 @@ -19,6 +21,13 @@ Further following libraries are required for MySQL GUID Storage builds: * LibMySQL * MySQLCPPConn +The following libraries are automatically installed: +* StormLib (by Ladislav Zezula) +* FastNoise2 (scripting only) +* sol2 (scripting only) +* lodepng (scripting only) +* nlohmann/json (scripting only) + ## Windows ## Text in `` below are up to your choice but shall be replaced with the same choice every time the same text is contained. @@ -29,7 +38,7 @@ remember which version you chose as later on you will have to pick corresponding versions for other dependencies. ### CMake ### -Any recent CMake 3.x version should work. Just take the latest. +Any recent CMake version >= 3.11 should work. Just take the latest. ### Boost ### Install boost to ``. The easiest is to download a pre-built @@ -47,22 +56,21 @@ Note that during installation you only need **one** version of Qt and also only **one** compiler version. If download size is noticably large (more than a few hundred MB), you're probably downloading way too much. -### StormLib ### -Download StormLib from https://github.com/ladislav-zezula/StormLib (any -recent version). - -* open CMake GUI -* set `CMAKE_INSTALL_PREFIX` (path) to `` (folder should - not yet exist). No other things should need to be configured. -* open solution with visual studio -* build ALL_BUILD -* build INSTALL -* Repeat for both release and debug. +### LuaJIT ### +_(Not necessary if disabling `NOGGIT_WITH_SCRIPTING`)_ +* Clone luajit to `` using git: `git clone https://luajit.org/git/luajit.git` +* Open up the visual studio command prompt (cmd / powershell does **NOT** work) + * The program is usually called something like "x64 Native Tools Command Prompt for VS 20xx" + * Usually enough to search for "x64 native" in the windows start menu + * It will open a command prompt that looks like the normal windows command prompt, but has a bunch of necessary visual studio variables set. +* Navigate to the `/src` (with the visual studio command prompt) +* Run "msvcbuild.bat" (with the visual studio command prompt) +* If successful, should give a message similar to `=== Successfully built LuaJIT for Windows/x64 ===` ### Noggit ### * open CMake GUI -* set `CMAKE_PREFIX_PATH` (path) to `";"`, - e.g. `"C:/Qt/5.6/msvc2015;D:/StormLib/install"` +* set `CMAKE_PREFIX_PATH` (path) to `""`, + e.g. `"C:/Qt/5.6/msvc2015"` * set `BOOST_ROOT` (path) to ``, e.g. `"C:/local/boost_1_60_0"` * (**unlikely to be required:**) move the libraries of Boost from where they are into `BOOST_ROOT/lib` so that CMake finds them automatically or @@ -70,11 +78,13 @@ recent version). is **highly** unlikely to be required. * set `CMAKE_INSTALL_PREFIX` (path) to an empty destination, e.g. `"C:/Users/blurb/Documents/noggitinstall` +* set `LUA_INCLUDE_DIR` to `/src` +* set `LUA_LIBRARY` to `/src/lua51.lib` * configure, generate * open solution with visual studio * build ALL_BUILD * build INSTALL - + To launch noggit you will need the following DLLs from Qt loadable. Install them in the system, or copy them from `C:/Qt/X.X/msvcXXXX/bin` into the directory containing noggit.exe, i.e. `CMAKE_INSTALL_PREFIX` configured. @@ -82,28 +92,77 @@ directory containing noggit.exe, i.e. `CMAKE_INSTALL_PREFIX` configured. * release: Qt5Core, Qt5OpenGL, Qt5Widgets, Qt5Gui * debug: Qt5Cored, Qt5OpenGLd, Qt5Widgetsd, Qt5Guid +* If using scripting, you will also need to copy `/src/lua51.dll` to `CMAKE_INSTALL_PREFIX` + ## Linux ## + +These instructions assume a working directory ``, for example `/home/myuser/` + +### Dependencies ### + On **Ubuntu** you can install the building requirements using: ```bash -sudo apt install freeglut3-dev libboost-all-dev qt5-default libstorm-dev +sudo apt install freeglut3-dev libboost-all-dev qt5-default libsdl2-dev libbz2-dev ``` -Compile and build using: +### LuaJIT ### + +From ``, build luajit using: +```bash +git clone https://luajit.org/git/luajit.git +cd luajit +make +cd .. +``` + +`/luajit` should now exist. + +### Build Noggit ### + +From ``, clone Noggit3 (change repo as needed): +```bash +git clone https://github.com/wowdev/noggit3 +``` + +`/noggit3` should now exist. + +From ``, compile and build using the following commands. +Note that `` should be written as the **full** path in the commands below. +For example: `cmake -DLUA_LIBRARIES=/home/myuser/luajit/src/libluajit.so -DLUA_INCLUDE_DIR=/home/myuser/luajit/src ../noggit3` ```bash mkdir build cd build -cmake .. +cmake -DLUA_LIBRARIES=/luajit/src/libluajit.so -DLUA_INCLUDE_DIR=/luajit/src ../noggit3 make -j $(nproc) ``` Instead of `make -j $(nproc)` you may want to pick a bigger number than `$(nproc)`, e.g. the number of `CPU cores * 1.5`. -If the build pass correctly without errors, you can go into build/bin/ -and run noggit. Note that `make install` will probably work but is not -tested, and nobody has built distributable packages in years. +From `/build`, if the build pass correctly without errors, you can finish the installation using: +```bash +cp -r ../noggit3/scripts ./bin/scripts +cp ../luajit/src/libluajit.a ./bin/libluajit.a +``` + +You can now go into `/build/bin` and run noggit. + +Note that `make install` will probably not work. + +# Building the Scripting documentation # +To generate the scripting API documentation, install any new version of Node.js and run: + +``` +npm i -g typedoc typedoc-plugin-markdown +``` + +Then, enter the "scripting" directory in this repository and run this command: + +``` +typedoc --disableSources --plugin typedoc-plugin-markdown --hideBreadcrumbs --out docs/api global.d.ts && rm docs/api/README.md +``` # DEVELOPMENT # Feel free to ask the owner of the official repository diff --git a/Scripting.md b/Scripting.md new file mode 100644 index 000000000..9bab817a2 --- /dev/null +++ b/Scripting.md @@ -0,0 +1,224 @@ +# Scripting + +This version of noggit has support for "Script Brushes", a special type of brush with scripted behavior. +Script brushes allow us to manipulate heightmaps, textures, vertex colors, water and m2/wmo objects in a customized manner. +Script brushes is an experimental feature, so please be careful and keep regular backups of your work when working with them. + +See [this video](https://youtu.be/J5-8zQ5U8gY) for an introduction to the UI. + + +## Introduction to Da Scripting + +The scripting language we use is called "Da". It's a statically typed language that is otherwise very similar to Python, +and is thus indention-based but has optional support for C-style brackets too. You can use the below guide to quickly learn how to write in Da, + +We recommend that you use +[VSCodium](https://vscodium.com/#install) +with our +[minimal da extension](https://github.com/tswow/das-minimal-extension/releases/tag/v0.0.1) +to easily get autocompletion of function names and type specifications for the Noggit API. + +To create a new script brush, create a `.das` file in the `scripts` subdirectory in your noggit installation. +We can register events by special named functions. The below code illustrates the bare minimum required for a simple left-click event with a custom title: + +```py +require noggit + +[export] +def title(): string + return "Hello World Brush" + +[export] +def left_click() + print("Hello World!") +``` + +### Events + +All event listeners are created as global functions with the `[export]` decorator, and none of them take any arguments. + +- `left_click`: Fires when the user first presses the left mouse button in the world. +- `left_hold`: Fires continuously as the user holds the left mouse button in the world. +- `left_release`: Fires when the user releases the left mouse button. +- `right_click`, `right_hold`, `right_release`: Right mouse button versions of the above three functions. +- `select`: Fires when the user selects this script in the tool window. This event is used to register custom brush options +- `title`: Only used to return a display name for this brush in the tool window. It must have the signature `def title(): string` if implemented. + + +### Quickstart for Da syntax and types + +Da has a lot of weird constructs and types, but interfacing the Noggit API mostly just consists of simple function calls and while loops. +This section aims to give you the basic knowledge you will need to use Da with Noggit, please refer to +[the official documentation](https://dascript.org/doc/reference/language/) for a more in-depth overview of what the language can actually do. + +Note: Da is statically typed language, and it's a little annoying that it has **no** automatic type conversions, +meaning you have to explicitly cast between `ints` and `floats`, and even between `ints` and `unsigned ints`. + +#### Numbers + - Because of the issue with type conversions, the Noggit API uses `int` for most integer parameters, and `float` for all floating point parameters. + - Number literals are assumed to be `int` if they are written like normal base-10 numbers with no fraction: `10` + - Float literals are defined by appending a fractional part to a number: `10.0` + - If a function takes a float parameter, you **must** specify the fractional part: `my_func(10.0)` + - Unsigned int literals are defined by appending "u" to an int literal: `10u` or by writing it in hexadecimal: `0xA` + - Currently, unsigned ints are only used for defining pixel values in `images` + + - Explicit casting between types is necessary: + ```py + var a: float = 10.0 + var b: int = 25 + var c: float = float(b)+a + var d: int = int(a)+b + var e = 0xff + var f = b + int(e) + ``` + +#### Arrays + - Create array: `var arr <- [{auto "one"; "two"; "three"}]` + - Push a value: `push(arr,"new value")` + - Length of array: `var len = length(arr)` + - Erase from array: `erase(arr,2)` + - Clear array: `clear(arr)` + +#### Tables + - Created table: `var tab: table` + - Write a value: `tab["key"] = 10`. + - Read a value: `var value = find(tab,"key")` + - Check if a value exists: `var exists = key_exists(tab,"key")` + +### Blocks and flow control + +Just like in python, empty blocks are not allowed and must at least have a "pass" statement in them if there are no other statements. + +#### Functions +```py +def my_function(arg1: int, arg2: string): int + return 25; +``` + +#### For loops + +Ranges: +```py +for i in range(0,10) + pass +``` + +#### Arrays +```py +var arr <- [{auto "one"; "two"; "three"}] +for val in arr + print("{val}") +``` + +#### Tables +```py +var tab: table +for k,v in keys(tab), values(tab) + print("{k} {v}") +``` + +#### While loops +```py +while some_value + pass +``` + +#### If statements +```py +if some_value + pass +elif some_other_value + pass +``` + +**TODO**: Explain structs + +### Exporting/Importing + +We can import the noggit API with the statement `require noggit` at the top of our script files, +and similarly we can import other .das files the same way. To allow other modules to access a function, use the same `[export]` tag as on event listeners: + +**file_a.das**: +```py +def local_function() + print("This function is only accessible inside file_a.das") + +[export] +def library_function() + print("This function is accessible to any file that 'requires' it") +``` + +**file_b.das**: + +```py +require noggit +require file_a + +[export] +def left_click() + print("This is an event listener, so it also has the 'export' tag") + library_function() +``` + +### Noggit API + +The Noggit API are the functions we expose from inside Noggit to scripts. The file `scripts/noggit.spec.das` contains specifications of all the functions we expose. +`.spec.das` files contain no actual implementations since they only describe existing C++ functions, and we use them similarly to `d.ts` files in JavaScript. + +To use the Noggit API, your script files must contain the line `require noggit` at the top. +If you can't see any noggit functions in your autocompletions, it's likely you forgot this line. + +Noggit API functions should not be called globally in your scripts, but we still made them globally accessible to make them less cumbersome to write. +The following two rules define where it's safe to call Noggit functions from in your scripts: + +- All functions `add_x_param` should be called from the `select` function **only** (or any functions it calls). +- All other functions should be called from click/hold/release events **only** (or any functions they call). + +#### Script Parameters + +Scripts can register custom parameters that can later be read when the user paints with them in the world. The below code illustrates a basic example property: + +```py +[export] +def select() + add_string_param("String Parameter","Value") + +[export] +def left_click() + var str = get_string_param("String Parameter") + print("The parameter was {str}") +``` + +### Selections + +Most Noggit operations involve some kind of selection using the Noggit API. The typical workflow is as follows: + +1. Make a selection around a clicked location +2. Iterate all models +3. Iterate all chunks + 3.1. For each chunk, iterate all vertices + 3.2. For each chunk, iterate all texture units + +The following code example illustrates how this can be achieved. + +```py +require noggit + +[export] +def left_click() + var sel = make_selector() + select_origin(sel,pos(),outer_radius(),outer_radius()) + while sel_next_model(sel) + var model = sel_get_model(sel) + model_remove(model) + + while sel_next_chunk(sel) + var chunk = sel_get_chunk(sel) + while(chunk_next_vert(chunk)) + var vert = chunk_get_vert(chunk) + vert_set_height(vert,0) + + while(chunk_next_tex(chunk)) + var tex = chunk_get_tex(chunk) + tex_set_alpha(tex,1,0.5) +``` diff --git a/cmake/deps/patch_dascript.cmake b/cmake/deps/patch_dascript.cmake new file mode 100644 index 000000000..9f9dde447 --- /dev/null +++ b/cmake/deps/patch_dascript.cmake @@ -0,0 +1,4 @@ +# please don't spam root source directory with test things +file (READ "CMakeLists.txt" cmakelists_content) +string (REPLACE "UNITIZE_BUILD(\"examples/test/unit_tests\" TEST_GENERATED_SRC)" "# noggit patch: examples removed" cmakelists_content "${cmakelists_content}") +file (WRITE "CMakeLists.txt" "${cmakelists_content}") diff --git a/cmake/deps/patch_fastnoise2.cmake b/cmake/deps/patch_fastnoise2.cmake new file mode 100644 index 000000000..b327eb681 --- /dev/null +++ b/cmake/deps/patch_fastnoise2.cmake @@ -0,0 +1,7 @@ +# set includes etc relative to fastnoise2 root directory, not noggit's +file (GLOB_RECURSE cmakelists LIST_DIRECTORIES FALSE "CMakeLists.txt") +foreach (cmakelist ${cmakelists}) + file (READ "${cmakelist}" cmakelists_content) + string (REPLACE "CMAKE_SOURCE_DIR" "PROJECT_SOURCE_DIR" cmakelists_content "${cmakelists_content}") + file (WRITE "${cmakelist}" "${cmakelists_content}") +endforeach() diff --git a/cmake/linux_postfind.cmake b/cmake/linux_postfind.cmake new file mode 100644 index 000000000..f334694d5 --- /dev/null +++ b/cmake/linux_postfind.cmake @@ -0,0 +1,7 @@ +# This file is part of Noggit3, licensed under GNU General Public License (version 3). + +# warnings? +if( NOGGIT_ALL_WARNINGS ) + MESSAGE( STATUS "Spilling out mass warnings." ) + set(noggit_warning_flags "${noggit_warning_flags} -W -Wall -Wshadow") +endif( NOGGIT_ALL_WARNINGS ) diff --git a/cmake/win32_postfind.cmake b/cmake/win32_postfind.cmake new file mode 100644 index 000000000..ed7788bc4 --- /dev/null +++ b/cmake/win32_postfind.cmake @@ -0,0 +1,23 @@ +# This file is part of Noggit3, licensed under GNU General Public License (version 3). + +STRING(REGEX REPLACE "/[^/]*$" "" Boost_STRIPPED_LIB_DIR "${Boost_THREAD_LIBRARY_DEBUG}") +LINK_DIRECTORIES(${Boost_STRIPPED_LIB_DIR} ${STORMLIB_LIBRARY_DIR}) + +#maybe in wrong order now +SET(IncludeDirectories ${IncludeDirectories} "${CMAKE_SOURCE_DIR}/include/win/") +SET(SourceFiles ${SourceFiles} "${CMAKE_SOURCE_DIR}/include/win/StackWalker.cpp") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /D NOMINMAX") + +# warnings? +if( NOGGIT_ALL_WARNINGS ) + MESSAGE( STATUS "Spilling out mass warnings." ) + set(noggit_warning_flags "${noggit_warning_flags} /W4 /Wall /Wp64") +endif( NOGGIT_ALL_WARNINGS ) + +# mark 32 bit executables large address aware so they can use > 2GB address space +if(CMAKE_SIZEOF_VOID_P MATCHES 4) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE") + message(STATUS "- MSVC: Enabled large address awareness!") +endif() + +set(ResFiles media/res.rc) diff --git a/scripts/clean.lua b/scripts/clean.lua new file mode 100644 index 000000000..62cf0e5d3 --- /dev/null +++ b/scripts/clean.lua @@ -0,0 +1,42 @@ +-- This file is part of Noggit3, licensed under GNU General Public License (version 3). +local clean = brush("Clean"); + +local def_height = clean:add_real_tag("Default height",-1000,1000,0) + +local tex_layer_1 = clean:add_string_tag("Texture layer 1","") +local prop_layer_1 = clean:add_int_tag("Effect layer 1",-2,9999999999,-2) +local tex_layer_2 = clean:add_string_tag("Texture layer 2","") +local prop_layer_2 = clean:add_int_tag("Effect layer 2",-2,9999999999,-2) +local tex_layer_3 = clean:add_string_tag("Texture layer 3","") +local prop_layer_3 = clean:add_int_tag("Effect layer 3",-2,9999999999,-2) +local tex_layer_4 = clean:add_string_tag("Texture layer 4","") +local prop_layer_4 = clean:add_int_tag("Effect layer 4",-2,9999999999,-2) + +function clean:on_left_hold(evt) + local sel = select_origin(evt:pos(), evt:outer_radius(), evt:outer_radius()) + if(holding_shift()) then + for i,chunk in pairs(sel:chunks()) do + chunk:clear_textures() + chunk:clear_colors() + if tex_layer_1:get() ~= "" then chunk:add_texture(tex_layer_1:get(),prop_layer_1:get()) end + if tex_layer_2:get() ~= "" then chunk:add_texture(tex_layer_2:get(),prop_layer_2:get()) end + if tex_layer_3:get() ~= "" then chunk:add_texture(tex_layer_3:get(),prop_layer_3:get()) end + if tex_layer_4:get() ~= "" then chunk:add_texture(tex_layer_4:get(),prop_layer_4:get()) end + chunk:apply_all() + end + end + + if(holding_ctrl()) then + for i,vert in pairs(sel:verts()) do + vert:set_height(def_height:get()) + end + end + + if(holding_alt()) then + for i,model in pairs(sel:models()) do + model:remove() + end + end + + sel:apply() +end \ No newline at end of file diff --git a/scripts/docs/README.md b/scripts/docs/README.md new file mode 100644 index 000000000..091073e27 --- /dev/null +++ b/scripts/docs/README.md @@ -0,0 +1,101 @@ +# Scripting + +[API Documentation](api/modules.md) + +This version of Noggit has support for scriptable brushes, meaning you can use the Lua programming language (version 5.1) to customize your own workflow. + +Script brushes should be placed in the `scripts` subdirectory in your Noggit installation. Script brushes can be loaded inside Noggit from the scripting tool (book icon) in the menu to the left. + +**Warning**: Scripts are created by third party developers and are not maintained by Noggit. Scripts downloaded from the internet might contain malicious code. + +## Hello World + +This example illustrates a simple working script brush that you can load in the scripting tool. + +```lua +-- We create a new script brush that becomes +local my_brush = brush("My Brush") + +-- We register an event for when this brush clicks on the ground +function my_brush:on_left_click(evt) + print("Hello world!") +end +``` + +## Script Parameters + +Script brushes can register custom settings that the user can configure without editing the script. + +```lua +local parameter_brush = brush("Parameter Brush") + +-- Editable string +local string_param = parameter_brush:add_string_tag("Parameter Name","default value") + +-- Integer between 1 and 50, default value of 5 +local int_param = parameter_brush:add_int_tag("Int Tag",1,50,5) + +-- Real between 0.0005 and 1, default value of 0.001 and at most 5 decimal points. +local real_param = parameter_brush:add_real_tag("Real Tag",0.0005,1.0,0.001,5) + +-- Checkbox +local bool_param = parameter_brush:add_bool_tag("Bool Tag",false) + +function parameter_brush:on_left_click(evt) + -- We can now access the tag values from the brush event + print("String: " .. string_param:get()) + print("Bool: " .. bool_param:get()) + print("Int: " .. int_param:get()) + print("Real: " .. real_param:get()) + + -- And we can access the special radius settings from the event parameter + print("Outer brush radius:" .. evt:outer_radius()) + print("Inner brush radius" .. evt:inner_radius()) +end +``` + +## Selections + +Most noggit operations involve some kind of selection using the Noggit API. + +The following code illustrates how we can iterate various data in Noggit: + +```lua +local selection_brush = brush("Selection Brush") + +function selection_brush:on_left_click(evt) + -- Creates a square selection at the clicked position + -- containing the entire outer brush circle + local sel = select_origin(evt:pos(), evt:outer_radius()) + + -- iterate selected chunks + for i,chunk in pairs(sel:chunks()) do + -- do something to the chunk here + end + + -- iterate selected vertices + for i,vert in pairs(sel:verts()) do + -- do something to the vertex here + end + + -- iterate selected texture units + for i,tex in pairs(sel:tex()) do + -- do something to the texture unit here + end + + -- iterate selected models (m2 and wmo) + for i,model in pairs(sel:model()) do + -- do something to the model here + end +end +``` + +## Noggit API + +To see all the predefined functions you can call from scripts, see the [API documentation](api/modules.md). + +### File System Permissions + +The functions [image::save](api/classes/image####save) and [write_file](api/modules.md####write_file) can be used to write to the users file systems. By default, when a script tries to call either of these functions the user will be prompted with a popup to confirm they wish to write to that file. If they answer no, an exception will be thrown and stop execution of the script, and if they answer yes the file will be written, and can be written to again without asking until Noggit is restarted. + +This default behavior can be disabled in the Noggit settings under `Allow scripts to write to any file`. diff --git a/scripts/docs/api/classes/chunk.md b/scripts/docs/api/classes/chunk.md new file mode 100644 index 000000000..9651c3e05 --- /dev/null +++ b/scripts/docs/api/classes/chunk.md @@ -0,0 +1,251 @@ +# Class: chunk + +Represents a chunk in the world + +## Table of contents + +### Constructors + +- [constructor](chunk.md#constructor) + +### Methods + +- [add\_texture](chunk.md#add_texture) +- [apply\_all](chunk.md#apply_all) +- [apply\_heightmap](chunk.md#apply_heightmap) +- [apply\_textures](chunk.md#apply_textures) +- [apply\_vertex\_color](chunk.md#apply_vertex_color) +- [clear\_colors](chunk.md#clear_colors) +- [clear\_textures](chunk.md#clear_textures) +- [get\_area\_id](chunk.md#get_area_id) +- [get\_effect](chunk.md#get_effect) +- [get\_texture](chunk.md#get_texture) +- [get\_texture\_count](chunk.md#get_texture_count) +- [remove\_texture](chunk.md#remove_texture) +- [set\_area\_id](chunk.md#set_area_id) +- [set\_effect](chunk.md#set_effect) +- [set\_hole](chunk.md#set_hole) +- [set\_impassable](chunk.md#set_impassable) + +## Constructors + +### constructor + +\+ **new chunk**(): [*chunk*](chunk.md) + +**Returns:** [*chunk*](chunk.md) + +## Methods + +### add\_texture + +▸ **add_texture**(`texture`: *string*, `effect`: *number*): *number* + +Adds a new texture at the current topmost layer. + +**`note`** A chunk can hold at most 4 texture layers. + +#### Parameters: + +Name | Type | Description | +:------ | :------ | :------ | +`texture` | *string* | | +`effect` | *number* | effect id to add - -2 (default): does not change effect - -1: clears current effect index - 0+: change to this effect index | + +**Returns:** *number* + +texture index added to + +___ + +### apply\_all + +▸ **apply_all**(): *void* + +Applies all changes in this chunk + +**Returns:** *void* + +___ + +### apply\_heightmap + +▸ **apply_heightmap**(): *void* + +Applies all changes to the heightmap in this chunk + +**Returns:** *void* + +___ + +### apply\_textures + +▸ **apply_textures**(): *void* + +Applies all changes to texture alphamaps in this chunk + +**Returns:** *void* + +___ + +### apply\_vertex\_color + +▸ **apply_vertex_color**(): *void* + +Applies all changes to vertex colors in this chunk + +**Returns:** *void* + +___ + +### clear\_colors + +▸ **clear_colors**(): *void* + +Removes all vertex colors in this chunk + +**Returns:** *void* + +___ + +### clear\_textures + +▸ **clear_textures**(): *void* + +Removes all texture layers in this chunk + +**Returns:** *void* + +___ + +### get\_area\_id + +▸ **get_area_id**(): *number* + +Returns the area id of a chunk + +**Returns:** *number* + +___ + +### get\_effect + +▸ **get_effect**(`layer`: *number*): *number* + +Returns the effect id at a texture layer + +#### Parameters: + +Name | Type | +:------ | :------ | +`layer` | *number* | + +**Returns:** *number* + +___ + +### get\_texture + +▸ **get_texture**(`index`: *number*): *string* + +Returns the name of the texture at the specified layer. + +#### Parameters: + +Name | Type | +:------ | :------ | +`index` | *number* | + +**Returns:** *string* + +___ + +### get\_texture\_count + +▸ **get_texture_count**(): *number* + +Returns the amount of textures on this chunk + +**Returns:** *number* + +___ + +### remove\_texture + +▸ **remove_texture**(`index`: *number*): *void* + +Removes a texture layer from this chunk +and decreases the texture ids of all higher layers by 1 + +#### Parameters: + +Name | Type | +:------ | :------ | +`index` | *number* | + +**Returns:** *void* + +___ + +### set\_area\_id + +▸ **set_area_id**(`value`: *number*): *void* + +Changes the area id of a chunk + +#### Parameters: + +Name | Type | +:------ | :------ | +`value` | *number* | + +**Returns:** *void* + +___ + +### set\_effect + +▸ **set_effect**(`layer`: *number*, `effect`: *number*): *any* + +Changes the effect id at a texture layer + +#### Parameters: + +Name | Type | Description | +:------ | :------ | :------ | +`layer` | *number* | | +`effect` | *number* | effect id to set (-1 to remove effects) | + +**Returns:** *any* + +___ + +### set\_hole + +▸ **set_hole**(`hole`: *boolean*): *void* + +Creates or removes a hole in this chunk + +#### Parameters: + +Name | Type | +:------ | :------ | +`hole` | *boolean* | + +**Returns:** *void* + +___ + +### set\_impassable + +▸ **set_impassable**(`impassable`: *boolean*): *void* + +Sets whether this chunk should be impassable for players or not + +#### Parameters: + +Name | Type | +:------ | :------ | +`impassable` | *boolean* | + +**Returns:** *void* diff --git a/scripts/docs/api/classes/image.md b/scripts/docs/api/classes/image.md new file mode 100644 index 000000000..c968dab6c --- /dev/null +++ b/scripts/docs/api/classes/image.md @@ -0,0 +1,209 @@ +# Class: image + +Represents a bitmap image + +images can be created from create_image or load_png + +## Table of contents + +### Constructors + +- [constructor](image.md#constructor) + +### Methods + +- [get\_alpha](image.md#get_alpha) +- [get\_blue](image.md#get_blue) +- [get\_green](image.md#get_green) +- [get\_pixel](image.md#get_pixel) +- [get\_red](image.md#get_red) +- [gradient\_scale](image.md#gradient_scale) +- [height](image.md#height) +- [save](image.md#save) +- [set\_pixel](image.md#set_pixel) +- [set\_pixel\_floats](image.md#set_pixel_floats) +- [width](image.md#width) + +## Constructors + +### constructor + +\+ **new image**(): [*image*](image.md) + +**Returns:** [*image*](image.md) + +## Methods + +### get\_alpha + +▸ **get_alpha**(`x`: *number*, `y`: *number*): *number* + +Returns the alpha channel (between 0-1) at an image coordinate + +#### Parameters: + +Name | Type | +:------ | :------ | +`x` | *number* | +`y` | *number* | + +**Returns:** *number* + +___ + +### get\_blue + +▸ **get_blue**(`x`: *number*, `y`: *number*): *number* + +Returns the blue channel (between 0-1) at an image coordinate + +#### Parameters: + +Name | Type | +:------ | :------ | +`x` | *number* | +`y` | *number* | + +**Returns:** *number* + +___ + +### get\_green + +▸ **get_green**(`x`: *number*, `y`: *number*): *number* + +Returns the green channel (between 0-1) at an image coordinate + +#### Parameters: + +Name | Type | +:------ | :------ | +`x` | *number* | +`y` | *number* | + +**Returns:** *number* + +___ + +### get\_pixel + +▸ **get_pixel**(`x`: *number*, `y`: *number*): *number* + +Returns the pixel value at a coordinate + +#### Parameters: + +Name | Type | +:------ | :------ | +`x` | *number* | +`y` | *number* | + +**Returns:** *number* + +___ + +### get\_red + +▸ **get_red**(`x`: *number*, `y`: *number*): *number* + +Returns the red channel (between 0-1) at an image coordinate + +#### Parameters: + +Name | Type | +:------ | :------ | +`x` | *number* | +`y` | *number* | + +**Returns:** *number* + +___ + +### gradient\_scale + +▸ **gradient_scale**(`rel`: *number*): *number* + +Returns the pixel value at a relative horizontal coordinate + +#### Parameters: + +Name | Type | Description | +:------ | :------ | :------ | +`rel` | *number* | horizontal relative position (between 0-1) | + +**Returns:** *number* + +___ + +### height + +▸ **height**(): *number* + +Returns the height of this image + +**Returns:** *number* + +___ + +### save + +▸ **save**(`filename`: *string*): *any* + +Saves this image to a file + +#### Parameters: + +Name | Type | +:------ | :------ | +`filename` | *string* | + +**Returns:** *any* + +___ + +### set\_pixel + +▸ **set_pixel**(`x`: *number*, `y`: *number*, `value`: *number*): *void* + +Sets the pixel value at an image coordinate + +#### Parameters: + +Name | Type | +:------ | :------ | +`x` | *number* | +`y` | *number* | +`value` | *number* | + +**Returns:** *void* + +___ + +### set\_pixel\_floats + +▸ **set_pixel_floats**(`x`: *number*, `y`: *number*, `r`: *number*, `g`: *number*, `b`: *number*, `a`: *number*): *void* + +Sets the pixel value at an image coordinate + +#### Parameters: + +Name | Type | Description | +:------ | :------ | :------ | +`x` | *number* | | +`y` | *number* | | +`r` | *number* | should be between 0-1 | +`g` | *number* | should be between 0-1 | +`b` | *number* | should be between 0-1 | +`a` | *number* | should be between 0-1 | + +**Returns:** *void* + +___ + +### width + +▸ **width**(): *number* + +Returns the width of this image + +**Returns:** *number* diff --git a/scripts/docs/api/classes/model.md b/scripts/docs/api/classes/model.md new file mode 100644 index 000000000..306c1fad5 --- /dev/null +++ b/scripts/docs/api/classes/model.md @@ -0,0 +1,149 @@ +# Class: model + +Represents a model in the world. Can represent both an m2 and wmo model. + +## Table of contents + +### Constructors + +- [constructor](model.md#constructor) + +### Methods + +- [get\_filename](model.md#get_filename) +- [get\_pos](model.md#get_pos) +- [get\_rot](model.md#get_rot) +- [get\_scale](model.md#get_scale) +- [get\_uid](model.md#get_uid) +- [has\_filename](model.md#has_filename) +- [remove](model.md#remove) +- [replace](model.md#replace) +- [set\_pos](model.md#set_pos) +- [set\_rot](model.md#set_rot) +- [set\_scale](model.md#set_scale) + +## Constructors + +### constructor + +\+ **new model**(): [*model*](model.md) + +**Returns:** [*model*](model.md) + +## Methods + +### get\_filename + +▸ **get_filename**(): *string* + +**Returns:** *string* + +___ + +### get\_pos + +▸ **get_pos**(): [*vector\_3d*](vector_3d.md) + +**Returns:** [*vector\_3d*](vector_3d.md) + +___ + +### get\_rot + +▸ **get_rot**(): [*vector\_3d*](vector_3d.md) + +**Returns:** [*vector\_3d*](vector_3d.md) + +___ + +### get\_scale + +▸ **get_scale**(): *number* + +**Returns:** *number* + +___ + +### get\_uid + +▸ **get_uid**(): *number* + +**Returns:** *number* + +___ + +### has\_filename + +▸ **has_filename**(`name`: *string*): *boolean* + +#### Parameters: + +Name | Type | +:------ | :------ | +`name` | *string* | + +**Returns:** *boolean* + +___ + +### remove + +▸ **remove**(): *void* + +**Returns:** *void* + +___ + +### replace + +▸ **replace**(`filename`: *string*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`filename` | *string* | + +**Returns:** *any* + +___ + +### set\_pos + +▸ **set_pos**(`pos`: [*vector\_3d*](vector_3d.md)): *void* + +#### Parameters: + +Name | Type | +:------ | :------ | +`pos` | [*vector\_3d*](vector_3d.md) | + +**Returns:** *void* + +___ + +### set\_rot + +▸ **set_rot**(`pos`: [*vector\_3d*](vector_3d.md)): *void* + +#### Parameters: + +Name | Type | +:------ | :------ | +`pos` | [*vector\_3d*](vector_3d.md) | + +**Returns:** *void* + +___ + +### set\_scale + +▸ **set_scale**(`scale`: *number*): *void* + +#### Parameters: + +Name | Type | +:------ | :------ | +`scale` | *number* | + +**Returns:** *void* diff --git a/scripts/docs/api/classes/noisemap.md b/scripts/docs/api/classes/noisemap.md new file mode 100644 index 000000000..4479dd1f9 --- /dev/null +++ b/scripts/docs/api/classes/noisemap.md @@ -0,0 +1,96 @@ +# Class: noisemap + +Represents a map of floats values, typically use with a +noise generator. + +## Table of contents + +### Constructors + +- [constructor](noisemap.md#constructor) + +### Methods + +- [get](noisemap.md#get) +- [height](noisemap.md#height) +- [is\_highest](noisemap.md#is_highest) +- [set](noisemap.md#set) +- [width](noisemap.md#width) + +## Constructors + +### constructor + +\+ **new noisemap**(): [*noisemap*](noisemap.md) + +**Returns:** [*noisemap*](noisemap.md) + +## Methods + +### get + +▸ **get**(`pos`: [*vector\_3d*](vector_3d.md)): *number* + +Returns the float value at a specific 3d position. + +**`note`** The 'y' value of pos is ignored by this operation. + +#### Parameters: + +Name | Type | +:------ | :------ | +`pos` | [*vector\_3d*](vector_3d.md) | + +**Returns:** *number* + +___ + +### height + +▸ **height**(): *number* + +**Returns:** *number* + +___ + +### is\_highest + +▸ **is_highest**(`pos`: [*vector\_3d*](vector_3d.md), `check_radius`: *number*): *boolean* + +Returns true if the float value at a 3d position +is the highest position within a given range. + +This is typically used for object placement. + +#### Parameters: + +Name | Type | +:------ | :------ | +`pos` | [*vector\_3d*](vector_3d.md) | +`check_radius` | *number* | + +**Returns:** *boolean* + +___ + +### set + +▸ **set**(`x`: *number*, `y`: *number*, `value`: *number*): *void* + +#### Parameters: + +Name | Type | +:------ | :------ | +`x` | *number* | +`y` | *number* | +`value` | *number* | + +**Returns:** *void* + +___ + +### width + +▸ **width**(): *number* + +**Returns:** *number* diff --git a/scripts/docs/api/classes/procedures_class.md b/scripts/docs/api/classes/procedures_class.md new file mode 100644 index 000000000..43729d51d --- /dev/null +++ b/scripts/docs/api/classes/procedures_class.md @@ -0,0 +1,41 @@ +# Class: procedures\_class + +Contains some general-purpose procedures that don't fit anywhere else. + +Access these functions through the global singleton "procedures". + +## Table of contents + +### Constructors + +- [constructor](procedures_class.md#constructor) + +### Methods + +- [paint\_texture](procedures_class.md#paint_texture) + +## Constructors + +### constructor + +\+ **new procedures_class**(): [*procedures\_class*](procedures_class.md) + +**Returns:** [*procedures\_class*](procedures_class.md) + +## Methods + +### paint\_texture + +▸ **paint_texture**(`sel`: [*selection*](selection.md), `img`: [*image*](image.md), `layer`: *number*, `pressure`: *number*, `angle`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`sel` | [*selection*](selection.md) | +`img` | [*image*](image.md) | +`layer` | *number* | +`pressure` | *number* | +`angle` | *number* | + +**Returns:** *any* diff --git a/scripts/docs/api/classes/random.md b/scripts/docs/api/classes/random.md new file mode 100644 index 000000000..d955cd2a9 --- /dev/null +++ b/scripts/docs/api/classes/random.md @@ -0,0 +1,52 @@ +# Class: random + +Represents a random generator and its state. + +## Table of contents + +### Constructors + +- [constructor](random.md#constructor) + +### Methods + +- [integer](random.md#integer) +- [real](random.md#real) + +## Constructors + +### constructor + +\+ **new random**(): [*random*](random.md) + +**Returns:** [*random*](random.md) + +## Methods + +### integer + +▸ **integer**(`low`: *number*, `high`: *number*): *number* + +#### Parameters: + +Name | Type | +:------ | :------ | +`low` | *number* | +`high` | *number* | + +**Returns:** *number* + +___ + +### real + +▸ **real**(`low`: *number*, `high`: *number*): *number* + +#### Parameters: + +Name | Type | +:------ | :------ | +`low` | *number* | +`high` | *number* | + +**Returns:** *number* diff --git a/scripts/docs/api/classes/script_brush.md b/scripts/docs/api/classes/script_brush.md new file mode 100644 index 000000000..7298e402b --- /dev/null +++ b/scripts/docs/api/classes/script_brush.md @@ -0,0 +1,233 @@ +# Class: script\_brush + +Represents a script brush in the script window. + +## Table of contents + +### Constructors + +- [constructor](script_brush.md#constructor) + +### Properties + +- [on\_left\_click](script_brush.md#on_left_click) +- [on\_left\_hold](script_brush.md#on_left_hold) +- [on\_left\_release](script_brush.md#on_left_release) +- [on\_right\_click](script_brush.md#on_right_click) +- [on\_right\_hold](script_brush.md#on_right_hold) +- [on\_right\_release](script_brush.md#on_right_release) + +### Methods + +- [add\_bool\_tag](script_brush.md#add_bool_tag) +- [add\_description](script_brush.md#add_description) +- [add\_int\_tag](script_brush.md#add_int_tag) +- [add\_null\_tag](script_brush.md#add_null_tag) +- [add\_real\_tag](script_brush.md#add_real_tag) +- [add\_string\_list\_tag](script_brush.md#add_string_list_tag) +- [add\_string\_tag](script_brush.md#add_string_tag) +- [get\_name](script_brush.md#get_name) +- [set\_name](script_brush.md#set_name) + +## Constructors + +### constructor + +\+ **new script_brush**(): [*script\_brush*](script_brush.md) + +**Returns:** [*script\_brush*](script_brush.md) + +## Properties + +### on\_left\_click + +• **on\_left\_click**: [*callback*](../modules.md#callback)<(`brush`: [*script\_brush*](script_brush.md), `event`: [*script\_brush\_event*](script_brush_event.md)) => *void*\> + +The function to call when the user left clicks +the world with this brush + +___ + +### on\_left\_hold + +• **on\_left\_hold**: [*callback*](../modules.md#callback)<(`brush`: [*script\_brush*](script_brush.md), `event`: [*script\_brush\_event*](script_brush_event.md)) => *void*\> + +The funciton to call when the user holds the left mouse button +in the world with this brush + +___ + +### on\_left\_release + +• **on\_left\_release**: [*callback*](../modules.md#callback)<(`brush`: [*script\_brush*](script_brush.md), `event`: [*script\_brush\_event*](script_brush_event.md)) => *void*\> + +The function to call when the user releases the left moues button +in the world with this brush + +___ + +### on\_right\_click + +• **on\_right\_click**: [*callback*](../modules.md#callback)<(`brush`: [*script\_brush*](script_brush.md), `event`: [*script\_brush\_event*](script_brush_event.md)) => *void*\> + +The function to call when the user right clicks +the world with this brush + +___ + +### on\_right\_hold + +• **on\_right\_hold**: [*callback*](../modules.md#callback)<(`brush`: [*script\_brush*](script_brush.md), `event`: [*script\_brush\_event*](script_brush_event.md)) => *void*\> + +The funciton to call when the user holds the right mouse button +in the world with this brush + +___ + +### on\_right\_release + +• **on\_right\_release**: [*callback*](../modules.md#callback)<(`brush`: [*script\_brush*](script_brush.md), `event`: [*script\_brush\_event*](script_brush_event.md)) => *void*\> + +The function to call when the user releases the right mouse button +in the world with this brush + +## Methods + +### add\_bool\_tag + +▸ **add_bool_tag**(`item`: *string*, `def`: *boolean*): [*tag*](tag.md) + +Adds a bool tag to the settings panel + +#### Parameters: + +Name | Type | +:------ | :------ | +`item` | *string* | +`def` | *boolean* | + +**Returns:** [*tag*](tag.md) + +___ + +### add\_description + +▸ **add_description**(`text`: *string*): *any* + +Adds a description row to the brush window + +#### Parameters: + +Name | Type | +:------ | :------ | +`text` | *string* | + +**Returns:** *any* + +___ + +### add\_int\_tag + +▸ **add_int_tag**(`item`: *string*, `low`: *number*, `high`: *number*, `def`: *number*): [*tag*](tag.md) + +Adds an integer tag to the settings panel + +#### Parameters: + +Name | Type | +:------ | :------ | +`item` | *string* | +`low` | *number* | +`high` | *number* | +`def` | *number* | + +**Returns:** [*tag*](tag.md) + +___ + +### add\_null\_tag + +▸ **add_null_tag**(): *any* + +Adds an empty tag, typically used to create empty lines in the settings panel + +**Returns:** *any* + +___ + +### add\_real\_tag + +▸ **add_real_tag**(`item`: *string*, `low`: *number*, `high`: *number*, `def`: *number*): [*tag*](tag.md) + +Adds a real (i.e. float) tag to the settings panel + +#### Parameters: + +Name | Type | +:------ | :------ | +`item` | *string* | +`low` | *number* | +`high` | *number* | +`def` | *number* | + +**Returns:** [*tag*](tag.md) + +___ + +### add\_string\_list\_tag + +▸ **add_string_list_tag**(`item`: *string*, ...`values`: *string*[]): [*tag*](tag.md) + +Adds a dropdown menu to the settings panel + +#### Parameters: + +Name | Type | +:------ | :------ | +`item` | *string* | +`...values` | *string*[] | + +**Returns:** [*tag*](tag.md) + +___ + +### add\_string\_tag + +▸ **add_string_tag**(`item`: *string*, `def`: *string*): [*tag*](tag.md) + +Adds a string tag to the settings panel + +#### Parameters: + +Name | Type | +:------ | :------ | +`item` | *string* | +`def` | *string* | + +**Returns:** [*tag*](tag.md) + +___ + +### get\_name + +▸ **get_name**(): *string* + +Returns the current name of this script brush + +**Returns:** *string* + +___ + +### set\_name + +▸ **set_name**(`name`: *string*): *void* + +Changes the name of this script brush + +#### Parameters: + +Name | Type | +:------ | :------ | +`name` | *string* | + +**Returns:** *void* diff --git a/scripts/docs/api/classes/script_brush_event.md b/scripts/docs/api/classes/script_brush_event.md new file mode 100644 index 000000000..b0c77e9b0 --- /dev/null +++ b/scripts/docs/api/classes/script_brush_event.md @@ -0,0 +1,99 @@ +# Class: script\_brush\_event + +Represents the event context passed to brush click events. + +## Table of contents + +### Constructors + +- [constructor](script_brush_event.md#constructor) + +### Methods + +- [dt](script_brush_event.md#dt) +- [inner\_radius](script_brush_event.md#inner_radius) +- [outer\_radius](script_brush_event.md#outer_radius) +- [pos](script_brush_event.md#pos) +- [set\_inner\_radius](script_brush_event.md#set_inner_radius) +- [set\_outer\_radius](script_brush_event.md#set_outer_radius) + +## Constructors + +### constructor + +\+ **new script_brush_event**(): [*script\_brush\_event*](script_brush_event.md) + +**Returns:** [*script\_brush\_event*](script_brush_event.md) + +## Methods + +### dt + +▸ **dt**(): *number* + +Returns the delta-time since the last update frame + +**Returns:** *number* + +___ + +### inner\_radius + +▸ **inner_radius**(): *number* + +Returns the current inner radius configured in the settings panel + +**Returns:** *number* + +___ + +### outer\_radius + +▸ **outer_radius**(): *number* + +Returns the current outer radius configured in the settings panel + +**Returns:** *number* + +___ + +### pos + +▸ **pos**(): [*vector\_3d*](vector_3d.md) + +Returns world position of this click event. +i.e. the world position where the user clicked, held or released a mouse button + +**Returns:** [*vector\_3d*](vector_3d.md) + +___ + +### set\_inner\_radius + +▸ **set_inner_radius**(`value`: *number*): *any* + +Sets the outer radius in the settings panel for this brush + +#### Parameters: + +Name | Type | Description | +:------ | :------ | :------ | +`value` | *number* | should be between 0-1 | + +**Returns:** *any* + +___ + +### set\_outer\_radius + +▸ **set_outer_radius**(`value`: *number*): *any* + +Sets the outer radius in the settings panel for this brush + +#### Parameters: + +Name | Type | +:------ | :------ | +`value` | *number* | + +**Returns:** *any* diff --git a/scripts/docs/api/classes/selection.md b/scripts/docs/api/classes/selection.md new file mode 100644 index 000000000..c0ecce7e9 --- /dev/null +++ b/scripts/docs/api/classes/selection.md @@ -0,0 +1,143 @@ +# Class: selection + +Represents a rectangular selection in the world and provides +iterators for heightmap vertices, texture units, chunks and models within it. + +## Table of contents + +### Constructors + +- [constructor](selection.md#constructor) + +### Methods + +- [apply](selection.md#apply) +- [center](selection.md#center) +- [chunks](selection.md#chunks) +- [make\_noise](selection.md#make_noise) +- [max](selection.md#max) +- [min](selection.md#min) +- [models](selection.md#models) +- [size](selection.md#size) +- [tex](selection.md#tex) +- [verts](selection.md#verts) + +## Constructors + +### constructor + +\+ **new selection**(): [*selection*](selection.md) + +**Returns:** [*selection*](selection.md) + +## Methods + +### apply + +▸ **apply**(): *void* + +Applies all changes made inside this selection. +You almost always want to call this function when you're done +with a selection. + +**Returns:** *void* + +___ + +### center + +▸ **center**(): [*vector\_3d*](vector_3d.md) + +Returns the center point of this selection + +**Returns:** [*vector\_3d*](vector_3d.md) + +___ + +### chunks + +▸ **chunks**(): [*chunk*](chunk.md)[] + +Creates and returns an iterator for all chunks inside this selection + +**Returns:** [*chunk*](chunk.md)[] + +___ + +### make\_noise + +▸ **make_noise**(`frequency`: *number*, `algorithm`: *string*, `seed`: *string*): [*noisemap*](noisemap.md) + +Creates a noisemap matching the location of this selection + +#### Parameters: + +Name | Type | +:------ | :------ | +`frequency` | *number* | +`algorithm` | *string* | +`seed` | *string* | + +**Returns:** [*noisemap*](noisemap.md) + +___ + +### max + +▸ **max**(): [*vector\_3d*](vector_3d.md) + +Returns the highest point of this selection + +**Returns:** [*vector\_3d*](vector_3d.md) + +___ + +### min + +▸ **min**(): [*vector\_3d*](vector_3d.md) + +Returns the smallest point of this selection + +**Returns:** [*vector\_3d*](vector_3d.md) + +___ + +### models + +▸ **models**(): [*model*](model.md)[] + +Creates and returns an iterator for all models inside this selection + +**Returns:** [*model*](model.md)[] + +___ + +### size + +▸ **size**(): [*vector\_3d*](vector_3d.md) + +Returns a vector representing the size of this selection on each axis. + +**`note`** for iterators, only x and z values are respected. y (height) is ignored. + +**Returns:** [*vector\_3d*](vector_3d.md) + +___ + +### tex + +▸ **tex**(): [*tex*](tex.md)[] + +Creates and returns an iterator for all texture units inside this selection + +**Returns:** [*tex*](tex.md)[] + +___ + +### verts + +▸ **verts**(): [*vert*](vert.md)[] + +Creates and returns an iterator for all vertices inside this selection + +**Returns:** [*vert*](vert.md)[] diff --git a/scripts/docs/api/classes/tag.md b/scripts/docs/api/classes/tag.md new file mode 100644 index 000000000..2212a7f9c --- /dev/null +++ b/scripts/docs/api/classes/tag.md @@ -0,0 +1,43 @@ +# Class: tag + +Represents a settings tag that can be accessed at any time by a script. + +## Type parameters + +Name | +:------ | +`T` | + +## Table of contents + +### Constructors + +- [constructor](tag.md#constructor) + +### Methods + +- [get](tag.md#get) + +## Constructors + +### constructor + +\+ **new tag**(): [*tag*](tag.md) + +#### Type parameters: + +Name | +:------ | +`T` | + +**Returns:** [*tag*](tag.md) + +## Methods + +### get + +▸ **get**(): T + +Returns the current value of this tag in the settings panel. + +**Returns:** T diff --git a/scripts/docs/api/classes/tex.md b/scripts/docs/api/classes/tex.md new file mode 100644 index 000000000..150b8df70 --- /dev/null +++ b/scripts/docs/api/classes/tex.md @@ -0,0 +1,64 @@ +# Class: tex + +Represents a single texture unit in the worlds texture layers. + +A texture unit represents the smallest area where it's possible to +affect textures alpha layers. This is much smaller than the areas made +up by heightmap vertices. + +## Table of contents + +### Constructors + +- [constructor](tex.md#constructor) + +### Methods + +- [get\_alpha](tex.md#get_alpha) +- [get\_pos\_2d](tex.md#get_pos_2d) +- [set\_alpha](tex.md#set_alpha) + +## Constructors + +### constructor + +\+ **new tex**(): [*tex*](tex.md) + +**Returns:** [*tex*](tex.md) + +## Methods + +### get\_alpha + +▸ **get_alpha**(`index`: *number*): *number* + +#### Parameters: + +Name | Type | +:------ | :------ | +`index` | *number* | + +**Returns:** *number* + +___ + +### get\_pos\_2d + +▸ **get_pos_2d**(): [*vector\_3d*](vector_3d.md) + +**Returns:** [*vector\_3d*](vector_3d.md) + +___ + +### set\_alpha + +▸ **set_alpha**(`index`: *number*, `alpha`: *number*): *void* + +#### Parameters: + +Name | Type | +:------ | :------ | +`index` | *number* | +`alpha` | *number* | + +**Returns:** *void* diff --git a/scripts/docs/api/classes/vector_3d.md b/scripts/docs/api/classes/vector_3d.md new file mode 100644 index 000000000..b69648c59 --- /dev/null +++ b/scripts/docs/api/classes/vector_3d.md @@ -0,0 +1,42 @@ +# Class: vector\_3d + +Represents a 3-dimensional vector. +Most functions do not use the 'y' (height) value at all + +## Table of contents + +### Constructors + +- [constructor](vector_3d.md#constructor) + +### Properties + +- [x](vector_3d.md#x) +- [y](vector_3d.md#y) +- [z](vector_3d.md#z) + +## Constructors + +### constructor + +\+ **new vector_3d**(): [*vector\_3d*](vector_3d.md) + +**Returns:** [*vector\_3d*](vector_3d.md) + +## Properties + +### x + +• **x**: *number* + +___ + +### y + +• **y**: *number* + +___ + +### z + +• **z**: *number* diff --git a/scripts/docs/api/classes/vert.md b/scripts/docs/api/classes/vert.md new file mode 100644 index 000000000..ee8436ccf --- /dev/null +++ b/scripts/docs/api/classes/vert.md @@ -0,0 +1,190 @@ +# Class: vert + +Represents a single heightmap vertex in the world. + +Changes to this vertex takes visible effect in Noggit after you call +"apply" on the chunk or selection that contains it. + +## Table of contents + +### Constructors + +- [constructor](vert.md#constructor) + +### Methods + +- [add\_height](vert.md#add_height) +- [get\_alpha](vert.md#get_alpha) +- [get\_pos](vert.md#get_pos) +- [is\_water\_aligned](vert.md#is_water_aligned) +- [set\_alpha](vert.md#set_alpha) +- [set\_color](vert.md#set_color) +- [set\_height](vert.md#set_height) +- [set\_hole](vert.md#set_hole) +- [set\_water](vert.md#set_water) +- [sub\_height](vert.md#sub_height) + +## Constructors + +### constructor + +\+ **new vert**(): [*vert*](vert.md) + +**Returns:** [*vert*](vert.md) + +## Methods + +### add\_height + +▸ **add_height**(`y`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`y` | *number* | + +**Returns:** *any* + +___ + +### get\_alpha + +▸ **get_alpha**(`index`: *number*): *any* + +Returns the average alpha of all texture units closest to this vertex. + +#### Parameters: + +Name | Type | +:------ | :------ | +`index` | *number* | + +**Returns:** *any* + +___ + +### get\_pos + +▸ **get_pos**(): [*vector\_3d*](vector_3d.md) + +Returns the full position of this vertex + +**Returns:** [*vector\_3d*](vector_3d.md) + +___ + +### is\_water\_aligned + +▸ **is_water_aligned**(): *boolean* + +Returns true if this vertex is aligned with water tiles. + +**Returns:** *boolean* + +___ + +### set\_alpha + +▸ **set_alpha**(`index`: *number*, `alpha`: *number*): *void* + +Sets a texture alpha layer of all texture units closest to this vertex. + +#### Parameters: + +Name | Type | +:------ | :------ | +`index` | *number* | +`alpha` | *number* | + +**Returns:** *void* + +___ + +### set\_color + +▸ **set_color**(`red`: *number*, `green`: *number*, `blue`: *number*): *void* + +Changes the vertex color that this vertex blends with the +underlying texture. Values generally range between 0-1, but can +also go higher. + +#### Parameters: + +Name | Type | Description | +:------ | :------ | :------ | +`red` | *number* | How much red should be used (default: 1) | +`green` | *number* | How much green should be used (default: 1) | +`blue` | *number* | How much blue should be used (default: 1) | + +**Returns:** *void* + +___ + +### set\_height + +▸ **set_height**(`y`: *number*): *any* + +Changes the height of this vertex + +#### Parameters: + +Name | Type | +:------ | :------ | +`y` | *number* | + +**Returns:** *any* + +___ + +### set\_hole + +▸ **set_hole**(`has_hole`: *boolean*): *void* + +Sets whether this vertex should be a hole, but only if the +vertex is aligned with hole tiles. If the vertex is not aligned +with a hole tile, this function does nothing. + +#### Parameters: + +Name | Type | +:------ | :------ | +`has_hole` | *boolean* | + +**Returns:** *void* + +___ + +### set\_water + +▸ **set_water**(`type`: *number*, `height`: *number*): *void* + +Changes the water type on this vertex, but only if the vertex is +aligned with water tiles. If the vertex is not aligned +with a water tile, this function does nothing. + +**`note`** The C++ function backing this operation is very slow for the moment. +use with care. + +#### Parameters: + +Name | Type | +:------ | :------ | +`type` | *number* | +`height` | *number* | + +**Returns:** *void* + +___ + +### sub\_height + +▸ **sub_height**(`y`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`y` | *number* | + +**Returns:** *any* diff --git a/scripts/docs/api/modules.md b/scripts/docs/api/modules.md new file mode 100644 index 000000000..dedef4ccb --- /dev/null +++ b/scripts/docs/api/modules.md @@ -0,0 +1,913 @@ +# + +## Table of contents + +### Classes + +- [chunk](classes/chunk.md) +- [image](classes/image.md) +- [model](classes/model.md) +- [noisemap](classes/noisemap.md) +- [procedures\_class](classes/procedures_class.md) +- [random](classes/random.md) +- [script\_brush](classes/script_brush.md) +- [script\_brush\_event](classes/script_brush_event.md) +- [selection](classes/selection.md) +- [tag](classes/tag.md) +- [tex](classes/tex.md) +- [vector\_3d](classes/vector_3d.md) +- [vert](classes/vert.md) + +### Type aliases + +- [brush\_callback](modules.md#brush_callback) +- [callback](modules.md#callback) +- [nil](modules.md#nil) + +### Variables + +- [procedures](modules.md#procedures) + +### Functions + +- [abs](modules.md#abs) +- [acos](modules.md#acos) +- [acosh](modules.md#acosh) +- [add\_m2](modules.md#add_m2) +- [add\_wmo](modules.md#add_wmo) +- [append\_file](modules.md#append_file) +- [asin](modules.md#asin) +- [asinh](modules.md#asinh) +- [atan](modules.md#atan) +- [atanh](modules.md#atanh) +- [brush](modules.md#brush) +- [cam\_pitch](modules.md#cam_pitch) +- [cam\_yaw](modules.md#cam_yaw) +- [camera\_pos](modules.md#camera_pos) +- [cbrt](modules.md#cbrt) +- [ceil](modules.md#ceil) +- [cos](modules.md#cos) +- [cosh](modules.md#cosh) +- [create\_image](modules.md#create_image) +- [dist\_2d](modules.md#dist_2d) +- [dist\_2d\_compare](modules.md#dist_2d_compare) +- [exp](modules.md#exp) +- [floor](modules.md#floor) +- [get\_area\_id](modules.md#get_area_id) +- [get\_map\_id](modules.md#get_map_id) +- [holding\_alt](modules.md#holding_alt) +- [holding\_ctrl](modules.md#holding_ctrl) +- [holding\_left\_mouse](modules.md#holding_left_mouse) +- [holding\_right\_mouse](modules.md#holding_right_mouse) +- [holding\_shift](modules.md#holding_shift) +- [holding\_space](modules.md#holding_space) +- [lerp](modules.md#lerp) +- [load\_png](modules.md#load_png) +- [log](modules.md#log) +- [log10](modules.md#log10) +- [make\_noise](modules.md#make_noise) +- [path\_exists](modules.md#path_exists) +- [pow](modules.md#pow) +- [print](modules.md#print) +- [random\_from\_seed](modules.md#random_from_seed) +- [random\_from\_time](modules.md#random_from_time) +- [read\_file](modules.md#read_file) +- [rotate\_2d](modules.md#rotate_2d) +- [round](modules.md#round) +- [select\_between](modules.md#select_between) +- [select\_origin](modules.md#select_origin) +- [sin](modules.md#sin) +- [sinh](modules.md#sinh) +- [sqrt](modules.md#sqrt) +- [tan](modules.md#tan) +- [tanh](modules.md#tanh) +- [vec](modules.md#vec) +- [write\_file](modules.md#write_file) + +## Type aliases + +### brush\_callback + +Ƭ **brush\_callback**: [*callback*](modules.md#callback)<(`brush`: [*script\_brush*](classes/script_brush.md), `event`: [*script\_brush\_event*](classes/script_brush_event.md)) => *void*\> + +The type of callback used for brush events. + +**`note`** In lua, the first argument becomes "self" argument if using colon notation + +___ + +### callback + +Ƭ **callback**: T \| [*nil*](modules.md#nil) + +Callback functions are unassigned by default, but may be assigned to +by the user + +#### Type parameters: + +Name | +:------ | +`T` | + +___ + +### nil + +Ƭ **nil**: *undefined* + +This is the documentation for the Noggit scripting API. +Functions not connected to a class are global and can be called from +anywhere in a script. + +## Variables + +### procedures + +• `Const` **procedures**: [*procedures\_class*](classes/procedures_class.md) + +singleton object + +## Functions + +### abs + +▸ **abs**(`arg`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`arg` | *number* | + +**Returns:** *any* + +___ + +### acos + +▸ **acos**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### acosh + +▸ **acosh**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### add\_m2 + +▸ **add_m2**(`filename`: *string*, `pos`: [*vector\_3d*](classes/vector_3d.md), `scale`: *number*, `rotation`: [*vector\_3d*](classes/vector_3d.md)): *void* + +Spawns an m2 model in the world. + +#### Parameters: + +Name | Type | +:------ | :------ | +`filename` | *string* | +`pos` | [*vector\_3d*](classes/vector_3d.md) | +`scale` | *number* | +`rotation` | [*vector\_3d*](classes/vector_3d.md) | + +**Returns:** *void* + +___ + +### add\_wmo + +▸ **add_wmo**(`filename`: *string*, `pos`: [*vector\_3d*](classes/vector_3d.md), `rot`: [*vector\_3d*](classes/vector_3d.md)): *void* + +Spawns a wmo model in the world. + +**`note`** wmo models cannot be scaled. + +#### Parameters: + +Name | Type | +:------ | :------ | +`filename` | *string* | +`pos` | [*vector\_3d*](classes/vector_3d.md) | +`rot` | [*vector\_3d*](classes/vector_3d.md) | + +**Returns:** *void* + +___ + +### append\_file + +▸ **append_file**(`file`: *string*, `content`: *string*): *void* + +Appends text to a file + +**`note`** This operation REQUIRES explicit permission from the user, +or it will throw an error. + +#### Parameters: + +Name | Type | +:------ | :------ | +`file` | *string* | +`content` | *string* | + +**Returns:** *void* + +___ + +### asin + +▸ **asin**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### asinh + +▸ **asinh**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### atan + +▸ **atan**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### atanh + +▸ **atanh**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### brush + +▸ **brush**(`name`: *string*): [*script\_brush*](classes/script_brush.md) + +Creates a new script brush + +#### Parameters: + +Name | Type | +:------ | :------ | +`name` | *string* | + +**Returns:** [*script\_brush*](classes/script_brush.md) + +___ + +### cam\_pitch + +▸ **cam_pitch**(): *number* + +Returns the cameras pitch rotation (the one you almost NEVER want) + +**Returns:** *number* + +___ + +### cam\_yaw + +▸ **cam_yaw**(): *number* + +Returns the cameras yaw rotation (the one you almost ALWAYS want) + +**Returns:** *number* + +___ + +### camera\_pos + +▸ **camera_pos**(): [*vector\_3d*](classes/vector_3d.md) + +Returns the current camera position + +**Returns:** [*vector\_3d*](classes/vector_3d.md) + +___ + +### cbrt + +▸ **cbrt**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### ceil + +▸ **ceil**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### cos + +▸ **cos**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### cosh + +▸ **cosh**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### create\_image + +▸ **create_image**(`width`: *number*, `height`: *number*): [*image*](classes/image.md) + +Creates a new blank image + +#### Parameters: + +Name | Type | +:------ | :------ | +`width` | *number* | +`height` | *number* | + +**Returns:** [*image*](classes/image.md) + +___ + +### dist\_2d + +▸ **dist_2d**(`from`: [*vector\_3d*](classes/vector_3d.md), `to`: [*vector\_3d*](classes/vector_3d.md)): *any* + +Returns the 2d distance (ignoring y) between two vectors + +#### Parameters: + +Name | Type | +:------ | :------ | +`from` | [*vector\_3d*](classes/vector_3d.md) | +`to` | [*vector\_3d*](classes/vector_3d.md) | + +**Returns:** *any* + +___ + +### dist\_2d\_compare + +▸ **dist_2d_compare**(`from`: [*vector\_3d*](classes/vector_3d.md), `to`: [*vector\_3d*](classes/vector_3d.md), `dist`: *number*): *number* + +Compares the 2d distance (ignoring y value) between two vectors to a given distance. +This operation is significantly faster than manually comparing to the result of dist_2d + +#### Parameters: + +Name | Type | +:------ | :------ | +`from` | [*vector\_3d*](classes/vector_3d.md) | +`to` | [*vector\_3d*](classes/vector_3d.md) | +`dist` | *number* | + +**Returns:** *number* + +___ + +### exp + +▸ **exp**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### floor + +▸ **floor**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### get\_area\_id + +▸ **get_area_id**(`pos`: [*vector\_3d*](classes/vector_3d.md)): *number* + +Returns the area id at a specific position. + +The 'y' value is ignored for this operation. + +#### Parameters: + +Name | Type | +:------ | :------ | +`pos` | [*vector\_3d*](classes/vector_3d.md) | + +**Returns:** *number* + +___ + +### get\_map\_id + +▸ **get_map_id**(): *number* + +Returns the id of the currently open map + +**Returns:** *number* + +___ + +### holding\_alt + +▸ **holding_alt**(): *boolean* + +Returns true if the user is currently pressing the alt key + +**Returns:** *boolean* + +___ + +### holding\_ctrl + +▸ **holding_ctrl**(): *boolean* + +Returns true if the user is currently pressing the ctrl key + +**Returns:** *boolean* + +___ + +### holding\_left\_mouse + +▸ **holding_left_mouse**(): *boolean* + +Returns true if the user is currently pressing the left mouse button + +**Returns:** *boolean* + +___ + +### holding\_right\_mouse + +▸ **holding_right_mouse**(): *boolean* + +Returns true if the user is currently pressing the right mouse button + +**Returns:** *boolean* + +___ + +### holding\_shift + +▸ **holding_shift**(): *boolean* + +Returns true if the user is currently pressing the shift key + +**Returns:** *boolean* + +___ + +### holding\_space + +▸ **holding_space**(): *boolean* + +Returns true if the user is currently pressing the spacebar + +**Returns:** *boolean* + +___ + +### lerp + +▸ **lerp**(`from`: *number*, `to`: *number*, `ratio`: *number*): *number* + +Returns the value at some percentage between two values. + +#### Parameters: + +Name | Type | Description | +:------ | :------ | :------ | +`from` | *number* | the minimum range value | +`to` | *number* | the maximum range value | +`ratio` | *number* | the percentage to take (typically between 0-1) | + +**Returns:** *number* + +___ + +### load\_png + +▸ **load_png**(`path`: *string*): [*image*](classes/image.md) + +Loads a png file into an in-memory image. + +#### Parameters: + +Name | Type | +:------ | :------ | +`path` | *string* | + +**Returns:** [*image*](classes/image.md) + +___ + +### log + +▸ **log**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### log10 + +▸ **log10**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### make\_noise + +▸ **make_noise**(`start_x`: *number*, `start_y`: *number*, `width`: *number*, `height`: *number*, `frequency`: *number*, `algorithm`: *string*, `seed`: *string*): *any* + +Creates a new noisemap + +#### Parameters: + +Name | Type | +:------ | :------ | +`start_x` | *number* | +`start_y` | *number* | +`width` | *number* | +`height` | *number* | +`frequency` | *number* | +`algorithm` | *string* | +`seed` | *string* | + +**Returns:** *any* + +___ + +### path\_exists + +▸ **path_exists**(`path`: *string*): *boolean* + +Returns true if a pathname exists already + +#### Parameters: + +Name | Type | +:------ | :------ | +`path` | *string* | + +**Returns:** *boolean* + +___ + +### pow + +▸ **pow**(`a1`: *number*, `a2`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a1` | *number* | +`a2` | *number* | + +**Returns:** *any* + +___ + +### print + +▸ **print**(): *void* + +**Returns:** *void* + +▸ **print**(...`args`: *any*[]): *any* + +Prints out a message to the script window. +(sometimes, with errors, print messages will be suppressed) + +#### Parameters: + +Name | Type | +:------ | :------ | +`...args` | *any*[] | + +**Returns:** *any* + +___ + +### random\_from\_seed + +▸ **random_from_seed**(`seed`: *string*): [*random*](classes/random.md) + +Creates a new random generator from a specific seed. + +#### Parameters: + +Name | Type | +:------ | :------ | +`seed` | *string* | + +**Returns:** [*random*](classes/random.md) + +___ + +### random\_from\_time + +▸ **random_from_time**(): [*random*](classes/random.md) + +Creates a new random generator from the current system time. + +**Returns:** [*random*](classes/random.md) + +___ + +### read\_file + +▸ **read_file**(`file`: *string*): *string* + +Reads a file from the file system. + +**`note`** This operation does NOT require explicit permission from the user. + +#### Parameters: + +Name | Type | +:------ | :------ | +`file` | *string* | + +**Returns:** *string* + +___ + +### rotate\_2d + +▸ **rotate_2d**(`point`: [*vector\_3d*](classes/vector_3d.md), `origin`: [*vector\_3d*](classes/vector_3d.md), `angle`: *number*): [*vector\_3d*](classes/vector_3d.md) + +Returns a 3d point around an origin, ignoring the y value. + +#### Parameters: + +Name | Type | +:------ | :------ | +`point` | [*vector\_3d*](classes/vector_3d.md) | +`origin` | [*vector\_3d*](classes/vector_3d.md) | +`angle` | *number* | + +**Returns:** [*vector\_3d*](classes/vector_3d.md) + +___ + +### round + +▸ **round**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### select\_between + +▸ **select_between**(`point1`: [*vector\_3d*](classes/vector_3d.md), `point2`: [*vector\_3d*](classes/vector_3d.md)): [*selection*](classes/selection.md) + +Makes and returns a rectangular selection between two points. + +#### Parameters: + +Name | Type | +:------ | :------ | +`point1` | [*vector\_3d*](classes/vector_3d.md) | +`point2` | [*vector\_3d*](classes/vector_3d.md) | + +**Returns:** [*selection*](classes/selection.md) + +___ + +### select\_origin + +▸ **select_origin**(`origin`: [*vector\_3d*](classes/vector_3d.md), `xRadius`: *number*, `zRadius`: *number*): [*selection*](classes/selection.md) + +Makes and returns a rectangular selection around an origin point + +#### Parameters: + +Name | Type | Description | +:------ | :------ | :------ | +`origin` | [*vector\_3d*](classes/vector_3d.md) | The center point of the selection | +`xRadius` | *number* | | +`zRadius` | *number* | | + +**Returns:** [*selection*](classes/selection.md) + +selection + +___ + +### sin + +▸ **sin**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### sinh + +▸ **sinh**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### sqrt + +▸ **sqrt**(`arg`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`arg` | *number* | + +**Returns:** *any* + +___ + +### tan + +▸ **tan**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### tanh + +▸ **tanh**(`a`: *number*): *any* + +#### Parameters: + +Name | Type | +:------ | :------ | +`a` | *number* | + +**Returns:** *any* + +___ + +### vec + +▸ **vec**(`x`: *number*, `y`: *number*, `z`: *number*): [*vector\_3d*](classes/vector_3d.md) + +Creates a new vector from its components + +#### Parameters: + +Name | Type | +:------ | :------ | +`x` | *number* | +`y` | *number* | +`z` | *number* | + +**Returns:** [*vector\_3d*](classes/vector_3d.md) + +___ + +### write\_file + +▸ **write_file**(`file`: *string*, `content`: *string*): *void* + +Writes text to a file + +**`note`** This operation REQUIRES explicit permission from the user, +or it will throw an error. + +#### Parameters: + +Name | Type | +:------ | :------ | +`file` | *string* | +`content` | *string* | + +**Returns:** *void* diff --git a/scripts/global.d.ts b/scripts/global.d.ts new file mode 100644 index 000000000..a008b3e89 --- /dev/null +++ b/scripts/global.d.ts @@ -0,0 +1,835 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +/** + * This is the documentation for the Noggit scripting API. + * Functions not connected to a class are global and can be called from + * anywhere in a script. + */ + +// While the language in this file is TypeScript, +// everything here applies to lua as well. + +type nil = undefined; + +/** + * Callback functions are unassigned by default, but may be assigned to + * by the user + */ +type callback = T|nil + +/** + * The type of callback used for brush events. + * + * @note In lua, the first argument becomes "self" argument if using colon notation + */ +type brush_callback = callback<((brush: script_brush, event: script_brush_event) => void)>; + +/** + * Represents a 3-dimensional vector. + * Most functions do not use the 'y' (height) value at all + */ +declare class vector_3d { + x: number; + y: number; + z: number; +} + +/** + * Represents the event context passed to brush click events. + */ +declare class script_brush_event { + /** + * Sets the outer radius in the settings panel for this brush + * @param value + */ + set_outer_radius(value: number); + + /** + * Sets the outer radius in the settings panel for this brush + * @param value - should be between 0-1 + */ + set_inner_radius(value: number); + + /** + * Returns the current outer radius configured in the settings panel + */ + outer_radius(): number; + + /** + * Returns the current inner radius configured in the settings panel + */ + inner_radius(): number; + + /** + * Returns the delta-time since the last update frame + */ + dt(): number; + + /** + * Returns world position of this click event. + * i.e. the world position where the user clicked, held or released a mouse button + */ + pos(): vector_3d; +} + + +/** + * Represents a script brush in the script window. + */ +declare class script_brush { + /** + * Changes the name of this script brush + * @param name + */ + set_name(name: string): void; + + /** + * Returns the current name of this script brush + */ + get_name(): string; + + /** + * Adds an empty tag, typically used to create empty lines in the settings panel + */ + add_null_tag(); + + /** + * Adds a description row to the brush window + * @param text + */ + add_description(text: string); + + /** + * Adds an integer tag to the settings panel + * @param item + * @param low + * @param high + * @param def + */ + add_int_tag(item: string, low: number, high: number, def: number): tag; + + /** + * Adds a real (i.e. float) tag to the settings panel + * @param item + * @param low + * @param high + * @param def + */ + add_real_tag(item: string, low: number, high: number, def: number): tag; + + /** + * Adds a string tag to the settings panel + * @param item + * @param def + */ + add_string_tag(item: string, def: string): tag; + + /** + * Adds a bool tag to the settings panel + * @param item + * @param def + */ + add_bool_tag(item: string, def: boolean): tag; + + /** + * Adds a dropdown menu to the settings panel + * @param item + * @param values + */ + add_string_list_tag(item: string, ...values: string[]): tag; + + /** + * The function to call when the user left clicks + * the world with this brush + */ + on_left_click: brush_callback; + + /** + * The funciton to call when the user holds the left mouse button + * in the world with this brush + */ + on_left_hold: brush_callback; + + /** + * The function to call when the user releases the left moues button + * in the world with this brush + */ + on_left_release: brush_callback; + + /** + * The function to call when the user right clicks + * the world with this brush + */ + on_right_click: brush_callback; + + /** + * The funciton to call when the user holds the right mouse button + * in the world with this brush + */ + on_right_hold: brush_callback; + + /** + * The function to call when the user releases the right mouse button + * in the world with this brush + */ + on_right_release: brush_callback; +} + +/** + * Creates a new script brush + * @param name + */ +declare function brush(name: string): script_brush; + + +/** + * Represents a chunk in the world + */ +declare class chunk { + /** + * Removes a texture layer from this chunk + * and decreases the texture ids of all higher layers by 1 + * @param index + */ + remove_texture(index: number): void; + + /** + * Returns the name of the texture at the specified layer. + * @param index + */ + get_texture(index: number): string; + + /** + * Returns the amount of textures on this chunk + */ + get_texture_count(): number + + /** + * Adds a new texture at the current topmost layer. + * + * @param texture + * @param effect - effect id to add + * - -2 (default): does not change effect + * - -1: clears current effect index + * - 0+: change to this effect index + * @note A chunk can hold at most 4 texture layers. + * @return texture index added to + */ + add_texture(texture: string, effect: number): number; + + /** + * Changes the effect id at a texture layer + * @param layer + * @param effect - effect id to set (-1 to remove effects) + */ + set_effect(layer: number, effect: number) + + /** + * Returns the effect id at a texture layer + * @param layer + */ + get_effect(layer: number): number + + /** + * Removes all texture layers in this chunk + */ + clear_textures(): void; + + /** + * Creates or removes a hole in this chunk + * @param hole + */ + set_hole(hole: boolean): void; + + /** + * Removes all vertex colors in this chunk + */ + clear_colors(): void; + + /** + * Applies all changes to texture alphamaps in this chunk + */ + apply_textures(): void; + + /** + * Applies all changes to the heightmap in this chunk + */ + apply_heightmap(): void; + + /** + * Applies all changes to vertex colors in this chunk + */ + apply_vertex_color(): void; + + /** + * Applies all changes in this chunk + */ + apply_all(): void; + + /** + * Sets whether this chunk should be impassable for players or not + */ + set_impassable(impassable: boolean): void; + + /** + * Returns the area id of a chunk + */ + get_area_id(): number; + + /** + * Changes the area id of a chunk + * @param value + */ + set_area_id(value: number): void; +} + +/** + * Writes text to a file + * @param file + * @param content + * + * @note This operation REQUIRES explicit permission from the user, + * or it will throw an error. + */ +declare function write_file(file: string, content: string): void; + +/** + * Appends text to a file + * @param file + * @param content + * + * @note This operation REQUIRES explicit permission from the user, + * or it will throw an error. + */ +declare function append_file(file: string, content: string): void; + +/** + * Reads a file from the file system. + * @param file + * @note This operation does NOT require explicit permission from the user. + */ +declare function read_file(file: string): string; + +/** + * Returns true if a pathname exists already + * @param path + */ +declare function path_exists(path: string): boolean; + +/** + * Creates a new vector from its components + * @param x + * @param y + * @param z + */ +declare function vec(x: number, y: number, z: number): vector_3d; + +/** + * Returns the current camera position + */ +declare function camera_pos(): vector_3d; + +/** + * Spawns an m2 model in the world. + * + * @param filename + * @param pos + * @param scale + * @param rotation + */ +declare function add_m2(filename: string + , pos: vector_3d + , scale: number + , rotation: vector_3d + ): void + +/** + * Spawns a wmo model in the world. + * + * @param filename + * @param pos + * @param rot + * + * @note wmo models cannot be scaled. + */ +declare function add_wmo( filename: string + , pos: vector_3d + , rot: vector_3d + ): void + +/** + * Returns the id of the currently open map + */ +declare function get_map_id(): number + +/** + * Returns the area id at a specific position. + * + * The 'y' value is ignored for this operation. + */ +declare function get_area_id(pos: vector_3d): number + +/** + * Returns the cameras pitch rotation (the one you almost NEVER want) + */ +declare function cam_pitch(): number + +/** + * Returns the cameras yaw rotation (the one you almost ALWAYS want) + */ +declare function cam_yaw(): number + +/** + * Returns true if the user is currently pressing the alt key + */ +declare function holding_alt(): boolean + +/** + * Returns true if the user is currently pressing the shift key + */ +declare function holding_shift(): boolean + +/** + * Returns true if the user is currently pressing the ctrl key + */ +declare function holding_ctrl(): boolean + +/** + * Returns true if the user is currently pressing the spacebar + */ +declare function holding_space(): boolean + +/** + * Returns true if the user is currently pressing the left mouse button + */ +declare function holding_left_mouse(): boolean + +/** + * Returns true if the user is currently pressing the right mouse button + */ +declare function holding_right_mouse(): boolean + +/** + * Prints out a message to the script window. + * (sometimes, with errors, print messages will be suppressed) + * @param args + */ +declare function print(...args: any[]) + +/** + * Represents a bitmap image + * + * images can be created from create_image or load_png + */ +declare class image { + /** + * Returns the pixel value at a coordinate + * @param x + * @param y + */ + get_pixel(x: number, y: number): number; + + /** + * Returns the blue channel (between 0-1) at an image coordinate + * @param x + * @param y + */ + get_blue(x: number, y: number): number; + + /** + * Returns the alpha channel (between 0-1) at an image coordinate + * @param x + * @param y + */ + get_alpha(x: number, y: number): number; + + /** + * Returns the red channel (between 0-1) at an image coordinate + * @param x + * @param y + */ + get_red(x: number, y: number): number; + + /** + * Returns the green channel (between 0-1) at an image coordinate + * @param x + * @param y + */ + get_green(x: number, y: number): number; + + /** + * Returns the pixel value at a relative horizontal coordinate + * @param rel horizontal relative position (between 0-1) + */ + gradient_scale(rel: number): number; + + /** + * Sets the pixel value at an image coordinate + * @param x + * @param y + * @param value + */ + set_pixel(x: number, y: number, value: number): void; + + /** + * Sets the pixel value at an image coordinate + * @param x + * @param y + * @param r - should be between 0-1 + * @param g - should be between 0-1 + * @param b - should be between 0-1 + * @param a - should be between 0-1 + */ + set_pixel_floats(x: number, y: number, r: number, g: number, b: number, a: number): void; + + /** + * Saves this image to a file + * @param filename + */ + save(filename: string); + + /** + * Returns the width of this image + */ + width(): number; + + /** + * Returns the height of this image + */ + height(): number; +} + +/** + * Creates a new blank image + * @param width + * @param height + */ +declare function create_image(width: number, height: number): image; + +/** + * Loads a png file into an in-memory image. + * @param path + */ +declare function load_png(path: string): image; + +declare function round(a: number); +declare function pow(a1: number, a2: number) +declare function log10(a: number); +declare function log(a: number); +declare function ceil(a: number); +declare function floor(a: number); +declare function exp(a: number); +declare function cbrt(a: number); +declare function acosh(a: number); +declare function asinh(a: number); +declare function atanh(a: number); +declare function cosh(a: number); +declare function sinh(a: number); +declare function tanh(a: number); +declare function acos(a: number); +declare function asin(a: number); +declare function atan(a: number); + +declare function cos(a: number); +declare function sin(a: number); +declare function tan(a: number); +declare function sqrt(arg: number); +declare function abs(arg: number); + +/** + * Returns the value at some percentage between two values. + * + * @param from - the minimum range value + * @param to - the maximum range value + * @param ratio - the percentage to take (typically between 0-1) + */ +declare function lerp(from: number, to: number, ratio: number): number; + +/** + * Returns the 2d distance (ignoring y) between two vectors + * @param from + * @param to + */ +declare function dist_2d(from: vector_3d, to: vector_3d); + +/** + * Compares the 2d distance (ignoring y value) between two vectors to a given distance. + * This operation is significantly faster than manually comparing to the result of dist_2d + * + * @param from + * @param to + * @param dist + */ +declare function dist_2d_compare(from: vector_3d, to:vector_3d, dist: number): number + +/** + * Returns a 3d point around an origin, ignoring the y value. + * @param point + * @param origin + * @param angle + */ +declare function rotate_2d(point: vector_3d, origin: vector_3d, angle: number): vector_3d + +/** + * Represents a model in the world. Can represent both an m2 and wmo model. + */ +declare class model { + get_pos(): vector_3d; + set_pos(pos: vector_3d): void; + get_rot(): vector_3d; + set_rot(pos: vector_3d): void; + get_scale(): number; + set_scale(scale: number): void; + get_uid(): number; + remove(): void; + get_filename(): string; + has_filename(name: string): boolean; + replace(filename: string); +} + +/** + * Represents a map of floats values, typically use with a + * noise generator. + */ +declare class noisemap { + /** + * Returns the float value at a specific 3d position. + * @param pos + * @note The 'y' value of pos is ignored by this operation. + */ + get(pos: vector_3d): number; + + /** + * Returns true if the float value at a 3d position + * is the highest position within a given range. + * + * This is typically used for object placement. + * + * @param pos + * @param check_radius + */ + is_highest(pos: vector_3d, check_radius: number): boolean + set(x: number, y: number, value: number): void; + width(): number; + height(): number; +} + +/** + * Creates a new noisemap + * @param start_x + * @param start_y + * @param width + * @param height + * @param frequency + * @param algorithm + * @param seed + */ +declare function make_noise(start_x: number, start_y: number, width: number, height: number, frequency: number, algorithm: string, seed: string) + +/** + * Represents a random generator and its state. + */ +declare class random { + integer(low: number, high: number): number; + real(low: number, high: number): number; +} + +/** + * Creates a new random generator from a specific seed. + * @param seed + */ +declare function random_from_seed(seed: string): random; + +/** + * Creates a new random generator from the current system time. + */ +declare function random_from_time(): random; + +/** + * Represents a rectangular selection in the world and provides + * iterators for heightmap vertices, texture units, chunks and models within it. + */ +declare class selection { + /** + * Creates a noisemap matching the location of this selection + * + * @param frequency + * @param algorithm + * @param seed + */ + make_noise(frequency: number, algorithm: string, seed: string): noisemap + + /** + * Returns the center point of this selection + */ + center(): vector_3d; + + /** + * Returns the smallest point of this selection + */ + min(): vector_3d; + + /** + * Returns the highest point of this selection + */ + max(): vector_3d; + + /** + * Returns a vector representing the size of this selection on each axis. + * @note for iterators, only x and z values are respected. y (height) is ignored. + */ + size(): vector_3d; + + /** + * Creates and returns an iterator for all models inside this selection + */ + models(): model[]; + + /** + * Creates and returns an iterator for all vertices inside this selection + */ + verts(): vert[]; + + /** + * Creates and returns an iterator for all texture units inside this selection + */ + tex(): tex[]; + + /** + * Creates and returns an iterator for all chunks inside this selection + */ + chunks(): chunk[]; + + /** + * Applies all changes made inside this selection. + * You almost always want to call this function when you're done + * with a selection. + */ + apply(): void; +} + +/** + * Makes and returns a rectangular selection between two points. + * @param point1 + * @param point2 + */ +declare function select_between(point1: vector_3d, point2: vector_3d): selection; + +/** + * Makes and returns a rectangular selection around an origin point + * + * @param origin - The center point of the selection + * @param xRadius + * @param zRadius + * @returns selection + */ +declare function select_origin(origin: vector_3d, xRadius: number, zRadius: number): selection; + +/** + * Represents a settings tag that can be accessed at any time by a script. + */ +declare class tag { + /** + * Returns the current value of this tag in the settings panel. + */ + get(): T; +} + +/** + * Represents a single texture unit in the worlds texture layers. + * + * A texture unit represents the smallest area where it's possible to + * affect textures alpha layers. This is much smaller than the areas made + * up by heightmap vertices. + */ +declare class tex { + set_alpha(index: number, alpha: number): void; + get_alpha(index: number): number; + get_pos_2d(): vector_3d; +} + +/** + * Represents a single heightmap vertex in the world. + * + * Changes to this vertex takes visible effect in Noggit after you call + * "apply" on the chunk or selection that contains it. + */ +declare class vert { + /** + * Returns the full position of this vertex + */ + get_pos(): vector_3d; + + /** + * Changes the height of this vertex + */ + set_height(y: number); + add_height(y: number); + sub_height(y: number); + + /** + * Changes the vertex color that this vertex blends with the + * underlying texture. Values generally range between 0-1, but can + * also go higher. + * + * @param red - How much red should be used (default: 1) + * @param green - How much green should be used (default: 1) + * @param blue - How much blue should be used (default: 1) + */ + set_color(red: number, green: number, blue: number): void; + + /** + * Changes the water type on this vertex, but only if the vertex is + * aligned with water tiles. If the vertex is not aligned + * with a water tile, this function does nothing. + * + * @param type + * @param height + * + * @note The C++ function backing this operation is very slow for the moment. + * use with care. + */ + set_water(type: number, height: number): void; + + /** + * Sets whether this vertex should be a hole, but only if the + * vertex is aligned with hole tiles. If the vertex is not aligned + * with a hole tile, this function does nothing. + * + * @param has_hole + */ + set_hole(has_hole: boolean): void; + + /** + * Sets a texture alpha layer of all texture units closest to this vertex. + * + * @param index + * @param alpha + */ + set_alpha(index: number, alpha: number): void; + + /** + * Returns the average alpha of all texture units closest to this vertex. + * @param index + */ + get_alpha(index: number); + + /** + * Returns true if this vertex is aligned with water tiles. + */ + is_water_aligned(): boolean; +} + +/** + * Contains some general-purpose procedures that don't fit anywhere else. + * + * Access these functions through the global singleton "procedures". + */ +declare class procedures_class { + paint_texture(sel: selection, img: image, layer: number, pressure: number, angle: number); +} + +/** + * singleton + */ +declare const procedures: procedures_class; \ No newline at end of file diff --git a/scripts/height_noise.lua b/scripts/height_noise.lua new file mode 100644 index 000000000..53f2577a0 --- /dev/null +++ b/scripts/height_noise.lua @@ -0,0 +1,27 @@ +-- This file is part of Noggit3, licensed under GNU General Public License (version 3). +local noise_brush = brush("Height Noise") + +local algo = noise_brush:add_string_tag("Algorithm","HgANAAUAAAAAAABAEAAAAAA/CAAAAACAPwAAAAA/AAAAAAABEwBI4RpAGwANAAMAAAAAAABACAAAAAAAPwAAAAAAAI/C9Tw=") +local seed = noise_brush:add_string_tag("Seed","noggit") +local frequency = noise_brush:add_real_tag("Frequency",0.0005,1.0,0.001,5) +local amplitude = noise_brush:add_real_tag("Amplitude",1.0,1000.0,410.0,2) + +function noise_brush:on_left_hold(evt) + local sel = select_origin( + evt:pos(), + evt:outer_radius(), + evt:outer_radius() + ) + local map = sel:make_noise( + frequency:get(), + algo:get(), + seed:get() + ) + for i,vert in pairs(sel:verts()) do + local height = map:get( + vert:get_pos() + ) * amplitude:get() + vert:set_height(height) + end + sel:apply() +end \ No newline at end of file diff --git a/scripts/image_brush.lua b/scripts/image_brush.lua new file mode 100644 index 000000000..d9d159b3a --- /dev/null +++ b/scripts/image_brush.lua @@ -0,0 +1,38 @@ +-- This file is part of Noggit3, licensed under GNU General Public License (version 3). +local painter_brush = brush("Image Painter") +local image_path = painter_brush:add_string_tag("Filename", "") + +function painter_brush:on_left_click(evt) + local img = load_png( + image_path:get() + ) + local origin = evt:pos() + local width = img:width() + local height = img:height() + local half_width = width / 2 + local half_height = height / 2 + local sel = select_origin(origin, width, height) + + for i,vert in pairs(sel:verts()) do + local angle = cam_yaw() - 90 + local pos = rotate_2d( + vert:get_pos(), + origin, + angle + ) + local local_x = round((pos.x - origin.x) + half_width) + local local_z = round((pos.z - origin.z) + half_height) + + if local_x >= 0 + and local_x < width + and local_z >= 0 + and local_z < height + and img:get_alpha(local_x,local_z)>0.5 then + local red = img:get_red(local_x, local_z) + local green = img:get_green(local_x, local_z) + local blue = img:get_blue(local_x, local_z) + vert:set_color(red, green, blue) + end + end + sel:apply() +end \ No newline at end of file diff --git a/scripts/prop_placer.lua b/scripts/prop_placer.lua new file mode 100644 index 000000000..7151c8166 --- /dev/null +++ b/scripts/prop_placer.lua @@ -0,0 +1,88 @@ +-- This file is part of Noggit3, licensed under GNU General Public License (version 3). +local prop_placer = brush("Prop Placer") + +local seed = prop_placer:add_string_tag("Seed","noggit") +local dist = prop_placer:add_int_tag("Distance",1,50,5) +local delete_all = prop_placer:add_bool_tag("Delete all models",false) +local circle_brush = prop_placer:add_bool_tag("Circle brush",false) + +function Prop(index) + local prop = {} + + prop.model_name = prop_placer:add_string_tag("Prop "..index) + prop.min_scale = prop_placer:add_real_tag("Prop "..index.." Min Scale",0.001,10,0.7,2) + prop.max_scale = prop_placer:add_real_tag("Prop "..index.." Max Scale",0.001,10,0.7,2) + + return prop +end + +prop_placer:add_null_tag() +local prop1 = Prop(1); +prop_placer:add_null_tag(); +local prop2 = Prop(2); +prop_placer:add_null_tag(); +local prop3 = Prop(3); + +local props = {prop1,prop2,prop3} + +function prop_placer:on_left_hold(evt) + local cur_props = {} + local count = 0 + for _,v in pairs(props) do + if string.len(v.model_name:get())>0 then + table.insert(cur_props,v) + count = count + 1 + end + end + + if count == 0 then + print("No models selected") + return + end + + local sel = select_origin(evt:pos(),evt:outer_radius(),evt:outer_radius()) + for _,v in pairs(cur_props) do + + for i,model in pairs(sel:models()) do + if( + (delete_all:get() or model:has_filename(v)) + and + ((not circle_brush:get()) + or dist_2d( + model:get_pos() + , evt:pos()) < evt:outer_radius()) + ) then + model:remove() + end + end + end + + local map = make_noise( + sel:min().x-dist:get() + , sel:min().z-dist:get() + , sel:size().x+2*dist:get() + , sel:size().z+2*dist:get() + , 1 + , "SIMPLEX" + , seed:get() + ) + + for i,vert in pairs(sel:verts()) do + if (not circle_brush:get()) or dist_2d( + vert:get_pos(), + evt:pos() + ) < evt:outer_radius() then + local loc = vert:get_pos() + if map:is_highest(loc,dist:get()) then + local rnd = random_from_seed(seed:get().." "..loc.x.." "..loc.z) + local index = rnd:integer(1,count+1) + local prop = cur_props[index] + local size = rnd:real(prop.min_scale:get(),prop.max_scale:get()) + local rot = rnd:real(0,360.0) + add_m2(prop.model_name:get(),loc,size,vec(0,rot,0)) + end + end + end + + sel:apply() +end \ No newline at end of file diff --git a/scripts/texture_brush.lua b/scripts/texture_brush.lua new file mode 100644 index 000000000..21061a099 --- /dev/null +++ b/scripts/texture_brush.lua @@ -0,0 +1,23 @@ +local texture_brush = brush("Texture Brush") +texture_brush:add_description("Description:") +texture_brush:add_description("- Uses a black / white texture to paint alpha layers. ") +texture_brush:add_description("- The painting is only additive at the moment,") +texture_brush:add_description(" meaning it cannot paint layers from \"underneath\"") +texture_brush:add_description(" another layer.") + +local texture = texture_brush:add_string_tag("Brush Texture", "") +local pressure = texture_brush:add_real_tag("Pressure", 0, 1000, 1, 2) +local index = texture_brush:add_int_tag("Texture Index", 1, 3, 1) + +texture_brush.on_left_hold = function(brush, evt) + local image = load_png( + texture:get() + ) + local sel = select_origin( + evt:pos(), + evt:outer_radius(), + evt:outer_radius() + ) + procedures:paint_texture(sel,image,index:get(),pressure:get(),cam_yaw()-90) + sel:apply() +end \ No newline at end of file diff --git a/scripts/texture_printer.lua b/scripts/texture_printer.lua new file mode 100644 index 000000000..951f816a9 --- /dev/null +++ b/scripts/texture_printer.lua @@ -0,0 +1,26 @@ +local texture_printer = brush("Texture Printer"); + +texture_printer:add_description("Description:") +texture_printer:add_description("Prints out texture paths and effect ids ") +texture_printer:add_description("in the clicked chunk.") +texture_printer:add_null_tag() + +function texture_printer:on_left_click(evt) + local sel = select_origin(evt:pos(), 1, 1) + + for i,chunk in pairs(sel:chunks()) do + if chunk:get_texture_count() == 0 then + print("Chunk has no textures") + end + + print("== Chunk Textures ==") + for i=0,chunk:get_texture_count()-1 do + local tex = chunk:get_texture(i) + local eff = chunk:get_effect(i) + print("Layer "..i..":") + print(" Texture: "..tex) + print(" Effect: "..eff) + end + print("") + end +end \ No newline at end of file diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json new file mode 100644 index 000000000..e5f132ba2 --- /dev/null +++ b/scripts/tsconfig.json @@ -0,0 +1,21 @@ +/** + * This file has a working configuration to write + * script brushes with TypeScriptToLua + * (https://github.com/TypeScriptToLua/TypeScriptToLua) + */ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "./_tsbuild", + "forceConsistentCasingInFileNames": true + }, + "tstl": { + "luaTarget": "5.1", + "luaPlugins": [], + "noImplicitSelf": true, + } +} diff --git a/src/math/trig.hpp b/src/math/trig.hpp index dbf64d620..5e337f7f6 100644 --- a/src/math/trig.hpp +++ b/src/math/trig.hpp @@ -54,6 +54,8 @@ namespace math return os << v._ << "°"; } + explicit operator float() const { return _; } + using vec3 = vector_3d_base; }; diff --git a/src/math/vector_3d.hpp b/src/math/vector_3d.hpp index 788ddd845..eeb7c351b 100644 --- a/src/math/vector_3d.hpp +++ b/src/math/vector_3d.hpp @@ -32,6 +32,13 @@ namespace math , z (z_) {} + template + explicit vector_3d_base (vector_3d_base const& other) + : x (other.x) + , y (other.y) + , z (other.z) + {} + inline static vector_3d_base min() { return {std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()}; diff --git a/src/noggit/MapChunk.cpp b/src/noggit/MapChunk.cpp index c40ba330d..97c51a3fa 100644 --- a/src/noggit/MapChunk.cpp +++ b/src/noggit/MapChunk.cpp @@ -821,6 +821,20 @@ bool MapChunk::changeTerrain(math::vector_3d const& pos, float change, float rad return changed; } +bool MapChunk::hasColors() +{ + return hasMCCV; +} + +void MapChunk::maybe_create_mccv() +{ + if (!hasMCCV) + { + std::fill (mccv, mccv + mapbufsize, math::vector_3d (1.f, 1.f, 1.f)); + hasMCCV = true; + } +} + bool MapChunk::ChangeMCCV(math::vector_3d const& pos, math::vector_4d const& color, float change, float radius, bool editMode) { float dist; @@ -875,6 +889,15 @@ bool MapChunk::ChangeMCCV(math::vector_3d const& pos, math::vector_4d const& col return changed; } +void MapChunk::UpdateMCCV() +{ + if(_uploaded) + { + gl.bufferData (_mccv_vbo, sizeof(mccv), mccv, GL_STATIC_DRAW); + _need_vao_update = true; + } +} + math::vector_3d MapChunk::pickMCCV(math::vector_3d const& pos) { float dist; @@ -1496,6 +1519,20 @@ void MapChunk::selectVertex(math::vector_3d const& pos, float radius, std::set& vertices) +{ + for(int i = 0; i< mapbufsize; ++i) + { + if( + pos1.x<=mVertices[i].x && pos2.x>=mVertices[i].x && + pos1.z<=mVertices[i].z && pos2.z>=mVertices[i].z + ) + { + vertices.emplace(&mVertices[i]); + } + } +} + void MapChunk::fixVertices(std::set& selected) { std::vector ids ={ 0, 1, 17, 18 }; diff --git a/src/noggit/MapChunk.h b/src/noggit/MapChunk.h index 851fe9108..7baa3f6c0 100644 --- a/src/noggit/MapChunk.h +++ b/src/noggit/MapChunk.h @@ -52,8 +52,6 @@ class MapChunk std::vector strip_without_holes; std::map> strip_lods; - math::vector_3d mccv[mapbufsize]; - std::vector compressed_shadow_map() const; bool shadow_map_is_empty() const; @@ -106,6 +104,7 @@ class MapChunk math::vector_3d mNormals[mapbufsize]; math::vector_3d mVertices[mapbufsize]; + math::vector_3d mccv[mapbufsize]; bool is_visible ( const float& cull_distance , const math::frustum& frustum @@ -147,6 +146,10 @@ class MapChunk void intersect (math::ray const&, selection_result*); bool ChangeMCCV(math::vector_3d const& pos, math::vector_4d const& color, float change, float radius, bool editMode); + //! Initialize MCCV to 1,1,1, do nothing if already exists. + void maybe_create_mccv(); + void UpdateMCCV(); + bool hasColors(); math::vector_3d pickMCCV(math::vector_3d const& pos); ChunkWater* liquid_chunk() const; @@ -200,4 +203,6 @@ class MapChunk bool fixGapLeft(const MapChunk* chunk); // fix the gaps with the chunk above bool fixGapAbove(const MapChunk* chunk); + + void selectVertex(math::vector_3d const& minPos, math::vector_3d const& maxPos, std::set& vertices); }; diff --git a/src/noggit/MapView.cpp b/src/noggit/MapView.cpp index 67b58507e..45e801b42 100644 --- a/src/noggit/MapView.cpp +++ b/src/noggit/MapView.cpp @@ -34,6 +34,10 @@ #include #include #include +#ifdef NOGGIT_HAS_SCRIPTING +#include +#include +#endif #include #include "revision.h" @@ -49,6 +53,7 @@ #include #include #include +#include #include #include @@ -120,9 +125,11 @@ void MapView::setToolPropertyWidgetVisibility(editing_mode mode) case editing_mode::object: _object_editor_dock->setVisible(!ui_hidden); break; +#ifdef NOGGIT_HAS_SCRIPTING + case editing_mode::scripting: + _script_tool_dock->setVisible(!ui_hidden); +#endif } - - } void MapView::ResetSelectedObjectRotation() @@ -185,7 +192,12 @@ QWidgetAction* MapView::createTextSeparator(const QString& text) void MapView::createGUI() { - // create tool widgets +#ifdef NOGGIT_HAS_SCRIPTING + _script_tool_dock = new QDockWidget("Scripting", this); + scriptingTool = new noggit::scripting::scripting_tool(_script_tool_dock, this, this->_settings); + _script_tool_dock->setWidget(scriptingTool); + _tool_properties_docks.insert(_script_tool_dock); +#endif _terrain_tool_dock = new QDockWidget("Raise / Lower", this); terrainTool = new noggit::ui::terrain_tool(_terrain_tool_dock); @@ -498,8 +510,6 @@ void MapView::createGUI() } \ while (false) - - ADD_ACTION (file_menu, "Save current tile", "Ctrl+Shift+S", [this] { save(save_mode::current); }); ADD_ACTION (file_menu, "Save changed tiles", QKeySequence::Save, [this] { save(save_mode::changed); }); ADD_ACTION (file_menu, "Save all tiles", "Ctrl+Shift+A", [this] { save(save_mode::all); }); @@ -1304,6 +1314,7 @@ MapView::MapView( math::degrees camera_yaw0 , bool from_bookmark ) : _camera (camera_pos, camera_yaw0, camera_pitch0) + , _world (std::move (world)) , mTimespeed(0.0f) , _uid_fix (uid_fix) , _from_bookmark (from_bookmark) @@ -1312,7 +1323,6 @@ MapView::MapView( math::degrees camera_yaw0 , shader_color (1.f, 1.f, 1.f, 1.f) , cursor_type (static_cast(cursor_mode::terrain)) , _main_window (main_window) - , _world (std::move (world)) , _status_position (new QLabel (this)) , _status_selection (new QLabel (this)) , _status_area (new QLabel (this)) @@ -1526,13 +1536,13 @@ void MapView::paintGL() _last_frame_durations.emplace_back (now - _last_update); - tick (now - _last_update); - _last_update = now; - gl.clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_map(); + tick (now - _last_update); + _last_update = now; + if (_world->uid_duplicates_found() && !_uid_duplicate_warning_shown) { _uid_duplicate_warning_shown = true; @@ -1812,6 +1822,13 @@ void MapView::tick (float dt) for (auto& selection : currentSelection) { +#ifdef NOGGIT_HAS_SCRIPTING + if (selection.which() == eEntry_MapChunk && terrainMode == editing_mode::scripting) + { + scriptingTool->sendBrushEvent(_cursor_pos, 7.5f * dt); + } +#endif + if (leftMouse && selection.which() == eEntry_MapChunk) { bool underMap = _world->isUnderMap(_cursor_pos); @@ -2390,6 +2407,12 @@ void MapView::draw_map() case editing_mode::mccv: radius = shaderTool->brushRadius(); break; +#ifdef NOGGIT_HAS_SCRIPTING + case editing_mode::scripting: + radius = scriptingTool->get_settings()->brushRadius(); + inner_radius = scriptingTool->get_settings()->innerRadius(); + break; +#endif } //! \note Select terrain below mouse, if no item selected or the item is map. diff --git a/src/noggit/MapView.h b/src/noggit/MapView.h index 497453544..092a05da4 100644 --- a/src/noggit/MapView.h +++ b/src/noggit/MapView.h @@ -51,6 +51,12 @@ namespace noggit struct main_window; struct tileset_chooser; } +#ifdef NOGGIT_HAS_SCRIPTING + namespace scripting + { + class scripting_tool; + } +#endif } enum class save_mode @@ -63,12 +69,19 @@ enum class save_mode class MapView : public QOpenGLWidget { Q_OBJECT -private: +public: + /// \todo getters? bool _mod_alt_down = false; bool _mod_ctrl_down = false; bool _mod_shift_down = false; bool _mod_space_down = false; bool _mod_num_down = false; + bool leftMouse = false; + bool leftClicked = false; + bool rightMouse = false; + noggit::camera _camera; + std::unique_ptr _world; +private: float _2d_zoom = 1.f; float moving, strafing, updown, mousedir, turn, lookat; @@ -77,7 +90,6 @@ class MapView : public QOpenGLWidget bool look, freelook; bool ui_hidden = false; - noggit::camera _camera; bool _camera_moved_since_last_draw = true; noggit::bool_toggle_property _draw_contour = {false}; @@ -136,10 +148,6 @@ class MapView : public QOpenGLWidget bool _rotation_editor_need_update = false; - bool leftMouse = false; - bool leftClicked = false; - bool rightMouse = false; - // Vars for the ground editing toggle mode store the status of some // view settings when the ground editing mode is switched on to // restore them if switch back again @@ -249,8 +257,6 @@ public slots: math::vector_4d normalized_device_coords (int x, int y) const; float aspect_ratio() const; - std::unique_ptr _world; - float _tablet_pressure; bool _tablet_active = false; @@ -312,4 +318,8 @@ public slots: QDockWidget* _vertex_shading_dock; noggit::ui::texturing_tool* texturingTool; QDockWidget* _texturing_dock; +#ifdef NOGGIT_HAS_SCRIPTING + noggit::scripting::scripting_tool* scriptingTool; + QDockWidget* _script_tool_dock; +#endif }; diff --git a/src/noggit/World.cpp b/src/noggit/World.cpp index 4162ac75c..902f9ab76 100644 --- a/src/noggit/World.cpp +++ b/src/noggit/World.cpp @@ -2322,6 +2322,61 @@ void World::delete_models(std::vector const& types) need_model_updates = true; } +void World::selectVertices(math::vector_3d const& pos1, math::vector_3d const& pos2) +{ + math::vector_3d pos_min = math::vector_3d(std::min(pos1.x,pos2.x),std::min(pos1.y,pos2.y),std::min(pos1.z,pos2.z)); + math::vector_3d pos_max = math::vector_3d(std::max(pos1.x,pos2.x),std::max(pos1.y,pos2.y),std::max(pos1.z,pos2.z)); + _vertex_center_updated = false; + _vertex_border_updated = false; + + for_all_chunks_between(pos_min, pos_max, [&](MapChunk* chunk){ + _vertex_chunks.emplace(chunk); + _vertex_tiles.emplace(chunk->mt); + chunk->selectVertex(pos_min, pos_max, _vertices_selected); + return true; + }); +} + +void World::select_all_chunks_between(math::vector_3d const& pos1, math::vector_3d const& pos2, std::vector& chunks_in) +{ + math::vector_3d pos_min = math::vector_3d(std::min(pos1.x,pos2.x),std::min(pos1.y,pos2.y),std::min(pos1.z,pos2.z)); + math::vector_3d pos_max = math::vector_3d(std::max(pos1.x,pos2.x),std::max(pos1.y,pos2.y),std::max(pos1.z,pos2.z)); + + for_all_chunks_between(pos_min, pos_max, [&](MapChunk* chunk){ + chunks_in.push_back(chunk); + return true; + }); +} + +std::set* World::getSelectedVertices() +{ + return &_vertices_selected; +} + +template +bool World::for_all_chunks_between (math::vector_3d const& pos1, math::vector_3d const& pos2,Fun&& fun) +{ + bool changed (false); + + for (MapTile* tile : mapIndex.tiles_between (pos1, pos2)) + { + if (!tile->finishedLoading()) + { + continue; + } + + for (MapChunk* chunk : tile->chunks_between(pos1, pos2)) + { + if (fun (chunk)) + { + changed = true; + mapIndex.setChanged (tile); + } + } + } + return changed; +} + bool World::deselectVertices(math::vector_3d const& pos, float radius) { _vertex_center_updated = false; diff --git a/src/noggit/World.h b/src/noggit/World.h index f54b24074..c25382c02 100644 --- a/src/noggit/World.h +++ b/src/noggit/World.h @@ -304,6 +304,16 @@ class World bool deselectVertices(math::vector_3d const& pos, float radius); void selectVertices(math::vector_3d const& pos, float radius); void delete_models(std::vector const& types); + void selectVertices(math::vector_3d const& pos1, math::vector_3d const& pos2); + std::set* getSelectedVertices(); + + template + bool for_all_chunks_between ( math::vector_3d const& pos1, + math::vector_3d const& pos2, + Fun&& /* MapChunk* -> bool changed */ + ); + + void select_all_chunks_between(math::vector_3d const& pos1, math::vector_3d const& pos2, std::vector& chunks_in); template void for_each_wmo_instance(Fun&& function) diff --git a/src/noggit/map_index.cpp b/src/noggit/map_index.cpp index c0182453f..348bc4e33 100644 --- a/src/noggit/map_index.cpp +++ b/src/noggit/map_index.cpp @@ -590,7 +590,7 @@ uint32_t MapIndex::newGUID() if (settings->value ("project/mysql/enabled", false).toBool()) { - mysql::updateUIDinDB(_map_id, highestGUID + 1); // update the highest uid in db, note that if the user don't save these uid won't be used (not really a problem tho) + mysql::updateUIDinDB(_map_id, highestGUID + 1); // update the highest uid in db, note that if the user don't save these uid won't be used (not really a problem tho) } #endif return ++highestGUID; diff --git a/src/noggit/scripting/script_brush.cpp b/src/noggit/scripting/script_brush.cpp new file mode 100644 index 000000000..2f004f415 --- /dev/null +++ b/src/noggit/scripting/script_brush.cpp @@ -0,0 +1,183 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include +#include + +#include +#include + +namespace noggit { + namespace scripting { + script_brush_event::script_brush_event( + script_settings * settings + , math::vector_3d const& pos + , float dt) + : _settings(settings) + , _pos(pos) + , _dt(dt) + {} + + math::vector_3d script_brush_event::pos() + { + return _pos; + } + + float script_brush_event::outer_radius() + { + return _settings->brushRadius(); + } + + float script_brush_event::inner_radius() + { + return _settings->innerRadius(); + } + + void script_brush_event::set_outer_radius(float radius) + { + _settings->setOuterRadius(radius); + } + + void script_brush_event::set_inner_radius(float radius) + { + _settings->setInnerRadius(radius); + } + + float script_brush_event::dt() + { + return _dt; + } + + script_brush::script_brush( + script_context * state + , std::string const& name) + : script_object(state) + , _name(name) + {}; + + void script_brush::set_name(std::string const& name) + { + _name = name; + } + + std::string script_brush::get_name() + { + return _name; + } + + std::shared_ptr script_brush::add_int_tag( + std::string const& item + , int low + , int high + , int def + , bool has_slider + ){ + auto tag = std::make_shared(state(), _name, item, low, high, def, has_slider); + _tags.push_back(tag); + return tag; + } + + void script_brush::add_null_tag() + { + add_description(""); + } + + void script_brush::add_description(std::string const& text) + { + _tags.push_back(std::make_shared(state(),_name,"__null"+std::to_string(_tags.size()),text)); + } + + std::shared_ptr script_brush::add_real_tag( + std::string const& item + , double low + , double high + , double def + , int zeros + , bool has_slider + ){ + auto tag = std::make_shared(state(), _name, item, low, high, def, zeros, has_slider); + _tags.push_back(tag); + return tag; + } + + std::shared_ptr script_brush::add_string_tag( + std::string const& item + , std::string const& def) + { + auto tag = std::make_shared(state(),_name, item, def); + _tags.push_back(tag); + return tag; + } + + std::shared_ptr script_brush::add_string_list_tag( + std::string const& item + , sol::variadic_args va) + { + std::vector vec; + for(auto v : va) + { + vec.push_back(v); + } + auto tag = std::make_shared(state(),_name, item, vec); + _tags.push_back(tag); + return tag; + } + + std::shared_ptr script_brush::add_bool_tag( + std::string const& item + , bool def + ) { + auto tag = std::make_shared(state(),_name,item,def); + _tags.push_back(tag); + return tag; + } + + void script_brush::on_selected() + { + for(auto tag : _tags) + { + tag->add_to_settings(); + } + } + + void register_script_brush(script_context * state) + { + state->new_usertype("script_brush_event" + ,"pos",&script_brush_event::pos + ,"set_outer_radius",&script_brush_event::set_outer_radius + ,"set_inner_radius",&script_brush_event::set_inner_radius + ,"outer_radius",&script_brush_event::outer_radius + ,"inner_radius",&script_brush_event::inner_radius + ,"dt",&script_brush_event::dt + ); + + state->new_usertype("script_brush" + , sol::meta_function::new_index, &script_brush::set + , sol::meta_function::index, &script_brush::get + ,"get_name",&script_brush::get_name + ,"add_int_tag",sol::overload( + &script_brush::add_int_tag + , &script_brush::add_int_tag_1 + , &script_brush::add_int_tag_2 + ) + ,"add_bool_tag",sol::overload( + &script_brush::add_bool_tag + , &script_brush::add_bool_tag_1 + ) + ,"add_real_tag", sol::overload( + &script_brush::add_real_tag + , &script_brush::add_real_tag_1 + , &script_brush::add_real_tag_2 + ) + ,"add_string_tag", sol::overload( + &script_brush::add_string_tag + , &script_brush::add_string_tag_1 + ) + ,"add_string_list_tag",&script_brush::add_string_list_tag + ,"add_null_tag",&script_brush::add_null_tag + ,"add_description",&script_brush::add_description + ); + } + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_brush.hpp b/src/noggit/scripting/script_brush.hpp new file mode 100644 index 000000000..7af60eae3 --- /dev/null +++ b/src/noggit/scripting/script_brush.hpp @@ -0,0 +1,144 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include +#include + +#include + +#include +#include + +namespace noggit { + namespace scripting { + class scripting_tool; + class script_settings; + class bool_tag; + class int_tag; + class real_tag; + class string_tag; + class string_list_tag; + class tag; + class script_context; + + enum class brush_event_type + { + CLICK, + HOLD, + RELEASE + }; + + class script_brush_event + { + public: + script_brush_event( script_settings * settings + , math::vector_3d const& pos + , float dt); + math::vector_3d pos(); + float outer_radius(); + float inner_radius(); + + void set_outer_radius(float radius); + void set_inner_radius(float radius); + + float dt(); + private: + script_settings * _settings; + math::vector_3d _pos; + float _dt; + }; + + class script_brush: public script_object { + public: + script_brush(script_context * state, std::string const& name); + void set_name(std::string const& name); + std::string get_name(); + void on_selected(); + + std::shared_ptr add_int_tag( + std::string const& item + , int low + , int high + , int def /* = low */ + , bool has_slider /* = false */ + ); + std::shared_ptr add_int_tag_1( + std::string const& item + , int low + , int high + , int def + ) { return add_int_tag(item,low,high,def, false);} + std::shared_ptr add_int_tag_2( + std::string const& item + , int low + , int high + ) { return add_int_tag_1(item,low,high,low);} + + std::shared_ptr add_real_tag( + std::string const& item + , double low + , double high + , double def + , int zeros /* = 5 */ + , bool has_slider /* = false */ + ); + std::shared_ptr add_real_tag_1( + std::string const& item + , double low + , double high + , double def + , int zeros + ) + { return add_real_tag(item,low,high,def,zeros, false); } + std::shared_ptr add_real_tag_2( + std::string const& item + , double low + , double high + , double def + ) + { return add_real_tag_1(item,low,high,def,5); } + + std::shared_ptr add_string_tag( + std::string const& item + , std::string const& def /* = "" */ + ); + std::shared_ptr add_string_tag_1( + std::string const& item) + { return add_string_tag(item,"");} + + std::shared_ptr add_string_list_tag( + std::string const& item + , sol::variadic_args va); + + std::shared_ptr add_bool_tag( + std::string const& item + , bool def /* = false */ + ); + std::shared_ptr add_bool_tag_1( + std::string const& item + ) { return add_bool_tag(item,false); } + + void add_null_tag(); + void add_description(std::string const& text); + + LUA_MEMBER_FUNC( + script_brush,std::shared_ptr,on_left_click); + LUA_MEMBER_FUNC( + script_brush,std::shared_ptr,on_left_hold); + LUA_MEMBER_FUNC( + script_brush,std::shared_ptr,on_left_release); + LUA_MEMBER_FUNC( + script_brush,std::shared_ptr,on_right_click); + LUA_MEMBER_FUNC( + script_brush,std::shared_ptr,on_right_hold); + LUA_MEMBER_FUNC( + script_brush,std::shared_ptr,on_right_release); + + private: + std::vector> _tags; + std::string _name; + }; + + void register_script_brush(script_context * state); + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_chunk.cpp b/src/noggit/scripting/script_chunk.cpp new file mode 100644 index 000000000..8e1fd8ecd --- /dev/null +++ b/src/noggit/scripting/script_chunk.cpp @@ -0,0 +1,169 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace noggit +{ + namespace scripting + { + chunk::chunk(script_context * ctx, MapChunk* chunk) + : script_object(ctx) + , _chunk(chunk) + {} + + void chunk::set_hole(bool hole) + { + _chunk->setHole(math::vector_3d(0, 0, 0), true, hole); + } + + int chunk::add_texture(std::string const& texture, int effectID) + { + std::string tex = std::string(texture); + int tex_index = _chunk->texture_set->addTexture(scoped_blp_texture_reference(tex)); + if (effectID >= -1) + { + set_effect(tex_index, effectID); + _chunk->texture_set->setEffect(tex_index, effectID); + } + return tex_index; + } + + int chunk::get_effect(int index) + { + return _chunk->texture_set->effect(index); + } + + void chunk::set_effect(int index, int value) + { + _chunk->texture_set->setEffect(index, value); + _chunk->texture_set->lod_texture_map(); + } + + void chunk::clear_textures() + { + _chunk->texture_set->eraseTextures(); + } + + void chunk::remove_texture(int index) + { + if(index<0||index>3) + { + throw script_exception( + "chunk_remove_texture", + "invalid texture index, must be between 0-3"); + } + _chunk->texture_set->eraseTexture(index); + } + + int chunk::get_texture_count() + { + return _chunk->texture_set->nTextures; + } + + std::string chunk::get_texture(int index) + { + if(index<0||index>3) + { + throw script_exception( + "chunk_get_texture", + "invalid texture index, must be between 0-3"); + } + + if (_chunk->texture_set->nTextures <= index) + { + throw script_exception( + "chunk_get_texture", + "texture index out of range" + ); + } + + return _chunk->texture_set->texture(index)->filename; + } + + void chunk::apply_heightmap () + { + _chunk->updateVerticesData(); + world()->recalc_norms(_chunk); + } + + void chunk::apply_textures() + { + _chunk->texture_set->apply_alpha_changes(); + } + + void chunk::apply_vertex_color() + { + _chunk->UpdateMCCV(); + } + + void chunk::apply_all() + { + apply_heightmap(); + apply_textures(); + apply_vertex_color(); + } + + int chunk::get_area_id() + { + return _chunk->getAreaID(); + } + + void chunk::set_area_id(int value) + { + return _chunk->setAreaID(value); + } + + void chunk::set_impassable(bool add) + { + _chunk->setFlag(add, 0x2); + } + + void chunk::clear_colors() + { + std::fill ( + _chunk->mccv, + _chunk->mccv + mapbufsize, + math::vector_3d (1.f, 1.f, 1.f) + ); + } + + std::shared_ptr chunk::to_selection() + { + return std::make_shared(state(), "chunk#to_selection", _chunk->vmin,_chunk->vmax); + } + + void register_chunk(script_context * state) + { + state->new_usertype("chunk" + , "remove_texture", &chunk::remove_texture + , "get_texture_count", &chunk::get_texture_count + , "get_texture", &chunk::get_texture + , "get_effect", &chunk::get_effect + , "set_effect", &chunk::set_effect + , "add_texture", sol::overload( + &chunk::add_texture + , &chunk::add_texture_1 + ) + , "clear_textures", &chunk::clear_textures + , "set_hole", &chunk::set_hole + , "clear_colors", &chunk::clear_colors + , "apply_textures", &chunk::apply_textures + , "apply_heightmap", &chunk::apply_heightmap + , "apply_vertex_color", &chunk::apply_vertex_color + , "apply_all", &chunk::apply_all + , "set_impassable", &chunk::set_impassable + , "get_area_id", &chunk::get_area_id + , "set_area_id", &chunk::set_area_id + , "to_selection", &chunk::to_selection + ); + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_chunk.hpp b/src/noggit/scripting/script_chunk.hpp new file mode 100644 index 000000000..c7a332e4f --- /dev/null +++ b/src/noggit/scripting/script_chunk.hpp @@ -0,0 +1,44 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include +#include +#include + +namespace noggit +{ + namespace scripting + { + class script_context; + class selection; + class chunk: public script_object + { + public: + chunk(script_context * ctx, MapChunk* chunk); + void remove_texture(int index); + std::string get_texture(int index); + int get_effect(int index); + void set_effect(int index, int effectID); + int add_texture(std::string const& texture, int effectID /* = -2*/); + int add_texture_1(std::string const& texture) + { return add_texture(texture,-2);} + int get_texture_count(); + void clear_textures(); + void set_hole(bool hole); + void clear_colors(); + void apply_textures(); + void apply_heightmap(); + void apply_vertex_color(); + void apply_all(); + void set_impassable(bool add); + int get_area_id(); + void set_area_id(int value); + std::shared_ptr to_selection(); + private: + MapChunk* _chunk; + friend class selection; + }; + + void register_chunk(script_context * state); + } // namespace scripting +} // namespace noggit \ No newline at end of file diff --git a/src/noggit/scripting/script_context.cpp b/src/noggit/scripting/script_context.cpp new file mode 100644 index 000000000..6a841f686 --- /dev/null +++ b/src/noggit/scripting/script_context.cpp @@ -0,0 +1,188 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +namespace noggit +{ + namespace scripting + { + + namespace + { + void set_tool_error(scripting_tool * tool) + { + tool->resetLogScroll(); + tool->setStyleSheet("background-color: #f0a5a5;"); + } + } + + script_context::script_context(scripting_tool * tool): _tool(tool) + { + open_libraries(sol::lib::base,sol::lib::table,sol::lib::string); + script_scoped_function(std::string const&)> + add_brush(this,"brush", + [this](std::string const& name) + { + auto brush = std::make_shared(this, name); + this->get_scripts().push_back(brush); + return brush; + }); + + set_function("require", [this](std::string const& name) { + return this->require(name); + }); + + register_functions(this); + + boost::filesystem::recursive_directory_iterator end; + + if(!boost::filesystem::exists("scripts")) + { + _tool->addLog("[error]: 'scripts' directory does not exist"); + set_tool_error(_tool); + return; + } + + if(!boost::filesystem::is_directory("scripts")) + { + _tool->addLog("[error]: 'scripts' is not a directory"); + set_tool_error(_tool); + return; + } + + unsigned int error_count = 0; + unsigned int file_count = 0; + + for (boost::filesystem::recursive_directory_iterator dir("scripts"); dir != end; ++dir) + { + std::string file = dir->path().string(); + if (!boost::ends_with(file, ".lua") || boost::ends_with(file, ".spec.lua")) + { + continue; + } + + ++file_count; + + try + { + execute_file(dir->path().string()); + } + catch (std::exception e) + { + ++error_count; + std::string what = e.what(); + if (what.size() == 0) + { + what = std::string("Generic error in file during initialization (check function names and arguments)"); + } + _tool->addLog("[error]: " + what + " (in file "+file+")"); + set_tool_error(_tool); + } + } + + if(file_count == 0) + { + _tool->addLog("[error]: no script files found (check your 'scripts' directory)"); + set_tool_error(_tool); + ++error_count; + } + + if(error_count == 0) + { + _tool->setStyleSheet(""); + } + } + + scripting_tool * script_context::tool() + { + return _tool; + } + + std::string script_context::get_selected_name() + { + if(_selected == -1) + { + return ""; + } + return _scripts[_selected]->get_name(); + } + + std::vector> & script_context::get_scripts() + { + return _scripts; + } + + void script_context::select_script(int index) + { + _selected = index; + auto v = get_scripts()[_selected]; + v->on_selected(); + } + + int script_context::get_selection() + { + return _selected; + } + + sol::table script_context::require(std::string const& mod) + { + std::string err_str; + for(auto& val: this->_file_stack) + { + err_str+=val; + if(val==mod) + { + throw script_exception("require","circular dependency: "+err_str); + } + err_str+="->"; + } + if(_modules.find(mod)==_modules.end()) + { + execute_file(module_to_file(mod)); + } + return _modules[mod]; + } + + World * script_context::world() + { + return _tool->get_view()->_world.get(); + } + + std::string script_context::file_to_module(std::string const& file) + { + auto rel = boost::filesystem::relative(boost::filesystem::path(file),boost::filesystem::path("scripts")) + .string(); + std::replace(rel.begin(),rel.end(),'\\','/'); + return rel.substr(0,rel.size()-strlen(".lua")); + } + + std::string script_context::module_to_file(std::string const& mod) + { + return (boost::filesystem::path("scripts") / boost::filesystem::path(mod + ".lua")).string(); + } + + void script_context::execute_file(std::string const& file) + { + auto mod = file_to_module(file); + _file_stack.push_back(mod); + sol::protected_function_result res = script_file(file); + _modules[mod] = res.get_type() == sol::type::table + ? res.get() + : create_table(); + _file_stack.pop_back(); + } + } // namespace scripting +} // namespace noggit \ No newline at end of file diff --git a/src/noggit/scripting/script_context.hpp b/src/noggit/scripting/script_context.hpp new file mode 100644 index 000000000..56ecb7366 --- /dev/null +++ b/src/noggit/scripting/script_context.hpp @@ -0,0 +1,66 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include + +#include +#include +#include + +class World; + +namespace noggit +{ + class camera; + namespace scripting + { + class scripting_tool; + + class script_context: public sol::state + { + public: + script_context(scripting_tool * tool); + void select_script(int index); + int get_selection(); + World * world(); + scripting_tool * tool(); + std::string get_selected_name(); + std::vector> &get_scripts(); + sol::table require(std::string const& path); + void execute_file(std::string const& filename); + std::string file_to_module(std::string const& file); + std::string module_to_file(std::string const& module); + private: + scripting_tool * _tool; + std::vector> _scripts; + std::map _modules; + std::vector _file_stack; + int _selected = -1; + }; + + template + class script_scoped_function + { + public: + script_scoped_function( script_context *lua + , std::string const &name + , std::function fun + ) + : _lua(lua) + , _name(name) + { + lua->set_function(name, fun); + } + + script_scoped_function() + { + _lua->set_function(_name, nullptr); + } + private: + script_context* _lua; + std::string _name; + }; + } // namespace scripting +} // namespace noggit \ No newline at end of file diff --git a/src/noggit/scripting/script_exception.cpp b/src/noggit/scripting/script_exception.cpp new file mode 100644 index 000000000..88b1120c3 --- /dev/null +++ b/src/noggit/scripting/script_exception.cpp @@ -0,0 +1,21 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include + +namespace noggit +{ + namespace scripting + { + script_exception::script_exception(std::string const& funcName, std::string const& msg) + : std::runtime_error(msg+" (in function "+funcName+")") + { + // TEMP: remove when exceptions are working + if(msg.find("C++ exception") != 0) + { + set_cur_exception(std::string(what())); + } + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_exception.hpp b/src/noggit/scripting/script_exception.hpp new file mode 100644 index 000000000..046925134 --- /dev/null +++ b/src/noggit/scripting/script_exception.hpp @@ -0,0 +1,17 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include +#include + +namespace noggit +{ + namespace scripting + { + class script_exception : public std::runtime_error + { + public: + script_exception(std::string const& funcName, std::string const& msg); + }; + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_filesystem.cpp b/src/noggit/scripting/script_filesystem.cpp new file mode 100644 index 000000000..4eae8b5b8 --- /dev/null +++ b/src/noggit/scripting/script_filesystem.cpp @@ -0,0 +1,113 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace fs = boost::filesystem; + +namespace noggit +{ + namespace scripting + { + namespace + { + void mkdirs(std::string const& pathstr) + { + auto path = fs::path(pathstr); + auto parent_path = path.parent_path(); + if (parent_path.string().size() > 0) + { + fs::create_directories(path.parent_path()); + } + } + } + + std::string read_file(std::string const& path) + { + if (!fs::exists(path)) + { + throw script_exception("read_file","no such file:" + std::string (path)); + } + std::ifstream t(path); + std::string str((std::istreambuf_iterator(t)), + std::istreambuf_iterator()); + return str; + } + + namespace { + std::set allowed_files; + } + + boost::filesystem::path get_writable_path(std::string const& caller, script_context * state, std::string const& path) + { + auto canonical = boost::filesystem::weakly_canonical(boost::filesystem::path(path)); + if (state->tool()->get_noggit_settings()->value("allow_scripts_write_any_file", false).toBool()) + { + return canonical; + } + if (allowed_files.find(canonical) != allowed_files.end()) + { + return canonical; + } + QMessageBox prompt; + prompt.setText(std::string("A script wants to write to the file "+canonical.string()).c_str()); + prompt.setInformativeText(std::string("Do you want to allow the script to write to "+canonical.string()+"?").c_str()); + prompt.setStandardButtons(QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No); + prompt.setDefaultButton(QMessageBox::No); + bool answer = prompt.exec() == QMessageBox::StandardButton::Yes; + if(!answer) + { + throw script_exception(caller,"No permission to write file "+canonical.string()); + } + return *allowed_files.emplace (canonical).first; + } + + void write_file(script_context * ctx, std::string const& path, std::string const& input) + { + auto writable_path = get_writable_path("write_file",ctx,path); + mkdirs(writable_path.string()); + std::ofstream(writable_path.string()) << input; + } + + void append_file(script_context * ctx, std::string const& path, std::string const& input) + { + auto writable_path = get_writable_path("append_file",ctx,path); + mkdirs(writable_path.string()); + std::ofstream outfile; + outfile.open(writable_path.string(), std::ios_base::app); // append instead of overwrite + outfile << input; + } + + bool path_exists(std::string const& path) + { + return fs::exists(path); + } + + void register_filesystem(script_context * state) + { + state->set_function("write_file", [state]( + std::string const& path + , std::string const& input + ) { + write_file(state, path, input); + }); + state->set_function("append_file", [state]( + std::string const& path + , std::string const& input + ) { + append_file(state, path, input); + }); + state->set_function("read_file",read_file); + state->set_function("path_exists",path_exists); + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_filesystem.hpp b/src/noggit/scripting/script_filesystem.hpp new file mode 100644 index 000000000..cb858bf66 --- /dev/null +++ b/src/noggit/scripting/script_filesystem.hpp @@ -0,0 +1,22 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include + +namespace noggit +{ + namespace scripting + { + class script_context; + class scripting_tool; + namespace fs = boost::filesystem; + boost::filesystem::path get_writable_path(std::string const& caller, script_context * state, std::string const& path); + void write_file(script_context * ctx, std::string const& path, std::string const& content); + void append_file(script_context * ctx, std::string const& path, std::string const& content); + std::string read_file(std::string const& path); + bool path_exists(std::string const& path); + void register_filesystem(script_context * state); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_global.cpp b/src/noggit/scripting/script_global.cpp new file mode 100644 index 000000000..62d9dd875 --- /dev/null +++ b/src/noggit/scripting/script_global.cpp @@ -0,0 +1,126 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include + +#include + +#include + +namespace noggit { + namespace scripting { + void register_global(script_context * state) + { + scripting_tool * global = state->tool(); + state->set_function("camera_pos",[global]() + { + return global->get_view()->_camera.position; + }); + + state->set_function("add_m2",[global]( + std::string const& filename + , math::vector_3d const& pos + , float scale + , math::vector_3d const& rotation) + { + object_paste_params p; + p.minScale = scale; + p.maxScale = scale; + global->get_view()->_world.get()-> + addM2(filename,pos,1,math::degrees::vec3(rotation), &p); + }); + + state->set_function("vec",[](float x, float y, float z){ + return math::vector_3d(x,y,z); + }); + + state->set_function("add_wmo",[global]( + std::string const& filename + , math::vector_3d const& pos + , math::vector_3d const& rotation) + { + global->get_view()->_world.get()->addWMO( + filename + , pos + , math::degrees::vec3(rotation)); + }); + + state->set_function("get_map_id",[global]() + { + return global->get_view()->_world.get()->getMapID(); + }); + + state->set_function("get_area_id",[global]( + math::vector_3d const& pos) + { + return global->get_view()->_world.get()->getAreaID(pos); + }); + + state->set_function("cam_pitch",[global]() + { + return global->get_view()->_camera.pitch()._; + }); + + state->set_function("cam_yaw",[global]() + { + return global->get_view()->_camera.yaw()._; + }); + + state->set_function("holding_alt",[global]() + { + return global->get_view()->_mod_alt_down; + }); + + state->set_function("holding_shift",[global]() + { + return global->get_view()->_mod_shift_down; + }); + + state->set_function("holding_ctrl",[global]() + { + return global->get_view()->_mod_ctrl_down; + }); + + state->set_function("holding_space",[global]() + { + return global->get_view()->_mod_space_down; + }); + + state->set_function("holding_left_mouse",[global]() + { + return global->get_view()->leftMouse; + }); + + state->set_function("holding_right_mouse",[global]() + { + return global->get_view()->rightMouse; + }); + + state->set_function("print",[global](sol::variadic_args va) + { + std::string str = ""; + for(auto v : va) + { + switch (v.get_type()) + { + case sol::type::boolean: + str += std::to_string((bool)v); + break; + case sol::type::number: + str += std::to_string(v.get()); + break; + case sol::type::string: + str += v.get(); + break; + case sol::type::table: + // TODO: implement + str += "{table}"; + break; + } + } + return global->addLog(str); + }); + } + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_global.hpp b/src/noggit/scripting/script_global.hpp new file mode 100644 index 000000000..5c8642f8e --- /dev/null +++ b/src/noggit/scripting/script_global.hpp @@ -0,0 +1,12 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +namespace noggit { + namespace scripting { + class scripting_tool; + class script_context; + void register_global(script_context * state); + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_image.cpp b/src/noggit/scripting/script_image.cpp new file mode 100644 index 000000000..7f41e097c --- /dev/null +++ b/src/noggit/scripting/script_image.cpp @@ -0,0 +1,186 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include +#include + +#include +#include + +namespace noggit +{ + namespace scripting + { + void image::resize(int width, int height) + { + if(width<=0||height<=0) + { + throw script_exception( + "img_resize", + std::string("tried to resize to invalid image size: x=") + + std::to_string(width) + + std::string(" y=") + + std::to_string(height) + ); + } + _size = width*height*4; + _width = width; + _height = height; + _image.resize(_width * _height * 4); + } + + image::image(script_context * ctx, std::string const& path) + : script_object(ctx) + { + unsigned error = lodepng::decode(_image, _width, _height, path); + if (error) + { + throw script_exception( + "img_load_png", + "failed to load png image with error code:" + + std::to_string (error)); + } + resize(_width, _height); + } + + image::image(script_context * ctx, int width, int height) + : script_object(ctx) + { + resize(width,height); + } + + int image::width() const + { + return _width; + } + + int image::height() const + { + return _height; + } + + int image::get_index(int x, int y) const + { + int index = ((x + y * _width) * 4); + if(index<0||index>=_size) + { + throw script_exception( + "img_get_index", + "image coordinates out of bounds: x=" + + std::to_string(x) + + " y=" + + std::to_string(y) + + " width=" + + std::to_string(_width) + + " height=" + + std::to_string(_height)); + } + return index; + } + + unsigned image::get_pixel(int x, int y) const + { + unsigned index = get_index(x, y); + return get_image()[index] << 24 + | get_image()[index + 1] << 16 + | get_image()[index + 2] << 8 + | get_image()[index + 3]; + } + + float image::get_alpha(int x, int y) const + { + return float(get_pixel(x,y) & 0xff)/255.0; + } + + float image::get_blue(int x, int y) const + { + return float((get_pixel(x,y) >> 8) & 0xff)/255.0; + } + + float image::get_green(int x, int y) const + { + return float((get_pixel(x,y) >> 16) & 0xff)/255.0; + } + + float image::get_red(int x, int y) const + { + return float((get_pixel(x,y) >> 24) & 0xff)/255.0; + } + + void image::set_pixel(int x, int y, unsigned value) + { + unsigned index = get_index(x, y); + get_image_w()[index] = (value << 24); + get_image_w()[index + 1] = (value << 16) & 0xff; + get_image_w()[index + 2] = (value << 8) & 0xff; + get_image_w()[index + 3] = (value) & 0xff; + } + + void image::set_pixel_floats(int x, int y, float r, float g, float b, float a) + { + unsigned index = get_index(x, y); + get_image_w()[index] = std::max(std::min(int(r * 255),255),0); + get_image_w()[index + 1] = std::max(std::min(int(g * 255),255),0); + get_image_w()[index + 2] = std::max(std::min(int(b * 255),255),0); + get_image_w()[index + 3] = std::max(std::min(int(a * 255),255),0); + } + + void image::save(std::string const& filename) + { + auto writable_path = get_writable_path("image::save", state(), filename); + unsigned error = lodepng::encode(filename, get_image(), _width, _height); + if (error) + { + throw script_exception( + "img_save", + "failed to save image with error " + + std::to_string (error)); + } + } + + float image::gradient_scale(float rel) const + { + if(rel<0||rel>=1) + { + throw script_exception( + "img_gradient_scale", + "relative image coordinate out of bounds: " + + std::to_string(rel) + + " (should be >= 0 and < 1)"); + } + int x = std::floor(rel * float(_width)); + // read red channel, but it shouldn't matter. + return float(get_image()[x * 4]) / 255.0; + } + + void register_image(script_context * state) + { + state->new_usertype("image" + , "get_index", &image::get_index + , "get_blue", &image::get_blue + , "get_red", &image::get_red + , "get_alpha", &image::get_alpha + , "get_green", &image::get_green + , "get_pixel", &image::get_pixel + , "gradient_scale", &image::gradient_scale + , "set_pixel", &image::set_pixel + , "set_pixel_floats", sol::overload( + &image::set_pixel_floats + , &image::set_pixel_floats_1 + ) + , "save", &image::save + , "width", &image::width + , "height", &image::height + ); + + state->set_function("create_image",[state](int width ,int height){ + return std::make_shared(state, width,height); + }); + + state->set_function("load_png", [state](std::string const& path) { + return std::make_shared(state, path); + }); + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_image.hpp b/src/noggit/scripting/script_image.hpp new file mode 100644 index 000000000..c1aa568d8 --- /dev/null +++ b/src/noggit/scripting/script_image.hpp @@ -0,0 +1,49 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include +#include +#include + +namespace noggit +{ + namespace scripting + { + class scripting_tool; + class script_context; + class image: public script_object + { + public: + image(script_context * ctx, std::string const& path); + image(script_context * ctx, int width, int height); + std::vector _image; + int get_index(int x, int y) const; + unsigned get_pixel(int x, int y) const; + float gradient_scale(float rel) const; + void set_pixel(int x, int y, unsigned value); + void set_pixel_floats(int x, int y, float r, float g, float b, float a /*= 1.0*/); + void set_pixel_floats_1(int x, int y, float r, float g, float b) + { + set_pixel_floats(x,y,r,g,b,1.0); + } + void save(std::string const& filename); + int width() const; + int height() const; + float get_blue(int x, int y) const; + float get_green(int x, int y) const; + float get_red(int x, int y) const; + float get_alpha(int x, int y) const; + private: + void resize(int width, int height); + unsigned char const * get_image() const {return _image.data();} + unsigned char * get_image_w() {return _image.data();} + unsigned _width = 0; + unsigned _height = 0; + unsigned _size = 0; + }; + + void register_image(script_context * state); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_math.cpp b/src/noggit/scripting/script_math.cpp new file mode 100644 index 000000000..6006aff73 --- /dev/null +++ b/src/noggit/scripting/script_math.cpp @@ -0,0 +1,98 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include + +#include +#include + +namespace noggit +{ + namespace scripting + { + int round(float a1) { return std::floor(a1); } + float pow(float a1, float a2) { return ::pow(a1, a2); } + float log10(float arg) { return ::log10(arg); } + float log(float arg) { return ::log(arg); } + int ceil(float arg) { return ::ceil(arg); } + int floor(float arg) { return std::floor(arg); } + float exp(float arg) { return ::exp(arg); } + float cbrt(float arg) { return ::cbrt(arg); } + float acosh(float arg) { return ::acosh(arg); } + float asinh(float arg) { return ::asinh(arg); } + float atanh(float arg) { return ::atanh(arg); } + float cosh(float arg) { return ::cosh(arg); } + float sinh(float arg) { return ::sinh(arg); } + float tanh(float arg) { return ::tanh(arg); } + float acos(float arg) { return ::acos(arg); } + float asin(float arg) { return ::asin(arg); } + float atan(float arg) { return ::atan(arg); } + float cos(float arg) { return ::cos(arg); } + float sin(float arg) { return ::sin(arg); } + float tan(float arg) { return ::tan(arg); } + float sqrt(float arg) { return ::sqrt(arg); } + float abs(float arg) { return ::abs(arg); } + float lerp(float from, float to, float ratio) { return from + ratio * (to - from); } + float dist_2d(math::vector_3d const& from, math::vector_3d const& to) + { + return std::sqrt(std::pow(from.x - to.x, 2) + std::pow(from.z - to.z, 2)); + } + + int dist_2d_compare(math::vector_3d const& from, math::vector_3d const& to, float compare) + { + float dist = std::pow(from.x - to.x, 2) + std::pow(from.z - to.z, 2); + compare = std::pow(compare, 2); + return dist > compare ? 1 : dist == compare ? 0 : -1; + } + + math::vector_3d rotate_2d(math::vector_3d const& point, math::vector_3d const& origin, float angle) + { + float s = std::sin(angle * 0.0174532925); + float c = std::cos(angle * 0.0174532925); + + float lx = point.x - origin.x; + float lz = point.z - origin.z; + + float nx = lx * c - lz * s + origin.x; + float nz = lx * s + lz * c + origin.z; + + return math::vector_3d(nx, point.y, nz); + } + + void register_math(script_context * state) + { + state->set_function("round",round); + state->set_function("pow",pow); + state->set_function("log10",log10); + state->set_function("log",log); + state->set_function("ceil",ceil); + state->set_function("floor",floor); + state->set_function("exp",exp); + state->set_function("cbrt",cbrt); + state->set_function("acosh",acosh); + state->set_function("asinh",asinh); + state->set_function("atanh",atanh); + state->set_function("cosh",cosh); + state->set_function("sinh",sinh); + state->set_function("tanh",tanh); + state->set_function("acos",acos); + state->set_function("asin",asin); + state->set_function("atan",atan); + state->set_function("cos",cos); + state->set_function("sin",sin); + state->set_function("tan",tan); + state->set_function("sqrt",sqrt); + state->set_function("abs",abs); + state->set_function("lerp",lerp); + state->set_function("dist_2d",dist_2d); + state->set_function("dist_2d_compare",dist_2d_compare); + state->set_function("rotate_2d",rotate_2d); + + state->new_usertype("vector_3d" + , "x", &math::vector_3d::x + , "y", &math::vector_3d::y + , "z", &math::vector_3d::z + ); + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_math.hpp b/src/noggit/scripting/script_math.hpp new file mode 100644 index 000000000..0f662a4f4 --- /dev/null +++ b/src/noggit/scripting/script_math.hpp @@ -0,0 +1,44 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include +#include + +namespace noggit +{ + namespace scripting + { + class scripting_tool; + class script_context; + int round(float a1); + float pow(float a1, float a2); + float log10(float arg); + float log(float arg); + int ceil(float arg); + int floor(float arg); + float exp(float arg); + float cbrt(float arg); + float acosh(float arg); + float asinh(float arg); + float atanh(float arg); + float cosh(float arg); + float sinh(float arg); + float tanh(float arg); + float acos(float arg); + float asin(float arg); + float atan(float arg); + float cos(float arg); + float sin(float arg); + float tan(float arg); + float sqrt(float arg); + float abs(float arg); + float lerp(float from, float to, float amount); + float dist_2d(math::vector_3d const& from, math::vector_3d const& to); + int dist_2d_compare(math::vector_3d const& from, math::vector_3d const& to, float dist); + math::vector_3d rotate_2d(math::vector_3d const& point, math::vector_3d const& origin, float angleDeg); + + void register_math(script_context * state); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_model.cpp b/src/noggit/scripting/script_model.cpp new file mode 100644 index 000000000..3ec135343 --- /dev/null +++ b/src/noggit/scripting/script_model.cpp @@ -0,0 +1,176 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +namespace noggit +{ + namespace scripting + { + model::model (script_context * ctx, ModelInstance* model) + : script_object(ctx) + , _impl (model) + {} + + model::model (script_context * ctx, WMOInstance* model) + : script_object(ctx) + , _impl (model) + {} + + math::vector_3d model::get_pos() + { + return util::visit (_impl, [] (auto x) { return x->pos; }); + } + + void model::set_pos(math::vector_3d& pos) + { + return util::visit (_impl, [&] (auto x) { x->pos = pos; }); + } + + math::vector_3d model::get_rot() + { + return math::vector_3d {util::visit (_impl, [] (auto x) { return x->dir; })}; + } + + void model::set_rot(math::vector_3d& rot) + { + return util::visit (_impl, [&] (auto x) { x->dir = math::degrees::vec3 {rot}; }); + } + + float model::get_scale() + { + return util::visit ( _impl + , [] (ModelInstance const* as_m2) { + return as_m2->scale; + } + , [] (WMOInstance const*) { + return 1.0f; + } + ); + } + + void model::set_scale(float scale) + { + return util::visit ( _impl + , [&] (ModelInstance* as_m2) { + as_m2->scale = scale; + } + , [] (WMOInstance*) {} + ); + } + + unsigned model::get_uid() + { + return util::visit ( _impl + , [] (ModelInstance const* as_m2) { + return as_m2->uid; + } + , [] (WMOInstance const* as_wmo) { + return as_wmo->mUniqueID; + } + ); + } + + std::string model::get_filename() + { + return util::visit ( _impl + , [] (ModelInstance const* as_m2) { + return as_m2->model->filename; + } + , [] (WMOInstance const* as_wmo) { + return as_wmo->wmo->filename; + } + ); + } + + bool model::has_filename(std::string const& name) + { + std::string copy = std::string(name); + boost::to_lower(copy); + std::replace(copy.begin(),copy.end(),'\\','/'); + return copy == get_filename(); + } + + void model::remove() + { + std::vector type; + util::visit (_impl, [&] (auto x) { type.emplace_back (x); }); + world()->delete_models(type); + } + + void model::replace(std::string const& filename) + { + if (get_filename() == filename) + { + return; + } + + remove(); + + if (boost::ends_with(filename, ".wmo")) + { + _impl = + world()->addWMO(filename, get_pos(), math::degrees::vec3 {get_rot()}); + } + else + { + auto params = object_paste_params(); + _impl = + world()->addM2(filename, get_pos(), get_scale(), math::degrees::vec3 {get_rot()}, ¶ms); + } + } + + void collect_models( + script_context * ctx + , World * world + , math::vector_3d const& min + , math::vector_3d const& max + , std::vector & vec + ) + { + world->for_each_m2_instance([&](ModelInstance& mod) { + if (mod.pos.x >= min.x && mod.pos.x <= max.x + && mod.pos.z >= min.z && mod.pos.z <= max.z) + { + vec.push_back(model(ctx, &mod)); + } + }); + world->for_each_wmo_instance([&](WMOInstance& mod) { + if (mod.pos.x >= min.x && mod.pos.x <= max.x + && mod.pos.z >= min.z && mod.pos.z <= max.z) + { + vec.push_back(model(ctx, &mod)); + } + }); + } + + void register_model(script_context * state) + { + state->new_usertype("model" + , "get_pos", &model::get_pos + , "set_pos", &model::set_pos + , "get_rot", &model::get_rot + , "set_rot", &model::set_rot + , "get_scale", &model::get_scale + , "set_scale", &model::set_scale + , "get_uid", &model::get_uid + , "remove", &model::remove + , "get_filename", &model::get_filename + , "has_filename", &model::has_filename + , "replace", &model::replace + ); + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_model.hpp b/src/noggit/scripting/script_model.hpp new file mode 100644 index 000000000..9a8b94c71 --- /dev/null +++ b/src/noggit/scripting/script_model.hpp @@ -0,0 +1,59 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include + +#include + +class World; + +class ModelInstance; +class WMOInstance; + +namespace noggit +{ + namespace scripting + { + class scripting_tool; + class script_context; + class model : public script_object + { + public: + model(script_context * ctx, ModelInstance* model); + model(script_context * ctx, WMOInstance* model); + + math::vector_3d get_pos(); + void set_pos(math::vector_3d& pos); + + math::vector_3d get_rot(); + void set_rot(math::vector_3d& rot); + + float get_scale(); + void set_scale(float scale); + + bool has_filename(std::string const& name); + + unsigned get_uid(); + + void remove(); + + std::string get_filename(); + void replace(std::string const& filename); + + private: + boost::variant _impl; + }; + + void collect_models( + script_context * ctx + , World * world + , math::vector_3d const& min + , math::vector_3d const& max + , std::vector& vec + ); + + void register_model(script_context * state); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_noise.cpp b/src/noggit/scripting/script_noise.cpp new file mode 100644 index 000000000..eb22da1c1 --- /dev/null +++ b/src/noggit/scripting/script_noise.cpp @@ -0,0 +1,217 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include + +#include + +namespace noggit +{ + namespace scripting + { + float noisemap::get_index(std::string const& caller, int x, int y) + { + unsigned index = x + y * _width; + if(index<0||index>=_size) + { + throw script_exception( + caller, + std::string("noise coordinates out of bounds: x=") + + std::to_string(x) + + std::string(" y=") + + std::to_string(y) + + std::string(" width=") + + std::to_string(_width) + + std::string(" height=") + + std::to_string(_height)); + } + return get_map()[index]; + } + + float noisemap::get(math::vector_3d& pos) + { + return get_index("noise_get",std::round(pos.x) - _start_x, std::round(pos.z) - _start_y); + } + + bool noisemap::is_highest(math::vector_3d& pos, int check_radius) + { + int x = std::round(pos.x) - _start_x; + int z = std::round(pos.z) - _start_y; + + float own = get_index("noise_is_highest", x, z); + + for (int xc = x - check_radius; xc < x + check_radius; ++xc) + { + for (int zc = z - check_radius; zc < z + check_radius; ++zc) + { + if (xc == x && zc == z) + { + continue; + } + + if (get_index("noise_is_highest",xc, zc) > own) + { + return false; + } + } + } + return true; + } + + void noisemap::set(int x, int y, float value) + { + unsigned index = x + y * _width; + if(index<0||index>=_size) + { + throw script_exception( + "noisemap::set", + std::string("noisemap coordinates out of bounds: x=") + + std::to_string(x) + + std::string(" y=") + + std::to_string(y) + + std::string(" width=") + + std::to_string(_width) + + std::string(" height=") + + std::to_string(_height)); + } + get_map()[index] = value; + } + + noisemap::noisemap( + script_context * ctx + , unsigned start_x + , unsigned start_y + , unsigned width + , unsigned height + , float frequency + , std::string const& algorithm + , std::string const& seed) + : script_object(ctx) + { + if(width<=0||height<=0) + { + throw script_exception( + "make_script_noise", + std::string("invalid noise map size:") + + " width=" + + std::to_string(width) + + " height=" + + std::to_string(height) + ); + } + _width = width; + _height = height; + _start_x = start_x; + _start_y = start_y; + _size = width*height; + _noise.resize(_size); + auto upper = boost::algorithm::to_upper_copy(algorithm); + + FastNoise::SmartNode<> generator = nullptr; + if(upper=="SIMPLEX") + { + generator = FastNoise::New(); + } + else if(upper=="PERLIN") + { + generator = FastNoise::New(); + } + else if(upper=="VALUE") + { + generator = FastNoise::New(); + } + else if(upper=="FRACTAL") + { + generator = FastNoise::New(); + } + else if(upper=="CELLULAR") + { + generator = FastNoise::New(); + } + else if(upper=="WHITE") + { + generator = FastNoise::New(); + } + else + { + generator = FastNoise::NewFromEncodedNodeTree(algorithm.c_str()); + } + + generator->GenUniformGrid2D( + get_map() + , start_x + , start_y + , width + , height + , frequency + , std::hash()(std::string(seed)) + ); + } + + math::vector_3d noisemap::start() + { + return math::vector_3d(_start_x,0,_start_y); + } + + unsigned noisemap::width() + { + return _width; + } + unsigned noisemap::height() + { + return _height; + } + + std::shared_ptr make_noise( + script_context * ctx + , int x_start + , int y_start + , int x_size + , int y_size + , float frequency + , std::string const& algorithm + , std::string const& seed) + { + return std::make_shared( ctx + , x_start + , y_start + , x_size + , y_size + , frequency + , algorithm + , seed); + } + + void register_noise(script_context * state) + { + state->new_usertype("noisemap" + , "get", &noisemap::get + , "is_highest", &noisemap::is_highest + , "set", &noisemap::set + , "start", &noisemap::start + , "width", &noisemap::width + , "height", &noisemap::height + ); + state->set_function("make_noise",[state]( + int sx + , int sy + , int width + , int height + , float frequency + , std::string const& algorithm + , std::string const& seed) + { + return make_noise( state + , sx + , sy + , width + , height + , frequency + , algorithm + , seed + ); + }); + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_noise.hpp b/src/noggit/scripting/script_noise.hpp new file mode 100644 index 000000000..51565944a --- /dev/null +++ b/src/noggit/scripting/script_noise.hpp @@ -0,0 +1,61 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include +#include + +#include + +#include +#include +#include +#include + +namespace noggit +{ + namespace scripting + { + class script_context; + class noisemap: public script_object + { + public: + noisemap(script_context * ctx + , unsigned start_x + , unsigned start_y + , unsigned width + , unsigned height + , float frequency + , std::string const& algorithm + , std::string const& seed); + + float get(math::vector_3d &pos); + bool is_highest(math::vector_3d &pos, int check_radius); + void set(int x, int y, float value); + math::vector_3d start(); + unsigned width(); + unsigned height(); + + private: + std::vector _noise; + float get_index(std::string const& caller, int x, int y); + float *get_map() { return _noise.data(); }; + unsigned _width; + unsigned _height; + unsigned _start_x; + unsigned _start_y; + unsigned _size; + }; + + std::shared_ptr make_noise( + script_context * ctx + , int start_x + , int start_y + , int width + , int height + , float frequency + , std::string const& algorithm + , std::string const& seed); + + void register_noise(script_context * state); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_object.cpp b/src/noggit/scripting/script_object.cpp new file mode 100644 index 000000000..2dc0505bd --- /dev/null +++ b/src/noggit/scripting/script_object.cpp @@ -0,0 +1,62 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include + +#include + +namespace noggit { + namespace scripting { + script_object::script_object(script_context * state) + : _state(state) + {} + + sol::object script_object::set(const std::string& key, sol::stack_object obj) + { + initialize_table(); + _table[key] = obj; + return obj; + } + + bool script_object::has_table() + { + return _initialized; + } + + World * script_object::world() + { + return _state->world(); + } + + void script_object::initialize_table() + { + if(!_initialized) + { + _table = _state->create_table(); + _initialized = true; + } + } + + sol::object script_object::get(const std::string& key) + { + initialize_table(); + return _table[key]; + } + + sol::table script_object::table() + { + initialize_table(); + return _table; + } + + script_context * script_object::state() + { + return _state; + } + + scripting_tool * script_object::tool() + { + return _state->tool(); + } + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_object.hpp b/src/noggit/scripting/script_object.hpp new file mode 100644 index 000000000..9b0fbcc2c --- /dev/null +++ b/src/noggit/scripting/script_object.hpp @@ -0,0 +1,89 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include + +class World; + +namespace noggit { + namespace scripting { + class script_context; + class scripting_tool; + + class script_object { + public: + // TODO: We can probably get this in a more intelligent way + script_object(script_context * state); + virtual sol::object set(const std::string& key, sol::stack_object obj); + virtual sol::object get(const std::string& key); + + script_context * state(); + scripting_tool * tool(); + World * world(); + sol::table table(); + bool has_table(); + protected: + sol::table _table; + void initialize_table(); + private: + bool _initialized = false; + script_context * _state; + }; + + template + class lua_function { + public: + lua_function(O * obj, std::string const& func) + : _obj(obj) + , _func(func) + {} + + bool exists() + { + if (!_obj->has_table()) + { + return false; + } + + auto fn = _obj->table()[_func]; + if (!fn.valid()) + { + return false; + } + + if (fn.get_type() == sol::type::function) + { + return true; + } + return false; + } + + void call_if_exists(std::string caller, Ts...args) + { + if (exists()) call(caller, args...); + } + + void call(std::string caller, Ts...args) + { + if(!exists()) + { + throw script_exception(caller,"calling null function"); + } + sol::protected_function fn = _obj->table()[_func]; + auto ret = fn(_obj, args...); + if (!ret.valid()) + { + sol::error err = ret; + throw script_exception(caller, err.what()); + } + } + private: + O * _obj; + std::string _func; + }; + + #define LUA_MEMBER_FUNC(selftype, type,name) lua_function name = lua_function(this,#name); + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_procedures.cpp b/src/noggit/scripting/script_procedures.cpp new file mode 100644 index 000000000..80a0bf135 --- /dev/null +++ b/src/noggit/scripting/script_procedures.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include + +#include + +namespace noggit { + namespace scripting { + void procedures::paint_texture( + selection & sel + , image const& img + , int layer + , float pressure + , float angle + ) + { + auto center = math::vector_3d(sel.min().x + (sel.max().x - sel.min().x) / 2, 0, sel.min().z + (sel.max().z - sel.min().z) / 2); + auto outer_radius = (sel.max().x - sel.min().x) / 2; + int width = img.width(); + int height = img.height(); + float half_width = float(width) / 2; + float half_height = float(height) / 2; + for (auto & tex : sel.textures_raw()) + { + auto global_pos = tex.get_pos_2d(); + auto dist = dist_2d(global_pos, center) / outer_radius; + global_pos = rotate_2d(global_pos, center, angle); + + auto rel_x = (global_pos.x - center.x) / outer_radius; + auto rel_z = (global_pos.z - center.z) / outer_radius; + + if (!(rel_x < -1 || rel_x > 1 || rel_z < -1 || rel_z > 1)) + { + auto img_x = round(half_width + half_width * rel_x); + auto img_z = round(half_height + half_height * rel_z); + if (img_x >= 0 && img_x < width && img_z >= 0 && img_z < height) { + auto old = tex.get_alpha(layer); + tex.set_alpha(layer, old + (img.get_red(img_x, img_z) * pressure * (1 - dist))); + } + } + } + } + + void register_procedures(script_context* state) + { + state->new_usertype("procedures_class" + , "paint_texture", &procedures::paint_texture + ); + state->set("procedures", procedures()); + } + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_procedures.hpp b/src/noggit/scripting/script_procedures.hpp new file mode 100644 index 000000000..1977715b4 --- /dev/null +++ b/src/noggit/scripting/script_procedures.hpp @@ -0,0 +1,24 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +namespace noggit { + namespace scripting { + class selection; + class image; + class script_context; + class procedures { + public: + void paint_texture( + selection & sel + , image const& image + , int layer + , float pressure + , float angle + ); + }; + + void register_procedures(script_context * state); + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_profiles.cpp b/src/noggit/scripting/script_profiles.cpp new file mode 100644 index 000000000..e3642d453 --- /dev/null +++ b/src/noggit/scripting/script_profiles.cpp @@ -0,0 +1,152 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include + +// TODO: duplicate +#define CUR_PROFILE_PATH "__cur_profile" + +namespace noggit +{ + namespace scripting + { + script_profiles::script_profiles(noggit::scripting::scripting_tool * tool) + : QGroupBox("Script Profiles"), _tool(tool) + { + _select_column = new QGridLayout(this); + + _selection = new QComboBox(this); + _selection->addItem("Default"); + _remove_button = new QPushButton("X", this); + _name_entry = new QLineEdit(this); + _create_button = new QPushButton("Add", this); + + _select_column->addWidget(_selection, 0, 0); + _select_column->addWidget(_remove_button, 0, 1); + + _select_column->addWidget(_name_entry, 1, 0); + _select_column->addWidget(_create_button, 1, 1); + + connect(_selection, QOverload::of(&QComboBox::activated), this, [this](auto index) { + select_profile_gui(index); + }); + + connect(_remove_button, &QPushButton::released, this, [this]() { + auto script_name = _tool->get_context()->get_selected_name(); + if (script_name.size() == 0) + { + // TODO: error? + return; + } + + auto index = _selection->currentIndex(); + + // do not allow deleting default settings + if (index == 0) + { + return; + } + + auto text = _selection->itemText(index).toStdString(); + _selection->removeItem(index); + + auto json = _tool->get_settings()->get_raw_json(); + + if (json->contains(script_name)) + { + if ((*json)[script_name].contains(text)) + { + (*json)[script_name].erase(text); + } + } + + select_profile_gui(0); + }); + + connect(_create_button, &QPushButton::released, this, [this]() { + auto script_name = _tool->get_context()->get_selected_name(); + + // do not allow invalid script + if (script_name.size() == 0) + return; + + auto newText = _name_entry->text(); + + // do not allow empty profiles + if (newText.isEmpty()) + return; + + auto count = _selection->count(); + for (int i = 0; i < count; ++i) + { + // do not allow duplicate profiles + if (_selection->itemText(i) == newText) + { + return; + } + } + + _name_entry->clear(); + _selection->addItem(newText); + + auto json = _tool->get_settings()->get_raw_json(); + + if (!(*json)[script_name].contains(newText.toStdString())) + { + if ((*json)[script_name].contains(_cur_profile)) + { + (*json)[script_name][newText.toStdString()] = (*json)[script_name][_cur_profile]; + } + } + + _selection->setCurrentIndex(count); + + select_profile_gui(count); + }); + } + + void script_profiles::select_profile_gui(int profile) + { + select_profile(profile); + _tool->clearDescription(); + _tool->get_context()->select_script(_tool->get_context()->get_selection()); + // string array / brush settings have changed + _tool->get_settings()->initialize(); + } + + void script_profiles::select_profile(int profile) + { + _tool->get_settings()->clear(); + _cur_profile = _selection->itemText(profile).toStdString(); + auto n = _tool->get_context()->get_selected_name(); + _selection->setCurrentIndex(profile); + (*_tool->get_settings()->get_raw_json())[n][CUR_PROFILE_PATH] = _cur_profile; + } + + std::string script_profiles::get_cur_profile() + { + return _cur_profile; + } + + void script_profiles::clear() + { + _selection->clear(); + } + + void script_profiles::add_profile(std::string const& profile) + { + _selection->addItem(QString::fromStdString (profile)); + } + + int script_profiles::profile_count() + { + return _selection->count(); + } + + std::string script_profiles::get_profile(int index) + { + return _selection->itemText(index).toStdString(); + } + } // namespace scripting +} // namespace noggit \ No newline at end of file diff --git a/src/noggit/scripting/script_profiles.hpp b/src/noggit/scripting/script_profiles.hpp new file mode 100644 index 000000000..fb56873b0 --- /dev/null +++ b/src/noggit/scripting/script_profiles.hpp @@ -0,0 +1,37 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#pragma once + +#include +#include +#include +#include +#include + +namespace noggit { + namespace scripting { + class scripting_tool; + class script_settings; + + class script_profiles : public QGroupBox { + public: + script_profiles(noggit::scripting::scripting_tool * tool); + void select_profile(int profile); + std::string get_cur_profile(); + void clear(); + void add_profile(std::string const& profile); + int profile_count(); + std::string get_profile(int index); + private: + noggit::scripting::scripting_tool* _tool; + QGridLayout* _select_column; + QComboBox* _selection; + QLineEdit* _name_entry; + QPushButton* _remove_button; + QPushButton* _create_button; + std::string _cur_profile; + void on_change_script(int selection); + void select_profile_gui(int profile); + }; + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_random.cpp b/src/noggit/scripting/script_random.cpp new file mode 100644 index 000000000..61f1dcc2f --- /dev/null +++ b/src/noggit/scripting/script_random.cpp @@ -0,0 +1,94 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include + +#include + +namespace noggit +{ + namespace scripting + { + random::random(script_context * ctx, unsigned seed) + : script_object(ctx) + , _state(seed) + { + } + + random::random(script_context * ctx, std::string const& seed) + : script_object(ctx) + , _state(std::hash()(seed)) + { + } + + random::random(script_context * ctx) + : script_object(ctx) + , _state(std::chrono::high_resolution_clock::now().time_since_epoch().count()) + { + } + + long random::integer(long low, long high) + { + if (low == high) + { + return low; + } + + if(low>=high) + { + throw script_exception( + "rand_int64", + "random lower bound "+ std::to_string(low) + " >= higher bound " + std::to_string(high)); + } + return std::uniform_int_distribution(low,high-1)(_state); + } + + double random::real(double low, double high) + { + if (low == high) + { + return low; + } + + if(low>=high) + { + throw script_exception( + "rand_double", + "random lower bound "+ std::to_string(low) + " >= higher bound " + std::to_string(high)); + } + double val; + do { + val = std::uniform_real_distribution(low,high)(_state); + } while(val == high); + return val; + } + + std::shared_ptr random_from_seed(script_context * ctx, std::string const& seed) + { + return std::make_shared(ctx, std::string(seed)); + } + + std::shared_ptr random_from_time(script_context * ctx) + { + return std::make_shared(ctx); + } + + void register_random(script_context * state) + { + state->new_usertype("random" + , "integer", &random::integer + , "real", &random::real + ); + state->set_function("random_from_seed",[state](std::string const& seed) + { + return random_from_seed(state, seed); + }); + + state->set_function("random_from_time",[state]() + { + return random_from_time(state); + }); + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_random.hpp b/src/noggit/scripting/script_random.hpp new file mode 100644 index 000000000..fd3ea4893 --- /dev/null +++ b/src/noggit/scripting/script_random.hpp @@ -0,0 +1,32 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include +#include +#include +namespace noggit +{ + namespace scripting + { + class scripting_tool; + class script_context; + class random: public script_object + { + public: + random(script_context * state, unsigned seed); + random(script_context * state, std::string const& seed); + random(script_context * state); + long integer(long low, long high); + double real(double low, double high); + private: + std::minstd_rand _state; + }; + + std::shared_ptr random_from_seed(script_context * state, std::string const& seed); + std::shared_ptr random_from_time(script_context * state); + + void register_random(script_context * state); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_registry.ipp b/src/noggit/scripting/script_registry.ipp new file mode 100644 index 000000000..fc68c8677 --- /dev/null +++ b/src/noggit/scripting/script_registry.ipp @@ -0,0 +1,47 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace noggit { + namespace scripting { + namespace { + void register_functions(script_context * lua) + { + // Register your functions / add registry functions here! + register_script_brush(lua); + register_model(lua); + register_global(lua); + register_vert(lua); + register_tex(lua); + register_chunk(lua); + register_selection(lua); + register_random(lua); + register_noise(lua); + register_math(lua); + register_image(lua); + register_filesystem(lua); + register_standard_brush(lua); + register_procedures(lua); + register_settings(lua); + } + } + } +} diff --git a/src/noggit/scripting/script_selection.cpp b/src/noggit/scripting/script_selection.cpp new file mode 100644 index 000000000..a8006ebcc --- /dev/null +++ b/src/noggit/scripting/script_selection.cpp @@ -0,0 +1,183 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace noggit +{ + namespace scripting + { + selection::selection(script_context * ctx, std::string const&,math::vector_3d const& point1, math::vector_3d const& point2) + : script_object(ctx) + , _world(ctx->world()) + { + _min = math::vector_3d( + std::min(point1.x, point2.x), + std::min(point1.y, point2.y), + std::min(point1.z, point2.z)); + + _max = math::vector_3d( + std::max(point1.x, point2.x), + std::max(point1.y, point2.y), + std::max(point1.z, point2.z)); + + _size = _max - _min; + _center = _min + (_size / 2); + } + + math::vector_3d selection::center() + { + return _center; + } + math::vector_3d selection::min() + { + return _min; + } + math::vector_3d selection::max() + { + return _max; + } + math::vector_3d selection::size() + { + return _size; + } + + std::shared_ptr selection::make_noise( + float frequency + , std::string const& algorithm + , std::string const& seed) + { + return noggit::scripting::make_noise( + state() + // padding to ensure we get no rounding errors (should be smaller?) + , std::floor(_min.x)-2 + , std::floor(_min.z)-2 + , std::ceil(_size.x)+4 + , std::ceil(_size.z)+4 + , frequency + , algorithm + , seed + ); + } + + std::vector selection::chunks_raw() + { + std::vector mapChunks; + _world->select_all_chunks_between(_min, _max, mapChunks); + std::vector chunks; + chunks.reserve(mapChunks.size()); + for (auto& chnk : mapChunks) chunks.emplace_back(state(), chnk); + return chunks; + } + + std::vector selection::verts_raw() + { + std::vector verts; + for (auto chunk : chunks_raw()) + { + for (int i = 0; i < mapbufsize; ++i) + { + auto& v = chunk._chunk->mVertices[i]; + if (v.x >= _min.x && v.x <= _max.x && + v.z >= _min.z && v.z <= _max.z) + { + verts.emplace_back(state(),chunk._chunk,i); + } + } + } + return verts; + } + + std::vector selection::textures_raw() + { + std::vector texvec; + for (auto chnk : chunks_raw()) + { + collect_textures(state(), chnk._chunk, texvec, _min, _max); + } + return texvec; + } + + std::vector selection::models_raw() + { + std::vector models; + collect_models(state(), world(), _min, _max, models); + return models; + } + + sol::as_table_t> selection::chunks() + { + return sol::as_table(chunks_raw()); + } + + sol::as_table_t> selection::verts() + { + return sol::as_table(verts_raw()); + } + + sol::as_table_t> selection::textures() + { + return sol::as_table(textures_raw()); + } + + sol::as_table_t> selection::models() + { + return sol::as_table(models_raw()); + } + + void selection::apply() + { + for (auto& chnk : chunks_raw()) + { + chnk.apply_all(); + } + } + + void register_selection(script_context* state) + { + state->new_usertype("selection" + , "center", &selection::center + , "min", &selection::min + , "max", &selection::max + , "size", &selection::size + , "apply", &selection::apply + , "verts", &selection::verts + , "tex", &selection::textures + , "models", &selection::models + , "chunks", &selection::chunks + , "make_noise", &selection::make_noise + ); + + state->set_function("select_origin", [state]( + math::vector_3d const& origin + , float xRadius + , float zRadius = -1 + ) + { + if(zRadius <= 0) + { + zRadius = xRadius; + } + return std::make_shared(state, "select_origin", + math::vector_3d(origin.x - xRadius, 0, origin.z - zRadius), + math::vector_3d(origin.x + xRadius, 0, origin.z + zRadius)); + }); + + state->set_function("select_between", [state]( + math::vector_3d const& point1 + , math::vector_3d const& point2 + ) + { + return std::make_shared(state, "select_between", + point1,point2); + }); + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_selection.hpp b/src/noggit/scripting/script_selection.hpp new file mode 100644 index 000000000..bcc58c41b --- /dev/null +++ b/src/noggit/scripting/script_selection.hpp @@ -0,0 +1,69 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include +#include +#include + +#include + +#include +#include +#include + +class MapChunk; +class World; + +namespace noggit +{ + namespace scripting + { + class script_context; + class model_iterator; + class vert_iterator; + class tex_iterator; + class noisemap; + + class selection: public script_object + { + public: + selection( script_context * ctx + , std::string const& caller + , math::vector_3d const& point1 + , math::vector_3d const& point2 + ); + + std::shared_ptr make_noise( + float frequency + , std::string const& algorithm + , std::string const& seed + ); + + math::vector_3d center(); + math::vector_3d min(); + math::vector_3d max(); + math::vector_3d size(); + + std::vector chunks_raw(); + std::vector verts_raw(); + std::vector textures_raw(); + std::vector models_raw(); + + sol::as_table_t> chunks(); + sol::as_table_t> verts(); + sol::as_table_t> textures(); + sol::as_table_t> models(); + + void apply(); + + private: + World* _world; + math::vector_3d _center; + math::vector_3d _min; + math::vector_3d _max; + math::vector_3d _size; + }; + + void register_selection(script_context * state); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_settings.cpp b/src/noggit/scripting/script_settings.cpp new file mode 100644 index 000000000..2eb10c986 --- /dev/null +++ b/src/noggit/scripting/script_settings.cpp @@ -0,0 +1,520 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define INNER_RADIUS_PATH "__inner_radius" +#define OUTER_RADIUS_PATH "__outer_radius" +#define SCRIPT_FILE "script_settings.json" + +namespace noggit +{ + namespace scripting + { + script_settings::script_settings(scripting_tool *tool) + : QGroupBox("Script Settings"), _tool(tool) + { + _layout = new QFormLayout(this); + + _radius_spin = new QDoubleSpinBox(this); + _radius_spin->setRange(0.0f, 1000.0f); + _radius_spin->setDecimals(2); + _radius_spin->setValue(_radius); + + _radius_slider = new QSlider(Qt::Orientation::Horizontal, this); + _radius_slider->setRange(0, 1000); + _radius_slider->setSliderPosition((int)std::round(_radius)); + + _inner_radius_spin = new QDoubleSpinBox(this); + _inner_radius_spin->setRange(0.0f, 1.0f); + _inner_radius_spin->setDecimals(2); + _inner_radius_spin->setValue(_inner_radius); + _inner_radius_spin->setSingleStep(0.05f); + + _inner_radius_slider = new QSlider(Qt::Orientation::Horizontal, this); + _inner_radius_slider->setRange(0, 100); + _inner_radius_slider->setSliderPosition((int)std::round(_inner_radius * 100)); + + _radius_group = new QGroupBox("Radius"); + _radius_layout = new QFormLayout(_radius_group); + _radius_layout->addRow("Outer:", _radius_spin); + _radius_layout->addRow(_radius_slider); + _radius_layout->addRow("Inner:", _inner_radius_spin); + _radius_layout->addRow(_inner_radius_slider); + + _custom_group = new QFrame(); + _custom_layout = new QFormLayout(_custom_group); + + _layout->addWidget(_radius_group); + _layout->addWidget(_custom_group); + + connect(_radius_spin, qOverload(&QDoubleSpinBox::valueChanged), [&](double v) { + _radius = v; + QSignalBlocker const blocker(_radius_slider); + _radius_slider->setSliderPosition((int)std::round(v)); + set_json (OUTER_RADIUS_PATH, v); + }); + + connect(_radius_slider, &QSlider::valueChanged, [&](int v) { + _radius = v; + QSignalBlocker const blocker(_radius_spin); + _radius_spin->setValue(v); + set_json (OUTER_RADIUS_PATH, v); + }); + + connect(_inner_radius_spin, qOverload(&QDoubleSpinBox::valueChanged), [&](double v) { + _inner_radius = v; + QSignalBlocker const blocker(_inner_radius_slider); + _inner_radius_slider->setSliderPosition((int)std::round(v * 100)); + set_json (INNER_RADIUS_PATH, v); + }); + + connect(_inner_radius_slider, &QSlider::valueChanged, [&](int v) { + _inner_radius = v / 100.0f; + QSignalBlocker const blocker(_inner_radius_spin); + _inner_radius_spin->setValue(_inner_radius); + set_json (INNER_RADIUS_PATH, _inner_radius); + }); + } + + template + T script_settings::get_json_safe(std::string const& key, T def, std::function)> check) + { + // TODO: this is terrible but accessing by reference didn't seem to work. + auto ssn = _tool->get_context()->get_selected_name(); + auto prof = _tool->get_profiles()->get_cur_profile(); + + if(!_json[ssn][prof].contains(key)) + { + _json[ssn][prof][key] = def; + return def; + } + + auto v = _json[ssn][prof][key]; + if (!check(v)) + { + _json[ssn][prof][key] = def; + } + + return _json[ssn][prof][key]; + } + + template + T script_settings::get_json_unsafe(std::string const& key) + { + auto ssn = _tool->get_context()->get_selected_name(); + auto prof = _tool->get_profiles()->get_cur_profile(); + return (_json)[ssn][prof][key].get(); + } + + template + void script_settings::set_json(std::string const& key, T def) + { + auto ssn = _tool->get_context()->get_selected_name(); + auto prof = _tool->get_profiles()->get_cur_profile(); + _json[ssn][prof][key] = def; + } + +// i don't remember why this was a macro +#define ADD_SLIDER(path, T, min, max, def, decimals, has_slider) \ + double dp1 = decimals > 0 ? decimals + 5 : decimals + 1; \ + auto spinner = new QDoubleSpinBox(this); \ + spinner->setRange(min, max); \ + spinner->setDecimals(decimals); \ + spinner->setValue(def); \ + auto slider = new QSlider(Qt::Orientation::Horizontal, this); \ + slider->setRange(min *dp1, max *dp1); \ + slider->setSliderPosition((int)std::round(def *dp1)); \ + auto label = new QLabel(this); \ + label->setText(name.c_str()); \ + connect(spinner, qOverload(&QDoubleSpinBox::valueChanged), [=](double v) { \ + set_json(path, (T)v); \ + QSignalBlocker const blocker(slider); \ + slider->setSliderPosition((int)std::round(v *dp1)); \ + }); \ + connect(slider, &QSlider::valueChanged, [=](int v) { \ + double t = double(v) / dp1; \ + set_json(path, t); \ + QSignalBlocker const blocker(spinner); \ + spinner->setValue(t); \ + }); \ + \ + _custom_layout->addRow(label, spinner); \ + if(has_slider) _custom_layout->addRow("", slider); \ + else slider->hide(); \ + _widgets.push_back(label); \ + _widgets.push_back(spinner); \ + _widgets.push_back(slider); \ + set_json(path, std::min(max, std::max(min, get_json_safe(path, def, [](auto json){ return json.is_number();})))); \ + auto v = get_json_safe(path, def,[](auto json){ return json.is_number(); }); \ + slider->setSliderPosition((int)std::round(v *dp1)); \ + spinner->setValue(v); + + double script_settings::get_double(std::string const& name) + { + return get_json_unsafe(name); + } + + int script_settings::get_int(std::string const& name) + { + return get_json_unsafe(name); + } + + bool script_settings::get_bool(std::string const& name) + { + return get_json_unsafe(name); + } + + std::string script_settings::get_string(std::string const& name) + { + return get_json_unsafe(name); + } + + std::string script_settings::get_string_list(std::string const& name) + { + return get_json_unsafe(name); + } + + void script_settings::add_double( + std::string const& name + , double min + , double max + , double def + , int zeros + , bool has_slider + ){ + ADD_SLIDER(name, double, min, max, def, zeros, has_slider); + } + + void script_settings::add_int( + std::string const& name + , int min + , int max + , int def + , bool has_slider + ){ + ADD_SLIDER(name, int, min, max, def, 0, has_slider); + } + + void script_settings::add_string(std::string const& name, std::string const& def) + { + auto tline = new QLineEdit(this); + auto label = new QLabel(this); + label->setText(name.c_str()); + connect(tline, &QLineEdit::textChanged, this, [=](auto text) { + set_json(name, text.toUtf8().constData()); + }); + _widgets.push_back(label); + _widgets.push_back(tline); + tline->setText(get_json_safe(name, def, [](auto json) {return json.is_string(); }).c_str()); + _custom_layout->addRow(label, tline); + } + + void script_settings::add_bool(std::string const& name, bool def) + { + auto checkbox = new QCheckBox(this); + auto label = new QLabel(this); + label->setText(name.c_str()); + connect(checkbox, &QCheckBox::stateChanged, this, [=](auto value) { + set_json(name, value ? true : false); + }); + + _widgets.push_back(checkbox); + _widgets.push_back(label); + _custom_layout->addRow(label, checkbox); + + checkbox->setCheckState(get_json_safe(name, def, [](auto json) { return json.is_boolean(); }) ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); + } + + void script_settings::add_null(std::string const& text) + { + auto label = new QLabel(this); + label->setText(text.c_str()); + _widgets.push_back(label); + _custom_layout->addRow(label); + } + + void script_settings::add_string_list(std::string const& name, std::string const& value) + { + if (_string_arrays.find(name) == _string_arrays.end()) + { + auto box = new QComboBox(this); + auto label = new QLabel(this); + + connect(box, QOverload::of(&QComboBox::activated), this, [=](auto index) { + set_json(name, box->itemText(index).toUtf8().constData()); + }); + + box->addItem(value.c_str()); + label->setText(name.c_str()); + + _string_arrays[name] = box; + _widgets.push_back(box); + _widgets.push_back(label); + _custom_layout->addRow(label, box); + + // ensure there is at least one valid value in it + get_json_safe(name, value, [](auto json) {return json.is_string(); }); + } + else + { + auto box = _string_arrays[name]; + box->addItem(value.c_str()); + + // we found the last selection, so change the index for that. + if (get_json_safe(name, "", [](auto json) {return json.is_string(); }) == value) + { + box->setCurrentIndex(box->count() - 1); + } + } + } + + void script_settings::setOuterRadius(float outerRadius) + { + _radius_spin->setValue(outerRadius); + _radius_slider->setSliderPosition(outerRadius); + set_json (OUTER_RADIUS_PATH, outerRadius); + } + + void script_settings::setInnerRadius(float innerRadius) + { + _inner_radius_spin->setValue(innerRadius); + _inner_radius_slider->setSliderPosition(innerRadius*100); + set_json (INNER_RADIUS_PATH, innerRadius); + } + + void script_settings::clear() + { + for (auto &widget : _widgets) + { + _custom_layout->removeWidget(widget); + delete widget; + } + _widgets.clear(); + _string_arrays.clear(); + } + + void script_settings::save_json() + { + std::ofstream(SCRIPT_FILE) << std::setw(4) << _json << "\n"; + } + + void script_settings::load_json() + { + if (!boost::filesystem::exists(SCRIPT_FILE)) + { + return; + } + + try + { + std::ifstream(SCRIPT_FILE) >> _json; + } + catch (std::exception err) + { + if (!boost::filesystem::exists(SCRIPT_FILE)) + { + return; + } + // back up broken script settings, since they won't be read and will be overwritten. + std::string backup_file = std::string(SCRIPT_FILE) + ".backup"; + int i = 0; + while (boost::filesystem::exists(backup_file + std::to_string(i))) + { + ++i; + } + boost::filesystem::copy(SCRIPT_FILE, backup_file + std::to_string(i)); + // Add a message box here + } + } + + void script_settings::initialize() + { + double inner_radius = get_json_safe(INNER_RADIUS_PATH, 0.5, [](auto json) {return json.is_number(); }); + double outer_radius = get_json_safe(OUTER_RADIUS_PATH, 40, [](auto json) {return json.is_number(); }); + + _radius_spin->setValue(outer_radius); + _inner_radius_spin->setValue(inner_radius); + + _radius_slider->setValue(std::round(outer_radius)); + _inner_radius_slider->setSliderPosition((int)std::round(inner_radius * 100)); + + for (auto& item : _string_arrays) + { + // if the index is 0, that MIGHT mean the value we have + // is invalid (old script), so we just write it again to be safe. + if (item.second->currentIndex() == 0) + { + set_json (item.first, item.second->itemText(0).toStdString()); + } + } + } + + nlohmann::json * script_settings::get_raw_json() + { + return &_json; + } + + tag::tag( script_context * ctx + , std::string const& script + , std::string const& item + ) + : script_object(ctx) + , _tool(ctx->tool()) + , _script(script) + , _item(item) + {} + + int_tag::int_tag(script_context * ctx + , std::string const& script + , std::string const& item + , int min + , int max + , int def + , bool has_slider + ) + : tag(ctx,script,item) + , _min(min) + , _max(max) + , _def(def) + , _has_slider(has_slider) + {} + + int int_tag::get() + { + return _tool->get_settings()->get_setting( + _script,_tool->get_profiles()->get_cur_profile(),_item,_def); + } + + void int_tag::add_to_settings() + { + _tool->get_settings()->add_int(_item, _min,_max,_def); + } + + null_tag::null_tag( + script_context * ctx + , std::string const& script + , std::string const& item + , std::string const& text + ) + : tag(ctx,script,item) + , _text(text) + {} + + void null_tag::add_to_settings() + { + _tool->get_settings()->add_null(_text); + } + + real_tag::real_tag(script_context * ctx + , std::string const& script + , std::string const& item + , double min + , double max + , double def + , int zeros + , bool has_slider + ) + : tag(ctx,script,item) + , _min(min) + , _max(max) + , _def(def) + , _zeros(zeros) + , _has_slider(has_slider) + {} + + + double real_tag::get() + { + return _tool->get_settings()->get_setting( + _script,_tool->get_profiles()->get_cur_profile(),_item,_def); + } + + void real_tag::add_to_settings() + { + _tool->get_settings()->add_double(_item, _min,_max,_def, _zeros, _has_slider); + } + + string_tag::string_tag(script_context * ctx + , std::string const& script + , std::string const& item + , std::string const& def + ) + : tag(ctx,script,item) + , _def(def) + {} + + std::string string_tag::get() + { + return _tool->get_settings()->get_setting( + _script,_tool->get_profiles()->get_cur_profile(),_item,_def); + } + + void string_tag::add_to_settings() + { + _tool->get_settings()->add_string(_item ,_def); + } + + string_list_tag::string_list_tag(script_context * ctx + , std::string const& script + , std::string const& item + , std::vector const& values + ) + : tag(ctx,script,item) + , _values(values) + {} + + std::string string_list_tag::get() + { + return _tool->get_settings()->get_setting( + _script,_tool->get_profiles()->get_cur_profile(),_item,_values[0]); + } + + void string_list_tag::add_to_settings() + { + for(auto& val: _values) + { + _tool->get_settings()->add_string_list(_item, val); + } + } + + bool_tag::bool_tag( + script_context * ctx + , std::string const& script + , std::string const& item + , bool def + ) + : tag(ctx,script,item) + , _def(def) + {} + + bool bool_tag::get() + { + return _tool->get_settings()->get_setting + ( + _script,_tool->get_profiles()->get_cur_profile(),_item,_def + ); + } + + void bool_tag::add_to_settings() + { + _tool->get_settings()->add_bool(_item,_def); + } + + void register_settings(script_context * state) + { + state->new_usertype("int_tag","get",&int_tag::get); + state->new_usertype("bool_tag", "get", &bool_tag::get); + state->new_usertype("real_tag","get",&real_tag::get); + state->new_usertype("string_tag","get",&string_tag::get); + state->new_usertype("string_list_tag","get",&string_list_tag::get); + } + } // namespace scripting +} // namespace noggit \ No newline at end of file diff --git a/src/noggit/scripting/script_settings.hpp b/src/noggit/scripting/script_settings.hpp new file mode 100644 index 000000000..760d95e26 --- /dev/null +++ b/src/noggit/scripting/script_settings.hpp @@ -0,0 +1,215 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace noggit { + namespace scripting { + class scripting_tool; + class script_profiles; + class script_context; + + class script_settings : public QGroupBox { + public: + script_settings(scripting_tool* tool); + void add_double( std::string const& name + , double min + , double max + , double def = 0 + , int zeros = 2 + , bool has_slider = false + ); + + void add_int( std::string const& name + , int min + , int max + , int def = 0 + , bool has_slider = false + ); + + void add_bool( std::string const& name, bool def = false); + void add_null( std::string const& text = ""); + void add_string(std::string const& name, std::string const& def = ""); + void add_string_list(std::string const& name, std::string const& value); + void add_description(std::string const& description); + + double get_double(std::string const& name); + int get_int(std::string const& name); + bool get_bool(std::string const& name); + std::string get_string(std::string const& name); + std::string get_string_list(std::string const& name); + + float brushRadius() const { return _radius; } + float innerRadius() const { return _inner_radius; } + + void setOuterRadius(float outerRadius); + void setInnerRadius(float innerRadius); + + void clear(); + + void save_json(); + void load_json(); + + nlohmann::json * get_raw_json(); + + template + T get_setting(std::string const& script + , std::string const& profile + , std::string const& item + , T def + ) + { + if(!_json[script][profile].contains(item)) + { + _json[script][profile][item] = def; + return def; + } + return _json[script][profile][item]; + } + + void initialize(); + private: + template + T get_json_safe(std::string const& key, T def, std::function)>); + template + T get_json_unsafe(std::string const& key); + template + void set_json(std::string const& key, T def); + + QGroupBox* _radius_group; + QFormLayout* _radius_layout; + QDoubleSpinBox* _radius_spin; + QSlider* _radius_slider; + + QDoubleSpinBox* _inner_radius_spin; + QSlider* _inner_radius_slider; + + QFormLayout* _layout; + + QFrame* _custom_group; + QFormLayout* _custom_layout; + + float _radius = 0; + float _inner_radius = 0; + private: + noggit::scripting::scripting_tool* _tool; + std::vector _widgets; + nlohmann::json _json; + std::map _string_arrays; + }; + + class tag : public script_object { + public: + tag( script_context * ctx + , std::string const& script + , std::string const& item + ); + virtual void add_to_settings() = 0; + protected: + scripting_tool * _tool; + std::string _script; + std::string _item; + private: + }; + + class int_tag : public tag { + public: + int_tag(script_context * ctx + , std::string const& script + , std::string const& item + , int min + , int max + , int def + , bool has_slider + ); + int get(); + void set(int value); + virtual void add_to_settings() override; + + private: + int _min,_max,_def; + bool _has_slider; + }; + + class real_tag : public tag { + public: + real_tag( script_context * ctx + , std::string const& script + , std::string const& item + , double min + , double max + , double def + , int zeros + , bool has_slider + ); + double get(); + virtual void add_to_settings() override; + private: + double _min,_max,_def; + int _zeros; + bool _has_slider; + }; + + class null_tag : public tag { + public: + null_tag(script_context* ctx + , std::string const& script + , std::string const& item + , std::string const& text = "" + ); + virtual void add_to_settings() override; + private: + std::string _text; + }; + + class string_tag : public tag { + public: + string_tag( script_context * ctx + , std::string const& script + , std::string const& item + , std::string const& def + ); + std::string get(); + virtual void add_to_settings() override; + private: + std::string _def; + }; + + class string_list_tag : public tag { + public: + string_list_tag( script_context * ctx + , std::string const& script + , std::string const& item + , std::vector const& strings + ); + std::string get(); + virtual void add_to_settings() override; + private: + std::vector _values; + }; + + class bool_tag : public tag { + public: + bool_tag( script_context * ctx + , std::string const& script + , std::string const& item + , bool def + ); + virtual void add_to_settings() override; + bool get(); + private: + bool _def; + }; + + void register_settings(script_context * state); + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_standard_brush.cpp b/src/noggit/scripting/script_standard_brush.cpp new file mode 100644 index 000000000..3275652da --- /dev/null +++ b/src/noggit/scripting/script_standard_brush.cpp @@ -0,0 +1,203 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace noggit { + namespace scripting { + standard_brush::standard_brush(script_context * ctx) + : script_object(ctx) + {} + + void standard_brush::set_area_id(math::vector_3d const& pos + , int id + , bool adt + ) + { + world()->setAreaID(pos, id, adt); + } + + void standard_brush::change_vertex_color( + math::vector_3d const& pos + , math::vector_3d const& color + , float alpha + , float change + , float radius + , bool editMode + ) + { + auto v = color; + world()->changeShader( + pos, math::vector_4d(v.x, v.y, v.z, alpha), change, radius, editMode); + } + + math::vector_3d standard_brush::get_vertex_color( + math::vector_3d const& pos) + { + return world()->pickShaderColor(pos); + } + + void standard_brush::flatten_terrain(math::vector_3d const& pos + , float remain + , float radius + , int brush_type + , bool lower + , bool raise + , math::vector_3d const& origin + , double angle + , double orientation + ) + { + world()->flattenTerrain( pos + , remain + , radius + , brush_type + , flatten_mode(raise, lower) + , origin + , math::degrees(angle) + , math::degrees(orientation)); + } + + void standard_brush::blur_terrain(math::vector_3d const& pos + , float remain + , float radius + , int brush_type + , bool lower + , bool raise + ) + { + world()->blurTerrain( pos + , remain + , radius + , brush_type + , flatten_mode(raise, lower)); + } + + void standard_brush::erase_textures(math::vector_3d const& pos) + { + world()->eraseTextures(pos); + } + + void standard_brush::clear_shadows(math::vector_3d const& pos) + { + world()->clear_shadows(pos); + } + + void standard_brush::clear_textures(math::vector_3d const& pos) + { + world()->clearTextures(pos); + } + + void standard_brush::clear_height(math::vector_3d const& pos) + { + world()->clearHeight(pos); + } + + void standard_brush::set_hole( math::vector_3d const& pos + , bool big + , bool hole + ) + { + world()->setHole(pos, big, hole); + } + + void standard_brush::set_hole_adt( math::vector_3d const& pos + , bool hole + ) + { + world()->setHoleADT(pos, hole); + } + + void standard_brush::update_vertices () + { + world()->updateVertexCenter(); + world()->updateSelectedVertices(); + } + + void standard_brush::deselect_vertices( math::vector_3d const& pos + , float radius + ) + { + world()->deselectVertices(pos, radius); + } + + void standard_brush::move_vertices(float h) + { + world()->moveVertices(h); + } + + void standard_brush::flatten_vertices(float h) + { + world()->flattenVertices(h); + } + + void standard_brush::clear_vertex_selection () + { + world()->clearVertexSelection(); + } + + void standard_brush::paint_texture( math::vector_3d const& pos + , float strength + , float pressure + , float hardness + , float radius + , std::string const& texture + ) + { + auto brush = Brush(); + brush.setHardness(hardness); + brush.setRadius(radius); + world()->paintTexture(pos + , &brush + , strength + , pressure + , scoped_blp_texture_reference(std::string(texture))); + } + + void standard_brush::change_terrain( math::vector_3d const& pos + , float change + , float radius + , float inner_radius + , int brush_type + ) + { + world()->changeTerrain( pos + , change + , radius + , brush_type + , inner_radius + ); + } + + void register_standard_brush(script_context * state) + { + state->new_usertype("standard_brush" + , "change_terrain", &standard_brush::change_terrain + , "set_area_id", &standard_brush::set_area_id + , "change_vertex_color", &standard_brush::change_vertex_color + , "get_vertex_color", &standard_brush::get_vertex_color + , "flatten_terrain", &standard_brush::flatten_terrain + , "blur_terrain", &standard_brush::blur_terrain + , "erase_textures", &standard_brush::erase_textures + , "clear_shadows", &standard_brush::clear_shadows + , "clear_textures", &standard_brush::clear_textures + , "clear_height", &standard_brush::clear_height + , "set_hole", &standard_brush::set_hole + , "set_hole_adt", &standard_brush::set_hole_adt + , "deselect_vertices", &standard_brush::deselect_vertices + , "clear_vertex_selection", &standard_brush::clear_vertex_selection + , "move_vertices", &standard_brush::move_vertices + , "flatten_vertices", &standard_brush::flatten_vertices + , "update_vertices", &standard_brush::update_vertices + , "paint_texture", &standard_brush::paint_texture + ); + } + } +} diff --git a/src/noggit/scripting/script_standard_brush.hpp b/src/noggit/scripting/script_standard_brush.hpp new file mode 100644 index 000000000..d67458e2a --- /dev/null +++ b/src/noggit/scripting/script_standard_brush.hpp @@ -0,0 +1,79 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include + +class World; + +namespace noggit +{ + namespace scripting + { + class scripting_tool; + class script_context; + class standard_brush : public script_object { + public: + standard_brush(script_context * ctx); + void change_terrain(math::vector_3d const& + , float change + , float radius + , float inner_radius + , int brush_type + ); + + void set_area_id(math::vector_3d const&, int id, bool adt); + + void change_vertex_color(math::vector_3d const& pos + , math::vector_3d const& color + , float alpha + , float change + , float radius + , bool editMode + ); + + math::vector_3d get_vertex_color(math::vector_3d const& pos); + + void flatten_terrain(math::vector_3d const& pos + , float remain + , float radius + , int brush_type + , bool lower + , bool raise + , math::vector_3d const& origin + , double angle + , double orientation + ); + + void blur_terrain(math::vector_3d const& pos + , float remain + , float radius + , int brush_type + , bool lower + , bool raise + ); + + void erase_textures(math::vector_3d const& pos); + void clear_shadows(math::vector_3d const& pos); + void clear_textures(math::vector_3d const& pos); + void clear_height(math::vector_3d const& pos); + void set_hole(math::vector_3d const& pos, bool big, bool hole); + void set_hole_adt(math::vector_3d const& pos, bool hole); + void deselect_vertices(math::vector_3d const& pos, float radius); + void clear_vertex_selection (); + void move_vertices(float h); + void flatten_vertices(float h); + void update_vertices (); + void paint_texture(math::vector_3d const& pos + , float strength + , float pressure + , float hardness + , float radius + , std::string const& texture + ); + }; + + void register_standard_brush(script_context * state); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_tex.cpp b/src/noggit/scripting/script_tex.cpp new file mode 100644 index 000000000..83bca304e --- /dev/null +++ b/src/noggit/scripting/script_tex.cpp @@ -0,0 +1,90 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include +#include +#include + +#include + +// amount of texunits per chunk length +#define TEXTURE_UNITS_WIDTH 64 +#define TEXTURE_UNITS_PER_CHUNK 4096 + +namespace noggit { + namespace scripting { + + tex::tex(script_context * ctx, MapChunk* chunk, int index) + : script_object(ctx) + , _chunk(chunk) + , _index(index) + {} + + float tex::get_alpha(int index) + { + auto& ts = _chunk->texture_set; + ts->create_temporary_alphamaps_if_needed(); + return ts->tmp_edit_values.get()[index][_index]; + } + + void tex::set_alpha(int index, float value) + { + if(index<0||index>3) + { + throw script_exception( + "tex_set_alpha", + std::string("invalid texture layer: ") + + std::to_string(index) + + std::string(" (in call to tex_set_alpha)") + ); + } + auto& ts = _chunk->texture_set; + ts->create_temporary_alphamaps_if_needed(); + ts->tmp_edit_values.get()[index][_index] = value; + } + + namespace { + math::vector_3d tex_location(MapChunk* chnk, int index) + { + float cx = chnk->xbase; + float cz = chnk->zbase; + float x = index % TEXTURE_UNITS_WIDTH; + float z = (float(index) / float(TEXTURE_UNITS_WIDTH)); + return math::vector_3d(cx + x * TEXDETAILSIZE, 0, cz + z * TEXDETAILSIZE); + } + } + + math::vector_3d tex::get_pos_2d() + { + return tex_location(_chunk, _index); + } + + void collect_textures( + script_context * ctx + , MapChunk* chnk + , std::vector& vec + , math::vector_3d const& min + , math::vector_3d const& max + ) + { + for (int i = 0; i < TEXTURE_UNITS_PER_CHUNK; ++i) + { + math::vector_3d loc = tex_location(chnk, i); + if (loc.x >= min.x && loc.x <= max.x && loc.z >= min.z && loc.z <= max.z) + { + vec.emplace_back(ctx, chnk, i); + } + } + } + + void register_tex(script_context * state) + { + state->new_usertype("tex" + , "set_alpha", &tex::set_alpha + , "get_alpha", &tex::get_alpha + , "get_pos_2d", &tex::get_pos_2d + ); + } + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_tex.hpp b/src/noggit/scripting/script_tex.hpp new file mode 100644 index 000000000..d0805b629 --- /dev/null +++ b/src/noggit/scripting/script_tex.hpp @@ -0,0 +1,59 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include + +#include +#include + +class MapChunk; + +namespace noggit { + namespace scripting { + class scripting_tool; + class script_context; + + class tex: public script_object + { + public: + tex(script_context * ctx, MapChunk* chunk, int index); + void set_alpha(int index, float alpha); + float get_alpha(int index); + math::vector_3d get_pos_2d(); + + private: + MapChunk* _chunk; + int _index; + }; + + void collect_textures( + script_context* ctx + , MapChunk* chnk + , std::vector& vec + , math::vector_3d const& min + , math::vector_3d const& max + ); + + class tex_iterator : public script_object { + public: + tex_iterator( script_context * ctx + , std::shared_ptr> chunks + , math::vector_3d const& min + , math::vector_3d const& max + ); + bool next(); + tex get(); + + void paint_image(image & img, int layer, float pressure, float angle); + + private: + int _tex_iter = -1; + std::shared_ptr> _chunks; + std::vector::iterator _chunk_iter; + math::vector_3d const& _min; + math::vector_3d const& _max; + }; + + void register_tex(script_context * state); + } +} \ No newline at end of file diff --git a/src/noggit/scripting/script_vert-script_texture_index.ipp b/src/noggit/scripting/script_vert-script_texture_index.ipp new file mode 100644 index 000000000..b306e72d8 --- /dev/null +++ b/src/noggit/scripting/script_vert-script_texture_index.ipp @@ -0,0 +1,160 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). + +// Note: This file is only a header to clean up script_vert.cpp, +// don't import it anywhere else! + +struct TextureIndex +{ + short indices[MAX_TEXUNITS_PER_VERT]; +}; + +namespace +{ + TextureIndex texture_index[145] = { + TextureIndex{{0, 1, 2, 3, 64, 65, 66, 128, 129, 192, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{5, 6, 7, 8, 9, 10, 11, 70, 71, 72, 73, 74, 135, 136, 137, 200, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{13, 14, 15, 16, 17, 18, 19, 78, 79, 80, 81, 82, 143, 144, 145, 208, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{21, 22, 23, 24, 25, 26, 27, 86, 87, 88, 89, 90, 151, 152, 153, 216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{29, 30, 31, 32, 33, 34, 35, 94, 95, 96, 97, 98, 159, 160, 161, 224, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{37, 38, 39, 40, 41, 42, 43, 102, 103, 104, 105, 106, 167, 168, 169, 232, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{45, 46, 47, 48, 49, 50, 51, 110, 111, 112, 113, 114, 175, 176, 177, 240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{53, 54, 55, 56, 57, 58, 59, 118, 119, 120, 121, 122, 183, 184, 185, 248, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{61, 62, 63, 126, 127, 191, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{4, 67, 68, 69, 130, 131, 132, 133, 134, 193, 194, 195, 196, 197, 198, 199, 256, 257, 258, 259, 260, 261, 262, 263, 321, 322, 323, 324, 325, 326, 386, 387, 388, 389, 451, 452}}, + TextureIndex{{12, 75, 76, 77, 138, 139, 140, 141, 142, 201, 202, 203, 204, 205, 206, 207, 265, 266, 267, 268, 269, 270, 271, 330, 331, 332, 333, 334, 395, 396, 397, 460, -1, -1, -1, -1}}, + TextureIndex{{20, 83, 84, 85, 146, 147, 148, 149, 150, 209, 210, 211, 212, 213, 214, 215, 273, 274, 275, 276, 277, 278, 279, 338, 339, 340, 341, 342, 403, 404, 405, 468, -1, -1, -1, -1}}, + TextureIndex{{28, 91, 92, 93, 154, 155, 156, 157, 158, 217, 218, 219, 220, 221, 222, 223, 281, 282, 283, 284, 285, 286, 287, 346, 347, 348, 349, 350, 411, 412, 413, 476, -1, -1, -1, -1}}, + TextureIndex{{36, 99, 100, 101, 162, 163, 164, 165, 166, 225, 226, 227, 228, 229, 230, 231, 289, 290, 291, 292, 293, 294, 295, 354, 355, 356, 357, 358, 419, 420, 421, 484, -1, -1, -1, -1}}, + TextureIndex{{44, 107, 108, 109, 170, 171, 172, 173, 174, 233, 234, 235, 236, 237, 238, 239, 297, 298, 299, 300, 301, 302, 303, 362, 363, 364, 365, 366, 427, 428, 429, 492, -1, -1, -1, -1}}, + TextureIndex{{52, 115, 116, 117, 178, 179, 180, 181, 182, 241, 242, 243, 244, 245, 246, 247, 305, 306, 307, 308, 309, 310, 311, 370, 371, 372, 373, 374, 435, 436, 437, 500, -1, -1, -1, -1}}, + TextureIndex{{60, 123, 124, 125, 186, 187, 188, 189, 190, 249, 250, 251, 252, 253, 254, 255, 313, 314, 315, 316, 317, 318, 319, 378, 379, 380, 381, 382, 443, 444, 445, 508, -1, -1, -1, -1}}, + TextureIndex{{320, 384, 385, 448, 449, 450, 512, 513, 514, 515, 576, 577, 578, 640, 641, 704, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{264, 327, 328, 329, 390, 391, 392, 393, 394, 453, 454, 455, 456, 457, 458, 459, 516, 517, 518, 519, 520, 521, 522, 523, 581, 582, 583, 584, 585, 586, 646, 647, 648, 649, 711, 712}}, + TextureIndex{{272, 335, 336, 337, 398, 399, 400, 401, 402, 461, 462, 463, 464, 465, 466, 467, 525, 526, 527, 528, 529, 530, 531, 590, 591, 592, 593, 594, 655, 656, 657, 720, -1, -1, -1, -1}}, + TextureIndex{{280, 343, 344, 345, 406, 407, 408, 409, 410, 469, 470, 471, 472, 473, 474, 475, 533, 534, 535, 536, 537, 538, 539, 598, 599, 600, 601, 602, 663, 664, 665, 728, -1, -1, -1, -1}}, + TextureIndex{{288, 351, 352, 353, 414, 415, 416, 417, 418, 477, 478, 479, 480, 481, 482, 483, 541, 542, 543, 544, 545, 546, 547, 606, 607, 608, 609, 610, 671, 672, 673, 736, -1, -1, -1, -1}}, + TextureIndex{{296, 359, 360, 361, 422, 423, 424, 425, 426, 485, 486, 487, 488, 489, 490, 491, 549, 550, 551, 552, 553, 554, 555, 614, 615, 616, 617, 618, 679, 680, 681, 744, -1, -1, -1, -1}}, + TextureIndex{{304, 367, 368, 369, 430, 431, 432, 433, 434, 493, 494, 495, 496, 497, 498, 499, 557, 558, 559, 560, 561, 562, 563, 622, 623, 624, 625, 626, 687, 688, 689, 752, -1, -1, -1, -1}}, + TextureIndex{{312, 375, 376, 377, 438, 439, 440, 441, 442, 501, 502, 503, 504, 505, 506, 507, 565, 566, 567, 568, 569, 570, 571, 630, 631, 632, 633, 634, 695, 696, 697, 760, -1, -1, -1, -1}}, + TextureIndex{{383, 446, 447, 509, 510, 511, 573, 574, 575, 638, 639, 703, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{579, 580, 642, 643, 644, 645, 705, 706, 707, 708, 709, 710, 768, 769, 770, 771, 772, 773, 774, 775, 833, 834, 835, 836, 837, 838, 898, 899, 900, 901, 963, 964, -1, -1, -1, -1}}, + TextureIndex{{524, 587, 588, 589, 650, 651, 652, 653, 654, 713, 714, 715, 716, 717, 718, 719, 776, 777, 778, 779, 780, 781, 782, 783, 841, 842, 843, 844, 845, 846, 906, 907, 908, 909, 971, 972}}, + TextureIndex{{532, 595, 596, 597, 658, 659, 660, 661, 662, 721, 722, 723, 724, 725, 726, 727, 785, 786, 787, 788, 789, 790, 791, 850, 851, 852, 853, 854, 915, 916, 917, 980, -1, -1, -1, -1}}, + TextureIndex{{540, 603, 604, 605, 666, 667, 668, 669, 670, 729, 730, 731, 732, 733, 734, 735, 793, 794, 795, 796, 797, 798, 799, 858, 859, 860, 861, 862, 923, 924, 925, 988, -1, -1, -1, -1}}, + TextureIndex{{548, 611, 612, 613, 674, 675, 676, 677, 678, 737, 738, 739, 740, 741, 742, 743, 801, 802, 803, 804, 805, 806, 807, 866, 867, 868, 869, 870, 931, 932, 933, 996, -1, -1, -1, -1}}, + TextureIndex{{556, 619, 620, 621, 682, 683, 684, 685, 686, 745, 746, 747, 748, 749, 750, 751, 809, 810, 811, 812, 813, 814, 815, 874, 875, 876, 877, 878, 939, 940, 941, 1004, -1, -1, -1, -1}}, + TextureIndex{{564, 627, 628, 629, 690, 691, 692, 693, 694, 753, 754, 755, 756, 757, 758, 759, 817, 818, 819, 820, 821, 822, 823, 882, 883, 884, 885, 886, 947, 948, 949, 1012, -1, -1, -1, -1}}, + TextureIndex{{572, 635, 636, 637, 698, 699, 700, 701, 702, 761, 762, 763, 764, 765, 766, 767, 825, 826, 827, 828, 829, 830, 831, 890, 891, 892, 893, 894, 955, 956, 957, 1020, -1, -1, -1, -1}}, + TextureIndex{{832, 896, 897, 960, 961, 962, 1024, 1025, 1026, 1027, 1088, 1089, 1090, 1152, 1153, 1216, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{839, 840, 902, 903, 904, 905, 965, 966, 967, 968, 969, 970, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1093, 1094, 1095, 1096, 1097, 1098, 1158, 1159, 1160, 1161, 1223, 1224, -1, -1, -1, -1}}, + TextureIndex{{784, 847, 848, 849, 910, 911, 912, 913, 914, 973, 974, 975, 976, 977, 978, 979, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1101, 1102, 1103, 1104, 1105, 1106, 1166, 1167, 1168, 1169, 1231, 1232}}, + TextureIndex{{792, 855, 856, 857, 918, 919, 920, 921, 922, 981, 982, 983, 984, 985, 986, 987, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1110, 1111, 1112, 1113, 1114, 1175, 1176, 1177, 1240, -1, -1, -1, -1}}, + TextureIndex{{800, 863, 864, 865, 926, 927, 928, 929, 930, 989, 990, 991, 992, 993, 994, 995, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1118, 1119, 1120, 1121, 1122, 1183, 1184, 1185, 1248, -1, -1, -1, -1}}, + TextureIndex{{808, 871, 872, 873, 934, 935, 936, 937, 938, 997, 998, 999, 1000, 1001, 1002, 1003, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1126, 1127, 1128, 1129, 1130, 1191, 1192, 1193, 1256, -1, -1, -1, -1}}, + TextureIndex{{816, 879, 880, 881, 942, 943, 944, 945, 946, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1134, 1135, 1136, 1137, 1138, 1199, 1200, 1201, 1264, -1, -1, -1, -1}}, + TextureIndex{{824, 887, 888, 889, 950, 951, 952, 953, 954, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1142, 1143, 1144, 1145, 1146, 1207, 1208, 1209, 1272, -1, -1, -1, -1}}, + TextureIndex{{895, 958, 959, 1021, 1022, 1023, 1085, 1086, 1087, 1150, 1151, 1215, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{1091, 1092, 1154, 1155, 1156, 1157, 1217, 1218, 1219, 1220, 1221, 1222, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1345, 1346, 1347, 1348, 1349, 1350, 1410, 1411, 1412, 1413, 1475, 1476, -1, -1, -1, -1}}, + TextureIndex{{1099, 1100, 1162, 1163, 1164, 1165, 1225, 1226, 1227, 1228, 1229, 1230, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1353, 1354, 1355, 1356, 1357, 1358, 1418, 1419, 1420, 1421, 1483, 1484, -1, -1, -1, -1}}, + TextureIndex{{1044, 1107, 1108, 1109, 1170, 1171, 1172, 1173, 1174, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1361, 1362, 1363, 1364, 1365, 1366, 1426, 1427, 1428, 1429, 1491, 1492}}, + TextureIndex{{1052, 1115, 1116, 1117, 1178, 1179, 1180, 1181, 1182, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1370, 1371, 1372, 1373, 1374, 1435, 1436, 1437, 1500, -1, -1, -1, -1}}, + TextureIndex{{1060, 1123, 1124, 1125, 1186, 1187, 1188, 1189, 1190, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1378, 1379, 1380, 1381, 1382, 1443, 1444, 1445, 1508, -1, -1, -1, -1}}, + TextureIndex{{1068, 1131, 1132, 1133, 1194, 1195, 1196, 1197, 1198, 1257, 1258, 1259, 1260, 1261, 1262, 1263, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1386, 1387, 1388, 1389, 1390, 1451, 1452, 1453, 1516, -1, -1, -1, -1}}, + TextureIndex{{1076, 1139, 1140, 1141, 1202, 1203, 1204, 1205, 1206, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1329, 1330, 1331, 1332, 1333, 1334, 1335, 1394, 1395, 1396, 1397, 1398, 1459, 1460, 1461, 1524, -1, -1, -1, -1}}, + TextureIndex{{1084, 1147, 1148, 1149, 1210, 1211, 1212, 1213, 1214, 1273, 1274, 1275, 1276, 1277, 1278, 1279, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1402, 1403, 1404, 1405, 1406, 1467, 1468, 1469, 1532, -1, -1, -1, -1}}, + TextureIndex{{1344, 1408, 1409, 1472, 1473, 1474, 1536, 1537, 1538, 1539, 1600, 1601, 1602, 1664, 1665, 1728, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{1351, 1352, 1414, 1415, 1416, 1417, 1477, 1478, 1479, 1480, 1481, 1482, 1540, 1541, 1542, 1543, 1544, 1545, 1546, 1547, 1605, 1606, 1607, 1608, 1609, 1610, 1670, 1671, 1672, 1673, 1735, 1736, -1, -1, -1, -1}}, + TextureIndex{{1359, 1360, 1422, 1423, 1424, 1425, 1485, 1486, 1487, 1488, 1489, 1490, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1613, 1614, 1615, 1616, 1617, 1618, 1678, 1679, 1680, 1681, 1743, 1744, -1, -1, -1, -1}}, + TextureIndex{{1304, 1367, 1368, 1369, 1430, 1431, 1432, 1433, 1434, 1493, 1494, 1495, 1496, 1497, 1498, 1499, 1556, 1557, 1558, 1559, 1560, 1561, 1562, 1563, 1621, 1622, 1623, 1624, 1625, 1626, 1686, 1687, 1688, 1689, 1751, 1752}}, + TextureIndex{{1312, 1375, 1376, 1377, 1438, 1439, 1440, 1441, 1442, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1565, 1566, 1567, 1568, 1569, 1570, 1571, 1630, 1631, 1632, 1633, 1634, 1695, 1696, 1697, 1760, -1, -1, -1, -1}}, + TextureIndex{{1320, 1383, 1384, 1385, 1446, 1447, 1448, 1449, 1450, 1509, 1510, 1511, 1512, 1513, 1514, 1515, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1638, 1639, 1640, 1641, 1642, 1703, 1704, 1705, 1768, -1, -1, -1, -1}}, + TextureIndex{{1328, 1391, 1392, 1393, 1454, 1455, 1456, 1457, 1458, 1517, 1518, 1519, 1520, 1521, 1522, 1523, 1581, 1582, 1583, 1584, 1585, 1586, 1587, 1646, 1647, 1648, 1649, 1650, 1711, 1712, 1713, 1776, -1, -1, -1, -1}}, + TextureIndex{{1336, 1399, 1400, 1401, 1462, 1463, 1464, 1465, 1466, 1525, 1526, 1527, 1528, 1529, 1530, 1531, 1589, 1590, 1591, 1592, 1593, 1594, 1595, 1654, 1655, 1656, 1657, 1658, 1719, 1720, 1721, 1784, -1, -1, -1, -1}}, + TextureIndex{{1407, 1470, 1471, 1533, 1534, 1535, 1597, 1598, 1599, 1662, 1663, 1727, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{1603, 1604, 1666, 1667, 1668, 1669, 1729, 1730, 1731, 1732, 1733, 1734, 1792, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1857, 1858, 1859, 1860, 1861, 1862, 1922, 1923, 1924, 1925, 1987, 1988, -1, -1, -1, -1}}, + TextureIndex{{1611, 1612, 1674, 1675, 1676, 1677, 1737, 1738, 1739, 1740, 1741, 1742, 1800, 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1865, 1866, 1867, 1868, 1869, 1870, 1930, 1931, 1932, 1933, 1995, 1996, -1, -1, -1, -1}}, + TextureIndex{{1619, 1620, 1682, 1683, 1684, 1685, 1745, 1746, 1747, 1748, 1749, 1750, 1808, 1809, 1810, 1811, 1812, 1813, 1814, 1815, 1873, 1874, 1875, 1876, 1877, 1878, 1938, 1939, 1940, 1941, 2003, 2004, -1, -1, -1, -1}}, + TextureIndex{{1564, 1627, 1628, 1629, 1690, 1691, 1692, 1693, 1694, 1753, 1754, 1755, 1756, 1757, 1758, 1759, 1816, 1817, 1818, 1819, 1820, 1821, 1822, 1823, 1881, 1882, 1883, 1884, 1885, 1886, 1946, 1947, 1948, 1949, 2011, 2012}}, + TextureIndex{{1572, 1635, 1636, 1637, 1698, 1699, 1700, 1701, 1702, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1890, 1891, 1892, 1893, 1894, 1955, 1956, 1957, 2020, -1, -1, -1, -1}}, + TextureIndex{{1580, 1643, 1644, 1645, 1706, 1707, 1708, 1709, 1710, 1769, 1770, 1771, 1772, 1773, 1774, 1775, 1833, 1834, 1835, 1836, 1837, 1838, 1839, 1898, 1899, 1900, 1901, 1902, 1963, 1964, 1965, 2028, -1, -1, -1, -1}}, + TextureIndex{{1588, 1651, 1652, 1653, 1714, 1715, 1716, 1717, 1718, 1777, 1778, 1779, 1780, 1781, 1782, 1783, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1906, 1907, 1908, 1909, 1910, 1971, 1972, 1973, 2036, -1, -1, -1, -1}}, + TextureIndex{{1596, 1659, 1660, 1661, 1722, 1723, 1724, 1725, 1726, 1785, 1786, 1787, 1788, 1789, 1790, 1791, 1849, 1850, 1851, 1852, 1853, 1854, 1855, 1914, 1915, 1916, 1917, 1918, 1979, 1980, 1981, 2044, -1, -1, -1, -1}}, + TextureIndex{{1856, 1920, 1921, 1984, 1985, 1986, 2048, 2049, 2050, 2051, 2112, 2113, 2114, 2176, 2177, 2240, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{1863, 1864, 1926, 1927, 1928, 1929, 1989, 1990, 1991, 1992, 1993, 1994, 2052, 2053, 2054, 2055, 2056, 2057, 2058, 2059, 2117, 2118, 2119, 2120, 2121, 2122, 2182, 2183, 2184, 2185, 2247, 2248, -1, -1, -1, -1}}, + TextureIndex{{1871, 1872, 1934, 1935, 1936, 1937, 1997, 1998, 1999, 2000, 2001, 2002, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2125, 2126, 2127, 2128, 2129, 2130, 2190, 2191, 2192, 2193, 2255, 2256, -1, -1, -1, -1}}, + TextureIndex{{1879, 1880, 1942, 1943, 1944, 1945, 2005, 2006, 2007, 2008, 2009, 2010, 2068, 2069, 2070, 2071, 2072, 2073, 2074, 2075, 2133, 2134, 2135, 2136, 2137, 2138, 2198, 2199, 2200, 2201, 2263, 2264, -1, -1, -1, -1}}, + TextureIndex{{1824, 1887, 1888, 1889, 1950, 1951, 1952, 1953, 1954, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2141, 2142, 2143, 2144, 2145, 2146, 2206, 2207, 2208, 2209, 2271, 2272}}, + TextureIndex{{1832, 1895, 1896, 1897, 1958, 1959, 1960, 1961, 1962, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2085, 2086, 2087, 2088, 2089, 2090, 2091, 2150, 2151, 2152, 2153, 2154, 2215, 2216, 2217, 2280, -1, -1, -1, -1}}, + TextureIndex{{1840, 1903, 1904, 1905, 1966, 1967, 1968, 1969, 1970, 2029, 2030, 2031, 2032, 2033, 2034, 2035, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2158, 2159, 2160, 2161, 2162, 2223, 2224, 2225, 2288, -1, -1, -1, -1}}, + TextureIndex{{1848, 1911, 1912, 1913, 1974, 1975, 1976, 1977, 1978, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2166, 2167, 2168, 2169, 2170, 2231, 2232, 2233, 2296, -1, -1, -1, -1}}, + TextureIndex{{1919, 1982, 1983, 2045, 2046, 2047, 2109, 2110, 2111, 2174, 2175, 2239, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{2115, 2116, 2178, 2179, 2180, 2181, 2241, 2242, 2243, 2244, 2245, 2246, 2304, 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2369, 2370, 2371, 2372, 2373, 2374, 2434, 2435, 2436, 2437, 2499, 2500, -1, -1, -1, -1}}, + TextureIndex{{2123, 2124, 2186, 2187, 2188, 2189, 2249, 2250, 2251, 2252, 2253, 2254, 2312, 2313, 2314, 2315, 2316, 2317, 2318, 2319, 2377, 2378, 2379, 2380, 2381, 2382, 2442, 2443, 2444, 2445, 2507, 2508, -1, -1, -1, -1}}, + TextureIndex{{2131, 2132, 2194, 2195, 2196, 2197, 2257, 2258, 2259, 2260, 2261, 2262, 2320, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2385, 2386, 2387, 2388, 2389, 2390, 2450, 2451, 2452, 2453, 2515, 2516, -1, -1, -1, -1}}, + TextureIndex{{2139, 2140, 2202, 2203, 2204, 2205, 2265, 2266, 2267, 2268, 2269, 2270, 2328, 2329, 2330, 2331, 2332, 2333, 2334, 2335, 2393, 2394, 2395, 2396, 2397, 2398, 2458, 2459, 2460, 2461, 2523, 2524, -1, -1, -1, -1}}, + TextureIndex{{2084, 2147, 2148, 2149, 2210, 2211, 2212, 2213, 2214, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2401, 2402, 2403, 2404, 2405, 2406, 2466, 2467, 2468, 2469, 2531, 2532}}, + TextureIndex{{2092, 2155, 2156, 2157, 2218, 2219, 2220, 2221, 2222, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2410, 2411, 2412, 2413, 2414, 2475, 2476, 2477, 2540, -1, -1, -1, -1}}, + TextureIndex{{2100, 2163, 2164, 2165, 2226, 2227, 2228, 2229, 2230, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2353, 2354, 2355, 2356, 2357, 2358, 2359, 2418, 2419, 2420, 2421, 2422, 2483, 2484, 2485, 2548, -1, -1, -1, -1}}, + TextureIndex{{2108, 2171, 2172, 2173, 2234, 2235, 2236, 2237, 2238, 2297, 2298, 2299, 2300, 2301, 2302, 2303, 2361, 2362, 2363, 2364, 2365, 2366, 2367, 2426, 2427, 2428, 2429, 2430, 2491, 2492, 2493, 2556, -1, -1, -1, -1}}, + TextureIndex{{2368, 2432, 2433, 2496, 2497, 2498, 2560, 2561, 2562, 2563, 2624, 2625, 2626, 2688, 2689, 2752, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{2375, 2376, 2438, 2439, 2440, 2441, 2501, 2502, 2503, 2504, 2505, 2506, 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2629, 2630, 2631, 2632, 2633, 2634, 2694, 2695, 2696, 2697, 2759, 2760, -1, -1, -1, -1}}, + TextureIndex{{2383, 2384, 2446, 2447, 2448, 2449, 2509, 2510, 2511, 2512, 2513, 2514, 2572, 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2637, 2638, 2639, 2640, 2641, 2642, 2702, 2703, 2704, 2705, 2767, 2768, -1, -1, -1, -1}}, + TextureIndex{{2391, 2392, 2454, 2455, 2456, 2457, 2517, 2518, 2519, 2520, 2521, 2522, 2580, 2581, 2582, 2583, 2584, 2585, 2586, 2587, 2645, 2646, 2647, 2648, 2649, 2650, 2710, 2711, 2712, 2713, 2775, 2776, -1, -1, -1, -1}}, + TextureIndex{{2399, 2400, 2462, 2463, 2464, 2465, 2525, 2526, 2527, 2528, 2529, 2530, 2588, 2589, 2590, 2591, 2592, 2593, 2594, 2595, 2653, 2654, 2655, 2656, 2657, 2658, 2718, 2719, 2720, 2721, 2783, 2784, -1, -1, -1, -1}}, + TextureIndex{{2344, 2407, 2408, 2409, 2470, 2471, 2472, 2473, 2474, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2596, 2597, 2598, 2599, 2600, 2601, 2602, 2603, 2661, 2662, 2663, 2664, 2665, 2666, 2726, 2727, 2728, 2729, 2791, 2792}}, + TextureIndex{{2352, 2415, 2416, 2417, 2478, 2479, 2480, 2481, 2482, 2541, 2542, 2543, 2544, 2545, 2546, 2547, 2605, 2606, 2607, 2608, 2609, 2610, 2611, 2670, 2671, 2672, 2673, 2674, 2735, 2736, 2737, 2800, -1, -1, -1, -1}}, + TextureIndex{{2360, 2423, 2424, 2425, 2486, 2487, 2488, 2489, 2490, 2549, 2550, 2551, 2552, 2553, 2554, 2555, 2613, 2614, 2615, 2616, 2617, 2618, 2619, 2678, 2679, 2680, 2681, 2682, 2743, 2744, 2745, 2808, -1, -1, -1, -1}}, + TextureIndex{{2431, 2494, 2495, 2557, 2558, 2559, 2621, 2622, 2623, 2686, 2687, 2751, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{2627, 2628, 2690, 2691, 2692, 2693, 2753, 2754, 2755, 2756, 2757, 2758, 2816, 2817, 2818, 2819, 2820, 2821, 2822, 2823, 2881, 2882, 2883, 2884, 2885, 2886, 2946, 2947, 2948, 2949, 3011, 3012, -1, -1, -1, -1}}, + TextureIndex{{2635, 2636, 2698, 2699, 2700, 2701, 2761, 2762, 2763, 2764, 2765, 2766, 2824, 2825, 2826, 2827, 2828, 2829, 2830, 2831, 2889, 2890, 2891, 2892, 2893, 2894, 2954, 2955, 2956, 2957, 3019, 3020, -1, -1, -1, -1}}, + TextureIndex{{2643, 2644, 2706, 2707, 2708, 2709, 2769, 2770, 2771, 2772, 2773, 2774, 2832, 2833, 2834, 2835, 2836, 2837, 2838, 2839, 2897, 2898, 2899, 2900, 2901, 2902, 2962, 2963, 2964, 2965, 3027, 3028, -1, -1, -1, -1}}, + TextureIndex{{2651, 2652, 2714, 2715, 2716, 2717, 2777, 2778, 2779, 2780, 2781, 2782, 2840, 2841, 2842, 2843, 2844, 2845, 2846, 2847, 2905, 2906, 2907, 2908, 2909, 2910, 2970, 2971, 2972, 2973, 3035, 3036, -1, -1, -1, -1}}, + TextureIndex{{2659, 2660, 2722, 2723, 2724, 2725, 2785, 2786, 2787, 2788, 2789, 2790, 2848, 2849, 2850, 2851, 2852, 2853, 2854, 2855, 2913, 2914, 2915, 2916, 2917, 2918, 2978, 2979, 2980, 2981, 3043, 3044, -1, -1, -1, -1}}, + TextureIndex{{2604, 2667, 2668, 2669, 2730, 2731, 2732, 2733, 2734, 2793, 2794, 2795, 2796, 2797, 2798, 2799, 2856, 2857, 2858, 2859, 2860, 2861, 2862, 2863, 2921, 2922, 2923, 2924, 2925, 2926, 2986, 2987, 2988, 2989, 3051, 3052}}, + TextureIndex{{2612, 2675, 2676, 2677, 2738, 2739, 2740, 2741, 2742, 2801, 2802, 2803, 2804, 2805, 2806, 2807, 2865, 2866, 2867, 2868, 2869, 2870, 2871, 2930, 2931, 2932, 2933, 2934, 2995, 2996, 2997, 3060, -1, -1, -1, -1}}, + TextureIndex{{2620, 2683, 2684, 2685, 2746, 2747, 2748, 2749, 2750, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2873, 2874, 2875, 2876, 2877, 2878, 2879, 2938, 2939, 2940, 2941, 2942, 3003, 3004, 3005, 3068, -1, -1, -1, -1}}, + TextureIndex{{2880, 2944, 2945, 3008, 3009, 3010, 3072, 3073, 3074, 3075, 3136, 3137, 3138, 3200, 3201, 3264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{2887, 2888, 2950, 2951, 2952, 2953, 3013, 3014, 3015, 3016, 3017, 3018, 3076, 3077, 3078, 3079, 3080, 3081, 3082, 3083, 3141, 3142, 3143, 3144, 3145, 3146, 3206, 3207, 3208, 3209, 3271, 3272, -1, -1, -1, -1}}, + TextureIndex{{2895, 2896, 2958, 2959, 2960, 2961, 3021, 3022, 3023, 3024, 3025, 3026, 3084, 3085, 3086, 3087, 3088, 3089, 3090, 3091, 3149, 3150, 3151, 3152, 3153, 3154, 3214, 3215, 3216, 3217, 3279, 3280, -1, -1, -1, -1}}, + TextureIndex{{2903, 2904, 2966, 2967, 2968, 2969, 3029, 3030, 3031, 3032, 3033, 3034, 3092, 3093, 3094, 3095, 3096, 3097, 3098, 3099, 3157, 3158, 3159, 3160, 3161, 3162, 3222, 3223, 3224, 3225, 3287, 3288, -1, -1, -1, -1}}, + TextureIndex{{2911, 2912, 2974, 2975, 2976, 2977, 3037, 3038, 3039, 3040, 3041, 3042, 3100, 3101, 3102, 3103, 3104, 3105, 3106, 3107, 3165, 3166, 3167, 3168, 3169, 3170, 3230, 3231, 3232, 3233, 3295, 3296, -1, -1, -1, -1}}, + TextureIndex{{2919, 2920, 2982, 2983, 2984, 2985, 3045, 3046, 3047, 3048, 3049, 3050, 3108, 3109, 3110, 3111, 3112, 3113, 3114, 3115, 3173, 3174, 3175, 3176, 3177, 3178, 3238, 3239, 3240, 3241, 3303, 3304, -1, -1, -1, -1}}, + TextureIndex{{2864, 2927, 2928, 2929, 2990, 2991, 2992, 2993, 2994, 3053, 3054, 3055, 3056, 3057, 3058, 3059, 3116, 3117, 3118, 3119, 3120, 3121, 3122, 3123, 3181, 3182, 3183, 3184, 3185, 3186, 3246, 3247, 3248, 3249, 3311, 3312}}, + TextureIndex{{2872, 2935, 2936, 2937, 2998, 2999, 3000, 3001, 3002, 3061, 3062, 3063, 3064, 3065, 3066, 3067, 3125, 3126, 3127, 3128, 3129, 3130, 3131, 3190, 3191, 3192, 3193, 3194, 3255, 3256, 3257, 3320, -1, -1, -1, -1}}, + TextureIndex{{2943, 3006, 3007, 3069, 3070, 3071, 3133, 3134, 3135, 3198, 3199, 3263, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3139, 3140, 3202, 3203, 3204, 3205, 3265, 3266, 3267, 3268, 3269, 3270, 3328, 3329, 3330, 3331, 3332, 3333, 3334, 3335, 3393, 3394, 3395, 3396, 3397, 3398, 3458, 3459, 3460, 3461, 3523, 3524, -1, -1, -1, -1}}, + TextureIndex{{3147, 3148, 3210, 3211, 3212, 3213, 3273, 3274, 3275, 3276, 3277, 3278, 3336, 3337, 3338, 3339, 3340, 3341, 3342, 3343, 3401, 3402, 3403, 3404, 3405, 3406, 3466, 3467, 3468, 3469, 3531, 3532, -1, -1, -1, -1}}, + TextureIndex{{3155, 3156, 3218, 3219, 3220, 3221, 3281, 3282, 3283, 3284, 3285, 3286, 3344, 3345, 3346, 3347, 3348, 3349, 3350, 3351, 3409, 3410, 3411, 3412, 3413, 3414, 3474, 3475, 3476, 3477, 3539, 3540, -1, -1, -1, -1}}, + TextureIndex{{3163, 3164, 3226, 3227, 3228, 3229, 3289, 3290, 3291, 3292, 3293, 3294, 3352, 3353, 3354, 3355, 3356, 3357, 3358, 3359, 3417, 3418, 3419, 3420, 3421, 3422, 3482, 3483, 3484, 3485, 3547, 3548, -1, -1, -1, -1}}, + TextureIndex{{3171, 3172, 3234, 3235, 3236, 3237, 3297, 3298, 3299, 3300, 3301, 3302, 3360, 3361, 3362, 3363, 3364, 3365, 3366, 3367, 3425, 3426, 3427, 3428, 3429, 3430, 3490, 3491, 3492, 3493, 3555, 3556, -1, -1, -1, -1}}, + TextureIndex{{3179, 3180, 3242, 3243, 3244, 3245, 3305, 3306, 3307, 3308, 3309, 3310, 3368, 3369, 3370, 3371, 3372, 3373, 3374, 3375, 3433, 3434, 3435, 3436, 3437, 3438, 3498, 3499, 3500, 3501, 3563, 3564, -1, -1, -1, -1}}, + TextureIndex{{3124, 3187, 3188, 3189, 3250, 3251, 3252, 3253, 3254, 3313, 3314, 3315, 3316, 3317, 3318, 3319, 3376, 3377, 3378, 3379, 3380, 3381, 3382, 3383, 3441, 3442, 3443, 3444, 3445, 3446, 3506, 3507, 3508, 3509, 3571, 3572}}, + TextureIndex{{3132, 3195, 3196, 3197, 3258, 3259, 3260, 3261, 3262, 3321, 3322, 3323, 3324, 3325, 3326, 3327, 3385, 3386, 3387, 3388, 3389, 3390, 3391, 3450, 3451, 3452, 3453, 3454, 3515, 3516, 3517, 3580, -1, -1, -1, -1}}, + TextureIndex{{3392, 3456, 3457, 3520, 3521, 3522, 3584, 3585, 3586, 3587, 3648, 3649, 3650, 3712, 3713, 3776, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3399, 3400, 3462, 3463, 3464, 3465, 3525, 3526, 3527, 3528, 3529, 3530, 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3595, 3653, 3654, 3655, 3656, 3657, 3658, 3718, 3719, 3720, 3721, 3783, 3784, -1, -1, -1, -1}}, + TextureIndex{{3407, 3408, 3470, 3471, 3472, 3473, 3533, 3534, 3535, 3536, 3537, 3538, 3596, 3597, 3598, 3599, 3600, 3601, 3602, 3603, 3661, 3662, 3663, 3664, 3665, 3666, 3726, 3727, 3728, 3729, 3791, 3792, -1, -1, -1, -1}}, + TextureIndex{{3415, 3416, 3478, 3479, 3480, 3481, 3541, 3542, 3543, 3544, 3545, 3546, 3604, 3605, 3606, 3607, 3608, 3609, 3610, 3611, 3669, 3670, 3671, 3672, 3673, 3674, 3734, 3735, 3736, 3737, 3799, 3800, -1, -1, -1, -1}}, + TextureIndex{{3423, 3424, 3486, 3487, 3488, 3489, 3549, 3550, 3551, 3552, 3553, 3554, 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, 3677, 3678, 3679, 3680, 3681, 3682, 3742, 3743, 3744, 3745, 3807, 3808, -1, -1, -1, -1}}, + TextureIndex{{3431, 3432, 3494, 3495, 3496, 3497, 3557, 3558, 3559, 3560, 3561, 3562, 3620, 3621, 3622, 3623, 3624, 3625, 3626, 3627, 3685, 3686, 3687, 3688, 3689, 3690, 3750, 3751, 3752, 3753, 3815, 3816, -1, -1, -1, -1}}, + TextureIndex{{3439, 3440, 3502, 3503, 3504, 3505, 3565, 3566, 3567, 3568, 3569, 3570, 3628, 3629, 3630, 3631, 3632, 3633, 3634, 3635, 3693, 3694, 3695, 3696, 3697, 3698, 3758, 3759, 3760, 3761, 3823, 3824, -1, -1, -1, -1}}, + TextureIndex{{3384, 3447, 3448, 3449, 3510, 3511, 3512, 3513, 3514, 3573, 3574, 3575, 3576, 3577, 3578, 3579, 3636, 3637, 3638, 3639, 3640, 3641, 3642, 3643, 3701, 3702, 3703, 3704, 3705, 3706, 3766, 3767, 3768, 3769, 3831, 3832}}, + TextureIndex{{3455, 3518, 3519, 3581, 3582, 3583, 3645, 3646, 3647, 3710, 3711, 3775, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3651, 3652, 3714, 3715, 3716, 3717, 3777, 3778, 3779, 3780, 3781, 3782, 3840, 3841, 3842, 3843, 3844, 3845, 3846, 3847, 3905, 3906, 3907, 3908, 3909, 3910, 3970, 3971, 3972, 3973, 4035, 4036, -1, -1, -1, -1}}, + TextureIndex{{3659, 3660, 3722, 3723, 3724, 3725, 3785, 3786, 3787, 3788, 3789, 3790, 3848, 3849, 3850, 3851, 3852, 3853, 3854, 3855, 3913, 3914, 3915, 3916, 3917, 3918, 3978, 3979, 3980, 3981, 4043, 4044, -1, -1, -1, -1}}, + TextureIndex{{3667, 3668, 3730, 3731, 3732, 3733, 3793, 3794, 3795, 3796, 3797, 3798, 3856, 3857, 3858, 3859, 3860, 3861, 3862, 3863, 3921, 3922, 3923, 3924, 3925, 3926, 3986, 3987, 3988, 3989, 4051, 4052, -1, -1, -1, -1}}, + TextureIndex{{3675, 3676, 3738, 3739, 3740, 3741, 3801, 3802, 3803, 3804, 3805, 3806, 3864, 3865, 3866, 3867, 3868, 3869, 3870, 3871, 3929, 3930, 3931, 3932, 3933, 3934, 3994, 3995, 3996, 3997, 4059, 4060, -1, -1, -1, -1}}, + TextureIndex{{3683, 3684, 3746, 3747, 3748, 3749, 3809, 3810, 3811, 3812, 3813, 3814, 3872, 3873, 3874, 3875, 3876, 3877, 3878, 3879, 3937, 3938, 3939, 3940, 3941, 3942, 4002, 4003, 4004, 4005, 4067, 4068, -1, -1, -1, -1}}, + TextureIndex{{3691, 3692, 3754, 3755, 3756, 3757, 3817, 3818, 3819, 3820, 3821, 3822, 3880, 3881, 3882, 3883, 3884, 3885, 3886, 3887, 3945, 3946, 3947, 3948, 3949, 3950, 4010, 4011, 4012, 4013, 4075, 4076, -1, -1, -1, -1}}, + TextureIndex{{3699, 3700, 3762, 3763, 3764, 3765, 3825, 3826, 3827, 3828, 3829, 3830, 3888, 3889, 3890, 3891, 3892, 3893, 3894, 3895, 3953, 3954, 3955, 3956, 3957, 3958, 4018, 4019, 4020, 4021, 4083, 4084, -1, -1, -1, -1}}, + TextureIndex{{3644, 3707, 3708, 3709, 3770, 3771, 3772, 3773, 3774, 3833, 3834, 3835, 3836, 3837, 3838, 3839, 3896, 3897, 3898, 3899, 3900, 3901, 3902, 3903, 3961, 3962, 3963, 3964, 3965, 3966, 4026, 4027, 4028, 4029, 4091, 4092}}, + TextureIndex{{3904, 3968, 3969, 4032, 4033, 4034, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3911, 3912, 3974, 3975, 3976, 3977, 4037, 4038, 4039, 4040, 4041, 4042, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3919, 3920, 3982, 3983, 3984, 3985, 4045, 4046, 4047, 4048, 4049, 4050, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3927, 3928, 3990, 3991, 3992, 3993, 4053, 4054, 4055, 4056, 4057, 4058, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3935, 3936, 3998, 3999, 4000, 4001, 4061, 4062, 4063, 4064, 4065, 4066, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3943, 3944, 4006, 4007, 4008, 4009, 4069, 4070, 4071, 4072, 4073, 4074, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3951, 3952, 4014, 4015, 4016, 4017, 4077, 4078, 4079, 4080, 4081, 4082, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3959, 3960, 4022, 4023, 4024, 4025, 4085, 4086, 4087, 4088, 4089, 4090, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + TextureIndex{{3967, 4030, 4031, 4093, 4094, 4095, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}, + }; +} diff --git a/src/noggit/scripting/script_vert.cpp b/src/noggit/scripting/script_vert.cpp new file mode 100644 index 000000000..cd400a326 --- /dev/null +++ b/src/noggit/scripting/script_vert.cpp @@ -0,0 +1,180 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include + +#include + +#include + +// maximum amount of texunits that can be closest to a vertex +#define MAX_TEXUNITS_PER_VERT 36 +// total amount of vertices in each pair of two rows +#define VERTS_PER_TWO_ROWS 17 +// maximum vertex index on odd rows +#define VERTS_ON_ODD_ROWS 8 + +#include + +namespace noggit +{ + namespace scripting + { + vert::vert(script_context * ctx, MapChunk* chunk, int index) + : script_object(ctx) + , _chunk(chunk) + , _index(index) + { + } + + void vert::set_height(float value) + { + _chunk->mVertices[_index].y = value; + } + + void vert::add_height(float value) + { + _chunk->mVertices[_index].y += value; + } + + void vert::sub_height(float value) + { + _chunk->mVertices[_index].y -= value; + } + + void vert::set_color(float r, float g, float b) + { + _chunk->maybe_create_mccv(); + _chunk->mccv[_index] = math::vector_3d(r, g, b); + } + + math::vector_3d vert::get_color() + { + if (!_chunk->hasColors()) + { + return math::vector_3d(1, 1, 1); + } + else + { + return math::vector_3d(_chunk->mccv[_index]); + } + } + + void vert::set_water(int type, float height) + { + if (is_water_aligned()) + { + return; + } + + // TODO: Extremely inefficient + _chunk->liquid_chunk()->paintLiquid(get_pos(), 1, type, true, math::radians(0), math::radians(0), true, math::vector_3d(0, height, 0), true, true, _chunk, 1); + } + + void vert::set_hole(bool add) + { + _chunk->setHole(get_pos(), false, add); + } + + math::vector_3d vert::get_pos() + { + return _chunk->mVertices[_index]; + } + + void vert::set_alpha(int index, float alpha) + { + if(index<0||index>3) + { + throw script_exception( + "vert::set_alpha", + std::string("invalid texture layer: ") + + std::to_string(index)); + } + if (index == 0) + { + return; + } + auto& ts = _chunk->texture_set; + ts->create_temporary_alphamaps_if_needed(); + + auto tex_indices = texture_index[_index]; + + for ( auto iter = std::begin(tex_indices.indices) + ; iter != std::end(tex_indices.indices) + ; ++iter + ) + { + if (*iter == -1) + break; + ts->tmp_edit_values.get()[index][*iter] = alpha; + } + } + + float vert::get_alpha(int index) + { + if(index<0||index>3) + { + throw script_exception( + "vert::get_alpha", + std::string("invalid texture layer: ") + + std::to_string(index)); + } + if (index == 0) + { + return 1; + } + auto& ts = _chunk->texture_set; + ts->create_temporary_alphamaps_if_needed(); + auto tex_indices = texture_index[_index]; + + float sum = 0; + int ctr = 0; + for (auto iter = std::begin(tex_indices.indices) + ; iter != std::end(tex_indices.indices) + ; ++iter + ) + { + if (*iter == -1) + break; + sum += ts->tmp_edit_values.get()[index][*iter]; + ++ctr; + } + return sum / float(ctr); + } + + bool vert::is_water_aligned() + { + return (_index % VERTS_PER_TWO_ROWS) > VERTS_ON_ODD_ROWS; + } + + sol::as_table_t> vert::textures() + { + std::vector texVec; + for (int i = 0; i < MAX_TEXUNITS_PER_VERT; ++i) + { + if (texture_index[_index].indices[i] == -1) break; + texVec.emplace_back(state(), _chunk, texture_index[_index].indices[i]); + } + return sol::as_table(texVec); + } + + void register_vert(script_context * state) + { + state->new_usertype("vert" + , "get_pos", &vert::get_pos + , "set_height", &vert::set_height + , "add_height", &vert::add_height + , "sub_height", &vert::sub_height + , "set_color", &vert::set_color + , "get_color", &vert::get_color + , "set_water", &vert::set_water + , "set_hole", &vert::set_hole + , "set_alpha", &vert::set_alpha + , "get_alpha", &vert::get_alpha + , "tex", &vert::textures + , "is_water_aligned", &vert::is_water_aligned + ); + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/script_vert.hpp b/src/noggit/scripting/script_vert.hpp new file mode 100644 index 000000000..44f98c20c --- /dev/null +++ b/src/noggit/scripting/script_vert.hpp @@ -0,0 +1,42 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include +#include + +#include +#include + +namespace noggit +{ + namespace scripting + { + class scripting_tool; + class script_context; + + class vert: public script_object + { + public: + vert(script_context * ctx, MapChunk* chunk, int index); + math::vector_3d get_pos(); + void set_height(float y); + void add_height(float y); + void sub_height(float y); + + math::vector_3d get_color(); + void set_color(float r, float g, float b); + void set_water(int type, float height); + void set_hole(bool add); + void set_alpha(int index, float alpha); + float get_alpha(int index); + sol::as_table_t> textures(); + bool is_water_aligned(); + + private: + MapChunk* _chunk; + int _index; + }; + + void register_vert(script_context * state); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/scripting_tool.cpp b/src/noggit/scripting/scripting_tool.cpp new file mode 100644 index 000000000..ebf983b23 --- /dev/null +++ b/src/noggit/scripting/scripting_tool.cpp @@ -0,0 +1,323 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define CUR_PROFILE_PATH "__cur_profile" + +namespace noggit +{ + namespace scripting + { + // TEMP: remove when exceptions are working + namespace + { + std::string cur_exception = ""; + } + void set_cur_exception(std::string const& exception) + { + cur_exception = exception; + } + + void scripting_tool::doReload() + { + get_settings()->clear(); + clearLog(); + int old_selection = -1; + try + { + std::string old_name = get_context() == nullptr ? "" : get_context()->get_selected_name(); + _script_context = std::make_unique(this); + for(int i=0;iget_scripts().size(); ++i) + { + if(get_context()->get_scripts()[i]->get_name() == old_name) + { + old_selection = i; + break; + } + } + + // default to 0 if there are entries + if(get_context()->get_scripts().size()>0 && old_selection < 0) + { + old_selection = 0; + } + } + catch (std::exception const& e) + { + addLog("[error]: " + std::string(e.what())); + resetLogScroll(); + return; + } + + _selection->clear(); + + for(auto& script : get_context()->get_scripts()) + { + _selection->addItem(script->get_name().c_str()); + } + + if (old_selection >= 0) + { + _selection->setCurrentIndex(old_selection); + change_script(old_selection); + } + } + + void scripting_tool::change_script(int selection) + { + std::lock_guard const lock (_script_change_mutex); + + clearDescription(); + get_settings()->clear(); + + auto sn = _script_context->get_scripts()[selection]->get_name(); + + get_profiles()->clear(); + + auto json = get_settings()->get_raw_json(); + + if (json->contains(sn)) + { + std::vector items; + for (auto& v : (*json)[sn].items()) + { + if (v.key() != CUR_PROFILE_PATH) + { + items.push_back(v.key()); + } + } + + std::sort(items.begin(), items.end(), [](auto a, auto b) { + if (a == "Default") + return true; + if (b == "Default") + return false; + return a < b; + }); + + for (auto& item : items) + { + get_profiles()->add_profile(item); + } + } + + if (get_profiles()->profile_count() == 0) + { + get_profiles()->add_profile("Default"); + } + + int next_profile = 0; + auto cur_script = get_context()->get_scripts()[selection]->get_name(); + if (json->contains(cur_script)) + { + if ((*json)[cur_script].contains(CUR_PROFILE_PATH)) + { + auto str = (*json)[cur_script][CUR_PROFILE_PATH].get(); + for (int i = 0; i < get_profiles()->profile_count(); ++i) + { + if (get_profiles()->get_profile(i) == str) + { + next_profile = i; + break; + } + } + } + } + + get_profiles()->select_profile(next_profile); + + try { + get_context()->select_script(selection); + } catch(script_exception const& err) + { + addLog(err.what()); + } + get_settings()->initialize(); + } + + scripting_tool::scripting_tool( + QWidget* parent + , MapView* view + , QSettings* noggit_settings + ) + : QWidget(parent) + , _cur_profile ("Default") + , _view(view) + , _noggit_settings(noggit_settings) + { + auto layout(new QVBoxLayout(this)); + _selection = new QComboBox(); + layout->addWidget(_selection); + + _reload_button = new QPushButton("Reload Scripts", this); + layout->addWidget(_reload_button); + connect(_reload_button, &QPushButton::released, this, [this]() { + doReload(); + }); + + _profiles = new script_profiles(this); + layout->addWidget(_profiles); + + _settings = new script_settings(this); + _settings->load_json(); + layout->addWidget(_settings); + + _description = new QLabel(this); + layout->addWidget(_description); + + _log = new QPlainTextEdit(this); + _log->setFont (QFontDatabase::systemFont (QFontDatabase::FixedFont)); + _log->setReadOnly(true); + layout->addWidget(_log); + + connect(_selection + , QOverload::of(&QComboBox::activated) + , this + , [this](auto index) + { + clearLog(); + change_script(index); + }); + + doReload(); + } + + scripting_tool::~scripting_tool() + { + get_settings()->save_json(); + } + + void scripting_tool::sendBrushEvent(math::vector_3d const& pos, float dt) + { + bool new_left = get_view()->leftMouse; + bool new_right = get_view()->rightMouse; + + auto evt = std::make_shared( + get_settings() + , pos + , dt + ); + + try + { + int sel = get_context()->get_selection(); + if(sel>=0) + { + auto brush = get_context()->get_scripts()[sel]; + if(new_left) + { + if(!_last_left ) brush->on_left_click.call_if_exists("brush_event",evt); + else brush->on_left_hold.call_if_exists("brush_event",evt); + } + else + { + if(_last_left) brush->on_left_release.call_if_exists("(brush_event)",evt); + } + + if(new_right) + { + if(!_last_right) brush->on_right_hold.call_if_exists("brush_event",evt); + else brush->on_right_hold.call_if_exists("brush_event",evt); + } + else + { + if(_last_right) brush->on_right_release.call_if_exists("(brush_event)",evt); + } + } + } + catch (std::exception const& e) + { + doReload(); + // TEMP: remove when exceptions are working + if(std::string(e.what()).find("C++ exception") == 0 && cur_exception.size()>0) + { + addLog("[error]: "+std::string(cur_exception)); + cur_exception = ""; + } + else + { + addLog(("[error]: " + std::string(e.what()))); + } + resetLogScroll(); + } + _last_left = new_left; + _last_right = new_right; + } + + void scripting_tool::addDescription(std::string const& stext) + { + _description->setText(_description->text() + + "\n" + + QString::fromStdString (stext) + ); + } + + void scripting_tool::addLog(std::string const& text) + { + + LogDebug << "[script window]: " << text << "\n"; + _log->appendPlainText (QString::fromStdString (text)); + _log->verticalScrollBar()->setValue(_log->verticalScrollBar()->maximum()); + } + + script_context* scripting_tool::get_context() + { + return _script_context.get(); + } + + MapView* scripting_tool::get_view() + { + return _view; + } + + void scripting_tool::resetLogScroll() + { + _log->verticalScrollBar()->setValue(0); + } + + void scripting_tool::clearLog() + { + _log->clear(); + } + + void scripting_tool::clearDescription() + { + _description->clear(); + } + + script_settings* scripting_tool::get_settings() + { + return _settings; + } + + script_profiles* scripting_tool::get_profiles() + { + return _profiles; + } + + QSettings* scripting_tool::get_noggit_settings() + { + return _noggit_settings; + } + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/scripting/scripting_tool.hpp b/src/noggit/scripting/scripting_tool.hpp new file mode 100644 index 000000000..aa86ca3ff --- /dev/null +++ b/src/noggit/scripting/scripting_tool.hpp @@ -0,0 +1,86 @@ +// This file is part of Noggit3, licensed under GNU General Public License (version 3). +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class World; +class MapView; + +namespace noggit +{ + class camera; + namespace scripting + { + class script_context; + class script_settings; + class script_profiles; + class scripting_tool : public QWidget + { + public: + scripting_tool(QWidget* parent + , MapView* view + , QSettings * noggit_settings + ); + ~scripting_tool(); + + void addDescription(std::string const& text); + void clearDescription(); + void addLog(std::string const& text); + void resetLogScroll(); + void clearLog(); + void doReload(); + void sendBrushEvent(math::vector_3d const& pos,float dt); + + MapView* get_view(); + script_context* get_context(); + script_settings* get_settings(); + script_profiles* get_profiles(); + QSettings* get_noggit_settings(); + + private: + std::mutex _script_change_mutex; + std::string _cur_profile; + + bool _last_left = false; + bool _last_right = false; + + private: + QComboBox* _selection; + QPushButton* _reload_button; + + QLabel* _description; + QPlainTextEdit* _log; + + script_settings *_settings; + script_profiles *_profiles; + private: + std::unique_ptr _script_context = nullptr; + MapView* _view; + QSettings * _noggit_settings; + void change_script(int script_index); + }; + + // TEMP: remove when exceptions are working + void set_cur_exception(std::string const& exception); + } // namespace scripting +} // namespace noggit diff --git a/src/noggit/texture_set.cpp b/src/noggit/texture_set.cpp index 85893b7a9..3d6895373 100644 --- a/src/noggit/texture_set.cpp +++ b/src/noggit/texture_set.cpp @@ -407,8 +407,6 @@ bool TextureSet::paintTexture(float xbase, float zbase, float x, float z, Brush* if (dist <= radius) { - std::size_t offset = i + 64 * j; - // use double for more precision std::array alpha_values; double total = 0.; @@ -623,6 +621,11 @@ unsigned int TextureSet::flag(size_t id) return _layers_info[id].flags; } +void TextureSet::setEffect(size_t id, int value) +{ + _layers_info[id].effectID = value; +} + unsigned int TextureSet::effect(size_t id) { return _layers_info[id].effectID; diff --git a/src/noggit/texture_set.hpp b/src/noggit/texture_set.hpp index c567f7064..0be400e64 100644 --- a/src/noggit/texture_set.hpp +++ b/src/noggit/texture_set.hpp @@ -57,6 +57,7 @@ class TextureSet size_t const& num() const { return nTextures; } unsigned int flag(size_t id); unsigned int effect(size_t id); + void setEffect(size_t id, int value); bool is_animated(std::size_t id) const; void change_texture_flag(scoped_blp_texture_reference const& tex, std::size_t flag, bool add); @@ -75,6 +76,10 @@ class TextureSet std::vector lod_texture_map(); bool apply_alpha_changes(); + + void create_temporary_alphamaps_if_needed(); + size_t nTextures; + boost::optional tmp_edit_values; private: int get_texture_index_or_add (scoped_blp_texture_reference texture, float target); @@ -89,16 +94,11 @@ class TextureSet std::array, 3> alphamaps; opengl::texture amap_gl_tex; bool _need_amap_update = true; - size_t nTextures; std::vector _lod_texture_map; bool _need_lod_texture_map_update = false; ENTRY_MCLY _layers_info[4]; - boost::optional tmp_edit_values; - - void create_temporary_alphamaps_if_needed(); - bool _do_not_convert_alphamaps; }; diff --git a/src/noggit/tool_enums.hpp b/src/noggit/tool_enums.hpp index b76a1b256..2ceafc673 100644 --- a/src/noggit/tool_enums.hpp +++ b/src/noggit/tool_enums.hpp @@ -70,6 +70,9 @@ enum class editing_mode water, mccv, object, +#ifdef NOGGIT_HAS_SCRIPTING + scripting +#endif }; enum water_opacity diff --git a/src/noggit/ui/SettingsPanel.cpp b/src/noggit/ui/SettingsPanel.cpp index 636fa6eff..548e47afc 100644 --- a/src/noggit/ui/SettingsPanel.cpp +++ b/src/noggit/ui/SettingsPanel.cpp @@ -171,6 +171,10 @@ namespace noggit layout->addRow("Additional file loading log", _additional_file_loading_log = new QCheckBox(this)); +#ifdef NOGGIT_HAS_SCRIPTING + layout->addRow("Allow scripts to write to any file",_allow_scripts_write_any_file = new QCheckBox(this)); +#endif + auto warning (new QWidget (this)); new QHBoxLayout (warning); auto icon (new QLabel (warning)); @@ -226,7 +230,9 @@ namespace noggit _adt_unload_check_interval->setValue(_settings->value("unload_interval", 5).toInt()); _uid_cb->setChecked(_settings->value("uid_startup_check", true).toBool()); _additional_file_loading_log->setChecked(_settings->value("additional_file_loading_log", false).toBool()); - +#ifdef NOGGIT_HAS_SCRIPTING + _allow_scripts_write_any_file->setChecked(_settings->value("allow_scripts_write_any_file",false).toBool()); +#endif #ifdef USE_MYSQL_UID_STORAGE _mysql_box->setChecked (_settings->value ("project/mysql/enabled").toBool()); _mysql_server_field->setText (_settings->value ("project/mysql/server").toString()); @@ -260,6 +266,10 @@ namespace noggit _settings->setValue ("uid_startup_check", _uid_cb->isChecked()); _settings->setValue ("additional_file_loading_log", _additional_file_loading_log->isChecked()); +#ifdef NOGGIT_HAS_SCRIPTING + _settings->setValue ("allow_scripts_write_any_file", _allow_scripts_write_any_file->isChecked()); +#endif + #ifdef USE_MYSQL_UID_STORAGE _settings->setValue ("project/mysql/enabled", _mysql_box->isChecked()); _settings->setValue ("project/mysql/server", _mysql_server_field->text()); diff --git a/src/noggit/ui/SettingsPanel.h b/src/noggit/ui/SettingsPanel.h index 6b73d5dc8..d528bde0e 100644 --- a/src/noggit/ui/SettingsPanel.h +++ b/src/noggit/ui/SettingsPanel.h @@ -54,6 +54,10 @@ namespace noggit QCheckBox* _additional_file_loading_log; +#ifdef NOGGIT_HAS_SCRIPTING + QCheckBox* _allow_scripts_write_any_file; +#endif + QGroupBox* _mysql_box; #ifdef USE_MYSQL_UID_STORAGE QLineEdit* _mysql_server_field; diff --git a/src/noggit/ui/Toolbar.cpp b/src/noggit/ui/Toolbar.cpp index 2f1651fff..7d4a762d6 100644 --- a/src/noggit/ui/Toolbar.cpp +++ b/src/noggit/ui/Toolbar.cpp @@ -19,6 +19,9 @@ namespace noggit add_tool_icon (editing_mode::water, tr("Water edit"), font_awesome::water); add_tool_icon (editing_mode::mccv, tr("Shader editor"), font_awesome::eyedropper); add_tool_icon (editing_mode::object, tr("Object editor"), font_awesome::cube); +#ifdef NOGGIT_HAS_SCRIPTING + add_tool_icon (editing_mode::scripting, tr("Script Editor"), font_awesome::book); +#endif } void toolbar::add_tool_icon(editing_mode mode, const QString& name, const font_awesome::icons& icon) diff --git a/src/noggit/ui/main_window.cpp b/src/noggit/ui/main_window.cpp index a64a1f23b..5d6e5b451 100644 --- a/src/noggit/ui/main_window.cpp +++ b/src/noggit/ui/main_window.cpp @@ -20,6 +20,9 @@ #include #include #include +#ifdef NOGGIT_HAS_SCRIPTING +#include +#endif #ifdef USE_MYSQL_UID_STORAGE #include @@ -40,6 +43,9 @@ namespace noggit { std::stringstream title; title << "Noggit - " << STRPRODUCTVER; +#ifdef TESTING_VERSION + title << " -- UNOFFICIAL TESTING VERSION"; +#endif setWindowTitle (QString::fromStdString (title.str())); setWindowIcon (QIcon (":/icon")); @@ -330,6 +336,7 @@ namespace noggit prompt.setDefaultButton (prompt.addButton ("Cancel", QMessageBox::RejectRole)); prompt.setWindowFlags (Qt::CustomizeWindowHint | Qt::WindowTitleHint); + prompt.exec(); switch (prompt.buttonRole(prompt.clickedButton())) diff --git a/src/util/visit.ipp b/src/util/visit.ipp index 38f12dba0..e49967c07 100644 --- a/src/util/visit.ipp +++ b/src/util/visit.ipp @@ -23,11 +23,14 @@ namespace util template auto visit (Variant& variant, Funs... funs) { - struct only_inherit_funs : Funs... {}; + struct only_inherit_funs : Funs... { + using Funs::operator()...; + }; using Ret = typename detail::require_all_results_same_for_variant_apply, only_inherit_funs>::type; struct lambda_visitor : boost::static_visitor, Funs... { + using Funs::operator()...; lambda_visitor (Funs... funs) : Funs (funs)... {}