svn merge ^/trunk/blender -r40644:40720

This commit is contained in:
Campbell Barton 2011-10-06 16:59:58 +00:00
commit 8695bedda2
112 changed files with 7115 additions and 7927 deletions

@ -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)

@ -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

@ -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'):

@ -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})

@ -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

@ -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")

@ -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}")

File diff suppressed because it is too large Load Diff

@ -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

@ -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

@ -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"
void rcIntArray::resize(int n)
float rcSqrt(float x)
{
if (n > m_cap)
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.
///
/// @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 (!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;
}
}
static int getSpanCount(unsigned char flags, rcHeightfield& hf)
/// @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;
}
}
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)
/// @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)
{
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)
{
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;
}
*/

@ -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;
}

@ -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);
}

@ -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);
const 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];
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;
}

@ -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);
void rcFilterLedgeSpans(const int walkableHeight,
const int walkableClimb,
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);
}
/// @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);
}

@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -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,50 @@ 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);
rcTimeVal endTime = rcGetPerformanceTimer();
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 int* 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 +325,63 @@ 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();
if (rcGetBuildTimes())
rcGetBuildTimes()->rasterizeTriangles += rcGetDeltaTimeUsec(startTime, endTime);
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 unsigned short* tris, 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[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);
}
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 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);
}

File diff suppressed because it is too large Load Diff

@ -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;
INIT_SCTX();
return rcBuildCompactHeightfield(sctx, walkableHeight, walkableClimb,
*(rcHeightfield *) hf, *(rcCompactHeightfield *) chf);
}
if(flags & RECAST_WALKABLE)
rcFlags |= RC_WALKABLE;
if(flags & RECAST_REACHABLE)
rcFlags |= RC_REACHABLE;
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;
}
}

@ -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
}

@ -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++;
}

@ -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 );

@ -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:

@ -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

81
po/README.txt Normal file

@ -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.

93
po/check_po.py Executable file

@ -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()

190
po/clean_po.py Executable file

@ -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()

168
po/merge_po.py Executable file

@ -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()

File diff suppressed because it is too large Load Diff

@ -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 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),
)
def process_po(po):
lang = os.path.basename(po)[:-3]
print(" ".join(cmd))
process = subprocess.Popen(cmd)
process.wait()
# 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():
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__)

@ -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)
walkProperties(bl_rna.properties)
if hasattr(bl_rna, 'bl_label') and bl_rna.bl_label:
messages.setdefault(bl_rna.bl_label, []).append(msgsrc)
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)
cls_list = bpy.types.OperatorProperties.__subclasses__()
cls_list.sort(key=full_class_id)
for cls in cls_list:
walkClass(cls)
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
walk_keymap_hierarchy(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))

@ -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]
if len(sys.argv) > 1:
for lang in sys.argv[1:]:
po = os.path.join(CURRENT_DIR, lang + '.po')
# 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 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__":

@ -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__":

@ -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)]

@ -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):

@ -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

@ -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);

@ -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

@ -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?

@ -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;

@ -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);
}
}

@ -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(len1==0.0f) len1=1.0f;
if(len2==0.0f) len2=1.0f;
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(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]);
}
}
}

@ -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) {

@ -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]);

@ -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");

@ -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;

@ -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)
{

@ -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;

@ -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)){

@ -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;

@ -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;
/* 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;
}
}
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;
}
}
/* put compatibility code here until next subversion bump */
{
}
/* 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! */

@ -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) \
{ \

@ -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 */

@ -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);

@ -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;

@ -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];

@ -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 */

@ -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;

@ -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");

@ -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)

@ -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];

@ -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;

@ -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 */

@ -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 */

@ -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;
}

@ -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);

@ -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);

@ -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", "");
}

@ -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;
}
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]);
camera_view_frame_ex(scene, cam, cam->drawsize, is_view, scale,
asp, shift, &drawsize, vec);
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);
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;
}
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;
/* 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();
}

@ -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, 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, 40, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "");
if(totradius)
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, 150, 200, 20, NULL, 0, 0, 0, 0, "");
uiBlockBeginAlign(block);
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, 110, 200, 20, &(tfp->ve_median[1]), -lim, lim, 10, 3, "");
uiButSetUnitType(but, PROP_UNIT_LENGTH);
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, 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, 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, 20, 200, 20, &(tfp->ve_median[4]), 0.0, 1.0, 10, 3, "");
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, 20, 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, "");
uiBlockBeginAlign(block);
but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "X:", 0, 110, 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, "");
uiButSetUnitType(but, PROP_UNIT_LENGTH);
but= uiDefButF(block, NUM, B_OBJECTPANELMEDIAN, "Z:", 0, 70, 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, "");
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");
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");
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");
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) {

@ -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);
}
}

@ -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))

@ -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);

@ -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

@ -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

@ -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 */

@ -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

@ -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},

@ -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 */

@ -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 */

@ -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

@ -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

@ -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);

@ -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");

@ -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);

@ -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);

@ -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 */

@ -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);

@ -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);

@ -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);

@ -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);

@ -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 */

@ -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\"");

@ -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", ""},

@ -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();

@ -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"

@ -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;
}

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