diff options
author | Campbell Barton <ideasman42@gmail.com> | 2011-10-06 20:59:58 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2011-10-06 20:59:58 +0400 |
commit | 8695bedda2cb57490bcea957b0a25eb85cb4c9a5 (patch) | |
tree | 4355e0c4f0e9492c53c7a9abf424748141ec320c | |
parent | 757f177d9d294451441c95f03dcf8327f59a4b98 (diff) | |
parent | 2bb59bc2734ac682208419e42aebf27285a88d22 (diff) |
svn merge ^/trunk/blender -r40644:40720
112 files changed, 7089 insertions, 7901 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b23959e5661..dddf06431e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -488,17 +488,17 @@ if(UNIX AND NOT APPLE) find_path(X11_XF86keysym_INCLUDE_PATH X11/XF86keysym.h ${X11_INC_SEARCH_PATH}) mark_as_advanced(X11_XF86keysym_INCLUDE_PATH) - list(APPEND PLATFORM_LINKLIBS ${X11_X11_LIB}) + set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS} ${X11_X11_LIB}") if(WITH_X11_XINPUT) - list(APPEND PLATFORM_LINKLIBS ${X11_Xinput_LIB}) + set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS} ${X11_Xinput_LIB}") endif() endif() if(CMAKE_SYSTEM_NAME MATCHES "Linux") if(NOT WITH_PYTHON_MODULE) # BSD's dont use libdl.so - list(APPEND PLATFORM_LINKLIBS -ldl) + set(PLATFORM_LINKLIBS "${PLATFORM_LINKLIBS} -ldl") # binreloc is linux only set(BINRELOC_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extern/binreloc/include) set(WITH_BINRELOC ON) diff --git a/GNUmakefile b/GNUmakefile index 9915406e52c..aad3c58938c 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -164,7 +164,7 @@ package_archive: # Other Targets # translations: - $(BUILD_DIR)/bin/blender --background --python po/update_msg.py + $(BUILD_DIR)/bin/blender --background --factory-startup --python po/update_msg.py python3 po/update_pot.py python3 po/update_po.py python3 po/update_mo.py diff --git a/SConstruct b/SConstruct index 42ee3342031..6de11d8fe4e 100644 --- a/SConstruct +++ b/SConstruct @@ -277,7 +277,7 @@ if env['OURPLATFORM']=='darwin': print "3D_CONNEXION_CLIENT_LIBRARY not found, disabling WITH_BF_3DMOUSE" # avoid build errors ! env['WITH_BF_3DMOUSE'] = 0 else: - env.Append(LINKFLAGS=['-weak_framework','3DconnexionClient']) + env.Append(LINKFLAGS=['-Xlinker','-weak_framework','-Xlinker','3DconnexionClient']) if env['WITH_BF_OPENMP'] == 1: if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'): diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index ef4edca1b22..8a665405e72 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -213,6 +213,7 @@ macro(setup_liblinks ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} + ${FREETYPE_LIBRARY} ${PLATFORM_LINKLIBS}) # since we are using the local libs for python when compiling msvc projects, we need to add _d when compiling debug versions @@ -233,13 +234,6 @@ macro(setup_liblinks target_link_libraries(${target} ${GLEW_LIBRARY}) endif() - target_link_libraries(${target} - ${OPENGL_glu_LIBRARY} - ${JPEG_LIBRARIES} - ${PNG_LIBRARIES} - ${ZLIB_LIBRARIES} - ${FREETYPE_LIBRARY}) - if(WITH_INTERNATIONAL) target_link_libraries(${target} ${GETTEXT_LIB}) diff --git a/build_files/scons/config/darwin-config.py b/build_files/scons/config/darwin-config.py index 29d2b39323e..935827e7237 100644 --- a/build_files/scons/config/darwin-config.py +++ b/build_files/scons/config/darwin-config.py @@ -90,9 +90,10 @@ LIBDIR = '${LCGDIR}' ################### Dependency settings ################## ############################################################################# -#Defaults openMP to true if compiler handles it -if CC == 'gcc-4.2' or CC == 'llvm-gcc-4.2': - WITH_BF_OPENMP = True # multithreading for fluids, cloth and smoke +#Defaults openMP to true if compiler handles it ( only gcc 4.6.1 and newer ) +# if your compiler does not have accurate suffix you may have to enable it by hand ! +if CC.endswith('4.6.1'): + WITH_BF_OPENMP = True # multithreading for fluids, cloth, sculpt and smoke else: WITH_BF_OPENMP = False diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index ca37030074a..c1bed089b5a 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -161,7 +161,7 @@ def range_str(val): def example_extract_docstring(filepath): - file = open(filepath, 'r') + file = open(filepath, "r", encoding="utf-8") line = file.readline() line_no = 0 text = [] @@ -360,7 +360,7 @@ def pymodule2sphinx(BASEPATH, module_name, module, title): if module_all: module_dir = module_all - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write @@ -510,7 +510,7 @@ def pycontext2sphinx(BASEPATH): # Only use once. very irregular filepath = os.path.join(BASEPATH, "bpy.context.rst") - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write fw("Context Access (bpy.context)\n") fw("============================\n\n") @@ -698,7 +698,7 @@ def pyrna2sphinx(BASEPATH): # return filepath = os.path.join(BASEPATH, "bpy.types.%s.rst" % struct.identifier) - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write base_id = getattr(struct.base, "identifier", "") @@ -912,7 +912,7 @@ def pyrna2sphinx(BASEPATH): def fake_bpy_type(class_value, class_name, descr_str, use_subclasses=True): filepath = os.path.join(BASEPATH, "bpy.types.%s.rst" % class_name) - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write write_title(fw, class_name, "=") @@ -963,7 +963,7 @@ def pyrna2sphinx(BASEPATH): for op_module_name, ops_mod in op_modules.items(): filepath = os.path.join(BASEPATH, "bpy.ops.%s.rst" % op_module_name) - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write title = "%s Operators" % op_module_name.replace("_", " ").title() @@ -1017,7 +1017,7 @@ def rna2sphinx(BASEPATH): # conf.py - empty for now filepath = os.path.join(BASEPATH, "conf.py") - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write version_string = ".".join(str(v) for v in bpy.app.version) @@ -1053,7 +1053,7 @@ def rna2sphinx(BASEPATH): # main page needed for sphinx (index.html) filepath = os.path.join(BASEPATH, "contents.rst") - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write fw("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n") @@ -1169,7 +1169,7 @@ def rna2sphinx(BASEPATH): # internal modules if "bpy.ops" not in EXCLUDE_MODULES: filepath = os.path.join(BASEPATH, "bpy.ops.rst") - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write fw("Operators (bpy.ops)\n") fw("===================\n\n") @@ -1181,7 +1181,7 @@ def rna2sphinx(BASEPATH): if "bpy.types" not in EXCLUDE_MODULES: filepath = os.path.join(BASEPATH, "bpy.types.rst") - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write fw("Types (bpy.types)\n") fw("=================\n\n") @@ -1194,7 +1194,7 @@ def rna2sphinx(BASEPATH): # not actually a module, only write this file so we # can reference in the TOC filepath = os.path.join(BASEPATH, "bpy.data.rst") - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write fw("Data Access (bpy.data)\n") fw("======================\n\n") @@ -1284,7 +1284,7 @@ def rna2sphinx(BASEPATH): if 0: filepath = os.path.join(BASEPATH, "bpy.rst") - file = open(filepath, "w") + file = open(filepath, "w", encoding="utf-8") fw = file.write fw("\n") diff --git a/extern/recastnavigation/CMakeLists.txt b/extern/recastnavigation/CMakeLists.txt index 660b881dd07..3d8b7ab1513 100644 --- a/extern/recastnavigation/CMakeLists.txt +++ b/extern/recastnavigation/CMakeLists.txt @@ -53,18 +53,19 @@ set(SRC Detour/Include/DetourTileNavMeshBuilder.h Recast/Source/Recast.cpp + Recast/Source/RecastAlloc.cpp + Recast/Source/RecastArea.cpp Recast/Source/RecastContour.cpp Recast/Source/RecastFilter.cpp - Recast/Source/RecastLog.cpp + Recast/Source/RecastLayers.cpp Recast/Source/RecastMesh.cpp Recast/Source/RecastMeshDetail.cpp Recast/Source/RecastRasterization.cpp Recast/Source/RecastRegion.cpp - Recast/Source/RecastTimer.cpp Recast/Include/Recast.h - Recast/Include/RecastLog.h - Recast/Include/RecastTimer.h + Recast/Include/RecastAlloc.h + Recast/Include/RecastAssert.h ) blender_add_lib(extern_recastnavigation "${SRC}" "${INC}" "${INC_SYS}") diff --git a/extern/recastnavigation/Recast/Include/Recast.h b/extern/recastnavigation/Recast/Include/Recast.h index f25ab47f8fa..4e20b0f0fff 100644 --- a/extern/recastnavigation/Recast/Include/Recast.h +++ b/extern/recastnavigation/Recast/Include/Recast.h @@ -1,5 +1,5 @@ // -// Copyright (c) 2009 Mikko Mononen memon@inside.org +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -19,298 +19,685 @@ #ifndef RECAST_H #define RECAST_H -// The units of the parameters are specified in parenthesis as follows: -// (vx) voxels, (wu) world units -struct rcConfig +/// The value of PI used by Recast. +static const float RC_PI = 3.14159265f; + +/// Recast log categories. +/// @see rcContext +enum rcLogCategory { - int width, height; // Dimensions of the rasterized heighfield (vx) - int tileSize; // Width and Height of a tile (vx) - int borderSize; // Non-navigable Border around the heightfield (vx) - float cs, ch; // Grid cell size and height (wu) - float bmin[3], bmax[3]; // Grid bounds (wu) - float walkableSlopeAngle; // Maximum walkble slope angle in degrees. - int walkableHeight; // Minimum height where the agent can still walk (vx) - int walkableClimb; // Maximum height between grid cells the agent can climb (vx) - int walkableRadius; // Radius of the agent in cells (vx) - int maxEdgeLen; // Maximum contour edge length (vx) - float maxSimplificationError; // Maximum distance error from contour to cells (vx) - int minRegionSize; // Minimum regions size. Smaller regions will be deleted (vx) - int mergeRegionSize; // Minimum regions size. Smaller regions will be merged (vx) - int maxVertsPerPoly; // Max number of vertices per polygon - float detailSampleDist; // Detail mesh sample spacing. - float detailSampleMaxError; // Detail mesh simplification max sample error. + RC_LOG_PROGRESS = 1, ///< A progress log entry. + RC_LOG_WARNING, ///< A warning log entry. + RC_LOG_ERROR, ///< An error log entry. }; -// Heightfield span. -struct rcSpan +/// Recast performance timer categories. +/// @see rcContext +enum rcTimerLabel +{ + /// The user defined total time of the build. + RC_TIMER_TOTAL, + /// A user defined build time. + RC_TIMER_TEMP, + /// The time to rasterize the triangles. (See: #rcRasterizeTriangle) + RC_TIMER_RASTERIZE_TRIANGLES, + /// The time to build the compact heightfield. (See: #rcBuildCompactHeightfield) + RC_TIMER_BUILD_COMPACTHEIGHTFIELD, + /// The total time to build the contours. (See: #rcBuildContours) + RC_TIMER_BUILD_CONTOURS, + /// The time to trace the boundaries of the contours. (See: #rcBuildContours) + RC_TIMER_BUILD_CONTOURS_TRACE, + /// The time to simplify the contours. (See: #rcBuildContours) + RC_TIMER_BUILD_CONTOURS_SIMPLIFY, + /// The time to filter ledge spans. (See: #rcFilterLedgeSpans) + RC_TIMER_FILTER_BORDER, + /// The time to filter low height spans. (See: #rcFilterWalkableLowHeightSpans) + RC_TIMER_FILTER_WALKABLE, + /// The time to apply the median filter. (See: #rcMedianFilterWalkableArea) + RC_TIMER_MEDIAN_AREA, + /// The time to filter low obstacles. (See: #rcFilterLowHangingWalkableObstacles) + RC_TIMER_FILTER_LOW_OBSTACLES, + /// The time to build the polygon mesh. (See: #rcBuildPolyMesh) + RC_TIMER_BUILD_POLYMESH, + /// The time to merge polygon meshes. (See: #rcMergePolyMeshes) + RC_TIMER_MERGE_POLYMESH, + /// The time to erode the walkable area. (See: #rcErodeWalkableArea) + RC_TIMER_ERODE_AREA, + /// The time to mark a box area. (See: #rcMarkBoxArea) + RC_TIMER_MARK_BOX_AREA, + /// The time to mark a cylinder area. (See: #rcMarkCylinderArea) + RC_TIMER_MARK_CYLINDER_AREA, + /// The time to mark a convex polygon area. (See: #rcMarkConvexPolyArea) + RC_TIMER_MARK_CONVEXPOLY_AREA, + /// The total time to build the distance field. (See: #rcBuildDistanceField) + RC_TIMER_BUILD_DISTANCEFIELD, + /// The time to build the distances of the distance field. (See: #rcBuildDistanceField) + RC_TIMER_BUILD_DISTANCEFIELD_DIST, + /// The time to blur the distance field. (See: #rcBuildDistanceField) + RC_TIMER_BUILD_DISTANCEFIELD_BLUR, + /// The total time to build the regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone) + RC_TIMER_BUILD_REGIONS, + /// The total time to apply the watershed algorithm. (See: #rcBuildRegions) + RC_TIMER_BUILD_REGIONS_WATERSHED, + /// The time to expand regions while applying the watershed algorithm. (See: #rcBuildRegions) + RC_TIMER_BUILD_REGIONS_EXPAND, + /// The time to flood regions while applying the watershed algorithm. (See: #rcBuildRegions) + RC_TIMER_BUILD_REGIONS_FLOOD, + /// The time to filter out small regions. (See: #rcBuildRegions, #rcBuildRegionsMonotone) + RC_TIMER_BUILD_REGIONS_FILTER, + /// The time to build heightfield layers. (See: #rcBuildHeightfieldLayers) + RC_TIMER_BUILD_LAYERS, + /// The time to build the polygon mesh detail. (See: #rcBuildPolyMeshDetail) + RC_TIMER_BUILD_POLYMESHDETAIL, + /// The time to merge polygon mesh details. (See: #rcMergePolyMeshDetails) + RC_TIMER_MERGE_POLYMESHDETAIL, + /// The maximum number of timers. (Used for iterating timers.) + RC_MAX_TIMERS +}; + +/// Provides an interface for optional logging and performance tracking of the Recast +/// build process. +/// @ingroup recast +class rcContext +{ +public: + + /// Contructor. + /// @param[in] state TRUE if the logging and performance timers should be enabled. [Default: true] + inline rcContext(bool state = true) : m_logEnabled(state), m_timerEnabled(state) {} + virtual ~rcContext() {} + + /// Enables or disables logging. + /// @param[in] state TRUE if logging should be enabled. + inline void enableLog(bool state) { m_logEnabled = state; } + + /// Clears all log entries. + inline void resetLog() { if (m_logEnabled) doResetLog(); } + + /// Logs a message. + /// @param[in] category The category of the message. + /// @param[in] format The message. + void log(const rcLogCategory category, const char* format, ...); + + /// Enables or disables the performance timers. + /// @param[in] state TRUE if timers should be enabled. + inline void enableTimer(bool state) { m_timerEnabled = state; } + + /// Clears all peformance timers. (Resets all to unused.) + inline void resetTimers() { if (m_timerEnabled) doResetTimers(); } + + /// Starts the specified performance timer. + /// @param label The category of timer. + inline void startTimer(const rcTimerLabel label) { if (m_timerEnabled) doStartTimer(label); } + + /// Stops the specified performance timer. + /// @param label The category of the timer. + inline void stopTimer(const rcTimerLabel label) { if (m_timerEnabled) doStopTimer(label); } + + /// Returns the total accumulated time of the specified performance timer. + /// @param label The category of the timer. + /// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started. + inline int getAccumulatedTime(const rcTimerLabel label) const { return m_timerEnabled ? doGetAccumulatedTime(label) : -1; } + +protected: + + /// Clears all log entries. + virtual void doResetLog() {} + + /// Logs a message. + /// @param[in] category The category of the message. + /// @param[in] msg The formatted message. + /// @param[in] len The length of the formatted message. + virtual void doLog(const rcLogCategory /*category*/, const char* /*msg*/, const int /*len*/) {} + + /// Clears all timers. (Resets all to unused.) + virtual void doResetTimers() {} + + /// Starts the specified performance timer. + /// @param[in] label The category of timer. + virtual void doStartTimer(const rcTimerLabel /*label*/) {} + + /// Stops the specified performance timer. + /// @param[in] label The category of the timer. + virtual void doStopTimer(const rcTimerLabel /*label*/) {} + + /// Returns the total accumulated time of the specified performance timer. + /// @param[in] label The category of the timer. + /// @return The accumulated time of the timer, or -1 if timers are disabled or the timer has never been started. + virtual int doGetAccumulatedTime(const rcTimerLabel /*label*/) const { return -1; } + + /// True if logging is enabled. + bool m_logEnabled; + + /// True if the performance timers are enabled. + bool m_timerEnabled; +}; + +/// Specifies a configuration to use when performing Recast builds. +/// @ingroup recast +struct rcConfig { - unsigned int smin : 15; // Span min height. - unsigned int smax : 15; // Span max height. - unsigned int flags : 2; // Span flags. - rcSpan* next; // Next span in column. + /// The width of the field along the x-axis. [Limit: >= 0] [Units: vx] + int width; + + /// The height of the field along the z-axis. [Limit: >= 0] [Units: vx] + int height; + + /// The width/height size of tile's on the xz-plane. [Limit: >= 0] [Units: vx] + int tileSize; + + /// The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx] + int borderSize; + + /// The xz-plane cell size to use for fields. [Limit: > 0] [Units: wu] + float cs; + + /// The y-axis cell size to use for fields. [Limit: > 0] [Units: wu] + float ch; + + /// The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] + float bmin[3]; + + /// The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] + float bmax[3]; + + /// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees] + float walkableSlopeAngle; + + /// Minimum floor to 'ceiling' height that will still allow the floor area to + /// be considered walkable. [Limit: >= 3] [Units: vx] + int walkableHeight; + + /// Maximum ledge height that is considered to still be traversable. [Limit: >=0] [Units: vx] + int walkableClimb; + + /// The distance to erode/shrink the walkable area of the heightfield away from + /// obstructions. [Limit: >=0] [Units: vx] + int walkableRadius; + + /// The maximum allowed length for contour edges along the border of the mesh. [Limit: >=0] [Units: vx] + int maxEdgeLen; + + /// The maximum distance a simplfied contour's border edges should deviate + /// the original raw contour. [Limit: >=0] [Units: wu] + float maxSimplificationError; + + /// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx] + int minRegionArea; + + /// Any regions with a span count smaller than this value will, if possible, + /// be merged with larger regions. [Limit: >=0] [Units: vx] + int mergeRegionArea; + + /// The maximum number of vertices allowed for polygons generated during the + /// contour to polygon conversion process. [Limit: >= 3] + int maxVertsPerPoly; + + /// Sets the sampling distance to use when generating the detail mesh. + /// (For height detail only.) [Limits: 0 or >= 0.9] [Units: wu] + float detailSampleDist; + + /// The maximum distance the detail mesh surface should deviate from heightfield + /// data. (For height detail only.) [Limit: >=0] [Units: wu] + float detailSampleMaxError; }; +/// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax. +static const int RC_SPAN_HEIGHT_BITS = 13; +/// Defines the maximum value for rcSpan::smin and rcSpan::smax. +static const int RC_SPAN_MAX_HEIGHT = (1<<RC_SPAN_HEIGHT_BITS)-1; + +/// The number of spans allocated per span spool. +/// @see rcSpanPool static const int RC_SPANS_PER_POOL = 2048; -// Memory pool used for quick span allocation. +/// Represents a span in a heightfield. +/// @see rcHeightfield +struct rcSpan +{ + unsigned int smin : 13; ///< The lower limit of the span. [Limit: < #smax] + unsigned int smax : 13; ///< The upper limit of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] + unsigned int area : 6; ///< The area id assigned to the span. + rcSpan* next; ///< The next span higher up in column. +}; + +/// A memory pool used for quick allocation of spans within a heightfield. +/// @see rcHeightfield struct rcSpanPool { - rcSpanPool* next; // Pointer to next pool. - rcSpan items[1]; // Array of spans (size RC_SPANS_PER_POOL). + rcSpanPool* next; ///< The next span pool. + rcSpan items[RC_SPANS_PER_POOL]; ///< Array of spans in the pool. }; -// Dynamic span-heightfield. +/// A dynamic heightfield representing obstructed space. +/// @ingroup recast struct rcHeightfield { - inline rcHeightfield() : width(0), height(0), spans(0), pools(0), freelist(0) {} - inline ~rcHeightfield() - { - // Delete span array. - delete [] spans; - // Delete span pools. - while (pools) - { - rcSpanPool* next = pools->next; - delete [] reinterpret_cast<unsigned char*>(pools); - pools = next; - } - } - int width, height; // Dimension of the heightfield. - float bmin[3], bmax[3]; // Bounding box of the heightfield - float cs, ch; // Cell size and height. - rcSpan** spans; // Heightfield of spans (width*height). - rcSpanPool* pools; // Linked list of span pools. - rcSpan* freelist; // Pointer to next free span. + int width; ///< The width of the heightfield. (Along the x-axis in cell units.) + int height; ///< The height of the heightfield. (Along the z-axis in cell units.) + float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)] + float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)] + float cs; ///< The size of each cell. (On the xz-plane.) + float ch; ///< The height of each cell. (The minimum increment along the y-axis.) + rcSpan** spans; ///< Heightfield of spans (width*height). + rcSpanPool* pools; ///< Linked list of span pools. + rcSpan* freelist; ///< The next free span. }; +/// Provides information on the content of a cell column in a compact heightfield. struct rcCompactCell { - unsigned int index : 24; // Index to first span in column. - unsigned int count : 8; // Number of spans in this column. + unsigned int index : 24; ///< Index to the first span in the column. + unsigned int count : 8; ///< Number of spans in the column. }; +/// Represents a span of unobstructed space within a compact heightfield. struct rcCompactSpan { - unsigned short y; // Bottom coordinate of the span. - unsigned short reg; // Region ID - unsigned short dist; // Distance to border - unsigned short con; // Connections to neighbour cells. - unsigned char h; // Height of the span. - unsigned char flags; // Flags. + unsigned short y; ///< The lower extent of the span. (Measured from the heightfield's base.) + unsigned short reg; ///< The id of the region the span belongs to. (Or zero if not in a region.) + unsigned int con : 24; ///< Packed neighbor connection data. + unsigned int h : 8; ///< The height of the span. (Measured from #y.) }; -// Compact static heightfield. +/// A compact, static heightfield representing unobstructed space. +/// @ingroup recast struct rcCompactHeightfield { - inline rcCompactHeightfield() : maxDistance(0), maxRegions(0), cells(0), spans(0) {} - inline ~rcCompactHeightfield() { delete [] cells; delete [] spans; } - int width, height; // Width and height of the heighfield. - int spanCount; // Number of spans in the heightfield. - int walkableHeight, walkableClimb; // Agent properties. - unsigned short maxDistance; // Maximum distance value stored in heightfield. - unsigned short maxRegions; // Maximum Region Id stored in heightfield. - float bmin[3], bmax[3]; // Bounding box of the heightfield. - float cs, ch; // Cell size and height. - rcCompactCell* cells; // Pointer to width*height cells. - rcCompactSpan* spans; // Pointer to spans. + int width; ///< The width of the heightfield. (Along the x-axis in cell units.) + int height; ///< The height of the heightfield. (Along the z-axis in cell units.) + int spanCount; ///< The number of spans in the heightfield. + int walkableHeight; ///< The walkable height used during the build of the field. (See: rcConfig::walkableHeight) + int walkableClimb; ///< The walkable climb used during the build of the field. (See: rcConfig::walkableClimb) + int borderSize; ///< The AABB border size used during the build of the field. (See: rcConfig::borderSize) + unsigned short maxDistance; ///< The maximum distance value of any span within the field. + unsigned short maxRegions; ///< The maximum region id of any span within the field. + float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)] + float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)] + float cs; ///< The size of each cell. (On the xz-plane.) + float ch; ///< The height of each cell. (The minimum increment along the y-axis.) + rcCompactCell* cells; ///< Array of cells. [Size: #width*#height] + rcCompactSpan* spans; ///< Array of spans. [Size: #spanCount] + unsigned short* dist; ///< Array containing border distance data. [Size: #spanCount] + unsigned char* areas; ///< Array containing area id data. [Size: #spanCount] +}; + +/// Represents a heightfield layer within a layer set. +/// @see rcHeightfieldLayerSet +struct rcHeightfieldLayer +{ + float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)] + float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)] + float cs; ///< The size of each cell. (On the xz-plane.) + float ch; ///< The height of each cell. (The minimum increment along the y-axis.) + int width; ///< The width of the heightfield. (Along the x-axis in cell units.) + int height; ///< The height of the heightfield. (Along the z-axis in cell units.) + int minx; ///< The minimum x-bounds of usable data. + int maxx; ///< The maximum x-bounds of usable data. + int miny; ///< The minimum y-bounds of usable data. (Along the z-axis.) + int maxy; ///< The maximum y-bounds of usable data. (Along the z-axis.) + int hmin; ///< The minimum height bounds of usable data. (Along the y-axis.) + int hmax; ///< The maximum height bounds of usable data. (Along the y-axis.) + unsigned char* heights; ///< The heightfield. [Size: (width - borderSize*2) * (h - borderSize*2)] + unsigned char* areas; ///< Area ids. [Size: Same as #heights] + unsigned char* cons; ///< Packed neighbor connection information. [Size: Same as #heights] +}; + +/// Represents a set of heightfield layers. +/// @ingroup recast +/// @see rcAllocHeightfieldLayerSet, rcFreeHeightfieldLayerSet +struct rcHeightfieldLayerSet +{ + rcHeightfieldLayer* layers; ///< The layers in the set. [Size: #nlayers] + int nlayers; ///< The number of layers in the set. }; +/// Represents a simple, non-overlapping contour in field space. struct rcContour { - inline rcContour() : verts(0), nverts(0), rverts(0), nrverts(0) { } - inline ~rcContour() { delete [] verts; delete [] rverts; } - int* verts; // Vertex coordinates, each vertex contains 4 components. - int nverts; // Number of vertices. - int* rverts; // Raw vertex coordinates, each vertex contains 4 components. - int nrverts; // Number of raw vertices. - unsigned short reg; // Region ID of the contour. + int* verts; ///< Simplified contour vertex and connection data. [Size: 4 * #nverts] + int nverts; ///< The number of vertices in the simplified contour. + int* rverts; ///< Raw contour vertex and connection data. [Size: 4 * #nrverts] + int nrverts; ///< The number of vertices in the raw contour. + unsigned short reg; ///< The region id of the contour. + unsigned char area; ///< The area id of the contour. }; +/// Represents a group of related contours. +/// @ingroup recast struct rcContourSet { - inline rcContourSet() : conts(0), nconts(0) {} - inline ~rcContourSet() { delete [] conts; } - rcContour* conts; // Pointer to all contours. - int nconts; // Number of contours. - float bmin[3], bmax[3]; // Bounding box of the heightfield. - float cs, ch; // Cell size and height. + rcContour* conts; ///< An array of the contours in the set. [Size: #nconts] + int nconts; ///< The number of contours in the set. + float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)] + float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)] + float cs; ///< The size of each cell. (On the xz-plane.) + float ch; ///< The height of each cell. (The minimum increment along the y-axis.) + int width; ///< The width of the set. (Along the x-axis in cell units.) + int height; ///< The height of the set. (Along the z-axis in cell units.) + int borderSize; ///< The AABB border size used to generate the source data from which the contours were derived. }; -// Polymesh store a connected mesh of polygons. -// The polygons are store in an array where each polygons takes -// 'nvp*2' elements. The first 'nvp' elements are indices to vertices -// and the second 'nvp' elements are indices to neighbour polygons. -// If a polygona has less than 'bvp' vertices, the remaining indices -// are set os 0xffff. If an polygon edge does not have a neighbour -// the neighbour index is set to 0xffff. -// Vertices can be transformed into world space as follows: -// x = bmin[0] + verts[i*3+0]*cs; -// y = bmin[1] + verts[i*3+1]*ch; -// z = bmin[2] + verts[i*3+2]*cs; +/// Represents a polygon mesh suitable for use in building a navigation mesh. +/// @ingroup recast struct rcPolyMesh -{ - inline rcPolyMesh() : verts(0), polys(0), regs(0), nverts(0), npolys(0), nvp(3) {} - inline ~rcPolyMesh() { delete [] verts; delete [] polys; delete [] regs; } - unsigned short* verts; // Vertices of the mesh, 3 elements per vertex. - unsigned short* polys; // Polygons of the mesh, nvp*2 elements per polygon. - unsigned short* regs; // Regions of the polygons. - int nverts; // Number of vertices. - int npolys; // Number of polygons. - int nvp; // Max number of vertices per polygon. - float bmin[3], bmax[3]; // Bounding box of the mesh. - float cs, ch; // Cell size and height. +{ + unsigned short* verts; ///< The mesh vertices. [Form: (x, y, z) * #nverts] + unsigned short* polys; ///< Polygon and neighbor data. [Length: #maxpolys * 2 * #nvp] + unsigned short* regs; ///< The region id assigned to each polygon. [Length: #maxpolys] + unsigned short* flags; ///< The user defined flags for each polygon. [Length: #maxpolys] + unsigned char* areas; ///< The area id assigned to each polygon. [Length: #maxpolys] + int nverts; ///< The number of vertices. + int npolys; ///< The number of polygons. + int maxpolys; ///< The number of allocated polygons. + int nvp; ///< The maximum number of vertices per polygon. + float bmin[3]; ///< The minimum bounds in world space. [(x, y, z)] + float bmax[3]; ///< The maximum bounds in world space. [(x, y, z)] + float cs; ///< The size of each cell. (On the xz-plane.) + float ch; ///< The height of each cell. (The minimum increment along the y-axis.) + int borderSize; ///< The AABB border size used to generate the source data from which the mesh was derived. }; -// Detail mesh generated from a rcPolyMesh. -// Each submesh represents a polygon in the polymesh and they are stored in -// excatly same order. Each submesh is described as 4 values: -// base vertex, vertex count, base triangle, triangle count. That is, -// const unsigned char* t = &dtl.tris[(tbase+i)*3]; and -// const float* v = &dtl.verts[(vbase+t[j])*3]; -// If the input polygon has 'n' vertices, those vertices are first in the -// submesh vertex list. This allows to compres the mesh by not storing the -// first vertices and using the polymesh vertices instead. - +/// Contains triangle meshes that represent detailed height data associated +/// with the polygons in its associated polygon mesh object. +/// @ingroup recast struct rcPolyMeshDetail { - inline rcPolyMeshDetail() : - meshes(0), verts(0), tris(0), - nmeshes(0), nverts(0), ntris(0) {} - inline ~rcPolyMeshDetail() - { - delete [] meshes; delete [] verts; delete [] tris; - } - - unsigned short* meshes; // Pointer to all mesh data. - float* verts; // Pointer to all vertex data. - unsigned char* tris; // Pointer to all triangle data. - int nmeshes; // Number of meshes. - int nverts; // Number of total vertices. - int ntris; // Number of triangles. + unsigned int* meshes; ///< The sub-mesh data. [Size: 4*#nmeshes] + float* verts; ///< The mesh vertices. [Size: 3*#nverts] + unsigned char* tris; ///< The mesh triangles. [Size: 4*#ntris] + int nmeshes; ///< The number of sub-meshes defined by #meshes. + int nverts; ///< The number of vertices in #verts. + int ntris; ///< The number of triangles in #tris. }; +/// @name Allocation Functions +/// Functions used to allocate and de-allocate Recast objects. +/// @see rcAllocSetCustom +/// @{ -// Simple dynamic array ints. -class rcIntArray -{ - int* m_data; - int m_size, m_cap; -public: - inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {} - inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(n) { m_data = new int[n]; } - inline ~rcIntArray() { delete [] m_data; } - void resize(int n); - inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; } - inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; } - inline const int& operator[](int i) const { return m_data[i]; } - inline int& operator[](int i) { return m_data[i]; } - inline int size() const { return m_size; } -}; +/// Allocates a heightfield object using the Recast allocator. +/// @return A heightfield that is ready for initialization, or null on failure. +/// @ingroup recast +/// @see rcCreateHeightfield, rcFreeHeightField +rcHeightfield* rcAllocHeightfield(); -enum rcSpanFlags -{ - RC_WALKABLE = 0x01, - RC_REACHABLE = 0x02, -}; +/// Frees the specified heightfield object using the Recast allocator. +/// @param[in] hf A heightfield allocated using #rcAllocHeightfield +/// @ingroup recast +/// @see rcAllocHeightfield +void rcFreeHeightField(rcHeightfield* hf); + +/// Allocates a compact heightfield object using the Recast allocator. +/// @return A compact heightfield that is ready for initialization, or null on failure. +/// @ingroup recast +/// @see rcBuildCompactHeightfield, rcFreeCompactHeightfield +rcCompactHeightfield* rcAllocCompactHeightfield(); + +/// Frees the specified compact heightfield object using the Recast allocator. +/// @param[in] chf A compact heightfield allocated using #rcAllocCompactHeightfield +/// @ingroup recast +/// @see rcAllocCompactHeightfield +void rcFreeCompactHeightfield(rcCompactHeightfield* chf); + +/// Allocates a heightfield layer set using the Recast allocator. +/// @return A heightfield layer set that is ready for initialization, or null on failure. +/// @ingroup recast +/// @see rcBuildHeightfieldLayers, rcFreeHeightfieldLayerSet +rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet(); + +/// Frees the specified heightfield layer set using the Recast allocator. +/// @param[in] lset A heightfield layer set allocated using #rcAllocHeightfieldLayerSet +/// @ingroup recast +/// @see rcAllocHeightfieldLayerSet +void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset); + +/// Allocates a contour set object using the Recast allocator. +/// @return A contour set that is ready for initialization, or null on failure. +/// @ingroup recast +/// @see rcBuildContours, rcFreeContourSet +rcContourSet* rcAllocContourSet(); + +/// Frees the specified contour set using the Recast allocator. +/// @param[in] cset A contour set allocated using #rcAllocContourSet +/// @ingroup recast +/// @see rcAllocContourSet +void rcFreeContourSet(rcContourSet* cset); + +/// Allocates a polygon mesh object using the Recast allocator. +/// @return A polygon mesh that is ready for initialization, or null on failure. +/// @ingroup recast +/// @see rcBuildPolyMesh, rcFreePolyMesh +rcPolyMesh* rcAllocPolyMesh(); + +/// Frees the specified polygon mesh using the Recast allocator. +/// @param[in] pmesh A polygon mesh allocated using #rcAllocPolyMesh +/// @ingroup recast +/// @see rcAllocPolyMesh +void rcFreePolyMesh(rcPolyMesh* pmesh); + +/// Allocates a detail mesh object using the Recast allocator. +/// @return A detail mesh that is ready for initialization, or null on failure. +/// @ingroup recast +/// @see rcBuildPolyMeshDetail, rcFreePolyMeshDetail +rcPolyMeshDetail* rcAllocPolyMeshDetail(); + +/// Frees the specified detail mesh using the Recast allocator. +/// @param[in] dmesh A detail mesh allocated using #rcAllocPolyMeshDetail +/// @ingroup recast +/// @see rcAllocPolyMeshDetail +void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh); -// If heightfield region ID has the following bit set, the region is on border area -// and excluded from many calculations. +/// @} + +/// Heighfield border flag. +/// If a heightfield region ID has this bit set, then the region is a border +/// region and its spans are considered unwalkable. +/// (Used during the region and contour build process.) +/// @see rcCompactSpan::reg static const unsigned short RC_BORDER_REG = 0x8000; -// If contour region ID has the following bit set, the vertex will be later -// removed in order to match the segments and vertices at tile boundaries. +/// Border vertex flag. +/// If a region ID has this bit set, then the associated element lies on +/// a tile border. If a contour vertex's region ID has this bit set, the +/// vertex will later be removed in order to match the segments and vertices +/// at tile boundaries. +/// (Used during the build process.) +/// @see rcCompactSpan::reg, #rcContour::verts, #rcContour::rverts static const int RC_BORDER_VERTEX = 0x10000; -// Compact span neighbour helpers. -inline int rcGetCon(const rcCompactSpan& s, int dir) -{ - return (s.con >> (dir*4)) & 0xf; -} +/// Area border flag. +/// If a region ID has this bit set, then the associated element lies on +/// the border of an area. +/// (Used during the region and contour build process.) +/// @see rcCompactSpan::reg, #rcContour::verts, #rcContour::rverts +static const int RC_AREA_BORDER = 0x20000; -inline int rcGetDirOffsetX(int dir) +/// Contour build flags. +/// @see rcBuildContours +enum rcBuildContoursFlags { - const int offset[4] = { -1, 0, 1, 0, }; - return offset[dir&0x03]; -} + RC_CONTOUR_TESS_WALL_EDGES = 0x01, ///< Tessellate solid (impassable) edges during contour simplification. + RC_CONTOUR_TESS_AREA_EDGES = 0x02, ///< Tessellate edges between areas during contour simplification. +}; -inline int rcGetDirOffsetY(int dir) -{ - const int offset[4] = { 0, 1, 0, -1 }; - return offset[dir&0x03]; -} +/// Applied to the region id field of contour vertices in order to extract the region id. +/// The region id field of a vertex may have several flags applied to it. So the +/// fields value can't be used directly. +/// @see rcContour::verts, rcContour::rverts +static const int RC_CONTOUR_REG_MASK = 0xffff; + +/// An value which indicates an invalid index within a mesh. +/// @note This does not necessarily indicate an error. +/// @see rcPolyMesh::polys +static const unsigned short RC_MESH_NULL_IDX = 0xffff; + +/// Represents the null area. +/// When a data element is given this value it is considered to no longer be +/// assigned to a usable area. (E.g. It is unwalkable.) +static const unsigned char RC_NULL_AREA = 0; + +/// The default area id used to indicate a walkable polygon. +/// This is also the maximum allowed area id, and the only non-null area id +/// recognized by some steps in the build process. +static const unsigned char RC_WALKABLE_AREA = 63; + +/// The value returned by #rcGetCon if the specified direction is not connected +/// to another span. (Has no neighbor.) +static const int RC_NOT_CONNECTED = 0x3f; + +/// @name General helper functions +/// @{ -// Common helper functions +/// Swaps the values of the two parameters. +/// @param[in,out] a Value A +/// @param[in,out] b Value B template<class T> inline void rcSwap(T& a, T& b) { T t = a; a = b; b = t; } + +/// Returns the minimum of two values. +/// @param[in] a Value A +/// @param[in] b Value B +/// @return The minimum of the two values. template<class T> inline T rcMin(T a, T b) { return a < b ? a : b; } + +/// Returns the maximum of two values. +/// @param[in] a Value A +/// @param[in] b Value B +/// @return The maximum of the two values. template<class T> inline T rcMax(T a, T b) { return a > b ? a : b; } + +/// Returns the absolute value. +/// @param[in] a The value. +/// @return The absolute value of the specified value. template<class T> inline T rcAbs(T a) { return a < 0 ? -a : a; } + +/// Return the square of a value. +/// @param[in] a The value. +/// @return The square of the value. template<class T> inline T rcSqr(T a) { return a*a; } + +/// Clamps the value to the specified range. +/// @param[in] v The value to clamp. +/// @param[in] mn The minimum permitted return value. +/// @param[in] mx The maximum permitted return value. +/// @return The value, clamped to the specified range. template<class T> inline T rcClamp(T v, T mn, T mx) { return v < mn ? mn : (v > mx ? mx : v); } -// Common vector helper functions. -inline void vcross(float* dest, const float* v1, const float* v2) +/// Returns the square root of the value. +/// @param[in] x The value. +/// @return The square root of the vlaue. +float rcSqrt(float x); + +/// Not documented. Internal use only. +/// @param[in] x Not documented. +/// @return Not documented. +inline int rcAlign4(int x) { return (x+3) & ~3; } + +/// @} +/// @name Vector helper functions. +/// @{ + +/// Derives the cross product of two vectors. (v1 x v2) +/// @param[out] dest The cross product. [(x, y, z)] +/// @param[in] v1 A Vector [(x, y, z)] +/// @param[in] v2 A vector [(x, y, z)] +inline void rcVcross(float* dest, const float* v1, const float* v2) { dest[0] = v1[1]*v2[2] - v1[2]*v2[1]; dest[1] = v1[2]*v2[0] - v1[0]*v2[2]; - dest[2] = v1[0]*v2[1] - v1[1]*v2[0]; + dest[2] = v1[0]*v2[1] - v1[1]*v2[0]; } -inline float vdot(const float* v1, const float* v2) +/// Derives the dot product of two vectors. (v1 . v2) +/// @param[in] v1 A Vector [(x, y, z)] +/// @param[in] v2 A vector [(x, y, z)] +/// @return The dot product. +inline float rcVdot(const float* v1, const float* v2) { return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; } -inline void vmad(float* dest, const float* v1, const float* v2, const float s) +/// Performs a scaled vector addition. (v1 + (v2 * s)) +/// @param[out] dest The result vector. [(x, y, z)] +/// @param[in] v1 The base vector [(x, y, z)] +/// @param[in] v2 The vector to scale and add to @p v1. [(x, y, z)] +/// @param[in] s The amount to scale @p v2 by before adding to @p v1. +inline void rcVmad(float* dest, const float* v1, const float* v2, const float s) { dest[0] = v1[0]+v2[0]*s; dest[1] = v1[1]+v2[1]*s; dest[2] = v1[2]+v2[2]*s; } -inline void vadd(float* dest, const float* v1, const float* v2) +/// Performs a vector addition. (@p v1 + @p v2) +/// @param[out] dest The result vector. [(x, y, z)] +/// @param[in] v1 The base vector [(x, y, z)] +/// @param[in] v2 The vector to add to @p v1. [(x, y, z)] +inline void rcVadd(float* dest, const float* v1, const float* v2) { dest[0] = v1[0]+v2[0]; dest[1] = v1[1]+v2[1]; dest[2] = v1[2]+v2[2]; } -inline void vsub(float* dest, const float* v1, const float* v2) +/// Performs a vector subtraction. (@p v1 - @p v2) +/// @param[out] dest The result vector. [(x, y, z)] +/// @param[in] v1 The base vector [(x, y, z)] +/// @param[in] v2 The vector to subtract from @p v1. [(x, y, z)] +inline void rcVsub(float* dest, const float* v1, const float* v2) { dest[0] = v1[0]-v2[0]; dest[1] = v1[1]-v2[1]; dest[2] = v1[2]-v2[2]; } -inline void vmin(float* mn, const float* v) +/// Selects the minimum value of each element from the specified vectors. +/// @param[in, out] mn A vector. (Will be updated with the result.) [(x, y, z)] +/// @param[in] v A vector. [(x, y, z)] +inline void rcVmin(float* mn, const float* v) { mn[0] = rcMin(mn[0], v[0]); mn[1] = rcMin(mn[1], v[1]); mn[2] = rcMin(mn[2], v[2]); } -inline void vmax(float* mx, const float* v) +/// Selects the maximum value of each element from the specified vectors. +/// @param[in, out] mx A vector. (Will be updated with the result.) [(x, y, z)] +/// @param[in] v A vector. [(x, y, z)] +inline void rcVmax(float* mx, const float* v) { mx[0] = rcMax(mx[0], v[0]); mx[1] = rcMax(mx[1], v[1]); mx[2] = rcMax(mx[2], v[2]); } -inline void vcopy(float* dest, const float* v) +/// Performs a vector copy. +/// @param[out] dest The result. [(x, y, z)] +/// @param[in] v The vector to copy [(x, y, z)] +inline void rcVcopy(float* dest, const float* v) { dest[0] = v[0]; dest[1] = v[1]; dest[2] = v[2]; } -inline float vdist(const float* v1, const float* v2) +/// Returns the distance between two points. +/// @param[in] v1 A point. [(x, y, z)] +/// @param[in] v2 A point. [(x, y, z)] +/// @return The distance between the two points. +inline float rcVdist(const float* v1, const float* v2) { float dx = v2[0] - v1[0]; float dy = v2[1] - v1[1]; float dz = v2[2] - v1[2]; - return sqrtf(dx*dx + dy*dy + dz*dz); + return rcSqrt(dx*dx + dy*dy + dz*dz); } -inline float vdistSqr(const float* v1, const float* v2) +/// Returns the square of the distance between two points. +/// @param[in] v1 A point. [(x, y, z)] +/// @param[in] v2 A point. [(x, y, z)] +/// @return The square of the distance between the two points. +inline float rcVdistSqr(const float* v1, const float* v2) { float dx = v2[0] - v1[0]; float dy = v2[1] - v1[1]; @@ -318,184 +705,424 @@ inline float vdistSqr(const float* v1, const float* v2) return dx*dx + dy*dy + dz*dz; } -inline void vnormalize(float* v) +/// Normalizes the vector. +/// @param[in,out] v The vector to normalize. [(x, y, z)] +inline void rcVnormalize(float* v) { - float d = 1.0f / sqrtf(rcSqr(v[0]) + rcSqr(v[1]) + rcSqr(v[2])); + float d = 1.0f / rcSqrt(rcSqr(v[0]) + rcSqr(v[1]) + rcSqr(v[2])); v[0] *= d; v[1] *= d; v[2] *= d; } -inline bool vequal(const float* p0, const float* p1) +/// Not documented. Internal use only. +/// @param[in] p0 Not documented. +/// @param[in] p1 Not documented. +/// @return Not documented. +inline bool rcVequal(const float* p0, const float* p1) { static const float thr = rcSqr(1.0f/16384.0f); - const float d = vdistSqr(p0, p1); + const float d = rcVdistSqr(p0, p1); return d < thr; } +/// @} +/// @name Heightfield Functions +/// @see rcHeightfield +/// @{ -// Calculated bounding box of array of vertices. -// Params: -// verts - (in) array of vertices -// nv - (in) vertex count -// bmin, bmax - (out) bounding box +/// Calculates the bounding box of an array of vertices. +/// @ingroup recast +/// @param[in] verts An array of vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices in the @p verts array. +/// @param[out] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu] +/// @param[out] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu] void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax); -// Calculates grid size based on bounding box and grid cell size. -// Params: -// bmin, bmax - (in) bounding box -// cs - (in) grid cell size -// w - (out) grid width -// h - (out) grid height +/// Calculates the grid size based on the bounding box and grid cell size. +/// @ingroup recast +/// @param[in] bmin The minimum bounds of the AABB. [(x, y, z)] [Units: wu] +/// @param[in] bmax The maximum bounds of the AABB. [(x, y, z)] [Units: wu] +/// @param[in] cs The xz-plane cell size. [Limit: > 0] [Units: wu] +/// @param[out] w The width along the x-axis. [Limit: >= 0] [Units: vx] +/// @param[out] h The height along the z-axis. [Limit: >= 0] [Units: vx] void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* h); -// Creates and initializes new heightfield. -// Params: -// hf - (in/out) heightfield to initialize. -// width - (in) width of the heightfield. -// height - (in) height of the heightfield. -// bmin, bmax - (in) bounding box of the heightfield -// cs - (in) grid cell size -// ch - (in) grid cell height -bool rcCreateHeightfield(rcHeightfield& hf, int width, int height, +/// Initializes a new heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] hf The allocated heightfield to initialize. +/// @param[in] width The width of the field along the x-axis. [Limit: >= 0] [Units: vx] +/// @param[in] height The height of the field along the z-axis. [Limit: >= 0] [Units: vx] +/// @param[in] bmin The minimum bounds of the field's AABB. [(x, y, z)] [Units: wu] +/// @param[in] bmax The maximum bounds of the field's AABB. [(x, y, z)] [Units: wu] +/// @param[in] cs The xz-plane cell size to use for the field. [Limit: > 0] [Units: wu] +/// @param[in] ch The y-axis cell size to use for field. [Limit: > 0] [Units: wu] +bool rcCreateHeightfield(rcContext* ctx, rcHeightfield& hf, int width, int height, const float* bmin, const float* bmax, float cs, float ch); -// Sets the WALKABLE flag for every triangle whose slope is below -// the maximun walkable slope angle. -// Params: -// walkableSlopeAngle - (in) maximun slope angle in degrees. -// verts - (in) array of vertices -// nv - (in) vertex count -// tris - (in) array of triangle vertex indices -// nt - (in) triangle count -// flags - (out) array of triangle flags -void rcMarkWalkableTriangles(const float walkableSlopeAngle, - const float* verts, int nv, - const int* tris, int nt, - unsigned char* flags); - -// Rasterizes a triangle into heightfield spans. -// Params: -// v0,v1,v2 - (in) the vertices of the triangle. -// flags - (in) triangle flags (uses WALKABLE) -// solid - (in) heighfield where the triangle is rasterized -void rcRasterizeTriangle(const float* v0, const float* v1, const float* v2, - unsigned char flags, rcHeightfield& solid); - -// Rasterizes the triangles into heightfield spans. -// Params: -// verts - (in) array of vertices -// nv - (in) vertex count -// tris - (in) array of triangle vertex indices -// norms - (in) array of triangle normals -// flags - (in) array of triangle flags (uses WALKABLE) -// nt - (in) triangle count -// solid - (in) heighfield where the triangles are rasterized -void rcRasterizeTriangles(const float* verts, int nv, - const int* tris, const unsigned char* flags, int nt, - rcHeightfield& solid); - -// Removes WALKABLE flag from all spans that are at ledges. This filtering -// removes possible overestimation of the conservative voxelization so that -// the resulting mesh will not have regions hanging in air over ledges. -// Params: -// walkableHeight - (in) minimum height where the agent can still walk -// walkableClimb - (in) maximum height between grid cells the agent can climb -// solid - (in/out) heightfield describing the solid space -void rcFilterLedgeSpans(const int walkableHeight, - const int walkableClimb, - rcHeightfield& solid); - -// Removes WALKABLE flag from all spans which have smaller than -// 'walkableHeight' clearane above them. -// Params: -// walkableHeight - (in) minimum height where the agent can still walk -// solid - (in/out) heightfield describing the solid space -void rcFilterWalkableLowHeightSpans(int walkableHeight, - rcHeightfield& solid); - -// Marks spans which are reachable from any of the topmost spans. -// Params: -// walkableHeight - (in) minimum height where the agent can still walk -// walkableClimb - (in) maximum height between grid cells the agent can climb -// solid - (in/out) heightfield describing the solid space -// Returns false if operation ran out of memory. -bool rcMarkReachableSpans(const int walkableHeight, - const int walkableClimb, - rcHeightfield& solid); - -// Builds compact representation of the heightfield. -// Params: -// walkableHeight - (in) minimum height where the agent can still walk -// walkableClimb - (in) maximum height between grid cells the agent can climb -// hf - (in) heightfield to be compacted -// chf - (out) compact heightfield representing the open space. -// Returns false if operation ran out of memory. -bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb, - unsigned char flags, - rcHeightfield& hf, - rcCompactHeightfield& chf); - -// Builds distance field and stores it into the combat heightfield. -// Params: -// chf - (in/out) compact heightfield representing the open space. -// Returns false if operation ran out of memory. -bool rcBuildDistanceField(rcCompactHeightfield& chf); - -// Divides the walkable heighfied into simple regions. -// Each region has only one contour and no overlaps. -// The regions are stored in the compact heightfield 'reg' field. -// The regions will be shrinked by the radius of the agent. -// The process sometimes creates small regions. The parameter -// 'minRegionSize' specifies the smallest allowed regions size. -// If the area of a regions is smaller than allowed, the regions is -// removed or merged to neighbour region. -// Params: -// chf - (in/out) compact heightfield representing the open space. -// walkableRadius - (in) the radius of the agent. -// minRegionSize - (in) the smallest allowed regions size. -// maxMergeRegionSize - (in) the largest allowed regions size which can be merged. -// Returns false if operation ran out of memory. -bool rcBuildRegions(rcCompactHeightfield& chf, - int walkableRadius, int borderSize, - int minRegionSize, int mergeRegionSize); - -// Builds simplified contours from the regions outlines. -// Params: -// chf - (in) compact heightfield which has regions set. -// maxError - (in) maximum allowed distance between simplified countour and cells. -// maxEdgeLen - (in) maximum allowed contour edge length in cells. -// cset - (out) Resulting contour set. -// Returns false if operation ran out of memory. -bool rcBuildContours(rcCompactHeightfield& chf, +/// Sets the area id of all triangles with a slope below the specified value +/// to #RC_WALKABLE_AREA. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. [Limits: 0 <= value < 90] +/// [Units: Degrees] +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] nt The number of triangles. +/// @param[out] areas The triangle area ids. [Length: >= @p nt] +void rcMarkWalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, + const int* tris, int nt, unsigned char* areas); + +/// Sets the area id of all triangles with a slope greater than or equal to the specified value to #RC_NULL_AREA. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableSlopeAngle The maximum slope that is considered walkable. [Limits: 0 <= value < 90] +/// [Units: Degrees] +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle vertex indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] nt The number of triangles. +/// @param[out] areas The triangle area ids. [Length: >= @p nt] +void rcClearUnwalkableTriangles(rcContext* ctx, const float walkableSlopeAngle, const float* verts, int nv, + const int* tris, int nt, unsigned char* areas); + +/// Adds a span to the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] hf An initialized heightfield. +/// @param[in] x The width index where the span is to be added. +/// [Limits: 0 <= value < rcHeightfield::width] +/// @param[in] y The height index where the span is to be added. +/// [Limits: 0 <= value < rcHeightfield::height] +/// @param[in] smin The minimum height of the span. [Limit: < @p smax] [Units: vx] +/// @param[in] smax The maximum height of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT] [Units: vx] +/// @param[in] area The area id of the span. [Limit: <= #RC_WALKABLE_AREA) +/// @param[in] flagMergeThr The merge theshold. [Limit: >= 0] [Units: vx] +void rcAddSpan(rcContext* ctx, rcHeightfield& hf, const int x, const int y, + const unsigned short smin, const unsigned short smax, + const unsigned char area, const int flagMergeThr); + +/// Rasterizes a triangle into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] v0 Triangle vertex 0 [(x, y, z)] +/// @param[in] v1 Triangle vertex 1 [(x, y, z)] +/// @param[in] v2 Triangle vertex 2 [(x, y, z)] +/// @param[in] area The area id of the triangle. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in, out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2, + const unsigned char area, rcHeightfield& solid, + const int flagMergeThr = 1); + +/// Rasterizes an indexed triangle mesh into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] +/// @param[in] nt The number of triangles. +/// @param[in, out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv, + const int* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr = 1); + +/// Rasterizes an indexed triangle mesh into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The vertices. [(x, y, z) * @p nv] +/// @param[in] nv The number of vertices. +/// @param[in] tris The triangle indices. [(vertA, vertB, vertC) * @p nt] +/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] +/// @param[in] nt The number of triangles. +/// @param[in, out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int nv, + const unsigned short* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr = 1); + +/// Rasterizes triangles into the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The triangle vertices. [(ax, ay, az, bx, by, bz, cx, by, cx) * @p nt] +/// @param[in] areas The area id's of the triangles. [Limit: <= #RC_WALKABLE_AREA] [Size: @p nt] +/// @param[in] nt The number of triangles. +/// @param[in, out] solid An initialized heightfield. +/// @param[in] flagMergeThr The distance where the walkable flag is favored over the non-walkable flag. +/// [Limit: >= 0] [Units: vx] +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr = 1); + +/// Marks non-walkable spans as walkable if their maximum is within @p walkableClimp of a walkable neihbor. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. +/// [Limit: >=0] [Units: vx] +/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid); + +/// Marks spans that are ledges as not-walkable. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to +/// be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. +/// [Limit: >=0] [Units: vx] +/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, + const int walkableClimb, rcHeightfield& solid); + +/// Marks walkable spans as not walkable if the clearence above the span is less than the specified height. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area to +/// be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[in,out] solid A fully built heightfield. (All spans have been added.) +void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid); + +/// Returns the number of spans contained in the specified heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] hf An initialized heightfield. +/// @returns The number of spans in the heightfield. +int rcGetHeightFieldSpanCount(rcContext* ctx, rcHeightfield& hf); + +/// @} +/// @name Compact Heightfield Functions +/// @see rcCompactHeightfield +/// @{ + +/// Builds a compact heightfield representing open space, from a heightfield representing solid space. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area +/// to be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[in] walkableClimb Maximum ledge height that is considered to still be traversable. +/// [Limit: >=0] [Units: vx] +/// @param[in] hf The heightfield to be compacted. +/// @param[out] chf The resulting compact heightfield. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb, + rcHeightfield& hf, rcCompactHeightfield& chf); + +/// Erodes the walkable area within the heightfield by the specified radius. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] radius The radius of erosion. [Limits: 0 < value < 255] [Units: vx] +/// @param[in,out] chf The populated compact heightfield to erode. +/// @returns True if the operation completed successfully. +bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf); + +/// Applies a median filter to walkable area types (based on area id), removing noise. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @returns True if the operation completed successfully. +bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf); + +/// Applies an area id to all spans within the specified bounding box. (AABB) +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] bmin The minimum of the bounding box. [(x, y, z)] +/// @param[in] bmax The maximum of the bounding box. [(x, y, z)] +/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] chf A populated compact heightfield. +void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId, + rcCompactHeightfield& chf); + +/// Applies the area id to the all spans within the specified convex polygon. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] verts The vertices of the polygon [Fomr: (x, y, z) * @p nverts] +/// @param[in] nverts The number of vertices in the polygon. +/// @param[in] hmin The height of the base of the polygon. +/// @param[in] hmax The height of the top of the polygon. +/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] chf A populated compact heightfield. +void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, + const float hmin, const float hmax, unsigned char areaId, + rcCompactHeightfield& chf); + +/// Applies the area id to all spans within the specified cylinder. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] pos The center of the base of the cylinder. [Form: (x, y, z)] +/// @param[in] r The radius of the cylinder. +/// @param[in] h The height of the cylinder. +/// @param[in] areaId The area id to apply. [Limit: <= #RC_WALKABLE_AREA] +/// @param[in,out] chf A populated compact heightfield. +void rcMarkCylinderArea(rcContext* ctx, const float* pos, + const float r, const float h, unsigned char areaId, + rcCompactHeightfield& chf); + +/// Builds the distance field for the specified compact heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @returns True if the operation completed successfully. +bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf); + +/// Builds region data for the heightfield using watershed partitioning. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx] +/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas. [Limit: >=0] +/// [Units: vx]. +/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible, +/// be merged with larger regions. [Limit: >=0] [Units: vx] +/// @returns True if the operation completed successfully. +bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea); + +/// Builds region data for the heightfield using simple monotone partitioning. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in,out] chf A populated compact heightfield. +/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx] +/// @param[in] minRegionArea The minimum number of cells allowed to form isolated island areas. [Limit: >=0] +/// [Units: vx]. +/// @param[in] mergeRegionArea Any regions with a span count smaller than this value will, if possible, +/// be merged with larger regions. [Limit: >=0] [Units: vx] +/// @returns True if the operation completed successfully. +bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea); + + +/// Sets the neighbor connection data for the specified direction. +/// @param[in] s The span to update. +/// @param[in] dir The direction to set. [Limits: 0 <= value < 4] +/// @param[in] i The index of the neighbor span. +inline void rcSetCon(rcCompactSpan& s, int dir, int i) +{ + const unsigned int shift = (unsigned int)dir*6; + unsigned int con = s.con; + s.con = (con & ~(0x3f << shift)) | (((unsigned int)i & 0x3f) << shift); +} + +/// Gets neighbor connection data for the specified direction. +/// @param[in] s The span to check. +/// @param[in] dir The direction to check. [Limits: 0 <= value < 4] +/// @return The neighbor connection data for the specified direction, +/// or #RC_NOT_CONNECTED if there is no connection. +inline int rcGetCon(const rcCompactSpan& s, int dir) +{ + const unsigned int shift = (unsigned int)dir*6; + return (s.con >> shift) & 0x3f; +} + +/// Gets the standard width (x-axis) offset for the specified direction. +/// @param[in] dir The direction. [Limits: 0 <= value < 4] +/// @return The width offset to apply to the current cell position to move +/// in the direction. +inline int rcGetDirOffsetX(int dir) +{ + const int offset[4] = { -1, 0, 1, 0, }; + return offset[dir&0x03]; +} + +/// Gets the standard height (z-axis) offset for the specified direction. +/// @param[in] dir The direction. [Limits: 0 <= value < 4] +/// @return The height offset to apply to the current cell position to move +/// in the direction. +inline int rcGetDirOffsetY(int dir) +{ + const int offset[4] = { 0, 1, 0, -1 }; + return offset[dir&0x03]; +} + +/// @} +/// @name Layer, Contour, Polymesh, and Detail Mesh Functions +/// @see rcHeightfieldLayer, rcContourSet, rcPolyMesh, rcPolyMeshDetail +/// @{ + +/// Builds a layer set from the specified compact heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] chf A fully built compact heightfield. +/// @param[in] borderSize The size of the non-navigable border around the heightfield. [Limit: >=0] +/// [Units: vx] +/// @param[in] walkableHeight Minimum floor to 'ceiling' height that will still allow the floor area +/// to be considered walkable. [Limit: >= 3] [Units: vx] +/// @param[out] lset The resulting layer set. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int walkableHeight, + rcHeightfieldLayerSet& lset); + +/// Builds a contour set from the region outlines in the provided compact heightfield. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] chf A fully built compact heightfield. +/// @param[in] maxError The maximum distance a simplfied contour's border edges should deviate +/// the original raw contour. [Limit: >=0] [Units: wu] +/// @param[in] maxEdgeLen The maximum allowed length for contour edges along the border of the mesh. +/// [Limit: >=0] [Units: vx] +/// @param[out] cset The resulting contour set. (Must be pre-allocated.) +/// @param[in] buildFlags The build flags. (See: #rcBuildContoursFlags) +/// @returns True if the operation completed successfully. +bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, const float maxError, const int maxEdgeLen, - rcContourSet& cset); - -// Builds connected convex polygon mesh from contour polygons. -// Params: -// cset - (in) contour set. -// nvp - (in) maximum number of vertices per polygon. -// mesh - (out) poly mesh. -// Returns false if operation ran out of memory. -bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh); - -bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh); - -// Builds detail triangle mesh for each polygon in the poly mesh. -// Params: -// mesh - (in) poly mesh to detail. -// chf - (in) compacy height field, used to query height for new vertices. -// sampleDist - (in) spacing between height samples used to generate more detail into mesh. -// sampleMaxError - (in) maximum allowed distance between simplified detail mesh and height sample. -// pmdtl - (out) detail mesh. -// Returns false if operation ran out of memory. -bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& chf, + rcContourSet& cset, const int flags = RC_CONTOUR_TESS_WALL_EDGES); + +/// Builds a polygon mesh from the provided contours. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] cset A fully built contour set. +/// @param[in] nvp The maximum number of vertices allowed for polygons generated during the +/// contour to polygon conversion process. [Limit: >= 3] +/// @param[out] mesh The resulting polygon mesh. (Must be re-allocated.) +/// @returns True if the operation completed successfully. +bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh); + +/// Merges multiple polygon meshes into a single mesh. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] meshes An array of polygon meshes to merge. [Size: @p nmeshes] +/// @param[in] nmeshes The number of polygon meshes in the meshes array. +/// @param[in] mesh The resulting polygon mesh. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh); + +/// Builds a detail mesh from the provided polygon mesh. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] mesh A fully built polygon mesh. +/// @param[in] chf The compact heightfield used to build the polygon mesh. +/// @param[in] sampleDist Sets the distance to use when samping the heightfield. [Limit: >=0] [Units: wu] +/// @param[in] sampleMaxError The maximum distance the detail mesh surface should deviate from +/// heightfield data. [Limit: >=0] [Units: wu] +/// @param[out] dmesh The resulting detail mesh. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf, const float sampleDist, const float sampleMaxError, rcPolyMeshDetail& dmesh); -bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh); +/// Merges multiple detail meshes into a single detail mesh. +/// @ingroup recast +/// @param[in,out] ctx The build context to use during the operation. +/// @param[in] meshes An array of detail meshes to merge. [Size: @p nmeshes] +/// @param[in] nmeshes The number of detail meshes in the meshes array. +/// @param[out] mesh The resulting detail mesh. (Must be pre-allocated.) +/// @returns True if the operation completed successfully. +bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh); bool buildMeshAdjacency(unsigned short* polys, const int npolys, const int nverts, const int vertsPerPoly); +/// @} + #endif // RECAST_H + +/////////////////////////////////////////////////////////////////////////// + +// Due to the large amount of detail documentation for this file, +// the content normally located at the end of the header file has been separated +// out to a file in /Docs/Extern. diff --git a/extern/recastnavigation/Recast/Include/RecastAlloc.h b/extern/recastnavigation/Recast/Include/RecastAlloc.h new file mode 100644 index 00000000000..0038c1a5c54 --- /dev/null +++ b/extern/recastnavigation/Recast/Include/RecastAlloc.h @@ -0,0 +1,122 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#ifndef RECASTALLOC_H +#define RECASTALLOC_H + +/// Provides hint values to the memory allocator on how long the +/// memory is expected to be used. +enum rcAllocHint +{ + RC_ALLOC_PERM, ///< Memory will persist after a function call. + RC_ALLOC_TEMP ///< Memory used temporarily within a function. +}; + +/// A memory allocation function. +// @param[in] size The size, in bytes of memory, to allocate. +// @param[in] rcAllocHint A hint to the allocator on how long the memory is expected to be in use. +// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed. +/// @see rcAllocSetCustom +typedef void* (rcAllocFunc)(int size, rcAllocHint hint); + +/// A memory deallocation function. +/// @see rcAllocSetCustom +// @param[in] ptr +typedef void (rcFreeFunc)(void* ptr); + +/// Sets the base custom allocation functions to be used by Recast. +/// @param[in] allocFunc The memory allocation function to be used by #rcAlloc +/// @param[in] freeFunc The memory de-allocation function to be used by #rcFree +void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc); + +/// Allocates a memory block. +/// @param[in] size The size, in bytes of memory, to allocate. +/// @param[in] hint A hint to the allocator on how long the memory is expected to be in use. +/// @return A pointer to the beginning of the allocated memory block, or null if the allocation failed. +void* rcAlloc(int size, rcAllocHint hint); + +/// Deallocates a memory block. +/// @param[in] ptr A pointer to a memory block previously allocated using #rcAlloc. +void rcFree(void* ptr); + + +/// A simple dynamic array of integers. +class rcIntArray +{ + int* m_data; + int m_size, m_cap; + inline rcIntArray(const rcIntArray&); + inline rcIntArray& operator=(const rcIntArray&); +public: + + /// Constructs an instance with an initial array size of zero. + inline rcIntArray() : m_data(0), m_size(0), m_cap(0) {} + + /// Constructs an instance initialized to the specified size. + /// @param[in] n The initial size of the integer array. + inline rcIntArray(int n) : m_data(0), m_size(0), m_cap(0) { resize(n); } + inline ~rcIntArray() { rcFree(m_data); } + + /// Specifies the new size of the integer array. + /// @param[in] n The new size of the integer array. + void resize(int n); + + /// Push the specified integer onto the end of the array and increases the size by one. + /// @param[in] item The new value. + inline void push(int item) { resize(m_size+1); m_data[m_size-1] = item; } + + /// Returns the value at the end of the array and reduces the size by one. + /// @return The value at the end of the array. + inline int pop() { if (m_size > 0) m_size--; return m_data[m_size]; } + + /// The value at the specified array index. + /// @warning Does not provide overflow protection. + /// @param[in] i The index of the value. + inline const int& operator[](int i) const { return m_data[i]; } + + /// The value at the specified array index. + /// @warning Does not provide overflow protection. + /// @param[in] i The index of the value. + inline int& operator[](int i) { return m_data[i]; } + + /// The current size of the integer array. + inline int size() const { return m_size; } +}; + +/// A simple helper class used to delete an array when it goes out of scope. +/// @note This class is rarely if ever used by the end user. +template<class T> class rcScopedDelete +{ + T* ptr; + inline T* operator=(T* p); +public: + + /// Constructs an instance with a null pointer. + inline rcScopedDelete() : ptr(0) {} + + /// Constructs an instance with the specified pointer. + /// @param[in] p An pointer to an allocated array. + inline rcScopedDelete(T* p) : ptr(p) {} + inline ~rcScopedDelete() { rcFree(ptr); } + + /// The root array pointer. + /// @return The root array pointer. + inline operator T*() { return ptr; } +}; + +#endif diff --git a/extern/recastnavigation/Recast/Include/RecastAssert.h b/extern/recastnavigation/Recast/Include/RecastAssert.h new file mode 100644 index 00000000000..b58b8fcd286 --- /dev/null +++ b/extern/recastnavigation/Recast/Include/RecastAssert.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#ifndef RECASTASSERT_H +#define RECASTASSERT_H + +// Note: This header file's only purpose is to include define assert. +// Feel free to change the file and include your own implementation instead. + +#ifdef NDEBUG +// From http://cnicholson.net/2009/02/stupid-c-tricks-adventures-in-assert/ +# define rcAssert(x) do { (void)sizeof(x); } while(__LINE__==-1,false) +#else +# include <assert.h> +# define rcAssert assert +#endif + +#endif // RECASTASSERT_H diff --git a/extern/recastnavigation/Recast/Source/Recast.cpp b/extern/recastnavigation/Recast/Source/Recast.cpp index 0db26c2c1cd..283cf0c128b 100644 --- a/extern/recastnavigation/Recast/Source/Recast.cpp +++ b/extern/recastnavigation/Recast/Source/Recast.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2009 Mikko Mononen memon@inside.org +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -22,35 +22,178 @@ #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <stdarg.h> #include "Recast.h" -#include "RecastLog.h" -#include "RecastTimer.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" +float rcSqrt(float x) +{ + return sqrtf(x); +} + +/// @class rcContext +/// @par +/// +/// This class does not provide logging or timer functionality on its +/// own. Both must be provided by a concrete implementation +/// by overriding the protected member functions. Also, this class does not +/// provide an interface for extracting log messages. (Only adding them.) +/// So concrete implementations must provide one. +/// +/// If no logging or timers are required, just pass an instance of this +/// class through the Recast build process. +/// -void rcIntArray::resize(int n) +/// @par +/// +/// Example: +/// @code +/// // Where ctx is an instance of rcContext and filepath is a char array. +/// ctx->log(RC_LOG_ERROR, "buildTiledNavigation: Could not load '%s'", filepath); +/// @endcode +void rcContext::log(const rcLogCategory category, const char* format, ...) { - if (n > m_cap) + if (!m_logEnabled) + return; + static const int MSG_SIZE = 512; + char msg[MSG_SIZE]; + va_list ap; + va_start(ap, format); + int len = vsnprintf(msg, MSG_SIZE, format, ap); + if (len >= MSG_SIZE) { - if (!m_cap) m_cap = 8; - while (m_cap < n) m_cap *= 2; - int* newData = new int[m_cap]; - if (m_size && newData) memcpy(newData, m_data, m_size*sizeof(int)); - delete [] m_data; - m_data = newData; + len = MSG_SIZE-1; + msg[MSG_SIZE-1] = '\0'; } - m_size = n; + va_end(ap); + doLog(category, msg, len); +} + +rcHeightfield* rcAllocHeightfield() +{ + rcHeightfield* hf = (rcHeightfield*)rcAlloc(sizeof(rcHeightfield), RC_ALLOC_PERM); + memset(hf, 0, sizeof(rcHeightfield)); + return hf; +} + +void rcFreeHeightField(rcHeightfield* hf) +{ + if (!hf) return; + // Delete span array. + rcFree(hf->spans); + // Delete span pools. + while (hf->pools) + { + rcSpanPool* next = hf->pools->next; + rcFree(hf->pools); + hf->pools = next; + } + rcFree(hf); +} + +rcCompactHeightfield* rcAllocCompactHeightfield() +{ + rcCompactHeightfield* chf = (rcCompactHeightfield*)rcAlloc(sizeof(rcCompactHeightfield), RC_ALLOC_PERM); + memset(chf, 0, sizeof(rcCompactHeightfield)); + return chf; +} + +void rcFreeCompactHeightfield(rcCompactHeightfield* chf) +{ + if (!chf) return; + rcFree(chf->cells); + rcFree(chf->spans); + rcFree(chf->dist); + rcFree(chf->areas); + rcFree(chf); +} + + +rcHeightfieldLayerSet* rcAllocHeightfieldLayerSet() +{ + rcHeightfieldLayerSet* lset = (rcHeightfieldLayerSet*)rcAlloc(sizeof(rcHeightfieldLayerSet), RC_ALLOC_PERM); + memset(lset, 0, sizeof(rcHeightfieldLayerSet)); + return lset; +} + +void rcFreeHeightfieldLayerSet(rcHeightfieldLayerSet* lset) +{ + if (!lset) return; + for (int i = 0; i < lset->nlayers; ++i) + { + rcFree(lset->layers[i].heights); + rcFree(lset->layers[i].areas); + rcFree(lset->layers[i].cons); + } + rcFree(lset->layers); + rcFree(lset); +} + + +rcContourSet* rcAllocContourSet() +{ + rcContourSet* cset = (rcContourSet*)rcAlloc(sizeof(rcContourSet), RC_ALLOC_PERM); + memset(cset, 0, sizeof(rcContourSet)); + return cset; +} + +void rcFreeContourSet(rcContourSet* cset) +{ + if (!cset) return; + for (int i = 0; i < cset->nconts; ++i) + { + rcFree(cset->conts[i].verts); + rcFree(cset->conts[i].rverts); + } + rcFree(cset->conts); + rcFree(cset); +} + +rcPolyMesh* rcAllocPolyMesh() +{ + rcPolyMesh* pmesh = (rcPolyMesh*)rcAlloc(sizeof(rcPolyMesh), RC_ALLOC_PERM); + memset(pmesh, 0, sizeof(rcPolyMesh)); + return pmesh; +} + +void rcFreePolyMesh(rcPolyMesh* pmesh) +{ + if (!pmesh) return; + rcFree(pmesh->verts); + rcFree(pmesh->polys); + rcFree(pmesh->regs); + rcFree(pmesh->flags); + rcFree(pmesh->areas); + rcFree(pmesh); +} + +rcPolyMeshDetail* rcAllocPolyMeshDetail() +{ + rcPolyMeshDetail* dmesh = (rcPolyMeshDetail*)rcAlloc(sizeof(rcPolyMeshDetail), RC_ALLOC_PERM); + memset(dmesh, 0, sizeof(rcPolyMeshDetail)); + return dmesh; +} + +void rcFreePolyMeshDetail(rcPolyMeshDetail* dmesh) +{ + if (!dmesh) return; + rcFree(dmesh->meshes); + rcFree(dmesh->verts); + rcFree(dmesh->tris); + rcFree(dmesh); } void rcCalcBounds(const float* verts, int nv, float* bmin, float* bmax) { // Calculate bounding box. - vcopy(bmin, verts); - vcopy(bmax, verts); + rcVcopy(bmin, verts); + rcVcopy(bmax, verts); for (int i = 1; i < nv; ++i) { const float* v = &verts[i*3]; - vmin(bmin, v); - vmax(bmax, v); + rcVmin(bmin, v); + rcVmax(bmax, v); } } @@ -60,17 +203,25 @@ void rcCalcGridSize(const float* bmin, const float* bmax, float cs, int* w, int* *h = (int)((bmax[2] - bmin[2])/cs+0.5f); } -bool rcCreateHeightfield(rcHeightfield& hf, int width, int height, +/// @par +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocHeightfield, rcHeightfield +bool rcCreateHeightfield(rcContext* /*ctx*/, rcHeightfield& hf, int width, int height, const float* bmin, const float* bmax, float cs, float ch) { + // TODO: VC complains about unref formal variable, figure out a way to handle this better. +// rcAssert(ctx); + hf.width = width; hf.height = height; - hf.spans = new rcSpan*[hf.width*hf.height]; - vcopy(hf.bmin, bmin); - vcopy(hf.bmax, bmax); + rcVcopy(hf.bmin, bmin); + rcVcopy(hf.bmax, bmax); hf.cs = cs; hf.ch = ch; + hf.spans = (rcSpan**)rcAlloc(sizeof(rcSpan*)*hf.width*hf.height, RC_ALLOC_PERM); if (!hf.spans) return false; memset(hf.spans, 0, sizeof(rcSpan*)*hf.width*hf.height); @@ -80,18 +231,29 @@ bool rcCreateHeightfield(rcHeightfield& hf, int width, int height, static void calcTriNormal(const float* v0, const float* v1, const float* v2, float* norm) { float e0[3], e1[3]; - vsub(e0, v1, v0); - vsub(e1, v2, v0); - vcross(norm, e0, e1); - vnormalize(norm); + rcVsub(e0, v1, v0); + rcVsub(e1, v2, v0); + rcVcross(norm, e0, e1); + rcVnormalize(norm); } -void rcMarkWalkableTriangles(const float walkableSlopeAngle, - const float* verts, int nv, +/// @par +/// +/// Only sets the aread id's for the walkable triangles. Does not alter the +/// area id's for unwalkable triangles. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles +void rcMarkWalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle, + const float* verts, int /*nv*/, const int* tris, int nt, - unsigned char* flags) + unsigned char* areas) { - const float walkableThr = cosf(walkableSlopeAngle/180.0f*(float)M_PI); + // TODO: VC complains about unref formal variable, figure out a way to handle this better. +// rcAssert(ctx); + + const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI); float norm[3]; @@ -101,12 +263,45 @@ void rcMarkWalkableTriangles(const float walkableSlopeAngle, calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm); // Check if the face is walkable. if (norm[1] > walkableThr) - flags[i] |= RC_WALKABLE; + areas[i] = RC_WALKABLE_AREA; + } +} + +/// @par +/// +/// Only sets the aread id's for the unwalkable triangles. Does not alter the +/// area id's for walkable triangles. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcHeightfield, rcClearUnwalkableTriangles, rcRasterizeTriangles +void rcClearUnwalkableTriangles(rcContext* /*ctx*/, const float walkableSlopeAngle, + const float* verts, int /*nv*/, + const int* tris, int nt, + unsigned char* areas) +{ + // TODO: VC complains about unref formal variable, figure out a way to handle this better. +// rcAssert(ctx); + + const float walkableThr = cosf(walkableSlopeAngle/180.0f*RC_PI); + + float norm[3]; + + for (int i = 0; i < nt; ++i) + { + const int* tri = &tris[i*3]; + calcTriNormal(&verts[tri[0]*3], &verts[tri[1]*3], &verts[tri[2]*3], norm); + // Check if the face is walkable. + if (norm[1] <= walkableThr) + areas[i] = RC_NULL_AREA; } } -static int getSpanCount(unsigned char flags, rcHeightfield& hf) +int rcGetHeightFieldSpanCount(rcContext* /*ctx*/, rcHeightfield& hf) { + // TODO: VC complains about unref formal variable, figure out a way to handle this better. +// rcAssert(ctx); + const int w = hf.width; const int h = hf.height; int spanCount = 0; @@ -116,7 +311,7 @@ static int getSpanCount(unsigned char flags, rcHeightfield& hf) { for (rcSpan* s = hf.spans[x + y*w]; s; s = s->next) { - if (s->flags == flags) + if (s->area != RC_NULL_AREA) spanCount++; } } @@ -124,21 +319,25 @@ static int getSpanCount(unsigned char flags, rcHeightfield& hf) return spanCount; } -inline void setCon(rcCompactSpan& s, int dir, int i) -{ - s.con &= ~(0xf << (dir*4)); - s.con |= (i&0xf) << (dir*4); -} - -bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb, - unsigned char flags, rcHeightfield& hf, - rcCompactHeightfield& chf) +/// @par +/// +/// This is just the beginning of the process of fully building a compact heightfield. +/// Various filters may be applied applied, then the distance field and regions built. +/// E.g: #rcBuildDistanceField and #rcBuildRegions +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocCompactHeightfield, rcHeightfield, rcCompactHeightfield, rcConfig +bool rcBuildCompactHeightfield(rcContext* ctx, const int walkableHeight, const int walkableClimb, + rcHeightfield& hf, rcCompactHeightfield& chf) { - rcTimeVal startTime = rcGetPerformanceTimer(); + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD); const int w = hf.width; const int h = hf.height; - const int spanCount = getSpanCount(flags, hf); + const int spanCount = rcGetHeightFieldSpanCount(ctx, hf); // Fill in header. chf.width = w; @@ -147,27 +346,32 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb chf.walkableHeight = walkableHeight; chf.walkableClimb = walkableClimb; chf.maxRegions = 0; - vcopy(chf.bmin, hf.bmin); - vcopy(chf.bmax, hf.bmax); + rcVcopy(chf.bmin, hf.bmin); + rcVcopy(chf.bmax, hf.bmax); chf.bmax[1] += walkableHeight*hf.ch; chf.cs = hf.cs; chf.ch = hf.ch; - chf.cells = new rcCompactCell[w*h]; + chf.cells = (rcCompactCell*)rcAlloc(sizeof(rcCompactCell)*w*h, RC_ALLOC_PERM); if (!chf.cells) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h); + ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.cells' (%d)", w*h); return false; } memset(chf.cells, 0, sizeof(rcCompactCell)*w*h); - chf.spans = new rcCompactSpan[spanCount]; + chf.spans = (rcCompactSpan*)rcAlloc(sizeof(rcCompactSpan)*spanCount, RC_ALLOC_PERM); if (!chf.spans) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount); + ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.spans' (%d)", spanCount); return false; } memset(chf.spans, 0, sizeof(rcCompactSpan)*spanCount); + chf.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*spanCount, RC_ALLOC_PERM); + if (!chf.areas) + { + ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Out of memory 'chf.areas' (%d)", spanCount); + return false; + } + memset(chf.areas, RC_NULL_AREA, sizeof(unsigned char)*spanCount); const int MAX_HEIGHT = 0xffff; @@ -185,12 +389,13 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb c.count = 0; while (s) { - if (s->flags == flags) + if (s->area != RC_NULL_AREA) { const int bot = (int)s->smax; const int top = s->next ? (int)s->next->smin : MAX_HEIGHT; chf.spans[idx].y = (unsigned short)rcClamp(bot, 0, 0xffff); chf.spans[idx].h = (unsigned char)rcClamp(top - bot, 0, 0xff); + chf.areas[idx] = s->area; idx++; c.count++; } @@ -200,6 +405,8 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb } // Find neighbour connections. + const int MAX_LAYERS = RC_NOT_CONNECTED-1; + int tooHighNeighbour = 0; for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) @@ -208,14 +415,16 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { rcCompactSpan& s = chf.spans[i]; + for (int dir = 0; dir < 4; ++dir) { - setCon(s, dir, 0xf); + rcSetCon(s, dir, RC_NOT_CONNECTED); const int nx = x + rcGetDirOffsetX(dir); const int ny = y + rcGetDirOffsetY(dir); // First check that the neighbour cell is in bounds. if (nx < 0 || ny < 0 || nx >= w || ny >= h) continue; + // Iterate over all neighbour spans and check if any of the is // accessible from current cell. const rcCompactCell& nc = chf.cells[nx+ny*w]; @@ -230,23 +439,34 @@ bool rcBuildCompactHeightfield(const int walkableHeight, const int walkableClimb if ((top - bot) >= walkableHeight && rcAbs((int)ns.y - (int)s.y) <= walkableClimb) { // Mark direction as walkable. - setCon(s, dir, k - (int)nc.index); + const int idx = k - (int)nc.index; + if (idx < 0 || idx > MAX_LAYERS) + { + tooHighNeighbour = rcMax(tooHighNeighbour, idx); + continue; + } + rcSetCon(s, dir, idx); break; } } + } } } } - rcTimeVal endTime = rcGetPerformanceTimer(); - - if (rcGetBuildTimes()) - rcGetBuildTimes()->buildCompact += rcGetDeltaTimeUsec(startTime, endTime); + if (tooHighNeighbour > MAX_LAYERS) + { + ctx->log(RC_LOG_ERROR, "rcBuildCompactHeightfield: Heightfield has too many layers %d (max: %d)", + tooHighNeighbour, MAX_LAYERS); + } + + ctx->stopTimer(RC_TIMER_BUILD_COMPACTHEIGHTFIELD); return true; } +/* static int getHeightfieldMemoryUsage(const rcHeightfield& hf) { int size = 0; @@ -270,3 +490,4 @@ static int getCompactHeightFieldMemoryusage(const rcCompactHeightfield& chf) size += sizeof(rcCompactCell) * chf.width * chf.height; return size; } +*/
\ No newline at end of file diff --git a/extern/recastnavigation/Recast/Source/RecastAlloc.cpp b/extern/recastnavigation/Recast/Source/RecastAlloc.cpp new file mode 100644 index 00000000000..b5ec1516146 --- /dev/null +++ b/extern/recastnavigation/Recast/Source/RecastAlloc.cpp @@ -0,0 +1,88 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#include <stdlib.h> +#include <string.h> +#include "RecastAlloc.h" + +static void *rcAllocDefault(int size, rcAllocHint) +{ + return malloc(size); +} + +static void rcFreeDefault(void *ptr) +{ + free(ptr); +} + +static rcAllocFunc* sRecastAllocFunc = rcAllocDefault; +static rcFreeFunc* sRecastFreeFunc = rcFreeDefault; + +/// @see rcAlloc, rcFree +void rcAllocSetCustom(rcAllocFunc *allocFunc, rcFreeFunc *freeFunc) +{ + sRecastAllocFunc = allocFunc ? allocFunc : rcAllocDefault; + sRecastFreeFunc = freeFunc ? freeFunc : rcFreeDefault; +} + +/// @see rcAllocSetCustom +void* rcAlloc(int size, rcAllocHint hint) +{ + return sRecastAllocFunc(size, hint); +} + +/// @par +/// +/// @warning This function leaves the value of @p ptr unchanged. So it still +/// points to the same (now invalid) location, and not to null. +/// +/// @see rcAllocSetCustom +void rcFree(void* ptr) +{ + if (ptr) + sRecastFreeFunc(ptr); +} + +/// @class rcIntArray +/// +/// While it is possible to pre-allocate a specific array size during +/// construction or by using the #resize method, certain methods will +/// automatically resize the array as needed. +/// +/// @warning The array memory is not initialized to zero when the size is +/// manually set during construction or when using #resize. + +/// @par +/// +/// Using this method ensures the array is at least large enough to hold +/// the specified number of elements. This can improve performance by +/// avoiding auto-resizing during use. +void rcIntArray::resize(int n) +{ + if (n > m_cap) + { + if (!m_cap) m_cap = n; + while (m_cap < n) m_cap *= 2; + int* newData = (int*)rcAlloc(m_cap*sizeof(int), RC_ALLOC_TEMP); + if (m_size && newData) memcpy(newData, m_data, m_size*sizeof(int)); + rcFree(m_data); + m_data = newData; + } + m_size = n; +} + diff --git a/extern/recastnavigation/Recast/Source/RecastArea.cpp b/extern/recastnavigation/Recast/Source/RecastArea.cpp new file mode 100644 index 00000000000..a59acc53eb6 --- /dev/null +++ b/extern/recastnavigation/Recast/Source/RecastArea.cpp @@ -0,0 +1,524 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#include <float.h> +#define _USE_MATH_DEFINES +#include <math.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" + +/// @par +/// +/// Basically, any spans that are closer to a boundary or obstruction than the specified radius +/// are marked as unwalkable. +/// +/// This method is usually called immediately after the heightfield has been built. +/// +/// @see rcCompactHeightfield, rcBuildCompactHeightfield, rcConfig::walkableRadius +bool rcErodeWalkableArea(rcContext* ctx, int radius, rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + const int w = chf.width; + const int h = chf.height; + + ctx->startTimer(RC_TIMER_ERODE_AREA); + + unsigned char* dist = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); + if (!dist) + { + ctx->log(RC_LOG_ERROR, "erodeWalkableArea: Out of memory 'dist' (%d).", chf.spanCount); + return false; + } + + // Init distance. + memset(dist, 0xff, sizeof(unsigned char)*chf.spanCount); + + // Mark boundary cells. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (chf.areas[i] == RC_NULL_AREA) + { + dist[i] = 0; + } + else + { + const rcCompactSpan& s = chf.spans[i]; + int nc = 0; + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int nx = x + rcGetDirOffsetX(dir); + const int ny = y + rcGetDirOffsetY(dir); + const int ni = (int)chf.cells[nx+ny*w].index + rcGetCon(s, dir); + if (chf.areas[ni] != RC_NULL_AREA) + { + nc++; + } + } + } + // At least one missing neighbour. + if (nc != 4) + dist[i] = 0; + } + } + } + } + + unsigned char nd; + + // Pass 1 + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + + if (rcGetCon(s, 0) != RC_NOT_CONNECTED) + { + // (-1,0) + const int ax = x + rcGetDirOffsetX(0); + const int ay = y + rcGetDirOffsetY(0); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0); + const rcCompactSpan& as = chf.spans[ai]; + nd = (unsigned char)rcMin((int)dist[ai]+2, 255); + if (nd < dist[i]) + dist[i] = nd; + + // (-1,-1) + if (rcGetCon(as, 3) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(3); + const int aay = ay + rcGetDirOffsetY(3); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 3); + nd = (unsigned char)rcMin((int)dist[aai]+3, 255); + if (nd < dist[i]) + dist[i] = nd; + } + } + if (rcGetCon(s, 3) != RC_NOT_CONNECTED) + { + // (0,-1) + const int ax = x + rcGetDirOffsetX(3); + const int ay = y + rcGetDirOffsetY(3); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3); + const rcCompactSpan& as = chf.spans[ai]; + nd = (unsigned char)rcMin((int)dist[ai]+2, 255); + if (nd < dist[i]) + dist[i] = nd; + + // (1,-1) + if (rcGetCon(as, 2) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(2); + const int aay = ay + rcGetDirOffsetY(2); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 2); + nd = (unsigned char)rcMin((int)dist[aai]+3, 255); + if (nd < dist[i]) + dist[i] = nd; + } + } + } + } + } + + // Pass 2 + for (int y = h-1; y >= 0; --y) + { + for (int x = w-1; x >= 0; --x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + + if (rcGetCon(s, 2) != RC_NOT_CONNECTED) + { + // (1,0) + const int ax = x + rcGetDirOffsetX(2); + const int ay = y + rcGetDirOffsetY(2); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 2); + const rcCompactSpan& as = chf.spans[ai]; + nd = (unsigned char)rcMin((int)dist[ai]+2, 255); + if (nd < dist[i]) + dist[i] = nd; + + // (1,1) + if (rcGetCon(as, 1) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(1); + const int aay = ay + rcGetDirOffsetY(1); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 1); + nd = (unsigned char)rcMin((int)dist[aai]+3, 255); + if (nd < dist[i]) + dist[i] = nd; + } + } + if (rcGetCon(s, 1) != RC_NOT_CONNECTED) + { + // (0,1) + const int ax = x + rcGetDirOffsetX(1); + const int ay = y + rcGetDirOffsetY(1); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 1); + const rcCompactSpan& as = chf.spans[ai]; + nd = (unsigned char)rcMin((int)dist[ai]+2, 255); + if (nd < dist[i]) + dist[i] = nd; + + // (-1,1) + if (rcGetCon(as, 0) != RC_NOT_CONNECTED) + { + const int aax = ax + rcGetDirOffsetX(0); + const int aay = ay + rcGetDirOffsetY(0); + const int aai = (int)chf.cells[aax+aay*w].index + rcGetCon(as, 0); + nd = (unsigned char)rcMin((int)dist[aai]+3, 255); + if (nd < dist[i]) + dist[i] = nd; + } + } + } + } + } + + const unsigned char thr = (unsigned char)(radius*2); + for (int i = 0; i < chf.spanCount; ++i) + if (dist[i] < thr) + chf.areas[i] = RC_NULL_AREA; + + rcFree(dist); + + ctx->stopTimer(RC_TIMER_ERODE_AREA); + + return true; +} + +static void insertSort(unsigned char* a, const int n) +{ + int i, j; + for (i = 1; i < n; i++) + { + const unsigned char value = a[i]; + for (j = i - 1; j >= 0 && a[j] > value; j--) + a[j+1] = a[j]; + a[j+1] = value; + } +} + +/// @par +/// +/// This filter is usually applied after applying area id's using functions +/// such as #rcMarkBoxArea, #rcMarkConvexPolyArea, and #rcMarkCylinderArea. +/// +/// @see rcCompactHeightfield +bool rcMedianFilterWalkableArea(rcContext* ctx, rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + const int w = chf.width; + const int h = chf.height; + + ctx->startTimer(RC_TIMER_MEDIAN_AREA); + + unsigned char* areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); + if (!areas) + { + ctx->log(RC_LOG_ERROR, "medianFilterWalkableArea: Out of memory 'areas' (%d).", chf.spanCount); + return false; + } + + // Init distance. + memset(areas, 0xff, sizeof(unsigned char)*chf.spanCount); + + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + if (chf.areas[i] == RC_NULL_AREA) + { + areas[i] = chf.areas[i]; + continue; + } + + unsigned char nei[9]; + for (int j = 0; j < 9; ++j) + nei[j] = chf.areas[i]; + + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + if (chf.areas[ai] != RC_NULL_AREA) + nei[dir*2+0] = chf.areas[ai]; + + const rcCompactSpan& as = chf.spans[ai]; + const int dir2 = (dir+1) & 0x3; + if (rcGetCon(as, dir2) != RC_NOT_CONNECTED) + { + const int ax2 = ax + rcGetDirOffsetX(dir2); + const int ay2 = ay + rcGetDirOffsetY(dir2); + const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2); + if (chf.areas[ai2] != RC_NULL_AREA) + nei[dir*2+1] = chf.areas[ai2]; + } + } + } + insertSort(nei, 9); + areas[i] = nei[4]; + } + } + } + + memcpy(chf.areas, areas, sizeof(unsigned char)*chf.spanCount); + + rcFree(areas); + + ctx->stopTimer(RC_TIMER_MEDIAN_AREA); + + return true; +} + +/// @par +/// +/// The value of spacial parameters are in world units. +/// +/// @see rcCompactHeightfield, rcMedianFilterWalkableArea +void rcMarkBoxArea(rcContext* ctx, const float* bmin, const float* bmax, unsigned char areaId, + rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_MARK_BOX_AREA); + + int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs); + int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch); + int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs); + int maxx = (int)((bmax[0]-chf.bmin[0])/chf.cs); + int maxy = (int)((bmax[1]-chf.bmin[1])/chf.ch); + int maxz = (int)((bmax[2]-chf.bmin[2])/chf.cs); + + if (maxx < 0) return; + if (minx >= chf.width) return; + if (maxz < 0) return; + if (minz >= chf.height) return; + + if (minx < 0) minx = 0; + if (maxx >= chf.width) maxx = chf.width-1; + if (minz < 0) minz = 0; + if (maxz >= chf.height) maxz = chf.height-1; + + for (int z = minz; z <= maxz; ++z) + { + for (int x = minx; x <= maxx; ++x) + { + const rcCompactCell& c = chf.cells[x+z*chf.width]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + rcCompactSpan& s = chf.spans[i]; + if ((int)s.y >= miny && (int)s.y <= maxy) + { + if (chf.areas[i] != RC_NULL_AREA) + chf.areas[i] = areaId; + } + } + } + } + + ctx->stopTimer(RC_TIMER_MARK_BOX_AREA); + +} + + +static int pointInPoly(int nvert, const float* verts, const float* p) +{ + int i, j, c = 0; + for (i = 0, j = nvert-1; i < nvert; j = i++) + { + const float* vi = &verts[i*3]; + const float* vj = &verts[j*3]; + if (((vi[2] > p[2]) != (vj[2] > p[2])) && + (p[0] < (vj[0]-vi[0]) * (p[2]-vi[2]) / (vj[2]-vi[2]) + vi[0]) ) + c = !c; + } + return c; +} + +/// @par +/// +/// The value of spacial parameters are in world units. +/// +/// The y-values of the polygon vertices are ignored. So the polygon is effectively +/// projected onto the xz-plane at @p hmin, then extruded to @p hmax. +/// +/// @see rcCompactHeightfield, rcMedianFilterWalkableArea +void rcMarkConvexPolyArea(rcContext* ctx, const float* verts, const int nverts, + const float hmin, const float hmax, unsigned char areaId, + rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_MARK_CONVEXPOLY_AREA); + + float bmin[3], bmax[3]; + rcVcopy(bmin, verts); + rcVcopy(bmax, verts); + for (int i = 1; i < nverts; ++i) + { + rcVmin(bmin, &verts[i*3]); + rcVmax(bmax, &verts[i*3]); + } + bmin[1] = hmin; + bmax[1] = hmax; + + int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs); + int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch); + int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs); + int maxx = (int)((bmax[0]-chf.bmin[0])/chf.cs); + int maxy = (int)((bmax[1]-chf.bmin[1])/chf.ch); + int maxz = (int)((bmax[2]-chf.bmin[2])/chf.cs); + + if (maxx < 0) return; + if (minx >= chf.width) return; + if (maxz < 0) return; + if (minz >= chf.height) return; + + if (minx < 0) minx = 0; + if (maxx >= chf.width) maxx = chf.width-1; + if (minz < 0) minz = 0; + if (maxz >= chf.height) maxz = chf.height-1; + + + // TODO: Optimize. + for (int z = minz; z <= maxz; ++z) + { + for (int x = minx; x <= maxx; ++x) + { + const rcCompactCell& c = chf.cells[x+z*chf.width]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + rcCompactSpan& s = chf.spans[i]; + if (chf.areas[i] == RC_NULL_AREA) + continue; + if ((int)s.y >= miny && (int)s.y <= maxy) + { + float p[3]; + p[0] = chf.bmin[0] + (x+0.5f)*chf.cs; + p[1] = 0; + p[2] = chf.bmin[2] + (z+0.5f)*chf.cs; + + if (pointInPoly(nverts, verts, p)) + { + chf.areas[i] = areaId; + } + } + } + } + } + + ctx->stopTimer(RC_TIMER_MARK_CONVEXPOLY_AREA); +} + +/// @par +/// +/// The value of spacial parameters are in world units. +/// +/// @see rcCompactHeightfield, rcMedianFilterWalkableArea +void rcMarkCylinderArea(rcContext* ctx, const float* pos, + const float r, const float h, unsigned char areaId, + rcCompactHeightfield& chf) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_MARK_CYLINDER_AREA); + + float bmin[3], bmax[3]; + bmin[0] = pos[0] - r; + bmin[1] = pos[1]; + bmin[2] = pos[2] - r; + bmax[0] = pos[0] + r; + bmax[1] = pos[1] + h; + bmax[2] = pos[2] + r; + const float r2 = r*r; + + int minx = (int)((bmin[0]-chf.bmin[0])/chf.cs); + int miny = (int)((bmin[1]-chf.bmin[1])/chf.ch); + int minz = (int)((bmin[2]-chf.bmin[2])/chf.cs); + int maxx = (int)((bmax[0]-chf.bmin[0])/chf.cs); + int maxy = (int)((bmax[1]-chf.bmin[1])/chf.ch); + int maxz = (int)((bmax[2]-chf.bmin[2])/chf.cs); + + if (maxx < 0) return; + if (minx >= chf.width) return; + if (maxz < 0) return; + if (minz >= chf.height) return; + + if (minx < 0) minx = 0; + if (maxx >= chf.width) maxx = chf.width-1; + if (minz < 0) minz = 0; + if (maxz >= chf.height) maxz = chf.height-1; + + + for (int z = minz; z <= maxz; ++z) + { + for (int x = minx; x <= maxx; ++x) + { + const rcCompactCell& c = chf.cells[x+z*chf.width]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + rcCompactSpan& s = chf.spans[i]; + + if (chf.areas[i] == RC_NULL_AREA) + continue; + + if ((int)s.y >= miny && (int)s.y <= maxy) + { + const float sx = chf.bmin[0] + (x+0.5f)*chf.cs; + const float sz = chf.bmin[2] + (z+0.5f)*chf.cs; + const float dx = sx - pos[0]; + const float dz = sz - pos[2]; + + if (dx*dx + dz*dz < r2) + { + chf.areas[i] = areaId; + } + } + } + } + } + + ctx->stopTimer(RC_TIMER_MARK_CYLINDER_AREA); +} diff --git a/extern/recastnavigation/Recast/Source/RecastContour.cpp b/extern/recastnavigation/Recast/Source/RecastContour.cpp index 96f763a18f3..078c464e5f4 100644 --- a/extern/recastnavigation/Recast/Source/RecastContour.cpp +++ b/extern/recastnavigation/Recast/Source/RecastContour.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2009 Mikko Mononen memon@inside.org +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -21,8 +21,8 @@ #include <string.h> #include <stdio.h> #include "Recast.h" -#include "RecastLog.h" -#include "RecastTimer.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" static int getCornerHeight(int x, int y, int i, int dir, @@ -33,44 +33,46 @@ static int getCornerHeight(int x, int y, int i, int dir, int ch = (int)s.y; int dirp = (dir+1) & 0x3; - unsigned short regs[4] = {0,0,0,0}; + unsigned int regs[4] = {0,0,0,0}; - regs[0] = s.reg; + // Combine region and area codes in order to prevent + // border vertices which are in between two areas to be removed. + regs[0] = chf.spans[i].reg | (chf.areas[i] << 16); - if (rcGetCon(s, dir) != 0xf) + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) { const int ax = x + rcGetDirOffsetX(dir); const int ay = y + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir); const rcCompactSpan& as = chf.spans[ai]; ch = rcMax(ch, (int)as.y); - regs[1] = as.reg; - if (rcGetCon(as, dirp) != 0xf) + regs[1] = chf.spans[ai].reg | (chf.areas[ai] << 16); + if (rcGetCon(as, dirp) != RC_NOT_CONNECTED) { const int ax2 = ax + rcGetDirOffsetX(dirp); const int ay2 = ay + rcGetDirOffsetY(dirp); const int ai2 = (int)chf.cells[ax2+ay2*chf.width].index + rcGetCon(as, dirp); const rcCompactSpan& as2 = chf.spans[ai2]; ch = rcMax(ch, (int)as2.y); - regs[2] = as2.reg; + regs[2] = chf.spans[ai2].reg | (chf.areas[ai2] << 16); } } - if (rcGetCon(s, dirp) != 0xf) + if (rcGetCon(s, dirp) != RC_NOT_CONNECTED) { const int ax = x + rcGetDirOffsetX(dirp); const int ay = y + rcGetDirOffsetY(dirp); const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dirp); const rcCompactSpan& as = chf.spans[ai]; ch = rcMax(ch, (int)as.y); - regs[3] = as.reg; - if (rcGetCon(as, dir) != 0xf) + regs[3] = chf.spans[ai].reg | (chf.areas[ai] << 16); + if (rcGetCon(as, dir) != RC_NOT_CONNECTED) { const int ax2 = ax + rcGetDirOffsetX(dir); const int ay2 = ay + rcGetDirOffsetY(dir); const int ai2 = (int)chf.cells[ax2+ay2*chf.width].index + rcGetCon(as, dir); const rcCompactSpan& as2 = chf.spans[ai2]; ch = rcMax(ch, (int)as2.y); - regs[2] = as2.reg; + regs[2] = chf.spans[ai2].reg | (chf.areas[ai2] << 16); } } @@ -86,8 +88,9 @@ static int getCornerHeight(int x, int y, int i, int dir, // followed by two interior cells and none of the regions are out of bounds. const bool twoSameExts = (regs[a] & regs[b] & RC_BORDER_REG) != 0 && regs[a] == regs[b]; const bool twoInts = ((regs[c] | regs[d]) & RC_BORDER_REG) == 0; + const bool intsSameArea = (regs[c]>>16) == (regs[d]>>16); const bool noZeros = regs[a] != 0 && regs[b] != 0 && regs[c] != 0 && regs[d] != 0; - if (twoSameExts && twoInts && noZeros) + if (twoSameExts && twoInts && intsSameArea && noZeros) { isBorderVertex = true; break; @@ -109,6 +112,8 @@ static void walkContour(int x, int y, int i, unsigned char startDir = dir; int starti = i; + const unsigned char area = chf.areas[i]; + int iter = 0; while (++iter < 40000) { @@ -116,6 +121,7 @@ static void walkContour(int x, int y, int i, { // Choose the edge corner bool isBorderVertex = false; + bool isAreaBorder = false; int px = x; int py = getCornerHeight(x, y, i, dir, chf, isBorderVertex); int pz = y; @@ -127,16 +133,19 @@ static void walkContour(int x, int y, int i, } int r = 0; const rcCompactSpan& s = chf.spans[i]; - if (rcGetCon(s, dir) != 0xf) + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) { const int ax = x + rcGetDirOffsetX(dir); const int ay = y + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir); - const rcCompactSpan& as = chf.spans[ai]; - r = (int)as.reg; + r = (int)chf.spans[ai].reg; + if (area != chf.areas[ai]) + isAreaBorder = true; } if (isBorderVertex) r |= RC_BORDER_VERTEX; + if (isAreaBorder) + r |= RC_AREA_BORDER; points.push(px); points.push(py); points.push(pz); @@ -151,7 +160,7 @@ static void walkContour(int x, int y, int i, const int nx = x + rcGetDirOffsetX(dir); const int ny = y + rcGetDirOffsetY(dir); const rcCompactSpan& s = chf.spans[i]; - if (rcGetCon(s, dir) != 0xf) + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) { const rcCompactCell& nc = chf.cells[nx+ny*chf.width]; ni = (int)nc.index + rcGetCon(s, dir); @@ -174,9 +183,9 @@ static void walkContour(int x, int y, int i, } } -static float distancePtSeg(int x, int y, int z, - int px, int py, int pz, - int qx, int qy, int qz) +static float distancePtSeg(const int x, const int z, + const int px, const int pz, + const int qx, const int qz) { /* float pqx = (float)(qx - px); float pqy = (float)(qy - py); @@ -218,20 +227,40 @@ static float distancePtSeg(int x, int y, int z, return dx*dx + dz*dz; } -static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float maxError, int maxEdgeLen) +static void simplifyContour(rcIntArray& points, rcIntArray& simplified, + const float maxError, const int maxEdgeLen, const int buildFlags) { // Add initial points. - bool noConnections = true; + bool hasConnections = false; for (int i = 0; i < points.size(); i += 4) { - if ((points[i+3] & 0xffff) != 0) + if ((points[i+3] & RC_CONTOUR_REG_MASK) != 0) { - noConnections = false; + hasConnections = true; break; } } - if (noConnections) + if (hasConnections) + { + // The contour has some portals to other regions. + // Add a new point to every location where the region changes. + for (int i = 0, ni = points.size()/4; i < ni; ++i) + { + int ii = (i+1) % ni; + const bool differentRegs = (points[i*4+3] & RC_CONTOUR_REG_MASK) != (points[ii*4+3] & RC_CONTOUR_REG_MASK); + const bool areaBorders = (points[i*4+3] & RC_AREA_BORDER) != (points[ii*4+3] & RC_AREA_BORDER); + if (differentRegs || areaBorders) + { + simplified.push(points[i*4+0]); + simplified.push(points[i*4+1]); + simplified.push(points[i*4+2]); + simplified.push(i); + } + } + } + + if (simplified.size() == 0) { // If there is no connections at all, // create some initial points for the simplification process. @@ -256,7 +285,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma llz = z; lli = i/4; } - if (x >= urx || (x == urx && z > urz)) + if (x > urx || (x == urx && z > urz)) { urx = x; ury = y; @@ -274,22 +303,6 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma simplified.push(urz); simplified.push(uri); } - else - { - // The contour has some portals to other regions. - // Add a new point to every location where the region changes. - for (int i = 0, ni = points.size()/4; i < ni; ++i) - { - int ii = (i+1) % ni; - if ((points[i*4+3] & 0xffff) != (points[ii*4+3] & 0xffff)) - { - simplified.push(points[i*4+0]); - simplified.push(points[i*4+1]); - simplified.push(points[i*4+2]); - simplified.push(i); - } - } - } // Add points until all raw points are within // error tolerance to the simplified shape. @@ -298,34 +311,48 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma { int ii = (i+1) % (simplified.size()/4); - int ax = simplified[i*4+0]; - int ay = simplified[i*4+1]; - int az = simplified[i*4+2]; - int ai = simplified[i*4+3]; - - int bx = simplified[ii*4+0]; - int by = simplified[ii*4+1]; - int bz = simplified[ii*4+2]; - int bi = simplified[ii*4+3]; + const int ax = simplified[i*4+0]; + const int az = simplified[i*4+2]; + const int ai = simplified[i*4+3]; + const int bx = simplified[ii*4+0]; + const int bz = simplified[ii*4+2]; + const int bi = simplified[ii*4+3]; + // Find maximum deviation from the segment. float maxd = 0; int maxi = -1; - int ci = (ai+1) % pn; + int ci, cinc, endi; - // Tesselate only outer edges. - if ((points[ci*4+3] & 0xffff) == 0) + // Traverse the segment in lexilogical order so that the + // max deviation is calculated similarly when traversing + // opposite segments. + if (bx > ax || (bx == ax && bz > az)) { - while (ci != bi) + cinc = 1; + ci = (ai+cinc) % pn; + endi = bi; + } + else + { + cinc = pn-1; + ci = (bi+cinc) % pn; + endi = ai; + } + + // Tessellate only outer edges or edges between areas. + if ((points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0 || + (points[ci*4+3] & RC_AREA_BORDER)) + { + while (ci != endi) { - float d = distancePtSeg(points[ci*4+0], points[ci*4+1]/4, points[ci*4+2], - ax, ay/4, az, bx, by/4, bz); + float d = distancePtSeg(points[ci*4+0], points[ci*4+2], ax, az, bx, bz); if (d > maxd) { maxd = d; maxi = ci; } - ci = (ci+1) % pn; + ci = (ci+cinc) % pn; } } @@ -336,7 +363,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma { // Add space for the new point. simplified.resize(simplified.size()+4); - int n = simplified.size()/4; + const int n = simplified.size()/4; for (int j = n-1; j > i; --j) { simplified[j*4+0] = simplified[(j-1)*4+0]; @@ -357,33 +384,52 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma } // Split too long edges. - if (maxEdgeLen > 0) + if (maxEdgeLen > 0 && (buildFlags & (RC_CONTOUR_TESS_WALL_EDGES|RC_CONTOUR_TESS_AREA_EDGES)) != 0) { for (int i = 0; i < simplified.size()/4; ) { - int ii = (i+1) % (simplified.size()/4); - - int ax = simplified[i*4+0]; - int az = simplified[i*4+2]; - int ai = simplified[i*4+3]; + const int ii = (i+1) % (simplified.size()/4); - int bx = simplified[ii*4+0]; - int bz = simplified[ii*4+2]; - int bi = simplified[ii*4+3]; + const int ax = simplified[i*4+0]; + const int az = simplified[i*4+2]; + const int ai = simplified[i*4+3]; + const int bx = simplified[ii*4+0]; + const int bz = simplified[ii*4+2]; + const int bi = simplified[ii*4+3]; + // Find maximum deviation from the segment. int maxi = -1; int ci = (ai+1) % pn; + + // Tessellate only outer edges or edges between areas. + bool tess = false; + // Wall edges. + if ((buildFlags & RC_CONTOUR_TESS_WALL_EDGES) && (points[ci*4+3] & RC_CONTOUR_REG_MASK) == 0) + tess = true; + // Edges between areas. + if ((buildFlags & RC_CONTOUR_TESS_AREA_EDGES) && (points[ci*4+3] & RC_AREA_BORDER)) + tess = true; - // Tesselate only outer edges. - if ((points[ci*4+3] & 0xffff) == 0) + if (tess) { int dx = bx - ax; int dz = bz - az; if (dx*dx + dz*dz > maxEdgeLen*maxEdgeLen) { - int n = bi < ai ? (bi+pn - ai) : (bi - ai); - maxi = (ai + n/2) % pn; + // Round based on the segments in lexilogical order so that the + // max tesselation is consistent regardles in which direction + // segments are traversed. + if (bx > ax || (bx == ax && bz > az)) + { + const int n = bi < ai ? (bi+pn - ai) : (bi - ai); + maxi = (ai + n/2) % pn; + } + else + { + const int n = bi < ai ? (bi+pn - ai) : (bi - ai); + maxi = (ai + (n+1)/2) % pn; + } } } @@ -393,7 +439,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma { // Add space for the new point. simplified.resize(simplified.size()+4); - int n = simplified.size()/4; + const int n = simplified.size()/4; for (int j = n-1; j > i; --j) { simplified[j*4+0] = simplified[(j-1)*4+0]; @@ -420,7 +466,7 @@ static void simplifyContour(rcIntArray& points, rcIntArray& simplified, float ma // and the neighbour region is take from the next raw point. const int ai = (simplified[i*4+3]+1) % pn; const int bi = simplified[i*4+3]; - simplified[i*4+3] = (points[ai*4+3] & 0xffff) | (points[bi*4+3] & RC_BORDER_VERTEX); + simplified[i*4+3] = (points[ai*4+3] & RC_CONTOUR_REG_MASK) | (points[bi*4+3] & RC_BORDER_VERTEX); } } @@ -446,7 +492,7 @@ static void removeDegenerateSegments(rcIntArray& simplified) simplified[j*4+2] = simplified[(j+1)*4+2]; simplified[j*4+3] = simplified[(j+1)*4+3]; } - simplified.pop(); + simplified.resize(simplified.size()-4); } } } @@ -463,25 +509,40 @@ static int calcAreaOfPolygon2D(const int* verts, const int nverts) return (area+1) / 2; } +inline bool ileft(const int* a, const int* b, const int* c) +{ + return (b[0] - a[0]) * (c[2] - a[2]) - (c[0] - a[0]) * (b[2] - a[2]) <= 0; +} + static void getClosestIndices(const int* vertsa, const int nvertsa, const int* vertsb, const int nvertsb, int& ia, int& ib) { int closestDist = 0xfffffff; + ia = -1, ib = -1; for (int i = 0; i < nvertsa; ++i) { + const int in = (i+1) % nvertsa; + const int ip = (i+nvertsa-1) % nvertsa; const int* va = &vertsa[i*4]; + const int* van = &vertsa[in*4]; + const int* vap = &vertsa[ip*4]; + for (int j = 0; j < nvertsb; ++j) { const int* vb = &vertsb[j*4]; - const int dx = vb[0] - va[0]; - const int dz = vb[2] - va[2]; - const int d = dx*dx + dz*dz; - if (d < closestDist) + // vb must be "infront" of va. + if (ileft(vap,va,vb) && ileft(va,van,vb)) { - ia = i; - ib = j; - closestDist = d; + const int dx = vb[0] - va[0]; + const int dz = vb[2] - va[2]; + const int d = dx*dx + dz*dz; + if (d < closestDist) + { + ia = i; + ib = j; + closestDist = d; + } } } } @@ -490,7 +551,7 @@ static void getClosestIndices(const int* vertsa, const int nvertsa, static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib) { const int maxVerts = ca.nverts + cb.nverts + 2; - int* verts = new int[maxVerts*4]; + int* verts = (int*)rcAlloc(sizeof(int)*maxVerts*4, RC_ALLOC_PERM); if (!verts) return false; @@ -520,47 +581,73 @@ static bool mergeContours(rcContour& ca, rcContour& cb, int ia, int ib) nv++; } - delete [] ca.verts; + rcFree(ca.verts); ca.verts = verts; ca.nverts = nv; - delete [] cb.verts; + rcFree(cb.verts); cb.verts = 0; cb.nverts = 0; return true; } -bool rcBuildContours(rcCompactHeightfield& chf, +/// @par +/// +/// The raw contours will match the region outlines exactly. The @p maxError and @p maxEdgeLen +/// parameters control how closely the simplified contours will match the raw contours. +/// +/// Simplified contours are generated such that the vertices for portals between areas match up. +/// (They are considered mandatory vertices.) +/// +/// Setting @p maxEdgeLength to zero will disabled the edge length feature. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocContourSet, rcCompactHeightfield, rcContourSet, rcConfig +bool rcBuildContours(rcContext* ctx, rcCompactHeightfield& chf, const float maxError, const int maxEdgeLen, - rcContourSet& cset) + rcContourSet& cset, const int buildFlags) { + rcAssert(ctx); + const int w = chf.width; const int h = chf.height; + const int borderSize = chf.borderSize; - rcTimeVal startTime = rcGetPerformanceTimer(); + ctx->startTimer(RC_TIMER_BUILD_CONTOURS); - vcopy(cset.bmin, chf.bmin); - vcopy(cset.bmax, chf.bmax); + rcVcopy(cset.bmin, chf.bmin); + rcVcopy(cset.bmax, chf.bmax); + if (borderSize > 0) + { + // If the heightfield was build with bordersize, remove the offset. + const float pad = borderSize*chf.cs; + cset.bmin[0] += pad; + cset.bmin[2] += pad; + cset.bmax[0] -= pad; + cset.bmax[2] -= pad; + } cset.cs = chf.cs; cset.ch = chf.ch; + cset.width = chf.width - chf.borderSize*2; + cset.height = chf.height - chf.borderSize*2; + cset.borderSize = chf.borderSize; - const int maxContours = chf.maxRegions*2; - cset.conts = new rcContour[maxContours]; + int maxContours = rcMax((int)chf.maxRegions, 8); + cset.conts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM); if (!cset.conts) return false; cset.nconts = 0; - unsigned char* flags = new unsigned char[chf.spanCount]; + rcScopedDelete<unsigned char> flags = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); if (!flags) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'flags'."); + ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'flags' (%d).", chf.spanCount); return false; } - rcTimeVal traceStartTime = rcGetPerformanceTimer(); - + ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE); // Mark boundaries. for (int y = 0; y < h; ++y) @@ -572,7 +659,7 @@ bool rcBuildContours(rcCompactHeightfield& chf, { unsigned char res = 0; const rcCompactSpan& s = chf.spans[i]; - if (!s.reg || (s.reg & RC_BORDER_REG)) + if (!chf.spans[i].reg || (chf.spans[i].reg & RC_BORDER_REG)) { flags[i] = 0; continue; @@ -580,15 +667,14 @@ bool rcBuildContours(rcCompactHeightfield& chf, for (int dir = 0; dir < 4; ++dir) { unsigned short r = 0; - if (rcGetCon(s, dir) != 0xf) + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) { const int ax = x + rcGetDirOffsetX(dir); const int ay = y + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); - const rcCompactSpan& as = chf.spans[ai]; - r = as.reg; + r = chf.spans[ai].reg; } - if (r == s.reg) + if (r == chf.spans[i].reg) res |= (1 << dir); } flags[i] = res ^ 0xf; // Inverse, mark non connected edges. @@ -596,9 +682,7 @@ bool rcBuildContours(rcCompactHeightfield& chf, } } - rcTimeVal traceEndTime = rcGetPerformanceTimer(); - - rcTimeVal simplifyStartTime = rcGetPerformanceTimer(); + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE); rcIntArray verts(256); rcIntArray simplified(64); @@ -615,36 +699,87 @@ bool rcBuildContours(rcCompactHeightfield& chf, flags[i] = 0; continue; } - unsigned short reg = chf.spans[i].reg; + const unsigned short reg = chf.spans[i].reg; if (!reg || (reg & RC_BORDER_REG)) continue; + const unsigned char area = chf.areas[i]; verts.resize(0); simplified.resize(0); + + ctx->startTimer(RC_TIMER_BUILD_CONTOURS_TRACE); walkContour(x, y, i, chf, flags, verts); - simplifyContour(verts, simplified, maxError, maxEdgeLen); + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_TRACE); + + ctx->startTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY); + simplifyContour(verts, simplified, maxError, maxEdgeLen, buildFlags); removeDegenerateSegments(simplified); + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS_SIMPLIFY); + // Store region->contour remap info. // Create contour. if (simplified.size()/4 >= 3) { if (cset.nconts >= maxContours) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildContours: Too many contours %d, max %d.", cset.nconts, maxContours); - return false; + // Allocate more contours. + // This can happen when there are tiny holes in the heightfield. + const int oldMax = maxContours; + maxContours *= 2; + rcContour* newConts = (rcContour*)rcAlloc(sizeof(rcContour)*maxContours, RC_ALLOC_PERM); + for (int j = 0; j < cset.nconts; ++j) + { + newConts[j] = cset.conts[j]; + // Reset source pointers to prevent data deletion. + cset.conts[j].verts = 0; + cset.conts[j].rverts = 0; + } + rcFree(cset.conts); + cset.conts = newConts; + + ctx->log(RC_LOG_WARNING, "rcBuildContours: Expanding max contours from %d to %d.", oldMax, maxContours); } rcContour* cont = &cset.conts[cset.nconts++]; cont->nverts = simplified.size()/4; - cont->verts = new int[cont->nverts*4]; + cont->verts = (int*)rcAlloc(sizeof(int)*cont->nverts*4, RC_ALLOC_PERM); + if (!cont->verts) + { + ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'verts' (%d).", cont->nverts); + return false; + } memcpy(cont->verts, &simplified[0], sizeof(int)*cont->nverts*4); + if (borderSize > 0) + { + // If the heightfield was build with bordersize, remove the offset. + for (int i = 0; i < cont->nverts; ++i) + { + int* v = &cont->verts[i*4]; + v[0] -= borderSize; + v[2] -= borderSize; + } + } cont->nrverts = verts.size()/4; - cont->rverts = new int[cont->nrverts*4]; + cont->rverts = (int*)rcAlloc(sizeof(int)*cont->nrverts*4, RC_ALLOC_PERM); + if (!cont->rverts) + { + ctx->log(RC_LOG_ERROR, "rcBuildContours: Out of memory 'rverts' (%d).", cont->nrverts); + return false; + } memcpy(cont->rverts, &verts[0], sizeof(int)*cont->nrverts*4); + if (borderSize > 0) + { + // If the heightfield was build with bordersize, remove the offset. + for (int i = 0; i < cont->nrverts; ++i) + { + int* v = &cont->rverts[i*4]; + v[0] -= borderSize; + v[2] -= borderSize; + } + } /* cont->cx = cont->cy = cont->cz = 0; for (int i = 0; i < cont->nverts; ++i) @@ -658,13 +793,14 @@ bool rcBuildContours(rcCompactHeightfield& chf, cont->cz /= cont->nverts;*/ cont->reg = reg; + cont->area = area; } } } } // Check and merge droppings. - // Sometimes the previous algorithms can fail and create several countours + // Sometimes the previous algorithms can fail and create several contours // per area. This pass will try to merge the holes into the main region. for (int i = 0; i < cset.nconts; ++i) { @@ -689,44 +825,29 @@ bool rcBuildContours(rcCompactHeightfield& chf, } if (mergeIdx == -1) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "rcBuildContours: Could not find merge target for bad contour %d.", i); + ctx->log(RC_LOG_WARNING, "rcBuildContours: Could not find merge target for bad contour %d.", i); } else { rcContour& mcont = cset.conts[mergeIdx]; // Merge by closest points. - int ia, ib; + int ia = 0, ib = 0; getClosestIndices(mcont.verts, mcont.nverts, cont.verts, cont.nverts, ia, ib); + if (ia == -1 || ib == -1) + { + ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to find merge points for %d and %d.", i, mergeIdx); + continue; + } if (!mergeContours(mcont, cont, ia, ib)) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "rcBuildContours: Failed to merge contours %d and %d.", i, mergeIdx); + ctx->log(RC_LOG_WARNING, "rcBuildContours: Failed to merge contours %d and %d.", i, mergeIdx); + continue; } } } } - - delete [] flags; - - rcTimeVal simplifyEndTime = rcGetPerformanceTimer(); - - rcTimeVal endTime = rcGetPerformanceTimer(); - -// if (rcGetLog()) -// { -// rcGetLog()->log(RC_LOG_PROGRESS, "Create contours: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); -// rcGetLog()->log(RC_LOG_PROGRESS, " - boundary: %.3f ms", rcGetDeltaTimeUsec(boundaryStartTime, boundaryEndTime)/1000.0f); -// rcGetLog()->log(RC_LOG_PROGRESS, " - contour: %.3f ms", rcGetDeltaTimeUsec(contourStartTime, contourEndTime)/1000.0f); -// } - - if (rcGetBuildTimes()) - { - rcGetBuildTimes()->buildContours += rcGetDeltaTimeUsec(startTime, endTime); - rcGetBuildTimes()->buildContoursTrace += rcGetDeltaTimeUsec(traceStartTime, traceEndTime); - rcGetBuildTimes()->buildContoursSimplify += rcGetDeltaTimeUsec(simplifyStartTime, simplifyEndTime); - } + ctx->stopTimer(RC_TIMER_BUILD_CONTOURS); return true; } diff --git a/extern/recastnavigation/Recast/Source/RecastFilter.cpp b/extern/recastnavigation/Recast/Source/RecastFilter.cpp index ebe60714a18..bf985c362c9 100644 --- a/extern/recastnavigation/Recast/Source/RecastFilter.cpp +++ b/extern/recastnavigation/Recast/Source/RecastFilter.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2009 Mikko Mononen memon@inside.org +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -20,15 +20,73 @@ #include <math.h> #include <stdio.h> #include "Recast.h" -#include "RecastLog.h" -#include "RecastTimer.h" +#include "RecastAssert.h" +/// @par +/// +/// Allows the formation of walkable regions that will flow over low lying +/// objects such as curbs, and up structures such as stairways. +/// +/// Two neighboring spans are walkable if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) < waklableClimb</tt> +/// +/// @warning Will override the effect of #rcFilterLedgeSpans. So if both filters are used, call +/// #rcFilterLedgeSpans after calling this filter. +/// +/// @see rcHeightfield, rcConfig +void rcFilterLowHangingWalkableObstacles(rcContext* ctx, const int walkableClimb, rcHeightfield& solid) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_FILTER_LOW_OBSTACLES); + + const int w = solid.width; + const int h = solid.height; + + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + rcSpan* ps = 0; + bool previousWalkable = false; + unsigned char previousArea = RC_NULL_AREA; + + for (rcSpan* s = solid.spans[x + y*w]; s; ps = s, s = s->next) + { + const bool walkable = s->area != RC_NULL_AREA; + // If current span is not walkable, but there is walkable + // span just below it, mark the span above it walkable too. + if (!walkable && previousWalkable) + { + if (rcAbs((int)s->smax - (int)ps->smax) <= walkableClimb) + s->area = previousArea; + } + // Copy walkable flag so that it cannot propagate + // past multiple non-walkable objects. + previousWalkable = walkable; + previousArea = s->area; + } + } + } + + ctx->stopTimer(RC_TIMER_FILTER_LOW_OBSTACLES); +} -void rcFilterLedgeSpans(const int walkableHeight, - const int walkableClimb, +/// @par +/// +/// A ledge is a span with one or more neighbors whose maximum is further away than @p walkableClimb +/// from the current span's maximum. +/// This method removes the impact of the overestimation of conservative voxelization +/// so the resulting mesh will not have regions hanging in the air over ledges. +/// +/// A span is a ledge if: <tt>rcAbs(currentSpan.smax - neighborSpan.smax) > walkableClimb</tt> +/// +/// @see rcHeightfield, rcConfig +void rcFilterLedgeSpans(rcContext* ctx, const int walkableHeight, const int walkableClimb, rcHeightfield& solid) { - rcTimeVal startTime = rcGetPerformanceTimer(); + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_FILTER_BORDER); const int w = solid.width; const int h = solid.height; @@ -42,15 +100,19 @@ void rcFilterLedgeSpans(const int walkableHeight, for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next) { // Skip non walkable spans. - if ((s->flags & RC_WALKABLE) == 0) + if (s->area == RC_NULL_AREA) continue; - const int bot = (int)s->smax; - const int top = s->next ? (int)s->next->smin : MAX_HEIGHT; + const int bot = (int)(s->smax); + const int top = s->next ? (int)(s->next->smin) : MAX_HEIGHT; // Find neighbours minimum height. int minh = MAX_HEIGHT; + // Min and max height of accessible neighbours. + int asmin = s->smax; + int asmax = s->smax; + for (int dir = 0; dir < 4; ++dir) { int dx = x + rcGetDirOffsetX(dir); @@ -77,30 +139,49 @@ void rcFilterLedgeSpans(const int walkableHeight, ntop = ns->next ? (int)ns->next->smin : MAX_HEIGHT; // Skip neightbour if the gap between the spans is too small. if (rcMin(top,ntop) - rcMax(bot,nbot) > walkableHeight) + { minh = rcMin(minh, nbot - bot); + + // Find min/max accessible neighbour height. + if (rcAbs(nbot - bot) <= walkableClimb) + { + if (nbot < asmin) asmin = nbot; + if (nbot > asmax) asmax = nbot; + } + + } } } // The current span is close to a ledge if the drop to any // neighbour span is less than the walkableClimb. if (minh < -walkableClimb) - s->flags &= ~RC_WALKABLE; - + s->area = RC_NULL_AREA; + + // If the difference between all neighbours is too large, + // we are at steep slope, mark the span as ledge. + if ((asmax - asmin) > walkableClimb) + { + s->area = RC_NULL_AREA; + } } } } - rcTimeVal endTime = rcGetPerformanceTimer(); -// if (rcGetLog()) -// rcGetLog()->log(RC_LOG_PROGRESS, "Filter border: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); - if (rcGetBuildTimes()) - rcGetBuildTimes()->filterBorder += rcGetDeltaTimeUsec(startTime, endTime); + ctx->stopTimer(RC_TIMER_FILTER_BORDER); } -void rcFilterWalkableLowHeightSpans(int walkableHeight, - rcHeightfield& solid) +/// @par +/// +/// For this filter, the clearance above the span is the distance from the span's +/// maximum to the next higher span's minimum. (Same grid column.) +/// +/// @see rcHeightfield, rcConfig +void rcFilterWalkableLowHeightSpans(rcContext* ctx, int walkableHeight, rcHeightfield& solid) { - rcTimeVal startTime = rcGetPerformanceTimer(); + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_FILTER_WALKABLE); const int w = solid.width; const int h = solid.height; @@ -114,136 +195,13 @@ void rcFilterWalkableLowHeightSpans(int walkableHeight, { for (rcSpan* s = solid.spans[x + y*w]; s; s = s->next) { - const int bot = (int)s->smax; - const int top = s->next ? (int)s->next->smin : MAX_HEIGHT; + const int bot = (int)(s->smax); + const int top = s->next ? (int)(s->next->smin) : MAX_HEIGHT; if ((top - bot) <= walkableHeight) - s->flags &= ~RC_WALKABLE; + s->area = RC_NULL_AREA; } } } - rcTimeVal endTime = rcGetPerformanceTimer(); - -// if (rcGetLog()) -// rcGetLog()->log(RC_LOG_PROGRESS, "Filter walkable: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); - if (rcGetBuildTimes()) - rcGetBuildTimes()->filterWalkable += rcGetDeltaTimeUsec(startTime, endTime); -} - - -struct rcReachableSeed -{ - inline void set(int ix, int iy, rcSpan* is) - { - x = (unsigned short)ix; - y = (unsigned short)iy; - s = is; - } - unsigned short x, y; - rcSpan* s; -}; - -bool rcMarkReachableSpans(const int walkableHeight, - const int walkableClimb, - rcHeightfield& solid) -{ - const int w = solid.width; - const int h = solid.height; - const int MAX_HEIGHT = 0xffff; - - rcTimeVal startTime = rcGetPerformanceTimer(); - - // Build navigable space. - const int MAX_SEEDS = w*h; - rcReachableSeed* stack = new rcReachableSeed[MAX_SEEDS]; - if (!stack) - { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcMarkReachableSpans: Out of memory 'stack' (%d).", MAX_SEEDS); - return false; - } - int stackSize = 0; - - for (int y = 0; y < h; ++y) - { - for (int x = 0; x < w; ++x) - { - rcSpan* topSpan = solid.spans[x + y*w]; - if (!topSpan) - continue; - while (topSpan->next) - topSpan = topSpan->next; - - // If the span is not walkable, skip it. - if ((topSpan->flags & RC_WALKABLE) == 0) - continue; - // If the span has been visited already, skip it. - if (topSpan->flags & RC_REACHABLE) - continue; - - // Start flood fill. - topSpan->flags |= RC_REACHABLE; - stackSize = 0; - stack[stackSize].set(x, y, topSpan); - stackSize++; - - while (stackSize) - { - // Pop a seed from the stack. - stackSize--; - rcReachableSeed cur = stack[stackSize]; - - const int bot = (int)cur.s->smax; - const int top = cur.s->next ? (int)cur.s->next->smin : MAX_HEIGHT; - - // Visit neighbours in all 4 directions. - for (int dir = 0; dir < 4; ++dir) - { - int dx = (int)cur.x + rcGetDirOffsetX(dir); - int dy = (int)cur.y + rcGetDirOffsetY(dir); - // Skip neighbour which are out of bounds. - if (dx < 0 || dy < 0 || dx >= w || dy >= h) - continue; - for (rcSpan* ns = solid.spans[dx + dy*w]; ns; ns = ns->next) - { - // Skip neighbour if it is not walkable. - if ((ns->flags & RC_WALKABLE) == 0) - continue; - // Skip the neighbour if it has been visited already. - if (ns->flags & RC_REACHABLE) - continue; - - const int nbot = (int)ns->smax; - const int ntop = ns->next ? (int)ns->next->smin : MAX_HEIGHT; - // Skip neightbour if the gap between the spans is too small. - if (rcMin(top,ntop) - rcMax(bot,nbot) < walkableHeight) - continue; - // Skip neightbour if the climb height to the neighbour is too high. - if (rcAbs(nbot - bot) >= walkableClimb) - continue; - - // This neighbour has not been visited yet. - // Mark it as reachable and add it to the seed stack. - ns->flags |= RC_REACHABLE; - if (stackSize < MAX_SEEDS) - { - stack[stackSize].set(dx, dy, ns); - stackSize++; - } - } - } - } - } - } - - delete [] stack; - - rcTimeVal endTime = rcGetPerformanceTimer(); - -// if (rcGetLog()) -// rcGetLog()->log(RC_LOG_PROGRESS, "Mark reachable: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); - if (rcGetBuildTimes()) - rcGetBuildTimes()->filterMarkReachable += rcGetDeltaTimeUsec(startTime, endTime); - - return true; + ctx->stopTimer(RC_TIMER_FILTER_WALKABLE); } diff --git a/extern/recastnavigation/Recast/Source/RecastLayers.cpp b/extern/recastnavigation/Recast/Source/RecastLayers.cpp new file mode 100644 index 00000000000..617cf45fe66 --- /dev/null +++ b/extern/recastnavigation/Recast/Source/RecastLayers.cpp @@ -0,0 +1,620 @@ +// +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. +// + +#include <float.h> +#define _USE_MATH_DEFINES +#include <math.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include "Recast.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" + + +static const int RC_MAX_LAYERS = RC_NOT_CONNECTED; +static const int RC_MAX_NEIS = 16; + +struct rcLayerRegion +{ + unsigned char layers[RC_MAX_LAYERS]; + unsigned char neis[RC_MAX_NEIS]; + unsigned short ymin, ymax; + unsigned char layerId; // Layer ID + unsigned char nlayers; // Layer count + unsigned char nneis; // Neighbour count + unsigned char base; // Flag indicating if the region is hte base of merged regions. +}; + + +static void addUnique(unsigned char* a, unsigned char& an, unsigned char v) +{ + const int n = (int)an; + for (int i = 0; i < n; ++i) + if (a[i] == v) + return; + a[an] = v; + an++; +} + +static bool contains(const unsigned char* a, const unsigned char an, const unsigned char v) +{ + const int n = (int)an; + for (int i = 0; i < n; ++i) + if (a[i] == v) + return true; + return false; +} + +inline bool overlapRange(const unsigned short amin, const unsigned short amax, + const unsigned short bmin, const unsigned short bmax) +{ + return (amin > bmax || amax < bmin) ? false : true; +} + + + +struct rcLayerSweepSpan +{ + unsigned short ns; // number samples + unsigned char id; // region id + unsigned char nei; // neighbour id +}; + +/// @par +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocHeightfieldLayerSet, rcCompactHeightfield, rcHeightfieldLayerSet, rcConfig +bool rcBuildHeightfieldLayers(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int walkableHeight, + rcHeightfieldLayerSet& lset) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_LAYERS); + + const int w = chf.width; + const int h = chf.height; + + rcScopedDelete<unsigned char> srcReg = (unsigned char*)rcAlloc(sizeof(unsigned char)*chf.spanCount, RC_ALLOC_TEMP); + if (!srcReg) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'srcReg' (%d).", chf.spanCount); + return false; + } + memset(srcReg,0xff,sizeof(unsigned char)*chf.spanCount); + + const int nsweeps = chf.width; + rcScopedDelete<rcLayerSweepSpan> sweeps = (rcLayerSweepSpan*)rcAlloc(sizeof(rcLayerSweepSpan)*nsweeps, RC_ALLOC_TEMP); + if (!sweeps) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'sweeps' (%d).", nsweeps); + return false; + } + + + // Partition walkable area into monotone regions. + int prevCount[256]; + unsigned char regId = 0; + + for (int y = borderSize; y < h-borderSize; ++y) + { + memset(prevCount,0,sizeof(int)*regId); + unsigned char sweepId = 0; + + for (int x = borderSize; x < w-borderSize; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + if (chf.areas[i] == RC_NULL_AREA) continue; + + unsigned char sid = 0xff; + + // -x + if (rcGetCon(s, 0) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(0); + const int ay = y + rcGetDirOffsetY(0); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0); + if (chf.areas[ai] != RC_NULL_AREA && srcReg[ai] != 0xff) + sid = srcReg[ai]; + } + + if (sid == 0xff) + { + sid = sweepId++; + sweeps[sid].nei = 0xff; + sweeps[sid].ns = 0; + } + + // -y + if (rcGetCon(s,3) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(3); + const int ay = y + rcGetDirOffsetY(3); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3); + const unsigned char nr = srcReg[ai]; + if (nr != 0xff) + { + // Set neighbour when first valid neighbour is encoutered. + if (sweeps[sid].ns == 0) + sweeps[sid].nei = nr; + + if (sweeps[sid].nei == nr) + { + // Update existing neighbour + sweeps[sid].ns++; + prevCount[nr]++; + } + else + { + // This is hit if there is nore than one neighbour. + // Invalidate the neighbour. + sweeps[sid].nei = 0xff; + } + } + } + + srcReg[i] = sid; + } + } + + // Create unique ID. + for (int i = 0; i < sweepId; ++i) + { + // If the neighbour is set and there is only one continuous connection to it, + // the sweep will be merged with the previous one, else new region is created. + if (sweeps[i].nei != 0xff && prevCount[sweeps[i].nei] == (int)sweeps[i].ns) + { + sweeps[i].id = sweeps[i].nei; + } + else + { + if (regId == 255) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Region ID overflow."); + return false; + } + sweeps[i].id = regId++; + } + } + + // Remap local sweep ids to region ids. + for (int x = borderSize; x < w-borderSize; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (srcReg[i] != 0xff) + srcReg[i] = sweeps[srcReg[i]].id; + } + } + } + + // Allocate and init layer regions. + const int nregs = (int)regId; + rcScopedDelete<rcLayerRegion> regs = (rcLayerRegion*)rcAlloc(sizeof(rcLayerRegion)*nregs, RC_ALLOC_TEMP); + if (!regs) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'regs' (%d).", nregs); + return false; + } + memset(regs, 0, sizeof(rcLayerRegion)*nregs); + for (int i = 0; i < nregs; ++i) + { + regs[i].layerId = 0xff; + regs[i].ymin = 0xffff; + regs[i].ymax = 0; + } + + // Find region neighbours and overlapping regions. + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + + unsigned char lregs[RC_MAX_LAYERS]; + int nlregs = 0; + + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + const unsigned char ri = srcReg[i]; + if (ri == 0xff) continue; + + regs[ri].ymin = rcMin(regs[ri].ymin, s.y); + regs[ri].ymax = rcMax(regs[ri].ymax, s.y); + + // Collect all region layers. + if (nlregs < RC_MAX_LAYERS) + lregs[nlregs++] = ri; + + // Update neighbours + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + const unsigned char rai = srcReg[ai]; + if (rai != 0xff && rai != ri) + addUnique(regs[ri].neis, regs[ri].nneis, rai); + } + } + + } + + // Update overlapping regions. + for (int i = 0; i < nlregs-1; ++i) + { + for (int j = i+1; j < nlregs; ++j) + { + if (lregs[i] != lregs[j]) + { + rcLayerRegion& ri = regs[lregs[i]]; + rcLayerRegion& rj = regs[lregs[j]]; + addUnique(ri.layers, ri.nlayers, lregs[j]); + addUnique(rj.layers, rj.nlayers, lregs[i]); + } + } + } + + } + } + + // Create 2D layers from regions. + unsigned char layerId = 0; + + static const int MAX_STACK = 64; + unsigned char stack[MAX_STACK]; + int nstack = 0; + + for (int i = 0; i < nregs; ++i) + { + rcLayerRegion& root = regs[i]; + // Skip alreadu visited. + if (root.layerId != 0xff) + continue; + + // Start search. + root.layerId = layerId; + root.base = 1; + + nstack = 0; + stack[nstack++] = (unsigned char)i; + + while (nstack) + { + // Pop front + rcLayerRegion& reg = regs[stack[0]]; + nstack--; + for (int j = 0; j < nstack; ++j) + stack[j] = stack[j+1]; + + const int nneis = (int)reg.nneis; + for (int j = 0; j < nneis; ++j) + { + const unsigned char nei = reg.neis[j]; + rcLayerRegion& regn = regs[nei]; + // Skip already visited. + if (regn.layerId != 0xff) + continue; + // Skip if the neighbour is overlapping root region. + if (contains(root.layers, root.nlayers, nei)) + continue; + // Skip if the height range would become too large. + const int ymin = rcMin(root.ymin, regn.ymin); + const int ymax = rcMin(root.ymax, regn.ymax); + if ((ymax - ymin) >= 255) + continue; + + if (nstack < MAX_STACK) + { + // Deepen + stack[nstack++] = (unsigned char)nei; + + // Mark layer id + regn.layerId = layerId; + // Merge current layers to root. + for (int k = 0; k < regn.nlayers; ++k) + addUnique(root.layers, root.nlayers, regn.layers[k]); + root.ymin = rcMin(root.ymin, regn.ymin); + root.ymax = rcMax(root.ymax, regn.ymax); + } + } + } + + layerId++; + } + + // Merge non-overlapping regions that are close in height. + const unsigned short mergeHeight = (unsigned short)walkableHeight * 4; + + for (int i = 0; i < nregs; ++i) + { + rcLayerRegion& ri = regs[i]; + if (!ri.base) continue; + + unsigned char newId = ri.layerId; + + for (;;) + { + unsigned char oldId = 0xff; + + for (int j = 0; j < nregs; ++j) + { + if (i == j) continue; + rcLayerRegion& rj = regs[j]; + if (!rj.base) continue; + + // Skip if teh regions are not close to each other. + if (!overlapRange(ri.ymin,ri.ymax+mergeHeight, rj.ymin,rj.ymax+mergeHeight)) + continue; + // Skip if the height range would become too large. + const int ymin = rcMin(ri.ymin, rj.ymin); + const int ymax = rcMin(ri.ymax, rj.ymax); + if ((ymax - ymin) >= 255) + continue; + + // Make sure that there is no overlap when mergin 'ri' and 'rj'. + bool overlap = false; + // Iterate over all regions which have the same layerId as 'rj' + for (int k = 0; k < nregs; ++k) + { + if (regs[k].layerId != rj.layerId) + continue; + // Check if region 'k' is overlapping region 'ri' + // Index to 'regs' is the same as region id. + if (contains(ri.layers,ri.nlayers, (unsigned char)k)) + { + overlap = true; + break; + } + } + // Cannot merge of regions overlap. + if (overlap) + continue; + + // Can merge i and j. + oldId = rj.layerId; + break; + } + + // Could not find anything to merge with, stop. + if (oldId == 0xff) + break; + + // Merge + for (int j = 0; j < nregs; ++j) + { + rcLayerRegion& rj = regs[j]; + if (rj.layerId == oldId) + { + rj.base = 0; + // Remap layerIds. + rj.layerId = newId; + // Add overlaid layers from 'rj' to 'ri'. + for (int k = 0; k < rj.nlayers; ++k) + addUnique(ri.layers, ri.nlayers, rj.layers[k]); + // Update heigh bounds. + ri.ymin = rcMin(ri.ymin, rj.ymin); + ri.ymax = rcMax(ri.ymax, rj.ymax); + } + } + } + } + + // Compact layerIds + unsigned char remap[256]; + memset(remap, 0, 256); + + // Find number of unique layers. + layerId = 0; + for (int i = 0; i < nregs; ++i) + remap[regs[i].layerId] = 1; + for (int i = 0; i < 256; ++i) + { + if (remap[i]) + remap[i] = layerId++; + else + remap[i] = 0xff; + } + // Remap ids. + for (int i = 0; i < nregs; ++i) + regs[i].layerId = remap[regs[i].layerId]; + + // No layers, return empty. + if (layerId == 0) + { + ctx->stopTimer(RC_TIMER_BUILD_LAYERS); + return true; + } + + // Create layers. + rcAssert(lset.layers == 0); + + const int lw = w - borderSize*2; + const int lh = h - borderSize*2; + + // Build contracted bbox for layers. + float bmin[3], bmax[3]; + rcVcopy(bmin, chf.bmin); + rcVcopy(bmax, chf.bmax); + bmin[0] += borderSize*chf.cs; + bmin[2] += borderSize*chf.cs; + bmax[0] -= borderSize*chf.cs; + bmax[2] -= borderSize*chf.cs; + + lset.nlayers = (int)layerId; + + lset.layers = (rcHeightfieldLayer*)rcAlloc(sizeof(rcHeightfieldLayer)*lset.nlayers, RC_ALLOC_PERM); + if (!lset.layers) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'layers' (%d).", lset.nlayers); + return false; + } + memset(lset.layers, 0, sizeof(rcHeightfieldLayer)*lset.nlayers); + + + // Store layers. + for (int i = 0; i < lset.nlayers; ++i) + { + unsigned char curId = (unsigned char)i; + + // Allocate memory for the current layer. + rcHeightfieldLayer* layer = &lset.layers[i]; + memset(layer, 0, sizeof(rcHeightfieldLayer)); + + const int gridSize = sizeof(unsigned char)*lw*lh; + + layer->heights = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM); + if (!layer->heights) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'heights' (%d).", gridSize); + return false; + } + memset(layer->heights, 0xff, gridSize); + + layer->areas = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM); + if (!layer->areas) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'areas' (%d).", gridSize); + return false; + } + memset(layer->areas, 0, gridSize); + + layer->cons = (unsigned char*)rcAlloc(gridSize, RC_ALLOC_PERM); + if (!layer->cons) + { + ctx->log(RC_LOG_ERROR, "rcBuildHeightfieldLayers: Out of memory 'cons' (%d).", gridSize); + return false; + } + memset(layer->cons, 0, gridSize); + + // Find layer height bounds. + int hmin = 0, hmax = 0; + for (int j = 0; j < nregs; ++j) + { + if (regs[j].base && regs[j].layerId == curId) + { + hmin = (int)regs[j].ymin; + hmax = (int)regs[j].ymax; + } + } + + layer->width = lw; + layer->height = lh; + layer->cs = chf.cs; + layer->ch = chf.ch; + + // Adjust the bbox to fit the heighfield. + rcVcopy(layer->bmin, bmin); + rcVcopy(layer->bmax, bmax); + layer->bmin[1] = bmin[1] + hmin*chf.ch; + layer->bmax[1] = bmin[1] + hmax*chf.ch; + layer->hmin = hmin; + layer->hmax = hmax; + + // Update usable data region. + layer->minx = layer->width; + layer->maxx = 0; + layer->miny = layer->height; + layer->maxy = 0; + + // Copy height and area from compact heighfield. + for (int y = 0; y < lh; ++y) + { + for (int x = 0; x < lw; ++x) + { + const int cx = borderSize+x; + const int cy = borderSize+y; + const rcCompactCell& c = chf.cells[cx+cy*w]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + // Skip unassigned regions. + if (srcReg[i] == 0xff) + continue; + // Skip of does nto belong to current layer. + unsigned char lid = regs[srcReg[i]].layerId; + if (lid != curId) + continue; + + // Update data bounds. + layer->minx = rcMin(layer->minx, x); + layer->maxx = rcMax(layer->maxx, x); + layer->miny = rcMin(layer->miny, y); + layer->maxy = rcMax(layer->maxy, y); + + // Store height and area type. + const int idx = x+y*lw; + layer->heights[idx] = (unsigned char)(s.y - hmin); + layer->areas[idx] = chf.areas[i]; + + // Check connection. + unsigned char portal = 0; + unsigned char con = 0; + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = cx + rcGetDirOffsetX(dir); + const int ay = cy + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + unsigned char alid = srcReg[ai] != 0xff ? regs[srcReg[ai]].layerId : 0xff; + // Portal mask + if (chf.areas[ai] != RC_NULL_AREA && lid != alid) + { + portal |= (unsigned char)(1<<dir); + // Update height so that it matches on both sides of the portal. + const rcCompactSpan& as = chf.spans[ai]; + if (as.y > hmin) + layer->heights[idx] = rcMax(layer->heights[idx], (unsigned char)(as.y - hmin)); + } + // Valid connection mask + if (chf.areas[ai] != RC_NULL_AREA && lid == alid) + { + const int nx = ax - borderSize; + const int ny = ay - borderSize; + if (nx >= 0 && ny >= 0 && nx < lw && ny < lh) + con |= (unsigned char)(1<<dir); + } + } + } + + layer->cons[idx] = (portal << 4) | con; + } + } + } + + if (layer->minx > layer->maxx) + layer->minx = layer->maxx = 0; + if (layer->miny > layer->maxy) + layer->miny = layer->maxy = 0; + } + + ctx->stopTimer(RC_TIMER_BUILD_LAYERS); + + return true; +} diff --git a/extern/recastnavigation/Recast/Source/RecastMesh.cpp b/extern/recastnavigation/Recast/Source/RecastMesh.cpp index 38d62904213..ef37d569a17 100644 --- a/extern/recastnavigation/Recast/Source/RecastMesh.cpp +++ b/extern/recastnavigation/Recast/Source/RecastMesh.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2009 Mikko Mononen memon@inside.org +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -21,9 +21,8 @@ #include <string.h> #include <stdio.h> #include "Recast.h" -#include "RecastLog.h" -#include "RecastTimer.h" - +#include "RecastAlloc.h" +#include "RecastAssert.h" struct rcEdge { @@ -32,36 +31,37 @@ struct rcEdge unsigned short poly[2]; }; -/*static */bool buildMeshAdjacency(unsigned short* polys, const int npolys, +/*static*/ bool buildMeshAdjacency(unsigned short* polys, const int npolys, const int nverts, const int vertsPerPoly) { // Based on code by Eric Lengyel from: // http://www.terathon.com/code/edges.php int maxEdgeCount = npolys*vertsPerPoly; - unsigned short* firstEdge = new unsigned short[nverts + maxEdgeCount]; + unsigned short* firstEdge = (unsigned short*)rcAlloc(sizeof(unsigned short)*(nverts + maxEdgeCount), RC_ALLOC_TEMP); if (!firstEdge) return false; unsigned short* nextEdge = firstEdge + nverts; int edgeCount = 0; - rcEdge* edges = new rcEdge[maxEdgeCount]; + rcEdge* edges = (rcEdge*)rcAlloc(sizeof(rcEdge)*maxEdgeCount, RC_ALLOC_TEMP); if (!edges) + { + rcFree(firstEdge); return false; + } for (int i = 0; i < nverts; i++) - firstEdge[i] = 0xffff; - - // Invalida indices are marked as 0xffff, the following code - // handles them just fine. + firstEdge[i] = RC_MESH_NULL_IDX; for (int i = 0; i < npolys; ++i) { unsigned short* t = &polys[i*vertsPerPoly*2]; for (int j = 0; j < vertsPerPoly; ++j) { + if (t[j] == RC_MESH_NULL_IDX) break; unsigned short v0 = t[j]; - unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == 0xffff) ? t[0] : t[j+1]; + unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1]; if (v0 < v1) { rcEdge& edge = edges[edgeCount]; @@ -73,7 +73,7 @@ struct rcEdge edge.polyEdge[1] = 0; // Insert edge nextEdge[edgeCount] = firstEdge[v0]; - firstEdge[v0] = edgeCount; + firstEdge[v0] = (unsigned short)edgeCount; edgeCount++; } } @@ -84,11 +84,12 @@ struct rcEdge unsigned short* t = &polys[i*vertsPerPoly*2]; for (int j = 0; j < vertsPerPoly; ++j) { + if (t[j] == RC_MESH_NULL_IDX) break; unsigned short v0 = t[j]; - unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == 0xffff) ? t[0] : t[j+1]; + unsigned short v1 = (j+1 >= vertsPerPoly || t[j+1] == RC_MESH_NULL_IDX) ? t[0] : t[j+1]; if (v0 > v1) { - for (unsigned short e = firstEdge[v1]; e != 0xffff; e = nextEdge[e]) + for (unsigned short e = firstEdge[v1]; e != RC_MESH_NULL_IDX; e = nextEdge[e]) { rcEdge& edge = edges[e]; if (edge.vert[1] == v0 && edge.poly[0] == edge.poly[1]) @@ -115,8 +116,8 @@ struct rcEdge } } - delete [] firstEdge; - delete [] edges; + rcFree(firstEdge); + rcFree(edges); return true; } @@ -133,8 +134,8 @@ inline int computeVertexHash(int x, int y, int z) return (int)(n & (VERTEX_BUCKET_COUNT-1)); } -static int addVertex(unsigned short x, unsigned short y, unsigned short z, - unsigned short* verts, int* firstVert, int* nextVert, int& nv) +static unsigned short addVertex(unsigned short x, unsigned short y, unsigned short z, + unsigned short* verts, int* firstVert, int* nextVert, int& nv) { int bucket = computeVertexHash(x, 0, z); int i = firstVert[bucket]; @@ -143,7 +144,7 @@ static int addVertex(unsigned short x, unsigned short y, unsigned short z, { const unsigned short* v = &verts[i*3]; if (v[0] == x && (rcAbs(v[1] - y) <= 2) && v[2] == z) - return i; + return (unsigned short)i; i = nextVert[i]; // next } @@ -156,7 +157,7 @@ static int addVertex(unsigned short x, unsigned short y, unsigned short z, nextVert[i] = firstVert[bucket]; firstVert[bucket] = i; - return i; + return (unsigned short)i; } inline int prev(int i, int n) { return i-1 >= 0 ? i-1 : n-1; } @@ -196,7 +197,7 @@ inline bool collinear(const int* a, const int* b, const int* c) // Returns true iff ab properly intersects cd: they share // a point interior to both segments. The properness of the // intersection is ensured by using strict leftness. -bool intersectProp(const int* a, const int* b, const int* c, const int* d) +static bool intersectProp(const int* a, const int* b, const int* c, const int* d) { // Eliminate improper cases. if (collinear(a,b,c) || collinear(a,b,d) || @@ -287,7 +288,7 @@ static bool diagonal(int i, int j, int n, const int* verts, int* indices) return inCone(i, j, n, verts, indices) && diagonalie(i, j, n, verts, indices); } -int triangulate(int n, const int* verts, int* indices, int* tris) +static int triangulate(int n, const int* verts, int* indices, int* tris) { int ntris = 0; int* dst = tris; @@ -328,8 +329,6 @@ int triangulate(int n, const int* verts, int* indices, int* tris) if (mini == -1) { // Should not happen. - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "triangulate: Failed to triangulate polygon."); /* printf("mini == -1 ntris=%d n=%d\n", ntris, n); for (int i = 0; i < n; i++) { @@ -379,7 +378,7 @@ int triangulate(int n, const int* verts, int* indices, int* tris) static int countPolyVerts(const unsigned short* p, const int nvp) { for (int i = 0; i < nvp; ++i) - if (p[i] == 0xffff) + if (p[i] == RC_MESH_NULL_IDX) return i; return nvp; } @@ -454,8 +453,7 @@ static int getPolyMergeValue(unsigned short* pa, unsigned short* pb, return dx*dx + dy*dy; } -static void mergePolys(unsigned short* pa, unsigned short* pb, - const unsigned short* verts, int ea, int eb, +static void mergePolys(unsigned short* pa, unsigned short* pb, int ea, int eb, unsigned short* tmp, const int nvp) { const int na = countPolyVerts(pa, nvp); @@ -474,6 +472,7 @@ static void mergePolys(unsigned short* pa, unsigned short* pb, memcpy(pa, tmp, sizeof(unsigned short)*nvp); } + static void pushFront(int v, int* arr, int& an) { an++; @@ -487,59 +486,157 @@ static void pushBack(int v, int* arr, int& an) an++; } -static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int maxTris) +static bool canRemoveVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short rem) { - unsigned short* tmpPoly; - int ntris; + const int nvp = mesh.nvp; + + // Count number of polygons to remove. + int numRemovedVerts = 0; + int numTouchedVerts = 0; + int numRemainingEdges = 0; + for (int i = 0; i < mesh.npolys; ++i) + { + unsigned short* p = &mesh.polys[i*nvp*2]; + const int nv = countPolyVerts(p, nvp); + int numRemoved = 0; + int numVerts = 0; + for (int j = 0; j < nv; ++j) + { + if (p[j] == rem) + { + numTouchedVerts++; + numRemoved++; + } + numVerts++; + } + if (numRemoved) + { + numRemovedVerts += numRemoved; + numRemainingEdges += numVerts-(numRemoved+1); + } + } + + // There would be too few edges remaining to create a polygon. + // This can happen for example when a tip of a triangle is marked + // as deletion, but there are no other polys that share the vertex. + // In this case, the vertex should not be removed. + if (numRemainingEdges <= 2) + return false; + + // Find edges which share the removed vertex. + const int maxEdges = numTouchedVerts*2; + int nedges = 0; + rcScopedDelete<int> edges = (int*)rcAlloc(sizeof(int)*maxEdges*3, RC_ALLOC_TEMP); + if (!edges) + { + ctx->log(RC_LOG_WARNING, "canRemoveVertex: Out of memory 'edges' (%d).", maxEdges*3); + return false; + } + + for (int i = 0; i < mesh.npolys; ++i) + { + unsigned short* p = &mesh.polys[i*nvp*2]; + const int nv = countPolyVerts(p, nvp); + + // Collect edges which touches the removed vertex. + for (int j = 0, k = nv-1; j < nv; k = j++) + { + if (p[j] == rem || p[k] == rem) + { + // Arrange edge so that a=rem. + int a = p[j], b = p[k]; + if (b == rem) + rcSwap(a,b); + + // Check if the edge exists + bool exists = false; + for (int k = 0; k < nedges; ++k) + { + int* e = &edges[k*3]; + if (e[1] == b) + { + // Exists, increment vertex share count. + e[2]++; + exists = true; + } + } + // Add new edge. + if (!exists) + { + int* e = &edges[nedges*3]; + e[0] = a; + e[1] = b; + e[2] = 1; + nedges++; + } + } + } + } - static const int nvp = mesh.nvp; + // There should be no more than 2 open edges. + // This catches the case that two non-adjacent polygons + // share the removed vertex. In that case, do not remove the vertex. + int numOpenEdges = 0; + for (int i = 0; i < nedges; ++i) + { + if (edges[i*3+2] < 2) + numOpenEdges++; + } + if (numOpenEdges > 2) + return false; + + return true; +} - int* edges = 0; - int nedges = 0; - int* hole = 0; - int nhole = 0; - int* hreg = 0; - int nhreg = 0; - int* tris = 0; - int* tverts = 0; - int* thole = 0; - unsigned short* polys = 0; - unsigned short* pregs = 0; - int npolys = 0; +static bool removeVertex(rcContext* ctx, rcPolyMesh& mesh, const unsigned short rem, const int maxTris) +{ + const int nvp = mesh.nvp; // Count number of polygons to remove. - int nrem = 0; + int numRemovedVerts = 0; for (int i = 0; i < mesh.npolys; ++i) { unsigned short* p = &mesh.polys[i*nvp*2]; - for (int j = 0; j < nvp; ++j) - if (p[j] == rem) { nrem++; break; } + const int nv = countPolyVerts(p, nvp); + for (int j = 0; j < nv; ++j) + { + if (p[j] == rem) + numRemovedVerts++; + } } - - edges = new int[nrem*nvp*3]; + + int nedges = 0; + rcScopedDelete<int> edges = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp*4, RC_ALLOC_TEMP); if (!edges) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", nrem*nvp*3); - goto failure; + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'edges' (%d).", numRemovedVerts*nvp*4); + return false; } - hole = new int[nrem*nvp]; + int nhole = 0; + rcScopedDelete<int> hole = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP); if (!hole) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", nrem*nvp); - goto failure; + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hole' (%d).", numRemovedVerts*nvp); + return false; } - hreg = new int[nrem*nvp]; + + int nhreg = 0; + rcScopedDelete<int> hreg = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP); if (!hreg) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", nrem*nvp); - goto failure; + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'hreg' (%d).", numRemovedVerts*nvp); + return false; + } + + int nharea = 0; + rcScopedDelete<int> harea = (int*)rcAlloc(sizeof(int)*numRemovedVerts*nvp, RC_ALLOC_TEMP); + if (!harea) + { + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'harea' (%d).", numRemovedVerts*nvp); + return false; } - for (int i = 0; i < mesh.npolys; ++i) { unsigned short* p = &mesh.polys[i*nvp*2]; @@ -554,17 +651,20 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m { if (p[j] != rem && p[k] != rem) { - int* e = &edges[nedges*3]; + int* e = &edges[nedges*4]; e[0] = p[k]; e[1] = p[j]; e[2] = mesh.regs[i]; + e[3] = mesh.areas[i]; nedges++; } } // Remove the polygon. unsigned short* p2 = &mesh.polys[(mesh.npolys-1)*nvp*2]; memcpy(p,p2,sizeof(unsigned short)*nvp); + memset(p+nvp,0xff,sizeof(unsigned short)*nvp); mesh.regs[i] = mesh.regs[mesh.npolys-1]; + mesh.areas[i] = mesh.areas[mesh.npolys-1]; mesh.npolys--; --i; } @@ -589,16 +689,18 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m } for (int i = 0; i < nedges; ++i) { - if (edges[i*3+0] > rem) edges[i*3+0]--; - if (edges[i*3+1] > rem) edges[i*3+1]--; + if (edges[i*4+0] > rem) edges[i*4+0]--; + if (edges[i*4+1] > rem) edges[i*4+1]--; } if (nedges == 0) return true; - hole[nhole] = edges[0]; - hreg[nhole] = edges[2]; - nhole++; + // Start with one vertex, keep appending connected + // segments to the start and end of the hole. + pushBack(edges[0], hole, nhole); + pushBack(edges[2], hreg, nhreg); + pushBack(edges[3], harea, nharea); while (nedges) { @@ -606,28 +708,34 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m for (int i = 0; i < nedges; ++i) { - const int ea = edges[i*3+0]; - const int eb = edges[i*3+1]; - const int r = edges[i*3+2]; + const int ea = edges[i*4+0]; + const int eb = edges[i*4+1]; + const int r = edges[i*4+2]; + const int a = edges[i*4+3]; bool add = false; if (hole[0] == eb) { + // The segment matches the beginning of the hole boundary. pushFront(ea, hole, nhole); pushFront(r, hreg, nhreg); + pushFront(a, harea, nharea); add = true; } else if (hole[nhole-1] == ea) { + // The segment matches the end of the hole boundary. pushBack(eb, hole, nhole); pushBack(r, hreg, nhreg); + pushBack(a, harea, nharea); add = true; } if (add) { - // Remove edge. - edges[i*3+0] = edges[(nedges-1)*3+0]; - edges[i*3+1] = edges[(nedges-1)*3+1]; - edges[i*3+2] = edges[(nedges-1)*3+2]; + // The edge segment was added, remove it. + edges[i*4+0] = edges[(nedges-1)*4+0]; + edges[i*4+1] = edges[(nedges-1)*4+1]; + edges[i*4+2] = edges[(nedges-1)*4+2]; + edges[i*4+3] = edges[(nedges-1)*4+3]; --nedges; match = true; --i; @@ -638,28 +746,25 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m break; } - tris = new int[nhole*3]; + rcScopedDelete<int> tris = (int*)rcAlloc(sizeof(int)*nhole*3, RC_ALLOC_TEMP); if (!tris) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3); - goto failure; + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tris' (%d).", nhole*3); + return false; } - tverts = new int[nhole*4]; + rcScopedDelete<int> tverts = (int*)rcAlloc(sizeof(int)*nhole*4, RC_ALLOC_TEMP); if (!tverts) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4); - goto failure; + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'tverts' (%d).", nhole*4); + return false; } - thole = new int[nhole]; + rcScopedDelete<int> thole = (int*)rcAlloc(sizeof(int)*nhole, RC_ALLOC_TEMP); if (!tverts) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole); - goto failure; + ctx->log(RC_LOG_WARNING, "removeVertex: Out of memory 'thole' (%d).", nhole); + return false; } // Generate temp vertex array for triangulation. @@ -674,27 +779,37 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m } // Triangulate the hole. - ntris = triangulate(nhole, &tverts[0], &thole[0], tris); - + int ntris = triangulate(nhole, &tverts[0], &thole[0], tris); + if (ntris < 0) + { + ntris = -ntris; + ctx->log(RC_LOG_WARNING, "removeVertex: triangulate() returned bad results."); + } + // Merge the hole triangles back to polygons. - polys = new unsigned short[(ntris+1)*nvp]; + rcScopedDelete<unsigned short> polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(ntris+1)*nvp, RC_ALLOC_TEMP); if (!polys) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp); - goto failure; + ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'polys' (%d).", (ntris+1)*nvp); + return false; } - pregs = new unsigned short[ntris]; + rcScopedDelete<unsigned short> pregs = (unsigned short*)rcAlloc(sizeof(unsigned short)*ntris, RC_ALLOC_TEMP); if (!pregs) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_WARNING, "removeVertex: Out of memory 'pregs' (%d).", ntris); - goto failure; + ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pregs' (%d).", ntris); + return false; + } + rcScopedDelete<unsigned char> pareas = (unsigned char*)rcAlloc(sizeof(unsigned char)*ntris, RC_ALLOC_TEMP); + if (!pregs) + { + ctx->log(RC_LOG_ERROR, "removeVertex: Out of memory 'pareas' (%d).", ntris); + return false; } - tmpPoly = &polys[ntris*nvp]; + unsigned short* tmpPoly = &polys[ntris*nvp]; // Build initial polygons. + int npolys = 0; memset(polys, 0xff, ntris*nvp*sizeof(unsigned short)); for (int j = 0; j < ntris; ++j) { @@ -704,7 +819,8 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m polys[npolys*nvp+0] = (unsigned short)hole[t[0]]; polys[npolys*nvp+1] = (unsigned short)hole[t[1]]; polys[npolys*nvp+2] = (unsigned short)hole[t[2]]; - pregs[npolys] = hreg[t[0]]; + pregs[npolys] = (unsigned short)hreg[t[0]]; + pareas[npolys] = (unsigned char)harea[t[0]]; npolys++; } } @@ -714,11 +830,11 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m // Merge polygons. if (nvp > 3) { - while (true) + for (;;) { // Find best polygons to merge. int bestMergeVal = 0; - int bestPa, bestPb, bestEa, bestEb; + int bestPa = 0, bestPb = 0, bestEa = 0, bestEb = 0; for (int j = 0; j < npolys-1; ++j) { @@ -744,9 +860,10 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m // Found best, merge. unsigned short* pa = &polys[bestPa*nvp]; unsigned short* pb = &polys[bestPb*nvp]; - mergePolys(pa, pb, mesh.verts, bestEa, bestEb, tmpPoly, nvp); + mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp); memcpy(pb, &polys[(npolys-1)*nvp], sizeof(unsigned short)*nvp); pregs[bestPb] = pregs[npolys-1]; + pareas[bestPb] = pareas[npolys-1]; npolys--; } else @@ -766,50 +883,43 @@ static bool removeVertex(rcPolyMesh& mesh, const unsigned short rem, const int m for (int j = 0; j < nvp; ++j) p[j] = polys[i*nvp+j]; mesh.regs[mesh.npolys] = pregs[i]; + mesh.areas[mesh.npolys] = pareas[i]; mesh.npolys++; + if (mesh.npolys > maxTris) + { + ctx->log(RC_LOG_ERROR, "removeVertex: Too many polygons %d (max:%d).", mesh.npolys, maxTris); + return false; + } } - delete [] edges; - delete [] hole; - delete [] hreg; - delete [] tris; - delete [] thole; - delete [] tverts; - delete [] polys; - delete [] pregs; - return true; - -failure: - delete [] edges; - delete [] hole; - delete [] hreg; - delete [] tris; - delete [] thole; - delete [] tverts; - delete [] polys; - delete [] pregs; - - return false; } - -bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh) +/// @par +/// +/// @note If the mesh data is to be used to construct a Detour navigation mesh, then the upper +/// limit must be retricted to <= #DT_VERTS_PER_POLYGON. +/// +/// @see rcAllocPolyMesh, rcContourSet, rcPolyMesh, rcConfig +bool rcBuildPolyMesh(rcContext* ctx, rcContourSet& cset, const int nvp, rcPolyMesh& mesh) { - unsigned short* tmpPoly; - rcTimeVal startTime = rcGetPerformanceTimer(); - rcTimeVal endTime; + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_POLYMESH); - vcopy(mesh.bmin, cset.bmin); - vcopy(mesh.bmax, cset.bmax); + rcVcopy(mesh.bmin, cset.bmin); + rcVcopy(mesh.bmax, cset.bmax); mesh.cs = cset.cs; mesh.ch = cset.ch; + mesh.borderSize = cset.borderSize; int maxVertices = 0; int maxTris = 0; int maxVertsPerCont = 0; for (int i = 0; i < cset.nconts; ++i) { + // Skip null contours. + if (cset.conts[i].nverts < 3) continue; maxVertices += cset.conts[i].nverts; maxTris += cset.conts[i].nverts - 2; maxVertsPerCont = rcMax(maxVertsPerCont, cset.conts[i].nverts); @@ -817,103 +927,95 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh) if (maxVertices >= 0xfffe) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many vertices %d.", maxVertices); + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many vertices %d.", maxVertices); return false; } - - unsigned char* vflags = 0; - int* nextVert = 0; - int* firstVert = 0; - int* indices = 0; - int* tris = 0; - unsigned short* polys = 0; - - vflags = new unsigned char[maxVertices]; + + rcScopedDelete<unsigned char> vflags = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxVertices, RC_ALLOC_TEMP); if (!vflags) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices); + return false; } memset(vflags, 0, maxVertices); - mesh.verts = new unsigned short[maxVertices*3]; + mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertices*3, RC_ALLOC_PERM); if (!mesh.verts) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.verts' (%d).", maxVertices); + return false; } - mesh.polys = new unsigned short[maxTris*nvp*2]; + mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris*nvp*2, RC_ALLOC_PERM); if (!mesh.polys) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.polys' (%d).", maxTris*nvp*2); + return false; } - mesh.regs = new unsigned short[maxTris]; + mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxTris, RC_ALLOC_PERM); if (!mesh.regs) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.regs' (%d).", maxTris); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.regs' (%d).", maxTris); + return false; + } + mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris, RC_ALLOC_PERM); + if (!mesh.areas) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.areas' (%d).", maxTris); + return false; } + mesh.nverts = 0; mesh.npolys = 0; mesh.nvp = nvp; + mesh.maxpolys = maxTris; memset(mesh.verts, 0, sizeof(unsigned short)*maxVertices*3); memset(mesh.polys, 0xff, sizeof(unsigned short)*maxTris*nvp*2); memset(mesh.regs, 0, sizeof(unsigned short)*maxTris); + memset(mesh.areas, 0, sizeof(unsigned char)*maxTris); - nextVert = new int[maxVertices]; + rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVertices, RC_ALLOC_TEMP); if (!nextVert) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'nextVert' (%d).", maxVertices); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'nextVert' (%d).", maxVertices); + return false; } memset(nextVert, 0, sizeof(int)*maxVertices); - firstVert = new int[VERTEX_BUCKET_COUNT]; + rcScopedDelete<int> firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP); if (!firstVert) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT); + return false; } for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i) firstVert[i] = -1; - indices = new int[maxVertsPerCont]; + rcScopedDelete<int> indices = (int*)rcAlloc(sizeof(int)*maxVertsPerCont, RC_ALLOC_TEMP); if (!indices) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'indices' (%d).", maxVertsPerCont); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'indices' (%d).", maxVertsPerCont); + return false; } - tris = new int[maxVertsPerCont*3]; + rcScopedDelete<int> tris = (int*)rcAlloc(sizeof(int)*maxVertsPerCont*3, RC_ALLOC_TEMP); if (!tris) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tris' (%d).", maxVertsPerCont*3); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'tris' (%d).", maxVertsPerCont*3); + return false; } - polys = new unsigned short[(maxVertsPerCont+1)*nvp]; + rcScopedDelete<unsigned short> polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*(maxVertsPerCont+1)*nvp, RC_ALLOC_TEMP); if (!polys) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'polys' (%d).", maxVertsPerCont*nvp); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'polys' (%d).", maxVertsPerCont*nvp); + return false; } - tmpPoly = &polys[maxVertsPerCont*nvp]; + unsigned short* tmpPoly = &polys[maxVertsPerCont*nvp]; for (int i = 0; i < cset.nconts; ++i) { rcContour& cont = cset.conts[i]; - // Skip empty contours. + // Skip null contours. if (cont.nverts < 3) continue; @@ -925,20 +1027,20 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh) if (ntris <= 0) { // Bad triangulation, should not happen. -/* for (int k = 0; k < cont.nverts; ++k) +/* printf("\tconst float bmin[3] = {%ff,%ff,%ff};\n", cset.bmin[0], cset.bmin[1], cset.bmin[2]); + printf("\tconst float cs = %ff;\n", cset.cs); + printf("\tconst float ch = %ff;\n", cset.ch); + printf("\tconst int verts[] = {\n"); + for (int k = 0; k < cont.nverts; ++k) { const int* v = &cont.verts[k*4]; printf("\t\t%d,%d,%d,%d,\n", v[0], v[1], v[2], v[3]); - if (nBadPos < 100) - { - badPos[nBadPos*3+0] = v[0]; - badPos[nBadPos*3+1] = v[1]; - badPos[nBadPos*3+2] = v[2]; - nBadPos++; - } - }*/ + } + printf("\t};\n\tconst int nverts = sizeof(verts)/(sizeof(int)*4);\n");*/ + ctx->log(RC_LOG_WARNING, "rcBuildPolyMesh: Bad triangulation Contour %d.", i); ntris = -ntris; } + // Add and merge vertices. for (int j = 0; j < cont.nverts; ++j) { @@ -972,11 +1074,11 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh) // Merge polygons. if (nvp > 3) { - while (true) + for(;;) { // Find best polygons to merge. int bestMergeVal = 0; - int bestPa, bestPb, bestEa, bestEb; + int bestPa = 0, bestPb = 0, bestEa = 0, bestEb = 0; for (int j = 0; j < npolys-1; ++j) { @@ -1002,7 +1104,7 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh) // Found best, merge. unsigned short* pa = &polys[bestPa*nvp]; unsigned short* pb = &polys[bestPb*nvp]; - mergePolys(pa, pb, mesh.verts, bestEa, bestEb, tmpPoly, nvp); + mergePolys(pa, pb, bestEa, bestEb, tmpPoly, nvp); memcpy(pb, &polys[(npolys-1)*nvp], sizeof(unsigned short)*nvp); npolys--; } @@ -1014,7 +1116,6 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh) } } - // Store polygons. for (int j = 0; j < npolys; ++j) { @@ -1023,7 +1124,13 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh) for (int k = 0; k < nvp; ++k) p[k] = q[k]; mesh.regs[mesh.npolys] = cont.reg; + mesh.areas[mesh.npolys] = cont.area; mesh.npolys++; + if (mesh.npolys > maxTris) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Too many polygons %d (max:%d).", mesh.npolys, maxTris); + return false; + } } } @@ -1033,131 +1140,174 @@ bool rcBuildPolyMesh(rcContourSet& cset, int nvp, rcPolyMesh& mesh) { if (vflags[i]) { - if (!removeVertex(mesh, i, maxTris)) - goto failure; - for (int j = i; j < mesh.nverts-1; ++j) + if (!canRemoveVertex(ctx, mesh, (unsigned short)i)) + continue; + if (!removeVertex(ctx, mesh, (unsigned short)i, maxTris)) + { + // Failed to remove vertex + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Failed to remove edge vertex %d.", i); + return false; + } + // Remove vertex + // Note: mesh.nverts is already decremented inside removeVertex()! + for (int j = i; j < mesh.nverts; ++j) vflags[j] = vflags[j+1]; --i; } } - - delete [] vflags; - delete [] firstVert; - delete [] nextVert; - delete [] indices; - delete [] tris; // Calculate adjacency. if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, nvp)) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMesh: Adjacency failed."); + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Adjacency failed."); return false; } - endTime = rcGetPerformanceTimer(); + // Find portal edges + if (mesh.borderSize > 0) + { + const int w = cset.width; + const int h = cset.height; + for (int i = 0; i < mesh.npolys; ++i) + { + unsigned short* p = &mesh.polys[i*2*nvp]; + for (int j = 0; j < nvp; ++j) + { + if (p[j] == RC_MESH_NULL_IDX) break; + // Skip connected edges. + if (p[nvp+j] != RC_MESH_NULL_IDX) + continue; + int nj = j+1; + if (nj >= nvp || p[nj] == RC_MESH_NULL_IDX) nj = 0; + const unsigned short* va = &mesh.verts[p[j]*3]; + const unsigned short* vb = &mesh.verts[p[nj]*3]; + + if ((int)va[0] == 0 && (int)vb[0] == 0) + p[nvp+j] = 0x8000 | 0; + else if ((int)va[2] == h && (int)vb[2] == h) + p[nvp+j] = 0x8000 | 1; + else if ((int)va[0] == w && (int)vb[0] == w) + p[nvp+j] = 0x8000 | 2; + else if ((int)va[2] == 0 && (int)vb[2] == 0) + p[nvp+j] = 0x8000 | 3; + } + } + } + + // Just allocate the mesh flags array. The user is resposible to fill it. + mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*mesh.npolys, RC_ALLOC_PERM); + if (!mesh.flags) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: Out of memory 'mesh.flags' (%d).", mesh.npolys); + return false; + } + memset(mesh.flags, 0, sizeof(unsigned short) * mesh.npolys); + + if (mesh.nverts > 0xffff) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff); + } + if (mesh.npolys > 0xffff) + { + ctx->log(RC_LOG_ERROR, "rcBuildPolyMesh: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff); + } -// if (rcGetLog()) -// rcGetLog()->log(RC_LOG_PROGRESS, "Build polymesh: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); - if (rcGetBuildTimes()) - rcGetBuildTimes()->buildPolymesh += rcGetDeltaTimeUsec(startTime, endTime); + ctx->stopTimer(RC_TIMER_BUILD_POLYMESH); return true; - -failure: - delete [] vflags; - delete [] tmpPoly; - delete [] firstVert; - delete [] nextVert; - delete [] indices; - delete [] tris; - - return false; } -bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh) +/// @see rcAllocPolyMesh, rcPolyMesh +bool rcMergePolyMeshes(rcContext* ctx, rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh) { + rcAssert(ctx); + if (!nmeshes || !meshes) return true; - rcTimeVal startTime = rcGetPerformanceTimer(); - rcTimeVal endTime; - - int* nextVert = 0; - int* firstVert = 0; - unsigned short* vremap = 0; + ctx->startTimer(RC_TIMER_MERGE_POLYMESH); mesh.nvp = meshes[0]->nvp; mesh.cs = meshes[0]->cs; mesh.ch = meshes[0]->ch; - vcopy(mesh.bmin, meshes[0]->bmin); - vcopy(mesh.bmax, meshes[0]->bmax); + rcVcopy(mesh.bmin, meshes[0]->bmin); + rcVcopy(mesh.bmax, meshes[0]->bmax); int maxVerts = 0; int maxPolys = 0; int maxVertsPerMesh = 0; for (int i = 0; i < nmeshes; ++i) { - vmin(mesh.bmin, meshes[i]->bmin); - vmax(mesh.bmax, meshes[i]->bmax); + rcVmin(mesh.bmin, meshes[i]->bmin); + rcVmax(mesh.bmax, meshes[i]->bmax); maxVertsPerMesh = rcMax(maxVertsPerMesh, meshes[i]->nverts); maxVerts += meshes[i]->nverts; maxPolys += meshes[i]->npolys; } mesh.nverts = 0; - mesh.verts = new unsigned short[maxVerts*3]; + mesh.verts = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVerts*3, RC_ALLOC_PERM); if (!mesh.verts) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.verts' (%d).", maxVerts*3); + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.verts' (%d).", maxVerts*3); return false; } mesh.npolys = 0; - mesh.polys = new unsigned short[maxPolys*2*mesh.nvp]; + mesh.polys = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys*2*mesh.nvp, RC_ALLOC_PERM); if (!mesh.polys) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.polys' (%d).", maxPolys*2*mesh.nvp); + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.polys' (%d).", maxPolys*2*mesh.nvp); return false; } memset(mesh.polys, 0xff, sizeof(unsigned short)*maxPolys*2*mesh.nvp); - mesh.regs = new unsigned short[maxPolys]; + mesh.regs = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM); if (!mesh.regs) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.regs' (%d).", maxPolys); + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.regs' (%d).", maxPolys); return false; } memset(mesh.regs, 0, sizeof(unsigned short)*maxPolys); + + mesh.areas = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxPolys, RC_ALLOC_PERM); + if (!mesh.areas) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.areas' (%d).", maxPolys); + return false; + } + memset(mesh.areas, 0, sizeof(unsigned char)*maxPolys); + + mesh.flags = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxPolys, RC_ALLOC_PERM); + if (!mesh.flags) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'mesh.flags' (%d).", maxPolys); + return false; + } + memset(mesh.flags, 0, sizeof(unsigned short)*maxPolys); - nextVert = new int[maxVerts]; + rcScopedDelete<int> nextVert = (int*)rcAlloc(sizeof(int)*maxVerts, RC_ALLOC_TEMP); if (!nextVert) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'nextVert' (%d).", maxVerts); - goto failure; + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'nextVert' (%d).", maxVerts); + return false; } memset(nextVert, 0, sizeof(int)*maxVerts); - firstVert = new int[VERTEX_BUCKET_COUNT]; + rcScopedDelete<int> firstVert = (int*)rcAlloc(sizeof(int)*VERTEX_BUCKET_COUNT, RC_ALLOC_TEMP); if (!firstVert) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT); - goto failure; + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'firstVert' (%d).", VERTEX_BUCKET_COUNT); + return false; } for (int i = 0; i < VERTEX_BUCKET_COUNT; ++i) firstVert[i] = -1; - vremap = new unsigned short[maxVertsPerMesh]; + rcScopedDelete<unsigned short> vremap = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxVertsPerMesh, RC_ALLOC_PERM); if (!vremap) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh); - goto failure; + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Out of memory 'vremap' (%d).", maxVertsPerMesh); + return false; } memset(nextVert, 0, sizeof(int)*maxVerts); @@ -1172,7 +1322,7 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh) { unsigned short* v = &pmesh->verts[j*3]; vremap[j] = addVertex(v[0]+ox, v[1], v[2]+oz, - mesh.verts, firstVert, nextVert, mesh.nverts); + mesh.verts, firstVert, nextVert, mesh.nverts); } for (int j = 0; j < pmesh->npolys; ++j) @@ -1180,10 +1330,12 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh) unsigned short* tgt = &mesh.polys[mesh.npolys*2*mesh.nvp]; unsigned short* src = &pmesh->polys[j*2*mesh.nvp]; mesh.regs[mesh.npolys] = pmesh->regs[j]; + mesh.areas[mesh.npolys] = pmesh->areas[j]; + mesh.flags[mesh.npolys] = pmesh->flags[j]; mesh.npolys++; for (int k = 0; k < mesh.nvp; ++k) { - if (src[k] == 0xffff) break; + if (src[k] == RC_MESH_NULL_IDX) break; tgt[k] = vremap[src[k]]; } } @@ -1192,27 +1344,20 @@ bool rcMergePolyMeshes(rcPolyMesh** meshes, const int nmeshes, rcPolyMesh& mesh) // Calculate adjacency. if (!buildMeshAdjacency(mesh.polys, mesh.npolys, mesh.nverts, mesh.nvp)) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcMergePolyMeshes: Adjacency failed."); + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: Adjacency failed."); return false; } - - delete [] firstVert; - delete [] nextVert; - delete [] vremap; - - endTime = rcGetPerformanceTimer(); + if (mesh.nverts > 0xffff) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many vertices %d (max %d). Data can be corrupted.", mesh.nverts, 0xffff); + } + if (mesh.npolys > 0xffff) + { + ctx->log(RC_LOG_ERROR, "rcMergePolyMeshes: The resulting mesh has too many polygons %d (max %d). Data can be corrupted.", mesh.npolys, 0xffff); + } - if (rcGetBuildTimes()) - rcGetBuildTimes()->mergePolyMesh += rcGetDeltaTimeUsec(startTime, endTime); + ctx->stopTimer(RC_TIMER_MERGE_POLYMESH); return true; - -failure: - delete [] firstVert; - delete [] nextVert; - delete [] vremap; - - return false; } diff --git a/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp b/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp index 55ba28ae7cf..126529e9779 100644 --- a/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp +++ b/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2009 Mikko Mononen memon@inside.org +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -23,248 +23,75 @@ #include <stdlib.h> #include <stdio.h> #include "Recast.h" -#include "RecastLog.h" -#include "RecastTimer.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" +static const unsigned RC_UNSET_HEIGHT = 0xffff; + struct rcHeightPatch { - inline rcHeightPatch() : data(0) {} - inline ~rcHeightPatch() { delete [] data; } + inline rcHeightPatch() : data(0), xmin(0), ymin(0), width(0), height(0) {} + inline ~rcHeightPatch() { rcFree(data); } unsigned short* data; int xmin, ymin, width, height; }; - -static int circumCircle(const float xp, const float yp, - const float x1, const float y1, - const float x2, const float y2, - const float x3, const float y3, - float& xc, float& yc, float& rsqr) +inline float vdot2(const float* a, const float* b) { - static const float EPSILON = 1e-6f; - - const float fabsy1y2 = rcAbs(y1-y2); - const float fabsy2y3 = rcAbs(y2-y3); - - /* Check for coincident points */ - if (fabsy1y2 < EPSILON && fabsy2y3 < EPSILON) - return 0; - - if (fabsy1y2 < EPSILON) - { - const float m2 = - (x3-x2) / (y3-y2); - const float mx2 = (x2 + x3) / 2.0f; - const float my2 = (y2 + y3) / 2.0f; - xc = (x2 + x1) / 2.0f; - yc = m2 * (xc - mx2) + my2; - } - else if (fabsy2y3 < EPSILON) - { - const float m1 = - (x2-x1) / (y2-y1); - const float mx1 = (x1 + x2) / 2.0f; - const float my1 = (y1 + y2) / 2.0f; - xc = (x3 + x2) / 2.0f; - yc = m1 * (xc - mx1) + my1; - } - else - { - const float m1 = - (x2-x1) / (y2-y1); - const float m2 = - (x3-x2) / (y3-y2); - const float mx1 = (x1 + x2) / 2.0f; - const float mx2 = (x2 + x3) / 2.0f; - const float my1 = (y1 + y2) / 2.0f; - const float my2 = (y2 + y3) / 2.0f; - xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2); - if (fabsy1y2 > fabsy2y3) - yc = m1 * (xc - mx1) + my1; - else - yc = m2 * (xc - mx2) + my2; - } - - float dx,dy; - - dx = x2 - xc; - dy = y2 - yc; - rsqr = dx*dx + dy*dy; - - dx = xp - xc; - dy = yp - yc; - const float drsqr = dx*dx + dy*dy; - - return (drsqr <= rsqr) ? 1 : 0; + return a[0]*b[0] + a[2]*b[2]; } - -static float *_qsort_verts; -static int ptcmp(const void *v1, const void *v2) + +inline float vdistSq2(const float* p, const float* q) { - const float* p1 = &_qsort_verts[(*(const int*)v1)*3]; - const float* p2 = &_qsort_verts[(*(const int*)v2)*3]; - if (p1[0] < p2[0]) - return -1; - else if (p1[0] > p2[0]) - return 1; - else - return 0; + const float dx = q[0] - p[0]; + const float dy = q[2] - p[2]; + return dx*dx + dy*dy; } -// Based on Paul Bourke's triangulate.c -// http://astronomy.swin.edu.au/~pbourke/terrain/triangulate/triangulate.c -static void delaunay(const int nv, float *verts, rcIntArray& idx, rcIntArray& tris, rcIntArray& edges) +inline float vdist2(const float* p, const float* q) { - // Sort vertices - idx.resize(nv); - for (int i = 0; i < nv; ++i) - idx[i] = i; - _qsort_verts = verts; - qsort(&idx[0], idx.size(), sizeof(int), ptcmp); - - // Find the maximum and minimum vertex bounds. - // This is to allow calculation of the bounding triangle - float xmin = verts[0]; - float ymin = verts[2]; - float xmax = xmin; - float ymax = ymin; - for (int i = 1; i < nv; ++i) - { - xmin = rcMin(xmin, verts[i*3+0]); - xmax = rcMax(xmax, verts[i*3+0]); - ymin = rcMin(ymin, verts[i*3+2]); - ymax = rcMax(ymax, verts[i*3+2]); - } - float dx = xmax - xmin; - float dy = ymax - ymin; - float dmax = (dx > dy) ? dx : dy; - float xmid = (xmax + xmin) / 2.0f; - float ymid = (ymax + ymin) / 2.0f; - - // Set up the supertriangle - // This is a triangle which encompasses all the sample points. - // The supertriangle coordinates are added to the end of the - // vertex list. The supertriangle is the first triangle in - // the triangle list. - float sv[3*3]; - - sv[0] = xmid - 20 * dmax; - sv[1] = 0; - sv[2] = ymid - dmax; - - sv[3] = xmid; - sv[4] = 0; - sv[5] = ymid + 20 * dmax; - - sv[6] = xmid + 20 * dmax; - sv[7] = 0; - sv[8] = ymid - dmax; - - tris.push(-3); - tris.push(-2); - tris.push(-1); - tris.push(0); // not completed - - for (int i = 0; i < nv; ++i) - { - const float xp = verts[idx[i]*3+0]; - const float yp = verts[idx[i]*3+2]; - - edges.resize(0); - - // Set up the edge buffer. - // If the point (xp,yp) lies inside the circumcircle then the - // three edges of that triangle are added to the edge buffer - // and that triangle is removed. - for (int j = 0; j < tris.size()/4; ++j) - { - int* t = &tris[j*4]; - if (t[3]) // completed? - continue; - const float* v1 = t[0] < 0 ? &sv[(t[0]+3)*3] : &verts[idx[t[0]]*3]; - const float* v2 = t[1] < 0 ? &sv[(t[1]+3)*3] : &verts[idx[t[1]]*3]; - const float* v3 = t[2] < 0 ? &sv[(t[2]+3)*3] : &verts[idx[t[2]]*3]; - float xc,yc,rsqr; - int inside = circumCircle(xp,yp, v1[0],v1[2], v2[0],v2[2], v3[0],v3[2], xc,yc,rsqr); - if (xc < xp && rcSqr(xp-xc) > rsqr) - t[3] = 1; - if (inside) - { - // Collect triangle edges. - edges.push(t[0]); - edges.push(t[1]); - edges.push(t[1]); - edges.push(t[2]); - edges.push(t[2]); - edges.push(t[0]); - // Remove triangle j. - t[0] = tris[tris.size()-4]; - t[1] = tris[tris.size()-3]; - t[2] = tris[tris.size()-2]; - t[3] = tris[tris.size()-1]; - tris.resize(tris.size()-4); - j--; - } - } - - // Remove duplicate edges. - const int ne = edges.size()/2; - for (int j = 0; j < ne-1; ++j) - { - for (int k = j+1; k < ne; ++k) - { - // Dupe?, make null. - if ((edges[j*2+0] == edges[k*2+1]) && (edges[j*2+1] == edges[k*2+0])) - { - edges[j*2+0] = 0; - edges[j*2+1] = 0; - edges[k*2+0] = 0; - edges[k*2+1] = 0; - } - } - } - - // Form new triangles for the current point - // Skipping over any null. - // All edges are arranged in clockwise order. - for (int j = 0; j < ne; ++j) - { - if (edges[j*2+0] == edges[j*2+1]) continue; - tris.push(edges[j*2+0]); - tris.push(edges[j*2+1]); - tris.push(i); - tris.push(0); // not completed - } - } - - // Remove triangles with supertriangle vertices - // These are triangles which have a vertex number greater than nv - for (int i = 0; i < tris.size()/4; ++i) - { - int* t = &tris[i*4]; - if (t[0] < 0 || t[1] < 0 || t[2] < 0) - { - t[0] = tris[tris.size()-4]; - t[1] = tris[tris.size()-3]; - t[2] = tris[tris.size()-2]; - t[3] = tris[tris.size()-1]; - tris.resize(tris.size()-4); - i--; - } - } - // Triangle vertices are pointing to sorted vertices, remap indices. - for (int i = 0; i < tris.size(); ++i) - tris[i] = idx[tris[i]]; + return sqrtf(vdistSq2(p,q)); } -inline float vdot2(const float* a, const float* b) +inline float vcross2(const float* p1, const float* p2, const float* p3) +{ + const float u1 = p2[0] - p1[0]; + const float v1 = p2[2] - p1[2]; + const float u2 = p3[0] - p1[0]; + const float v2 = p3[2] - p1[2]; + return u1 * v2 - v1 * u2; +} + +static bool circumCircle(const float* p1, const float* p2, const float* p3, + float* c, float& r) { - return a[0]*b[0] + a[2]*b[2]; + static const float EPS = 1e-6f; + + const float cp = vcross2(p1, p2, p3); + if (fabsf(cp) > EPS) + { + const float p1Sq = vdot2(p1,p1); + const float p2Sq = vdot2(p2,p2); + const float p3Sq = vdot2(p3,p3); + c[0] = (p1Sq*(p2[2]-p3[2]) + p2Sq*(p3[2]-p1[2]) + p3Sq*(p1[2]-p2[2])) / (2*cp); + c[2] = (p1Sq*(p3[0]-p2[0]) + p2Sq*(p1[0]-p3[0]) + p3Sq*(p2[0]-p1[0])) / (2*cp); + r = vdist2(c, p1); + return true; + } + + c[0] = p1[0]; + c[2] = p1[2]; + r = 0; + return false; } static float distPtTri(const float* p, const float* a, const float* b, const float* c) { float v0[3], v1[3], v2[3]; - vsub(v0, c,a); - vsub(v1, b,a); - vsub(v2, p,a); + rcVsub(v0, c,a); + rcVsub(v1, b,a); + rcVsub(v2, p,a); const float dot00 = vdot2(v0, v0); const float dot01 = vdot2(v0, v1); @@ -273,15 +100,15 @@ static float distPtTri(const float* p, const float* a, const float* b, const flo const float dot12 = vdot2(v1, v2); // Compute barycentric coordinates - float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); - float u = (dot11 * dot02 - dot01 * dot12) * invDenom; + const float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01); + const float u = (dot11 * dot02 - dot01 * dot12) * invDenom; float v = (dot00 * dot12 - dot01 * dot02) * invDenom; // If point lies inside the triangle, return interpolated y-coord. static const float EPS = 1e-4f; if (u >= -EPS && v >= -EPS && (u+v) <= 1+EPS) { - float y = a[1] + v0[1]*u + v1[1]*v; + const float y = a[1] + v0[1]*u + v1[1]*v; return fabsf(y-p[1]); } return FLT_MAX; @@ -332,7 +159,7 @@ static float distancePtSeg2d(const float* pt, const float* p, const float* q) return dx*dx + dz*dz; } -static float distToTriMesh(const float* p, const float* verts, int nverts, const int* tris, int ntris) +static float distToTriMesh(const float* p, const float* verts, const int /*nverts*/, const int* tris, const int ntris) { float dmin = FLT_MAX; for (int i = 0; i < ntris; ++i) @@ -366,35 +193,335 @@ static float distToPoly(int nvert, const float* verts, const float* p) } -static unsigned short getHeight(const float* pos, const float* bmin, const float ics, const rcHeightPatch& hp) +static unsigned short getHeight(const float fx, const float fy, const float fz, + const float /*cs*/, const float ics, const float ch, + const rcHeightPatch& hp) { - int ix = (int)floorf((pos[0]-bmin[0])*ics + 0.01f); - int iz = (int)floorf((pos[2]-bmin[2])*ics + 0.01f); + int ix = (int)floorf(fx*ics + 0.01f); + int iz = (int)floorf(fz*ics + 0.01f); ix = rcClamp(ix-hp.xmin, 0, hp.width); iz = rcClamp(iz-hp.ymin, 0, hp.height); unsigned short h = hp.data[ix+iz*hp.width]; + if (h == RC_UNSET_HEIGHT) + { + // Special case when data might be bad. + // Find nearest neighbour pixel which has valid height. + const int off[8*2] = { -1,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1}; + float dmin = FLT_MAX; + for (int i = 0; i < 8; ++i) + { + const int nx = ix+off[i*2+0]; + const int nz = iz+off[i*2+1]; + if (nx < 0 || nz < 0 || nx >= hp.width || nz >= hp.height) continue; + const unsigned short nh = hp.data[nx+nz*hp.width]; + if (nh == RC_UNSET_HEIGHT) continue; + + const float d = fabsf(nh*ch - fy); + if (d < dmin) + { + h = nh; + dmin = d; + } + +/* const float dx = (nx+0.5f)*cs - fx; + const float dz = (nz+0.5f)*cs - fz; + const float d = dx*dx+dz*dz; + if (d < dmin) + { + h = nh; + dmin = d; + } */ + } + } return h; } -static bool buildPolyDetail(const float* in, const int nin, unsigned short reg, + +enum EdgeValues +{ + UNDEF = -1, + HULL = -2, +}; + +static int findEdge(const int* edges, int nedges, int s, int t) +{ + for (int i = 0; i < nedges; i++) + { + const int* e = &edges[i*4]; + if ((e[0] == s && e[1] == t) || (e[0] == t && e[1] == s)) + return i; + } + return UNDEF; +} + +static int addEdge(rcContext* ctx, int* edges, int& nedges, const int maxEdges, int s, int t, int l, int r) +{ + if (nedges >= maxEdges) + { + ctx->log(RC_LOG_ERROR, "addEdge: Too many edges (%d/%d).", nedges, maxEdges); + return UNDEF; + } + + // Add edge if not already in the triangulation. + int e = findEdge(edges, nedges, s, t); + if (e == UNDEF) + { + int* e = &edges[nedges*4]; + e[0] = s; + e[1] = t; + e[2] = l; + e[3] = r; + return nedges++; + } + else + { + return UNDEF; + } +} + +static void updateLeftFace(int* e, int s, int t, int f) +{ + if (e[0] == s && e[1] == t && e[2] == UNDEF) + e[2] = f; + else if (e[1] == s && e[0] == t && e[3] == UNDEF) + e[3] = f; +} + +static int overlapSegSeg2d(const float* a, const float* b, const float* c, const float* d) +{ + const float a1 = vcross2(a, b, d); + const float a2 = vcross2(a, b, c); + if (a1*a2 < 0.0f) + { + float a3 = vcross2(c, d, a); + float a4 = a3 + a2 - a1; + if (a3 * a4 < 0.0f) + return 1; + } + return 0; +} + +static bool overlapEdges(const float* pts, const int* edges, int nedges, int s1, int t1) +{ + for (int i = 0; i < nedges; ++i) + { + const int s0 = edges[i*4+0]; + const int t0 = edges[i*4+1]; + // Same or connected edges do not overlap. + if (s0 == s1 || s0 == t1 || t0 == s1 || t0 == t1) + continue; + if (overlapSegSeg2d(&pts[s0*3],&pts[t0*3], &pts[s1*3],&pts[t1*3])) + return true; + } + return false; +} + +static void completeFacet(rcContext* ctx, const float* pts, int npts, int* edges, int& nedges, const int maxEdges, int& nfaces, int e) +{ + static const float EPS = 1e-5f; + + int* edge = &edges[e*4]; + + // Cache s and t. + int s,t; + if (edge[2] == UNDEF) + { + s = edge[0]; + t = edge[1]; + } + else if (edge[3] == UNDEF) + { + s = edge[1]; + t = edge[0]; + } + else + { + // Edge already completed. + return; + } + + // Find best point on left of edge. + int pt = npts; + float c[3] = {0,0,0}; + float r = -1; + for (int u = 0; u < npts; ++u) + { + if (u == s || u == t) continue; + if (vcross2(&pts[s*3], &pts[t*3], &pts[u*3]) > EPS) + { + if (r < 0) + { + // The circle is not updated yet, do it now. + pt = u; + circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r); + continue; + } + const float d = vdist2(c, &pts[u*3]); + const float tol = 0.001f; + if (d > r*(1+tol)) + { + // Outside current circumcircle, skip. + continue; + } + else if (d < r*(1-tol)) + { + // Inside safe circumcircle, update circle. + pt = u; + circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r); + } + else + { + // Inside epsilon circum circle, do extra tests to make sure the edge is valid. + // s-u and t-u cannot overlap with s-pt nor t-pt if they exists. + if (overlapEdges(pts, edges, nedges, s,u)) + continue; + if (overlapEdges(pts, edges, nedges, t,u)) + continue; + // Edge is valid. + pt = u; + circumCircle(&pts[s*3], &pts[t*3], &pts[u*3], c, r); + } + } + } + + // Add new triangle or update edge info if s-t is on hull. + if (pt < npts) + { + // Update face information of edge being completed. + updateLeftFace(&edges[e*4], s, t, nfaces); + + // Add new edge or update face info of old edge. + e = findEdge(edges, nedges, pt, s); + if (e == UNDEF) + addEdge(ctx, edges, nedges, maxEdges, pt, s, nfaces, UNDEF); + else + updateLeftFace(&edges[e*4], pt, s, nfaces); + + // Add new edge or update face info of old edge. + e = findEdge(edges, nedges, t, pt); + if (e == UNDEF) + addEdge(ctx, edges, nedges, maxEdges, t, pt, nfaces, UNDEF); + else + updateLeftFace(&edges[e*4], t, pt, nfaces); + + nfaces++; + } + else + { + updateLeftFace(&edges[e*4], s, t, HULL); + } +} + +static void delaunayHull(rcContext* ctx, const int npts, const float* pts, + const int nhull, const int* hull, + rcIntArray& tris, rcIntArray& edges) +{ + int nfaces = 0; + int nedges = 0; + const int maxEdges = npts*10; + edges.resize(maxEdges*4); + + for (int i = 0, j = nhull-1; i < nhull; j=i++) + addEdge(ctx, &edges[0], nedges, maxEdges, hull[j],hull[i], HULL, UNDEF); + + int currentEdge = 0; + while (currentEdge < nedges) + { + if (edges[currentEdge*4+2] == UNDEF) + completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge); + if (edges[currentEdge*4+3] == UNDEF) + completeFacet(ctx, pts, npts, &edges[0], nedges, maxEdges, nfaces, currentEdge); + currentEdge++; + } + + // Create tris + tris.resize(nfaces*4); + for (int i = 0; i < nfaces*4; ++i) + tris[i] = -1; + + for (int i = 0; i < nedges; ++i) + { + const int* e = &edges[i*4]; + if (e[3] >= 0) + { + // Left face + int* t = &tris[e[3]*4]; + if (t[0] == -1) + { + t[0] = e[0]; + t[1] = e[1]; + } + else if (t[0] == e[1]) + t[2] = e[0]; + else if (t[1] == e[0]) + t[2] = e[1]; + } + if (e[2] >= 0) + { + // Right + int* t = &tris[e[2]*4]; + if (t[0] == -1) + { + t[0] = e[1]; + t[1] = e[0]; + } + else if (t[0] == e[0]) + t[2] = e[1]; + else if (t[1] == e[1]) + t[2] = e[0]; + } + } + + for (int i = 0; i < tris.size()/4; ++i) + { + int* t = &tris[i*4]; + if (t[0] == -1 || t[1] == -1 || t[2] == -1) + { + ctx->log(RC_LOG_WARNING, "delaunayHull: Removing dangling face %d [%d,%d,%d].", i, t[0],t[1],t[2]); + t[0] = tris[tris.size()-4]; + t[1] = tris[tris.size()-3]; + t[2] = tris[tris.size()-2]; + t[3] = tris[tris.size()-1]; + tris.resize(tris.size()-4); + --i; + } + } +} + + +inline float getJitterX(const int i) +{ + return (((i * 0x8da6b343) & 0xffff) / 65535.0f * 2.0f) - 1.0f; +} + +inline float getJitterY(const int i) +{ + return (((i * 0xd8163841) & 0xffff) / 65535.0f * 2.0f) - 1.0f; +} + +static bool buildPolyDetail(rcContext* ctx, const float* in, const int nin, const float sampleDist, const float sampleMaxError, const rcCompactHeightfield& chf, const rcHeightPatch& hp, float* verts, int& nverts, rcIntArray& tris, - rcIntArray& edges, rcIntArray& idx, rcIntArray& samples) + rcIntArray& edges, rcIntArray& samples) { - static const int MAX_VERTS = 256; - static const int MAX_EDGE = 64; - float edge[(MAX_EDGE+1)*3]; + static const int MAX_VERTS = 127; + static const int MAX_TRIS = 255; // Max tris for delaunay is 2n-2-k (n=num verts, k=num hull verts). + static const int MAX_VERTS_PER_EDGE = 32; + float edge[(MAX_VERTS_PER_EDGE+1)*3]; + int hull[MAX_VERTS]; + int nhull = 0; nverts = 0; for (int i = 0; i < nin; ++i) - vcopy(&verts[i*3], &in[i*3]); + rcVcopy(&verts[i*3], &in[i*3]); nverts = nin; - const float ics = 1.0f/chf.cs; + const float cs = chf.cs; + const float ics = 1.0f/cs; - // Tesselate outlines. + // Tessellate outlines. // This is done in separate pass in order to ensure // seamless height values across the ply boundaries. if (sampleDist > 0) @@ -403,17 +530,24 @@ static bool buildPolyDetail(const float* in, const int nin, unsigned short reg, { const float* vj = &in[j*3]; const float* vi = &in[i*3]; + bool swapped = false; // Make sure the segments are always handled in same order // using lexological sort or else there will be seams. if (fabsf(vj[0]-vi[0]) < 1e-6f) { if (vj[2] > vi[2]) + { rcSwap(vj,vi); + swapped = true; + } } else { if (vj[0] > vi[0]) + { rcSwap(vj,vi); + swapped = true; + } } // Create samples along the edge. float dx = vi[0] - vj[0]; @@ -421,9 +555,10 @@ static bool buildPolyDetail(const float* in, const int nin, unsigned short reg, float dz = vi[2] - vj[2]; float d = sqrtf(dx*dx + dz*dz); int nn = 1 + (int)floorf(d/sampleDist); - if (nn > MAX_EDGE) nn = MAX_EDGE; + if (nn >= MAX_VERTS_PER_EDGE) nn = MAX_VERTS_PER_EDGE-1; if (nverts+nn >= MAX_VERTS) nn = MAX_VERTS-1-nverts; + for (int k = 0; k <= nn; ++k) { float u = (float)k/(float)nn; @@ -431,10 +566,10 @@ static bool buildPolyDetail(const float* in, const int nin, unsigned short reg, pos[0] = vj[0] + dx*u; pos[1] = vj[1] + dy*u; pos[2] = vj[2] + dz*u; - pos[1] = chf.bmin[1] + getHeight(pos, chf.bmin, ics, hp)*chf.ch; + pos[1] = getHeight(pos[0],pos[1],pos[2], cs, ics, chf.ch, hp)*chf.ch; } // Simplify samples. - int idx[MAX_EDGE] = {0,nn}; + int idx[MAX_VERTS_PER_EDGE] = {0,nn}; int nidx = 2; for (int k = 0; k < nidx-1; ) { @@ -468,31 +603,61 @@ static bool buildPolyDetail(const float* in, const int nin, unsigned short reg, ++k; } } + + hull[nhull++] = j; // Add new vertices. - for (int k = 1; k < nidx-1; ++k) + if (swapped) + { + for (int k = nidx-2; k > 0; --k) + { + rcVcopy(&verts[nverts*3], &edge[idx[k]*3]); + hull[nhull++] = nverts; + nverts++; + } + } + else { - vcopy(&verts[nverts*3], &edge[idx[k]*3]); - nverts++; + for (int k = 1; k < nidx-1; ++k) + { + rcVcopy(&verts[nverts*3], &edge[idx[k]*3]); + hull[nhull++] = nverts; + nverts++; + } } } } - // Tesselate the base mesh. + + // Tessellate the base mesh. edges.resize(0); tris.resize(0); - idx.resize(0); - delaunay(nverts, verts, idx, tris, edges); + + delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges); + + if (tris.size() == 0) + { + // Could not triangulate the poly, make sure there is some valid data there. + ctx->log(RC_LOG_WARNING, "buildPolyDetail: Could not triangulate polygon, adding default data."); + for (int i = 2; i < nverts; ++i) + { + tris.push(0); + tris.push(i-1); + tris.push(i); + tris.push(0); + } + return true; + } if (sampleDist > 0) { // Create sample locations in a grid. float bmin[3], bmax[3]; - vcopy(bmin, in); - vcopy(bmax, in); + rcVcopy(bmin, in); + rcVcopy(bmax, in); for (int i = 1; i < nin; ++i) { - vmin(bmin, &in[i*3]); - vmax(bmax, &in[i*3]); + rcVmin(bmin, &in[i*3]); + rcVmax(bmax, &in[i*3]); } int x0 = (int)floorf(bmin[0]/sampleDist); int x1 = (int)ceilf(bmax[0]/sampleDist); @@ -505,56 +670,71 @@ static bool buildPolyDetail(const float* in, const int nin, unsigned short reg, { float pt[3]; pt[0] = x*sampleDist; + pt[1] = (bmax[1]+bmin[1])*0.5f; pt[2] = z*sampleDist; // Make sure the samples are not too close to the edges. if (distToPoly(nin,in,pt) > -sampleDist/2) continue; samples.push(x); - samples.push(getHeight(pt, chf.bmin, ics, hp)); + samples.push(getHeight(pt[0], pt[1], pt[2], cs, ics, chf.ch, hp)); samples.push(z); + samples.push(0); // Not added } } // Add the samples starting from the one that has the most // error. The procedure stops when all samples are added // or when the max error is within treshold. - const int nsamples = samples.size()/3; + const int nsamples = samples.size()/4; for (int iter = 0; iter < nsamples; ++iter) { + if (nverts >= MAX_VERTS) + break; + // Find sample with most error. - float bestpt[3]; + float bestpt[3] = {0,0,0}; float bestd = 0; + int besti = -1; for (int i = 0; i < nsamples; ++i) { + const int* s = &samples[i*4]; + if (s[3]) continue; // skip added. float pt[3]; - pt[0] = samples[i*3+0]*sampleDist; - pt[1] = chf.bmin[1] + samples[i*3+1]*chf.ch; - pt[2] = samples[i*3+2]*sampleDist; + // The sample location is jittered to get rid of some bad triangulations + // which are cause by symmetrical data from the grid structure. + pt[0] = s[0]*sampleDist + getJitterX(i)*cs*0.1f; + pt[1] = s[1]*chf.ch; + pt[2] = s[2]*sampleDist + getJitterY(i)*cs*0.1f; float d = distToTriMesh(pt, verts, nverts, &tris[0], tris.size()/4); if (d < 0) continue; // did not hit the mesh. if (d > bestd) { bestd = d; - vcopy(bestpt,pt); + besti = i; + rcVcopy(bestpt,pt); } } // If the max error is within accepted threshold, stop tesselating. - if (bestd <= sampleMaxError) + if (bestd <= sampleMaxError || besti == -1) break; - + // Mark sample as added. + samples[besti*4+3] = 1; // Add the new sample point. - vcopy(&verts[nverts*3],bestpt); + rcVcopy(&verts[nverts*3],bestpt); nverts++; // Create new triangulation. // TODO: Incremental add instead of full rebuild. edges.resize(0); tris.resize(0); - idx.resize(0); - delaunay(nverts, verts, idx, tris, edges); + delaunayHull(ctx, nverts, verts, nhull, hull, tris, edges); + } + } - if (nverts >= MAX_VERTS) - break; - } + const int ntris = tris.size()/4; + if (ntris > MAX_TRIS) + { + tris.resize(MAX_TRIS*4); + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Shrinking triangle count from %d to max %d.", ntris, MAX_TRIS); } return true; @@ -562,82 +742,178 @@ static bool buildPolyDetail(const float* in, const int nin, unsigned short reg, static void getHeightData(const rcCompactHeightfield& chf, const unsigned short* poly, const int npoly, - const unsigned short* verts, + const unsigned short* verts, const int bs, rcHeightPatch& hp, rcIntArray& stack) { // Floodfill the heightfield to get 2D height data, // starting at vertex locations as seeds. - memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height); - + // Note: Reads to the compact heightfield are offset by border size (bs) + // since border size offset is already removed from the polymesh vertices. + + memset(hp.data, 0, sizeof(unsigned short)*hp.width*hp.height); + stack.resize(0); + static const int offset[9*2] = + { + 0,0, -1,-1, 0,-1, 1,-1, 1,0, 1,1, 0,1, -1,1, -1,0, + }; + // Use poly vertices as seed points for the flood fill. for (int j = 0; j < npoly; ++j) { - const int ax = (int)verts[poly[j]*3+0]; - const int ay = (int)verts[poly[j]*3+1]; - const int az = (int)verts[poly[j]*3+2]; - if (ax < hp.xmin || ax >= hp.xmin+hp.width || - az < hp.ymin || az >= hp.ymin+hp.height) - continue; - - const rcCompactCell& c = chf.cells[ax+az*chf.width]; - int dmin = 0xffff; - int ai = -1; - for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + int cx = 0, cz = 0, ci =-1; + int dmin = RC_UNSET_HEIGHT; + for (int k = 0; k < 9; ++k) { - const rcCompactSpan& s = chf.spans[i]; - int d = rcAbs(ay - (int)s.y); - if (d < dmin) + const int ax = (int)verts[poly[j]*3+0] + offset[k*2+0]; + const int ay = (int)verts[poly[j]*3+1]; + const int az = (int)verts[poly[j]*3+2] + offset[k*2+1]; + if (ax < hp.xmin || ax >= hp.xmin+hp.width || + az < hp.ymin || az >= hp.ymin+hp.height) + continue; + + const rcCompactCell& c = chf.cells[(ax+bs)+(az+bs)*chf.width]; + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { - ai = i; - dmin = d; + const rcCompactSpan& s = chf.spans[i]; + int d = rcAbs(ay - (int)s.y); + if (d < dmin) + { + cx = ax; + cz = az; + ci = i; + dmin = d; + } } } - if (ai != -1) + if (ci != -1) { - stack.push(ax); - stack.push(az); - stack.push(ai); + stack.push(cx); + stack.push(cz); + stack.push(ci); } } - + + // Find center of the polygon using flood fill. + int pcx = 0, pcz = 0; + for (int j = 0; j < npoly; ++j) + { + pcx += (int)verts[poly[j]*3+0]; + pcz += (int)verts[poly[j]*3+2]; + } + pcx /= npoly; + pcz /= npoly; + + for (int i = 0; i < stack.size(); i += 3) + { + int cx = stack[i+0]; + int cy = stack[i+1]; + int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width; + hp.data[idx] = 1; + } + while (stack.size() > 0) { int ci = stack.pop(); int cy = stack.pop(); int cx = stack.pop(); - - // Skip already visited locations. - int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width; - if (hp.data[idx] != 0xffff) - continue; + + // Check if close to center of the polygon. + if (rcAbs(cx-pcx) <= 1 && rcAbs(cy-pcz) <= 1) + { + stack.resize(0); + stack.push(cx); + stack.push(cy); + stack.push(ci); + break; + } const rcCompactSpan& cs = chf.spans[ci]; - hp.data[idx] = cs.y; for (int dir = 0; dir < 4; ++dir) { - if (rcGetCon(cs, dir) == 0xf) continue; + if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue; const int ax = cx + rcGetDirOffsetX(dir); const int ay = cy + rcGetDirOffsetY(dir); - + if (ax < hp.xmin || ax >= (hp.xmin+hp.width) || ay < hp.ymin || ay >= (hp.ymin+hp.height)) continue; - - if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0xffff) + + if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != 0) continue; + + const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir); - const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(cs, dir); + int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width; + hp.data[idx] = 1; stack.push(ax); stack.push(ay); stack.push(ai); } - } + } + + memset(hp.data, 0xff, sizeof(unsigned short)*hp.width*hp.height); + + // Mark start locations. + for (int i = 0; i < stack.size(); i += 3) + { + int cx = stack[i+0]; + int cy = stack[i+1]; + int ci = stack[i+2]; + int idx = cx-hp.xmin+(cy-hp.ymin)*hp.width; + const rcCompactSpan& cs = chf.spans[ci]; + hp.data[idx] = cs.y; + } + + static const int RETRACT_SIZE = 256; + int head = 0; + + while (head*3 < stack.size()) + { + int cx = stack[head*3+0]; + int cy = stack[head*3+1]; + int ci = stack[head*3+2]; + head++; + if (head >= RETRACT_SIZE) + { + head = 0; + if (stack.size() > RETRACT_SIZE*3) + memmove(&stack[0], &stack[RETRACT_SIZE*3], sizeof(int)*(stack.size()-RETRACT_SIZE*3)); + stack.resize(stack.size()-RETRACT_SIZE*3); + } + + const rcCompactSpan& cs = chf.spans[ci]; + for (int dir = 0; dir < 4; ++dir) + { + if (rcGetCon(cs, dir) == RC_NOT_CONNECTED) continue; + + const int ax = cx + rcGetDirOffsetX(dir); + const int ay = cy + rcGetDirOffsetY(dir); + + if (ax < hp.xmin || ax >= (hp.xmin+hp.width) || + ay < hp.ymin || ay >= (hp.ymin+hp.height)) + continue; + + if (hp.data[ax-hp.xmin+(ay-hp.ymin)*hp.width] != RC_UNSET_HEIGHT) + continue; + + const int ai = (int)chf.cells[(ax+bs)+(ay+bs)*chf.width].index + rcGetCon(cs, dir); + + const rcCompactSpan& as = chf.spans[ai]; + int idx = ax-hp.xmin+(ay-hp.ymin)*hp.width; + hp.data[idx] = as.y; + + stack.push(ax); + stack.push(ay); + stack.push(ai); + } + } + } static unsigned char getEdgeFlags(const float* va, const float* vb, @@ -664,51 +940,48 @@ static unsigned char getTriFlags(const float* va, const float* vb, const float* return flags; } - - -bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& chf, +/// @par +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// @see rcAllocPolyMeshDetail, rcPolyMesh, rcCompactHeightfield, rcPolyMeshDetail, rcConfig +bool rcBuildPolyMeshDetail(rcContext* ctx, const rcPolyMesh& mesh, const rcCompactHeightfield& chf, const float sampleDist, const float sampleMaxError, rcPolyMeshDetail& dmesh) { + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_POLYMESHDETAIL); + if (mesh.nverts == 0 || mesh.npolys == 0) return true; - - rcTimeVal startTime = rcGetPerformanceTimer(); - rcTimeVal endTime; - - int vcap; - int tcap; - + const int nvp = mesh.nvp; const float cs = mesh.cs; const float ch = mesh.ch; const float* orig = mesh.bmin; + const int borderSize = mesh.borderSize; rcIntArray edges(64); rcIntArray tris(512); - rcIntArray idx(512); rcIntArray stack(512); rcIntArray samples(512); float verts[256*3]; - float* poly = 0; - int* bounds = 0; rcHeightPatch hp; int nPolyVerts = 0; int maxhw = 0, maxhh = 0; - bounds = new int[mesh.npolys*4]; + rcScopedDelete<int> bounds = (int*)rcAlloc(sizeof(int)*mesh.npolys*4, RC_ALLOC_TEMP); if (!bounds) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'bounds' (%d).", mesh.npolys*4); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'bounds' (%d).", mesh.npolys*4); + return false; } - poly = new float[nvp*3]; - if (!bounds) + rcScopedDelete<float> poly = (float*)rcAlloc(sizeof(float)*nvp*3, RC_ALLOC_TEMP); + if (!poly) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'poly' (%d).", nvp*3); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'poly' (%d).", nvp*3); + return false; } // Find max size for a polygon area. @@ -725,7 +998,7 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c ymax = 0; for (int j = 0; j < nvp; ++j) { - if(p[j] == 0xffff) break; + if(p[j] == RC_MESH_NULL_IDX) break; const unsigned short* v = &mesh.verts[p[j]*3]; xmin = rcMin(xmin, (int)v[0]); xmax = rcMax(xmax, (int)v[0]); @@ -742,58 +1015,54 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c maxhh = rcMax(maxhh, ymax-ymin); } - hp.data = new unsigned short[maxhw*maxhh]; + hp.data = (unsigned short*)rcAlloc(sizeof(unsigned short)*maxhw*maxhh, RC_ALLOC_TEMP); if (!hp.data) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'hp.data' (%d).", maxhw*maxhh); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'hp.data' (%d).", maxhw*maxhh); + return false; } - + dmesh.nmeshes = mesh.npolys; dmesh.nverts = 0; dmesh.ntris = 0; - dmesh.meshes = new unsigned short[dmesh.nmeshes*4]; + dmesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*dmesh.nmeshes*4, RC_ALLOC_PERM); if (!dmesh.meshes) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.meshes' (%d).", dmesh.nmeshes*4); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.meshes' (%d).", dmesh.nmeshes*4); + return false; } - vcap = nPolyVerts+nPolyVerts/2; - tcap = vcap*2; + int vcap = nPolyVerts+nPolyVerts/2; + int tcap = vcap*2; dmesh.nverts = 0; - dmesh.verts = new float[vcap*3]; + dmesh.verts = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM); if (!dmesh.verts) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", vcap*3); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", vcap*3); + return false; } dmesh.ntris = 0; - dmesh.tris = new unsigned char[tcap*4]; + dmesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char*)*tcap*4, RC_ALLOC_PERM); if (!dmesh.tris) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", tcap*4); + return false; } for (int i = 0; i < mesh.npolys; ++i) { const unsigned short* p = &mesh.polys[i*nvp*2]; - // Find polygon bounding box. + // Store polygon vertices for processing. int npoly = 0; for (int j = 0; j < nvp; ++j) { - if(p[j] == 0xffff) break; + if(p[j] == RC_MESH_NULL_IDX) break; const unsigned short* v = &mesh.verts[p[j]*3]; - poly[j*3+0] = orig[0] + v[0]*cs; - poly[j*3+1] = orig[1] + v[1]*ch; - poly[j*3+2] = orig[2] + v[2]*cs; + poly[j*3+0] = v[0]*cs; + poly[j*3+1] = v[1]*ch; + poly[j*3+2] = v[2]*cs; npoly++; } @@ -802,29 +1071,40 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c hp.ymin = bounds[i*4+2]; hp.width = bounds[i*4+1]-bounds[i*4+0]; hp.height = bounds[i*4+3]-bounds[i*4+2]; - getHeightData(chf, p, npoly, mesh.verts, hp, stack); + getHeightData(chf, p, npoly, mesh.verts, borderSize, hp, stack); // Build detail mesh. int nverts = 0; - if (!buildPolyDetail(poly, npoly, mesh.regs[i], + if (!buildPolyDetail(ctx, poly, npoly, sampleDist, sampleMaxError, chf, hp, verts, nverts, tris, - edges, idx, samples)) + edges, samples)) { - goto failure; + return false; } - // Offset detail vertices, unnecassary? + // Move detail verts to world space. for (int j = 0; j < nverts; ++j) - verts[j*3+1] += chf.ch; + { + verts[j*3+0] += orig[0]; + verts[j*3+1] += orig[1] + chf.ch; // Is this offset necessary? + verts[j*3+2] += orig[2]; + } + // Offset poly too, will be used to flag checking. + for (int j = 0; j < npoly; ++j) + { + poly[j*3+0] += orig[0]; + poly[j*3+1] += orig[1]; + poly[j*3+2] += orig[2]; + } // Store detail submesh. const int ntris = tris.size()/4; - - dmesh.meshes[i*4+0] = dmesh.nverts; - dmesh.meshes[i*4+1] = (unsigned short)nverts; - dmesh.meshes[i*4+2] = dmesh.ntris; - dmesh.meshes[i*4+3] = (unsigned short)ntris; + + dmesh.meshes[i*4+0] = (unsigned int)dmesh.nverts; + dmesh.meshes[i*4+1] = (unsigned int)nverts; + dmesh.meshes[i*4+2] = (unsigned int)dmesh.ntris; + dmesh.meshes[i*4+3] = (unsigned int)ntris; // Store vertices, allocate more memory if necessary. if (dmesh.nverts+nverts > vcap) @@ -832,16 +1112,15 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c while (dmesh.nverts+nverts > vcap) vcap += 256; - float* newv = new float[vcap*3]; + float* newv = (float*)rcAlloc(sizeof(float)*vcap*3, RC_ALLOC_PERM); if (!newv) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newv' (%d).", vcap*3); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newv' (%d).", vcap*3); + return false; } if (dmesh.nverts) memcpy(newv, dmesh.verts, sizeof(float)*3*dmesh.nverts); - delete [] dmesh.verts; + rcFree(dmesh.verts); dmesh.verts = newv; } for (int j = 0; j < nverts; ++j) @@ -857,16 +1136,15 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c { while (dmesh.ntris+ntris > tcap) tcap += 256; - unsigned char* newt = new unsigned char[tcap*4]; + unsigned char* newt = (unsigned char*)rcAlloc(sizeof(unsigned char)*tcap*4, RC_ALLOC_PERM); if (!newt) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newt' (%d).", tcap*4); - goto failure; + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'newt' (%d).", tcap*4); + return false; } if (dmesh.ntris) memcpy(newt, dmesh.tris, sizeof(unsigned char)*4*dmesh.ntris); - delete [] dmesh.tris; + rcFree(dmesh.tris); dmesh.tris = newt; } for (int j = 0; j < ntris; ++j) @@ -879,29 +1157,19 @@ bool rcBuildPolyMeshDetail(const rcPolyMesh& mesh, const rcCompactHeightfield& c dmesh.ntris++; } } - - delete [] bounds; - delete [] poly; - - endTime = rcGetPerformanceTimer(); - - if (rcGetBuildTimes()) - rcGetBuildTimes()->buildDetailMesh += rcGetDeltaTimeUsec(startTime, endTime); + + ctx->stopTimer(RC_TIMER_BUILD_POLYMESHDETAIL); return true; - -failure: - - delete [] bounds; - delete [] poly; - - return false; } -bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh) +/// @see rcAllocPolyMeshDetail, rcPolyMeshDetail +bool rcMergePolyMeshDetails(rcContext* ctx, rcPolyMeshDetail** meshes, const int nmeshes, rcPolyMeshDetail& mesh) { - rcTimeVal startTime = rcGetPerformanceTimer(); + rcAssert(ctx); + ctx->startTimer(RC_TIMER_MERGE_POLYMESHDETAIL); + int maxVerts = 0; int maxTris = 0; int maxMeshes = 0; @@ -915,29 +1183,26 @@ bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPoly } mesh.nmeshes = 0; - mesh.meshes = new unsigned short[maxMeshes*4]; + mesh.meshes = (unsigned int*)rcAlloc(sizeof(unsigned int)*maxMeshes*4, RC_ALLOC_PERM); if (!mesh.meshes) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'pmdtl.meshes' (%d).", maxMeshes*4); + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'pmdtl.meshes' (%d).", maxMeshes*4); return false; } mesh.ntris = 0; - mesh.tris = new unsigned char[maxTris*4]; + mesh.tris = (unsigned char*)rcAlloc(sizeof(unsigned char)*maxTris*4, RC_ALLOC_PERM); if (!mesh.tris) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", maxTris*4); + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.tris' (%d).", maxTris*4); return false; } mesh.nverts = 0; - mesh.verts = new float[maxVerts*3]; + mesh.verts = (float*)rcAlloc(sizeof(float)*maxVerts*3, RC_ALLOC_PERM); if (!mesh.verts) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", maxVerts*3); + ctx->log(RC_LOG_ERROR, "rcBuildPolyMeshDetail: Out of memory 'dmesh.verts' (%d).", maxVerts*3); return false; } @@ -948,18 +1213,18 @@ bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPoly if (!dm) continue; for (int j = 0; j < dm->nmeshes; ++j) { - unsigned short* dst = &mesh.meshes[mesh.nmeshes*4]; - unsigned short* src = &dm->meshes[j*4]; - dst[0] = mesh.nverts+src[0]; + unsigned int* dst = &mesh.meshes[mesh.nmeshes*4]; + unsigned int* src = &dm->meshes[j*4]; + dst[0] = (unsigned int)mesh.nverts+src[0]; dst[1] = src[1]; - dst[2] = mesh.ntris+src[2]; + dst[2] = (unsigned int)mesh.ntris+src[2]; dst[3] = src[3]; mesh.nmeshes++; } for (int k = 0; k < dm->nverts; ++k) { - vcopy(&mesh.verts[mesh.nverts*3], &dm->verts[k*3]); + rcVcopy(&mesh.verts[mesh.nverts*3], &dm->verts[k*3]); mesh.nverts++; } for (int k = 0; k < dm->ntris; ++k) @@ -972,10 +1237,7 @@ bool rcMergePolyMeshDetails(rcPolyMeshDetail** meshes, const int nmeshes, rcPoly } } - rcTimeVal endTime = rcGetPerformanceTimer(); - - if (rcGetBuildTimes()) - rcGetBuildTimes()->mergePolyMeshDetail += rcGetDeltaTimeUsec(startTime, endTime); + ctx->stopTimer(RC_TIMER_MERGE_POLYMESHDETAIL); return true; } diff --git a/extern/recastnavigation/Recast/Source/RecastRasterization.cpp b/extern/recastnavigation/Recast/Source/RecastRasterization.cpp index 658b0e1fb51..d2bb7c98f18 100644 --- a/extern/recastnavigation/Recast/Source/RecastRasterization.cpp +++ b/extern/recastnavigation/Recast/Source/RecastRasterization.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2009 Mikko Mononen memon@inside.org +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -20,8 +20,8 @@ #include <math.h> #include <stdio.h> #include "Recast.h" -#include "RecastTimer.h" -#include "RecastLog.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" inline bool overlapBounds(const float* amin, const float* amax, const float* bmin, const float* bmax) { @@ -48,8 +48,7 @@ static rcSpan* allocSpan(rcHeightfield& hf) { // Create new page. // Allocate memory for the new pool. - const int size = (sizeof(rcSpanPool)-sizeof(rcSpan)) + sizeof(rcSpan)*RC_SPANS_PER_POOL; - rcSpanPool* pool = reinterpret_cast<rcSpanPool*>(new unsigned char[size]); + rcSpanPool* pool = (rcSpanPool*)rcAlloc(sizeof(rcSpanPool), RC_ALLOC_PERM); if (!pool) return 0; pool->next = 0; // Add the pool into the list of pools. @@ -83,16 +82,17 @@ static void freeSpan(rcHeightfield& hf, rcSpan* ptr) hf.freelist = ptr; } -static void addSpan(rcHeightfield& hf, int x, int y, - unsigned short smin, unsigned short smax, - unsigned short flags) +static void addSpan(rcHeightfield& hf, const int x, const int y, + const unsigned short smin, const unsigned short smax, + const unsigned char area, const int flagMergeThr) { + int idx = x + y*hf.width; rcSpan* s = allocSpan(hf); s->smin = smin; s->smax = smax; - s->flags = flags; + s->area = area; s->next = 0; // Empty cell, add he first span. @@ -127,9 +127,8 @@ static void addSpan(rcHeightfield& hf, int x, int y, s->smax = cur->smax; // Merge flags. -// if (s->smax == cur->smax) - if (rcAbs((int)s->smax - (int)cur->smax) <= 1) - s->flags |= cur->flags; + if (rcAbs((int)s->smax - (int)cur->smax) <= flagMergeThr) + s->area = rcMax(s->area, cur->area); // Remove current span. rcSpan* next = cur->next; @@ -155,6 +154,21 @@ static void addSpan(rcHeightfield& hf, int x, int y, } } +/// @par +/// +/// The span addition can be set to favor flags. If the span is merged to +/// another span and the new @p smax is within @p flagMergeThr units +/// from the existing span, the span flags are merged. +/// +/// @see rcHeightfield, rcSpan. +void rcAddSpan(rcContext* /*ctx*/, rcHeightfield& hf, const int x, const int y, + const unsigned short smin, const unsigned short smax, + const unsigned char area, const int flagMergeThr) +{ +// rcAssert(ctx); + addSpan(hf, x,y, smin, smax, area, flagMergeThr); +} + static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, float pd) { float d[12]; @@ -186,9 +200,10 @@ static int clipPoly(const float* in, int n, float* out, float pnx, float pnz, fl } static void rasterizeTri(const float* v0, const float* v1, const float* v2, - unsigned char flags, rcHeightfield& hf, + const unsigned char area, rcHeightfield& hf, const float* bmin, const float* bmax, - const float cs, const float ics, const float ich) + const float cs, const float ics, const float ich, + const int flagMergeThr) { const int w = hf.width; const int h = hf.height; @@ -196,12 +211,12 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2, const float by = bmax[1] - bmin[1]; // Calculate the bounding box of the triangle. - vcopy(tmin, v0); - vcopy(tmax, v0); - vmin(tmin, v1); - vmin(tmin, v2); - vmax(tmax, v1); - vmax(tmax, v2); + rcVcopy(tmin, v0); + rcVcopy(tmax, v0); + rcVmin(tmin, v1); + rcVmin(tmin, v2); + rcVmax(tmax, v1); + rcVmax(tmax, v2); // If the triangle does not touch the bbox of the heightfield, skip the triagle. if (!overlapBounds(bmin, bmax, tmin, tmax)) @@ -223,9 +238,9 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2, for (int y = y0; y <= y1; ++y) { // Clip polygon to row. - vcopy(&in[0], v0); - vcopy(&in[1*3], v1); - vcopy(&in[2*3], v2); + rcVcopy(&in[0], v0); + rcVcopy(&in[1*3], v1); + rcVcopy(&in[2*3], v2); int nvrow = 3; const float cz = bmin[2] + y*cs; nvrow = clipPoly(in, nvrow, out, 0, 1, -cz); @@ -256,38 +271,78 @@ static void rasterizeTri(const float* v0, const float* v1, const float* v2, if (smax < 0.0f) continue; if (smin > by) continue; // Clamp the span to the heightfield bbox. - if (smin < 0.0f) smin = bmin[1]; - if (smax > by) smax = bmax[1]; + if (smin < 0.0f) smin = 0; + if (smax > by) smax = by; // Snap the span to the heightfield height grid. - unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, 0x7fff); - unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), 0, 0x7fff); + unsigned short ismin = (unsigned short)rcClamp((int)floorf(smin * ich), 0, RC_SPAN_MAX_HEIGHT); + unsigned short ismax = (unsigned short)rcClamp((int)ceilf(smax * ich), (int)ismin+1, RC_SPAN_MAX_HEIGHT); - addSpan(hf, x, y, ismin, ismax, flags); + addSpan(hf, x, y, ismin, ismax, area, flagMergeThr); } } } -void rcRasterizeTriangle(const float* v0, const float* v1, const float* v2, - unsigned char flags, rcHeightfield& solid) +/// @par +/// +/// No spans will be added if the triangle does not overlap the heightfield grid. +/// +/// @see rcHeightfield +void rcRasterizeTriangle(rcContext* ctx, const float* v0, const float* v1, const float* v2, + const unsigned char area, rcHeightfield& solid, + const int flagMergeThr) { - rcTimeVal startTime = rcGetPerformanceTimer(); + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES); const float ics = 1.0f/solid.cs; const float ich = 1.0f/solid.ch; - rasterizeTri(v0, v1, v2, flags, solid, solid.bmin, solid.bmax, solid.cs, ics, ich); + rasterizeTri(v0, v1, v2, area, solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); + + ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); +} + +/// @par +/// +/// Spans will only be added for triangles that overlap the heightfield grid. +/// +/// @see rcHeightfield +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/, + const int* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr) +{ + rcAssert(ctx); - rcTimeVal endTime = rcGetPerformanceTimer(); + ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES); + + const float ics = 1.0f/solid.cs; + const float ich = 1.0f/solid.ch; + // Rasterize triangles. + for (int i = 0; i < nt; ++i) + { + const float* v0 = &verts[tris[i*3+0]*3]; + const float* v1 = &verts[tris[i*3+1]*3]; + const float* v2 = &verts[tris[i*3+2]*3]; + // Rasterize. + rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); + } - if (rcGetBuildTimes()) - rcGetBuildTimes()->rasterizeTriangles += rcGetDeltaTimeUsec(startTime, endTime); + ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); } - -void rcRasterizeTriangles(const float* verts, int nv, - const int* tris, const unsigned char* flags, int nt, - rcHeightfield& solid) + +/// @par +/// +/// Spans will only be added for triangles that overlap the heightfield grid. +/// +/// @see rcHeightfield +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const int /*nv*/, + const unsigned short* tris, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr) { - rcTimeVal startTime = rcGetPerformanceTimer(); + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES); const float ics = 1.0f/solid.cs; const float ich = 1.0f/solid.ch; @@ -298,11 +353,35 @@ void rcRasterizeTriangles(const float* verts, int nv, const float* v1 = &verts[tris[i*3+1]*3]; const float* v2 = &verts[tris[i*3+2]*3]; // Rasterize. - rasterizeTri(v0, v1, v2, flags[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich); + rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); } - rcTimeVal endTime = rcGetPerformanceTimer(); + ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); +} - if (rcGetBuildTimes()) - rcGetBuildTimes()->rasterizeTriangles += rcGetDeltaTimeUsec(startTime, endTime); +/// @par +/// +/// Spans will only be added for triangles that overlap the heightfield grid. +/// +/// @see rcHeightfield +void rcRasterizeTriangles(rcContext* ctx, const float* verts, const unsigned char* areas, const int nt, + rcHeightfield& solid, const int flagMergeThr) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_RASTERIZE_TRIANGLES); + + const float ics = 1.0f/solid.cs; + const float ich = 1.0f/solid.ch; + // Rasterize triangles. + for (int i = 0; i < nt; ++i) + { + const float* v0 = &verts[(i*3+0)*3]; + const float* v1 = &verts[(i*3+1)*3]; + const float* v2 = &verts[(i*3+2)*3]; + // Rasterize. + rasterizeTri(v0, v1, v2, areas[i], solid, solid.bmin, solid.bmax, solid.cs, ics, ich, flagMergeThr); + } + + ctx->stopTimer(RC_TIMER_RASTERIZE_TRIANGLES); } diff --git a/extern/recastnavigation/Recast/Source/RecastRegion.cpp b/extern/recastnavigation/Recast/Source/RecastRegion.cpp index 5c557cf0681..4290972ed24 100644 --- a/extern/recastnavigation/Recast/Source/RecastRegion.cpp +++ b/extern/recastnavigation/Recast/Source/RecastRegion.cpp @@ -1,5 +1,5 @@ // -// Copyright (c) 2009 Mikko Mononen memon@inside.org +// Copyright (c) 2009-2010 Mikko Mononen memon@inside.org // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages @@ -23,13 +23,12 @@ #include <stdlib.h> #include <stdio.h> #include "Recast.h" -#include "RecastLog.h" -#include "RecastTimer.h" +#include "RecastAlloc.h" +#include "RecastAssert.h" +#include <new> -static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, - unsigned short* src, unsigned short* dst, - unsigned short& maxDist) +static void calculateDistanceField(rcCompactHeightfield& chf, unsigned short* src, unsigned short& maxDist) { const int w = chf.width; const int h = chf.height; @@ -47,11 +46,19 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { const rcCompactSpan& s = chf.spans[i]; + const unsigned char area = chf.areas[i]; + int nc = 0; for (int dir = 0; dir < 4; ++dir) { - if (rcGetCon(s, dir) != 0xf) - nc++; + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(dir); + const int ay = y + rcGetDirOffsetY(dir); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); + if (area == chf.areas[ai]) + nc++; + } } if (nc != 4) src[i] = 0; @@ -59,6 +66,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, } } + // Pass 1 for (int y = 0; y < h; ++y) { @@ -69,7 +77,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, { const rcCompactSpan& s = chf.spans[i]; - if (rcGetCon(s, 0) != 0xf) + if (rcGetCon(s, 0) != RC_NOT_CONNECTED) { // (-1,0) const int ax = x + rcGetDirOffsetX(0); @@ -80,7 +88,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, src[i] = src[ai]+2; // (-1,-1) - if (rcGetCon(as, 3) != 0xf) + if (rcGetCon(as, 3) != RC_NOT_CONNECTED) { const int aax = ax + rcGetDirOffsetX(3); const int aay = ay + rcGetDirOffsetY(3); @@ -89,7 +97,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, src[i] = src[aai]+3; } } - if (rcGetCon(s, 3) != 0xf) + if (rcGetCon(s, 3) != RC_NOT_CONNECTED) { // (0,-1) const int ax = x + rcGetDirOffsetX(3); @@ -100,7 +108,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, src[i] = src[ai]+2; // (1,-1) - if (rcGetCon(as, 2) != 0xf) + if (rcGetCon(as, 2) != RC_NOT_CONNECTED) { const int aax = ax + rcGetDirOffsetX(2); const int aay = ay + rcGetDirOffsetY(2); @@ -123,7 +131,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, { const rcCompactSpan& s = chf.spans[i]; - if (rcGetCon(s, 2) != 0xf) + if (rcGetCon(s, 2) != RC_NOT_CONNECTED) { // (1,0) const int ax = x + rcGetDirOffsetX(2); @@ -134,7 +142,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, src[i] = src[ai]+2; // (1,1) - if (rcGetCon(as, 1) != 0xf) + if (rcGetCon(as, 1) != RC_NOT_CONNECTED) { const int aax = ax + rcGetDirOffsetX(1); const int aay = ay + rcGetDirOffsetY(1); @@ -143,7 +151,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, src[i] = src[aai]+3; } } - if (rcGetCon(s, 1) != 0xf) + if (rcGetCon(s, 1) != RC_NOT_CONNECTED) { // (0,1) const int ax = x + rcGetDirOffsetX(1); @@ -154,7 +162,7 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, src[i] = src[ai]+2; // (-1,1) - if (rcGetCon(as, 0) != 0xf) + if (rcGetCon(as, 0) != RC_NOT_CONNECTED) { const int aax = ax + rcGetDirOffsetX(0); const int aay = ay + rcGetDirOffsetY(0); @@ -171,8 +179,6 @@ static unsigned short* calculateDistanceField(rcCompactHeightfield& chf, for (int i = 0; i < chf.spanCount; ++i) maxDist = rcMax(src[i], maxDist); - return src; - } static unsigned short* boxBlur(rcCompactHeightfield& chf, int thr, @@ -191,17 +197,17 @@ static unsigned short* boxBlur(rcCompactHeightfield& chf, int thr, for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { const rcCompactSpan& s = chf.spans[i]; - int cd = (int)src[i]; + const unsigned short cd = src[i]; if (cd <= thr) { dst[i] = cd; continue; } - int d = cd; + int d = (int)cd; for (int dir = 0; dir < 4; ++dir) { - if (rcGetCon(s, dir) != 0xf) + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) { const int ax = x + rcGetDirOffsetX(dir); const int ay = y + rcGetDirOffsetY(dir); @@ -210,7 +216,7 @@ static unsigned short* boxBlur(rcCompactHeightfield& chf, int thr, const rcCompactSpan& as = chf.spans[ai]; const int dir2 = (dir+1) & 0x3; - if (rcGetCon(as, dir2) != 0xf) + if (rcGetCon(as, dir2) != RC_NOT_CONNECTED) { const int ax2 = ax + rcGetDirOffsetX(dir2); const int ay2 = ay + rcGetDirOffsetY(dir2); @@ -236,22 +242,24 @@ static unsigned short* boxBlur(rcCompactHeightfield& chf, int thr, static bool floodRegion(int x, int y, int i, - unsigned short level, unsigned short minLevel, unsigned short r, + unsigned short level, unsigned short r, rcCompactHeightfield& chf, - unsigned short* src, + unsigned short* srcReg, unsigned short* srcDist, rcIntArray& stack) { const int w = chf.width; + const unsigned char area = chf.areas[i]; + // Flood fill mark region. stack.resize(0); stack.push((int)x); stack.push((int)y); stack.push((int)i); - src[i*2] = r; - src[i*2+1] = 0; + srcReg[i] = r; + srcDist[i] = 0; - unsigned short lev = level >= minLevel+2 ? level-2 : minLevel; + unsigned short lev = level >= 2 ? level-2 : 0; int count = 0; while (stack.size() > 0) @@ -267,25 +275,30 @@ static bool floodRegion(int x, int y, int i, for (int dir = 0; dir < 4; ++dir) { // 8 connected - if (rcGetCon(cs, dir) != 0xf) + if (rcGetCon(cs, dir) != RC_NOT_CONNECTED) { const int ax = cx + rcGetDirOffsetX(dir); const int ay = cy + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir); - unsigned short nr = src[ai*2]; + if (chf.areas[ai] != area) + continue; + unsigned short nr = srcReg[ai]; + if (nr & RC_BORDER_REG) // Do not take borders into account. + continue; if (nr != 0 && nr != r) ar = nr; const rcCompactSpan& as = chf.spans[ai]; const int dir2 = (dir+1) & 0x3; - if (rcGetCon(as, dir2) != 0xf) + if (rcGetCon(as, dir2) != RC_NOT_CONNECTED) { const int ax2 = ax + rcGetDirOffsetX(dir2); const int ay2 = ay + rcGetDirOffsetY(dir2); const int ai2 = (int)chf.cells[ax2+ay2*w].index + rcGetCon(as, dir2); - - unsigned short nr = src[ai2*2]; + if (chf.areas[ai2] != area) + continue; + unsigned short nr = srcReg[ai2]; if (nr != 0 && nr != r) ar = nr; } @@ -293,7 +306,7 @@ static bool floodRegion(int x, int y, int i, } if (ar != 0) { - src[ci*2] = 0; + srcReg[ci] = 0; continue; } count++; @@ -301,21 +314,20 @@ static bool floodRegion(int x, int y, int i, // Expand neighbours. for (int dir = 0; dir < 4; ++dir) { - if (rcGetCon(cs, dir) != 0xf) + if (rcGetCon(cs, dir) != RC_NOT_CONNECTED) { const int ax = cx + rcGetDirOffsetX(dir); const int ay = cy + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(cs, dir); - if (chf.spans[ai].dist >= lev) + if (chf.areas[ai] != area) + continue; + if (chf.dist[ai] >= lev && srcReg[ai] == 0) { - if (src[ai*2] == 0) - { - src[ai*2] = r; - src[ai*2+1] = 0; - stack.push(ax); - stack.push(ay); - stack.push(ai); - } + srcReg[ai] = r; + srcDist[ai] = 0; + stack.push(ax); + stack.push(ay); + stack.push(ai); } } } @@ -326,8 +338,8 @@ static bool floodRegion(int x, int y, int i, static unsigned short* expandRegions(int maxIter, unsigned short level, rcCompactHeightfield& chf, - unsigned short* src, - unsigned short* dst, + unsigned short* srcReg, unsigned short* srcDist, + unsigned short* dstReg, unsigned short* dstDist, rcIntArray& stack) { const int w = chf.width; @@ -342,7 +354,7 @@ static unsigned short* expandRegions(int maxIter, unsigned short level, const rcCompactCell& c = chf.cells[x+y*w]; for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { - if (chf.spans[i].dist >= level && src[i*2] == 0) + if (chf.dist[i] >= level && srcReg[i] == 0 && chf.areas[i] != RC_NULL_AREA) { stack.push(x); stack.push(y); @@ -357,7 +369,8 @@ static unsigned short* expandRegions(int maxIter, unsigned short level, { int failed = 0; - memcpy(dst, src, sizeof(unsigned short)*chf.spanCount*2); + memcpy(dstReg, srcReg, sizeof(unsigned short)*chf.spanCount); + memcpy(dstDist, srcDist, sizeof(unsigned short)*chf.spanCount); for (int j = 0; j < stack.size(); j += 3) { @@ -370,29 +383,31 @@ static unsigned short* expandRegions(int maxIter, unsigned short level, continue; } - unsigned short r = src[i*2]; + unsigned short r = srcReg[i]; unsigned short d2 = 0xffff; + const unsigned char area = chf.areas[i]; const rcCompactSpan& s = chf.spans[i]; for (int dir = 0; dir < 4; ++dir) { - if (rcGetCon(s, dir) == 0xf) continue; + if (rcGetCon(s, dir) == RC_NOT_CONNECTED) continue; const int ax = x + rcGetDirOffsetX(dir); const int ay = y + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, dir); - if (src[ai*2] > 0 && (src[ai*2] & RC_BORDER_REG) == 0) + if (chf.areas[ai] != area) continue; + if (srcReg[ai] > 0 && (srcReg[ai] & RC_BORDER_REG) == 0) { - if ((int)src[ai*2+1]+2 < (int)d2) + if ((int)srcDist[ai]+2 < (int)d2) { - r = src[ai*2]; - d2 = src[ai*2+1]+2; + r = srcReg[ai]; + d2 = srcDist[ai]+2; } } } if (r) { stack[j+2] = -1; // mark as used - dst[i*2] = r; - dst[i*2+1] = d2; + dstReg[i] = r; + dstDist[i] = d2; } else { @@ -401,7 +416,8 @@ static unsigned short* expandRegions(int maxIter, unsigned short level, } // rcSwap source and dest. - rcSwap(src, dst); + rcSwap(srcReg, dstReg); + rcSwap(srcDist, dstDist); if (failed*3 == stack.size()) break; @@ -414,17 +430,25 @@ static unsigned short* expandRegions(int maxIter, unsigned short level, } } - return src; + return srcReg; } struct rcRegion { - inline rcRegion() : count(0), id(0), remap(false) {} + inline rcRegion(unsigned short i) : + spanCount(0), + id(i), + areaType(0), + remap(false), + visited(false) + {} - int count; - unsigned short id; + int spanCount; // Number of spans belonging to this region + unsigned short id; // ID of the region + unsigned char areaType; // Are type. bool remap; + bool visited; rcIntArray connections; rcIntArray floors; }; @@ -467,25 +491,27 @@ static void replaceNeighbour(rcRegion& reg, unsigned short oldId, unsigned short removeAdjacentNeighbours(reg); } -static bool canMergeWithRegion(rcRegion& reg, unsigned short id) +static bool canMergeWithRegion(const rcRegion& rega, const rcRegion& regb) { + if (rega.areaType != regb.areaType) + return false; int n = 0; - for (int i = 0; i < reg.connections.size(); ++i) + for (int i = 0; i < rega.connections.size(); ++i) { - if (reg.connections[i] == id) + if (rega.connections[i] == regb.id) n++; } if (n > 1) return false; - for (int i = 0; i < reg.floors.size(); ++i) + for (int i = 0; i < rega.floors.size(); ++i) { - if (reg.floors[i] == id) + if (rega.floors[i] == regb.id) return false; } return true; } -static void addUniqueFloorRegion(rcRegion& reg, unsigned short n) +static void addUniqueFloorRegion(rcRegion& reg, int n) { for (int i = 0; i < reg.floors.size(); ++i) if (reg.floors[i] == n) @@ -543,8 +569,8 @@ static bool mergeRegions(rcRegion& rega, rcRegion& regb) for (int j = 0; j < regb.floors.size(); ++j) addUniqueFloorRegion(rega, regb.floors[j]); - rega.count += regb.count; - regb.count = 0; + rega.spanCount += regb.spanCount; + regb.spanCount = 0; regb.connections.resize(0); return true; @@ -562,26 +588,26 @@ static bool isRegionConnectedToBorder(const rcRegion& reg) return false; } -static bool isSolidEdge(rcCompactHeightfield& chf, unsigned short* src, +static bool isSolidEdge(rcCompactHeightfield& chf, unsigned short* srcReg, int x, int y, int i, int dir) { const rcCompactSpan& s = chf.spans[i]; unsigned short r = 0; - if (rcGetCon(s, dir) != 0xf) + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) { const int ax = x + rcGetDirOffsetX(dir); const int ay = y + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir); - r = src[ai*2]; + r = srcReg[ai]; } - if (r == src[i*2]) + if (r == srcReg[i]) return false; return true; } static void walkContour(int x, int y, int i, int dir, rcCompactHeightfield& chf, - unsigned short* src, + unsigned short* srcReg, rcIntArray& cont) { int startDir = dir; @@ -589,12 +615,12 @@ static void walkContour(int x, int y, int i, int dir, const rcCompactSpan& ss = chf.spans[i]; unsigned short curReg = 0; - if (rcGetCon(ss, dir) != 0xf) + if (rcGetCon(ss, dir) != RC_NOT_CONNECTED) { const int ax = x + rcGetDirOffsetX(dir); const int ay = y + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(ss, dir); - curReg = src[ai*2]; + curReg = srcReg[ai]; } cont.push(curReg); @@ -603,16 +629,16 @@ static void walkContour(int x, int y, int i, int dir, { const rcCompactSpan& s = chf.spans[i]; - if (isSolidEdge(chf, src, x, y, i, dir)) + if (isSolidEdge(chf, srcReg, x, y, i, dir)) { // Choose the edge corner unsigned short r = 0; - if (rcGetCon(s, dir) != 0xf) + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) { const int ax = x + rcGetDirOffsetX(dir); const int ay = y + rcGetDirOffsetY(dir); const int ai = (int)chf.cells[ax+ay*chf.width].index + rcGetCon(s, dir); - r = src[ai*2]; + r = srcReg[ai]; } if (r != curReg) { @@ -627,7 +653,7 @@ static void walkContour(int x, int y, int i, int dir, int ni = -1; const int nx = x + rcGetDirOffsetX(dir); const int ny = y + rcGetDirOffsetY(dir); - if (rcGetCon(s, dir) != 0xf) + if (rcGetCon(s, dir) != RC_NOT_CONNECTED) { const rcCompactCell& nc = chf.cells[nx+ny*chf.width]; ni = (int)nc.index + rcGetCon(s, dir); @@ -667,26 +693,26 @@ static void walkContour(int x, int y, int i, int dir, } } -static bool filterSmallRegions(int minRegionSize, int mergeRegionSize, +static bool filterSmallRegions(rcContext* ctx, int minRegionArea, int mergeRegionSize, unsigned short& maxRegionId, rcCompactHeightfield& chf, - unsigned short* src) + unsigned short* srcReg) { const int w = chf.width; const int h = chf.height; - - int nreg = maxRegionId+1; - rcRegion* regions = new rcRegion[nreg]; + + const int nreg = maxRegionId+1; + rcRegion* regions = (rcRegion*)rcAlloc(sizeof(rcRegion)*nreg, RC_ALLOC_TEMP); if (!regions) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "filterSmallRegions: Out of memory 'regions' (%d).", nreg); + ctx->log(RC_LOG_ERROR, "filterSmallRegions: Out of memory 'regions' (%d).", nreg); return false; } - - for (int i = 0; i < nreg; ++i) - regions[i].id = (unsigned short)i; + // Construct regions + for (int i = 0; i < nreg; ++i) + new(®ions[i]) rcRegion((unsigned short)i); + // Find edge of a region and find connections around the contour. for (int y = 0; y < h; ++y) { @@ -695,19 +721,19 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize, const rcCompactCell& c = chf.cells[x+y*w]; for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { - unsigned short r = src[i*2]; + unsigned short r = srcReg[i]; if (r == 0 || r >= nreg) continue; rcRegion& reg = regions[r]; - reg.count++; + reg.spanCount++; + - // Update floors. for (int j = (int)c.index; j < ni; ++j) { if (i == j) continue; - unsigned short floorId = src[j*2]; + unsigned short floorId = srcReg[j]; if (floorId == 0 || floorId >= nreg) continue; addUniqueFloorRegion(reg, floorId); @@ -717,11 +743,13 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize, if (reg.connections.size() > 0) continue; + reg.areaType = chf.areas[i]; + // Check if this cell is next to a border. int ndir = -1; for (int dir = 0; dir < 4; ++dir) { - if (isSolidEdge(chf, src, x, y, i, dir)) + if (isSolidEdge(chf, srcReg, x, y, i, dir)) { ndir = dir; break; @@ -732,32 +760,77 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize, { // The cell is at border. // Walk around the contour to find all the neighbours. - walkContour(x, y, i, ndir, chf, src, reg.connections); + walkContour(x, y, i, ndir, chf, srcReg, reg.connections); } } } } - - // Remove too small unconnected regions. + + // Remove too small regions. + rcIntArray stack(32); + rcIntArray trace(32); for (int i = 0; i < nreg; ++i) { rcRegion& reg = regions[i]; if (reg.id == 0 || (reg.id & RC_BORDER_REG)) - continue; - if (reg.count == 0) + continue; + if (reg.spanCount == 0) continue; + if (reg.visited) + continue; + + // Count the total size of all the connected regions. + // Also keep track of the regions connects to a tile border. + bool connectsToBorder = false; + int spanCount = 0; + stack.resize(0); + trace.resize(0); + + reg.visited = true; + stack.push(i); - if (reg.connections.size() == 1 && reg.connections[0] == 0) + while (stack.size()) { - if (reg.count < minRegionSize) + // Pop + int ri = stack.pop(); + + rcRegion& creg = regions[ri]; + + spanCount += creg.spanCount; + trace.push(ri); + + for (int j = 0; j < creg.connections.size(); ++j) { - // Non-connected small region, remove. - reg.count = 0; - reg.id = 0; + if (creg.connections[j] & RC_BORDER_REG) + { + connectsToBorder = true; + continue; + } + rcRegion& nreg = regions[creg.connections[j]]; + if (nreg.visited) + continue; + if (nreg.id == 0 || (nreg.id & RC_BORDER_REG)) + continue; + // Visit + stack.push(nreg.id); + nreg.visited = true; } } - } + // If the accumulated regions size is too small, remove it. + // Do not remove areas which connect to tile borders + // as their size cannot be estimated correctly and removing them + // can potentially remove necessary areas. + if (spanCount < minRegionArea && !connectsToBorder) + { + // Kill all visited regions. + for (int j = 0; j < trace.size(); ++j) + { + regions[trace[j]].spanCount = 0; + regions[trace[j]].id = 0; + } + } + } // Merge too small regions to neighbour regions. int mergeCount = 0 ; @@ -768,14 +841,14 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize, { rcRegion& reg = regions[i]; if (reg.id == 0 || (reg.id & RC_BORDER_REG)) - continue; - if (reg.count == 0) + continue; + if (reg.spanCount == 0) continue; - + // Check to see if the region should be merged. - if (reg.count > mergeRegionSize && isRegionConnectedToBorder(reg)) + if (reg.spanCount > mergeRegionSize && isRegionConnectedToBorder(reg)) continue; - + // Small region with more than 1 connection. // Or region which is not connected to a border at all. // Find smallest neighbour region that connects to this one. @@ -786,11 +859,11 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize, if (reg.connections[j] & RC_BORDER_REG) continue; rcRegion& mreg = regions[reg.connections[j]]; if (mreg.id == 0 || (mreg.id & RC_BORDER_REG)) continue; - if (mreg.count < smallest && - canMergeWithRegion(reg, mreg.id) && - canMergeWithRegion(mreg, reg.id)) + if (mreg.spanCount < smallest && + canMergeWithRegion(reg, mreg) && + canMergeWithRegion(mreg, reg)) { - smallest = mreg.count; + smallest = mreg.spanCount; mergeId = mreg.id; } } @@ -821,16 +894,16 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize, } } while (mergeCount > 0); - + // Compress region Ids. for (int i = 0; i < nreg; ++i) { regions[i].remap = false; - if (regions[i].id == 0) continue; // Skip nil regions. - if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions. + if (regions[i].id == 0) continue; // Skip nil regions. + if (regions[i].id & RC_BORDER_REG) continue; // Skip external regions. regions[i].remap = true; } - + unsigned short regIdGen = 0; for (int i = 0; i < nreg; ++i) { @@ -848,91 +921,88 @@ static bool filterSmallRegions(int minRegionSize, int mergeRegionSize, } } maxRegionId = regIdGen; - + // Remap regions. for (int i = 0; i < chf.spanCount; ++i) { - if ((src[i*2] & RC_BORDER_REG) == 0) - src[i*2] = regions[src[i*2]].id; + if ((srcReg[i] & RC_BORDER_REG) == 0) + srcReg[i] = regions[srcReg[i]].id; } - delete [] regions; + for (int i = 0; i < nreg; ++i) + regions[i].~rcRegion(); + rcFree(regions); return true; } -bool rcBuildDistanceField(rcCompactHeightfield& chf) +/// @par +/// +/// This is usually the second to the last step in creating a fully built +/// compact heightfield. This step is required before regions are built +/// using #rcBuildRegions or #rcBuildRegionsMonotone. +/// +/// After this step, the distance data is available via the rcCompactHeightfield::maxDistance +/// and rcCompactHeightfield::dist fields. +/// +/// @see rcCompactHeightfield, rcBuildRegions, rcBuildRegionsMonotone +bool rcBuildDistanceField(rcContext* ctx, rcCompactHeightfield& chf) { - rcTimeVal startTime = rcGetPerformanceTimer(); + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD); + + if (chf.dist) + { + rcFree(chf.dist); + chf.dist = 0; + } - unsigned short* dist0 = new unsigned short[chf.spanCount]; - if (!dist0) + unsigned short* src = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); + if (!src) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dist0' (%d).", chf.spanCount); + ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'src' (%d).", chf.spanCount); return false; } - unsigned short* dist1 = new unsigned short[chf.spanCount]; - if (!dist1) + unsigned short* dst = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); + if (!dst) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dist1' (%d).", chf.spanCount); - delete [] dist0; + ctx->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'dst' (%d).", chf.spanCount); + rcFree(src); return false; } - unsigned short* src = dist0; - unsigned short* dst = dist1; - unsigned short maxDist = 0; - rcTimeVal distStartTime = rcGetPerformanceTimer(); - - if (calculateDistanceField(chf, src, dst, maxDist) != src) - rcSwap(src, dst); + ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST); + calculateDistanceField(chf, src, maxDist); chf.maxDistance = maxDist; - rcTimeVal distEndTime = rcGetPerformanceTimer(); + ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_DIST); - rcTimeVal blurStartTime = rcGetPerformanceTimer(); + ctx->startTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR); // Blur if (boxBlur(chf, 1, src, dst) != src) rcSwap(src, dst); // Store distance. - for (int i = 0; i < chf.spanCount; ++i) - chf.spans[i].dist = src[i]; - - rcTimeVal blurEndTime = rcGetPerformanceTimer(); + chf.dist = src; - delete [] dist0; - delete [] dist1; - - rcTimeVal endTime = rcGetPerformanceTimer(); + ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD_BLUR); + + ctx->stopTimer(RC_TIMER_BUILD_DISTANCEFIELD); -/* if (rcGetLog()) - { - rcGetLog()->log(RC_LOG_PROGRESS, "Build distance field: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); - rcGetLog()->log(RC_LOG_PROGRESS, " - dist: %.3f ms", rcGetDeltaTimeUsec(distStartTime, distEndTime)/1000.0f); - rcGetLog()->log(RC_LOG_PROGRESS, " - blur: %.3f ms", rcGetDeltaTimeUsec(blurStartTime, blurEndTime)/1000.0f); - }*/ - if (rcGetBuildTimes()) - { - rcGetBuildTimes()->buildDistanceField += rcGetDeltaTimeUsec(startTime, endTime); - rcGetBuildTimes()->buildDistanceFieldDist += rcGetDeltaTimeUsec(distStartTime, distEndTime); - rcGetBuildTimes()->buildDistanceFieldBlur += rcGetDeltaTimeUsec(blurStartTime, blurEndTime); - } + rcFree(dst); return true; } -static void paintRectRegion(int minx, int maxx, int miny, int maxy, - unsigned short regId, unsigned short minLevel, - rcCompactHeightfield& chf, unsigned short* src) +static void paintRectRegion(int minx, int maxx, int miny, int maxy, unsigned short regId, + rcCompactHeightfield& chf, unsigned short* srcReg) { - const int w = chf.width; + const int w = chf.width; for (int y = miny; y < maxy; ++y) { for (int x = minx; x < maxx; ++x) @@ -940,77 +1010,283 @@ static void paintRectRegion(int minx, int maxx, int miny, int maxy, const rcCompactCell& c = chf.cells[x+y*w]; for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { - if (chf.spans[i].dist >= minLevel) - src[i*2] = regId; + if (chf.areas[i] != RC_NULL_AREA) + srcReg[i] = regId; } } } } -bool rcBuildRegions(rcCompactHeightfield& chf, - int walkableRadius, int borderSize, - int minRegionSize, int mergeRegionSize) + +static const unsigned short RC_NULL_NEI = 0xffff; + +struct rcSweepSpan +{ + unsigned short rid; // row id + unsigned short id; // region id + unsigned short ns; // number samples + unsigned short nei; // neighbour id +}; + +/// @par +/// +/// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour. +/// Contours will form simple polygons. +/// +/// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be +/// re-assigned to the zero (null) region. +/// +/// Partitioning can result in smaller than necessary regions. @p mergeRegionArea helps +/// reduce unecessarily small regions. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// The region data will be available via the rcCompactHeightfield::maxRegions +/// and rcCompactSpan::reg fields. +/// +/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions. +/// +/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig +bool rcBuildRegionsMonotone(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea) { - rcTimeVal startTime = rcGetPerformanceTimer(); + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_REGIONS); const int w = chf.width; const int h = chf.height; + unsigned short id = 1; - unsigned short* tmp1 = new unsigned short[chf.spanCount*2]; - if (!tmp1) + rcScopedDelete<unsigned short> srcReg = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount, RC_ALLOC_TEMP); + if (!srcReg) + { + ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'src' (%d).", chf.spanCount); + return false; + } + memset(srcReg,0,sizeof(unsigned short)*chf.spanCount); + + const int nsweeps = rcMax(chf.width,chf.height); + rcScopedDelete<rcSweepSpan> sweeps = (rcSweepSpan*)rcAlloc(sizeof(rcSweepSpan)*nsweeps, RC_ALLOC_TEMP); + if (!sweeps) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'tmp1' (%d).", chf.spanCount*2); + ctx->log(RC_LOG_ERROR, "rcBuildRegionsMonotone: Out of memory 'sweeps' (%d).", nsweeps); return false; } - unsigned short* tmp2 = new unsigned short[chf.spanCount*2]; - if (!tmp2) + + + // Mark border regions. + if (borderSize > 0) + { + // Make sure border will not overflow. + const int bw = rcMin(w, borderSize); + const int bh = rcMin(h, borderSize); + // Paint regions + paintRectRegion(0, bw, 0, h, id|RC_BORDER_REG, chf, srcReg); id++; + paintRectRegion(w-bw, w, 0, h, id|RC_BORDER_REG, chf, srcReg); id++; + paintRectRegion(0, w, 0, bh, id|RC_BORDER_REG, chf, srcReg); id++; + paintRectRegion(0, w, h-bh, h, id|RC_BORDER_REG, chf, srcReg); id++; + + chf.borderSize = borderSize; + } + + rcIntArray prev(256); + + // Sweep one line at a time. + for (int y = borderSize; y < h-borderSize; ++y) { - if (rcGetLog()) - rcGetLog()->log(RC_LOG_ERROR, "rcBuildDistanceField: Out of memory 'tmp2' (%d).", chf.spanCount*2); - delete [] tmp1; + // Collect spans from this row. + prev.resize(id+1); + memset(&prev[0],0,sizeof(int)*id); + unsigned short rid = 1; + + for (int x = borderSize; x < w-borderSize; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + const rcCompactSpan& s = chf.spans[i]; + if (chf.areas[i] == RC_NULL_AREA) continue; + + // -x + unsigned short previd = 0; + if (rcGetCon(s, 0) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(0); + const int ay = y + rcGetDirOffsetY(0); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 0); + if ((srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai]) + previd = srcReg[ai]; + } + + if (!previd) + { + previd = rid++; + sweeps[previd].rid = previd; + sweeps[previd].ns = 0; + sweeps[previd].nei = 0; + } + + // -y + if (rcGetCon(s,3) != RC_NOT_CONNECTED) + { + const int ax = x + rcGetDirOffsetX(3); + const int ay = y + rcGetDirOffsetY(3); + const int ai = (int)chf.cells[ax+ay*w].index + rcGetCon(s, 3); + if (srcReg[ai] && (srcReg[ai] & RC_BORDER_REG) == 0 && chf.areas[i] == chf.areas[ai]) + { + unsigned short nr = srcReg[ai]; + if (!sweeps[previd].nei || sweeps[previd].nei == nr) + { + sweeps[previd].nei = nr; + sweeps[previd].ns++; + prev[nr]++; + } + else + { + sweeps[previd].nei = RC_NULL_NEI; + } + } + } + + srcReg[i] = previd; + } + } + + // Create unique ID. + for (int i = 1; i < rid; ++i) + { + if (sweeps[i].nei != RC_NULL_NEI && sweeps[i].nei != 0 && + prev[sweeps[i].nei] == (int)sweeps[i].ns) + { + sweeps[i].id = sweeps[i].nei; + } + else + { + sweeps[i].id = id++; + } + } + + // Remap IDs + for (int x = borderSize; x < w-borderSize; ++x) + { + const rcCompactCell& c = chf.cells[x+y*w]; + + for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) + { + if (srcReg[i] > 0 && srcReg[i] < rid) + srcReg[i] = sweeps[srcReg[i]].id; + } + } + } + + ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER); + + // Filter out small regions. + chf.maxRegions = id; + if (!filterSmallRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg)) + return false; + + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER); + + // Store the result out. + for (int i = 0; i < chf.spanCount; ++i) + chf.spans[i].reg = srcReg[i]; + + ctx->stopTimer(RC_TIMER_BUILD_REGIONS); + + return true; +} + +/// @par +/// +/// Non-null regions will consist of connected, non-overlapping walkable spans that form a single contour. +/// Contours will form simple polygons. +/// +/// If multiple regions form an area that is smaller than @p minRegionArea, then all spans will be +/// re-assigned to the zero (null) region. +/// +/// Watershed partitioning can result in smaller than necessary regions, especially in diagonal corridors. +/// @p mergeRegionArea helps reduce unecessarily small regions. +/// +/// See the #rcConfig documentation for more information on the configuration parameters. +/// +/// The region data will be available via the rcCompactHeightfield::maxRegions +/// and rcCompactSpan::reg fields. +/// +/// @warning The distance field must be created using #rcBuildDistanceField before attempting to build regions. +/// +/// @see rcCompactHeightfield, rcCompactSpan, rcBuildDistanceField, rcBuildRegionsMonotone, rcConfig +bool rcBuildRegions(rcContext* ctx, rcCompactHeightfield& chf, + const int borderSize, const int minRegionArea, const int mergeRegionArea) +{ + rcAssert(ctx); + + ctx->startTimer(RC_TIMER_BUILD_REGIONS); + + const int w = chf.width; + const int h = chf.height; + + rcScopedDelete<unsigned short> buf = (unsigned short*)rcAlloc(sizeof(unsigned short)*chf.spanCount*4, RC_ALLOC_TEMP); + if (!buf) + { + ctx->log(RC_LOG_ERROR, "rcBuildRegions: Out of memory 'tmp' (%d).", chf.spanCount*4); return false; } - rcTimeVal regStartTime = rcGetPerformanceTimer(); + ctx->startTimer(RC_TIMER_BUILD_REGIONS_WATERSHED); rcIntArray stack(1024); rcIntArray visited(1024); - unsigned short* src = tmp1; - unsigned short* dst = tmp2; + unsigned short* srcReg = buf; + unsigned short* srcDist = buf+chf.spanCount; + unsigned short* dstReg = buf+chf.spanCount*2; + unsigned short* dstDist = buf+chf.spanCount*3; - memset(src, 0, sizeof(unsigned short) * chf.spanCount*2); + memset(srcReg, 0, sizeof(unsigned short)*chf.spanCount); + memset(srcDist, 0, sizeof(unsigned short)*chf.spanCount); unsigned short regionId = 1; unsigned short level = (chf.maxDistance+1) & ~1; - - unsigned short minLevel = (unsigned short)(walkableRadius*2); - - const int expandIters = 4 + walkableRadius * 2; - // Mark border regions. - paintRectRegion(0, borderSize, 0, h, regionId|RC_BORDER_REG, minLevel, chf, src); regionId++; - paintRectRegion(w-borderSize, w, 0, h, regionId|RC_BORDER_REG, minLevel, chf, src); regionId++; - paintRectRegion(0, w, 0, borderSize, regionId|RC_BORDER_REG, minLevel, chf, src); regionId++; - paintRectRegion(0, w, h-borderSize, h, regionId|RC_BORDER_REG, minLevel, chf, src); regionId++; + // TODO: Figure better formula, expandIters defines how much the + // watershed "overflows" and simplifies the regions. Tying it to + // agent radius was usually good indication how greedy it could be. +// const int expandIters = 4 + walkableRadius * 2; + const int expandIters = 8; + + if (borderSize > 0) + { + // Make sure border will not overflow. + const int bw = rcMin(w, borderSize); + const int bh = rcMin(h, borderSize); + // Paint regions + paintRectRegion(0, bw, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + paintRectRegion(w-bw, w, 0, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + paintRectRegion(0, w, 0, bh, regionId|RC_BORDER_REG, chf, srcReg); regionId++; + paintRectRegion(0, w, h-bh, h, regionId|RC_BORDER_REG, chf, srcReg); regionId++; - rcTimeVal expTime = 0; - rcTimeVal floodTime = 0; + chf.borderSize = borderSize; + } - while (level > minLevel) + while (level > 0) { level = level >= 2 ? level-2 : 0; - rcTimeVal expStartTime = rcGetPerformanceTimer(); + ctx->startTimer(RC_TIMER_BUILD_REGIONS_EXPAND); // Expand current regions until no empty connected cells found. - if (expandRegions(expandIters, level, chf, src, dst, stack) != src) - rcSwap(src, dst); + if (expandRegions(expandIters, level, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg) + { + rcSwap(srcReg, dstReg); + rcSwap(srcDist, dstDist); + } - expTime += rcGetPerformanceTimer() - expStartTime; + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_EXPAND); - rcTimeVal floodStartTime = rcGetPerformanceTimer(); + ctx->startTimer(RC_TIMER_BUILD_REGIONS_FLOOD); // Mark new regions with IDs. for (int y = 0; y < h; ++y) @@ -1020,61 +1296,41 @@ bool rcBuildRegions(rcCompactHeightfield& chf, const rcCompactCell& c = chf.cells[x+y*w]; for (int i = (int)c.index, ni = (int)(c.index+c.count); i < ni; ++i) { - if (chf.spans[i].dist < level || src[i*2] != 0) + if (chf.dist[i] < level || srcReg[i] != 0 || chf.areas[i] == RC_NULL_AREA) continue; - - if (floodRegion(x, y, i, minLevel, level, regionId, chf, src, stack)) + if (floodRegion(x, y, i, level, regionId, chf, srcReg, srcDist, stack)) regionId++; } } } - floodTime += rcGetPerformanceTimer() - floodStartTime; - + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FLOOD); } // Expand current regions until no empty connected cells found. - if (expandRegions(expandIters*8, minLevel, chf, src, dst, stack) != src) - rcSwap(src, dst); + if (expandRegions(expandIters*8, 0, chf, srcReg, srcDist, dstReg, dstDist, stack) != srcReg) + { + rcSwap(srcReg, dstReg); + rcSwap(srcDist, dstDist); + } - rcTimeVal regEndTime = rcGetPerformanceTimer(); + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_WATERSHED); - rcTimeVal filterStartTime = rcGetPerformanceTimer(); + ctx->startTimer(RC_TIMER_BUILD_REGIONS_FILTER); // Filter out small regions. chf.maxRegions = regionId; - if (!filterSmallRegions(minRegionSize, mergeRegionSize, chf.maxRegions, chf, src)) + if (!filterSmallRegions(ctx, minRegionArea, mergeRegionArea, chf.maxRegions, chf, srcReg)) return false; - rcTimeVal filterEndTime = rcGetPerformanceTimer(); - + ctx->stopTimer(RC_TIMER_BUILD_REGIONS_FILTER); + // Write the result out. for (int i = 0; i < chf.spanCount; ++i) - chf.spans[i].reg = src[i*2]; - - delete [] tmp1; - delete [] tmp2; + chf.spans[i].reg = srcReg[i]; - rcTimeVal endTime = rcGetPerformanceTimer(); + ctx->stopTimer(RC_TIMER_BUILD_REGIONS); -/* if (rcGetLog()) - { - rcGetLog()->log(RC_LOG_PROGRESS, "Build regions: %.3f ms", rcGetDeltaTimeUsec(startTime, endTime)/1000.0f); - rcGetLog()->log(RC_LOG_PROGRESS, " - reg: %.3f ms", rcGetDeltaTimeUsec(regStartTime, regEndTime)/1000.0f); - rcGetLog()->log(RC_LOG_PROGRESS, " - exp: %.3f ms", rcGetDeltaTimeUsec(0, expTime)/1000.0f); - rcGetLog()->log(RC_LOG_PROGRESS, " - flood: %.3f ms", rcGetDeltaTimeUsec(0, floodTime)/1000.0f); - rcGetLog()->log(RC_LOG_PROGRESS, " - filter: %.3f ms", rcGetDeltaTimeUsec(filterStartTime, filterEndTime)/1000.0f); - } -*/ - if (rcGetBuildTimes()) - { - rcGetBuildTimes()->buildRegions += rcGetDeltaTimeUsec(startTime, endTime); - rcGetBuildTimes()->buildRegionsReg += rcGetDeltaTimeUsec(regStartTime, regEndTime); - rcGetBuildTimes()->buildRegionsExp += rcGetDeltaTimeUsec(0, expTime); - rcGetBuildTimes()->buildRegionsFlood += rcGetDeltaTimeUsec(0, floodTime); - rcGetBuildTimes()->buildRegionsFilter += rcGetDeltaTimeUsec(filterStartTime, filterEndTime); - } - return true; } diff --git a/extern/recastnavigation/recast-capi.cpp b/extern/recastnavigation/recast-capi.cpp index 2348497b0d7..42a9a4b82c8 100644 --- a/extern/recastnavigation/recast-capi.cpp +++ b/extern/recastnavigation/recast-capi.cpp @@ -30,6 +30,11 @@ #include <math.h> #include "Recast.h" +static rcContext *sctx; + +#define INIT_SCTX() \ + if (sctx == NULL) sctx = new rcContext(false) + int recast_buildMeshAdjacency(unsigned short* polys, const int npolys, const int nverts, const int vertsPerPoly) { @@ -48,109 +53,123 @@ void recast_calcGridSize(const float *bmin, const float *bmax, float cs, int *w, struct recast_heightfield *recast_newHeightfield(void) { - return (struct recast_heightfield *) (new rcHeightfield); + return (struct recast_heightfield *) rcAllocHeightfield(); } void recast_destroyHeightfield(struct recast_heightfield *heightfield) { - delete (rcHeightfield *) heightfield; + rcFreeHeightField((rcHeightfield *) heightfield); } int recast_createHeightfield(struct recast_heightfield *hf, int width, int height, const float *bmin, const float* bmax, float cs, float ch) { - return rcCreateHeightfield(*(rcHeightfield *)hf, width, height, bmin, bmax, cs, ch); + INIT_SCTX(); + return rcCreateHeightfield(sctx, *(rcHeightfield *)hf, width, height, bmin, bmax, cs, ch); } void recast_markWalkableTriangles(const float walkableSlopeAngle,const float *verts, int nv, const int *tris, int nt, unsigned char *flags) { - rcMarkWalkableTriangles(walkableSlopeAngle, verts, nv, tris, nt, flags); + INIT_SCTX(); + rcMarkWalkableTriangles(sctx, walkableSlopeAngle, verts, nv, tris, nt, flags); } void recast_rasterizeTriangles(const float *verts, int nv, const int *tris, const unsigned char *flags, int nt, struct recast_heightfield *solid) { - rcRasterizeTriangles(verts, nv, tris, flags, nt, *(rcHeightfield *) solid); + INIT_SCTX(); + rcRasterizeTriangles(sctx, verts, nv, tris, flags, nt, *(rcHeightfield *) solid); } void recast_filterLedgeSpans(const int walkableHeight, const int walkableClimb, struct recast_heightfield *solid) { - rcFilterLedgeSpans(walkableHeight, walkableClimb, *(rcHeightfield *) solid); + INIT_SCTX(); + rcFilterLedgeSpans(sctx, walkableHeight, walkableClimb, *(rcHeightfield *) solid); } void recast_filterWalkableLowHeightSpans(int walkableHeight, struct recast_heightfield *solid) { - rcFilterWalkableLowHeightSpans(walkableHeight, *(rcHeightfield *) solid); + INIT_SCTX(); + rcFilterWalkableLowHeightSpans(sctx, walkableHeight, *(rcHeightfield *) solid); +} + +void recast_filterLowHangingWalkableObstacles(const int walkableClimb, struct recast_heightfield *solid) +{ + INIT_SCTX(); + rcFilterLowHangingWalkableObstacles(sctx, walkableClimb, *(rcHeightfield *) solid); } struct recast_compactHeightfield *recast_newCompactHeightfield(void) { - return (struct recast_compactHeightfield *) (new rcCompactHeightfield); + return (struct recast_compactHeightfield *) rcAllocCompactHeightfield(); } void recast_destroyCompactHeightfield(struct recast_compactHeightfield *compactHeightfield) { - delete (rcCompactHeightfield *) compactHeightfield; + rcFreeCompactHeightfield( (rcCompactHeightfield *) compactHeightfield); } int recast_buildCompactHeightfield(const int walkableHeight, const int walkableClimb, - unsigned char flags, struct recast_heightfield *hf, struct recast_compactHeightfield *chf) + struct recast_heightfield *hf, struct recast_compactHeightfield *chf) { - int rcFlags = 0; - - if(flags & RECAST_WALKABLE) - rcFlags |= RC_WALKABLE; - - if(flags & RECAST_REACHABLE) - rcFlags |= RC_REACHABLE; + INIT_SCTX(); + return rcBuildCompactHeightfield(sctx, walkableHeight, walkableClimb, + *(rcHeightfield *) hf, *(rcCompactHeightfield *) chf); +} - return rcBuildCompactHeightfield(walkableHeight, walkableClimb, rcFlags, - *(rcHeightfield *) hf, *(rcCompactHeightfield *) chf); +int recast_erodeWalkableArea(int radius, struct recast_compactHeightfield *chf) +{ + INIT_SCTX(); + return rcErodeWalkableArea(sctx, radius, *(rcCompactHeightfield *) chf); } int recast_buildDistanceField(struct recast_compactHeightfield *chf) { - return rcBuildDistanceField(*(rcCompactHeightfield *) chf); + INIT_SCTX(); + return rcBuildDistanceField(sctx, *(rcCompactHeightfield *) chf); } -int recast_buildRegions(struct recast_compactHeightfield *chf, int walkableRadius, int borderSize, +int recast_buildRegions(struct recast_compactHeightfield *chf, int borderSize, int minRegionSize, int mergeRegionSize) { - return rcBuildRegions(*(rcCompactHeightfield *) chf, walkableRadius, borderSize, + INIT_SCTX(); + return rcBuildRegions(sctx, *(rcCompactHeightfield *) chf, borderSize, minRegionSize, mergeRegionSize); } struct recast_contourSet *recast_newContourSet(void) { - return (struct recast_contourSet *) (new rcContourSet); + return (struct recast_contourSet *) rcAllocContourSet(); } void recast_destroyContourSet(struct recast_contourSet *contourSet) { - delete (rcContourSet *) contourSet; + rcFreeContourSet((rcContourSet *) contourSet); } int recast_buildContours(struct recast_compactHeightfield *chf, const float maxError, const int maxEdgeLen, struct recast_contourSet *cset) { - return rcBuildContours(*(rcCompactHeightfield *) chf, maxError, maxEdgeLen, *(rcContourSet *) cset); + INIT_SCTX(); + return rcBuildContours(sctx, *(rcCompactHeightfield *) chf, maxError, maxEdgeLen, *(rcContourSet *) cset); } struct recast_polyMesh *recast_newPolyMesh(void) { - return (recast_polyMesh *) (new rcPolyMesh); + return (recast_polyMesh *) rcAllocPolyMesh(); } void recast_destroyPolyMesh(struct recast_polyMesh *polyMesh) { - delete (rcPolyMesh *) polyMesh; + rcFreePolyMesh((rcPolyMesh *) polyMesh); } int recast_buildPolyMesh(struct recast_contourSet *cset, int nvp, struct recast_polyMesh *mesh) { - return rcBuildPolyMesh(*(rcContourSet *) cset, nvp, * (rcPolyMesh *) mesh); + INIT_SCTX(); + return rcBuildPolyMesh(sctx, *(rcContourSet *) cset, nvp, * (rcPolyMesh *) mesh); } unsigned short *recast_polyMeshGetVerts(struct recast_polyMesh *mesh, int *nverts) @@ -206,18 +225,19 @@ unsigned short *recast_polyMeshGetPolys(struct recast_polyMesh *mesh, int *npoly struct recast_polyMeshDetail *recast_newPolyMeshDetail(void) { - return (struct recast_polyMeshDetail *) (new rcPolyMeshDetail); + return (struct recast_polyMeshDetail *) rcAllocPolyMeshDetail(); } void recast_destroyPolyMeshDetail(struct recast_polyMeshDetail *polyMeshDetail) { - delete (rcPolyMeshDetail *) polyMeshDetail; + rcFreePolyMeshDetail((rcPolyMeshDetail *) polyMeshDetail); } int recast_buildPolyMeshDetail(const struct recast_polyMesh *mesh, const struct recast_compactHeightfield *chf, const float sampleDist, const float sampleMaxError, struct recast_polyMeshDetail *dmesh) { - return rcBuildPolyMeshDetail(*(rcPolyMesh *) mesh, *(rcCompactHeightfield *) chf, + INIT_SCTX(); + return rcBuildPolyMeshDetail(sctx, *(rcPolyMesh *) mesh, *(rcCompactHeightfield *) chf, sampleDist, sampleMaxError, *(rcPolyMeshDetail *) dmesh); } @@ -241,7 +261,7 @@ unsigned char *recast_polyMeshDetailGetTris(struct recast_polyMeshDetail *mesh, return dmesh->tris; } -unsigned short *recast_polyMeshDetailGetMeshes(struct recast_polyMeshDetail *mesh, int *nmeshes) +unsigned int *recast_polyMeshDetailGetMeshes(struct recast_polyMeshDetail *mesh, int *nmeshes) { rcPolyMeshDetail *dmesh = (rcPolyMeshDetail *)mesh; @@ -250,3 +270,130 @@ unsigned short *recast_polyMeshDetailGetMeshes(struct recast_polyMeshDetail *mes return dmesh->meshes; } + +// qsort based on FreeBSD source (libkern\qsort.c) +typedef int cmp_t(void *, const void *, const void *); +static inline char *med3(char *, char *, char *, cmp_t *, void *); +static inline void swapfunc(char *, char *, int, int); + +#define min(a, b) (a) < (b) ? a : b +#define swapcode(TYPE, parmi, parmj, n) \ +{ \ + long i = (n) / sizeof (TYPE); \ + TYPE *pi = (TYPE *) (parmi); \ + TYPE *pj = (TYPE *) (parmj); \ + do { \ + TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static inline void swapfunc(char* a, char* b, int n, int swaptype) +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b);\ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) +#define CMP(t, x, y) (cmp((t), (x), (y))) + +static inline char * med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk) +{ + return CMP(thunk, a, b) < 0 ? + (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a )) + :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c )); +} + +void recast_qsort(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + +loop: + SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; + pl > (char *)a && CMP(thunk, pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk); + pm = med3(pm - d, pm, pm + d, cmp, thunk); + pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk); + } + pm = med3(pl, pm, pn, cmp, thunk); + } + swap((char *)a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = CMP(thunk, pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; + pl > (char *)a && CMP(thunk, pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap((char *)a, pb - r, r); + r = min(pd - pc, pn - pd - es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > es) + recast_qsort(a, r / es, es, thunk, cmp); + if ((r = pd - pc) > es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +} + diff --git a/extern/recastnavigation/recast-capi.h b/extern/recastnavigation/recast-capi.h index 58fe08e6335..e8831bcdc58 100644 --- a/extern/recastnavigation/recast-capi.h +++ b/extern/recastnavigation/recast-capi.h @@ -28,6 +28,9 @@ #ifndef RECAST_C_API_H #define RECAST_C_API_H +// for size_t +#include <stddef.h> + #ifdef __cplusplus extern "C" { #endif @@ -69,16 +72,20 @@ void recast_filterLedgeSpans(const int walkableHeight, const int walkableClimb, void recast_filterWalkableLowHeightSpans(int walkableHeight, struct recast_heightfield *solid); +void recast_filterLowHangingWalkableObstacles(const int walkableClimb, struct recast_heightfield *solid); + struct recast_compactHeightfield *recast_newCompactHeightfield(void); void recast_destroyCompactHeightfield(struct recast_compactHeightfield *compactHeightfield); int recast_buildCompactHeightfield(const int walkableHeight, const int walkableClimb, - unsigned char flags, struct recast_heightfield *hf, struct recast_compactHeightfield *chf); + struct recast_heightfield *hf, struct recast_compactHeightfield *chf); + +int recast_erodeWalkableArea(int radius, struct recast_compactHeightfield *chf); int recast_buildDistanceField(struct recast_compactHeightfield *chf); -int recast_buildRegions(struct recast_compactHeightfield *chf, int walkableRadius, int borderSize, +int recast_buildRegions(struct recast_compactHeightfield *chf, int borderSize, int minRegionSize, int mergeRegionSize); /* Contour set */ @@ -119,7 +126,12 @@ float *recast_polyMeshDetailGetVerts(struct recast_polyMeshDetail *mesh, int *nv unsigned char *recast_polyMeshDetailGetTris(struct recast_polyMeshDetail *mesh, int *ntris); -unsigned short *recast_polyMeshDetailGetMeshes(struct recast_polyMeshDetail *mesh, int *nmeshes); +unsigned int *recast_polyMeshDetailGetMeshes(struct recast_polyMeshDetail *mesh, int *nmeshes); + +/* utility function: quick sort reentrant */ +typedef int recast_cmp_t(void *ctx, const void *a, const void *b); + +void recast_qsort(void *a, size_t n, size_t es, void *thunk, recast_cmp_t *cmp); #ifdef __cplusplus } diff --git a/intern/audaspace/intern/AUD_SequencerReader.cpp b/intern/audaspace/intern/AUD_SequencerReader.cpp index c468de19580..c8af1161530 100644 --- a/intern/audaspace/intern/AUD_SequencerReader.cpp +++ b/intern/audaspace/intern/AUD_SequencerReader.cpp @@ -132,8 +132,14 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer) while(eit != m_factory->m_entries.end()) { - handle = new AUD_SequencerHandle(*eit, m_device); - handles.push_front(handle); + try + { + handle = new AUD_SequencerHandle(*eit, m_device); + handles.push_front(handle); + } + catch(AUD_Exception&) + { + } eit++; } diff --git a/intern/elbeem/intern/ntl_world.cpp b/intern/elbeem/intern/ntl_world.cpp index 38b8cc3518c..42ee94b2cf5 100644 --- a/intern/elbeem/intern/ntl_world.cpp +++ b/intern/elbeem/intern/ntl_world.cpp @@ -216,7 +216,6 @@ void ntlWorld::finishWorldInit() } long stopTime = getTime(); - mSimulationTime += (*mpSims)[mFirstSim]->getStartTime(); debMsgStd("ntlWorld::ntlWorld",DM_MSG,"Time for start-sims:"<< getTimeString(stopTime-startTime) , 1); #ifndef NOGUI guiResetSimulationTimeRange( mSimulationTime ); diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript index 7869921ce02..ccf641eaee1 100644 --- a/intern/ghost/SConscript +++ b/intern/ghost/SConscript @@ -102,8 +102,8 @@ if window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-v if window_system in ('win32-vc', 'win64-vc'): env.BlenderLib ('bf_intern_ghost', sources, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15]) #, cc_compileflags=env['CCFLAGS'].append('/WX') ) -elif env['OURPLATFORM'] == 'darwin' and env['CC'].endswith('4.6.1'): # compile ghost always with apple-gcc to keep objectiveC compatibility - env.BlenderLib ('bf_intern_ghost', sources, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15], cc_compilerchange='/usr/bin/gcc-4.2', cxx_compilerchange='/usr/bin/gcc-4.2' ) #, cc_compileflags=env['CXXFLAGS'].append('-fobjc-exceptions') +elif env['OURPLATFORM'] == 'darwin': # always use Apple-gcc-4.2 for objC language, for gnu-compilers do not support it fully yet + env.BlenderLib ('bf_intern_ghost', sources, Split(incs), defines=defs, libtype=['intern','player'], priority = [40,15], cc_compilerchange='/usr/bin/gcc-4.2', cxx_compilerchange='/usr/bin/gcc-4.2' ) print "GHOST COCOA WILL BE COMPILED WITH APPLE GCC" else: diff --git a/po/POTFILES.in b/po/POTFILES.in index 4c791dd9369..30c1d91b572 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,6 +1,5 @@ release/scripts/modules/rna_prop_ui.py -release/scripts/startup/bl_operators/animsys_update.py release/scripts/startup/bl_operators/object.py release/scripts/startup/bl_operators/object_align.py release/scripts/startup/bl_operators/object_quick_effects.py diff --git a/po/README.txt b/po/README.txt new file mode 100644 index 00000000000..76dce7b414c --- /dev/null +++ b/po/README.txt @@ -0,0 +1,81 @@ +Blender translation HOWTO +========================= + +I'll try briefly explain how translation works and how to update translation files. + +1. How it works +--------------- + +This folder contains source files for translation system. This source files have +got .po extension and they've got pretty simple syntax: + +msgid "some message id" +msgstr "translation for this message" + +This means when string "some message id" is used as operator name, tooltip, menu +and so it'll be displayed on the screen as "translation for this message". +Pretty simple. + +This source files are pre-compiled into ../relese/bin/.blender/locale/<language>/LC_MESSAGES/blender.mo, +so they aren't getting compiled every time Blender is compiling to same some time and prevent +failure on systems which doesn't have needed tools for compiling .po files. + +2. How to update translations +----------------------------- + +It's also pretty simple. If you can find string you want to translate in <language>.po +file as msgid, just write correct msgstr string for it. If msgid is marked as fuzzy, +i.e. + +#, fuzzy +msgid "some message id" +msgstr "translation for this message" + +it means translation used to exist for this message, but message was changed, so translation +also have to be updated (it's easier to make new translation based on previos translation). +When translation was updated, remove line with '#, fuzzy' and it'll work. + +If there's no message in .po file you want to translate, probably .po file should be updated. +Use the following steps for this: +- With newly compiled blender run: + `blender --background --factory-startup --python update_msg.py` + to update messages.txt file (this file contains strings collected + automatically from RNA system and python UI scripts) +- Run update_pot.py script which will update blender.pot file. This file contains all + strings which should be transated. +- Run update_po.py script to merge all .po files with blender.pot (so all .po files + will contain all msgid-s declared in blender.pot) or update_po.py <language> to + update only needed .po file(s) to save time when you're busy with translation. + But before ocmmit all .po files better be updated. + +When you've finished with translation, you should re-compile .po file into .mo file. +It's also pretty simple: just run update_mo.py script to recompile all languages or +just update_mo.py <language> to re-compile only needed language(s). + +NOTE: msgfmt, msgmerge and xgettext tools should be available in your PATH. + +This steps to update template, translation files and compile them can be made in "batch" mode +using GNUMakefile: + +make -f GNUMakefile translations + +NOTE: Blender has to be compiled using GNUMakefile first. + + +3. Note for Windows users +------------------------- +You can find compiled builds of gettext in the lib folder under "binaries\gettext\" for both windows and win64. +In order to run the scripts you will need to replace the location of the GETTEXT_..._EXeCUTABLE. + +For example in update_pot.py: +-GETTEXT_XGETTEXT_EXECUTABLE = "xgettext" ++GETTEXT_XGETTEXT_EXECUTABLE = "C:\\Blender\\lib\\\windows\\\binaries\\\gettext\\xgettext.exe" + +4. Other scripts +---------------- + +- check_po.py: this script checks if all messages declared in blender.pot exists in.po files + and that no extra messages are declared in .po files +- clean_po.py: this script removes all commented messages which aren't required by .pot file anymore. +- merge_po.py: this scripts accepts two files as arguments and copies translations from second file + into first file. diff --git a/po/check_po.py b/po/check_po.py new file mode 100755 index 00000000000..a402c2b592c --- /dev/null +++ b/po/check_po.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python + +# $Id$ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +# <pep8 compliant> + +# update the pot file according the POTFILES.in + +import os +import sys +from codecs import open + +CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) + +FILE_NAME_POT = os.path.join(CURRENT_DIR, "blender.pot") + + +def read_messages(fname): + def stripeol(s): + return s.rstrip("\n\r") + + messages = {} + reading_message = False + message = "" + with open(fname, 'r', "utf-8") as handle: + while True: + line = handle.readline() + + if not line: + break + + line = stripeol(line) + if line.startswith("msgid"): + reading_message = True + message = line[7:-1] + elif line.startswith("msgstr"): + reading_message = False + messages[message] = True + elif reading_message: + message += line[1:-1] + return messages + + +def main(): + pot_messages = read_messages(FILE_NAME_POT) + + if len(sys.argv) > 1: + for lang in sys.argv[1:]: + po = os.path.join(CURRENT_DIR, lang + '.po') + + if os.path.exists(po): + po_messages = read_messages(po) + for msgid in po_messages: + if not pot_messages.get(msgid): + print('Unneeded message id \'%s\'' % (msgid)) + + for msgid in pot_messages: + if not po_messages.get(msgid): + print('Missed message id \'%s\'' % (msgid)) + else: + for po in os.listdir(CURRENT_DIR): + if po.endswith('.po'): + print('Processing %s...' % (po)) + po_messages = read_messages(po) + for msgid in po_messages: + if not pot_messages.get(msgid): + print(' Unneeded message id \'%s\'' % (msgid)) + + for msgid in pot_messages: + if not po_messages.get(msgid): + print(' Missed message id \'%s\'' % (msgid)) + + +if __name__ == "__main__": + print("\n\n *** Running %r *** \n" % __file__) + main() diff --git a/po/clean_po.py b/po/clean_po.py new file mode 100755 index 00000000000..2cbd2cb33ac --- /dev/null +++ b/po/clean_po.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python + +# $Id$ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +# <pep8 compliant> + +# update the pot file according the POTFILES.in + +import os +import sys +import collections + +from codecs import open + +CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) + +FILE_NAME_POT = os.path.join(CURRENT_DIR, "blender.pot") + + +def read_messages(fname): + def stripeol(s): + return s.rstrip("\n\r") + + last_message = None + + if hasattr(collections, 'OrderedDict'): + messages = collections.OrderedDict() + commented_messages = collections.OrderedDict() + else: + messages = {} + commented_messages = {} + + reading_message = False + reading_translation = False + commented = False + message = "" + translation = "" + message_lines = [] + translation_lines = [] + comment_lines = [] + with open(fname, 'r', "utf-8") as handle: + while True: + line = handle.readline() + + if not line: + break + + line = stripeol(line) + if line.startswith("msgid") or line.startswith("#~ msgid"): + if reading_translation: + last_message['translation'] = translation + translation_lines = [] + + reading_message = True + reading_translation = False + + if line.startswith('#~'): + message = line[10:-1] + commented = True + else: + message = line[7:-1] + commented = False + + message_lines.append(message) + elif line.startswith("msgstr") or line.startswith("#~ msgstr"): + reading_message = False + reading_translation = True + last_message = {'comment_lines': comment_lines, + 'message_lines': message_lines, + 'translation_lines': translation_lines} + + if commented: + translation = line[11:-1] + commented_messages[message] = last_message + else: + translation = line[8:-1] + messages[message] = last_message + + message_lines = [] + comment_lines = [] + translation_lines.append(translation) + elif not line.startswith('"') and not line.startswith('#~ "'): + if reading_translation: + last_message['translation'] = translation + else: + comment_lines.append(line) + + reading_message = False + reading_translation = False + message_lines = [] + translation_lines = [] + elif reading_message: + if line.startswith('#~ "'): + m = line[4:-1] + else: + m = line[1:-1] + + message += m + message_lines.append(m) + elif reading_translation: + if line.startswith('#~ "'): + t = line[4:-1] + else: + t = line[1:-1] + + translation += t + translation_lines.append(t) + + return (messages, commented_messages) + + +def do_clean(po, pot_messages): + po_messages, commented_messages = read_messages(po) + + for msgid in commented_messages: + if pot_messages.get(msgid): + t = po_messages.get(msgid) + if not t: + print(('Reusing full item from commented ' + \ + 'lines for msgid \'%s\'') % (msgid)) + po_messages[msgid] = commented_messages[msgid] + elif not t['translation']: + print(('Reusing translation from commented ' + \ + 'lines for msgid \'%s\'') % (msgid)) + m = commented_messages[msgid] + t['translation'] = m['translation'] + t['translation_lines'] = m['translation_lines'] + + with open(po, 'w', 'utf-8') as handle: + for msgid in po_messages: + item = po_messages[msgid] + + for x in item['comment_lines']: + handle.write(x + "\n") + + first = True + for x in item['message_lines']: + if first: + handle.write("msgid \"%s\"\n" % (x)) + else: + handle.write("\"%s\"\n" % (x)) + first = False + + first = True + for x in item['translation_lines']: + if first: + handle.write("msgstr \"%s\"\n" % (x)) + else: + handle.write("\"%s\"\n" % (x)) + first = False + + handle.write("\n") + + +def main(): + pot_messages, commented_messages = read_messages(FILE_NAME_POT) + + if len(sys.argv) > 1: + for lang in sys.argv[1:]: + po = os.path.join(CURRENT_DIR, lang + '.po') + + if os.path.exists(po): + do_clean(po, pot_messages) + else: + for po in os.listdir(CURRENT_DIR): + if po.endswith('.po'): + print('Processing %s...' % (po)) + do_clean(po, pot_messages) + + +if __name__ == "__main__": + print("\n\n *** Running %r *** \n" % __file__) + main() diff --git a/po/merge_po.py b/po/merge_po.py new file mode 100755 index 00000000000..b4a1ffa399e --- /dev/null +++ b/po/merge_po.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python + +# $Id$ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +# <pep8 compliant> + +# update the pot file according the POTFILES.in + +import os +import sys +import collections + +from codecs import open + + +def read_messages(fname): + def stripeol(s): + return s.rstrip("\n\r") + + last_message = None + + if hasattr(collections, 'OrderedDict'): + messages = collections.OrderedDict() + commented_messages = collections.OrderedDict() + else: + messages = {} + commented_messages = {} + + reading_message = False + reading_translation = False + commented = False + message = "" + translation = "" + message_lines = [] + translation_lines = [] + comment_lines = [] + with open(fname, 'r', "utf-8") as handle: + while True: + line = handle.readline() + + if not line: + break + + line = stripeol(line) + if line.startswith("msgid") or line.startswith("#~ msgid"): + if reading_translation: + last_message['translation'] = translation + translation_lines = [] + + reading_message = True + reading_translation = False + + if line.startswith('#~'): + message = line[10:-1] + commented = True + else: + message = line[7:-1] + commented = False + + message_lines.append(message) + elif line.startswith("msgstr") or line.startswith("#~ msgstr"): + reading_message = False + reading_translation = True + last_message = {'comment_lines': comment_lines, + 'message_lines': message_lines, + 'translation_lines': translation_lines} + + if commented: + translation = line[11:-1] + commented_messages[message] = last_message + else: + translation = line[8:-1] + messages[message] = last_message + + message_lines = [] + comment_lines = [] + translation_lines.append(translation) + elif not line.startswith('"') and not line.startswith('#~ "'): + if reading_translation: + last_message['translation'] = translation + else: + comment_lines.append(line) + + reading_message = False + reading_translation = False + message_lines = [] + translation_lines = [] + elif reading_message: + if line.startswith('#~ "'): + m = line[4:-1] + else: + m = line[1:-1] + + message += m + message_lines.append(m) + elif reading_translation: + if line.startswith('#~ "'): + t = line[4:-1] + else: + t = line[1:-1] + + translation += t + translation_lines.append(t) + + return (messages, commented_messages) + + +def main(): + if len(sys.argv) == 3: + dst_messages, tmp = read_messages(sys.argv[1]) + from_messages, tmp = read_messages(sys.argv[2]) + + for msgid in dst_messages: + msg = dst_messages.get(msgid) + from_msg = from_messages.get(msgid) + + if from_msg and from_msg['translation']: + msg['translation'] = from_msg['translation'] + msg['translation_lines'] = from_msg['translation_lines'] + + with open(sys.argv[1], 'w', 'utf-8') as handle: + for msgid in dst_messages: + item = dst_messages[msgid] + + for x in item['comment_lines']: + handle.write(x + "\n") + + first = True + for x in item['message_lines']: + if first: + handle.write("msgid \"%s\"\n" % (x)) + else: + handle.write("\"%s\"\n" % (x)) + first = False + + first = True + for x in item['translation_lines']: + if first: + handle.write("msgstr \"%s\"\n" % (x)) + else: + handle.write("\"%s\"\n" % (x)) + first = False + + handle.write("\n") + else: + print('Usage: %s <destination-po> <source-po>' % (sys.argv[0])) + + +if __name__ == "__main__": + print("\n\n *** Running %r *** \n" % __file__) + main() diff --git a/po/messages.txt b/po/messages.txt deleted file mode 100644 index b491061cdc4..00000000000 --- a/po/messages.txt +++ /dev/null @@ -1,5433 +0,0 @@ -The edited object -Bezier curve point with two handles defining a Keyframe on an F-Curve -Max Climb -Media Stop -System & OpenGL -Strips Selected -Active Keying Set -Action Blending -Bone is able to be selected -Defines where the color of the environment light comes from -Display files as short list -Build 75% proxy resolution -Right Mouse -Cubic Catmull-Rom -Particle system can be edited in particle mode -UV editor data for the image editor space -Editing hair -Zoom using opposite direction -Graph Editor space data -Create obstacle -Tiles -Align newly added objects to the world coordinates -Index of custom color set -Sample point for F-Curve -AVI Raw -Linear Drag -Color to display the marker with -Channels Region -Lower bound of envelope at this control-point -Fluid -Regions this area is subdivided in -Double Click -Disable simulation of linear motion along the X axis -Sequencer OpenGL -Child particles generated by the particle system -Point in a shape key for curves -Lock to Bone -Sun Size -Set modifier expanded in the user interface -Multiple Scattering -ID Name -Steering -Animation Visualisation -Keyed States -Fixed size vertex indices array -Normal Size -Track To -Time since last access of a GL texture in seconds after which it is freed. (Set to 0 to keep textures allocated.) -Collection of keymaps -Texture datablocks -Number of vertical pixels in the screen -Fluid Simulation -Zooms in and out like scaling the view, mouse movements relative to center -Lattice Edit -Snap onto its self (editmode) -Only render what's in front of the solid z values -True when multiple enums -Backdrop Zoom -Causes mesh data to be duplicated with the object -Automatic -Small Caps -UV Project -UV Sync Selection -Cloth dynamics for hair -File Browser Main -Sensitivity -Amount of rotation around side vector -Specify how many frames the Map Old will last -Start Still -Unique datablock ID name -Active pose marker for this Action -Draw Channels -Smoothens emitted smoke to avoid blockiness -Tool Settings -Text Line -Bone Constraints -Toggle whether the material is linked to object data or the object block -Falloff power for transmissivity filter effect (1.0 is linear) -Only use case sensitive matches of search string -Screw -Region Text -Representation of alpha information in the RGBA pixels -Edges receive a drag force from surrounding media -Sequence Transform -Over Drop -Domain Settings -New F-Curve Colors - XYZ to RGB -Space that owner is evaluated in -Frame Step -Enumeration -Value of the item -Parent of this pose bone -B-Bone Z size -Up Arrow -For reactor systems, the object that has the target particle system (empty if same object) -Shift key pressed -Auto Refresh -Bone Color Sets -Positive values make strands rounder, negative makes strands spiky -Collection of images -Show actuators of active object -interpolate a global timestamp using the record date and time written by recording device -Main Lattices -Variable from some source/target for driver relationship -Z Location -Auto-Clamped handle selected color -Fixed Alternate -Game engine sensor to detect events -Include the frame number in image metadata -Bone does not deform any geometry -UV Textures -Game -Minimal Spring length * Ball Size -16384 -Line in which the marker is located -Offset X -Rasterized cell height -Edge Threshold --Z -Set audio channels to mono -Jump Speed -HuffYUV -Active Bone -View3D Fly Modal -Sets the audio channel count -Rotation Damping -Max Air Acceleration -Snap center onto target -Spring Damping -Compact with Milliseconds -Maintain speed, flight level or wander -Interpolation type -Type Info -SIMD QBVH -active -Armature -Match case -16 Bit -XZY Rotation Order. Prone to Gimbal Lock -Auto handle selected color -Theme File Browser -Bake the normals in object space -Enable color range used for weight visualization in weight painting mode -Vorticity -Open window -Shows sensors for this object in the user interface -Radius of head of bone (for Envelope deform only) -Plain diffuse energy (white.) -Elasticity -Cache Step -View Sliders -Hair -Filter Movies -Material datablock used by this material slot -Smooth Emitter -Catalan (Català ) -RVO (cells) -Home -Action Mouse -Show Debug Info -Loads a saved environment map image from disk -is_baking -Scene datablocks -Wire -Group -On Land -Group Objects -Time Step -Keep UI -Bone inherits rotation or scale from parent bone -Show Selected Object -Theme settings for the Outliner -Time of key over the simulation -Header Text -Health -Similar to SMPTE (Compact), except that instead of frames, milliseconds are shown instead -Blender Original -Deliver texture UV pass -Index number of the vertex -Stepped Interpolation -Adds diagonal springs on 4-gons -Shear -Tent -Strength of force field -Space that target is evaluated in -F11 -Star -Library datablocks -Line Input -Lighten -In Range -Use Blender units for widths instead of pixels -F17 -Node Socket -Quad-Buffer -Sets scaling for the texture's X, Y and Z sizes -F14 -Motion Path settings for animation visualisation -Make hairs longer -Set audio sample format to 32 bit float -Amount of anti-aliasing samples per pixel -type -Use optimized Bullet DBVT tree for view frustum and occlusion culling -Make this surface a closed loop in the V direction -Alpha Over -Media player for video & png/jpeg/sgi image sequences -Second input for the effect strip -Space Logic Editor -Snap during transform -Edit Methods -Left Handle -B-Bone Ease Out -Cyclic Offset -Subtype -Object Base -Vertex Group Clump -Letterbox -Set audio channels to 7.1 surround sound -V -Quaternion (WXYZ) -Image File -Preset configs for external animation players -Maximum Value -Make this nurbs curve or surface act like a Bezier spline in the U direction (Order U must be 3 or 4, Cyclic U must be disabled) -uk_UA -3x3 bone matrix -Vertex Weight -Display Material -Use a custom transform orientation -GLSL Shaders -Text -Deliver shadow pass -From node -Keyframes -Main Brushes -Deliver diffuse pass -Header -Level detector, trigger controllers of new states(only applicable upon logic state transition) -Collision Compound -Increment -Trackball -Active Strip -Initial Rest Length -User defined layer of string text values -Edge Tag Mode -Invert tilt Axis -Deliver emission pass -Face Selected -Xor -Voronoi Crackle -Align the transformation axes to the window -Line sample -Default Goal (vertex target position) value, when no Vertex Group used -Type of raytrace accelerator structure -Area Spaces -Project individual elements on the surface of other objects -Use the angle between two bones -Aero -Zmask -Set audio sample format to 32 bit signed integer -Scene render size -Multiplier to convert blender units to physical distance -Free Image Textures -Metaball datablocks -DPI -Fill in Z values for solid faces in invisible layers, for masking -Active Action for this datablock -Use turntable style rotation in the viewport -Format -Use a Catmull-Rom filter for anti-aliasing -Link material to object or the object's data -Type of participation in the fluid simulation -face normal -Enable -Final 4x4 matrix after constraints and drivers are applied (object space) -Diameter of widget, in 10 pixel units -ID Property -Radius of tail of bone (for Envelope deform only) -Custom Shape Transform -Action FCurves -Envelope Deform Weight -A -Renders star shaped lines over halo -Fade-out Color -Syntax Built-in -Samples below this threshold will be considered fully shadowed/unshadowed and skipped (for Raytrace Adaptive QMC) -Camera datablocks -Bounding Box Center -Middle Mouse -Framerate base -Touch -Vortex -Manipulator Size -F-Curve Colors - XYZ to RGB -Invert Output -Calculate heights against unsubdivided low resolution mesh -Shrinkwrap -Window Deactivate -Y position of the sequence strip -The frame on which this sketch appears -Snap to increments of grid -Rest Length -All -Serbian (СÑпÑком ÑезикÑ) -Sample Method -Text Anti-aliasing -Only allows given density value in emitter area -Sequencer Preview Shading -Lower field first -File Name -Show timing in seconds not frames -Display the object as wire edges -Billboard with Z-axis constraint -Curves -Displays clock frequency of fullscreen display -X Rotation -Sphere -Select UVs that share mesh vertex, irrespective if they are in the same location -8 bit RAW -0.5 means no distance at all, 1.0 is maximum distance -Sequencer -Max Ghost Range -An object instance in a scene -User Interface -Alt -Vertex group name -PNG -Animated Selected -Blue -Damping of the spring force, when inside the physics distance area -Plugin Strip -Hide -Pose Matrix -Guide-free time from particle life's end -Frame is being edited (painted on) -Large Cursors -Limit Rotation -Draw only faces with the currently displayed image assigned -Record Run -Pixel width over which the reconstruction filter combines samples -Global Scene -Defines the structure of the header in the UI -Source List Text Highlight -User-editable keyframes -Scaling factor for action -Inner -Active Constraint -Side-by-side -Right Arrow -Causes the 1 to 0 keys to act as the numpad (useful for laptops) -A collection of pose channels, including settings for animating bones -Lennard-Jones -Use a maximum radial distance for the field to work -Location of tail end of the bone relative to armature -Edit All -estimate matrix .. split to COM , ROT ,SCALE -Use Coordinates -Theme User Preferences -Show line numbers next to the text -Minimum speed in air (relative to maximum speed) -Display keymap datablocks -, -Display Summary -Channel Driver (only set for Driver F-Curves) -Item -In/Out Node -Frame that modifier's influence ends (if Restrict Frame Range is in use) -Premultiplied -Number of frames cached -Description of the Struct's purpose -Tilt in 3D View -Show Debug -Offsets image horizontally from the world origin -region_data -Protect layer from further editing and/or frame changes -File Format -Retarget roll mode -IK rot control -Upper bound of envelope at this control-point -Interaction Radius -Syntax String -Vertex group to control density -Show Overexposed -Vertices -Kerning Style -IK X Minimum -Sets the factor by which the flare is larger than the halo -Absolute ball size or factor if not manual adjusted -Blend Opacity -Steps -Texture -Settings for the visualisation of motion -Group of vertices, used for armature deform and other purposes -Limit Distance -Minus -No interpolation, fast but blocky and low quality -Control -Full SMPTE timecode. Format is HH:MM:SS:FF -Open On Mouse Over -Show sensors of active object -Frame Server Port -Noise patterns will remain unchanged, faster and suitable for stills -Start -RLE (lossless) -True when the property is not saved in presets -Images are rendered in new Window -Theme Timeline -If this is set, the header gets a custom ID, otherwise it takes the name of the class used to define the panel. For example, if the class name is "OBJECT_HT_hello", and bl_idname is not set by the script, then bl_idname = "OBJECT_HT_hello" -The color that rays with no intersection within the Max Distance take (material color can be best for indoor scenes, sky color for outdoor) -Show Cursor -Goal Default -Shape Key Point -Object Origin Size -Orthographic -Invert y axis -Unit Scale -Collection of points for Bezier curves only -Mouse -Pivot Point -UV Layer to control billboard splitting -Only insert keyframes where they're needed in the relevant F-Curves -IK Z Minimum -Distance -Key rotation quaternion -Backscattered light -Texture effector weight -Volume rendering settings for a Material datablock -Which output node to use, for node-based textures -Handle 1 selection status -Always render a still frame from the voxel data sequence -Factor -+Z -Numpad 4 -Type -Action Groups -Styles -rv -Recast data for a Game datablock -Number of frames to show before the current frame (only for 'Around Current Frame' Onion-skinning method) -Description of the property for tooltips -Area in a subdivided screen, containing an editor -IK Z Maximum -Effect fader position -Particle System to render as points -Vertex Group Size Negate -Simplify Subdivision -Warp -3D View center is locked to this bone's position -Enable cluster collision between soft and rigid body -04 - Theme Color Set -Lamps -Color Picker Type -Location of the hair key in its internal coordinate system, relative to the emitting face -Properties Space -The view mode to use for displaying sequencer output -Hold -Prefetch Frames -Pose Tail Position -Amount of pixels to extend the baked result with, as post process filter -Dummy -Deliver full combined RGBA buffer -Long Key Selected -Extension -Complete Matches Only -Lines -The external source data file to use -The time (in minutes) to wait between automatic temporary saves -Undo Memory Size -Type of event mapping -Animation Data -Unique node identifier -Draw white edges -Show Menus -W -Inverse Kinematics -Number of times a map will be rendered recursively (mirror effects.) -Face Mask -Density is calculated as a factor of default density (depends on particle size) -Soft -Use a maximum distance for the field to work -Has IK -Power of Fresnel for transparency (Ray or ZTransp) -Name of PoseBone to use as target -Display files as thumbnails -Transparency blending mode -Multiple Engines -Bits -Active Boid Rule Index -Child Of -Metric -Proxy size 100% -Module name -Visible -NLA Strip references some Action -Average screen dimension of stars -Converter Node -Mirror -Method of calculating aerodynamic interaction -Curl -Main Objects -Only include channels relating to selected objects and data -Set audio mixing buffer size to 256 samples -Bake normals -Uses direction of strands as normal for tangent-shading -Textbox Width -Pose -Plasticity -Object scale factor -Boid effector weight -Mass Vertex Group -Fight -Adjust the offset to the beginning/end -Bone Solid -NLA Strip representing a sound event for speakers -Maximum contour edge length -Build free run time code index using Record Date/Time -End frame displayed in the sequence editor after offsets are applied -NLA Strip acts as a container for adjacent strips -Offsets image vertically from the world origin -Block anything else from using the cursor -Inverse Lift -Maximum for slider -Mode of automatic keyframe insertion for Objects and Bones (default setting used for new Scenes) -Render Solid faces in this Layer -Vertex Weight Edit -Rotation style in the viewport -Active Vertex Color Index -Show the active object's smoke cache -Action Extrapolation -Resolution X -Mesh -Progress Bar Widget Colors -Lock editing of rotation in the interface -Draw faces over the image -Press -Weight Color Range -Collection of vertex colors -Thickness of strokes (in pixels) -Resolution V -Particle Target -Object duplicate transformation matrix -Luma -Blend Out -B -B-Bone X size -Anti-Aliasing Level -Handle Vertex Size -IK Lin Weight -Negative -End Still -Y Offset -Edge -Amount of stickness to surface collision -Bone Matrix -Randomizes ring dimension and line location -Velocity -Respect the frame rate rather than rendering as many frames as possible -Distance to the view location -High res -Object to take point data from -Falloff type for proportional editing mode -Region width -Border Minimum Y -Flash Video -Active Section -Channel defining pose data for a bone in a Pose -Smoothed high quality interpolation, but slower -Sets the audio sample rate -Deliver raytraced refraction pass -Land Personal Space -Curve Splines -Operating system key pressed -14 - Theme Color Set -Grease pencil data for this space -Child particle interpolated from simulated or edited particles -Editor header containing UI elements -Select Head -Catmull-Rom -GLSL Nodes -Make edges 'sail' -Scattering -Wire Select -Unit -Bezier Points -Frame on which the simulation starts -Animation Player -Sequence Crop -Autoname -Dying -Floor -True when the property is hidden -Cache Compression -Keep Root -Render Output Directory -Multiple Caches -External Shadows -Points V -Show Debug Properties -White Level -Framing Color -Line Feed -Logarithmic dissolve -Circle -Show movie files -Maximum distance for the field to work -Vertex Group Kink -Enable anisotropic friction -Use color management for GLSL rendering -Exec Screen -Render Layer -Validity -Show sensors of all selected objects -Tessellation -- -F-Curve Modifier's effects will be tempered by a default factor -Paths Type -Cine-Scope 24fps 2048x858 -Use Mist -Object Duplicate Matrix -Repulsion force to apply on cloth when close to colliding -Marker is temporary -Collection of screens -Lock X Axis -Octree Resolution -Control how much mist density decreases with height -Custom Color Set -Texture Context -Active Vertex Group -Disallow movement around the Y axis -Edge Color -Datablocks -Channels of the image to draw -2D Cursor -Constant QMC -Shape Key Curve Point -Command output -turbulence_strength -Color used for active bones -3D View center is locked to this object's position -Vertex groups of the object -Weights for the vertex groups this vertex is member of -Invert Axes -Euler Rotation -Material to override all other materials in this render layer -Tag Sharp -Is part of an IK chain -Output image in JPEG format -Main Groups -Slider Min -Side -Bone -Square (HV + S) -Transforms include effects of parenting/restpose and constraints -Name of operator to call on input event -Particle Speed -Motion Blur -Nurb V-lines -Font size to use for displaying the text -Tools -Float -Dynamic -Scene -Color curve mapping to use for displaying the image -Set audio channels to 4 channels -Free handle color -16-bit Signed -Active object for this scene -Previous Angular Velocity -Material Link To -Solid Light -Property Value -Worldspace distance over which to blend in the surface normal -NLA Strip is active -Mini Axis Size -Multiply direct lighting with ambient occlusion, darkening the result -Moving things with a mouse drag confirms when releasing the button -Show Render -Camera this timeline sets to active -Update Automatically -Inwards component of the vortex force -Edit texture nodes from Brush -Current perspective matrix of the 3D region -Opaque -Goal (vertex target position) friction -All rules are averaged -Grease Pencil Stroke -Display Object Info -The maximum distance from which a boid can attack -Curve interpolation at this point: Bezier or vector -Both Z -Textbox Y Offset -Node group datablocks -Ogg Theora -Logic And -Identifier of operator to call on input event -Spaces contained in this area, the first being the active space. NOTE: Useful for example to restore a previously used 3d view space in a certain area to get the old view orientation -Set audio channels to stereo -Order V -View & Controls -Rec Run -Upward spring force, when inside the physics distance area -Mesh Texture Face Layer -Transformation orientation -Gives a radial field toward the center of object -layout -Extend -Collision margin for soft body. Small value makes the algorithm unstable -box radius -Cache Index -Free -Inbetween Move -Packed File -Capsule -UV projector used by the UV project modifier -F-Curve Modifier has invalid settings and will not be evaluated -Dopesheet -Only Selected -Replace Text -Freq -Sets maximum Y value for the render border -Compositing nodes -Waveform Opacity -Layers that contain something -Skip Save -Same Types -Include Missing NLA -Level -Free Unused Nodes -Maximum distance to apply repulsion force, must be greater then minimum distance -Display tooltips -Hold RMB Open Toolbox Delay -Random variation of friction -Proportional Editing Falloff -Object Modifiers -Logic Xnor -Move to center of neighbors and match their velocity -Stretch or squeeze the viewport to fill the display window -X -Show frame numbers of Keyframes on Motion Paths -Shaded -Enhance the resolution of smoke by this factor using noise -Backdrop -Selected -Refraction Exclude -Enable bitmap text on face -Button4 Mouse -The direction that the OpenGL light is shining -Images are rendered without forcing UI changes, optionally showing result -A circular Hue/Saturation color wheel, with Value slider -Input 3 -Input 2 -Input 1 -Engine to use for rendering -Active UV Texture Index -Include the render time in the stamp image -Disabled -Sets the amount mirror reflection for raytrace -Game Object Settings -Clear -Max Physics Steps -Find All -3D View far clipping distance -Activate or deactivate item -Blobby element in a MetaBall datablock -Only Render -Radius of the agent -Show Navigation Guide -Default Colors -Sets the dimension of the sub-flares, dots and circles -Dynamic Friction -fi_FI -Viewpoint Object -Display the object solid, lit with default OpenGL lights -Use Global Coordinates -Use the initial length as spring rest length instead of 2 * particle size -Priority -Render polygon transparent, depending on alpha channel of the texture -Active File -Manually determine the number of threads -User Defined -Vertex group to control clump -Enable/Disable Constraint -Object is detected by the Near and Radar sensor -VBOs -When false, this (sub)layout is greyed out -Select Mouse -The Drivers/Expressions for this datablock -Individual Centers -Enables automatic saving of preview images in the .blend file (Windows only) -Shape key in a shape keys datablock -Use left Mouse Button for selection -Pivot around the 3D cursor -Auto -Registered -Flares Sub -Short List -Sounds Directory -Interpolate -Game engine properties -Allow drawing multiple strokes at a time with Grease Pencil -Output image in (old!) SGI IRIS format -Left Alt -Sub Level Menu Open Delay -Number of frames at start of strip to fade in influence -Keyframe Points -Noise algorithm - Voronoi F3: Returns distance to the 3rd closest feature point -Display error text -Vertex group for fine control over structural stiffness -RNA Path (from ID-block) to property used -Info -User preferences space data -C -Emit Exclude -Thumbnails -Collision Sensor, detects static and dynamic objects but not the other collision sensor objects -Lamp Sky Settings -3D View center is locked to the cursor's position -Manoeuvre to avoid collisions with other boids and deflector objects in near future -Global gravity weight -Curve or Surface subdivisions per segment -The nominal number of game frames per second. Physics fixed timestep = 1/fps, independently of actual frame rate -Back scattering (-1.0) to Forward scattering (1.0) and the range in between -Library Path -Calculate shadows while rendering -Defines the strength of environment light -Mux packet size (byte) -Croatian (Hrvatski) -Separate Colors -Collider Friction -Goal minimum, vertex group weights are scaled to match this range -Gamma Cross -Driver for the value of a setting based on an external value -Unit System -Highlight Line -Constraint is the one being edited -Draw F-Curves using Anti-Aliasing and other fancy effects. Disable for better performance -Keying Set -UV Local View -Changing edges seam re-calculates UV unwrap -View3D Move Modal -Any Type -Image Paint -Set audio mixing buffer size to 16384 samples -Creates turbulence with a noise field -Active EditBone -Brush -Show only sensors connected to active states -Disable simulation of angular motion along the Z axis -3D View Generic -Shape used as a relative key -World Stars -Use Environment Lighting -X Location -Auto Save Temporary Files -Surface subdivisions per segment -Output image in OpenEXR format -Center -Air has normally some thickness which slows falling things down -Defines if the panel has to be open or collapsed at the time of its creation -Parameters for the function -Keep root keys unmodified -Interpolate new particles from the existing ones -Include visualization of Node related Animation data -25% -Sets the number of simulation substep per physic timestep, higher value give better physics precision -Space in which transforms are used -16x -Sets the number of images of a movie to use -Callback function defines for built-in Keying Sets -20 - Theme Color Set -How much heat effects smoke motion, higher value results in faster rising smoke -Display when not linked to a visible states controller -Collection of scenes -256 -Smooth View -Choose shading information to bake into the image -Sets the number of star shaped lines rendered over the halo -Textures -Active spline -Maximum bending stiffness value -Eye Separation -Window event timer -Armature EditBones -Game engine actuators to act on events -End frame of range of paths to display/calculate (not for 'Around Current Frame' Onion-skinning method) -Quad Split -Auto handles clamped to not overshoot -How much the spring has to be stretched/compressed in order to change it's rest length -Show Brush On Surface -. -Defines the structure of the panel in the UI -Handle 2 selected -Use lights for GLSL rendering -Groups -Textured -Camera rotation in horizontal axis -Blender RNA -Type of ID-block that can be used -Column number to show right margin at -Game Soft Body Settings -Activity Culling -Local Space -Sets the layer as active for rendering -Rotate From Normal -IK Y Lock -Amount of influence constraint will have on the final solution -The window relative horizontal location of the mouse -Set audio mixing buffer size to 2048 samples -Lighting Mode -Object to use as projector transform -Numpad - -Location to store the proxy files -Add directed noise to the density at render-time -Physics Sub Steps -Mesh Faces -Apply on spline -Armature Sketch -Render Halos in this Layer (on top of Solid) -Nla Strips -Weight used by the Bevel modifier -Color range used for weight visualization in weight painting mode -Boid Rules -Delay between repeated pulses(in logic tics, 0=no delay) -Billboard Time Index UV -Game Data -IK X Limit -Theora -Hook -Collection of materials -Lifetime mapped as 0.0 - 1.0 intensity -Property Editor -Vorbis -Allow Land -Tip select mode -Navigation Mesh -Limit the texture size to save graphics memory -Game engine user defined object property -Sticky vertex selection disabled -Display an isolated sub-set of objects, apart from the scene visibility -Straight Alpha -Wheel Out -Sequence Proxy -Text displayed and edited in this space -Custom Object -Numpad + -Menu -Active Point Cache Index -Starting frame of the stored range -Panel Style -Emphasize position of keyframes on Motion Paths -Libraries -Restrict Frame Range -Quadratic Drag -Display X Axis -Copy of the colors associated with the group's color set -Use a Mitchell-Netravali filter for anti-aliasing -ID of the item -Marker selection state -Good smoothness and speed -Use Onion Skinning -Draw type for drawing UV edges -id -Result strip replaces the accumulated results by amount specified by influence -Transform Space -Speed factor -Collection of group sockets -Highlight Keyframes -Hide files/datablocks that start with a dot(.*) -Use 3D transform manipulator -Value of shape key at the current frame -Python -Save tiles for all RenderLayers and SceneNodes to files in the temp directory (saves memory, required for Full Sample) -Perspective Matrix -Meta strip stack, last is currently edited meta strip -Noise algorithm - Voronoi F2: Returns distance to the 2nd closest feature point -Auto Keyframe Insert Keying Set -2D Cursor Location -Vertex Weight Mix -Group Index -Add hairs -Bake textures -Crop to Border -Initial boid health when born -When rendering animations, save JPG preview images in same directory -The number of grid lines to display in perspective view -Worlds -The distance between 3D View grid lines -Vector font datablocks -Tag Bevel -Negate the effect of the kink vertex group -Use viscoelastic springs instead of Hooke's springs -Frameserver Port for Frameserver Rendering -Shows actuators for this object in the user interface -Show Info -Grease Pencil Euclidean Distance -Pixels moved by mouse per axis when drawing stroke -Color balance parameters for a sequence strip -Collision Quality -Triple Buffer -Face is used for shadow -Include visualization of World related Animation data -Resolution of the voxel grid, low resolutions are faster, high resolutions use more memory -Regular Widget Colors -Y -Bezier Curve Point -To node -Puff Mode -Root -Deliver Z values pass -Coordinates of the control point -Transforms don't include parenting/restpose or constraints -Keying Set Path -Friction force if a collision happened. (higher = less movement) -Theme settings defining draw style and colors in the user interface -MPEG-4(divx) -Display reference images behind objects in the 3D View -Collection of Node Links -Follow Leader -Hide objects on these layers when generating the Environment Map -Line Number -Fields per Frame -Harmonic Damping -Weight hair particles -Use the Blender internal rendering engine for rendering -Rotation/Scaling Pivot -Minimum radial distance for the field's fall-off -Duration -Causes curve data to be duplicated with the object -Absolute -pt_BR -Active Layer -YCbCr (ITU 601) -Average distance between any two stars -Multitexture materials -GLSL -Current Scene -How many keys to make new particles with -Hide element -Main Meshes -Text character formatting settings -Main Material -Collection of object modifiers -Maximal resolution used in the fluid domain -Amount of light that gets emitted by the volume -Grid -Use For Growing Hair -Parent edit bone (in same Armature) -Use a column layout for toolbox -Sort by time -When transforming strips, changes to the animation data are flushed to other views -Theme settings for widget color sets -Inner Thickness -Keying Set defines specific paths/settings to be keyframed (i.e. is not reliant on context info) -Constant Jittered -Weight to assign in vertex groups -Bone Armature-Relative Matrix -Rest length of the harmonic force -user_preferences -Gimbal -Alpha Under -RNA property definition -YXZ Euler -Use shadows for GLSL rendering -IOR -Gives the flare extra strength -Editor menu containing buttons -Right handle selection status -Minimum Value -Action referenced by this strip -Display and edit the grease pencil freehand annotations overlay -Path edit mode -Smooth falloff -Preferences related to viewing data -Max Edge Error -A square showing Hue/Value, with Saturation slider -D -Material slot in an object -Set audio sample format to 8 bit unsigned integer -User defined integer number value in an integer properties layer -Output image to a frameserver -Single Layer -Radius of boids personal space in air (% of particle size) -YCbCr (Jpeg) -Length -Specular -Proportional Editing using connected geometry only -Convex Hull -Mid-range quality and speed -Scale of the added turbulent noise -Only use complete matches of search string -Show Splash -Wind -Repulsion Force -Method used to convert stroke to bones -Show Pose Markers -Frame on which the simulation stops -Warp Data -Key angular velocity -select_start -Show Linked to Controller -Struct in which this struct is always nested, and to which it logically belongs -Include a custom note in image metadata -Log conversion gamma -Transform Orientation -Number of CPU threads to use simultaneously while rendering (for multi-core/CPU systems) -Which style to use for font kerning -Fall-Off -Render voxels from a Blender smoke simulation -Draw the points which make up the strokes (for debugging purposes) -Frames -Original image height -Use face for collision and ray-sensor detection -Around Frame -Image Strip -Bounding Box -Device up/down directly controls your Z position -The Runge-Kutta ODE solver error limit, low value gives more precision, high values speed -Original image width -Show Margin -Transform Modal Map -Stiff Quads -System -Spherical Panoramic -Onion Skinning settings for animation visualisation -KeyMap Items -Valid -MP2 -Handle 2 Type -Italic -Material Raytrace Mirror -Object Grouped Active -Use Frame Rate -sv_SE -Samples -Name -Material mode to use for rendering -Cube -Result color of the volume, after other light has been scattered/absorbed -Use Min -Display the center and axis during rotation -Multiplier for intensity values -Render Edge-enhance in this Layer (only works for Solid faces) -Material datablocks -/ -Arabic (اÙعربÙØ©) -Most compact representation. Uses '+' as separator for sub-second frame numbers, with left and right truncation of the timecode as necessary -Filter 2D -Lift -Lighting for a World datablock -External -Collection of metaballs -Sets the hardness of the halo -General rotation damping -Constraint name -Hardness -Syntax highlight for scripting -Parameters and Settings for the Filebrowser -Edit Path -Rot Matrix -Global Time -Grease Pencil Manhattan Distance -Grouping Method -Lock view rotation in side views -Effector Group -Collection of armature edit bones -Flare -Control Point selected -Freehand curves defining the sketch on this frame -Make this nurbs surface act like a Bezier spline in the V direction (Order V must be 3 or 4, Cyclic V must be disabled) -Operator -Near -Use the pinned context -Display files as a detailed list -On Selected Bones Only -Has Reports -Property -Collection of related sketches -Control point mass values -Chance that the particle will pass through the mesh -Sticky Selection Mode -Font -Key Modifier -Clip -Edit texture nodes from Object -resolution_y -Storage of an operator being executed, or registered after execution -Image -Density Scale -Active Render Layer -Space DopeSheet Editor -Maximal -Indirect Factor -Pixel Filter -Upper field first -Static -AVI -Internal Friction -Global Hair -Level height -Bake Specular colors -DopeSheet space data -Registered Optionally -Causes actions to be duplicated with the object -Enable collisions with other objects -Theme settings for the Properties -Region ID -Strength -Use nodes for GLSL rendering -General Mass value -Damping Factor -Show Paint -Weight of a particle dupliobject in a group -Shows controllers for this object in the user interface -Allow the use of colors indicating constraints/keyed status -Target Object -Texture Paint -Defines how AO mixes with material shading -Driver Variable -Wrap words if there is not enough horizontal space -Point in a shape key for Bezier curves -Directory/name to save animations, # characters defines the position and length of frame numbers -Follow Path -Use a cubic filter for anti-aliasing -Media First -Use so the operator grabs the mouse focus, enables wrapping when continuous grab is enabled -Draw Frames -Length of rays, defines how far away other faces give occlusion effect -Lock Scale -Method of attenuating density by distance from the point -8-bit Unsigned -File Paths -Point Source -cs_CZ -Pose Space -Sort the file list alphabetically -Provides an alternative access to loc/scale/rotation relative to the parent and own rest bone -Collision Type -Collection of node trees -Occlusion Resolution -Apply sun effect on sky -Stamp Note Text -Traditional Chinese (ç¹é«ä¸æ) -Scene layers included in this render layer -Weight used by the Bevel modifier 'Only Vertices' option -IK Y Stiffness -The default directory to search for texture plugins -Vertex Group Velocity Negate -Modifiers -Invoke Region Window -Auto Perspective -Module -The clarity of the refraction. Values < 1.0 give diffuse, blurry refractions -Display Camera -Subdivisions -Blendfile Data -Location of custom proxy file -Solidify -Do a full redraw each time, slow, only use for reference or when all else fails -Horizon Spread -06 - Theme Color Set -Show a visualization of physics bounds and interactions -Z -Quick Cache -Show Error -Left -Property that stores arbitrary, user defined properties -UV 4 -Resolution % -Scattering color -UV 1 -UV 3 -UV 2 -Handle 2 -Display datablocks in visible layers -Handle 1 -Left handle selection status -Active Keying Set Index -SMPTE (Full) -Use textures to affect material properties -Draw Modified Edges -Maximum caused damage on attack per second -Shape Key -Enable file compression when saving .blend files -Script datablocks (DEPRECATED) -Frame rate for the screencast to be played back -MPEG-1 -Use Sketching Sessions -MP3 -Use ObColor instead of vertex colors -Lock X Rotation Axis -Envelope Tail Radius -Causes armature data to be duplicated with the object -The menu label -Allow Flight -Keyed timing -Free Run (rec date) -Use a 3D manipulator widget for controlling transforms -Insert Keyframes - Only Needed -Show handles of Bezier control points -Bone is not visible when it is not in Edit Mode (i.e. in Object or Pose Modes) -Inverse Quadratic -ru_RU -Use the value from some RNA property (Default) -Calculate point velocities automatically -Actions -Modifiers affecting all the F-Curves in the referenced Action -Enables automatic saving of preview images in the .blend file -Animation Player Preset -16 - Theme Color Set -Vector handle color -Proxy render size -Clip Max X -Clip Max Y -Open in thumbnail view for images and movies -Physics Engine -Description -Sort files by size -Particle Cache -Action Influence -Envelope -View Perspective -IK X Maximum -Boid States -Display datablocks of selected objects -Full Sample -Animation data for datablock -Channel -Interpolation mode used for first keyframe on newly added F-Curves. Subsequent keyframes take interpolation from preceeding keyframe -Order U -Timecode -Distance moved by mouse when drawing stroke (in pixels) to include -Calculate radiosity in a pre-process before rendering -Selected to Active -For RGB curves, the color that black is mapped to -Mesh Texture Face -E -For Pose-Mode drawing, only draw ghosts for selected bones -Landing Smoothness -Grease Pencil Frame -Shift -Mouse Move -Button 3 -Auto-detect -Space Timeline Editor -Only Selected Keyframes Handles -Use smoke density as texture data -Operator has a set of reports (warnings and errors) from last execution -Layered -Object Vertices -Set audio mixing buffer size to 512 samples -Duplicate Metaball -Saves this datablock even if it has no users -Cine-Scope 48fps 2048x858 -Ad-hoc correction for over-occlusion due to the approximation -Line Info -Filtering Group -Choose the method used to split a quad into 2 triangles for baking -Menu Item Colors -Blending factor for Fresnel -Constant -Mitchell-Netravali -Color -Button 8 -IK solver for which these parameters are defined, 0 for Legacy, 1 for iTaSC -Include visualization of Camera related Animation data -Free Run -Opacity of the points -Button 9 -Collection of speakers -Adaptive QMC -Layers the object base is on -NLA Generic -Sort by size -Friend -Velocity Min -The brightness of the icon -Show the active object's cloth point cache -Invoke Default -Amplification -Display warnings -Realtime -Size of the font used when rendering stamp text -Refraction -Third input for the effect strip -Snap to vertices -Global child particles percentage -Faces collide too, can be very slow -Disable collision for this object -Disable the time difference between fields -The default directory to search for loading fonts -Automatic keyframe insertion in available curves -Bake the normals in camera space -Show Header -layers -Color for all strokes in this layer -Top Level Menu Open Delay -Exec Area -Auto Render -Type of periodic offset on the curve -Key location -Use scaled and grid-fitted kerning distances -Stars setting for a World data-block -Burn -Set audio sample format to 24 bit signed integer -Standard -0 -Tag Crease -Image Sequence -Function is registered as callback as part of type registration -UV Layer to control billboard normals -Auto-Keying Mode -Bitrate -Back scattering weight -Select where rendered images will be displayed -The shape of the reflection, from 0.0 (circular) to 1.0 (fully stretched along the tangent -Gamma Corrected Color -AutoMerge Keyframes -Hold the first frame if no previous strips in track, and always hold last frame -Active PoseChannel constraint -Scene Bases -Vertex Colors -Collection of mesh faces -string -Live search filtering string -Sequencers active strip -Number of scene samples to take with motion blur -Vertex Group for pinning of vertices -Display libraries -The number of fields per rendered frame (2 fields is 1 image) -Allow any .blend file to run scripts automatically (unsafe with blend files from an untrusted source) -Frame of referenced Action to evaluate -Line Error -Plus -Coordinates -Roll CW -Envelope Control Point -Invert roll Axis -Source List Text -The file extension used for saving renders -Last selected element -Radial falloff power (real gravitational falloff = 2) -Face Normal -Fluid Simulation Settings -Disable or enable the render layer -Tap -Active Bone Group -Show render related properties -Number of vertical pixels in the rendered image -Child of this pose bone -Location of Center of mass -Show background image in back view -Max Land Acceleration -3D View -Snap to actual frames/seconds (nla-action time) -Two-side -Tag -Enables Anti-aliasing -Smoke domain settings -Tab -Default Closed -SPH Fluid Settings -Dome physical configurations -Theme settings for the User Preferences -Front-Truncated -Has the current session been saved to disk as a .blend file -12 - Theme Color Set -Box -Constraint modifying the transformation of objects and bones -Curve datablocks -Adjustment Layer -Velocity Scale -Field of View of the Dome - it only works in mode Fisheye and Truncated -Jitter -Audio Window -Use Grease Pencil -Filter Blender -Start frame displayed in the sequence editor after offsets are applied, setting this is equivalent to moving the handle, not the actual start frame -Create springs for this number of frames since particles birth (0 is always) -Label -Object this base links to -Apply channel rotation as IK constraint -PCM -Percentage -Render Sky in this Layer -Red -pl_PL -Datablock whose nodes are being edited -Draw user interface text anti-aliased -Head -Subdivide stroke in bones of specific length -Use the depth under the mouse to improve view pan/rotate/zoom functionality -Texture to use as force -RNA type definition -PIZ (lossless) -Bit depth per channel -Billboard Split UV -Pxr24 (lossy) -Region height -Heat -Particle select and display mode -Normalized -Mux Packet Size -Diameter in Pixels for Object/Lamp origin display -Distance between subsequent volume depth samples -Swap the Mouse Wheel zoom direction -Sequence editor space data -The context in which the panel belongs to. (TODO: explain the possible combinations bl_context/bl_region_type/bl_space_type) -Bake from Multires -Start size of strands in pixels or Blender units -Shape Key datablocks -Targa -Particle Instance -Bezier V -Multiplier to bring particle speed within an acceptable range -Collision Group -Limit effectors to this Group -Display datablocks of all objects of same type as selected object -The constraint is applied relative to the local coordinate system of the object, with the parent transformation added -Deliver normal pass -Location of tail end of the bone -The transformation of the target is evaluated relative to the world coordinate system -File Path -O -FLAC -UV Layer to control billboard time index (X-Y) -Blender Units -Vertex Group Tangent Negate -Set color of selected color stop -Pivot center for rotation/scaling -Set audio sample format to 16 bit signed integer -Zooms in and out based on horizontal mouse movement -Invert Zoom -Alpha Mode -bl_use_postprocess -Land Stick Force -Create empty placeholder files while rendering frames (similar to Unix 'touch') -Face Collision -Automatic keyframe insertion for Objects and Bones -Damp -Disable simulation of angular motion along the X axis -RNA Array Index -Unsigned Number -Output video in MPEG format -Dead -Text Widget Colors -Auto Save Time -Freehand curve defining part of a sketch -Header Text Highlight -Seed -True when the Ctrl key is held -Raytrace Acceleration Structure -Which direction is used to calculate the effector force -Addon Key Configuration -Data point for freehand stroke curve -Number of cone samples averaged for blurry reflections -F8 -Filter Sound -Mass of cloth material -Matrix -Action Group that this F-Curve belongs to -Subdivide stroke adaptively, with more subdivision in curvier parts -How many steps to draw the path with -Space Text Editor -Handle Vertex -Render face two-sided -Mist uses inverse quadratic progression -DV -Has Maximum -Skip Quad to Triangles -Number of times to repeat the action range -Maximum Distance -is_baked -Amount of damping during collision -F9 -8192 -X Offset -Image Pin -Accuracy of attack -Continuously unwrap the selected UV island while transforming pinned vertices -Collection of grease pencils -Gesture Border -Exclude raytraced reflection pass from combined -Choose normal space for baking -Boid state for boid physics -Occluder for optimizing scene rendering -Axis Angle -Field settings for an object in physics simulation -Rotation Mode -Active Spline -Buoyancy -Element of a curve, either Nurbs, Bezier or Polyline or a character with text objects -Start player with a visible mouse cursor -Bars -Armatures active edit bone -Breakdown -Color Mode -Diffuse -01 - Theme Color Set -Start position of the marker in the line -Consider objects as whole when finding volume center -Iris -Save Buffers -Time Scale -Split quads predictably (1,2,3) (1,3,0) -Constraint -Display Hidden -Receive shadows from sources outside the volume (temporary) -Required -Domain -Display Speaker -GLSL Ramps -Point data to use as renderable point density -Keyframe insertion only when keyframe needed -Audio Sample Rate -Area width -Time -Texture datablock used by this texture slot -Draw Waveform -DPX -Expression -Voxel data settings -Constraints -State Colors -Influence setting is controlled by an F-Curve rather than automatically determined -Number of frames between paths shown (not for 'On Keyframes' Onion-skinning method) -Set audio sampling rate to 48000 samples per second -Order of video fields. Select which lines get rendered first, to create smooth motion for TV output -Surface Diffuse -Magnetic -Stamp Background -Radius of the activity bubble, in Manhattan length. Objects outside the box are activity-culled -Show Warn -When bone has a parent, bone's head is struck to the parent's tail -Timer 0 -Timer 1 -Timer 2 -Display Y Axis -Frame player from IRIDAS -Children -Zoom To Mouse Position -Shadows -Use High Quality Drawing -Exclude emission pass from combined -Invert rotation axis -Plane -Drivers -Particle system in an object -Shader Nodes -Z-Buffer -Soft to Soft Body -Expanded in the user interface -After Current -Mix -Object Color -Fresnel -Main Cameras -Atmosphere Extinction -Use Indirect Lighting -Elastic Limit -Material Slot -Resolution of raytrace accelerator. Use higher resolutions for larger scenes -Falloff Power -Mesh Deform -Show influence curves on strips -Tweak timing for physics to control frequency and speed -IK X Stiffness -Theme settings for the File Browser -Images are saved with RGB (color) data -1 -Textured Fonts -Data type of the property -Gain -Scale X -Is Perspective -Metaball -IK Z Stiffness -B-Bone Display X Width -Space Console -Handle type for handles of new keyframes -Left Mouse -Macro -Average -Curve -Sketches for this layer on different frames -User interface layout in a panel or header -Error Tolerance -Axis of mouse movement to zoom in or out on -Disable auto (de)activation in physics simulation -Softness -Inherit Scale -Graph Editor -Method of shading, attenuating, and scattering light through the volume -View -Position Iterations -H.264 -Romanian (Român) -Still Frame Number -Extension Filter -Vertex Group Roughness End Negate -Specular Colors -Minimal Info -Face selection mode -Reflection Color -Node Editor -Proportional distance over which the light is diffused -Use Local Coords -Zmask Negate -Property that gives the name of the struct -Rotation in quaternions (keep normalized) -On Keyframes -Pulse False Level -Animated -Main Grease Pencils -Alpha Sort -Factor for ambient occlusion blending -Active vertex color index -Generator -Author -Restrict Animation Updates -Lock editing of four component rotations by components (instead of as Eulers) -NLA Track is evaluated itself (i.e. active Action and all other NLA Tracks in the same AnimData block are disabled) -The diffuse color of the OpenGL light -Do not calculate lighting and shadows -Max Sample Error -Cut -Starting distance of the mist, measured from the camera -Damping -Push an undo event (needed for operator redo) -White -Sets the strength of the add effect -Collection of lamps -Animation -Parent bone (in same Armature) -Environment Maps -Inputs -Direction -Max difference in heights of obstacles to enable their interaction -group -75% -Hide this curve in editmode -Deformed Location -Include visualization of Lattice related Animation data -Weighted result of strip is multiplied with the accumulated results -Cloth Settings -Sharp edge for the EdgeSplit modifier -Collection of groups -window -Preset -Theme Outliner -Fast Navigate -Draw Smooth Edges -Collection of curves -Star Tips -NLA Evaluation Enabled -3D Cursor Location -Spline Bezier Points -Stereo -Page Up -Negate the effect of the field vertex group -Collide All -Items Expanded -Marker for noting points in the timeline -Z Direction -Causes lamp data to be duplicated with the object -Scene Strip -Boid state name -Simulation value to be used as a texture -64-bit Float -Domain Object -Right -Shape of clumping -XZY Euler -Group Sockets -Individual pose bones for the armature -Min Step -Manipulator Scale -Main Armatures -Die Time -Number of frames to show after the current frame (only for 'Around Current Frame' Onion-skinning method) -Placeholders -name -Unfitted -Minimum regions size. Smaller regions will be merged -Mesh Selection Mode -Method to draw in the sequencer view -Mute -Down Arrow -Render Strands in this Layer -Child Particles -Duplicate Action -IK Param -Main Images -Weight for cloth simulation -Index number of the vertex group -Collection of NLA Tracks -Sequence strip data for a single frame -Sculpt/Paint Use Unified Strength -Audio Mixing Buffer -ID-block that the specific property used can be found from (id_type property must be set first) -Linear physics -Use Collision Bounds -Passes -Noise algorithm - Original Perlin: Smooth interpolated noise -Additive -Handle 2 selection status -Trigger controllers only for an instant, even while the sensor remains true -Loose edge -Edit animation/keyframes displayed as 2D curves -Sculpt/Paint Use Unified Radius -Index to the specific property affected by F-Curve if applicable -Main Window Managers -Unit to use for displaying/editing rotation values -Editmode bone in an Armature datablock -Bending Stiffness Maximum -Selection state of the curve point -Enable pinning of cloth vertices to other objects/positions -Shared -Zoom = Up/Down -NLA Strips -Text to search for with the find tool -Use a DCI Standard preset for saving jpeg2000 -Blend Mode -Space Sequence Editor -Textures Directory -Bone is always drawn as Wireframe regardless of viewport draw mode. Useful for non-obstructive custom bone shapes -Include the name of the active scene in image metadata -F-Curve Name Filter -Time in 1/10 seconds to hold the Right Mouse Button before opening the toolbox -pin_id -Fluid interaction radius -NLA Strip 'transitions' between adjacent strips -Editable -Emission -Template armature that will be retargeted to the stroke -Selection status -Texture slot defining the mapping and influence of a texture -Connected -Key -Align the transformation axes to world space -Transform parameters for a sequence strip -Layer Opacity -Use the Bullet physics engine -Method for generating shadow samples (for Raytrace) -Effect particles' dynamic rotation -Show options for whether channels related to certain types of data are included -G -Collection of group objects -Make hairs shorter -Show properties marked for debugging while the game runs -Invert x axis -Greek (Îλληνικά) -Smooth -Sync view position between side views -Used Layers -Active File Text -F18 -F19 -Force effector weight -The distance over which the mist effect fades in -Edge Select -F12 -F13 -F10 -Display Meshes -F16 -Options -Grease Pencil datablocks -F15 -Output video in AVI JPEG format -Sky Color -blend_data -Temporary Directory -Current rendering engine is a game engine -100% -Vertex Group Roughness 2 -IK Rot Weight -Handle Type -Bevel Weight -F-Curve Modifier Type -int -No Sleeping -Save TIFF with 16 bits per channel -ID Property Group -Island selection mode -Collection of texts -Edges collide too -512 -Sets minimum Y value for the render border -Mouse X Position -Active screen showing in the window -Stamp Note -Number of horizontal tiles to use while rendering -Tilt -Child Particle -Action Start Frame -Media Last -Pass in multilayer image -Back Space -Outflow -Active Boid State Index -Enable cluster collision between soft and soft body -Instance support leads to effective memory reduction when using duplicates -Xvid -Realtime display of a modifier -Sets the layer as active for display and editing -Wireframe -Grease Pencil Eraser Radius -Accurate, but slow when noise-free results are required -Syntax Special -Repeat -Global undo works by keeping a full copy of the file itself in memory, so takes extra memory -Strength of noise -Vertical -Separate -Self Friction -Snap median onto target -Area -Falloff -REC709 -Smooth the normals of the surface or beveled curve -2D View Minimum Grid Spacing -Font Style -Image datablocks -3D region in this space, in case of quad view the camera region -Sound datablocks -Auto Velocity -Data -Bake the normals in world space -Lock Camera and Layers -Vertex group to control rotation -Global -Sun Brightness -Optional custom node label -Align to Normal -Directory displayed in the file browser -Deliver speed vector pass -Enabled -Frame player from Tweak Software -Weighted result of strip is removed from the accumulated results -A animation layer containing Actions referenced as NLA strips -Key configuration that can be extended by addons, and is added to the active configuration when handling events -Dominant -Line Output -Seam edge for UV unwrapping -Options for this panel type -Menu Widget Colors -Main Worlds -Shadowed -11 -Atmosphere -Create representation for obstacle simulation -Estimated rotation matrix -16 -Pose -Sun size -NodeTree -RGB -2048 -Anaglyph -Active Object -Collection of curve splines -Marker highlighting a portion of text in a Text datablock -DopeSheet -Magnetic effector weight -Render face transparent and add color of face -Previous Rotation -Display Shapekeys -Aggression -en_US -Color space to use for internal XYZ->RGB color conversion -Numpad 7 -Sets the maximum number of physics step per game frame if graphics slows down the game, higher value allows physics to keep up with realtime -Keying Sets All -Boid -Numpad 6 -Snap Element -it_IT -Include the name of the foreground sequence strip in image metadata -Metaballs -Active particle system being displayed -Toggle between moving the viewpoint or moving the scene being viewed -Use a Gaussian filter for anti-aliasing -ChannelDriver Variables -MetaBall -Combined -FFmpeg video codec #1 -Use Default Fade -Numpad 3 -ZXY Rotation Order. Prone to Gimbal Lock -Index to the specific setting if applicable -Bake Mirror values -Use vBVH -Apply channel size as IK constraint if stretching is enabled -Invert Zoom Direction -Numpad 1 -Edge Sharp -Unit Settings -Stamp Frame -Brush datablocks -use global timestamp written by recording device -Mapping -Snap active onto target -Rigid Body Joint -Rate control: buffer size (kb) -Scale factor along the Y for items in this (sub)layout -RGBA -Half -Sets the number of rings rendered over the halo -Turbulence -Graph Editor instance has some ghost curves stored -Halo -No display -Stiffness Scaling -Use a custom falloff curve -Contents Follow Opening Direction -Off -Seam -Sculpt -Sequences -Stiff viscosity is a factor of normal viscosity -Curve Guide -Proportional Editing disabled -Rotate Around Selection -Key Maps -Minimum -Align newly added objects facing the active 3D View direction -Tool Properties -Amount of noise for the force strength -Amount of ray samples. Higher values give smoother results and longer rendering times -Numpad 8 -] -Exclude specular pass from combined -Stamp Scene -Collection of grease pencil layers -Choose Collision Type -Amount to blend in the material's diffuse color in raytraced transparency (simulating absorption) -Particle system has been edited in particle mode -Stroke conversion method -Properties acting as inputs for this driver -Point Cache -Window Manager Event -Collection of brushes -Don't use a physics engine -Material Override -Temperature difference to ambient temperature -State determining which controllers are displayed -All Object Origins -Uses extreme alpha -Node Tree -Before Current -Array -Collision settings for object in physics simulation -Stretch To -F-Curves for controlling the strip's influence and timing -Field Order -Hide Dot Files/Datablocks -Loose -Use Game Engine -Onion Skinning (ghosting) settings for visualisation -Draw dashed black-white edges -Align handle selected color -Minimum number of pixels between each gridline in 2D Viewports -Sky -Spring Frames -Location of head end of the bone -Active key configuration (preset) -Width -Action Group is selected -Collection of Texture Nodes -Collection of add-ons -States which are being used by controllers -Gravity or external force vector -NLA Track is active -Ogg -Roll -Grless -Wheel Down -Amount of friction during particle collision -Search in all text datablocks, instead of only the active one -View pivot location -Draw image with RGB colors and alpha transparency -Resolution -Use the scene's active camera and layers in this view, rather than local layers -Every point is effected by multiple springs -Vertex -Include the filename of the .blend file in image metadata -Maximum distance error from contour to cells -Output video in H.264 format -Action displayed and edited in this space -History -Local View -Stamp Text Color -Translation -IK Y Maximum -File Select Parameters -Shared Vertex -Safe Margin -Tip Size -Edge color -Negate the effect of the size vertex group -Game engine controllers to process events, connecting sensor to actuators -Triangle Mesh -NLA Strip is played back in reverse order (only when timing is automatically determined) -Scale Y -H -Main Lamps -Approximate -Controllers -Deliver specular pass -The number of old versions to maintain in the current directory, when manually saving -Theme settings for the NLA Editor -Nearest Marker -Randomize star colors -Theme settings for the Sequence Editor -Index of refraction (higher values are denser) -Local Location -Default Key Configuration -Show background image while looking to the right -The space where the header is going to be used in -Max number of vertices per polygon -Quality of JPEG images, AVI Jpeg and SGI movies, Compression for PNG's -Averaged Value -Use a box filter for anti-aliasing -Spin CCW -Color to use for stamp text -Wheel Invert Zoom -Lock Camera to View -New Interpolation Type -Main data structure representing a .blend file and all its datablocks -Calculate bone paths from heads -Layer of vertex colors in a Mesh datablock -Is this keymap item user defined (doesn't just replace a builtin item) -Main Textures -Enable soft body shape matching goal -How many self collision iterations should be done. (higher is better quality but slower) -Collection of scene bases -Show right margin -Ambient Occlusion -Frame this control-point occurs on -Snap to edges -Turbulence effector weight -Build record run time code index -float -Use Edges as springs -Rings -Color Ramp Elements -Charge -Thickness -Zmask Layers -The panel label, shows up in the panel header at the right of the triangle used to collapse the panel -Spread -Cluster Iterations -Location -Weight Paint -15 - Theme Color Set -space_data -Vertex group to control kink -If this is set, the menu gets a custom ID, otherwise it takes the name of the class used to define the panel. For example, if the class name is "OBJECT_MT_hello", and bl_idname is not set by the script, then bl_idname = "OBJECT_MT_hello" -Path is being edited -ShapeKey Editor -AC3 -Set audio channels to 5.1 surround sound -Minimum Size -Path to a custom animation/frame sequence player -Smoke inherits it's velocity from the emitter particle -Display Lists -Maximum number of frames on either side of the active frame to show (0 = show the 'first' available sketch on either side) -Compress File -Bezier U -Displace -Velocity Max -Use Right Mouse Button for selection -Box Backdrop Colors -Exec Default -3 -Path point is selected for editing -Bone Group -When calculating Bone Paths, use Head or Tips -Project Individual Elements -Parameters for IK solver -Show the object origin center dot for all (selected and unselected) objects -BLI BVH -Realtime Updates -Shutter -How strongly the fluid tries to keep from clustering (factor of stiffness) -Target -Scrollbar -Show controllers of all selected objects -Instead of per brush radius, the radius is shared across brushes -screen -Use large mouse cursors when available -Keymap is defined by the user -Grease Pencil Stroke Point -48 kHz -Use the manipulator for rotation transformations -Bullet -Armature Bones -Directory -TimeCode Style -Identifier -Does full Sky texture render for diffuse energy -Items in the keymap, linking an operator to an input event -AvMinMax -Multiply the current speed of the sequence with this number or remap current frame to this frame -Apply force only in 2d -MPEG -Is this keymap item modified by the user -Zoom in towards the mouse pointer's position in the 3D view, rather than the 2D window center -How smoothly the boids land -region -Swedish (Svenska) -Region in a subdivided screen area -Add indirect light bouncing of surrounding objects -Factor Radius -Obstacle -Color used for selected bones -Line Numbers -Draw edges after modifiers are applied -Space Info -Multicam Selector -Reflection Exclude -Weight of scale constraint for IK -Node editor space data -Link between nodes in a node tree -Show the entire viewport in the display window, viewing more horizontally or vertically -Pixel distance around the handles to accept mouse clicks -Initial State -Sum Values -Channel Group -Tools can use this to tag data, (initial state is undefined) -The default directory to search for textures -Lin error -F-Curve is selected for editing -Keying Sets -Release confirms -64 -Title for the file browser -Sets the audio sample format -Invert y Axis -Include the name of the last marker in image metadata -Collection of keyframe points -3D View space data -Vortex effector weight -Object adds fluid to the simulation -Use smoke velocity as texture data -Maximum Radial Distance -The axis to display the image on -Keying set options -Horizon Brightness -Render Engine -Display Particle -Exclude AO pass from combined -Lights user to display objects in solid draw mode -Textbox Height -Point coordinates -Axis Angle (W+XYZ). Defines a rotation around some axis defined by 3D-Vector -Text Editor -Use display lists to speed up rendering by keeping geometry on the GPU -Actuators -Make this nurbs curve or surface meet the endpoints in the U direction (Cyclic U must be disabled) -es_ES -Auto Run Python Scripts -Subtract -Screen Editing -Properties in the struct -Set audio sampling rate to 96000 samples per second -Scale to use when converting between blender units and dimensions -Mouse/Trackpad Zoom -X Ray -Maximum distance of reflected rays (reflections further than this range fade to sky color or material color) -True when this property is an output value from an RNA function -False when F-Curve could not be evaluated in past, so should be skipped when evaluating -Fresnel Factor -Minimum for slider -Use Goal -Sets how the texture is extrapolated past its original bounds -Minimum size of strands in pixels -Points -Motion Path -Emission Color -Global maximum shadow samples -Path -Action -Sets the number of sub-flares -Used State -Update other affected window spaces automatically to reflect changes during interactive operations such as transform -Filter Script -Method to interpolate/smooth values between voxel cells -Gives halo a texture -Show markers belonging to the active action instead of Scene markers (Action and Shape Key Editors only) -Divide -Proportional Editing mode, allows transforms with distance fall-off -Angular distortion between UV and 3D angles -Random variation of damping -Channels Selected -plugin -Spline IK -The frame on which the timeline marker appears -Snap to 1.0 frame/second intervals -Handle 1 selected -Free all image texture from memory after render, to save memory before compositing -Method used for combining Active Action's result with result of NLA stack -If enabled, stiffness can be scaled along a weight painted vertex group -Invert z Axis -Minimum regions size. Smaller regions will be deleted -Display Mode -Text bounding box for layout -Onion Skinning -Open -User Add-Ons -Output file format -Size -Backdrop X offset -Active Pose Marker Index -Text Marker -Number of preprocessing passes to reduce overocclusion -Modifiers affecting the shape of the F-Curve -Wheel In -Mesh Face -Rotation Angle -Path to a setting for use in a Keying Set -Sync Markers with keyframe edits -Whether to use minimum clipping value -Main Actions -Editing context being displayed -Raytraced refraction settings for a Material datablock -Enable image painting mode -Hidden -When adding objects from a 3D View menu, either align them to that view's direction or the world coordinates -Only show and edit handles of selected keyframes -Cinema 48fps 2048x1080 -Max Rate -Envelope Head Radius -Use old Octree structure -Global maximum subdivision level -Use this object's coordinate system instead of global coordinate system -Viscosity -Theme Properties -Boolean Property -UV Selection Mode -Force the curve view to fit a defined boundary -Objects -Default (Default) -Shade Down -Grease Pencil Layers -Current Keying Set index -Shadow Exclude -Root Size -Rest Shade Key -Framerate, expressed in frames per second -Scrollback -Overlay Lock -Duplicate Text -Russian (Ð ÑÑÑкий) -10 - Theme Color Set -Collection of texture slots -ID Materials -I -The distance from which particles are affected fully -Action Pose Markers -Clamp velocity to this maximum speed -English (English) -JPEG -L -Display only files with extensions in the image select window -Theme Sequence Editor -ID From -All Scenes -Make hairs longer or shorter -Handle Vertex Select -With displacement normalize to the distance, with ambient occlusion normalize without using material settings -Physics -ID -Mesh Vertex Color Layer -Use curve weights to influence the particle influence along the curve -Cached location on path -Motion -Node tree being displayed and edited -Tangent Shading -Mesh Vertex Color -B-Spline -Based on distance/falloff it adds a portion of the entire path -Theme settings for the Audio Window -Displacement -Coordinates of the second handle -Rendering settings for a Scene datablock -Radius of boids personal space on land (% of particle size) -Live Edit -The length of the contents of this strip before the handles are applied -Display Armature -Length Mode -Display datablocks of active object -SDL -Collection of Nla Strips -Amount the Active Action contributes to the result of the NLA stack -Show only actuators connected to active states -Vertex group for fine control over bending stiffness -4 Channels -Bake displacement -Acceleration -Angular Velocity -Boid Rule -Action Group -Split quads predictably (0,1,2) (0,2,3) -Struct definition this is derived from -Include the current date in image metadata -Action Group is expanded -Draw title safe margins in preview -Output image in DPX format -Include visualization of Object-level Animation data (mostly Transforms) -Proxy size 25% -16 bit color channels -The default directory to search for sounds -Log -Redraw all overlapping regions, minimal memory usage but more redraws -International Fonts -5.1 Surround -Linear -Settings that should be keyframed together -Factor Repulsion -Overlap Flip -The active face for this mesh -Turn on SB diagnose console prints -Dome -Brazilian Portuguese (Português do Brasil) -Make hairs stand up -Uses the vertex normal to specify the dimension of the halo -Key maps configured as part of this configuration -Active Space -4 -Theme Text Editor -Method to display/shade objects in the 3D View -Make this nurbs surface meet the endpoints in the V direction (Cyclic V must be disabled) -Normalized Coordinates -Glow -Diffusion -Enemy -Co-ordinate system to cache vertices in -Show state panel -Show ghosts on keyframes -Anti-Aliasing -Zoom Axis -Reactor Target Particle System -First input for the effect strip -Radians -Free Nodes that are not used while compositing, to save memory -Transform -Free handle selected color -Maximum depth for light to travel through the transparent material before becoming fully filtered (0.0 is disabled) -Button 10 -Amplitude -Show Active States -Space Nla Editor -Vertex group to control length -In text window, paste with middle mouse button instead of panning -Collection of object constraints -Transparent RGB pixels are multiplied by the alpha channel -Calculates environment map at each rendering -Deform -Choose BW for saving greyscale images, RGB for saving red, green and blue channels, AND RGBA for saving red, green, blue + alpha channels -Tweak Right -44.1 kHz -Include visualization of Texture related Animation data -Set layer Visibility -Deliver mist factor pass (0.0-1.0) -Sort files by modification time -Minimal # solver steps/frame -Have recent edits been saved to disk -Keying Set Paths to define settings that get keyframed together -Pressure of tablet at point when drawing it -Show background image while looking to the left -Sharp -Only include F-Curves with names containing search text -Number of spaces to display tabs with -Puff Volume -Video bitrate(kb/s) -Linear Stiffness -Vertex Group Tangent -Amount of dithering noise added to the rendered image to break up banding -Absorption -Find Wrap -Enable hair dynamics using cloth simulation -The type of the Sequencer view (sequencer, preview or both) -Number Widget Colors -File Extensions -Theme Node Editor -Object Duplicate -Goal Maximum -Size of element, use of components depends on element type -Word Wrap -Any -More than one rendering engine is available -Cached positions per frame -Control key pressed -Collection of armatures -Gloss Anisotropy -Tracking by taking the shortest path -Spherical falloff -Objects further than this are not visible to map -Driver could not be evaluated in past, so should be skipped -Insert Keyframes - Visual -Rule Evaluation -Negate the effect of the velocity vertex group -The frame number to always use -ca_AD -Visibility -Bone associated with this PoseBone -Envelope Deform Distance -Invoke Area -Theme Info -Current Keying Set index (negative for 'builtin' and positive for 'absolute') -Black -Lock editing of location in the interface -Interface -Auto Keying Enable -Save luminance-chrominance-chrominance channels instead of RGB colors -Left Ctrl -Multiplier to adjust velocity passed to smoke -Font size and resolution for display -Extreme -Show Controllers -Render engine -Render image to two fields per frame, for interlaced TV output -To socket -Activate TRUE level triggering (pulse mode) -Temp. Diff. -Expanded -Target particle system -Which part to snap onto the target -local space unit length normal vector for this face -Keying Set Name -Python Console -Show Hidden -The region relative horizontal location of the mouse -Nurb active V-lines -Set position of selected color stop -Fixed size UV coordinates array -Reactor Target Object -Node tree type to display and edit -Display datablocks in current scene -Color and Alpha -Causes texture data to be duplicated with the object -Item in a Key Map -3D View region data -Display face-assigned textures in solid view -Disable simulation of linear motion along the Z axis -Point of a curve used for a curve mapping -Include visualization of Metaball related Animation data -Structural Stiffness Maximum -Factor Density -Simple Deform -The default color for textures that don't return RGB or when RGB to intensity is enabled -Name of UV unwrapping layer -Outputs -Images -Message -Ray -Theme Bone Color Set -Redraw all overlapping regions, minimal memory usage but more redraws (for graphics drivers that do flipping) -IK stiffness around the Y axis -Edge spring stiffness when shorter than rest length -Menu Backdrop Colors -50% -Heads -Stereo Mode -Soft body simulation settings for an object in the game engine -Show Framerate and Profile -Right Shift -Direct conversion of frame numbers to seconds -Log conversion reference whitepoint -Radius -Linear stiffness of the soft body links -View3D Rotate Modal -SMPTE -Add -Show framerate and profiling information while the game runs -Degrees -Gather Method -Output -Set audio sampling rate to 192000 samples per second -End -Include visualization of Material related Animation data -Sets the layer as active for cloning -Save for every anti-aliasing sample the entire RenderLayer results. This solves anti-aliasing issues with compositing -When bone doesn't have a parent, it receives cyclic offset effects -Enable self collisions -Property is registered as part of type registration -Syntax Comment -Draw Particles -area -Basis Matrix -Active vertex color layer -Image and UV editor space data -Set metaball as negative one -Collection -JPEG Quality of proxies to build -Zbuf -Show the Z axis line in perspective view -Tails -Show Active Object -Defines size of derivative offset used for calculating gradient and curl -Color Set -Integer -Output image in bitmap format -OpenAL -Particle Systems -Display the user preference datablocks -Size of packed file in bytes -Ukrainian (УкÑаÑнÑÑкий) -Mono -No proxy, full render -Fullscreen -Allow scaling of the bone for IK -Creates viscosity for expanding fluid) -J -Blend mode for combining sun sky with world sky -Global Undo -Quicktime -Draw frames rather than seconds -Bake shading on the surface of selected objects to the active object -Frame currently being displayed for this layer -Never None -alignment -Bulgarian (ÐÑлгаÑÑки) -Light -Maximal Spring length * Ball Size -Emulates Middle Mouse with Alt+Left Mouse (doesn't work with Left Mouse Select option) -Text datablocks -Welding -Heavy -Quick Sketching -Method used to determine color of F-Curve in Graph Editor -Show UV Editor -Cut hairs -Expand -Effect particles' location -View Matrix -Allow boids to climb goal objects -Sequence -Bone Name -Seed of the noise -Motion Path Cache Point -Use modifier while in the edit mode -Meshes -For reactor systems, index of particle system on the target object -Billboard -Automatically set based on graphics card and driver -Macro Operator -DopeSheet Channel -Render and combine multiple samples per pixel to prevent jagged edges -Render Z-Transparent faces in this Layer (On top of Solid and Halos) -Output image in uncompressed Targa format -Paths -Left Arrow -Collection of spline bezirt points -Layout -Show Physics Visualization -Number of bones in the subdivided stroke -Vertex Group Clump Negate -Negate the effect of the tangent vertex group -Base type for IK solver parameters -Active camera used in this view (when unlocked from the scene's active camera) -Re-render and composite changed layer on 3D edits -ISO 2 -Active Layer Index -Esc -Show Frame Number Indicator -End Offset -Use active Viewer Node output as backdrop for compositing nodes -Blender command line animation playback - path to Blender 2.4 -Frequency -Pivot around the median point of selected objects -Blend vertex colors across face when vertices are shared -Game engine logic brick to detect events -Causes the image to repeat horizontally and vertically -Bone location is set in local space -User Preferences -Show Operator -Max Logic Steps -Damping of the harmonic force -Vertex of a simulated fluid mesh -Graph Editor Generic -18 - Theme Color Set -Average Speed -Console -Total number points for the surface on the V direction -Use the manipulator for scale transformations -Disable -5 -13 - Theme Color Set -Vertex group to control field -12 -Shared Location -Transparent pixels are filled with sky color -Atmosphere Turbidity -Widget Style -RNA function definition -NLA Strip is not evaluated -Recast Data -4096 -Right Handle Selected -Cyclic -Color Ramp -Self Collision Quality -Index of active pose marker -Vertex Group Density Negate -Dome Mode -Image and settings for display in the 3d View background -Process the render (and composited) result through the video sequence editor pipeline, if sequencer strips exist -FPS -Normals -SIMD SVBVH -Minimum distance between collision objects before collision response takes in -Color balance gamma (midtones) -Minimum distance for the field's fall-off -Limit fluid objects to this group -Load UI -Factor Stiff Viscosity -Draw preview using full resolution or different proxy resolutions -Paint Lock -Sets the number of samples used by the audio mixing buffer -Source List -Around Current Frame -Scroll Handle -Add light coming from the environment -Color of the F-Curve in the Graph Editor -Exclude indirect pass from combined -Selection of IK solver for IK chain, current choice is 0 for Legacy, 1 for iTaSC -Bias -Text Input -Pitch -2D -Braid -Modifier name -Use extra textures like normal or specular maps for GLSL rendering -Stamp Marker -ZXY Euler -Function does not pass its self as an argument (becomes a class method in python) -Sun Intensity -Fit -AO Exclude -Integer Property -Tube -ZYX Rotation Order. Prone to Gimbal Lock -Default paths for external files -Solid -Lock the same rotation/scaling pivot in all 3D Views -Groups of F-Curves -Display the object solid, with face-assigned textures -Quadratic -ID-Block that keyframes for Keying Set should be added to (for Absolute Keying Sets only) -Inaccurate, but faster and without noise -Unique ID for this region -Lock Y Axis -Logic Nor -Gaussian -Euler -Settings for filtering the channels shown in Animation Editors -Invoke Region Channels -Crop the rendered frame to the defined border size -Limit Location -Radius of the brush in pixels -Automatically select also UVs sharing the same vertex as the ones being selected -Title -Histogram -Display raw datablocks -Bone deformation distance (for Envelope deform only) -Forcefield based on the Lennard-Jones potential -Action Group is locked -XYZ Euler -Outline Width -Upper First -Subdivide stroke in fixed number of bones -Action Clip -Use 16 bit floats instead of 32 bit floats per channel -Stamp Camera -Texture Nodes -Falloff power (real gravitational falloff = 2) -3D View near clipping distance -Color Randomization -Snap Peel Object -Determine the amount of render threads used -Amount -F-Curve -Zmask scene layers for solid faces -Bone Group this pose channel belongs to (0=no group) -Constraint's panel is expanded in UI -Collection of Color Ramp Elements -Grease Pencil -Show controllers of active object -Instead of per brush strength, the strength is shared across brushes -Allow boids to move on land -Negate the effect of the clump vertex group -` -Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis -Highlight the current line -Simplify Child Particles -Lattice -Timeline Markers -Draw actual particles -XYZ -Collection of spaces -Bake Mode -Sub -Enable Stereo environment -F-Curve defining values of a period of time -Rules are gone through top to bottom. Only the first rule that effect above fuzziness threshold is evaluated -Constraint to stay within the image bounds while editing -Only Selected Curve Keyframes -Scroll Bar -Theme settings for Font -Allow Climbing -Syntax Highlight -ASCII -Properties space data -Lamp datablocks -Pivot around bounding box center of selected object(s) -Max Res -Mouse Previous X Position -Simplify the final stroke -Frame is selected for editing in the DopeSheet -OS Key -Function is optionally registered as callback part of type registration -Ease -Renders halo as a star -NLA Channels -Use the speed vector pass to reduce AO samples in fast moving pixels. Higher values result in more aggressive sample reduction. Requires Vec pass enabled (for Raytrace Adaptive QMC) -nl_NL -Alt key pressed -Limit movement around the Y axis -Z Scale -Actuator -Motion Path for this element -Slider Widget Colors -Name of Vertex color layer -Xnor -Bone Group this pose channel belongs to -Quad View Region -Edge Split -Noise algorithm - Voronoi Crackle: Voronoi tessellation with sharp edges -Max Air Angular Velocity -Use Bone Sketching -Automatic keyframe insertion using active Keying Set only -Colors -Starting frame of range of paths to display/calculate (not for 'Around Current Frame' Onion-skinning method) -Show script files -Cloth simulation settings for self collision and collision with other objects -Object to use as the environment map's viewpoint location -The interpolation type for this curve element -Vertically Open -Show the expanded in the user interface -Emit Object Location -Toggle Widget Colors -Rotation -Current Transformation orientation -Total number points for the curve or surface in the U direction -Active Particle System Index -Material Physics -Pull -List Item Colors -Show a small rotating 3D axis in the bottom left corner of the 3D View -Add-Ons -Render face with texture -Tilt Interpolation -K -Collection of particle systems -Text editor space data -Zoom -Goal minimum, vertex weights are scaled to match this range -When deforming bone, multiply effects of Vertex Group weights with Envelope influence -F-Curve Sample -Radius of eraser 'brush' -Finnish (Suomi) -Turbulent noise driven by the global current frame -Raytraced reflection settings for a Material datablock -Convert effector force into air flow velocity -True when the Shift key is held -Audio Sample Format -Bold -Vertex colors for a face in a Mesh -Cursor -Mouse/Trackpad Pan -Display Paths of poses within specified range -Info space data -Duplicate Armature -Settings for Bullet soft body simulation -Name of the theme -Collection of scene objects -B-Bone Display Z Width -Zoom using up/down on the device (otherwise forward/backward) -Enter Edit Mode automatically after adding a new object -Apply gravitation to point movement -Info on current cache status -Cone -Lock Z Rotation Axis -GLSL Extra Textures -Starts player in a new fullscreen display -Named Group -Samplerate -Children expanded in the user interface -Border -Armatures active bone -Active Path Index -Texture Type -Amount of clumping -Style -Collection of render layers -Show Restriction Columns -Soft Body -Drag effector weight -Layers visible in this 3D View -Top -Quality of the simulation in steps per frame. (higher is better quality but slower) -The constraint is applied in Pose Space, the object transformation is ignored -View Rotation -Gravitation -Cardinal -Dolly -8 bit greyscale binary data -Chroma Vectorscope -Active bone group for this pose -Repulsion Factor -Object Constraints -Filter Text -Vertex group to control tangent -Default builtin key configuration -Show folders -Page Down -Elements -View3D Zoom Modal -Show Actuators -Deletes smoke from simulation -Filter File Extensions -Control point selection status -Left Handle Selected -Draw Stretch -Align rotation with the snapping target -Cloth -Show the name of the view's direction in each 3D View -Display Filter -Object does not restitute collisions, like a ghost -Particle Velocity -Relative time of key over hair length -6 -Threshold for drawing outlines on geometry edges -Lighting -MPEG-4 -Delete -MPEG-2 -Curve Edit -Distance of the physics area -Boid Settings -Pixel resolution of the rendered environment map -Goal maximum, vertex group weights are scaled to match this range -Vertex Group Roughness 2 Negate -Manipulator Rotate -Limits -Current Frame -Project to Self -Sticky texture coordinate location -Transition -Duplicate Texture -Mask -Description of the Function's purpose -Generate voxels from a sequence of image slices -Theme settings for the Node Editor -Automatic time snapping settings for transformations -Banking -Texture Plugin Directory -Mass -Mist settings for a World data-block -Show column -Tool Widget Colors -Clip Alpha -Retarget -Drag component proportional to velocity -Blocking -Mirror Colors -Number of frames between ghosts shown (not for 'On Keyframes' Onion-skinning method) -Bars Selected -Use a minimum radial distance for the field's fall-off -Edit Object -Cineon -Height -Texture Factor -Draw Wire -Manipulate object centers only -Custom color set to use -Negate the effect of the density vertex group -SL -Enable Self Collision -Correction -Self Minimum Distance -Keying set paths -Invoke Region Preview -Causes material data to be duplicated with the object -Sample Distance -Vertex Group Field -Multiplier to make out-scattered light brighter or darker (non-physically correct) -Object Selected -Keyframe Selected -Pose Bone -Set sensor expanded in the user interface -Theme Audio Window -Strip Time -Number of frames from start frame for influence to fade out -Codec -Speaker -Image Generic -3D Region -Copy Scale -Duplicate Surface -Particle key for hair particle system -Particle Edit -Number of cone samples averaged for blurry refractions -Keep from going through other boids -Output image in DDS format -Orig Height -In Air -Constraint was added in this proxy instance (i.e. did not belong to source Armature) -OpenGL shading language shaders -Render the stamp info text in the rendered image -read only area of the face -Exec Region Channels -Smoke collides with every side -Enable Collision -The mouse button used for selection -How strong a force must be to start effecting a boid on land -Imperial -Vertex Group Length -SDL device - simple direct media layer, recommended for sequencer usage -Pixel Aspect Y -Shadow -Show the active object's softbody point cache -ZIP (lossless) -Collection of Compositor Nodes -Viewport Shading -Mean red/green/blue scattering path length -Ball inflating pressure -Snap to nearest marker -Vertical aspect ratio - for anamorphic or non-square pixel output -Window Sliders -Color ramp mapping a scalar value to a color -Make hairs less puffy -Active UV texture index -Location of head end of the bone relative to its parent -Display Texture -Group Node -Collection of meshes -Continue -Grease Pencil Smooth Stroke -Set audio mixing buffer size to 4096 samples -Transparent RGB and alpha pixels are unmodified -Nearest Neighbor -Gives a constant force along the force objects local Z axis -Emit -Bake the normals in tangent space -Active Base -Active UV texture -Falloff Curve -Sun intensity -Collection of related sketches on a particular frame -Vector Fonts -Mesh Edit -String Property -Variables -3D View Space -Show the active object's particle point cache -Cinema 24fps 2048x1080 -The default directory for rendering output, for new scenes -Audio bitrate(kb/s) -Font Size -File -Automatically converts all new tabs into spaces for new and loaded text files -Search again from the start of the file when reaching the end -Driver variable type -Search term for filtering in the UI -Show UV editing related properties -Subdivision Surface -Mipmaps -Simplified Chinese (ç®ä½ä¸æ) -Edge Length Text -View2D -Step Size -All effector's weight -GOP Size -Bottom -Color balance lift (shadows) -True when this value can't be set to None -The color of the lights specular highlight -Free Run (Rec Date) -How much the spring rest length can change after the elastic limit is crossed -Nand -Background Images -Vertex Group Roughness 1 Negate -Follow a boid or assigned object -Collection of Shader Nodes -Show Brush -Save Preview Images -Use Influence -Add/Replace -Enable direct editing of modifier control cage -Overwrite characters when typing rather than inserting them -Multitexture -Full -Modifier affecting the geometry data of an object -Text to replace selected text with using the replace tool -Particle Age -Unique name used in the code and scripting -Movie Strip -Python Scripts Directory -Global user preferences -Proportional Size -Location of the hair key in object space -Window Manager -Selectable -Diffuse subsurface scattering settings for a Material datablock -Air Personal Space -Which axis to use for offset -Sound -Include Animation Data blocks with no NLA data. (NLA Editor only) -Tree Type -The index of particle system on the target object -Noise algorithm - Voronoi F1-F2 -Autosplit Output -Type of transition used to fade mist -Logic Nand -Enable this OpenGL light in solid draw mode -Explode -Tilt CW -ID-Block -Diffusion factor, the strength of the blurring effect -Rate control: min rate(kb/s) -Alter spring length to shrink/blow up (unit %) 0 to disable -Object is made a particle system to display particles generated by a fluidsim domain object -Alternate script path, matching the default layout with subdirs: startup, addons & modules (requires restart) -channels -Head Select -Nearest Frame -WPaint Auto-Normalize -View3D Gesture Circle -Active index in render layer array -True when the Cmd key is held -When an 'array/vector' type is chosen (Location, Rotation, Color, etc.), entire array is to be used -Poly -Name of the key map -Roll bones to face the view -Cycle the animated time within the action start & end -Metaball Edit -Use anti-aliasing for the 3D view (may impact redraw performance) -Key Configuration -NLA editor space data -Sounds -Noise formula used for turbulence -Show Thumbnails -Output video in AVI Raw format -Shape Keys -Cloth simulation settings for an object -Transparency along the width of the strand -Name of UV layer to override -Custom animation player executable path -Spring Vertex Group -Luma Waveform -Goal Damping -French (Française) -tool_settings -3D Cursor -Collection of lattices -Display -Center of mass -The type of radius interpolation for Bezier curves -Global approximate AA and SSS quality factor -Type of data to take texture from -Build -Logic Xor -Backdrop zoom factor -Collection of worlds -Python addons to be loaded automatically -Proxy size 50% -Intensity of the mist effect -UV Editor -Opacity -JPEG 2000 -ID Type -Wires -Texture Face -The default directory to search for sequence plugins -Physics settings for a Material datablock -Size of the turbulence -Plastic -Viscoelastic Springs -Keyframe Insert Needed -Threads Mode -Exclude environment pass from combined -Display an additional 'summary' line. (DopeSheet Editors only) -Blend factor with sky -BMP -Obstacle simulation -Relative friction coefficient in the in the X, Y and Z directions, when anisotropic friction is enabled -7 -Enable naive vertex ball self collision -Text Character Format -Particle System -Active section of the user preferences shown in the user interface -Outliner -Don't use any brush -Pulldown Widget Colors -Duplicate Lamp -Spring rest length (factor of particle radius) -Softens the edges of halos at intersections with other geometry -None -ko_KR -Only Matching F-Curves -Active Particle Target -TIFF -Keyboard -Strand settings for a Material datablock -" -Material Index -Targa Raw -Name that will be used in exported files when format supports such feature -F-Curve is not evaluated -Texture Collection Rate -Blend -Stop ray marching early if transmission drops below this luminance - higher values give speedups in dense volumes at the expense of accuracy -rect -08 - Theme Color Set -Sharp falloff -Proxy Local -Repulsion Distance -Method used for combining strip's result with accumulated result -Particle speed (absolute magnitude of velocity) mapped as 0.0-1.0 intensity -Syntax Numbers -Images get saved in 8 bits grayscale (only PNG, JPEG, TGA, TIF) -Global Space -Save the z-depth per pixel (32 bit unsigned int z-buffer) -Curving of the noodle -View Type -Children Expanded -Shape -Background Image -Dash -Pass -Snap to Pixels -Engine -Vertex Select -Specular Exclude -Color 2 -Brush strength -Control point weight values -Maximum memory usage in megabytes (0 means unlimited) -Pivot around each object's own origin -Island -Softbody goal weight -Exclude shadow pass from combined -Method for driving added turbulent noise -Sampled colors along line -Offsets the number of the frame to use in the animation -Maximum angular velocity on land (relative to 180 degrees) -Start Frame -Middle Mouse Paste -Edge Seam -Display UV coordinates from 0.0 to 1.0 rather than in pixels -Find Text -Inverse Gamma -Smooth hairs -Graphics driver and operating system settings -How much density effects smoke motion, higher value results in faster rising smoke -passes -Boid rule name -Maximum number of recently opened files to remember -Path to property setting -Level of detail in the added turbulent noise -Screen -Billboard Normal UV -Selects the type of physical representation -Clip End -Creates a force along a curve object -Time delay in 1/10 seconds before automatically opening top level menus -Autosplit output at 2GB boundary -Resolution Y -Artificial buoyancy force in negative gravity direction based on pressure differences inside the fluid -Gamma -Light Cache -Offset -Voronoi F2-F1 -Hair keys are in global coordinate space -Structs -Particle system name -Don't adjust roll -Bevel -UI Layout -Movie Format -Fast but not so effective compression -Use linear workflow - gamma corrected imaging pipeline -Delta -Gravity -Mist uses linear progression -BSpline -Type of element to snap to -Set audio mixing buffer size to 32768 samples -Show the Y axis line in perspective view -Action End Frame -Settings for input devices -Joystick -Window manager datablocks -Left Handle Type -Points U -bl_description -Collection of mesh edges -Clip objects based on what's visible in other side views -Object Grouped -Backscattered Light -Active grease pencil layer -Animated Influence -Atmosphere Inscatter -Color of emitted light -Lock Location -Active Vertex Color Layer -Spaces -Properties of particle editing mode -Area height -Material nodes -Collection of armature bones -Resolution U -Click -Filter Files -Display general information -Bone Groups -Overlay -Muted -Movie -Auto Clamped -Individual Origins -Overlap -Custom -Particles -Use Max -Window -File browser space data -AVI JPEG -Friction Coefficients -Object base selection state -Bone Pose -Sequence strip in the sequence editor -Display Background Images -Name to use in scripted expressions/functions. (No spaces or dots are allowed. Also, must not start with a symbol or digit) -User defined layer of floating pointer number values -96 kHz -Occlude -Images are rendered in Image Editor -States -Saturation -Location of this character in the text data (only for text curves) -Users -Scene Objects -Goal Stiffness -Audio Codec -Collection of objects -Type of NLA Strip -Minimum distance to the camera for stars -Main Scenes -Clips to image size and sets exterior pixels as transparent -Interpolation method to use for segment of the curve from this Keyframe until the next Keyframe -Radius from the shaded sample to look for points within -Layer of texture faces in a Mesh datablock -Tangent -Stamp Time -Comb hairs -24-bit Signed -Show Handles -Alpha -Difference -The frequency of the offset (1/total length) -Layer Membership -Render layer -ro_RO -Vector Coordinates -Spring force -Flare Boost -Scopes -Description of the item's purpose -Camera Parent Lock -Invert the axis of mouse movement for zooming -Socket name -M -Enable diffuse subsurface scatting effects in a material -Color Factor -Noise algorithm - Cell Noise: Square cell tessallation -For PoseBone paths, use the bone head location when calculating this path -Max Land Speed -Show linked objects to sensor/actuator -Edit drivers -F-Curve Modifier is the one being edited -Channel Matrix -Has Ghost Curves -Threshold for adaptive sampling (if a sample contributes less than this amount [as a percentage], sampling is stopped) -Selects which domain border will be treated as collision object -Object that defines custom draw type for this bone -Still Frame Only -Invert tilt axis -The name of the active key configuration -Apply sun effect on atmosphere -Spacebar -Limit effectors to this group -Keep paths from intersecting the emitter -Input or output socket of a node -Transform Channel -Storage of a macro operator being executed, or registered after execution -Sets the number of points on the star shaped halo -Display the object's local bounding boxes only -Goal (vertex target position) spring stiffness -Boolean -Cyclic U -Cinema 24fps 4096x2160 -Images are saved with RGB and Alpha data (if supported) -Cyclic V -Indirect -Show Points -Speed -Copy Location -GLSL Lights -resolution_x -All available keying sets -Specular Color -Convert to logarithmic color space -Show keyframes for active Object and/or its selected bones only -Use Visual keying automatically for constrained objects -Game Property -Merged Region Size -Material Halo -Flare Seed -No Gimbal Lock (default) -Bending Const -Null device - there will be no audio output -Main Fonts -Sensor -Output image in Cineon format -Set audio sample format to 64 bit float -Whether to use maximum clipping value -Display units in pairs -Form factor scales the inertia tensor -Filter Images -Value to use for Ref, Spec, Amb, Emit, Alpha, RayMir, TransLu and Hard -Draw UV edges anti-aliased -Search string is sensitive to uppercase and lowercase letters -Region Text Titles -Flow Settings -Texture Slot -Enable debug visualization for obstacle simulation -Wrinkle coefficient. (higher = less smaller but more big wrinkles) -Action to take for gaps past the Active Action's range (when evaluating with NLA) -Spring rest length is a factor of 2 * particle size -Mist uses quadratic progression -Base -Enter Edit Mode -Widget Label Style -For Zmask, only render what is behind solid z values instead of in front -Face Angle Text -8 -Face Dot Size -Grow -Strips -Vertex group to control roughness end -Texture Slots -Snap UVs to pixel locations while editing -Border Minimum X -Value -Button5 Mouse -Roll CCW -Deprecation Warnings -Source List Title -Collection of fonts -Effector weights for physics simulation -2 -Input line for the interactive console -; -Soft body -Display Lamp -Tail Select -Rotation in Quaternions -Main MetaBall -Right Alt -Waveform Mode -Audio samplerate(samples/s) -Random -Harmonic -hr_HR -Themes -Texture scatting blend factor -Selected File -Cache AO results in pixels and interpolate over neighbouring pixels for speedup -double -Negate -Mute this shape key -Fgon -RVO (rays) -External file packed into the .blend file -Causes text data to be duplicated with the object -Include visualization of Speaker related Animation data -Zoom factor -Tweak Select -Shape Match -Spherical forcefield based on the charge of particles, only influences other charge force fields -Active Boid Rule -Active index in bone groups array -IK stiffness around the X axis -Go to assigned object or loudest assigned signal source -Wait Timer (ms) -The region relative vertical location of the mouse -Mouse/Trackpad Rotate -02 - Theme Color Set -Show Control Curves -Time taken in frames between shutter open and close -Textured Solid -Tail -Lift Force -The type of event, only applies to some -Targets -Main Texts -Draw Axes -Space data type -Subsurface Scattering -Mesh Vertex -Max Slope -Specular Intensity -Smoke collision settings -Cubic -Set all state bits -Action to take for gaps past the strip extents -Neutral -UV mapping, texturing and game engine data for a face -Minimum value for clipping -zh_CN -Wheel Scroll Lines -Shadow color in grey value -The constraint is applied relative to the world coordinate system -Icon File -Theme Console -Step Calculation -Amount the strip contributes to the current result -Shape Key Bezier Point -Smoke doesn't collide with top and bottom sides -Fastest and gives the most noise -Source of input values for driver variables -Show Keyframe Numbers -Image opacity to blend the image against the background color -Outline -window_manager -DDS -Show key map event and property details in the user interface -Bake ambient occlusion -Long List -Manual -Kink -Display Metaball -View Location -Radio Widget Colors -Weights -Cache of the worldspace positions of an element over a frame range -Theme settings for the Text Editor -Number of frames for Blending In/Out is automatically determined from overlapping strips -Collection of Driver F-Curves -Use SIMD QBVH -UV/Image Editor -Use degrees for measuring rotation -Resolution of the voxel grid -Physics Gravity -bl_idname -Name of the key configuration -Agent Radius -Keyed particles target is valid -Use force fields when growing hair -Point in the lattice grid -The amplitude of the offset -End Frame -Lets halo receive light and shadows from external objects -Pivot -Maximum walkable slope angle in degrees -Permeability -User defined floating point number value in a float properties layer -Render Result -Objects nearer than this are not visible to map -Pivot around active object -Operator Node -Local With Parent -Blender RNA structure definitions -Radius of bounding sphere and material physics -Bezier -Blend Type -Original Perlin -Active UV Texture -Active Object constraint -Armature-Relative Head -F-Curve's settings cannot be edited -7.1 Surround -Fluid Mesh Vertex -Long Key -Do not show any ghosts -Frame for absolute keys -Wav -Preview -[ -ObData -Emulate Numpad -Theme settings for the Timeline -Cell Size -Clamp velocity to this minimum speed (except when totally still) -Specify old mapping value in frames -Type of texture data to display and edit -Show ghosts for the specified frame range -Radius for bevelling -Maximal # solver steps/frame -Copy Rotation -07 - Theme Color Set -Use object/global coordinates for texture -If set to True, the panel shows a header, which contains a clickable arrow to collapse the panel and the label (see bl_label) -Sequence Element -Use rule when boid is flying -Simplify Shadow Samples -Deliver indirect lighting pass -Particle Key -Time since last step in seconds -Properties -Y Scale -Minimum Radial Distance -Sampled Points -Theme Logic Editor -Use Stars -Manipulator Translate -Brush steps -Active Pose Marker -F-Modifier -N -True when the Alt/Option key is held -Decimate -Use multi-sampled 3D scene motion blur -Type of active data to display and edit -Permanent deform -Onion Skinning Settings -Mode of automatic keyframe insertion for Objects and Bones -Theme settings for bone color sets -Scopes for statistical view of an image -Push -Show Seconds -Logic Or -Buffer Resolution -Create a toon outline around the edges of geometry -Regions -Damped Track -Active Bone Group Index -Automatically select acceleration structure -Specify a collision bounds type other than the default -Auto-Clamped handle color -Vertex Group Roughness End -Sets the maximum number of logic frame per game frame if graphics slows down the game, higher value allows better synchronization with physics -Control Point -Particle count -Turntable -Use Weight Color Range -Octree -Environment Exclude -Fuzziness while on collision, high values make collision handling faster but less stable -Tweak -Marker -Shadeless -Align handle color -Mist -Scene Render Layer -Sequence editing data for a Scene datablock -Structural Stiffness Vertex Group -Meta Stack -Duplicate F-Curve -Show sound files -Render layer name -Index of active particle system slot -Roll bone to original joint plane offset -Filter Fonts -Material Subsurface Scattering -Tip -Invalid -Show Cache -Delay -Blend factor for SSS colors -Fluid Group -Causes F-curve data to be duplicated with the object -Stationary object -el_GR -Compression method to be used -Speaker datablocks -B-Bone Ease In -Relative Paths -Mesh Int Property Layer -Enable smoke to disappear over time -Double Click Timeout -Cell Noise -Particle system has multiple point caches -Human readable name -The object that has the target particle system (empty if same object) -Maximum acceleration on land (relative to maximum speed) -Legacy -Clip alpha below this threshold in the 3D textured view -Display a preset button with the operators settings -Force gets absorbed by collision objects -9 -Noise method which is used for creating the high resolution -Manipulator -Select UVs that are at the same location and share a mesh vertex -Shadow offset in pixels -Bake directly from multires object -Insert -Wind effector weight -DopeSheet Editor -Entire Array -Use smoke heat as texture data. Values from -2.0 to 2.0 are used -Sequence Color Balance -Disallow movement around the X axis -Scenes -Active KeyConfig -Distance between two bones or objects -Rate control: max rate(kb/s) -Active file in the file browser -Limit collisions to this group -Nurbs weight -Outline Selected -Extrapolate the curve or extend it horizontally -Right Handle -Collection of mesh vertices -Smooth the final stroke -Current Transform Orientation -F-Curve live filtering string -Softness of the 'soft' falloff option -Selection Mode -Proportional Editing -Collection of keying set paths -Build 25% proxy resolution -DBVT culling -Armature Edit -Show Datablock Filters -A valid edit mode exists -World Mist -Default Value -Full Screen -Text in the line -Quality -A container referencing an existing Action -Layer name -Auto Start -Visualization -Show text files -Draw faces colored according to the difference in shape between UVs and their 3D coordinates (blue for low distortion, red for high distortion) -Snap Align Rotation -Angle of Rotation for Axis-Angle rotation representation -192 kHz -From socket -Nurb active U-lines -Constraints that act on this PoseChannel -Cyclic Strip Time -Space Outliner -Constraint has valid settings and can be evaluated -Debug -Pose Bones -Show image files -Goal maximum, vertex weights are scaled to match this range -Puff -Right Handle Type -Include the name of the active cameras lens in image metadata -Sky Color Space -Include visualization of Armature related Animation data -Character Index -Pin (vertex target position) spring stiffness -Open source frame player: http://djv.sourceforge.net -Grab Pointer -Bone is not able to be transformed when in Edit Mode -Show linked objects to the controller -Blend Distance -Edited -The mode used to apply the texture -Locked Track -File Browser -Vertex weight group, to blend with basis shape -The type of keyframe (for visual purposes only -Obstacle Radius -Drawing method used by the window manager -Active Particle Target Index -Front -Enable starfield generation -Particle datablocks -Show an outline highlight around selected objects in non-wireframe views -Zooms in and out based on vertical mouse movement -Calculate sub-surface scattering in materials rendering -Parent this node is attached to -ar_EG -Include the render frame as HH:MM:SS.FF in image metadata -Line of text in a Text datablock -Detail mesh sample spacing -Active Theme Area -Theme Widget Color Set -Boid height relative to particle size -Using 1/x -Scene keying sets -Show Sliders -All Z -Environment Color -Position -Buffersize -Adapt To Speed -Or -World datablocks -Effect Strip -Group of ID properties -Proxy size 75% -Vertex Paint -Hair Dynamics -Stroke Points -NLA Track is locked -Which mesh elements selection works on -Weight of rotation constraint for IK -Always refresh image on frame changes -Use horizon and zenith color for diffuse energy -Extra margin around object for collision detection, small amount required for stability -Collection of vertex groups -Coordinates of the first handle -Sky Blend Mode -Mesh Edge -Adjust simulation speed -Bounding box of this object represents the computational domain of the fluid simulation -Color balance gain (highlights) -Normal Space -Layers -Spin CW -Mesh Float Property Layer -Buffer Resolution - decrease it to increase speed -12 bit color channels -Space Graph Editor -Directory Path -False when this property is an optional argument in an RNA function -Framing Types -Display Paths of poses within a fixed number of frames around the current frame -Last selected point -Cropping parameters for a sequence strip -Min Air Speed -Wavelet -Color used for the surface of bones -Window Managers -Occlude objects with the environment color as they are further away -Attenuation falloff strength, the higher, the less influence distant objects have -Driven Selected -Surface Edit -Causes metaball data to be duplicated with the object -Main Curves -Japanese (æ¥æ¬èª) -Vertex Group Field Negate -Collection of uv textures -Enable simplification of scene for quicker preview renders -String -Randomized -Retarget template bone chain to stroke -Use the manipulator for movement transformations -Command line prompt language -How the rules in the list are evaluated -Color of texture overlay -Text Box -Modifier for values of F-Curve -Specify the number of cluster iterations -Mass of the object -React to force field physics settings in materials -The window relative vertical location of the mouse -YCbCr (ITU 709) -Linear viscosity -8x -Nothing -IK Z Limit -Sensors -Child Seed -Tweak Middle -Object represents a volume of fluid in the simulation -Property is editable through RNA -Theme settings for the Console -Datablock from which the edited datablock is linked -Particle -Solo -Mark controller for execution before all non-marked controllers (good for startup scripts) -FFMpeg audio codec to use -ZTransp -Location (Object Space) -IK Z Lock -Display size for normals in the 3D view -Use a tent filter for anti-aliasing -Original IK solver -Use velocities for automagic step sizes -Multiplier -Constraint Target -Draw Repeated -For RGB curves, the color that white is mapped to -Noise algorithm - Voronoi F1: Returns distance to the closest feature point -IK Y Minimum -Pin Stiffness -Cache Info -No Ghosts -Duplicate Material -Nurbs order in the V direction (For surfaces only), Higher values let points influence a greater area -Spanish (Español) -Sets the dimension of the halo -Vertex in a Mesh datablock -Line Numbers Background -Shadow Size -Depth -Rest Density -Frame Server -alert -Meta Element -Show actuators of all selected objects -Calculate environment maps while rendering -Motion Path Settings -Interlaced -Space type -Display the operator log -Show background image in front view -Simple -Storage of a sub operator in a macro after it has been added -Collision Bounds -Maximum value for clipping -Transparency -Armature-Relative Tail -Display in the info window and support the redo toolbar panel -FFMpeg codec to use -Show frame numbers on Motion Paths -Maximum allowed number of light inter-refractions -Use a third buffer for minimal redraws at the cost of more memory -Game engine logic brick to process events, connecting sensors to actuators -Layer in multilayer image -Depth Cutoff -Mesh Edges -Max Edge Length -The number of lines scrolled at a time with the mouse wheel -Root Texture Coordinates -Tag Seam -Visibility status -Birth Time -Mini Axis Brightness -Environment -Accuracy -Driven -Air Damping -Use Vertex Buffer Objects (or Vertex Arrays, if unsupported) for viewport rendering -Normal -Keys -The axis icon's size -Spring Force -Brushes -Drag -Emulate 3 Button Mouse -Sculpt/Paint Overlay Color -Collection of keymap items -Shadow Y Offset -Fuzzy -Comb -Theme settings for the 3D View -End frame of the stored range -Grid Subdivisions -Layers bone exists in -Base type for datablocks, defining a unique name, linking from other libraries and garbage collection -Numpad 5 -face area -Clip Start -Numpad 2 -Tweak Action -Numpad 0 -Use this files path when library linked into another file -GL Texture Limit -Only keyframes of selected F-Curves are visible and editable -Numpad 9 -Crease -Filter -Minimum angles for IK Limit -Scatter contribution factor -Bones which are children of this bone -Main Particle Settings -Collection of particle settings -Use modifier during rendering -Numpad / -Numpad . -05 - Theme Color Set -Read Only -Include visualization of Particle related Animation data -Numpad * -Bone is not visible when in Edit Mode -Width Fade -Amount of rotation around velocity vector on turns -Czech (Äeský) -Display datablocks in all scenes -Turbulent noise driven by the particle's age between birth and death -Aerodynamics Type -Best quality -Use effector/global coordinates for turbulence -Target particle systems -Min Rate -Distance to keep particles away from the emitter -Type of information to display -Limit movement around the Z axis -NLA stack is evaluated when evaluating this block -Apply puff to unselected end-points, (helps maintain hair volume when puffing root) -Fgon edge -Perspective -Bone rotation around head-tail axis -Pan/Zoom -Add a new NLA Track + Strip for every loop/pass made over the animation to allow non-destructive tweaking -No Auto-Snap -Active Texture Face -Node Backdrop -Count -Amount of influence F-Curve Modifier will have when not fading in/out -Collection of points that make up this poly or nurbs spline -Enable All Codecs -Auto Blend In/Out -Show Python Tooltips -Show menus in the header -Action datablocks -Edit texture nodes from World -Cross -Particle target name -Frame Map Old -Collection of channel driver Variables -Lower First -Stamp Render Time -Groups of the bones -Vertex Group Velocity -Cine-Flat 48fps 1998x1080 -Snap -Extreme Alpha -2x -Group datablocks -Overall sensitivity of the 3D Mouse -Images are rendered in full Screen -Activity culling is enabled -2D cursor location for this view -Metaball types -F -Show Linked to Actuator -Square (HS + V) -Node Groups -Name Property -Dither Intensity -Reconstruction filter used for combining anti-aliasing samples -Minimal -Active Face -Scripts -Scale factor along the X for items in this (sub)layout -Image Axis -Orig Width -Pose Head Position -Cursor Y-Value -Property is optionally registered as part of type registration -IK stiffness around the Z axis -NLA Tracks -Constrain to Image Bounds -Arrangement of the panels -Length of second Bezier Handle (for B-Bones only) -Median -Indirect Exclude -AO -Node in a node tree -Cast -Save cache files to disk (.blend file must be saved first) -Simplify AO and SSS -Use key times -de_DE -Property has been dynamically created at runtime -Ball Size -Display sequence datablocks -Read-only matrix calculated from the roll (armature space) -Noise algorithm - Improved Perlin: Smooth interpolated noise -Automatically start game at load time -Generate point density from a particle system -How much of effector force gets lost during collision with this object (in percent) -Deliver AO pass -Group that included Object should be a member of -Cell Height -Shear Stiffness -Material Volume -Maximum number of lines to store for the console buffer -Include visualization of Mesh related Animation data -Object Non-modal -Maximum acceleration in air (relative to maximum speed) -Pin ID -Radar -Render color of textured face as color -Parts Y -Parts X -Collection of F-Curve Modifiers -Verts Per Poly -Lock to Cursor -Theme Image Editor -Graph Editor 2D-Value cursor - Y-Value component -Automatically merge vertices moved to the same location -Stencil -Lock strip so that it can't be transformed -Vertex Group Rotation -Djv -Use a quadratic filter for anti-aliasing -Calculates environment map only once -Node Links -The number of subdivisions between grid lines -Filter Folder -use images in the order as they are recorded -Collection of libraries -Use selection as the pivot point -Auto Snap -The original matrix of this object before it was duplicated -The unit system to use for button display -Limit selection to visible (clipped with depth buffer) -Type of field -float_array -Root falloff -The quality of the anisotropic filtering (values greater than 1.0 enable anisotropic filtering) -Dodge -Active Vertex Group Index -Method used for determining what ghosts get drawn -Proportional Editing Objects -Parent -Particle dupliobject name -Theme Widget State Color -Tilt CCW -Mirror Intensity -Object -Include visualization of Lamp related Animation data -Object Location -select_end -FrameCycler -Joint -Backdrop X -Backdrop Y -Use Instances -Y Rotation -Nor -Addon -Anti-Aliasing Samples -frames_skipped -Stamp Lens -Make hairs more puffy -Offsets image horizontally from the view center -Negate the effect of the roughness 2 vertex group -Invoke Screen -A square showing Hue/Saturation, with Value slider -NLA Track -Outer Thickness -Format of Time Codes displayed when not displaying timing in terms of frames -Display Node -Boid will fight this times stronger enemy -Custom Color -P -Negate the effect of the rotation vertex group -Select Tail -Settings for boid physics -Options for this operator type -Mouse Y Position -Input properties of an Operator -Fixed -Current windowmanager and data context -Collection of actions -Tab Width -Theme 3D View -Render -Auto Keyframe Insert Available -Grid Scale -Number of undo steps available (smaller values conserve memory) -Show background image in bottom view -Theme Graph Editor -Surface -Flash -Collision -Grid Lines -Pre Roll -Strand -The transformation of the target bone is evaluated relative its local coordinate system, with the parent transformation added -Disables non-planer quads being triangulated -Particle Brush -Smoke doesn't collide with any border -Ghost frames on either side of frame -Frame -Select -ID-Block representing source data, currently ID_SCE (for Dopesheet), and ID_SC (for Grease Pencil) -Index -Functions -03 - Theme Color Set -Built-In Function -Display objects name and frame number in 3D view -Custom text to appear in the stamp note -Cameras -Noise algorithm - Voronoi F4: Returns distance to the 4th closest feature point -Estimated scale matrix -Overall stiffness of structure -State -Camera -Distance between key frames -Image Painting -Object is made a fluid control mesh, which influences the fluid -Draw image with RGB colors -Build 100% proxy resolution -Space Type -Transformation -Method of calculating the steps through the volume -Material slot name -Number of frames between cached frames -Repulsion is a factor of stiffness -Edge spring friction -Face Area Text -Frame Map New -Media Play/Pause -Mux Rate -Show background image in all views -Slider Max -Every Point -Stub RNA type used for pointers to unknown or internal data -Number of indirect diffuse light bounces -Clip Min X -Clip Min Y -Link -Record animation to fcurves -Object removes fluid from the simulation -The number of times this object is repeated with respect to other objects -Line -Method used to define which Group-name to use -Use Material Force Field -Multi constraint, stateful IK solver -Texture nodes -Locked -Filebrowser Parameter -Path to an image editor -Weights for the vertex groups this point is member of -Insert keyframes based on 'visual transforms' -Armatures -Nabla -Mesh String Property -Collection of action groups -Keep path lengths constant -The type of tilt interpolation for 3D, Bezier curves -Creates a force that dampens motion -Disable simulation of linear motion along the Y axis -Green -Layer is selected for editing in the DopeSheet -Voronoi F2 -Voronoi F3 -Active F-Curve Modifier -Cycles -Margin -Voronoi F4 -Theme settings for the Image Editor -Face Dot Selected -Damping of cloth velocity. (higher = more smooth, less jiggling) -GLSL Color Management -Prompt -Length of first Bezier Handle (for B-Bones only) -Theme settings for style sets -Ctrl -Show intermediate values for the driver calculations to allow debugging of drivers -Apply this and all preceding deformation modifiers on splines' points rather than on filled curve/surface -Vertex indices -Lens angle (mm) in perspective view -Back -German (Deutsch) -Color of light scattered out of the volume (does not affect transmission) -Build free run time code index -Extrapolation -Theme settings for Info -Collection of metaball elements -Use face normal to rotate object, so that it points away from the surface -Lens -Otherwise menus, etc will always be top to bottom, left to right, no matter opening direction -Particle Dupliobject Weight -Use textures for drawing international fonts -Use light for face -The edge flag to tag when selecting the shortest path -Vinterlace -Cycle the images in the movie -Display Z Axis -Reflectivity -Window Draw Method -Set audio sampling rate to 44100 samples per second -Causes particle systems to be duplicated with the object -Scripts Window -The space where the panel is going to be used in -SMPTE (Compact) -Automatically merge nearby keyframes -Fast in high-contrast areas -YCC -Deliver object index pass -Bake shadows -Continuous Grab -Alive State -Input -Adaptive -Single texture face materials -Color Ramp Element -Hue -Error tolerance (low values are slower and higher quality) -Transforms include effects of constraints but not parenting/restpose -Collision Settings -Collection of cameras -Command line prompt -Cache file path -Object Space -Driver -End size of strands in pixels or Blender units -Weighted result of strip is added to the accumulated results -NLA Track is selected -Quaternion -DOC BROKEN -19 - Theme Color Set -Debug State -Active Keying Set used to insert/delete keyframes -Lock Rotations (4D) -Sets the audio output device -Channels to display when drawing the histogram -Displays bit depth of full screen display -Sky Blend -Reflection -Vertex group to control roughness 1 -Bake Emit values (glow) -Language use for translation -Atmosphere Distance Factor -Emit Object Space -Motion Path Points -IK Solver -F-Curves -Semantic interpretation of the property -Partial overlay on top of the sequencer -Unborn -Effect in full or only positive/negative Z direction -Format of the source data set to render -Space UV Editor -Solid Lights -F1 -F2 -F3 -F4 -F5 -F6 -F7 -Fonts Directory -Single ASCII character for this event -Invert x Axis -Allow boids to move in air -Zoom Style -Library -Sky related settings for a sun lamp -Inherit Rotation -Disable Stereo and Dome environments -KeyConfigs -IK Stretch -Voronoi F1 -Rigid Body -operator_context -Rotation Units -Defines the structure of the menu in the UI -idp_array -XYZ velocity mapped to RGB colors -Editmode -Particle Location -Tabs as Spaces -Region Background -Render Layers -Stiff viscosity -Scale Matrix -Pinned -Sequence Editor -Vertex Normal -Display current image regardless of object selection -Display Lattices -Density -Exclude raytraced refraction pass from combined -Charge effector weight -Limit colliders to this Group -Square (SV + H) -Space currently being displayed in this area -Show frame number beside the current frame indicator line -Face -Normalized quaternion rotation -Proportional Editing enabled -Vector handle selected color -Scope region background color -Show font files -Wave -Stickness -Vertex Groups -The time to animate the view in milliseconds, zero to disable -Number of times this datablock is referenced -Source Path -Forcefield based on a texture -Lattices -Object used as the smoke simulation domain -Parameters defining which layer, pass and frame of the image is displayed -Vertex Size -Italian (Italiano) -Physics Type -Ghost -Audio Device -Display Scene -Limit Scale -Enable Dome environment -Vertex Group Kink Negate -Radial Falloff Power -Value Sliders -collection -Meta Elements -Q -Display Transforms -Texture Time Out -Output image in TIFF format -Key Map -Navigation mesh -Fade effect using the built-in default (usually make transition as long as effect strip) -Include visualization of ShapeKey related Animation data -Manual adjust -Space User Preferences -NLA Track is not evaluated -Use rule when boid is on land -Anisotropic Filter -Red Green Blue -Radiance HDR -Active object base in the scene -User defined layer of integer number values -Object Mode -Maximum height between grid cells the agent can climb -Texts -Sort the file list by extension -Settings for filtering animation data -Number of horizontal pixels in the screen -Path to the .blend file -Converts texture RGB values to intensity (gray) values -Different styles of displaying the color picker widget -Initial state when the game starts -Nurbs order in the U direction (For splines and surfaces), Higher values let points influence a greater area -Show sliders beside F-Curve channels -Fisheye -Show View Name -Sequencer and Image Preview -Fake User -Video Sequence Editor -Struct Definition -The directory for storing temporary save files -Record Animation -F-Curve Modifier will not be evaluated -Full Render -Only one side is rendered, with Z axis pointing in direction of image -Show ghosts from around the current frame -Display Channel -Automatically switch between orthographic and perspective when changing from top/front/side views -Print debug information for this property -Update simulation with cache steps -Relationship Lines -RNA Path to property affected by F-Curve -Median Point -Mesh datablocks -Sets angular index of refraction for raytraced refraction -Node Socket type -Outliner space data -Shadow X Offset -Amount of residual error in Blender space unit for constraints that work on position -Make diffuse shading more similar to shading the surface -Scale textures for the 3D View (looks nicer but uses more memory and slows image reloading) -Draw white edges with black outline -UV selection and display mode -No -Show linked objects to the actuator -Key Config -Pressure -Render Data -Quaternion Rotation -Multiply -Control point for envelope F-Modifier -Proportion of original image source pixel lines to sample -Avoid Collision -Snap to volume -Starting frame of range of Ghosts to display (not for 'Around Current Frame' Onion-skinning method) -Automatically determine the number of threads, based on CPUs -Curve mapping to map color, vector and scalar values to other values using a user defined curve -Run python while editing -Selects the collision type -Active Vert/Edge/Face -Tessellation level - check the generated mesh in wireframe mode -Register -Transform Markers -Include visualization of Scene related Animation data -Index number of cache files -Text Highlight -Halo particle effect settings for a Material datablock -MPlayer -Previous Particle Location -Recent Files -Legacy tracking constraint prone to twisting artifacts -Edges receive a lift force when passing through surrounding media -Optional region type keymap is associated with -Output image in JPEG 2000 format -Self Collision -Enable bending constraints -Theme DopeSheet -Layer -Drag Threshold -Factor Rest Length -Which style to use for viewport scaling -Data to derive color results from -3D cursor location for this view (dependent on local view setting) -Nested -MultiLayer -Display Curve -Disk Cache -Transform markers as well as strips -mode -Target object for multi-target constraints -Multiplier for the material's density -FPS Base -Grease Pencil Simplify Stroke -Edit all markers of the same group as one -Harmonic effector weight -Location of head end of the bone relative to armature -Texture coordinates from root particle locations -Stereo Options -Disallow movement around the Z axis -Number of vertical tiles to use while rendering -Random Friction -Specifies an offset in the flare seed table -Horizon brightness -Language -Sound Clip -Light used for OpenGL lighting in solid draw mode -Screen datablocks -NLA Editor -Vertex group to control velocity -input_count -Only hold last frame -Elasticity of collisions -Sky Texture -Use SIMD SVBVH -Sort alphabetically -New Handles Type -Display only objects which will be rendered -Noise -The time (in ms) for a double click -matrix -channel_id -Only render the active layer -Material -Standard Modal Map -No TC in use -Output image in multilayer OpenEXR format -Empty -Always -Enable filtering of files -Template -When the camera is locked to the view and in fly mode, transform the parent rather than the camera -Show Sensors -Auto handle color -Custom Warp Mesh data file -Audio Channels -Available as GameObject attributes in the game engine's python API -Offset Y -Min Region Size -Pre-calculate the raytrace accelerator and render raytracing effects -For multires, show low resolution while navigating the view -Active curve spline -Strength of sky shading exponential exposure correction -Print Performance to Console -Power of Fresnel for mirror reflection -Default binary voxel file format -Copy Transforms -Draw alpha transparency channel -4x4 bone matrix relative to armature -Edge spring stiffness when longer than rest length -When true the format is a movie -Read cache from an external location -Object Index -Print warnings when using deprecated features in the python API -Option Widget Colors -Auto Depth -Goal Minimum -Display size for proportional editing circle -Point -NLA Strip -Strokes -Lock editing of scale in the interface -Sensor name -Point in a shape key -Dutch (Nederlandse taal) -Only Objects in Group -The shininess of the reflection (values < 1.0 give diffuse, blurry reflections) -Default relative path option for the file selector -Proportional editing object mode -Sampled animation data -Output image in PNG format -Owner Space -Align the transformation axes to the selected objects' local space -If this is set, the panel gets a custom ID, otherwise it takes the name of the class used to define the panel. For example, if the class name is "OBJECT_PT_hello", and bl_idname is not set by the script, then bl_idname = "OBJECT_PT_hello" -Lock Rotation (4D Angle) -Overdraw Sketching -Pause -Maximum speed in air -Backdrop Y offset -Ellipsoid -Separate Units -Object is a fixed obstacle -scene -Load user interface setup when loading .blend files -'Viscosity' inside collision target -Bake everything -Lamp -Negate the effect of the length vertex group -Invert z axis -Armature datablocks -Shadow size in pixels (0, 3 and 5 supported) -Rasterized cell size -Collection of timeline markers -Local -Old style zoom, continues while moving mouse up or down -Tooltips -Edge Collision -Fluid rest density -Blender Voxel -Bezier curve point with two handles -Runtime -Regular key pressed as a modifier -UV Layer -Initial Velocity -Sources of input data for evaluating this variable -Timeline -Game engine related settings for the object -Hide Recent Locations -Include the name of the active camera in image metadata -Colored Constraints -Particle Hair Key -Y Location -Exec Region Window -Stereographic techniques -UV editor settings -General movement damping -Estimate matrix -Global Pivot -IK X Lock -Keep UV and edit mode mesh selection in sync -Vector Handle -Number of frames from start frame for influence to take effect -int_array -Key velocity -Negate the effect of the roughness 1 vertex group -Output Path -Image User -AutoMerge Editing -Flare Subsize -Handle 2 Location -Edge UV Face Select -Clamp To -NDOF -The transformation of the target is only evaluated in the Pose Space, the target armature object transformation is ignored -Particle systems emitted from the object -Wheel Up -Linear falloff -Show the status of cached frames in the timeline -R -Keyframe -Blender Render -Noise Basis -How the texture effect is calculated (RGB & Curl need a RGB texture else Gradient will be used instead) -Display Grid Floor -Transmission Color -Parameters defining how an Image datablock is used by another datablock -Spline point without handles -8 bit color channels -Collapse summary when shown, so all other channels get hidden. (DopeSheet Editors Only) -Draw Z-buffer associated with image (mapped from camera clip start to end) -Filter Size -Density is constant within lookup radius -Clear Images before baking -Animation Channels -Snap closest point onto target -Cloth Collision Settings -Sequence Plugin Directory -Size of widget handles as percentage of widget radius -Friction -Main Speakers -Offset in the random number table, to get a different randomized result -Keep Lengths -Vertex Group Element -Snap to faces -Case Sensitive Matches Only -Time delay in 1/10 seconds before automatically opening sub level menus -RNA structure definition -F-Curve Modifier is only applied for the specified frame range to help mask off effects in order to chain them -Collection of pose bone constraints -Angle -Gives a spiraling force that twists the force objects local Z axis -AAC -The constraint is applied relative to the local coordinate sytem of the object -Separate color channels in preview -Absolute Density -Target Particle System -When transforming keyframes, changes to the animation data are flushed to other views -Markers -Amount of pixels you have to drag before dragging UI items happens -Manipulator Hotspot -Nurb U-lines -Output video in Ogg format -double_array -Shape matching threshold -Drag component proportional to the square of velocity -Inner Selected -Show Playback FPS -Interpolation -Space File Browser -Hold LMB Open Toolbox Delay -Vertex Group Weight -Timeline editor space data -Main Screens -Improved Perlin -The value this event translates to in a modal keymap -Theme settings for widget state colors -Reversed -Mesh Float Property -Sky Exposure -Align each axis to the Euler rotation axis as used for input -Show Frame Numbers -Action Editor -17 - Theme Color Set -Soft body simulation settings for an object -Mesh Vertices -32-bit Float -Invisible -Number of horizontal pixels in the rendered image -= -Handle types -Stricky texture coordinate -Max Land Angular Velocity -Struct definition used for properties assigned to this item -RGB to Intensity -Mapping settings -Name of Shape Key -Shadow Alpha -Radius Interpolation -Pulse True Level -Bounces -Exec Region Preview -Edge Draw Type -Color Management -Raytrace -Forcefield depends on the speed of the particles -Mode -Stiffness -Radial -Noise Method -Number of seconds between each run of the GL texture garbage collector -Gravitational constant used for physics simulation in the game engine -Logic Editor -Text Selected -Point Caches -No compression -Vertex coordinates are stored localy on each primitive. Increases memory usage, but may have impact on speed -Edge Crease -Invert rotation Axis -Use Ambient Occlusion to add shadowing based on distance between objects -Frame that modifier's influence starts (if Restrict Frame Range is in use) -active_strip -Lock -Collection of window managers -Cine-Flat 24fps 1998x1080 -Sort by extension -All Views -Enum Item Definition -Button 4 -Button 5 -Button 6 -Button 7 -Button 1 -Button 2 -Maximum angles for IK Limit -Render Pass -Selected Text -Whether to draw the sound's waveform -Data Path -Enum Flag -Soft Light -Define forces for vertices to stick to animated position -Sample every pixel of the image -Invert roll axis -Goal -Dissolve Speed -Textbox X Offset -Sky turbidity -A random rule is selected for each boid -OpenAL device - supports 3D audio, recommended for game engine usage -Console Input -Invert the level(output) of this sensor -Memory Cache Limit -Point Cache List -Motion Path settings for visualisation -Endpoint V -The rotation step for numerical pad keys (2 4 6 8) -Linear and angular physics -NLA Strip is selected -The channel number shown in the image preview. 0 is the result of all strips combined -Shrink -Limit movement around the X axis -Draw Action -Display debug reporting info -Collection of action fcurves -Bone inherits scaling from parent bone -Lock current frame displayed by layer -Type of stretch to draw -Friction/damping with self contact -Undo -ZYX Euler -Scaling factor for the background image -vBVH -Axis-Angle Rotation -Bone deformation weight (for Envelope deform only) -Interaction radius is a factor of 4 * particle size -Shape key to use the rest spring lengths from -Use this texture as a blending value on the next texture -Deliver environment lighting pass -Show Python references in tooltips -Theme NLA Editor -Above-Below -Transition Strip -NLA Strips on this NLA-track -Draw black edges -Removes the operator from search results -Light Override -Only include channels from Objects in the specified Group -Compositing -128 -Random Damping -Effector Weights -Location of tail of the channel's bone -Frame Number -Image displayed and edited in this space -Vertex group to control roughness 2 -Show background image in camera view -How incompressible the fluid is -Point select mode -Panel containing UI elements -Stamp Date -Inverts the values of the texture to reverse its effect -Smoke flow settings -Active Particle System -Channels -Type of this region -Intensity -Audio Strip -Blending -Enable this objects as a collider for physics systems -Tracking along a single axis -Weight used by the Subsurf modifier for creasing -Duplicate Mesh -Keying Set Info -Map Type -Use BLI K-Dop BVH.c -Amount of turbulence/rotation in fluid -Add light and shadow -Random falloff -Script -Edge selection mode -Auto Handle -Collection of bone groups -Vertex Group Roughness 1 -Sets minimum X value to for the render border -Coordinates of the left handle (before the control point) -Source -Output Node -Groups of Pose Channels (Bones) -Hide recent locations in the file selector -Particle editing brush -Show the ground plane grid in perspective view -Snap Target -Scripted Expression -Shadow Brightness -Noise algorithm - Blender original: Smooth interpolated noise -Rot error -Amount of damping during particle collision -Save Versions -Anti-aliasing -Endpoint U -Sub-Target -Settings -Use international fonts -Show Mini Axis -Previous Particle Velocity -Edge in a Mesh datablock -Function Definition -Physics engine used for physics simulation in the game engine -Softbody -Theme settings for the DopeSheet -Vertex Group Size -Add the file format extensions to the rendered file name (eg: filename + .jpg) -Collection of KeyConfigs -Active Element -Wipe -Deliver raytraced reflection pass -Fade paths and keys further away from current frame -Threshold for adaptive sampling. If a sample contributes less than this amount (as a percentage), sampling is stopped -Control point spring strength values -Extends by repeating edge pixels of the image -File is Saved -Region Type -OpenEXR -Auto Keying -S -Vector -Texture Mapping -Cache name -Smoke -Boid State -Space Node Editor -Multiresolution -No Preset -Maximum allowed number of light inter-reflections -Final key configuration that combines keymaps from the active and addon configurations, and can be edited by the user -Allow Negative Frames -Bending -Group to override all other lights in this render layer -Position solver iterations -Exists -Lock editing of 'angle' component of four-component rotations in the interface -Deliver shade-less color pass -Rear-Truncated -RNA -Has Minimum -Strip has no influence past its extents -Lennard-Jones effector weight -Screens -Window Background -current_character -Meta -Theme settings for the Logic Editor -Floating-Point Property -Structural Stiffness -Particle system settings -Codec settings for OpenEXR -Axis -Forces the current Scene to be displayed in all Screens -Indicates that a keymap is used for translate modal events for an operator -Environment map created by the renderer and cached for subsequent renders -Rotational Difference -Goal Vertex Group -Use shaders for GLSL rendering -Multiple Springs -Emitter Distance -Edit Bone -Indicates that a keyconfig was defined by the user -Include channels from objects/bone that aren't visible -Align dynamic game objects along the surface normal, when inside the physics distance area -Frames Per Second -Set the distance between the eyes - the camera focal length/30 should be fine -Draw Other Objects -Mouse Previous Y Position -Flare Size -Align the transformation axes to average normal of selected elements (bone Y axis for pose mode) -Maintain Volume -Display mode for the file list -Max Step -Activate FALSE level triggering (pulse mode) -Active Render -Size Y -Size X -Display splash screen on startup -Size Z -Grease Pencil Layer -X/Y coordinates of the curve point -Use a minimum distance for the field's fall-off -Show 2D cursor -Frame Locked -Active -Horizontal -Editing -Factor for how much surrounding objects contribute to light -Blend In -Sets the global starting frame of the movie/sequence, assuming first picture has a #1 -bg_BG -The size of the occlusion buffer in pixel, use higher value for better precision (slower) -Horizontal aspect ratio - for anamorphic or non-square pixel output -4x4 matrix, before constraints -Minimum Distance -End frame of range of Ghosts to display (not for 'Around Current Frame' Onion-skinning method) -Particles generated by the particle system -Region Text Highlight -Align -zh_TW -Overwrite existing files while rendering -Cylinder -How many frames to fade -Driver type -World -Theme settings for user interface elements -Bending Stiffness -Draw other selected objects that share the same image -Show dashed lines indicating parent or constraint relationships -And -Bevel Radius -Extrapolated -Force -Active Brush -Distance will be used to attenuate shadows -Method used to adjust the roll of bones when retargeting -Form Factor -Scopes to visualize image statistics -Number -Shade Top -Number of frames to render ahead during playback -High quality interpolation, but slower -Current view matrix of the 3D region -Handle 1 Location -Vertex Group Density -Active Frame -IK Y Limit -Blending to inelastic collision -Enable high resolution (using amplification) -Simulation starts on this frame -Properties to set when the operator is called -Result of rendering, including all layers and passes -iTaSC -Mesh String Property Layer -Tweak Left -True if this map is ready for use, False if it needs rendering -X Scale -Bone in an Armature datablock -Output image in Targa format -Stamp Sequence Strip -F-Curve Modifier's panel is expanded in UI -Build 50% proxy resolution -An object duplicate -Start Offset -Items -Fluid simulation settings for an object taking part in the simulation -Set audio mixing buffer size to 8192 samples -Material Strand -Inflow -Sort -Relative Key -Motion Paths -Return -Stiffness defines how much of the element to fill -Detail mesh simplification max sample error -Meta Strip -Bake Alpha values (transparency) -Memory cache limit in sequencer (megabytes) -Input configuration, including keymaps -Select the type of Framing you want -Animation data for this datablock -Raytracing -Key Map Item -Split quads to give the least distortion while baking -Show overexposed areas with zebra stripes -1024 -Bias towards faces further away from the object (in blender units) -Strip time is controlled by an F-Curve rather than automatically determined -Bake Location -sr_RS -Panel -Main Libraries -Edit Edit -Get away from assigned object or loudest assigned signal source -Darken -Active index in vertex group array -Average Separation -F-Curve Modifiers -RNA type used for pointers to any possible data -Space Image Editor -UV Selected -Handle 1 Type -Choke -Use Simplify -Maximum -YZX Euler -No Self -Helicopter Mode -Rotation in Eulers -On Cage -Bone that defines the display transform of this custom shape -Main Node Trees -Undo Steps -Cube Map -Point cache for physics simulations -Interactive python console -Use environment map with six cube sides -Show .blend files -Kill Particles -Sets maximum X value for the render border -Only Seconds -NLA Tracks (i.e. Animation Layers) -Timer Property -Z Rotation -Ensure all bone-deforming vertex groups add up to 1.0 while weight painting -Rigid to Soft Body -Lock to Object -Threshold -Enable sorting of faces for correct alpha drawing (slow, use Clip Alpha instead when possible) -Occlude Geometry -Causes surface data to be duplicated with the object -Use the images alpha values clipped with no blending (binary alpha) -Hold Forward -Set Controller state index (1 to 30) -Amount of light that gets scattered out by the volume - the more out-scattering, the shallower the light will penetrate -Lock Horizon -Ignore Layers -Object Matrix -Pixel Aspect X -Filename -Use Ambient Occlusion -The transformation of the target is evaluated relative to its local coordinate system -The region where the panel is going to be used in -BW -Bake Specular values -Tool -Margin Column -Maximum distance from active object to other object (in blender units -Final transformation value of object or bone -Group Name -Proxy parameters for a sequence strip -fr_FR -Kill collided particles -Disable simulation of angular motion along the Y axis -Collision Margin -SMPTE timecode showing minutes, seconds, and frames only. Hours are also shown if necessary, but not by default -bl_use_preview -Draw Faces -Vertex Group Rotation Negate -\ -New Window -Turbulent noise driven by particle velocity -Lock Rotation -Color Source -Print state debug info in the game engine -Location of head of the channel's bone -Timer -Output video in Xvid format -Enable raytraced reflections -Image Preview -Optional space type keymap is associated with -Use ramps for GLSL rendering -Motion Samples -Vectorscope Opacity -Element defining a color at a position in the color ramp -All Action Keyframes -Automatic keyframe insertion for Objects and Bones (default setting used for new Scenes) -Align Object To -Welding threshold: distance between nearby vertices to be considered equal => set to 0.0 to disable welding test and speed up scene loading (ok if the mesh has no duplicates) -Limit -T -Diffuse Color -Release -User defined string text value in a string properties layer -Histogram for viewing image statistics -Scroll Widget Colors -General media friction for point movements -Lock Y Rotation Axis -Set audio mixing buffer size to 1024 samples -Draw the image repeated outside of the main view -Mesh Int Property -Noodle curving -Unknown Type -Add & Replace -Border Collisions -Add children to form a compound collision object -Influence -Show high resolution (using amplification) -Collection of sounds -Use Bone Heads -Actuator to apply actions in the game engine -Mp3 -Go to closest enemy and attack when in range -Type of range to show for Motion Paths -Use trackball style rotation in the viewport -32768 -Overwrite -Duplicate Particle -32-bit Signed -Scale -Expression to use for Scripted Expression -Pre-calculate the shading information into a voxel grid, speeds up shading at slightly less accuracy -Parameters -Material Mode -Avoid -Cache is outdated -File Browser Buttons -Actor -Bone Group Index -Toolbox Column Layout -Show the frames per second screen refresh rate, while animation is played back -Image Editor -Mesh Vertex Sticky Texture Coordinate -Vertex Weight Proximity -Average Spring length * Ball Size -Renders rings over halo -Offset in the random number table for child particles, to get a different randomized result -Auto Keying Mode -B-Bone Segments -Time in 1/10 seconds to hold the Left Mouse Button before opening the toolbox -Visible Layers -File format to save the rendered images as -Enable view navigation within the camera view -Show background image in top view -Sun brightness -Closest -Make this curve or surface a closed loop in the U direction -Command history -XYZ Rotation Order. Prone to Gimbal Lock -Draw Stretch Type -Percentage scale for render resolution -F-Curve and its keyframes are hidden in the Graph Editor graphs -F-Curve Editor -Area distortion between UV and 3D faces -YXZ Rotation Order. Prone to Gimbal Lock -Effective but slow compression -Fields -For bone motion paths, search whole Action for keyframes instead of in group with matching name only (is slower) -Process the render result through the compositing pipeline, if compositing nodes are enabled -Co-ordinate system to cache particles in -Error Limit -Curve guide effector weight -Default -Black Level -ISO 1 -Fine tunes texture mapping X, Y and Z locations -Single Property -Korean (íêµ ì¸ì´) -DopeSheet Sub-Channel -Max Air Speed -Vertex Group Length Negate -Key location for a particle over time -Render a user-defined border region, within the frame size. Note, this disables save_buffers and full_sample -Range -Materials -Show hidden dot files -Numpad Enter -Polish (Polski) -Automatic saving of temporary files in temp directory, uses process ID -Cubic B-Spline -Logic editor space data -Open menu buttons and pulldowns automatically when the mouse is hovering -Use to check if an operator is a macro -Display zoom level -Stamp Filename -Weight -Bias (in radians) to prevent smoothed faces from showing banding (for Raytrace Constant Jittered) -Auto XYZ to RGB -UV -Audio volume -Restrict the number of animation updates to the animation FPS. This is better for performance, but can cause issues with smooth playback -Replace -Show paint related properties -Target Space -Gloss Samples -UI -Keep horizon level while flying with 3D Mouse -Texture Mode -Shaded + Multiple Scattering -Lifetime -Settings for particle fluids physics -Type of units for this property -Pointer -Field Settings -PoseBone Constraints -Right Ctrl -User Key Configuration -Color 3 -Speakers -Color 1 -Spline Points -Color 4 -Gradient -Rule Fuzziness -YZX Rotation Order. Prone to Gimbal Lock -Amount of residual error in radiant for constraints that work on orientation -GLSL Shadows -Radius of object representation in obstacle simulation -Show the entire viewport in the display window, using bar horizontally or vertically -Dissolve Smoke -Internal -Library file the datablock is linked from -Outer face thickness -Any modifier keys pressed -Screen aligned billboard -Allow moving the mouse outside the view on some manipulations (transform, ui control drag) -NLA Strips that this strip acts as a container for (if it is of type Meta) -Pixel Cache -Texture slot name -Render Stamp -bl_label -Settings for interacting with Blender data -Ball -Active Clone -Editbone Matrix -ja_JP -Curve in a curve mapping -Auto Rainbow -Maximum angular velocity in air (relative to 180 degrees) -Operator Properties -Material Raytrace Transparency -Child -Modal Keymap -Color to use behind stamp text -Theme settings for the graph editor -Aligned -Border Maximum X -Border Maximum Y -Type of event -Set color of the bars -Collapse Summary -How many collision iterations should be done. (higher is better quality but slower) -Consant falloff -Fields Still -Main Sounds -Definition of a choice in an RNA enum property -Translate Tooltips -Sync Markers -Object being duplicated -Face in a Mesh datablock -Calculate bone paths from tails -Display World -UV Pinned -No Collision -Active Channel Group -Make face invisible -Number of subdivisions of bone (for B-Bones only) -Renders halo as a lens flare -Only Selected Channels -Minimum height where the agent can still walk -Stroke data points -Multiply Vertex Group with Envelope -Inner face thickness -Set actuator expanded in the user interface -Low values are slower and higher quality -Vertices Cache -Lattice datablocks -Current frame number can be manually set to a negative value -Set controller expanded in the user interface -Simulation used for obstacle avoidance in the game engine -Duplicate Curve -List of background images -Manipulator Handle Size -Alive -Lock Z Axis -Tex -A square showing Saturation/Value, with Hue slider -Deliver material index pass -XXX todo -Collection of spline points -Flock -Linear Light -Live Unwrap -Radiosity -Turbulence Influence -Object datablocks -Left Shift -The source of this force field is the zero point of a harmonic oscillator -Driver Target -CIE -Show High Resolution -Pin Cloth -Soft Body Settings -Threads -Negate the effect of the roughness end vertex group -Gloss Threshold -World Space -Game data for a Scene datablock -Blender 2.4 -Coordinates of the right handle (after the control point) -View2D Buttons List -F-Curves in this group -Point cache list -3D View Region -Show the X axis line in perspective view -Matroska -Node Generic -Extinction scattering contribution factor -Callback function defines for builtin Keying Sets -Generate point density from an object's vertices -Coulomb friction coefficient, when inside the physics distance area -Temporary -Vertex group to control size -Time in milliseconds between each frame recorded for screencast -Low Resolution Mesh -Maximum structural stiffness value -Maximum radial distance for the field to work -Collection of point caches -Volume -Asymmetry -Mux rate (bits/s(!)) -Weight value of a vertex in a vertex group -Log conversion reference blackpoint -Point density settings -Show Mouse -Name of Action Group to assign setting(s) for this path to -Rotate -Multiplier for multiple scattered light energy -09 - Theme Color Set -(Min+Max)/2 * Ball Size -Flow -Output image in Radiance HDR format -Show Expanded -11 - Theme Color Set -Front scattering weight -Maximum speed for jumping -Compositor Nodes -Particle in a particle system -Vertex Group -U -Bending Stiffness Vertex Group -Context -Vertex selection mode -Use scaled but un-grid-fitted kerning distances -Gloss Amount -3D region that defines the quad view settings -Display groups and their datablocks -Include visualization of Curve related Animation data -User Modified -Statistical view of the levels of color in an image -Anisotropic Friction -4x -Inverse Gain -Fade Time -Visual Keying -Agent Height -Underline -Translate Interface -Property Definition -Bake Mirror colors -Animated Strip Time -Friction Factor -Space data for a screen area -Maximum speed on land -Theme User Interface -Deflect Emitter -Use Edges -The base density of the volume diff --git a/po/update_mo.py b/po/update_mo.py index 51591af8a0e..33b7baaed69 100755 --- a/po/update_mo.py +++ b/po/update_mo.py @@ -25,29 +25,43 @@ import subprocess import os +import sys -CURRENT_DIR = os.path.dirname(__file__) +GETTEXT_MSGFMT_EXECUTABLE = "msgfmt" +CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) SOURCE_DIR = os.path.normpath(os.path.abspath(os.path.join(CURRENT_DIR, ".."))) LOCALE_DIR = os.path.join(SOURCE_DIR, "release", "bin", ".blender", "locale") DOMAIN = "blender" +def process_po(po): + lang = os.path.basename(po)[:-3] + + # show stats + cmd = (GETTEXT_MSGFMT_EXECUTABLE, + "--statistics", + os.path.join(CURRENT_DIR, "%s.po" % lang), + "-o", + os.path.join(LOCALE_DIR, lang, "LC_MESSAGES", "%s.mo" % DOMAIN), + ) + + print(" ".join(cmd)) + process = subprocess.Popen(cmd) + process.wait() + + def main(): - for po in os.listdir(CURRENT_DIR): - if po.endswith(".po"): - lang = po[:-3] - # show stats - cmd = ("msgfmt", - "--statistics", - os.path.join(CURRENT_DIR, "%s.po" % lang), - "-o", - os.path.join(LOCALE_DIR, lang, "LC_MESSAGES", "%s.mo" % DOMAIN), - ) - - print(" ".join(cmd)) - process = subprocess.Popen(cmd) - process.wait() + if len(sys.argv) > 1: + for lang in sys.argv[1:]: + po = os.path.join(CURRENT_DIR, lang + '.po') + + if os.path.exists(po): + process_po(po) + else: + for po in os.listdir(CURRENT_DIR): + if po.endswith(".po"): + process_po(po) if __name__ == "__main__": print("\n\n *** Running %r *** \n" % __file__) diff --git a/po/update_msg.py b/po/update_msg.py index a58fd4b7998..9fc9967146d 100644 --- a/po/update_msg.py +++ b/po/update_msg.py @@ -26,10 +26,11 @@ import os -CURRENT_DIR = os.path.dirname(__file__) +CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) SOURCE_DIR = os.path.normpath(os.path.abspath(os.path.join(CURRENT_DIR, ".."))) FILE_NAME_MESSAGES = os.path.join(CURRENT_DIR, "messages.txt") +COMMENT_PREFIX = "#~ " def dump_messages_rna(messages): @@ -38,55 +39,102 @@ def dump_messages_rna(messages): # ------------------------------------------------------------------------- # Function definitions - def walkProperties(properties): + def walkProperties(bl_rna): import bpy - for prop in properties: - messages.add(prop.name) - messages.add(prop.description) + + # get our parents properties not to export them multiple times + bl_rna_base = bl_rna.base + if bl_rna_base: + bl_rna_base_props = bl_rna_base.properties.values() + else: + bl_rna_base_props = () + + for prop in bl_rna.properties: + # only write this property is our parent hasn't got it. + if prop in bl_rna_base_props: + continue + if prop.identifier == "rna_type": + continue + + msgsrc = "bpy.types.%s.%s" % (bl_rna.identifier, prop.identifier) + messages.setdefault(prop.name, []).append(msgsrc) + messages.setdefault(prop.description, []).append(msgsrc) if isinstance(prop, bpy.types.EnumProperty): for item in prop.enum_items: - messages.add(item.name) - messages.add(item.description) + msgsrc = "bpy.types.%s.%s, '%s'" % (bl_rna.identifier, + prop.identifier, + item.identifier, + ) + messages.setdefault(item.name, []).append(msgsrc) + messages.setdefault(item.description, []).append(msgsrc) def walkRNA(bl_rna): + msgsrc = "bpy.types.%s" % bl_rna.identifier + if bl_rna.name and bl_rna.name != bl_rna.identifier: - messages.add(bl_rna.name) + messages.setdefault(bl_rna.name, []).append(msgsrc) if bl_rna.description: - messages.add(bl_rna.description) + messages.setdefault(bl_rna.description, []).append(msgsrc) + + if hasattr(bl_rna, 'bl_label') and bl_rna.bl_label: + messages.setdefault(bl_rna.bl_label, []).append(msgsrc) - walkProperties(bl_rna.properties) + walkProperties(bl_rna) def walkClass(cls): walkRNA(cls.bl_rna) - def walk_keymap_hierarchy(hier): + def walk_keymap_hierarchy(hier, msgsrc_prev): for lvl in hier: - messages.add(lvl[0]) + msgsrc = "%s.%s" % (msgsrc_prev, lvl[1]) + messages.setdefault(lvl[0], []).append(msgsrc) if lvl[3]: - walk_keymap_hierarchy(lvl[3]) + walk_keymap_hierarchy(lvl[3], msgsrc) # ------------------------------------------------------------------------- # Dump Messages - for cls in type(bpy.context).__base__.__subclasses__(): + def full_class_id(cls): + """ gives us 'ID.Lamp.AreaLamp' which is best for sorting. + """ + cls_id = "" + bl_rna = cls.bl_rna + while bl_rna: + cls_id = "%s.%s" % (bl_rna.identifier, cls_id) + bl_rna = bl_rna.base + return cls_id + + cls_list = type(bpy.context).__base__.__subclasses__() + cls_list.sort(key=full_class_id) + for cls in cls_list: walkClass(cls) - for cls in bpy.types.Space.__subclasses__(): + cls_list = bpy.types.Space.__subclasses__() + cls_list.sort(key=full_class_id) + for cls in cls_list: walkClass(cls) - for cls in bpy.types.Operator.__subclasses__(): + cls_list = bpy.types.Operator.__subclasses__() + cls_list.sort(key=full_class_id) + for cls in cls_list: walkClass(cls) - from bpy_extras.keyconfig_utils import KM_HIERARCHY + cls_list = bpy.types.OperatorProperties.__subclasses__() + cls_list.sort(key=full_class_id) + for cls in cls_list: + walkClass(cls) - walk_keymap_hierarchy(KM_HIERARCHY) + cls_list = bpy.types.Menu.__subclasses__() + cls_list.sort(key=full_class_id) + for cls in cls_list: + walkClass(cls) + from bpy_extras.keyconfig_utils import KM_HIERARCHY - ## XXX. what is this supposed to do, we wrote the file already??? - #_walkClass(bpy.types.SpaceDopeSheetEditor) + walk_keymap_hierarchy(KM_HIERARCHY, "KM_HIERARCHY") def dump_messages_pytext(messages): @@ -121,26 +169,30 @@ def dump_messages_pytext(messages): # ------------------------------------------------------------------------- # Function definitions - def extract_strings(fp, node_container): + def extract_strings(fp_rel, node_container): """ Recursively get strings, needed incase we have "Blah" + "Blah", passed as an argument in that case it wont evaluate to a string. """ + for node in ast.walk(node_container): if type(node) == ast.Str: eval_str = ast.literal_eval(node) if eval_str: - # print("%s:%d: %s" % (fp, node.lineno, eval_str)) # testing - messages.add(eval_str) + # print("%s:%d: %s" % (fp, node.lineno, eval_str)) + msgsrc = "%s:%s" % (fp_rel, node.lineno) + messages.setdefault(eval_str, []).append(msgsrc) - def extract_strings_from_file(fn): - filedata = open(fn, 'r', encoding="utf8") - root_node = ast.parse(filedata.read(), fn, 'exec') + def extract_strings_from_file(fp): + filedata = open(fp, 'r', encoding="utf8") + root_node = ast.parse(filedata.read(), fp, 'exec') filedata.close() + fp_rel = os.path.relpath(fp, SOURCE_DIR) + for node in ast.walk(root_node): if type(node) == ast.Call: # print("found function at") - # print("%s:%d" % (fn, node.lineno)) + # print("%s:%d" % (fp, node.lineno)) # lambda's if type(node.func) == ast.Name: @@ -155,29 +207,60 @@ def dump_messages_pytext(messages): # do nothing if not found for arg_kw, arg_pos in translate_args: if arg_pos < len(node.args): - extract_strings(fn, node.args[arg_pos]) + extract_strings(fp_rel, node.args[arg_pos]) else: for kw in node.keywords: if kw.arg == arg_kw: - extract_strings(fn, kw.value) + extract_strings(fp_rel, kw.value) # ------------------------------------------------------------------------- # Dump Messages - mod_dir = os.path.join(SOURCE_DIR, "release", "scripts", "startup", "bl_ui") + mod_dir = os.path.join(SOURCE_DIR, + "release", + "scripts", + "startup", + "bl_ui") - files = [os.path.join(mod_dir, f) - for f in os.listdir(mod_dir) - if not f.startswith("_") - if f.endswith("py") + files = [os.path.join(mod_dir, fn) + for fn in sorted(os.listdir(mod_dir)) + if not fn.startswith("_") + if fn.endswith("py") ] - for fn in files: - extract_strings_from_file(fn) + for fp in files: + extract_strings_from_file(fp) def dump_messages(): - messages = {""} + + def filter_message(msg): + + # check for strings like ": %d" + msg_test = msg + for ignore in ("%d", "%s", "%r", # string formatting + "*", ".", "(", ")", "-", "/", "\\", "+", ":", "#", "%" + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "x", # used on its own eg: 100x200 + "X", "Y", "Z", # used alone. no need to include + ): + msg_test = msg_test.replace(ignore, "") + msg_test = msg_test.strip() + if not msg_test: + # print("Skipping: '%s'" % msg) + return True + + # we could filter out different strings here + + return False + + if 1: + import collections + messages = collections.OrderedDict() + else: + messages = {} + + messages[""] = [] # get strings from RNA dump_messages_rna(messages) @@ -185,10 +268,21 @@ def dump_messages(): # get strings from UI layout definitions text="..." args dump_messages_pytext(messages) - messages.remove("") + del messages[""] message_file = open(FILE_NAME_MESSAGES, 'w', encoding="utf8") - message_file.writelines("\n".join(sorted(messages))) + # message_file.writelines("\n".join(sorted(messages))) + + for key, value in messages.items(): + + # filter out junk values + if filter_message(key): + continue + + for msgsrc in value: + message_file.write("%s%s\n" % (COMMENT_PREFIX, msgsrc)) + message_file.write("%s\n" % key) + message_file.close() print("Written %d messages to: %r" % (len(messages), FILE_NAME_MESSAGES)) diff --git a/po/update_po.py b/po/update_po.py index bbdf7224908..3dcaa9d8f1b 100755 --- a/po/update_po.py +++ b/po/update_po.py @@ -25,27 +25,41 @@ import subprocess import os +import sys -CURRENT_DIR = os.path.dirname(__file__) +GETTEXT_MSGMERGE_EXECUTABLE = "msgmerge" +CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) DOMAIN = "blender" +def process_po(po): + lang = os.path.basename(po)[:-3] + + # update po file + cmd = (GETTEXT_MSGMERGE_EXECUTABLE, + "--update", + "--backup=none", + "--lang=%s" % lang, + os.path.join(CURRENT_DIR, "%s.po" % lang), + os.path.join(CURRENT_DIR, "%s.pot" % DOMAIN), + ) + + print(" ".join(cmd)) + process = subprocess.Popen(cmd) + process.wait() + + def main(): - for po in os.listdir(CURRENT_DIR): - if po.endswith(".po"): - lang = po[:-3] - - # update po file - cmd = ("msgmerge", - "--update", - "--lang=%s" % lang, - os.path.join(CURRENT_DIR, "%s.po" % lang), - os.path.join(CURRENT_DIR, "%s.pot" % DOMAIN), - ) - - print(" ".join(cmd)) - process = subprocess.Popen(cmd) - process.wait() + if len(sys.argv) > 1: + for lang in sys.argv[1:]: + po = os.path.join(CURRENT_DIR, lang + '.po') + + if os.path.exists(po): + process_po(po) + else: + for po in os.listdir(CURRENT_DIR): + if po.endswith(".po"): + process_po(po) if __name__ == "__main__": diff --git a/po/update_pot.py b/po/update_pot.py index 6c1d473b7f8..4e202026444 100755 --- a/po/update_pot.py +++ b/po/update_pot.py @@ -25,11 +25,13 @@ import subprocess import os +from codecs import open GETTEXT_XGETTEXT_EXECUTABLE = "xgettext" -CURRENT_DIR = os.path.dirname(__file__) +CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) SOURCE_DIR = os.path.normpath(os.path.abspath(os.path.join(CURRENT_DIR, ".."))) DOMAIN = "blender" +COMMENT_PREFIX = "#~ " # from update_msg.py FILE_NAME_POT = os.path.join(CURRENT_DIR, "blender.pot") FILE_NAME_MESSAGES = os.path.join(CURRENT_DIR, "messages.txt") @@ -55,7 +57,7 @@ def main(): pot_messages = {} reading_message = False message = "" - with open(FILE_NAME_POT, 'r') as handle: + with open(FILE_NAME_POT, 'r', "utf-8") as handle: while True: line = handle.readline() @@ -73,8 +75,9 @@ def main(): message += line[1:-1] # add messages collected automatically from RNA - with open(FILE_NAME_POT, "a") as pot_handle: - with open(FILE_NAME_MESSAGES, 'r') as handle: + with open(FILE_NAME_POT, "a", "utf-8") as pot_handle: + with open(FILE_NAME_MESSAGES, 'r', "utf-8") as handle: + msgsrc_ls = [] while True: line = handle.readline() @@ -82,13 +85,21 @@ def main(): break line = stripeol(line) - line = line.replace("\\", "\\\\") - line = line.replace("\"", "\\\"") - if not pot_messages.get(line): - pot_handle.write("\n#: Automatically collected from RNA\n") - pot_handle.write("msgid \"%s\"\n" % (line)) - pot_handle.write("msgstr \"\"\n") + # COMMENT_PREFIX + if line.startswith(COMMENT_PREFIX): + msgsrc_ls.append(line[len(COMMENT_PREFIX):].strip()) + else: + line = line.replace("\\", "\\\\") + line = line.replace("\"", "\\\"") + line = line.replace("\t", "\\t") + + if not pot_messages.get(line): + for msgsrc in msgsrc_ls: + pot_handle.write("#: %s\n" % msgsrc) + pot_handle.write("msgid \"%s\"\n" % line) + pot_handle.write("msgstr \"\"\n\n") + msgsrc_ls[:] = [] if __name__ == "__main__": diff --git a/release/bin/.blender/fonts/droidsans.ttf.gz b/release/bin/.blender/fonts/droidsans.ttf.gz Binary files differindex 82b413bcdd0..a00f35f3a66 100644 --- a/release/bin/.blender/fonts/droidsans.ttf.gz +++ b/release/bin/.blender/fonts/droidsans.ttf.gz diff --git a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py index 015a2cd0c36..3c5bc68203f 100644 --- a/release/scripts/startup/bl_operators/screen_play_rendered_anim.py +++ b/release/scripts/startup/bl_operators/screen_play_rendered_anim.py @@ -136,7 +136,7 @@ class PlayRenderedAnim(Operator): del process # ----------------------------------------------------------------- - opts = ["-a", "-f", str(rd.fps), str(rd.fps_base), file] + opts = ["-a", "-f", str(rd.fps), str(rd.fps_base), "-j", str(scene.frame_step), file] cmd.extend(opts) elif preset == 'DJV': opts = [file, "-playback_speed", "%d" % int(rd.fps / rd.fps_base)] diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index cabd8356ad0..c59f9bebb97 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -145,6 +145,7 @@ class SEQUENCER_MT_select(Menu): layout.operator("sequencer.select_handles", text="Left Handle").side = 'LEFT' layout.operator("sequencer.select_handles", text="Right Handle").side = 'RIGHT' layout.separator() + layout.operator_menu_enum("object.select_grouped", "type", text="Grouped") layout.operator("sequencer.select_linked") layout.operator("sequencer.select_all_toggle") layout.operator("sequencer.select_inverse") @@ -407,7 +408,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): return strip.type in {'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER', 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP', 'PLUGIN', - 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED', + 'WIPE', 'GLOW', 'TRANSFORM', 'SPEED', 'MULTICAM', 'ADJUSTMENT'} def draw(self, context): diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 8e2d9b47ec0..4ddd2c74f47 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -44,7 +44,7 @@ extern "C" { * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 259 -#define BLENDER_SUBVERSION 3 +#define BLENDER_SUBVERSION 4 #define BLENDER_MINVERSION 250 #define BLENDER_MINSUBVERSION 0 diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 244fda33a52..08798a6ddf0 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -231,7 +231,7 @@ short fcurve_is_keyframable(struct FCurve *fcu); /* -------- Curve Sanity -------- */ void calchandles_fcurve(struct FCurve *fcu); -void testhandles_fcurve(struct FCurve *fcu); +void testhandles_fcurve(struct FCurve *fcu, const short use_handle); void sort_time_fcurve(struct FCurve *fcu); short test_time_fcurve(struct FCurve *fcu); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 7e39461a032..b1943fdf97c 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -146,6 +146,11 @@ void object_camera_matrix( float winmat[][4], struct rctf *viewplane, float *clipsta, float *clipend, float *lens, float *ycor, float *viewdx, float *viewdy); +void camera_view_frame_ex(struct Scene *scene, struct Camera *camera, float drawsize, const short do_clip, const float scale[3], + float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]); + +void camera_view_frame(struct Scene *scene, struct Camera *camera, float r_vec[4][3]); + void object_relink(struct Object *ob); #ifdef __cplusplus diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c index 19027647537..622ea38a80c 100644 --- a/source/blender/blenkernel/intern/cloth.c +++ b/source/blender/blenkernel/intern/cloth.c @@ -742,7 +742,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) MDeformVert *dvert = NULL; Cloth *clothObj = NULL; int numverts; - float goalfac = 0; + /* float goalfac = 0; */ /* UNUSED */ ClothVertex *verts = NULL; if (!clmd || !dm) return; @@ -765,7 +765,7 @@ static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm ) if (( dvert->dw[j].def_nr == (clmd->sim_parms->vgroup_mass-1)) && (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL )) { verts->goal = dvert->dw [j].weight; - goalfac= 1.0f; + /* goalfac= 1.0f; */ /* UNUSED */ /* // Kicking goal factor to simplify things...who uses that anyway? diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index fcf9f69ed0c..bb918b3f3f0 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -2365,7 +2365,7 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl { Cloth *cloth= clmd->clothObject; BVHTree *cloth_bvh= cloth->bvhtree; - unsigned int i=0, numfaces = 0, numverts = 0, k, l, j; + unsigned int i=0, /* numfaces = 0, */ /* UNUSED */ numverts = 0, k, l, j; int rounds = 0; // result counts applied collisions; ic is for debug output; ClothVertex *verts = NULL; int ret = 0, ret2 = 0; @@ -2376,7 +2376,7 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl return 0; verts = cloth->verts; - numfaces = cloth->numfaces; + /* numfaces = cloth->numfaces; */ /* UNUSED */ numverts = cloth->numverts; //////////////////////////////////////////////////////////// @@ -2478,7 +2478,7 @@ int cloth_bvh_objcollision (Object *ob, ClothModifierData * clmd, float step, fl // collisions = 1; verts = cloth->verts; // needed for openMP - numfaces = cloth->numfaces; + /* numfaces = cloth->numfaces; */ /* UNUSED */ numverts = cloth->numverts; verts = cloth->verts; diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index 61e9daf4138..7747e4750b7 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -361,72 +361,70 @@ void curvemap_sethandle(CurveMap *cuma, int type) static void calchandle_curvemap(BezTriple *bezt, BezTriple *prev, BezTriple *next, int UNUSED(mode)) { float *p1,*p2,*p3,pt[3]; - float dx1,dy1, dx,dy, vx,vy, len,len1,len2; - - if(bezt->h1==0 && bezt->h2==0) return; + float len,len_a, len_b; + float dvec_a[2], dvec_b[2]; + + if(bezt->h1==0 && bezt->h2==0) { + return; + } p2= bezt->vec[1]; if(prev==NULL) { p3= next->vec[1]; - pt[0]= 2*p2[0]- p3[0]; - pt[1]= 2*p2[1]- p3[1]; + pt[0]= 2.0f*p2[0] - p3[0]; + pt[1]= 2.0f*p2[1] - p3[1]; p1= pt; } - else p1= prev->vec[1]; + else { + p1= prev->vec[1]; + } if(next==NULL) { p1= prev->vec[1]; - pt[0]= 2*p2[0]- p1[0]; - pt[1]= 2*p2[1]- p1[1]; + pt[0]= 2.0f*p2[0] - p1[0]; + pt[1]= 2.0f*p2[1] - p1[1]; p3= pt; } - else p3= next->vec[1]; - - dx= p2[0]- p1[0]; - dy= p2[1]- p1[1]; + else { + p3= next->vec[1]; + } - len1= (float)sqrt(dx*dx+dy*dy); - - dx1= p3[0]- p2[0]; - dy1= p3[1]- p2[1]; + sub_v2_v2v2(dvec_a, p2, p1); + sub_v2_v2v2(dvec_b, p3, p2); - len2= (float)sqrt(dx1*dx1+dy1*dy1); - - if(len1==0.0f) len1=1.0f; - if(len2==0.0f) len2=1.0f; - - if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */ - vx= dx1/len2 + dx/len1; - vy= dy1/len2 + dy/len1; - - len= 2.5614f*(float)sqrt(vx*vx + vy*vy); + len_a= len_v2(dvec_a); + len_b= len_v2(dvec_b); + + if(len_a==0.0f) len_a=1.0f; + if(len_b==0.0f) len_b=1.0f; + + if(bezt->h1==HD_AUTO || bezt->h2==HD_AUTO) { /* auto */ + float tvec[2]; + tvec[0]= dvec_b[0]/len_b + dvec_a[0]/len_a; + tvec[1]= dvec_b[1]/len_b + dvec_a[1]/len_a; + + len= len_v2(tvec) * 2.5614f; if(len!=0.0f) { if(bezt->h1==HD_AUTO) { - len1/=len; - *(p2-3)= *p2-vx*len1; - *(p2-2)= *(p2+1)-vy*len1; + len_a/=len; + madd_v2_v2v2fl(p2-3, p2, tvec, -len_a); } if(bezt->h2==HD_AUTO) { - len2/=len; - *(p2+3)= *p2+vx*len2; - *(p2+4)= *(p2+1)+vy*len2; + len_b/=len; + madd_v2_v2v2fl(p2+3, p2, tvec, len_b); } } } if(bezt->h1==HD_VECT) { /* vector */ - dx/=3.0f; - dy/=3.0f; - *(p2-3)= *p2-dx; - *(p2-2)= *(p2+1)-dy; + mul_v2_fl(dvec_a, 1.0f/3.0f); + sub_v2_v2v2(p2-3, p2, dvec_a); } if(bezt->h2==HD_VECT) { - dx1/=3.0f; - dy1/=3.0f; - *(p2+3)= *p2+dx1; - *(p2+4)= *(p2+1)+dy1; + mul_v2_fl(dvec_b, 1.0f/3.0f); + sub_v2_v2v2(p2+3, p2, dvec_b); } } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index c0d2eca9217..3bf3c0f9ed8 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -2458,72 +2458,77 @@ void makeBevelList(Object *ob) void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) { float *p1,*p2,*p3, pt[3]; - float dx1,dy1,dz1,dx,dy,dz,vx,vy,vz,len,len1,len2; + float dvec_a[3], dvec_b[3]; + float len, len_a, len_b; const float eps= 1e-5; - if(bezt->h1==0 && bezt->h2==0) return; + if(bezt->h1==0 && bezt->h2==0) { + return; + } p2= bezt->vec[1]; if(prev==NULL) { p3= next->vec[1]; - pt[0]= 2*p2[0]- p3[0]; - pt[1]= 2*p2[1]- p3[1]; - pt[2]= 2*p2[2]- p3[2]; + pt[0]= 2.0f*p2[0] - p3[0]; + pt[1]= 2.0f*p2[1] - p3[1]; + pt[2]= 2.0f*p2[2] - p3[2]; p1= pt; } - else p1= prev->vec[1]; + else { + p1= prev->vec[1]; + } if(next==NULL) { - pt[0]= 2*p2[0]- p1[0]; - pt[1]= 2*p2[1]- p1[1]; - pt[2]= 2*p2[2]- p1[2]; + pt[0]= 2.0f*p2[0] - p1[0]; + pt[1]= 2.0f*p2[1] - p1[1]; + pt[2]= 2.0f*p2[2] - p1[2]; p3= pt; } - else p3= next->vec[1]; + else { + p3= next->vec[1]; + } - dx= p2[0]- p1[0]; - dy= p2[1]- p1[1]; - dz= p2[2]- p1[2]; - - if(mode) len1= dx; - else len1= (float)sqrt(dx*dx+dy*dy+dz*dz); - - dx1= p3[0]- p2[0]; - dy1= p3[1]- p2[1]; - dz1= p3[2]- p2[2]; - - if(mode) len2= dx1; - else len2= (float)sqrt(dx1*dx1+dy1*dy1+dz1*dz1); + sub_v3_v3v3(dvec_a, p2, p1); + sub_v3_v3v3(dvec_b, p3, p2); + + if (mode != 0) { + len_a= dvec_a[0]; + len_b= dvec_b[0]; + } + else { + len_a= len_v3(dvec_a); + len_b= len_v3(dvec_b); + } - if(len1==0.0f) len1=1.0f; - if(len2==0.0f) len2=1.0f; + if(len_a==0.0f) len_a=1.0f; + if(len_b==0.0f) len_b=1.0f; if(ELEM(bezt->h1,HD_AUTO,HD_AUTO_ANIM) || ELEM(bezt->h2,HD_AUTO,HD_AUTO_ANIM)) { /* auto */ - vx= dx1/len2 + dx/len1; - vy= dy1/len2 + dy/len1; - vz= dz1/len2 + dz/len1; - len= 2.5614f*(float)sqrt(vx*vx + vy*vy + vz*vz); + float tvec[3]; + tvec[0]= dvec_b[0]/len_b + dvec_a[0]/len_a; + tvec[1]= dvec_b[1]/len_b + dvec_a[1]/len_a; + tvec[2]= dvec_b[2]/len_b + dvec_a[2]/len_a; + len= len_v3(tvec) * 2.5614f; + if(len!=0.0f) { int leftviolate=0, rightviolate=0; /* for mode==2 */ - if(len1>5.0f*len2) len1= 5.0f*len2; - if(len2>5.0f*len1) len2= 5.0f*len1; + if(len_a>5.0f*len_b) len_a= 5.0f*len_b; + if(len_b>5.0f*len_a) len_b= 5.0f*len_a; if(ELEM(bezt->h1,HD_AUTO,HD_AUTO_ANIM)) { - len1/=len; - *(p2-3)= *p2-vx*len1; - *(p2-2)= *(p2+1)-vy*len1; - *(p2-1)= *(p2+2)-vz*len1; + len_a/=len; + madd_v3_v3v3fl(p2-3, p2, tvec, -len_a); - if((bezt->h1==HD_AUTO_ANIM) && next && prev) { // keep horizontal if extrema + if((bezt->h1==HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ float ydiff1= prev->vec[1][1] - bezt->vec[1][1]; float ydiff2= next->vec[1][1] - bezt->vec[1][1]; if( (ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f) ) { bezt->vec[0][1]= bezt->vec[1][1]; } - else { // handles should not be beyond y coord of two others + else { /* handles should not be beyond y coord of two others */ if(ydiff1 <= 0.0f) { if(prev->vec[1][1] > bezt->vec[0][1]) { bezt->vec[0][1]= prev->vec[1][1]; @@ -2540,18 +2545,16 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) } } if(ELEM(bezt->h2,HD_AUTO,HD_AUTO_ANIM)) { - len2/=len; - *(p2+3)= *p2+vx*len2; - *(p2+4)= *(p2+1)+vy*len2; - *(p2+5)= *(p2+2)+vz*len2; + len_b/=len; + madd_v3_v3v3fl(p2+3, p2, tvec, len_b); - if((bezt->h2==HD_AUTO_ANIM) && next && prev) { // keep horizontal if extrema + if((bezt->h2==HD_AUTO_ANIM) && next && prev) { /* keep horizontal if extrema */ float ydiff1= prev->vec[1][1] - bezt->vec[1][1]; float ydiff2= next->vec[1][1] - bezt->vec[1][1]; if( (ydiff1 <= 0.0f && ydiff2 <= 0.0f) || (ydiff1 >= 0.0f && ydiff2 >= 0.0f) ) { bezt->vec[2][1]= bezt->vec[1][1]; } - else { // handles should not be beyond y coord of two others + else { /* andles should not be beyond y coord of two others */ if(ydiff1 <= 0.0f) { if(next->vec[1][1] < bezt->vec[2][1]) { bezt->vec[2][1]= next->vec[1][1]; @@ -2567,25 +2570,25 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) } } } - if(leftviolate || rightviolate) { /* align left handle */ + if(leftviolate || rightviolate) { /* align left handle */ float h1[3], h2[3]; + float dot; sub_v3_v3v3(h1, p2-3, p2); sub_v3_v3v3(h2, p2, p2+3); - len1= normalize_v3(h1); - len2= normalize_v3(h2); - vz= dot_v3v3(h1, h2); + len_a= normalize_v3(h1); + len_b= normalize_v3(h2); + + dot= dot_v3v3(h1, h2); if(leftviolate) { - *(p2+3)= *(p2) - vz*len2*h1[0]; - *(p2+4)= *(p2+1) - vz*len2*h1[1]; - *(p2+5)= *(p2+2) - vz*len2*h1[2]; + mul_v3_fl(h1, dot * len_b); + sub_v3_v3v3(p2+3, p2, h1); } else { - *(p2-3)= *(p2) + vz*len1*h2[0]; - *(p2-2)= *(p2+1) + vz*len1*h2[1]; - *(p2-1)= *(p2+2) + vz*len1*h2[2]; + mul_v3_fl(h2, dot * len_a); + add_v3_v3v3(p2-3, p2, h2); } } @@ -2593,60 +2596,52 @@ void calchandleNurb(BezTriple *bezt, BezTriple *prev, BezTriple *next, int mode) } if(bezt->h1==HD_VECT) { /* vector */ - dx/=3.0f; - dy/=3.0f; - dz/=3.0f; - *(p2-3)= *p2-dx; - *(p2-2)= *(p2+1)-dy; - *(p2-1)= *(p2+2)-dz; + mul_v3_fl(dvec_a, 1.0f/3.0f); + sub_v3_v3v3(p2-3, p2, dvec_a); } if(bezt->h2==HD_VECT) { - dx1/=3.0f; - dy1/=3.0f; - dz1/=3.0f; - *(p2+3)= *p2+dx1; - *(p2+4)= *(p2+1)+dy1; - *(p2+5)= *(p2+2)+dz1; + mul_v3_fl(dvec_b, 1.0f/3.0f); + sub_v3_v3v3(p2+3, p2, dvec_b); } - len2= len_v3v3(p2, p2+3); - len1= len_v3v3(p2, p2-3); - if(len1==0.0f) len1= 1.0f; - if(len2==0.0f) len2= 1.0f; + len_b= len_v3v3(p2, p2+3); + len_a= len_v3v3(p2, p2-3); + if(len_a==0.0f) len_a= 1.0f; + if(len_b==0.0f) len_b= 1.0f; if(bezt->f1 & SELECT) { /* order of calculation */ - if(bezt->h2==HD_ALIGN) { /* aligned */ - if(len1>eps) { - len= len2/len1; - p2[3]= p2[0]+len*(p2[0]-p2[-3]); - p2[4]= p2[1]+len*(p2[1]-p2[-2]); - p2[5]= p2[2]+len*(p2[2]-p2[-1]); + if(bezt->h2==HD_ALIGN) { /* aligned */ + if(len_a>eps) { + len= len_b/len_a; + p2[3]= p2[0]+len*(p2[0] - p2[-3]); + p2[4]= p2[1]+len*(p2[1] - p2[-2]); + p2[5]= p2[2]+len*(p2[2] - p2[-1]); } } if(bezt->h1==HD_ALIGN) { - if(len2>eps) { - len= len1/len2; - p2[-3]= p2[0]+len*(p2[0]-p2[3]); - p2[-2]= p2[1]+len*(p2[1]-p2[4]); - p2[-1]= p2[2]+len*(p2[2]-p2[5]); + if(len_b>eps) { + len= len_a/len_b; + p2[-3]= p2[0]+len*(p2[0] - p2[3]); + p2[-2]= p2[1]+len*(p2[1] - p2[4]); + p2[-1]= p2[2]+len*(p2[2] - p2[5]); } } } else { if(bezt->h1==HD_ALIGN) { - if(len2>eps) { - len= len1/len2; - p2[-3]= p2[0]+len*(p2[0]-p2[3]); - p2[-2]= p2[1]+len*(p2[1]-p2[4]); - p2[-1]= p2[2]+len*(p2[2]-p2[5]); + if(len_b>eps) { + len= len_a/len_b; + p2[-3]= p2[0]+len*(p2[0] - p2[3]); + p2[-2]= p2[1]+len*(p2[1] - p2[4]); + p2[-1]= p2[2]+len*(p2[2] - p2[5]); } } if(bezt->h2==HD_ALIGN) { /* aligned */ - if(len1>eps) { - len= len2/len1; - p2[3]= p2[0]+len*(p2[0]-p2[-3]); - p2[4]= p2[1]+len*(p2[1]-p2[-2]); - p2[5]= p2[2]+len*(p2[2]-p2[-1]); + if(len_a>eps) { + len= len_b/len_a; + p2[3]= p2[0]+len*(p2[0] - p2[-3]); + p2[4]= p2[1]+len*(p2[1] - p2[-2]); + p2[5]= p2[2]+len*(p2[2] - p2[-1]); } } } diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 3916d0ca701..8ea80ae9296 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -818,7 +818,7 @@ void calchandles_fcurve (FCurve *fcu) * -> Vector handles: become 'nothing' when (one half selected AND other not) * - PHASE 2: recalculate handles */ -void testhandles_fcurve (FCurve *fcu) +void testhandles_fcurve (FCurve *fcu, const short use_handle) { BezTriple *bezt; unsigned int a; @@ -834,9 +834,16 @@ void testhandles_fcurve (FCurve *fcu) /* flag is initialised as selection status * of beztriple control-points (labelled 0,1,2) */ - if (bezt->f1 & SELECT) flag |= (1<<0); // == 1 if (bezt->f2 & SELECT) flag |= (1<<1); // == 2 - if (bezt->f3 & SELECT) flag |= (1<<2); // == 4 + if(use_handle == FALSE) { + if(flag & 2) { + flag |= (1<<0) | (1<<2); + } + } + else { + if (bezt->f1 & SELECT) flag |= (1<<0); // == 1 + if (bezt->f3 & SELECT) flag |= (1<<2); // == 4 + } /* one or two handles selected only */ if (ELEM(flag, 0, 7)==0) { diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c index 295669c98c0..cef3eee8c5e 100644 --- a/source/blender/blenkernel/intern/implicit.c +++ b/source/blender/blenkernel/intern/implicit.c @@ -913,7 +913,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z { // Solves for unknown X in equation AX=B unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100; - float conjgrad_epsilon=0.0001f, conjgrad_lasterror=0; + float conjgrad_epsilon=0.0001f /* , conjgrad_lasterror=0 */ /* UNUSED */; lfVector *q, *d, *tmp, *r; float s, starget, a, s_prev; unsigned int numverts = lA[0].vcount; @@ -964,7 +964,7 @@ static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z conjgrad_loopcount++; } - conjgrad_lasterror = s; + /* conjgrad_lasterror = s; */ /* UNUSED */ del_lfvector(q); del_lfvector(d); @@ -1777,7 +1777,7 @@ int cloth_calc_helper_forces(Object *UNUSED(ob), ClothModifierData * clmd, float steps = 55; for (i=0; i<steps; i++) { for (node=cloth->springs; node; node=node->next) { - ClothVertex *cv1, *cv2; + /* ClothVertex *cv1, *cv2; */ /* UNUSED */ int v1, v2; float len, c, l, vec[3]; @@ -1786,8 +1786,8 @@ int cloth_calc_helper_forces(Object *UNUSED(ob), ClothModifierData * clmd, float continue; v1 = spring->ij; v2 = spring->kl; - cv1 = cloth->verts + v1; - cv2 = cloth->verts + v2; + /* cv1 = cloth->verts + v1; */ /* UNUSED */ + /* cv2 = cloth->verts + v2; */ /* UNUSED */ len = len_v3v3(cos[v1], cos[v2]); sub_v3_v3v3(vec, cos[v1], cos[v2]); diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 5df07246b73..48995572117 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -1177,7 +1177,7 @@ static void old_mdisps_convert(MFace *mface, MDisps *mdisp) int nvert = (mface->v4)? 4: 3; int newtotdisp = multires_grid_tot[newlvl]*nvert; int x, y, S; - float (*disps)[3], (*out)[3], u, v; + float (*disps)[3], (*out)[3], u = 0.0f, v = 0.0f; /* Quite gcc barking. */ disps = BLI_cellalloc_calloc(sizeof(float) * 3 * newtotdisp, "multires disps"); diff --git a/source/blender/blenkernel/intern/navmesh_conversion.c b/source/blender/blenkernel/intern/navmesh_conversion.c index 8a2ec1e5169..04f6ff19564 100644 --- a/source/blender/blenkernel/intern/navmesh_conversion.c +++ b/source/blender/blenkernel/intern/navmesh_conversion.c @@ -328,14 +328,10 @@ struct SortContext const int* trisToFacesMap; }; -/* XXX: not thread-safe, but it's called only from modifiers stack - which isn't threaded. Anyway, better to avoid this in the future */ -static struct SortContext *_qsort_context; - -static int compareByData(const void * a, const void * b) +static int compareByData(void *ctx, const void * a, const void * b) { - return ( _qsort_context->recastData[_qsort_context->trisToFacesMap[*(int*)a]] - - _qsort_context->recastData[_qsort_context->trisToFacesMap[*(int*)b]] ); + return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int*)a]] - + ((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int*)b]] ); } int buildNavMeshData(const int nverts, const float* verts, @@ -367,8 +363,7 @@ int buildNavMeshData(const int nverts, const float* verts, trisMapping[i]=i; context.recastData = recastData; context.trisToFacesMap = trisToFacesMap; - _qsort_context = &context; - qsort(trisMapping, ntris, sizeof(int), compareByData); + recast_qsort(trisMapping, ntris, sizeof(int), &context, compareByData); //search first valid triangle - triangle of convex polygon validTriStart = -1; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index e7203775a22..13d891dcd64 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -3067,6 +3067,82 @@ void object_camera_matrix( } +void camera_view_frame_ex(Scene *scene, Camera *camera, float drawsize, const short do_clip, const float scale[3], + float r_asp[2], float r_shift[2], float *r_drawsize, float r_vec[4][3]) +{ + float aspx, aspy; + float facx, facy; + float depth; + + /* aspect correcton */ + if (scene) { + aspx= (float) scene->r.xsch*scene->r.xasp; + aspy= (float) scene->r.ysch*scene->r.yasp; + + if(aspx < aspy) { + r_asp[0]= aspx / aspy; + r_asp[1]= 1.0; + } + else { + r_asp[0]= 1.0; + r_asp[1]= aspy / aspx; + } + } + else { + aspx= 1.0f; + aspy= 1.0f; + r_asp[0]= 1.0f; + r_asp[1]= 1.0f; + } + + if(camera->type==CAM_ORTHO) { + facx= 0.5f * camera->ortho_scale * r_asp[0] * scale[0]; + facy= 0.5f * camera->ortho_scale * r_asp[1] * scale[1]; + r_shift[0]= camera->shiftx * camera->ortho_scale * scale[0]; + r_shift[1]= camera->shifty * camera->ortho_scale * scale[1]; + depth= do_clip ? -((camera->clipsta * scale[2]) + 0.1f) : - drawsize * camera->ortho_scale * scale[2]; + + *r_drawsize= 0.5f * camera->ortho_scale; + } + else { + /* that way it's always visible - clipsta+0.1 */ + float fac; + *r_drawsize= drawsize / ((scale[0] + scale[1] + scale[2]) / 3.0f); + + if(do_clip) { + /* fixed depth, variable size (avoids exceeding clipping range) */ + depth = -(camera->clipsta + 0.1f); + fac = depth / (camera->lens/-16.0f * scale[2]); + } + else { + /* fixed size, variable depth (stays a reasonable size in the 3D view) */ + depth= *r_drawsize * camera->lens/-16.0f * scale[2]; + fac= *r_drawsize; + } + + facx= fac * r_asp[0] * scale[0]; + facy= fac * r_asp[1] * scale[1]; + r_shift[0]= camera->shiftx*fac*2 * scale[0]; + r_shift[1]= camera->shifty*fac*2 * scale[1]; + } + + r_vec[0][0]= r_shift[0] + facx; r_vec[0][1]= r_shift[1] + facy; r_vec[0][2]= depth; + r_vec[1][0]= r_shift[0] + facx; r_vec[1][1]= r_shift[1] - facy; r_vec[1][2]= depth; + r_vec[2][0]= r_shift[0] - facx; r_vec[2][1]= r_shift[1] - facy; r_vec[2][2]= depth; + r_vec[3][0]= r_shift[0] - facx; r_vec[3][1]= r_shift[1] + facy; r_vec[3][2]= depth; +} + +void camera_view_frame(Scene *scene, Camera *camera, float r_vec[4][3]) +{ + float dummy_asp[2]; + float dummy_shift[2]; + float dummy_drawsize; + const float dummy_scale[3]= {1.0f, 1.0f, 1.0f}; + + camera_view_frame_ex(scene, camera, FALSE, 1.0, dummy_scale, + dummy_asp, dummy_shift, &dummy_drawsize, r_vec); +} + #if 0 static int pc_findindex(ListBase *listbase, int index) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index d8ae36b4ab5..1a72405ad5e 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -526,7 +526,7 @@ Scene *add_scene(const char *name) sce->gm.recastData.agentradius = 0.6f; sce->gm.recastData.edgemaxlen = 12.0f; sce->gm.recastData.edgemaxerror = 1.3f; - sce->gm.recastData.regionminsize = 50.f; + sce->gm.recastData.regionminsize = 8.f; sce->gm.recastData.regionmergesize = 20.f; sce->gm.recastData.vertsperpoly = 6; sce->gm.recastData.detailsampledist = 6.0f; diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 2960d8a41e5..784c67d6d77 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -1744,12 +1744,12 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], GHash *hash; GHashIterator *ihash; float nv1[3], nv2[3], nv3[3], nv4[3], edge1[3], edge2[3],d_nvect[3], dv1[3],ve[3],avel[3]={0.0,0.0,0.0}, - vv1[3], vv2[3], vv3[3], vv4[3], coledge[3]={0.0f, 0.0f, 0.0f}, mindistedge = 1000.0f, - outerforceaccu[3],innerforceaccu[3], - facedist,n_mag,force_mag_norm,minx,miny,minz,maxx,maxy,maxz, - innerfacethickness = -0.5f, outerfacethickness = 0.2f, - ee = 5.0f, ff = 0.1f, fa=1; - int a, deflected=0, cavel=0,ci=0; + vv1[3], vv2[3], vv3[3], vv4[3], coledge[3]={0.0f, 0.0f, 0.0f}, mindistedge = 1000.0f, + outerforceaccu[3], innerforceaccu[3], + facedist, /* n_mag, */ /* UNUSED */ force_mag_norm, minx, miny, minz, maxx, maxy, maxz, + innerfacethickness = -0.5f, outerfacethickness = 0.2f, + ee = 5.0f, ff = 0.1f, fa=1; + int a, deflected=0, cavel=0, ci=0; /* init */ *intrusion = 0.0f; hash = vertexowner->soft->scratch->colliderhash; @@ -1869,7 +1869,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], VECSUB(dv1,opco,nv2); /* abuse dv1 to have vertex in question at *origin* of triangle */ cross_v3_v3v3(d_nvect, edge2, edge1); - n_mag = normalize_v3(d_nvect); + /* n_mag = */ /* UNUSED */ normalize_v3(d_nvect); facedist = dot_v3v3(dv1,d_nvect); // so rules are // @@ -1906,7 +1906,7 @@ static int sb_detect_vertex_collisionCached(float opco[3], float facenormal[3], VECSUB(dv1,opco,nv4); /* abuse dv1 to have vertex in question at *origin* of triangle */ cross_v3_v3v3(d_nvect, edge2, edge1); - n_mag = normalize_v3(d_nvect); + /* n_mag = */ /* UNUSED */ normalize_v3(d_nvect); facedist = dot_v3v3(dv1,d_nvect); if ((facedist > innerfacethickness) && (facedist < outerfacethickness)){ diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 38165182d83..ea6f6eb702b 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -640,7 +640,11 @@ void default_mtex(MTex *mtex) mtex->size[1]= 1.0; mtex->size[2]= 1.0; mtex->tex= NULL; - mtex->texflag= MTEX_3TAP_BUMP | MTEX_BUMP_OBJECTSPACE; + + /* MTEX_BUMP_FLIPPED is temporary before 2.61 release to prevent flipping normals + when creating file in 2.60, opening it in 2.59, saving and opening in 2.60 again */ + mtex->texflag= MTEX_3TAP_BUMP | MTEX_BUMP_OBJECTSPACE | MTEX_BUMP_FLIPPED; + mtex->colormodel= 0; mtex->r= 1.0; mtex->g= 0.0; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 829e1ddcc76..4ecfc648ebf 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -7124,7 +7124,7 @@ void convert_tface_mt(FileData *fd, Main *main) G.main = main; if(!(do_version_tface(main, 1))) { - BKE_report(fd->reports, RPT_ERROR, "Texface conversion problem. Error in console"); + BKE_report(fd->reports, RPT_WARNING, "Texface conversion problem. Error in console"); } //XXX hack, material.c uses G.main allover the place, instead of main @@ -12129,9 +12129,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) } } - /* put compatibility code here until next subversion bump */ - - { + if (main->versionfile < 259 || (main->versionfile == 259 && main->subversionfile < 4)){ { /* Adaptive time step for particle systems */ ParticleSettings *part; @@ -12140,45 +12138,72 @@ static void do_versions(FileData *fd, Library *lib, Main *main) part->time_flag &= ~PART_TIME_AUTOSF; } } + + { + /* set defaults for obstacle avoidance, recast data */ + Scene *sce; + for(sce = main->scene.first; sce; sce = sce->id.next) + { + if (sce->gm.levelHeight == 0.f) + sce->gm.levelHeight = 2.f; + + if(sce->gm.recastData.cellsize == 0.0f) + sce->gm.recastData.cellsize = 0.3f; + if(sce->gm.recastData.cellheight == 0.0f) + sce->gm.recastData.cellheight = 0.2f; + if(sce->gm.recastData.agentmaxslope == 0.0f) + sce->gm.recastData.agentmaxslope = (float)M_PI/4; + if(sce->gm.recastData.agentmaxclimb == 0.0f) + sce->gm.recastData.agentmaxclimb = 0.9f; + if(sce->gm.recastData.agentheight == 0.0f) + sce->gm.recastData.agentheight = 2.0f; + if(sce->gm.recastData.agentradius == 0.0f) + sce->gm.recastData.agentradius = 0.6f; + if(sce->gm.recastData.edgemaxlen == 0.0f) + sce->gm.recastData.edgemaxlen = 12.0f; + if(sce->gm.recastData.edgemaxerror == 0.0f) + sce->gm.recastData.edgemaxerror = 1.3f; + if(sce->gm.recastData.regionminsize == 0.0f) + sce->gm.recastData.regionminsize = 8.f; + if(sce->gm.recastData.regionmergesize == 0.0f) + sce->gm.recastData.regionmergesize = 20.f; + if(sce->gm.recastData.vertsperpoly<3) + sce->gm.recastData.vertsperpoly = 6; + if(sce->gm.recastData.detailsampledist == 0.0f) + sce->gm.recastData.detailsampledist = 6.0f; + if(sce->gm.recastData.detailsamplemaxerror == 0.0f) + sce->gm.recastData.detailsamplemaxerror = 1.0f; + } + } + + { + /* flip normals */ + Material *ma= main->mat.first; + while(ma) { + int a; + for(a= 0; a<MAX_MTEX; a++) { + MTex *mtex= ma->mtex[a]; + + if(mtex) { + if((mtex->texflag&MTEX_BUMP_FLIPPED)==0) { + if((mtex->mapto&MAP_NORM) && mtex->texflag&(MTEX_COMPAT_BUMP|MTEX_3TAP_BUMP|MTEX_5TAP_BUMP)) { + mtex->norfac= -mtex->norfac; + mtex->texflag|= MTEX_BUMP_FLIPPED; + } + } + } + } + + ma= ma->id.next; + } + } + } - //set defaults for obstacle avoidance, recast data + /* put compatibility code here until next subversion bump */ { - Scene *sce; - for(sce = main->scene.first; sce; sce = sce->id.next) - { - if (sce->gm.levelHeight == 0.f) - sce->gm.levelHeight = 2.f; - - if(sce->gm.recastData.cellsize == 0.0f) - sce->gm.recastData.cellsize = 0.3f; - if(sce->gm.recastData.cellheight == 0.0f) - sce->gm.recastData.cellheight = 0.2f; - if(sce->gm.recastData.agentmaxslope == 0.0f) - sce->gm.recastData.agentmaxslope = (float)M_PI/4; - if(sce->gm.recastData.agentmaxclimb == 0.0f) - sce->gm.recastData.agentmaxclimb = 0.9f; - if(sce->gm.recastData.agentheight == 0.0f) - sce->gm.recastData.agentheight = 2.0f; - if(sce->gm.recastData.agentradius == 0.0f) - sce->gm.recastData.agentradius = 0.6f; - if(sce->gm.recastData.edgemaxlen == 0.0f) - sce->gm.recastData.edgemaxlen = 12.0f; - if(sce->gm.recastData.edgemaxerror == 0.0f) - sce->gm.recastData.edgemaxerror = 1.3f; - if(sce->gm.recastData.regionminsize == 0.0f) - sce->gm.recastData.regionminsize = 50.f; - if(sce->gm.recastData.regionmergesize == 0.0f) - sce->gm.recastData.regionmergesize = 20.f; - if(sce->gm.recastData.vertsperpoly<3) - sce->gm.recastData.vertsperpoly = 6; - if(sce->gm.recastData.detailsampledist == 0.0f) - sce->gm.recastData.detailsampledist = 6.0f; - if(sce->gm.recastData.detailsamplemaxerror == 0.0f) - sce->gm.recastData.detailsamplemaxerror = 1.0f; - } } - + /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index bd5935c893c..c982a1d7f86 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -343,6 +343,13 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac) * channel can be kept around). No need to clear channels-flag in order to * keep expander channels with no sub-data out, as those cases should get * dealt with by the recursive detection idiom in place. + * + * Implementation Note: + * YES the _doSubChannels variable is NOT read anywhere. BUT, this is NOT an excuse + * to go steamrolling the logic into a single-line expression as from experience, + * those are notoriously difficult to read + debug when extending later on. The code + * below is purposefully laid out so that each case noted above corresponds clearly to + * one case below. */ #define BEGIN_ANIMFILTER_SUBCHANNELS(expanded_check) \ { \ diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index fa619e4cf44..af78fe739cc 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -51,6 +51,7 @@ #include "DNA_node_types.h" #include "DNA_particle_types.h" #include "DNA_scene_types.h" +#include "DNA_space_types.h" #include "DNA_world_types.h" #include "BKE_fcurve.h" @@ -386,6 +387,9 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac) ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; int filter; + /* when not in graph view, don't use handles */ + SpaceIpo *sipo= (ac->spacetype == SPACE_IPO) ? (SpaceIpo *)ac->sl : NULL; + const short use_handle = sipo ? !(sipo->flag & SIPO_NOHANDLES) : FALSE; /* filter animation data */ filter= ANIMFILTER_DATA_VISIBLE; @@ -397,7 +401,7 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac) /* make sure keyframes in F-Curve are all in order, and handles are in valid positions */ sort_time_fcurve(fcu); - testhandles_fcurve(fcu); + testhandles_fcurve(fcu, use_handle); } /* free temp data */ diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 4a895472b33..a5781ab7267 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -787,6 +787,7 @@ void UI_buttons_operatortypes(void); /* Helpers for Operators */ void uiContextActiveProperty(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index); +void uiContextActivePropertyHandle(struct bContext *C); void uiContextAnimUpdate(const struct bContext *C); void uiFileBrowseContextProperty(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop); void uiIDContextProperty(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 286906402b9..a3ae39c8440 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -678,6 +678,11 @@ static int ui_but_update_from_old_block(const bContext *C, uiBlock *block, uiBut SWAP(void *, oldbut->func_argN, but->func_argN) } + /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position + when scrolling without moving mouse (see [#28432]) */ + if(ELEM(oldbut->type, ROW, LISTROW)) + oldbut->hardmax= but->hardmax; + ui_but_update_linklines(block, oldbut, but); BLI_remlink(&block->buttons, but); @@ -746,7 +751,7 @@ static int ui_but_is_rna_undo(uiBut *but) * unforseen conciquences, so best check for ID's we _know_ are not * handled by undo - campbell */ ID *id= but->rnapoin.id.data; - if(ELEM(GS(id->name), ID_SCR, ID_WM)) { + if(ID_CHECK_UNDO(id) == FALSE) { return FALSE; } else { @@ -2467,7 +2472,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str, but->pointype= type & BUTPOIN; but->bit= type & BIT; but->bitnr= type & 31; - but->icon = 0; + but->icon = ICON_NONE; but->iconadd=0; but->retval= retval; diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index b65be48f7ee..a40900fb39b 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -466,6 +466,7 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w { #ifdef WITH_HEADLESS (void)rect; + (void)but; #else ImBuf *ibuf= (ImBuf *)but->poin; //GLint scissor[4]; diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 082ddb5b060..929a8bf1dc6 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -5089,19 +5089,16 @@ void ui_button_active_free(const bContext *C, uiBut *but) } } -/* helper function for insert keyframe, reset to default, etc operators */ -void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index) +static uiBut *ui_context_rna_button_active(const bContext *C) { - ARegion *ar= CTX_wm_region(C); + uiBut *rnabut= NULL; - memset(ptr, 0, sizeof(*ptr)); - *prop= NULL; - *index= 0; + ARegion *ar= CTX_wm_region(C); while(ar) { uiBlock *block; uiBut *but, *activebut= NULL; - + /* find active button */ for(block=ar->uiblocks.first; block; block=block->next) { for(but=block->buttons.first; but; but= but->next) { @@ -5115,24 +5112,53 @@ void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct P if(activebut && activebut->rnapoin.data) { uiHandleButtonData *data= activebut->active; - /* found RNA button */ - *ptr= activebut->rnapoin; - *prop= activebut->rnaprop; - *index= activebut->rnaindex; + rnabut= activebut; /* recurse into opened menu, like colorpicker case */ if(data && data->menu && (ar != data->menu->region)) { ar = data->menu->region; } else { - return; + return rnabut; } } else { /* no active button */ - return; + return rnabut; } } + + return rnabut; +} + +/* helper function for insert keyframe, reset to default, etc operators */ +void uiContextActiveProperty(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index) +{ + uiBut *activebut= ui_context_rna_button_active(C); + + memset(ptr, 0, sizeof(*ptr)); + + if(activebut && activebut->rnapoin.data) { + *ptr= activebut->rnapoin; + *prop= activebut->rnaprop; + *index= activebut->rnaindex; + } + else { + *prop= NULL; + *index= 0; + } +} + +void uiContextActivePropertyHandle(bContext *C) +{ + uiBut *activebut= ui_context_rna_button_active(C); + if(activebut) { + /* TODO, look into a better way to handle the button change + * currently this is mainly so reset defaults works for the + * operator redo panel - campbell */ + uiBlock *block= activebut->block; + block->handle_func(C, block->handle_func_arg, 0); + } } /* helper function for insert keyframe, reset to default, etc operators */ diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index fbad34252e7..24434465f5f 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1018,9 +1018,9 @@ static void ui_id_icon_render(bContext *C, ID *id, int big) { /* create the rect if necessary */ - icon_set_image(C, id, pi, 0); /* icon size */ + icon_set_image(C, id, pi, ICON_SIZE_ICON); /* icon size */ if (big) - icon_set_image(C, id, pi, 1); /* bigger preview size */ + icon_set_image(C, id, pi, ICON_SIZE_PREVIEW); /* bigger preview size */ pi->changed[0] = 0; } @@ -1030,7 +1030,7 @@ static void ui_id_icon_render(bContext *C, ID *id, int big) static void ui_id_brush_render(bContext *C, ID *id) { PreviewImage *pi = BKE_previewimg_get(id); - int i; + enum eIconSizes i; if(!pi) return; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index fd9386dc5ab..081b528d153 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -295,10 +295,28 @@ static int reset_default_button_exec(bContext *C, wmOperator *op) if(RNA_property_reset(&ptr, prop, (all)? -1: index)) { /* perform updates required for this property */ RNA_property_update(C, &ptr, prop); + + /* as if we pressed the button */ + uiContextActivePropertyHandle(C); + success= 1; } } - + + /* Since we dont want to undo _all_ edits to settings, eg window + * edits on the screen or on operator settings. + * it might be better to move undo's inline - campbell */ + if(success) { + ID *id= ptr.id.data; + if(id && ID_CHECK_UNDO(id)) { + /* do nothing, go ahead with undo */ + } + else { + return OPERATOR_CANCELLED; + } + } + /* end hack */ + return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; } @@ -314,7 +332,7 @@ static void UI_OT_reset_default_button(wmOperatorType *ot) ot->exec= reset_default_button_exec; /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; + ot->flag= OPTYPE_UNDO; /* properties */ RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 44aa6d1e090..ff6ef41bfb0 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -415,7 +415,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str BLI_snprintf(str, sizeof(str), "%d", id->us); but= uiDefBut(block, BUT, 0, str, 0,0,UI_UNIT_X + ((id->us < 10) ? 0:10), UI_UNIT_Y, NULL, 0, 0, 0, 0, - UI_translate_do_tooltip(_("Displays number of users of this data. Click to make a single-user copy"))); + UI_translate_do_tooltip(_("Display number of users of this data (click to make a single-user copy)"))); uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE)); if(!id_copy(id, NULL, 1 /* test only */) || (idfrom && idfrom->lib) || !editable) diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c index 1cd5dcdb241..e4b884744e1 100644 --- a/source/blender/editors/mesh/mesh_navmesh.c +++ b/source/blender/editors/mesh/mesh_navmesh.c @@ -174,7 +174,7 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts struct recast_compactHeightfield* chf; struct recast_contourSet *cset; int width, height, walkableHeight, walkableClimb, walkableRadius; - int minRegionSize, mergeRegionSize, maxEdgeLen; + int minRegionArea, mergeRegionArea, maxEdgeLen; float detailSampleDist, detailSampleMaxError; recast_calcBounds(verts, nverts, bmin, bmax); @@ -183,8 +183,8 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts walkableHeight= (int)ceilf(recastParams->agentheight/ recastParams->cellheight); walkableClimb= (int)floorf(recastParams->agentmaxclimb / recastParams->cellheight); walkableRadius= (int)ceilf(recastParams->agentradius / recastParams->cellsize); - minRegionSize= (int)(recastParams->regionminsize * recastParams->regionminsize); - mergeRegionSize= (int)(recastParams->regionmergesize * recastParams->regionmergesize); + minRegionArea= (int)(recastParams->regionminsize * recastParams->regionminsize); + mergeRegionArea= (int)(recastParams->regionmergesize * recastParams->regionmergesize); maxEdgeLen= (int)(recastParams->edgemaxlen/recastParams->cellsize); detailSampleDist= recastParams->detailsampledist< 0.9f ? 0 : recastParams->cellsize * recastParams->detailsampledist; @@ -212,13 +212,14 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts MEM_freeN(triflags); /* ** Step 3: Filter walkables surfaces ** */ + recast_filterLowHangingWalkableObstacles(walkableClimb, solid); recast_filterLedgeSpans(walkableHeight, walkableClimb, solid); recast_filterWalkableLowHeightSpans(walkableHeight, solid); /* ** Step 4: Partition walkable surface to simple regions ** */ chf= recast_newCompactHeightfield(); - if(!recast_buildCompactHeightfield(walkableHeight, walkableClimb, RECAST_WALKABLE, solid, chf)) { + if(!recast_buildCompactHeightfield(walkableHeight, walkableClimb, solid, chf)) { recast_destroyHeightfield(solid); recast_destroyCompactHeightfield(chf); @@ -226,6 +227,13 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts } recast_destroyHeightfield(solid); + solid = NULL; + + if (!recast_erodeWalkableArea(walkableRadius, chf)) { + recast_destroyCompactHeightfield(chf); + + return 0; + } /* Prepare for region partitioning, by calculating distance field along the walkable surface */ if(!recast_buildDistanceField(chf)) { @@ -235,7 +243,7 @@ static int buildNavMesh(const RecastData *recastParams, int nverts, float *verts } /* Partition the walkable surface into simple regions without holes */ - if(!recast_buildRegions(chf, walkableRadius, 0, minRegionSize, mergeRegionSize)) { + if(!recast_buildRegions(chf, 0, minRegionArea, mergeRegionArea)) { recast_destroyCompactHeightfield(chf); return 0; @@ -293,7 +301,8 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, Object* obedit; int createob= base==NULL; int nverts, nmeshes, nvp; - unsigned short *verts, *meshes, *polys; + unsigned short *verts, *polys; + unsigned int *meshes; float bmin[3], cs, ch, *dverts; unsigned char *tris; ModifierData *md; @@ -348,7 +357,7 @@ static Object* createRepresentation(bContext *C, struct recast_polyMesh *pmesh, for(i= 0; i<nmeshes; i++) { int uniquevbase= em->totvert; - unsigned short vbase= meshes[4*i+0]; + unsigned int vbase= meshes[4*i+0]; unsigned short ndv= meshes[4*i+1]; unsigned short tribase= meshes[4*i+2]; unsigned short trinum= meshes[4*i+3]; diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index 2f62e55bcd8..918adcac138 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -1145,7 +1145,7 @@ static int fluid_bake_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event) { /* only one bake job at a time */ if(WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C))) - return 0; + return OPERATOR_CANCELLED; if(!fluidsimBake(C, op->reports, CTX_data_active_object(C), TRUE)) return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 60662334e20..fdf9209c813 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -233,7 +233,8 @@ static void get_keyframe_extents (bAnimContext *ac, float *min, float *max, cons /* get data to filter, from Action or Dopesheet */ // XXX: what is sel doing here?! - filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); + // Commented it, was breaking things (eg. the "auto preview range" tool). + filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL *//*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS); ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* set large values to try to override */ diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 28fd1cd3304..f1593105d5b 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -245,13 +245,15 @@ static short get_active_fcurve_keyframe_edit(FCurve *fcu, BezTriple **bezt, BezT } /* update callback for active keyframe properties - base updates stuff */ -static void graphedit_activekey_update_cb(bContext *UNUSED(C), void *fcu_ptr, void *UNUSED(bezt_ptr)) +static void graphedit_activekey_update_cb(bContext *C, void *fcu_ptr, void *UNUSED(bezt_ptr)) { + SpaceIpo *sipo= CTX_wm_space_graph(C); + const short use_handle = !(sipo->flag & SIPO_NOHANDLES); FCurve *fcu = (FCurve *)fcu_ptr; /* make sure F-Curve and its handles are still valid after this editing */ sort_time_fcurve(fcu); - testhandles_fcurve(fcu); + testhandles_fcurve(fcu, use_handle); } /* update callback for active keyframe properties - handle-editing wrapper */ diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 49d8b6b5da4..673ddaebc5f 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -182,6 +182,10 @@ static void outliner_main_area_listener(ARegion *ar, wmNotifier *wmn) case ND_NLA_ACTCHANGE: ED_region_tag_redraw(ar); break; + case ND_ANIMCHAN: + if(wmn->action==NA_SELECTED) + ED_region_tag_redraw(ar); + break; } break; } diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 89e9a22c9a1..a0999c9a03b 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -134,7 +134,7 @@ void SEQUENCER_OT_select_handles(struct wmOperatorType *ot); void SEQUENCER_OT_select_active_side(struct wmOperatorType *ot); void SEQUENCER_OT_select_border(struct wmOperatorType *ot); void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot); - +void SEQUENCER_OT_select_grouped(struct wmOperatorType *ot); /* sequencer_select.c */ void SEQUENCER_OT_scene_strip_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index 5c13b57cca8..b53284136de 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -103,7 +103,8 @@ void sequencer_operatortypes(void) WM_operatortype_append(SEQUENCER_OT_select_handles); WM_operatortype_append(SEQUENCER_OT_select_active_side); WM_operatortype_append(SEQUENCER_OT_select_border); - + WM_operatortype_append(SEQUENCER_OT_select_grouped); + /* sequencer_add.c */ WM_operatortype_append(SEQUENCER_OT_scene_strip_add); WM_operatortype_append(SEQUENCER_OT_movie_strip_add); @@ -165,7 +166,7 @@ void sequencer_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_toggle", TABKEY, KM_PRESS, 0, 0); - WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_make", GKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_make", GKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "SEQUENCER_OT_meta_separate", GKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "SEQUENCER_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); @@ -247,6 +248,8 @@ void sequencer_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "SEQUENCER_OT_select_border", BKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "SEQUENCER_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_menu(keymap, "SEQUENCER_MT_add", AKEY, KM_PRESS, KM_SHIFT, 0); WM_keymap_add_menu(keymap, "SEQUENCER_MT_change", CKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index 3ea27899128..45dd08e3ece 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -47,6 +47,7 @@ #include "DNA_scene_types.h" #include "BKE_context.h" +#include "BKE_report.h" #include "BKE_sequencer.h" #include "WM_api.h" @@ -882,3 +883,270 @@ void SEQUENCER_OT_select_border(wmOperatorType *ot) /* rna */ WM_operator_properties_gesture_border(ot, FALSE); } + +/* ****** Selected Grouped ****** */ + +static EnumPropertyItem sequencer_prop_select_grouped_types[] = { + {1, "TYPE", 0, "Type", "Shared strip type"}, + {2, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"}, + {3, "TYPE_EFFECT", 0, "Effect Type", + "Shared strip effect type (if active strip is not an effect one, select all non-effect strips)"}, + {4, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"}, + {5, "EFFECT", 0, "Effect", "Shared effects"}, + {6, "EFFECT_LINK", 0, "Effect/Linked", + "Other strips affected by the active one (sharing some time, and below or effect-assigned)"}, + {7, "OVERLAP", 0, "Overlap", "Overlapping time"}, + {0, NULL, 0, NULL, NULL} +}; + +#define SEQ_IS_SOUND(_seq) ((_seq->type & SEQ_SOUND) && !(_seq->type & SEQ_EFFECT)) + +#define SEQ_IS_EFFECT(_seq) (_seq->type & SEQ_EFFECT) + +#define SEQ_USE_DATA(_seq) (_seq->type == SEQ_SCENE || SEQ_HAS_PATH(_seq)) + +static short select_grouped_type(Editing *ed, Sequence *actseq) +{ + Sequence *seq; + short changed = FALSE; + + SEQP_BEGIN(ed, seq) { + if (seq->type == actseq->type) { + seq->flag |= SELECT; + changed = TRUE; + } + } + SEQ_END; + + return changed; +} + +static short select_grouped_type_basic(Editing *ed, Sequence *actseq) +{ + Sequence *seq; + short changed = FALSE; + short is_sound = SEQ_IS_SOUND(actseq); + + SEQP_BEGIN(ed, seq) { + if (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq)) { + seq->flag |= SELECT; + changed = TRUE; + } + } + SEQ_END; + + return changed; +} + +static short select_grouped_type_effect(Editing *ed, Sequence *actseq) +{ + Sequence *seq; + short changed = FALSE; + short is_effect = SEQ_IS_EFFECT(actseq); + + SEQP_BEGIN(ed, seq) { + if (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq)) { + seq->flag |= SELECT; + changed = TRUE; + } + } + SEQ_END; + + return changed; +} + +static short select_grouped_data(Editing *ed, Sequence *actseq) +{ + Sequence *seq; + short changed = FALSE; + Scene *sce = actseq->scene; + char *dir = actseq->strip ? actseq->strip->dir : NULL; + + if (!SEQ_USE_DATA(actseq)) + return changed; + + if (SEQ_HAS_PATH(actseq) && dir) { + SEQP_BEGIN(ed, seq) { + if (SEQ_HAS_PATH(seq) && seq->strip && strcmp(seq->strip->dir, dir) == 0) { + seq->flag |= SELECT; + changed = TRUE; + } + } + SEQ_END; + } + else { + SEQP_BEGIN(ed, seq) { + if (seq->type == SEQ_SCENE && seq->scene == sce) { + seq->flag |= SELECT; + changed = TRUE; + } + } + SEQ_END; + } + + return changed; +} + +static short select_grouped_effect(Editing *ed, Sequence *actseq) +{ + Sequence *seq; + short changed = FALSE; + short effects[SEQ_EFFECT_MAX+1]; + int i; + + for (i = 0; i <= SEQ_EFFECT_MAX; i++) + effects[i] = FALSE; + + SEQP_BEGIN(ed, seq) { + if (ELEM3(actseq, seq->seq1, seq->seq2, seq->seq3)) { + effects[seq->type] = TRUE; + } + } + SEQ_END; + + SEQP_BEGIN(ed, seq) { + if (effects[seq->type]) { + if(seq->seq1) seq->seq1->flag |= SELECT; + if(seq->seq2) seq->seq2->flag |= SELECT; + if(seq->seq3) seq->seq3->flag |= SELECT; + changed = TRUE; + } + } + SEQ_END; + + return changed; +} + +static short select_grouped_time_overlap(Editing *ed, Sequence *actseq) +{ + Sequence *seq; + short changed = FALSE; + + SEQP_BEGIN(ed, seq) { + if (!((seq->startdisp >= actseq->enddisp) || (seq->enddisp < actseq->startdisp))) { + seq->flag |= SELECT; + changed = TRUE; + } + } + SEQ_END; + + return changed; +} + +static short select_grouped_effect_link(Editing *ed, Sequence *actseq) +{ + Sequence *seq = NULL; + short changed = FALSE; + short is_audio = ((actseq->type == SEQ_META) || SEQ_IS_SOUND(actseq)); + int startdisp = actseq->startdisp; + int enddisp = actseq->enddisp; + int machine = actseq->machine; + SeqIterator iter; + + SEQP_BEGIN(ed, seq) { + seq->tmp= NULL; + } + SEQ_END; + + seq->tmp= SET_INT_IN_POINTER(TRUE); + + for(seq_begin(ed, &iter, 1); iter.valid; seq_next(&iter)) { + seq = iter.seq; + + /* Ignore all seqs already selected! */ + /* Ignore all seqs not sharing some time with active one. */ + /* Ignore all seqs of incompatible types (audio vs video). */ + if ((seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) + || (!is_audio && SEQ_IS_SOUND(seq)) + || (is_audio && !((seq->type == SEQ_META) || SEQ_IS_SOUND(seq)))) + continue; + + /* If the seq is an effect one, we need extra cheking! */ + if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) || + (seq->seq2 && seq->seq2->tmp) || + (seq->seq3 && seq->seq3->tmp))) + { + if (startdisp > seq->startdisp) startdisp = seq->startdisp; + if (enddisp < seq->enddisp) enddisp = seq->enddisp; + if (machine < seq->machine) machine = seq->machine; + + seq->tmp= SET_INT_IN_POINTER(TRUE); + + seq->flag |= SELECT; + changed = TRUE; + + /* Unfortunately, we must restart checks from the begining. */ + seq_end(&iter); + seq_begin(ed, &iter, 1); + } + + /* Video strips bellow active one, or any strip for audio (order do no matters here!). */ + else if (seq->machine < machine || is_audio) { + seq->flag |= SELECT; + changed = TRUE; + } + } + seq_end(&iter); + + return changed; +} + +static int sequencer_select_grouped_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + Editing *ed = seq_give_editing(scene, 0); + Sequence *seq, *actseq = seq_active_get(scene); + int type = RNA_enum_get(op->ptr, "type"); + short changed = 0, extend; + + extend = RNA_boolean_get(op->ptr, "extend"); + + if (actseq == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Active Sequence!"); + return OPERATOR_CANCELLED; + } + + if (extend == 0) { + SEQP_BEGIN(ed, seq) { + seq->flag &= ~SELECT; + changed = TRUE; + } + SEQ_END; + } + + if(type==1) changed |= select_grouped_type(ed, actseq); + else if(type==2) changed |= select_grouped_type_basic(ed, actseq); + else if(type==3) changed |= select_grouped_type_effect(ed, actseq); + else if(type==4) changed |= select_grouped_data(ed, actseq); + else if(type==5) changed |= select_grouped_effect(ed, actseq); + else if(type==6) changed |= select_grouped_effect_link(ed, actseq); + else if(type==7) changed |= select_grouped_time_overlap(ed, actseq); + + if (changed) { + WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene); + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +void SEQUENCER_OT_select_grouped(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Grouped"; + ot->description = "Select all strips grouped by various properties"; + ot->idname = "SEQUENCER_OT_select_grouped"; + + /* api callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = sequencer_select_grouped_exec; + ot->poll = sequencer_edit_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first"); + ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", ""); +} + diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index cb7ee18e829..b8fb8934dd9 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1373,15 +1373,12 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob { /* a standing up pyramid with (0,0,0) as top */ Camera *cam; - float vec[8][4], facx, facy, depth, aspx, aspy, caspx, caspy, shx, shy; + float tvec[3]; + float vec[4][3], asp[2], shift[2], scale[3]; int i; float drawsize; const short is_view= (rv3d->persp==RV3D_CAMOB && ob==v3d->camera); - const float scax= 1.0f / len_v3(ob->obmat[0]); - const float scay= 1.0f / len_v3(ob->obmat[1]); - const float scaz= 1.0f / len_v3(ob->obmat[2]); - #ifdef VIEW3D_CAMERA_BORDER_HACK if(is_view && !(G.f & G_PICKSEL)) { glGetFloatv(GL_CURRENT_COLOR, view3d_camera_border_hack_col); @@ -1391,82 +1388,43 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob #endif cam= ob->data; - aspx= (float) scene->r.xsch*scene->r.xasp; - aspy= (float) scene->r.ysch*scene->r.yasp; - if(aspx < aspy) { - caspx= aspx / aspy; - caspy= 1.0; - } - else { - caspx= 1.0; - caspy= aspy / aspx; - } - - glDisable(GL_LIGHTING); - glDisable(GL_CULL_FACE); - - if(cam->type==CAM_ORTHO) { - facx= 0.5f * cam->ortho_scale * caspx * scax; - facy= 0.5f * cam->ortho_scale * caspy * scay; - shx= cam->shiftx * cam->ortho_scale * scax; - shy= cam->shifty * cam->ortho_scale * scay; - depth= is_view ? -((cam->clipsta * scaz) + 0.1f) : - cam->drawsize * cam->ortho_scale * scaz; - - drawsize= 0.5f * cam->ortho_scale; - } - else { - /* that way it's always visible - clipsta+0.1 */ - float fac; - drawsize= cam->drawsize / ((scax + scay + scaz) / 3.0f); + scale[0]= 1.0f / len_v3(ob->obmat[0]); + scale[1]= 1.0f / len_v3(ob->obmat[1]); + scale[2]= 1.0f / len_v3(ob->obmat[2]); - if(is_view) { - /* fixed depth, variable size (avoids exceeding clipping range) */ - depth = -(cam->clipsta + 0.1f); - fac = depth / (cam->lens/-16.0f * scaz); - } - else { - /* fixed size, variable depth (stays a reasonable size in the 3D view) */ - depth= drawsize * cam->lens/-16.0f * scaz; - fac= drawsize; - } + camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale, + asp, shift, &drawsize, vec); - facx= fac * caspx * scax; - facy= fac * caspy * scay; - shx= cam->shiftx*fac*2 * scax; - shy= cam->shifty*fac*2 * scay; - } - - vec[0][0]= 0.0; vec[0][1]= 0.0; vec[0][2]= 0.0; - vec[1][0]= shx + facx; vec[1][1]= shy + facy; vec[1][2]= depth; - vec[2][0]= shx + facx; vec[2][1]= shy - facy; vec[2][2]= depth; - vec[3][0]= shx - facx; vec[3][1]= shy - facy; vec[3][2]= depth; - vec[4][0]= shx - facx; vec[4][1]= shy + facy; vec[4][2]= depth; + glDisable(GL_LIGHTING); + glDisable(GL_CULL_FACE); /* camera frame */ glBegin(GL_LINE_LOOP); - glVertex3fv(vec[1]); - glVertex3fv(vec[2]); - glVertex3fv(vec[3]); - glVertex3fv(vec[4]); + glVertex3fv(vec[0]); + glVertex3fv(vec[1]); + glVertex3fv(vec[2]); + glVertex3fv(vec[3]); glEnd(); if(is_view) return; + zero_v3(tvec); + /* center point to camera frame */ glBegin(GL_LINE_STRIP); - glVertex3fv(vec[2]); - glVertex3fv(vec[0]); - glVertex3fv(vec[1]); - glVertex3fv(vec[4]); - glVertex3fv(vec[0]); - glVertex3fv(vec[3]); + glVertex3fv(vec[1]); + glVertex3fv(tvec); + glVertex3fv(vec[0]); + glVertex3fv(vec[3]); + glVertex3fv(tvec); + glVertex3fv(vec[2]); glEnd(); /* arrow on top */ - vec[0][2]= depth; + tvec[2]= vec[1][2]; /* copy the depth */ /* draw an outline arrow for inactive cameras and filled @@ -1477,16 +1435,16 @@ static void drawcamera(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob else if (i==1 && (ob == v3d->camera)) glBegin(GL_TRIANGLES); else break; - vec[0][0]= shx + ((-0.7f * drawsize) * scax); - vec[0][1]= shy + ((drawsize * (caspy + 0.1f)) * scay); - glVertex3fv(vec[0]); /* left */ + tvec[0]= shift[0] + ((-0.7f * drawsize) * scale[0]); + tvec[1]= shift[1] + ((drawsize * (asp[1] + 0.1f)) * scale[1]); + glVertex3fv(tvec); /* left */ - vec[0][0]= shx + ((0.7f * drawsize) * scax); - glVertex3fv(vec[0]); /* right */ + tvec[0]= shift[0] + ((0.7f * drawsize) * scale[0]); + glVertex3fv(tvec); /* right */ - vec[0][0]= shx; - vec[0][1]= shy + ((1.1f * drawsize * (caspy + 0.7f)) * scay); - glVertex3fv(vec[0]); /* top */ + tvec[0]= shift[0]; + tvec[1]= shift[1] + ((1.1f * drawsize * (asp[1] + 0.7f)) * scale[1]); + glVertex3fv(tvec); /* top */ glEnd(); } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 3cb11b95665..7fefc4ae0fe 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -127,7 +127,7 @@ typedef struct { float ob_scale[3]; // need temp space due to linked values float ob_dims[3]; short link_scale; - float ve_median[6]; + float ve_median[7]; int curdef; float *defweightp; } TransformProperties; @@ -139,11 +139,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float uiBlock *block= (layout)? uiLayoutAbsoluteBlock(layout): NULL; MDeformVert *dvert=NULL; TransformProperties *tfp; - float median[6], ve_median[6]; + float median[7], ve_median[7]; int tot, totw, totweight, totedge, totradius; char defstr[320]; - - median[0]= median[1]= median[2]= median[3]= median[4]= median[5]= 0.0; + + median[0]= median[1]= median[2]= median[3]= median[4]= median[5]= median[6]= 0.0; tot= totw= totweight= totedge= totradius= 0; defstr[0]= 0; @@ -170,10 +170,14 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float BM_ITER(eed, &iter, bm, BM_EDGES_OF_MESH, NULL) { if(BM_TestHFlag(eed, BM_SELECT)) { - float *f = bm_get_cd_float(&bm->edata, eed->head.data, CD_CREASE); + float *f; totedge++; + f = bm_get_cd_float(&bm->edata, eed->head.data, CD_CREASE); median[3]+= f ? *f : 0.0f; + + f = bm_get_cd_float(&bm->edata, eed->head.data, CD_BWEIGHT); + median[6]+= f ? *f : 0.0f; } } @@ -284,7 +288,10 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float median[0] /= (float)tot; median[1] /= (float)tot; median[2] /= (float)tot; - if(totedge) median[3] /= (float)totedge; + if (totedge) { + median[3] /= (float)totedge; + median[6] /= (float)totedge; + } else if(totw) median[3] /= (float)totw; if(totweight) median[4] /= (float)totweight; if(totradius) median[5] /= (float)totradius; @@ -299,78 +306,82 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float uiBlockBeginAlign(block); if(tot==1) { - uiDefBut(block, LABEL, 0, "Vertex:", 0, 130, 200, 20, NULL, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "Vertex:", 0, 150, 200, 20, NULL, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); - but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "X:", 0, 110, 200, 20, &(tfp->ve_median[0]), -lim, lim, 10, 3, ""); + but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "X:", 0, 130, 200, 20, &(tfp->ve_median[0]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); - but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Y:", 0, 90, 200, 20, &(tfp->ve_median[1]), -lim, lim, 10, 3, ""); + but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Y:", 0, 110, 200, 20, &(tfp->ve_median[1]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); - but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Z:", 0, 70, 200, 20, &(tfp->ve_median[2]), -lim, lim, 10, 3, ""); + but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Z:", 0, 90, 200, 20, &(tfp->ve_median[2]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); if(totw==1) { - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "W:", 0, 50, 200, 20, &(tfp->ve_median[3]), 0.01, 100.0, 1, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "W:", 0, 70, 200, 20, &(tfp->ve_median[3]), 0.01, 100.0, 1, 3, ""); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); - uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); + uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); + uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); uiBlockEndAlign(block); if(totweight) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 0, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 1, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 1, 3, ""); if(totradius) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 0, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 1, 3, "Radius of curve CPs"); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 20, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 1, 3, "Radius of curve CPs"); } else { uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); - uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); + uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 65, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); + uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 65, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); uiBlockEndAlign(block); if(totweight) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 40, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, ""); if(totradius) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 20, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 10, 3, "Radius of curve CPs"); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 40, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 10, 3, "Radius of curve CPs"); } } else { - uiDefBut(block, LABEL, 0, "Median:", 0, 130, 200, 20, NULL, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "Median:", 0, 150, 200, 20, NULL, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); - but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "X:", 0, 110, 200, 20, &(tfp->ve_median[0]), -lim, lim, 10, 3, ""); + but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "X:", 0, 130, 200, 20, &(tfp->ve_median[0]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); - but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Y:", 0, 90, 200, 20, &(tfp->ve_median[1]), -lim, lim, 10, 3, ""); + but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Y:", 0, 110, 200, 20, &(tfp->ve_median[1]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); - but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Z:", 0, 70, 200, 20, &(tfp->ve_median[2]), -lim, lim, 10, 3, ""); + but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Z:", 0, 90, 200, 20, &(tfp->ve_median[2]), -lim, lim, 10, 3, ""); uiButSetUnitType(but, PROP_UNIT_LENGTH); if(totw==tot) { - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "W:", 0, 50, 200, 20, &(tfp->ve_median[3]), 0.01, 100.0, 1, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "W:", 0, 70, 200, 20, &(tfp->ve_median[3]), 0.01, 100.0, 1, 3, ""); uiBlockEndAlign(block); uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); - uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 25, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); + uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); + uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); uiBlockEndAlign(block); if(totweight) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 0, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "Weight is used for SoftBody Goal"); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "Weight is used for SoftBody Goal"); if(totradius) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 0, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 10, 3, "Radius of curve CPs"); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 20, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 10, 3, "Radius of curve CPs"); uiBlockEndAlign(block); } else { uiBlockBeginAlign(block); - uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); - uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 45, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); + uiDefButBitS(block, TOG, V3D_GLOBAL_STATS, B_REDR, "Global", 0, 65, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays global values"); + uiDefButBitS(block, TOGN, V3D_GLOBAL_STATS, B_REDR, "Local", 100, 65, 100, 20, &v3d->flag, 0, 0, 0, 0, "Displays local values"); uiBlockEndAlign(block); if(totweight) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 1, 3, "Weight is used for SoftBody Goal"); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Weight:", 0, 40, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 1, 3, "Weight is used for SoftBody Goal"); if(totradius) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 0, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 1, 3, "Radius of curve CPs"); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Radius:", 0, 20, 200, 20, &(tfp->ve_median[5]), 0.0, 100.0, 1, 3, "Radius of curve CPs"); uiBlockEndAlign(block); } } - - if(totedge==1) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Crease:", 0, 20, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 1, 3, ""); - else if(totedge>1) - uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Mean Crease:", 0, 20, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 1, 3, ""); - + + if(totedge==1){ + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Crease:", 0, 40, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 1, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Bevel Weight:", 0, 20, 200, 20, &(tfp->ve_median[6]), 0.0, 1.0, 1, 3, ""); + } + else if(totedge>1){ + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Mean Crease:", 0, 40, 200, 20, &(tfp->ve_median[3]), 0.0, 1.0, 1, 3, ""); + uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Mean Bevel Weight:", 0, 20, 200, 20, &(tfp->ve_median[6]), 0.0, 1.0, 1, 3, ""); + } + } else { // apply memcpy(ve_median, tfp->ve_median, sizeof(tfp->ve_median)); @@ -384,6 +395,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float median[3]= ve_median[3]-median[3]; median[4]= ve_median[4]-median[4]; median[5]= ve_median[5]-median[5]; + median[6]= ve_median[6]-median[6]; if(ob->type==OB_MESH) { Mesh *me= ob->data; @@ -458,7 +470,54 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float } } } - + if (median[6] != 0.0f) { +#if 0 // BMESH_TODO + EditEdge *eed; + const float fixed_bweight= (ve_median[6] <= 0.0f ? 0.0f : (ve_median[6] >= 1.0f ? 1.0f : FLT_MAX)); + + if(fixed_bweight != FLT_MAX) { + /* simple case */ + + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f & SELECT) { + eed->bweight= fixed_bweight; + } + } + } + else { + /* scale crease to target median */ + float median_new= ve_median[6]; + float median_orig= ve_median[6] - median[6]; /* previous median value */ + + /* incase of floating point error */ + CLAMP(median_orig, 0.0f, 1.0f); + CLAMP(median_new, 0.0f, 1.0f); + + if(median_new < median_orig) { + /* scale down */ + const float sca= median_new / median_orig; + + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f & SELECT) { + eed->bweight *= sca; + CLAMP(eed->bweight, 0.0f, 1.0f); + } + } + } + else { + /* scale up */ + const float sca= (1.0f - median_new) / (1.0f - median_orig); + + for(eed= em->edges.first; eed; eed= eed->next) { + if(eed->f & SELECT) { + eed->bweight = 1.0f - ((1.0f - eed->bweight) * sca); + CLAMP(eed->bweight, 0.0f, 1.0f); + } + } + } + } +#endif // BMESH_TODO + } EDBM_RecalcNormals(em); } else if(ob->type==OB_CURVE || ob->type==OB_SURF) { diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 30436fad772..ea71e89f883 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -2322,6 +2322,12 @@ void flushTransNodes(TransInfo *t) } /* *** SEQUENCE EDITOR *** */ + +/* commented _only_ because the meta may have animaion data which + * needs moving too [#28158] */ + +#define SEQ_TX_NESTED_METAS + void flushTransSeq(TransInfo *t) { ListBase *seqbasep= seq_give_editing(t->scene, FALSE)->seqbasep; /* Editing null check already done */ @@ -2347,9 +2353,13 @@ void flushTransSeq(TransInfo *t) switch (tdsq->sel_flag) { case SELECT: +#ifdef SEQ_TX_NESTED_METAS + if ((seq->depth != 0 || seq_tx_test(seq))) /* for meta's, their children move */ + seq->start= new_frame - tdsq->start_offset; +#else if (seq->type != SEQ_META && (seq->depth != 0 || seq_tx_test(seq))) /* for meta's, their children move */ seq->start= new_frame - tdsq->start_offset; - +#endif if (seq->depth==0) { seq->machine= (int)floor(td2d->loc[1] + 0.5f); CLAMP(seq->machine, 1, MAXSEQ); @@ -2404,7 +2414,7 @@ void flushTransSeq(TransInfo *t) seq_prev= seq; } - if (t->mode == TFM_TIME_TRANSLATE) { /* originally TFM_TIME_EXTEND, transform changes */ + if (t->mode == TFM_SEQ_SLIDE) { /* originally TFM_TIME_EXTEND, transform changes */ /* Special annoying case here, need to calc metas with TFM_TIME_EXTEND only */ seq= seqbasep->first; @@ -2906,7 +2916,7 @@ static void posttrans_gpd_clean (bGPdata *gpd) /* Called during special_aftertrans_update to make sure selected keyframes replace * any other keyframes which may reside on that frame (that is not selected). */ -static void posttrans_fcurve_clean (FCurve *fcu) +static void posttrans_fcurve_clean (FCurve *fcu, const short use_handle) { float *selcache; /* cache for frame numbers of selected frames (fcu->totvert*sizeof(float)) */ int len, index, i; /* number of frames in cache, item index */ @@ -2955,7 +2965,7 @@ static void posttrans_fcurve_clean (FCurve *fcu) } } - testhandles_fcurve(fcu); + testhandles_fcurve(fcu, use_handle); } /* free cache */ @@ -2986,11 +2996,11 @@ static void posttrans_action_clean (bAnimContext *ac, bAction *act) if (adt) { ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); - posttrans_fcurve_clean(ale->key_data); + posttrans_fcurve_clean(ale->key_data, FALSE); /* only use handles in graph editor */ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); } else - posttrans_fcurve_clean(ale->key_data); + posttrans_fcurve_clean(ale->key_data, FALSE); /* only use handles in graph editor */ } /* free temp data */ @@ -3011,12 +3021,11 @@ static int count_fcurve_keys(FCurve *fcu, char side, float cfra) /* only include points that occur on the right side of cfra */ for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { if (bezt->f2 & SELECT) { - /* fully select the other two keys */ - bezt->f1 |= SELECT; - bezt->f3 |= SELECT; - - if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) + /* no need to adjust the handle selection since they are assumed + * selected (like graph editor with SIPO_NOHANDLES) */ + if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) { count += 1; + } } } @@ -3441,9 +3450,9 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse */ for (i=0, bezt=fcu->bezt; i < fcu->totvert; i++, bezt++) { if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) { - const char sel1= use_handle ? bezt->f1 & SELECT : 0; const char sel2= bezt->f2 & SELECT; - const char sel3= use_handle ? bezt->f3 & SELECT : 0; + const char sel1= use_handle ? bezt->f1 & SELECT : sel2; + const char sel3= use_handle ? bezt->f3 & SELECT : sel2; if (ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE)) { /* for 'normal' pivots - just include anything that is selected. @@ -3534,9 +3543,9 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) /* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */ for (i=0, bezt= fcu->bezt; i < fcu->totvert; i++, bezt++) { if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) { - const char sel1= use_handle ? bezt->f1 & SELECT : 0; const char sel2= bezt->f2 & SELECT; - const char sel3= use_handle ? bezt->f3 & SELECT : 0; + const char sel1= use_handle ? bezt->f1 & SELECT : sel2; + const char sel3= use_handle ? bezt->f3 & SELECT : sel2; TransDataCurveHandleFlags *hdata = NULL; /* short h1=1, h2=1; */ /* UNUSED */ @@ -3596,7 +3605,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t) } /* Sets handles based on the selection */ - testhandles_fcurve(fcu); + testhandles_fcurve(fcu, use_handle); } /* cleanup temp list */ @@ -3800,7 +3809,7 @@ void remake_graph_transdata (TransInfo *t, ListBase *anim_data) sort_time_fcurve(fcu); /* make sure handles are all set correctly */ - testhandles_fcurve(fcu); + testhandles_fcurve(fcu, use_handle); } } } @@ -3958,6 +3967,11 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count else { /* Nested, different rules apply */ +#ifdef SEQ_TX_NESTED_METAS + *flag= (seq->flag | SELECT) & ~(SEQ_LEFTSEL|SEQ_RIGHTSEL); + *count= 1; /* ignore the selection for nested */ + *recursive = (seq->type == SEQ_META ); +#else if (seq->type == SEQ_META) { /* Meta's can only directly be moved between channels since they * dont have their start and length set directly (children affect that) @@ -3972,6 +3986,7 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count *count= 1; /* ignore the selection for nested */ *recursive = 0; } +#endif } } } @@ -4947,11 +4962,11 @@ void special_aftertrans_update(bContext *C, TransInfo *t) { if (adt) { ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 1); - posttrans_fcurve_clean(fcu); + posttrans_fcurve_clean(fcu, FALSE); /* only use handles in graph editor */ ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 1); } else - posttrans_fcurve_clean(fcu); + posttrans_fcurve_clean(fcu, FALSE); /* only use handles in graph editor */ } } @@ -5031,6 +5046,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) else if (t->spacetype == SPACE_IPO) { SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first; bAnimContext ac; + const short use_handle = !(sipo->flag & SIPO_NOHANDLES); /* initialise relevant anim-context 'context' data */ if (ANIM_animdata_get_context(C, &ac) == 0) @@ -5059,11 +5075,11 @@ void special_aftertrans_update(bContext *C, TransInfo *t) { if (adt) { ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 0); - posttrans_fcurve_clean(fcu); + posttrans_fcurve_clean(fcu, use_handle); ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 0); } else - posttrans_fcurve_clean(fcu); + posttrans_fcurve_clean(fcu, use_handle); } } diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index c3cbcb61622..a792b51e1cf 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -903,7 +903,7 @@ static void do_material_tex(GPUShadeInput *shi) /*char *lastuvname = NULL;*/ /*UNUSED*/ float one = 1.0f, norfac, ofs[3]; int tex_nr, rgbnor, talpha; - int init_done = 0, iBumpSpacePrev; + int init_done = 0, iBumpSpacePrev = 0; /* Not necessary, quiting gcc warning. */ GPUNodeLink *vNorg, *vNacc, *fPrevMagnitude; int iFirstTimeNMap=1; int found_deriv_map = 0; @@ -1101,7 +1101,12 @@ static void do_material_tex(GPUShadeInput *shi) if( mtex->texflag & MTEX_BUMP_TEXTURESPACE ) hScale = hScaleTex; - norfac = hScale * mtex->norfac; + + // The negate on norfac is done because the + // normal in the renderer points inward which corresponds + // to inverting the bump map. Should this ever change + // this negate must be removed. + norfac = -hScale * mtex->norfac; tnorfac = GPU_uniform(&norfac); if(GPU_link_changed(stencil)) diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 3c3cecc0e96..b9500c2f798 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -900,8 +900,8 @@ static ImBuf * ffmpeg_fetchibuf(struct anim * anim, int position, long long st_time; struct anim_index * tc_index = 0; AVStream * v_st; - int new_frame_index; - int old_frame_index; + int new_frame_index = 0; /* To quite gcc barking... */ + int old_frame_index = 0; /* To quite gcc barking... */ if (anim == 0) return (0); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 80fc6f63363..f81a05f5625 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -125,7 +125,7 @@ typedef struct Library { enum eIconSizes { ICON_SIZE_ICON, - ICON_SIZE_PREVIEW, + ICON_SIZE_PREVIEW }; #define NUM_ICON_SIZES (ICON_SIZE_PREVIEW + 1) @@ -204,6 +204,8 @@ typedef struct PreviewImage { #define ID_REAL_USERS(id) (((ID *)id)->us - ((((ID *)id)->flag & LIB_FAKEUSER) ? 1:0)) +#define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM)) + #ifdef GS #undef GS #endif diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 6e850a07d94..d878a759d22 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -466,6 +466,7 @@ typedef struct TexMapping { #define MTEX_5TAP_BUMP 512 #define MTEX_BUMP_OBJECTSPACE 1024 #define MTEX_BUMP_TEXTURESPACE 2048 +#define MTEX_BUMP_FLIPPED 4096 /* temp flag for 2.59/2.60 */ /* blendtype */ #define MTEX_BLEND 0 diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 47ebf111eba..9e94ebfb6e8 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -295,6 +295,7 @@ typedef struct wmKeyConfig { /* wmKeyConfig.flag */ #define KEYCONF_USER (1 << 1) +#define KEYCONF_INIT_DEFAULT (1 << 2) /* this one is the operator itself, stored in files for macros etc */ /* operator + operatortype should be able to redo entirely, but for different contextes */ diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 539005f2142..f51bea9a4ef 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -95,6 +95,7 @@ set(APISRC rna_actuator_api.c rna_animation_api.c rna_armature_api.c + rna_camera_api.c rna_controller_api.c rna_fcurve_api.c rna_image_api.c diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 80352d3f03e..bc45ea4deed 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -2432,7 +2432,7 @@ static RNAProcessItem PROCESS_ITEMS[]= { {"rna_armature.c", "rna_armature_api.c", RNA_def_armature}, {"rna_boid.c", NULL, RNA_def_boid}, {"rna_brush.c", NULL, RNA_def_brush}, - {"rna_camera.c", NULL, RNA_def_camera}, + {"rna_camera.c", "rna_camera_api.c", RNA_def_camera}, {"rna_cloth.c", NULL, RNA_def_cloth}, {"rna_color.c", NULL, RNA_def_color}, {"rna_constraint.c", NULL, RNA_def_constraint}, diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index a834fcf820b..75c21e3f47e 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -752,7 +752,7 @@ static void rna_def_armature_bones(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_struct_type(prop, "Bone"); RNA_def_property_pointer_sdna(prop, NULL, "act_bone"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Active Bone", "Armatures active bone"); + RNA_def_property_ui_text(prop, "Active Bone", "Armature's active bone"); RNA_def_property_pointer_funcs(prop, NULL, "rna_Armature_act_bone_set", NULL, NULL); /* todo, redraw */ diff --git a/source/blender/makesrna/intern/rna_boid.c b/source/blender/makesrna/intern/rna_boid.c index c9d261e8143..357f613f65f 100644 --- a/source/blender/makesrna/intern/rna_boid.c +++ b/source/blender/makesrna/intern/rna_boid.c @@ -554,7 +554,7 @@ static void rna_def_boid_settings(BlenderRNA *brna) prop= RNA_def_property(srna, "range", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.0, 100.0); - RNA_def_property_ui_text(prop, "Range", "The maximum distance from which a boid can attack"); + RNA_def_property_ui_text(prop, "Range", "Maximum distance from which a boid can attack"); RNA_def_property_update(prop, 0, "rna_Boids_reset"); /* physical properties */ diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 37912f810fc..9954fdfd88d 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -209,6 +209,9 @@ void RNA_def_camera(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "DOF Object", "Use this object to define the depth of field focal point"); RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL); + + /* Camera API */ + RNA_api_camera(srna); } #endif diff --git a/source/blender/makesrna/intern/rna_camera_api.c b/source/blender/makesrna/intern/rna_camera_api.c new file mode 100644 index 00000000000..39478713663 --- /dev/null +++ b/source/blender/makesrna/intern/rna_camera_api.c @@ -0,0 +1,88 @@ +/* + * $Id$ + * + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/makesrna/intern/rna_camera_api.c + * \ingroup RNA + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + + +#include "RNA_define.h" +#include "BKE_utildefines.h" + +#ifdef RNA_RUNTIME + +#include "DNA_scene_types.h" +#include "BKE_context.h" +#include "BKE_object.h" + +void rna_camera_view_frame(struct Camera *camera, struct Scene *scene, + float vec1_r[3], float vec2_r[3], float vec3_r[3], float vec4_r[3]) +{ + float vec[4][3]; + + camera_view_frame(scene, camera, vec); + + copy_v3_v3(vec1_r, vec[0]); + copy_v3_v3(vec2_r, vec[1]); + copy_v3_v3(vec3_r, vec[2]); + copy_v3_v3(vec4_r, vec[3]); +} + +#else + +void RNA_api_camera(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func= RNA_def_function(srna, "view_frame", "rna_camera_view_frame"); + RNA_def_function_ui_description(func, "Return 4 points for the cameras frame (before object transformation)"); + + RNA_def_pointer(func, "scene", "Scene", "", "Scene to use for aspect calculation, when omitted 1:1 aspect is used"); + + /* return location and normal */ + parm= RNA_def_float_vector(func, "result_1", 3, NULL, -FLT_MAX, FLT_MAX, "Result", NULL, -1e4, 1e4); + RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_function_output(func, parm); + + parm= RNA_def_float_vector(func, "result_2", 3, NULL, -FLT_MAX, FLT_MAX, "Result", NULL, -1e4, 1e4); + RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_function_output(func, parm); + + parm= RNA_def_float_vector(func, "result_3", 3, NULL, -FLT_MAX, FLT_MAX, "Result", NULL, -1e4, 1e4); + RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_function_output(func, parm); + + parm= RNA_def_float_vector(func, "result_4", 3, NULL, -FLT_MAX, FLT_MAX, "Result", NULL, -1e4, 1e4); + RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_function_output(func, parm); +} + +#endif + diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 78b8c67d92c..cf1be39124e 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -234,6 +234,7 @@ char *rna_TextureSlot_path(struct PointerRNA *ptr); void RNA_api_action(StructRNA *srna); void RNA_api_armature_edit_bone(StructRNA *srna); void RNA_api_bone(StructRNA *srna); +void RNA_api_camera(StructRNA *srna); void RNA_api_drivers(StructRNA *srna); void RNA_api_image(struct StructRNA *srna); void RNA_api_operator(struct StructRNA *srna); diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 0a23010a1b9..21e816ad222 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -670,7 +670,7 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_srna(cprop, "BlendDataMaterials"); srna= RNA_def_struct(brna, "BlendDataMaterials", NULL); RNA_def_struct_sdna(srna, "Main"); - RNA_def_struct_ui_text(srna, "Main Material", "Collection of materials"); + RNA_def_struct_ui_text(srna, "Main Materials", "Collection of materials"); func= RNA_def_function(srna, "new", "rna_Main_materials_new"); RNA_def_function_ui_description(func, "Add a new material to the main database"); @@ -949,7 +949,7 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_srna(cprop, "BlendDataMetaBalls"); srna= RNA_def_struct(brna, "BlendDataMetaBalls", NULL); RNA_def_struct_sdna(srna, "Main"); - RNA_def_struct_ui_text(srna, "Main MetaBall", "Collection of metaballs"); + RNA_def_struct_ui_text(srna, "Main MetaBalls", "Collection of metaballs"); func= RNA_def_function(srna, "new", "rna_Main_metaballs_new"); RNA_def_function_ui_description(func, "Add a new metaball to the main database"); diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index c046c222898..0b137633349 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1680,7 +1680,7 @@ static void rna_def_softbody(BlenderRNA *brna) prop= RNA_def_property(srna, "use_estimate_matrix", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "solverflags", SBSO_ESTIMATEIPO); - RNA_def_property_ui_text(prop, "Estimate matrix", "estimate matrix .. split to COM , ROT ,SCALE "); + RNA_def_property_ui_text(prop, "Estimate matrix", "Estimate matrix... split to COM, ROT, SCALE"); /***********************************************************************************/ @@ -1722,7 +1722,7 @@ static void rna_def_softbody(BlenderRNA *brna) prop= RNA_def_property(srna, "use_stiff_quads", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_SoftBodySettings_stiff_quads_get", "rna_SoftBodySettings_stiff_quads_set"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); - RNA_def_property_ui_text(prop, "Stiff Quads", "Adds diagonal springs on 4-gons"); + RNA_def_property_ui_text(prop, "Stiff Quads", "Add diagonal springs on 4-gons"); RNA_def_property_update(prop, 0, "rna_softbody_update"); prop= RNA_def_property(srna, "use_edge_collision", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 1d8a91861d6..8eb25290b18 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -2068,7 +2068,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop= RNA_def_property(srna, "courant_target", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.01, 10); RNA_def_property_float_default(prop, 0.2); - RNA_def_property_ui_text(prop, "Adaptive Subframe Threshold", "The relative distance a particle can move before requiring more subframes (target Courant number). 0.1-0.3 is the recommended range"); + RNA_def_property_ui_text(prop, "Adaptive Subframe Threshold", "The relative distance a particle can move before requiring more subframes (target Courant number); 0.1-0.3 is the recommended range"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop= RNA_def_property(srna, "jitter_factor", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 8084ddc60f8..2eb095aea3d 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -1242,7 +1242,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop= RNA_def_property(srna, "use_snap_self", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "snap_flag", SCE_SNAP_NO_SELF); - RNA_def_property_ui_text(prop, "Project to Self", "Snap onto its self (editmode)"); + RNA_def_property_ui_text(prop, "Project to Self", "Snap onto itself (editmode)"); RNA_def_property_ui_icon(prop, ICON_ORTHO, 0); RNA_def_property_update(prop, NC_SCENE|ND_TOOLSETTINGS, NULL); /* header redraw */ @@ -1874,19 +1874,19 @@ static void rna_def_scene_game_data(BlenderRNA *brna) prop= RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "depth"); RNA_def_property_range(prop, 8, 32); - RNA_def_property_ui_text(prop, "Bits", "Displays bit depth of full screen display"); + RNA_def_property_ui_text(prop, "Bits", "Display bit depth of full screen display"); RNA_def_property_update(prop, NC_SCENE, NULL); // Do we need it here ? (since we already have it in World prop= RNA_def_property(srna, "frequency", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "freqplay"); RNA_def_property_range(prop, 4, 2000); - RNA_def_property_ui_text(prop, "Freq", "Displays clock frequency of fullscreen display"); + RNA_def_property_ui_text(prop, "Freq", "Display clock frequency of fullscreen display"); RNA_def_property_update(prop, NC_SCENE, NULL); prop= RNA_def_property(srna, "show_fullscreen", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "fullscreen", 1.0); - RNA_def_property_ui_text(prop, "Fullscreen", "Starts player in a new fullscreen display"); + RNA_def_property_ui_text(prop, "Fullscreen", "Start player in a new fullscreen display"); RNA_def_property_update(prop, NC_SCENE, NULL); /* Framing */ diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 686c8dffcd1..840a24c23f4 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -148,9 +148,9 @@ static void rna_def_area(BlenderRNA *brna) RNA_def_property_collection_sdna(prop, NULL, "spacedata", NULL); RNA_def_property_struct_type(prop, "Space"); RNA_def_property_ui_text(prop, "Spaces", - "Spaces contained in this area, the first being the active space. " - "NOTE: Useful for example to restore a previously used 3d view space " - "in a certain area to get the old view orientation"); + "Spaces contained in this area, the first being the active space " + "(NOTE: Useful for example to restore a previously used 3D view space " + "in a certain area to get the old view orientation)"); rna_def_area_spaces(brna, prop); prop= RNA_def_property(srna, "regions", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index d7e0113f56e..3d81ec24d29 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -559,7 +559,8 @@ static void rna_Sequence_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *p { Editing *ed= seq_give_editing(scene, FALSE); - free_imbuf_seq(scene, &ed->seqbase, FALSE, TRUE); + if(ed) + free_imbuf_seq(scene, &ed->seqbase, FALSE, TRUE); } static void rna_Sequence_update_reopen_files(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) @@ -820,16 +821,14 @@ static void rna_def_strip_proxy(BlenderRNA *brna) PropertyRNA *prop; static const EnumPropertyItem seq_tc_items[]= { - {SEQ_PROXY_TC_NONE, "NONE", 0, "No TC in use", ""}, + {SEQ_PROXY_TC_NONE, "NONE", 0, "No TC in use", ""}, {SEQ_PROXY_TC_RECORD_RUN, "RECORD_RUN", 0, "Record Run", - "use images in the order as they are recorded"}, - {SEQ_PROXY_TC_FREE_RUN, "FREE_RUN", 0, "Free Run", - "use global timestamp written by recording device"}, - {SEQ_PROXY_TC_INTERP_REC_DATE_FREE_RUN, "FREE_RUN_REC_DATE", - 0, "Free Run (rec date)", - "interpolate a global timestamp using the " - "record date and time written by recording " - "device"}, + "Use images in the order as they are recorded"}, + {SEQ_PROXY_TC_FREE_RUN, "FREE_RUN", 0, "Free Run", + "Use global timestamp written by recording device"}, + {SEQ_PROXY_TC_INTERP_REC_DATE_FREE_RUN, "FREE_RUN_REC_DATE", 0, "Free Run (rec date)", + "Interpolate a global timestamp using the " + "record date and time written by recording device"}, {0, NULL, 0, NULL, NULL}}; srna = RNA_def_struct(brna, "SequenceProxy", NULL); diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 8ea00530c2f..217d68860f2 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -255,7 +255,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) prop= RNA_def_property(srna, "smooth_emitter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_HIGH_SMOOTH); - RNA_def_property_ui_text(prop, "Smooth Emitter", "Smoothens emitted smoke to avoid blockiness"); + RNA_def_property_ui_text(prop, "Smooth Emitter", "Smoothen emitted smoke to avoid blockiness"); RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Smoke_reset"); prop= RNA_def_property(srna, "time_scale", PROP_FLOAT, PROP_NONE); @@ -305,11 +305,11 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna) prop= RNA_def_property(srna, "use_outflow", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "type", MOD_SMOKE_FLOW_TYPE_OUTFLOW); - RNA_def_property_ui_text(prop, "Outflow", "Deletes smoke from simulation"); + RNA_def_property_ui_text(prop, "Outflow", "Delete smoke from simulation"); prop= RNA_def_property(srna, "use_absolute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_ABSOLUTE); - RNA_def_property_ui_text(prop, "Absolute Density", "Only allows given density value in emitter area"); + RNA_def_property_ui_text(prop, "Absolute Density", "Only allow given density value in emitter area"); prop= RNA_def_property(srna, "initial_velocity", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_SMOKE_FLOW_INITVELOCITY); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index e561065cb09..fa98e07da20 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2068,7 +2068,7 @@ static void rna_def_space_graph(BlenderRNA *brna) prop= RNA_def_property(srna, "use_beauty_drawing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_BEAUTYDRAW_OFF); RNA_def_property_ui_text(prop, "Use High Quality Drawing", - "Draw F-Curves using Anti-Aliasing and other fancy effects. Disable for better performance"); + "Draw F-Curves using Anti-Aliasing and other fancy effects (disable for better performance)"); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_GRAPH, NULL); /* editing */ @@ -2144,7 +2144,7 @@ static void rna_def_space_nla(BlenderRNA *brna) prop= RNA_def_property(srna, "show_strip_curves", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOSTRIPCURVES); - RNA_def_property_ui_text(prop, "Show Control Curves", "Show influence curves on strips"); + RNA_def_property_ui_text(prop, "Show Control F-Curves", "Show influence F-Curves on strips"); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_NLA, NULL); /* editing */ @@ -2516,7 +2516,7 @@ static void rna_def_space_node(BlenderRNA *brna) prop= RNA_def_property(srna, "use_auto_render", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SNODE_AUTO_RENDER); - RNA_def_property_ui_text(prop, "Auto Render", "Re-render and composite changed layer on 3D edits"); + RNA_def_property_ui_text(prop, "Auto Render", "Re-render and composite changed layers on 3D edits"); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_NODE_VIEW, NULL); prop= RNA_def_property(srna, "backdrop_zoom", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index e2beabf789d..21a426640f2 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -57,20 +57,23 @@ EnumPropertyItem texture_filter_items[] = { EnumPropertyItem texture_type_items[] = { {0, "NONE", 0, "None", ""}, - {TEX_BLEND, "BLEND", ICON_TEXTURE, "Blend", "Procedural - Creates a ramp texture"}, - {TEX_CLOUDS, "CLOUDS", ICON_TEXTURE, "Clouds", "Procedural - Creates a cloud-like fractal noise texture"}, - {TEX_DISTNOISE, "DISTORTED_NOISE", ICON_TEXTURE, "Distorted Noise", "Procedural - Noise texture distorted by two noise algorithms"}, - {TEX_ENVMAP, "ENVIRONMENT_MAP", ICON_IMAGE_DATA, "Environment Map", "Creates a render of the environment mapped to a texture"}, - {TEX_IMAGE, "IMAGE", ICON_IMAGE_DATA, "Image or Movie", "Allows for images or movies to be used as textures"}, + {TEX_BLEND, "BLEND", ICON_TEXTURE, "Blend", "Procedural - create a ramp texture"}, + {TEX_CLOUDS, "CLOUDS", ICON_TEXTURE, "Clouds", "Procedural - create a cloud-like fractal noise texture"}, + {TEX_DISTNOISE, "DISTORTED_NOISE", ICON_TEXTURE, + "Distorted Noise", "Procedural - Noise texture distorted by two noise algorithms"}, + {TEX_ENVMAP, "ENVIRONMENT_MAP", ICON_IMAGE_DATA, + "Environment Map", "Create a render of the environment mapped to a texture"}, + {TEX_IMAGE, "IMAGE", ICON_IMAGE_DATA, "Image or Movie", "Allow for images or movies to be used as textures"}, {TEX_MAGIC, "MAGIC", ICON_TEXTURE, "Magic", "Procedural - Color texture based on trigonometric functions"}, {TEX_MARBLE, "MARBLE", ICON_TEXTURE, "Marble", "Procedural - Marble-like noise texture with wave generated bands"}, {TEX_MUSGRAVE, "MUSGRAVE", ICON_TEXTURE, "Musgrave", "Procedural - Highly flexible fractal noise texture"}, - {TEX_NOISE, "NOISE", ICON_TEXTURE, "Noise", "Procedural - Random noise, gives a different result every time, for every frame, for every pixel"}, + {TEX_NOISE, "NOISE", ICON_TEXTURE, "Noise", + "Procedural - Random noise, gives a different result every time, for every frame, for every pixel"}, //{TEX_PLUGIN, "PLUGIN", ICON_PLUGIN, "Plugin", ""}, /* Nothing yet */ {TEX_POINTDENSITY, "POINT_DENSITY", ICON_TEXTURE, "Point Density", ""}, - {TEX_STUCCI, "STUCCI", ICON_TEXTURE, "Stucci", "Procedural - Creates a fractal noise texture"}, - {TEX_VORONOI, "VORONOI", ICON_TEXTURE, "Voronoi", "Procedural - Creates cell-like patterns based on Worley noise"}, - {TEX_VOXELDATA, "VOXEL_DATA", ICON_TEXTURE, "Voxel Data", "Creates a 3d texture based on volumetric data"}, + {TEX_STUCCI, "STUCCI", ICON_TEXTURE, "Stucci", "Procedural - Create a fractal noise texture"}, + {TEX_VORONOI, "VORONOI", ICON_TEXTURE, "Voronoi", "Procedural - Create cell-like patterns based on Worley noise"}, + {TEX_VOXELDATA, "VOXEL_DATA", ICON_TEXTURE, "Voxel Data", "Create a 3d texture based on volumetric data"}, {TEX_WOOD, "WOOD", ICON_TEXTURE, "Wood", "Procedural - Wave generated bands or rings, with optional noise"}, {0, NULL, 0, NULL, NULL}}; @@ -493,25 +496,26 @@ static void rna_def_mtex(BlenderRNA *brna) prop= RNA_def_property(srna, "offset", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_float_sdna(prop, NULL, "ofs"); RNA_def_property_ui_range(prop, -10, 10, 10, 2); - RNA_def_property_ui_text(prop, "Offset", "Fine tunes texture mapping X, Y and Z locations"); + RNA_def_property_ui_text(prop, "Offset", "Fine tune of the texture mapping X, Y and Z locations"); RNA_def_property_update(prop, 0, "rna_TextureSlot_update"); prop= RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ); RNA_def_property_float_sdna(prop, NULL, "size"); RNA_def_property_ui_range(prop, -100, 100, 10, 2); - RNA_def_property_ui_text(prop, "Size", "Sets scaling for the texture's X, Y and Z sizes"); + RNA_def_property_ui_text(prop, "Size", "Set scaling for the texture's X, Y and Z sizes"); RNA_def_property_update(prop, 0, "rna_TextureSlot_update"); prop= RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "r"); RNA_def_property_array(prop, 3); - RNA_def_property_ui_text(prop, "Color", "The default color for textures that don't return RGB or when RGB to intensity is enabled"); + RNA_def_property_ui_text(prop, "Color", + "Default color for textures that don't return RGB or when RGB to intensity is enabled"); RNA_def_property_update(prop, 0, "rna_TextureSlot_update"); prop= RNA_def_property(srna, "blend_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "blendtype"); RNA_def_property_enum_items(prop, prop_blend_type_items); - RNA_def_property_ui_text(prop, "Blend Type", "The mode used to apply the texture"); + RNA_def_property_ui_text(prop, "Blend Type", "Mode used to apply the texture"); RNA_def_property_update(prop, 0, "rna_TextureSlot_update"); prop= RNA_def_property(srna, "use_stencil", PROP_BOOLEAN, PROP_NONE); @@ -521,12 +525,12 @@ static void rna_def_mtex(BlenderRNA *brna) prop= RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_NEGATIVE); - RNA_def_property_ui_text(prop, "Negate", "Inverts the values of the texture to reverse its effect"); + RNA_def_property_ui_text(prop, "Negate", "Invert the values of the texture to reverse its effect"); RNA_def_property_update(prop, 0, "rna_TextureSlot_update"); prop= RNA_def_property(srna, "use_rgb_to_intensity", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_RGBTOINT); - RNA_def_property_ui_text(prop, "RGB to Intensity", "Converts texture RGB values to intensity (gray) values"); + RNA_def_property_ui_text(prop, "RGB to Intensity", "Convert texture RGB values to intensity (gray) values"); RNA_def_property_update(prop, 0, "rna_TextureSlot_update"); prop= RNA_def_property(srna, "default_value", PROP_FLOAT, PROP_NONE); @@ -567,13 +571,15 @@ static void rna_def_filter_common(StructRNA *srna) prop= RNA_def_property(srna, "filter_probes", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "afmax"); RNA_def_property_range(prop, 1, 256); - RNA_def_property_ui_text(prop, "Filter Probes", "Maximum number of samples. Higher gives less blur at distant/oblique angles, but is also slower"); + RNA_def_property_ui_text(prop, "Filter Probes", + "Maximum number of samples. Higher gives less blur at distant/oblique angles, but is also slower"); RNA_def_property_update(prop, 0, "rna_Texture_update"); prop= RNA_def_property(srna, "filter_eccentricity", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "afmax"); RNA_def_property_range(prop, 1, 256); - RNA_def_property_ui_text(prop, "Filter Eccentricity", "Maximum eccentricity. Higher gives less blur at distant/oblique angles, but is also slower"); + RNA_def_property_ui_text(prop, "Filter Eccentricity", + "Maximum eccentricity. Higher gives less blur at distant/oblique angles, but is also slower"); RNA_def_property_update(prop, 0, "rna_Texture_update"); prop= RNA_def_property(srna, "use_filter_size_min", PROP_BOOLEAN, PROP_NONE); @@ -662,7 +668,7 @@ static void rna_def_environment_map(BlenderRNA *brna) prop= RNA_def_property(srna, "depth", PROP_INT, PROP_UNSIGNED); RNA_def_property_range(prop, 0, 5); - RNA_def_property_ui_text(prop, "Depth", "Number of times a map will be rendered recursively (mirror effects.)"); + RNA_def_property_ui_text(prop, "Depth", "Number of times a map will be rendered recursively (mirror effects)"); RNA_def_property_update(prop, 0, "rna_Texture_update"); prop= RNA_def_property(srna, "is_valid", PROP_BOOLEAN, 0); @@ -926,13 +932,13 @@ static void rna_def_texture_blend(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem prop_blend_progression[] = { - {TEX_LIN, "LINEAR", 0, "Linear", "Creates a linear progression"}, - {TEX_QUAD, "QUADRATIC", 0, "Quadratic", "Creates a quadratic progression"}, - {TEX_EASE, "EASING", 0, "Easing", "Creates a progression easing from one step to the next"}, - {TEX_DIAG, "DIAGONAL", 0, "Diagonal", "Creates a diagonal progression"}, - {TEX_SPHERE, "SPHERICAL", 0, "Spherical", "Creates a spherical progression"}, - {TEX_HALO, "QUADRATIC_SPHERE", 0, "Quadratic sphere", "Creates a quadratic progression in the shape of a sphere"}, - {TEX_RAD, "RADIAL", 0, "Radial", "Creates a radial progression"}, + {TEX_LIN, "LINEAR", 0, "Linear", "Create a linear progression"}, + {TEX_QUAD, "QUADRATIC", 0, "Quadratic", "Create a quadratic progression"}, + {TEX_EASE, "EASING", 0, "Easing", "Create a progression easing from one step to the next"}, + {TEX_DIAG, "DIAGONAL", 0, "Diagonal", "Create a diagonal progression"}, + {TEX_SPHERE, "SPHERICAL", 0, "Spherical", "Create a spherical progression"}, + {TEX_HALO, "QUADRATIC_SPHERE", 0, "Quadratic sphere", "Create a quadratic progression in the shape of a sphere"}, + {TEX_RAD, "RADIAL", 0, "Radial", "Create a radial progression"}, {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem prop_flip_axis_items[]= { @@ -1021,11 +1027,12 @@ static void rna_def_texture_image(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem prop_image_extension[] = { - {TEX_EXTEND, "EXTEND", 0, "Extend", "Extends by repeating edge pixels of the image"}, - {TEX_CLIP, "CLIP", 0, "Clip", "Clips to image size and sets exterior pixels as transparent"}, - {TEX_CLIPCUBE, "CLIP_CUBE", 0, "Clip Cube", "Clips to cubic-shaped area around the image and sets exterior pixels as transparent"}, - {TEX_REPEAT, "REPEAT", 0, "Repeat", "Causes the image to repeat horizontally and vertically"}, - {TEX_CHECKER, "CHECKER", 0, "Checker", "Causes the image to repeat in checker board pattern"}, + {TEX_EXTEND, "EXTEND", 0, "Extend", "Extend by repeating edge pixels of the image"}, + {TEX_CLIP, "CLIP", 0, "Clip", "Clip to image size and sets exterior pixels as transparent"}, + {TEX_CLIPCUBE, "CLIP_CUBE", 0, "Clip Cube", + "Clip to cubic-shaped area around the image and sets exterior pixels as transparent"}, + {TEX_REPEAT, "REPEAT", 0, "Repeat", "Cause the image to repeat horizontally and vertically"}, + {TEX_CHECKER, "CHECKER", 0, "Checker", "Cause the image to repeat in checker board pattern"}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "ImageTexture", "Texture"); @@ -1219,11 +1226,15 @@ static void rna_def_texture_musgrave(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem prop_musgrave_type[] = { - {TEX_MFRACTAL, "MULTIFRACTAL", 0, "Multifractal", "Fractal noise algorithm. Multifractal: Uses Perlin noise as a basis"}, - {TEX_RIDGEDMF, "RIDGED_MULTIFRACTAL", 0, "Ridged Multifractal", "Fractal noise algorithm. Ridged Multifractal: Uses Perlin noise with inflection as a basis"}, - {TEX_HYBRIDMF, "HYBRID_MULTIFRACTAL", 0, "Hybrid Multifractal", "Fractal noise algorithm.Hybrid Multifractal: Uses Perlin noise as a basis, with extended controls"}, + {TEX_MFRACTAL, "MULTIFRACTAL", 0, "Multifractal", + "Fractal noise algorithm. Multifractal: Uses Perlin noise as a basis"}, + {TEX_RIDGEDMF, "RIDGED_MULTIFRACTAL", 0, "Ridged Multifractal", + "Fractal noise algorithm. Ridged Multifractal: Uses Perlin noise with inflection as a basis"}, + {TEX_HYBRIDMF, "HYBRID_MULTIFRACTAL", 0, "Hybrid Multifractal", + "Fractal noise algorithm.Hybrid Multifractal: Uses Perlin noise as a basis, with extended controls"}, {TEX_FBM, "FBM", 0, "fBM", "Fractal noise algorithm. Fractal Brownian Motion: Uses Brownian noise as a basis"}, - {TEX_HTERRAIN, "HETERO_TERRAIN", 0, "Hetero Terrain", "Fractal noise algorithm. Hetero Terrain: similar to multifractal"}, + {TEX_HTERRAIN, "HETERO_TERRAIN", 0, "Hetero Terrain", + "Fractal noise algorithm. Hetero Terrain: similar to multifractal"}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "MusgraveTexture", "Texture"); @@ -1298,13 +1309,28 @@ static void rna_def_texture_voronoi(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem prop_distance_metric_items[] = { - {TEX_DISTANCE, "DISTANCE", 0, "Actual Distance", "Algorithm used to calculate distance of sample points to feature points. Actual Distance: sqrt(x*x+y*y+z*z)"}, - {TEX_DISTANCE_SQUARED, "DISTANCE_SQUARED", 0, "Distance Squared", "Algorithm used to calculate distance of sample points to feature points. Distance squared: (x*x+y*y+z*z)"}, - {TEX_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Algorithm used to calculate distance of sample points to feature points. Manhattan: The length of the distance in axial directions"}, - {TEX_CHEBYCHEV, "CHEBYCHEV", 0, "Chebychev", "Algorithm used to calculate distance of sample points to feature points. Chebychev: The length of the longest Axial journey"}, - {TEX_MINKOVSKY_HALF, "MINKOVSKY_HALF", 0, "Minkovsky 1/2", "Algorithm used to calculate distance of sample points to feature points. Minovsky 1/2: Sets Minkovsky variable to 0.5"}, - {TEX_MINKOVSKY_FOUR, "MINKOVSKY_FOUR", 0, "Minkovsky 4", "Algorithm used to calculate distance of sample points to feature points. Minkovsky 4: Sets Minkovsky variable to 4"}, - {TEX_MINKOVSKY, "MINKOVSKY", 0, "Minkovsky", "Algorithm used to calculate distance of sample points to feature points. Minkovsky: Uses the Minkowsky function to calculate distance. Exponent value determines the shape of the boundaries"}, + {TEX_DISTANCE, "DISTANCE", 0, "Actual Distance", + "Algorithm used to calculate distance of sample points to feature points; " + "Actual Distance: sqrt(x*x+y*y+z*z)"}, + {TEX_DISTANCE_SQUARED, "DISTANCE_SQUARED", 0, "Distance Squared", + "Algorithm used to calculate distance of sample points to feature points; " + "Distance squared: (x*x+y*y+z*z)"}, + {TEX_MANHATTAN, "MANHATTAN", 0, "Manhattan", + "Algorithm used to calculate distance of sample points to feature points; " + "Manhattan: The length of the distance in axial directions"}, + {TEX_CHEBYCHEV, "CHEBYCHEV", 0, "Chebychev", + "Algorithm used to calculate distance of sample points to feature points; " + "Chebychev: The length of the longest Axial journey"}, + {TEX_MINKOVSKY_HALF, "MINKOVSKY_HALF", 0, "Minkovsky 1/2", + "Algorithm used to calculate distance of sample points to feature points; " + "Minovsky 1/2: Sets Minkovsky variable to 0.5"}, + {TEX_MINKOVSKY_FOUR, "MINKOVSKY_FOUR", 0, "Minkovsky 4", + "Algorithm used to calculate distance of sample points to feature points; " + "Minkovsky 4: Sets Minkovsky variable to 4"}, + {TEX_MINKOVSKY, "MINKOVSKY", 0, "Minkovsky", + "Algorithm used to calculate distance of sample points to feature points; " + "Minkovsky: Uses the Minkowsky function to calculate distance " + "(exponent value determines the shape of the boundaries)"}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem prop_coloring_items[] = { @@ -1312,7 +1338,8 @@ static void rna_def_texture_voronoi(BlenderRNA *brna) {TEX_INTENSITY, "INTENSITY", 0, "Intensity", "Only calculate intensity"}, {TEX_COL1, "POSITION", 0, "Position", "Color cells by position"}, {TEX_COL2, "POSITION_OUTLINE", 0, "Position and Outline", "Use position plus an outline based on F2-F.1"}, - {TEX_COL3, "POSITION_OUTLINE_INTENSITY", 0, "Position, Outline, and Intensity", "Multiply position and outline by intensity"}, + {TEX_COL3, "POSITION_OUTLINE_INTENSITY", 0, "Position, Outline, and Intensity", + "Multiply position and outline by intensity"}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "VoronoiTexture", "Texture"); @@ -1458,14 +1485,16 @@ static void rna_def_texture_pointdensity(BlenderRNA *brna) static EnumPropertyItem color_source_items[] = { {TEX_PD_COLOR_CONSTANT, "CONSTANT", 0, "Constant", ""}, {TEX_PD_COLOR_PARTAGE, "PARTICLE_AGE", 0, "Particle Age", "Lifetime mapped as 0.0 - 1.0 intensity"}, - {TEX_PD_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed", "Particle speed (absolute magnitude of velocity) mapped as 0.0-1.0 intensity"}, + {TEX_PD_COLOR_PARTSPEED, "PARTICLE_SPEED", 0, "Particle Speed", + "Particle speed (absolute magnitude of velocity) mapped as 0.0-1.0 intensity"}, {TEX_PD_COLOR_PARTVEL, "PARTICLE_VELOCITY", 0, "Particle Velocity", "XYZ velocity mapped to RGB colors"}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem turbulence_influence_items[] = { {TEX_PD_NOISE_STATIC, "STATIC", 0, "Static", "Noise patterns will remain unchanged, faster and suitable for stills"}, {TEX_PD_NOISE_VEL, "PARTICLE_VELOCITY", 0, "Particle Velocity", "Turbulent noise driven by particle velocity"}, - {TEX_PD_NOISE_AGE, "PARTICLE_AGE", 0, "Particle Age", "Turbulent noise driven by the particle's age between birth and death"}, + {TEX_PD_NOISE_AGE, "PARTICLE_AGE", 0, "Particle Age", + "Turbulent noise driven by the particle's age between birth and death"}, {TEX_PD_NOISE_TIME, "GLOBAL_TIME", 0, "Global Time", "Turbulent noise driven by the global current frame"}, {0, NULL, 0, NULL, NULL}}; @@ -1760,17 +1789,17 @@ static void rna_def_texture(BlenderRNA *brna) prop= RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "bright"); RNA_def_property_range(prop, 0, 2); - RNA_def_property_ui_text(prop, "Brightness", "Adjusts the brightness of the texture"); + RNA_def_property_ui_text(prop, "Brightness", "Adjust the brightness of the texture"); RNA_def_property_update(prop, 0, "rna_Texture_update"); prop= RNA_def_property(srna, "contrast", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0.01, 5); - RNA_def_property_ui_text(prop, "Contrast", "Adjusts the contrast of the texture"); + RNA_def_property_ui_text(prop, "Contrast", "Adjust the contrast of the texture"); RNA_def_property_update(prop, 0, "rna_Texture_update"); prop= RNA_def_property(srna, "saturation", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, 0, 2); - RNA_def_property_ui_text(prop, "Saturation", "Adjusts the saturation of colors in the texture"); + RNA_def_property_ui_text(prop, "Saturation", "Adjust the saturation of colors in the texture"); RNA_def_property_update(prop, 0, "rna_Texture_update"); /* RGB Factor */ diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 52c359d79dd..29357362ae2 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -719,7 +719,7 @@ static void rna_def_header(BlenderRNA *brna) prop= RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "layout"); RNA_def_property_struct_type(prop, "UILayout"); - RNA_def_property_ui_text(prop, "Layout", "Defines the structure of the header in the UI"); + RNA_def_property_ui_text(prop, "Layout", "Structure of the header in the UI"); /* registration */ prop= RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); @@ -727,7 +727,7 @@ static void rna_def_header(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REGISTER|PROP_NEVER_CLAMP); RNA_def_property_ui_text(prop, "ID Name", "If this is set, the header gets a custom ID, otherwise it takes the " - "name of the class used to define the panel. For example, if the " + "name of the class used to define the panel; for example, if the " "class name is \"OBJECT_HT_hello\", and bl_idname is not set by the " "script, then bl_idname = \"OBJECT_HT_hello\""); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b81b370a890..5d2f24e8324 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -2003,10 +2003,16 @@ static void rna_def_userdef_solidlight(BlenderRNA *brna) static void rna_def_userdef_view(BlenderRNA *brna) { static EnumPropertyItem timecode_styles[] = { - {USER_TIMECODE_MINIMAL, "MINIMAL", 0, "Minimal Info", "Most compact representation. Uses '+' as separator for sub-second frame numbers, with left and right truncation of the timecode as necessary"}, - {USER_TIMECODE_SMPTE_FULL, "SMPTE", 0, "SMPTE (Full)", "Full SMPTE timecode. Format is HH:MM:SS:FF"}, - {USER_TIMECODE_SMPTE_MSF, "SMPTE_COMPACT", 0, "SMPTE (Compact)", "SMPTE timecode showing minutes, seconds, and frames only. Hours are also shown if necessary, but not by default"}, - {USER_TIMECODE_MILLISECONDS, "MILLISECONDS", 0, "Compact with Milliseconds", "Similar to SMPTE (Compact), except that instead of frames, milliseconds are shown instead"}, + {USER_TIMECODE_MINIMAL, "MINIMAL", 0, "Minimal Info", + "Most compact representation, uses '+' as separator for sub-second frame numbers, " + "with left and right truncation of the timecode as necessary"}, + {USER_TIMECODE_SMPTE_FULL, "SMPTE", 0, "SMPTE (Full)", "Full SMPTE timecode (format is HH:MM:SS:FF)"}, + {USER_TIMECODE_SMPTE_MSF, "SMPTE_COMPACT", 0, "SMPTE (Compact)", + "SMPTE timecode showing minutes, seconds, and frames only - " + "hours are also shown if necessary, but not by default"}, + {USER_TIMECODE_MILLISECONDS, "MILLISECONDS", 0, "Compact with Milliseconds", + "Similar to SMPTE (Compact), except that instead of frames, " + "milliseconds are shown instead"}, {USER_TIMECODE_SECONDS_ONLY, "SECONDS_ONLY", 0, "Only Seconds", "Direct conversion of frame numbers to seconds"}, {0, NULL, 0, NULL, NULL}}; @@ -2036,7 +2042,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop= RNA_def_property(srna, "use_global_scene", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_SCENEGLOBAL); - RNA_def_property_ui_text(prop, "Global Scene", "Forces the current Scene to be displayed in all Screens"); + RNA_def_property_ui_text(prop, "Global Scene", "Force the current Scene to be displayed in all Screens"); RNA_def_property_update(prop, 0, "rna_userdef_update"); prop= RNA_def_property(srna, "show_large_cursors", PROP_BOOLEAN, PROP_NONE); @@ -2055,34 +2061,40 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop= RNA_def_property(srna, "show_playback_fps", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_FPS); - RNA_def_property_ui_text(prop, "Show Playback FPS", "Show the frames per second screen refresh rate, while animation is played back"); + RNA_def_property_ui_text(prop, "Show Playback FPS", + "Show the frames per second screen refresh rate, while animation is played back"); RNA_def_property_update(prop, 0, "rna_userdef_update"); /* menus */ prop= RNA_def_property(srna, "use_mouse_over_open", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_MENUOPENAUTO); - RNA_def_property_ui_text(prop, "Open On Mouse Over", "Open menu buttons and pulldowns automatically when the mouse is hovering"); + RNA_def_property_ui_text(prop, "Open On Mouse Over", + "Open menu buttons and pulldowns automatically when the mouse is hovering"); prop= RNA_def_property(srna, "open_toplevel_delay", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "menuthreshold1"); RNA_def_property_range(prop, 1, 40); - RNA_def_property_ui_text(prop, "Top Level Menu Open Delay", "Time delay in 1/10 seconds before automatically opening top level menus"); + RNA_def_property_ui_text(prop, "Top Level Menu Open Delay", + "Time delay in 1/10 seconds before automatically opening top level menus"); prop= RNA_def_property(srna, "open_sublevel_delay", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "menuthreshold2"); RNA_def_property_range(prop, 1, 40); - RNA_def_property_ui_text(prop, "Sub Level Menu Open Delay", "Time delay in 1/10 seconds before automatically opening sub level menus"); + RNA_def_property_ui_text(prop, "Sub Level Menu Open Delay", + "Time delay in 1/10 seconds before automatically opening sub level menus"); /* Toolbox click-hold delay */ prop= RNA_def_property(srna, "open_left_mouse_delay", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "tb_leftmouse"); RNA_def_property_range(prop, 1, 40); - RNA_def_property_ui_text(prop, "Hold LMB Open Toolbox Delay", "Time in 1/10 seconds to hold the Left Mouse Button before opening the toolbox"); + RNA_def_property_ui_text(prop, "Hold LMB Open Toolbox Delay", + "Time in 1/10 seconds to hold the Left Mouse Button before opening the toolbox"); prop= RNA_def_property(srna, "open_right_mouse_delay", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "tb_rightmouse"); RNA_def_property_range(prop, 1, 40); - RNA_def_property_ui_text(prop, "Hold RMB Open Toolbox Delay", "Time in 1/10 seconds to hold the Right Mouse Button before opening the toolbox"); + RNA_def_property_ui_text(prop, "Hold RMB Open Toolbox Delay", + "Time in 1/10 seconds to hold the Right Mouse Button before opening the toolbox"); prop= RNA_def_property(srna, "show_column_layout", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_PLAINMENUS); @@ -2090,7 +2102,8 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop= RNA_def_property(srna, "use_directional_menus", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_MENUFIXEDORDER); - RNA_def_property_ui_text(prop, "Contents Follow Opening Direction", "Otherwise menus, etc will always be top to bottom, left to right, no matter opening direction"); + RNA_def_property_ui_text(prop, "Contents Follow Opening Direction", + "Otherwise menus, etc will always be top to bottom, left to right, no matter opening direction"); prop= RNA_def_property(srna, "use_global_pivot", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCKAROUND); @@ -2102,17 +2115,22 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop= RNA_def_property(srna, "use_camera_lock_parent", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_CAM_LOCK_NO_PARENT); - RNA_def_property_ui_text(prop, "Camera Parent Lock", "When the camera is locked to the view and in fly mode, transform the parent rather than the camera"); + RNA_def_property_ui_text(prop, "Camera Parent Lock", + "When the camera is locked to the view and in fly mode, " + "transform the parent rather than the camera"); /* view zoom */ prop= RNA_def_property(srna, "use_zoom_to_mouse", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ZOOM_TO_MOUSEPOS); - RNA_def_property_ui_text(prop, "Zoom To Mouse Position", "Zoom in towards the mouse pointer's position in the 3D view, rather than the 2D window center"); + RNA_def_property_ui_text(prop, "Zoom To Mouse Position", + "Zoom in towards the mouse pointer's position in the 3D view, rather than the 2D window center"); /* view rotation */ prop= RNA_def_property(srna, "use_auto_perspective", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_AUTOPERSP); - RNA_def_property_ui_text(prop, "Auto Perspective", "Automatically switch between orthographic and perspective when changing from top/front/side views"); + RNA_def_property_ui_text(prop, "Auto Perspective", + "Automatically switch between orthographic and perspective when changing " + "from top/front/side views"); prop= RNA_def_property(srna, "use_rotate_around_active", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ORBIT_SELECTION); @@ -2121,30 +2139,30 @@ static void rna_def_userdef_view(BlenderRNA *brna) /* mini axis */ prop= RNA_def_property(srna, "show_mini_axis", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_SHOW_ROTVIEWICON); - RNA_def_property_ui_text(prop, "Show Mini Axis", "Show a small rotating 3D axis in the bottom left corner of the 3D View"); + RNA_def_property_ui_text(prop, "Show Mini Axes", "Show a small rotating 3D axes in the bottom left corner of the 3D View"); RNA_def_property_update(prop, 0, "rna_userdef_update"); prop= RNA_def_property(srna, "mini_axis_size", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "rvisize"); RNA_def_property_range(prop, 10, 64); - RNA_def_property_ui_text(prop, "Mini Axis Size", "The axis icon's size"); + RNA_def_property_ui_text(prop, "Mini Axes Size", "The axes icon's size"); RNA_def_property_update(prop, 0, "rna_userdef_update"); prop= RNA_def_property(srna, "mini_axis_brightness", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "rvibright"); RNA_def_property_range(prop, 0, 10); - RNA_def_property_ui_text(prop, "Mini Axis Brightness", "The brightness of the icon"); + RNA_def_property_ui_text(prop, "Mini Axes Brightness", "Brightness of the icon"); RNA_def_property_update(prop, 0, "rna_userdef_update"); prop= RNA_def_property(srna, "smooth_view", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "smooth_viewtx"); RNA_def_property_range(prop, 0, 1000); - RNA_def_property_ui_text(prop, "Smooth View", "The time to animate the view in milliseconds, zero to disable"); + RNA_def_property_ui_text(prop, "Smooth View", "Time to animate the view in milliseconds, zero to disable"); prop= RNA_def_property(srna, "rotation_angle", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "pad_rot_angle"); RNA_def_property_range(prop, 0, 90); - RNA_def_property_ui_text(prop, "Rotation Angle", "The rotation step for numerical pad keys (2 4 6 8)"); + RNA_def_property_ui_text(prop, "Rotation Angle", "Rotation step for numerical pad keys (2 4 6 8)"); /* 3D transform widget */ prop= RNA_def_property(srna, "show_manipulator", PROP_BOOLEAN, PROP_NONE); @@ -2182,7 +2200,8 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop= RNA_def_property(srna, "view2d_grid_spacing_min", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "v2d_min_gridsize"); RNA_def_property_range(prop, 1, 500); // XXX: perhaps the lower range should only go down to 5? - RNA_def_property_ui_text(prop, "2D View Minimum Grid Spacing", "Minimum number of pixels between each gridline in 2D Viewports"); + RNA_def_property_ui_text(prop, "2D View Minimum Grid Spacing", + "Minimum number of pixels between each gridline in 2D Viewports"); RNA_def_property_update(prop, 0, "rna_userdef_update"); // TODO: add a setter for this, so that we can bump up the minimum size as necessary... @@ -2190,7 +2209,8 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_enum_items(prop, timecode_styles); RNA_def_property_enum_sdna(prop, NULL, "timecode_style"); RNA_def_property_enum_funcs(prop, NULL, "rna_userdef_timecode_style_set", NULL); - RNA_def_property_ui_text(prop, "TimeCode Style", "Format of Time Codes displayed when not displaying timing in terms of frames"); + RNA_def_property_ui_text(prop, "TimeCode Style", + "Format of Time Codes displayed when not displaying timing in terms of frames"); RNA_def_property_update(prop, 0, "rna_userdef_update"); } @@ -2210,7 +2230,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}}; static const EnumPropertyItem object_align_items[]= { - {0, "WORLD", 0, "World", "Align newly added objects to the world coordinates"}, + {0, "WORLD", 0, "World", "Align newly added objects to the world coordinate system"}, {USER_ADD_VIEWALIGNED, "VIEW", 0, "View", "Align newly added objects facing the active 3D View direction"}, {0, NULL, 0, NULL, NULL}}; @@ -2224,12 +2244,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop= RNA_def_property(srna, "material_link", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, material_link_items); - RNA_def_property_ui_text(prop, "Material Link To", "Toggle whether the material is linked to object data or the object block"); + RNA_def_property_ui_text(prop, "Material Link To", + "Toggle whether the material is linked to object data or the object block"); prop= RNA_def_property(srna, "object_align", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, object_align_items); - RNA_def_property_ui_text(prop, "Align Object To", "When adding objects from a 3D View menu, either align them to that view's direction or the world coordinates"); + RNA_def_property_ui_text(prop, "Align Object To", + "When adding objects from a 3D View menu, either align them with that view or with the world"); prop= RNA_def_property(srna, "use_enter_edit_mode", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_ADD_EDITMODE); @@ -2252,22 +2274,26 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop= RNA_def_property(srna, "use_global_undo", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_GLOBALUNDO); - RNA_def_property_ui_text(prop, "Global Undo", "Global undo works by keeping a full copy of the file itself in memory, so takes extra memory"); + RNA_def_property_ui_text(prop, "Global Undo", + "Global undo works by keeping a full copy of the file itself in memory, so takes extra memory"); /* auto keyframing */ prop= RNA_def_property(srna, "use_auto_keying", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "autokey_mode", AUTOKEY_ON); - RNA_def_property_ui_text(prop, "Auto Keying Enable", "Automatic keyframe insertion for Objects and Bones (default setting used for new Scenes)"); + RNA_def_property_ui_text(prop, "Auto Keying Enable", + "Automatic keyframe insertion for Objects and Bones (default setting used for new Scenes)"); RNA_def_property_ui_icon(prop, ICON_REC, 0); prop= RNA_def_property(srna, "auto_keying_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, auto_key_modes); RNA_def_property_enum_funcs(prop, "rna_userdef_autokeymode_get", "rna_userdef_autokeymode_set", NULL); - RNA_def_property_ui_text(prop, "Auto Keying Mode", "Mode of automatic keyframe insertion for Objects and Bones (default setting used for new Scenes)"); + RNA_def_property_ui_text(prop, "Auto Keying Mode", + "Mode of automatic keyframe insertion for Objects and Bones " + "(default setting used for new Scenes)"); prop= RNA_def_property(srna, "use_keyframe_insert_available", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_INSERTAVAIL); - RNA_def_property_ui_text(prop, "Auto Keyframe Insert Available", "Automatic keyframe insertion in available curves"); + RNA_def_property_ui_text(prop, "Auto Keyframe Insert Available", "Automatic keyframe insertion in available F-Curves"); /* keyframing settings */ prop= RNA_def_property(srna, "use_keyframe_insert_needed", PROP_BOOLEAN, PROP_NONE); @@ -2280,12 +2306,16 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop= RNA_def_property(srna, "use_insertkey_xyz_to_rgb", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_XYZ2RGB); - RNA_def_property_ui_text(prop, "New F-Curve Colors - XYZ to RGB", "Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis"); + RNA_def_property_ui_text(prop, "New F-Curve Colors - XYZ to RGB", + "Color for newly added transformation F-Curves (Location, Rotation, Scale) " + "and also Color is based on the transform axis"); prop= RNA_def_property(srna, "keyframe_new_interpolation_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, beztriple_interpolation_mode_items); RNA_def_property_enum_sdna(prop, NULL, "ipo_new"); - RNA_def_property_ui_text(prop, "New Interpolation Type", "Interpolation mode used for first keyframe on newly added F-Curves. Subsequent keyframes take interpolation from preceeding keyframe"); + RNA_def_property_ui_text(prop, "New Interpolation Type", + "Interpolation mode used for first keyframe on newly added F-Curves " + "(subsequent keyframes take interpolation from preceeding keyframe)"); prop= RNA_def_property(srna, "keyframe_new_handle_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, keyframe_handle_type_items); @@ -2306,7 +2336,8 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop= RNA_def_property(srna, "grease_pencil_euclidean_distance", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "gp_euclideandist"); RNA_def_property_range(prop, 0, 100); - RNA_def_property_ui_text(prop, "Grease Pencil Euclidean Distance", "Distance moved by mouse when drawing stroke (in pixels) to include"); + RNA_def_property_ui_text(prop, "Grease Pencil Euclidean Distance", + "Distance moved by mouse when drawing stroke (in pixels) to include"); prop= RNA_def_property(srna, "use_grease_pencil_smooth_stroke", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "gp_settings", GP_PAINT_DOSMOOTH); @@ -2459,10 +2490,14 @@ static void rna_def_userdef_system(BlenderRNA *brna) static EnumPropertyItem draw_method_items[] = { {USER_DRAW_AUTOMATIC, "AUTOMATIC", 0, "Automatic", "Automatically set based on graphics card and driver"}, - {USER_DRAW_TRIPLE, "TRIPLE_BUFFER", 0, "Triple Buffer", "Use a third buffer for minimal redraws at the cost of more memory"}, + {USER_DRAW_TRIPLE, "TRIPLE_BUFFER", 0, "Triple Buffer", + "Use a third buffer for minimal redraws at the cost of more memory"}, {USER_DRAW_OVERLAP, "OVERLAP", 0, "Overlap", "Redraw all overlapping regions, minimal memory usage but more redraws"}, - {USER_DRAW_OVERLAP_FLIP, "OVERLAP_FLIP", 0, "Overlap Flip", "Redraw all overlapping regions, minimal memory usage but more redraws (for graphics drivers that do flipping)"}, - {USER_DRAW_FULL, "FULL", 0, "Full", "Do a full redraw each time, slow, only use for reference or when all else fails"}, + {USER_DRAW_OVERLAP_FLIP, "OVERLAP_FLIP", 0, "Overlap Flip", + "Redraw all overlapping regions, minimal memory usage but more redraws " + "(for graphics drivers that do flipping)"}, + {USER_DRAW_FULL, "FULL", 0, "Full", + "Do a full redraw each time, slow, only use for reference or when everything else fails"}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem color_picker_types[] = { @@ -2536,7 +2571,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop= RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, language_items); - RNA_def_property_ui_text(prop, "Language", "Language use for translation"); + RNA_def_property_ui_text(prop, "Language", "Language used for translation"); RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update"); prop= RNA_def_property(srna, "use_translate_tooltips", PROP_BOOLEAN, PROP_NONE); @@ -2563,7 +2598,8 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop= RNA_def_property(srna, "use_weight_color_range", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_CUSTOM_RANGE); - RNA_def_property_ui_text(prop, "Use Weight Color Range", "Enable color range used for weight visualization in weight painting mode"); + RNA_def_property_ui_text(prop, "Use Weight Color Range", + "Enable color range used for weight visualization in weight painting mode"); RNA_def_property_update(prop, 0, "rna_UserDef_weight_color_update"); prop= RNA_def_property(srna, "weight_color_range", PROP_POINTER, PROP_NONE); @@ -2580,16 +2616,20 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop= RNA_def_property(srna, "use_preview_images", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_ALLWINCODECS); - RNA_def_property_ui_text(prop, "Enable All Codecs", "Enables automatic saving of preview images in the .blend file (Windows only)"); + RNA_def_property_ui_text(prop, "Enable All Codecs", + "Allow user to choose any codec (Windows only, might generate instability)"); prop= RNA_def_property(srna, "use_scripts_auto_execute", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_SCRIPT_AUTOEXEC_DISABLE); - RNA_def_property_ui_text(prop, "Auto Run Python Scripts", "Allow any .blend file to run scripts automatically (unsafe with blend files from an untrusted source)"); + RNA_def_property_ui_text(prop, "Auto Run Python Scripts", + "Allow any .blend file to run scripts automatically " + "(unsafe with blend files from an untrusted source)"); RNA_def_property_update(prop, 0, "rna_userdef_script_autoexec_update"); prop= RNA_def_property(srna, "use_tabs_as_spaces", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_TXT_TABSTOSPACES_DISABLE); - RNA_def_property_ui_text(prop, "Tabs as Spaces", "Automatically converts all new tabs into spaces for new and loaded text files"); + RNA_def_property_ui_text(prop, "Tabs as Spaces", + "Automatically convert all new tabs into spaces for new and loaded text files"); prop= RNA_def_property(srna, "prefetch_frames", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "prefetchframes"); @@ -2615,12 +2655,14 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop= RNA_def_property(srna, "use_mipmaps", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflags", USER_DISABLE_MIPMAP); - RNA_def_property_ui_text(prop, "Mipmaps", "Scale textures for the 3D View (looks nicer but uses more memory and slows image reloading)"); + RNA_def_property_ui_text(prop, "Mipmaps", + "Scale textures for the 3D View (looks nicer but uses more memory and slows image reloading)"); RNA_def_property_update(prop, 0, "rna_userdef_mipmap_update"); prop= RNA_def_property(srna, "use_vertex_buffer_objects", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflags", USER_DISABLE_VBO); - RNA_def_property_ui_text(prop, "VBOs", "Use Vertex Buffer Objects (or Vertex Arrays, if unsupported) for viewport rendering"); + RNA_def_property_ui_text(prop, "VBOs", + "Use Vertex Buffer Objects (or Vertex Arrays, if unsupported) for viewport rendering"); prop= RNA_def_property(srna, "use_antialiasing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "gameflags", USER_DISABLE_AA); @@ -2630,7 +2672,8 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "anisotropic_filter"); RNA_def_property_enum_items(prop, anisotropic_items); RNA_def_property_enum_default(prop, 1); - RNA_def_property_ui_text(prop, "Anisotropic Filter", "The quality of the anisotropic filtering (values greater than 1.0 enable anisotropic filtering)"); + RNA_def_property_ui_text(prop, "Anisotropic Filter", + "Quality of the anisotropic filtering (values greater than 1.0 enable anisotropic filtering)"); RNA_def_property_update(prop, 0, "rna_userdef_anisotropic_update"); prop= RNA_def_property(srna, "gl_texture_limit", PROP_ENUM, PROP_NONE); @@ -2642,12 +2685,15 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop= RNA_def_property(srna, "texture_time_out", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "textimeout"); RNA_def_property_range(prop, 0, 3600); - RNA_def_property_ui_text(prop, "Texture Time Out", "Time since last access of a GL texture in seconds after which it is freed. (Set to 0 to keep textures allocated.)"); + RNA_def_property_ui_text(prop, "Texture Time Out", + "Time since last access of a GL texture in seconds after which it is freed " + "(set to 0 to keep textures allocated)"); prop= RNA_def_property(srna, "texture_collection_rate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "texcollectrate"); RNA_def_property_range(prop, 1, 3600); - RNA_def_property_ui_text(prop, "Texture Collection Rate", "Number of seconds between each run of the GL texture garbage collector"); + RNA_def_property_ui_text(prop, "Texture Collection Rate", + "Number of seconds between each run of the GL texture garbage collector"); prop= RNA_def_property(srna, "window_draw_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "wmdrawmethod"); @@ -2658,31 +2704,31 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop= RNA_def_property(srna, "audio_mixing_buffer", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "mixbufsize"); RNA_def_property_enum_items(prop, audio_mixing_samples_items); - RNA_def_property_ui_text(prop, "Audio Mixing Buffer", "Sets the number of samples used by the audio mixing buffer"); + RNA_def_property_ui_text(prop, "Audio Mixing Buffer", "Number of samples used by the audio mixing buffer"); RNA_def_property_update(prop, 0, "rna_UserDef_audio_update"); prop= RNA_def_property(srna, "audio_device", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "audiodevice"); RNA_def_property_enum_items(prop, audio_device_items); - RNA_def_property_ui_text(prop, "Audio Device", "Sets the audio output device"); + RNA_def_property_ui_text(prop, "Audio Device", "Audio output device"); RNA_def_property_update(prop, 0, "rna_UserDef_audio_update"); prop= RNA_def_property(srna, "audio_sample_rate", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "audiorate"); RNA_def_property_enum_items(prop, audio_rate_items); - RNA_def_property_ui_text(prop, "Audio Sample Rate", "Sets the audio sample rate"); + RNA_def_property_ui_text(prop, "Audio Sample Rate", "Audio sample rate"); RNA_def_property_update(prop, 0, "rna_UserDef_audio_update"); prop= RNA_def_property(srna, "audio_sample_format", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "audioformat"); RNA_def_property_enum_items(prop, audio_format_items); - RNA_def_property_ui_text(prop, "Audio Sample Format", "Sets the audio sample format"); + RNA_def_property_ui_text(prop, "Audio Sample Format", "Audio sample format"); RNA_def_property_update(prop, 0, "rna_UserDef_audio_update"); prop= RNA_def_property(srna, "audio_channels", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "audiochannels"); RNA_def_property_enum_items(prop, audio_channel_items); - RNA_def_property_ui_text(prop, "Audio Channels", "Sets the audio channel count"); + RNA_def_property_ui_text(prop, "Audio Channels", "Audio channel count"); RNA_def_property_update(prop, 0, "rna_UserDef_audio_update"); prop= RNA_def_property(srna, "screencast_fps", PROP_INT, PROP_NONE); @@ -2703,11 +2749,11 @@ static void rna_def_userdef_system(BlenderRNA *brna) #if 0 prop= RNA_def_property(srna, "verse_master", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "versemaster"); - RNA_def_property_ui_text(prop, "Verse Master", "The Verse Master-server IP"); + RNA_def_property_ui_text(prop, "Verse Master", "Verse Master-server IP"); prop= RNA_def_property(srna, "verse_username", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "verseuser"); - RNA_def_property_ui_text(prop, "Verse Username", "The Verse user name"); + RNA_def_property_ui_text(prop, "Verse Username", "Verse user name"); #endif } @@ -2728,13 +2774,13 @@ static void rna_def_userdef_input(BlenderRNA *brna) static EnumPropertyItem view_zoom_styles[] = { {USER_ZOOM_CONT, "CONTINUE", 0, "Continue", "Old style zoom, continues while moving mouse up or down"}, - {USER_ZOOM_DOLLY, "DOLLY", 0, "Dolly", "Zooms in and out based on vertical mouse movement"}, - {USER_ZOOM_SCALE, "SCALE", 0, "Scale", "Zooms in and out like scaling the view, mouse movements relative to center"}, + {USER_ZOOM_DOLLY, "DOLLY", 0, "Dolly", "Zoom in and out based on vertical mouse movement"}, + {USER_ZOOM_SCALE, "SCALE", 0, "Scale", "Zoom in and out like scaling the view, mouse movements relative to center"}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem view_zoom_axes[] = { - {0, "VERTICAL", 0, "Vertical", "Zooms in and out based on vertical mouse movement"}, - {USER_ZOOM_HORIZ, "HORIZONTAL", 0, "Horizontal", "Zooms in and out based on horizontal mouse movement"}, + {0, "VERTICAL", 0, "Vertical", "Zoom in and out based on vertical mouse movement"}, + {USER_ZOOM_HORIZ, "HORIZONTAL", 0, "Horizontal", "Zoom in and out based on horizontal mouse movement"}, {0, NULL, 0, NULL, NULL}}; srna= RNA_def_struct(brna, "UserPreferencesInput", NULL); @@ -2746,7 +2792,7 @@ static void rna_def_userdef_input(BlenderRNA *brna) RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, select_mouse_items); RNA_def_property_enum_funcs(prop, NULL, "rna_userdef_select_mouse_set", NULL); - RNA_def_property_ui_text(prop, "Select Mouse", "The mouse button used for selection"); + RNA_def_property_ui_text(prop, "Select Mouse", "Mouse button used for selection"); prop= RNA_def_property(srna, "view_zoom_method", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "viewzoom"); @@ -2769,7 +2815,8 @@ static void rna_def_userdef_input(BlenderRNA *brna) prop= RNA_def_property(srna, "use_mouse_continuous", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_CONTINUOUS_MOUSE); - RNA_def_property_ui_text(prop, "Continuous Grab", "Allow moving the mouse outside the view on some manipulations (transform, ui control drag)"); + RNA_def_property_ui_text(prop, "Continuous Grab", + "Allow moving the mouse outside the view on some manipulations (transform, ui control drag)"); /* tweak tablet & mouse preset */ prop= RNA_def_property(srna, "drag_threshold", PROP_INT, PROP_NONE); @@ -2846,15 +2893,16 @@ static void rna_def_userdef_input(BlenderRNA *brna) prop= RNA_def_property(srna, "mouse_double_click_time", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "dbl_click_time"); RNA_def_property_range(prop, 1, 1000); - RNA_def_property_ui_text(prop, "Double Click Timeout", "The time (in ms) for a double click"); + RNA_def_property_ui_text(prop, "Double Click Timeout", "Time/delay (in ms) for a double click"); prop= RNA_def_property(srna, "use_mouse_emulate_3_button", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TWOBUTTONMOUSE); - RNA_def_property_ui_text(prop, "Emulate 3 Button Mouse", "Emulates Middle Mouse with Alt+Left Mouse (doesn't work with Left Mouse Select option)"); + RNA_def_property_ui_text(prop, "Emulate 3 Button Mouse", + "Emulate Middle Mouse with Alt+Left Mouse (doesn't work with Left Mouse Select option)"); prop= RNA_def_property(srna, "use_emulate_numpad", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_NONUMPAD); - RNA_def_property_ui_text(prop, "Emulate Numpad", "Causes the 1 to 0 keys to act as the numpad (useful for laptops)"); + RNA_def_property_ui_text(prop, "Emulate Numpad", "Main 1 to 0 keys act as the numpad ones (useful for laptops)"); /* middle mouse button */ prop= RNA_def_property(srna, "use_mouse_mmb_paste", PROP_BOOLEAN, PROP_NONE); @@ -2868,7 +2916,7 @@ static void rna_def_userdef_input(BlenderRNA *brna) prop= RNA_def_property(srna, "wheel_scroll_lines", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "wheellinescroll"); RNA_def_property_range(prop, 0, 32); - RNA_def_property_ui_text(prop, "Wheel Scroll Lines", "The number of lines scrolled at a time with the mouse wheel"); + RNA_def_property_ui_text(prop, "Wheel Scroll Lines", "Number of lines scrolled at a time with the mouse wheel"); prop= RNA_def_property(srna, "active_keyconfig", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_sdna(prop, NULL, "keyconfigstr"); @@ -2897,7 +2945,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) prop= RNA_def_property(srna, "show_hidden_files_datablocks", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_HIDE_DOT); - RNA_def_property_ui_text(prop, "Hide Dot Files/Datablocks", "Hide files/datablocks that start with a dot(.*)"); + RNA_def_property_ui_text(prop, "Hide Dot Files/Datablocks", "Hide files/datablocks that start with a dot (.*)"); prop= RNA_def_property(srna, "use_filter_files", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_FILTERFILEEXTS); @@ -2945,7 +2993,9 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) prop= RNA_def_property(srna, "script_directory", PROP_STRING, PROP_DIRPATH); RNA_def_property_string_sdna(prop, NULL, "pythondir"); - RNA_def_property_ui_text(prop, "Python Scripts Directory", "Alternate script path, matching the default layout with subdirs: startup, addons & modules (requires restart)"); + RNA_def_property_ui_text(prop, "Python Scripts Directory", + "Alternate script path, matching the default layout with subdirs: " + "startup, addons & modules (requires restart)"); /* TODO, editing should reset sys.path! */ prop= RNA_def_property(srna, "sound_directory", PROP_STRING, PROP_DIRPATH); @@ -2976,11 +3026,13 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna) prop= RNA_def_property(srna, "save_version", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "versions"); RNA_def_property_range(prop, 0, 32); - RNA_def_property_ui_text(prop, "Save Versions", "The number of old versions to maintain in the current directory, when manually saving"); + RNA_def_property_ui_text(prop, "Save Versions", + "The number of old versions to maintain in the current directory, when manually saving"); prop= RNA_def_property(srna, "use_auto_save_temporary_files", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_AUTOSAVE); - RNA_def_property_ui_text(prop, "Auto Save Temporary Files", "Automatic saving of temporary files in temp directory, uses process ID"); + RNA_def_property_ui_text(prop, "Auto Save Temporary Files", + "Automatic saving of temporary files in temp directory, uses process ID"); RNA_def_property_update(prop, 0, "rna_userdef_autosave_update"); prop= RNA_def_property(srna, "auto_save_time", PROP_INT, PROP_NONE); @@ -3006,7 +3058,7 @@ void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_srna(cprop, "Addons"); srna= RNA_def_struct(brna, "Addons", NULL); - RNA_def_struct_ui_text(srna, "User Add-Ons", "Collection of add-ons"); + RNA_def_struct_ui_text(srna, "User Addons", "Collection of addons"); func= RNA_def_function(srna, "new", "rna_userdef_addon_new"); RNA_def_function_flag(func, FUNC_NO_SELF); @@ -3031,7 +3083,7 @@ void RNA_def_userdef(BlenderRNA *brna) {USER_SECTION_INTERFACE, "INTERFACE", 0, "Interface", ""}, {USER_SECTION_EDIT, "EDITING", 0, "Editing", ""}, {USER_SECTION_INPUT, "INPUT", 0, "Input", ""}, - {USER_SECTION_ADDONS, "ADDONS", 0, "Add-Ons", ""}, + {USER_SECTION_ADDONS, "ADDONS", 0, "Addons", ""}, {USER_SECTION_THEME, "THEMES", 0, "Themes", ""}, {USER_SECTION_FILE, "FILES", 0, "File", ""}, {USER_SECTION_SYSTEM, "SYSTEM", 0, "System", ""}, diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c index 645079ca24e..59461d18f8f 100644 --- a/source/blender/modifiers/intern/MOD_explode.c +++ b/source/blender/modifiers/intern/MOD_explode.c @@ -558,7 +558,9 @@ static DerivedMesh * cutEdges(ExplodeModifierData *emd, DerivedMesh *dm) int *vertpa = MEM_callocN(sizeof(int)*totvert,"explode_vertpa2"); int *facepa = emd->facepa; int *fs, totesplit=0,totfsplit=0,curdupface=0; - int i,j,v1,v2,v3,v4,esplit, v[4], uv[4]; + int i,j,v1,v2,v3,v4,esplit, + v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */ + uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */ int numlayer; edgehash= BLI_edgehash_new(); diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 04c64bcbd3c..88383ce84d5 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -267,6 +267,18 @@ static int bpy_prop_callback_assign(struct PropertyRNA *prop, PyObject *update_c return 0; } +/* utility function we need for parsing int's in an if statement */ +static int py_long_as_int(PyObject *py_long, int *r_int) +{ + if(PyLong_CheckExact(py_long)) { + *r_int= (int)PyLong_AS_LONG(py_long); + return 0; + } + else { + return -1; + } +} + /* this define runs at the start of each function and deals with * returning a deferred property (to be registered later) */ #define BPY_PROPDEF_HEAD(_func) \ @@ -914,6 +926,7 @@ static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, i for(i=0; i<seq_len; i++) { EnumPropertyItem tmp= {0, "", 0, "", ""}; + Py_ssize_t item_size; Py_ssize_t id_str_size; Py_ssize_t name_str_size; Py_ssize_t desc_str_size; @@ -921,13 +934,17 @@ static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, i item= PySequence_Fast_GET_ITEM(seq_fast, i); if( (PyTuple_CheckExact(item)) && - (PyTuple_GET_SIZE(item) == 3) && + (item_size= PyTuple_GET_SIZE(item)) && + (item_size == 3 || item_size == 4) && (tmp.identifier= _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 0), &id_str_size)) && (tmp.name= _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 1), &name_str_size)) && - (tmp.description= _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 2), &desc_str_size)) + (tmp.description= _PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(item, 2), &desc_str_size)) && + (item_size < 4 || py_long_as_int(PyTuple_GET_ITEM(item, 3), &tmp.value) != -1) /* TODO, number isnt ensured to be unique from the script author */ ) { if(is_enum_flag) { - tmp.value= 1<<i; + if(item_size < 4) { + tmp.value= 1<<i; + } if(def && PySet_Contains(def, PyTuple_GET_ITEM(item, 0))) { *defvalue |= tmp.value; @@ -935,7 +952,9 @@ static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, i } } else { - tmp.value= i; + if(item_size < 4) { + tmp.value= i; + } if(def && def_used == 0 && strcmp(def_cmp, tmp.identifier)==0) { *defvalue= tmp.value; @@ -950,7 +969,10 @@ static EnumPropertyItem *enum_items_from_py(PyObject *seq_fast, PyObject *def, i } else { MEM_freeN(items); - PyErr_SetString(PyExc_TypeError, "EnumProperty(...): expected an tuple containing (identifier, name description)"); + PyErr_SetString(PyExc_TypeError, + "EnumProperty(...): expected an tuple containing " + "(identifier, name description) and optionally a " + "unique number"); return NULL; } @@ -1081,8 +1103,9 @@ BPY_PROPDEF_DESC_DOC " :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'ENUM_FLAG'].\n" " :type options: set\n" " :arg items: sequence of enum items formatted:\n" -" [(identifier, name, description), ...] where the identifier is used\n" +" [(identifier, name, description, number), ...] where the identifier is used\n" " for python access and other values are used for the interface.\n" +" Note the item is optional.\n" " For dynamic values a callback can be passed which returns a list in\n" " the same format as the static list.\n" " This function must take 2 arguments (self, context)\n" diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index cbd6affb117..98aa8c9be35 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -6238,7 +6238,11 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param ParameterIterator iter; PointerRNA funcptr; int err= 0, i, flag, ret_len=0; - int is_static= RNA_function_flag(func) & FUNC_NO_SELF; + const char is_static= (RNA_function_flag(func) & FUNC_NO_SELF) != 0; + + /* annoying!, need to check if the screen gets set to NULL which is a + * hint that the file was actually re-loaded. */ + char is_valid_wm; PropertyRNA *pret_single= NULL; void *retdata_single= NULL; @@ -6265,6 +6269,8 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param if(C==NULL) C= BPy_GetContext(); + is_valid_wm= (CTX_wm_manager(C) != NULL); + bpy_context_set(C, &gilstate); if (!is_static) { @@ -6498,7 +6504,11 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param if(err != 0) { ReportList *reports; /* alert the user, else they wont know unless they see the console. */ - if (!is_static && ptr->data && RNA_struct_is_a(ptr->type, &RNA_Operator)) { + if ( (!is_static) && + (ptr->data) && + (RNA_struct_is_a(ptr->type, &RNA_Operator)) && + (is_valid_wm == (CTX_wm_manager(C) != NULL))) + { wmOperator *op= ptr->data; reports= op->reports; } diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index 30f6c02115a..502fa25c872 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -44,9 +44,6 @@ /* support for inter references, currently only needed for corner case */ #define USE_PYRNA_STRUCT_REFERENCE -/* use real collection iterators rather than faking with a list */ -#define USE_PYRNA_ITER - #else /* WITH_PYTHON_SAFETY */ /* default, no defines! */ @@ -67,6 +64,11 @@ * so prefer the leak to the memory bloat for now. */ // #define PYRNA_FREE_SUPPORT +/* use real collection iterators rather than faking with a list + * this is needed so enums can be iterated over without crashing, + * since finishing the iteration frees temp allocated enums */ +#define USE_PYRNA_ITER + /* --- end bpy build options --- */ struct ID; diff --git a/source/blender/quicktime/SConscript b/source/blender/quicktime/SConscript index 24dfab13fd9..82735dc96bd 100644 --- a/source/blender/quicktime/SConscript +++ b/source/blender/quicktime/SConscript @@ -35,5 +35,6 @@ defs=['WITH_QUICKTIME'] if env['WITH_GHOST_COCOA']: defs.append('GHOST_COCOA') - -env.BlenderLib ('bf_quicktime', sources=source_files, includes=incs, defines=defs, libtype=types, priority=priorities) + env.BlenderLib ('bf_quicktime', sources=source_files, includes=incs, defines=defs, libtype=types, priority=priorities, cc_compilerchange='/usr/bin/gcc-4.2', cxx_compilerchange='/usr/bin/gcc-4.2') # always use Apple-gcc-4.2 for objC language, for gnu-compilers do not support it fully yet +else: + env.BlenderLib ('bf_quicktime', sources=source_files, includes=incs, defines=defs, libtype=types, priority=priorities) diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 0b339d285ce..6d27c7707f0 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -485,7 +485,6 @@ typedef struct VolPrecachePart int res[3]; float bbmin[3]; float voxel[3]; - int working, done; struct Render *re; } VolPrecachePart; diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 8d953ccc73d..ae814f67450 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -1748,7 +1748,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; // temp TexResult float tco[3], texv[3], cd, ud, vd, du, dv, idu, idv; const int fromrgb = ((tex->type == TEX_IMAGE) || ((tex->flag & TEX_COLORBAND)!=0)); - const float bf = 0.04f*Tnor*mtex->norfac; + const float bf = -0.04f*Tnor*mtex->norfac; int rgbnor; // disable internal bump eval float* nvec = texres->nor; @@ -1904,7 +1904,14 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; // temp TexResult const int fromrgb = ((tex->type == TEX_IMAGE) || ((tex->flag & TEX_COLORBAND)!=0)); - float Hscale = Tnor*mtex->norfac; + + // The negate on Hscale is done because the + // normal in the renderer points inward which corresponds + // to inverting the bump map. The normals are generated + // this way in calc_vertexnormals(). Should this ever change + // this negate must be removed. + float Hscale = -Tnor*mtex->norfac; + int dimx=512, dimy=512; const int imag_tspace_dimension_x = 1024; // only used for texture space variant float aspect = 1.0f; diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 18132c4a7f3..d6cfcee4ac9 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -477,6 +477,11 @@ static void *vol_precache_part_test(void *data) } #endif +typedef struct VolPrecacheQueue { + ThreadQueue *work; + ThreadQueue *done; +} VolPrecacheQueue; + /* Iterate over the 3d voxel grid, and fill the voxels with scattering information * * It's stored in memory as 3 big float grids next to each other, one for each RGB channel. @@ -485,58 +490,65 @@ static void *vol_precache_part_test(void *data) */ static void *vol_precache_part(void *data) { - VolPrecachePart *pa = (VolPrecachePart *)data; - ObjectInstanceRen *obi = pa->obi; - RayObject *tree = pa->tree; - ShadeInput *shi = pa->shi; - float scatter_col[3] = {0.f, 0.f, 0.f}; - float co[3], cco[3], view[3]; - int x, y, z, i; - int res[3]; - - res[0]= pa->res[0]; - res[1]= pa->res[1]; - res[2]= pa->res[2]; - - for (z= pa->minz; z < pa->maxz; z++) { - co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f)); - - for (y= pa->miny; y < pa->maxy; y++) { - co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f)); + VolPrecacheQueue *queue = (VolPrecacheQueue*)data; + VolPrecachePart *pa; + + while ((pa = BLI_thread_queue_pop(queue->work))) { + ObjectInstanceRen *obi = pa->obi; + RayObject *tree = pa->tree; + ShadeInput *shi = pa->shi; + float scatter_col[3] = {0.f, 0.f, 0.f}; + float co[3], cco[3], view[3]; + int x, y, z, i; + int res[3]; + + if (pa->re->test_break && pa->re->test_break(pa->re->tbh)) + break; + + res[0]= pa->res[0]; + res[1]= pa->res[1]; + res[2]= pa->res[2]; + + for (z= pa->minz; z < pa->maxz; z++) { + co[2] = pa->bbmin[2] + (pa->voxel[2] * (z + 0.5f)); - for (x=pa->minx; x < pa->maxx; x++) { - co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f)); - - if (pa->re->test_break && pa->re->test_break(pa->re->tbh)) - break; + for (y= pa->miny; y < pa->maxy; y++) { + co[1] = pa->bbmin[1] + (pa->voxel[1] * (y + 0.5f)); - /* convert from world->camera space for shading */ - mul_v3_m4v3(cco, pa->viewmat, co); - - i= V_I(x, y, z, res); + for (x=pa->minx; x < pa->maxx; x++) { + co[0] = pa->bbmin[0] + (pa->voxel[0] * (x + 0.5f)); + + if (pa->re->test_break && pa->re->test_break(pa->re->tbh)) + break; + + /* convert from world->camera space for shading */ + mul_v3_m4v3(cco, pa->viewmat, co); + + i= V_I(x, y, z, res); + + // don't bother if the point is not inside the volume mesh + if (!point_inside_obi(tree, obi, cco)) { + obi->volume_precache->data_r[i] = -1.0f; + obi->volume_precache->data_g[i] = -1.0f; + obi->volume_precache->data_b[i] = -1.0f; + continue; + } + + copy_v3_v3(view, cco); + normalize_v3(view); + vol_get_scattering(shi, scatter_col, cco, view); - // don't bother if the point is not inside the volume mesh - if (!point_inside_obi(tree, obi, cco)) { - obi->volume_precache->data_r[i] = -1.0f; - obi->volume_precache->data_g[i] = -1.0f; - obi->volume_precache->data_b[i] = -1.0f; - continue; + obi->volume_precache->data_r[i] = scatter_col[0]; + obi->volume_precache->data_g[i] = scatter_col[1]; + obi->volume_precache->data_b[i] = scatter_col[2]; + } - - copy_v3_v3(view, cco); - normalize_v3(view); - vol_get_scattering(shi, scatter_col, cco, view); - - obi->volume_precache->data_r[i] = scatter_col[0]; - obi->volume_precache->data_g[i] = scatter_col[1]; - obi->volume_precache->data_b[i] = scatter_col[2]; - } } + + BLI_thread_queue_push(queue->done, pa); } - pa->done = 1; - return NULL; } @@ -602,9 +614,6 @@ static void precache_init_parts(Render *re, RayObject *tree, ShadeInput *shi, Ob minz = z * sizez; maxz = minz + sizez; maxz = (maxz>res[2])?res[2]:maxz; - - pa->done = 0; - pa->working = 0; pa->re = re; pa->num = i; @@ -630,21 +639,6 @@ static void precache_init_parts(Render *re, RayObject *tree, ShadeInput *shi, Ob } } -static VolPrecachePart *precache_get_new_part(Render *re) -{ - VolPrecachePart *pa, *nextpa=NULL; - - for (pa = re->volume_precache_parts.first; pa; pa=pa->next) - { - if (pa->done==0 && pa->working==0) { - nextpa = pa; - break; - } - } - - return nextpa; -} - /* calculate resolution from bounding box in world space */ static int precache_resolution(Render *re, VolumePrecache *vp, ObjectInstanceRen *obi, int res) { @@ -678,14 +672,15 @@ static int precache_resolution(Render *re, VolumePrecache *vp, ObjectInstanceRen static void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *obi, Material *ma) { VolumePrecache *vp; - VolPrecachePart *nextpa, *pa; + VolPrecachePart *pa; RayObject *tree; ShadeInput shi; ListBase threads; + VolPrecacheQueue queue; int parts[3] = {1, 1, 1}, totparts; - int caching=1, counter=0; - int totthread = re->r.threads; + int counter=0; + int totthread = re->r.threads, thread; double time, lasttime= PIL_check_seconds_timer(); @@ -718,34 +713,29 @@ static void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *o precache_init_parts(re, tree, &shi, obi, totthread, parts); totparts = parts[0] * parts[1] * parts[2]; + + /* setup work and done queues */ + queue.work = BLI_thread_queue_init(); + queue.done = BLI_thread_queue_init(); + BLI_thread_queue_nowait(queue.work); + + for(pa= re->volume_precache_parts.first; pa; pa= pa->next) + BLI_thread_queue_push(queue.work, pa); + /* launch threads */ BLI_init_threads(&threads, vol_precache_part, totthread); + + for(thread= 0; thread<totthread; thread++) + BLI_insert_thread(&threads, &queue); - while(caching) { + /* loop waiting for work to be done */ + while(counter < totparts) { + if(re->test_break && re->test_break(re->tbh)) + break; - if(BLI_available_threads(&threads) && !(re->test_break(re->tbh))) { - nextpa = precache_get_new_part(re); - if (nextpa) { - nextpa->working = 1; - BLI_insert_thread(&threads, nextpa); - } - } - else PIL_sleep_ms(50); + if(BLI_thread_queue_pop_timeout(queue.done, 50)) + counter++; - caching=0; - counter=0; - for(pa= re->volume_precache_parts.first; pa; pa= pa->next) { - - if(pa->done) { - counter++; - BLI_remove_thread(&threads, pa); - } else - caching = 1; - } - - if (re->test_break(re->tbh) && BLI_available_threads(&threads)==totthread) - caching=0; - time= PIL_check_seconds_timer(); if(time-lasttime>1.0) { char str[64]; @@ -757,7 +747,10 @@ static void vol_precache_objectinstance_threads(Render *re, ObjectInstanceRen *o } } + /* free */ BLI_end_threads(&threads); + BLI_thread_queue_free(queue.work); + BLI_thread_queue_free(queue.done); BLI_freelistN(&re->volume_precache_parts); if(tree) { @@ -788,13 +781,22 @@ void volume_precache(Render *re) ObjectInstanceRen *obi; VolumeOb *vo; + re->i.infostr= "Volume preprocessing"; + re->stats_draw(re->sdh, &re->i); + for(vo= re->volumes.first; vo; vo= vo->next) { if (using_lightcache(vo->ma)) { for(obi= re->instancetable.first; obi; obi= obi->next) { if (obi->obr == vo->obr) { vol_precache_objectinstance_threads(re, obi, vo->ma); + + if(re->test_break && re->test_break(re->tbh)) + break; } } + + if(re->test_break && re->test_break(re->tbh)) + break; } } diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 9299b50103c..5beb07a1ed0 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -230,6 +230,7 @@ void WM_keymap_init(bContext *C) { wmWindowManager *wm= CTX_wm_manager(C); + /* create standard key configs */ if(!wm->defaultconf) wm->defaultconf= WM_keyconfig_new(wm, "Blender"); if(!wm->addonconf) @@ -237,10 +238,17 @@ void WM_keymap_init(bContext *C) if(!wm->userconf) wm->userconf= WM_keyconfig_new(wm, "Blender User"); + /* initialize only after python init is done, for keymaps that + use python operators */ if(CTX_py_init_get(C) && (wm->initialized & WM_INIT_KEYMAP) == 0) { - /* create default key config */ - wm_window_keymap(wm->defaultconf); - ED_spacetypes_keymap(wm->defaultconf); + /* create default key config, only initialize once, + it's persistent across sessions */ + if(!(wm->defaultconf->flag & KEYCONF_INIT_DEFAULT)) { + wm_window_keymap(wm->defaultconf); + ED_spacetypes_keymap(wm->defaultconf); + + wm->defaultconf->flag |= KEYCONF_INIT_DEFAULT; + } WM_keyconfig_update_tag(NULL, NULL); WM_keyconfig_update(wm); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index cfeaee18416..596fa35d597 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1223,41 +1223,47 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand retval= ot->modal(C, op, event); OPERATOR_RETVAL_CHECK(retval); - if(ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) - wm->op_undo_depth--; + /* when this is _not_ the case the modal modifier may have loaded + * a new blend file (demo mode does this), so we have to assume + * the event, operator etc have all been freed. - campbell */ + if(CTX_wm_manager(C) == wm) { - /* putting back screen context, reval can pass trough after modal failures! */ - if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) { - CTX_wm_area_set(C, area); - CTX_wm_region_set(C, region); - } - else { - /* this special cases is for areas and regions that get removed */ - CTX_wm_area_set(C, NULL); - CTX_wm_region_set(C, NULL); - } + if(ot->flag & OPTYPE_UNDO) + wm->op_undo_depth--; - if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) - wm_operator_reports(C, op, retval, 0); - - if(retval & OPERATOR_FINISHED) { - wm_operator_finished(C, op, 0); - handler->op= NULL; - } - else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { - WM_operator_free(op); - handler->op= NULL; - } - - /* remove modal handler, operator itself should have been cancelled and freed */ - if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { - WM_cursor_ungrab(CTX_wm_window(C)); + /* putting back screen context, reval can pass trough after modal failures! */ + if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) { + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + } + else { + /* this special cases is for areas and regions that get removed */ + CTX_wm_area_set(C, NULL); + CTX_wm_region_set(C, NULL); + } - BLI_remlink(handlers, handler); - wm_event_free_handler(handler); - - /* prevent silly errors from operator users */ - //retval &= ~OPERATOR_PASS_THROUGH; + if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) + wm_operator_reports(C, op, retval, 0); + + if(retval & OPERATOR_FINISHED) { + wm_operator_finished(C, op, 0); + handler->op= NULL; + } + else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { + WM_operator_free(op); + handler->op= NULL; + } + + /* remove modal handler, operator itself should have been cancelled and freed */ + if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { + WM_cursor_ungrab(CTX_wm_window(C)); + + BLI_remlink(handlers, handler); + wm_event_free_handler(handler); + + /* prevent silly errors from operator users */ + //retval &= ~OPERATOR_PASS_THROUGH; + } } } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index f862af6173a..76ebeaa9f21 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -226,13 +226,16 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist) oldwm= oldwmlist->first; wm= G.main->wm.first; - /* move addon key configuration to new wm, to preserve their keymaps */ - if(oldwm->addonconf) { - wm->addonconf= oldwm->addonconf; - BLI_remlink(&oldwm->keyconfigs, oldwm->addonconf); - oldwm->addonconf= NULL; - BLI_addtail(&wm->keyconfigs, wm->addonconf); - } + /* preserve key configurations in new wm, to preserve their keymaps */ + wm->keyconfigs= oldwm->keyconfigs; + wm->addonconf= oldwm->addonconf; + wm->defaultconf= oldwm->defaultconf; + wm->userconf= oldwm->userconf; + + oldwm->keyconfigs.first= oldwm->keyconfigs.last= NULL; + oldwm->addonconf= NULL; + oldwm->defaultconf= NULL; + oldwm->userconf= NULL; /* ensure making new keymaps and set space types */ wm->initialized= 0; @@ -286,7 +289,8 @@ static void wm_init_userdef(bContext *C) if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) G.f |= G_SCRIPT_AUTOEXEC; else G.f &= ~G_SCRIPT_AUTOEXEC; } - if(U.tempdir[0]) BLI_where_is_temp(btempdir, FILE_MAX, 1); + /* update tempdir from user preferences */ + BLI_where_is_temp(btempdir, FILE_MAX, 1); } @@ -850,14 +854,14 @@ void wm_autosave_location(char *filepath) * BLI_make_file_string will create string that has it most likely on C:\ * through get_default_root(). * If there is no C:\tmp autosave fails. */ - if (!BLI_exists(U.tempdir)) { + if (!BLI_exists(btempdir)) { savedir = BLI_get_folder_create(BLENDER_USER_AUTOSAVE, NULL); BLI_make_file_string("/", filepath, savedir, pidstr); return; } #endif - - BLI_make_file_string("/", filepath, U.tempdir, pidstr); + + BLI_make_file_string("/", filepath, btempdir, pidstr); } void WM_autosave_init(wmWindowManager *wm) @@ -915,7 +919,7 @@ void wm_autosave_delete(void) if(BLI_exists(filename)) { char str[FILE_MAXDIR+FILE_MAXFILE]; - BLI_make_file_string("/", str, U.tempdir, "quit.blend"); + BLI_make_file_string("/", str, btempdir, "quit.blend"); /* if global undo; remove tempsave, otherwise rename */ if(U.uiflag & USER_GLOBALUNDO) BLI_delete(filename, 0, 0); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 296cd1b86d8..4639e2a0514 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -428,6 +428,8 @@ void WM_exit_ext(bContext *C, const short do_python) * the pyDriver bug can be fixed if it happens again we can deal with it then */ BPY_python_end(); } +#else + (void)do_python; #endif GPU_global_buffer_pool_free(); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 841198c0664..b980b45bae4 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1208,9 +1208,6 @@ static int wm_resource_check_prev(void) static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(arg)) { - extern char datatoc_splash_png[]; - extern int datatoc_splash_png_size; - uiBlock *block; uiBut *but; uiLayout *layout, *split, *col; @@ -1219,9 +1216,17 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar int i; MenuType *mt= WM_menutype_find("USERPREF_MT_splash", TRUE); char url[96]; - /* hardcoded to splash, loading and freeing every draw, eek! */ + +#ifndef WITH_HEADLESS + extern char datatoc_splash_png[]; + extern int datatoc_splash_png_size; + ImBuf *ibuf= IMB_ibImageFromMemory((unsigned char*)datatoc_splash_png, datatoc_splash_png_size, IB_rect); - +#else + ImBuf *ibuf= NULL; +#endif + + #ifdef WITH_BUILDINFO int ver_width, rev_width; char *version_str = NULL; diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp index 5747d8641d0..0ee1ca20234 100644 --- a/source/gameengine/Ketsji/KX_NavMeshObject.cpp +++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp @@ -518,7 +518,7 @@ void KX_NavMeshObject::DrawNavMesh(NavMeshRenderMode renderMode) else v = m_navMesh->getDetailVertex(pd->vbase+(t[k]-p->nv)); float pos[3]; - vcopy(pos, v); + rcVcopy(pos, v); flipAxes(pos); tri[k].setValue(pos); } diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp index a0a2e148c1e..1edecdf44d2 100644 --- a/source/gameengine/Ketsji/KX_SteeringActuator.cpp +++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp @@ -325,9 +325,9 @@ inline float vdot2(const float* a, const float* b) static bool barDistSqPointToTri(const float* p, const float* a, const float* b, const float* c) { float v0[3], v1[3], v2[3]; - vsub(v0, c,a); - vsub(v1, b,a); - vsub(v2, p,a); + rcVsub(v0, c,a); + rcVsub(v1, b,a); + rcVsub(v2, p,a); const float dot00 = vdot2(v0, v0); const float dot01 = vdot2(v0, v1); |