Merged changes in the trunk up to revision 52815.

This commit is contained in:
Tamito Kajiyama 2012-12-08 12:35:14 +00:00
commit ec33687d6c
179 changed files with 7153 additions and 5305 deletions

@ -127,7 +127,7 @@ option(WITH_PYTHON_MODULE "Enable building as a python module which runs without
option(WITH_BUILDINFO "Include extra build details (only disable for development & faster builds)" ON)
option(WITH_IK_ITASC "Enable ITASC IK solver (only disable for development & for incompatible C++ compilers)" ON)
option(WITH_IK_SOLVER "Enable Legacy IK solver (only disable for development)" ON)
option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke and audio effects)" OFF)
option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke and audio effects)" ON)
option(WITH_BULLET "Enable Bullet (Physics Engine)" ON)
option(WITH_GAMEENGINE "Enable Game Engine" ON)
option(WITH_PLAYER "Build Player" OFF)
@ -387,10 +387,6 @@ if(WITH_PYTHON_MODULE AND WITH_PYTHON_INSTALL)
endif()
if(NOT WITH_FFTW3 AND WITH_MOD_OCEANSIM)
message(FATAL_ERROR "WITH_MOD_OCEANSIM requires WITH_FFTW3 to be ON")
endif()
# may as well build python module without a UI
if(WITH_PYTHON_MODULE)
set(WITH_HEADLESS ON)
@ -1670,6 +1666,10 @@ if(APPLE OR WIN32)
endif()
endif()
if(NOT WITH_FFTW3 AND WITH_MOD_OCEANSIM)
message(FATAL_ERROR "WITH_MOD_OCEANSIM requires WITH_FFTW3 to be ON")
endif()
if(WITH_CYCLES)
if(NOT WITH_OPENIMAGEIO)
message(FATAL_ERROR "Cycles reqires WITH_OPENIMAGEIO, the library may not have been found. Configure OIIO or disable WITH_CYCLES")
@ -1932,12 +1932,13 @@ if(WITH_PYTHON)
if(WITH_PYTHON_INSTALL AND WITH_PYTHON_INSTALL_NUMPY)
# set but invalid
# -- disabled until we make numpy bundled with blender - campbell
if(NOT ${PYTHON_NUMPY_PATH} STREQUAL "")
if(NOT EXISTS "${PYTHON_NUMPY_PATH}/numpy")
message(WARNING "PYTHON_NUMPY_PATH is invalid, numpy not found in '${PYTHON_NUMPY_PATH}' "
"WITH_PYTHON_INSTALL_NUMPY option will be ignored when installing python")
set(WITH_PYTHON_INSTALL_NUMPY OFF)
endif()
# if(NOT EXISTS "${PYTHON_NUMPY_PATH}/numpy")
# message(WARNING "PYTHON_NUMPY_PATH is invalid, numpy not found in '${PYTHON_NUMPY_PATH}' "
# "WITH_PYTHON_INSTALL_NUMPY option will be ignored when installing python")
# set(WITH_PYTHON_INSTALL_NUMPY OFF)
# endif()
# not set, so initialize
else()
string(REPLACE "." ";" _PY_VER_SPLIT "${PYTHON_VERSION}")

@ -700,6 +700,8 @@ if env['OURPLATFORM']!='darwin':
source.remove('kernel.cpp')
source.remove('CMakeLists.txt')
source.remove('svm')
source.remove('closure')
source.remove('shaders')
source.remove('osl')
source=['intern/cycles/kernel/'+s for s in source]
source.append('intern/cycles/util/util_color.h')
@ -715,6 +717,14 @@ if env['OURPLATFORM']!='darwin':
if '__pycache__' in source: source.remove('__pycache__')
source=['intern/cycles/kernel/svm/'+s for s in source]
scriptinstall.append(env.Install(dir=dir,source=source))
# closure
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'kernel', 'closure')
source=os.listdir('intern/cycles/kernel/closure')
if '.svn' in source: source.remove('.svn')
if '_svn' in source: source.remove('_svn')
if '__pycache__' in source: source.remove('__pycache__')
source=['intern/cycles/kernel/closure/'+s for s in source]
scriptinstall.append(env.Install(dir=dir,source=source))
# licenses
dir=os.path.join(env['BF_INSTALLDIR'], VERSION, 'scripts', 'addons','cycles', 'license')

File diff suppressed because it is too large Load Diff

@ -651,7 +651,7 @@ def AppIt(target=None, source=None, env=None):
commands.getoutput(cmd)
cmd = 'cp -R %s/kernel/*.h %s/kernel/*.cl %s/kernel/*.cu %s/kernel/' % (croot, croot, croot, cinstalldir)
commands.getoutput(cmd)
cmd = 'cp -R %s/kernel/svm %s/util/util_color.h %s/util/util_math.h %s/util/util_transform.h %s/util/util_types.h %s/kernel/' % (croot, croot, croot, croot, croot, cinstalldir)
cmd = 'cp -R %s/kernel/svm %s/kernel/closure %s/util/util_color.h %s/util/util_math.h %s/util/util_transform.h %s/util/util_types.h %s/kernel/' % (croot, croot, croot, croot, croot, croot, cinstalldir)
commands.getoutput(cmd)
cmd = 'cp -R %s/../intern/cycles/kernel/*.cubin %s/lib/' % (builddir, cinstalldir)
commands.getoutput(cmd)

@ -1,4 +1,4 @@
.TH "BLENDER" "1" "October 04, 2012" "Blender Blender 2\&.64 (sub 0)"
.TH "BLENDER" "1" "December 04, 2012" "Blender Blender 2\&.65"
.SH NAME
blender \- a 3D modelling and rendering package
@ -15,7 +15,7 @@ Use Blender to create TV commercials, to make technical visualizations, business
http://www.blender.org
.SH OPTIONS
Blender 2.64 (sub 0)
Blender 2.65
Usage: blender [args ...] [file] [args ...]
.br
.SS "Render Options:"
@ -145,6 +145,10 @@ Playback <file(s)>, only operates this way when not running in background.
.br
\-j <frame> Set frame step to <frame>
.br
\-s <frame> Play from <frame>
.br
\-e <frame> Play until <frame>
.br
.IP
@ -344,6 +348,12 @@ Enable debug messages for python
Enable debug messages for the event system
.br
.TP
.B \-\-debug\-handlers
.br
Enable debug messages for event handling
.br
.TP
.B \-\-debug\-wm
.br

