Merged changes in the trunk up to revision 52690.

Conflicts resolved:
release/datafiles/startup.blend
source/blender/blenlib/intern/bpath.c
This commit is contained in:
2012-12-01 02:47:59 +00:00
259 changed files with 4507 additions and 2592 deletions

View File

@@ -0,0 +1,106 @@
# This script uses bmesh operators to make 2 links of a chain.
import bpy
import bmesh
import math
import mathutils
# Make a new BMesh
bm = bmesh.new()
# Add a circle XXX, should return all geometry created, not just verts.
bmesh.ops.create_circle(
bm,
cap_ends=False,
diameter=0.2,
segments=8)
# Spin and deal with geometry on side 'a'
edges_start_a = bm.edges[:]
geom_start_a = bm.verts[:] + edges_start_a
ret = bmesh.ops.spin(
bm,
geom=geom_start_a,
angle=math.radians(180.0),
steps=8,
axis=(1.0, 0.0, 0.0),
cent=(0.0, 1.0, 0.0))
edges_end_a = [ele for ele in ret["geom_last"]
if isinstance(ele, bmesh.types.BMEdge)]
del ret
# Extrude and create geometry on side 'b'
ret = bmesh.ops.extrude_edge_only(
bm,
edges=edges_start_a)
geom_extrude_mid = ret["geom"]
del ret
# Collect the edges to spin XXX, 'extrude_edge_only' could return this.
verts_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMVert)]
edges_extrude_b = [ele for ele in geom_extrude_mid
if isinstance(ele, bmesh.types.BMEdge) and ele.is_boundary]
bmesh.ops.translate(
bm,
verts=verts_extrude_b,
vec=(0.0, 0.0, 1.0))
# Create the circle on side 'b'
ret = bmesh.ops.spin(
bm,
geom=verts_extrude_b + edges_extrude_b,
angle=-math.radians(180.0),
steps=8,
axis=(1.0, 0.0, 0.0),
cent=(0.0, 1.0, 1.0))
edges_end_b = [ele for ele in ret["geom_last"]
if isinstance(ele, bmesh.types.BMEdge)]
del ret
# Bridge the resulting edge loops of both spins 'a & b'
bmesh.ops.bridge_loops(
bm,
edges=edges_end_a + edges_end_b)
# Now we have made a links of the chain, make a copy and rotate it
# (so this looks something like a chain)
ret = bmesh.ops.duplicate(
bm,
geom=bm.verts[:] + bm.edges[:] + bm.faces[:])
geom_dupe = ret["geom"]
verts_dupe = [ele for ele in geom_dupe if isinstance(ele, bmesh.types.BMVert)]
del ret
# position the new link
bmesh.ops.translate(
bm,
verts=verts_dupe,
vec=(0.0, 0.0, 2.0))
bmesh.ops.rotate(
bm,
verts=verts_dupe,
cent=(0.0, 1.0, 0.0),
matrix=mathutils.Matrix.Rotation(math.radians(90.0), 3, 'Z'))
# Done with creating the mesh, simply link it into the scene so we can see it
# Finish up, write the bmesh into a new mesh
me = bpy.data.meshes.new("Mesh")
bm.to_mesh(me)
# Add the mesh to the scene
scene = bpy.context.scene
obj = bpy.data.objects.new("Object", me)
scene.objects.link(obj)
# Select and make active
scene.objects.active = obj
obj.select = True

View File

