From 89872dfb77af5ec6449550b4dd67ab50afc84a9c Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 6 Dec 2024 06:35:06 +0000 Subject: [PATCH 1/4] Add support for perlin noise fuzzy skin --- src/CMakeLists.txt | 1 + src/libnoise/CMakeLists.txt | 38 ++ src/libnoise/INSTALL | 34 ++ src/libnoise/Makefile | 23 ++ src/libnoise/README.md | 8 + src/libnoise/include/Makefile | 14 + src/libnoise/lib/Makefile | 8 + src/libnoise/libnoise.dsp | 432 +++++++++++++++++++++ src/libnoise/libnoise.dsw | 29 ++ src/libnoise/libnoise.ncb | Bin 0 -> 2221056 bytes src/libnoise/libnoise.opt | Bin 0 -> 49664 bytes src/libnoise/libnoise.plg | 136 +++++++ src/libnoise/noise.aps | Bin 0 -> 31420 bytes src/libnoise/src/Makefile | 56 +++ src/libnoise/src/Sources | 80 ++++ src/libnoise/src/basictypes.h | 60 +++ src/libnoise/src/exception.h | 74 ++++ src/libnoise/src/interp.h | 112 ++++++ src/libnoise/src/latlon.cpp | 34 ++ src/libnoise/src/latlon.h | 52 +++ src/libnoise/src/mathconsts.h | 54 +++ src/libnoise/src/misc.h | 97 +++++ src/libnoise/src/model/cylinder.cpp | 47 +++ src/libnoise/src/model/cylinder.h | 131 +++++++ src/libnoise/src/model/line.cpp | 65 ++++ src/libnoise/src/model/line.h | 198 ++++++++++ src/libnoise/src/model/model.h | 31 ++ src/libnoise/src/model/plane.cpp | 43 ++ src/libnoise/src/model/plane.h | 121 ++++++ src/libnoise/src/model/sphere.cpp | 46 +++ src/libnoise/src/model/sphere.h | 131 +++++++ src/libnoise/src/module/abs.cpp | 37 ++ src/libnoise/src/module/abs.h | 76 ++++ src/libnoise/src/module/add.cpp | 39 ++ src/libnoise/src/module/add.h | 77 ++++ src/libnoise/src/module/billow.cpp | 74 ++++ src/libnoise/src/module/billow.h | 277 +++++++++++++ src/libnoise/src/module/blend.cpp | 43 ++ src/libnoise/src/module/blend.h | 144 +++++++ src/libnoise/src/module/cache.cpp | 45 +++ src/libnoise/src/module/cache.h | 118 ++++++ src/libnoise/src/module/checkerboard.cpp | 38 ++ src/libnoise/src/module/checkerboard.h | 81 ++++ src/libnoise/src/module/clamp.cpp | 54 +++ src/libnoise/src/module/clamp.h | 152 ++++++++ src/libnoise/src/module/const.cpp | 31 ++ src/libnoise/src/module/const.h | 111 ++++++ src/libnoise/src/module/curve.cpp | 143 +++++++ src/libnoise/src/module/curve.h | 197 ++++++++++ src/libnoise/src/module/cylinders.cpp | 44 +++ src/libnoise/src/module/cylinders.h | 129 ++++++ src/libnoise/src/module/displace.cpp | 48 +++ src/libnoise/src/module/displace.h | 259 ++++++++++++ src/libnoise/src/module/exponent.cpp | 39 ++ src/libnoise/src/module/exponent.h | 119 ++++++ src/libnoise/src/module/invert.cpp | 37 ++ src/libnoise/src/module/invert.h | 75 ++++ src/libnoise/src/module/max.cpp | 41 ++ src/libnoise/src/module/max.h | 76 ++++ src/libnoise/src/module/min.cpp | 41 ++ src/libnoise/src/module/min.h | 76 ++++ src/libnoise/src/module/module.h | 55 +++ src/libnoise/src/module/modulebase.cpp | 46 +++ src/libnoise/src/module/modulebase.h | 366 +++++++++++++++++ src/libnoise/src/module/multiply.cpp | 39 ++ src/libnoise/src/module/multiply.h | 76 ++++ src/libnoise/src/module/perlin.cpp | 72 ++++ src/libnoise/src/module/perlin.h | 359 +++++++++++++++++ src/libnoise/src/module/power.cpp | 38 ++ src/libnoise/src/module/power.h | 80 ++++ src/libnoise/src/module/ridgedmulti.cpp | 114 ++++++ src/libnoise/src/module/ridgedmulti.h | 313 +++++++++++++++ src/libnoise/src/module/rotatepoint.cpp | 68 ++++ src/libnoise/src/module/rotatepoint.h | 233 +++++++++++ src/libnoise/src/module/scalebias.cpp | 39 ++ src/libnoise/src/module/scalebias.h | 151 +++++++ src/libnoise/src/module/scalepoint.cpp | 41 ++ src/libnoise/src/module/scalepoint.h | 212 ++++++++++ src/libnoise/src/module/select.cpp | 109 ++++++ src/libnoise/src/module/select.h | 267 +++++++++++++ src/libnoise/src/module/spheres.cpp | 45 +++ src/libnoise/src/module/spheres.h | 127 ++++++ src/libnoise/src/module/terrace.cpp | 160 ++++++++ src/libnoise/src/module/terrace.h | 242 ++++++++++++ src/libnoise/src/module/translatepoint.cpp | 41 ++ src/libnoise/src/module/translatepoint.h | 223 +++++++++++ src/libnoise/src/module/turbulence.cpp | 91 +++++ src/libnoise/src/module/turbulence.h | 269 +++++++++++++ src/libnoise/src/module/voronoi.cpp | 101 +++++ src/libnoise/src/module/voronoi.h | 246 ++++++++++++ src/libnoise/src/noise.h | 74 ++++ src/libnoise/src/noisegen.cpp | 220 +++++++++++ src/libnoise/src/noisegen.h | 208 ++++++++++ src/libnoise/src/vectortable.h | 290 ++++++++++++++ src/libnoise/src/win32/dllmain.cpp | 28 ++ src/libnoise/src/win32/libnoise.def | 154 ++++++++ src/libnoise/src/win32/noise.aps | Bin 0 -> 31404 bytes src/libnoise/src/win32/noise.rc | 106 +++++ src/libnoise/src/win32/resource.h | 15 + src/libslic3r/CMakeLists.txt | 1 + src/libslic3r/LayerRegion.cpp | 1 + src/libslic3r/PerimeterGenerator.cpp | 70 +++- src/libslic3r/PerimeterGenerator.hpp | 21 +- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 35 ++ src/libslic3r/PrintConfig.hpp | 4 + src/libslic3r/PrintObject.cpp | 4 + src/slic3r/CMakeLists.txt | 2 +- src/slic3r/GUI/ConfigManipulation.cpp | 6 +- src/slic3r/GUI/Tab.cpp | 4 + 110 files changed, 10324 insertions(+), 20 deletions(-) create mode 100644 src/libnoise/CMakeLists.txt create mode 100644 src/libnoise/INSTALL create mode 100644 src/libnoise/Makefile create mode 100644 src/libnoise/README.md create mode 100644 src/libnoise/include/Makefile create mode 100644 src/libnoise/lib/Makefile create mode 100644 src/libnoise/libnoise.dsp create mode 100644 src/libnoise/libnoise.dsw create mode 100644 src/libnoise/libnoise.ncb create mode 100644 src/libnoise/libnoise.opt create mode 100644 src/libnoise/libnoise.plg create mode 100644 src/libnoise/noise.aps create mode 100644 src/libnoise/src/Makefile create mode 100644 src/libnoise/src/Sources create mode 100644 src/libnoise/src/basictypes.h create mode 100644 src/libnoise/src/exception.h create mode 100644 src/libnoise/src/interp.h create mode 100644 src/libnoise/src/latlon.cpp create mode 100644 src/libnoise/src/latlon.h create mode 100644 src/libnoise/src/mathconsts.h create mode 100644 src/libnoise/src/misc.h create mode 100644 src/libnoise/src/model/cylinder.cpp create mode 100644 src/libnoise/src/model/cylinder.h create mode 100644 src/libnoise/src/model/line.cpp create mode 100644 src/libnoise/src/model/line.h create mode 100644 src/libnoise/src/model/model.h create mode 100644 src/libnoise/src/model/plane.cpp create mode 100644 src/libnoise/src/model/plane.h create mode 100644 src/libnoise/src/model/sphere.cpp create mode 100644 src/libnoise/src/model/sphere.h create mode 100644 src/libnoise/src/module/abs.cpp create mode 100644 src/libnoise/src/module/abs.h create mode 100644 src/libnoise/src/module/add.cpp create mode 100644 src/libnoise/src/module/add.h create mode 100644 src/libnoise/src/module/billow.cpp create mode 100644 src/libnoise/src/module/billow.h create mode 100644 src/libnoise/src/module/blend.cpp create mode 100644 src/libnoise/src/module/blend.h create mode 100644 src/libnoise/src/module/cache.cpp create mode 100644 src/libnoise/src/module/cache.h create mode 100644 src/libnoise/src/module/checkerboard.cpp create mode 100644 src/libnoise/src/module/checkerboard.h create mode 100644 src/libnoise/src/module/clamp.cpp create mode 100644 src/libnoise/src/module/clamp.h create mode 100644 src/libnoise/src/module/const.cpp create mode 100644 src/libnoise/src/module/const.h create mode 100644 src/libnoise/src/module/curve.cpp create mode 100644 src/libnoise/src/module/curve.h create mode 100644 src/libnoise/src/module/cylinders.cpp create mode 100644 src/libnoise/src/module/cylinders.h create mode 100644 src/libnoise/src/module/displace.cpp create mode 100644 src/libnoise/src/module/displace.h create mode 100644 src/libnoise/src/module/exponent.cpp create mode 100644 src/libnoise/src/module/exponent.h create mode 100644 src/libnoise/src/module/invert.cpp create mode 100644 src/libnoise/src/module/invert.h create mode 100644 src/libnoise/src/module/max.cpp create mode 100644 src/libnoise/src/module/max.h create mode 100644 src/libnoise/src/module/min.cpp create mode 100644 src/libnoise/src/module/min.h create mode 100644 src/libnoise/src/module/module.h create mode 100644 src/libnoise/src/module/modulebase.cpp create mode 100644 src/libnoise/src/module/modulebase.h create mode 100644 src/libnoise/src/module/multiply.cpp create mode 100644 src/libnoise/src/module/multiply.h create mode 100644 src/libnoise/src/module/perlin.cpp create mode 100644 src/libnoise/src/module/perlin.h create mode 100644 src/libnoise/src/module/power.cpp create mode 100644 src/libnoise/src/module/power.h create mode 100644 src/libnoise/src/module/ridgedmulti.cpp create mode 100644 src/libnoise/src/module/ridgedmulti.h create mode 100644 src/libnoise/src/module/rotatepoint.cpp create mode 100644 src/libnoise/src/module/rotatepoint.h create mode 100644 src/libnoise/src/module/scalebias.cpp create mode 100644 src/libnoise/src/module/scalebias.h create mode 100644 src/libnoise/src/module/scalepoint.cpp create mode 100644 src/libnoise/src/module/scalepoint.h create mode 100644 src/libnoise/src/module/select.cpp create mode 100644 src/libnoise/src/module/select.h create mode 100644 src/libnoise/src/module/spheres.cpp create mode 100644 src/libnoise/src/module/spheres.h create mode 100644 src/libnoise/src/module/terrace.cpp create mode 100644 src/libnoise/src/module/terrace.h create mode 100644 src/libnoise/src/module/translatepoint.cpp create mode 100644 src/libnoise/src/module/translatepoint.h create mode 100644 src/libnoise/src/module/turbulence.cpp create mode 100644 src/libnoise/src/module/turbulence.h create mode 100644 src/libnoise/src/module/voronoi.cpp create mode 100644 src/libnoise/src/module/voronoi.h create mode 100644 src/libnoise/src/noise.h create mode 100644 src/libnoise/src/noisegen.cpp create mode 100644 src/libnoise/src/noisegen.h create mode 100644 src/libnoise/src/vectortable.h create mode 100644 src/libnoise/src/win32/dllmain.cpp create mode 100644 src/libnoise/src/win32/libnoise.def create mode 100644 src/libnoise/src/win32/noise.aps create mode 100644 src/libnoise/src/win32/noise.rc create mode 100644 src/libnoise/src/win32/resource.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8133c2b06a3..0ca6f6c385e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,6 +18,7 @@ add_subdirectory(libigl) add_subdirectory(hints) add_subdirectory(mcut) add_subdirectory(qoi) +add_subdirectory(libnoise) # Adding libnest2d project for bin packing... add_subdirectory(libnest2d) diff --git a/src/libnoise/CMakeLists.txt b/src/libnoise/CMakeLists.txt new file mode 100644 index 00000000000..5dee620e99b --- /dev/null +++ b/src/libnoise/CMakeLists.txt @@ -0,0 +1,38 @@ +project(libnoise) +cmake_minimum_required(VERSION 3.0) + +add_library(libnoise INTERFACE) + +# Define the source directory +set(SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src") + +file(GLOB NOISE_SOURCES_LIST + "${SOURCE_DIR}/*.cpp" + "${SOURCE_DIR}/model/*.cpp" + "${SOURCE_DIR}/module/*.cpp") + +file(GLOB NOISE_HEADERS_LIST + "${SOURCE_DIR}/*.h" + "${SOURCE_DIR}/model/*.h" + "${SOURCE_DIR}/module/*.h") + +# Conditionally include win32 files if compiling on Windows +if(WIN32) + set(WIN32_DIR "${SOURCE_DIR}/win32") + file(GLOB WIN32_SOURCES "${WIN32_DIR}/*.cpp") + file(GLOB WIN32_HEADERS "${WIN32_DIR}/*.h") + list(APPEND NOISE_SOURCES_LIST ${WIN32_SOURCES}) + list(APPEND NOISE_HEADERS_LIST ${WIN32_HEADERS}) +endif() + +# Add the static library +add_library(libnoise_static STATIC ${NOISE_SOURCES_LIST} ${NOISE_HEADERS_LIST}) + +if(${CMAKE_C_COMPILER_ID} STREQUAL "GNU") + target_compile_definitions(libnoise_static PRIVATE _GNU_SOURCE) +endif() + +target_link_libraries(libnoise INTERFACE libnoise_static) +target_include_directories(libnoise INTERFACE ${SOURCE_DIR}) + +message(STATUS "libnoise using bundled version...") diff --git a/src/libnoise/INSTALL b/src/libnoise/INSTALL new file mode 100644 index 00000000000..d822a27fd82 --- /dev/null +++ b/src/libnoise/INSTALL @@ -0,0 +1,34 @@ +Installing libnoise: + +1. Make! + +CXXFLAGS='-O3 -fomit-frame-pointer ...options of choice...' make + +Using compiler optimizations for libnoise is *strongly recommended*. Using the +unoptimized library is roughly a fifth as fast as using -O3 on my test +computer. + +2. Install! + +The 'include' directory should be copied to your software include directory, +usually /usr/local/include, with an appropriate name. I use + + cp -R include /usr/local/include/noise + +Similarly, the *contents* of the 'lib' directory should go into your library +directory (usually /usr/local/lib). Once you've done that, run 'ldconfig', +then make a symlink from LIBDIR/libnoise.so to LIBDIR/libnoise.so.0. I use: + + cp lib/* /usr/local/lib + ldconfig + ln -s /usr/local/lib/libnoise.so.0 /usr/local/lib/libnoise.so + +At this point, you should be able to include libnoise in your projects using + + #include + +and + + g++ ...options... -lnoise + +At some point we'll automate this process. diff --git a/src/libnoise/Makefile b/src/libnoise/Makefile new file mode 100644 index 00000000000..cb1c7a08a54 --- /dev/null +++ b/src/libnoise/Makefile @@ -0,0 +1,23 @@ +.PHONY: all doc src include +all: doc src include lib +clean: cleandoc cleansrc cleaninclude cleanlib +install: installinclude installlib + +doc src include lib: + $(MAKE) -C $@ + +lib: include + +cleandoc: + $(MAKE) -C doc clean +cleansrc: + $(MAKE) -C src clean +cleaninclude: + $(MAKE) -C include clean +cleanlib: + $(MAKE) -C lib clean + +installinclude: + $(MAKE) -C include include +installlib: + $(MAKE) -C lib include diff --git a/src/libnoise/README.md b/src/libnoise/README.md new file mode 100644 index 00000000000..646c843b89c --- /dev/null +++ b/src/libnoise/README.md @@ -0,0 +1,8 @@ +This distribution of noise library is only meant for interfacing noise with OrcaSlicer. + +The noise source file was acquired from https://sourceforge.net/projects/libnoise/ version 1.0. + +No changes to the noise library were made except for deleting the 'doc' directory. + +Nick Johnson +2 December 2024 diff --git a/src/libnoise/include/Makefile b/src/libnoise/include/Makefile new file mode 100644 index 00000000000..eae5c747d18 --- /dev/null +++ b/src/libnoise/include/Makefile @@ -0,0 +1,14 @@ +.PHONY: all here clean +all: here model module + +here: + cp ../src/*.h . +model: + (mkdir $@ && cp ../src/model/*.h $@) +module: + (mkdir $@ && cp ../src/$@/*.h $@) + +clean: + -rm *.h + -rm -rf model + -rm -rf module diff --git a/src/libnoise/lib/Makefile b/src/libnoise/lib/Makefile new file mode 100644 index 00000000000..86affd7f3f1 --- /dev/null +++ b/src/libnoise/lib/Makefile @@ -0,0 +1,8 @@ +VPATH=../src/ + +.PHONY: all clean +all: libnoise.a libnoise.la libnoise.so.0.3 + -cp $? . + +clean: + -rm libnoise.* diff --git a/src/libnoise/libnoise.dsp b/src/libnoise/libnoise.dsp new file mode 100644 index 00000000000..89c364ab1a9 --- /dev/null +++ b/src/libnoise/libnoise.dsp @@ -0,0 +1,432 @@ +# Microsoft Developer Studio Project File - Name="libnoise" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=libnoise - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libnoise.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libnoise.mak" CFG="libnoise - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libnoise - Win32 Release" (based on\ + "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libnoise - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libnoise - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "win32/Release" +# PROP Intermediate_Dir "win32/Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# SUBTRACT LINK32 /map + +!ELSEIF "$(CFG)" == "libnoise - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "win32/Debug" +# PROP Intermediate_Dir "win32/Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o NUL /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /map /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "libnoise - Win32 Release" +# Name "libnoise - Win32 Debug" +# Begin Group "modules" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\src\module\abs.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\abs.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\add.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\add.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\billow.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\billow.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\blend.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\blend.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\cache.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\cache.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\checkerboard.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\checkerboard.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\clamp.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\clamp.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\const.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\const.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\curve.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\curve.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\cylinders.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\cylinders.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\displace.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\displace.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\exponent.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\exponent.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\invert.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\invert.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\max.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\max.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\min.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\min.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\module.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\modulebase.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\modulebase.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\multiply.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\multiply.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\perlin.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\perlin.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\power.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\power.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\ridgedmulti.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\ridgedmulti.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\rotatepoint.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\rotatepoint.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\scalebias.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\scalebias.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\scalepoint.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\scalepoint.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\select.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\select.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\spheres.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\spheres.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\terrace.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\terrace.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\translatepoint.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\translatepoint.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\turbulence.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\turbulence.h +# End Source File +# Begin Source File + +SOURCE=.\src\module\voronoi.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\module\voronoi.h +# End Source File +# End Group +# Begin Group "models" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\src\model\cylinder.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\model\cylinder.h +# End Source File +# Begin Source File + +SOURCE=.\src\model\line.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\model\line.h +# End Source File +# Begin Source File + +SOURCE=.\src\model\model.h +# End Source File +# Begin Source File + +SOURCE=.\src\model\plane.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\model\plane.h +# End Source File +# Begin Source File + +SOURCE=.\src\model\sphere.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\model\sphere.h +# End Source File +# End Group +# Begin Group "win32" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\src\win32\dllmain.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\win32\libnoise.def +# End Source File +# Begin Source File + +SOURCE=.\src\win32\noise.rc +# End Source File +# End Group +# Begin Source File + +SOURCE=.\src\basictypes.h +# End Source File +# Begin Source File + +SOURCE=.\src\exception.h +# End Source File +# Begin Source File + +SOURCE=.\src\interp.h +# End Source File +# Begin Source File + +SOURCE=.\src\latlon.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\latlon.h +# End Source File +# Begin Source File + +SOURCE=.\src\mathconsts.h +# End Source File +# Begin Source File + +SOURCE=.\src\misc.h +# End Source File +# Begin Source File + +SOURCE=.\src\noise.h +# End Source File +# Begin Source File + +SOURCE=.\src\noisegen.cpp +# End Source File +# Begin Source File + +SOURCE=.\src\noisegen.h +# End Source File +# Begin Source File + +SOURCE=.\src\vectortable.h +# End Source File +# End Target +# End Project diff --git a/src/libnoise/libnoise.dsw b/src/libnoise/libnoise.dsw new file mode 100644 index 00000000000..9ef1804ed22 --- /dev/null +++ b/src/libnoise/libnoise.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "libnoise"=.\libnoise.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/src/libnoise/libnoise.ncb b/src/libnoise/libnoise.ncb new file mode 100644 index 0000000000000000000000000000000000000000..29bce143c65c03a36750bca19781ff609728f467 GIT binary patch literal 2221056 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 z z!NL-d-0e8vOaGHmKRd2Bn$V`?goX}P>T zxc;|$l;$86*>a#w`o9Cl|APHL+2&N>KHxydbHJDW_xAt2@()>Q`~M8=dH4T#<$tT% zN+`kjU&rTg5MscA);Zuy|9j=1;L`U0z2pBW`v18q{|~VGt3XB7M*aq~1W!(ZC`d#j z}2H!8#6MUGG(|!m~ zUC-ZOmb}TSF8x=i;sK#S*dMCCA^1d9JSbEMewg|dJI?#ZRdHcx753SC0~V*>q(GU;;+;pxpI{SNvhpV9aDjK0Su z^gT#xUN8C`U)24MJgCe2C4H6K3V9C3ekji&Ji~Z~Tc=*g$rp0Eob2ouD9<9kJxBSF zM@|Bglg#W#zLl|{POb}SSO9>+|ZRdb5 z{ZH^|`~TRx^gr^RY5Xr&>OhPT#R{f$~kDd=E^(fv(5_U;3Yf zrIml$2WjQM3$_0P`R|IQIH0+$9B7mNN8VlSf3N&|+y7li{?B1Nf51g5a+I~*N1u)< z_!w(j4(redS{rjBM_b#1SPyUTW2|i?tV?HC%>dFn*4mb$PumlGoV9&NpByRpcx(HQ zKBZ|uNJWlS$68r+#c$D>3^^M z6QN80XOjP}HvZS0wlV&zY38*v;Ie9>Tt9E=QGCPKVuyJLdM}QWgMPU13F^;kBmv$W9o7e ztl)ARgg_Zfmoal0OE2ey1N#9D%s$8gU-}=uq?Lc#2d?(NSN^+D``?oP#txMKyOIAe z^8YI%|CfqR4dj0x6t$d8a+~x&^6t|AUit6B{r{ZIq=2Y^1D(VHU-}>UcIkicdTM}{ z^FMgIjK7xiKal@#sPBTee*TB|{*PQa|G&fa|3B^ix6%LKLH~az_w;|B)z_E#f!)XZ zWS!5RTknyGez48xjS;>Ej@xPpwe{cVv^>(iQKe(&^5AN#!gSYhm|Bd|1 z{G06m;po7Y{Xdng!)u`bUrGP}i}e3FPB5<*{r^R*!}~kq@PB6wgal4F*3{ulHsB@8Hl-@Wb?aU)KK)4Gjm6==Hw%A0CQ;kI?IVS^pbh{qG>w z|Azi$#v82pe#cs0*=HzgeLpjGOvz2Mcy>BDzVts-c;(-v|7jn%+W*LVS8e}y zI>Unq0uJO52im0nz5Rc${CDC0e-33$KuW-YPUnCx{qODnd*vT0UHU(e|4z@hAcBAc z9l-%#`rj-6MC@w+gQu1M6#f5P9slbHo(5qA9Ox<>@TLDrjJN;aq}K7ZpE{Sz7z%j% zDt|5Wf5`g{>U-d3{x606->)9PK6(D{FVru+(;|`v=7qCKZ5Pu{}agn zK2yYkgyt{@+NA%HcbES6%0Ke%(*IpZ{@;-OypH|9)_z~d{$G2)uf6}*-tTMg{~hev z|2xXy_Ws}T2DkVBTKjz+`+u$dzVOT5|2tFMr`i9T!$m6~tqX9#m;U$m|Gn~0I$iod zkpGtb|AG8>0U_9jN%W=vz48ygT>3wg{CA=L|2|w4f~4<*9Pp+8;Y-^7KlU#D--XBj z_Q4_$BzYg^fG_T^4nQhCtw)Xk9twHY`gL8hu z-gEDqYmjeVKl1I=6muQU@7^%>;i4NPy#qMVCjIa2|9j=X3-|wR`F~5j6UcuDl&>I& z+~$BU{qODnd*z=by4wGN{Hs9!=XSXdsM8$qrT@M1kJs)x{uk)~Kr;3v4*1glFeGjN zAA6Vn_xAt0(D;8K|NBzu57O#O|7VhaZ~xyb|6OSOZ`To==h>)=KTv<<)Q&o?Jz;s~__|pHR&pZB?R{rV#cXj#Sp*~FZ{}WMl zHh)(C{~m|@JNy66_J5%NyRby;TcrEa|C!{U_JK?Pd*wgH_+L)zfA0Hn$v@+NE%MJW zM~nV<_Wy(S|Gp(S-6XYb(*MZ2OaFW2A9;7_|E?zgjQ_jjUpeHTZckp{6yyJa{_iFd zv2P{Am;Oh-UG0Cb{KGPr{_pDY&%%F~{7-bqKlcOXg#!8Cx1^-|rq-AK_sT!)aOwX{ z@}FY;PfoZ0Ie*_J|4#kSJiI0U^^E_W>KOkE^ndpil5U(bU;3Z)yYxSJTKV_(|GS#} zd-cCl{%0ZoGmQRU8jF{1>3Ttx@kxpmuPQQ5aiP2l zY5Xu1IYE66JWs`q{pZwV@UX_~Rb;%H2%fJd82gFpIPm>i@T1i+;62nS#{L*J7JUB} z{5W+ycu#ePu^+2g_{thv8$Vv10NzWDIoUdoIC8$a4ZJ|jfqu>>j!af7!3))mf>S@m zR1NrWb%t?&hk672aAmFk$G*M$f1P{wTRXQ{+{jv8@1Fj2=K^@$2J3&xw!pNR1D5lH8 zU~--VZPou;{*v;qXW0?81SV2*Y$ysf9eBW zUnJ#U*AGeg*Y!hE|JSJR6P}TO>Vrw@T=1m)uT)jwN%_A`y#}6?|2NeCfVchppFsX$ zUtn^c18vg(=+Ab^Kl1L9f5J;E|JbLMf9i*{@{fO){8JwU@}KiXGazseaG+E4Kl13( z|5kq?js9=1{Nvvx|HyZRx(V(j+y9f)Ip9hCzf`ROPwM}h)yv>X{l8tk3LfZxm=Kt5 z%z-xPf8@Dc`X701m;P@VA85V(zee3it~uNPUipt>pOpWb)bGHP^8d2>J$NAhFd;DA zm;)W6|B=T|?f+9>q;3Cu^*{I;^=)#k75z{9V5xG;|BdQJ+$ZJ#cj~{v1Nra9ML$Ry z9B7mNN50yn|14s?kAN1oE^ z|MvF(sSnzv|EUjl@Be%Ce<1(eyQBxHOT~dU>Hodm|EIoj&Hqt9xW@mmPpkh^w*Le9 zPgOpGZ{3>%ZPov2*Z&}oS*`z}K5?!8X_4=?um34m-y!3Y{r?ly67b~s|1z~2JURaN zUG*FAWc&ZO)_g$F{)Z`n>Bbyrlm16O)5<^gY2_bz*X{XM*8gRaf9e-K{*WC1cdh@! zzf1nn_ksL(<3b!Ht<4@=yJcw*Qa&p#9&y%W;spwsD|S z^gr_G8vonV{eSd*(Ee{*c?f*%TO4SU{_pJmKl(at|DXEBrT=lCR{sa>|9z`a2dVYV zfez9C$YZDW|B>%@_5XwRzwh!8INY~5&?fzlJauaSpZX-N{wMyl`afv@?^}g9NNt-r z&{qBLI{y!O?9}uBs1J1eJ~{rc>!0NMAKm^)p8r$f+5bCPErmzP^?%Df`~PnW_W!lH z3oiEi&F&;Qfy`{erntn@$f?b82V`3Dc=zvIeK5K`CWK%4YG@{?8j-z)#f zyB^O=uK&+U{;6Mr_PtR2BNYk;i$K_ygcS;n`}w2l_wPB&uuC(^mbj;DKZSpUCg%2NJ^*{B2OaBvJu>XIr6}ced9O6KS=zrufSpTn-^PXSln4RsqAFlm>E%ifk{eRl?KNt__F8%)zrzjn{gm>+O=}!zlm74Q{y*WTo&TqPap`}r z{DZsne>Wcg59GhKk{x{a!+{Rb|Hxz7@qhGthtB^Y-&x5&?p^bLLHplN(Fok^0~~0R z{_pJmKlMpk{hvwxgZBSEP;!GLb_54HME@g?Y4tz$Y4v}m{y+6WyUza$+W#FgkQ+?~?-^qW_VsWC9C_+p{~z@KeHQev=kQ|9@-xKQG)% z<%N5zJk^J%FHb*}_t}9w1uAdR0Pur&2J#Hz8O(D4&k&wMo`ZRY@*Ki5OzjFO>)E)U zQXd|xlt6hF@m<;^@)U8rlk7XPANl4y_dvdj`+L}@BrtNYhUeo?@L2|za}&H_e)j|& zZrXwzShk4+ZPNc_U#Ir}2|sQBpZdk6|8bwo`hRc8f13(J;Ax-ZKo#|J0rE3V%^~gi zYP!Kkt0TepSE~&^K^+g?OWkVl#cDZtU#q^qfNz)ce1m5;&s?5mo_DF^f6TWBc?v?& z$XC=Asz2fPWzQ;jQH81m@2M^y4W5YR-J)&*@1r&gu2j!g)vMqKss?edqLJ&=*TMU% zErK^jBR8roU;|VS_QPVY9^|h-`Ym7lH%8T5{`#Zq9>aZqrHbEFZvzLbmj!QB#c!+k zz=x<^f=^V%@2U5}3)LXw|7>+O_`xbvt5jYHT^d7&)`iiJ`8+*&dZ1hP=RxOQEIJo` znup%Kct76J#n7Jj5W4ra{+7Or60Yz>^rF1aBHq??r?`8iuXZQzSK(In`^tN3`k%}R zOu&JR95{&bhdiKf$Kf`lKBi3dFIADl6@`*gd#JG=rzV1j)qa9Mt|GdA$X9)g{gLWu z?DuPFE81;Ffgoc&E5N$|2lhz&A9+nH|0;w0d-eZBkNjuq|2x|M%NZZ&-y+|G^>{!_eK15#G4{GY zVEX?~`Cn_~zrxf1&)EK_@BdJL`u_)ZO8;NR4xDFzb%CN6keCA;c$ohAfFG*JQ09BY z{8(`I#~jR9mzbxe{|-EcKZTByF{fobah_V9FY#Q?vxdL^j1N>YY#`%x&#Gs^_fyYG ze;@svmHd1A|Dg=}pZXwe|KHL6x8xsrf5VLbS>u7!2X_D8mVa0OKjCQqUx@tYoAJMz z+|mDm{7Y#KOtu`bG%{hvwyd*vT_Pb>ck zPx~MLE&czCkpD39-wXYp)AG**fiKg{3`XaepDg|;%8;_Ujz{zeQ~Madba`lMR-tCk zr?#R`8oGW9O)|dCQU;9vZEKixiB+VaXSD79mHM@z>quylc{ZIdO#F0^i4aayelVib z#e5DP4A`O~gP98xa~gPo)gBlD*1EngQ6=d2JT=GC_ffb0&m{lo>$Lsn&``;!1$h%Ab(>`$NfBd`TU)Itv*O(V~=>LrE|IVHNOQZjrC11tNIaAByqZF(> ziu?ZhbI1Nh2h5`AW@Wx<%KiS(bTCB8ilhS5{>&<%jEGO5=d1mqJ6n#wky2Wym>Bnaf z5f;&15@}J_Eumg$==vixz0Y!+0ch?6S##zx(PkHFkiN(FJbhFui}rrY3Hi^Y|Gne? z%qP0~|C!{UQf9CJv)cd2w@d$LlK+X0_Wvs6-){e3L7l#5W-9U=E4ol=EH9cUAv&^M6$0v?R#e&sorx!{=NF&+y3{i|7E<-CI8e1S?T{w z@}F+~?<$AJO0<`(El-q z{5$o3my!RLvXJIwqcs}-xG7(iG*NHi=}bM8h8Pi~q=|&ovxctwq3P=rlsXI{8?4;T z<482=CG*?&?mTDAGmA63Yt2P3MhF-KGjx5z)cFLa)Ata+XmO=9^X#vGFm#;;O_e;( zdNn8HpY^|K`~P13&n$*Z|AVL1|1@u1?SJIm)&BR6|9Ry<)QbF*!+QS@9L=%zzn%AO zgw2`!ogsS7m_duQ9=dY4Qr|yJv13?v5*OLlE*OzcewmMA zfAqIY{=MUWUioiXADCkQUkUnO_W#NJUu*Jj@Bfn?_(gkW|Btu-FU`;Ohb#5cNM-Hx z@8=z7qTm#CZs}4>E*W{p$c4!gy495X525LB)OEgPl|{cJnheYH*1C={^7@>i z>v(8-ny0mKfX?QZCTP_Q*Bi=SHgvrPO+Ol~%*g6)P572{=+1@%jXK`lugx}^6Y|gc zAD903%D;E~kM#pt>Hkdf?_K|wPXCv+BLBJB{(tbaMR$5t(?DAV?`P(>dmlxaM|Y=} zN6KA$RJRV?E_S;?Cz1UPT@#_}rvtOq+s%>P0&mlY-GljfmTu>q16_m02s=XbliI@+ zi?H1z@=xyzXT#TZhF>Q`(@Q+P9CS5j2&+rVzjypE)B0cK(f{7{f0^{Zv;8mfZ;$`y zwbK5-(6Rq_5AFZoP5)=e_l(vQ>t@|xR*Ovex`-v<_weY?83a0G1nqD@8%#{h(6tqs z4jbDM^4LaMwpp=ir$tw#p=&%eE#}eIwj;~Qp7|*-wQ5LrF6s>s|ljmH%wl|9ad1Uj6TF|0f*%|1yXChaK|o)c+SbwmoMf9CsL?f-1$->d(<@}F+~|0;+4ciZv*+%B^Lbsfin zPiX|Ogjh}BPt4y1FIBV#bbG*BC;qtN^e-xO%-|lV|BBt6Y;uQwP0#PU1MBL zoxGwf-ngQ^u5?9pO+|g&daH~jDr>68me$s)BJ*Beq%8Z%lV`^gvumms)+|}NOf}Y2 zl-c3qu;sO;+I}4!X-dAXOTMm88*{ljsVbHzA6tHkDw3Ddn(F#Q{aA=_#-5UPr*k!L zma@D?G+)$$v*#~dIYEPoYTEP}D;J)%a{iQQibr1glA5lniu%&AjW?3}U*4pTTwK46h zUg@CawurY%s%mNy<=*HGRoYSlvg9B6b;&=tOa8&r%0KmkOa7@pT=I{6y5t{u z-dpltT^d)XRa8>ICQn`vPb?7D+IZE<)phan8{*Za>m1)IW2Ft%vAT+c^P|Pbvm0WS z?$0%)iCANNDg`&;2!X;|Us0bR++^HUE3I6$qt-BW@zce2MTteVu5rve#cXv&U43HZ z>eH%Jys5UPnv%9MR#z8mDOSrP6URr+Ra0Y?r3-2)p>?s!bK(_i$`kc!enr`uc-fqW z%0$KF$r&9~t+XSU;tqe#lqD;tcs* zTXL31=FgfoWBRm}Nn3A}r8TAJsbUn5ZDe3yOraS&-^8N2`{n*jBzW@C! z;1?qkA z6%&K2mi!~HF8N2EUGk5Am;6&7WTpS{pOyTxAK9hpiLVt%FDIcgH^ z8)+b10N-UX)vV)y@N*aLWl~$rLzJ5%DJN$g2!9zwxr;W_mWkRe!dijl(?#6RFQ8~o$p9QpuH<`Bjv%C8*q@G0T`02-vDFGeQyj-Wg*=i6ThPs~tw zHy;1XBNnPIGx9NlxWvfD0obLEFzI+7I%N}$ZF=c5C@fSCoRGsNpQ60m=3Wz?jelzV zZin8ddH$2fY5rl5@zB_t{Ov`0oTexAE+tM`pf4Mr-Xq_ihrk5ir5^bwbeH~r+@t>q&n5rJvrGSjyW0PZH@M`#1Ka;CjCd42eh9xm8Qk*8digst zW1A_++$oghJoxT4vN`T$^6D7E5fep@o^-4X{e--@gEGX(iM5IHc_Sy{Ru;Fu!84tF zl?|0cfG-oz?f4(d`*6zKLzIz6C#I{pGb2G;Lol=D8s_Z-;6#PoV2=(U8qg}ju-j50`>&b&?j9tuA%p#BovVz6LLBGl95&1~Sg*vVIZUM#Eou%DBVUJN_qC(*Wdch*>Xk648*7NFiro zi?PQ4u^&T?AtPa;x}^VpoH`NQod1J7e_ovdzMnqN8+^8E0zY7{_x~Y+ydW))!K+iq zH@N_z(IMZzHTiTS-)+-?e8~kBGP$}GKf4acA7$_Rlr1sunDX!lc85_Xj0W0fICAqW zWoa;syqR)(GZq^uS3kpD73JVcWLz%2c+*jLT!~DiGd1{?gNwv`i)Rv<<}^1rBfu`yCaA4gUeWkMLyk-zIOD6ZR4C z_`!(vspUs5M!26i#5|AttMNOKayf^5k&Wy!87oE>v)^LElf~^~W*huj%9I#67)H!e zGEgR%Z$*9=BX1udPoLm+B6ZCS%(%{VB$cER>OndFlL$X@sW! z=3RfGeT=dC8k1S#+kC&bouPdpE)n%6y z21Yv|Cq`u z>T8*$$Syf8p8UsSPXJ_F8z;uyX2qx!X^LUF8vSQQTjhCM%T(TbXLVg z`|zKYb=DkQmCV6q6_3+j7O~YNVu^Td4U@*%#pdwmKeqbPSY^DVB9>hRnDmupOxY*P zib{LSBCdEP)2LaouU>n}B97YfcpZ%}SzY3{3aK}K{Kvw|g}T@tx&H_Gb;&>Y-jaW- zm2Iuyv73uDM*Z?RUb#ZE*=OC0`%-pxwd0ZYciOB4dKXO)Rl|^$pD*-7Rf-@N8qD@HxRxI7JU&Y149pBF9TYCWh6=l z%yuw(I~OQ}MMSOE5dJy9-}4Z)x){190k6e91Agie+|L320%A@99?J+DpVTFUD+6Dj z;AtB0T;LR-7`&>n{KzE1QryD=^$+Ng!N()0vNl{fYP{1I13t)CCYFgJe$< z-c;bLcwPXMS@9_F|DfYkpwLc|)z=7bHt;0EmjSi8SR4bKiNATkD~X2zZ?zSABEV0< zWdclQ%4Y%t(+M1q%$EH-(~QguWSE>K(Q|d zZUjyOivO7gUt;ibgEs;1A)Jjssf0EI=Yii2lyDvfN;umLz8&})d9cIayNrF$H&*2> z!CfKnF6@he3Ghik8CISNl<<}Sh3;~LHvxA@{6L9kGw>G@KTzm?SnPq@fIETPf!nd) z0lW-+7qBPc_k2^kF9cfY2R?xPB;fCWGl7!6CBTm)eqa>5$-s?3alaWT!hgGg4+EuA z-e%x-;1=*52JQmpgZF$(^Q91I#Sa{;)`ZGK6`?PN&I`ptSA@S7zA}7O`0DUA;cLU! zg|8293SXe+=a+;^LuH|OXmw~oXklnkXmRMA(2~&7(6Z3-|Igl;z)MnAcl%WL%$*IG zJNw2!Gk}cj4EuiBVPM!~AP`Kfi zh2?)OZz}&=`Ihqg%O5EJd-<~RpOycm{Qt@)mrp7GNBNBMndKLhSC`K&|4I4W@(0U* zUVc&eFUqHT7nUz7UtE51`6cB`%BOmlme-ZnmtR)?tMbdsmzS?7Zz#W_{MY5bDPLKB zW%*?96z}Tt-<4loeogt>@@vc2m9H9X75^he)Zz|RO-U(MDN*>GU?PVp&A+cl;-}4_XP-N}whEPx8;FQ{#X5&m;af{%e0W z`;V1CCMD34{_{xt+vHpjHAc=|4xO@{fPuwErdf#~)~?{jX8} z-}tZn+3Y`70-2ORxAT7uTL1q{3e8SpB`_o|*j@2YeUjt&{~`Iy*=<+}bYB9W z;}m_L{}VAFzWe|nNs@mF-AX6VVlY}jg3|0H_u>WEl_W3wr$wP*=DhC zHrpJ33hO5s8?R%Fb&R5JI*w7d#PUxUxxp(@jvXm z4BP#U8vnYqjOzav`58z5Oaza!tlUl08M4b^;L-2cB{9%O&y|34`IgB|(*|054$NB;lA@(4EmKa-GmQ|9_O(E5f}Og8!WT z|1J23cgO$FlK)l4e-WN*yN1?EU{v|ft^Hs716lsRwTI7+>U#+klK;Hp|2+Huuxy&c z|KFwc2R8q|?*NSW1$>N4thP5%*(f(-%@)5s0lq)V z&n)ukll1f0r}8t4{(XN+E^wB|a(VJ&?D_I(K0oVnS^i_%?`F}yca-kmAj=<-pJ6YQ zdBNw;kTbAp-@6FDnfJKbhri74No@4>SxevFi(vf%+W4=bjo%*wK)?U1C-Z;W{G|Ml;3C^p1_cbr6|38WA2y>M6`u^X~;+f%RZs6Fn$Eu%ydn~u9@BKPBkBti$ zaj;vweV>1Lch>)*K4_Q!w#NVQec}3_KCjqL`yb;Av+VyLXC!R@&&~gTe?tFL#{(tw z-}?Wy_|)2AS(QLm`oA~pd7^HzbG1KwWnWp3U6yl#{`NXQ@Hkp|F6#lJ_m%79@3AM# zi5#!C>iIZ2x?Yc`ef}N%jN>1?Q1{EkvUke6`8`#xt)8#+9@ZBe$3OUg!TE2ITd=p0 zBlP?-QTc$}#_w^ty88Lb$K_L4vnAyJYw|VhsQ>>}_$TrF|2O1Y*irwVZ~6WEqy9g- zK4`rE&-YlC+wcGLw*mj^6U5v9TFL(#|5-iOcAgeXAS?ZM_`g70{^7YT{_)obmj5TZ z(0}Xy)8bQWhh&wjlZ^Xa#{~s-|2IOvY(f_3XpEv*Lxs(5I#y{8N`2Sh* ze--*4&i~Wy_+Qii0ikAiE;B3rKR^zoP)hRmhYGEHQaMl#!7kTqZ6DA*XY2m$H9xQ) z_T;L~@w*58i`MA=mrG?2*^~WK#JAbMpX`r4RW1w8zo+blJ*{T%F9%>xmsQM#Ile|J zhsd8}&z6m9?b|e z*=$Sp*@>@D8qUvoJLmo++nsFsUh*^g-jVyHzn?sZ_VclMLHSeJtD_RQw8ZldU(c5n ze14J~7ubiRiOS!_fqjykf<0Z{7uc)iJnXIgK5JL;-gRtmV>^ZIRJQXH|JUdAR^Iz4 zo7NAh{IlQTpZdV~uht93KaZWgGAn^b{2w7l@f{KWD}{k=G5*h%KgI5hf9;=>n*Yb2 zciR8yAMEu1*)UPu{y#I#|Ih56qx@jV*DT6Y(8-7 z|C{>*ZeNgE0*(03RsZ2#$NR+l|Gq`uh8^|)y-9Auj{5)V_?~$GUmYJ5@BjOLc|Ug4 z|M%bJL)cOO-%rS=v7-LJIzB1h|Myk$D(qqFhQK|9^{o5Ige!KPI2R3jBX~{|Y}f{~!BGe&YUr zb-ka+|F6aak^f(f2O|IfJN|e;{Qom!{LhH-Z~cFAd4BDr-Ic&d@K1cvGyboO@!xLz zZ{vTudzkIhZI{4M@(=Hh{x{)7hVq$^!bv>T74UnZIK`bKmIeaJA`=w~)3jeVu(+ zwSR84|E*WG*!-Te6mrE;)b%K65t{ek)XI(Z}Z!fJnD<{SG* zc_;Q#Ss5JvZr1ay_5WqR&hOJr|KE6D-i!H;^=wzNb=xo4`v37~u~%j#@KmYF_X%=> zf6m9$ram}cj`!{R)TTZ-PLA{KU*X>}Unc!?_l7P{w$k~&u(zE5=Q8$3^MAcsUX2~h z|J82(kN$s7{*V5DPW~^c|D50P|FNC;AHB~_|8@SKPRIY4|DV}&Z6|821bqJCJC%R* z)8QXGm4E7keWeTj;n~UmH{&0k9sj?d{Qn;Q7u8w+x0U(-jQ`diT01JU639gVsSh0e z$8L*%;&rF}uNnXJ|8?}gX#B_5|5$AE|7Z5F+KDnR0YCmn|DE_B|35YUhwn_|f5!JY z@jvHx;{V!sVT=DQ{?8nNkv?HZ`M+-YhxgR{Uy^_9)chaygXRBNLu65PO^_SO$=LcI zBaL;-H=m3C!=sb`hxfMf|LyY6@y5UL-||Cm2i8iUBmIZxO#OfOP4)ki`cM60?SIud zglztw+M{g$>7WEM(SLaCs{OxN{Ga3>+xR#BJ9ymfBZ(5|NdMulEB$X4|5Kkh`9I^o zHZP#%{}KIdWB z_#aV(ySnXM^dBCb{6D;==Kn4JZ+TvD^Z&bg-0j1O66i?(;W^j%pYx~2|I{yz{&T$P zzv+MC(KfS%639gV;W5|vAHFUAxB35Dc%1E!HcOx*{m(o8r#?y5f9eC%e{271^HI0M z>y$ty`VWt(`p^EZ;(zJ`(|^S; zNYL2(o9syc;W5|vpZX+K|M`B?f7Aco(=vSDn2G+wW2*jl8~;-uv>*Rp#vd!1|98E- z2|Jqq_sy&)6rcb1X8CXI9pzc(J055LUtQnR=KrM#>^0OS(2@T4JN{4VKlQ_w`G4d8 zt<+_I&HT+@=LvoZ)3=A)P(RRib8VGCF8U9TPW~TWyK4XE^QQln|8MKTwu4(LfsXVa z9&?TVIe%*WPyNz7{x|(M{cj0@kv=FB{fEa~v@`fvK*>N9P}wO#@p>3`nwKfI^L|I{xQ|6Bau z`crO4HY$Nk^dBB`jsH#mGtK{-|KEs)(R;rm{fEa~1sv)BJ`^T&_+|9)4# zkG)(pAKuEQ`R#aaTyx$>?o;*IFFsskJ=>LR*YN&zY&Wol?en+u|4*{r8N8QvuH>=t z{Ck*pZ?^uQ@jrT;H@f3Y^dBBm^}pNrpZXyG_}};s>$!Sub=LmZh@ioKza#zccl@8! zf9i+s^Z$d-f2jK(*gJjwU(^4=W;V;K&qe>?(aHbAYgg_6eBSiGdH&z{&ytMMI9Esd z50AOV|C~QH{-=Ji_3}ng2Kb zjsHv#8S0bdqW|#dxsLQd@Ax0yQ{#W?7mNQb|KBHMhU#lG z(SLZ%HU2mKuk|HP_Wv!(4Dxwfv2D$^jg)qqDWzR!@&DOubJ*sx&10L-wt#IRo6Y|* zR1kM@GaczaJmwnzQ=g>jKi_ZqU)6u(zl(?8J}Q~$KRl-Df4A{J^?}9z7XKTr*_S{^ z`rq&PKdJxJ50?KIvHm~V^D*pa%tim<(aHbAYgg_6eBSiGzW$s4KkS6&dw(72KRo6d z|8xG-_@Da4;(v?(^Ce?6&Yp?>!(*=Tzv;i_|3?GIp5J9h`k#0FPkoZA|I`QB>;HEt z`)K^neewWy@yGv||KD?DhUyD5(SLYM)qnPP75`Ho-keg^Z)*pycs*1|My0DH+D4t z?|bDw>?r=fUmnD^_}}7x9)lr%b)^6Bm}~sc`BUS6>X+v6zwvMLe+)6W8QoeY`VWt} z#{Z`O?e+gR|34!-hW|7j>3`nwKlMqf{!<^A{-?D6+x%a{4{k$$`H^)cmSIR$G>COCe4gUAMX z1@<=b!oa>>uE(Aum#WSA{z=}0Jx@Ndx5zZ?9pzBpo?l&WQ$8dg#$F;H)Z@1o`A>d0 zOtih}!m`MvY#Z24Xa9nIs?Yw#e0DwCm2B6r?>e>{f@8FgYJ6^N{hXfbs^E8{b0$CY z1nc9CKR!`;OdjWM=E!u4LG35yX{>p<#C-Y~#)K<}jc3xoW>?qOzU01NI_$joQad zRG#NOAA5=1h&_vj#67)zu(y>>fxVBnANErDbYSo29f-Z1+#A>jdWT?dFOLTHA>Luw z74f*K(xP!Gm8Y>yXD;tL^M9NE^Ov_*D<$Cb5AP2DfavfK@2ULrMaF-D__zFDE04Y% zLkYB`|4IJ&oTLBPsr+v+{m)GQS*E;%2U5bTYN-Flzp>q73ACjDoXgRF>{R~Y-SPj8 z|LpvKx+xp~Ek4|KSkn?{N&h)ZD*yNgj{Yb4xA;F>{+q@BrvFW!dpn?70v+kU<^TGZ z|6`a!)BKg1 zPsaZP#DB{LX9rpd3_%IBr2pJ!D*yNgsr(O+|33tOQo98!ftE|4BmGat|4IIn{=f0x z^54S_v=ZoL3ACjD$@o9XKNsxizwzJ8KcRh>l|aWO(31Wq`RCh)HUHOfLD~nc1O~7K zTGD^+Yb6W{eSX%>;-ZawvOj} zTAssRC~phw=cMF~Gyd<^z%F@{u@}o-fj!xqg1tn%L$v*F8@8!z^x>Dp7{1+R@}BnZ z57zLh%;EoY+2*m$mnS{(w{Wg*{jK91bqm+&(BEpu$2{tLtNHA0W7Xdb@bc}Gg5Pgt z9A)x6oWfp1UIHEIKfF8opX49j9sM6b{(r{!-#Gujl_wnjpOR-C{+|`k;otKnIs8xZ z#;W`?*4gKOfB4riyzTIRnejj5IQIPZTGD^`cJx2VKUeMOzwy7kA^&fN|1tEx+yVcl z|2^kp*uStP{ZH~wp*Z^AjQ;_O|3m*jH~oKC7yO(44?B)MzrU9BpR028A3K%*0nY#B z&i}u{e>u?qcH@8Jzvp}m`xmyP|IPSM#{WtFE&g9#i~nB@|BE{G|Be4)$Fb-4*OC4w zZ&=MTAkVZ#z= zN&l1af0BRBK5Y5FN8}d{|G$?1bNJW!K;!LyPs?WPsQquV-yRsX|CRjq0QkQ(#{V9c z|8MwU+K!%-Kuh|c67KrTyRh z|DG^0N?+2F{!<{MmjBC*|LHOQuW6HiYyTT1G<$NdE$M$V{*&?l5aj=IkIzEW}|HJU#sQteg|Caw7Nk;R$>6Y}L3mCQh-$U{< zhyVYTUpf5$PX6HV{|CQ4Fyg;DJ}~0{Iln%D|F6J*qyGQKf1Z!Jox4s6w50#d_)o_F zLy-T=jsFkE{D05<|2mJPz171K=t%#Q@qd#4A;|yb#=pk@o%;V4|M!rL(fF#C^gkK@ zC;6wShAsb>8~-=O^nWYU|IwhVxOdr-{wMk8c7{FwmmB{_nf@1-hS9sSmh_)uvHV{~ z`9B&4YVCjRw*Q;|KYD=Xe8(;6e>47*@xSH&g82dK6 zzvb=x|C4NY2Jh*7mRGSaITvR9oXO8jEcfUCl)vL=9KF5y`PKP8!}kB%1G_pNc%ghN zu&eEXi{zJq{Rh8)z+&;%!@ED1=M;V?=KS0o^!a%}=L4nR-wfvc{Pt}AAI$lA+Pp31 z`%KQ!S#Pe-_&lFCay@E)VDIX0o#!+B%u5!EgqzL($-^>&ua@*b8UH8wr`+1j|BVd) zZx8q{!@th?7yA5b8S{4q{I8|YZzKMh^EWx)ukk;Ekmh*HE$M%ff3Bz7{9mE@-!PG# z{_g<)W6b59wZQ{}g%i*%wIV1UbRK$j8+F zj8u-7<9+)+wc+_VInKAQ)%})`o!bp*ypnz7sppVC7zmITg{~}K@x7HuvC-NBfe0g!uU*K2rTkM5$74|F<`ujYEy-3~`*iXrG*o)=Xze#<{E>PzJ7hMa0aeudn=hqX7dYdC zZeX0`>zH3mw^qgpX}^s4Si#Dos(n)MyWW_aih!18qdPg_8%{EP8F z#Ax>9)>_j4I{a^tSMcsO@CnE2k3pI6m3z4@hM(zN)@%RU5rtgfFYFuV8C? z-5&gC|3LNO&SSfXZ9Us7*{);TTlVF+l1$Jach)qi>?;Rgmt_M!DgJTg067?YlAN#m zu@9ERuqVrUwdpT>n7k5uOx}pC{eRyiZ^52Y?GH?Uzjw$+?5WlMz}TDQ{n*oL{ef?l z4`WZS_6NRvV%hC-2lk9=e_;9penLKhJ+syy`1SI7Y&?4WaqSQMS?Zs0dO92bBIf_= zlRp}-j{JZ0K2`tW+w{N1`2RA~|1|B_efG+)1X}X{lli|S|6HEq|HJ<~2V){@1!t(!Hwhs;rm?T)>z+=#9I!9L!8*h^(oVDIN0guR`7I}1~pJ%4z<@Vmm_?6Ox*CD4)n z!@J}EC;3nM|AWT=;{(M1JpupfJ2c{db!<-YuAtMEpND5&zFk z#Q$>>@&DXJ{69Al|Ia1x$qy=2Zv%;YWV=I59Sj8hxq`l59Vrnz>J_i zxUkduKy&}v2C#%}+gckym=ow#OrYaN!}vmf+bf?EXi5M1>Qw&m4^sID>}3A0(EJDa zzk%fcJPM_ z|9{&p|55wD>3=bq&GM>R(*I=qpX8qla`b=D`494cz19DW_}Bgfnh)$)|Be4F`6~Lk zTGIa{|J;|NYSSc>8}w{L_r$^RN8@9-%+L5y4yn@%{jh#`*(X+qge~ z>3`Ab?f&{&(to}t8UJ6&c)fW3{|)j6>?r^DZuvLt#{GXkA)jP_)c^PE{>b0{=l|pV z|7MZz3+DsX`9EeQ=Kq*QzArxi$1L(@(fl9Ja{OZXMv%{Ymia$salih2ApZOxld!iH ze?E}&W%(p;411|~6kDm>;do%?11W7<=;Z7g(u!(-p=x_!I35`Oy-xf8Y)fnrwE=`Q~O`9_+Li77Ow;HdHU_F zE$M$V{*&>4lK%nf|I_#Q|5LH}Um319AMopg{NH4J`0vH$@aS>=?|^_&%l{8 zC*%Jl|Caw-{*-js{`~jW+%Vod0rS{$KbF=l^}~Fy^yJ#{WtFxqZj~ zH~u^4e_c%flR3O_J&-o|Z{)9s%xZqE)AoPke{i`Eue>GwPx8-)E&ul%y@TBOe+rTR zzcq;eb^gD2>=4iYhx36}Ku|8M;FZvOv}|H(1_uVUhb;d$#ALU2Yc1(Nr%H|g+3)CoGXA&xU+?<=eLjf)Urzl0 zOoR0Ru8ocVf6(&(t&uXEN42E?&G=8o|4IG_DF1i!RFPYzMSV|`dF+kzs_R+kF&|;O zX}*Yl<}>`(+;`8{|2i^=|Ci$bvtDwEHIhqroBuzYv}S)-9qB*3JN|!?e~bTn7ymPj zil6^e{^!Kj|I_^6X7YcVE&rE2HN$hpmh>OK9sfVcKgHqr|Hgms_}B3Qn*WdMzo7rd z|L{PX5XeL2Sec%c89|2O_~q-J>2JL~^p zJL~_z`=GA>GdzD;yAvyc<|WXQ{&SjC{_zh|`LC1zE9&}R%}dOVuo4)a66i?(;oZ^y zB>(X4=>Gumul?A=zU=xtng7>0Za-S7wgG&H-{J8bYA-8+fh&QQ^gkK@C;8{D9sM`{ z2ktqr3m(l9Xi5K*{8Lnp{$r=|Unl=pRR2HJ^R#hnrvIbK$}rw_OZv}^r^f$D{s%b! zXZ#Q2Q*QUvs03Qle?FYbe=`10@^A5fqvE&stpxg70v+jpGX78UZ}ER$|EBikRsyY- zKuh|cjQ^AT^JS^=zv+Lge-1m&N}#7D(31Wq`R58P|0iPYe?5Iv?aOi~ffZ$u*`JZh z0$JdneP^{Vkji}Kw$#_*YNOu^S=&lqXEPu0q?b!&PuUC0tJ>_}Uk<=7$wj&!`v5r@ zyIiyP5+;jh&x&CG3fUKXa?RdNcE=u*BZB?A3kzW~o-MTZmHn`%%1Yh8y;Sy)J+Y@% zZN6_m*&lnl>~=Ww6=NSPOr*>IR&o7mzfArSd!cMpoBYIEAK`Q_7D7_`C;7*2i+^}e)qm=fRQ)&pYraCbKHyQ_vEDrDFTXz6SC${^ z9gn?}c)A{#)(5&Cpw0(=JY#}|F~J?q2VA1g%yUh^mr*ZhonUoCZz_aL^uHPZ@ZOdG zPkrF{|Hl6o{2z_}$N4|bJE6+|pX&HP_}BTsb)0ZJ{2#JVN}HGuc++C)izRHjHmLF6 z8!~(IEgk89zvKTT|I`m##{Z+?|A*@ZAA{b{NAG=q0R2DSI|+N|sz0z+mY?LEjQu?E z&JXGXjSu|#K>h!~C-B!7V(qcju!Y^RX95sX={ElI?op6PRz1eVvet{=;Ki z`9F*QJI?=w{2z;e|CQb;*gK1Nn)0t~hy2%z2Q+`c+M>zzLAvBW zxu!>2AM4x3s&N1d(fRR!v7bHrdd80QAN_Umf6e@V_B;N6v-qFmQ{#W?7t8-u+Ydti zkMmA+_&?Ft`-uOOy;W8IXTkpp_)m=ojQ@OSE8bZ%(SLYM&Hr^9|5G1W{9kQLOt$}p z{8xF8^#5ew{@Nu+{kA{QoXt&Eeyj=s!HB>OcD( z{~z0F|7#ZiQy-ZAr|W-J?<4&`)jPw{|1-Q7RQ3PQ;eRZq|Hgj~R1MB4JJNsn?Q8tc z_dEJe{V?kJ|CaebC(!?JePH8%aA3{hN^{YFcy#jr7XRng|2K^PTju|2<39(C2KJO4 z>3`nwKl+{;|5Lv>`p@y*>;GW({}1`E`umape};FKjKi}V6|Be56|DPKF46Ahd|5*G#irClgITQVd$5j3AHvXqRF#WHe z|1WK(zpme2PfmY~K6|gH&0c~w`&;R=yQ$h{7az0p7~_(|am?X-hhf{C_Q`9fUtTy) zN5?YPJ6G*Nv;P#b1Ul0He#iew{ilA|GX5V8{rCA_t^IZ2KiOy3_%9@LMY^b5^dBCb z{6D;Q)&9@tP5)E$-}o;QQUi4@9qB(j<{JNV{?z!N`o-e^YX85|g*sl(^nakBE6~Me zqW|!iYy5BeUzjKlOp>f1v;IF+Ab;{nrQnfaU{# zSU(?FlEu!L{Va2W$+5bY8!T?ckcs}oW2*kMzpMD4`oQA<2JwGA{#%F#jQ`>?*~=^I zNdMuvukn9U|EV8FHvez@_Y#+(`>tH{A0D0jf4A-b@NW9wK>t@UhF9nBTFacCmuw@g z<^xUthYsbAZm1*u&pZBy_tf~G`o-e^l=$DD|2w@ufbriEE<^XBO!OZfbB+H^{~PE3 z&Ho=dCVP299qB(j<{JM~pQP$P-*5V#qW_lv>m@=1{au;pKRl-Df4A{J^+Epe|9AL1 zM&tj!C--9y;rPFB{-1DtpjCC||N3Dt|KDWV4)2f6|7Y`m4K(ZZF1{oE?|1y4)PL%S zQO*CiJ^q*ZwEgja;ru`K`1k#XI`e-U|Md_W==XBbe|U8A|M1#X`#+!0U;hVl{J*Y2 ztm|c+vaI_1yx{js_#KYN)8F>85~x=K9qB(j<{JNV{?z!N`o-e^YW#2f*L$k%y;e&g z6a9zBT;qS!|AzU0-HxkQ0v+jp-tj;6Nvi%+ADI4|{?~h+?Y;I&AQSzE$5j1i ze^>E8^?}9z_51&|_t&=t%$Jxv%kmQvazRMm7I$xjpxJHmki7$VLC*(aHaJ z+x`#lrvLTz-}rCudAFn866i?(^N#=FJvIKPezEw!8vh&r?(=L`dnJ&G{=;Lg@xSSR z!~DPT-`?|XN4q7^k^aMDuJJ$hNvi(y{igq>|L&7)RwpHpiT=Z5s{VHy|5G1W{BQAp zC(pNiCcOkY(*J(P|4IF)e%Lbqe;GGEE~{9VVw~gG%bTzl%0{&}NafA45qqhuJiNO9 zX8AUDH2&wi@_p>$kN+|MpFfkmIxc}+^dBCb{6GA4)&9@t+t+{NzvG9(J~%QZ(2@Sb zW3KT(=TD9Qsb8AM|Hl8wJj8aR9hX2R`VWt}#{Z`OmjCbg3AYcXl|V=OpLhIEeUhsG z)CZ>jmj6$Cu5DjyC6I~!!(*!cv%jnOpZdV!f6M>3_C(uJ?UX=A`VY^2jsKJSPyJx| z|91ZBcC3{^wFGj}e|U8A|J}C#!@KE!ef@u8*Xq1K7t*eIDcc6Nv&Tes*{yoKwhtyZ zd-kma!V>66|MQOj;XO6}r+%^czZ(A=|KXEtzdI>`O!OZfbB+H^{~PB2>(2j4$ECBp zbG-SolRV0NpR=&f@y^BGS-h*6|5J2rkm*t?v3AgI%>V1Lc95`kkg%3Gy`@SI1oQun zG5_z?HvexYTn)-+I?{i5%r*X}K1tPozTfn}s{d{C|7gJf68Mj=9iseihX2j*Z}a~S z3cg)mXD0d&kE#0KZTwGtkbnID-;`z4|Mxp`A9nHk|F+Hlb^-t4{NK8EpalAF{CCaM zpq-#2{qJ}DpVWWqhwk(LBf|f^G5_E6f6#Ev{CacIe|U8A|M1#X`#+!0U;hVl{7>8Z ze-->M3gUm`KXaZ2?SviaKRo6d|8xG-_@Da4;{Oigf8{^S{~7;-hHK{6n~DCzW3KVP z>3??l|9xWom&yNI{GT~fgLJ}<^gr+TpZX+K|EUj5|2x$Gb?`ri|Gyvkf8&3UP|f99 zGtqx|Ox1t(cNPCrA6WcfzyDv`@&9!AFT;OY{{Nw%{okYg|AE%p|6ey*spJN$pV@1nk^>lxlgA4dIMq5p#Zei@(D-zNq3`r!9l>F?O+ z{J8)#WGC%N|M|1@HU8)O9sQ?%=sy2HnCpL^x3Ay7$IrLUr~UE@wRe}w!E%^r|DQLg zeTh^KlOwU||5Ntp??ap4UX!Q;CgcB)u}xu{O56W5HvEEzG%lb`(4$YlgF&AldJ&aQ zrQX=Yy1<*L7sRa>`pJ2tdS}Q`&E1sP5-O;|GM#iIl=#o82^XC|CM#vmmv1vjPL(YtWWR*vG~7< z{~zY_G#}SWt}m-RpT+;3R~4D)KRl-Df4A{J^?}9z_4EHe|K$5L-%|7c$@e+=KmIpp%>`4Fn9seiwpZZ~>uOJo&`lBGa&UltX=ces#SKxkEmV zy+l5!$8Rt4HGcS7zb!Z39(+3c7toHZKIO%Hc0JpbY}e54dmY;iYmCFZJDS%CXZt;k|(isJpFIw3GBtP)&AHQ z$nq!TN$e%EgWBwWQl7!yRt^g6XJj+>QaM#^PnK^+h3Ct5a-rJmWI39Qy}iuP_PX;m zzS*1OE3#A2zPGpRi@k#!q4tI94;_HLOnm)sC;xXc{4aw4eaZbj)jCHP<1 zgn!D@;lG{y-^PIdWZQq-|8K;<#s33Fck|2bNdMv8(f=g>JfDvK4;ufA68t}v;D2Eg z{*(HDT7v(VCiuTN!9V5Y=>J7har8gQKeprlQ-3@0e?0&9rI`Mg+th#Kzd29?c0^11 z58saepX8r=cJ!a;aiIBsX@dWY6Z|Lr|BDj(pX49g(f@LS{~1mA$KOxozn%QwGw{C+ z{{M>-ZU3hK14eE(m)ny5C;8{A9sO^{|DeVHQ6`iU($sCr2ePn|3d!N|Np+}e>M~i?pa#We{Rpwf9zELM=k&Nk|z8o^}kvE550Hz zzaYUs`9UZCZzumZ6aBB(_s8^qa3SvE%3IR^X8b4P|0MtD)1c-59+IDsUk~#C<#^OkG>U(TP}|Cjp3`v1oI|F)C=i}Sw* z{eM+3_SgLX9?(|2ugFCI;W5|#zo!2U=l?3+6J=L4NF~sb{^#BQm--}C|EUj}>pv4+ z(Q|JVeF5pOSb3TJBlbess5beDx5&G&m&(d&f5ggr{QvjK1K7o%|DTJrmz6-r zC6I~!!&j>Qv%jnOpZcKv_i_p(kpCZJ{NE!s{;w5|2KAU+^dBCb{6FzR zs{X_CZn8T?I3`Ch-iRSP=Km9?gzI_h9G6E1W1!;WmGu3#$NzjU;NSB9gNkgX*WHo+ z=Ne#92JQbg{x4JZig2<_^dBB`jsM}> z;{W>X{}%rjfug~^hK}?f9&?TVsZT8b-ClmdL$6Vuo__p}p;{RUo zFlyg%!EPcm*GT0cc^SQLL|(Zo^Z#OR%h+|be>M-B`6qNfP_=K>`GMK5^M$JY1Kkgw zOBnmE_FB$2zGgy>;Ac#{nthZUg}m2H>{*Y?PV4;ZV{OVif_bYhq}}?wpxs)g`}6;5zt<add0Bo{PAi3s^s6S8YFMJq=w$(_dqc>yFK%t=BWbdG)tmv;JRy zpA_`p)oYK>SFFd~zjgGP8#qq;`|A7V|5I4@>bL}a{^2*3e|S&jpZcL^{I3c4-z^xo zx=A@}o&Syt%06f%FoY%G^AEqN{8K-q@=yKHGyY%I9sf5!AH8Q_->2lWsQ4VYJ+MD3 zpU0jn-wN!{%NMcd$u9%@i}Gdc`QqIa=>INgemSUve62_0b?vOpXuqdxXVY)q8)vJo zn;T!FO7&eg)qLIR>HTeizTe3AtIlftir5={R!216k>VMb#{~7$3 z@&A)!XYfIc{~kWL_Enjbz`*(cx5V`SYU1sQ_Wb{@`TyI1e=jk2p7Ec_^JpjOZ3%pK zF8RC1qxFB@HzmsV>6P5V`cz?lPwnSVt=gI&)Ys0_u;oB$b{#R)G2Md4kI!A5R1KCgZ^KJXbN}!t(@cAeH57+UxmSi4p>-<@}`ubM( zb5I*OMsrbQ!{j#${Crw4KXplFkei}?4ZYI!Da*2p+URw4e%eWLGcreeUa&sZWI0;* z^ZnKJsmJ7OwfVjya=Wk59;l z_?b_>@CiNsMH3ZmFPu+)a5~GRjvq5o8S|!jI$!v?!S&4Y=3+0B6}q4A-^JSldx@MI z*av!tU@w)|1on~M(b(I|jo6x>Ji%LuU6D|p) zKUCMJ3;3sgaQNqZUGWcZ4*&4p7XObAG5^N}{LhB}as&QX2mI3>f&#D^|LGJB?%sD$ zKhK1>Z_5cDp}myRd(8)Ee6RLzHQt0@jqlZdM&o_9A33cn^_-wD*nQGfjz^U!SzfD{E-RN{C@UNlfMi; zzniy${aeXvu<<9BAB3JxrN7Plb^rOY)6w2>*fXpC3;O*aKT}cS(ygj{PYtg}VTg%N{iGyK-i6kh*-8t`9E(SPHgCv`Ml zKL7BU%0E1}#Xt3h!#|(Tm4DXTarmddU_<^tqq+zG`@(;D1o=M){>$2TG2nmO6#rlK z|9aE^VXg_TW&Uf`{}pl$df7n#ll;SXr}}?`&bR$IfvY!_?<>j1s$H7t&BQLthXZ?w zw*-5NX#K?T@)$p=|DV$R=gYD~iI-LXzmBc?ei+}P&sWa$R%6eU*H&$LoF8BR z|2yEHbB`qdSHu5Uz`y$c_4qgaA78#G^qf1&aJ9Qym8zXUso|L4#*e!bd!|6%e<_K(RMvBxi;sJuzuf;~n4O>N@& zcgRNUsq*idU&H9 z`M|r>W_|G`-csyJ(EpG)W^%RPL+KAN%zgP|4L0M~Xb$h;YM;Z>ByxCH$71+f$>D8^ za(MBaU0S|Q1wbfBz#dKrdU=fB0@o|2e+38gBUY{NrCc z`dT}=OV ztZ~S{AHNghEC2B}JoEnx!Ca9pqA&cT->Lrpo=x~q`v2|lKP}MzJA?dR#`+)j{|)>1 zhW&rT{=H%U->`pg*#9@|-|P4HC0+{q_xk;P>HoXG?C(D|+Rr5%`=`I{WhKx}355JV zBxeyX_bC2Hzn>L6WYo!T|0mwx%G(M%ivJgq539xhYbMCH{mhB~5Au#=e-Qt}|8bu7 zUkKuV^#3&POzfcjpZLGpet>RXm9PJA{CD#-+Gl%R0wMo>&Hv%=r{@3mY?A+LNB{S2 zz<);le~kZLKf(5W-IPGc{|`m;BmFF(YEX`N!Ka<6{rH;bK%iTL}K~ z|1;%(jqK#`kN;4OA9#-6+6Vrr4;=o>3I1nv$^Y&N{x3=JPyJ9GUjhHq;eTur`9tPW zcqB20LCF7V+Cns+sQsj=Lu>r&xS?cD(fA+es$wYkr~Tj2f7<^Y{)zwl%Kz>O{x3=J zPyLXp|BUxaISE`A{Sr~Sb3|7rhs z_$U9@kbiA6*Z%*+7JmQVjPw6t`+sijf2Rihe=gL13*3v2UDDVk-u`!W(En#LzB&__ z)W+~x`(G0pMsIh>|BpoT<-LplpO!M;7v=w_LkQ4@~8s{9(uZhw;Cc(EmZ=U;F=P|KD&7UsC^#{|;#wy^r;UfAl+*fAWD2|7#{t z|Cs)F!~c{({|_B-{ zM(=cm;2(cKm4EX0UGcwWg6Kbp|6djGuj>cs{2v+T{|Z0<&rO;?pdD`s<#16fcc^WB z;rxGo{*c_^7`a26|8J-(g+lO;-e<}`?f*{x5C5UY|EB`}lktB>{eN=L|LOQ2&10(n zulfH~F^0qOKMz^{f2g6&@a97P``Z5({!{z^qW_tV{}1E;ocOQX|1a79$4j*TuS>N5 zUzq6shwZfgpC8Vz8ub6$H_`uRQKJ3-saX5})3Nq{=3DXGL1`KB{h+Y_&!a(mqW1rL z$lCui#I10r8c6=T8UG))|LOdnIr#s!{$Jr9al4?D5-249 zz<-$c%5eRU8vi@Oe;NM$?=b$u=goc>s{{(cKkfgi{FDFhYW|-!vH5?L|M$RuPWeCY z_vpXhKgakl){|~mQ?CRH!9VSPnetEjzcc?A{zGm4uW)+Jo|5+1`--+7)4)!M4AI<-BymumYH2=@( zo~~yY&HwWY`31DYpZ0$z{-^!l;UE8@#{W|}^M7Y7{+}84G2lBb|37T#48{EnB>%J@IQc)?{~i8m z|8L0u?E(MV{vXf(XQlts8t8v3{9F6~P%t$}HxcsR)A4`F@juD-zco$T|GH`aSN?VU zUtanDF#nf~|69rb8~=lZ&QM%yU-<85`~RW_{(na8e+#zv*Y8~Z1^Egq<83Q@1@>3u zF6^apLSWw|-@x8ZUKrTlkbAMWmn#DMUimI|MQ#Y}@5=YFcaVPx?C;A1*vo{j%+zH% z2VlIvQ7|{)X8Id%W~}jpn(t(+@l@JB!?l4Ltm9XbMI5`BZAon`vW`ivH|{tbmmH2O z*73?~mWr%ryP7Su^|!vKzxDn2=UVyyP=Hp@n+W;u>HL4__cJny_W7v&KXv}UHBILK zqyOKr-tkWR|EZp?XB@Tv|6G1vZU5hS$oM}l;Que+e`zeHS<8Luc!P`Je|5lrxQ=hi zI-bUVK|#&wviib5{=dUN{(dU|r+;pT+++tjsMF^|94LC|A>AE-)Z{a!P99U$-4wX{tLDKFZF@5{vZ0Ey8aLC|IYfqwEsKn zf7JR9;+H=Z6r-$4lsB>%J@IP3q?{_pTl`+r0Je+-Md zu7&phzc73L{q;Z2m*szur)56*|AY3YJz!s1{ut?!5X zE-Z^&%C><`+XKV7iYtq%_RIL3zJF3+uMd9fT*hHrVe;JZIg|DOkL@F(*JH2dCD0fC z(Qjw{U;KS%{Xg=7ZTbK0@V|e||IeZSUrXzMl@t8WXu>~yJL`WX`QJUk|0N0jIsPy? zlKNq1@xB>b|EttM|Be6V;0(zTec>PdPUSxt|F3Bh|F^^cw*&t3>i>Im5dT~Mzab%H zxNoB`{L}vL@Q=Um=zo%b^7pCvzjpbr*Z()G{C^|;HS38tA|AKcIvR_hpCt_q6|Svi~1?-?R4rQ*-A38v*}1|7UHC5#MR; zf5Q#ZfZp9u@K5`{)Bm6Lf2aQs{zI+*&s*}1|8L#4I{ru7`^FhZb5~$9Er>VHm>Ta* z)DN0h58EDJuXTft-wAT=yCw4Nl{xI2%QlZ~er-&S=C{Kw%!`M4_IkN?eXm}=JV0=$7|0nJL4*#_Or}AGf{?BOqUmHblhgu2ry#xx$ zKl#7~-U9fZB5#~0=xCz z*h}Qxz&_AB1beBxCa{n6j>g_zZp5C2KXZb&61yUs0(+&m3VR2+gT8ILe--l^X#c-Y z2m8QXN zL*8Kud54Fqd503Sjg({|TQomNiT=$c?xDmyCXM>wX^tYyPbB;8wUejlq+eiBnJdzD z^@aar{vUroHUFRG`2P=&IRAea@ULSM{dt3eykngI)dBypyrc17BxRlV`PcTpQRUz7pBV6er|ExoBn{@7 z29p17+W$lTYkl*A_5U*J|Nmn8`)Iyzk~hVhL%#2-p#RTS-c0Omc5ktD+hD@hJA6dFl+4w|`xb>c zK>e(}`dQ|G%5||Bna$e{%iLLE-oW z57Y-p%>S?Ld*S*Y58)St>wmm9hz*jyL7n#fFh0=V_1fygc76RF#saqfNAa1DUtwSP z?`Qjeoc|o=|LHmZhXnlVctc(PV>)%(bbN#O`X8FxZ*d;4c>f;bKTgVU{=X3X_p<%} zt1zuf*%c48}m97>=s{P(l{Kjc5z|1YEd|2h1L z?37jlxs^c3|3h*X*)WkZd92xwOJ!U7s;d24@?B~#rLU^m&ye#{dpr87s{ONI|6=C4 zQ~OqOW4eC{eP7l7f$nGhiA9VXS9@p9KTiAqvohJwz8$VM`M<5at+2~-USKcu7GekU z|E!sipYb!5IW+&Wx_{Y0-jVDN=Ko?m{Bhn1*jvl{{r$4jY2KOGGi6@&czKMUsoHN= z*Z=agJ&d+8-l^sPjDP+*_8PSk=nMa}|2zES@2B$5`2WoKf3N}n7XOdhqi^?12^4~V z+W%AeXZ(Lx{I8ja^#9i}{(l<3H5=e_j8xp8uZ_ z|D}&pr|eE&ybFmhv|sKI8DFn`afS7EH`6aq`{-Yzb9~becQWJit|lhYv3mYoJ6p@y zVRFU#!iq#dofS|I2jDuJIo}d-l8kB`}cu zchLS{<6pH{^&z~_#ct>|FN9;|GDu$8srSeUG|0lWd5(0?f+Zn%>SeY{I`<-xA=cJpc+(DMHSM8arZY9aVf#{byO;{VkCziI9N zvjhH<Hl?}0NwPxE4GPjJwDmKe?P~BpViO& zE;xQexq2>Z{~t|mv%2e{;Ggz?r~m(+iT*$F{Gal#`F{_6j_3c3|EwMz(Dd( z`+=kXdnWjo6#ich|7G}Jr~Y}&|2O^z=&7|!&8h?n$$ty&{|^7{jQ`X5|CRr>3I4Nc z|1->MJ|HgmO z9!0yJK9oRT`0r=?|JMWlU!3s&E&lJr(`R4V?-B_4|1m97y&V7doQ(Os@BR6IX#d~Z z+ZsEX|7Q{FU)JXTA%FiUKk@m04)!M4AI<-BymumYH2=@(o{nb>=KonUA-~|qpa18g z2KsOO_xn+_@9#qi6oP-+`!nUA_J4)w|M5rh_`Z^a^M6kD_=)-dbG^CP!Tg`_ z`!GK>|DX1Q{k%ijANc>Y{~zTYgB|(*Cwr%2NArLFRDN3Z|4#_`_xtBs{=dIZpM873 zOQ4Ya)Bc~zKkWw&|Fr+N%zqgFC;fkG|LgaoXy4z566g#6=y$6AlMhVgpZ0@}`Tta) z|Ni`3rvH6-YW#mP;Qz8j`@iXb!JbUJoL-c`Q1DOtzmxx`{ommq|DneJ z@d5weGX8t0 ze;fZh08gu3V%8;42>yH7{y((=|JMGO^`m9y8-Nlh1pmEk{}0#yRsCl~VCL(8*!-UZ z@YLHSh9xi*{I}EozY+b{^}mh(@DZ@zBU}Ol$$vNP|GNIydGN2}|4si#_{q0h*Agfs z|9Q6m9~bbi&yC|9>dpe{v%KZ~p&igD|3Z zUr7G*Z2wpOr_uhGZ2vd@N0flkzU{v7-_Q2{l@0uV%m0ry2qSv;ec`{K?ftz>b{qK3+Jg%p~`rpJ4`+JA6KUn{p_Wz^3W3hwv zznTC46z??bI_rPm-oXDi{zsI6(Z210yKTP&`oez;?f%X5)Bf+o|Fr)%jQ_t7@PDD{zdij{0t3lE?FUZ$Py4^ae_H-e z`~QdS|K|T203%)kh2+15_J4=}cJluh1^g%1|Fr%;BTm9--hN;B&!GLkWB#8C_}@P# z|Nnv+QhIc&YQLgMTTAKT$^4)1q%E>U%SB0M$!bqz;(6l#{_9fp|N8r+T}1Tv*Lf5# zEQ?&qwt-ELzkloKGdFPD*<;oBXYN(~jM~2rKCkDnmz6*(CD0fC``P~got*vu&G4_j z1Z|Zi`XiL2Km6~qTeTk1x+J-^@?6+4qfr7O|38r4j{kX5g#I}tIb7TG@%N{AQ?Sc& zUbTI{G}oJp9gP1WfB$2C;_d(K_WylE9^v!o@2#W3|7bkDc9-3jKq2_2{Xdm|>5~67 z6VM;<|K6PWSO32N`rqwyVV@t35-0@!wEt(yKkfg{_+R{o8vpkh|D*9_+g-L&0z<)n z3*-N5{C_gwe{GKWziWf|-y{Bipg-|{D}Q@C#!6ry`R`!-e~tez{!jM*%c}iP{r`~v zlJReZ6}toq$$y>s|DF6_2jl;1{67%rf0F;K`u{5b*T?k#4W|FaCSbI$t}pzf-%kEN z8UK?Hbn^e*=KuJ7jsMX9?*;#=|F1RvN1L!>-+f>BN550~r#^7_U(;p&KhFQvIqSc+ z|E~`8zmM(z#eVAS>WWeVec_++zYhPsZ2#B!f3^SrOA`6Ntm6NI@NfNpib7biucHwB z4omKv?Ao>3-|I+r3mB5xI&=>wY82_Ic|2h|kuK%0Y`rq3B@3leu zzxMyJ{(oCOboNeRN}w$3{f{3= zf%1Pz{co55I`jY6;{T24|9OG_Ulr5;EcrM6H?#(%1PY=5$^3u2{I@Xwe~o{Q|Ci<* z|Gyy?|6BXtfRHenmpPF9(|+Li|1He_U*rF81O3v5* z3z@%n9h?4N=jYW;-@9U)$kyZQ&HEdERzLH*;P}yeTJ5g0E`gB$2jvB{zxQbUU-ExX zk%g;L`| z{%;Qa|6^nPXXXDJ|5-nxcD@`-z~_I1j2|xV^1tOJ3q@u=E|qu5IUZB-${v$NW?vwc zMY2fLzHfmrgS}LClRdFL`AuN&Df?iTWCov~#pm~t{jkfji`pE&pB#uiNp9Y!y8l2q z1bea^t@|&R${}(%_L!U<9Iw|iAO6>2k3T+9xn1tSo+{S{_UGh3v8TyfS5)`kCHG)Y zmv;pFza#fy&yWuV_K%o9cs`7ORc)E5{7fFh-dgTcd&9)C|CL{1ZzJ#Jey~fwk>6m? zmK&?K+{({)Zp5a%mLKPxh+UCQfqkNPGWHH~hn64vPxem3UM8Oo z_MhgRiM^xTtM3JB#;D;jc7XN`FZ`NcmLfDy5y0doOLq zZ`sTo$*-M-Jx5BD=1S@6dHi4hvJ0ei=t3!RL8VQLv6rxI%eItlJ9!enMz`1Tyy)-8 zxK91QZlNEvjIvQ5M(xlCO8PwdzWPYF1?wB|;Q98;_^iHvQedwSe!rFV5gMJ}f1vH3 z)Dj5v-{l`39sV~Y_=j(Yf9eN^e|T?;e~x$f=lq%S4}T8-8`|Xm@rmK#|HlFUW%%E} z0spH5{|j!{owFV{owGQ)PL#+NB=pW zqyJg+5ATlt!+Tr&Kc3M4VdDRy82^p*-}oOOg1fuamiUKfhktl=_{Vnmr+#qspZdY! zpYu8VQ$INR&-vQYe|UHNe|T?;|Hl*l|1k6aS@qk|3``c|7e5%sm6ct3GVI+ z>*_x|I{d@0qyN+oj{Y~}pZyO1oX_DO+u@)3!Qmg?o%|oXx5YoaJO2MD^M7j_{9F9r z9b5zOX`lbgw~YTc%Gua|Ec^OJIMc||G$u5Vh8zu z{QqCeud##tKkbhn7DF1($ zcO-U{|3B6{0Xxe7pWv;;j`II2y;HHH{J*w$#`FJYcxPcp`Tw&#{d_|X^@GDd$2=%{5t%z-{GJ7!Qr3d z9sW7q;h*}!;UB&o{qL54@(E7=N*=^PrR)wEw?4X#dyz|7&CI|EB**d!|>&P!_y3^> zaV`GGpLkS$fgSb#d)$xrqyB%tmEW>Ii2rH-zm1=G{Qn1e3OkDbCo_LpJpLc|=3qzh z|MR@vv7`9^0PkSzDE>dfI|@6B|Bv@h!j9tqle|-~qxk<6?{w@a{y*J&0d~~??*)Fm zAI1M?d;0ez{{J@oj|J_2jrf06jQ@Wy{s$iNlpBcr|9AUG`SCw`?eLEtr~3c+>yG{> z{eNsn|IvF#|Jm>8Kl=}tF8GIchktl)i+}QeL(BhXV*EF1|GzrM|KG;=xBh=ABn{@S z&(5v(@1KvF>Fcy9^jEJ)Wii?$;>lmB4WHYSOBVX;hyAzXFXRGj#^>ld zeV=Cz-95(WuY!H`H2L(d)jr>P4I9|PKI2dDzOH*=FDn5nf!0dkWcZ$me(xax6Uz>gL$OQM`r^ci(&2JA_Lz8=dc0ef z((~9`uGSy*>X6dzx*x``o??8r_NTL>tOU9)f%n0$j_(Wg|KEL{BmMuV+P?ljkMF9l z|K~9->moMg+Fn)yRsw@l0)G7OkN=6q|L~rg|0h4-wEvMGaN>XBcPIZ({o=&`oWFVe zA8Y?_mj5T-ciR7n_nr2CY^VJn+sXfrQvcr*TWJ4_$N!f99~_uFxYAqpclH0}*sAx7 z$t7$2fAM}*duKTbyT1Ob|FDGIw#NVOCk7wCe4=uqoPzDiy=s4ALSD#^#{Uni4X+o= zCD>zfliD*U$OueePmy`V@3YFX(`B+An|S|IY`YTwUr225U2*}RjpF~%@6d7K8vCpN zVex+l4}pDTWJ@5@|5*PY_;>UlJ$Lf|?057Z+tGjg14sYy4;=mHe2)H8e>nMn&X?N$ zPyONa|3S~&(trGkk=6e@1O2D1v|;;yIR4kh{|$Y;5Vils_=m@~_=jhQfB1Fy$9DLq zesK7wesK8bd=CHc?)3kG_qO` zQ$INR-;96uJN$D#hktB`f9eMt|C7`BAA-B4{eMFJpKSgAhYt9}4f*{0IX;voAJ+nhkwr37XRpZrsMw@|Kp7R+b~4q{~m9F|FuE?AD#bi zZLI%~_5V%KGx+At)7<>uUfAO&YW{CKZqAd#)P~23?2cVO|3|)0{*<3ue(w_#l?&y? z*g<}e+};uV)be{GJFS(=u*vPci@e^h^bhcR59nIiQTxB;_Xhv@vO6et2}JRKO#jhi zNB{B19sQ?1aP*(!9sS2YaP*(!9seKy!14dv)qnKf8UNp{{xkm18UMdwi1q&~vHV}7 z{=cFBZ}Wc?8{Q1AZaw-w6F!fYm!QW%|3Ah9D(`Ch{r_fE`B%H@A56%J{Al~$2H#(p zShiADVVA1@0{#C^lhd%rQpR{x|ght^Geo@``clE75ly|Fb{i^=jjP z=nt&C*Bk%i`v>U#q5gOuPp z)Bj>T6?PS)QUd=4zwz-u_xn7n|Gzy&;K|R_MxS>O2JRBC{~@sV5;_W#zi$+`Pn{vM zn9c9sOZz}W|9|V4|F8J~%m0tcqi6S7fD-Wie}De3SpFa0o%}y`s{hY^$N$IQcl>|i z1IPd8c*p-w=KqNgGWGxQ_nrBFH?-;hGyl)f%>P?z!T%4}|5N|}nppe4_5UjXvDsdN z&%ZzaSB!snboeJeaQKH`C;o57Kl>g2Ilsd{^@9`tb9`6)!@D#8H@vsSe{%lsVdB36 z|2qFyEB$|y{r`;rY~d@w+3M#1;L+h9J$CqqUx$C{2S@+m*U|rG{IlQTpYylHKfF8r z|KPnX{+rGJKTP~T6Vv~&{eM+r{om_i^M9HC7l6|IF5xUrJqv!9$WmI{J(;sN`2ctf z=kxm6ylQ?x`PcS;e|#_f`;M2D*unT-a(}7gd+Wsiweh{*kH!B_S^S^hU)s)WC9q`) z`15;os4JY)Aj`4;=l+KXCLP{dV-9`o;18IiKVIW4ERM=)Keb54~?o|7kyT z+W$sL|F!+Eng1Wx|7$J&-;$c)d1t$=-2DG??D1Db{r@$;uk8bl{==W6|LD7;|M&;a z{2urR$^3s!|Gya1|07NRhv&(%I~jx$xD?)JmZfr#tfA#C=>O}<_yo+V9iRVGZNGlF zQ1|M7PhPI|g*Q<-j{d;R&Lgi=yIk!LJcW5b-&ftg>@+!({Zr)j;P^kG$KVwD13!R0 zi_^Zy|NiN6uG;%bWp_D<{WHXy7R(>2{e}0|`hog_J*Bl#+he0P$ggp(uXD{$64}_x zO2A5B%MxhG|Hq$q{D1s)$N$H6{D0yD$NwijaQuJH=lK8l7mokW`JDV8{)W^44}ZTc z{~v$f$^VbC|9?c_|CgEnC(Qq`4oZo&PfMF;vW-jW4YB;+-<$uxB{jqIPTl-JJZ_Ay z|I>_r_B;H;ufspK!$0+d!$0+d!$0S9_=k6A{U2;+{U7Yq^?%^qS^opuS^tOl-&y}B zx&8;f&d{v?b5jfaUmx(F9RFwI|AzT`ri-9Pq3r)zke?O ziyf{1{Y&``cCh{z^MCxG{2z9({ulFqe2Aa;`d?4V)7a7aUtqzft>}dV3>U!VN`d=%(RqT(}|61j*_Z_YORbB5pTL0@T?;MVg z*8e)k)4%7=;yqob{V%EiVgLVR`@iu&bo|fT+Rgv%&S2o#jQ3r@TK4)n1Y7(6E(!Vr zpBC6V$ZqVdKOe~btl_g}FOkjszJlMI*xtluFDn5nfnt?_um5%D|2hx72=pKQcH)2h z14sX<9~}Rm_`&i2o9RFM9sTEgN&UY=K8fB&>wo^Id;K;gVuk+9Tsr&4^?wI!)%$S%&;0_sB8}JoEA$Q8#aRhh2{bH$ zYv5bw|2SAKrB_YR|L1NQ-;MRT>-GP+jN|FAgZ}G&PyG6V{(ndD zyDaZg8+|>K`TwRc$A@2^Fu&$Gat`)X`Al_x_|X`yKwN9~}NU-r=9)9sa2wy5b++@0SP3&jjs~3_HmGWB;%G3OmUEn*^J^8dSfdt*oW|3kdPv7`L|(cW>`QU1T$-XG=vS9zziKg$1~?wy4l<^QYg{Zan^ z96#S5<^Rv~^zTXje`X8(hy8za{*Ql%_5U;e2b}gTFW=|C?))Dy{?TJc|KZos|7QHN z-{BwL9sa2w9R4}JE&k!%Y5#-ow)m(2-^lR4ss;WV_5ZQ_-fwdpUrKR^EbpFh?3opC$C z9H8~$bbZfWRsvQ6y)S{f@jrUJQDXX!Kkn#%(*LJ^aQuJt+wuRK=|B4&{pb9t`j6f_ z{eRH=w)CHTg5&>>lKxZImde5WUk}ZoZr+M5G5#mie{28iJ&-;A#$^BBJJ9dhcSrqy zzv}C`R4THZE1M*r3+yHS`hb)D+uOIH7C><_``~JUQKioYb2k_(j|9@rve{ui%c4ebp z0!jTpWG?!@Cer_tv9&)?sQ*U?w(0+hlm8=s=j8v0FP!#2&gZoM zVW;N*$oDz@|H=2YmH#8(=d}Nia{li%vHV}7`G3OvUvm7vwf_xWCE(BR2cPrl&7!Y2 zGT-+&{4VzMeI=R4+v@-C>aYJ*_SgH`$T8J6yGgPY`Mzp@U&&S9AO=sGl>Ue)0?>9;Qp!)Co152^% zxA%2>4fc5}0V{$2lz^}Q^#50V*VnP|Ka=_Y!}h@V{NLI>xXP~|qWoXAzKGiYs`W*z z{qLLTO$+`1E-llyknI|_>)38!JDo4oIOBHy|4FtxgZH#=!By;>{{V832&z}|KXUgP|~m1C3q>w8JY)8317ugBTTO2A4WDuKHFe~HJP{=d!Q zfA%}^Km0rKKeiM9Q@=RzKluSC{^xvc#s9?jPXFI-N5O;o%qc2 zWEWZvo-ez~Zn8UV275AZ;NG&2tdMLMx2vy<;k{n`ulqIrU#s=O`}{}=f^1p2l9htvLtfA94F>DK>e z{%>deKl76ft^ZFxwdMA|Aszqs$45UmAv!l4+jf+Pu4^Cu+c|s{sfyeXm}1)%Vg}-JO}t z^bB2-PWM-@>ecJl^?Tp#D^aJ zmAG8nDbpzwr!V(c>Eg9~cx?b+aLzrxTni}Et-N%-*^#@jzDk$h)+)CPH*tmSp!?(c zdWbTewEHfm(Py1o? zKlZ_Z>VNdTiT@{_urB>SoYw!FTZjH1;_-if=K1gUV?J~1v*oufWuV$|SB+T|=N07I zVo6<>^7+$O<96bYl<6nqRL{1^c*ewQ-e`~8Yd*Nlfpg<>-B?^ABMR5L11j@>A?rof zxc(>YgW(_E4gaD2Py1l_=XhiP(?0ac{)cxH{|oPR@xKe!|2#4}p88DJ|2#Q*0dl(j z=bY$twjJl>F>$)&JU3eS-94zRwhlj{8+6UHP9v z{XOhu&2I`Ne-gR%vi9jK%44WV@F?EB7JqD^s2m z=XW2^C!E5V>9Jn^vOIvizntOa2jm;b2grq9{szx4oC5z_y!5Xt8A-~vXi@c z#KaC;?}MLr{j@jJH$I19a)!X_+S9G3mKg9S5&bF=aPPji295dHl){{OdL-iLd$()hnC zWP5sjL}^Ewk`RPeJ{H+d%(_o-X=@tPndYEKlR<;ihsukDU-%6 z@5*+ya%tN$NjJLB5BPHJPnk5nx?DdkbCQ1S_xs-Ff1~q>KkCcXMVT}%bc8!-C;cYz z$@Vg}Nhu(Dd@+&(z8(LLAEQi<5VpQAfb8XIDwAa~bL*8!-l<*f(M>l#_olsfyYBXb z>Gb>U=I_Mi`YUD9aq$7Vzg#nslp*uJB>DV#U#`hkkjKfdko9>%*UI(C z3y~fKC*ZZ95<$YZH+SmDi^?aRF z&m8h!@$dK&%JM62E45n3)9UZI?c(}!7aY0t&_k9S5%Kx8569*DD`i@8khZJ3#oi|O zvD|-k+$fx0-_e}V&hPn%FV~fn>H7zZv-HP7WVp3%3-|P|eD1XezxUwfX`b7E7}wXM zlX3=v%k?lD)~7>nD`y zF3j<&qre0o}JZKvgv8^S(`h~t+S5u}B^NM#5V(Hez<=W)S^##iG9G0Kz zJC8f}>z970iyn6c`E{*xO=#_PX5dc25!*4Nj$_w+S=W;~x;KdT;t3! zX)jFwA30b5lWzL|Qfn@98{d zolM`*-La*s^Vs<9n03?Lp3W}a(b*Nt>wDJfhdFI4J36<6!I#rzdU}sB7Tc^_H=f3B>BzX*n9Tst}UHOetJ@TPJGIh$$`r@ba(fz z3oq|W6(^dEe2UqZUmH~Hn$<&zZMy-lF9aCZ4`@-dQW=Et+%Q z4k^p#&6_K0yEpc5D^T9E5-1R-Zt2eIglr`PmUBynf zkIL`eyrnZe_l(Y7j@#6=dTr+hZcLMK`sU7;ZRy;&_6oCiS@)LBYdhmI%<0||oU=^t z&Qd|<_audgi`3!DlBRQY_rs-omIdYUgmjcGBL}Bt^haL2W1%_B7Hh+*^7(C871vTy z=(JcHR+Y(j!z#yOSuXq?vU&|H$m}&e`f6({ec+4lSdZ?IQkCRp+tCp>KdbowYqL8# z$h@N?{!nuklq_@3js?mq0yo%3Ux@glHh{+*b1XNiZv#)$Bih>Bn|Pt7qWS#db24YT zJUTb~+dt+a77ooEwd2?D*XA~;oI~-@qPuJ<`@HYIcJ&3~Dn)^U%?Gxo;}sD&Y(DWRJ@IKI=NyzO-}mn(oz`{ZGmd z=~O_X+4yeh5&CU2GG96)1xdA4LFRmL$b|UVv)h&I*|KRx6^n>% z@!BFzS+QhEDJ3l8g0v9+OHl4I6%v03(pF^381LM$D)UWzCL31O`dw5P`Py_JwKnww zwW)8p+R_2b&s+Msix(|JMb2KZVqTm{k`?84xy7o%=U@Jd#@8mz9LtZF$-pZHcX@Nz zhE>^pUc$OHp~5FUf`Ts^y9- z7tNiwblIxZW~_9D)G#U?LI0y{Ymt<(tqpL>o|iR$@@ge9tKv#2Nz@4@l`}Hi+LBM1 zT{Trmnp^42(uWG)EV-0RJ~xrP{g8+*@w`MTmw0}~MC!|?^@KY3a+@9|Uy+}DWssbR z?w6|kg(z0#FGOPah4OyV&dWD-Z=`1s|D+{}pLCv2p}*ljWp>r{lcu?ql)}7omn>eS zy`=JamfyRh2274~6_p4{tJ}F_ak2c9oq3h9e&beJ+PEtGXDVX8+uPO_zn8?Csvyb5 zpOrm%$8VKav<<5-kISVWDAdB$m$$X?U;Lq_vbZz#_|iFb7Gb@2ifrJ67GeEHim-lT z{GqlY=$U$a>6|)?;JU_SF@3f6ywta|rK@-SrmicTfWbzy9e-3)%6;0rzT=Y44tHEE zclWOD?cAh#+Q~g@S9f);S-(2Y&q*n{^=nadvSyg-@5cKjidMDD~LOTo@e zDZIgs=PWE2$7RcOr>GRuErsy1Lik>yck`mLe+p#1YR+YOjIF-3b4c@Fx zuFcdt@szb2R`=3mEYUsOkouMgwcU|GhAxf^VU zoja%)a|HKgg>sNmsT?F#EJt#qo2z8+_8=j1%Lggh`#wmj>a^XQF#z(-OP}gDGK{%R@gtQ!u~Qv+_3733b|iVA@?gPdzsp{r(xUDQA$2$ch=NYrdg)<-)Zw_FDu=9%jV2pFfYwE{p9X3y?n6Cl_lJ_ zLt9iTvFqizY`hXxYdw29H%*+SPj@BG9G-MdHk6lJ^mp6J@d2Y{&b0dApL!ooH=jlysS63 zT+XS9mA&4Mnz@up{gpWojZaC> zo8t#FvWNDh$vX^Z_~SBFT-uWz(kSiJKoXlb-LI31z3~@uC9B@$_DADJ@>wPCt{6Mk zyg$mN`p@o4*)ff{I*u?oWsi+ZRmv&$C3>+Z4&jJ>g-HlUdT38_SbP!z7^O5Fno*Z! zazr*|li%rznpmTm0&ZB1it#sQ;o&FE5k0LPx1G&`9(|d8I`*JJXtATr6a*cZm#E_onKSb$F>z<=Po8(2`eXBs>FiqB;~GeH z-fD--c^ds&5?2*BalYM6+ToIjHt}CI))#RWiO=-V>~UU6y9>GsE^}hBt1ikmsf{XC#-ZJaovnTbn_e=Ms-yrj=x%l75g7{zJaZUU$vWfpCKG?+n5+7{hf5Z7d#0Q)BU-C2a zf2zg*67O4A{4epnX8vzq_v0wDsSmp6&GXG#oe1%(GTsCIHl;$ zk*-ZklX7ME7q!qw6c0}dpE+zsX2PMaY@pjzHxE$c^{guRQD$a|)WknL8~)+d@Q-Zx zr+qN-|FjQ=fATZ@(>|E^fATZ&|JC@1Z!`a|ul(jWl_ zvmlq7g|7R5PdRlJ@nqYbYb9GJvmf_hcHLL@PWCYK-{+U?dB&fst8nVdoVr?Pc6-_j z$N6&aKBesZA9ytSzZ(Cf8~)+f@Q-Zxr+qN|(>@sf$uF0G`2J7U*PP6{UTHaIGFYNxX&XwCi{MJyi8Pfms`cKoi^oOcpt(0M`@pu z?N^lR9h6HqU7cej*ZLOa(G|^fH9y@>ak@PItpA_SciTj}b|2TeX`IM&IbT;1+T`=q z)g0rktp0~b!$15Q{ZIQ~^nW$}NjLnHpWz?b@K5_-_=j&}|M!)D<`bIv{{!&+pN8Up zlwbcx*9~S(#RAWmDzKJfVLNLCZ)c6*z7*RyUwLld%^z!LP0&`Vp3fIgw*;!(JFg8NNjuG=cZqIZjt+-jC0(Ka!{G zQ0@ykznk~pjuv?yZPdT`@1m=lKgx<9-Q=;BV_!|4hwxnUI{U2T5cw&^! z|JTy%{QrYlpHt`mzmt|m<$c}yj+NE}{3%E2N-@dyy#wP<7t)qxwZ#k$nG~4^H;dcJrN{$9`SScu&&SBEOXU^yv@3 zr_TOP{x|SV9^m(BBTb)j!~zxaBkCo)>FU%QGHto8tgNfBe}{9Q&g|E7?j)bram`5) z(|f3^0@vJxjkkt$T~T`^-}Qae!ymc!_+#U9^#3<_`)(`8>S|U0l(iYT&u3HSIYp75 zl0PAn(nWdhHqr7u~MXe{Up@ zkNJA|Cda>qbN8lR7xKI4lYDeFnq<4f=clXt>bAhkU!xv$(q?BeqLr?)KA!vMtNy;z-6Ajl7Qc-CS$hx~aWzm)wQCr>Hfh`MpQp z&-*yppmI-aFSN4fEk6A|`4ZAZXA$Y~-;jrp_x9~sJFQy>@+3$4ge@}Td-5>yWOwjRs8~dOBfwBK-4^01`{(>?=sKhhnY9&~w!_}3$n*>*L?k+NcXoC7q zD9tR(o>mk8@N4*oSHnN;gW;d!4gVZ(_@{j^{Byj~|FjQv>3?`PBzjl-hi=&3BMxnHIf zYg+3WF4iyU{~P@ek8hKeJTKDr|5bh%uZ*tmZ}{hU!$0YUf7%DbKgS#XIo|M3`*14# z|H=3Ry78jw_?|w0Z!-P>9YNLpyY}Zxgb{ugLNMwXB8H<>kYpVad&YA-%5e@C7q zIzrnzr@c5P8cTgmk@IFEQ{KIz$;i`WrlwQgBckJw)8~J-MW-UC&;L9vnunY||MNxB zLge)Mp9`ZU$OpGMCAN9Q1?&;L9pIv+WG{^$9T{+>Ml6E9t%rONvM z!-W6!Yn-`HFivf_?ijn{Q0iU1`I64wW0^hevMU~4JV%3kic5(}XZ5$Z<*0Pf+|D&y zE{P8zDz}Ge*6TN3+|9!)as2V(*N_{Zvwi#abDp{8H?wYe<1?@RF VsJ!qj$uqcc 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" with flags "" + +Creating command line "rc.exe /l 0x409 /fo"win32/Release/noise.res" /i "src\win32" /d "NDEBUG" "C:\dev\src\noise\src\win32\noise.rc"" +Creating temp file "C:\DOCUME~1\jas\LOCALS~1\Temp\RSP2AB7.tmp" with contents +Creating command line "cl.exe @C:\DOCUME~1\jas\LOCALS~1\Temp\RSP2AB7.tmp" +Creating temp file "C:\DOCUME~1\jas\LOCALS~1\Temp\RSP2AB8.tmp" with contents +Creating command line "link.exe @C:\DOCUME~1\jas\LOCALS~1\Temp\RSP2AB8.tmp" +Compiling resources... +Compiling... +abs.cpp +add.cpp +billow.cpp +blend.cpp +cache.cpp +checkerboard.cpp +clamp.cpp +const.cpp +curve.cpp +cylinders.cpp +displace.cpp +exponent.cpp +invert.cpp +max.cpp +min.cpp +modulebase.cpp +multiply.cpp +perlin.cpp +power.cpp +ridgedmulti.cpp +rotatepoint.cpp +scalebias.cpp +scalepoint.cpp +select.cpp +spheres.cpp +terrace.cpp +translatepoint.cpp +turbulence.cpp +voronoi.cpp +cylinder.cpp +line.cpp +plane.cpp +sphere.cpp +dllmain.cpp +latlon.cpp +noisegen.cpp +Linking... + Creating library win32/Release/libnoise.lib and object win32/Release/libnoise.exp + + + +libnoise.dll - 0 error(s), 0 warning(s) diff --git a/src/libnoise/noise.aps b/src/libnoise/noise.aps new file mode 100644 index 0000000000000000000000000000000000000000..78625e2ebe320934198443ac3f511b6d7d5ab671 GIT binary patch literal 31420 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 $@.$$$$; \ + sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ + rm -f $@.$$$$ + +# C and C++ libtool (rather than raw CXX/CC) use +%.o %.lo: %.cpp + $(LIBTOOL) --mode=compile $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $(@:.lo=.o) + +%.o %.lo: %.c + $(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $(@:.lo=.o) + +# If dependancies have never been built this will produce a horde of +# "file not found" warnings and *then* build the deps. Very odd. +include $(DEPENDS) diff --git a/src/libnoise/src/Sources b/src/libnoise/src/Sources new file mode 100644 index 00000000000..73a9b3e6a8d --- /dev/null +++ b/src/libnoise/src/Sources @@ -0,0 +1,80 @@ +SOURCES=../src/latlon.cpp \ + ../src/noisegen.cpp \ + ../src/model/cylinder.cpp \ + ../src/model/line.cpp \ + ../src/model/plane.cpp \ + ../src/model/sphere.cpp \ + ../src/module/abs.cpp \ + ../src/module/add.cpp \ + ../src/module/billow.cpp \ + ../src/module/blend.cpp \ + ../src/module/cache.cpp \ + ../src/module/checkerboard.cpp \ + ../src/module/clamp.cpp \ + ../src/module/const.cpp \ + ../src/module/curve.cpp \ + ../src/module/cylinders.cpp \ + ../src/module/displace.cpp \ + ../src/module/exponent.cpp \ + ../src/module/invert.cpp \ + ../src/module/max.cpp \ + ../src/module/min.cpp \ + ../src/module/modulebase.cpp \ + ../src/module/multiply.cpp \ + ../src/module/perlin.cpp \ + ../src/module/power.cpp \ + ../src/module/ridgedmulti.cpp \ + ../src/module/rotatepoint.cpp \ + ../src/module/scalebias.cpp \ + ../src/module/scalepoint.cpp \ + ../src/module/select.cpp \ + ../src/module/spheres.cpp \ + ../src/module/terrace.cpp \ + ../src/module/translatepoint.cpp \ + ../src/module/turbulence.cpp \ + ../src/module/voronoi.cpp + +HEADERS=../src/basictypes.h \ + ../src/exception.h \ + ../src/interp.h \ + ../src/latlon.h \ + ../src/mathconsts.h \ + ../src/misc.h \ + ../src/noisegen.h \ + ../src/noise.h \ + ../src/vectortable.h \ + ../src/model/cylinder.h \ + ../src/model/model.h \ + ../src/model/sphere.h \ + ../src/model/line.h \ + ../src/model/plane.h \ + ../src/module/abs.h \ + ../src/module/add.h \ + ../src/module/billow.h \ + ../src/module/blend.h \ + ../src/module/cache.h \ + ../src/module/checkerboard.h \ + ../src/module/clamp.h \ + ../src/module/const.h \ + ../src/module/curve.h \ + ../src/module/cylinders.h \ + ../src/module/displace.h \ + ../src/module/exponent.h \ + ../src/module/invert.h \ + ../src/module/max.h \ + ../src/module/min.h \ + ../src/module/module.h \ + ../src/module/modulebase.h \ + ../src/module/multiply.h \ + ../src/module/perlin.h \ + ../src/module/power.h \ + ../src/module/ridgedmulti.h \ + ../src/module/rotatepoint.h \ + ../src/module/scalebias.h \ + ../src/module/scalepoint.h \ + ../src/module/select.h \ + ../src/module/spheres.h \ + ../src/module/terrace.h \ + ../src/module/translatepoint.h \ + ../src/module/turbulence.h \ + ../src/module/voronoi.h diff --git a/src/libnoise/src/basictypes.h b/src/libnoise/src/basictypes.h new file mode 100644 index 00000000000..6c5f9f0d5ac --- /dev/null +++ b/src/libnoise/src/basictypes.h @@ -0,0 +1,60 @@ +// basictypes.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_BASICTYPES_H +#define NOISE_BASICTYPES_H + +// You may need to modify these constants for your compiler or platform. + +namespace noise +{ + + /// @defgroup libnoise libnoise + /// @addtogroup libnoise + /// @{ + + /// Unsigned integer type. + typedef unsigned int uint; + + /// 32-bit unsigned integer type. + typedef unsigned int uint32; + + /// 16-bit unsigned integer type. + typedef unsigned short uint16; + + /// 8-bit unsigned integer type. + typedef unsigned char uint8; + + /// 32-bit signed integer type. + typedef int int32; + + /// 16-bit signed integer type. + typedef short int16; + + /// 8-bit signed integer type. + typedef char int8; + + /// @} + +} + +#endif diff --git a/src/libnoise/src/exception.h b/src/libnoise/src/exception.h new file mode 100644 index 00000000000..b760563c2b1 --- /dev/null +++ b/src/libnoise/src/exception.h @@ -0,0 +1,74 @@ +// exception.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_EXCEPTION_H +#define NOISE_EXCEPTION_H + +namespace noise +{ + + /// @addtogroup libnoise + /// @{ + + /// Abstract base class for libnoise exceptions + class Exception + { + }; + + /// Invalid parameter exception + /// + /// An invalid parameter was passed to a libnoise function or method. + class ExceptionInvalidParam: public Exception + { + }; + + /// No module exception + /// + /// Could not retrieve a source module from a noise module. + /// + /// @note If one or more required source modules were not connected to a + /// specific noise module, and its GetValue() method was called, that + /// method will raise a debug assertion instead of this exception. This + /// is done for performance reasons. + class ExceptionNoModule: public Exception + { + }; + + /// Out of memory exception + /// + /// There was not enough memory to perform an action. + class ExceptionOutOfMemory: public Exception + { + }; + + /// Unknown exception + /// + /// libnoise raised an unknown exception. + class ExceptionUnknown: public Exception + { + }; + + /// @} + +} + +#endif diff --git a/src/libnoise/src/interp.h b/src/libnoise/src/interp.h new file mode 100644 index 00000000000..a657cb169c4 --- /dev/null +++ b/src/libnoise/src/interp.h @@ -0,0 +1,112 @@ +// interp.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_INTERP_H +#define NOISE_INTERP_H + +namespace noise +{ + + /// @addtogroup libnoise + /// @{ + + /// Performs cubic interpolation between two values bound between two other + /// values. + /// + /// @param n0 The value before the first value. + /// @param n1 The first value. + /// @param n2 The second value. + /// @param n3 The value after the second value. + /// @param a The alpha value. + /// + /// @returns The interpolated value. + /// + /// The alpha value should range from 0.0 to 1.0. If the alpha value is + /// 0.0, this function returns @a n1. If the alpha value is 1.0, this + /// function returns @a n2. + inline double CubicInterp (double n0, double n1, double n2, double n3, + double a) + { + double p = (n3 - n2) - (n0 - n1); + double q = (n0 - n1) - p; + double r = n2 - n0; + double s = n1; + return p * a * a * a + q * a * a + r * a + s; + } + + /// Performs linear interpolation between two values. + /// + /// @param n0 The first value. + /// @param n1 The second value. + /// @param a The alpha value. + /// + /// @returns The interpolated value. + /// + /// The alpha value should range from 0.0 to 1.0. If the alpha value is + /// 0.0, this function returns @a n0. If the alpha value is 1.0, this + /// function returns @a n1. + inline double LinearInterp (double n0, double n1, double a) + { + return ((1.0 - a) * n0) + (a * n1); + } + + /// Maps a value onto a cubic S-curve. + /// + /// @param a The value to map onto a cubic S-curve. + /// + /// @returns The mapped value. + /// + /// @a a should range from 0.0 to 1.0. + /// + /// The derivitive of a cubic S-curve is zero at @a a = 0.0 and @a a = + /// 1.0 + inline double SCurve3 (double a) + { + return (a * a * (3.0 - 2.0 * a)); + } + + /// Maps a value onto a quintic S-curve. + /// + /// @param a The value to map onto a quintic S-curve. + /// + /// @returns The mapped value. + /// + /// @a a should range from 0.0 to 1.0. + /// + /// The first derivitive of a quintic S-curve is zero at @a a = 0.0 and + /// @a a = 1.0 + /// + /// The second derivitive of a quintic S-curve is zero at @a a = 0.0 and + /// @a a = 1.0 + inline double SCurve5 (double a) + { + double a3 = a * a * a; + double a4 = a3 * a; + double a5 = a4 * a; + return (6.0 * a5) - (15.0 * a4) + (10.0 * a3); + } + + // @} + +} + +#endif diff --git a/src/libnoise/src/latlon.cpp b/src/libnoise/src/latlon.cpp new file mode 100644 index 00000000000..7fe97c698db --- /dev/null +++ b/src/libnoise/src/latlon.cpp @@ -0,0 +1,34 @@ +// latlon.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "latlon.h" + +using namespace noise; + +void noise::LatLonToXYZ (double lat, double lon, double& x, double& y, + double& z) +{ + double r = cos (DEG_TO_RAD * lat); + x = r * cos (DEG_TO_RAD * lon); + y = sin (DEG_TO_RAD * lat); + z = r * sin (DEG_TO_RAD * lon); +} diff --git a/src/libnoise/src/latlon.h b/src/libnoise/src/latlon.h new file mode 100644 index 00000000000..5cdf85d4c68 --- /dev/null +++ b/src/libnoise/src/latlon.h @@ -0,0 +1,52 @@ +// latlon.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_LATLON_H +#define NOISE_LATLON_H + +#include +#include "mathconsts.h" + +namespace noise +{ + + /// @addtogroup libnoise + /// @{ + + /// Converts latitude/longitude coordinates on a unit sphere into 3D + /// Cartesian coordinates. + /// + /// @param lat The latitude, in degrees. + /// @param lon The longitude, in degrees. + /// @param x On exit, this parameter contains the @a x coordinate. + /// @param y On exit, this parameter contains the @a y coordinate. + /// @param z On exit, this parameter contains the @a z coordinate. + /// + /// @pre lat must range from @b -90 to @b +90. + /// @pre lon must range from @b -180 to @b +180. + void LatLonToXYZ (double lat, double lon, double& x, double& y, double& z); + + /// @} + +} + +#endif diff --git a/src/libnoise/src/mathconsts.h b/src/libnoise/src/mathconsts.h new file mode 100644 index 00000000000..70b3bd5e263 --- /dev/null +++ b/src/libnoise/src/mathconsts.h @@ -0,0 +1,54 @@ +// mathconsts.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MATHCONSTS_H +#define NOISE_MATHCONSTS_H + +// For whatever reason, I can't find the basic math consts in the MSVC version +// of math.h. + +namespace noise +{ + + /// @addtogroup libnoise + /// @{ + + /// Pi. + const double PI = 3.1415926535897932385; + + /// Square root of 2. + const double SQRT_2 = 1.4142135623730950488; + + /// Square root of 3. + const double SQRT_3 = 1.7320508075688772935; + + /// Converts an angle from degrees to radians. + const double DEG_TO_RAD = PI / 180.0; + + /// Converts an angle from radians to degrees. + const double RAD_TO_DEG = 1.0 / DEG_TO_RAD; + + /// @} + +} + +#endif diff --git a/src/libnoise/src/misc.h b/src/libnoise/src/misc.h new file mode 100644 index 00000000000..cfdb5364ff7 --- /dev/null +++ b/src/libnoise/src/misc.h @@ -0,0 +1,97 @@ +// misc.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MISC_H +#define NOISE_MISC_H + +namespace noise +{ + + /// Clamps a value onto a clamping range. + /// + /// @param value The value to clamp. + /// @param lowerBound The lower bound of the clamping range. + /// @param upperBound The upper bound of the clamping range. + /// + /// @returns + /// - @a value if @a value lies between @a lowerBound and @a upperBound. + /// - @a lowerBound if @a value is less than @a lowerBound. + /// - @a upperBound if @a value is greater than @a upperBound. + /// + /// This function does not modify any parameters. + inline int ClampValue (int value, int lowerBound, int upperBound) + { + if (value < lowerBound) { + return lowerBound; + } else if (value > upperBound) { + return upperBound; + } else { + return value; + } + } + + /// @addtogroup libnoise + /// @{ + + /// Returns the maximum of two values. + /// + /// @param a The first value. + /// @param b The second value. + /// + /// @returns The maximum of the two values. + template + T GetMax (const T& a, const T& b) + { + return (a > b? a: b); + } + + /// Returns the minimum of two values. + /// + /// @param a The first value. + /// @param b The second value. + /// + /// @returns The minimum of the two values. + template + T GetMin (const T& a, const T& b) + { + return (a < b? a: b); + } + + /// Swaps two values. + /// + /// @param a A variable containing the first value. + /// @param b A variable containing the second value. + /// + /// @post The values within the the two variables are swapped. + template + void SwapValues (T& a, T& b) + { + T c = a; + a = b; + b = c; + } + + /// @} + +} + +#endif diff --git a/src/libnoise/src/model/cylinder.cpp b/src/libnoise/src/model/cylinder.cpp new file mode 100644 index 00000000000..defded2978f --- /dev/null +++ b/src/libnoise/src/model/cylinder.cpp @@ -0,0 +1,47 @@ +// cylinder.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../mathconsts.h" +#include "cylinder.h" + +using namespace noise; +using namespace noise::model; + +Cylinder::Cylinder (): m_pModule (NULL) +{ +} + +Cylinder::Cylinder (const module::Module& module): + m_pModule (&module) +{ +} + +double Cylinder::GetValue (double angle, double height) const +{ + assert (m_pModule != NULL); + + double x, y, z; + x = cos (angle * DEG_TO_RAD); + y = height; + z = sin (angle * DEG_TO_RAD); + return m_pModule->GetValue (x, y, z); +} diff --git a/src/libnoise/src/model/cylinder.h b/src/libnoise/src/model/cylinder.h new file mode 100644 index 00000000000..627abb326dc --- /dev/null +++ b/src/libnoise/src/model/cylinder.h @@ -0,0 +1,131 @@ +// cylinder.h +// +// Copyright 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODEL_CYLINDER_H +#define NOISE_MODEL_CYLINDER_H + +#include +#include +#include +#include "../module/modulebase.h" + +namespace noise +{ + + namespace model + { + + /// @addtogroup libnoise + /// @{ + + /// @defgroup models Models + /// @addtogroup models + /// @{ + + /// Model that defines the surface of a cylinder. + /// + /// @image html modelcylinder.png + /// + /// This model returns an output value from a noise module given the + /// coordinates of an input value located on the surface of a cylinder. + /// + /// To generate an output value, pass the (angle, height) coordinates of + /// an input value to the GetValue() method. + /// + /// This model is useful for creating: + /// - seamless textures that can be mapped onto a cylinder + /// + /// This cylinder has a radius of 1.0 unit and has infinite height. It is + /// oriented along the @a y axis. Its center is located at the origin. + class Cylinder + { + + public: + + /// Constructor. + Cylinder (); + + /// Constructor + /// + /// @param module The noise module that is used to generate the output + /// values. + Cylinder (const module::Module& module); + + /// Returns the noise module that is used to generate the output + /// values. + /// + /// @returns A reference to the noise module. + /// + /// @pre A noise module was passed to the SetModule() method. + const module::Module& GetModule () const + { + assert (m_pModule != NULL); + return *m_pModule; + } + + /// Returns the output value from the noise module given the + /// (angle, height) coordinates of the specified input value located + /// on the surface of the cylinder. + /// + /// @param angle The angle around the cylinder's center, in degrees. + /// @param height The height along the @a y axis. + /// + /// @returns The output value from the noise module. + /// + /// @pre A noise module was passed to the SetModule() method. + /// + /// This output value is generated by the noise module passed to the + /// SetModule() method. + /// + /// This cylinder has a radius of 1.0 unit and has infinite height. + /// It is oriented along the @a y axis. Its center is located at the + /// origin. + double GetValue (double angle, double height) const; + + /// Sets the noise module that is used to generate the output values. + /// + /// @param module The noise module that is used to generate the output + /// values. + /// + /// This noise module must exist for the lifetime of this object, + /// until you pass a new noise module to this method. + void SetModule (const module::Module& module) + { + m_pModule = &module; + } + + private: + + /// A pointer to the noise module used to generate the output values. + const module::Module* m_pModule; + + }; + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/model/line.cpp b/src/libnoise/src/model/line.cpp new file mode 100644 index 00000000000..dab5e4f7cb7 --- /dev/null +++ b/src/libnoise/src/model/line.cpp @@ -0,0 +1,65 @@ +// line.cpp +// +// Copyright (C) 2004 Keith Davies +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#include "line.h" + +using namespace noise; +using namespace noise::model; + +Line::Line (): + + m_attenuate (true), + m_pModule (NULL), + m_x0 (0.0), + m_x1 (1.0), + m_y0 (0.0), + m_y1 (1.0), + m_z0 (0.0), + m_z1 (1.0) +{ +} + +Line::Line (const module::Module& module): + + m_attenuate (true), + m_pModule (&module), + m_x0 (0.0), + m_x1 (1.0), + m_y0 (0.0), + m_y1 (1.0), + m_z0 (0.0), + m_z1 (1.0) +{ +} + +double Line::GetValue (double p) const +{ + assert (m_pModule != NULL); + + double x = (m_x1 - m_x0) * p + m_x0; + double y = (m_y1 - m_y0) * p + m_y0; + double z = (m_z1 - m_z0) * p + m_z0; + double value = m_pModule->GetValue (x, y, z); + + if (m_attenuate) { + return p * (1.0 - p) * 4 * value; + } else { + return value; + } +} diff --git a/src/libnoise/src/model/line.h b/src/libnoise/src/model/line.h new file mode 100644 index 00000000000..cf3a8087bd7 --- /dev/null +++ b/src/libnoise/src/model/line.h @@ -0,0 +1,198 @@ +// line.h +// +// Copyright (C) 2004 Keith Davies +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// + +#ifndef NOISE_MODEL_LINE_H +#define NOISE_MODEL_LINE_H + +#include +#include +#include +#include "../module/modulebase.h" + +namespace noise +{ + + namespace model + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup models + /// @{ + + /// Model that defines the displacement of a line segment. + /// + /// This model returns an output value from a noise module given the + /// one-dimensional coordinate of an input value located on a line + /// segment, which can be used as displacements. + /// + /// This class is useful for creating: + /// - roads and rivers + /// - disaffected college students + /// + /// To generate an output value, pass an input value between 0.0 and 1.0 + /// to the GetValue() method. 0.0 represents the start position of the + /// line segment and 1.0 represents the end position of the line segment. + class Line + { + + public: + + /// Constructor. + Line (); + + /// Constructor + /// + /// @param module The noise module that is used to generate the output + /// values. + Line (const module::Module& module); + + /// Returns a flag indicating whether the output value is to be + /// attenuated (moved toward 0.0) as the ends of the line segment are + /// approached by the input value. + /// + /// @returns + /// - @a true if the value is to be attenuated + /// - @a false if not. + bool GetAttenuate () const + { + return m_attenuate; + } + + /// Returns the noise module that is used to generate the output + /// values. + /// + /// @returns A reference to the noise module. + /// + /// @pre A noise module was passed to the SetModule() method. + const module::Module& GetModule () const + { + assert (m_pModule != NULL); + return *m_pModule; + } + + /// Returns the output value from the noise module given the + /// one-dimensional coordinate of the specified input value located + /// on the line segment. + /// + /// @param p The distance along the line segment (ranges from 0.0 + /// to 1.0) + /// + /// @returns The output value from the noise module. + /// + /// @pre A noise module was passed to the SetModule() method. + /// @pre The start and end points of the line segment were specified. + /// + /// The output value is generated by the noise module passed to the + /// SetModule() method. This value may be attenuated (moved toward + /// 0.0) as @a p approaches either end of the line segment; this is + /// the default behavior. + /// + /// If the value is not to be attenuated, @a p can safely range + /// outside the 0.0 to 1.0 range; the output value will be + /// extrapolated along the line that this segment is part of. + double GetValue (double p) const; + + /// Sets a flag indicating that the output value is to be attenuated + /// (moved toward 0.0) as the ends of the line segment are approached. + /// + /// @param att A flag that specifies whether the output value is to be + /// attenuated. + void SetAttenuate (bool att) + { + m_attenuate = att; + } + + /// Sets the position ( @a x, @a y, @a z ) of the end of the line + /// segment to choose values along. + /// + /// @param x x coordinate of the end position. + /// @param y y coordinate of the end position. + /// @param z z coordinate of the end position. + void SetEndPoint (double x, double y, double z) + { + m_x1 = x; + m_y1 = y; + m_z1 = z; + } + + /// Sets the noise module that is used to generate the output values. + /// + /// @param module The noise module that is used to generate the output + /// values. + /// + /// This noise module must exist for the lifetime of this object, + /// until you pass a new noise module to this method. + void SetModule (const module::Module& module) + { + m_pModule = &module; + } + + /// Sets the position ( @a x, @a y, @a z ) of the start of the line + /// segment to choose values along. + /// + /// @param x x coordinate of the start position. + /// @param y y coordinate of the start position. + /// @param z z coordinate of the start position. + void SetStartPoint (double x, double y, double z) + { + m_x0 = x; + m_y0 = y; + m_z0 = z; + } + + private: + + /// A flag that specifies whether the value is to be attenuated + /// (moved toward 0.0) as the ends of the line segment are approached. + bool m_attenuate; + + /// A pointer to the noise module used to generate the output values. + const module::Module* m_pModule; + + /// @a x coordinate of the start of the line segment. + double m_x0; + + /// @a x coordinate of the end of the line segment. + double m_x1; + + /// @a y coordinate of the start of the line segment. + double m_y0; + + /// @a y coordinate of the end of the line segment. + double m_y1; + + /// @a z coordinate of the start of the line segment. + double m_z0; + + /// @a z coordinate of the end of the line segment. + double m_z1; + + }; + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/model/model.h b/src/libnoise/src/model/model.h new file mode 100644 index 00000000000..e3ce92ce80e --- /dev/null +++ b/src/libnoise/src/model/model.h @@ -0,0 +1,31 @@ +// model.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODEL_H +#define NOISE_MODEL_H + +#include "cylinder.h" +#include "line.h" +#include "plane.h" +#include "sphere.h" + +#endif diff --git a/src/libnoise/src/model/plane.cpp b/src/libnoise/src/model/plane.cpp new file mode 100644 index 00000000000..c5fd02f7ee1 --- /dev/null +++ b/src/libnoise/src/model/plane.cpp @@ -0,0 +1,43 @@ +// plane.cpp +// +// Copyright (C) 2004 Owen Jacobson +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is ojacobson@lionsanctuary.net +// + +#include "plane.h" + +using namespace noise; +using namespace noise::model; + +Plane::Plane (): + m_pModule (NULL) +{ +} + +Plane::Plane (const module::Module& module) : + m_pModule( &module) +{ +} + +// Told you this was trivial. +double Plane::GetValue (double x, double z) const +{ + assert (m_pModule != NULL); + + return m_pModule->GetValue (x, 0, z); +} diff --git a/src/libnoise/src/model/plane.h b/src/libnoise/src/model/plane.h new file mode 100644 index 00000000000..fe08f9b3c8e --- /dev/null +++ b/src/libnoise/src/model/plane.h @@ -0,0 +1,121 @@ +// plane.h +// +// Copyright (C) 2004 Owen Jacobson +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is ojacobson@lionsanctuary.net +// + +#ifndef NOISE_MODEL_PLANE_H +#define NOISE_MODEL_PLANE_H + +#include +#include "../module/modulebase.h" + +namespace noise +{ + + namespace model + { + /// @addtogroup libnoise + /// @{ + + /// @addtogroup models + /// @{ + + /// Model that defines the surface of a plane. + /// + /// This model returns an output value from a noise module given the + /// coordinates of an input value located on the surface of an ( @a x, + /// @a z ) plane. + /// + /// To generate an output value, pass the ( @a x, @a z ) coordinates of + /// an input value to the GetValue() method. + /// + /// This model is useful for creating: + /// - two-dimensional textures + /// - terrain height maps for local areas + /// + /// This plane extends infinitely in both directions. + class Plane + { + + public: + + /// Constructor. + Plane (); + + /// Constructor + /// + /// @param module The noise module that is used to generate the output + /// values. + Plane (const module::Module& module); + + /// Returns the noise module that is used to generate the output + /// values. + /// + /// @returns A reference to the noise module. + /// + /// @pre A noise module was passed to the SetModule() method. + const module::Module& GetModule () const + { + assert (m_pModule != NULL); + return *m_pModule; + } + + /// Returns the output value from the noise module given the + /// ( @a x, @a z ) coordinates of the specified input value located + /// on the surface of the plane. + /// + /// @param x The @a x coordinate of the input value. + /// @param z The @a z coordinate of the input value. + /// + /// @returns The output value from the noise module. + /// + /// @pre A noise module was passed to the SetModule() method. + /// + /// This output value is generated by the noise module passed to the + /// SetModule() method. + double GetValue (double x, double z) const; + + /// Sets the noise module that is used to generate the output values. + /// + /// @param module The noise module that is used to generate the output + /// values. + /// + /// This noise module must exist for the lifetime of this object, + /// until you pass a new noise module to this method. + void SetModule (const module::Module& module) + { + m_pModule = &module; + } + + private: + + /// A pointer to the noise module used to generate the output values. + const module::Module* m_pModule; + + }; + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/model/sphere.cpp b/src/libnoise/src/model/sphere.cpp new file mode 100644 index 00000000000..77ead1c4458 --- /dev/null +++ b/src/libnoise/src/model/sphere.cpp @@ -0,0 +1,46 @@ +// sphere.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../latlon.h" +#include "sphere.h" + +using namespace noise; +using namespace noise::model; + +Sphere::Sphere (): + m_pModule (NULL) +{ +} + +Sphere::Sphere (const module::Module& module): + m_pModule (&module) +{ +} + +double Sphere::GetValue (double lat, double lon) const +{ + assert (m_pModule != NULL); + + double x, y, z; + LatLonToXYZ (lat, lon, x, y, z); + return m_pModule->GetValue (x, y, z); +} diff --git a/src/libnoise/src/model/sphere.h b/src/libnoise/src/model/sphere.h new file mode 100644 index 00000000000..63a2a51609b --- /dev/null +++ b/src/libnoise/src/model/sphere.h @@ -0,0 +1,131 @@ +// sphere.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODEL_SPHERE_H +#define NOISE_MODEL_SPHERE_H + +#include +#include "../module/modulebase.h" + +namespace noise +{ + + namespace model + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup models + /// @{ + + /// Model that defines the surface of a sphere. + /// + /// @image html modelsphere.png + /// + /// This model returns an output value from a noise module given the + /// coordinates of an input value located on the surface of a sphere. + /// + /// To generate an output value, pass the (latitude, longitude) + /// coordinates of an input value to the GetValue() method. + /// + /// This model is useful for creating: + /// - seamless textures that can be mapped onto a sphere + /// - terrain height maps for entire planets + /// + /// This sphere has a radius of 1.0 unit and its center is located at + /// the origin. + class Sphere + { + + public: + + /// Constructor. + Sphere (); + + /// Constructor + /// + /// @param module The noise module that is used to generate the output + /// values. + Sphere (const module::Module& module); + + /// Returns the noise module that is used to generate the output + /// values. + /// + /// @returns A reference to the noise module. + /// + /// @pre A noise module was passed to the SetModule() method. + const module::Module& GetModule () const + { + assert (m_pModule != NULL); + return *m_pModule; + } + + /// Returns the output value from the noise module given the + /// (latitude, longitude) coordinates of the specified input value + /// located on the surface of the sphere. + /// + /// @param lat The latitude of the input value, in degrees. + /// @param lon The longitude of the input value, in degrees. + /// + /// @returns The output value from the noise module. + /// + /// @pre A noise module was passed to the SetModule() method. + /// + /// This output value is generated by the noise module passed to the + /// SetModule() method. + /// + /// Use a negative latitude if the input value is located on the + /// southern hemisphere. + /// + /// Use a negative longitude if the input value is located on the + /// western hemisphere. + double GetValue (double lat, double lon) const; + + /// Sets the noise module that is used to generate the output values. + /// + /// @param module The noise module that is used to generate the output + /// values. + /// + /// This noise module must exist for the lifetime of this object, + /// until you pass a new noise module to this method. + void SetModule (const module::Module& module) + { + m_pModule = &module; + } + + private: + + /// A pointer to the noise module used to generate the output values. + const module::Module* m_pModule; + + }; + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/abs.cpp b/src/libnoise/src/module/abs.cpp new file mode 100644 index 00000000000..13a5d63f28d --- /dev/null +++ b/src/libnoise/src/module/abs.cpp @@ -0,0 +1,37 @@ +// abs.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "abs.h" + +using namespace noise::module; + +Abs::Abs (): + Module (GetSourceModuleCount ()) +{ +} + +double Abs::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + return fabs (m_pSourceModule[0]->GetValue (x, y, z)); +} diff --git a/src/libnoise/src/module/abs.h b/src/libnoise/src/module/abs.h new file mode 100644 index 00000000000..7efba39d661 --- /dev/null +++ b/src/libnoise/src/module/abs.h @@ -0,0 +1,76 @@ +// abs.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_ABS_H +#define NOISE_MODULE_ABS_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @defgroup modifiermodules Modifier Modules + /// @addtogroup modifiermodules + /// @{ + + /// Noise module that outputs the absolute value of the output value from + /// a source module. + /// + /// @image html moduleabs.png + /// + /// This noise module requires one source module. + class Abs: public Module + { + + public: + + /// Constructor. + Abs (); + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/add.cpp b/src/libnoise/src/module/add.cpp new file mode 100644 index 00000000000..1b011625668 --- /dev/null +++ b/src/libnoise/src/module/add.cpp @@ -0,0 +1,39 @@ +// add.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "add.h" + +using namespace noise::module; + +Add::Add (): + Module (GetSourceModuleCount ()) +{ +} + +double Add::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_pSourceModule[1] != NULL); + + return m_pSourceModule[0]->GetValue (x, y, z) + + m_pSourceModule[1]->GetValue (x, y, z); +} diff --git a/src/libnoise/src/module/add.h b/src/libnoise/src/module/add.h new file mode 100644 index 00000000000..a7a2de6783d --- /dev/null +++ b/src/libnoise/src/module/add.h @@ -0,0 +1,77 @@ +// add.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_ADD_H +#define NOISE_MODULE_ADD_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @defgroup combinermodules Combiner Modules + /// @addtogroup combinermodules + /// @{ + + /// Noise module that outputs the sum of the two output values from two + /// source modules. + /// + /// @image html moduleadd.png + /// + /// This noise module requires two source modules. + class Add: public Module + { + + public: + + /// Constructor. + Add (); + + virtual int GetSourceModuleCount () const + { + return 2; + } + + virtual double GetValue (double x, double y, double z) const; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/billow.cpp b/src/libnoise/src/module/billow.cpp new file mode 100644 index 00000000000..8c3c0aba845 --- /dev/null +++ b/src/libnoise/src/module/billow.cpp @@ -0,0 +1,74 @@ +// billow.cpp +// +// Copyright (C) 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "billow.h" + +using namespace noise::module; + +Billow::Billow (): + Module (GetSourceModuleCount ()), + m_frequency (DEFAULT_BILLOW_FREQUENCY ), + m_lacunarity (DEFAULT_BILLOW_LACUNARITY ), + m_noiseQuality (DEFAULT_BILLOW_QUALITY ), + m_octaveCount (DEFAULT_BILLOW_OCTAVE_COUNT), + m_persistence (DEFAULT_BILLOW_PERSISTENCE ), + m_seed (DEFAULT_BILLOW_SEED) +{ +} + +double Billow::GetValue (double x, double y, double z) const +{ + double value = 0.0; + double signal = 0.0; + double curPersistence = 1.0; + double nx, ny, nz; + int seed; + + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + for (int curOctave = 0; curOctave < m_octaveCount; curOctave++) { + + // Make sure that these floating-point values have the same range as a 32- + // bit integer so that we can pass them to the coherent-noise functions. + nx = MakeInt32Range (x); + ny = MakeInt32Range (y); + nz = MakeInt32Range (z); + + // Get the coherent-noise value from the input value and add it to the + // final result. + seed = (m_seed + curOctave) & 0xffffffff; + signal = GradientCoherentNoise3D (nx, ny, nz, seed, m_noiseQuality); + signal = 2.0 * fabs (signal) - 1.0; + value += signal * curPersistence; + + // Prepare the next octave. + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + curPersistence *= m_persistence; + } + value += 0.5; + + return value; +} diff --git a/src/libnoise/src/module/billow.h b/src/libnoise/src/module/billow.h new file mode 100644 index 00000000000..f9ef09220b6 --- /dev/null +++ b/src/libnoise/src/module/billow.h @@ -0,0 +1,277 @@ +// billow.h +// +// Copyright (C) 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_BILLOW_H +#define NOISE_MODULE_BILLOW_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup generatormodules + /// @{ + + /// Default frequency for the noise::module::Billow noise module. + const double DEFAULT_BILLOW_FREQUENCY = 1.0; + + /// Default lacunarity for the the noise::module::Billow noise module. + const double DEFAULT_BILLOW_LACUNARITY = 2.0; + + /// Default number of octaves for the the noise::module::Billow noise + /// module. + const int DEFAULT_BILLOW_OCTAVE_COUNT = 6; + + /// Default persistence value for the the noise::module::Billow noise + /// module. + const double DEFAULT_BILLOW_PERSISTENCE = 0.5; + + /// Default noise quality for the the noise::module::Billow noise module. + const noise::NoiseQuality DEFAULT_BILLOW_QUALITY = QUALITY_STD; + + /// Default noise seed for the the noise::module::Billow noise module. + const int DEFAULT_BILLOW_SEED = 0; + + /// Maximum number of octaves for the the noise::module::Billow noise + /// module. + const int BILLOW_MAX_OCTAVE = 30; + + /// Noise module that outputs three-dimensional "billowy" noise. + /// + /// @image html modulebillow.png + /// + /// This noise module generates "billowy" noise suitable for clouds and + /// rocks. + /// + /// This noise module is nearly identical to noise::module::Perlin except + /// this noise module modifies each octave with an absolute-value + /// function. See the documentation of noise::module::Perlin for more + /// information. + class Billow: public Module + { + + public: + + /// Constructor. + /// + /// The default frequency is set to + /// noise::module::DEFAULT_BILLOW_FREQUENCY. + /// + /// The default lacunarity is set to + /// noise::module::DEFAULT_BILLOW_LACUNARITY. + /// + /// The default number of octaves is set to + /// noise::module::DEFAULT_BILLOW_OCTAVE_COUNT. + /// + /// The default persistence value is set to + /// noise::module::DEFAULT_BILLOW_PERSISTENCE. + /// + /// The default seed value is set to + /// noise::module::DEFAULT_BILLOW_SEED. + Billow (); + + /// Returns the frequency of the first octave. + /// + /// @returns The frequency of the first octave. + double GetFrequency () const + { + return m_frequency; + } + + /// Returns the lacunarity of the billowy noise. + /// + /// @returns The lacunarity of the billowy noise. + /// + /// The lacunarity is the frequency multiplier between successive + /// octaves. + double GetLacunarity () const + { + return m_lacunarity; + } + + /// Returns the quality of the billowy noise. + /// + /// @returns The quality of the billowy noise. + /// + /// See noise::NoiseQuality for definitions of the various + /// coherent-noise qualities. + noise::NoiseQuality GetNoiseQuality () const + { + return m_noiseQuality; + } + + /// Returns the number of octaves that generate the billowy noise. + /// + /// @returns The number of octaves that generate the billowy noise. + /// + /// The number of octaves controls the amount of detail in the billowy + /// noise. + int GetOctaveCount () const + { + return m_octaveCount; + } + + /// Returns the persistence value of the billowy noise. + /// + /// @returns The persistence value of the billowy noise. + /// + /// The persistence value controls the roughness of the billowy noise. + double GetPersistence () const + { + return m_persistence; + } + + /// Returns the seed value used by the billowy-noise function. + /// + /// @returns The seed value. + int GetSeed () const + { + return m_seed; + } + + virtual int GetSourceModuleCount () const + { + return 0; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the frequency of the first octave. + /// + /// @param frequency The frequency of the first octave. + void SetFrequency (double frequency) + { + m_frequency = frequency; + } + + /// Sets the lacunarity of the billowy noise. + /// + /// @param lacunarity The lacunarity of the billowy noise. + /// + /// The lacunarity is the frequency multiplier between successive + /// octaves. + /// + /// For best results, set the lacunarity to a number between 1.5 and + /// 3.5. + void SetLacunarity (double lacunarity) + { + m_lacunarity = lacunarity; + } + + /// Sets the quality of the billowy noise. + /// + /// @param noiseQuality The quality of the billowy noise. + /// + /// See noise::NoiseQuality for definitions of the various + /// coherent-noise qualities. + void SetNoiseQuality (noise::NoiseQuality noiseQuality) + { + m_noiseQuality = noiseQuality; + } + + /// Sets the number of octaves that generate the billowy noise. + /// + /// @param octaveCount The number of octaves that generate the billowy + /// noise. + /// + /// @pre The number of octaves ranges from 1 to + /// noise::module::BILLOW_MAX_OCTAVE. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// The number of octaves controls the amount of detail in the billowy + /// noise. + /// + /// The larger the number of octaves, the more time required to + /// calculate the billowy-noise value. + void SetOctaveCount (int octaveCount) + { + if (octaveCount < 1 || octaveCount > BILLOW_MAX_OCTAVE) { + throw noise::ExceptionInvalidParam (); + } + m_octaveCount = octaveCount; + } + + /// Sets the persistence value of the billowy noise. + /// + /// @param persistence The persistence value of the billowy noise. + /// + /// The persistence value controls the roughness of the billowy noise. + /// + /// For best results, set the persistence value to a number between + /// 0.0 and 1.0. + void SetPersistence (double persistence) + { + m_persistence = persistence; + } + + /// Sets the seed value used by the billowy-noise function. + /// + /// @param seed The seed value. + void SetSeed (int seed) + { + m_seed = seed; + } + + protected: + + /// Frequency of the first octave. + double m_frequency; + + /// Frequency multiplier between successive octaves. + double m_lacunarity; + + /// Quality of the billowy noise. + noise::NoiseQuality m_noiseQuality; + + /// Total number of octaves that generate the billowy noise. + int m_octaveCount; + + /// Persistence value of the billowy noise. + double m_persistence; + + /// Seed value used by the billowy-noise function. + int m_seed; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/blend.cpp b/src/libnoise/src/module/blend.cpp new file mode 100644 index 00000000000..8c8e08821da --- /dev/null +++ b/src/libnoise/src/module/blend.cpp @@ -0,0 +1,43 @@ +// blend.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "blend.h" +#include "../interp.h" + +using namespace noise::module; + +Blend::Blend (): + Module (GetSourceModuleCount ()) +{ +} + +double Blend::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_pSourceModule[1] != NULL); + assert (m_pSourceModule[2] != NULL); + + double v0 = m_pSourceModule[0]->GetValue (x, y, z); + double v1 = m_pSourceModule[1]->GetValue (x, y, z); + double alpha = (m_pSourceModule[2]->GetValue (x, y, z) + 1.0) / 2.0; + return LinearInterp (v0, v1, alpha); +} diff --git a/src/libnoise/src/module/blend.h b/src/libnoise/src/module/blend.h new file mode 100644 index 00000000000..9d23c111a3a --- /dev/null +++ b/src/libnoise/src/module/blend.h @@ -0,0 +1,144 @@ +// blend.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_BLEND_H +#define NOISE_MODULE_BLEND_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @defgroup selectormodules Selector Modules + /// @addtogroup selectormodules + /// @{ + + /// Noise module that outputs a weighted blend of the output values from + /// two source modules given the output value supplied by a control module. + /// + /// @image html moduleblend.png + /// + /// Unlike most other noise modules, the index value assigned to a source + /// module determines its role in the blending operation: + /// - Source module 0 (upper left in the diagram) outputs one of the + /// values to blend. + /// - Source module 1 (lower left in the diagram) outputs one of the + /// values to blend. + /// - Source module 2 (bottom of the diagram) is known as the control + /// module. The control module determines the weight of the + /// blending operation. Negative values weigh the blend towards the + /// output value from the source module with an index value of 0. + /// Positive values weigh the blend towards the output value from the + /// source module with an index value of 1. + /// + /// An application can pass the control module to the SetControlModule() + /// method instead of the SetSourceModule() method. This may make the + /// application code easier to read. + /// + /// This noise module uses linear interpolation to perform the blending + /// operation. + /// + /// This noise module requires three source modules. + class Blend: public Module + { + + public: + + /// Constructor. + Blend (); + + /// Returns the control module. + /// + /// @returns A reference to the control module. + /// + /// @pre A control module has been added to this noise module via a + /// call to SetSourceModule() or SetControlModule(). + /// + /// @throw noise::ExceptionNoModule See the preconditions for more + /// information. + /// + /// The control module determines the weight of the blending + /// operation. Negative values weigh the blend towards the output + /// value from the source module with an index value of 0. Positive + /// values weigh the blend towards the output value from the source + /// module with an index value of 1. + const Module& GetControlModule () const + { + if (m_pSourceModule == NULL || m_pSourceModule[2] == NULL) { + throw noise::ExceptionNoModule (); + } + return *(m_pSourceModule[2]); + } + + virtual int GetSourceModuleCount () const + { + return 3; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the control module. + /// + /// @param controlModule The control module. + /// + /// The control module determines the weight of the blending + /// operation. Negative values weigh the blend towards the output + /// value from the source module with an index value of 0. Positive + /// values weigh the blend towards the output value from the source + /// module with an index value of 1. + /// + /// This method assigns the control module an index value of 2. + /// Passing the control module to this method produces the same + /// results as passing the control module to the SetSourceModule() + /// method while assigning that noise module an index value of 2. + /// + /// This control module must exist throughout the lifetime of this + /// noise module unless another control module replaces that control + /// module. + void SetControlModule (const Module& controlModule) + { + assert (m_pSourceModule != NULL); + m_pSourceModule[2] = &controlModule; + } + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/cache.cpp b/src/libnoise/src/module/cache.cpp new file mode 100644 index 00000000000..d88633507bc --- /dev/null +++ b/src/libnoise/src/module/cache.cpp @@ -0,0 +1,45 @@ +// cache.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "cache.h" + +using namespace noise::module; + +Cache::Cache (): + Module (GetSourceModuleCount ()), + m_isCached (false) +{ +} + +double Cache::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + if (!(m_isCached && x == m_xCache && y == m_yCache && z == m_zCache)) { + m_cachedValue = m_pSourceModule[0]->GetValue (x, y, z); + m_xCache = x; + m_yCache = y; + m_zCache = z; + } + m_isCached = true; + return m_cachedValue; +} diff --git a/src/libnoise/src/module/cache.h b/src/libnoise/src/module/cache.h new file mode 100644 index 00000000000..7d4d1bab937 --- /dev/null +++ b/src/libnoise/src/module/cache.h @@ -0,0 +1,118 @@ +// cache.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_CACHE_H +#define NOISE_MODULE_CACHE_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @defgroup miscmodules Miscellaneous Modules + /// @addtogroup miscmodules + /// @{ + + /// Noise module that caches the last output value generated by a source + /// module. + /// + /// If an application passes an input value to the GetValue() method that + /// differs from the previously passed-in input value, this noise module + /// instructs the source module to calculate the output value. This + /// value, as well as the ( @a x, @a y, @a z ) coordinates of the input + /// value, are stored (cached) in this noise module. + /// + /// If the application passes an input value to the GetValue() method + /// that is equal to the previously passed-in input value, this noise + /// module returns the cached output value without having the source + /// module recalculate the output value. + /// + /// If an application passes a new source module to the SetSourceModule() + /// method, the cache is invalidated. + /// + /// Caching a noise module is useful if it is used as a source module for + /// multiple noise modules. If a source module is not cached, the source + /// module will redundantly calculate the same output value once for each + /// noise module in which it is included. + /// + /// This noise module requires one source module. + class Cache: public Module + { + + public: + + /// Constructor. + Cache (); + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + virtual void SetSourceModule (int index, const Module& sourceModule) + { + Module::SetSourceModule (index, sourceModule); + m_isCached = false; + } + + protected: + + /// The cached output value at the cached input value. + mutable double m_cachedValue; + + /// Determines if a cached output value is stored in this noise + /// module. + mutable double m_isCached; + + /// @a x coordinate of the cached input value. + mutable double m_xCache; + + /// @a y coordinate of the cached input value. + mutable double m_yCache; + + /// @a z coordinate of the cached input value. + mutable double m_zCache; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/checkerboard.cpp b/src/libnoise/src/module/checkerboard.cpp new file mode 100644 index 00000000000..c71f343a7e3 --- /dev/null +++ b/src/libnoise/src/module/checkerboard.cpp @@ -0,0 +1,38 @@ +// checkerboard.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "checkerboard.h" + +using namespace noise::module; + +Checkerboard::Checkerboard (): + Module (GetSourceModuleCount ()) +{ +} + +double Checkerboard::GetValue (double x, double y, double z) const +{ + int ix = (int)(floor (MakeInt32Range (x))); + int iy = (int)(floor (MakeInt32Range (y))); + int iz = (int)(floor (MakeInt32Range (z))); + return (ix & 1 ^ iy & 1 ^ iz & 1)? -1.0: 1.0; +} diff --git a/src/libnoise/src/module/checkerboard.h b/src/libnoise/src/module/checkerboard.h new file mode 100644 index 00000000000..fcd663c4979 --- /dev/null +++ b/src/libnoise/src/module/checkerboard.h @@ -0,0 +1,81 @@ +// checkerboard.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_CHECKERBOARD_H +#define NOISE_MODULE_CHECKERBOARD_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup generatormodules + /// @{ + + /// Noise module that outputs a checkerboard pattern. + /// + /// @image html modulecheckerboard.png + /// + /// This noise module outputs unit-sized blocks of alternating values. + /// The values of these blocks alternate between -1.0 and +1.0. + /// + /// This noise module is not really useful by itself, but it is often used + /// for debugging purposes. + /// + /// This noise module does not require any source modules. + class Checkerboard: public Module + { + + public: + + /// Constructor. + Checkerboard (); + + virtual int GetSourceModuleCount () const + { + return 0; + } + + virtual double GetValue (double x, double y, double z) const; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/clamp.cpp b/src/libnoise/src/module/clamp.cpp new file mode 100644 index 00000000000..12ca4704d8e --- /dev/null +++ b/src/libnoise/src/module/clamp.cpp @@ -0,0 +1,54 @@ +// clamp.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "clamp.h" + +using namespace noise::module; + +Clamp::Clamp (): + Module (GetSourceModuleCount ()), + m_lowerBound (DEFAULT_CLAMP_LOWER_BOUND), + m_upperBound (DEFAULT_CLAMP_UPPER_BOUND) +{ +} + +double Clamp::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + double value = m_pSourceModule[0]->GetValue (x, y, z); + if (value < m_lowerBound) { + return m_lowerBound; + } else if (value > m_upperBound) { + return m_upperBound; + } else { + return value; + } +} + +void Clamp::SetBounds (double lowerBound, double upperBound) +{ + assert (lowerBound < upperBound); + + m_lowerBound = lowerBound; + m_upperBound = upperBound; +} diff --git a/src/libnoise/src/module/clamp.h b/src/libnoise/src/module/clamp.h new file mode 100644 index 00000000000..15ea8224904 --- /dev/null +++ b/src/libnoise/src/module/clamp.h @@ -0,0 +1,152 @@ +// clamp.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_CLAMP_H +#define NOISE_MODULE_CLAMP_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup modifiermodules + /// @{ + + /// Default lower bound of the clamping range for the noise::module::Clamp + /// noise module. + const double DEFAULT_CLAMP_LOWER_BOUND = -1.0; + + /// Default upper bound of the clamping range for the noise::module::Clamp + /// noise module. + const double DEFAULT_CLAMP_UPPER_BOUND = 1.0; + + /// Noise module that clamps the output value from a source module to a + /// range of values. + /// + /// @image html moduleclamp.png + /// + /// The range of values in which to clamp the output value is called the + /// clamping range. + /// + /// If the output value from the source module is less than the lower + /// bound of the clamping range, this noise module clamps that value to + /// the lower bound. If the output value from the source module is + /// greater than the upper bound of the clamping range, this noise module + /// clamps that value to the upper bound. + /// + /// To specify the upper and lower bounds of the clamping range, call the + /// SetBounds() method. + /// + /// This noise module requires one source module. + class Clamp: public Module + { + + public: + + /// Constructor. + /// + /// The default lower bound of the clamping range is set to + /// noise::module::DEFAULT_CLAMP_LOWER_BOUND. + /// + /// The default upper bound of the clamping range is set to + /// noise::module::DEFAULT_CLAMP_UPPER_BOUND. + Clamp (); + + /// Returns the lower bound of the clamping range. + /// + /// @returns The lower bound. + /// + /// If the output value from the source module is less than the lower + /// bound of the clamping range, this noise module clamps that value + /// to the lower bound. + double GetLowerBound () const + { + return m_lowerBound; + } + + virtual int GetSourceModuleCount () const + { + return 1; + } + + /// Returns the upper bound of the clamping range. + /// + /// @returns The upper bound. + /// + /// If the output value from the source module is greater than the + /// upper bound of the clamping range, this noise module clamps that + /// value to the upper bound. + double GetUpperBound () const + { + return m_upperBound; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the lower and upper bounds of the clamping range. + /// + /// @param lowerBound The lower bound. + /// @param upperBound The upper bound. + /// + /// @pre The lower bound must be less than or equal to the + /// upper bound. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// If the output value from the source module is less than the lower + /// bound of the clamping range, this noise module clamps that value + /// to the lower bound. If the output value from the source module + /// is greater than the upper bound of the clamping range, this noise + /// module clamps that value to the upper bound. + void SetBounds (double lowerBound, double upperBound); + + protected: + + /// Lower bound of the clamping range. + double m_lowerBound; + + /// Upper bound of the clamping range. + double m_upperBound; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/const.cpp b/src/libnoise/src/module/const.cpp new file mode 100644 index 00000000000..5b28717c808 --- /dev/null +++ b/src/libnoise/src/module/const.cpp @@ -0,0 +1,31 @@ +// const.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "const.h" + +using namespace noise::module; + +Const::Const (): + Module (GetSourceModuleCount ()), + m_constValue (DEFAULT_CONST_VALUE) +{ +} diff --git a/src/libnoise/src/module/const.h b/src/libnoise/src/module/const.h new file mode 100644 index 00000000000..ffc64d9e058 --- /dev/null +++ b/src/libnoise/src/module/const.h @@ -0,0 +1,111 @@ +// const.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_CONST_H +#define NOISE_MODULE_CONST_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @defgroup generatormodules Generator Modules + /// @addtogroup generatormodules + /// @{ + + /// Default constant value for the noise::module::Const noise module. + const double DEFAULT_CONST_VALUE = 0.0; + + /// Noise module that outputs a constant value. + /// + /// @image html moduleconst.png + /// + /// To specify the constant value, call the SetConstValue() method. + /// + /// This noise module is not useful by itself, but it is often used as a + /// source module for other noise modules. + /// + /// This noise module does not require any source modules. + class Const: public Module + { + + public: + + /// Constructor. + /// + /// The default constant value is set to + /// noise::module::DEFAULT_CONST_VALUE. + Const (); + + /// Returns the constant output value for this noise module. + /// + /// @returns The constant output value for this noise module. + double GetConstValue () const + { + return m_constValue; + } + + virtual int GetSourceModuleCount () const + { + return 0; + } + + virtual double GetValue (double x, double y, double z) const + { + return m_constValue; + } + + /// Sets the constant output value for this noise module. + /// + /// @param constValue The constant output value for this noise module. + void SetConstValue (double constValue) + { + m_constValue = constValue; + } + + protected: + + /// Constant value. + double m_constValue; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/curve.cpp b/src/libnoise/src/module/curve.cpp new file mode 100644 index 00000000000..f15c5dc668d --- /dev/null +++ b/src/libnoise/src/module/curve.cpp @@ -0,0 +1,143 @@ +// curve.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../interp.h" +#include "../misc.h" +#include "curve.h" + +using namespace noise::module; + +Curve::Curve (): + Module (GetSourceModuleCount ()), + m_pControlPoints (NULL) +{ + m_controlPointCount = 0; +} + +Curve::~Curve () +{ + delete[] m_pControlPoints; +} + +void Curve::AddControlPoint (double inputValue, double outputValue) +{ + // Find the insertion point for the new control point and insert the new + // point at that position. The control point array will remain sorted by + // input value. + int insertionPos = FindInsertionPos (inputValue); + InsertAtPos (insertionPos, inputValue, outputValue); +} + +void Curve::ClearAllControlPoints () +{ + delete[] m_pControlPoints; + m_pControlPoints = NULL; + m_controlPointCount = 0; +} + +int Curve::FindInsertionPos (double inputValue) +{ + int insertionPos; + for (insertionPos = 0; insertionPos < m_controlPointCount; insertionPos++) { + if (inputValue < m_pControlPoints[insertionPos].inputValue) { + // We found the array index in which to insert the new control point. + // Exit now. + break; + } else if (inputValue == m_pControlPoints[insertionPos].inputValue) { + // Each control point is required to contain a unique input value, so + // throw an exception. + throw noise::ExceptionInvalidParam (); + } + } + return insertionPos; +} + +double Curve::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_controlPointCount >= 4); + + // Get the output value from the source module. + double sourceModuleValue = m_pSourceModule[0]->GetValue (x, y, z); + + // Find the first element in the control point array that has an input value + // larger than the output value from the source module. + int indexPos; + for (indexPos = 0; indexPos < m_controlPointCount; indexPos++) { + if (sourceModuleValue < m_pControlPoints[indexPos].inputValue) { + break; + } + } + + // Find the four nearest control points so that we can perform cubic + // interpolation. + int index0 = ClampValue (indexPos - 2, 0, m_controlPointCount - 1); + int index1 = ClampValue (indexPos - 1, 0, m_controlPointCount - 1); + int index2 = ClampValue (indexPos , 0, m_controlPointCount - 1); + int index3 = ClampValue (indexPos + 1, 0, m_controlPointCount - 1); + + // If some control points are missing (which occurs if the value from the + // source module is greater than the largest input value or less than the + // smallest input value of the control point array), get the corresponding + // output value of the nearest control point and exit now. + if (index1 == index2) { + return m_pControlPoints[index1].outputValue; + } + + // Compute the alpha value used for cubic interpolation. + double input0 = m_pControlPoints[index1].inputValue; + double input1 = m_pControlPoints[index2].inputValue; + double alpha = (sourceModuleValue - input0) / (input1 - input0); + + // Now perform the cubic interpolation given the alpha value. + return CubicInterp ( + m_pControlPoints[index0].outputValue, + m_pControlPoints[index1].outputValue, + m_pControlPoints[index2].outputValue, + m_pControlPoints[index3].outputValue, + alpha); +} + +void Curve::InsertAtPos (int insertionPos, double inputValue, + double outputValue) +{ + // Make room for the new control point at the specified position within the + // control point array. The position is determined by the input value of + // the control point; the control points must be sorted by input value + // within that array. + ControlPoint* newControlPoints = new ControlPoint[m_controlPointCount + 1]; + for (int i = 0; i < m_controlPointCount; i++) { + if (i < insertionPos) { + newControlPoints[i] = m_pControlPoints[i]; + } else { + newControlPoints[i + 1] = m_pControlPoints[i]; + } + } + delete[] m_pControlPoints; + m_pControlPoints = newControlPoints; + ++m_controlPointCount; + + // Now that we've made room for the new control point within the array, add + // the new control point. + m_pControlPoints[insertionPos].inputValue = inputValue ; + m_pControlPoints[insertionPos].outputValue = outputValue; +} diff --git a/src/libnoise/src/module/curve.h b/src/libnoise/src/module/curve.h new file mode 100644 index 00000000000..dabf49b68fc --- /dev/null +++ b/src/libnoise/src/module/curve.h @@ -0,0 +1,197 @@ +// curve.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_CURVE_H +#define NOISE_MODULE_CURVE_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// This structure defines a control point. + /// + /// Control points are used for defining splines. + struct ControlPoint + { + + /// The input value. + double inputValue; + + /// The output value that is mapped from the input value. + double outputValue; + + }; + + /// @addtogroup modules + /// @{ + + /// @addtogroup modifiermodules + /// @{ + + /// Noise module that maps the output value from a source module onto an + /// arbitrary function curve. + /// + /// @image html modulecurve.png + /// + /// This noise module maps the output value from the source module onto an + /// application-defined curve. This curve is defined by a number of + /// control points; each control point has an input value + /// that maps to an output value. Refer to the following + /// illustration: + /// + /// @image html curve.png + /// + /// To add the control points to this curve, call the AddControlPoint() + /// method. + /// + /// Since this curve is a cubic spline, an application must add a minimum + /// of four control points to the curve. If this is not done, the + /// GetValue() method fails. Each control point can have any input and + /// output value, although no two control points can have the same input + /// value. There is no limit to the number of control points that can be + /// added to the curve. + /// + /// This noise module requires one source module. + class Curve: public Module + { + + public: + + /// Constructor. + Curve (); + + /// Destructor. + ~Curve (); + + /// Adds a control point to the curve. + /// + /// @param inputValue The input value stored in the control point. + /// @param outputValue The output value stored in the control point. + /// + /// @pre No two control points have the same input value. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// It does not matter which order these points are added. + void AddControlPoint (double inputValue, double outputValue); + + /// Deletes all the control points on the curve. + /// + /// @post All points on the curve are deleted. + void ClearAllControlPoints (); + + /// Returns a pointer to the array of control points on the curve. + /// + /// @returns A pointer to the array of control points. + /// + /// Before calling this method, call GetControlPointCount() to + /// determine the number of control points in this array. + /// + /// It is recommended that an application does not store this pointer + /// for later use since the pointer to the array may change if the + /// application calls another method of this object. + const ControlPoint* GetControlPointArray () const + { + return m_pControlPoints; + } + + /// Returns the number of control points on the curve. + /// + /// @returns The number of control points on the curve. + int GetControlPointCount () const + { + return m_controlPointCount; + } + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + protected: + + /// Determines the array index in which to insert the control point + /// into the internal control point array. + /// + /// @param inputValue The input value of the control point. + /// + /// @returns The array index in which to insert the control point. + /// + /// @pre No two control points have the same input value. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// By inserting the control point at the returned array index, this + /// class ensures that the control point array is sorted by input + /// value. The code that maps a value onto the curve requires a + /// sorted control point array. + int FindInsertionPos (double inputValue); + + /// Inserts the control point at the specified position in the + /// internal control point array. + /// + /// @param insertionPos The zero-based array position in which to + /// insert the control point. + /// @param inputValue The input value stored in the control point. + /// @param outputValue The output value stored in the control point. + /// + /// To make room for this new control point, this method reallocates + /// the control point array and shifts all control points occurring + /// after the insertion position up by one. + /// + /// Because the curve mapping algorithm used by this noise module + /// requires that all control points in the array must be sorted by + /// input value, the new control point should be inserted at the + /// position in which the order is still preserved. + void InsertAtPos (int insertionPos, double inputValue, + double outputValue); + + /// Number of control points on the curve. + int m_controlPointCount; + + /// Array that stores the control points. + ControlPoint* m_pControlPoints; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/cylinders.cpp b/src/libnoise/src/module/cylinders.cpp new file mode 100644 index 00000000000..f695d45d77d --- /dev/null +++ b/src/libnoise/src/module/cylinders.cpp @@ -0,0 +1,44 @@ +// cylinders.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../misc.h" +#include "cylinders.h" + +using namespace noise::module; + +Cylinders::Cylinders (): + Module (GetSourceModuleCount ()), + m_frequency (DEFAULT_CYLINDERS_FREQUENCY) +{ +} + +double Cylinders::GetValue (double x, double y, double z) const +{ + x *= m_frequency; + z *= m_frequency; + + double distFromCenter = sqrt (x * x + z * z); + double distFromSmallerSphere = distFromCenter - floor (distFromCenter); + double distFromLargerSphere = 1.0 - distFromSmallerSphere; + double nearestDist = GetMin (distFromSmallerSphere, distFromLargerSphere); + return 1.0 - (nearestDist * 4.0); // Puts it in the -1.0 to +1.0 range. +} diff --git a/src/libnoise/src/module/cylinders.h b/src/libnoise/src/module/cylinders.h new file mode 100644 index 00000000000..e290dc6233d --- /dev/null +++ b/src/libnoise/src/module/cylinders.h @@ -0,0 +1,129 @@ +// cylinders.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_CYLINDERS_H +#define NOISE_MODULE_CYLINDERS_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup generatormodules + /// @{ + + /// Default frequency value for the noise::module::Cylinders noise module. + const double DEFAULT_CYLINDERS_FREQUENCY = 1.0; + + /// Noise module that outputs concentric cylinders. + /// + /// @image html modulecylinders.png + /// + /// This noise module outputs concentric cylinders centered on the origin. + /// These cylinders are oriented along the @a y axis similar to the + /// concentric rings of a tree. Each cylinder extends infinitely along + /// the @a y axis. + /// + /// The first cylinder has a radius of 1.0. Each subsequent cylinder has + /// a radius that is 1.0 unit larger than the previous cylinder. + /// + /// The output value from this noise module is determined by the distance + /// between the input value and the the nearest cylinder surface. The + /// input values that are located on a cylinder surface are given the + /// output value 1.0 and the input values that are equidistant from two + /// cylinder surfaces are given the output value -1.0. + /// + /// An application can change the frequency of the concentric cylinders. + /// Increasing the frequency reduces the distances between cylinders. To + /// specify the frequency, call the SetFrequency() method. + /// + /// This noise module, modified with some low-frequency, low-power + /// turbulence, is useful for generating wood-like textures. + /// + /// This noise module does not require any source modules. + class Cylinders: public Module + { + + public: + + /// Constructor. + /// + /// The default frequency is set to + /// noise::module::DEFAULT_CYLINDERS_FREQUENCY. + Cylinders (); + + /// Returns the frequency of the concentric cylinders. + /// + /// @returns The frequency of the concentric cylinders. + /// + /// Increasing the frequency increases the density of the concentric + /// cylinders, reducing the distances between them. + double GetFrequency () const + { + return m_frequency; + } + + virtual int GetSourceModuleCount () const + { + return 0; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the frequenct of the concentric cylinders. + /// + /// @param frequency The frequency of the concentric cylinders. + /// + /// Increasing the frequency increases the density of the concentric + /// cylinders, reducing the distances between them. + void SetFrequency (double frequency) + { + m_frequency = frequency; + } + + protected: + + /// Frequency of the concentric cylinders. + double m_frequency; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/displace.cpp b/src/libnoise/src/module/displace.cpp new file mode 100644 index 00000000000..b1c77f3d65f --- /dev/null +++ b/src/libnoise/src/module/displace.cpp @@ -0,0 +1,48 @@ +// displace.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "displace.h" + +using namespace noise::module; + +Displace::Displace (): + Module (GetSourceModuleCount ()) +{ +} + +double Displace::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_pSourceModule[1] != NULL); + assert (m_pSourceModule[2] != NULL); + assert (m_pSourceModule[3] != NULL); + + // Get the output values from the three displacement modules. Add each + // value to the corresponding coordinate in the input value. + double xDisplace = x + (m_pSourceModule[1]->GetValue (x, y, z)); + double yDisplace = y + (m_pSourceModule[2]->GetValue (x, y, z)); + double zDisplace = z + (m_pSourceModule[3]->GetValue (x, y, z)); + + // Retrieve the output value using the offsetted input value instead of + // the original input value. + return m_pSourceModule[0]->GetValue (xDisplace, yDisplace, zDisplace); +} diff --git a/src/libnoise/src/module/displace.h b/src/libnoise/src/module/displace.h new file mode 100644 index 00000000000..97f610af73c --- /dev/null +++ b/src/libnoise/src/module/displace.h @@ -0,0 +1,259 @@ +// displace.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_DISPLACE_H +#define NOISE_MODULE_DISPLACE_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @defgroup transformermodules Transformer Modules + /// @addtogroup transformermodules + /// @{ + + /// Noise module that uses three source modules to displace each + /// coordinate of the input value before returning the output value from + /// a source module. + /// + /// @image html moduledisplace.png + /// + /// Unlike most other noise modules, the index value assigned to a source + /// module determines its role in the displacement operation: + /// - Source module 0 (left in the diagram) outputs a value. + /// - Source module 1 (lower left in the diagram) specifies the offset to + /// apply to the @a x coordinate of the input value. + /// - Source module 2 (lower center in the diagram) specifies the + /// offset to apply to the @a y coordinate of the input value. + /// - Source module 3 (lower right in the diagram) specifies the offset + /// to apply to the @a z coordinate of the input value. + /// + /// The GetValue() method modifies the ( @a x, @a y, @a z ) coordinates of + /// the input value using the output values from the three displacement + /// modules before retrieving the output value from the source module. + /// + /// The noise::module::Turbulence noise module is a special case of the + /// displacement module; internally, there are three Perlin-noise modules + /// that perform the displacement operation. + /// + /// This noise module requires four source modules. + class Displace: public Module + { + + public: + + /// Constructor. + Displace (); + + virtual int GetSourceModuleCount () const + { + return 4; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Returns the @a x displacement module. + /// + /// @returns A reference to the @a x displacement module. + /// + /// @pre This displacement module has been added to this noise module + /// via a call to SetSourceModule() or SetXDisplaceModule(). + /// + /// @throw noise::ExceptionNoModule See the preconditions for more + /// information. + /// + /// The GetValue() method displaces the input value by adding the output + /// value from this displacement module to the @a x coordinate of the + /// input value before returning the output value from the source + /// module. + const Module& GetXDisplaceModule () const + { + if (m_pSourceModule == NULL || m_pSourceModule[1] == NULL) { + throw noise::ExceptionNoModule (); + } + return *(m_pSourceModule[1]); + } + + /// Returns the @a y displacement module. + /// + /// @returns A reference to the @a y displacement module. + /// + /// @pre This displacement module has been added to this noise module + /// via a call to SetSourceModule() or SetYDisplaceModule(). + /// + /// @throw noise::ExceptionNoModule See the preconditions for more + /// information. + /// + /// The GetValue() method displaces the input value by adding the output + /// value from this displacement module to the @a y coordinate of the + /// input value before returning the output value from the source + /// module. + const Module& GetYDisplaceModule () const + { + if (m_pSourceModule == NULL || m_pSourceModule[2] == NULL) { + throw noise::ExceptionNoModule (); + } + return *(m_pSourceModule[2]); + } + + /// Returns the @a z displacement module. + /// + /// @returns A reference to the @a z displacement module. + /// + /// @pre This displacement module has been added to this noise module + /// via a call to SetSourceModule() or SetZDisplaceModule(). + /// + /// @throw noise::ExceptionNoModule See the preconditions for more + /// information. + /// + /// The GetValue() method displaces the input value by adding the output + /// value from this displacement module to the @a z coordinate of the + /// input value before returning the output value from the source + /// module. + const Module& GetZDisplaceModule () const + { + if (m_pSourceModule == NULL || m_pSourceModule[3] == NULL) { + throw noise::ExceptionNoModule (); + } + return *(m_pSourceModule[3]); + } + + /// Sets the @a x, @a y, and @a z displacement modules. + /// + /// @param xDisplaceModule Displacement module that displaces the @a x + /// coordinate of the input value. + /// @param yDisplaceModule Displacement module that displaces the @a y + /// coordinate of the input value. + /// @param zDisplaceModule Displacement module that displaces the @a z + /// coordinate of the input value. + /// + /// The GetValue() method displaces the input value by adding the output + /// value from each of the displacement modules to the corresponding + /// coordinates of the input value before returning the output value + /// from the source module. + /// + /// This method assigns an index value of 1 to the @a x displacement + /// module, an index value of 2 to the @a y displacement module, and an + /// index value of 3 to the @a z displacement module. + /// + /// These displacement modules must exist throughout the lifetime of + /// this noise module unless another displacement module replaces it. + void SetDisplaceModules (const Module& xDisplaceModule, + const Module& yDisplaceModule, const Module& zDisplaceModule) + { + SetXDisplaceModule (xDisplaceModule); + SetYDisplaceModule (yDisplaceModule); + SetZDisplaceModule (zDisplaceModule); + } + + /// Sets the @a x displacement module. + /// + /// @param xDisplaceModule Displacement module that displaces the @a x + /// coordinate. + /// + /// The GetValue() method displaces the input value by adding the output + /// value from this displacement module to the @a x coordinate of the + /// input value before returning the output value from the source + /// module. + /// + /// This method assigns an index value of 1 to the @a x displacement + /// module. Passing this displacement module to this method produces + /// the same results as passing this displacement module to the + /// SetSourceModule() method while assigning it an index value of 1. + /// + /// This displacement module must exist throughout the lifetime of this + /// noise module unless another displacement module replaces it. + void SetXDisplaceModule (const Module& xDisplaceModule) + { + assert (m_pSourceModule != NULL); + m_pSourceModule[1] = &xDisplaceModule; + } + + /// Sets the @a y displacement module. + /// + /// @param yDisplaceModule Displacement module that displaces the @a y + /// coordinate. + /// + /// The GetValue() method displaces the input value by adding the output + /// value from this displacement module to the @a y coordinate of the + /// input value before returning the output value from the source + /// module. + /// + /// This method assigns an index value of 2 to the @a y displacement + /// module. Passing this displacement module to this method produces + /// the same results as passing this displacement module to the + /// SetSourceModule() method while assigning it an index value of 2. + /// + /// This displacement module must exist throughout the lifetime of this + /// noise module unless another displacement module replaces it. + void SetYDisplaceModule (const Module& yDisplaceModule) + { + assert (m_pSourceModule != NULL); + m_pSourceModule[2] = &yDisplaceModule; + } + + /// Sets the @a z displacement module. + /// + /// @param zDisplaceModule Displacement module that displaces the @a z + /// coordinate. + /// + /// The GetValue() method displaces the input value by adding the output + /// value from this displacement module to the @a z coordinate of the + /// input value before returning the output value from the source + /// module. + /// + /// This method assigns an index value of 3 to the @a z displacement + /// module. Passing this displacement module to this method produces + /// the same results as passing this displacement module to the + /// SetSourceModule() method while assigning it an index value of 3. + /// + /// This displacement module must exist throughout the lifetime of this + /// noise module unless another displacement module replaces it. + void SetZDisplaceModule (const Module& zDisplaceModule) + { + assert (m_pSourceModule != NULL); + m_pSourceModule[3] = &zDisplaceModule; + } + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/exponent.cpp b/src/libnoise/src/module/exponent.cpp new file mode 100644 index 00000000000..3b3ffc62b10 --- /dev/null +++ b/src/libnoise/src/module/exponent.cpp @@ -0,0 +1,39 @@ +// exponent.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "exponent.h" + +using namespace noise::module; + +Exponent::Exponent (): + Module (GetSourceModuleCount ()), + m_exponent (DEFAULT_EXPONENT) +{ +} + +double Exponent::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + double value = m_pSourceModule[0]->GetValue (x, y, z); + return (pow (fabs ((value + 1.0) / 2.0), m_exponent) * 2.0 - 1.0); +} diff --git a/src/libnoise/src/module/exponent.h b/src/libnoise/src/module/exponent.h new file mode 100644 index 00000000000..a87eb3fa4aa --- /dev/null +++ b/src/libnoise/src/module/exponent.h @@ -0,0 +1,119 @@ +// exponent.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_EXPONENT_H +#define NOISE_MODULE_EXPONENT_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup modifiermodules + /// @{ + + /// Default exponent for the noise::module::Exponent noise module. + const double DEFAULT_EXPONENT = 1.0; + + /// Noise module that maps the output value from a source module onto an + /// exponential curve. + /// + /// @image html moduleexponent.png + /// + /// Because most noise modules will output values that range from -1.0 to + /// +1.0, this noise module first normalizes this output value (the range + /// becomes 0.0 to 1.0), maps that value onto an exponential curve, then + /// rescales that value back to the original range. + /// + /// This noise module requires one source module. + class Exponent: public Module + { + + public: + + /// Constructor. + /// + /// The default exponent is set to noise::module::DEFAULT_EXPONENT. + Exponent (); + + /// Returns the exponent value to apply to the output value from the + /// source module. + /// + /// @returns The exponent value. + /// + /// Because most noise modules will output values that range from -1.0 + /// to +1.0, this noise module first normalizes this output value (the + /// range becomes 0.0 to 1.0), maps that value onto an exponential + /// curve, then rescales that value back to the original range. + double GetExponent () const + { + return m_exponent; + } + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the exponent value to apply to the output value from the + /// source module. + /// + /// @param exponent The exponent value. + /// + /// Because most noise modules will output values that range from -1.0 + /// to +1.0, this noise module first normalizes this output value (the + /// range becomes 0.0 to 1.0), maps that value onto an exponential + /// curve, then rescales that value back to the original range. + void SetExponent (double exponent) + { + m_exponent = exponent; + } + + protected: + + /// Exponent to apply to the output value from the source module. + double m_exponent; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/invert.cpp b/src/libnoise/src/module/invert.cpp new file mode 100644 index 00000000000..9b481919770 --- /dev/null +++ b/src/libnoise/src/module/invert.cpp @@ -0,0 +1,37 @@ +// invert.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "invert.h" + +using namespace noise::module; + +Invert::Invert (): + Module (GetSourceModuleCount ()) +{ +} + +double Invert::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + return -(m_pSourceModule[0]->GetValue (x, y, z)); +} diff --git a/src/libnoise/src/module/invert.h b/src/libnoise/src/module/invert.h new file mode 100644 index 00000000000..994dccf50ea --- /dev/null +++ b/src/libnoise/src/module/invert.h @@ -0,0 +1,75 @@ +// invert.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_INVERT_H +#define NOISE_MODULE_INVERT_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup modifiermodules + /// @{ + + /// Noise module that inverts the output value from a source module. + /// + /// @image html moduleinvert.png + /// + /// This noise module requires one source module. + class Invert: public Module + { + + public: + + /// Constructor. + Invert (); + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/max.cpp b/src/libnoise/src/module/max.cpp new file mode 100644 index 00000000000..2d295c204d6 --- /dev/null +++ b/src/libnoise/src/module/max.cpp @@ -0,0 +1,41 @@ +// max.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../misc.h" +#include "max.h" + +using namespace noise::module; + +Max::Max (): + Module (GetSourceModuleCount ()) +{ +} + +double Max::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_pSourceModule[1] != NULL); + + double v0 = m_pSourceModule[0]->GetValue (x, y, z); + double v1 = m_pSourceModule[1]->GetValue (x, y, z); + return GetMax (v0, v1); +} diff --git a/src/libnoise/src/module/max.h b/src/libnoise/src/module/max.h new file mode 100644 index 00000000000..87b854e53ba --- /dev/null +++ b/src/libnoise/src/module/max.h @@ -0,0 +1,76 @@ +// max.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_MAX_H +#define NOISE_MODULE_MAX_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup combinermodules + /// @{ + + /// Noise module that outputs the larger of the two output values from two + /// source modules. + /// + /// @image html modulemax.png + /// + /// This noise module requires two source modules. + class Max: public Module + { + + public: + + /// Constructor. + Max (); + + virtual int GetSourceModuleCount () const + { + return 2; + } + + virtual double GetValue (double x, double y, double z) const; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/min.cpp b/src/libnoise/src/module/min.cpp new file mode 100644 index 00000000000..60cb5f576ed --- /dev/null +++ b/src/libnoise/src/module/min.cpp @@ -0,0 +1,41 @@ +// min.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../misc.h" +#include "min.h" + +using namespace noise::module; + +Min::Min (): + Module (GetSourceModuleCount ()) +{ +} + +double Min::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_pSourceModule[1] != NULL); + + double v0 = m_pSourceModule[0]->GetValue (x, y, z); + double v1 = m_pSourceModule[1]->GetValue (x, y, z); + return GetMin (v0, v1); +} diff --git a/src/libnoise/src/module/min.h b/src/libnoise/src/module/min.h new file mode 100644 index 00000000000..76de943174e --- /dev/null +++ b/src/libnoise/src/module/min.h @@ -0,0 +1,76 @@ +// min.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_MIN_H +#define NOISE_MODULE_MIN_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup combinermodules + /// @{ + + /// Noise module that outputs the smaller of the two output values from + /// two source modules. + /// + /// @image html modulemin.png + /// + /// This noise module requires two source modules. + class Min: public Module + { + + public: + + /// Constructor. + Min (); + + virtual int GetSourceModuleCount () const + { + return 2; + } + + virtual double GetValue (double x, double y, double z) const; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/module.h b/src/libnoise/src/module/module.h new file mode 100644 index 00000000000..820df8b767f --- /dev/null +++ b/src/libnoise/src/module/module.h @@ -0,0 +1,55 @@ +// module.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_H +#define NOISE_MODULE_H + +#include "add.h" +#include "abs.h" +#include "billow.h" +#include "blend.h" +#include "cache.h" +#include "checkerboard.h" +#include "clamp.h" +#include "const.h" +#include "curve.h" +#include "cylinders.h" +#include "displace.h" +#include "exponent.h" +#include "invert.h" +#include "max.h" +#include "min.h" +#include "multiply.h" +#include "perlin.h" +#include "power.h" +#include "ridgedmulti.h" +#include "rotatepoint.h" +#include "scalebias.h" +#include "scalepoint.h" +#include "select.h" +#include "spheres.h" +#include "terrace.h" +#include "translatepoint.h" +#include "turbulence.h" +#include "voronoi.h" + +#endif diff --git a/src/libnoise/src/module/modulebase.cpp b/src/libnoise/src/module/modulebase.cpp new file mode 100644 index 00000000000..7805e193c77 --- /dev/null +++ b/src/libnoise/src/module/modulebase.cpp @@ -0,0 +1,46 @@ +// modulebase.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "modulebase.h" + +using namespace noise::module; + +Module::Module (int sourceModuleCount) +{ + m_pSourceModule = NULL; + + // Create an array of pointers to all source modules required by this + // noise module. Set these pointers to NULL. + if (sourceModuleCount > 0) { + m_pSourceModule = new const Module*[sourceModuleCount]; + for (int i = 0; i < sourceModuleCount; i++) { + m_pSourceModule[i] = NULL; + } + } else { + m_pSourceModule = NULL; + } +} + +Module::~Module () +{ + delete[] m_pSourceModule; +} diff --git a/src/libnoise/src/module/modulebase.h b/src/libnoise/src/module/modulebase.h new file mode 100644 index 00000000000..913945ea9e7 --- /dev/null +++ b/src/libnoise/src/module/modulebase.h @@ -0,0 +1,366 @@ +// modulebase.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULEBASE_H +#define NOISE_MODULEBASE_H + +#include +#include +#include +#include "../basictypes.h" +#include "../exception.h" +#include "../noisegen.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @defgroup modules Noise Modules + /// @addtogroup modules + /// @{ + + /// Abstract base class for noise modules. + /// + /// A noise module is an object that calculates and outputs a value + /// given a three-dimensional input value. + /// + /// Each type of noise module uses a specific method to calculate an + /// output value. Some of these methods include: + /// + /// - Calculating a value using a coherent-noise function or some other + /// mathematical function. + /// - Mathematically changing the output value from another noise module + /// in various ways. + /// - Combining the output values from two noise modules in various ways. + /// + /// An application can use the output values from these noise modules in + /// the following ways: + /// + /// - It can be used as an elevation value for a terrain height map + /// - It can be used as a grayscale (or an RGB-channel) value for a + /// procedural texture + /// - It can be used as a position value for controlling the movement of a + /// simulated lifeform. + /// + /// A noise module defines a near-infinite 3-dimensional texture. Each + /// position in this "texture" has a specific value. + /// + /// Combining noise modules + /// + /// Noise modules can be combined with other noise modules to generate + /// complex output values. A noise module that is used as a source of + /// output values for another noise module is called a source + /// module. Each of these source modules may be connected to other + /// source modules, and so on. + /// + /// There is no limit to the number of noise modules that can be connected + /// together in this way. However, each connected noise module increases + /// the time required to calculate an output value. + /// + /// Noise-module categories + /// + /// The noise module classes that are included in libnoise can be roughly + /// divided into five categories. + /// + /// Generator Modules + /// + /// A generator module outputs a value generated by a coherent-noise + /// function or some other mathematical function. + /// + /// Examples of generator modules include: + /// - noise::module::Const: Outputs a constant value. + /// - noise::module::Perlin: Outputs a value generated by a Perlin-noise + /// function. + /// - noise::module::Voronoi: Outputs a value generated by a Voronoi-cell + /// function. + /// + /// Modifier Modules + /// + /// A modifer module mathematically modifies the output value from a + /// source module. + /// + /// Examples of modifier modules include: + /// - noise::module::Curve: Maps the output value from the source module + /// onto an arbitrary function curve. + /// - noise::module::Invert: Inverts the output value from the source + /// module. + /// + /// Combiner Modules + /// + /// A combiner module mathematically combines the output values from two + /// or more source modules together. + /// + /// Examples of combiner modules include: + /// - noise::module::Add: Adds the two output values from two source + /// modules. + /// - noise::module::Max: Outputs the larger of the two output values from + /// two source modules. + /// + /// Selector Modules + /// + /// A selector module uses the output value from a control module + /// to specify how to combine the output values from its source modules. + /// + /// Examples of selector modules include: + /// - noise::module::Blend: Outputs a value that is linearly interpolated + /// between the output values from two source modules; the interpolation + /// weight is determined by the output value from the control module. + /// - noise::module::Select: Outputs the value selected from one of two + /// source modules chosen by the output value from a control module. + /// + /// Transformer Modules + /// + /// A transformer module applies a transformation to the coordinates of + /// the input value before retrieving the output value from the source + /// module. A transformer module does not modify the output value. + /// + /// Examples of transformer modules include: + /// - RotatePoint: Rotates the coordinates of the input value around the + /// origin before retrieving the output value from the source module. + /// - ScalePoint: Multiplies each coordinate of the input value by a + /// constant value before retrieving the output value from the source + /// module. + /// + /// Connecting source modules to a noise module + /// + /// An application connects a source module to a noise module by passing + /// the source module to the SetSourceModule() method. + /// + /// The application must also pass an index value to + /// SetSourceModule() as well. An index value is a numeric identifier for + /// that source module. Index values are consecutively numbered starting + /// at zero. + /// + /// To retrieve a reference to a source module, pass its index value to + /// the GetSourceModule() method. + /// + /// Each noise module requires the attachment of a certain number of + /// source modules before it can output a value. For example, the + /// noise::module::Add module requires two source modules, while the + /// noise::module::Perlin module requires none. Call the + /// GetSourceModuleCount() method to retrieve the number of source modules + /// required by that module. + /// + /// For non-selector modules, it usually does not matter which index value + /// an application assigns to a particular source module, but for selector + /// modules, the purpose of a source module is defined by its index value. + /// For example, consider the noise::module::Select noise module, which + /// requires three source modules. The control module is the source + /// module assigned an index value of 2. The control module determines + /// whether the noise module will output the value from the source module + /// assigned an index value of 0 or the output value from the source + /// module assigned an index value of 1. + /// + /// Generating output values with a noise module + /// + /// Once an application has connected all required source modules to a + /// noise module, the application can now begin to generate output values + /// with that noise module. + /// + /// To generate an output value, pass the ( @a x, @a y, @a z ) coordinates + /// of an input value to the GetValue() method. + /// + /// Using a noise module to generate terrain height maps or textures + /// + /// One way to generate a terrain height map or a texture is to first + /// allocate a 2-dimensional array of floating-point values. For each + /// array element, pass the array subscripts as @a x and @a y coordinates + /// to the GetValue() method (leaving the @a z coordinate set to zero) and + /// place the resulting output value into the array element. + /// + /// Creating your own noise modules + /// + /// Create a class that publicly derives from noise::module::Module. + /// + /// In the constructor, call the base class' constructor while passing the + /// return value from GetSourceModuleCount() to it. + /// + /// Override the GetSourceModuleCount() pure virtual method. From this + /// method, return the number of source modules required by your noise + /// module. + /// + /// Override the GetValue() pure virtual method. For generator modules, + /// calculate and output a value given the coordinates of the input value. + /// For other modules, retrieve the output values from each source module + /// referenced in the protected @a m_pSourceModule array, mathematically + /// combine those values, and return the combined value. + /// + /// When developing a noise module, you must ensure that your noise module + /// does not modify any source module or control module connected to it; a + /// noise module can only modify the output value from those source + /// modules. You must also ensure that if an application fails to connect + /// all required source modules via the SetSourceModule() method and then + /// attempts to call the GetValue() method, your module will raise an + /// assertion. + /// + /// It shouldn't be too difficult to create your own noise module. If you + /// still have some problems, take a look at the source code for + /// noise::module::Add, which is a very simple noise module. + class Module + { + + public: + + /// Constructor. + Module (int sourceModuleCount); + + /// Destructor. + virtual ~Module (); + + /// Returns a reference to a source module connected to this noise + /// module. + /// + /// @param index The index value assigned to the source module. + /// + /// @returns A reference to the source module. + /// + /// @pre The index value ranges from 0 to one less than the number of + /// source modules required by this noise module. + /// @pre A source module with the specified index value has been added + /// to this noise module via a call to SetSourceModule(). + /// + /// @throw noise::ExceptionNoModule See the preconditions for more + /// information. + /// + /// Each noise module requires the attachment of a certain number of + /// source modules before an application can call the GetValue() + /// method. + virtual const Module& GetSourceModule (int index) const + { + assert (m_pSourceModule != NULL); + + // The following fix was provided by Will Hawkins: + // + // m_pSourceModule[index] != NULL + // + // was incorrect; it should be: + // + // m_pSourceModule[index] == NULL + if (index >= GetSourceModuleCount () || index < 0 + || m_pSourceModule[index] == NULL) { + throw noise::ExceptionNoModule (); + } + return *(m_pSourceModule[index]); + } + + /// Returns the number of source modules required by this noise + /// module. + /// + /// @returns The number of source modules required by this noise + /// module. + virtual int GetSourceModuleCount () const = 0; + + /// Generates an output value given the coordinates of the specified + /// input value. + /// + /// @param x The @a x coordinate of the input value. + /// @param y The @a y coordinate of the input value. + /// @param z The @a z coordinate of the input value. + /// + /// @returns The output value. + /// + /// @pre All source modules required by this noise module have been + /// passed to the SetSourceModule() method. + /// + /// Before an application can call this method, it must first connect + /// all required source modules via the SetSourceModule() method. If + /// these source modules are not connected to this noise module, this + /// method raises a debug assertion. + /// + /// To determine the number of source modules required by this noise + /// module, call the GetSourceModuleCount() method. + virtual double GetValue (double x, double y, double z) const = 0; + + /// Connects a source module to this noise module. + /// + /// @param index An index value to assign to this source module. + /// @param sourceModule The source module to attach. + /// + /// @pre The index value ranges from 0 to one less than the number of + /// source modules required by this noise module. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// A noise module mathematically combines the output values from the + /// source modules to generate the value returned by GetValue(). + /// + /// The index value to assign a source module is a unique identifier + /// for that source module. If an index value has already been + /// assigned to a source module, this noise module replaces the old + /// source module with the new source module. + /// + /// Before an application can call the GetValue() method, it must + /// first connect all required source modules. To determine the + /// number of source modules required by this noise module, call the + /// GetSourceModuleCount() method. + /// + /// This source module must exist throughout the lifetime of this + /// noise module unless another source module replaces that source + /// module. + /// + /// A noise module does not modify a source module; it only modifies + /// its output values. + virtual void SetSourceModule (int index, const Module& sourceModule) + { + assert (m_pSourceModule != NULL); + if (index >= GetSourceModuleCount () || index < 0) { + throw noise::ExceptionInvalidParam (); + } + m_pSourceModule[index] = &sourceModule; + } + + protected: + + /// An array containing the pointers to each source module required by + /// this noise module. + const Module** m_pSourceModule; + + private: + + /// Assignment operator. + /// + /// This assignment operator does nothing and cannot be overridden. + /// This restriction is necessary because if this object was copied, + /// all source modules assigned to this noise module would need to be + /// copied as well. + const Module& operator= (const Module& m) + { + return *this; + } + + }; + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/multiply.cpp b/src/libnoise/src/module/multiply.cpp new file mode 100644 index 00000000000..592aac30d59 --- /dev/null +++ b/src/libnoise/src/module/multiply.cpp @@ -0,0 +1,39 @@ +// multiply.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "multiply.h" + +using namespace noise::module; + +Multiply::Multiply (): + Module (GetSourceModuleCount ()) +{ +} + +double Multiply::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_pSourceModule[1] != NULL); + + return m_pSourceModule[0]->GetValue (x, y, z) + * m_pSourceModule[1]->GetValue (x, y, z); +} diff --git a/src/libnoise/src/module/multiply.h b/src/libnoise/src/module/multiply.h new file mode 100644 index 00000000000..e15a92dbdb2 --- /dev/null +++ b/src/libnoise/src/module/multiply.h @@ -0,0 +1,76 @@ +// multiply.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_MULTIPLY_H +#define NOISE_MODULE_MULTIPLY_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup combinermodules + /// @{ + + /// Noise module that outputs the product of the two output values from + /// two source modules. + /// + /// @image html modulemultiply.png + /// + /// This noise module requires two source modules. + class Multiply: public Module + { + + public: + + /// Constructor. + Multiply (); + + virtual int GetSourceModuleCount () const + { + return 2; + } + + virtual double GetValue (double x, double y, double z) const; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/perlin.cpp b/src/libnoise/src/module/perlin.cpp new file mode 100644 index 00000000000..f3effb5c2e8 --- /dev/null +++ b/src/libnoise/src/module/perlin.cpp @@ -0,0 +1,72 @@ +// perlin.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "perlin.h" + +using namespace noise::module; + +Perlin::Perlin (): + Module (GetSourceModuleCount ()), + m_frequency (DEFAULT_PERLIN_FREQUENCY ), + m_lacunarity (DEFAULT_PERLIN_LACUNARITY ), + m_noiseQuality (DEFAULT_PERLIN_QUALITY ), + m_octaveCount (DEFAULT_PERLIN_OCTAVE_COUNT), + m_persistence (DEFAULT_PERLIN_PERSISTENCE ), + m_seed (DEFAULT_PERLIN_SEED) +{ +} + +double Perlin::GetValue (double x, double y, double z) const +{ + double value = 0.0; + double signal = 0.0; + double curPersistence = 1.0; + double nx, ny, nz; + int seed; + + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + for (int curOctave = 0; curOctave < m_octaveCount; curOctave++) { + + // Make sure that these floating-point values have the same range as a 32- + // bit integer so that we can pass them to the coherent-noise functions. + nx = MakeInt32Range (x); + ny = MakeInt32Range (y); + nz = MakeInt32Range (z); + + // Get the coherent-noise value from the input value and add it to the + // final result. + seed = (m_seed + curOctave) & 0xffffffff; + signal = GradientCoherentNoise3D (nx, ny, nz, seed, m_noiseQuality); + value += signal * curPersistence; + + // Prepare the next octave. + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + curPersistence *= m_persistence; + } + + return value; +} diff --git a/src/libnoise/src/module/perlin.h b/src/libnoise/src/module/perlin.h new file mode 100644 index 00000000000..043c07333dc --- /dev/null +++ b/src/libnoise/src/module/perlin.h @@ -0,0 +1,359 @@ +// perlin.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_PERLIN_H +#define NOISE_MODULE_PERLIN_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup generatormodules + /// @{ + + /// Default frequency for the noise::module::Perlin noise module. + const double DEFAULT_PERLIN_FREQUENCY = 1.0; + + /// Default lacunarity for the noise::module::Perlin noise module. + const double DEFAULT_PERLIN_LACUNARITY = 2.0; + + /// Default number of octaves for the noise::module::Perlin noise module. + const int DEFAULT_PERLIN_OCTAVE_COUNT = 6; + + /// Default persistence value for the noise::module::Perlin noise module. + const double DEFAULT_PERLIN_PERSISTENCE = 0.5; + + /// Default noise quality for the noise::module::Perlin noise module. + const noise::NoiseQuality DEFAULT_PERLIN_QUALITY = QUALITY_STD; + + /// Default noise seed for the noise::module::Perlin noise module. + const int DEFAULT_PERLIN_SEED = 0; + + /// Maximum number of octaves for the noise::module::Perlin noise module. + const int PERLIN_MAX_OCTAVE = 30; + + /// Noise module that outputs 3-dimensional Perlin noise. + /// + /// @image html moduleperlin.png + /// + /// Perlin noise is the sum of several coherent-noise functions of + /// ever-increasing frequencies and ever-decreasing amplitudes. + /// + /// An important property of Perlin noise is that a small change in the + /// input value will produce a small change in the output value, while a + /// large change in the input value will produce a random change in the + /// output value. + /// + /// This noise module outputs Perlin-noise values that usually range from + /// -1.0 to +1.0, but there are no guarantees that all output values will + /// exist within that range. + /// + /// For a better description of Perlin noise, see the links in the + /// References and Acknowledgments section. + /// + /// This noise module does not require any source modules. + /// + /// Octaves + /// + /// The number of octaves control the amount of detail of the + /// Perlin noise. Adding more octaves increases the detail of the Perlin + /// noise, but with the drawback of increasing the calculation time. + /// + /// An octave is one of the coherent-noise functions in a series of + /// coherent-noise functions that are added together to form Perlin + /// noise. + /// + /// An application may specify the frequency of the first octave by + /// calling the SetFrequency() method. + /// + /// An application may specify the number of octaves that generate Perlin + /// noise by calling the SetOctaveCount() method. + /// + /// These coherent-noise functions are called octaves because each octave + /// has, by default, double the frequency of the previous octave. Musical + /// tones have this property as well; a musical C tone that is one octave + /// higher than the previous C tone has double its frequency. + /// + /// Frequency + /// + /// An application may specify the frequency of the first octave by + /// calling the SetFrequency() method. + /// + /// Persistence + /// + /// The persistence value controls the roughness of the Perlin + /// noise. Larger values produce rougher noise. + /// + /// The persistence value determines how quickly the amplitudes diminish + /// for successive octaves. The amplitude of the first octave is 1.0. + /// The amplitude of each subsequent octave is equal to the product of the + /// previous octave's amplitude and the persistence value. So a + /// persistence value of 0.5 sets the amplitude of the first octave to + /// 1.0; the second, 0.5; the third, 0.25; etc. + /// + /// An application may specify the persistence value by calling the + /// SetPersistence() method. + /// + /// Lacunarity + /// + /// The lacunarity specifies the frequency multipler between successive + /// octaves. + /// + /// The effect of modifying the lacunarity is subtle; you may need to play + /// with the lacunarity value to determine the effects. For best results, + /// set the lacunarity to a number between 1.5 and 3.5. + /// + /// References & acknowledgments + /// + /// The Noise Machine - + /// From the master, Ken Perlin himself. This page contains a + /// presentation that describes Perlin noise and some of its variants. + /// He won an Oscar for creating the Perlin noise algorithm! + /// + /// + /// Perlin Noise - Hugo Elias's webpage contains a very good + /// description of Perlin noise and describes its many applications. This + /// page gave me the inspiration to create libnoise in the first place. + /// Now that I know how to generate Perlin noise, I will never again use + /// cheesy subdivision algorithms to create terrain (unless I absolutely + /// need the speed.) + /// + /// The + /// Perlin noise math FAQ - A good page that describes Perlin noise in + /// plain English with only a minor amount of math. During development of + /// libnoise, I noticed that my coherent-noise function generated terrain + /// with some "regularity" to the terrain features. This page describes a + /// better coherent-noise function called gradient noise. This + /// version of noise::module::Perlin uses gradient coherent noise to + /// generate Perlin noise. + class Perlin: public Module + { + + public: + + /// Constructor. + /// + /// The default frequency is set to + /// noise::module::DEFAULT_PERLIN_FREQUENCY. + /// + /// The default lacunarity is set to + /// noise::module::DEFAULT_PERLIN_LACUNARITY. + /// + /// The default number of octaves is set to + /// noise::module::DEFAULT_PERLIN_OCTAVE_COUNT. + /// + /// The default persistence value is set to + /// noise::module::DEFAULT_PERLIN_PERSISTENCE. + /// + /// The default seed value is set to + /// noise::module::DEFAULT_PERLIN_SEED. + Perlin (); + + /// Returns the frequency of the first octave. + /// + /// @returns The frequency of the first octave. + double GetFrequency () const + { + return m_frequency; + } + + /// Returns the lacunarity of the Perlin noise. + /// + /// @returns The lacunarity of the Perlin noise. + /// + /// The lacunarity is the frequency multiplier between successive + /// octaves. + double GetLacunarity () const + { + return m_lacunarity; + } + + /// Returns the quality of the Perlin noise. + /// + /// @returns The quality of the Perlin noise. + /// + /// See noise::NoiseQuality for definitions of the various + /// coherent-noise qualities. + noise::NoiseQuality GetNoiseQuality () const + { + return m_noiseQuality; + } + + /// Returns the number of octaves that generate the Perlin noise. + /// + /// @returns The number of octaves that generate the Perlin noise. + /// + /// The number of octaves controls the amount of detail in the Perlin + /// noise. + int GetOctaveCount () const + { + return m_octaveCount; + } + + /// Returns the persistence value of the Perlin noise. + /// + /// @returns The persistence value of the Perlin noise. + /// + /// The persistence value controls the roughness of the Perlin noise. + double GetPersistence () const + { + return m_persistence; + } + + /// Returns the seed value used by the Perlin-noise function. + /// + /// @returns The seed value. + int GetSeed () const + { + return m_seed; + } + + virtual int GetSourceModuleCount () const + { + return 0; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the frequency of the first octave. + /// + /// @param frequency The frequency of the first octave. + void SetFrequency (double frequency) + { + m_frequency = frequency; + } + + /// Sets the lacunarity of the Perlin noise. + /// + /// @param lacunarity The lacunarity of the Perlin noise. + /// + /// The lacunarity is the frequency multiplier between successive + /// octaves. + /// + /// For best results, set the lacunarity to a number between 1.5 and + /// 3.5. + void SetLacunarity (double lacunarity) + { + m_lacunarity = lacunarity; + } + + /// Sets the quality of the Perlin noise. + /// + /// @param noiseQuality The quality of the Perlin noise. + /// + /// See noise::NoiseQuality for definitions of the various + /// coherent-noise qualities. + void SetNoiseQuality (noise::NoiseQuality noiseQuality) + { + m_noiseQuality = noiseQuality; + } + + /// Sets the number of octaves that generate the Perlin noise. + /// + /// @param octaveCount The number of octaves that generate the Perlin + /// noise. + /// + /// @pre The number of octaves ranges from 1 to + /// noise::module::PERLIN_MAX_OCTAVE. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// The number of octaves controls the amount of detail in the Perlin + /// noise. + /// + /// The larger the number of octaves, the more time required to + /// calculate the Perlin-noise value. + void SetOctaveCount (int octaveCount) + { + if (octaveCount < 1 || octaveCount > PERLIN_MAX_OCTAVE) { + throw noise::ExceptionInvalidParam (); + } + m_octaveCount = octaveCount; + } + + /// Sets the persistence value of the Perlin noise. + /// + /// @param persistence The persistence value of the Perlin noise. + /// + /// The persistence value controls the roughness of the Perlin noise. + /// + /// For best results, set the persistence to a number between 0.0 and + /// 1.0. + void SetPersistence (double persistence) + { + m_persistence = persistence; + } + + /// Sets the seed value used by the Perlin-noise function. + /// + /// @param seed The seed value. + void SetSeed (int seed) + { + m_seed = seed; + } + + protected: + + /// Frequency of the first octave. + double m_frequency; + + /// Frequency multiplier between successive octaves. + double m_lacunarity; + + /// Quality of the Perlin noise. + noise::NoiseQuality m_noiseQuality; + + /// Total number of octaves that generate the Perlin noise. + int m_octaveCount; + + /// Persistence of the Perlin noise. + double m_persistence; + + /// Seed value used by the Perlin-noise function. + int m_seed; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/power.cpp b/src/libnoise/src/module/power.cpp new file mode 100644 index 00000000000..393853b69b3 --- /dev/null +++ b/src/libnoise/src/module/power.cpp @@ -0,0 +1,38 @@ +// power.cpp +// +// Copyright (C) 2004 Owen Jacobson +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is angstrom@lionsanctuary.net +// + +#include "power.h" + +using namespace noise::module; + +Power::Power (): + Module (GetSourceModuleCount ()) +{ +} + +double Power::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_pSourceModule[1] != NULL); + + return pow (m_pSourceModule[0]->GetValue (x, y, z), + m_pSourceModule[1]->GetValue (x, y, z)); +} diff --git a/src/libnoise/src/module/power.h b/src/libnoise/src/module/power.h new file mode 100644 index 00000000000..1b741117c3b --- /dev/null +++ b/src/libnoise/src/module/power.h @@ -0,0 +1,80 @@ +// power.h +// +// Copyright (C) 2004 Owen Jacobson +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is angstrom@lionsanctuary.net +// + +#ifndef NOISE_MODULE_POWER_H +#define NOISE_MODULE_POWER_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @defgroup combinermodules Combiner Modules + /// @addtogroup combinermodules + /// @{ + + /// Noise module that raises the output value from a first source module + /// to the power of the output value from a second source module. + /// + /// @image html modulepower.png + /// + /// The first source module must have an index value of 0. + /// + /// The second source module must have an index value of 1. + /// + /// This noise module requires two source modules. + class Power: public Module + { + + public: + + /// Constructor. + Power (); + + virtual int GetSourceModuleCount () const + { + return 2; + } + + virtual double GetValue (double x, double y, double z) const; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/ridgedmulti.cpp b/src/libnoise/src/module/ridgedmulti.cpp new file mode 100644 index 00000000000..5a81a903bf8 --- /dev/null +++ b/src/libnoise/src/module/ridgedmulti.cpp @@ -0,0 +1,114 @@ +// ridgedmulti.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "ridgedmulti.h" + +using namespace noise::module; + +RidgedMulti::RidgedMulti (): + Module (GetSourceModuleCount ()), + m_frequency (DEFAULT_RIDGED_FREQUENCY ), + m_lacunarity (DEFAULT_RIDGED_LACUNARITY ), + m_noiseQuality (DEFAULT_RIDGED_QUALITY ), + m_octaveCount (DEFAULT_RIDGED_OCTAVE_COUNT), + m_seed (DEFAULT_RIDGED_SEED) +{ + CalcSpectralWeights (); +} + +// Calculates the spectral weights for each octave. +void RidgedMulti::CalcSpectralWeights () +{ + // This exponent parameter should be user-defined; it may be exposed in a + // future version of libnoise. + double h = 1.0; + + double frequency = 1.0; + for (int i = 0; i < RIDGED_MAX_OCTAVE; i++) { + // Compute weight for each frequency. + m_pSpectralWeights[i] = pow (frequency, -h); + frequency *= m_lacunarity; + } +} + +// Multifractal code originally written by F. Kenton "Doc Mojo" Musgrave, +// 1998. Modified by jas for use with libnoise. +double RidgedMulti::GetValue (double x, double y, double z) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + double signal = 0.0; + double value = 0.0; + double weight = 1.0; + + // These parameters should be user-defined; they may be exposed in a + // future version of libnoise. + double offset = 1.0; + double gain = 2.0; + + for (int curOctave = 0; curOctave < m_octaveCount; curOctave++) { + + // Make sure that these floating-point values have the same range as a 32- + // bit integer so that we can pass them to the coherent-noise functions. + double nx, ny, nz; + nx = MakeInt32Range (x); + ny = MakeInt32Range (y); + nz = MakeInt32Range (z); + + // Get the coherent-noise value. + int seed = (m_seed + curOctave) & 0x7fffffff; + signal = GradientCoherentNoise3D (nx, ny, nz, seed, m_noiseQuality); + + // Make the ridges. + signal = fabs (signal); + signal = offset - signal; + + // Square the signal to increase the sharpness of the ridges. + signal *= signal; + + // The weighting from the previous octave is applied to the signal. + // Larger values have higher weights, producing sharp points along the + // ridges. + signal *= weight; + + // Weight successive contributions by the previous signal. + weight = signal * gain; + if (weight > 1.0) { + weight = 1.0; + } + if (weight < 0.0) { + weight = 0.0; + } + + // Add the signal to the output value. + value += (signal * m_pSpectralWeights[curOctave]); + + // Go to the next octave. + x *= m_lacunarity; + y *= m_lacunarity; + z *= m_lacunarity; + } + + return (value * 1.25) - 1.0; +} diff --git a/src/libnoise/src/module/ridgedmulti.h b/src/libnoise/src/module/ridgedmulti.h new file mode 100644 index 00000000000..99617f91d53 --- /dev/null +++ b/src/libnoise/src/module/ridgedmulti.h @@ -0,0 +1,313 @@ +// ridgedmulti.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_RIDGEDMULTI_H +#define NOISE_MODULE_RIDGEDMULTI_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup generatormodules + /// @{ + + /// Default frequency for the noise::module::RidgedMulti noise module. + const double DEFAULT_RIDGED_FREQUENCY = 1.0; + + /// Default lacunarity for the noise::module::RidgedMulti noise module. + const double DEFAULT_RIDGED_LACUNARITY = 2.0; + + /// Default number of octaves for the noise::module::RidgedMulti noise + /// module. + const int DEFAULT_RIDGED_OCTAVE_COUNT = 6; + + /// Default noise quality for the noise::module::RidgedMulti noise + /// module. + const noise::NoiseQuality DEFAULT_RIDGED_QUALITY = QUALITY_STD; + + /// Default noise seed for the noise::module::RidgedMulti noise module. + const int DEFAULT_RIDGED_SEED = 0; + + /// Maximum number of octaves for the noise::module::RidgedMulti noise + /// module. + const int RIDGED_MAX_OCTAVE = 30; + + /// Noise module that outputs 3-dimensional ridged-multifractal noise. + /// + /// @image html moduleridgedmulti.png + /// + /// This noise module, heavily based on the Perlin-noise module, generates + /// ridged-multifractal noise. Ridged-multifractal noise is generated in + /// much of the same way as Perlin noise, except the output of each octave + /// is modified by an absolute-value function. Modifying the octave + /// values in this way produces ridge-like formations. + /// + /// Ridged-multifractal noise does not use a persistence value. This is + /// because the persistence values of the octaves are based on the values + /// generated from from previous octaves, creating a feedback loop (or + /// that's what it looks like after reading the code.) + /// + /// This noise module outputs ridged-multifractal-noise values that + /// usually range from -1.0 to +1.0, but there are no guarantees that all + /// output values will exist within that range. + /// + /// @note For ridged-multifractal noise generated with only one octave, + /// the output value ranges from -1.0 to 0.0. + /// + /// Ridged-multifractal noise is often used to generate craggy mountainous + /// terrain or marble-like textures. + /// + /// This noise module does not require any source modules. + /// + /// Octaves + /// + /// The number of octaves control the amount of detail of the + /// ridged-multifractal noise. Adding more octaves increases the detail + /// of the ridged-multifractal noise, but with the drawback of increasing + /// the calculation time. + /// + /// An application may specify the number of octaves that generate + /// ridged-multifractal noise by calling the SetOctaveCount() method. + /// + /// Frequency + /// + /// An application may specify the frequency of the first octave by + /// calling the SetFrequency() method. + /// + /// Lacunarity + /// + /// The lacunarity specifies the frequency multipler between successive + /// octaves. + /// + /// The effect of modifying the lacunarity is subtle; you may need to play + /// with the lacunarity value to determine the effects. For best results, + /// set the lacunarity to a number between 1.5 and 3.5. + /// + /// References & Acknowledgments + /// + /// F. + /// Kenton "Doc Mojo" Musgrave's texturing page - This page contains + /// links to source code that generates ridged-multfractal noise, among + /// other types of noise. The source file + /// fractal.c contains the code I used in my ridged-multifractal class + /// (see the @a RidgedMultifractal() function.) This code was written by F. + /// Kenton Musgrave, the person who created + /// MojoWorld. He is also one of + /// the authors in Texturing and Modeling: A Procedural Approach + /// (Morgan Kaufmann, 2002. ISBN 1-55860-848-6.) + class RidgedMulti: public Module + { + + public: + + /// Constructor. + /// + /// The default number of octaves is set to + /// noise::module::DEFAULT_RIDGED_OCTAVE_COUNT. + /// + /// The default frequency is set to + /// noise::module::DEFAULT_RIDGED_FREQUENCY. + /// + /// The default lacunarity is set to + /// noise::module::DEFAULT_RIDGED_LACUNARITY. + /// + /// The default seed value is set to + /// noise::module::DEFAULT_RIDGED_SEED. + RidgedMulti (); + + /// Returns the frequency of the first octave. + /// + /// @returns The frequency of the first octave. + double GetFrequency () const + { + return m_frequency; + } + + /// Returns the lacunarity of the ridged-multifractal noise. + /// + /// @returns The lacunarity of the ridged-multifractal noise. + /// + /// The lacunarity is the frequency multiplier between successive + /// octaves. + double GetLacunarity () const + { + return m_lacunarity; + } + + /// Returns the quality of the ridged-multifractal noise. + /// + /// @returns The quality of the ridged-multifractal noise. + /// + /// See noise::NoiseQuality for definitions of the various + /// coherent-noise qualities. + noise::NoiseQuality GetNoiseQuality () const + { + return m_noiseQuality; + } + + /// Returns the number of octaves that generate the + /// ridged-multifractal noise. + /// + /// @returns The number of octaves that generate the + /// ridged-multifractal noise. + /// + /// The number of octaves controls the amount of detail in the + /// ridged-multifractal noise. + int GetOctaveCount () const + { + return m_octaveCount; + } + + /// Returns the seed value used by the ridged-multifractal-noise + /// function. + /// + /// @returns The seed value. + int GetSeed () const + { + return m_seed; + } + + virtual int GetSourceModuleCount () const + { + return 0; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the frequency of the first octave. + /// + /// @param frequency The frequency of the first octave. + void SetFrequency (double frequency) + { + m_frequency = frequency; + } + + /// Sets the lacunarity of the ridged-multifractal noise. + /// + /// @param lacunarity The lacunarity of the ridged-multifractal noise. + /// + /// The lacunarity is the frequency multiplier between successive + /// octaves. + /// + /// For best results, set the lacunarity to a number between 1.5 and + /// 3.5. + void SetLacunarity (double lacunarity) + { + m_lacunarity = lacunarity; + CalcSpectralWeights (); + } + + /// Sets the quality of the ridged-multifractal noise. + /// + /// @param noiseQuality The quality of the ridged-multifractal noise. + /// + /// See noise::NoiseQuality for definitions of the various + /// coherent-noise qualities. + void SetNoiseQuality (noise::NoiseQuality noiseQuality) + { + m_noiseQuality = noiseQuality; + } + + /// Sets the number of octaves that generate the ridged-multifractal + /// noise. + /// + /// @param octaveCount The number of octaves that generate the + /// ridged-multifractal noise. + /// + /// @pre The number of octaves ranges from 1 to + /// noise::module::RIDGED_MAX_OCTAVE. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// The number of octaves controls the amount of detail in the + /// ridged-multifractal noise. + /// + /// The larger the number of octaves, the more time required to + /// calculate the ridged-multifractal-noise value. + void SetOctaveCount (int octaveCount) + { + if (octaveCount > RIDGED_MAX_OCTAVE) { + throw noise::ExceptionInvalidParam (); + } + m_octaveCount = octaveCount; + } + + /// Sets the seed value used by the ridged-multifractal-noise + /// function. + /// + /// @param seed The seed value. + void SetSeed (int seed) + { + m_seed = seed; + } + + protected: + + /// Calculates the spectral weights for each octave. + /// + /// This method is called when the lacunarity changes. + void CalcSpectralWeights (); + + /// Frequency of the first octave. + double m_frequency; + + /// Frequency multiplier between successive octaves. + double m_lacunarity; + + /// Quality of the ridged-multifractal noise. + noise::NoiseQuality m_noiseQuality; + + /// Total number of octaves that generate the ridged-multifractal + /// noise. + int m_octaveCount; + + /// Contains the spectral weights for each octave. + double m_pSpectralWeights[RIDGED_MAX_OCTAVE]; + + /// Seed value used by the ridged-multfractal-noise function. + int m_seed; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/rotatepoint.cpp b/src/libnoise/src/module/rotatepoint.cpp new file mode 100644 index 00000000000..dccac82e1e7 --- /dev/null +++ b/src/libnoise/src/module/rotatepoint.cpp @@ -0,0 +1,68 @@ +// rotatepoint.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../mathconsts.h" +#include "rotatepoint.h" + +using namespace noise::module; + +RotatePoint::RotatePoint (): + Module (GetSourceModuleCount ()) +{ + SetAngles (DEFAULT_ROTATE_X, DEFAULT_ROTATE_Y, DEFAULT_ROTATE_Z); +} + +double RotatePoint::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + double nx = (m_x1Matrix * x) + (m_y1Matrix * y) + (m_z1Matrix * z); + double ny = (m_x2Matrix * x) + (m_y2Matrix * y) + (m_z2Matrix * z); + double nz = (m_x3Matrix * x) + (m_y3Matrix * y) + (m_z3Matrix * z); + return m_pSourceModule[0]->GetValue (nx, ny, nz); +} + +void RotatePoint::SetAngles (double xAngle, double yAngle, + double zAngle) +{ + double xCos, yCos, zCos, xSin, ySin, zSin; + xCos = cos (xAngle * DEG_TO_RAD); + yCos = cos (yAngle * DEG_TO_RAD); + zCos = cos (zAngle * DEG_TO_RAD); + xSin = sin (xAngle * DEG_TO_RAD); + ySin = sin (yAngle * DEG_TO_RAD); + zSin = sin (zAngle * DEG_TO_RAD); + + m_x1Matrix = ySin * xSin * zSin + yCos * zCos; + m_y1Matrix = xCos * zSin; + m_z1Matrix = ySin * zCos - yCos * xSin * zSin; + m_x2Matrix = ySin * xSin * zCos - yCos * zSin; + m_y2Matrix = xCos * zCos; + m_z2Matrix = -yCos * xSin * zCos - ySin * zSin; + m_x3Matrix = -ySin * xCos; + m_y3Matrix = xSin; + m_z3Matrix = yCos * xCos; + + m_xAngle = xAngle; + m_yAngle = yAngle; + m_zAngle = zAngle; +} diff --git a/src/libnoise/src/module/rotatepoint.h b/src/libnoise/src/module/rotatepoint.h new file mode 100644 index 00000000000..34c8830b773 --- /dev/null +++ b/src/libnoise/src/module/rotatepoint.h @@ -0,0 +1,233 @@ +// rotatepoint.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_ROTATEPOINT_H +#define NOISE_MODULE_ROTATEPOINT_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup transformermodules + /// @{ + + /// Default @a x rotation angle for the noise::module::RotatePoint noise + /// module. + const double DEFAULT_ROTATE_X = 0.0; + + /// Default @a y rotation angle for the noise::module::RotatePoint noise + /// module. + const double DEFAULT_ROTATE_Y = 0.0; + + /// Default @a z rotation angle for the noise::module::RotatePoint noise + /// module. + const double DEFAULT_ROTATE_Z = 0.0; + + /// Noise module that rotates the input value around the origin before + /// returning the output value from a source module. + /// + /// @image html modulerotatepoint.png + /// + /// The GetValue() method rotates the coordinates of the input value + /// around the origin before returning the output value from the source + /// module. To set the rotation angles, call the SetAngles() method. To + /// set the rotation angle around the individual @a x, @a y, or @a z axes, + /// call the SetXAngle(), SetYAngle() or SetZAngle() methods, + /// respectively. + /// + /// The coordinate system of the input value is assumed to be + /// "left-handed" (@a x increases to the right, @a y increases upward, + /// and @a z increases inward.) + /// + /// This noise module requires one source module. + class RotatePoint: public Module + { + + public: + + /// Constructor. + /// + /// The default rotation angle around the @a x axis, in degrees, is + /// set to noise::module::DEFAULT_ROTATE_X. + /// + /// The default rotation angle around the @a y axis, in degrees, is + /// set to noise::module::DEFAULT_ROTATE_Y. + /// + /// The default rotation angle around the @a z axis, in degrees, is + /// set to noise::module::DEFAULT_ROTATE_Z. + RotatePoint (); + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Returns the rotation angle around the @a x axis to apply to the + /// input value. + /// + /// @returns The rotation angle around the @a x axis, in degrees. + double GetXAngle () const + { + return m_xAngle; + } + + /// Returns the rotation angle around the @a y axis to apply to the + /// input value. + /// + /// @returns The rotation angle around the @a y axis, in degrees. + double GetYAngle () const + { + return m_yAngle; + } + + /// Returns the rotation angle around the @a z axis to apply to the + /// input value. + /// + /// @returns The rotation angle around the @a z axis, in degrees. + double GetZAngle () const + { + return m_zAngle; + } + + /// Sets the rotation angles around all three axes to apply to the + /// input value. + /// + /// @param xAngle The rotation angle around the @a x axis, in degrees. + /// @param yAngle The rotation angle around the @a y axis, in degrees. + /// @param zAngle The rotation angle around the @a z axis, in degrees. + /// + /// The GetValue() method rotates the coordinates of the input value + /// around the origin before returning the output value from the + /// source module. + void SetAngles (double xAngle, double yAngle, double zAngle); + + /// Sets the rotation angle around the @a x axis to apply to the input + /// value. + /// + /// @param xAngle The rotation angle around the @a x axis, in degrees. + /// + /// The GetValue() method rotates the coordinates of the input value + /// around the origin before returning the output value from the + /// source module. + void SetXAngle (double xAngle) + { + SetAngles (xAngle, m_yAngle, m_zAngle); + } + + /// Sets the rotation angle around the @a y axis to apply to the input + /// value. + /// + /// @param yAngle The rotation angle around the @a y axis, in degrees. + /// + /// The GetValue() method rotates the coordinates of the input value + /// around the origin before returning the output value from the + /// source module. + void SetYAngle (double yAngle) + { + SetAngles (m_xAngle, yAngle, m_zAngle); + } + + /// Sets the rotation angle around the @a z axis to apply to the input + /// value. + /// + /// @param zAngle The rotation angle around the @a z axis, in degrees. + /// + /// The GetValue() method rotates the coordinates of the input value + /// around the origin before returning the output value from the + /// source module. + void SetZAngle (double zAngle) + { + SetAngles (m_xAngle, m_yAngle, zAngle); + } + + protected: + + /// An entry within the 3x3 rotation matrix used for rotating the + /// input value. + double m_x1Matrix; + + /// An entry within the 3x3 rotation matrix used for rotating the + /// input value. + double m_x2Matrix; + + /// An entry within the 3x3 rotation matrix used for rotating the + /// input value. + double m_x3Matrix; + + /// @a x rotation angle applied to the input value, in degrees. + double m_xAngle; + + /// An entry within the 3x3 rotation matrix used for rotating the + /// input value. + double m_y1Matrix; + + /// An entry within the 3x3 rotation matrix used for rotating the + /// input value. + double m_y2Matrix; + + /// An entry within the 3x3 rotation matrix used for rotating the + /// input value. + double m_y3Matrix; + + /// @a y rotation angle applied to the input value, in degrees. + double m_yAngle; + + /// An entry within the 3x3 rotation matrix used for rotating the + /// input value. + double m_z1Matrix; + + /// An entry within the 3x3 rotation matrix used for rotating the + /// input value. + double m_z2Matrix; + + /// An entry within the 3x3 rotation matrix used for rotating the + /// input value. + double m_z3Matrix; + + /// @a z rotation angle applied to the input value, in degrees. + double m_zAngle; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/scalebias.cpp b/src/libnoise/src/module/scalebias.cpp new file mode 100644 index 00000000000..67ba8d9fa72 --- /dev/null +++ b/src/libnoise/src/module/scalebias.cpp @@ -0,0 +1,39 @@ +// scalebias.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "scalebias.h" + +using namespace noise::module; + +ScaleBias::ScaleBias (): + Module (GetSourceModuleCount ()), + m_bias (DEFAULT_BIAS ), + m_scale (DEFAULT_SCALE) +{ +} + +double ScaleBias::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + return m_pSourceModule[0]->GetValue (x, y, z) * m_scale + m_bias; +} diff --git a/src/libnoise/src/module/scalebias.h b/src/libnoise/src/module/scalebias.h new file mode 100644 index 00000000000..419efca23af --- /dev/null +++ b/src/libnoise/src/module/scalebias.h @@ -0,0 +1,151 @@ +// scalebias.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_SCALEBIAS_H +#define NOISE_MODULE_SCALEBIAS_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup modifiermodules + /// @{ + + /// Default bias for the noise::module::ScaleBias noise module. + const double DEFAULT_BIAS = 0.0; + + /// Default scale for the noise::module::ScaleBias noise module. + const double DEFAULT_SCALE = 1.0; + + /// Noise module that applies a scaling factor and a bias to the output + /// value from a source module. + /// + /// @image html modulescalebias.png + /// + /// The GetValue() method retrieves the output value from the source + /// module, multiplies it with a scaling factor, adds a bias to it, then + /// outputs the value. + /// + /// This noise module requires one source module. + class ScaleBias: public Module + { + + public: + + /// Constructor. + /// + /// The default bias is set to noise::module::DEFAULT_BIAS. + /// + /// The default scaling factor is set to noise::module::DEFAULT_SCALE. + ScaleBias (); + + /// Returns the bias to apply to the scaled output value from the + /// source module. + /// + /// @returns The bias to apply. + /// + /// The GetValue() method retrieves the output value from the source + /// module, multiplies it with the scaling factor, adds the bias to + /// it, then outputs the value. + double GetBias () const + { + return m_bias; + } + + /// Returns the scaling factor to apply to the output value from the + /// source module. + /// + /// @returns The scaling factor to apply. + /// + /// The GetValue() method retrieves the output value from the source + /// module, multiplies it with the scaling factor, adds the bias to + /// it, then outputs the value. + double GetScale () const + { + return m_scale; + } + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the bias to apply to the scaled output value from the source + /// module. + /// + /// @param bias The bias to apply. + /// + /// The GetValue() method retrieves the output value from the source + /// module, multiplies it with the scaling factor, adds the bias to + /// it, then outputs the value. + void SetBias (double bias) + { + m_bias = bias; + } + + /// Sets the scaling factor to apply to the output value from the + /// source module. + /// + /// @param scale The scaling factor to apply. + /// + /// The GetValue() method retrieves the output value from the source + /// module, multiplies it with the scaling factor, adds the bias to + /// it, then outputs the value. + void SetScale (double scale) + { + m_scale = scale; + } + + protected: + + /// Bias to apply to the scaled output value from the source module. + double m_bias; + + /// Scaling factor to apply to the output value from the source + /// module. + double m_scale; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/scalepoint.cpp b/src/libnoise/src/module/scalepoint.cpp new file mode 100644 index 00000000000..f0c9676e051 --- /dev/null +++ b/src/libnoise/src/module/scalepoint.cpp @@ -0,0 +1,41 @@ +// scalepoint.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "scalepoint.h" + +using namespace noise::module; + +ScalePoint::ScalePoint (): + Module (GetSourceModuleCount ()), + m_xScale (DEFAULT_SCALE_POINT_X), + m_yScale (DEFAULT_SCALE_POINT_Y), + m_zScale (DEFAULT_SCALE_POINT_Z) +{ +} + +double ScalePoint::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + return m_pSourceModule[0]->GetValue (x * m_xScale, y * m_yScale, + z * m_zScale); +} diff --git a/src/libnoise/src/module/scalepoint.h b/src/libnoise/src/module/scalepoint.h new file mode 100644 index 00000000000..cd11956a1a5 --- /dev/null +++ b/src/libnoise/src/module/scalepoint.h @@ -0,0 +1,212 @@ +// scalepoint.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_SCALEPOINT_H +#define NOISE_MODULE_SCALEPOINT_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup transformermodules + /// @{ + + /// Default scaling factor applied to the @a x coordinate for the + /// noise::module::ScalePoint noise module. + const double DEFAULT_SCALE_POINT_X = 1.0; + + /// Default scaling factor applied to the @a y coordinate for the + /// noise::module::ScalePoint noise module. + const double DEFAULT_SCALE_POINT_Y = 1.0; + + /// Default scaling factor applied to the @a z coordinate for the + /// noise::module::ScalePoint noise module. + const double DEFAULT_SCALE_POINT_Z = 1.0; + + /// Noise module that scales the coordinates of the input value before + /// returning the output value from a source module. + /// + /// @image html modulescalepoint.png + /// + /// The GetValue() method multiplies the ( @a x, @a y, @a z ) coordinates + /// of the input value with a scaling factor before returning the output + /// value from the source module. To set the scaling factor, call the + /// SetScale() method. To set the scaling factor to apply to the + /// individual @a x, @a y, or @a z coordinates, call the SetXScale(), + /// SetYScale() or SetZScale() methods, respectively. + /// + /// This noise module requires one source module. + class ScalePoint: public Module + { + + public: + + /// Constructor. + /// + /// The default scaling factor applied to the @a x coordinate is set + /// to noise::module::DEFAULT_SCALE_POINT_X. + /// + /// The default scaling factor applied to the @a y coordinate is set + /// to noise::module::DEFAULT_SCALE_POINT_Y. + /// + /// The default scaling factor applied to the @a z coordinate is set + /// to noise::module::DEFAULT_SCALE_POINT_Z. + ScalePoint (); + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Returns the scaling factor applied to the @a x coordinate of the + /// input value. + /// + /// @returns The scaling factor applied to the @a x coordinate. + double GetXScale () const + { + return m_xScale; + } + + /// Returns the scaling factor applied to the @a y coordinate of the + /// input value. + /// + /// @returns The scaling factor applied to the @a y coordinate. + double GetYScale () const + { + return m_yScale; + } + + /// Returns the scaling factor applied to the @a z coordinate of the + /// input value. + /// + /// @returns The scaling factor applied to the @a z coordinate. + double GetZScale () const + { + return m_zScale; + } + + /// Sets the scaling factor to apply to the input value. + /// + /// @param scale The scaling factor to apply. + /// + /// The GetValue() method multiplies the ( @a x, @a y, @a z ) + /// coordinates of the input value with a scaling factor before + /// returning the output value from the source module. + void SetScale (double scale) + { + m_xScale = scale; + m_yScale = scale; + m_zScale = scale; + } + + /// Sets the scaling factor to apply to the ( @a x, @a y, @a z ) + /// coordinates of the input value. + /// + /// @param xScale The scaling factor to apply to the @a x coordinate. + /// @param yScale The scaling factor to apply to the @a y coordinate. + /// @param zScale The scaling factor to apply to the @a z coordinate. + /// + /// The GetValue() method multiplies the ( @a x, @a y, @a z ) + /// coordinates of the input value with a scaling factor before + /// returning the output value from the source module. + void SetScale (double xScale, double yScale, double zScale) + { + m_xScale = xScale; + m_yScale = yScale; + m_zScale = zScale; + } + + /// Sets the scaling factor to apply to the @a x coordinate of the + /// input value. + /// + /// @param xScale The scaling factor to apply to the @a x coordinate. + /// + /// The GetValue() method multiplies the ( @a x, @a y, @a z ) + /// coordinates of the input value with a scaling factor before + /// returning the output value from the source module. + void SetXScale (double xScale) + { + m_xScale = xScale; + } + + /// Sets the scaling factor to apply to the @a y coordinate of the + /// input value. + /// + /// @param yScale The scaling factor to apply to the @a y coordinate. + /// + /// The GetValue() method multiplies the ( @a x, @a y, @a z ) + /// coordinates of the input value with a scaling factor before + /// returning the output value from the source module. + void SetYScale (double yScale) + { + m_yScale = yScale; + } + + /// Sets the scaling factor to apply to the @a z coordinate of the + /// input value. + /// + /// @param zScale The scaling factor to apply to the @a z coordinate. + /// + /// The GetValue() method multiplies the ( @a x, @a y, @a z ) + /// coordinates of the input value with a scaling factor before + /// returning the output value from the source module. + void SetZScale (double zScale) + { + m_zScale = zScale; + } + + protected: + + /// Scaling factor applied to the @a x coordinate of the input value. + double m_xScale; + + /// Scaling factor applied to the @a y coordinate of the input value. + double m_yScale; + + /// Scaling factor applied to the @a z coordinate of the input value. + double m_zScale; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/select.cpp b/src/libnoise/src/module/select.cpp new file mode 100644 index 00000000000..d59e6aa2ada --- /dev/null +++ b/src/libnoise/src/module/select.cpp @@ -0,0 +1,109 @@ +// select.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../interp.h" +#include "select.h" + +using namespace noise::module; + +Select::Select (): + Module (GetSourceModuleCount ()), + m_edgeFalloff (DEFAULT_SELECT_EDGE_FALLOFF), + m_lowerBound (DEFAULT_SELECT_LOWER_BOUND), + m_upperBound (DEFAULT_SELECT_UPPER_BOUND) +{ +} + +double Select::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_pSourceModule[1] != NULL); + assert (m_pSourceModule[2] != NULL); + + double controlValue = m_pSourceModule[2]->GetValue (x, y, z); + double alpha; + if (m_edgeFalloff > 0.0) { + if (controlValue < (m_lowerBound - m_edgeFalloff)) { + // The output value from the control module is below the selector + // threshold; return the output value from the first source module. + return m_pSourceModule[0]->GetValue (x, y, z); + + } else if (controlValue < (m_lowerBound + m_edgeFalloff)) { + // The output value from the control module is near the lower end of the + // selector threshold and within the smooth curve. Interpolate between + // the output values from the first and second source modules. + double lowerCurve = (m_lowerBound - m_edgeFalloff); + double upperCurve = (m_lowerBound + m_edgeFalloff); + alpha = SCurve3 ( + (controlValue - lowerCurve) / (upperCurve - lowerCurve)); + return LinearInterp (m_pSourceModule[0]->GetValue (x, y, z), + m_pSourceModule[1]->GetValue (x, y, z), + alpha); + + } else if (controlValue < (m_upperBound - m_edgeFalloff)) { + // The output value from the control module is within the selector + // threshold; return the output value from the second source module. + return m_pSourceModule[1]->GetValue (x, y, z); + + } else if (controlValue < (m_upperBound + m_edgeFalloff)) { + // The output value from the control module is near the upper end of the + // selector threshold and within the smooth curve. Interpolate between + // the output values from the first and second source modules. + double lowerCurve = (m_upperBound - m_edgeFalloff); + double upperCurve = (m_upperBound + m_edgeFalloff); + alpha = SCurve3 ( + (controlValue - lowerCurve) / (upperCurve - lowerCurve)); + return LinearInterp (m_pSourceModule[1]->GetValue (x, y, z), + m_pSourceModule[0]->GetValue (x, y, z), + alpha); + + } else { + // Output value from the control module is above the selector threshold; + // return the output value from the first source module. + return m_pSourceModule[0]->GetValue (x, y, z); + } + } else { + if (controlValue < m_lowerBound || controlValue > m_upperBound) { + return m_pSourceModule[0]->GetValue (x, y, z); + } else { + return m_pSourceModule[1]->GetValue (x, y, z); + } + } +} + +void Select::SetBounds (double lowerBound, double upperBound) +{ + assert (lowerBound < upperBound); + + m_lowerBound = lowerBound; + m_upperBound = upperBound; + + // Make sure that the edge falloff curves do not overlap. + SetEdgeFalloff (m_edgeFalloff); +} + +void Select::SetEdgeFalloff (double edgeFalloff) +{ + // Make sure that the edge falloff curves do not overlap. + double boundSize = m_upperBound - m_lowerBound; + m_edgeFalloff = (edgeFalloff > boundSize / 2)? boundSize / 2: edgeFalloff; +} diff --git a/src/libnoise/src/module/select.h b/src/libnoise/src/module/select.h new file mode 100644 index 00000000000..4e1dbd3fe90 --- /dev/null +++ b/src/libnoise/src/module/select.h @@ -0,0 +1,267 @@ +// select.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_SELECT_H +#define NOISE_MODULE_SELECT_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup selectormodules + /// @{ + + /// Default edge-falloff value for the noise::module::Select noise module. + const double DEFAULT_SELECT_EDGE_FALLOFF = 0.0; + + /// Default lower bound of the selection range for the + /// noise::module::Select noise module. + const double DEFAULT_SELECT_LOWER_BOUND = -1.0; + + /// Default upper bound of the selection range for the + /// noise::module::Select noise module. + const double DEFAULT_SELECT_UPPER_BOUND = 1.0; + + /// Noise module that outputs the value selected from one of two source + /// modules chosen by the output value from a control module. + /// + /// @image html moduleselect.png + /// + /// Unlike most other noise modules, the index value assigned to a source + /// module determines its role in the selection operation: + /// - Source module 0 (upper left in the diagram) outputs a value. + /// - Source module 1 (lower left in the diagram) outputs a value. + /// - Source module 2 (bottom of the diagram) is known as the control + /// module. The control module determines the value to select. If + /// the output value from the control module is within a range of values + /// known as the selection range, this noise module outputs the + /// value from the source module with an index value of 1. Otherwise, + /// this noise module outputs the value from the source module with an + /// index value of 0. + /// + /// To specify the bounds of the selection range, call the SetBounds() + /// method. + /// + /// An application can pass the control module to the SetControlModule() + /// method instead of the SetSourceModule() method. This may make the + /// application code easier to read. + /// + /// By default, there is an abrupt transition between the output values + /// from the two source modules at the selection-range boundary. To + /// smooth the transition, pass a non-zero value to the SetEdgeFalloff() + /// method. Higher values result in a smoother transition. + /// + /// This noise module requires three source modules. + class Select: public Module + { + + public: + + /// Constructor. + /// + /// The default falloff value at the edge transition is set to + /// noise::module::DEFAULT_SELECT_EDGE_FALLOFF. + /// + /// The default lower bound of the selection range is set to + /// noise::module::DEFAULT_SELECT_LOWER_BOUND. + /// + /// The default upper bound of the selection range is set to + /// noise::module::DEFAULT_SELECT_UPPER_BOUND. + Select (); + + /// Returns the control module. + /// + /// @returns A reference to the control module. + /// + /// @pre A control module has been added to this noise module via a + /// call to SetSourceModule() or SetControlModule(). + /// + /// @throw noise::ExceptionNoModule See the preconditions for more + /// information. + /// + /// The control module determines the output value to select. If the + /// output value from the control module is within a range of values + /// known as the selection range, the GetValue() method outputs + /// the value from the source module with an index value of 1. + /// Otherwise, this method outputs the value from the source module + /// with an index value of 0. + const Module& GetControlModule () const + { + if (m_pSourceModule == NULL || m_pSourceModule[2] == NULL) { + throw noise::ExceptionNoModule (); + } + return *(m_pSourceModule[2]); + } + + /// Returns the falloff value at the edge transition. + /// + /// @returns The falloff value at the edge transition. + /// + /// The falloff value is the width of the edge transition at either + /// edge of the selection range. + /// + /// By default, there is an abrupt transition between the output + /// values from the two source modules at the selection-range + /// boundary. + double GetEdgeFalloff () const + { + return m_edgeFalloff; + } + + /// Returns the lower bound of the selection range. + /// + /// @returns The lower bound of the selection range. + /// + /// If the output value from the control module is within the + /// selection range, the GetValue() method outputs the value from the + /// source module with an index value of 1. Otherwise, this method + /// outputs the value from the source module with an index value of 0. + double GetLowerBound () const + { + return m_lowerBound; + } + + virtual int GetSourceModuleCount () const + { + return 3; + } + + /// Returns the upper bound of the selection range. + /// + /// @returns The upper bound of the selection range. + /// + /// If the output value from the control module is within the + /// selection range, the GetValue() method outputs the value from the + /// source module with an index value of 1. Otherwise, this method + /// outputs the value from the source module with an index value of 0. + double GetUpperBound () const + { + return m_upperBound; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the lower and upper bounds of the selection range. + /// + /// @param lowerBound The lower bound. + /// @param upperBound The upper bound. + /// + /// @pre The lower bound must be less than or equal to the upper + /// bound. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// If the output value from the control module is within the + /// selection range, the GetValue() method outputs the value from the + /// source module with an index value of 1. Otherwise, this method + /// outputs the value from the source module with an index value of 0. + void SetBounds (double lowerBound, double upperBound); + + /// Sets the control module. + /// + /// @param controlModule The control module. + /// + /// The control module determines the output value to select. If the + /// output value from the control module is within a range of values + /// known as the selection range, the GetValue() method outputs + /// the value from the source module with an index value of 1. + /// Otherwise, this method outputs the value from the source module + /// with an index value of 0. + /// + /// This method assigns the control module an index value of 2. + /// Passing the control module to this method produces the same + /// results as passing the control module to the SetSourceModule() + /// method while assigning that noise module an index value of 2. + /// + /// This control module must exist throughout the lifetime of this + /// noise module unless another control module replaces that control + /// module. + void SetControlModule (const Module& controlModule) + { + assert (m_pSourceModule != NULL); + m_pSourceModule[2] = &controlModule; + } + + /// Sets the falloff value at the edge transition. + /// + /// @param edgeFalloff The falloff value at the edge transition. + /// + /// The falloff value is the width of the edge transition at either + /// edge of the selection range. + /// + /// By default, there is an abrupt transition between the values from + /// the two source modules at the boundaries of the selection range. + /// + /// For example, if the selection range is 0.5 to 0.8, and the edge + /// falloff value is 0.1, then the GetValue() method outputs: + /// - the output value from the source module with an index value of 0 + /// if the output value from the control module is less than 0.4 + /// ( = 0.5 - 0.1). + /// - a linear blend between the two output values from the two source + /// modules if the output value from the control module is between + /// 0.4 ( = 0.5 - 0.1) and 0.6 ( = 0.5 + 0.1). + /// - the output value from the source module with an index value of 1 + /// if the output value from the control module is between 0.6 + /// ( = 0.5 + 0.1) and 0.7 ( = 0.8 - 0.1). + /// - a linear blend between the output values from the two source + /// modules if the output value from the control module is between + /// 0.7 ( = 0.8 - 0.1 ) and 0.9 ( = 0.8 + 0.1). + /// - the output value from the source module with an index value of 0 + /// if the output value from the control module is greater than 0.9 + /// ( = 0.8 + 0.1). + void SetEdgeFalloff (double edgeFalloff); + + protected: + + /// Edge-falloff value. + double m_edgeFalloff; + + /// Lower bound of the selection range. + double m_lowerBound; + + /// Upper bound of the selection range. + double m_upperBound; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/spheres.cpp b/src/libnoise/src/module/spheres.cpp new file mode 100644 index 00000000000..4b625b6ff84 --- /dev/null +++ b/src/libnoise/src/module/spheres.cpp @@ -0,0 +1,45 @@ +// spheres.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../misc.h" +#include "spheres.h" + +using namespace noise::module; + +Spheres::Spheres (): + Module (GetSourceModuleCount ()), + m_frequency (DEFAULT_SPHERES_FREQUENCY) +{ +} + +double Spheres::GetValue (double x, double y, double z) const +{ + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + double distFromCenter = sqrt (x * x + y * y + z * z); + double distFromSmallerSphere = distFromCenter - floor (distFromCenter); + double distFromLargerSphere = 1.0 - distFromSmallerSphere; + double nearestDist = GetMin (distFromSmallerSphere, distFromLargerSphere); + return 1.0 - (nearestDist * 4.0); // Puts it in the -1.0 to +1.0 range. +} diff --git a/src/libnoise/src/module/spheres.h b/src/libnoise/src/module/spheres.h new file mode 100644 index 00000000000..059ac6c9e79 --- /dev/null +++ b/src/libnoise/src/module/spheres.h @@ -0,0 +1,127 @@ +// spheres.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_SPHERES_H +#define NOISE_MODULE_SPHERES_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup generatormodules + /// @{ + + /// Default frequency value for the noise::module::Spheres noise module. + const double DEFAULT_SPHERES_FREQUENCY = 1.0; + + /// Noise module that outputs concentric spheres. + /// + /// @image html modulespheres.png + /// + /// This noise module outputs concentric spheres centered on the origin + /// like the concentric rings of an onion. + /// + /// The first sphere has a radius of 1.0. Each subsequent sphere has a + /// radius that is 1.0 unit larger than the previous sphere. + /// + /// The output value from this noise module is determined by the distance + /// between the input value and the the nearest spherical surface. The + /// input values that are located on a spherical surface are given the + /// output value 1.0 and the input values that are equidistant from two + /// spherical surfaces are given the output value -1.0. + /// + /// An application can change the frequency of the concentric spheres. + /// Increasing the frequency reduces the distances between spheres. To + /// specify the frequency, call the SetFrequency() method. + /// + /// This noise module, modified with some low-frequency, low-power + /// turbulence, is useful for generating agate-like textures. + /// + /// This noise module does not require any source modules. + class Spheres: public Module + { + + public: + + /// Constructor. + /// + /// The default frequency is set to + /// noise::module::DEFAULT_SPHERES_FREQUENCY. + Spheres (); + + /// Returns the frequency of the concentric spheres. + /// + /// @returns The frequency of the concentric spheres. + /// + /// Increasing the frequency increases the density of the concentric + /// spheres, reducing the distances between them. + double GetFrequency () const + { + return m_frequency; + } + + virtual int GetSourceModuleCount () const + { + return 0; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the frequenct of the concentric spheres. + /// + /// @param frequency The frequency of the concentric spheres. + /// + /// Increasing the frequency increases the density of the concentric + /// spheres, reducing the distances between them. + void SetFrequency (double frequency) + { + m_frequency = frequency; + } + + protected: + + /// Frequency of the concentric spheres. + double m_frequency; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/terrace.cpp b/src/libnoise/src/module/terrace.cpp new file mode 100644 index 00000000000..cfecaab8055 --- /dev/null +++ b/src/libnoise/src/module/terrace.cpp @@ -0,0 +1,160 @@ +// terrace.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../interp.h" +#include "../misc.h" +#include "terrace.h" + +using namespace noise::module; + +using namespace noise; + +Terrace::Terrace (): + Module (GetSourceModuleCount ()), + m_controlPointCount (0), + m_invertTerraces (false), + m_pControlPoints (NULL) +{ +} + +Terrace::~Terrace () +{ + delete[] m_pControlPoints; +} + +void Terrace::AddControlPoint (double value) +{ + // Find the insertion point for the new control point and insert the new + // point at that position. The control point array will remain sorted by + // value. + int insertionPos = FindInsertionPos (value); + InsertAtPos (insertionPos, value); +} + +void Terrace::ClearAllControlPoints () +{ + delete[] m_pControlPoints; + m_pControlPoints = NULL; + m_controlPointCount = 0; +} + +int Terrace::FindInsertionPos (double value) +{ + int insertionPos; + for (insertionPos = 0; insertionPos < m_controlPointCount; insertionPos++) { + if (value < m_pControlPoints[insertionPos]) { + // We found the array index in which to insert the new control point. + // Exit now. + break; + } else if (value == m_pControlPoints[insertionPos]) { + // Each control point is required to contain a unique value, so throw + // an exception. + throw noise::ExceptionInvalidParam (); + } + } + return insertionPos; +} + +double Terrace::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + assert (m_controlPointCount >= 2); + + // Get the output value from the source module. + double sourceModuleValue = m_pSourceModule[0]->GetValue (x, y, z); + + // Find the first element in the control point array that has a value + // larger than the output value from the source module. + int indexPos; + for (indexPos = 0; indexPos < m_controlPointCount; indexPos++) { + if (sourceModuleValue < m_pControlPoints[indexPos]) { + break; + } + } + + // Find the two nearest control points so that we can map their values + // onto a quadratic curve. + int index0 = ClampValue (indexPos - 1, 0, m_controlPointCount - 1); + int index1 = ClampValue (indexPos , 0, m_controlPointCount - 1); + + // If some control points are missing (which occurs if the output value from + // the source module is greater than the largest value or less than the + // smallest value of the control point array), get the value of the nearest + // control point and exit now. + if (index0 == index1) { + return m_pControlPoints[index1]; + } + + // Compute the alpha value used for linear interpolation. + double value0 = m_pControlPoints[index0]; + double value1 = m_pControlPoints[index1]; + double alpha = (sourceModuleValue - value0) / (value1 - value0); + if (m_invertTerraces) { + alpha = 1.0 - alpha; + SwapValues (value0, value1); + } + + // Squaring the alpha produces the terrace effect. + alpha *= alpha; + + // Now perform the linear interpolation given the alpha value. + return LinearInterp (value0, value1, alpha); +} + +void Terrace::InsertAtPos (int insertionPos, double value) +{ + // Make room for the new control point at the specified position within + // the control point array. The position is determined by the value of + // the control point; the control points must be sorted by value within + // that array. + double* newControlPoints = new double[m_controlPointCount + 1]; + for (int i = 0; i < m_controlPointCount; i++) { + if (i < insertionPos) { + newControlPoints[i] = m_pControlPoints[i]; + } else { + newControlPoints[i + 1] = m_pControlPoints[i]; + } + } + delete[] m_pControlPoints; + m_pControlPoints = newControlPoints; + ++m_controlPointCount; + + // Now that we've made room for the new control point within the array, + // add the new control point. + m_pControlPoints[insertionPos] = value; +} + +void Terrace::MakeControlPoints (int controlPointCount) +{ + if (controlPointCount < 2) { + throw noise::ExceptionInvalidParam (); + } + + ClearAllControlPoints (); + + double terraceStep = 2.0 / ((double)controlPointCount - 1.0); + double curValue = -1.0; + for (int i = 0; i < (int)controlPointCount; i++) { + AddControlPoint (curValue); + curValue += terraceStep; + } +} diff --git a/src/libnoise/src/module/terrace.h b/src/libnoise/src/module/terrace.h new file mode 100644 index 00000000000..c1f665ab10b --- /dev/null +++ b/src/libnoise/src/module/terrace.h @@ -0,0 +1,242 @@ +// terrace.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_TERRACE_H +#define NOISE_MODULE_TERRACE_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup modifiermodules + /// @{ + + /// Noise module that maps the output value from a source module onto a + /// terrace-forming curve. + /// + /// @image html moduleterrace.png + /// + /// This noise module maps the output value from the source module onto a + /// terrace-forming curve. The start of this curve has a slope of zero; + /// its slope then smoothly increases. This curve also contains + /// control points which resets the slope to zero at that point, + /// producing a "terracing" effect. Refer to the following illustration: + /// + /// @image html terrace.png + /// + /// To add a control point to this noise module, call the + /// AddControlPoint() method. + /// + /// An application must add a minimum of two control points to the curve. + /// If this is not done, the GetValue() method fails. The control points + /// can have any value, although no two control points can have the same + /// value. There is no limit to the number of control points that can be + /// added to the curve. + /// + /// This noise module clamps the output value from the source module if + /// that value is less than the value of the lowest control point or + /// greater than the value of the highest control point. + /// + /// This noise module is often used to generate terrain features such as + /// your stereotypical desert canyon. + /// + /// This noise module requires one source module. + class Terrace: public Module + { + + public: + + /// Constructor. + Terrace (); + + /// Destructor. + ~Terrace (); + + /// Adds a control point to the terrace-forming curve. + /// + /// @param value The value of the control point to add. + /// + /// @pre No two control points have the same value. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// Two or more control points define the terrace-forming curve. The + /// start of this curve has a slope of zero; its slope then smoothly + /// increases. At the control points, its slope resets to zero. + /// + /// It does not matter which order these points are added. + void AddControlPoint (double value); + + /// Deletes all the control points on the terrace-forming curve. + /// + /// @post All control points on the terrace-forming curve are deleted. + void ClearAllControlPoints (); + + /// Returns a pointer to the array of control points on the + /// terrace-forming curve. + /// + /// @returns A pointer to the array of control points in this noise + /// module. + /// + /// Two or more control points define the terrace-forming curve. The + /// start of this curve has a slope of zero; its slope then smoothly + /// increases. At the control points, its slope resets to zero. + /// + /// Before calling this method, call GetControlPointCount() to + /// determine the number of control points in this array. + /// + /// It is recommended that an application does not store this pointer + /// for later use since the pointer to the array may change if the + /// application calls another method of this object. + const double* GetControlPointArray () const + { + return m_pControlPoints; + } + + /// Returns the number of control points on the terrace-forming curve. + /// + /// @returns The number of control points on the terrace-forming + /// curve. + int GetControlPointCount () const + { + return m_controlPointCount; + } + + virtual int GetSourceModuleCount () const + { + return 1; + } + + /// Enables or disables the inversion of the terrace-forming curve + /// between the control points. + /// + /// @param invert Specifies whether to invert the curve between the + /// control points. + void InvertTerraces (bool invert = true) + { + m_invertTerraces = invert; + } + + /// Determines if the terrace-forming curve between the control + /// points is inverted. + /// + /// @returns + /// - @a true if the curve between the control points is inverted. + /// - @a false if the curve between the control points is not + /// inverted. + bool IsTerracesInverted () const + { + return m_invertTerraces; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Creates a number of equally-spaced control points that range from + /// -1 to +1. + /// + /// @param controlPointCount The number of control points to generate. + /// + /// @pre The number of control points must be greater than or equal to + /// 2. + /// + /// @post The previous control points on the terrace-forming curve are + /// deleted. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// Two or more control points define the terrace-forming curve. The + /// start of this curve has a slope of zero; its slope then smoothly + /// increases. At the control points, its slope resets to zero. + void MakeControlPoints (int controlPointCount); + + protected: + + /// Determines the array index in which to insert the control point + /// into the internal control point array. + /// + /// @param value The value of the control point. + /// + /// @returns The array index in which to insert the control point. + /// + /// @pre No two control points have the same value. + /// + /// @throw noise::ExceptionInvalidParam An invalid parameter was + /// specified; see the preconditions for more information. + /// + /// By inserting the control point at the returned array index, this + /// class ensures that the control point array is sorted by value. + /// The code that maps a value onto the curve requires a sorted + /// control point array. + int FindInsertionPos (double value); + + /// Inserts the control point at the specified position in the + /// internal control point array. + /// + /// @param insertionPos The zero-based array position in which to + /// insert the control point. + /// @param value The value of the control point. + /// + /// To make room for this new control point, this method reallocates + /// the control point array and shifts all control points occurring + /// after the insertion position up by one. + /// + /// Because the curve mapping algorithm in this noise module requires + /// that all control points in the array be sorted by value, the new + /// control point should be inserted at the position in which the + /// order is still preserved. + void InsertAtPos (int insertionPos, double value); + + /// Number of control points stored in this noise module. + int m_controlPointCount; + + /// Determines if the terrace-forming curve between all control points + /// is inverted. + bool m_invertTerraces; + + /// Array that stores the control points. + double* m_pControlPoints; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/translatepoint.cpp b/src/libnoise/src/module/translatepoint.cpp new file mode 100644 index 00000000000..eecdf84ac40 --- /dev/null +++ b/src/libnoise/src/module/translatepoint.cpp @@ -0,0 +1,41 @@ +// translatepoint.cpp +// +// Copyright (C) 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "translatepoint.h" + +using namespace noise::module; + +TranslatePoint::TranslatePoint (): + Module (GetSourceModuleCount ()), + m_xTranslation (DEFAULT_TRANSLATE_POINT_X), + m_yTranslation (DEFAULT_TRANSLATE_POINT_Y), + m_zTranslation (DEFAULT_TRANSLATE_POINT_Z) +{ +} + +double TranslatePoint::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + return m_pSourceModule[0]->GetValue (x + m_xTranslation, y + m_yTranslation, + z + m_zTranslation); +} diff --git a/src/libnoise/src/module/translatepoint.h b/src/libnoise/src/module/translatepoint.h new file mode 100644 index 00000000000..46adac42cb3 --- /dev/null +++ b/src/libnoise/src/module/translatepoint.h @@ -0,0 +1,223 @@ +// translatepoint.h +// +// Copyright (C) 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_TRANSLATEPOINT_H +#define NOISE_MODULE_TRANSLATEPOINT_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup transformermodules + /// @{ + + /// Default translation factor applied to the @a x coordinate for the + /// noise::module::TranslatePoint noise module. + const double DEFAULT_TRANSLATE_POINT_X = 0.0; + + /// Default translation factor applied to the @a y coordinate for the + /// noise::module::TranslatePoint noise module. + const double DEFAULT_TRANSLATE_POINT_Y = 0.0; + + /// Default translation factor applied to the @a z coordinate for the + /// noise::module::TranslatePoint noise module. + const double DEFAULT_TRANSLATE_POINT_Z = 0.0; + + /// Noise module that moves the coordinates of the input value before + /// returning the output value from a source module. + /// + /// @image html moduletranslatepoint.png + /// + /// The GetValue() method moves the ( @a x, @a y, @a z ) coordinates of + /// the input value by a translation amount before returning the output + /// value from the source module. To set the translation amount, call + /// the SetTranslation() method. To set the translation amount to + /// apply to the individual @a x, @a y, or @a z coordinates, call the + /// SetXTranslation(), SetYTranslation() or SetZTranslation() methods, + /// respectively. + /// + /// This noise module requires one source module. + class TranslatePoint: public Module + { + + public: + + /// Constructor. + /// + /// The default translation amount to apply to the @a x coordinate is + /// set to noise::module::DEFAULT_TRANSLATE_POINT_X. + /// + /// The default translation amount to apply to the @a y coordinate is + /// set to noise::module::DEFAULT_TRANSLATE_POINT_Y. + /// + /// The default translation amount to apply to the @a z coordinate is + /// set to noise::module::DEFAULT_TRANSLATE_POINT_Z. + TranslatePoint (); + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Returns the translation amount to apply to the @a x coordinate of + /// the input value. + /// + /// @returns The translation amount to apply to the @a x coordinate. + double GetXTranslation () const + { + return m_xTranslation; + } + + /// Returns the translation amount to apply to the @a y coordinate of + /// the input value. + /// + /// @returns The translation amount to apply to the @a y coordinate. + double GetYTranslation () const + { + return m_yTranslation; + } + + /// Returns the translation amount to apply to the @a z coordinate of + /// the input value. + /// + /// @returns The translation amount to apply to the @a z coordinate. + double GetZTranslation () const + { + return m_zTranslation; + } + + /// Sets the translation amount to apply to the input value. + /// + /// @param translation The translation amount to apply. + /// + /// The GetValue() method moves the ( @a x, @a y, @a z ) coordinates + /// of the input value by a translation amount before returning the + /// output value from the source module + void SetTranslation (double translation) + { + m_xTranslation = translation; + m_yTranslation = translation; + m_zTranslation = translation; + } + + /// Sets the translation amounts to apply to the ( @a x, @a y, @a z ) + /// coordinates of the input value. + /// + /// @param xTranslation The translation amount to apply to the @a x + /// coordinate. + /// @param yTranslation The translation amount to apply to the @a y + /// coordinate. + /// @param zTranslation The translation amount to apply to the @a z + /// coordinate. + /// + /// The GetValue() method moves the ( @a x, @a y, @a z ) coordinates + /// of the input value by a translation amount before returning the + /// output value from the source module + void SetTranslation (double xTranslation, double yTranslation, + double zTranslation) + { + m_xTranslation = xTranslation; + m_yTranslation = yTranslation; + m_zTranslation = zTranslation; + } + + /// Sets the translation amount to apply to the @a x coordinate of the + /// input value. + /// + /// @param xTranslation The translation amount to apply to the @a x + /// coordinate. + /// + /// The GetValue() method moves the ( @a x, @a y, @a z ) coordinates + /// of the input value by a translation amount before returning the + /// output value from the source module + void SetXTranslation (double xTranslation) + { + m_xTranslation = xTranslation; + } + + /// Sets the translation amount to apply to the @a y coordinate of the + /// input value. + /// + /// @param yTranslation The translation amount to apply to the @a y + /// coordinate. + /// + /// The GetValue() method moves the ( @a x, @a y, @a z ) coordinates + /// of the input value by a translation amount before returning the + /// output value from the source module + void SetYTranslation (double yTranslation) + { + m_yTranslation = yTranslation; + } + + /// Sets the translation amount to apply to the @a z coordinate of the + /// input value. + /// + /// @param zTranslation The translation amount to apply to the @a z + /// coordinate. + /// + /// The GetValue() method moves the ( @a x, @a y, @a z ) coordinates + /// of the input value by a translation amount before returning the + /// output value from the source module + void SetZTranslation (double zTranslation) + { + m_zTranslation = zTranslation; + } + + protected: + + /// Translation amount applied to the @a x coordinate of the input + /// value. + double m_xTranslation; + + /// Translation amount applied to the @a y coordinate of the input + /// value. + double m_yTranslation; + + /// Translation amount applied to the @a z coordinate of the input + /// value. + double m_zTranslation; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/turbulence.cpp b/src/libnoise/src/module/turbulence.cpp new file mode 100644 index 00000000000..82a3ed94e2e --- /dev/null +++ b/src/libnoise/src/module/turbulence.cpp @@ -0,0 +1,91 @@ +// turbulence.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "turbulence.h" + +using namespace noise::module; + +Turbulence::Turbulence (): + Module (GetSourceModuleCount ()), + m_power (DEFAULT_TURBULENCE_POWER) +{ + SetSeed (DEFAULT_TURBULENCE_SEED); + SetFrequency (DEFAULT_TURBULENCE_FREQUENCY); + SetRoughness (DEFAULT_TURBULENCE_ROUGHNESS); +} + +double Turbulence::GetFrequency () const +{ + // Since each noise::module::Perlin noise module has the same frequency, it + // does not matter which module we use to retrieve the frequency. + return m_xDistortModule.GetFrequency (); +} + +int Turbulence::GetSeed () const +{ + return m_xDistortModule.GetSeed (); +} + +double Turbulence::GetValue (double x, double y, double z) const +{ + assert (m_pSourceModule[0] != NULL); + + // Get the values from the three noise::module::Perlin noise modules and + // add each value to each coordinate of the input value. There are also + // some offsets added to the coordinates of the input values. This prevents + // the distortion modules from returning zero if the (x, y, z) coordinates, + // when multiplied by the frequency, are near an integer boundary. This is + // due to a property of gradient coherent noise, which returns zero at + // integer boundaries. + double x0, y0, z0; + double x1, y1, z1; + double x2, y2, z2; + x0 = x + (12414.0 / 65536.0); + y0 = y + (65124.0 / 65536.0); + z0 = z + (31337.0 / 65536.0); + x1 = x + (26519.0 / 65536.0); + y1 = y + (18128.0 / 65536.0); + z1 = z + (60493.0 / 65536.0); + x2 = x + (53820.0 / 65536.0); + y2 = y + (11213.0 / 65536.0); + z2 = z + (44845.0 / 65536.0); + double xDistort = x + (m_xDistortModule.GetValue (x0, y0, z0) + * m_power); + double yDistort = y + (m_yDistortModule.GetValue (x1, y1, z1) + * m_power); + double zDistort = z + (m_zDistortModule.GetValue (x2, y2, z2) + * m_power); + + // Retrieve the output value at the offsetted input value instead of the + // original input value. + return m_pSourceModule[0]->GetValue (xDistort, yDistort, zDistort); +} + +void Turbulence::SetSeed (int seed) +{ + // Set the seed of each noise::module::Perlin noise modules. To prevent any + // sort of weird artifacting, use a slightly different seed for each noise + // module. + m_xDistortModule.SetSeed (seed ); + m_yDistortModule.SetSeed (seed + 1); + m_zDistortModule.SetSeed (seed + 2); +} diff --git a/src/libnoise/src/module/turbulence.h b/src/libnoise/src/module/turbulence.h new file mode 100644 index 00000000000..1561561a0eb --- /dev/null +++ b/src/libnoise/src/module/turbulence.h @@ -0,0 +1,269 @@ +// turbulence.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_TURBULENCE_H +#define NOISE_MODULE_TURBULENCE_H + +#include "perlin.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup transformermodules + /// @{ + + /// Default frequency for the noise::module::Turbulence noise module. + const double DEFAULT_TURBULENCE_FREQUENCY = DEFAULT_PERLIN_FREQUENCY; + + /// Default power for the noise::module::Turbulence noise module. + const double DEFAULT_TURBULENCE_POWER = 1.0; + + /// Default roughness for the noise::module::Turbulence noise module. + const int DEFAULT_TURBULENCE_ROUGHNESS = 3; + + /// Default noise seed for the noise::module::Turbulence noise module. + const int DEFAULT_TURBULENCE_SEED = DEFAULT_PERLIN_SEED; + + /// Noise module that randomly displaces the input value before + /// returning the output value from a source module. + /// + /// @image html moduleturbulence.png + /// + /// @a Turbulence is the pseudo-random displacement of the input value. + /// The GetValue() method randomly displaces the ( @a x, @a y, @a z ) + /// coordinates of the input value before retrieving the output value from + /// the source module. To control the turbulence, an application can + /// modify its frequency, its power, and its roughness. + /// + /// The frequency of the turbulence determines how rapidly the + /// displacement amount changes. To specify the frequency, call the + /// SetFrequency() method. + /// + /// The power of the turbulence determines the scaling factor that is + /// applied to the displacement amount. To specify the power, call the + /// SetPower() method. + /// + /// The roughness of the turbulence determines the roughness of the + /// changes to the displacement amount. Low values smoothly change the + /// displacement amount. High values roughly change the displacement + /// amount, which produces more "kinky" changes. To specify the + /// roughness, call the SetRoughness() method. + /// + /// Use of this noise module may require some trial and error. Assuming + /// that you are using a generator module as the source module, you + /// should first: + /// - Set the frequency to the same frequency as the source module. + /// - Set the power to the reciprocal of the frequency. + /// + /// From these initial frequency and power values, modify these values + /// until this noise module produce the desired changes in your terrain or + /// texture. For example: + /// - Low frequency (1/8 initial frequency) and low power (1/8 initial + /// power) produces very minor, almost unnoticeable changes. + /// - Low frequency (1/8 initial frequency) and high power (8 times + /// initial power) produces "ropey" lava-like terrain or marble-like + /// textures. + /// - High frequency (8 times initial frequency) and low power (1/8 + /// initial power) produces a noisy version of the initial terrain or + /// texture. + /// - High frequency (8 times initial frequency) and high power (8 times + /// initial power) produces nearly pure noise, which isn't entirely + /// useful. + /// + /// Displacing the input values result in more realistic terrain and + /// textures. If you are generating elevations for terrain height maps, + /// you can use this noise module to produce more realistic mountain + /// ranges or terrain features that look like flowing lava rock. If you + /// are generating values for textures, you can use this noise module to + /// produce realistic marble-like or "oily" textures. + /// + /// Internally, there are three noise::module::Perlin noise modules + /// that displace the input value; one for the @a x, one for the @a y, + /// and one for the @a z coordinate. + /// + /// This noise module requires one source module. + class Turbulence: public Module + { + + public: + + /// Constructor. + /// + /// The default frequency is set to + /// noise::module::DEFAULT_TURBULENCE_FREQUENCY. + /// + /// The default power is set to + /// noise::module::DEFAULT_TURBULENCE_POWER. + /// + /// The default roughness is set to + /// noise::module::DEFAULT_TURBULENCE_ROUGHNESS. + /// + /// The default seed value is set to + /// noise::module::DEFAULT_TURBULENCE_SEED. + Turbulence (); + + /// Returns the frequency of the turbulence. + /// + /// @returns The frequency of the turbulence. + /// + /// The frequency of the turbulence determines how rapidly the + /// displacement amount changes. + double GetFrequency () const; + + /// Returns the power of the turbulence. + /// + /// @returns The power of the turbulence. + /// + /// The power of the turbulence determines the scaling factor that is + /// applied to the displacement amount. + double GetPower () const + { + return m_power; + } + + /// Returns the roughness of the turbulence. + /// + /// @returns The roughness of the turbulence. + /// + /// The roughness of the turbulence determines the roughness of the + /// changes to the displacement amount. Low values smoothly change + /// the displacement amount. High values roughly change the + /// displacement amount, which produces more "kinky" changes. + int GetRoughnessCount () const + { + return m_xDistortModule.GetOctaveCount (); + } + + /// Returns the seed value of the internal Perlin-noise modules that + /// are used to displace the input values. + /// + /// @returns The seed value. + /// + /// Internally, there are three noise::module::Perlin noise modules + /// that displace the input value; one for the @a x, one for the @a y, + /// and one for the @a z coordinate. + int GetSeed () const; + + virtual int GetSourceModuleCount () const + { + return 1; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the frequency of the turbulence. + /// + /// @param frequency The frequency of the turbulence. + /// + /// The frequency of the turbulence determines how rapidly the + /// displacement amount changes. + void SetFrequency (double frequency) + { + // Set the frequency of each Perlin-noise module. + m_xDistortModule.SetFrequency (frequency); + m_yDistortModule.SetFrequency (frequency); + m_zDistortModule.SetFrequency (frequency); + } + + /// Sets the power of the turbulence. + /// + /// @param power The power of the turbulence. + /// + /// The power of the turbulence determines the scaling factor that is + /// applied to the displacement amount. + void SetPower (double power) + { + m_power = power; + } + + /// Sets the roughness of the turbulence. + /// + /// @param roughness The roughness of the turbulence. + /// + /// The roughness of the turbulence determines the roughness of the + /// changes to the displacement amount. Low values smoothly change + /// the displacement amount. High values roughly change the + /// displacement amount, which produces more "kinky" changes. + /// + /// Internally, there are three noise::module::Perlin noise modules + /// that displace the input value; one for the @a x, one for the @a y, + /// and one for the @a z coordinate. The roughness value is equal to + /// the number of octaves used by the noise::module::Perlin noise + /// modules. + void SetRoughness (int roughness) + { + // Set the octave count for each Perlin-noise module. + m_xDistortModule.SetOctaveCount (roughness); + m_yDistortModule.SetOctaveCount (roughness); + m_zDistortModule.SetOctaveCount (roughness); + } + + /// Sets the seed value of the internal noise modules that are used to + /// displace the input values. + /// + /// @param seed The seed value. + /// + /// Internally, there are three noise::module::Perlin noise modules + /// that displace the input value; one for the @a x, one for the @a y, + /// and one for the @a z coordinate. This noise module assigns the + /// following seed values to the noise::module::Perlin noise modules: + /// - It assigns the seed value (@a seed + 0) to the @a x noise module. + /// - It assigns the seed value (@a seed + 1) to the @a y noise module. + /// - It assigns the seed value (@a seed + 2) to the @a z noise module. + void SetSeed (int seed); + + protected: + + /// The power (scale) of the displacement. + double m_power; + + /// Noise module that displaces the @a x coordinate. + Perlin m_xDistortModule; + + /// Noise module that displaces the @a y coordinate. + Perlin m_yDistortModule; + + /// Noise module that displaces the @a z coordinate. + Perlin m_zDistortModule; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/module/voronoi.cpp b/src/libnoise/src/module/voronoi.cpp new file mode 100644 index 00000000000..759e2a93c9b --- /dev/null +++ b/src/libnoise/src/module/voronoi.cpp @@ -0,0 +1,101 @@ +// voronoi.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "../mathconsts.h" +#include "voronoi.h" + +using namespace noise::module; + +Voronoi::Voronoi (): + Module (GetSourceModuleCount ()), + m_displacement (DEFAULT_VORONOI_DISPLACEMENT), + m_enableDistance (false ), + m_frequency (DEFAULT_VORONOI_FREQUENCY ), + m_seed (DEFAULT_VORONOI_SEED ) +{ +} + +double Voronoi::GetValue (double x, double y, double z) const +{ + // This method could be more efficient by caching the seed values. Fix + // later. + + x *= m_frequency; + y *= m_frequency; + z *= m_frequency; + + int xInt = (x > 0.0? (int)x: (int)x - 1); + int yInt = (y > 0.0? (int)y: (int)y - 1); + int zInt = (z > 0.0? (int)z: (int)z - 1); + + double minDist = 2147483647.0; + double xCandidate = 0; + double yCandidate = 0; + double zCandidate = 0; + + // Inside each unit cube, there is a seed point at a random position. Go + // through each of the nearby cubes until we find a cube with a seed point + // that is closest to the specified position. + for (int zCur = zInt - 2; zCur <= zInt + 2; zCur++) { + for (int yCur = yInt - 2; yCur <= yInt + 2; yCur++) { + for (int xCur = xInt - 2; xCur <= xInt + 2; xCur++) { + + // Calculate the position and distance to the seed point inside of + // this unit cube. + double xPos = xCur + ValueNoise3D (xCur, yCur, zCur, m_seed ); + double yPos = yCur + ValueNoise3D (xCur, yCur, zCur, m_seed + 1); + double zPos = zCur + ValueNoise3D (xCur, yCur, zCur, m_seed + 2); + double xDist = xPos - x; + double yDist = yPos - y; + double zDist = zPos - z; + double dist = xDist * xDist + yDist * yDist + zDist * zDist; + + if (dist < minDist) { + // This seed point is closer to any others found so far, so record + // this seed point. + minDist = dist; + xCandidate = xPos; + yCandidate = yPos; + zCandidate = zPos; + } + } + } + } + + double value; + if (m_enableDistance) { + // Determine the distance to the nearest seed point. + double xDist = xCandidate - x; + double yDist = yCandidate - y; + double zDist = zCandidate - z; + value = (sqrt (xDist * xDist + yDist * yDist + zDist * zDist) + ) * SQRT_3 - 1.0; + } else { + value = 0.0; + } + + // Return the calculated distance with the displacement value applied. + return value + (m_displacement * (double)ValueNoise3D ( + (int)(floor (xCandidate)), + (int)(floor (yCandidate)), + (int)(floor (zCandidate)))); +} diff --git a/src/libnoise/src/module/voronoi.h b/src/libnoise/src/module/voronoi.h new file mode 100644 index 00000000000..16a8783bbfa --- /dev/null +++ b/src/libnoise/src/module/voronoi.h @@ -0,0 +1,246 @@ +// voronoi.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_MODULE_VORONOI_H +#define NOISE_MODULE_VORONOI_H + +#include "modulebase.h" + +namespace noise +{ + + namespace module + { + + /// @addtogroup libnoise + /// @{ + + /// @addtogroup modules + /// @{ + + /// @addtogroup generatormodules + /// @{ + + /// Default displacement to apply to each cell for the + /// noise::module::Voronoi noise module. + const double DEFAULT_VORONOI_DISPLACEMENT = 1.0; + + /// Default frequency of the seed points for the noise::module::Voronoi + /// noise module. + const double DEFAULT_VORONOI_FREQUENCY = 1.0; + + /// Default seed of the noise function for the noise::module::Voronoi + /// noise module. + const int DEFAULT_VORONOI_SEED = 0; + + /// Noise module that outputs Voronoi cells. + /// + /// @image html modulevoronoi.png + /// + /// In mathematics, a Voronoi cell is a region containing all the + /// points that are closer to a specific seed point than to any + /// other seed point. These cells mesh with one another, producing + /// polygon-like formations. + /// + /// By default, this noise module randomly places a seed point within + /// each unit cube. By modifying the frequency of the seed points, + /// an application can change the distance between seed points. The + /// higher the frequency, the closer together this noise module places + /// the seed points, which reduces the size of the cells. To specify the + /// frequency of the cells, call the SetFrequency() method. + /// + /// This noise module assigns each Voronoi cell with a random constant + /// value from a coherent-noise function. The displacement value + /// controls the range of random values to assign to each cell. The + /// range of random values is +/- the displacement value. Call the + /// SetDisplacement() method to specify the displacement value. + /// + /// To modify the random positions of the seed points, call the SetSeed() + /// method. + /// + /// This noise module can optionally add the distance from the nearest + /// seed to the output value. To enable this feature, call the + /// EnableDistance() method. This causes the points in the Voronoi cells + /// to increase in value the further away that point is from the nearest + /// seed point. + /// + /// Voronoi cells are often used to generate cracked-mud terrain + /// formations or crystal-like textures + /// + /// This noise module requires no source modules. + class Voronoi: public Module + { + + public: + + /// Constructor. + /// + /// The default displacement value is set to + /// noise::module::DEFAULT_VORONOI_DISPLACEMENT. + /// + /// The default frequency is set to + /// noise::module::DEFAULT_VORONOI_FREQUENCY. + /// + /// The default seed value is set to + /// noise::module::DEFAULT_VORONOI_SEED. + Voronoi (); + + /// Enables or disables applying the distance from the nearest seed + /// point to the output value. + /// + /// @param enable Specifies whether to apply the distance to the + /// output value or not. + /// + /// Applying the distance from the nearest seed point to the output + /// value causes the points in the Voronoi cells to increase in value + /// the further away that point is from the nearest seed point. + /// Setting this value to @a true (and setting the displacement to a + /// near-zero value) causes this noise module to generate cracked mud + /// formations. + void EnableDistance (bool enable = true) + { + m_enableDistance = enable; + } + + /// Returns the displacement value of the Voronoi cells. + /// + /// @returns The displacement value of the Voronoi cells. + /// + /// This noise module assigns each Voronoi cell with a random constant + /// value from a coherent-noise function. The displacement + /// value controls the range of random values to assign to each + /// cell. The range of random values is +/- the displacement value. + double GetDisplacement () const + { + return m_displacement; + } + + /// Returns the frequency of the seed points. + /// + /// @returns The frequency of the seed points. + /// + /// The frequency determines the size of the Voronoi cells and the + /// distance between these cells. + double GetFrequency () const + { + return m_frequency; + } + + virtual int GetSourceModuleCount () const + { + return 0; + } + + /// Returns the seed value used by the Voronoi cells + /// + /// @returns The seed value. + /// + /// The positions of the seed values are calculated by a + /// coherent-noise function. By modifying the seed value, the output + /// of that function changes. + int GetSeed () const + { + return m_seed; + } + + /// Determines if the distance from the nearest seed point is applied + /// to the output value. + /// + /// @returns + /// - @a true if the distance is applied to the output value. + /// - @a false if not. + /// + /// Applying the distance from the nearest seed point to the output + /// value causes the points in the Voronoi cells to increase in value + /// the further away that point is from the nearest seed point. + bool IsDistanceEnabled () const + { + return m_enableDistance; + } + + virtual double GetValue (double x, double y, double z) const; + + /// Sets the displacement value of the Voronoi cells. + /// + /// @param displacement The displacement value of the Voronoi cells. + /// + /// This noise module assigns each Voronoi cell with a random constant + /// value from a coherent-noise function. The displacement + /// value controls the range of random values to assign to each + /// cell. The range of random values is +/- the displacement value. + void SetDisplacement (double displacement) + { + m_displacement = displacement; + } + + /// Sets the frequency of the seed points. + /// + /// @param frequency The frequency of the seed points. + /// + /// The frequency determines the size of the Voronoi cells and the + /// distance between these cells. + void SetFrequency (double frequency) + { + m_frequency = frequency; + } + + /// Sets the seed value used by the Voronoi cells + /// + /// @param seed The seed value. + /// + /// The positions of the seed values are calculated by a + /// coherent-noise function. By modifying the seed value, the output + /// of that function changes. + void SetSeed (int seed) + { + m_seed = seed; + } + + protected: + + /// Scale of the random displacement to apply to each Voronoi cell. + double m_displacement; + + /// Determines if the distance from the nearest seed point is applied to + /// the output value. + bool m_enableDistance; + + /// Frequency of the seed points. + double m_frequency; + + /// Seed value used by the coherent-noise function to determine the + /// positions of the seed points. + int m_seed; + + }; + + /// @} + + /// @} + + /// @} + + } + +} + +#endif diff --git a/src/libnoise/src/noise.h b/src/libnoise/src/noise.h new file mode 100644 index 00000000000..39aa75f762b --- /dev/null +++ b/src/libnoise/src/noise.h @@ -0,0 +1,74 @@ +// noise.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_H +#define NOISE_H + +/// @mainpage libnoise +/// +/// @section intro Introduction +/// +/// libnoise is a portable C++ library that is used to generate coherent +/// noise, a type of smoothly-changing noise. libnoise can generate Perlin +/// noise, ridged multifractal noise, and other types of coherent noise. +/// +/// Coherent noise is often used by graphics programmers to generate +/// natural-looking textures, planetary terrain, and other things. It can +/// also be used to move critters in a realistic way. +/// +/// libnoise is known to compile using the following compilers on the +/// following platforms: +/// - Microsoft Visual C++ 5.0 under Microsoft Windows 2000 Service Pack 4 +/// - gcc 3.3.4 under Gentoo Linux 10.0 (x86) +/// +/// It is not known if libnoise will compile on 64-bit platforms, although +/// there is a good change that it will. +/// +/// @section noise Noise Modules +/// +/// In libnoise, coherent-noise generators are encapsulated in classes called +/// noise modules. There are many different types of noise modules. +/// Some noise modules can combine or modify the outputs of other noise +/// modules in various ways; you can join these modules together to generate +/// very complex coherent noise. +/// +/// A noise module receives a 3-dimensional input value from the application, +/// computes the noise value given that input value, and returns the resulting +/// value back to the application. +/// +/// If the application passes the same input value to a noise module, the +/// noise module returns the same output value. +/// +/// All noise modules are derived from the noise::module::Module abstract +/// base class. +/// +/// @section contact Contact +/// +/// Contact jas for questions about libnoise. The spam-resistant email +/// address is jlbezigvins@gmzigail.com (For great email, take off every +/// zig.) + +#include "module/module.h" +#include "model/model.h" +#include "misc.h" + +#endif diff --git a/src/libnoise/src/noisegen.cpp b/src/libnoise/src/noisegen.cpp new file mode 100644 index 00000000000..fa9250b90fc --- /dev/null +++ b/src/libnoise/src/noisegen.cpp @@ -0,0 +1,220 @@ +// noisegen.cpp +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include "noisegen.h" +#include "interp.h" +#include "vectortable.h" + +using namespace noise; + +// Specifies the version of the coherent-noise functions to use. +// - Set to 2 to use the current version. +// - Set to 1 to use the flawed version from the original version of libnoise. +// If your application requires coherent-noise values that were generated by +// an earlier version of libnoise, change this constant to the appropriate +// value and recompile libnoise. +#define NOISE_VERSION 2 + +// These constants control certain parameters that all coherent-noise +// functions require. +#if (NOISE_VERSION == 1) +// Constants used by the original version of libnoise. +// Because X_NOISE_GEN is not relatively prime to the other values, and +// Z_NOISE_GEN is close to 256 (the number of random gradient vectors), +// patterns show up in high-frequency coherent noise. +const int X_NOISE_GEN = 1; +const int Y_NOISE_GEN = 31337; +const int Z_NOISE_GEN = 263; +const int SEED_NOISE_GEN = 1013; +const int SHIFT_NOISE_GEN = 13; +#else +// Constants used by the current version of libnoise. +const int X_NOISE_GEN = 1619; +const int Y_NOISE_GEN = 31337; +const int Z_NOISE_GEN = 6971; +const int SEED_NOISE_GEN = 1013; +const int SHIFT_NOISE_GEN = 8; +#endif + +double noise::GradientCoherentNoise3D (double x, double y, double z, int seed, + NoiseQuality noiseQuality) +{ + // Create a unit-length cube aligned along an integer boundary. This cube + // surrounds the input point. + int x0 = (x > 0.0? (int)x: (int)x - 1); + int x1 = x0 + 1; + int y0 = (y > 0.0? (int)y: (int)y - 1); + int y1 = y0 + 1; + int z0 = (z > 0.0? (int)z: (int)z - 1); + int z1 = z0 + 1; + + // Map the difference between the coordinates of the input value and the + // coordinates of the cube's outer-lower-left vertex onto an S-curve. + double xs = 0, ys = 0, zs = 0; + switch (noiseQuality) { + case QUALITY_FAST: + xs = (x - (double)x0); + ys = (y - (double)y0); + zs = (z - (double)z0); + break; + case QUALITY_STD: + xs = SCurve3 (x - (double)x0); + ys = SCurve3 (y - (double)y0); + zs = SCurve3 (z - (double)z0); + break; + case QUALITY_BEST: + xs = SCurve5 (x - (double)x0); + ys = SCurve5 (y - (double)y0); + zs = SCurve5 (z - (double)z0); + break; + } + + // Now calculate the noise values at each vertex of the cube. To generate + // the coherent-noise value at the input point, interpolate these eight + // noise values using the S-curve value as the interpolant (trilinear + // interpolation.) + double n0, n1, ix0, ix1, iy0, iy1; + n0 = GradientNoise3D (x, y, z, x0, y0, z0, seed); + n1 = GradientNoise3D (x, y, z, x1, y0, z0, seed); + ix0 = LinearInterp (n0, n1, xs); + n0 = GradientNoise3D (x, y, z, x0, y1, z0, seed); + n1 = GradientNoise3D (x, y, z, x1, y1, z0, seed); + ix1 = LinearInterp (n0, n1, xs); + iy0 = LinearInterp (ix0, ix1, ys); + n0 = GradientNoise3D (x, y, z, x0, y0, z1, seed); + n1 = GradientNoise3D (x, y, z, x1, y0, z1, seed); + ix0 = LinearInterp (n0, n1, xs); + n0 = GradientNoise3D (x, y, z, x0, y1, z1, seed); + n1 = GradientNoise3D (x, y, z, x1, y1, z1, seed); + ix1 = LinearInterp (n0, n1, xs); + iy1 = LinearInterp (ix0, ix1, ys); + + return LinearInterp (iy0, iy1, zs); +} + +double noise::GradientNoise3D (double fx, double fy, double fz, int ix, + int iy, int iz, int seed) +{ + // Randomly generate a gradient vector given the integer coordinates of the + // input value. This implementation generates a random number and uses it + // as an index into a normalized-vector lookup table. + int vectorIndex = ( + X_NOISE_GEN * ix + + Y_NOISE_GEN * iy + + Z_NOISE_GEN * iz + + SEED_NOISE_GEN * seed) + & 0xffffffff; + vectorIndex ^= (vectorIndex >> SHIFT_NOISE_GEN); + vectorIndex &= 0xff; + + double xvGradient = g_randomVectors[(vectorIndex << 2) ]; + double yvGradient = g_randomVectors[(vectorIndex << 2) + 1]; + double zvGradient = g_randomVectors[(vectorIndex << 2) + 2]; + + // Set up us another vector equal to the distance between the two vectors + // passed to this function. + double xvPoint = (fx - (double)ix); + double yvPoint = (fy - (double)iy); + double zvPoint = (fz - (double)iz); + + // Now compute the dot product of the gradient vector with the distance + // vector. The resulting value is gradient noise. Apply a scaling value + // so that this noise value ranges from -1.0 to 1.0. + return ((xvGradient * xvPoint) + + (yvGradient * yvPoint) + + (zvGradient * zvPoint)) * 2.12; +} + +int noise::IntValueNoise3D (int x, int y, int z, int seed) +{ + // All constants are primes and must remain prime in order for this noise + // function to work correctly. + int n = ( + X_NOISE_GEN * x + + Y_NOISE_GEN * y + + Z_NOISE_GEN * z + + SEED_NOISE_GEN * seed) + & 0x7fffffff; + n = (n >> 13) ^ n; + return (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; +} + +double noise::ValueCoherentNoise3D (double x, double y, double z, int seed, + NoiseQuality noiseQuality) +{ + // Create a unit-length cube aligned along an integer boundary. This cube + // surrounds the input point. + int x0 = (x > 0.0? (int)x: (int)x - 1); + int x1 = x0 + 1; + int y0 = (y > 0.0? (int)y: (int)y - 1); + int y1 = y0 + 1; + int z0 = (z > 0.0? (int)z: (int)z - 1); + int z1 = z0 + 1; + + // Map the difference between the coordinates of the input value and the + // coordinates of the cube's outer-lower-left vertex onto an S-curve. + double xs = 0, ys = 0, zs = 0; + switch (noiseQuality) { + case QUALITY_FAST: + xs = (x - (double)x0); + ys = (y - (double)y0); + zs = (z - (double)z0); + break; + case QUALITY_STD: + xs = SCurve3 (x - (double)x0); + ys = SCurve3 (y - (double)y0); + zs = SCurve3 (z - (double)z0); + break; + case QUALITY_BEST: + xs = SCurve5 (x - (double)x0); + ys = SCurve5 (y - (double)y0); + zs = SCurve5 (z - (double)z0); + break; + } + + // Now calculate the noise values at each vertex of the cube. To generate + // the coherent-noise value at the input point, interpolate these eight + // noise values using the S-curve value as the interpolant (trilinear + // interpolation.) + double n0, n1, ix0, ix1, iy0, iy1; + n0 = ValueNoise3D (x0, y0, z0, seed); + n1 = ValueNoise3D (x1, y0, z0, seed); + ix0 = LinearInterp (n0, n1, xs); + n0 = ValueNoise3D (x0, y1, z0, seed); + n1 = ValueNoise3D (x1, y1, z0, seed); + ix1 = LinearInterp (n0, n1, xs); + iy0 = LinearInterp (ix0, ix1, ys); + n0 = ValueNoise3D (x0, y0, z1, seed); + n1 = ValueNoise3D (x1, y0, z1, seed); + ix0 = LinearInterp (n0, n1, xs); + n0 = ValueNoise3D (x0, y1, z1, seed); + n1 = ValueNoise3D (x1, y1, z1, seed); + ix1 = LinearInterp (n0, n1, xs); + iy1 = LinearInterp (ix0, ix1, ys); + return LinearInterp (iy0, iy1, zs); +} + +double noise::ValueNoise3D (int x, int y, int z, int seed) +{ + return 1.0 - ((double)IntValueNoise3D (x, y, z, seed) / 1073741824.0); +} + diff --git a/src/libnoise/src/noisegen.h b/src/libnoise/src/noisegen.h new file mode 100644 index 00000000000..192ece9fce9 --- /dev/null +++ b/src/libnoise/src/noisegen.h @@ -0,0 +1,208 @@ +// noisegen.h +// +// Copyright (C) 2003, 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#ifndef NOISE_NOISEGEN_H +#define NOISE_NOISEGEN_H + +#include +#include "basictypes.h" + +namespace noise +{ + + /// @addtogroup libnoise + /// @{ + + /// Enumerates the noise quality. + enum NoiseQuality + { + + /// Generates coherent noise quickly. When a coherent-noise function with + /// this quality setting is used to generate a bump-map image, there are + /// noticeable "creasing" artifacts in the resulting image. This is + /// because the derivative of that function is discontinuous at integer + /// boundaries. + QUALITY_FAST = 0, + + /// Generates standard-quality coherent noise. When a coherent-noise + /// function with this quality setting is used to generate a bump-map + /// image, there are some minor "creasing" artifacts in the resulting + /// image. This is because the second derivative of that function is + /// discontinuous at integer boundaries. + QUALITY_STD = 1, + + /// Generates the best-quality coherent noise. When a coherent-noise + /// function with this quality setting is used to generate a bump-map + /// image, there are no "creasing" artifacts in the resulting image. This + /// is because the first and second derivatives of that function are + /// continuous at integer boundaries. + QUALITY_BEST = 2 + + }; + + /// Generates a gradient-coherent-noise value from the coordinates of a + /// three-dimensional input value. + /// + /// @param x The @a x coordinate of the input value. + /// @param y The @a y coordinate of the input value. + /// @param z The @a z coordinate of the input value. + /// @param seed The random number seed. + /// @param noiseQuality The quality of the coherent-noise. + /// + /// @returns The generated gradient-coherent-noise value. + /// + /// The return value ranges from -1.0 to +1.0. + /// + /// For an explanation of the difference between gradient noise and + /// value noise, see the comments for the GradientNoise3D() function. + double GradientCoherentNoise3D (double x, double y, double z, int seed = 0, + NoiseQuality noiseQuality = QUALITY_STD); + + /// Generates a gradient-noise value from the coordinates of a + /// three-dimensional input value and the integer coordinates of a + /// nearby three-dimensional value. + /// + /// @param fx The floating-point @a x coordinate of the input value. + /// @param fy The floating-point @a y coordinate of the input value. + /// @param fz The floating-point @a z coordinate of the input value. + /// @param ix The integer @a x coordinate of a nearby value. + /// @param iy The integer @a y coordinate of a nearby value. + /// @param iz The integer @a z coordinate of a nearby value. + /// @param seed The random number seed. + /// + /// @returns The generated gradient-noise value. + /// + /// @pre The difference between @a fx and @a ix must be less than or equal + /// to one. + /// + /// @pre The difference between @a fy and @a iy must be less than or equal + /// to one. + /// + /// @pre The difference between @a fz and @a iz must be less than or equal + /// to one. + /// + /// A gradient-noise function generates better-quality noise than a + /// value-noise function. Most noise modules use gradient noise for + /// this reason, although it takes much longer to calculate. + /// + /// The return value ranges from -1.0 to +1.0. + /// + /// This function generates a gradient-noise value by performing the + /// following steps: + /// - It first calculates a random normalized vector based on the + /// nearby integer value passed to this function. + /// - It then calculates a new value by adding this vector to the + /// nearby integer value passed to this function. + /// - It then calculates the dot product of the above-generated value + /// and the floating-point input value passed to this function. + /// + /// A noise function differs from a random-number generator because it + /// always returns the same output value if the same input value is passed + /// to it. + double GradientNoise3D (double fx, double fy, double fz, int ix, int iy, + int iz, int seed = 0); + + /// Generates an integer-noise value from the coordinates of a + /// three-dimensional input value. + /// + /// @param x The integer @a x coordinate of the input value. + /// @param y The integer @a y coordinate of the input value. + /// @param z The integer @a z coordinate of the input value. + /// @param seed A random number seed. + /// + /// @returns The generated integer-noise value. + /// + /// The return value ranges from 0 to 2147483647. + /// + /// A noise function differs from a random-number generator because it + /// always returns the same output value if the same input value is passed + /// to it. + int IntValueNoise3D (int x, int y, int z, int seed = 0); + + /// Modifies a floating-point value so that it can be stored in a + /// noise::int32 variable. + /// + /// @param n A floating-point number. + /// + /// @returns The modified floating-point number. + /// + /// This function does not modify @a n. + /// + /// In libnoise, the noise-generating algorithms are all integer-based; + /// they use variables of type noise::int32. Before calling a noise + /// function, pass the @a x, @a y, and @a z coordinates to this function to + /// ensure that these coordinates can be cast to a noise::int32 value. + /// + /// Although you could do a straight cast from double to noise::int32, the + /// resulting value may differ between platforms. By using this function, + /// you ensure that the resulting value is identical between platforms. + inline double MakeInt32Range (double n) + { + if (n >= 1073741824.0) { + return (2.0 * fmod (n, 1073741824.0)) - 1073741824.0; + } else if (n <= -1073741824.0) { + return (2.0 * fmod (n, 1073741824.0)) + 1073741824.0; + } else { + return n; + } + } + + /// Generates a value-coherent-noise value from the coordinates of a + /// three-dimensional input value. + /// + /// @param x The @a x coordinate of the input value. + /// @param y The @a y coordinate of the input value. + /// @param z The @a z coordinate of the input value. + /// @param seed The random number seed. + /// @param noiseQuality The quality of the coherent-noise. + /// + /// @returns The generated value-coherent-noise value. + /// + /// The return value ranges from -1.0 to +1.0. + /// + /// For an explanation of the difference between gradient noise and + /// value noise, see the comments for the GradientNoise3D() function. + double ValueCoherentNoise3D (double x, double y, double z, int seed = 0, + NoiseQuality noiseQuality = QUALITY_STD); + + /// Generates a value-noise value from the coordinates of a + /// three-dimensional input value. + /// + /// @param x The @a x coordinate of the input value. + /// @param y The @a y coordinate of the input value. + /// @param z The @a z coordinate of the input value. + /// @param seed A random number seed. + /// + /// @returns The generated value-noise value. + /// + /// The return value ranges from -1.0 to +1.0. + /// + /// A noise function differs from a random-number generator because it + /// always returns the same output value if the same input value is passed + /// to it. + double ValueNoise3D (int x, int y, int z, int seed = 0); + + /// @} + +} + +#endif diff --git a/src/libnoise/src/vectortable.h b/src/libnoise/src/vectortable.h new file mode 100644 index 00000000000..cc25429a76e --- /dev/null +++ b/src/libnoise/src/vectortable.h @@ -0,0 +1,290 @@ +// vectortable.h +// +// Written by Jason Bevins. Actually it's the output of a program written +// by me. I'm not going to copyright a bunch of random numbers (although +// you could probably do so in the States, the way things are going down +// there :-) +// +// This file is in the public domain. +// + +#ifndef NOISE_VECTORTABLE_H +#define NOISE_VECTORTABLE_H + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +namespace noise +{ + + // A table of 256 random normalized vectors. Each row is an (x, y, z, 0) + // coordinate. The 0 is used as padding so we can use bit shifts to index + // any row in the table. These vectors have an even statistical + // distribution, which improves the quality of the coherent noise + // generated by these vectors. For more information, see "GPU Gems", + // Chapter 5 - Implementing Improved Perlin Noise by Ken Perlin, + // specifically page 76. + double g_randomVectors[256 * 4] = + { + -0.763874, -0.596439, -0.246489, 0.0, + 0.396055, 0.904518, -0.158073, 0.0, + -0.499004, -0.8665, -0.0131631, 0.0, + 0.468724, -0.824756, 0.316346, 0.0, + 0.829598, 0.43195, 0.353816, 0.0, + -0.454473, 0.629497, -0.630228, 0.0, + -0.162349, -0.869962, -0.465628, 0.0, + 0.932805, 0.253451, 0.256198, 0.0, + -0.345419, 0.927299, -0.144227, 0.0, + -0.715026, -0.293698, -0.634413, 0.0, + -0.245997, 0.717467, -0.651711, 0.0, + -0.967409, -0.250435, -0.037451, 0.0, + 0.901729, 0.397108, -0.170852, 0.0, + 0.892657, -0.0720622, -0.444938, 0.0, + 0.0260084, -0.0361701, 0.999007, 0.0, + 0.949107, -0.19486, 0.247439, 0.0, + 0.471803, -0.807064, -0.355036, 0.0, + 0.879737, 0.141845, 0.453809, 0.0, + 0.570747, 0.696415, 0.435033, 0.0, + -0.141751, -0.988233, -0.0574584, 0.0, + -0.58219, -0.0303005, 0.812488, 0.0, + -0.60922, 0.239482, -0.755975, 0.0, + 0.299394, -0.197066, -0.933557, 0.0, + -0.851615, -0.220702, -0.47544, 0.0, + 0.848886, 0.341829, -0.403169, 0.0, + -0.156129, -0.687241, 0.709453, 0.0, + -0.665651, 0.626724, 0.405124, 0.0, + 0.595914, -0.674582, 0.43569, 0.0, + 0.171025, -0.509292, 0.843428, 0.0, + 0.78605, 0.536414, -0.307222, 0.0, + 0.18905, -0.791613, 0.581042, 0.0, + -0.294916, 0.844994, 0.446105, 0.0, + 0.342031, -0.58736, -0.7335, 0.0, + 0.57155, 0.7869, 0.232635, 0.0, + 0.885026, -0.408223, 0.223791, 0.0, + -0.789518, 0.571645, 0.223347, 0.0, + 0.774571, 0.31566, 0.548087, 0.0, + -0.79695, -0.0433603, -0.602487, 0.0, + -0.142425, -0.473249, -0.869339, 0.0, + -0.0698838, 0.170442, 0.982886, 0.0, + 0.687815, -0.484748, 0.540306, 0.0, + 0.543703, -0.534446, -0.647112, 0.0, + 0.97186, 0.184391, -0.146588, 0.0, + 0.707084, 0.485713, -0.513921, 0.0, + 0.942302, 0.331945, 0.043348, 0.0, + 0.499084, 0.599922, 0.625307, 0.0, + -0.289203, 0.211107, 0.9337, 0.0, + 0.412433, -0.71667, -0.56239, 0.0, + 0.87721, -0.082816, 0.47291, 0.0, + -0.420685, -0.214278, 0.881538, 0.0, + 0.752558, -0.0391579, 0.657361, 0.0, + 0.0765725, -0.996789, 0.0234082, 0.0, + -0.544312, -0.309435, -0.779727, 0.0, + -0.455358, -0.415572, 0.787368, 0.0, + -0.874586, 0.483746, 0.0330131, 0.0, + 0.245172, -0.0838623, 0.965846, 0.0, + 0.382293, -0.432813, 0.81641, 0.0, + -0.287735, -0.905514, 0.311853, 0.0, + -0.667704, 0.704955, -0.239186, 0.0, + 0.717885, -0.464002, -0.518983, 0.0, + 0.976342, -0.214895, 0.0240053, 0.0, + -0.0733096, -0.921136, 0.382276, 0.0, + -0.986284, 0.151224, -0.0661379, 0.0, + -0.899319, -0.429671, 0.0812908, 0.0, + 0.652102, -0.724625, 0.222893, 0.0, + 0.203761, 0.458023, -0.865272, 0.0, + -0.030396, 0.698724, -0.714745, 0.0, + -0.460232, 0.839138, 0.289887, 0.0, + -0.0898602, 0.837894, 0.538386, 0.0, + -0.731595, 0.0793784, 0.677102, 0.0, + -0.447236, -0.788397, 0.422386, 0.0, + 0.186481, 0.645855, -0.740335, 0.0, + -0.259006, 0.935463, 0.240467, 0.0, + 0.445839, 0.819655, -0.359712, 0.0, + 0.349962, 0.755022, -0.554499, 0.0, + -0.997078, -0.0359577, 0.0673977, 0.0, + -0.431163, -0.147516, -0.890133, 0.0, + 0.299648, -0.63914, 0.708316, 0.0, + 0.397043, 0.566526, -0.722084, 0.0, + -0.502489, 0.438308, -0.745246, 0.0, + 0.0687235, 0.354097, 0.93268, 0.0, + -0.0476651, -0.462597, 0.885286, 0.0, + -0.221934, 0.900739, -0.373383, 0.0, + -0.956107, -0.225676, 0.186893, 0.0, + -0.187627, 0.391487, -0.900852, 0.0, + -0.224209, -0.315405, 0.92209, 0.0, + -0.730807, -0.537068, 0.421283, 0.0, + -0.0353135, -0.816748, 0.575913, 0.0, + -0.941391, 0.176991, -0.287153, 0.0, + -0.154174, 0.390458, 0.90762, 0.0, + -0.283847, 0.533842, 0.796519, 0.0, + -0.482737, -0.850448, 0.209052, 0.0, + -0.649175, 0.477748, 0.591886, 0.0, + 0.885373, -0.405387, -0.227543, 0.0, + -0.147261, 0.181623, -0.972279, 0.0, + 0.0959236, -0.115847, -0.988624, 0.0, + -0.89724, -0.191348, 0.397928, 0.0, + 0.903553, -0.428461, -0.00350461, 0.0, + 0.849072, -0.295807, -0.437693, 0.0, + 0.65551, 0.741754, -0.141804, 0.0, + 0.61598, -0.178669, 0.767232, 0.0, + 0.0112967, 0.932256, -0.361623, 0.0, + -0.793031, 0.258012, 0.551845, 0.0, + 0.421933, 0.454311, 0.784585, 0.0, + -0.319993, 0.0401618, -0.946568, 0.0, + -0.81571, 0.551307, -0.175151, 0.0, + -0.377644, 0.00322313, 0.925945, 0.0, + 0.129759, -0.666581, -0.734052, 0.0, + 0.601901, -0.654237, -0.457919, 0.0, + -0.927463, -0.0343576, -0.372334, 0.0, + -0.438663, -0.868301, -0.231578, 0.0, + -0.648845, -0.749138, -0.133387, 0.0, + 0.507393, -0.588294, 0.629653, 0.0, + 0.726958, 0.623665, 0.287358, 0.0, + 0.411159, 0.367614, -0.834151, 0.0, + 0.806333, 0.585117, -0.0864016, 0.0, + 0.263935, -0.880876, 0.392932, 0.0, + 0.421546, -0.201336, 0.884174, 0.0, + -0.683198, -0.569557, -0.456996, 0.0, + -0.117116, -0.0406654, -0.992285, 0.0, + -0.643679, -0.109196, -0.757465, 0.0, + -0.561559, -0.62989, 0.536554, 0.0, + 0.0628422, 0.104677, -0.992519, 0.0, + 0.480759, -0.2867, -0.828658, 0.0, + -0.228559, -0.228965, -0.946222, 0.0, + -0.10194, -0.65706, -0.746914, 0.0, + 0.0689193, -0.678236, 0.731605, 0.0, + 0.401019, -0.754026, 0.52022, 0.0, + -0.742141, 0.547083, -0.387203, 0.0, + -0.00210603, -0.796417, -0.604745, 0.0, + 0.296725, -0.409909, -0.862513, 0.0, + -0.260932, -0.798201, 0.542945, 0.0, + -0.641628, 0.742379, 0.192838, 0.0, + -0.186009, -0.101514, 0.97729, 0.0, + 0.106711, -0.962067, 0.251079, 0.0, + -0.743499, 0.30988, -0.592607, 0.0, + -0.795853, -0.605066, -0.0226607, 0.0, + -0.828661, -0.419471, -0.370628, 0.0, + 0.0847218, -0.489815, -0.8677, 0.0, + -0.381405, 0.788019, -0.483276, 0.0, + 0.282042, -0.953394, 0.107205, 0.0, + 0.530774, 0.847413, 0.0130696, 0.0, + 0.0515397, 0.922524, 0.382484, 0.0, + -0.631467, -0.709046, 0.313852, 0.0, + 0.688248, 0.517273, 0.508668, 0.0, + 0.646689, -0.333782, -0.685845, 0.0, + -0.932528, -0.247532, -0.262906, 0.0, + 0.630609, 0.68757, -0.359973, 0.0, + 0.577805, -0.394189, 0.714673, 0.0, + -0.887833, -0.437301, -0.14325, 0.0, + 0.690982, 0.174003, 0.701617, 0.0, + -0.866701, 0.0118182, 0.498689, 0.0, + -0.482876, 0.727143, 0.487949, 0.0, + -0.577567, 0.682593, -0.447752, 0.0, + 0.373768, 0.0982991, 0.922299, 0.0, + 0.170744, 0.964243, -0.202687, 0.0, + 0.993654, -0.035791, -0.106632, 0.0, + 0.587065, 0.4143, -0.695493, 0.0, + -0.396509, 0.26509, -0.878924, 0.0, + -0.0866853, 0.83553, -0.542563, 0.0, + 0.923193, 0.133398, -0.360443, 0.0, + 0.00379108, -0.258618, 0.965972, 0.0, + 0.239144, 0.245154, -0.939526, 0.0, + 0.758731, -0.555871, 0.33961, 0.0, + 0.295355, 0.309513, 0.903862, 0.0, + 0.0531222, -0.91003, -0.411124, 0.0, + 0.270452, 0.0229439, -0.96246, 0.0, + 0.563634, 0.0324352, 0.825387, 0.0, + 0.156326, 0.147392, 0.976646, 0.0, + -0.0410141, 0.981824, 0.185309, 0.0, + -0.385562, -0.576343, -0.720535, 0.0, + 0.388281, 0.904441, 0.176702, 0.0, + 0.945561, -0.192859, -0.262146, 0.0, + 0.844504, 0.520193, 0.127325, 0.0, + 0.0330893, 0.999121, -0.0257505, 0.0, + -0.592616, -0.482475, -0.644999, 0.0, + 0.539471, 0.631024, -0.557476, 0.0, + 0.655851, -0.027319, -0.754396, 0.0, + 0.274465, 0.887659, 0.369772, 0.0, + -0.123419, 0.975177, -0.183842, 0.0, + -0.223429, 0.708045, 0.66989, 0.0, + -0.908654, 0.196302, 0.368528, 0.0, + -0.95759, -0.00863708, 0.288005, 0.0, + 0.960535, 0.030592, 0.276472, 0.0, + -0.413146, 0.907537, 0.0754161, 0.0, + -0.847992, 0.350849, -0.397259, 0.0, + 0.614736, 0.395841, 0.68221, 0.0, + -0.503504, -0.666128, -0.550234, 0.0, + -0.268833, -0.738524, -0.618314, 0.0, + 0.792737, -0.60001, -0.107502, 0.0, + -0.637582, 0.508144, -0.579032, 0.0, + 0.750105, 0.282165, -0.598101, 0.0, + -0.351199, -0.392294, -0.850155, 0.0, + 0.250126, -0.960993, -0.118025, 0.0, + -0.732341, 0.680909, -0.0063274, 0.0, + -0.760674, -0.141009, 0.633634, 0.0, + 0.222823, -0.304012, 0.926243, 0.0, + 0.209178, 0.505671, 0.836984, 0.0, + 0.757914, -0.56629, -0.323857, 0.0, + -0.782926, -0.339196, 0.52151, 0.0, + -0.462952, 0.585565, 0.665424, 0.0, + 0.61879, 0.194119, -0.761194, 0.0, + 0.741388, -0.276743, 0.611357, 0.0, + 0.707571, 0.702621, 0.0752872, 0.0, + 0.156562, 0.819977, 0.550569, 0.0, + -0.793606, 0.440216, 0.42, 0.0, + 0.234547, 0.885309, -0.401517, 0.0, + 0.132598, 0.80115, -0.58359, 0.0, + -0.377899, -0.639179, 0.669808, 0.0, + -0.865993, -0.396465, 0.304748, 0.0, + -0.624815, -0.44283, 0.643046, 0.0, + -0.485705, 0.825614, -0.287146, 0.0, + -0.971788, 0.175535, 0.157529, 0.0, + -0.456027, 0.392629, 0.798675, 0.0, + -0.0104443, 0.521623, -0.853112, 0.0, + -0.660575, -0.74519, 0.091282, 0.0, + -0.0157698, -0.307475, -0.951425, 0.0, + -0.603467, -0.250192, 0.757121, 0.0, + 0.506876, 0.25006, 0.824952, 0.0, + 0.255404, 0.966794, 0.00884498, 0.0, + 0.466764, -0.874228, -0.133625, 0.0, + 0.475077, -0.0682351, -0.877295, 0.0, + -0.224967, -0.938972, -0.260233, 0.0, + -0.377929, -0.814757, -0.439705, 0.0, + -0.305847, 0.542333, -0.782517, 0.0, + 0.26658, -0.902905, -0.337191, 0.0, + 0.0275773, 0.322158, -0.946284, 0.0, + 0.0185422, 0.716349, 0.697496, 0.0, + -0.20483, 0.978416, 0.0273371, 0.0, + -0.898276, 0.373969, 0.230752, 0.0, + -0.00909378, 0.546594, 0.837349, 0.0, + 0.6602, -0.751089, 0.000959236, 0.0, + 0.855301, -0.303056, 0.420259, 0.0, + 0.797138, 0.0623013, -0.600574, 0.0, + 0.48947, -0.866813, 0.0951509, 0.0, + 0.251142, 0.674531, 0.694216, 0.0, + -0.578422, -0.737373, -0.348867, 0.0, + -0.254689, -0.514807, 0.818601, 0.0, + 0.374972, 0.761612, 0.528529, 0.0, + 0.640303, -0.734271, -0.225517, 0.0, + -0.638076, 0.285527, 0.715075, 0.0, + 0.772956, -0.15984, -0.613995, 0.0, + 0.798217, -0.590628, 0.118356, 0.0, + -0.986276, -0.0578337, -0.154644, 0.0, + -0.312988, -0.94549, 0.0899272, 0.0, + -0.497338, 0.178325, 0.849032, 0.0, + -0.101136, -0.981014, 0.165477, 0.0, + -0.521688, 0.0553434, -0.851339, 0.0, + -0.786182, -0.583814, 0.202678, 0.0, + -0.565191, 0.821858, -0.0714658, 0.0, + 0.437895, 0.152598, -0.885981, 0.0, + -0.92394, 0.353436, -0.14635, 0.0, + 0.212189, -0.815162, -0.538969, 0.0, + -0.859262, 0.143405, -0.491024, 0.0, + 0.991353, 0.112814, 0.0670273, 0.0, + 0.0337884, -0.979891, -0.196654, 0.0 + }; + +} + +#endif + +#endif diff --git a/src/libnoise/src/win32/dllmain.cpp b/src/libnoise/src/win32/dllmain.cpp new file mode 100644 index 00000000000..8acda06a12b --- /dev/null +++ b/src/libnoise/src/win32/dllmain.cpp @@ -0,0 +1,28 @@ +// dllmain.cpp +// +// Copyright (C) 2004 Jason Bevins +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 2.1 of the License, or (at +// your option) any later version. +// +// This library is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +// License (COPYING.txt) for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this library; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// The developer's email is jlbezigvins@gmzigail.com (for great email, take +// off every 'zig'.) +// + +#include + +BOOL WINAPI DllMain (HINSTANCE hInst, ULONG reason, LPVOID lpReserved) +{ + return TRUE; +} diff --git a/src/libnoise/src/win32/libnoise.def b/src/libnoise/src/win32/libnoise.def new file mode 100644 index 00000000000..4028a887699 --- /dev/null +++ b/src/libnoise/src/win32/libnoise.def @@ -0,0 +1,154 @@ +LIBRARY libnoise + +EXPORTS + ?LatLonToXYZ@noise@@YAXNNAAN00@Z @ 1 + ?GradientNoise3D@noise@@YANNNNHHHH@Z @ 2 + ?IntValueNoise3D@noise@@YAHHHHH@Z @ 3 + ?ValueNoise3D@noise@@YANHHHH@Z @ 6 + ??0Add@module@noise@@QAE@XZ @ 9 + ?GetValue@Add@module@noise@@UBENNNN@Z @ 10 + ?GetSourceModule@Module@module@noise@@UBEABV123@H@Z @ 11 + ?SetSourceModule@Module@module@noise@@UAEXHABV123@@Z @ 12 + ?GetSourceModuleCount@Add@module@noise@@UBEHXZ @ 13 + ??0Blend@module@noise@@QAE@XZ @ 14 + ?GetValue@Blend@module@noise@@UBENNNN@Z @ 15 + ?GetSourceModuleCount@Blend@module@noise@@UBEHXZ @ 16 + ??0Cache@module@noise@@QAE@XZ @ 17 + ?GetValue@Cache@module@noise@@UBENNNN@Z @ 18 + ?GetSourceModuleCount@Cache@module@noise@@UBEHXZ @ 19 + ?SetSourceModule@Cache@module@noise@@UAEXHABVModule@23@@Z @ 20 + ??0Checkerboard@module@noise@@QAE@XZ @ 21 + ?GetValue@Checkerboard@module@noise@@UBENNNN@Z @ 22 + ?GetSourceModuleCount@Checkerboard@module@noise@@UBEHXZ @ 24 + ??0Clamp@module@noise@@QAE@XZ @ 25 + ?GetValue@Clamp@module@noise@@UBENNNN@Z @ 26 + ?SetBounds@Clamp@module@noise@@QAEXNN@Z @ 27 + ?GetSourceModuleCount@Clamp@module@noise@@UBEHXZ @ 28 + ??0Const@module@noise@@QAE@XZ @ 29 + ?GetSourceModuleCount@Const@module@noise@@UBEHXZ @ 30 + ?GetValue@Const@module@noise@@UBENNNN@Z @ 31 + ??0Curve@module@noise@@QAE@XZ @ 32 + ?AddControlPoint@Curve@module@noise@@QAEXNN@Z @ 34 + ?ClearAllControlPoints@Curve@module@noise@@QAEXXZ @ 35 + ?FindInsertionPos@Curve@module@noise@@IAEHN@Z @ 36 + ?GetValue@Curve@module@noise@@UBENNNN@Z @ 37 + ?InsertAtPos@Curve@module@noise@@IAEXHNN@Z @ 38 + ?GetSourceModuleCount@Curve@module@noise@@UBEHXZ @ 42 + ??0Cylinders@module@noise@@QAE@XZ @ 43 + ?GetValue@Cylinders@module@noise@@UBENNNN@Z @ 44 + ?GetSourceModuleCount@Cylinders@module@noise@@UBEHXZ @ 46 + ??0Displace@module@noise@@QAE@XZ @ 47 + ?GetValue@Displace@module@noise@@UBENNNN@Z @ 48 + ?GetSourceModuleCount@Displace@module@noise@@UBEHXZ @ 49 + ??0Exponent@module@noise@@QAE@XZ @ 50 + ?GetValue@Exponent@module@noise@@UBENNNN@Z @ 51 + ?GetSourceModuleCount@Exponent@module@noise@@UBEHXZ @ 52 + ??0Invert@module@noise@@QAE@XZ @ 53 + ?GetValue@Invert@module@noise@@UBENNNN@Z @ 54 + ?GetSourceModuleCount@Invert@module@noise@@UBEHXZ @ 55 + ??0Max@module@noise@@QAE@XZ @ 56 + ?GetValue@Max@module@noise@@UBENNNN@Z @ 57 + ?GetSourceModuleCount@Max@module@noise@@UBEHXZ @ 59 + ??0Min@module@noise@@QAE@XZ @ 60 + ?GetValue@Min@module@noise@@UBENNNN@Z @ 61 + ?GetSourceModuleCount@Min@module@noise@@UBEHXZ @ 62 + ??0Module@module@noise@@QAE@H@Z @ 63 + ??0Multiply@module@noise@@QAE@XZ @ 64 + ?GetValue@Multiply@module@noise@@UBENNNN@Z @ 65 + ?GetSourceModuleCount@Multiply@module@noise@@UBEHXZ @ 66 + ??0Perlin@module@noise@@QAE@XZ @ 67 + ?GetValue@Perlin@module@noise@@UBENNNN@Z @ 68 + ?GetSourceModuleCount@Perlin@module@noise@@UBEHXZ @ 69 + ??0Power@module@noise@@QAE@XZ @ 70 + ?GetValue@Power@module@noise@@UBENNNN@Z @ 71 + ?GetSourceModuleCount@Power@module@noise@@UBEHXZ @ 72 + ??0RidgedMulti@module@noise@@QAE@XZ @ 73 + ?GetValue@RidgedMulti@module@noise@@UBENNNN@Z @ 74 + ?GetSourceModuleCount@RidgedMulti@module@noise@@UBEHXZ @ 75 + ??0RotatePoint@module@noise@@QAE@XZ @ 76 + ?GetValue@RotatePoint@module@noise@@UBENNNN@Z @ 77 + ?SetAngles@RotatePoint@module@noise@@QAEXNNN@Z @ 78 + ?GetSourceModuleCount@RotatePoint@module@noise@@UBEHXZ @ 79 + ??0ScaleBias@module@noise@@QAE@XZ @ 80 + ?GetValue@ScaleBias@module@noise@@UBENNNN@Z @ 81 + ?GetSourceModuleCount@ScaleBias@module@noise@@UBEHXZ @ 82 + ??0ScalePoint@module@noise@@QAE@XZ @ 83 + ?GetValue@ScalePoint@module@noise@@UBENNNN@Z @ 84 + ?GetSourceModuleCount@ScalePoint@module@noise@@UBEHXZ @ 85 + ??0Select@module@noise@@QAE@XZ @ 86 + ?GetValue@Select@module@noise@@UBENNNN@Z @ 87 + ?SetBounds@Select@module@noise@@QAEXNN@Z @ 88 + ?SetEdgeFalloff@Select@module@noise@@QAEXN@Z @ 89 + ?GetSourceModuleCount@Select@module@noise@@UBEHXZ @ 90 + ??0Spheres@module@noise@@QAE@XZ @ 91 + ?GetValue@Spheres@module@noise@@UBENNNN@Z @ 92 + ?GetSourceModuleCount@Spheres@module@noise@@UBEHXZ @ 93 + ??0Terrace@module@noise@@QAE@XZ @ 94 + ?FindInsertionPos@Terrace@module@noise@@IAEHN@Z @ 98 + ?GetValue@Terrace@module@noise@@UBENNNN@Z @ 99 + ?InsertAtPos@Terrace@module@noise@@IAEXHN@Z @ 100 + ?GetSourceModuleCount@Terrace@module@noise@@UBEHXZ @ 103 + ??0Turbulence@module@noise@@QAE@XZ @ 104 + ?GetFrequency@Turbulence@module@noise@@QBENXZ @ 105 + ?GetSeed@Turbulence@module@noise@@QBEHXZ @ 106 + ?GetValue@Turbulence@module@noise@@UBENNNN@Z @ 107 + ?SetSeed@Turbulence@module@noise@@QAEXH@Z @ 109 + ?GetSourceModuleCount@Turbulence@module@noise@@UBEHXZ @ 115 + ??0Voronoi@module@noise@@QAE@XZ @ 116 + ?GetValue@Voronoi@module@noise@@UBENNNN@Z @ 117 + ?GetSourceModuleCount@Voronoi@module@noise@@UBEHXZ @ 118 + ??0Abs@module@noise@@QAE@XZ @ 119 + ?GetValue@Abs@module@noise@@UBENNNN@Z @ 120 + ?GetSourceModuleCount@Abs@module@noise@@UBEHXZ @ 121 + ??0Line@model@noise@@QAE@XZ @ 122 + ?GetValue@Line@model@noise@@QBENN@Z @ 123 + ??0Plane@model@noise@@QAE@XZ @ 124 + ?GetValue@Plane@model@noise@@QBENNN@Z @ 125 + ??0Sphere@model@noise@@QAE@XZ @ 126 + ?GetValue@Sphere@model@noise@@QBENNN@Z @ 127 + ??0Cylinder@model@noise@@QAE@XZ @ 128 + ?GetValue@Cylinder@model@noise@@QBENNN@Z @ 129 + ??_7Add@module@noise@@6B@ @ 130 + ??_7Blend@module@noise@@6B@ @ 131 + ??_7Cache@module@noise@@6B@ @ 132 + ??_7Checkerboard@module@noise@@6B@ @ 133 + ??_7Clamp@module@noise@@6B@ @ 134 + ??_7Const@module@noise@@6B@ @ 135 + ??_7Curve@module@noise@@6B@ @ 136 + ??_7Module@module@noise@@6B@ @ 137 + ??_7Cylinders@module@noise@@6B@ @ 138 + ??_7Displace@module@noise@@6B@ @ 139 + ??_7Exponent@module@noise@@6B@ @ 140 + ??_7Invert@module@noise@@6B@ @ 141 + ??_7Max@module@noise@@6B@ @ 142 + ??_7Min@module@noise@@6B@ @ 143 + ??_7Multiply@module@noise@@6B@ @ 144 + ??_7Perlin@module@noise@@6B@ @ 145 + ??_7Power@module@noise@@6B@ @ 146 + ??_7RidgedMulti@module@noise@@6B@ @ 147 + ??_7RotatePoint@module@noise@@6B@ @ 148 + ??_7ScaleBias@module@noise@@6B@ @ 149 + ??_7ScalePoint@module@noise@@6B@ @ 150 + ??_7Select@module@noise@@6B@ @ 151 + ??_7Spheres@module@noise@@6B@ @ 152 + ??_7Terrace@module@noise@@6B@ @ 153 + ??_7Turbulence@module@noise@@6B@ @ 154 + ??_7Voronoi@module@noise@@6B@ @ 155 + ??_7Abs@module@noise@@6B@ @ 156 + ??0Billow@module@noise@@QAE@XZ @ 159 + ?GetValue@Billow@module@noise@@UBENNNN@Z @ 160 + ?GetSourceModuleCount@Billow@module@noise@@UBEHXZ @ 161 + ??_7Billow@module@noise@@6B@ @ 163 + ?CalcSpectralWeights@RidgedMulti@module@noise@@IAEXXZ @ 164 + ??0TranslatePoint@module@noise@@QAE@XZ @ 166 + ?GetValue@TranslatePoint@module@noise@@UBENNNN@Z @ 167 + ?GetSourceModuleCount@TranslatePoint@module@noise@@UBEHXZ @ 168 + ??_7TranslatePoint@module@noise@@6B@ @ 169 + ?AddControlPoint@Terrace@module@noise@@QAEXN@Z @ 170 + ?ClearAllControlPoints@Terrace@module@noise@@QAEXXZ @ 171 + ?MakeControlPoints@Terrace@module@noise@@QAEXH@Z @ 172 + ?GradientCoherentNoise3D@noise@@YANNNNHW4NoiseQuality@1@@Z @ 173 + ?ValueCoherentNoise3D@noise@@YANNNNHW4NoiseQuality@1@@Z @ 174 + ??1Terrace@module@noise@@UAE@XZ @ 175 + ??1Curve@module@noise@@UAE@XZ @ 176 + ??1Module@module@noise@@UAE@XZ @ 177 diff --git a/src/libnoise/src/win32/noise.aps b/src/libnoise/src/win32/noise.aps new file mode 100644 index 0000000000000000000000000000000000000000..ee7906dc8899f344f92e86b44a7e34a583eb1a7a GIT binary patch literal 31404 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, + this->layer()->slice_z, this->flow(frPerimeter), ®ion_config, &this->layer()->object()->config(), diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 50d86a3d068..9800c12f2dc 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -22,6 +22,7 @@ #include "libslic3r/AABBTreeLines.hpp" #include "Print.hpp" #include "Algorithm/LineSplit.hpp" +#include "noise.h" static const int overhang_sampling_number = 6; static const double narrow_loop_length_threshold = 10; static const double min_degree_gap = 0.1; @@ -44,6 +45,14 @@ static double random_value() { return dist(gen); } +class UniformNoise: public noise::module::Module { + public: + UniformNoise(): Module (GetSourceModuleCount ()) {}; + + virtual int GetSourceModuleCount() const { return 0; } + virtual double GetValue(double x, double y, double z) const { return random_value() * 2 - 1; } +}; + // Hierarchy of perimeters. class PerimeterGeneratorLoop { public: @@ -67,8 +76,19 @@ class PerimeterGeneratorLoop { }; // Thanks Cura developers for this function. -static void fuzzy_polyline(Points& poly, bool closed, const FuzzySkinConfig& cfg) +static void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkinConfig& cfg) { + std::unique_ptr noise; + if(cfg.use_noise) { + auto perlin_noise = noise::module::Perlin(); + perlin_noise.SetFrequency(1 / cfg.noise_scale); + perlin_noise.SetOctaveCount(cfg.noise_octaves); + perlin_noise.SetPersistence(cfg.noise_persistence); + noise = std::make_unique(perlin_noise); + } else { + noise = std::make_unique(); + } + const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value const double range_random_point_dist = cfg.point_distance / 2.; double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point @@ -90,8 +110,9 @@ static void fuzzy_polyline(Points& poly, bool closed, const FuzzySkinConfig& cfg for (; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist) { - double r = random_value() * (cfg.thickness * 2.) - cfg.thickness; - out.emplace_back(*p0 + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast()); + Point pa = *p0 + (p0p1 * (p0pa_dist / p0p1_size)).cast(); + double r = noise->GetValue(unscale_(pa.x()), unscale_(pa.y()), slice_z) * cfg.thickness; + out.emplace_back(pa + (perp(p0p1).cast().normalized() * r).cast()); } dist_left_over = p0pa_dist - p0p1_size; p0 = &p1; @@ -108,8 +129,19 @@ static void fuzzy_polyline(Points& poly, bool closed, const FuzzySkinConfig& cfg } // Thanks Cura developers for this function. -static void fuzzy_extrusion_line(std::vector& ext_lines, const FuzzySkinConfig& cfg) +static void fuzzy_extrusion_line(std::vector& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg) { + std::unique_ptr noise; + if(cfg.use_noise) { + auto perlin_noise = noise::module::Perlin(); + perlin_noise.SetFrequency(1 / cfg.noise_scale); + perlin_noise.SetOctaveCount(cfg.noise_octaves); + perlin_noise.SetPersistence(cfg.noise_persistence); + noise = std::make_unique(perlin_noise); + } else { + noise = std::make_unique(); + } + const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value const double range_random_point_dist = cfg.point_distance / 2.; double dist_left_over = random_value() * (min_dist_between_points / 2.); // the distance to be traversed on the line before making the first new point @@ -128,8 +160,9 @@ static void fuzzy_extrusion_line(std::vector& ext_li double p0p1_size = p0p1.norm(); double p0pa_dist = dist_left_over; for (; p0pa_dist < p0p1_size; p0pa_dist += min_dist_between_points + random_value() * range_random_point_dist) { - double r = random_value() * (cfg.thickness * 2.) - cfg.thickness; - out.emplace_back(p0->p + (p0p1 * (p0pa_dist / p0p1_size) + perp(p0p1).cast().normalized() * r).cast(), p1.w, p1.perimeter_index); + Point pa = p0->p + (p0p1 * (p0pa_dist / p0p1_size)).cast(); + double r = noise->GetValue(unscale_(pa.x()), unscale_(pa.y()), slice_z) * cfg.thickness; + out.emplace_back(pa + (perp(p0p1).cast().normalized() * r).cast(), p1.w, p1.perimeter_index); } dist_left_over = p0pa_dist - p0p1_size; p0 = &p1; @@ -544,7 +577,7 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime } fuzzified = loop.polygon; - fuzzy_polyline(fuzzified.points, true, config); + fuzzy_polyline(fuzzified.points, true, perimeter_generator.slice_z, config); return &fuzzified; } @@ -589,16 +622,17 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime // Fuzzy splitted polygon if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) { // The entire polygon is fuzzified - fuzzy_polyline(fuzzified.points, true, r.first); + fuzzy_polyline(fuzzified.points, true, perimeter_generator.slice_z, r.first); } else { Points segment; segment.reserve(splitted.size()); fuzzified.points.clear(); - const auto fuzzy_current_segment = [&segment, &fuzzified, &r]() { + const auto slice_z = perimeter_generator.slice_z; + const auto fuzzy_current_segment = [&segment, &fuzzified, &r, slice_z]() { fuzzified.points.push_back(segment.front()); const auto back = segment.back(); - fuzzy_polyline(segment, false, r.first); + fuzzy_polyline(segment, false, slice_z, r.first); fuzzified.points.insert(fuzzified.points.end(), segment.begin(), segment.end()); fuzzified.points.push_back(back); segment.clear(); @@ -970,6 +1004,8 @@ static void smooth_overhang_level(ExtrusionPaths &paths) static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& perimeter_generator, std::vector& pg_extrusions, bool &steep_overhang_contour, bool &steep_overhang_hole) { + const auto slice_z = perimeter_generator.slice_z; + // Detect steep overhangs bool overhangs_reverse = perimeter_generator.config->overhang_reverse && perimeter_generator.layer_id % 2 == 1; // Only calculate overhang degree on even (from GUI POV) layers @@ -989,7 +1025,7 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p const auto& config = regions.begin()->first; const bool fuzzify = should_fuzzify(config, perimeter_generator.layer_id, extrusion->inset_idx, is_contour); if (fuzzify) - fuzzy_extrusion_line(extrusion->junctions, config); + fuzzy_extrusion_line(extrusion->junctions, slice_z, config); } else { // Find all affective regions std::vector> fuzzified_regions; @@ -1011,17 +1047,17 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p // Fuzzy splitted extrusion if (std::all_of(splitted.begin(), splitted.end(), [](const Algorithm::SplitLineJunction& j) { return j.clipped; })) { // The entire polygon is fuzzified - fuzzy_extrusion_line(extrusion->junctions, r.first); + fuzzy_extrusion_line(extrusion->junctions, slice_z, r.first); } else { const auto current_ext = extrusion->junctions; std::vector segment; segment.reserve(current_ext.size()); extrusion->junctions.clear(); - const auto fuzzy_current_segment = [&segment, extrusion, &r]() { + const auto fuzzy_current_segment = [&segment, extrusion, &r, slice_z]() { extrusion->junctions.push_back(segment.front()); const auto back = segment.back(); - fuzzy_extrusion_line(segment, r.first); + fuzzy_extrusion_line(segment, slice_z, r.first); extrusion->junctions.insert(extrusion->junctions.end(), segment.begin(), segment.end()); extrusion->junctions.push_back(back); segment.clear(); @@ -1858,7 +1894,11 @@ static void group_region_by_fuzzify(PerimeterGenerator& g) region_config.fuzzy_skin, scaled(region_config.fuzzy_skin_thickness.value), scaled(region_config.fuzzy_skin_point_distance.value), - region_config.fuzzy_skin_first_layer + region_config.fuzzy_skin_first_layer, + region_config.fuzzy_skin_use_noise, + region_config.fuzzy_skin_scale, + region_config.fuzzy_skin_octaves, + region_config.fuzzy_skin_persistence }; auto& surfaces = regions[cfg]; for (const auto& surface : region->slices.surfaces) { diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index 733920e3106..7f45700bc8c 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -16,10 +16,21 @@ struct FuzzySkinConfig coord_t thickness; coord_t point_distance; bool fuzzy_first_layer; + bool use_noise; + double noise_scale; + int noise_octaves; + double noise_persistence; bool operator==(const FuzzySkinConfig& r) const { - return type == r.type && thickness == r.thickness && point_distance == r.point_distance && fuzzy_first_layer == r.fuzzy_first_layer; + return type == r.type + && thickness == r.thickness + && point_distance == r.point_distance + && fuzzy_first_layer == r.fuzzy_first_layer + && use_noise == r.use_noise + && noise_scale == r.noise_scale + && noise_octaves == r.noise_octaves + && noise_persistence == r.noise_persistence; } bool operator!=(const FuzzySkinConfig& r) const { return !(*this == r); } @@ -35,6 +46,10 @@ template<> struct hash boost::hash_combine(seed, std::hash{}(c.thickness)); boost::hash_combine(seed, std::hash{}(c.point_distance)); boost::hash_combine(seed, std::hash{}(c.fuzzy_first_layer)); + boost::hash_combine(seed, std::hash{}(c.use_noise)); + boost::hash_combine(seed, std::hash{}(c.noise_scale)); + boost::hash_combine(seed, std::hash{}(c.noise_octaves)); + boost::hash_combine(seed, std::hash{}(c.noise_persistence)); return seed; } }; @@ -51,6 +66,7 @@ class PerimeterGenerator { const ExPolygons *lower_slices; double layer_height; int layer_id; + coordf_t slice_z; Flow perimeter_flow; Flow ext_perimeter_flow; Flow overhang_flow; @@ -83,6 +99,7 @@ class PerimeterGenerator { const SurfaceCollection* slices, const LayerRegionPtrs *compatible_regions, double layer_height, + coordf_t slice_z, Flow flow, const PrintRegionConfig* config, const PrintObjectConfig* object_config, @@ -98,7 +115,7 @@ class PerimeterGenerator { //BBS ExPolygons* fill_no_overlap) : slices(slices), compatible_regions(compatible_regions), upper_slices(nullptr), lower_slices(nullptr), layer_height(layer_height), - layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow), + slice_z(slice_z), layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow), overhang_flow(flow), solid_infill_flow(flow), config(config), object_config(object_config), print_config(print_config), m_spiral_vase(spiral_mode), diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 30c9bc230f7..a13dc0855db 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -769,7 +769,7 @@ static std::vector s_Preset_print_options { "minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target", "ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "max_travel_detour_distance", - "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", + "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_use_noise", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence", "max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length", "inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", "top_surface_speed", "support_speed", "support_object_xy_distance", "support_interface_speed", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index d7812e6b420..a4b5a8372fa 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2606,6 +2606,41 @@ void PrintConfigDef::init_fff_params() def->mode = comSimple; def->set_default_value(new ConfigOptionBool(0)); + def = this->add("fuzzy_skin_use_noise", coBool); + def->label = L("Use Perlin noise for fuzzy skin"); + def->category = L("Others"); + def->tooltip = L("Use Perlin noise to generate fuzzy skin. If disabled, the naive random generator will be used instead"); + def->mode = comSimple; + def->set_default_value(new ConfigOptionBool(0)); + + def = this->add("fuzzy_skin_scale", coFloat); + def->label = L("Fuzzy skin noise scale"); + def->category = L("Others"); + def->tooltip = L("The base size of the Perlin noise, in mm. Higher values will result in larger features."); + def->sidetext = L("mm"); + def->min = 0.1; + def->max = 500; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(1.0)); + + def = this->add("fuzzy_skin_octaves", coInt); + def->label = L("Fuzzy Skin Noise Octaves"); + def->category = L("Others"); + def->tooltip = L("The number of octaves of perlin noise to use. Higher values increase the detail of the noise, but also increase computation time."); + def->min = 1; + def->max = 10; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionInt(4)); + + def = this->add("fuzzy_skin_persistence", coFloat); + def->label = L("Fuzzy skin noise persistence"); + def->category = L("Others"); + def->tooltip = L("The decay rate for higher octaves of the Perlin noise. Lower values will result in smoother noise."); + def->min = 0.01; + def->max = 1; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionFloat(0.5)); + def = this->add("filter_out_gap_fill", coFloat); def->label = L("Filter out tiny gaps"); def->category = L("Layers and Perimeters"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 18f007a40ad..953f17226a0 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -906,6 +906,10 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, fuzzy_skin_thickness)) ((ConfigOptionFloat, fuzzy_skin_point_distance)) ((ConfigOptionBool, fuzzy_skin_first_layer)) + ((ConfigOptionBool, fuzzy_skin_use_noise)) + ((ConfigOptionFloat, fuzzy_skin_scale)) + ((ConfigOptionInt, fuzzy_skin_octaves)) + ((ConfigOptionFloat, fuzzy_skin_persistence)) ((ConfigOptionFloat, gap_infill_speed)) ((ConfigOptionInt, sparse_infill_filament)) ((ConfigOptionFloatOrPercent, sparse_infill_line_width)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 1530fe655c6..f31cbf1f553 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1116,6 +1116,10 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "fuzzy_skin_thickness" || opt_key == "fuzzy_skin_point_distance" || opt_key == "fuzzy_skin_first_layer" + || opt_key == "fuzzy_skin_use_noise" + || opt_key == "fuzzy_skin_scale" + || opt_key == "fuzzy_skin_octaves" + || opt_key == "fuzzy_skin_persistence" || opt_key == "detect_overhang_wall" || opt_key == "overhang_reverse" || opt_key == "overhang_reverse_internal_only" diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 10d3f376480..2275982f542 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -616,7 +616,7 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SLIC3R_GUI_SOURCES}) encoding_check(libslic3r_gui) -target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto) +target_link_libraries(libslic3r_gui libslic3r cereal::cereal imgui imguizmo minilzo GLEW::GLEW OpenGL::GL hidapi ${wxWidgets_LIBRARIES} glfw libcurl OpenSSL::SSL OpenSSL::Crypto libnoise_static) if (MSVC) target_link_libraries(libslic3r_gui Setupapi.lib) diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 704fdf0dac1..69edee085cb 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -706,9 +706,13 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line("support_interface_not_for_body",config->opt_int("support_interface_filament")&&!config->opt_int("support_filament")); bool has_fuzzy_skin = (config->opt_enum("fuzzy_skin") != FuzzySkinType::None); - for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer"}) + for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_use_noise"}) toggle_line(el, has_fuzzy_skin); + bool fuzzy_skin_use_noise = config->opt_bool("fuzzy_skin_use_noise"); + for (auto el : { "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence"}) + toggle_line(el, has_fuzzy_skin && fuzzy_skin_use_noise); + bool have_arachne = config->opt_enum("wall_generator") == PerimeterGeneratorType::Arachne; for (auto el : { "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", "min_feature_size", "min_length_factor", "min_bead_width", "wall_distribution_count", "initial_layer_min_bead_width"}) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 05b741bcb56..0fc828de938 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2349,6 +2349,10 @@ page = add_options_page(L("Others"), "custom-gcode_other"); // ORCA: icon only v optgroup->append_single_option_line("fuzzy_skin_point_distance"); optgroup->append_single_option_line("fuzzy_skin_thickness"); optgroup->append_single_option_line("fuzzy_skin_first_layer"); + optgroup->append_single_option_line("fuzzy_skin_use_noise"); + optgroup->append_single_option_line("fuzzy_skin_scale"); + optgroup->append_single_option_line("fuzzy_skin_octaves"); + optgroup->append_single_option_line("fuzzy_skin_persistence"); optgroup = page->new_optgroup(L("G-code output"), L"param_gcode"); optgroup->append_single_option_line("reduce_infill_retraction"); From 02e1aff9f62bb2a32953720f1b522d5aa2ba67d7 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 6 Dec 2024 10:34:37 +0000 Subject: [PATCH 2/4] Support multiple types of coherent noise --- src/libslic3r/PerimeterGenerator.cpp | 46 ++++++++++++++++----------- src/libslic3r/PerimeterGenerator.hpp | 6 ++-- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 28 +++++++++++++--- src/libslic3r/PrintConfig.hpp | 11 ++++++- src/libslic3r/PrintObject.cpp | 2 +- src/slic3r/GUI/ConfigManipulation.cpp | 9 +++--- src/slic3r/GUI/Tab.cpp | 2 +- 8 files changed, 73 insertions(+), 33 deletions(-) diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 9800c12f2dc..50690c3af7e 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -75,19 +75,38 @@ class PerimeterGeneratorLoop { bool is_internal_contour() const; }; -// Thanks Cura developers for this function. -static void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkinConfig& cfg) -{ - std::unique_ptr noise; - if(cfg.use_noise) { +static std::unique_ptr get_noise_module(const FuzzySkinConfig& cfg) { + if (cfg.noise_type == NoiseType::Perlin) { auto perlin_noise = noise::module::Perlin(); perlin_noise.SetFrequency(1 / cfg.noise_scale); perlin_noise.SetOctaveCount(cfg.noise_octaves); perlin_noise.SetPersistence(cfg.noise_persistence); - noise = std::make_unique(perlin_noise); + return std::make_unique(perlin_noise); + } else if (cfg.noise_type == NoiseType::Billow) { + auto billow_noise = noise::module::Billow(); + billow_noise.SetFrequency(1 / cfg.noise_scale); + billow_noise.SetOctaveCount(cfg.noise_octaves); + billow_noise.SetPersistence(cfg.noise_persistence); + return std::make_unique(billow_noise); + } else if (cfg.noise_type == NoiseType::RidgedMulti) { + auto ridged_multi_noise = noise::module::RidgedMulti(); + ridged_multi_noise.SetFrequency(1 / cfg.noise_scale); + ridged_multi_noise.SetOctaveCount(cfg.noise_octaves); + return std::make_unique(ridged_multi_noise); + } else if (cfg.noise_type == NoiseType::Voronoi) { + auto voronoi_noise = noise::module::Voronoi(); + voronoi_noise.SetFrequency(1 / cfg.noise_scale); + voronoi_noise.SetDisplacement(1.0); + return std::make_unique(voronoi_noise); } else { - noise = std::make_unique(); + return std::make_unique(); } +} + +// Thanks Cura developers for this function. +static void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const FuzzySkinConfig& cfg) +{ + std::unique_ptr noise = get_noise_module(cfg); const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value const double range_random_point_dist = cfg.point_distance / 2.; @@ -131,16 +150,7 @@ static void fuzzy_polyline(Points& poly, bool closed, coordf_t slice_z, const Fu // Thanks Cura developers for this function. static void fuzzy_extrusion_line(std::vector& ext_lines, coordf_t slice_z, const FuzzySkinConfig& cfg) { - std::unique_ptr noise; - if(cfg.use_noise) { - auto perlin_noise = noise::module::Perlin(); - perlin_noise.SetFrequency(1 / cfg.noise_scale); - perlin_noise.SetOctaveCount(cfg.noise_octaves); - perlin_noise.SetPersistence(cfg.noise_persistence); - noise = std::make_unique(perlin_noise); - } else { - noise = std::make_unique(); - } + std::unique_ptr noise = get_noise_module(cfg); const double min_dist_between_points = cfg.point_distance * 3. / 4.; // hardcoded: the point distance may vary between 3/4 and 5/4 the supplied value const double range_random_point_dist = cfg.point_distance / 2.; @@ -1895,7 +1905,7 @@ static void group_region_by_fuzzify(PerimeterGenerator& g) scaled(region_config.fuzzy_skin_thickness.value), scaled(region_config.fuzzy_skin_point_distance.value), region_config.fuzzy_skin_first_layer, - region_config.fuzzy_skin_use_noise, + region_config.fuzzy_skin_noise_type, region_config.fuzzy_skin_scale, region_config.fuzzy_skin_octaves, region_config.fuzzy_skin_persistence diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index 7f45700bc8c..0b79cc40c29 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -16,7 +16,7 @@ struct FuzzySkinConfig coord_t thickness; coord_t point_distance; bool fuzzy_first_layer; - bool use_noise; + NoiseType noise_type; double noise_scale; int noise_octaves; double noise_persistence; @@ -27,7 +27,7 @@ struct FuzzySkinConfig && thickness == r.thickness && point_distance == r.point_distance && fuzzy_first_layer == r.fuzzy_first_layer - && use_noise == r.use_noise + && noise_type == r.noise_type && noise_scale == r.noise_scale && noise_octaves == r.noise_octaves && noise_persistence == r.noise_persistence; @@ -46,7 +46,7 @@ template<> struct hash boost::hash_combine(seed, std::hash{}(c.thickness)); boost::hash_combine(seed, std::hash{}(c.point_distance)); boost::hash_combine(seed, std::hash{}(c.fuzzy_first_layer)); - boost::hash_combine(seed, std::hash{}(c.use_noise)); + boost::hash_combine(seed, std::hash{}(c.noise_type)); boost::hash_combine(seed, std::hash{}(c.noise_scale)); boost::hash_combine(seed, std::hash{}(c.noise_octaves)); boost::hash_combine(seed, std::hash{}(c.noise_persistence)); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index a13dc0855db..1529f46acb2 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -769,7 +769,7 @@ static std::vector s_Preset_print_options { "minimum_sparse_infill_area", "reduce_infill_retraction","internal_solid_infill_pattern","gap_fill_target", "ironing_type", "ironing_pattern", "ironing_flow", "ironing_speed", "ironing_spacing", "ironing_angle", "max_travel_detour_distance", - "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_use_noise", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence", + "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type", "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence", "max_volumetric_extrusion_rate_slope", "max_volumetric_extrusion_rate_slope_segment_length", "inner_wall_speed", "outer_wall_speed", "sparse_infill_speed", "internal_solid_infill_speed", "top_surface_speed", "support_speed", "support_object_xy_distance", "support_interface_speed", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index a4b5a8372fa..92cc15353df 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -123,6 +123,15 @@ static t_config_enum_values s_keys_map_FuzzySkinType { }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(FuzzySkinType) +static t_config_enum_values s_keys_map_NoiseType { + { "classic", int(NoiseType::Classic) }, + { "perlin", int(NoiseType::Perlin) }, + { "billow", int(NoiseType::Billow) }, + { "ridgedmulti", int(NoiseType::RidgedMulti) }, + { "voronoi", int(NoiseType::Voronoi) } +}; +CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(NoiseType) + static t_config_enum_values s_keys_map_InfillPattern { { "concentric", ipConcentric }, { "zig-zag", ipRectilinear }, @@ -2606,12 +2615,23 @@ void PrintConfigDef::init_fff_params() def->mode = comSimple; def->set_default_value(new ConfigOptionBool(0)); - def = this->add("fuzzy_skin_use_noise", coBool); - def->label = L("Use Perlin noise for fuzzy skin"); + def = this->add("fuzzy_skin_noise_type", coEnum); + def->label = L("Fuzzy skin noise type"); def->category = L("Others"); - def->tooltip = L("Use Perlin noise to generate fuzzy skin. If disabled, the naive random generator will be used instead"); + def->tooltip = L("Noise type to use for fuzzy skin generation"); + def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); + def->enum_values.push_back("classic"); + def->enum_values.push_back("perlin"); + def->enum_values.push_back("billow"); + def->enum_values.push_back("ridgedmulti"); + def->enum_values.push_back("voronoi"); + def->enum_labels.push_back(L("Classic")); + def->enum_labels.push_back(L("Perlin")); + def->enum_labels.push_back(L("Billow")); + def->enum_labels.push_back(L("Ridged Multifractal")); + def->enum_labels.push_back(L("Voronoi")); def->mode = comSimple; - def->set_default_value(new ConfigOptionBool(0)); + def->set_default_value(new ConfigOptionEnum(NoiseType::Classic)); def = this->add("fuzzy_skin_scale", coFloat); def->label = L("Fuzzy skin noise scale"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 953f17226a0..0918824b91a 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -41,6 +41,14 @@ enum class FuzzySkinType { AllWalls, }; +enum class NoiseType { + Classic, + Perlin, + Billow, + RidgedMulti, + Voronoi, +}; + enum PrintHostType { htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htESP3D, htCrealityPrint, htObico, htFlashforge, htSimplyPrint }; @@ -392,6 +400,7 @@ static std::string get_bed_temp_1st_layer_key(const BedType type) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(PrinterTechnology) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeFlavor) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(FuzzySkinType) +CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(NoiseType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InfillPattern) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(IroningType) CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SlicingMode) @@ -906,7 +915,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloat, fuzzy_skin_thickness)) ((ConfigOptionFloat, fuzzy_skin_point_distance)) ((ConfigOptionBool, fuzzy_skin_first_layer)) - ((ConfigOptionBool, fuzzy_skin_use_noise)) + ((ConfigOptionEnum, fuzzy_skin_noise_type)) ((ConfigOptionFloat, fuzzy_skin_scale)) ((ConfigOptionInt, fuzzy_skin_octaves)) ((ConfigOptionFloat, fuzzy_skin_persistence)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index f31cbf1f553..36345f955a1 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1116,7 +1116,7 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "fuzzy_skin_thickness" || opt_key == "fuzzy_skin_point_distance" || opt_key == "fuzzy_skin_first_layer" - || opt_key == "fuzzy_skin_use_noise" + || opt_key == "fuzzy_skin_noise_type" || opt_key == "fuzzy_skin_scale" || opt_key == "fuzzy_skin_octaves" || opt_key == "fuzzy_skin_persistence" diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 69edee085cb..3fee6e7ae27 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -706,12 +706,13 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co toggle_line("support_interface_not_for_body",config->opt_int("support_interface_filament")&&!config->opt_int("support_filament")); bool has_fuzzy_skin = (config->opt_enum("fuzzy_skin") != FuzzySkinType::None); - for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_use_noise"}) + for (auto el : { "fuzzy_skin_thickness", "fuzzy_skin_point_distance", "fuzzy_skin_first_layer", "fuzzy_skin_noise_type"}) toggle_line(el, has_fuzzy_skin); - bool fuzzy_skin_use_noise = config->opt_bool("fuzzy_skin_use_noise"); - for (auto el : { "fuzzy_skin_scale", "fuzzy_skin_octaves", "fuzzy_skin_persistence"}) - toggle_line(el, has_fuzzy_skin && fuzzy_skin_use_noise); + NoiseType fuzzy_skin_noise_type = config->opt_enum("fuzzy_skin_noise_type"); + toggle_line("fuzzy_skin_scale", has_fuzzy_skin && fuzzy_skin_noise_type != NoiseType::Classic); + toggle_line("fuzzy_skin_octaves", has_fuzzy_skin && fuzzy_skin_noise_type != NoiseType::Classic && fuzzy_skin_noise_type != NoiseType::Voronoi); + toggle_line("fuzzy_skin_persistence", has_fuzzy_skin && (fuzzy_skin_noise_type == NoiseType::Perlin || fuzzy_skin_noise_type == NoiseType::Billow)); bool have_arachne = config->opt_enum("wall_generator") == PerimeterGeneratorType::Arachne; for (auto el : { "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 0fc828de938..583b2bfd865 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2349,7 +2349,7 @@ page = add_options_page(L("Others"), "custom-gcode_other"); // ORCA: icon only v optgroup->append_single_option_line("fuzzy_skin_point_distance"); optgroup->append_single_option_line("fuzzy_skin_thickness"); optgroup->append_single_option_line("fuzzy_skin_first_layer"); - optgroup->append_single_option_line("fuzzy_skin_use_noise"); + optgroup->append_single_option_line("fuzzy_skin_noise_type"); optgroup->append_single_option_line("fuzzy_skin_scale"); optgroup->append_single_option_line("fuzzy_skin_octaves"); optgroup->append_single_option_line("fuzzy_skin_persistence"); From 0c5d31da54d270366db9da4c5bddcfd8d90d41db Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Fri, 6 Dec 2024 12:36:22 +0000 Subject: [PATCH 3/4] Updated tooltips for more clarity. --- src/libslic3r/PrintConfig.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 92cc15353df..eded2f0eadb 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2618,7 +2618,12 @@ void PrintConfigDef::init_fff_params() def = this->add("fuzzy_skin_noise_type", coEnum); def->label = L("Fuzzy skin noise type"); def->category = L("Others"); - def->tooltip = L("Noise type to use for fuzzy skin generation"); + def->tooltip = L("Noise type to use for fuzzy skin generation.\n" + "Classic: Classic uniform random noise.\n" + "Perlin: Perlin noise, which gives a more consistent texture.\n" + "Billow: Similar to perlin noise, but clumpier.\n" + "Ridged Multifractal: Ridged noise with sharp, jagged features. Creates marble-like textures.\n" + "Voronoi: Divides the surface into voronoi cells, and displaces each one by a random amount. Creates a patchwork texture."); def->enum_keys_map = &ConfigOptionEnum::get_enum_values(); def->enum_values.push_back("classic"); def->enum_values.push_back("perlin"); @@ -2634,9 +2639,9 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionEnum(NoiseType::Classic)); def = this->add("fuzzy_skin_scale", coFloat); - def->label = L("Fuzzy skin noise scale"); + def->label = L("Fuzzy skin feature size"); def->category = L("Others"); - def->tooltip = L("The base size of the Perlin noise, in mm. Higher values will result in larger features."); + def->tooltip = L("The base size of the coherent noise features, in mm. Higher values will result in larger features."); def->sidetext = L("mm"); def->min = 0.1; def->max = 500; @@ -2646,7 +2651,7 @@ void PrintConfigDef::init_fff_params() def = this->add("fuzzy_skin_octaves", coInt); def->label = L("Fuzzy Skin Noise Octaves"); def->category = L("Others"); - def->tooltip = L("The number of octaves of perlin noise to use. Higher values increase the detail of the noise, but also increase computation time."); + def->tooltip = L("The number of octaves of coherent noise to use. Higher values increase the detail of the noise, but also increase computation time."); def->min = 1; def->max = 10; def->mode = comAdvanced; @@ -2655,7 +2660,7 @@ void PrintConfigDef::init_fff_params() def = this->add("fuzzy_skin_persistence", coFloat); def->label = L("Fuzzy skin noise persistence"); def->category = L("Others"); - def->tooltip = L("The decay rate for higher octaves of the Perlin noise. Lower values will result in smoother noise."); + def->tooltip = L("The decay rate for higher octaves of the coherent noise. Lower values will result in smoother noise."); def->min = 0.01; def->max = 1; def->mode = comAdvanced; From 6c1b0c29e17ea795c567d8333c42826d11400c28 Mon Sep 17 00:00:00 2001 From: Nick Johnson Date: Mon, 16 Dec 2024 08:48:45 +0000 Subject: [PATCH 4/4] Reorder options as suggested by @discip --- src/slic3r/GUI/Tab.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 583b2bfd865..b421b085db2 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2346,13 +2346,13 @@ page = add_options_page(L("Others"), "custom-gcode_other"); // ORCA: icon only v optgroup->append_single_option_line("timelapse_type", "Timelapse"); optgroup->append_single_option_line("fuzzy_skin"); + optgroup->append_single_option_line("fuzzy_skin_noise_type"); optgroup->append_single_option_line("fuzzy_skin_point_distance"); optgroup->append_single_option_line("fuzzy_skin_thickness"); - optgroup->append_single_option_line("fuzzy_skin_first_layer"); - optgroup->append_single_option_line("fuzzy_skin_noise_type"); optgroup->append_single_option_line("fuzzy_skin_scale"); optgroup->append_single_option_line("fuzzy_skin_octaves"); optgroup->append_single_option_line("fuzzy_skin_persistence"); + optgroup->append_single_option_line("fuzzy_skin_first_layer"); optgroup = page->new_optgroup(L("G-code output"), L"param_gcode"); optgroup->append_single_option_line("reduce_infill_retraction");