@ -95,6 +95,8 @@ bmesh.ops.rotate(
# Finish up, write the bmesh into a new mesh
me = bpy.data.meshes.new("Mesh")
bm.to_mesh(me)
bm.free()
# Add the mesh to the scene
scene = bpy.context.scene

@ -4,6 +4,13 @@
./blender.bin -b -noaudio -P doc/python_api/sphinx_doc_gen.py -- --partial bmesh* ; cd doc/python_api ; sphinx-build sphinx-in sphinx-out ; cd ../../
Submodules:
* :mod:`bmesh.ops`
* :mod:`bmesh.types`
* :mod:`bmesh.utils`
Intro
-----
@ -35,7 +42,6 @@ For an overview of BMesh data types and how they reference each other see:
TODO items are...
* add access to BMesh **walkers**
* add api for calling BMesh operators (unrelated to bpy.ops)
* add custom-data manipulation functions add/remove/rename.
Example Script

@ -0,0 +1,305 @@
*******************
Reference API Usage
*******************
Blender has many interlinking data types which have an auto-generated reference api which often has the information
you need to write a script, but can be difficult to use.
This document is designed to help you understand how to use the reference api.
Reference API Scope
===================
The reference API covers :mod:`bpy.types`, which stores types accessed via :mod:`bpy.context` - *The user context*
or :mod:`bpy.data` - *Blend file data*.
Other modules such as :mod:`bge`, :mod:`bmesh` and :mod:`aud` are not using Blenders data API
so this document doesn't apply to those modules.
Data Access
===========
The most common case for using the reference API is to find out how to access data in the blend file.
Before going any further its best to be aware of ID Data-Blocks in Blender since you will often find properties
relative to them.
ID Data
-------
ID Data-Blocks are used in Blender as top-level data containers.
From the user interface this isn't so obvious, but when developing you need to know about ID Data-Blocks.
ID data types include Scene, Group, Object, Mesh, Screen, World, Armature, Image and Texture.
for a full list see the sub-classes of :class:`bpy.types.ID`
Here are some characteristics ID Data-Blocks share.
- ID's are blend file data, so loading a new blend file reloads an entire new set of Data-Blocks.
- ID's can be accessed in Python from ``bpy.data.*``
- Each data-block has a unique ``.name`` attribute, displayed in the interface.
- Animation data is stored in ID's ``.animation_data``.
- ID's are the only data types that can be linked between blend files.
- ID's can be added/copied and removed via Python.
- ID's have their own garbage-collection system which frees unused ID's when saving.
- When a data-block has a reference to some external data, this is typically an ID Data-Block.
Simple Data Access
------------------
Lets start with a simple case, say you wan't a python script to adjust the objects location.
Start by finding this setting in the interface ``Properties Window -> Object -> Transform -> Location``
From the button you can right click and select **Online Python Reference**, this will link you to:
:class:`bpy.types.Object.location`
Being an API reference, this link often gives little more information then the tool-tip, though some of the pages
include examples (normally at the top of the page).
At this point you may say *Now what?* - you know that you have to use ``.location`` and that its an array of 3 floats
but you're still left wondering how to access this in a script.
So the next step is to find out where to access objects, go down to the bottom of the page to the **References**
section, for objects there are many references, but one of the most common places to access objects is via the context.
It's easy to be overwhelmed at this point since there ``Object`` get referenced in so many places - modifiers,
functions, textures and constraints.
But if you want to access any data the user has selected
you typically only need to check the :mod:`bpy.context` references.
Even then, in this case there are quite a few though if you read over these - most are mode specific.
If you happen to be writing a tool that only runs in weight paint mode, then using ``weight_paint_object``
would be appropriate.
However to access an item the user last selected, look for the ``active`` members,
Having access to a single active member the user selects is a convention in Blender: eg. ``active_bone``,
``active_pose_bone``, ``active_node`` ... and in this case we can use - ``active_object``.
So now we have enough information to find the location of the active object.
.. code-block:: python
bpy.context.active_object.location
You can type this into the python console to see the result.
The other common place to access objects in the reference is :class:`bpy.types.BlendData.objects`.
.. note::
This is **not** listed as :mod:`bpy.data.objects`,
this is because :mod:`bpy.data` is an instance of the :class:`bpy.types.BlendData` class,
so the documentation points there.
With :mod:`bpy.data.objects`, this is a collection of objects so you need to access one of its members.
.. code-block:: python
bpy.data.objects["Cube"].location
Nested Properties
-----------------
The previous example is quite straightforward because ``location`` is a property of ``Object`` which can be accessed
from the context directly.
Here are some more complex examples:
.. code-block:: python
# access a render layers samples
bpy.context.scene.render.layers["RenderLayer"].samples
# access to the current weight paint brush size
bpy.context.tool_settings.weight_paint.brush.size
# check if the window is fullscreen
bpy.context.window.screen.show_fullscreen
As you can see there are times when you want to access data which is nested
in a way that causes you to go through a few indirections.
The properties are arranged to match how data is stored internally (in blenders C code) which is often logical but
not always quite what you would expect from using Blender.
So this takes some time to learn, it helps you understand how data fits together in Blender which is important
to know when writing scripts.
When starting out scripting you will often run into the problem where you're not sure how to access the data you want.
There are a few ways to do this.
- Use the Python console's auto-complete to inspect properties. *This can be hit-and-miss but has the advantage
that you can easily see the values of properties and assign them to interactively see the results.*
- Copy the Data-Path from the user interface. *Explained further in :ref:`Copy Data Path <info_data_path_copy>`*
- Using the documentation to follow references. *Explained further in :ref:`Indirect Data Access <info_data_path_indirect>`*
.. _info_data_path_copy
Copy Data Path
--------------
Blender can compute the Python string to a property which is shown in the tool-tip, on the line below ``Python: ...``,
This saves having to use the API reference to click back up the references to find where data is accessed from.
There is a user-interface feature to copy the data-path which gives the path from an :class:`bpy.types.ID` data-block,
to its property.
To see how this works we'll get the path to the Subdivision-Surface modifiers subdivision setting.
Start with the default scene and select the **Modifiers** tab, then add a **Subdivision-Surface** modifier to the cube.
Now hover your mouse over the button labeled **View**, The tool-tip includes :class:`bpy.types.SubsurfModifier.levels`
but we want the path from the object to this property.
Note that the text copied won't include the ``bpy.data.collection["name"].`` component since its assumed that
you won't be doing collection look-ups on every access and typically you'll want to use the context rather
then access each :class:`bpy.types.ID` instance by name.
Type in the ID path into a Python console :mod:`bpy.context.active_object`. Include the trailing dot and don't hit "enter", yet.
Now right-click on the button and select **Copy Data Path**, then paste the result into the console.
So now you should have the answer:
.. code-block:: python
bpy.context.active_object.modifiers["Subsurf"].levels
Hit "enter" and you'll get the current value of 1. Now try changing the value to 2:
.. code-block:: python
bpy.context.active_object.modifiers["Subsurf"].levels = 2
You can see the value update in the Subdivision-Surface modifier's UI as well as the cube.
.. _info_data_path_indirect
Indirect Data Access
--------------------
For this example we'll go over something more involved, showing the steps to access the active sculpt brushes texture.
Lets say we want to access the texture of a brush via Python, to adjust its ``contrast`` for example.
- Start in the default scene and enable 'Sculpt' mode from the 3D-View header.
- From the toolbar expand the **Texture** panel and add a new texture.
*Notice the texture button its self doesn't have very useful links (you can check the tool-tips).*
- The contrast setting isn't exposed in the sculpt toolbar, so view the texture in the properties panel...
- In the properties button select the Texture context.
- Select the Brush icon to show the brush texture.
- Expand the **Colors** panel to locate the **Contrast** button.
- Right click on the contrast button and select **Online Python Reference** This takes you to ``bpy.types.Texture.contrast``
- Now we can see that ``contrast`` is a property of texture, so next we'll check on how to access the texture from the brush.
- Check on the **References** at the bottom of the page, sometimes there are many references, and it may take
some guess work to find the right one, but in this case its obviously ``Brush.texture``.
*Now we know that the texture can be accessed from* ``bpy.data.brushes["BrushName"].texture``
*but normally you won't want to access the brush by name, so we'll see now to access the active brush instead.*
- So the next step is to check on where brushes are accessed from via the **References**.
In this case there is simply ``bpy.context.brush`` which is all we need.
Now you can use the Python console to form the nested properties needed to access brush textures contrast,
logically we now know.
*Context -> Brush -> Texture -> Contrast*
Since the attribute for each is given along the way we can compose the data path in the python console:
.. code-block:: python
bpy.context.brush.texture.contrast
There can be multiple ways to access the same data, which you choose often depends on the task.
An alternate path to access the same setting is...
.. code-block:: python
bpy.context.sculpt.brush.texture.contrast
Or access the brush directly...
.. code-block:: python
bpy.data.brushes["BrushName"].texture.contrast
If you are writing a user tool normally you want to use the :mod:`bpy.context` since the user normally expects
the tool to operate on what they have selected.
For automation you are more likely to use :mod:`bpy.data` since you want to be able to access specific data and manipulate
it, no matter what the user currently has the view set at.
Operators
=========
Most key-strokes and buttons in Blender call an operator which is also exposed to python via :mod:`bpy.ops`,
To see the Python equivalent hover your mouse over the button and see the tool-tip,
eg ``Python: bpy.ops.render.render()``,
If there is no tool-tip or the ``Python:`` line is missing then this button is not using an operator and
can't be accessed from Python.
If you want to use this in a script you can press :kbd:`Control-C` while your mouse is over the button to copy it to the
clipboard.
You can also right click on the button and view the **Online Python Reference**, this mainly shows arguments and
their defaults however operators written in Python show their file and line number which may be useful if you
are interested to check on the source code.
.. note::
Not all operators can be called usefully from Python, for more on this see :ref:`using operators <using_operators>`.
Info View
---------
Blender records operators you run and displays them in the **Info** space.
This is located above the file-menu which can be dragged down to display its contents.
Select the **Script** screen that comes default with Blender to see its output.
You can perform some actions and see them show up - delete a vertex for example.
Each entry can be selected (Right-Mouse-Button), then copied :kbd:`Control-C`, usually to paste in the text editor or python console.
.. note::
Not all operators get registered for display,
zooming the view for example isn't so useful to repeat so its excluded from the output.
To display *every* operator that runs see :ref:`Show All Operators <info_show_all_operators>`

@ -5,6 +5,8 @@ Gotchas
This document attempts to help you work with the Blender API in areas that can be troublesome and avoid practices that are known to give instability.
.. _using_operators:
Using Operators
===============
@ -494,7 +496,7 @@ Heres an example of threading supported by Blender:
t.join()
This an example of a timer which runs many times a second and moves the default cube continuously while Blender runs (Unsupported).
This an example of a timer which runs many times a second and moves the default cube continuously while Blender runs **(Unsupported)**.
.. code-block:: python
@ -517,7 +519,7 @@ So far, no work has gone into making Blender's python integration thread safe, s
.. note::
Pythons threads only allow co-currency and won't speed up your scripts on multi-processor systems, the ``subprocess`` and ``multiprocess`` modules can be used with blender and make use of multiple CPU's too.
Pythons threads only allow co-currency and won't speed up your scripts on multi-processor systems, the ``subprocess`` and ``multiprocess`` modules can be used with Blender and make use of multiple CPU's too.
Help! My script crashes Blender
@ -537,11 +539,18 @@ Here are some general hints to avoid running into these problems.
* Crashes may not happen every time, they may happen more on some configurations/operating-systems.
.. note::
To find the line of your script that crashes you can use the ``faulthandler`` module.
See `faulthandler docs <http://docs.python.org/dev/library/faulthandler.html>`_.
While the crash may be in Blenders C/C++ code, this can help a lot to track down the area of the script that causes the crash.
Undo/Redo
---------
Undo invalidates all :class:`bpy.types.ID` instances (Object, Scene, Mesh etc).
Undo invalidates all :class:`bpy.types.ID` instances (Object, Scene, Mesh, Lamp... etc).
This example shows how you can tell undo changes the memory locations.
@ -659,9 +668,9 @@ But take care because this is limited to scripts accessing the variable which is
sys.exit
========
Some python modules will call sys.exit() themselves when an error occurs, while not common behavior this is something to watch out for because it may seem as if blender is crashing since sys.exit() will quit blender immediately.
Some python modules will call ``sys.exit()`` themselves when an error occurs, while not common behavior this is something to watch out for because it may seem as if blender is crashing since ``sys.exit()`` will quit blender immediately.
For example, the ``optparse`` module will print an error and exit if the arguments are invalid.
An ugly way of troubleshooting this is to set ``sys.exit = None`` and see what line of python code is quitting, you could of course replace ``sys.exit``/ with your own function but manipulating python in this way is bad practice.
An ugly way of troubleshooting this is to set ``sys.exit = None`` and see what line of python code is quitting, you could of course replace ``sys.exit`` with your own function but manipulating python in this way is bad practice.

@ -1,3 +1,5 @@
.. _info_overview:
*******************
Python API Overview
*******************

@ -1,3 +1,5 @@
.. _info_quickstart:
***********************
Quickstart Introduction
***********************

@ -44,15 +44,17 @@ if this can't be generated, only the property name is copied.
.. note::
This uses the same method for creating the animation path used by :class:`FCurve.data_path` and :class:`DriverTarget.data_path` drivers.
This uses the same method for creating the animation path used by :class:`bpy.types.FCurve.data_path` and :class:`bpy.types.DriverTarget.data_path` drivers.
.. _info_show_all_operators
Show All Operators
==================
While blender logs operators in the Info space, this only reports operators with the ``REGISTER`` option enabeld so as not to flood the Info view with calls to ``bpy.ops.view3d.smoothview`` and ``bpy.ops.view3d.zoom``.
However, for testing it can be useful to see **every** operator called in a terminal, do this by enabling the debug option either by passing the ``--debug`` argument when starting blender or by setting :mod:`bpy.app.debug` to True while blender is running.
However, for testing it can be useful to see **every** operator called in a terminal, do this by enabling the debug option either by passing the ``--debug-wm`` argument when starting blender or by setting :mod:`bpy.app.debug_wm` to True while blender is running.
Use an External Editor
@ -218,6 +220,14 @@ The next example is an equivalent single line version of the script above which
``code.interact`` can be added at any line in the script and will pause the script an launch an interactive interpreter in the terminal, when you're done you can quit the interpreter and the script will continue execution.
If you have **IPython** installed you can use their ``embed()`` function which will implicitly use the current namespace, this has autocomplete and some useful features that the standard python eval-loop doesn't have.
.. code-block:: python
import IPython
IPython.embed()
Admittedly this highlights the lack of any python debugging support built into blender, but its still handy to know.
.. note::

@ -0,0 +1,645 @@
Addon Tutorial
##############
************
Introduction
************
Intended Audience
=================
This tutorial is designed to help technical artists or developers learn to extend Blender.
An understanding of the basics of Python is expected for those working through this tutorial.
Prerequisites
-------------
Before going through the tutorial you should...
* Familiarity with the basics of working in Blender.
* Know how to run a script in Blender's text editor (as documented in the quick-start)
* Have an understanding of Python primitive types (int, boolean, string, list, tuple, dictionary, and set).
* Be familiar with the concept of Python modules.
* Basic understanding of classes (object orientation) in Python.
Suggested reading before starting this tutorial.
* `Dive Into Python <http://getpython3.com/diveintopython3/index.html>`_ sections (1, 2, 3, 4, and 7).
* :ref:`Blender API Quickstart <info_quickstart>`
to help become familiar with Blender/Python basics.
To best troubleshoot any error message Python prints while writing scripts you run blender with from a terminal,
see :ref:`Use The Terminal <use_the_terminal>`.
Documentation Links
===================
While going through the tutorial you may want to look into our reference documentation.
* :ref:`Blender API Overview <info_overview>`. -
*This document is rather detailed but helpful if you want to know more on a topic.*
* :mod:`bpy.context` api reference. -
*Handy to have a list of available items your script may operate on.*
* :class:`bpy.types.Operator`. -
*The following addons define operators, these docs give details and more examples of operators.*
******
Addons
******
What is an Addon?
=================
An addon is simply a Python module with some additional requirements so Blender can display it in a list with useful
information.
To give an example, here is the simplest possible addon.
.. code-block:: python
bl_info = {"name": "My Test Addon", "category": "Object"}
def register():
print("Hello World")
def unregister():
print("Goodbye World")
* ``bl_info`` is a dictionary containing addon meta-data such as the title, version and author to be displayed in the
user preferences addon list.
* ``register`` is a function which only runs when enabling the addon, this means the module can be loaded without
activating the addon.
* ``unregister`` is a function to unload anything setup by ``register``, this is called when the addon is disabled.
Notice this addon does not do anything related to Blender, (the :mod:`bpy` module is not imported for example).
This is a contrived example of an addon that serves to illustrate the point
that the base requirements of an addon are simple.
An addon will typically register operators, panels, menu items etc, but its worth noting that _any_ script can do this,
when executed from the text editor or even the interactive console - there is nothing inherently different about an
addon that allows it to integrate with Blender, such functionality is just provided by the :mod:`bpy` module for any
script to access.
So an addon is just a way to encapsulate a Python module in a way a user can easily utilize.
.. note::
Running this script within the text editor won't print anything,
to see the output it must be installed through the user preferences.
Messages will be printed when enabling and disabling.
Your First Addon
================
The simplest possible addon above was useful as an example but not much else.
This next addon is simple but shows how to integrate a script into Blender using an ``Operator``
which is the typical way to define a tool accessed from menus, buttons and keyboard shortcuts.
For the first example we'll make a script that simply moves all objects in a scene.
Write The Script
----------------
Add the following script to the text editor in Blender.
.. code-block:: python
import bpy
scene = bpy.context.scene
for obj in scene.objects:
obj.location.x += 1.0
.. image:: run_script.png
:width: 924px
:align: center
:height: 574px
:alt: Run Script button
Click the Run Script button, all objects in the active scene are moved by 1.0 Blender unit.
Next we'll make this script into an addon.
Write the Addon (Simple)
------------------------
This addon takes the body of the script above, and adds them to an operator's ``execute()`` function.
.. code-block:: python
bl_info = {
"name": "Move X Axis",
"category": "Object",
}
import bpy
class ObjectMoveX(bpy.types.Operator):
"""My Object Moving Script""" # blender will use this as a tooltip for menu items and buttons.
bl_idname = "object.move_x" # unique identifier for buttons and menu items to reference.
bl_label = "Move X by One" # display name in the interface.
bl_options = {'REGISTER', 'UNDO'} # enable undo for the operator.
def execute(self, context): # execute() is called by blender when running the operator.
# The original script
scene = context.scene
for obj in scene.objects:
obj.location.x += 1.0
return {'FINISHED'} # this lets blender know the operator finished successfully.
def register():
bpy.utils.register_class(ObjectMoveX)
def unregister():
bpy.utils.unregister_class(ObjectMoveX)
# This allows you to run the script directly from blenders text editor
# to test the addon without having to install it.
if __name__ == "__main__":
register()
.. note:: ``bl_info`` is split across multiple lines, this is just a style convention used to more easily add items.
.. note:: Rather than using ``bpy.context.scene``, we use the ``context.scene`` argument passed to ``execute()``.
In most cases these will be the same however in some cases operators will be passed a custom context
so script authors should prefer the ``context`` argument passed to operators.
To test the script you can copy and paste this into Blender text editor and run it, this will execute the script
directly and call register immediately.
However running the script wont move any objects, for this you need to execute the newly registered operator.
.. image:: spacebar.png
:width: 924px
:align: center
:height: 574px
:alt: Spacebar
Do this by pressing ``SpaceBar`` to bring up the operator search dialog and type in "Move X by One" (the ``bl_label``),
then press ``Enter``.
The objects should move as before.
*Keep this addon open in Blender for the next step - Installing.*
Install The Addon
-----------------
Once you have your addon within in Blender's text editor, you will want to be able to install it so it can be enabled in
the user preferences to load on startup.
Even though the addon above is a test, lets go through the steps anyway so you know how to do it for later.
To install the Blender text as an addon you will first have to save it to disk, take care to obey the naming
restrictions that apply to Python modules and end with a ``.py`` extension.
Once the file is on disk, you can install it as you would for an addon downloaded online.
Open the user **File -> User Preferences**, Select the **Addon** section, press **Install Addon...** and select the file.
Now the addon will be listed and you can enable it by pressing the check-box, if you want it to be enabled on restart,
press **Save as Default**.
.. note::
The destination of the addon depends on your Blender configuration.
When installing an addon the source and destination path are printed in the console.
You can also find addon path locations by running this in the Python console.
.. code-block:: python
import addon_utils
print(addon_utils.paths())
More is written on this topic here:
`Directory Layout <http://wiki.blender.org/index.php/Doc:2.6/Manual/Introduction/Installing_Blender/DirectoryLayout>`_
Your Second Addon
=================
For our second addon, we will focus on object instancing - this is - to make linked copies of an object in a
similar way to what you may have seen with the array modifier.
Write The Script
----------------
As before, first we will start with a script, develop it, then convert into an addon.
.. code-block:: python
import bpy
from bpy import context
# Get the current scene
scene = context.scene
# Get the 3D cursor
cursor = scene.cursor_location
# Get the active object (assume we have one)
obj = scene.objects.active
# Now make a copy of the object
obj_new = obj.copy()
# The object won't automatically get into a new scene
scene.objects.link(obj_new)
# Now we can place the object
obj_new.location = cursor
Now try copy this script into Blender and run it on the default cube.
Make sure you click to move the 3D cursor before running as the duplicate will appear at the cursor's location.
... go off and test ...
After running, notice that when you go into edit-mode to change the cube - all of the copies change,
in Blender this is known as *Linked-Duplicates*.
Next, we're going to do this in a loop, to make an array of objects between the active object and the cursor.
.. code-block:: python
import bpy
from bpy import context
scene = context.scene
cursor = scene.cursor_location
obj = scene.objects.active
# Use a fixed value for now, eventually make this user adjustable
total = 10
# Add 'total' objects into the scene
for i in range(total):
obj_new = obj.copy()
scene.objects.link(obj_new)
# Now place the object in between the cursor
# and the active object based on 'i'
factor = i / total
obj_new.location = (obj.location * factor) + (cursor * (1.0 - factor))
Try run this script with with the active object and the cursor spaced apart to see the result.
With this script you'll notice we're doing some math with the object location and cursor, this works because both are
3D :class:`mathutils.Vector` instances, a convenient class provided by the :mod:`mathutils` module and
allows vectors to be multiplied by numbers and matrices.
If you are interested in this area, read into :class:`mathutils.Vector` - there are many handy utility functions
such as getting the angle between vectors, cross product, dot products
as well as more advanced functions in :mod:`mathutils.geometry` such as bezier spline interpolation and
ray-triangle intersection.
For now we'll focus on making this script an addon, but its good to know that this 3D math module is available and
can help you with more advanced functionality later on.
Write the Addon
---------------
The first step is to convert the script as-is into an addon.
.. code-block:: python
bl_info = {
"name": "Cursor Array",
"category": "Object",
}
import bpy
class ObjectCursorArray(bpy.types.Operator):
"""Object Cursor Array"""
bl_idname = "object.cursor_array"
bl_label = "Cursor Array"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
cursor = scene.cursor_location
obj = scene.objects.active
total = 10
for i in range(total):
obj_new = obj.copy()
scene.objects.link(obj_new)
factor = i / total
obj_new.location = (obj.location * factor) + (cursor * (1.0 - factor))
return {'FINISHED'}
def register():
bpy.utils.register_class(ObjectCursorArray)
def unregister():
bpy.utils.unregister_class(ObjectCursorArray)
if __name__ == "__main__":
register()
Everything here has been covered in the previous steps, you may want to try run the addon still
and consider what could be done to make it more useful.
... go off and test ...
The two of the most obvious missing things are - having the total fixed at 10, and having to access the operator from
space-bar is not very convenient.
Both these additions are explained next, with the final script afterwards.
Operator Property
^^^^^^^^^^^^^^^^^
There are a variety of property types that are used for tool settings, common property types include:
int, float, vector, color, boolean and string.
These properties are handled differently to typical Python class attributes
because Blender needs to be display them in the interface,
store their settings in key-maps and keep settings for re-use.
While this is handled in a fairly Pythonic way, be mindful that you are in fact defining tool settings that
are loaded into Blender and accessed by other parts of Blender, outside of Python.
To get rid of the literal 10 for `total`, we'll us an operator property.
Operator properties are defined via bpy.props module, this is added to the class body.
.. code-block:: python
# moved assignment from execute() to the body of the class...
total = bpy.props.IntProperty(name="Steps", default=2, min=1, max=100)
# and this is accessed on the class
# instance within the execute() function as...
self.total
These properties from :mod:`bpy.props` are handled specially by Blender when the class is registered
so they display as buttons in the user interface.
There are many arguments you can pass to properties to set limits, change the default and display a tooltip.
.. seealso:: :mod:`bpy.props.IntProperty`
This document doesn't go into details about using other property types,
however the link above includes examples of more advanced property usage.
Menu Item
^^^^^^^^^
Addons can add to the user interface of existing panels, headers and menus defined in Python.
For this example we'll add to an existing menu.
.. image:: menu_id.png
:width: 334px
:align: center
:height: 128px
:alt: Menu Identifier
To find the identifier of a menu you can hover your mouse over the menu item and the identifier is displayed.
The method used for adding a menu item is to append a draw function into an existing class.
.. code-block:: python
def menu_func(self, context):
self.layout.operator(ObjectCursorArray.bl_idname)
def register():
bpy.types.VIEW3D_MT_object.append(menu_func)
For docs on extending menus see: :doc:`bpy.types.Menu`.
Keymap
^^^^^^
In Blender addons have their own key-maps so as not to interfere with Blenders built in key-maps.
In the example below, a new object-mode :class:`bpy.types.KeyMap` is added,
then a :class:`bpy.types.KeyMapItem` is added to the key-map which references our newly added operator,
using :kbd:`Ctrl-Shift-Space` as the key shortcut to activate it.
.. code-block:: python
# store keymaps here to access after registration
addon_keymaps = []
def register():
# handle the keymap
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
kmi = km.keymap_items.new(ObjectCursorArray.bl_idname, 'SPACE', 'PRESS', ctrl=True, shift=True)
kmi.properties.total = 4
addon_keymaps.append(km)
def unregister():
# handle the keymap
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
# clear the list
addon_keymaps.clear()
Notice how the key-map item can have a different ``total`` setting then the default set by the operator,
this allows you to have multiple keys accessing the same operator with different settings.
.. note::
While :kbd:`Ctrl-Shift-Space` isn't a default Blender key shortcut, its hard to make sure addons won't
overwrite each others keymaps, At least take care when assigning keys that they don't
conflict with important functionality within Blender.
For API documentation on the functions listed above, see:
:class:`bpy.types.KeyMaps.new`,
:class:`bpy.types.KeyMap`,
:class:`bpy.types.KeyMapItems.new`,
:class:`bpy.types.KeyMapItem`.
Bringing it all together
^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: python
bl_info = {
"name": "Cursor Array",
"category": "Object",
}
import bpy
class ObjectCursorArray(bpy.types.Operator):
"""Object Cursor Array"""
bl_idname = "object.cursor_array"
bl_label = "Cursor Array"
bl_options = {'REGISTER', 'UNDO'}
total = bpy.props.IntProperty(name="Steps", default=2, min=1, max=100)
def execute(self, context):
scene = context.scene
cursor = scene.cursor_location
obj = scene.objects.active
for i in range(self.total):
obj_new = obj.copy()
scene.objects.link(obj_new)
factor = i / self.total
obj_new.location = (obj.location * factor) + (cursor * (1.0 - factor))
return {'FINISHED'}
def menu_func(self, context):
self.layout.operator(ObjectCursorArray.bl_idname)
# store keymaps here to access after registration
addon_keymaps = []
def register():
bpy.utils.register_class(ObjectCursorArray)
bpy.types.VIEW3D_MT_object.append(menu_func)
# handle the keymap
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
kmi = km.keymap_items.new(ObjectCursorArray.bl_idname, 'SPACE', 'PRESS', ctrl=True, shift=True)
kmi.properties.total = 4
addon_keymaps.append(km)
def unregister():
bpy.utils.unregister_class(ObjectCursorArray)
bpy.types.VIEW3D_MT_object.remove(menu_func)
# handle the keymap
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
# clear the list
del addon_keymaps[:]
if __name__ == "__main__":
register()
.. image:: in_menu.png
:width: 591px
:align: center
:height: 649px
:alt: In the menu
Run the script (or save it and add it through the Preferences like before) and it will appear in the menu.
.. image:: op_prop.png
:width: 669px
:align: center
:height: 644px
:alt: Operator Property
After selecting it from the menu, you can choose how many instance of the cube you want created.
.. note::
Directly executing the script multiple times will add the menu each time too.
While not useful behavior, theres nothing to worry about since addons won't register them selves multiple
times when enabled through the user preferences.
Conclusions
===========
Addons can encapsulate certain functionality neatly for writing tools to improve your work-flow or for writing utilities
for others to use.
While there are limits to what Python can do within Blender, there is certainly a lot that can be achieved without
having to dive into Blender's C/C++ code.
The example given in the tutorial is limited, but shows the Blender API used for common tasks that you can expand on
to write your own tools.
Further Reading
---------------
Blender comes commented templates which are accessible from the text editor header, if you have specific areas
you want to see example code for, this is a good place to start.
Here are some sites you might like to check on after completing this tutorial.
* :ref:`Blender/Python API Overview <info_overview>` -
*For more background details on Blender/Python integration.*
* `How to Think Like a Computer Scientist <http://interactivepython.org/courselib/static/thinkcspy/index.html>`_ -
*Great info for those who are still learning Python.*
* `Blender Development (Wiki) <http://wiki.blender.org/index.php/Dev:Contents>`_ -
*Blender Development, general information and helpful links.*
* `Blender Artists (Coding Section) <http://blenderartists.org/forum/forumdisplay.php?47-Coding>`_ -
*forum where people ask Python development questions*

@ -317,6 +317,8 @@ RST_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "rst"))
INFO_DOCS = (
("info_quickstart.rst", "Blender/Python Quickstart: new to blender/scripting and want to get your feet wet?"),
("info_overview.rst", "Blender/Python API Overview: a more complete explanation of python integration"),
("info_tutorial_addon.rst", "Blender/Python Addon Tutorial: a step by step guide on how to write an addon from scratch"),
("info_api_reference.rst", "Blender/Python API Reference Usage: examples of how to use the API reference docs"),
("info_best_practice.rst", "Best Practice: Conventions to follow for writing good scripts"),
("info_tips_and_tricks.rst", "Tips and Tricks: Hints to help you while writing scripts for blender"),
("info_gotcha.rst", "Gotcha's: some of the problems you may come up against when writing scripts"),
@ -1546,8 +1548,8 @@ def write_rst_contents(basepath):
"mathutils", "mathutils.geometry", "mathutils.noise",
# misc
"Freestyle", "bgl", "blf", "gpu", "aud", "bpy_extras",
# bmesh
"bmesh", "bmesh.types", "bmesh.utils", "bmesh.ops",
# bmesh, submodules are in own page
"bmesh",
)
for mod in standalone_modules:
@ -1733,6 +1735,11 @@ def copy_handwritten_rsts(basepath):
# changelog
shutil.copy2(os.path.join(RST_DIR, "change_log.rst"), basepath)
# copy images, could be smarter but just glob for now.
for f in os.listdir(RST_DIR):
if f.endswith(".png"):
shutil.copy2(os.path.join(RST_DIR, f), basepath)
def rna2sphinx(basepath):