@@ -416,9 +416,9 @@ Sensor Status
.. data:: KX_SENSOR_ACTIVE
.. data:: KX_SENSOR_JUST_DEACTIVATED
-------------
---------------
Armature Sensor
-------------
---------------
.. _armaturesensor-type:
@@ -537,9 +537,9 @@ See :class:`bge.types.BL_ActionActuator`
.. data:: KX_ACTIONACT_LOOPEND
.. data:: KX_ACTIONACT_PROPERTY
---------------
-----------------
Armature Actuator
---------------
-----------------
.. _armatureactuator-constants-type:
@@ -556,13 +556,13 @@ See :class:`bge.types.BL_ArmatureActuator.type`
.. data:: KX_ACT_ARMATURE_ENABLE
Enable the constraint.
:value: 1
.. data:: KX_ACT_ARMATURE_DISABLE
Disable the constraint (runtime constraint values are not updated).
:value: 2
.. data:: KX_ACT_ARMATURE_SETTARGET
@@ -809,9 +809,9 @@ See :class:`bge.types.KX_SoundActuator`
:value: 6
--------------
-----------------
Steering Actuator
--------------
-----------------
.. _logic-steering-actuator:
@@ -961,9 +961,9 @@ See :class:`bge.types.BL_ArmatureChannel.rotation_mode`
:value: 6
----------------
-------------------
Armature Constraint
----------------
-------------------
.. _armatureconstraint-constants-type:
See :class:`bge.types.BL_ArmatureConstraint.type`
@@ -1075,9 +1075,9 @@ See :class:`bge.types.SCA_PythonKeyboard`, :class:`bge.types.SCA_PythonMouse`, :
.. data:: KX_INPUT_ACTIVE
.. data:: KX_INPUT_JUST_RELEASED
------------
-------------
KX_GameObject
-----------
-------------
.. _gameobject-playaction-mode:
See :class:`bge.types.KX_GameObject.playAction`
@@ -1111,9 +1111,9 @@ See :class:`bge.types.SCA_MouseSensor`
.. data:: KX_MOUSE_BUT_MIDDLE
.. data:: KX_MOUSE_BUT_RIGHT
------------
--------------------------
Navigation Mesh Draw Modes
------------
--------------------------
.. _navmesh-draw-mode:
@@ -1199,25 +1199,25 @@ See :class:`bge.types.KX_StateActuator.operation`
.. data:: KX_STATE_OP_CLR
Substract bits to state mask
:value: 0
.. data:: KX_STATE_OP_CPY
Copy state mask
:value: 1
.. data:: KX_STATE_OP_NEG
Invert bits to state mask
:value: 2
.. data:: KX_STATE_OP_SET
Add bits to state mask
:value: 3
.. _Two-D-FilterActuator-mode:

View File

@@ -759,6 +759,10 @@ Types
The id is derived from a memory location and will be different each time the game engine starts.
.. warning::
The id can't be stored as an integer in game object properties, as those only have a limited range that the id may not be contained in. Instead an id can be stored as a string game property and converted back to an integer for use in from_id lookups.
.. class:: KX_BlenderMaterial(PyObjectPlus)
KX_BlenderMaterial

View File

