Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2011-10-06 20:59:58 +0400
committerCampbell Barton <ideasman42@gmail.com>2011-10-06 20:59:58 +0400
commit8695bedda2cb57490bcea957b0a25eb85cb4c9a5 (patch)
tree4355e0c4f0e9492c53c7a9abf424748141ec320c
parent757f177d9d294451441c95f03dcf8327f59a4b98 (diff)
parent2bb59bc2734ac682208419e42aebf27285a88d22 (diff)
svn merge ^/trunk/blender -r40644:40720
-rw-r--r--CMakeLists.txt6
-rw-r--r--GNUmakefile2
-rw-r--r--SConstruct2
-rw-r--r--build_files/cmake/macros.cmake8
-rw-r--r--build_files/scons/config/darwin-config.py7
-rw-r--r--doc/python_api/sphinx_doc_gen.py24
-rw-r--r--extern/recastnavigation/CMakeLists.txt9
-rw-r--r--extern/recastnavigation/Recast/Include/Recast.h1297
-rw-r--r--extern/recastnavigation/Recast/Include/RecastAlloc.h122
-rw-r--r--extern/recastnavigation/Recast/Include/RecastAssert.h33
-rw-r--r--extern/recastnavigation/Recast/Source/Recast.cpp335
-rw-r--r--extern/recastnavigation/Recast/Source/RecastAlloc.cpp88
-rw-r--r--extern/recastnavigation/Recast/Source/RecastArea.cpp524
-rw-r--r--extern/recastnavigation/Recast/Source/RecastContour.cpp399
-rw-r--r--extern/recastnavigation/Recast/Source/RecastFilter.cpp250
-rw-r--r--extern/recastnavigation/Recast/Source/RecastLayers.cpp620
-rw-r--r--extern/recastnavigation/Recast/Source/RecastMesh.cpp679
-rw-r--r--extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp1068
-rw-r--r--extern/recastnavigation/Recast/Source/RecastRasterization.cpp167
-rw-r--r--extern/recastnavigation/Recast/Source/RecastRegion.cpp730
-rw-r--r--extern/recastnavigation/recast-capi.cpp211
-rw-r--r--extern/recastnavigation/recast-capi.h18
-rw-r--r--intern/audaspace/intern/AUD_SequencerReader.cpp10
-rw-r--r--intern/elbeem/intern/ntl_world.cpp1
-rw-r--r--intern/ghost/SConscript4
-rw-r--r--po/POTFILES.in1
-rw-r--r--po/README.txt81
-rwxr-xr-xpo/check_po.py93
-rwxr-xr-xpo/clean_po.py190
-rwxr-xr-xpo/merge_po.py168
-rw-r--r--po/messages.txt5433
-rwxr-xr-xpo/update_mo.py44
-rw-r--r--po/update_msg.py172
-rwxr-xr-xpo/update_po.py46
-rwxr-xr-xpo/update_pot.py31
-rw-r--r--release/bin/.blender/fonts/droidsans.ttf.gzbin2259055 -> 2263650 bytes
-rw-r--r--release/scripts/startup/bl_operators/screen_play_rendered_anim.py2
-rw-r--r--release/scripts/startup/bl_ui/space_sequencer.py3
-rw-r--r--source/blender/blenkernel/BKE_blender.h2
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h2
-rw-r--r--source/blender/blenkernel/BKE_object.h5
-rw-r--r--source/blender/blenkernel/intern/cloth.c4
-rw-r--r--source/blender/blenkernel/intern/collision.c6
-rw-r--r--source/blender/blenkernel/intern/colortools.c78
-rw-r--r--source/blender/blenkernel/intern/curve.c175
-rw-r--r--source/blender/blenkernel/intern/fcurve.c13
-rw-r--r--source/blender/blenkernel/intern/implicit.c10
-rw-r--r--source/blender/blenkernel/intern/multires.c2
-rw-r--r--source/blender/blenkernel/intern/navmesh_conversion.c13
-rw-r--r--source/blender/blenkernel/intern/object.c76
-rw-r--r--source/blender/blenkernel/intern/scene.c2
-rw-r--r--source/blender/blenkernel/intern/softbody.c16
-rw-r--r--source/blender/blenkernel/intern/texture.c6
-rw-r--r--source/blender/blenloader/intern/readfile.c103
-rw-r--r--source/blender/editors/animation/anim_filter.c7
-rw-r--r--source/blender/editors/animation/keyframes_edit.c6
-rw-r--r--source/blender/editors/include/UI_interface.h1
-rw-r--r--source/blender/editors/interface/interface.c9
-rw-r--r--source/blender/editors/interface/interface_draw.c1
-rw-r--r--source/blender/editors/interface/interface_handlers.c52
-rw-r--r--source/blender/editors/interface/interface_icons.c6
-rw-r--r--source/blender/editors/interface/interface_ops.c22
-rw-r--r--source/blender/editors/interface/interface_templates.c2
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c23
-rw-r--r--source/blender/editors/physics/physics_fluid.c2
-rw-r--r--source/blender/editors/space_action/action_edit.c3
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c6
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c7
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c268
-rw-r--r--source/blender/editors/space_view3d/drawobject.c102
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c137
-rw-r--r--source/blender/editors/transform/transform_conversions.c58
-rw-r--r--source/blender/gpu/intern/gpu_material.c9
-rw-r--r--source/blender/imbuf/intern/anim_movie.c4
-rw-r--r--source/blender/makesdna/DNA_ID.h4
-rw-r--r--source/blender/makesdna/DNA_texture_types.h1
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h1
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt1
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_armature.c2
-rw-r--r--source/blender/makesrna/intern/rna_boid.c2
-rw-r--r--source/blender/makesrna/intern/rna_camera.c3
-rw-r--r--source/blender/makesrna/intern/rna_camera_api.c88
-rw-r--r--source/blender/makesrna/intern/rna_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c4
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c4
-rw-r--r--source/blender/makesrna/intern/rna_particle.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c8
-rw-r--r--source/blender/makesrna/intern/rna_screen.c6
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c19
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c6
-rw-r--r--source/blender/makesrna/intern/rna_space.c6
-rw-r--r--source/blender/makesrna/intern/rna_texture.c123
-rw-r--r--source/blender/makesrna/intern/rna_ui.c4
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c188
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c4
-rw-r--r--source/blender/python/intern/bpy_props.c35
-rw-r--r--source/blender/python/intern/bpy_rna.c14
-rw-r--r--source/blender/python/intern/bpy_rna.h8
-rw-r--r--source/blender/quicktime/SConscript5
-rw-r--r--source/blender/render/intern/include/render_types.h1
-rw-r--r--source/blender/render/intern/source/render_texture.c11
-rw-r--r--source/blender/render/intern/source/volume_precache.c178
-rw-r--r--source/blender/windowmanager/intern/wm.c14
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c70
-rw-r--r--source/blender/windowmanager/intern/wm_files.c28
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c15
-rw-r--r--source/gameengine/Ketsji/KX_NavMeshObject.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_SteeringActuator.cpp6
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(&regions[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
index 82b413bcdd0..a00f35f3a66 100644
--- a/release/bin/.blender/fonts/droidsans.ttf.gz
+++ b/release/bin/.blender/fonts/droidsans.ttf.gz
Binary files differ
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);