@ -102,6 +102,8 @@ set(SRC
libmv/multiview/conditioning.h
libmv/multiview/euclidean_resection.h
libmv/multiview/fundamental.h
libmv/multiview/homography.h
libmv/multiview/homography_parameterization.h
libmv/multiview/nviewtriangulation.h
libmv/multiview/projection.h
libmv/multiview/resection.h
@ -131,6 +133,7 @@ set(SRC
libmv/tracking/pyramid_region_tracker.h
libmv/tracking/region_tracker.h
libmv/tracking/retrack_region_tracker.h
libmv/tracking/track_region.h
libmv/tracking/trklt_region_tracker.h
third_party/fast/fast.h

@ -900,7 +900,7 @@ void libmv_CameraIntrinsicsUpdate(struct libmv_CameraIntrinsics *libmvIntrinsics
intrinsics->SetFocalLength(focal_length, focal_length);
if (intrinsics->principal_point_x() != principal_x || intrinsics->principal_point_y() != principal_y)
intrinsics->SetFocalLength(focal_length, focal_length);
intrinsics->SetPrincipalPoint(principal_x, principal_y);
if (intrinsics->k1() != k1 || intrinsics->k2() != k2 || intrinsics->k3() != k3)
intrinsics->SetRadialDistortion(k1, k2, k3);

@ -81,7 +81,7 @@ void AUD_LinearResampleReader::read(int& length, bool& eos, sample_t* buffer)
int samplesize = AUD_SAMPLE_SIZE(specs);
int size = length;
float factor = m_rate / m_reader->getSpecs().rate;
float spos;
float spos = 0.0f;
sample_t low, high;
eos = false;

@ -1026,6 +1026,8 @@ def get_panels():
bpy.types.TEXTURE_PT_voxeldata,
bpy.types.TEXTURE_PT_pointdensity,
bpy.types.TEXTURE_PT_pointdensity_turbulence,
bpy.types.TEXTURE_PT_mapping,
bpy.types.TEXTURE_PT_influence,
bpy.types.PARTICLE_PT_context_particles,
bpy.types.PARTICLE_PT_emission,
bpy.types.PARTICLE_PT_hair_dynamics,

@ -445,7 +445,7 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
}
case BL::ShaderNode::type_SCRIPT: {
#ifdef WITH_OSL
if(scene->params.shadingsystem != SceneParams::OSL)
if(!scene->shader_manager->use_osl())
break;
/* create script node */

@ -367,12 +367,22 @@ struct ObjectKey {
bool operator<(const ObjectKey& k) const
{
return (parent < k.parent) ||
(parent == k.parent && (memcmp(id, k.id, sizeof(id)) < 0)) ||
(memcmp(id, k.id, sizeof(id)) == 0 && ob < k.ob);
if(ob < k.ob) {
return true;
}
else if(ob == k.ob) {
if(parent < k.parent)
return true;
else if(parent == k.parent)
return memcmp(id, k.id, sizeof(id)) < 0;
}
return false;
}
};
/* Particle System Key */
struct ParticleSystemKey {
void *ob;
int id[OBJECT_PERSISTENT_ID_SIZE];
@ -389,8 +399,12 @@ struct ParticleSystemKey {
bool operator<(const ParticleSystemKey& k) const
{
/* first id is particle index, we don't compare that */
return (ob < k.ob) ||
(ob == k.ob && (memcmp(id+1, k.id+1, sizeof(int)*(OBJECT_PERSISTENT_ID_SIZE-1)) < 0));
if(ob < k.ob)
return true;
else if(ob == k.ob)
return memcmp(id+1, k.id+1, sizeof(int)*(OBJECT_PERSISTENT_ID_SIZE-1)) < 0;
return false;
}
};

@ -23,9 +23,12 @@
#include "device_intern.h"
#include "kernel.h"
#include "kernel_compat_cpu.h"
#include "kernel_types.h"
#include "kernel_globals.h"
#include "osl_shader.h"
#include "osl_globals.h"
#include "buffers.h"
@ -43,11 +46,16 @@ class CPUDevice : public Device
{
public:
TaskPool task_pool;
KernelGlobals *kg;
KernelGlobals kernel_globals;
#ifdef WITH_OSL
OSLGlobals osl_globals;
#endif
CPUDevice(Stats &stats) : Device(stats)
{
kg = kernel_globals_create();
#ifdef WITH_OSL
kernel_globals.osl = &osl_globals;
#endif
/* do now to avoid thread issues */
system_cpu_support_optimized();
@ -56,7 +64,6 @@ public:
~CPUDevice()
{
task_pool.stop();
kernel_globals_free(kg);
}
bool support_advanced_shading()
@ -95,12 +102,12 @@ public:
void const_copy_to(const char *name, void *host, size_t size)
{
kernel_const_copy(kg, name, host, size);
kernel_const_copy(&kernel_globals, name, host, size);
}
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
{
kernel_tex_copy(kg, name, mem.data_pointer, mem.data_width, mem.data_height);
kernel_tex_copy(&kernel_globals, name, mem.data_pointer, mem.data_width, mem.data_height);
mem.device_pointer = mem.data_pointer;
stats.mem_alloc(mem.memory_size());
@ -116,7 +123,7 @@ public:
void *osl_memory()
{
#ifdef WITH_OSL
return kernel_osl_memory(kg);
return &osl_globals;
#else
return NULL;
#endif
@ -148,9 +155,10 @@ public:
return;
}
KernelGlobals kg = kernel_globals;
#ifdef WITH_OSL
if(kernel_osl_use(kg))
OSLShader::thread_init(kg);
OSLShader::thread_init(&kg, &kernel_globals, &osl_globals);
#endif
RenderTile tile;
@ -171,7 +179,7 @@ public:
for(int y = tile.y; y < tile.y + tile.h; y++) {
for(int x = tile.x; x < tile.x + tile.w; x++) {
kernel_cpu_optimized_path_trace(kg, render_buffer, rng_state,
kernel_cpu_optimized_path_trace(&kg, render_buffer, rng_state,
sample, x, y, tile.offset, tile.stride);
}
}
@ -192,7 +200,7 @@ public:
for(int y = tile.y; y < tile.y + tile.h; y++) {
for(int x = tile.x; x < tile.x + tile.w; x++) {
kernel_cpu_path_trace(kg, render_buffer, rng_state,
kernel_cpu_path_trace(&kg, render_buffer, rng_state,
sample, x, y, tile.offset, tile.stride);
}
}
@ -212,8 +220,7 @@ public:
}
#ifdef WITH_OSL
if(kernel_osl_use(kg))
OSLShader::thread_free(kg);
OSLShader::thread_free(&kg);
#endif
}
@ -223,7 +230,7 @@ public:
if(system_cpu_support_optimized()) {
for(int y = task.y; y < task.y + task.h; y++)
for(int x = task.x; x < task.x + task.w; x++)
kernel_cpu_optimized_tonemap(kg, (uchar4*)task.rgba, (float*)task.buffer,
kernel_cpu_optimized_tonemap(&kernel_globals, (uchar4*)task.rgba, (float*)task.buffer,
task.sample, task.resolution, x, y, task.offset, task.stride);
}
else
@ -231,22 +238,23 @@ public:
{
for(int y = task.y; y < task.y + task.h; y++)
for(int x = task.x; x < task.x + task.w; x++)
kernel_cpu_tonemap(kg, (uchar4*)task.rgba, (float*)task.buffer,
kernel_cpu_tonemap(&kernel_globals, (uchar4*)task.rgba, (float*)task.buffer,
task.sample, task.resolution, x, y, task.offset, task.stride);
}
}
void thread_shader(DeviceTask& task)
{
KernelGlobals kg = kernel_globals;
#ifdef WITH_OSL
if(kernel_osl_use(kg))
OSLShader::thread_init(kg);
OSLShader::thread_init(&kg, &kernel_globals, &osl_globals);
#endif
#ifdef WITH_OPTIMIZED_KERNEL
if(system_cpu_support_optimized()) {
for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++) {
kernel_cpu_optimized_shader(kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x);
kernel_cpu_optimized_shader(&kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x);
if(task_pool.cancelled())
break;
@ -256,7 +264,7 @@ public:
#endif
{
for(int x = task.shader_x; x < task.shader_x + task.shader_w; x++) {
kernel_cpu_shader(kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x);
kernel_cpu_shader(&kg, (uint4*)task.shader_input, (float4*)task.shader_output, task.shader_eval_type, x);
if(task_pool.cancelled())
break;
@ -264,8 +272,7 @@ public:
}
#ifdef WITH_OSL
if(kernel_osl_use(kg))
OSLShader::thread_free(kg);
OSLShader::thread_free(&kg);
#endif
}

@ -32,16 +32,17 @@ if env['WITH_BF_CYCLES_CUDA_BINARIES']:
kernel_file = os.path.join(source_dir, "kernel.cu")
util_dir = os.path.join(source_dir, "../util")
svm_dir = os.path.join(source_dir, "../svm")
closure_dir = os.path.join(source_dir, "../closure")
# nvcc flags
nvcc_flags = "-m%s" % (bits)
nvcc_flags += " --cubin --ptxas-options=\"-v\" --maxrregcount=24"
nvcc_flags += " --opencc-options -OPT:Olimit=0"
nvcc_flags += " -DCCL_NAMESPACE_BEGIN= -DCCL_NAMESPACE_END= -DNVCC"
nvcc_flags += " -I \"%s\" -I \"%s\"" % (util_dir, svm_dir)
nvcc_flags += " -I \"%s\" -I \"%s\" -I \"%s\"" % (util_dir, svm_dir, closure_dir)
# dependencies
dependencies = ['kernel.cu'] + kernel.Glob('*.h') + kernel.Glob('../util/*.h') + kernel.Glob('svm/*.h')
dependencies = ['kernel.cu'] + kernel.Glob('*.h') + kernel.Glob('../util/*.h') + kernel.Glob('svm/*.h') + kernel.Glob('closure/*.h')
last_cubin_file = None
# add command for each cuda architecture

@ -29,38 +29,6 @@
CCL_NAMESPACE_BEGIN
/* Globals */
KernelGlobals *kernel_globals_create()
{
KernelGlobals *kg = new KernelGlobals();
#ifdef WITH_OSL
kg->osl.use = false;
#endif
return kg;
}
void kernel_globals_free(KernelGlobals *kg)
{
delete kg;
}
/* OSL */
#ifdef WITH_OSL
void *kernel_osl_memory(KernelGlobals *kg)
{
return (void*)&kg->osl;
}
bool kernel_osl_use(KernelGlobals *kg)
{
return kg->osl.use;
}
#endif
/* Memory Copy */
void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size)

@ -19,13 +19,6 @@
#ifndef __KERNEL_ATTRIBUTE_CL__
#define __KERNEL_ATTRIBUTE_CL__
#include "util_types.h"
#ifdef __OSL__
#include <string>
#include "util_attribute.h"
#endif
CCL_NAMESPACE_BEGIN
/* note: declared in kernel.h, have to add it here because kernel.h is not available */
@ -33,20 +26,9 @@ bool kernel_osl_use(KernelGlobals *kg);
__device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id)
{
#ifdef __OSL__
if (kernel_osl_use(kg)) {
/* for OSL, a hash map is used to lookup the attribute by name. */
OSLGlobals::AttributeMap &attr_map = kg->osl.attribute_map[sd->object];
ustring stdname(std::string("std::") + std::string(attribute_standard_name((AttributeStandard)id)));
OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
if (it != attr_map.end()) {
const OSLGlobals::Attribute &osl_attr = it->second;
/* return result */
return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
}
else
return (int)ATTR_STD_NOT_FOUND;
if (kg->osl) {
return OSLShader::find_attribute(kg, sd, id);
}
else
#endif

@ -18,14 +18,6 @@
/* Constant Globals */
#ifdef __KERNEL_CPU__
#ifdef __OSL__
#include "osl_globals.h"
#endif
#endif
CCL_NAMESPACE_BEGIN
/* On the CPU, we pass along the struct KernelGlobals to nearly everywhere in
@ -35,6 +27,12 @@ CCL_NAMESPACE_BEGIN
#ifdef __KERNEL_CPU__
#ifdef __OSL__
struct OSLGlobals;
struct OSLThreadData;
struct OSLShadingSystem;
#endif
#define MAX_BYTE_IMAGES 512
#define MAX_FLOAT_IMAGES 5
@ -51,7 +49,9 @@ typedef struct KernelGlobals {
#ifdef __OSL__
/* On the CPU, we also have the OSL globals here. Most data structures are shared
* with SVM, the difference is in the shaders and object/mesh attributes. */
OSLGlobals osl;
OSLGlobals *osl;
OSLShadingSystem *osl_ss;
OSLThreadData *osl_tdata;
#endif
} KernelGlobals;

@ -16,10 +16,16 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef __OSL__
#include "osl_shader.h"
#endif
#include "kernel_differential.h"
#include "kernel_montecarlo.h"
#include "kernel_projection.h"
#include "kernel_object.h"
#include "kernel_attribute.h"
#include "kernel_projection.h"
#include "kernel_triangle.h"
#ifdef __QBVH__
#include "kernel_qbvh.h"

@ -26,10 +26,6 @@
*
*/
#ifdef __OSL__
#include "osl_shader.h"
#endif
#include "closure/bsdf.h"
#include "closure/emissive.h"
#include "closure/volume.h"
@ -61,7 +57,7 @@ __device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
const Intersection *isect, const Ray *ray)
{
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
OSLShader::init(kg, sd);
#endif
@ -147,7 +143,7 @@ __device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
int shader, int object, int prim, float u, float v, float t, float time)
{
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
OSLShader::init(kg, sd);
#endif
@ -278,7 +274,7 @@ __device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
__device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray)
{
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
OSLShader::init(kg, sd);
#endif
@ -387,7 +383,7 @@ __device void shader_bsdf_eval(KernelGlobals *kg, const ShaderData *sd,
bsdf_eval_init(eval, NBUILTIN_CLOSURES, make_float3(0.0f, 0.0f, 0.0f), kernel_data.film.use_light_pass);
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
return _shader_bsdf_multi_eval_osl(sd, omega_in, pdf, -1, eval, 0.0f, 0.0f);
else
#endif
@ -444,7 +440,7 @@ __device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
*pdf = 0.0f;
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
label = OSLShader::bsdf_sample(sd, sc, randu, randv, eval, *omega_in, *domega_in, *pdf);
else
#endif
@ -456,7 +452,7 @@ __device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
if(sd->num_closure > 1) {
float sweight = sc->sample_weight;
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
_shader_bsdf_multi_eval_osl(sd, *omega_in, pdf, sampled, bsdf_eval, *pdf*sweight, sweight);
else
#endif
@ -483,7 +479,7 @@ __device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *sd,
*pdf = 0.0f;
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
label = OSLShader::bsdf_sample(sd, sc, randu, randv, eval, *omega_in, *domega_in, *pdf);
else
#endif
@ -503,7 +499,7 @@ __device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughnes
if(CLOSURE_IS_BSDF(sc->type)) {
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
OSLShader::bsdf_blur(sc, roughness);
else
#endif
@ -650,7 +646,7 @@ __device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd)
if(CLOSURE_IS_EMISSION(sc->type)) {
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
eval += OSLShader::emissive_eval(sd, sc)*sc->weight;
else
#endif
@ -694,7 +690,7 @@ __device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
float randb, int path_flag)
{
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
OSLShader::eval_surface(kg, sd, randb, path_flag);
else
#endif
@ -702,7 +698,7 @@ __device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
#ifdef __SVM__
svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, randb, path_flag);
#else
bsdf_diffuse_setup(sd, &sd->closure);
bsdf_diffuse_setup(&sd->closure);
sd->closure.weight = make_float3(0.8f, 0.8f, 0.8f);
#endif
}
@ -713,7 +709,7 @@ __device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
__device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
{
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
return OSLShader::eval_background(kg, sd, path_flag);
else
#endif
@ -759,7 +755,7 @@ __device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
if(CLOSURE_IS_VOLUME(sc->type)) {
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
eval += OSLShader::volume_eval_phase(sc, omega_in, omega_out);
else
#endif
@ -780,7 +776,7 @@ __device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
{
#ifdef __SVM__
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
OSLShader::eval_volume(kg, sd, randb, path_flag);
else
#endif
@ -795,7 +791,7 @@ __device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd)
/* this will modify sd->P */
#ifdef __SVM__
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
OSLShader::eval_displacement(kg, sd);
else
#endif
@ -851,7 +847,7 @@ __device void shader_merge_closures(KernelGlobals *kg, ShaderData *sd)
__device void shader_release(KernelGlobals *kg, ShaderData *sd)
{
#ifdef __OSL__
if (kernel_osl_use(kg))
if (kg->osl)
OSLShader::release(kg, sd);
#endif
}

@ -16,9 +16,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kernel_attribute.h"
#include "kernel_projection.h"
CCL_NAMESPACE_BEGIN
/* Point on triangle for Moller-Trumbore triangles */

@ -366,9 +366,6 @@ typedef struct ShaderClosure {
float sample_weight;
#endif
#ifdef __OSL__
void *prim;
#endif
float data0;
float data1;
@ -377,6 +374,9 @@ typedef struct ShaderClosure {
float3 T;
#endif
#ifdef __OSL__
void *prim;
#endif
} ShaderClosure;
/* Shader Data
@ -403,7 +403,8 @@ enum ShaderDataFlag {
/* object flags */
SD_HOLDOUT_MASK = 4096, /* holdout for camera rays */
SD_OBJECT_MOTION = 8192 /* has object motion blur */
SD_OBJECT_MOTION = 8192, /* has object motion blur */
SD_TRANSFORM_APPLIED = 16384 /* vertices have transform applied */
};
typedef struct ShaderData {

@ -153,8 +153,9 @@ static void register_closure(OSL::ShadingSystem *ss, const char *name, int id, O
ss->register_closure(name, id, params, prepare, generic_closure_setup, generic_closure_compare);
}
void OSLShader::register_closures(OSL::ShadingSystem *ss)
void OSLShader::register_closures(OSLShadingSystem *ss_)
{
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)ss_;
int id = 0;
register_closure(ss, "diffuse", id++,

@ -38,7 +38,14 @@ CCL_NAMESPACE_BEGIN
class OSLRenderServices;
struct OSLGlobals {
/* use */
OSLGlobals()
{
ss = NULL;
ts = NULL;
services = NULL;
use = false;
}
bool use;
/* shading system */
@ -66,19 +73,12 @@ struct OSLGlobals {
vector<AttributeMap> attribute_map;
ObjectNameMap object_name_map;
vector<ustring> object_names;
};
/* thread key for thread specific data lookup */
struct ThreadData {
OSL::ShaderGlobals globals;
OSL::PerThreadInfo *thread_info;
};
static tls_ptr(ThreadData, thread_data);
static thread_mutex thread_data_mutex;
static volatile int thread_data_users;
void thread_data_init();
void thread_data_free();
/* thread key for thread specific data lookup */
struct OSLThreadData {
OSL::ShaderGlobals globals;
OSL::PerThreadInfo *thread_info;
};
CCL_NAMESPACE_END

@ -23,6 +23,7 @@
#include "scene.h"
#include "osl_closures.h"
#include "osl_globals.h"
#include "osl_services.h"
#include "osl_shader.h"
@ -36,6 +37,8 @@
#include "kernel_differential.h"
#include "kernel_object.h"
#include "kernel_bvh.h"
#include "kernel_attribute.h"
#include "kernel_projection.h"
#include "kernel_triangle.h"
#include "kernel_accumulate.h"
#include "kernel_shader.h"
@ -53,6 +56,34 @@ ustring OSLRenderServices::u_camera("camera");
ustring OSLRenderServices::u_screen("screen");
ustring OSLRenderServices::u_raster("raster");
ustring OSLRenderServices::u_ndc("NDC");
ustring OSLRenderServices::u_object_location("object:location");
ustring OSLRenderServices::u_object_index("object:index");
ustring OSLRenderServices::u_geom_dupli_generated("geom:dupli_generated");
ustring OSLRenderServices::u_geom_dupli_uv("geom:dupli_uv");
ustring OSLRenderServices::u_material_index("material:index");
ustring OSLRenderServices::u_object_random("object:random");
ustring OSLRenderServices::u_particle_index("particle:index");
ustring OSLRenderServices::u_particle_age("particle:age");
ustring OSLRenderServices::u_particle_lifetime("particle:lifetime");
ustring OSLRenderServices::u_particle_location("particle:location");
ustring OSLRenderServices::u_particle_rotation("particle:rotation");
ustring OSLRenderServices::u_particle_size("particle:size");
ustring OSLRenderServices::u_particle_velocity("particle:velocity");
ustring OSLRenderServices::u_particle_angular_velocity("particle:angular_velocity");
ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
ustring OSLRenderServices::u_geom_name("geom:name");
ustring OSLRenderServices::u_path_ray_length("path:ray_length");
ustring OSLRenderServices::u_trace("trace");
ustring OSLRenderServices::u_hit("hit");
ustring OSLRenderServices::u_hitdist("hitdist");
ustring OSLRenderServices::u_N("N");
ustring OSLRenderServices::u_Ng("Ng");
ustring OSLRenderServices::u_P("P");
ustring OSLRenderServices::u_I("I");
ustring OSLRenderServices::u_u("u");
ustring OSLRenderServices::u_v("v");
ustring OSLRenderServices::u_empty;
OSLRenderServices::OSLRenderServices()
@ -488,104 +519,108 @@ static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivat
memset((char *)val + datasize, 0, datasize * 2);
}
static bool get_object_standard_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
TypeDesc type, bool derivatives, void *val)
bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
TypeDesc type, bool derivatives, void *val)
{
/* todo: turn this into hash table returning int, which can be used in switch */
/* todo: turn this into hash table? */
/* Object Attributes */
if (name == "object:location") {
if (name == u_object_location) {
float3 f = object_location(kg, sd);
return set_attribute_float3(f, type, derivatives, val);
}
else if (name == "object:index") {
else if (name == u_object_index) {
float f = object_pass_id(kg, sd->object);
return set_attribute_float(f, type, derivatives, val);
}
else if (name == "geom:dupli_generated") {
else if (name == u_geom_dupli_generated) {
float3 f = object_dupli_generated(kg, sd->object);
return set_attribute_float3(f, type, derivatives, val);
}
else if (name == "geom:dupli_uv") {
else if (name == u_geom_dupli_uv) {
float3 f = object_dupli_uv(kg, sd->object);
return set_attribute_float3(f, type, derivatives, val);
}
else if (name == "material:index") {
else if (name == u_material_index) {
float f = shader_pass_id(kg, sd);
return set_attribute_float(f, type, derivatives, val);
}
else if (name == "object:random") {
else if (name == u_object_random) {
float f = object_random_number(kg, sd->object);
return set_attribute_float(f, type, derivatives, val);
}
/* Particle Attributes */
else if (name == "particle:index") {
else if (name == u_particle_index) {
uint particle_id = object_particle_id(kg, sd->object);
float f = particle_index(kg, particle_id);
return set_attribute_float(f, type, derivatives, val);
}
else if (name == "particle:age") {
else if (name == u_particle_age) {
uint particle_id = object_particle_id(kg, sd->object);
float f = particle_age(kg, particle_id);
return set_attribute_float(f, type, derivatives, val);
}
else if (name == "particle:lifetime") {
else if (name == u_particle_lifetime) {
uint particle_id = object_particle_id(kg, sd->object);
float f= particle_lifetime(kg, particle_id);
return set_attribute_float(f, type, derivatives, val);
}
else if (name == "particle:location") {
else if (name == u_particle_location) {
uint particle_id = object_particle_id(kg, sd->object);
float3 f = particle_location(kg, particle_id);
return set_attribute_float3(f, type, derivatives, val);
}
#if 0 /* unsupported */
else if (name == "particle:rotation") {
else if (name == u_particle_rotation) {
uint particle_id = object_particle_id(kg, sd->object);
float4 f = particle_rotation(kg, particle_id);
return set_attribute_float4(f, type, derivatives, val);
}
#endif
else if (name == "particle:size") {
else if (name == u_particle_size) {
uint particle_id = object_particle_id(kg, sd->object);
float f = particle_size(kg, particle_id);
return set_attribute_float(f, type, derivatives, val);
}
else if (name == "particle:velocity") {
else if (name == u_particle_velocity) {
uint particle_id = object_particle_id(kg, sd->object);
float3 f = particle_velocity(kg, particle_id);
return set_attribute_float3(f, type, derivatives, val);
}
else if (name == "particle:angular_velocity") {
else if (name == u_particle_angular_velocity) {
uint particle_id = object_particle_id(kg, sd->object);
float3 f = particle_angular_velocity(kg, particle_id);
return set_attribute_float3(f, type, derivatives, val);
}
else if (name == "geom:numpolyvertices") {
else if (name == u_geom_numpolyvertices) {
return set_attribute_int(3, type, derivatives, val);
}
else if (name == "geom:trianglevertices" || name == "geom:polyvertices") {
else if (name == u_geom_trianglevertices || name == u_geom_polyvertices) {
float3 P[3];
triangle_vertices(kg, sd->prim, P);
object_position_transform(kg, sd, &P[0]);
object_position_transform(kg, sd, &P[1]);
object_position_transform(kg, sd, &P[2]);
if(!(sd->flag & SD_TRANSFORM_APPLIED)) {
object_position_transform(kg, sd, &P[0]);
object_position_transform(kg, sd, &P[1]);
object_position_transform(kg, sd, &P[2]);
}
return set_attribute_float3_3(P, type, derivatives, val);
}
else if(name == "geom:name") {
ustring object_name = kg->osl.object_names[sd->object];
else if(name == u_geom_name) {
ustring object_name = kg->osl->object_names[sd->object];
return set_attribute_string(object_name, type, derivatives, val);
}
else
return false;
}
static bool get_background_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
TypeDesc type, bool derivatives, void *val)
bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
TypeDesc type, bool derivatives, void *val)
{
/* Ray Length */
if (name == "path:ray_length") {
if (name == u_path_ray_length) {
float f = sd->ray_length;
return set_attribute_float(f, type, derivatives, val);
}
@ -604,9 +639,9 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
/* lookup of attribute on another object */
if (object_name != u_empty) {
OSLGlobals::ObjectNameMap::iterator it = kg->osl.object_name_map.find(object_name);
OSLGlobals::ObjectNameMap::iterator it = kg->osl->object_name_map.find(object_name);
if (it == kg->osl.object_name_map.end())
if (it == kg->osl->object_name_map.end())
return false;
object = it->second;
@ -617,7 +652,7 @@ bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustri
}
/* find attribute on object */
OSLGlobals::AttributeMap& attribute_map = kg->osl.attribute_map[object];
OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object];
OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
if (it != attribute_map.end()) {
@ -663,7 +698,7 @@ bool OSLRenderServices::texture(ustring filename, TextureOpt &options,
float s, float t, float dsdx, float dtdx,
float dsdy, float dtdy, float *result)
{
OSL::TextureSystem *ts = kernel_globals->osl.ts;
OSL::TextureSystem *ts = kernel_globals->osl->ts;
bool status = ts->texture(filename, options, s, t, dsdx, dtdx, dsdy, dtdy, result);
if(!status) {
@ -685,7 +720,7 @@ bool OSLRenderServices::texture3d(ustring filename, TextureOpt &options,
const OSL::Vec3 &dPdx, const OSL::Vec3 &dPdy,
const OSL::Vec3 &dPdz, float *result)
{
OSL::TextureSystem *ts = kernel_globals->osl.ts;
OSL::TextureSystem *ts = kernel_globals->osl->ts;
bool status = ts->texture3d(filename, options, P, dPdx, dPdy, dPdz, result);
if(!status) {
@ -707,7 +742,7 @@ bool OSLRenderServices::environment(ustring filename, TextureOpt &options,
OSL::ShaderGlobals *sg, const OSL::Vec3 &R,
const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy, float *result)
{
OSL::TextureSystem *ts = kernel_globals->osl.ts;
OSL::TextureSystem *ts = kernel_globals->osl->ts;
bool status = ts->environment(filename, options, R, dRdx, dRdy, result);
if(!status) {
@ -728,7 +763,7 @@ bool OSLRenderServices::get_texture_info(ustring filename, int subimage,
ustring dataname,
TypeDesc datatype, void *data)
{
OSL::TextureSystem *ts = kernel_globals->osl.ts;
OSL::TextureSystem *ts = kernel_globals->osl->ts;
return ts->get_texture_info(filename, subimage, dataname, datatype, data);
}
@ -798,12 +833,12 @@ bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustri
{
TraceData *tracedata = (TraceData*)sg->tracedata;
if(source == "trace" && tracedata) {
if(name == "hit") {
if(source == u_trace && tracedata) {
if(name == u_hit) {
return set_attribute_int((tracedata->isect.prim != ~0), type, derivatives, val);
}
else if(tracedata->isect.prim != ~0) {
if(name == "hitdist") {
if(name == u_hitdist) {
float f[3] = {tracedata->isect.t, 0.0f, 0.0f};
return set_attribute_float(f, type, derivatives, val);
}
@ -817,25 +852,25 @@ bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustri
tracedata->setup = true;
}
if(name == "N") {
if(name == u_N) {
return set_attribute_float3(sd->N, type, derivatives, val);
}
else if(name == "Ng") {
else if(name == u_Ng) {
return set_attribute_float3(sd->Ng, type, derivatives, val);
}
else if(name == "P") {
else if(name == u_P) {
float3 f[3] = {sd->P, sd->dP.dx, sd->dP.dy};
return set_attribute_float3(f, type, derivatives, val);
}
else if(name == "I") {
else if(name == u_I) {
float3 f[3] = {sd->I, sd->dI.dx, sd->dI.dy};
return set_attribute_float3(f, type, derivatives, val);
}
else if(name == "u") {
else if(name == u_u) {
float f[3] = {sd->u, sd->du.dx, sd->du.dy};
return set_attribute_float(f, type, derivatives, val);
}
else if(name == "v") {
else if(name == u_v) {
float f[3] = {sd->v, sd->dv.dx, sd->dv.dy};
return set_attribute_float(f, type, derivatives, val);
}

@ -101,6 +101,11 @@ public:
bool get_texture_info(ustring filename, int subimage,
ustring dataname, TypeDesc datatype, void *data);
static bool get_background_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
TypeDesc type, bool derivatives, void *val);
static bool get_object_standard_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
TypeDesc type, bool derivatives, void *val);
struct TraceData {
Ray ray;
Intersection isect;
@ -114,6 +119,34 @@ public:
static ustring u_screen;
static ustring u_raster;
static ustring u_ndc;
static ustring u_object_location;
static ustring u_object_index;
static ustring u_geom_dupli_generated;
static ustring u_geom_dupli_uv;
static ustring u_material_index;
static ustring u_object_random;
static ustring u_particle_index;
static ustring u_particle_age;
static ustring u_particle_lifetime;
static ustring u_particle_location;
static ustring u_particle_rotation;
static ustring u_particle_size;
static ustring u_particle_velocity;
static ustring u_particle_angular_velocity;
static ustring u_geom_numpolyvertices;
static ustring u_geom_trianglevertices;
static ustring u_geom_polyvertices;
static ustring u_geom_name;
static ustring u_path_ray_length;
static ustring u_trace;
static ustring u_hit;
static ustring u_hitdist;
static ustring u_N;
static ustring u_Ng;
static ustring u_P;
static ustring u_I;
static ustring u_u;
static ustring u_v;
static ustring u_empty;
private:

@ -22,65 +22,56 @@
#include "kernel_object.h"
#include "osl_closures.h"
#include "osl_globals.h"
#include "osl_services.h"
#include "osl_shader.h"
#include "util_attribute.h"
#include "util_foreach.h"
#include <OSL/oslexec.h>
CCL_NAMESPACE_BEGIN
tls_ptr(OSLGlobals::ThreadData, OSLGlobals::thread_data);
volatile int OSLGlobals::thread_data_users = 0;
thread_mutex OSLGlobals::thread_data_mutex;
/* Threads */
void OSLGlobals::thread_data_init()
void OSLShader::thread_init(KernelGlobals *kg, KernelGlobals *kernel_globals, OSLGlobals *osl_globals)
{
thread_scoped_lock thread_data_lock(thread_data_mutex);
/* no osl used? */
if(!osl_globals->use) {
kg->osl = NULL;
return;
}
if(thread_data_users == 0)
tls_create(OSLGlobals::ThreadData, thread_data);
/* per thread kernel data init*/
kg->osl = osl_globals;
kg->osl->services->thread_init(kernel_globals);
thread_data_users++;
}
void OSLGlobals::thread_data_free()
{
/* thread local storage delete */
thread_scoped_lock thread_data_lock(thread_data_mutex);
thread_data_users--;
if(thread_data_users == 0)
tls_delete(OSLGlobals::ThreadData, thread_data);
}
void OSLShader::thread_init(KernelGlobals *kg)
{
OSL::ShadingSystem *ss = kg->osl.ss;
OSLGlobals::ThreadData *tdata = new OSLGlobals::ThreadData();
OSL::ShadingSystem *ss = kg->osl->ss;
OSLThreadData *tdata = new OSLThreadData();
memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
tdata->thread_info = ss->create_thread_info();
tls_set(kg->osl.thread_data, tdata);
kg->osl.services->thread_init(kg);
kg->osl_ss = (OSLShadingSystem*)ss;
kg->osl_tdata = tdata;
}
void OSLShader::thread_free(KernelGlobals *kg)
{
OSL::ShadingSystem *ss = kg->osl.ss;
if(!kg->osl)
return;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
OSLThreadData *tdata = kg->osl_tdata;
ss->destroy_thread_info(tdata->thread_info);
delete tdata;
kg->osl = NULL;
kg->osl_ss = NULL;
kg->osl_tdata = NULL;
}
/* Globals */
@ -159,13 +150,14 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
/* sample weight */
float sample_weight = fabsf(average(weight));
sd->flag |= bsdf->shaderdata_flag();
sc.sample_weight = sample_weight;
sc.type = bsdf->shaderclosure_type();
/* add */
sd->closure[sd->num_closure++] = sc;
if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
sd->flag |= bsdf->shaderdata_flag();
}
break;
}
case OSL::ClosurePrimitive::Emissive: {
@ -179,9 +171,10 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
sc.type = CLOSURE_EMISSION_ID;
/* flag */
sd->flag |= SD_EMISSION;
sd->closure[sd->num_closure++] = sc;
if(sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
sd->flag |= SD_EMISSION;
}
break;
}
case AmbientOcclusion: {
@ -194,8 +187,10 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
sc.sample_weight = sample_weight;
sc.type = CLOSURE_AMBIENT_OCCLUSION_ID;
sd->closure[sd->num_closure++] = sc;
sd->flag |= SD_AO;
if(sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
sd->flag |= SD_AO;
}
break;
}
case OSL::ClosurePrimitive::Holdout:
@ -204,8 +199,11 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
sc.sample_weight = 0.0f;
sc.type = CLOSURE_HOLDOUT_ID;
sd->flag |= SD_HOLDOUT;
sd->closure[sd->num_closure++] = sc;
if(sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
sd->flag |= SD_HOLDOUT;
}
break;
case OSL::ClosurePrimitive::BSSRDF:
case OSL::ClosurePrimitive::Debug:
@ -230,8 +228,8 @@ static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
{
/* gather pointers */
OSL::ShadingSystem *ss = kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
OSLThreadData *tdata = kg->osl_tdata;
OSL::ShaderGlobals *globals = &tdata->globals;
OSL::ShadingContext *ctx = (OSL::ShadingContext *)sd->osl_ctx;
@ -241,8 +239,8 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int
/* execute shader for this point */
int shader = sd->shader & SHADER_MASK;
if (kg->osl.surface_state[shader])
ss->execute(*ctx, *(kg->osl.surface_state[shader]), *globals);
if (kg->osl->surface_state[shader])
ss->execute(*ctx, *(kg->osl->surface_state[shader]), *globals);
/* free trace data */
if(globals->tracedata)
@ -291,8 +289,8 @@ static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
{
/* gather pointers */
OSL::ShadingSystem *ss = kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
OSLThreadData *tdata = kg->osl_tdata;
OSL::ShaderGlobals *globals = &tdata->globals;
OSL::ShadingContext *ctx = (OSL::ShadingContext *)sd->osl_ctx;
@ -300,8 +298,8 @@ float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_fl
shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
/* execute shader for this point */
if (kg->osl.background_state)
ss->execute(*ctx, *(kg->osl.background_state), *globals);
if (kg->osl->background_state)
ss->execute(*ctx, *(kg->osl->background_state), *globals);
/* free trace data */
if(globals->tracedata)
@ -343,7 +341,8 @@ static void flatten_volume_closure_tree(ShaderData *sd,
sc.type = CLOSURE_VOLUME_ID;
/* add */
sd->closure[sd->num_closure++] = sc;
if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE)
sd->closure[sd->num_closure++] = sc;
break;
}
case OSL::ClosurePrimitive::Holdout:
@ -371,8 +370,8 @@ static void flatten_volume_closure_tree(ShaderData *sd,
void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
{
/* gather pointers */
OSL::ShadingSystem *ss = kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
OSLThreadData *tdata = kg->osl_tdata;
OSL::ShaderGlobals *globals = &tdata->globals;
OSL::ShadingContext *ctx = (OSL::ShadingContext *)sd->osl_ctx;
@ -382,8 +381,8 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int
/* execute shader */
int shader = sd->shader & SHADER_MASK;
if (kg->osl.volume_state[shader])
ss->execute(*ctx, *(kg->osl.volume_state[shader]), *globals);
if (kg->osl->volume_state[shader])
ss->execute(*ctx, *(kg->osl->volume_state[shader]), *globals);
/* free trace data */
if(globals->tracedata)
@ -398,8 +397,8 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int
void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd)
{
/* gather pointers */
OSL::ShadingSystem *ss = kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
OSLThreadData *tdata = kg->osl_tdata;
OSL::ShaderGlobals *globals = &tdata->globals;
OSL::ShadingContext *ctx = (OSL::ShadingContext *)sd->osl_ctx;
@ -409,8 +408,8 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd)
/* execute shader */
int shader = sd->shader & SHADER_MASK;
if (kg->osl.displacement_state[shader])
ss->execute(*ctx, *(kg->osl.displacement_state[shader]), *globals);
if (kg->osl->displacement_state[shader])
ss->execute(*ctx, *(kg->osl->displacement_state[shader]), *globals);
/* free trace data */
if(globals->tracedata)
@ -422,15 +421,15 @@ void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd)
void OSLShader::init(KernelGlobals *kg, ShaderData *sd)
{
OSL::ShadingSystem *ss = kg->osl.ss;
OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
OSLThreadData *tdata = kg->osl_tdata;
sd->osl_ctx = ss->get_context(tdata->thread_info);
}
void OSLShader::release(KernelGlobals *kg, ShaderData *sd)
{
OSL::ShadingSystem *ss = kg->osl.ss;
OSL::ShadingSystem *ss = (OSL::ShadingSystem*)kg->osl_ss;
ss->release_context((OSL::ShadingContext *)sd->osl_ctx);
}
@ -488,5 +487,23 @@ float3 OSLShader::volume_eval_phase(const ShaderClosure *sc, const float3 omega_
return TO_FLOAT3(volume_eval) * sc->weight;
}
/* Attributes */
int OSLShader::find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id)
{
/* for OSL, a hash map is used to lookup the attribute by name. */
OSLGlobals::AttributeMap &attr_map = kg->osl->attribute_map[sd->object];
ustring stdname(std::string("std::") + std::string(attribute_standard_name((AttributeStandard)id)));
OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
if (it != attr_map.end()) {
const OSLGlobals::Attribute &osl_attr = it->second;
/* return result */
return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
}
else
return (int)ATTR_STD_NOT_FOUND;
}
CCL_NAMESPACE_END

@ -31,33 +31,27 @@
* This means no thread state must be passed along in the kernel itself.
*/
#include <OSL/oslexec.h>
#include <OSL/oslclosure.h>
#include "kernel_types.h"
#include "util_map.h"
#include "util_param.h"
#include "util_vector.h"
CCL_NAMESPACE_BEGIN
namespace OSL = ::OSL;
class OSLRenderServices;
class Scene;
struct ShaderClosure;
struct ShaderData;
struct differential3;
struct KernelGlobals;
struct OSLGlobals;
struct OSLShadingSystem;
class OSLShader {
public:
/* init */
static void register_closures(OSL::ShadingSystem *ss);
static void register_closures(OSLShadingSystem *ss);
/* per thread data */
static void thread_init(KernelGlobals *kg);
static void thread_init(KernelGlobals *kg, KernelGlobals *kernel_globals, OSLGlobals *osl_globals);
static void thread_free(KernelGlobals *kg);
/* eval */
@ -82,6 +76,9 @@ public:
/* release */
static void init(KernelGlobals *kg, ShaderData *sd);
static void release(KernelGlobals *kg, ShaderData *sd);
/* attributes */
static int find_attribute(KernelGlobals *kg, const ShaderData *sd, uint id);
};
CCL_NAMESPACE_END

@ -28,7 +28,7 @@ shader node_convert_from_color(
output normal Normal = normal(0.0, 0.0, 0.0))
{
Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722;
ValInt = (int)(Color[0]*0.2126 + Color[1]*0.7152 + Color[2]*0.0722);
ValInt = (int)(Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722);
Vector = vector(Color[0], Color[1], Color[2]);
Point = point(Color[0], Color[1], Color[2]);
Normal = normal(Color[0], Color[1], Color[2]);

@ -21,8 +21,8 @@
vector environment_texture_direction_to_equirectangular(vector dir)
{
float u = -atan2(dir[1], dir[0])/(2.0*M_PI) + 0.5;
float v = atan2(dir[2], hypot(dir[0], dir[1]))/M_PI + 0.5;
float u = -atan2(dir[1], dir[0]) / (2.0 * M_PI) + 0.5;
float v = atan2(dir[2], hypot(dir[0], dir[1])) / M_PI + 0.5;
return vector(u, v, 0.0);
}
@ -31,12 +31,12 @@ vector environment_texture_direction_to_mirrorball(vector dir)
{
dir[1] -= 1.0;
float div = 2.0*sqrt(max(-0.5*dir[1], 0.0));
if(div > 0.0)
float div = 2.0 * sqrt(max(-0.5 * dir[1], 0.0));
if (div > 0.0)
dir /= div;
float u = 0.5*(dir[0] + 1.0);
float v = 0.5*(dir[2] + 1.0);
float u = 0.5 * (dir[0] + 1.0);
float v = 0.5 * (dir[2] + 1.0);
return vector(u, v, 0.0);
}

@ -51,7 +51,12 @@ shader node_geometry(
/* try to create spherical tangent from generated coordinates */
if (getattribute("geom:generated", generated)) {
vector T = vector(-(generated[1] - 0.5), (generated[0] - 0.5), 0.0);
matrix project = matrix(0.0, 1.0, 0.0, 0.0,
-1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0,
0.5, -0.5, 0.0, 1.0);
vector T = transform(project, generated);
T = transform("object", "world", T);
Tangent = cross(Normal, normalize(cross(T, Normal)));
}

@ -68,26 +68,26 @@ shader node_image_texture(
vector weight = vector(0.0, 0.0, 0.0);
float blend = projection_blend;
float limit = 0.5*(1.0 + blend);
float limit = 0.5 * (1.0 + blend);
/* first test for corners with single texture */
if (Nob[0] > limit*(Nob[0] + Nob[1]) && Nob[0] > limit*(Nob[0] + Nob[2])) {
if (Nob[0] > limit * (Nob[0] + Nob[1]) && Nob[0] > limit * (Nob[0] + Nob[2])) {
weight[0] = 1.0;
}
else if (Nob[1] > limit*(Nob[0] + Nob[1]) && Nob[1] > limit*(Nob[1] + Nob[2])) {
else if (Nob[1] > limit * (Nob[0] + Nob[1]) && Nob[1] > limit * (Nob[1] + Nob[2])) {
weight[1] = 1.0;
}
else if (Nob[2] > limit*(Nob[0] + Nob[2]) && Nob[2] > limit*(Nob[1] + Nob[2])) {
else if (Nob[2] > limit * (Nob[0] + Nob[2]) && Nob[2] > limit * (Nob[1] + Nob[2])) {
weight[2] = 1.0;
}
else if (blend > 0.0) {
/* in case of blending, test for mixes between two textures */
if (Nob[2] < (1.0 - limit)*(Nob[1] + Nob[0])) {
if (Nob[2] < (1.0 - limit) * (Nob[1] + Nob[0])) {
weight[0] = Nob[0] / (Nob[0] + Nob[1]);
weight[0] = clamp((weight[0] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
weight[1] = 1.0 - weight[0];
}
else if (Nob[0] < (1.0 - limit)*(Nob[1] + Nob[2])) {
else if (Nob[0] < (1.0 - limit) * (Nob[1] + Nob[2])) {
weight[1] = Nob[1] / (Nob[1] + Nob[2]);
weight[1] = clamp((weight[1] - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
weight[2] = 1.0 - weight[1];
@ -111,16 +111,16 @@ shader node_image_texture(
float tmp_alpha;
if (weight[0] > 0.0) {
Color += weight[0]*image_texture_lookup(filename, color_space, p[1], p[2], tmp_alpha);
Alpha += weight[0]*tmp_alpha;
Color += weight[0] * image_texture_lookup(filename, color_space, p[1], p[2], tmp_alpha);
Alpha += weight[0] * tmp_alpha;
}
if (weight[1] > 0.0) {
Color += weight[1]*image_texture_lookup(filename, color_space, p[0], p[2], tmp_alpha);
Alpha += weight[1]*tmp_alpha;
Color += weight[1] * image_texture_lookup(filename, color_space, p[0], p[2], tmp_alpha);
Alpha += weight[1] * tmp_alpha;
}
if (weight[2] > 0.0) {
Color += weight[2]*image_texture_lookup(filename, color_space, p[1], p[0], tmp_alpha);
Alpha += weight[2]*tmp_alpha;
Color += weight[2] * image_texture_lookup(filename, color_space, p[1], p[0], tmp_alpha);
Alpha += weight[2] * tmp_alpha;
}
}
}

@ -30,7 +30,7 @@ shader node_light_falloff(
getattribute("path:ray_length", ray_length);
if (Smooth > 0.0) {
float squared = ray_length*ray_length;
float squared = ray_length * ray_length;
strength *= squared / (Smooth + squared);
}
@ -38,9 +38,9 @@ shader node_light_falloff(
Quadratic = strength;
/* Linear */
Linear = (strength*ray_length);
Linear = (strength * ray_length);
/* Constant */
Constant = (strength*ray_length*ray_length);
Constant = (strength * ray_length * ray_length);
}

@ -20,9 +20,17 @@
shader node_mapping(
matrix Matrix = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
point mapping_min = point(0.0, 0.0, 0.0),
point mapping_max = point(0.0, 0.0, 0.0),
int use_minmax = 0,
point VectorIn = point(0.0, 0.0, 0.0),
output point VectorOut = point(0.0, 0.0, 0.0))
{
VectorOut = transform(Matrix, VectorIn);
point p = transform(Matrix, VectorIn);
if(use_minmax)
p = min(max(mapping_min, p), mapping_max);
VectorOut = p;
}

@ -272,7 +272,7 @@ color node_mix_clamp(color col)
color outcol = col;
outcol[0] = clamp(col[0], 0.0, 1.0);
outcol[1] = clamp(col[2], 0.0, 1.0);
outcol[1] = clamp(col[1], 0.0, 1.0);
outcol[2] = clamp(col[2], 0.0, 1.0);
return outcol;

@ -27,7 +27,7 @@ shader node_normal_map(
string attr_sign_name = "geom:tangent_sign",
output normal Normal = NormalIn)
{
color mcolor = 2.0*color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5);
color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5);
if (space == "Tangent") {
vector tangent;
@ -47,6 +47,6 @@ shader node_normal_map(
Normal = normalize(vector(mcolor));
if (Strength != 1.0)
Normal = normalize(NormalIn + (Normal - NormalIn)*max(Strength, 0.0));
Normal = normalize(NormalIn + (Normal - NormalIn) * max(Strength, 0.0));
}

@ -29,7 +29,10 @@ shader node_rgb_ramp(
{
float f = clamp(Fac, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1);
/* clamp int as well in case of NaN */
int i = (int)f;
if (i < 0) i = 0;
if (i >= RAMP_TABLE_SIZE) i = RAMP_TABLE_SIZE - 1;
float t = f - (float)i;
Color = ramp_color[i];

@ -73,7 +73,7 @@ __device_inline ShaderClosure *svm_node_closure_get_bsdf(ShaderData *sd, float m
#ifdef __MULTI_CLOSURE__
ShaderClosure *sc = &sd->closure[sd->num_closure];
float3 weight = sc->weight * mix_weight;
float sample_weight = fabsf(average(sc->weight));
float sample_weight = fabsf(average(weight));
if(sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) {
sc->weight = weight;

@ -25,7 +25,8 @@ __device float4 rgb_ramp_lookup(KernelGlobals *kg, int offset, float f)
{
f = clamp(f, 0.0f, 1.0f)*(RAMP_TABLE_SIZE-1);
int i = (int)f;
/* clamp int as well in case of NaN */
int i = clamp((int)f, 0, RAMP_TABLE_SIZE-1);
float t = f - (float)i;
float4 a = fetch_node_float(kg, offset+i);

@ -547,7 +547,7 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene,
}
/* create attribute lookup maps */
if(scene->params.shadingsystem == SceneParams::OSL)
if(scene->shader_manager->use_osl())
update_osl_attributes(device, scene, mesh_attributes);
else
update_svm_attributes(device, dscene, scene, mesh_attributes);

@ -1098,6 +1098,9 @@ void MappingNode::compile(OSLCompiler& compiler)
{
Transform tfm = transform_transpose(tex_mapping.compute_transform());
compiler.parameter("Matrix", tfm);
compiler.parameter_point("mapping_min", tex_mapping.min);
compiler.parameter_point("mapping_max", tex_mapping.max);
compiler.parameter("use_minmax", tex_mapping.use_minmax);
compiler.add(this, "node_mapping");
}

@ -148,10 +148,9 @@ ObjectManager::~ObjectManager()
{
}
void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress)
{
float4 *objects = dscene->objects.resize(OBJECT_SIZE*scene->objects.size());
uint *object_flag = dscene->object_flag.resize(scene->objects.size());
int i = 0;
map<Mesh*, float> surface_area_map;
Scene::MotionType need_motion = scene->need_motion(device->info.advanced_shading);
@ -257,7 +256,6 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
}
device->tex_alloc("__objects", dscene->objects);
device->tex_alloc("__object_flag", dscene->object_flag);
dscene->data.bvh.have_motion = have_motion;
}
@ -272,9 +270,12 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
if(scene->objects.size() == 0)
return;
/* object info flag */
uint *object_flag = dscene->object_flag.resize(scene->objects.size());
/* set object transform matrices, before applying static transforms */
progress.set_status("Updating Objects", "Copying Transformations to device");
device_update_transforms(device, dscene, scene, progress);
device_update_transforms(device, dscene, scene, object_flag, progress);
if(progress.get_cancel()) return;
@ -282,10 +283,11 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc
/* todo: do before to support getting object level coords? */
if(scene->params.bvh_type == SceneParams::BVH_STATIC) {
progress.set_status("Updating Objects", "Applying Static Transformations");
apply_static_transforms(scene, progress);
apply_static_transforms(scene, object_flag, progress);
}
if(progress.get_cancel()) return;
/* allocate object flag */
device->tex_alloc("__object_flag", dscene->object_flag);
need_update = false;
}
@ -299,7 +301,7 @@ void ObjectManager::device_free(Device *device, DeviceScene *dscene)
dscene->object_flag.clear();
}
void ObjectManager::apply_static_transforms(Scene *scene, Progress& progress)
void ObjectManager::apply_static_transforms(Scene *scene, uint *object_flag, Progress& progress)
{
/* todo: normals and displacement should be done before applying transform! */
/* todo: create objects/meshes in right order! */
@ -312,6 +314,7 @@ void ObjectManager::apply_static_transforms(Scene *scene, Progress& progress)
#else
bool motion_blur = false;
#endif
int i = 0;
foreach(Object *object, scene->objects) {
map<Mesh*, int>::iterator it = mesh_users.find(object->mesh);
@ -334,8 +337,12 @@ void ObjectManager::apply_static_transforms(Scene *scene, Progress& progress)
if(progress.get_cancel()) return;
}
object_flag[i] |= SD_TRANSFORM_APPLIED;
}
}
i++;
}
}

@ -73,12 +73,12 @@ public:
~ObjectManager();
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_transforms(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_update_transforms(Device *device, DeviceScene *dscene, Scene *scene, uint *object_flag, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
void tag_update(Scene *scene);
void apply_static_transforms(Scene *scene, Progress& progress);
void apply_static_transforms(Scene *scene, uint *object_flag, Progress& progress);
};
CCL_NAMESPACE_END

@ -45,8 +45,6 @@ CCL_NAMESPACE_BEGIN
OSLShaderManager::OSLShaderManager()
{
thread_data_initialized = false;
services = new OSLRenderServices();
shading_system_init();
@ -103,11 +101,6 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
scene->image_manager->set_osl_texture_system((void*)ts);
device_update_common(device, dscene, scene, progress);
if(!thread_data_initialized) {
og->thread_data_init();
thread_data_initialized = true;
}
}
void OSLShaderManager::device_free(Device *device, DeviceScene *dscene)
@ -125,11 +118,6 @@ void OSLShaderManager::device_free(Device *device, DeviceScene *dscene)
og->volume_state.clear();
og->displacement_state.clear();
og->background_state.reset();
if(thread_data_initialized) {
og->thread_data_free();
thread_data_initialized = false;
}
}
void OSLShaderManager::texture_system_init()
@ -170,7 +158,7 @@ void OSLShaderManager::shading_system_init()
const int nraytypes = sizeof(raytypes)/sizeof(raytypes[0]);
ss->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes);
OSLShader::register_closures(ss);
OSLShader::register_closures((OSLShadingSystem*)ss);
loaded_shaders.clear();
}

@ -52,6 +52,8 @@ public:
OSLShaderManager();
~OSLShaderManager();
bool use_osl() { return true; }
void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress);
void device_free(Device *device, DeviceScene *dscene);
@ -73,8 +75,6 @@ protected:
OSLRenderServices *services;
OSL::ErrorHandler errhandler;
set<string> loaded_shaders;
bool thread_data_initialized;
};
#endif

@ -44,10 +44,6 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
device = NULL;
memset(&dscene.data, 0, sizeof(dscene.data));
/* OSL only works on the CPU */
if(device_info_.type != DEVICE_CPU)
params.shadingsystem = SceneParams::SVM;
camera = new Camera();
filter = new Filter();
film = new Film();
@ -57,9 +53,14 @@ Scene::Scene(const SceneParams& params_, const DeviceInfo& device_info_)
object_manager = new ObjectManager();
integrator = new Integrator();
image_manager = new ImageManager();
shader_manager = ShaderManager::create(this);
particle_system_manager = new ParticleSystemManager();
/* OSL only works on the CPU */
if(device_info_.type == DEVICE_CPU)
shader_manager = ShaderManager::create(this, params.shadingsystem);
else
shader_manager = ShaderManager::create(this, SceneParams::SVM);
if (device_info_.type == DEVICE_CPU)
image_manager->set_extended_image_limits();
}

@ -121,12 +121,12 @@ ShaderManager::~ShaderManager()
{
}
ShaderManager *ShaderManager::create(Scene *scene)
ShaderManager *ShaderManager::create(Scene *scene, int shadingsystem)
{
ShaderManager *manager;
#ifdef WITH_OSL
if(scene->params.shadingsystem == SceneParams::OSL)
if(shadingsystem == SceneParams::OSL)
manager = new OSLShaderManager();
else
#endif

@ -107,9 +107,11 @@ class ShaderManager {
public:
bool need_update;
static ShaderManager *create(Scene *scene);
static ShaderManager *create(Scene *scene, int shadingsystem);
virtual ~ShaderManager();
virtual bool use_osl() { return false; }
/* device update */
virtual void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) = 0;
virtual void device_free(Device *device, DeviceScene *dscene) = 0;

@ -54,6 +54,7 @@ set(SRC_HEADERS
util_path.h
util_progress.h
util_set.h
util_stats.h
util_string.h
util_system.h
util_task.h
@ -61,8 +62,8 @@ set(SRC_HEADERS
util_time.h
util_transform.h
util_types.h
util_view.h
util_vector.h
util_view.h
util_xml.h
)

@ -70,37 +70,6 @@ protected:
bool joined;
};
/* Thread Local Storage
*
* Boost implementation is a bit slow, and Mac OS X __thread is not supported
* but the pthreads implementation is optimized, so we use these macros. */
#if defined(__APPLE__) || defined(_WIN32)
#define tls_ptr(type, name) \
pthread_key_t name
#define tls_set(name, value) \
pthread_setspecific(name, value)
#define tls_get(type, name) \
((type*)pthread_getspecific(name))
#define tls_create(type, name) \
pthread_key_create(&name, NULL)
#define tls_delete(type, name) \
pthread_key_delete(name);
#else
#define tls_ptr(type, name) \
__thread type *name
#define tls_set(name, value) \
name = value
#define tls_get(type, name) \
name
#define tls_create(type, name)
#define tls_delete(type, name)
#endif
CCL_NAMESPACE_END
#endif /* __UTIL_THREAD_H__ */

@ -41,7 +41,9 @@
#define __align(...) __declspec(align(__VA_ARGS__))
#else
#define __device_inline static inline __attribute__((always_inline))
#ifndef FREE_WINDOWS64
#define __forceinline inline __attribute__((always_inline))
#endif
#define __align(...) __attribute__((aligned(__VA_ARGS__)))
#endif

@ -90,8 +90,8 @@ bool GHOST_NDOFManagerX11::processEvents()
case SPNAV_EVENT_MOTION:
{
/* convert to blender view coords */
short t[3] = {e.motion.x, e.motion.y, -e.motion.z};
short r[3] = {-e.motion.rx, -e.motion.ry, e.motion.rz};
short t[3] = {(short)e.motion.x, (short)e.motion.y, (short)-e.motion.z};
short r[3] = {(short)-e.motion.rx, (short)-e.motion.ry, (short)e.motion.rz};
updateTranslation(t, now);
updateRotation(r, now);

@ -73,7 +73,7 @@ GHOST_SystemSDL::createWindow(const STR_String& title,
{
GHOST_WindowSDL *window = NULL;
window = new GHOST_WindowSDL(this, title, left, top, width, height, state, parentWindow, type, stereoVisual, 1);
window = new GHOST_WindowSDL(this, title, left, top, width, height, state, parentWindow, type, stereoVisual, numOfAASamples);
if (window) {
if (GHOST_kWindowStateFullScreen == state) {

@ -609,9 +609,12 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa()
[m_openGLView release];
if (m_window) {
// previously we called [m_window release], but on 10.8 this does not
// remove the window from [NSApp orderedWindows] and perhaps other
// places, leading to crashes. so instead we set setReleasedWhenClosed
// back to YES right before closing
[m_window setReleasedWhenClosed:YES];
[m_window close];
[[m_window delegate] release];
[m_window release];
m_window = nil;
}

@ -26,6 +26,7 @@
#include "GHOST_WindowSDL.h"
#include "SDL_mouse.h"
#include <GL/glew.h>
#include <assert.h>
static SDL_GLContext s_firstContext = NULL;
@ -48,6 +49,20 @@ GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system,
m_invalid_window(false),
m_sdl_custom_cursor(NULL)
{
SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
if (numOfAASamples) {
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, numOfAASamples);
}
/* creating the window _must_ come after setting attributes */
m_sdl_win = SDL_CreateWindow(title,
left,
top,
@ -55,14 +70,7 @@ GHOST_WindowSDL::GHOST_WindowSDL(GHOST_SystemSDL *system,
height,
SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
m_sdl_glcontext = SDL_GL_CreateContext(m_sdl_win);
@ -164,6 +172,10 @@ GHOST_WindowSDL::activateDrawingContext()
if (m_sdl_glcontext != NULL) {
int status = SDL_GL_MakeCurrent(m_sdl_win, m_sdl_glcontext);
(void)status;
/* Disable AA by default */
if (m_numOfAASamples > 0) {
glDisable(GL_MULTISAMPLE_ARB);
}
return GHOST_kSuccess;
}
return GHOST_kFailure;

@ -868,7 +868,7 @@ GHOST_TSuccess GHOST_WindowWin32::installDrawingContext(GHOST_TDrawingContextTyp
}
// Attempt to enable multisample
if (m_multisample && WGL_ARB_multisample && !m_multisampleEnabled)
if (m_multisample && WGL_ARB_multisample && !m_multisampleEnabled && !is_crappy_intel_card())
{
success = initMultisample(preferredFormat);

@ -32,6 +32,8 @@ set(INC_SYS
set(SRC
boost_locale_wrapper.cpp
boost_locale_wrapper.h
)
if(WITH_INTERNATIONAL)

@ -167,6 +167,8 @@ static void generatTile_FFT(float* const noiseTileData, std::string filename)
for (int x = 0; x < xRes; x++, index++)
noise[index] -= forward[index][0] / totalCells;
// fill noiseTileData
memcpy(noiseTileData, noise, sizeof(float) * totalCells);
// save out the noise tile
saveTile(noise, filename);

@ -220,21 +220,25 @@ void WTURBULENCE::setNoise(int type)
{
if(type == (1<<1)) // FFT
{
#ifdef WITH_FFTW3
// needs fft
#ifdef WITH_FFTW3
std::string noiseTileFilename = std::string("noise.fft");
generatTile_FFT(_noiseTile, noiseTileFilename);
#endif
return;
#else
fprintf(stderr, "FFTW not enabled, falling back to wavelet noise.\n");
#endif
}
else if(type == (1<<2)) // curl
#if 0
if(type == (1<<2)) // curl
{
// TODO: not supported yet
return;
}
else // standard - wavelet
{
std::string noiseTileFilename = std::string("noise.wavelets");
generateTile_WAVELET(_noiseTile, noiseTileFilename);
}
#endif
std::string noiseTileFilename = std::string("noise.wavelets");
generateTile_WAVELET(_noiseTile, noiseTileFilename);
}
// init direct access functions from blender

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 KiB

After

Width:  |  Height:  |  Size: 185 KiB

@ -74,7 +74,7 @@ class BPyOpsSubMod(object):
eg. bpy.ops.object
"""
__keys__ = ("module",)
__slots__ = ("module",)
def __init__(self, module):
self.module = module
@ -111,7 +111,7 @@ class BPyOpsSubModOp(object):
eg. bpy.ops.object.somefunc
"""
__keys__ = ("module", "func")
__slots__ = ("module", "func")
def _get_doc(self):
return op_as_string(self.idname())

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1049,6 +1049,8 @@ class WM_OT_properties_edit(Operator):
try:
value_eval = eval(value)
# assert else None -> None, not "None", see [#33431]
assert(type(value_eval) in {str, float, int, bool, tuple, list})
except:
value_eval = value

@ -414,7 +414,9 @@ class IMAGE_HT_header(Header):
row = layout.row(align=True)
row.prop(toolsettings, "use_snap", text="")
row.prop(toolsettings, "snap_target", text="")
row.prop(toolsettings, "snap_uv_element", text="", icon_only=True)
if toolsettings.snap_uv_element != 'INCREMENT':
row.prop(toolsettings, "snap_target", text="")
mesh = context.edit_object.data
layout.prop_search(mesh.uv_textures, "active", mesh, "uv_textures", text="")

@ -437,6 +437,7 @@ class USERPREF_PT_system(Panel):
col.label(text="OpenGL:")
col.prop(system, "gl_clip_alpha", slider=True)
col.prop(system, "use_mipmaps")
col.prop(system, "use_gpu_mipmap")
col.prop(system, "use_16bit_textures")
col.label(text="Anisotropic Filtering")
col.prop(system, "anisotropic_filter", text="")

@ -19,3 +19,4 @@ for v in bm.verts:
# Finish up, write the bmesh back to the mesh
bm.to_mesh(me)
bm.free() # free and prevent further access

@ -30,9 +30,7 @@
/** \file BKE_icons.h
* \ingroup bke
*/
/*
*
* Resizable Icons for Blender
*/

@ -314,6 +314,8 @@ void ntreeUserIncrefID(struct bNodeTree *ntree);
void ntreeUserDecrefID(struct bNodeTree *ntree);
struct bNodeTree *ntreeFromID(struct ID *id);
void ntreeMakeLocal(struct bNodeTree *ntree);
int ntreeHasType(struct bNodeTree *ntree, int type);
void ntreeUpdateTree(struct bNodeTree *ntree);

@ -257,13 +257,13 @@ if(WITH_BULLET)
add_definitions(-DUSE_BULLET)
endif()
if(WITH_MOD_CLOTH_ELTOPO)
list(APPEND INC
../../../extern/eltopo
../../../extern/eltopo/eltopo3d
)
add_definitions(-DWITH_ELTOPO)
endif()
#if(WITH_MOD_CLOTH_ELTOPO)
# list(APPEND INC
# ../../../extern/eltopo
# ../../../extern/eltopo/eltopo3d
# )
# add_definitions(-DWITH_ELTOPO)
#endif()
if(WITH_IMAGE_OPENEXR)
add_definitions(-DWITH_OPENEXR)

@ -392,7 +392,7 @@ void DM_ensure_tessface(DerivedMesh *dm)
}
else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX));
BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX) || numTessFaces == 0);
DM_update_tessface_data(dm);
}
@ -1159,120 +1159,65 @@ void DM_update_weight_mcol(Object *ob, DerivedMesh *dm, int const draw_flag,
ColorBand *coba = stored_cb; /* warning, not a local var */
unsigned char *wtcol_v;
#if 0 /* See coment below. */
unsigned char *wtcol_f = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
#endif
unsigned char(*wtcol_l)[4] = CustomData_get_layer(dm->getLoopDataLayout(dm), CD_PREVIEW_MLOOPCOL);
#if 0 /* See coment below. */
MFace *mf = dm->getTessFaceArray(dm);
#endif
MLoop *mloop = dm->getLoopArray(dm), *ml;
MPoly *mp = dm->getPolyArray(dm);
#if 0
int numFaces = dm->getNumTessFaces(dm);
#endif
int numVerts = dm->getNumVerts(dm);
int totloop;
int i, j;
#if 0 /* See comment below */
/* If no CD_PREVIEW_MCOL existed yet, add a new one! */
if (!wtcol_f)
wtcol_f = CustomData_add_layer(&dm->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
if (wtcol_f) {
unsigned char *wtcol_f_step = wtcol_f;
# else
#if 0
/* XXX We have to create a CD_PREVIEW_MCOL, else it might sigsev (after a SubSurf mod, eg)... */
if (!dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL))
CustomData_add_layer(&dm->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
#endif
{
#endif
/* Weights are given by caller. */
if (weights) {
float *w = weights;
/* If indices is not NULL, it means we do not have weights for all vertices,
* so we must create them (and set them to zero)... */
if (indices) {
w = MEM_callocN(sizeof(float) * numVerts, "Temp weight array DM_update_weight_mcol");
i = num;
while (i--)
w[indices[i]] = weights[i];
}
/* Convert float weights to colors. */
wtcol_v = calc_colors_from_weights_array(numVerts, w);
if (indices)
MEM_freeN(w);
/* Weights are given by caller. */
if (weights) {
float *w = weights;
/* If indices is not NULL, it means we do not have weights for all vertices,
* so we must create them (and set them to zero)... */
if (indices) {
w = MEM_callocN(sizeof(float) * numVerts, "Temp weight array DM_update_weight_mcol");
i = num;
while (i--)
w[indices[i]] = weights[i];
}
/* No weights given, take them from active vgroup(s). */
else
wtcol_v = calc_weightpaint_vert_array(ob, dm, draw_flag, coba);
/* Convert float weights to colors. */
wtcol_v = calc_colors_from_weights_array(numVerts, w);
/* Now copy colors in all face verts. */
/* first add colors to the tessellation faces */
/* XXX Why update that layer? We have to update WEIGHT_MLOOPCOL anyway,
* and tessellation recreates mface layers from mloop/mpoly ones, so no
* need to fill WEIGHT_MCOL here. */
#if 0
for (i = 0; i < numFaces; i++, mf++, wtcol_f_step += (4 * 4)) {
/*origindex being NULL means we're operating on original mesh data*/
#if 0
unsigned int fidx = mf->v4 ? 3 : 2;
#else /* better zero out triangles 4th component. else valgrind complains when the buffer's copied */
unsigned int fidx;
if (mf->v4) {
fidx = 3;
}
else {
fidx = 2;
*(int *)(&wtcol_f_step[3 * 4]) = 0;
}
#endif
do {
copy_v4_v4_char((char *)&wtcol_f_step[fidx * 4],
(char *)&wtcol_v[4 * (*(&mf->v1 + fidx))]);
} while (fidx--);
}
#endif
/*now add to loops, so the data can be passed through the modifier stack*/
/* If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
if (!wtcol_l) {
BLI_array_declare(wtcol_l);
totloop = 0;
for (i = 0; i < dm->numPolyData; i++, mp++) {
ml = mloop + mp->loopstart;
BLI_array_grow_items(wtcol_l, mp->totloop);
for (j = 0; j < mp->totloop; j++, ml++, totloop++) {
copy_v4_v4_char((char *)&wtcol_l[totloop],
(char *)&wtcol_v[4 * ml->v]);
}
}
CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, totloop);
}
else {
totloop = 0;
for (i = 0; i < dm->numPolyData; i++, mp++) {
ml = mloop + mp->loopstart;
for (j = 0; j < mp->totloop; j++, ml++, totloop++) {
copy_v4_v4_char((char *)&wtcol_l[totloop],
(char *)&wtcol_v[4 * ml->v]);
}
}
}
MEM_freeN(wtcol_v);
if (indices)
MEM_freeN(w);
}
/* No weights given, take them from active vgroup(s). */
else
wtcol_v = calc_weightpaint_vert_array(ob, dm, draw_flag, coba);
/* now add to loops, so the data can be passed through the modifier stack */
/* If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
if (!wtcol_l) {
BLI_array_declare(wtcol_l);
totloop = 0;
for (i = 0; i < dm->numPolyData; i++, mp++) {
ml = mloop + mp->loopstart;
BLI_array_grow_items(wtcol_l, mp->totloop);
for (j = 0; j < mp->totloop; j++, ml++, totloop++) {
copy_v4_v4_char((char *)&wtcol_l[totloop],
(char *)&wtcol_v[4 * ml->v]);
}
}
CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, totloop);
}
else {
totloop = 0;
for (i = 0; i < dm->numPolyData; i++, mp++) {
ml = mloop + mp->loopstart;
for (j = 0; j < mp->totloop; j++, ml++, totloop++) {
copy_v4_v4_char((char *)&wtcol_l[totloop],
(char *)&wtcol_v[4 * ml->v]);
}
}
}
MEM_freeN(wtcol_v);
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
}

@ -279,7 +279,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
/* this can happen when active scene was lib-linked, and doesn't exist anymore */
if (CTX_data_scene(C) == NULL) {
/* in case we don't even have a local scene, add one */
if(!G.main->scene.first)
if (!G.main->scene.first)
BKE_scene_add("Scene");
CTX_data_scene_set(C, G.main->scene.first);

@ -653,12 +653,29 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
else {
if (index_mf_to_mpoly) {
orig = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, i);
if (orig == ORIGINDEX_NONE) { if (nors) nors += 3; continue; }
if (drawParamsMapped) { draw_option = drawParamsMapped(userData, orig); }
else { if (nors) nors += 3; continue; }
if (orig == ORIGINDEX_NONE) {
/* XXX, this is not really correct
* it will draw the previous faces context for this one when we don't know its settings.
* but better then skipping it altogether. - campbell */
draw_option = DM_DRAW_OPTION_NORMAL;
}
else if (drawParamsMapped) {
draw_option = drawParamsMapped(userData, orig);
}
else {
if (nors) {
nors += 3; continue;
}
}
}
else if (drawParamsMapped) {
draw_option = drawParamsMapped(userData, i);
}
else {
if (nors) {
nors += 3; continue;
}
}
else if (drawParamsMapped) { draw_option = drawParamsMapped(userData, i); }
else { if (nors) nors += 3; continue; }
}
if (draw_option != DM_DRAW_OPTION_SKIP) {
@ -742,9 +759,12 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
if (index_mf_to_mpoly) {
orig = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, actualFace);
if (orig == ORIGINDEX_NONE) {
continue;
/* XXX, this is not really correct
* it will draw the previous faces context for this one when we don't know its settings.
* but better then skipping it altogether. - campbell */
draw_option = DM_DRAW_OPTION_NORMAL;
}
if (drawParamsMapped) {
else if (drawParamsMapped) {
draw_option = drawParamsMapped(userData, orig);
}
}

@ -84,15 +84,9 @@
#include "BKE_movieclip.h"
#ifdef WITH_PYTHON
#include "BPY_extern.h"
# include "BPY_extern.h"
#endif
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* ************************ Constraints - General Utilities *************************** */
/* These functions here don't act on any specific constraints, and are therefore should/will
* not require any of the special function-pointers afforded by the relevant constraint

@ -1940,13 +1940,13 @@ void DAG_scene_sort(Main *bmain, Scene *sce)
static void lib_id_recalc_tag(Main *bmain, ID *id)
{
id->flag |= LIB_ID_RECALC;
bmain->id_tag_update[id->name[0]] = 1;
DAG_id_type_tag(bmain, GS(id->name));
}
static void lib_id_recalc_data_tag(Main *bmain, ID *id)
{
id->flag |= LIB_ID_RECALC_DATA;
bmain->id_tag_update[id->name[0]] = 1;
DAG_id_type_tag(bmain, GS(id->name));
}
/* node was checked to have lasttime != curtime and is if type ID_OB */
@ -2818,6 +2818,7 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, int time)
void DAG_ids_clear_recalc(Main *bmain)
{
ListBase *lbarray[MAX_LIBARRAY];
bNodeTree *ntree;
int a;
/* loop over all ID types */
@ -2830,9 +2831,15 @@ void DAG_ids_clear_recalc(Main *bmain)
/* we tag based on first ID type character to avoid
* looping over all ID's in case there are no tags */
if (id && bmain->id_tag_update[id->name[0]]) {
for (; id; id = id->next)
for (; id; id = id->next) {
if (id->flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA))
id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
/* some ID's contain semi-datablock nodetree */
ntree = ntreeFromID(id);
if (ntree && (ntree->id.flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA)))
ntree->id.flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
}
}
}
@ -2899,8 +2906,18 @@ void DAG_id_tag_update(ID *id, short flag)
}
}
void DAG_id_type_tag(struct Main *bmain, short idtype)
void DAG_id_type_tag(Main *bmain, short idtype)
{
if (idtype == ID_NT) {
/* stupid workaround so parent datablocks of nested nodetree get looped
* over when we loop over tagged datablock types */
DAG_id_type_tag(bmain, ID_MA);
DAG_id_type_tag(bmain, ID_TE);
DAG_id_type_tag(bmain, ID_LA);
DAG_id_type_tag(bmain, ID_WO);
DAG_id_type_tag(bmain, ID_SCE);
}
bmain->id_tag_update[((char *)&idtype)[0]] = 1;
}

@ -3366,7 +3366,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface,
(!hit_found || (brush->flags & MOD_DPAINT_INVERSE_PROX)))
{
float proxDist = -1.0f;
float hitCo[3];
float hitCo[3] = {0.0f, 0.0f, 0.0f};
short hQuad;
int face;
@ -3723,6 +3723,8 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface,
float smooth_range = smooth * (1.0f - strength), dist;
/* calculate max range that can have particles with higher influence than the nearest one */
float max_range = smooth - strength * smooth + solidradius;
/* Make gcc happy! */
dist = max_range;
particles = BLI_kdtree_range_search(tree, max_range, bData->realCoord[bData->s_pos[index]].v, NULL, &nearest);

@ -38,9 +38,13 @@
#include "DNA_action_types.h"
#include "DNA_anim_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "DNA_node_types.h"
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "BLI_string.h"
#include "BLI_math.h"
@ -1154,6 +1158,18 @@ void ntreeSetOutput(bNodeTree *ntree)
* might be different for editor or for "real" use... */
}
bNodeTree *ntreeFromID(ID *id)
{
switch (GS(id->name)) {
case ID_MA: return ((Material*)id)->nodetree;
case ID_LA: return ((Lamp*)id)->nodetree;
case ID_WO: return ((World*)id)->nodetree;
case ID_TE: return ((Tex*)id)->nodetree;
case ID_SCE: return ((Scene*)id)->nodetree;
default: return NULL;
}
}
typedef struct MakeLocalCallData {
ID *group_id;
ID *new_id;

@ -2140,16 +2140,22 @@ static void psys_update_effectors(ParticleSimulationData *sim)
precalc_guides(sim, sim->psys->effectors);
}
static void integrate_particle(ParticleSettings *part, ParticleData *pa, float dtime, float *external_acceleration, void (*force_func)(void *forcedata, ParticleKey *state, float *force, float *impulse), void *forcedata)
static void integrate_particle(ParticleSettings *part, ParticleData *pa, float dtime, float *external_acceleration,
void (*force_func)(void *forcedata, ParticleKey *state, float *force, float *impulse),
void *forcedata)
{
#define ZERO_F43 {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}
ParticleKey states[5];
float force[3],acceleration[3],impulse[3],dx[4][3],dv[4][3],oldpos[3];
float force[3], acceleration[3], impulse[3], dx[4][3] = ZERO_F43, dv[4][3] = ZERO_F43, oldpos[3];
float pa_mass= (part->flag & PART_SIZEMASS ? part->mass * pa->size : part->mass);
int i, steps=1;
int integrator = part->integrator;
#undef ZERO_F43
copy_v3_v3(oldpos, pa->state.co);
/* Verlet integration behaves strangely with moving emitters, so do first step with euler. */
if (pa->prev_state.time < 0.f && integrator == PART_INT_VERLET)
integrator = PART_INT_EULER;

@ -408,6 +408,7 @@ Scene *BKE_scene_add(const char *name)
sce->r.im_format.planes = R_IMF_PLANES_RGB;
sce->r.im_format.imtype = R_IMF_IMTYPE_PNG;
sce->r.im_format.quality = 90;
sce->r.im_format.compress = 90;
sce->r.displaymode = R_OUTPUT_AREA;
sce->r.framapto = 100;

@ -2019,8 +2019,14 @@ void txt_do_undo(Text *text)
/* get and restore the cursors */
txt_undo_read_cursors(text->undo_buf, &text->undo_pos, &curln, &curc, &selln, &selc);
txt_move_to(text, curln, curc, 0);
txt_move_to(text, curln, curc + linep, 1);
txt_move_to(text, selln, selc, 1);
if ((curln == selln) && (curc == selc)) {
for (i = 0; i < linep; i++)
txt_move_right(text, 1);
}
txt_delete_selected(text);
@ -2269,6 +2275,8 @@ void txt_split_curline(Text *text)
txt_delete_sel(text);
if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, '\n');
/* Make the two half strings */
left = MEM_mallocN(text->curc + 1, "textline_string");
@ -2300,7 +2308,6 @@ void txt_split_curline(Text *text)
txt_clean_text(text);
txt_pop_sel(text);
if (!undoing) txt_undo_add_charop(text, UNDO_INSERT_1, '\n');
}
static void txt_delete_line(Text *text, TextLine *line)

@ -129,6 +129,7 @@ set(SRC
BLI_math_color.h
BLI_math_geom.h
BLI_math_inline.h
BLI_math_interp.h
BLI_math_matrix.h
BLI_math_rotation.h
BLI_math_vector.h

@ -501,7 +501,7 @@ void BLI_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int
Material *ma = (Material *)id;
bNodeTree *ntree = ma->nodetree;
if(ntree) {
if (ntree) {
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {

@ -2410,6 +2410,8 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
ntree->adt = newdataadr(fd, ntree->adt);
direct_link_animdata(fd, ntree->adt);
ntree->id.flag &= ~(LIB_ID_RECALC|LIB_ID_RECALC_DATA);
link_list(fd, &ntree->nodes);
for (node = ntree->nodes.first; node; node = node->next) {
node->typeinfo = NULL;
@ -8533,7 +8535,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
for (clip = main->movieclip.first; clip; clip = clip->id.next) {
if (clip->tracking.settings.reconstruction_success_threshold == 0.0f) {
clip->tracking.settings.reconstruction_success_threshold = 1e-3;
clip->tracking.settings.reconstruction_success_threshold = 1e-3f;
}
}
}

@ -42,8 +42,8 @@
#include "intern/bmesh_private.h"
/* used as an extern, defined in bmesh.h */
BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512};
const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512};
static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize)
{
@ -109,7 +109,7 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm)
*
* \note ob is needed by multires
*/
BMesh *BM_mesh_create(BMAllocTemplate *allocsize)
BMesh *BM_mesh_create(const BMAllocTemplate *allocsize)
{
/* allocate the structure */
BMesh *bm = MEM_callocN(sizeof(BMesh), __func__);
@ -206,6 +206,11 @@ void BM_mesh_clear(BMesh *bm)
bm->stackdepth = 1;
bm->totflags = 1;
CustomData_reset(&bm->vdata);
CustomData_reset(&bm->edata);
CustomData_reset(&bm->ldata);
CustomData_reset(&bm->pdata);
}
/**

@ -31,7 +31,7 @@ struct BMAllocTemplate;
void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
BMesh *BM_mesh_create(struct BMAllocTemplate *allocsize);
BMesh *BM_mesh_create(const struct BMAllocTemplate *allocsize);
void BM_mesh_free(BMesh *bm);
void BM_mesh_data_free(BMesh *bm);
@ -57,8 +57,8 @@ typedef struct BMAllocTemplate {
int totvert, totedge, totloop, totface;
} BMAllocTemplate;
extern BMAllocTemplate bm_mesh_allocsize_default;
extern BMAllocTemplate bm_mesh_chunksize_default;
extern const BMAllocTemplate bm_mesh_allocsize_default;
extern const BMAllocTemplate bm_mesh_chunksize_default;
enum {
BM_MESH_CREATE_USE_TOOLFLAGS = (1 << 0)

@ -256,7 +256,7 @@ BMOpSlot *BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identif
if (UNLIKELY(slot_code < 0)) {
//return &BMOpEmptySlot;
BLI_assert(0);
NULL; /* better crash */
return NULL; /* better crash */
}
return &slot_args[slot_code];

@ -382,18 +382,19 @@ void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op)
/* compute summed length between vertices in forward direction */
len = 0.0f;
for (j = 0; j < lenv2; j++) {
for (j = 0; (j < lenv2) && (len < min); j++) {
len += len_v3v3(vv1[clamp_index(i + j, lenv1)]->co, vv2[j]->co);
}
if (len < min) {
min = len;
starti = i;
dir1 = 1;
}
/* compute summed length between vertices in backward direction */
len = 0.0f;
for (j = 0; j < lenv2; j++) {
for (j = 0; (j < lenv2) && (len < min); j++) {
len += len_v3v3(vv1[clamp_index(i - j, lenv1)]->co, vv2[j]->co);
}

@ -689,8 +689,16 @@ static BMFace *BME_bevel_poly(BMesh *bm, BMFace *f, float value, int options, BM
BMO_elem_flag_test(bm, l->v, BME_BEVEL_ORIG) &&
!BMO_elem_flag_test(bm, l->prev->e, BME_BEVEL_BEVEL))
{
max = 1.0f;
l = BME_bevel_vert(bm, l, value, options, up_vec, td);
/* avoid making double vertices [#33438] */
BME_TransData *vtd;
vtd = BME_get_transdata(td, l->v);
if (vtd->weight == 0.0f) {
BMO_elem_flag_disable(bm, l->v, BME_BEVEL_BEVEL);
}
else {
max = 1.0f;
l = BME_bevel_vert(bm, l, value, options, up_vec, td);
}
}
}

@ -375,8 +375,9 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f,
static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
BMVert *v, BMFace *f1, BMFace *f2, float meetco[3])
{
float dir1[3], dir2[3], norm_perp1[3], norm_perp2[3],
off1a[3], off1b[3], off2a[3], off2b[3], isect2[3], co[3];
float dir1[3], dir2[3], dirmid[3], norm_perp1[3], norm_perp2[3],
off1a[3], off1b[3], off2a[3], off2b[3], isect2[3], co[3],
f1no[3], f2no[3];
int iret;
BLI_assert(f1 != NULL && f2 != NULL);
@ -384,17 +385,21 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
/* get direction vectors for two offset lines */
sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co);
sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co);
sub_v3_v3v3(dirmid, BM_edge_other_vert(emid->e, v)->co, v->co);
/* get directions into offset planes */
cross_v3_v3v3(norm_perp1, dir1, f1->no);
/* calculate face normals at corner in case faces are nonplanar */
cross_v3_v3v3(f1no, dirmid, dir1);
cross_v3_v3v3(f2no, dirmid, dir2);
cross_v3_v3v3(norm_perp1, dir1, f1no);
normalize_v3(norm_perp1);
cross_v3_v3v3(norm_perp2, dir2, f2->no);
cross_v3_v3v3(norm_perp2, dir2, f2no);
normalize_v3(norm_perp2);
/* get points that are offset distances from each line, then another point on each line */
copy_v3_v3(off1a, v->co);
madd_v3_v3fl(off1a, norm_perp1, e1->offset);
add_v3_v3v3(off1b, off1a, dir1);
sub_v3_v3v3(off1b, off1a, dir1);
copy_v3_v3(off2a, v->co);
madd_v3_v3fl(off2a, norm_perp2, e2->offset);
add_v3_v3v3(off2b, off2a, dir2);
@ -404,7 +409,7 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
copy_v3_v3(meetco, off1a);
}
else {
iret =isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2);
iret = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2);
if (iret == 0) {
/* lines colinear: another test says they are parallel. so shouldn't happen */
copy_v3_v3(meetco, off1a);
@ -426,10 +431,10 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
* from eh's direction. */
static void offset_in_plane(EdgeHalf *e, const float plane_no[3], int left, float r[3])
{
float dir[3], no[3];
float dir[3], no[3], fdir[3];
BMVert *v;
v = e->is_rev ? e->e->v1 : e->e->v2;
v = e->is_rev ? e->e->v2 : e->e->v1;
sub_v3_v3v3(dir, BM_edge_other_vert(e->e, v)->co, v->co);
normalize_v3(dir);
@ -444,11 +449,12 @@ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], int left, floa
no[1] = 1.0f;
}
if (left)
cross_v3_v3v3(r, no, dir);
cross_v3_v3v3(fdir, dir, no);
else
cross_v3_v3v3(r, dir, no);
normalize_v3(r);
mul_v3_fl(r, e->offset);
cross_v3_v3v3(fdir, no, dir);
normalize_v3(fdir);
copy_v3_v3(r, v->co);
madd_v3_v3fl(r, fdir, e->offset);
}
/* Calculate coordinates of a point a distance d from v on e->e and return it in slideco */
@ -563,100 +569,11 @@ static void get_point_on_round_edge(const float uv[2],
#else /* USE_ALTERNATE_ADJ */
#ifdef OLD_ROUND_EDGE
/*
* calculation of points on the round profile
* r - result, coordinate of point on round profile
* method:
* Inscribe a circle in angle va - v -vb
* such that it touches the arms at offset from v.
* Rotate the center-va segment by (i/n) of the
* angle va - center -vb, and put the endpoint
* of that segment in r.
*/
static void get_point_on_round_profile(float r_co[3], float offset, int k, int count,
const float va[3], const float v[3], const float vb[3])
{
float vva[3], vvb[3], angle, center[3], rv[3], axis[3], co[3];
sub_v3_v3v3(vva, va, v);
sub_v3_v3v3(vvb, vb, v);
normalize_v3(vva);
normalize_v3(vvb);
angle = angle_normalized_v3v3(vva, vvb);
add_v3_v3v3(center, vva, vvb);
normalize_v3(center);
mul_v3_fl(center, offset * (1.0f / cosf(0.5f * angle)));
add_v3_v3(center, v); /* coordinates of the center of the inscribed circle */
sub_v3_v3v3(rv, va, center); /* radius vector */
sub_v3_v3v3(co, v, center);
cross_v3_v3v3(axis, rv, co); /* calculate axis */
sub_v3_v3v3(vva, va, center);
sub_v3_v3v3(vvb, vb, center);
angle = angle_v3v3(vva, vvb);
rotate_v3_v3v3fl(co, rv, axis, angle * (float)k / (float)count);
add_v3_v3(co, center);
copy_v3_v3(r_co, co);
}
/*
* Find the point (/n) of the way around the round profile for e,
* where start point is va, midarc point is vmid, and end point is vb.
* Return the answer in profileco.
* Method:
* Adjust va and vb (along edge direction) so that they are perpendicular
* to edge at v, then use get_point_on_round_profile, then project
* back onto original va - vmid - vb plane.
* If va, vmid, and vb are all on the same plane, just interpolate between va and vb.
*/
static void get_point_on_round_edge(EdgeHalf *e, int k,
const float va[3], const float vmid[3], const float vb[3],
float r_co[3])
{
float vva[3], vvb[3], point[3], dir[3], vaadj[3], vbadj[3], p2[3], pn[3];
int n = e->seg;
sub_v3_v3v3(vva, va, vmid);
sub_v3_v3v3(vvb, vb, vmid);
if (e->is_rev)
sub_v3_v3v3(dir, e->e->v1->co, e->e->v2->co);
else
sub_v3_v3v3(dir, e->e->v2->co, e->e->v1->co);
normalize_v3(dir);
if (fabsf(angle_v3v3(vva, vvb) - (float)M_PI) > 100.f *(float)BEVEL_EPSILON) {
copy_v3_v3(vaadj, va);
madd_v3_v3fl(vaadj, dir, -len_v3(vva) * cosf(angle_v3v3(vva, dir)));
copy_v3_v3(vbadj, vb);
madd_v3_v3fl(vbadj, dir, -len_v3(vvb) * cosf(angle_v3v3(vvb, dir)));
get_point_on_round_profile(point, e->offset, k, n, vaadj, vmid, vbadj);
add_v3_v3v3(p2, point, dir);
cross_v3_v3v3(pn, vva, vvb);
if (!isect_line_plane_v3(r_co, point, p2, vmid, pn, 0)) {
/* TODO: track down why this sometimes fails */
copy_v3_v3(r_co, point);
}
}
else {
/* planar case */
interp_v3_v3v3(r_co, va, vb, (float)k / (float)n);
}
}
#else
/*
* Find the point (/n) of the way around the round profile for e,
* where start point is va, midarc point is vmid, and end point is vb.
* Return the answer in profileco.
/* Fill matrix r_mat so that a point in the sheared parallelogram with corners
* va, vmid, vb (and the 4th that is implied by it being a parallelogram)
* is transformed to the unit square by multiplication with r_mat.
* If it can't be done because the parallelogram is degenerate, return FALSE
* else return TRUE.
* Method:
* Find vo, the origin of the parallelogram with other three points va, vmid, vb.
* Also find vd, which is in direction normal to parallelogram and 1 unit away
@ -668,16 +585,14 @@ static void get_point_on_round_edge(EdgeHalf *e, int k,
* (1,1,0) -> vmid
* (1,0,0) -> vb
* (0,1,1) -> vd
* However if va -- vmid -- vb is approximately a straight line, just
* interpolate along the line.
*/
static void get_point_on_round_edge(EdgeHalf *e, int k,
const float va[3], const float vmid[3], const float vb[3],
float r_co[3])
* We want M to make M*A=B where A has the left side above, as columns
* and B has the right side as columns - both extended into homogeneous coords.
* So M = B*(Ainverse). Doing Ainverse by hand gives the code below.
*/
static int make_unit_square_map(const float va[3], const float vmid[3], const float vb[3],
float r_mat[4][4])
{
float vo[3], vd[3], vb_vmid[3], va_vmid[3], vddir[3], p[3], angle;
float m[4][4] = MAT4_UNITY;
int n = e->seg;
float vo[3], vd[3], vb_vmid[3], va_vmid[3], vddir[3];
sub_v3_v3v3(va_vmid, vmid, va);
sub_v3_v3v3(vb_vmid, vmid, vb);
@ -688,17 +603,43 @@ static void get_point_on_round_edge(EdgeHalf *e, int k,
add_v3_v3v3(vd, vo, vddir);
/* The cols of m are: {vmid - va, vmid - vb, vmid + vd - va -vb, va + vb - vmid;
* blender transform matrices are stored such that m[i][*] is ith column;
* the last elements of each col remain as they are in unity matrix */
sub_v3_v3v3(&m[0][0], vmid, va);
sub_v3_v3v3(&m[1][0], vmid, vb);
add_v3_v3v3(&m[2][0], vmid, vd);
sub_v3_v3(&m[2][0], va);
sub_v3_v3(&m[2][0], vb);
add_v3_v3v3(&m[3][0], va, vb);
sub_v3_v3(&m[3][0], vmid);
* blender transform matrices are stored such that m[i][*] is ith column;
* the last elements of each col remain as they are in unity matrix */
sub_v3_v3v3(&r_mat[0][0], vmid, va);
r_mat[0][3] = 0.0f;
sub_v3_v3v3(&r_mat[1][0], vmid, vb);
r_mat[1][3] = 0.0f;
add_v3_v3v3(&r_mat[2][0], vmid, vd);
sub_v3_v3(&r_mat[2][0], va);
sub_v3_v3(&r_mat[2][0], vb);
r_mat[2][3] = 0.0f;
add_v3_v3v3(&r_mat[3][0], va, vb);
sub_v3_v3(&r_mat[3][0], vmid);
r_mat[3][3] = 1.0f;
/* Now find point k/(e->seg) along quarter circle from (0,1,0) to (1,0,0) */
return TRUE;
}
else
return FALSE;
}
/*
* Find the point (/n) of the way around the round profile for e,
* where start point is va, midarc point is vmid, and end point is vb.
* Return the answer in profileco.
* If va -- vmid -- vb is approximately a straight line, just
* interpolate along the line.
*/
static void get_point_on_round_edge(EdgeHalf *e, int k,
const float va[3], const float vmid[3], const float vb[3],
float r_co[3])
{
float p[3], angle;
float m[4][4];
int n = e->seg;
if (make_unit_square_map(va, vmid, vb, m)) {
/* Find point k/(e->seg) along quarter circle from (0,1,0) to (1,0,0) */
angle = (float)M_PI * (float)k / (2.0f * (float)n); /* angle from y axis */
p[0] = sinf(angle);
p[1] = cosf(angle);
@ -706,11 +647,47 @@ static void get_point_on_round_edge(EdgeHalf *e, int k,
mul_v3_m4v3(r_co, m, p);
}
else {
/* planar case */
/* degenerate case: profile is a line */
interp_v3_v3v3(r_co, va, vb, (float)k / (float)n);
}
}
#endif /* ! OLD_ROUND_EDGE */
/* Calculate a snapped point to the transformed profile of edge e, extended as
* in a cylinder-like surface in the direction of e.
* co is the point to snap and is modified in place.
* va and vb are the limits of the profile (with peak on e). */
static void snap_to_edge_profile(EdgeHalf *e, const float va[3], const float vb[3],
float co[3])
{
float m[4][4], minv[4][4];
float edir[3], va0[3], vb0[3], vmid0[3], p[3], snap[3];
sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co);
normalize_v3(edir);
/* project va and vb onto plane P, with normal edir and containing co */
closest_to_plane_v3(va0, co, edir, va);
closest_to_plane_v3(vb0, co, edir, vb);
project_to_edge(e->e, va0, vb0, vmid0);
if (make_unit_square_map(va0, vmid0, vb0, m)) {
/* Transform co and project it onto the unit circle.
* Projecting is in fact just normalizing the transformed co */
if (!invert_m4_m4(minv, m)) {
/* shouldn't happen, by angle test and construction of vd */
BLI_assert(!"failed inverse during profile snap");
return;
}
mul_v3_m4v3(p, minv, co);
normalize_v3(p);
mul_v3_m4v3(snap, m, p);
copy_v3_v3(co, snap);
}
else {
/* planar case: just snap to line va--vb */
closest_to_line_segment_v3(p, co, va, vb);
copy_v3_v3(co, p);
}
}
#endif /* !USE_ALTERNATE_ADJ */
@ -748,7 +725,9 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv)
slide_dist(e->next, bv->v, e->offset, co);
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = v->elast = e->next;
vm->mesh_kind = M_POLY;
e->next->leftv = e->next->rightv = v;
/* could use M_POLY too, but tri-fan looks nicer)*/
vm->mesh_kind = M_TRI_FAN;
return;
}
@ -839,7 +818,6 @@ static void build_boundary(MemArena *mem_arena, BevVert *bv)
else {
vm->mesh_kind = M_ADJ;
}
/* TODO: if vm->count == 4 and bv->selcount == 4, use M_CROSS pattern */
}
/*
@ -852,9 +830,11 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
VMesh *vm = bv->vmesh;
BoundVert *v, *vprev, *vnext;
NewVert *nv, *nvprev, *nvnext;
EdgeHalf *e1, *e2, *epipe;
BMVert *bmv, *bmv1, *bmv2, *bmv3, *bmv4;
BMFace *f;
float co[3], coa[3], cob[3], midco[3];
float va_pipe[3], vb_pipe[3];
#ifdef USE_ALTERNATE_ADJ
/* ordered as follows (orig, prev, center, next)*/
@ -873,6 +853,29 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
ns = vm->seg;
ns2 = ns / 2;
BLI_assert(n > 2 && ns > 1);
/* special case: two beveled edges are in line and share a face, making a "pipe" */
epipe = NULL;
if (bv->selcount > 2) {
for (e1 = &bv->edges[0]; epipe == NULL && e1 != &bv->edges[bv->edgecount]; e1++) {
if (e1->is_bev) {
for (e2 = &bv->edges[0]; e2 != &bv->edges[bv->edgecount]; e2++) {
if (e1 != e2 && e2->is_bev) {
if ((e1->fnext == e2->fprev) || (e1->fprev == e2->fnext)) {
float dir1[3], dir2[3];
sub_v3_v3v3(dir1, bv->v->co, BM_edge_other_vert(e1->e, bv->v)->co);
sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, bv->v)->co, bv->v->co);
if (angle_v3v3(dir1, dir2) < 100.0f * (float)BEVEL_EPSILON) {
epipe = e1;
break;
}
}
}
}
}
}
}
/* Make initial rings, going between points on neighbors.
* After this loop, will have coords for all (i, r, k) where
* BoundVert for i has a bevel, 0 <= r <= ns2, 0 <= k <= ns */
@ -943,6 +946,12 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
get_point_on_round_edge(v->ebev, k, coa, midco, cob, co);
copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co);
}
if (v->ebev == epipe) {
/* save profile extremes for later snapping */
copy_v3_v3(va_pipe, mesh_vert(vm, i, 0, 0)->co);
copy_v3_v3(vb_pipe, mesh_vert(vm, i, 0, ns)->co);
}
#endif
}
} while ((v = v->next) != vm->boundstart);
@ -968,6 +977,9 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
nv = mesh_vert(vm, i, ring, k);
nvprev = mesh_vert(vm, vprev->index, k, ns - ring);
mid_v3_v3v3(co, nv->co, nvprev->co);
if (epipe)
snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
#endif
@ -1017,6 +1029,8 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
nvnext = mesh_vert(vm, vnext->index, ns2, k);
if (vprev->ebev && vnext->ebev) {
mid_v3_v3v3v3(co, nvprev->co, nv->co, nvnext->co);
if (epipe)
snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
#endif
@ -1027,6 +1041,8 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
}
else if (vprev->ebev) {
mid_v3_v3v3(co, nvprev->co, nv->co);
if (epipe)
snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
#endif
@ -1037,6 +1053,8 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
}
else if (vnext->ebev) {
mid_v3_v3v3(co, nv->co, nvnext->co);
if (epipe)
snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
#endif
@ -1064,6 +1082,8 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
}
} while ((v = v->next) != vm->boundstart);
mul_v3_fl(midco, 1.0f / nn);
if (epipe)
snap_to_edge_profile(epipe, va_pipe, vb_pipe, midco);
bmv = BM_vert_create(bm, midco, NULL, 0);
v = vm->boundstart;
do {
@ -1275,39 +1295,27 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv)
EdgeHalf *eh_b = next_bev(bv, eh_a->next); /* since (selcount == 2) we know this is valid */
BMLoop *l_a = BM_face_vert_share_loop(f, eh_a->rightv->nv.v);
BMLoop *l_b = BM_face_vert_share_loop(f, eh_b->leftv->nv.v);
int seg_count = bv->vmesh->seg; /* ensure we don't walk past the segments */
int split_count = bv->vmesh->seg + 1; /* ensure we don't walk past the segments */
if (l_a == l_b) {
/* step once around if we hit the same loop */
l_a = l_a->prev;
l_b = l_b->next;
seg_count--;
}
BLI_assert(l_a != l_b);
while (f->len > 4) {
while (f->len > 4 && split_count > 0) {
BMLoop *l_new;
BLI_assert(l_a->f == f);
BLI_assert(l_b->f == f);
BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, FALSE);
if (seg_count-- == 0) {
break;
if (l_a-> v == l_b->v || l_a->next == l_b) {
/* l_a->v and l_b->v can be the same or such that we'd make a 2-vertex poly */
l_a = l_a->prev;
l_b = l_b->next;
}
else {
BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, FALSE);
f = l_new->f;
/* turns out we don't need this,
* because of how BM_face_split works we always get the loop of the next face */
#if 0
if (l_new->f->len < l_new->radial_next->f->len) {
l_new = l_new->radial_next;
/* walk around the new face to get the next verts to split */
l_a = l_new->prev;
l_b = l_new->next->next;
}
#endif
f = l_new->f;
/* walk around the new face to get the next verts to split */
l_a = l_new->prev;
l_b = l_new->next->next;
split_count--;
}
}
}

@ -589,7 +589,7 @@ void MeshImporter::read_lines(COLLADAFW::Mesh *mesh, Mesh *me)
for (int i = 0; i < edge_count; i++, med++) {
med->bweight = 0;
med->crease = 0;
med->flag = 0;
med->flag |= ME_LOOSEEDGE;
med->v1 = indices[2 * i];
med->v2 = indices[2 * i + 1];
}

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