@@ -0,0 +1,380 @@
# ##### 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>
# This is a quite stupid script which extracts bmesh api docs from
# 'bmesh_opdefines.c' in order to avoid having to add a lot of introspection
# data access into the api.
#
# The script is stupid becase it makes assumptions about formatting...
# that each arg has its own line, that comments above or directly after will be __doc__ etc...
#
# We may want to replace this script with something else one day but for now its good enough.
# if it needs large updates it may be better to rewrite using a real parser or
# add introspection into bmesh.ops.
# - campbell
import os
CURRENT_DIR = os.path.abspath(os.path.dirname(__file__))
SOURCE_DIR = os.path.normpath(os.path.abspath(os.path.normpath(os.path.join(CURRENT_DIR, "..", ".."))))
FILE_OP_DEFINES_C = os.path.join(SOURCE_DIR, "source", "blender", "bmesh", "intern", "bmesh_opdefines.c")
OUT_RST = os.path.join(CURRENT_DIR, "rst", "bmesh.ops.rst")
HEADER = r"""
BMesh Operators (bmesh.ops)
===========================
.. module:: bmesh.ops
This module gives access to low level bmesh operations.
Most operators take input and return output, they can be chained together
to perform useful operations.
.. note::
This API us new in 2.65 and not yet well tested.
Operator Example
++++++++++++++++
This script shows how operators can be used to model a link of a chain.
.. literalinclude:: ../examples/bmesh.ops.1.py
"""
def main():
fsrc = open(FILE_OP_DEFINES_C, 'r', encoding="utf-8")
blocks = []
is_block = False
is_comment = False # /* global comments only */
comment_ctx = None
block_ctx = None
for l in fsrc:
l = l[:-1]
# weak but ok
if ("BMOpDefine" in l and l.split()[1] == "BMOpDefine") and not "bmo_opdefines[]" in l:
is_block = True
block_ctx = []
blocks.append((comment_ctx, block_ctx))
elif l.strip().startswith("/*"):
is_comment = True
comment_ctx = []
if is_block:
if l.strip().startswith("//"):
pass
else:
# remove c++ comment if we have one
cpp_comment = l.find("//")
if cpp_comment != -1:
l = l[:cpp_comment]
block_ctx.append(l)
if l.strip() == "};":
is_block = False
comment_ctx = None
if is_comment:
c_comment_start = l.find("/*")
if c_comment_start != -1:
l = l[c_comment_start + 2:]
c_comment_end = l.find("*/")
if c_comment_end != -1:
l = l[:c_comment_end]
is_comment = False
comment_ctx.append(l)
fsrc.close()
del fsrc
# namespace hack
vars = (
"BMO_OP_SLOT_ELEMENT_BUF",
"BMO_OP_SLOT_BOOL",
"BMO_OP_SLOT_FLT",
"BMO_OP_SLOT_INT",
"BMO_OP_SLOT_MAT",
"BMO_OP_SLOT_VEC",
"BMO_OP_SLOT_PTR",
"BMO_OP_SLOT_MAPPING",
"BMO_OP_SLOT_SUBTYPE_MAP_ELEM",
"BMO_OP_SLOT_SUBTYPE_MAP_BOOL",
"BMO_OP_SLOT_SUBTYPE_MAP_INT",
"BMO_OP_SLOT_SUBTYPE_MAP_FLT",
"BMO_OP_SLOT_SUBTYPE_MAP_EMPTY",
"BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL",
"BMO_OP_SLOT_SUBTYPE_PTR_SCENE",
"BMO_OP_SLOT_SUBTYPE_PTR_OBJECT",
"BMO_OP_SLOT_SUBTYPE_PTR_MESH",
"BMO_OP_SLOT_SUBTYPE_PTR_BMESH",
"BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE",
"BM_VERT",
"BM_EDGE",
"BM_FACE",
"BMO_OP_FLAG_UNTAN_MULTIRES",
)
vars_dict = {}
for i, v in enumerate(vars):
vars_dict[v] = (1 << i)
globals().update(vars_dict)
# reverse lookup
vars_dict_reverse = {v: k for k, v in vars_dict.items()}
# end namespace hack
blocks_py = []
for comment, b in blocks:
# magic, translate into python
b[0] = b[0].replace("static BMOpDefine ", "")
for i, l in enumerate(b):
l = l.strip()
l = l.replace("{", "(")
l = l.replace("}", ")")
if l.startswith("/*"):
l = l.replace("/*", "'''own <")
else:
l = l.replace("/*", "'''inline <")
l = l.replace("*/", ">''',")
# exec func. eg: bmo_rotate_edges_exec,
if l.startswith("bmo_") and l.endswith("_exec,"):
l = "None,"
b[i] = l
#for l in b:
# print(l)
text = "\n".join(b)
global_namespace = {
"__file__": "generated",
"__name__": "__main__",
}
global_namespace.update(vars_dict)
text_a, text_b = text.split("=", 1)
text = "result = " + text_b
exec(compile(text, "generated", 'exec'), global_namespace)
# print(global_namespace["result"])
blocks_py.append((comment, global_namespace["result"]))
# ---------------------
# Now convert into rst.
fout = open(OUT_RST, 'w', encoding="utf-8")
fw = fout.write
fw(HEADER)
for comment, b in blocks_py:
args_in = None
args_out = None
for member in b[1:]:
if type(member) == tuple:
if args_in is None:
args_in = member
elif args_out is None:
args_out = member
break
args_in_index = []
args_out_index = []
if args_in is not None:
args_in_index[:] = [i for (i, a) in enumerate(args_in) if type(a) == tuple]
if args_out is not None:
args_out_index[:] = [i for (i, a) in enumerate(args_out) if type(a) == tuple]
fw(".. function:: %s(bm, %s)\n\n" % (b[0], ", ".join([args_in[i][0] for i in args_in_index])))
# -- wash the comment
comment_washed = []
for i, l in enumerate(comment):
assert((l.strip() == "") or
(l in {"/*", " *"}) or
(l.startswith(("/* ", " * "))))
l = l[3:]
if i == 0 and not l.strip():
continue
if l.strip():
l = " " + l
comment_washed.append(l)
fw("\n".join(comment_washed))
fw("\n")
# -- done
# get the args
def get_args_wash(args, args_index, is_ret):
args_wash = []
for i in args_index:
arg = args[i]
if len(arg) == 3:
name, tp, tp_sub = arg
elif len(arg) == 2:
name, tp = arg
tp_sub = None
else:
print(arg)
assert(0)
tp_str = ""
comment_prev = ""
comment_next = ""
if i != 0:
comment_prev = args[i + 1]
if type(comment_prev) == str and comment_prev.startswith("our <"):
comment_prev = comment_next[5:-1] # strip inline <...>
else:
comment_prev = ""
if i + 1 < len(args):
comment_next = args[i + 1]
if type(comment_next) == str and comment_next.startswith("inline <"):
comment_next = comment_next[8:-1] # strip inline <...>
else:
comment_next = ""
comment = ""
if comment_prev:
comment += comment_prev.strip()
if comment_next:
comment += ("\n" if comment_prev else "") + comment_next.strip()
if tp == BMO_OP_SLOT_FLT:
tp_str = "float"
elif tp == BMO_OP_SLOT_INT:
tp_str = "int"
elif tp == BMO_OP_SLOT_BOOL:
tp_str = "bool"
elif tp == BMO_OP_SLOT_MAT:
tp_str = ":class:`mathutils.Matrix`"
elif tp == BMO_OP_SLOT_VEC:
tp_str = ":class:`mathutils.Vector`"
if not is_ret:
tp_str += " or any sequence of 3 floats"
elif tp == BMO_OP_SLOT_PTR:
tp_str = "dict"
assert(tp_sub is not None)
if tp_sub == BMO_OP_SLOT_SUBTYPE_PTR_BMESH:
tp_str = ":class:`bmesh.types.BMesh`"
elif tp_sub == BMO_OP_SLOT_SUBTYPE_PTR_SCENE:
tp_str = ":class:`bpy.types.Scene`"
elif tp_sub == BMO_OP_SLOT_SUBTYPE_PTR_OBJECT:
tp_str = ":class:`bpy.types.Object`"
elif tp_sub == BMO_OP_SLOT_SUBTYPE_PTR_MESH:
tp_str = ":class:`bpy.types.Mesh`"
else:
print("Cant find", vars_dict_reverse[tp_sub])
assert(0)
elif tp == BMO_OP_SLOT_ELEMENT_BUF:
assert(tp_sub is not None)
ls = []
if tp_sub & BM_VERT: ls.append(":class:`bmesh.types.BMVert`")
if tp_sub & BM_EDGE: ls.append(":class:`bmesh.types.BMEdge`")
if tp_sub & BM_FACE: ls.append(":class:`bmesh.types.BMFace`")
assert(ls) # must be at least one
if tp_sub & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE:
tp_str = "/".join(ls)
else:
tp_str = ("list of (%s)" % ", ".join(ls))
del ls
elif tp == BMO_OP_SLOT_MAPPING:
if tp_sub & BMO_OP_SLOT_SUBTYPE_MAP_EMPTY:
tp_str = "set of vert/edge/face type"
else:
tp_str = "dict mapping vert/edge/face types to "
if tp_sub == BMO_OP_SLOT_SUBTYPE_MAP_BOOL:
tp_str += "bool"
elif tp_sub == BMO_OP_SLOT_SUBTYPE_MAP_INT:
tp_str += "int"
elif tp_sub == BMO_OP_SLOT_SUBTYPE_MAP_FLT:
tp_str += "float"
elif tp_sub == BMO_OP_SLOT_SUBTYPE_MAP_ELEM:
tp_str += ":class:`bmesh.types.BMVert`/:class:`bmesh.types.BMEdge`/:class:`bmesh.types.BMFace`"
elif tp_sub == BMO_OP_SLOT_SUBTYPE_MAP_INTERNAL:
tp_str += "unknown internal data, not compatible with python"
else:
print("Cant find", vars_dict_reverse[tp_sub])
assert(0)
else:
print("Cant find", vars_dict_reverse[tp])
assert(0)
args_wash.append((name, tp_str, comment))
return args_wash
# end get_args_wash
# all ops get this arg
fw(" :arg bm: The bmesh to operate on.\n")
fw(" :type bm: :class:`bmesh.types.BMesh`\n")
args_in_wash = get_args_wash(args_in, args_in_index, False)
args_out_wash = get_args_wash(args_out, args_out_index, True)
for (name, tp, comment) in args_in_wash:
if comment == "":
comment = "Undocumented."
fw(" :arg %s: %s\n" % (name, comment))
fw(" :type %s: %s\n" % (name, tp))
if args_out_wash:
fw(" :return:\n\n")
for (name, tp, comment) in args_out_wash:
assert(name.endswith(".out"))
name = name[:-4]
fw(" - ``%s``: %s\n\n" % (name, comment))
fw(" **type** %s\n" % tp)
fw("\n")
fw(" :rtype: dict with string keys\n")
fw("\n\n")
fout.close()
del fout
print(OUT_RST)
if __name__ == "__main__":
main()

View File

@@ -35,7 +35,7 @@ API dump in RST files
./blender.bin --background --python doc/python_api/sphinx_doc_gen.py -- --output ../python_api
For quick builds:
./blender.bin --background --python doc/python_api/sphinx_doc_gen.py -- --partial
./blender.bin --background --python doc/python_api/sphinx_doc_gen.py -- --partial bmesh.*
Sphinx: HTML generation
@@ -245,6 +245,7 @@ else:
"bgl",
"blf",
"bmesh",
"bmesh.ops",
"bmesh.types",
"bmesh.utils",
"bpy.app",
@@ -298,7 +299,7 @@ try:
__import__("aud")
except ImportError:
BPY_LOGGER.debug("Warning: Built without 'aud' module, docs incomplete...")
EXCLUDE_MODULES = EXCLUDE_MODULES + ("aud", )
EXCLUDE_MODULES = list(EXCLUDE_MODULES) + ["aud"]
# examples
EXAMPLES_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "examples"))
@@ -1480,6 +1481,11 @@ def write_sphinx_conf_py(basepath):
file.close()
def execfile(filepath):
global_namespace = {"__file__": filepath, "__name__": "__main__"}
exec(compile(open(filepath).read(), filepath, 'exec'), global_namespace)
def write_rst_contents(basepath):
'''
Write the rst file of the main page, needed for sphinx (index.html)
@@ -1541,13 +1547,17 @@ def write_rst_contents(basepath):
# misc
"Freestyle", "bgl", "blf", "gpu", "aud", "bpy_extras",
# bmesh
"bmesh", "bmesh.types", "bmesh.utils",
"bmesh", "bmesh.types", "bmesh.utils", "bmesh.ops",
)
for mod in standalone_modules:
if mod not in EXCLUDE_MODULES:
fw(" %s\n\n" % mod)
# special case, this 'bmesh.ops.rst' is extracted from C source
if "bmesh.ops" not in EXCLUDE_MODULES:
execfile(os.path.join(SCRIPT_DIR, "rst_from_bmesh_opdefines.py"))
# game engine
if "bge" not in EXCLUDE_MODULES:
fw(title_string("Game Engine Modules", "=", double=True))
@@ -1710,6 +1720,8 @@ def copy_handwritten_rsts(basepath):
"bgl", # "Blender OpenGl wrapper"
"gpu", # "GPU Shader Module"
"bmesh.ops", # generated by rst_from_bmesh_opdefines.py
# includes...
"include__bmesh",
]