1
1

Compare commits

...

156 Commits

Author SHA1 Message Date
a377a7edf6 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r32300:32571 2010-10-19 00:45:37 +00:00
08232350d5 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r32200:32300 2010-10-18 02:43:53 +00:00
5b31d545df svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r31926:32200 2010-10-18 01:10:35 +00:00
9e7142e2b0 == Multires ==
Fixed a crash when drawing without ptex
2010-09-14 23:41:11 +00:00
7eec372df3 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r31833:31926 2010-09-14 23:37:58 +00:00
72b7528388 == Multires ==
Drawing optimization for VBO: only create one index buffer object for a single grid level
2010-09-14 22:33:29 +00:00
1e24fceb5d == Ptex ==
Missed a conflict in my last merge
2010-09-10 17:54:52 +00:00
716647d394 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r31667:31833 2010-09-09 04:07:28 +00:00
f2ba2f5d87 == Ptex ==
* Fix blur tool on mesh border
2010-09-06 00:07:01 +00:00
b972793aaf == Ptex ==
* Fixed blurring brush to work with ptex
* Added a convert operator to convert ptex data between 8-bit, 16-bit, and float

Still has some issues; blurring 8-bit data darkens it, and there are small seams between tiles
2010-09-05 19:10:11 +00:00
a81177545e svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r31488:31667 2010-08-30 19:06:15 +00:00
fa9bfe2a61 == Ptex ==
* Added subface hiding and subface masking to ptex edit mode
* Added hotkeys and menu items (HKEY and alt+HKEY for hiding and unhiding, MKEY and alt+MKEY for masking and unmasking)
2010-08-21 04:45:28 +00:00
19746b8979 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r31296:31488 2010-08-21 04:06:07 +00:00
dd972441a9 == Ptex ==
Resolution editing works now with VBO enabled
2010-08-21 03:09:20 +00:00
e926f32f3b == Ptex ==
Enabled VBO drawing for ptex paint
2010-08-21 00:31:08 +00:00
a7bb0ff8f6 == Ptex ==
* added an operator for removing the active ptex layer
* added a save operator for ptex layers. Note that it doesn't save adjacency data yet (doesn't affect painting, but needed for renderer filtering)
2010-08-20 23:39:08 +00:00
9d24cebdcc == Ptex ==
Fixed grid artifacts when painting on subdivided mesh
2010-08-20 02:58:58 +00:00
da9ff99007 == Ptex ==
* Moved ptex loading and resolution changing into BKE ptex
* Renamed "vpaint" stuff to paint ptex and moved it into paint_ptex.c
2010-08-19 23:07:43 +00:00
bb61af7b42 == Ptex ==
Brought back ptex resolution editing

Improvements:
* For nonquads, subfaces can now be directly selected, so there's no need to display multiple resolutions for triangles
* Display and selection use the same pbvh as for painting, so for example subsurf shows correctly
2010-08-19 21:11:48 +00:00
4b2a0e65ad == Ptex ==
Missed a file
2010-08-19 12:50:40 +00:00
a8fc0361c9 == Ptex ==
Changed the internal ptex format to always use subfaces

* Changed MPtex to references MPtexSubfaces, each of which is a quad with U and V resolution and it's own ptex data pointer.
* This format is basically the same as what triangles were already using, but now quads work the same way.
* This format is also closer to the way multires grid data was already stored.
* Ptex loading (and saving, once that's implemented) requires some extra work to convert to the internal format, but everywhere else the code is much simpler.
* Fixed undoing ptex changes on a different multires level from where they were painted.
* Ptex paint now always uses an all-quad DM (generated with one level of ccgdm simple subsurf.) This is a bit ugly, just stuck on the end of calc_mesh_modifiers. This is only done if there's no multires or subsurf modifier at the end of the stack.
* Resolution editing is disabled for now, will restore it in next commit
2010-08-18 23:59:26 +00:00
22b6f0cd52 Merged GPUDrawFlags into DMDrawFlags, cleaned up DMDrawFlags 2010-08-18 22:08:45 +00:00
8765be1bfe == Ptex ==
For ptex-resolution editing mode, show a tiled pattern representing ptex texels.
2010-08-13 05:59:24 +00:00
bfea9c12a1 == Ptex ==
Fixed anchored and drag dot stroke modes.

* Vpaint mesh restore
2010-08-13 01:59:42 +00:00
ac1b780577 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r31183:31296 2010-08-12 18:08:22 +00:00
e21cdfa4a8 == Ptex ==
Controls for setting local ptex resolution

* Fixed various problems preventing the old paint mask mode from showing correctly, repurposed it for editing ptex resolution
* Added an operator that resizes a ptex face (uses bilinear interpolation)
* Added a new ptex panel that only shows in paint mask mode
** Two buttons, Half and Double, that cut the U/V resolutions in half or double them, for all selected faces
** For more precise control, the U and V resolutions can be individually selected for a single face
** For triangles, the resolution of individual subfaces can be set
** Lastly, the resolution of the active face is shown (one resolution for each subface)
** The UI is not good, but the underlying code is there at least.
2010-08-12 17:37:36 +00:00
9a49c92059 Fixed some python merge errors in my branch. 2010-08-09 21:54:17 +00:00
62f8fbc87f == Ptex ==
* Enabled undo for multires
* Changed texture interpolation to linear
2010-08-09 21:48:13 +00:00
488a28336b == Ptex ==
Accidentally left in a statement before declaration error
2010-08-09 15:29:33 +00:00
079d77b9f8 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r31091:31183 2010-08-09 03:21:30 +00:00
7906ff6924 == Ptex ==
* Enabled drawing of ptex on a multires mesh
* Enabled ptex painting on a multires mesh

Note that the multires level doesn't effect the ptex resolution; multires has no effect on ptex other than making the display smoother.
2010-08-09 01:20:13 +00:00
1f1d2e27f2 == VPaint ==
Removed a bunch of unused code
2010-08-07 00:33:53 +00:00
bf47cf4b57 == Ptex ==
Undo support
2010-08-06 23:16:31 +00:00
8970423d2a == Ptex ==
* Removing some old vpaint/multires stuff that is obseleted by ptex
2010-08-06 21:21:01 +00:00
3227dbc9fb == Paint ==
* Missed a few things in my last commit
2010-08-06 20:04:37 +00:00
44b1294f24 == Paint ==
Paint overlay

* Added a new vpaint input that samples an image rather than using the
  brush color

* The image is displayed as a translucent overlay in vpaint mode
** Can be toggled on and off in the UI or with IKEY

* A color can be marked as transparent so that it will not affect the
  brush color
** There's a tolerance value to set how close colors have to be to the
   transparency color

* The image overlay can be moved with G/S/R when its enabled

* For now only enabled in vpaint mode, should be enabled for texpaint too
2010-08-06 19:51:23 +00:00
f36b5666a7 == Ptex ==
Fixed unitialized variable reported by mariusz
2010-08-06 15:58:15 +00:00
3c2f4416d5 == Ptex ==
* Small bugfix for my previous commit, broke ptex generation
2010-08-06 05:57:23 +00:00
893afe0e84 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30887:31091 2010-08-06 04:55:32 +00:00
7d84048df6 == Ptex ==
Fixes for triangles

* the quad-mesh-with-triangles example file from ptex contains subfaces with
  non-matching resolutions; changed the internal MPtex format to store
  separate resolutions for each subface

* changed ptex drawing to give each subface its own texture

* various fixes to the loading and painting code to support triangles

* small change to the ptex build files, hopefully fixes and MSVC issue
2010-08-06 04:16:13 +00:00
847a581e34 == Ptex ==
Another scons fix provided by mariusz
2010-08-05 20:16:38 +00:00
84c346a45d == Ptex ==
Cmake fix from mariusz.
2010-08-05 19:20:00 +00:00
44e9f0c40d == Ptex ==
Missed a file in my last commit
2010-08-05 14:03:30 +00:00
3e8c3c8f15 == Ptex ==
Hopefully fixes building with scons
2010-08-05 01:42:34 +00:00
04e6a8c7a2 == Ptex ==
initial ptex integration

* added the ptex C++ library to extern

* wrote a small C api for the library; just the functions I've used so
  far are in the C api, but easy to add more

* added a new CustomData type (face data), stored as struct MPtex

* added RNA for CD_MPTEX

* each MPtex stores:
** the U- and V-resolution (always a power of two)
** the number of color channels (e.g. RGB or RGBA)
** the data type (can be bytes, shorts, or floats)
** the number of subfaces (for triangles now, will work also for ngons)

* for drawing ptex, one power of two texture is assigned to each face
** for quads, the texture is mapped normally across the full face
** for triangles, the face is split into four quads for drawing, and each
   subface gets an equal-sized portion of the texture
** the texture is created with the same internal format as the ptex layer

* added an operator for loading ptex files

* added an operator for creating ptex layers; takes data type, number of
  channels, and texel density as inputs. has some hackish code to allocate
  texels based on a faces catmull-clark limit surface area

* added a simple ptex UI, shows ptex layers in the mesh data panel

* modified vpaint to paint on ptex instead of mcols


partial todo list:
* VBO drawing (make sure to turn VBO off before testing ptex for now)
* ptex saving
* better texel allocation
* upsampling/downsampling faces
* UI for setting individual faces' resolutions
2010-08-05 00:53:02 +00:00
d4f91858f2 == VPaint ==
Bugfix: force update multires vpaint before saving the file
2010-08-02 03:03:54 +00:00
ddcfb4601a == Multires ==
* Separate mdisp re-allocation from customdata realloc
2010-07-31 00:15:17 +00:00
f220e4a3c3 == VPaint/Multires ==
Added a function to apply multires colors as regular mcols; used when applying multires modifier and rendering
2010-07-30 23:45:40 +00:00
c227e25b28 == VPaint ==
* Added an operator to convert vcols to texture; works for multires vcols too
* Still has some seam issues, need to do more intelligent bleeding
* Current UI is a menu item in the Image menu (Vertex Colors to Texture)
2010-07-30 22:10:34 +00:00
94e47bfc4c == Paint ==
* Refactored paint mask undo to support any customdata type
* Automatically make layer multires when adding vcols to a multires mesh in vpaint mode
* Fixed vcol multires toggle so that it updates the dm

TODO:
* Add paint undo for vcol layers
2010-07-30 15:20:07 +00:00
9688dd9a2a svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30846:30887 2010-07-30 05:51:32 +00:00
49b9e09a05 == VPaint ==
* Switched vpaint to use paint/pbvh undo system

TODO:
* Undo for adding/removing color layers
2010-07-30 01:27:38 +00:00
390a6c691c == Paint/PBVH ==
Undo refactor

* Renamed sculpt_undo.c to pbvh_undo.c
* Modified node push take a flag (PBVHUndoFlag) that controls what data gets pushed
* Changed sculpt code to only push coords, changed masking to only push paint masks
* Added undo code to save/restore mcols too, but not used yet
* Fixed a weight paint crash
2010-07-30 00:55:37 +00:00
6806c315b2 == VPaint ==
More fixes and cleanups

* Removed unused parameters in vpaint
* Use more of paint stroke in vpaint
* Partial fix of anchored brush in vpaint, doesn't restore colors yet though
* Fixed smooth stroke

TODO:
* Color restore for vpaint
2010-07-29 03:20:37 +00:00
0dbb7dd293 == VPaint ==
* Bugfix: don't start until mouse goes over the mesh
2010-07-29 01:16:40 +00:00
1cacc6f9ea == Paint ==
* Moved a bunch more sculpt stroke stuff into paint stroke
* Made all the sculpt stroke UI visible for vpaint too
* Most of sculpt's stroke features work in vpaint now

TODO:
* Drag dot for vpaint
* Anchored for vpaint
* Smooth stroke broken
2010-07-29 00:47:10 +00:00
ef18a05d51 == Multires ==
* Fixed a memory leak when deleting multires data
2010-07-28 20:27:56 +00:00
68b4ecd28e svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30795:30846 2010-07-28 20:23:10 +00:00
3f7c3fad07 == Paint ==
* More texture refactoring; brush texture symmetry now works properly in sculpt mode again, also works in vpaint now.

TODO:
* Fixed texture mode doesn't work in vpaint
* Anchored brush needs updating
2010-07-28 19:43:48 +00:00
6b8f3f475b == PBVH ==
* Some interface cleanups, should be no functional changes
2010-07-28 17:26:56 +00:00
7e2b206ca5 == PBVH ==
Note to testers: if you couldn't see colors or masks before, this should fix it.

* Updated non-VBO drawing for colors; paintmasks and vertex colors should now work OK with VBO disabled (or for OOM condition)
2010-07-28 16:46:49 +00:00
b94be08123 == VPaint ==
* Fixed going into edit mode losing multires color data
2010-07-28 14:42:03 +00:00
aacaea02f5 == VPaint ==
* Blur brush works for multires now
2010-07-28 06:38:24 +00:00
a9c8547550 == VPaint ==
* Implemented blur brush for non-multires models
2010-07-28 05:41:32 +00:00
e33fd64f24 == VPaint ==
* Removed some code cruft and out of date comments
2010-07-28 02:06:42 +00:00
8de0a82727 == Paint ==
* Replaced sd->flags with paint->flags
2010-07-28 00:39:12 +00:00
430ae43ccf == Paint ==
* Changed SCULPT_USE_OPENMP to PAINT_USE_OPENMP
2010-07-28 00:34:04 +00:00
c352b580ac == VPaint ==
VPaint symmetry enabled. Made a lot of changes here; hopefully nothings broken as a result.

* Sculpt had a ton of symmetry code; moved most of it into the PaintStroke system
** Added a couple new PaintStroke callbacks, one for updating symmetry data in case a paint mode has local data that needs to be flipped or rotated (sculpt does), and one for applying a brush action (one brush action per symmetry "dab")
* Ported sculpt's symmetry code to the new system
* Added symmetry support to vpaint

TODO:
* Symmetry for brush textures still needs to be updated
2010-07-27 23:46:09 +00:00
01105dd937 == VPaint ==
Masking for vpaint

* Enabled combined display of masks and vertex colors
* Added mask painting to vpaint
* VPaint factors masks into strength
* Added functions in BKE paint to find the combined mask value for an element

TODO:
* Because vpaint doesn't have proper undo yet, and mask painting is shared between sculpt and vpaint, undoing the effects of the mask brush is disabled for now.
2010-07-27 19:56:16 +00:00
99a161fa0c == VPaint ==
* Changed add vcol operator to not duplicate previous layer's data
* Updated pbvh mesh drawing to work with layers (still requiring VBO though)
2010-07-27 07:50:03 +00:00
7262769ec3 == VPaint ==
* Merged the two alpha brushes into one, added RNA/UI for switching between adding and erasing alpha
2010-07-27 07:17:01 +00:00
3440d5217f svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30764:30795 2010-07-27 06:48:09 +00:00
d29f55bc40 == Sculpt ==
* Removed the mask brush, replaced with a BRUSH_MASK flag
* Added RNA/UI for that (UI is a checkbox in the brush panel)

TODO:
* For now, all brushes behave the same in mask mode; some brushes should have special behavior (e.g. smooth should smooth the mask)
2010-07-27 05:53:28 +00:00
6db17c557f == VPaint ==
* Enabled fast navigate option for vpaint
* Moved fast navigate UI button back to options panel for now
* Fixed vpaint partial redraw, wasn't actually passing the redraw planes in
2010-07-27 05:38:26 +00:00
c2d656d3d2 == Sculpt ==
* Added back mask brush, accidentally removed during last merge
* Removed an incorrect assert in paint mask
2010-07-27 00:09:25 +00:00
4635e0f3e2 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30722:30764 2010-07-27 00:03:02 +00:00
3d0afea083 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30668:30722 2010-07-26 16:48:02 +00:00
bdc929ea6b == Sculpt/Paint ==
* Fixed a crash on loading files with a paint mode active
* Fixed a type warning
2010-07-26 05:44:34 +00:00
ef74fc391d == VPaint ==
Enabled textures for vpaint brushes. Not all of the texture options work yet.
2010-07-25 05:01:55 +00:00
164e552e81 == VPaint ==
* Updated non VP_AREA painting for both regular and multires meshes. Still looks bad because of drawing issues though.
2010-07-25 01:36:47 +00:00
2b5d510e94 == VPaint ==
* Re-enabled all the vpaint tools except for blur
* Also added alpha blending modes
* Removed dead code

TODO:
* Combine the add and erase alpha modes, only separate for now to match the IMB_BLEND modes more easily
2010-07-25 00:19:18 +00:00
26aad77d26 == VPaint ==
Removed non-PBVH vpaint.
2010-07-24 21:23:15 +00:00
cf2b3db4d9 == Multires ==
* Renamed Sculpt Level to Edit Level (works now for vpaint too)
2010-07-24 20:49:10 +00:00
22c4ad34fe == Multires/VPaint ==
Enable multires painting.

* Added operator/RNA/UI to toggle multires for vertex colors. (UI is not great right now, just a button in mesh data properties.)
* Added layer names to GridKey. These are used (in combination with CD type) to identify the source layer from CustomData.
* Changed default mcol to white with alpha=0
* Renamed CD_FACEGRID to CD_GRIDS, removed CD_DISP
* Added a new CustomDataMultires type (CD_GRIDS), which stores layered data like CustomData. However, it only stores float types, and is very simplified.
* Reworked PaintMask to use the new CD multires stuff, also used for vertex colors.
* Started changing vpaint to internally use floats.
* Layering support for multires vpaint. Layer alpha is used to combine the output.

TODO:
* Doesn't handle layer renaming yet (so if you rename your mcol layer, it'll disassociate from the multires data)
* Layers for non-multires vpaint
* Default mcol layer in the startup blend has full alpha, so for testing layers you have to delete the default mcol layer and add new ones.
* Multires level in vpaint is controlled by the Preview level
2010-07-24 20:33:35 +00:00
a36f3c5cbf == PBVH ==
* Moved glShadeModel from pbvh.c to gpu_buffers.c, also fixes bad include of glew
2010-07-24 18:32:57 +00:00
a2a1c111a5 == Multires ==
Some refactoring to support vpaint

* For multires_mark_as_modified, make sure the DM is a CCGDM first
* Make the gridkey a parameter to various functions, rather than using the same one everywhere.
** Most important, when doing a multires update, enforces use of the same gridkey as the DM its updating from.
2010-07-24 18:05:33 +00:00
ac212f1cd0 == VPaint ==
Added partial redraw to vpaint.

Updated the PBVH docs in the wiki to include some info about partial redraw:
http://wiki.blender.org/index.php/Dev:2.5/Source/Modeling/PBVH#Partial_Redraw

* Moved some sculpt-pbvh functions to paint_util for general use
** sculpt_get_redraw_rect -> paint_get_redraw_rect
** sculpt_get_redraw_planes -> paint_get_redraw_planes
** Some of the code from sculpt_flush_update is now paint_tag_partial_redraw
* Added some debugging code to show the area being redraw during partial redraw
** Draws a box around the area being updated
** Set rt to 444 to see it
2010-07-24 17:18:42 +00:00
ca227a94ac == Sculpt ==
Fix for some brushes exploding

* Replaced partial initialization of pbvh iterator with memset (this was how it was originally, probably changed after merging from trunk some time I guess)
2010-07-23 21:08:27 +00:00
aa6935890a svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30563:30668 2010-07-23 20:06:59 +00:00
7a6b98b5c2 == Multires ==
Small bug fixes

* When dropping down to multires level zero in sculpt mode, update PBVH from the CDDM
* When checking for modifiers in sculpt, ignore multires on level zero
2010-07-23 19:08:05 +00:00
6f4039ec1d svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30510:30563 2010-07-21 03:43:38 +00:00
c16049ab5c == VPaint ==
Work-in-progress, vpaint + multires. This commit just adds gpu drawing and vpaint editing of the multires colors through the PBVH. The colors aren't stored or subdivided yet though, so as soon as you switch levels or otherwise rebuild the PBVH the painted colors will disappear.
2010-07-21 00:47:19 +00:00
5c51671227 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30325:30510 2010-07-19 22:05:25 +00:00
bf22acbaff svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30324:30325
Nasty merge conflicts in editors/sculpt_paint, probably made some mistakes. Will finish merging to latest trunk before fixing bugs though.
2010-07-19 20:52:33 +00:00
7b480e34fd svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r30167:30324 2010-07-16 23:06:48 +00:00
b0deed9cf8 Changed glew include from "" to <> 2010-07-11 02:30:18 +00:00
b65d0c1b11 == New VPaint ==
* Make disabling All Faces option work. This is a little different from old vpaint, but basically it just fills in whatever face is under the brush. Unlike old vpaint, all corners are filled the same way.
* Display of this feature isn't too good right now. It may look like the colors are being assigned to the wrong face, or not at all. This is just due to the way VBOs are being filled though; switching temporarily to old vpaint shows the colors are on the correct face.
2010-07-11 01:11:21 +00:00
a6f2dec7e1 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r29912:30167 2010-07-10 06:03:27 +00:00
0eadc41ad3 * VPaint brush strength works again
* Finally fixed the mesh-turns-orange problem with glColorMaterial
2010-07-10 04:48:38 +00:00
5352328af0 Begin updating vpaint to use the PBVH
* Added a new flag (plus RNA/UI) to switch between old vpaint and new vpaint
* For new vpaint, draw using the PBVH. Lighting is enabled for new vpaint.
* Note that the full model is still being redrawn, partial redraw isn't enabled yet.
* For new vpaint, use the PBVH to determine which faces to paint on. Only mix brush works right now.
2010-07-09 21:27:29 +00:00
7167f3b75a Some more changes for improving non-sculpt paint modes:
• Add face customdata to the pbvh
• Return more data from BLI_pbvh_node_get_faces
• Add some drawing flags for the pbvh/VBO drawing code
• Some initial support for drawing mesh colors (not used yet)
• Abstracted sculpt's get_location a bit so it can be used for other types of paint strokes
• Moved and renamed unproject_brush_radius so other paint modes can use it
• There should be no visible changes from this commit
2010-07-07 22:55:57 +00:00
8514290319 Some preparation for accelerating other paint modes than sculpt
* Replaced Object.sculpt with Object.paint. This new PaintSession type for now just contains the PBVH so it can be built more or less the same for different paint modes. It also contains the old SculptSession data.
* Removed a couple of unused fields from SculptSession.
* Changed a lot of sculpt functions to pass around the Object rather than SculptSession; made sense anyway because we added an Object field to SculptSession to work around that problem.
* There should be no visible changes from this commit.
2010-07-07 19:11:55 +00:00
2e0f477510 Experimental feature, multires apply base, as suggested by renderdemon
* Attempts to fix the "spike" problem with multires
* For example, take the grab brush and pulling a large chunk of the mesh around will create ugly spikes at lower levels
* Another problem is that a multires mesh heavily changed in sculpt mode will still have the original shape in editmode, which might not be very useful
* Solution here is a new operator "Apply Base" that modifies the mesh to conform better to the sculpt multires mesh.
* Like applying the modifier, this changes actual mesh data, not disps
* Some attempt is made to avoid shrinking the base mesh too much, but the algorithm used is just my guess based on how catmull clark behaves
* So far as I know there are no published algorithms for correctly reversing catmull clark when the subdivided mesh has been deformed
2010-07-05 06:28:53 +00:00
48e04c1f84 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r29790:29912 2010-07-04 02:08:39 +00:00
e34405e64a * Added DNA/RNA/UI for enabling and disabling mask layers. 2010-07-03 07:07:54 +00:00
9ba3a1827f Added a new mask operator to create a mask from a texture.
* Moved get_texture value out of MOD_util and into BKE texture
* Added a new pbvh function similar to get_grids but for faces
* The new operator should work for ORCO and UV mapping
* UI is just a new menu item in the drop-down menu next to the texture slots list
* Also fixed a crash in the mask_set operator where sculpt's PBVH wasn't updated
2010-07-03 06:34:07 +00:00
3c822fb348 * Fixed masks not updating after undo 2010-07-03 05:31:06 +00:00
7f32239475 Make mask opacity actually do something; I had forgotten to update the PBVH iterator to take mask opacity into account. 2010-07-02 18:18:11 +00:00
77d68836f4 Made mask layer's opacity adjustable.
* Added a new "strength" field to CustomDataLayer, set to 1 by default.
* Added RNA for strength; the update function is ugly, commented in the file
* Added a slider control to adjust strength
2010-07-02 01:29:10 +00:00
cccf56b0cf Some cleanups and optimizations for masks:
* Mesh/grid VBO buffers can now be updated separately for coord/normal data and mask data
* Added a typedef for GPU_Buffers so we don't have the void* cast
* Changed the PBVH update to allow separate updating of mask data
* Fixed a memory leak for the mask_set operator
2010-07-02 00:38:04 +00:00
b1414eb7a1 * Moved subsurf grid stuff into it's own header file
* Changed gridkey in CCGSubsurf to not be dynamically allocated
* Fixes at least one small memory leak
2010-06-30 18:16:52 +00:00
a7fb2aba9d svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r29583:29790 2010-06-29 16:55:04 +00:00
854da3194e Fixed paint masks + multires going into and out of editmode; wasn't setting the right number of grid elements when copying face grids. 2010-06-29 15:38:19 +00:00
443e61c096 Fixed uninitialized variable. 2010-06-29 03:06:59 +00:00
2358843670 Multires+mask bugfixes:
* Crash when changing modes from sculptmode
* Crash when adding multires modifier on a mesh that already has paintmask layers
* Smooth brush eating holes in a mesh without a paintmask layer
2010-06-28 21:12:32 +00:00
848b944baa Added undo pushes for the mask_set operator. Also removed a bunch of old crufty declarations in sculpt_intern.h. 2010-06-24 00:53:11 +00:00
a1b8ce5f42 Enabled multiple paint mask layers for both regular and multires meshes.
* Iteration over vertices in the PBVH now has two mask components, the active mask, which is editable by the mask brush, and the combined mask, which adds all the mask layers together (clamped to [0,1]), and is used to mask off other brushes
* Layer adds and removes are handled by the paint undo system used in sculpt mode
* Added a new customdata function that adds a layer at an offset (into other layers of its type.)
2010-06-23 23:29:35 +00:00
0dbfec0adc More changes in prepping for mask layers:
* Reversed direction of mask strength
* Changed subsurf_make_derived_from_derived to take a gridkey parameter, or NULL for the default key (just coords + normals)
2010-06-21 19:46:23 +00:00
c783060f35 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r29453:29583 2010-06-21 05:37:12 +00:00
07f2354524 * Added paint mask mask to editmode mask so it's not destroyed when going into editmode. 2010-06-20 18:55:31 +00:00
d07b5501df * Added mesh rna for paint masks
* Added operators to add/remove paint mask layers
* Added UI to select paint mask layer and add/remove

Note that this commit doesn't include the code for actually using multiple layers in sculpt mode.
2010-06-20 17:42:24 +00:00
ed08eb6132 * Added/clarified some comments in customdata, make it clearer what some of the layer accessor functions do. 2010-06-20 01:13:17 +00:00
e73938d51f * Changed a couple mesh functions to make them public within the editors module 2010-06-19 23:54:22 +00:00
e8e7b42535 * Change default mask layer name to "Mask". 2010-06-19 23:37:12 +00:00
d8301f9053 * Changed gridkey to be a struct rather than an int. Has fields for the total number of each type it contains (types currently being coords, masks, normals.)
* This is a step towards having multiple layers of coords or masks.
* Should be no visible change in behavior from this commit.
2010-06-18 03:28:27 +00:00
888691bc81 Added undo for masks in sculpt. 2010-06-17 06:19:07 +00:00
55064b567c Bugfix: sculpting along the boundary between hidden areas and unhidden areas on a multires could leave cracks when things were unhidden. Fixed with a call to stitch grids. 2010-06-17 03:56:15 +00:00
c992b9d9e5 Several bug fixes:
* Added layerFree_grid to fix leaked memory when freeing CD_FACEGRID
* Added layerCopy_grid to fix copying a multires mesh and having masks not transfer over
* Added writing for CD_PAINTMASK layer
* Added writing and reading for CD_FACEGRID
2010-06-17 02:11:00 +00:00
2c23650ce7 Brought back hiding parts of the mesh in sculpt mode in proper 2.5-style. (No more ugly reordering of mesh elements leading to mesh corruption!)
UI changes:
* Ctrl+Alt brings up a border select you can hide a rectangular area of the mesh with.
* Ctrl+Shift is the same, but hides the area outside of the rectangle.
* Clicking without dragging while holding either Ctrl+Alt or Ctrl+Shift will re-show hidden areas.
* Added these three operations to the Sculpt menu.

Hiding areas is done by rebuilding the PBVH and excluding primitives based on whether their AABB intersects the user-selected areas. Note that for multires meshes, the primitives are grids, not faces, so if you are bad and use multires on a plain cube, there are only 6*4 grids that can be hidden.

TODO:
* Applying multires temporarily shows hidden areas. Once you start sculpting they hide themselves again. Same for turning off display of multires modifier.
* Going to multires level zero also shows hidden areas improperly.
2010-06-16 04:55:06 +00:00
51d0d0b895 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r29389:29453 2010-06-14 19:14:21 +00:00
80daebbdaa Small hack just for my branch to get mesh VBOs working right with my drivers, which don't like glNormalPointer to use GL_SHORT for some reason. 2010-06-14 11:19:10 +00:00
b3b8846fda svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r29346:29389 2010-06-10 19:10:43 +00:00
e8fab1e9cf * Initial support for dynamically-sized Griddata from subsurf.
CCGSubsurf internally already fully supports vertdata of any size. This commit basically extends that support to all the code using the output of subsurf (with dm->getGridData).

For now, two types of grid data are set up: coords+normals with masks, and coords+normals without masks. More types to come.

For future reference, emacs find/replace regexps used to make some of the changes:

\(data\|subgrid\|grid\|edgeData\|faceGridData\)\[\(.*?\)\].\(co\|no\|mask\)
GRIDELEM_\,(upcase \3)_AT(\1, \2, gridkey)

&\(diffGrid\|gridA\|gridB\|faceGridData\|gridData\[i\]\|lowGridData\[i\]\)\[\(.*?\)\]
GRIDELEM_AT(\1, \2, gridkey)

\(vi\.grid\|vd\|a\|b\|vda\|vdb\)->\(co\|no\|mask\)
GRIDELEM_\,(upcase \2)(\1, gridkey)
2010-06-10 18:20:55 +00:00
529c194d99 * Added a button to invert the mask
* Renamed mask "Full" to "Fill"
2010-06-09 00:34:20 +00:00
f63c44ec68 * Updated the default blend (only in my branch) to add a mask brush for sculpt. 2010-06-08 22:59:26 +00:00
4218d34a23 * A little refactoring, pulled some common code together in multires 2010-06-08 22:46:29 +00:00
5cdc07f931 * Fixed masks not updating correctly from lower levels. 2010-06-08 22:40:02 +00:00
b19a0759ec svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r29193:29346 2010-06-08 21:44:26 +00:00
3f17a4274f * Replaced bad usage of inline keyword with CCG_INLINE. 2010-06-07 22:57:54 +00:00
d8e36bd68a * Fixed a bug in the mesh color buffer updating
* Added a mask brush to sculpt mode, behaves as a normal brush but affects mask not coords. Note that for non-multires, you have to create a mask layer before the brush will do anything.
* Cleared some memory that valgrind warned was uninitialized
2010-06-06 23:46:14 +00:00
ece6e5a41e * Sculpting now pays attention to the mask 2010-06-06 21:44:11 +00:00
428f1848e2 * Started integrating the customdata facegrids type. For now it's used for storing paintmasks with multires, more to come here.
* Updated disp_run to update masks. I'm treating mask layers as actual values rather than displacements as is done with mdisps; results look better this way I think.
* Added color buffer updating for VBOs built from grids.
* Changed the paint_mask_set operator to update multires too.

Notes
* For now I've hardcoded the use of mask data into DMGridData and other places. We don't actually always want that extra float though, that's temporary. Plan is to set up something similar to the way CCGSubsurf deals with variable-sized vert/edge/face data.
* This commit enables all the calculations needed to create, show, and update masks, but they aren't used for sculpting yet, that comes soon
2010-06-06 21:13:03 +00:00
a8ad20c31c * PBVH can now iterate over mask data coming from a mesh (not multires yet)
* The paint_mask_set operator can be used to create a mask layer and fill it with zeroes, ones, or random data (for testing)
* gpu_buffers will display the mask layer (again, only for regular meshes not multires grids yet.)
2010-06-06 17:03:06 +00:00
73ab6f7138 * Updated the paint_mask_set operator so that it can set mask values using the sculpt PBVH. The mask-setting part is commented out until the PBVH is ready. 2010-06-06 07:31:52 +00:00
3073f84da1 Preparing VBO drawing code for colors.
* Added functions to load paintmask data into the color buffer
* Drawing is enabled, but no visible effect since I haven't set up any paintmask layers yet.
2010-06-06 07:07:58 +00:00
4ddacf11ce * Fixed bug in the buffer VBO code; no reading from a buffer mapped as GL_WRITE_ONLY. 2010-06-06 06:30:22 +00:00
fc708877b0 * Changed CCGSubSurf's Vert macros into functions that operate on any number of floats, rather than just three.
* Added a new field to CCGMeshIFC to control how many floats those functions will operate on.
* For now it's always three, so there should be no visible change in behavior.
2010-06-06 06:10:54 +00:00
d00b733415 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r29022:29193 2010-06-03 20:27:16 +00:00
b21d92d827 * Filled out LAYERTYPEINFO and LAYERNAMETYPES for the new custom data types I added. 2010-05-31 02:51:30 +00:00
a9773aeec0 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r28753:29022 2010-05-27 09:23:26 +00:00
d4ca9be709 * Added a few new customdata types:
* FACEGRID will be the new way all CustomData for multires gets stored. Its backing type is CustomData. It's intended to be used in the CustomData for mesh faces. This is similar to CD_MDISPS, except that instead of storing just triples of floats, we can store a grid for any type (so long as there's a CustomData layer for it.)
* CD_DISP will be the replacement for CD_MDISPS. It's a triple of floats.
* PAINTMASK is simply a layer of floats; will be used to describe the intensity of the mask at each vertex (or at each grid point for multires.)
2010-05-25 19:50:15 +00:00
45eb1629b0 * Added a temporary operator to set masks, does nothing yet
* Added a temporary UI for the temporary operator for testing
2010-05-25 19:13:37 +00:00
1145425a57 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r28663:28753 2010-05-14 01:42:42 +00:00
438a5b22fd * Small refactoring to improve readability, no functionality changes.
* Replaced the invert and add parameters of disp_run to a single DispOp parameter. This makes explicit that we can CALC disps, APPLY disps, and ADD disps.
* Renamed "mat" in disp run.
2010-05-09 04:23:51 +00:00
e6bd313de9 svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r28447:28663 2010-05-08 08:54:22 +00:00
6dadec2972 branching for GSOC 2010 2010-04-27 02:17:27 +00:00
125 changed files with 20433 additions and 3741 deletions

View File

@@ -48,3 +48,5 @@ ENDIF(WITH_LZO)
IF(WITH_LZMA)
ADD_SUBDIRECTORY(lzma)
ENDIF(WITH_LZMA)
ADD_SUBDIRECTORY(ptex)

1
extern/SConscript vendored
View File

@@ -3,6 +3,7 @@
Import('env')
SConscript(['glew/SConscript'])
SConscript(['ptex/SConscript'])
if env['WITH_BF_BULLET']:
SConscript(['bullet2/src/SConscript'])

20
extern/ptex/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,20 @@
SET(INC ${ZLIB_INC} src .)
SET(SRC
src/ptex/PtexCache.cpp
src/ptex/PtexFilters.cpp
src/ptex/PtexHalf.cpp
src/ptex/PtexReader.cpp
src/ptex/PtexSeparableFilter.cpp
src/ptex/PtexSeparableKernel.cpp
src/ptex/PtexTriangleFilter.cpp
src/ptex/PtexTriangleKernel.cpp
src/ptex/PtexUtils.cpp
src/ptex/PtexWriter.cpp
ptex_C_api.cpp
)
ADD_DEFINITIONS(-DPTEX_STATIC)
BLENDERLIB(extern_ptex "${SRC}" "${INC}")

15
extern/ptex/SConscript vendored Normal file
View File

@@ -0,0 +1,15 @@
#!/usr/bin/python
import sys
import os
Import('env')
sources = ['src/glew.c']
sources = env.Glob('src/ptex/*.cpp')
sources += env.Glob('*.cpp')
defs = 'PTEX_STATIC'
incs = 'src/ptex'
incs += ' ' + env['BF_ZLIB_INC']
env.BlenderLib ( 'extern_ptex', sources, Split(incs), Split(defs), libtype=['extern','player'], priority=[50,230])

52
extern/ptex/ptex.h vendored Normal file
View File

@@ -0,0 +1,52 @@
#ifndef PTEX_H
#define PTEX_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct PtexTextureHandle PtexTextureHandle;
typedef struct PtexFaceInfoHandle PtexFaceInfoHandle;
typedef struct PtexResHandle PtexResHandle;
typedef struct PtexWriterHandle PtexWriterHandle;
typedef enum {
PTEX_DT_UINT8,
PTEX_DT_UINT16,
PTEX_DT_FLOAT,
PTEX_DT_UNSUPPORTED
} PtexDataType;
/* PtexTexture class */
extern PtexTextureHandle *ptex_open(const char *path, int print_error, int premultiply);
extern void ptex_texture_release(PtexTextureHandle *ptex_texture_handle);
extern PtexDataType ptex_texture_data_type(PtexTextureHandle *ptex_texture_handle);
extern int ptex_texture_num_channels(PtexTextureHandle *ptex_texture_handle);
extern PtexFaceInfoHandle *ptex_texture_get_face_info(PtexTextureHandle* ptex_texture_handle, int faceid);
extern void ptex_texture_get_data(PtexTextureHandle *ptex_texture_handle, int faceid, void *buffer, int stride, PtexResHandle *res_handle);
extern void ptex_texture_get_pixel(PtexTextureHandle *ptex_texture_handle, int faceid, int u, int v, float *result, int firstchan, int nchannels, PtexResHandle res_handle);
/* FaceInfo struct */
PtexFaceInfoHandle *ptex_face_info_new(int u, int v, int adjfaces[4], int adjedges[4], int isSubface);
extern PtexResHandle *ptex_face_info_get_res(PtexFaceInfoHandle *face_info_handle);
extern int ptex_face_info_is_subface(PtexFaceInfoHandle *face_info_handle);
/* Res struct */
extern int ptex_res_u(PtexResHandle *ptex_res_handle);
extern int ptex_res_v(PtexResHandle *ptex_res_handle);
/* PtexWriter class */
extern PtexWriterHandle *ptex_writer_open(const char *path, PtexDataType dt, int nchannels, int alphachan, int nfaces, int genmipmaps);
extern void ptex_writer_write_face(PtexWriterHandle *ptex_writer_handle, int faceid, PtexFaceInfoHandle *info, const void *data, int stride);
extern void ptex_writer_release(PtexWriterHandle *ptex_writer_handle);
/* Utils */
int ptex_data_size(PtexDataType type);
int ptex_res_to_log2(int res);
#ifdef __cplusplus
}
#endif
#endif

184
extern/ptex/ptex_C_api.cpp vendored Normal file
View File

@@ -0,0 +1,184 @@
#include "ptex.h"
#include "src/ptex/Ptexture.h"
#include <iostream>
/**** PtexTexture class ****/
PtexTextureHandle *ptex_open(const char *path, int print_error, int premultiply)
{
PtexTextureHandle *ptex_texture_handle;
Ptex::String error_string;
ptex_texture_handle = (PtexTextureHandle*)PtexTexture::open(path, error_string, premultiply);
if(!ptex_texture_handle && print_error)
std::cout << "Ptex error: " << error_string << std::endl;
return ptex_texture_handle;
}
void ptex_texture_release(PtexTextureHandle *ptex_texture_handle)
{
((PtexTexture*)ptex_texture_handle)->release();
}
PtexDataType ptex_texture_data_type(PtexTextureHandle *ptex_texture_handle)
{
Ptex::DataType type = ((PtexTexture*)ptex_texture_handle)->dataType();
switch(type) {
case Ptex::dt_uint8:
return PTEX_DT_UINT8;
case Ptex::dt_uint16:
return PTEX_DT_UINT16;
case Ptex::dt_float:
return PTEX_DT_FLOAT;
default:
return PTEX_DT_UNSUPPORTED;
}
}
int ptex_texture_num_channels(PtexTextureHandle *ptex_texture_handle)
{
return ((PtexTexture*)ptex_texture_handle)->numChannels();
}
PtexFaceInfoHandle *ptex_texture_get_face_info(PtexTextureHandle *ptex_texture_handle, int faceid)
{
return (PtexFaceInfoHandle*)(&((PtexTexture*)ptex_texture_handle)->getFaceInfo(faceid));
}
void ptex_texture_get_data(PtexTextureHandle *ptex_texture_handle, int faceid, void *buffer, int stride, PtexResHandle *res_handle)
{
((PtexTexture*)ptex_texture_handle)->getData(faceid, buffer, stride, *((Ptex::Res*)res_handle));
}
void ptex_texture_get_pixel(PtexTextureHandle *ptex_texture_handle, int faceid, int u, int v, float *result, int firstchan, int nchannels, PtexResHandle *res_handle)
{
((PtexTexture*)ptex_texture_handle)->getPixel(faceid, u, v, result, firstchan, nchannels, *((Ptex::Res*)res_handle));
}
/**** FaceInfo struct ****/
PtexFaceInfoHandle *ptex_face_info_new(int u, int v, int adjfaces[4], int adjedges[4], int isSubface)
{
int ulog2 = ptex_res_to_log2(u);
int vlog2 = ptex_res_to_log2(v);
return (PtexFaceInfoHandle*)(new Ptex::FaceInfo(Ptex::Res(ulog2, vlog2), adjfaces, adjedges, isSubface));
}
PtexResHandle *ptex_face_info_get_res(PtexFaceInfoHandle *face_info_handle)
{
return (PtexResHandle*)(&((Ptex::FaceInfo*)face_info_handle)->res);
}
int ptex_face_info_is_subface(PtexFaceInfoHandle *face_info_handle)
{
return ((Ptex::FaceInfo*)face_info_handle)->isSubface();
}
/**** Res struct ****/
int ptex_res_u(PtexResHandle *ptex_res_handle)
{
return ((Ptex::Res*)ptex_res_handle)->u();
}
int ptex_res_v(PtexResHandle *ptex_res_handle)
{
return ((Ptex::Res*)ptex_res_handle)->v();
}
/**** PtexWriter class ****/
PtexWriterHandle *ptex_writer_open(const char *path, PtexDataType dt, int nchannels, int alphachan, int nfaces, int genmipmaps)
{
Ptex::DataType ptex_data_type;
Ptex::String error;
switch(dt) {
case PTEX_DT_UINT8:
ptex_data_type = Ptex::dt_uint8;
break;
case PTEX_DT_UINT16:
ptex_data_type = Ptex::dt_uint16;
break;
case PTEX_DT_FLOAT:
ptex_data_type = Ptex::dt_float;
break;
default:
return NULL;
}
return (PtexWriterHandle*)PtexWriter::open(path, Ptex::mt_quad, ptex_data_type, nchannels, alphachan, nfaces, error, genmipmaps);
}
void ptex_writer_write_face(PtexWriterHandle *ptex_writer_handle, int faceid, PtexFaceInfoHandle *info, const void *data, int stride)
{
((PtexWriter*)ptex_writer_handle)->writeFace(faceid, *(Ptex::FaceInfo*)info, data, stride);
}
void ptex_writer_release(PtexWriterHandle *ptex_writer_handle)
{
((PtexWriter*)ptex_writer_handle)->release();
}
/**** Utils ****/
int ptex_data_size(PtexDataType type)
{
switch(type) {
case PTEX_DT_UINT8:
return 1;
case PTEX_DT_UINT16:
return 2;
case PTEX_DT_FLOAT:
return 4;
default:
return 0;
}
}
int ptex_res_to_log2(int res)
{
switch(res) {
case (1<<0): return 0;
case (1<<1): return 1;
case (1<<2): return 2;
case (1<<3): return 3;
case (1<<4): return 4;
case (1<<5): return 5;
case (1<<6): return 6;
case (1<<7): return 7;
case (1<<8): return 8;
case (1<<9): return 9;
case (1<<10): return 10;
case (1<<11): return 11;
case (1<<12): return 12;
case (1<<13): return 13;
case (1<<14): return 14;
case (1<<15): return 15;
case (1<<16): return 16;
case (1<<17): return 17;
case (1<<18): return 18;
case (1<<19): return 19;
case (1<<20): return 20;
case (1<<21): return 21;
case (1<<22): return 22;
case (1<<23): return 23;
case (1<<24): return 24;
case (1<<25): return 25;
case (1<<26): return 26;
case (1<<27): return 27;
case (1<<28): return 28;
case (1<<29): return 29;
case (1<<30): return 30;
case (1<<31): return 31;
default: return 0;
}
}

13
extern/ptex/src/Makefile vendored Normal file
View File

@@ -0,0 +1,13 @@
SUBDIRS = ptex utils tests
.PHONY: subdirs $(SUBDIRS)
subdirs: $(SUBDIRS)
clean:
for s in $(SUBDIRS); do \
$(MAKE) -C $$s clean; \
done
$(SUBDIRS):
$(MAKE) -C $@

89
extern/ptex/src/ptex/Makefile vendored Normal file
View File

@@ -0,0 +1,89 @@
# use compiler from CXX env var if present, otherwise default to g++
ifndef CXX
CXX = g++
LINK = g++
else
LINK = $(CXX)
endif
# DEBUG = -g -DDEBUG
DEBUG = -O2 -DNDEBUG
INCPATH = -I.
DEFINES =
ifdef PRMAN_15_COMPATIBLE_PTEX
DEFINES += -DPTEX_NO_LARGE_METADATA_BLOCKS
endif
ifdef PTEX_STATIC
DEFINES += -DPTEX_STATIC
endif
CXXFLAGS = -Wall -pedantic -W -std=c++98 $(DEBUG) $(INCPATH) $(DEFINES) -fPIC
LFLAGS =
LIBS = -lm -lz -lpthread
SRCS = \
PtexCache.cpp \
PtexFilters.cpp \
PtexHalf.cpp \
PtexReader.cpp \
PtexSeparableFilter.cpp \
PtexSeparableKernel.cpp \
PtexTriangleFilter.cpp \
PtexTriangleKernel.cpp \
PtexUtils.cpp \
PtexWriter.cpp
OBJECTS = $(patsubst %.cpp,%.o,$(SRCS))
INSTALLDIR = ../../install
INSTALL = \
lib/libPtex.a \
include/Ptexture.h \
include/PtexHalf.h \
include/PtexInt.h \
include/PtexUtils.h
ALL = libPtex.a
ifndef PTEX_STATIC
ALL += libPtex.so
INSTALL += lib/libPtex.so
endif
$(INSTALLDIR)/lib/% : %
@ mkdir -p $(@D)
cp $^ $@
$(INSTALLDIR)/bin/% : %
@ mkdir -p $(@D)
cp $^ $@
$(INSTALLDIR)/include/% : %
@ mkdir -p $(@D)
cp $^ $@
install: all $(patsubst %,$(INSTALLDIR)/%,$(INSTALL))
all: $(ALL)
clean:
rm -f *.o $(ALL)
ifdef PTEX_STATIC
libPtex.a : libPtex.a($(OBJECTS))
ar -r $@
else
libPtex.a : libPtex.a($(OBJECTS))
libPtex.so: $(OBJECTS)
$(LINK) $(LFLAGS) -shared -o $@ $(OBJECTS) $(LIBS)
endif
depend:
$(CXX) -MM $(SRCS) > Makefile.deps
include Makefile.deps

25
extern/ptex/src/ptex/Makefile.deps vendored Normal file
View File

@@ -0,0 +1,25 @@
PtexCache.o: PtexCache.cpp PtexPlatform.h Ptexture.h PtexInt.h \
PtexReader.h PtexIO.h PtexCache.h PtexMutex.h PtexDict.h PtexUtils.h \
PtexHashMap.h
PtexFilters.o: PtexFilters.cpp PtexPlatform.h Ptexture.h PtexInt.h \
PtexSeparableFilter.h PtexSeparableKernel.h PtexUtils.h \
PtexTriangleFilter.h
PtexHalf.o: PtexHalf.cpp PtexHalf.h PtexInt.h
PtexReader.o: PtexReader.cpp PtexPlatform.h Ptexture.h PtexInt.h \
PtexUtils.h PtexReader.h PtexIO.h PtexCache.h PtexMutex.h PtexDict.h \
PtexHashMap.h
PtexSeparableFilter.o: PtexSeparableFilter.cpp PtexPlatform.h \
PtexSeparableFilter.h Ptexture.h PtexInt.h PtexSeparableKernel.h \
PtexUtils.h
PtexSeparableKernel.o: PtexSeparableKernel.cpp PtexPlatform.h PtexUtils.h \
Ptexture.h PtexInt.h PtexHalf.h PtexSeparableKernel.h
PtexTriangleFilter.o: PtexTriangleFilter.cpp PtexPlatform.h \
PtexTriangleFilter.h Ptexture.h PtexInt.h PtexTriangleKernel.h \
PtexUtils.h
PtexTriangleKernel.o: PtexTriangleKernel.cpp PtexPlatform.h PtexUtils.h \
Ptexture.h PtexInt.h PtexHalf.h PtexTriangleKernel.h
PtexUtils.o: PtexUtils.cpp PtexPlatform.h PtexHalf.h PtexInt.h \
PtexUtils.h Ptexture.h
PtexWriter.o: PtexWriter.cpp PtexPlatform.h Ptexture.h PtexInt.h \
PtexUtils.h PtexWriter.h PtexIO.h PtexReader.h PtexCache.h PtexMutex.h \
PtexDict.h PtexHashMap.h

419
extern/ptex/src/ptex/PtexCache.cpp vendored Normal file
View File

@@ -0,0 +1,419 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/**
@file PtexCache.cpp
@brief LRU Cache Implementation
<b> Ownership.</b>
The cache owns all files and data. If an object is in use, the
cache will not delete it. When it is no longer in use, it may be
kept or may be deleted to keep resource usage under the set limits.
Deletions are done in lru order.
<b> Resource Tracking.</b>
All objects are created as part of the cache and have a ptr back to
the cache. Each object updates the cache's resource total when it is
created or deleted. Unused objects are kept in an lru list in the
cache. Only objects in the lru list can be deleted.
<b> Reference Counting.</b>
Every object has a ref count to track whether it is being used.
But objects don't generally ref their parent or children (otherwise
nothing would get freed).
A data handle must hold onto (and ref) all the objects it is using
or may need in the future. E.g. For a non-tiled face, this is just
the single face data block. For a tiled face, the file, the tiled
face, and the current tile must all be ref'd.
<b> Parents, Children, and Orphans.</b>
Every object must be reachable by some other object, generally the
object that created it, i.e. it's parent. Even though the parent
doesn't own it's children (the cache does), it must still track
them. Parentless objects (i.e. orphans) are not reachable and are
not retained in the cache.
When any object is deleted (file, tiled face, etc.), it must orphan
its children. If an orphaned child is not in use, then it is
immediately deleted. Otherwise, the child's parent ptr is set to
null and the child is deleted when it is no longer in use. A
parent may also orphan a child that it no longer needs; the
behavior is the same.
Each object stores a ptr to its own entry within its parent. When
the object is deleted by the cache, it clears this pointer so that
the parent no longer sees it.
<b> Cache LifeTime.</b>
When a cache is released from its owner, it will delete itself but
only after all objects it owns are no longer in use. To do this, a
ref count on the cache is used. The owner holds 1 ref (only one
owner allowed), and each object holds a ref (maintained internally).
<b> Threading.</b>
To fully support multi-threading, the following data structures
must be protected with a mutex: the cache lru lists, ref counts,
and parent/child ptrs. This is done with a single mutex per cache.
To avoid the need for recursive locks and to minimize the number of
lock points, this mutex is locked and unlocked primarily at the
external api boundary for methods that affect the cache state:
(e.g. getMetaData, getData, getTile, release, purge, and purgeAll).
Care must be taken to release the cache lock when calling any external
api from within the library.
Also, in order to prevent thread starvation, the cache lock is
released during file reads and significant computation such as
generating an image data reduction. Additional mutexes are used to
prevent contention in these cases:
- 1 mutex per cache to prevent concurrent file opens
- 1 mutex per file to prevent concurrent file reads
- 1 mutex per file to prevent concurrent (and possibly redundant)
reductions.
*/
#include "PtexPlatform.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <iostream>
#include <ctype.h>
#include "Ptexture.h"
#include "PtexReader.h"
#include "PtexCache.h"
#ifdef GATHER_STATS
namespace PtexInternal {
CacheStats::~CacheStats() {
if (getenv("PTEX_STATS"))
print();
}
void CacheStats::print()
{
if (nfilesOpened || ndataAllocated || nblocksRead) {
printf("Ptex Stats:\n");
printf(" nfilesOpened: %6d\n", nfilesOpened);
printf(" nfilesClosed: %6d\n", nfilesClosed);
printf(" ndataAllocated: %6d\n", ndataAllocated);
printf(" ndataFreed: %6d\n", ndataFreed);
printf(" nblocksRead: %6d\n", nblocksRead);
printf(" nseeks: %6d\n", nseeks);
if (nblocksRead)
printf(" avgReadSize: %6d\n", int(nbytesRead/nblocksRead));
if (nseeks)
printf(" avgSeqReadSize: %6d\n", int(nbytesRead/nseeks));
printf(" MbytesRead: %6.2f\n", nbytesRead/(1024.0*1024.0));
}
}
CacheStats stats;
}
#endif
PtexCacheImpl::~PtexCacheImpl()
{
// explicitly pop all unused items so that they are
// destroyed while cache is still valid
AutoLockCache locker(cachelock);
while (_unusedData.pop());
while (_unusedFiles.pop());
}
void PtexCacheImpl::setFileInUse(PtexLruItem* file)
{
assert(cachelock.locked());
_unusedFiles.extract(file);
_unusedFileCount--;
}
void PtexCacheImpl::setFileUnused(PtexLruItem* file)
{
assert(cachelock.locked());
_unusedFiles.push(file);
_unusedFileCount++;
}
void PtexCacheImpl::removeFile()
{
// cachelock should be locked, but might not be if cache is being deleted
_unusedFileCount--;
STATS_INC(nfilesClosed);
}
void PtexCacheImpl::setDataInUse(PtexLruItem* data, int size)
{
assert(cachelock.locked());
_unusedData.extract(data);
_unusedDataCount--;
_unusedDataSize -= size;
}
void PtexCacheImpl::setDataUnused(PtexLruItem* data, int size)
{
assert(cachelock.locked());
_unusedData.push(data);
_unusedDataCount++;
_unusedDataSize += size;
}
void PtexCacheImpl::removeData(int size) {
// cachelock should be locked, but might not be if cache is being deleted
_unusedDataCount--;
_unusedDataSize -= size;
STATS_INC(ndataFreed);
}
/** Cache for reading Ptex texture files */
class PtexReaderCache : public PtexCacheImpl
{
public:
PtexReaderCache(int maxFiles, int maxMem, bool premultiply, PtexInputHandler* handler)
: PtexCacheImpl(maxFiles, maxMem),
_io(handler), _cleanupCount(0), _premultiply(premultiply)
{}
~PtexReaderCache()
{
// orphan all files since we're about to delete the file table
// and we don't want the base dtor to try to access it
purgeAll();
}
virtual void setSearchPath(const char* path)
{
// get the open lock since the path is used during open operations
AutoMutex locker(openlock);
// record path
_searchpath = path ? path : "";
// split into dirs
_searchdirs.clear();
char* buff = strdup(path);
char* pos = 0;
char* token = strtok_r(buff, ":", &pos);
while (token) {
if (token[0]) _searchdirs.push_back(token);
token = strtok_r(0, ":", &pos);
}
free(buff);
}
virtual const char* getSearchPath()
{
// get the open lock since the path is used during open operations
AutoMutex locker(openlock);
return _searchpath.c_str();
}
virtual PtexTexture* get(const char* path, Ptex::String& error);
virtual void purge(PtexTexture* texture)
{
PtexReader* reader = dynamic_cast<PtexReader*>(texture);
if (!reader) return;
purge(reader->path());
}
virtual void purge(const char* filename)
{
AutoLockCache locker(cachelock);
FileMap::iterator iter = _files.find(filename);
if (iter != _files.end()) {
PtexReader* reader = iter->second;
if (reader && intptr_t(reader) != -1) {
reader->orphan();
iter->second = 0;
}
_files.erase(iter);
}
}
virtual void purgeAll()
{
AutoLockCache locker(cachelock);
FileMap::iterator iter = _files.begin();
while (iter != _files.end()) {
PtexReader* reader = iter->second;
if (reader && intptr_t(reader) != -1) {
reader->orphan();
iter->second = 0;
}
iter = _files.erase(iter);
}
}
void removeBlankEntries()
{
// remove blank file entries to keep map size in check
for (FileMap::iterator i = _files.begin(); i != _files.end();) {
if (i->second == 0) i = _files.erase(i);
else i++;
}
}
private:
PtexInputHandler* _io;
std::string _searchpath;
std::vector<std::string> _searchdirs;
typedef PtexDict<PtexReader*> FileMap;
FileMap _files;
int _cleanupCount;
bool _premultiply;
};
PtexTexture* PtexReaderCache::get(const char* filename, Ptex::String& error)
{
AutoLockCache locker(cachelock);
// lookup reader in map
PtexReader* reader = _files[filename];
if (reader) {
// -1 means previous open attempt failed
if (intptr_t(reader) == -1) return 0;
reader->ref();
return reader;
}
else {
bool ok = true;
// get open lock and make sure we still need to open
// temporarily release cache lock while we open acquire open lock
cachelock.unlock();
AutoMutex openlocker(openlock);
cachelock.lock();
// lookup entry again (it might have changed in another thread)
PtexReader** entry = &_files[filename];
if (*entry) {
// another thread opened it while we were waiting
if (intptr_t(*entry) == -1) return 0;
(*entry)->ref();
return *entry;
}
// make a new reader
reader = new PtexReader((void**)entry, this, _premultiply, _io);
// temporarily release cache lock while we open the file
cachelock.unlock();
std::string tmppath;
const char* pathToOpen = filename;
if (!_io) {
bool isAbsolute = (filename[0] == '/'
#ifdef WINDOWS
|| filename[0] == '\\'
|| (isalpha(filename[0]) && filename[1] == ':')
#endif
);
if (!isAbsolute && !_searchdirs.empty()) {
// file is relative, search in searchpath
tmppath.reserve(256); // minimize reallocs (will grow automatically)
bool found = false;
struct stat statbuf;
for (size_t i = 0, size = _searchdirs.size(); i < size; i++) {
tmppath = _searchdirs[i];
tmppath += "/";
tmppath += filename;
if (stat(tmppath.c_str(), &statbuf) == 0) {
found = true;
pathToOpen = tmppath.c_str();
break;
}
}
if (!found) {
std::string errstr = "Can't find ptex file: ";
errstr += filename;
error = errstr.c_str();
ok = false;
}
}
}
if (ok) ok = reader->open(pathToOpen, error);
// reacquire cache lock
cachelock.lock();
if (!ok) {
// open failed, clear parent ptr and unref to delete
*entry = reader; // to pass parent check in orphan()
reader->orphan();
reader->unref();
*entry = (PtexReader*)-1; // flag for future lookups
return 0;
}
// successful open, record in _files map entry
*entry = reader;
// clean up unused files
purgeFiles();
// Cleanup map every so often so it doesn't get HUGE
// from being filled with blank entries from dead files.
// Note: this must be done while we still have the open lock!
if (++_cleanupCount >= 1000) {
_cleanupCount = 0;
removeBlankEntries();
}
}
return reader;
}
PtexCache* PtexCache::create(int maxFiles, int maxMem, bool premultiply,
PtexInputHandler* handler)
{
// set default files to 100
if (maxFiles <= 0) maxFiles = 100;
// set default memory to 100 MB
const int MB = 1024*1024;
if (maxMem <= 0) maxMem = 100 * MB;
// if memory is < 1 MB, warn
if (maxMem < 1 * MB) {
std::cerr << "Warning, PtexCache created with < 1 MB" << std::endl;
}
return new PtexReaderCache(maxFiles, maxMem, premultiply, handler);
}

300
extern/ptex/src/ptex/PtexCache.h vendored Normal file
View File

@@ -0,0 +1,300 @@
#ifndef PtexCache_h
#define PtexCache_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "PtexPlatform.h"
#include <assert.h>
#include "PtexMutex.h"
#include "Ptexture.h"
#include "PtexDict.h"
#define USE_SPIN // use spinlocks instead of mutex for main cache lock
namespace PtexInternal {
#ifdef USE_SPIN
typedef SpinLock CacheLock;
#else
typedef Mutex CacheLock;
#endif
typedef AutoLock<CacheLock> AutoLockCache;
#ifndef NDEBUG
#define GATHER_STATS
#endif
#ifdef GATHER_STATS
struct CacheStats{
int nfilesOpened;
int nfilesClosed;
int ndataAllocated;
int ndataFreed;
int nblocksRead;
long int nbytesRead;
int nseeks;
CacheStats()
: nfilesOpened(0),
nfilesClosed(0),
ndataAllocated(0),
ndataFreed(0),
nblocksRead(0),
nbytesRead(0),
nseeks(0) {}
~CacheStats();
void print();
static void inc(int& val) {
static SpinLock spinlock;
AutoSpin lock(spinlock);
val++;
}
static void add(long int& val, int inc) {
static SpinLock spinlock;
AutoSpin lock(spinlock);
val+=inc;
}
};
extern CacheStats stats;
#define STATS_INC(x) stats.inc(stats.x);
#define STATS_ADD(x, y) stats.add(stats.x, y);
#else
#define STATS_INC(x)
#define STATS_ADD(x, y)
#endif
}
using namespace PtexInternal;
/** One item in a cache, typically an open file or a block of memory */
class PtexLruItem {
public:
bool inuse() { return _prev == 0; }
void orphan()
{
// parent no longer wants me
void** p = _parent;
_parent = 0;
assert(p && *p == this);
if (!inuse()) delete this;
*p = 0;
}
template <typename T> static void orphanList(T& list)
{
for (typename T::iterator i=list.begin(); i != list.end(); i++) {
PtexLruItem* obj = *i;
if (obj) {
assert(obj->_parent == (void**)&*i);
obj->orphan();
}
}
}
protected:
PtexLruItem(void** parent=0)
: _parent(parent), _prev(0), _next(0) {}
virtual ~PtexLruItem()
{
// detach from parent (if any)
if (_parent) { assert(*_parent == this); *_parent = 0; }
// unlink from lru list (if in list)
if (_prev) {
_prev->_next = _next;
_next->_prev = _prev;
}
}
private:
friend class PtexLruList; // maintains prev/next, deletes
void** _parent; // pointer to this item within parent
PtexLruItem* _prev; // prev in lru list (0 if in-use)
PtexLruItem* _next; // next in lru list (0 if in-use)
};
/** A list of items kept in least-recently-used (LRU) order.
Only items not in use are kept in the list. */
class PtexLruList {
public:
PtexLruList() { _end._prev = _end._next = &_end; }
~PtexLruList() { while (pop()); }
void extract(PtexLruItem* node)
{
// remove from list
node->_prev->_next = node->_next;
node->_next->_prev = node->_prev;
node->_next = node->_prev = 0;
}
void push(PtexLruItem* node)
{
// delete node if orphaned
if (!node->_parent) delete node;
else {
// add to end of list
node->_next = &_end;
node->_prev = _end._prev;
_end._prev->_next = node;
_end._prev = node;
}
}
bool pop()
{
if (_end._next == &_end) return 0;
delete _end._next; // item will unlink itself
return 1;
}
private:
PtexLruItem _end;
};
/** Ptex cache implementation. Maintains a file and memory cache
within set limits */
class PtexCacheImpl : public PtexCache {
public:
PtexCacheImpl(int maxFiles, int maxMem)
: _pendingDelete(false),
_maxFiles(maxFiles), _unusedFileCount(0),
_maxDataSize(maxMem),
_unusedDataSize(0), _unusedDataCount(0)
{
/* Allow for a minimum number of data blocks so cache doesn't
thrash too much if there are any really big items in the
cache pushing over the limit. It's better to go over the
limit in this case and make sure there's room for at least
a modest number of objects in the cache.
*/
// try to allow for at least 10 objects per file (up to 100 files)
_minDataCount = 10 * maxFiles;
// but no more than 1000
if (_minDataCount > 1000) _minDataCount = 1000;
}
virtual void release() { delete this; }
Mutex openlock;
CacheLock cachelock;
// internal use - only call from reader classes for deferred deletion
void setPendingDelete() { _pendingDelete = true; }
void handlePendingDelete() { if (_pendingDelete) delete this; }
// internal use - only call from PtexCachedFile, PtexCachedData
static void addFile() { STATS_INC(nfilesOpened); }
void setFileInUse(PtexLruItem* file);
void setFileUnused(PtexLruItem* file);
void removeFile();
static void addData() { STATS_INC(ndataAllocated); }
void setDataInUse(PtexLruItem* data, int size);
void setDataUnused(PtexLruItem* data, int size);
void removeData(int size);
void purgeFiles() {
while (_unusedFileCount > _maxFiles)
{
if (!_unusedFiles.pop()) break;
// note: pop will destroy item and item destructor will
// call removeFile which will decrement _unusedFileCount
}
}
void purgeData() {
while ((_unusedDataSize > _maxDataSize) &&
(_unusedDataCount > _minDataCount))
{
if (!_unusedData.pop()) break;
// note: pop will destroy item and item destructor will
// call removeData which will decrement _unusedDataSize
// and _unusedDataCount
}
}
protected:
~PtexCacheImpl();
private:
bool _pendingDelete; // flag set if delete is pending
int _maxFiles, _unusedFileCount; // file limit, current unused file count
long int _maxDataSize, _unusedDataSize; // data limit (bytes), current size
int _minDataCount, _unusedDataCount; // min, current # of unused data blocks
PtexLruList _unusedFiles, _unusedData; // lists of unused items
};
/** Cache entry for open file handle */
class PtexCachedFile : public PtexLruItem
{
public:
PtexCachedFile(void** parent, PtexCacheImpl* cache)
: PtexLruItem(parent), _cache(cache), _refcount(1)
{ _cache->addFile(); }
void ref() { assert(_cache->cachelock.locked()); if (!_refcount++) _cache->setFileInUse(this); }
void unref() { assert(_cache->cachelock.locked()); if (!--_refcount) _cache->setFileUnused(this); }
protected:
virtual ~PtexCachedFile() { _cache->removeFile(); }
PtexCacheImpl* _cache;
private:
int _refcount;
};
/** Cache entry for allocated memory block */
class PtexCachedData : public PtexLruItem
{
public:
PtexCachedData(void** parent, PtexCacheImpl* cache, int size)
: PtexLruItem(parent), _cache(cache), _refcount(1), _size(size)
{ _cache->addData(); }
void ref() { assert(_cache->cachelock.locked()); if (!_refcount++) _cache->setDataInUse(this, _size); }
void unref() { assert(_cache->cachelock.locked()); if (!--_refcount) _cache->setDataUnused(this, _size); }
protected:
void incSize(int size) { _size += size; }
virtual ~PtexCachedData() { _cache->removeData(_size); }
PtexCacheImpl* _cache;
private:
int _refcount;
int _size;
};
#endif

595
extern/ptex/src/ptex/PtexDict.h vendored Normal file
View File

@@ -0,0 +1,595 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/**
@file PtexDict.h
@brief Contains PtexDict, a string-keyed hash table.
*/
#ifndef PtexDict_h
#define PtexDict_h
/**
@class PtexDict
@brief A string-keyed dictionary template, using a hash table.
<P>
An efficient string dictionary template. A hash table is used
that automatically doubles in size when it is more than 50%
full. It is hard-coded to use string keys for efficiency.
<P>
The interface is compatible with std::hash_map<>, though not all methods
are provided. Methods provided:
<UL>
<LI>iterator begin();
<LI>const_iterator begin() const;
<LI>iterator end();
<LI>const_iterator end() const;
<LI>T& operator[] (const char*);
<LI>iterator find(const char* key);
<LI>const_iterator find(const char* key) const;
<LI>bool erase(const char* key);
<LI>iterator erase(iterator);
<LI>void clear();
<LI>int size() const;
</UL>
<P>
Unlike std::hash_map<>, PtexDict doesn't have to construct a string
object to do a lookup. As a result, it is about 4-10 times faster
depending on the length of the keys. And when compiling
non-optimized, it is 6-10 times faster.
<P>
We have decided NOT to follow the coding standard's naming comvention for
this class, since it needed to remain generic, and compatible with the
STL std::hash_map<> class.
@author brentb
@author longson
@version <B>1.0 brentb 11/01/2000:</B> Initial version
@version <B>1.1 longson 06/26/2001:</B> Added file and class comment headers
@version <B>2.0 longson 01/16/2002:</B> Updated to support most of the coding standards, except for the naming conventions. Added const_iterator to provide const-safe access. Fixed problem with iterators and not allowing modification.
*/
/**
@struct PtexDict::value_type
@brief Internal class used to provide a return value for the value type
All data members and member functions are declared public by design
Default Copy and Assignment operators are sufficient..
<P>
We have decided NOT to follow the coding standard's naming comvention for
this class, since it needed to remain compatible with the STL std::pair<>
class.
@author brentb
@author longson
@version <B>1.0 brentb 11/01/2000:</B> Initial version
@version <B>1.1 longson 06/26/2001:</B> Added file and class comment headers
*/
template<class T>
class PtexDict
{
class Entry; ///< forward declared private class
public: // Public Types
class iterator; ///< forward declared class
class const_iterator; ///< forward declared class
friend class iterator;
friend class const_iterator;
typedef const char* key_type; ///< This is the lookup type
typedef T mapped_type; ///< The data type stored
struct value_type {
public:
/// Default constructor references default_value, with a 0 for first
value_type(): first(0), second() {}
/// Creation constructor
value_type(key_type f, const T& s): first(f), second(s) {}
const key_type first; ///< Reference to the key type
T second; ///< Reference to the data
};
public: // Public Member Interfce
/// Default contructor initializes the dictionary.
PtexDict() : _numEntries(0), _numBuckets(0), _bucketMask(0), _buckets(0) {}
/// clears the entries in the dictionary
virtual ~PtexDict() { clear(); }
/// Locates an entry, creating a new one if necessary.
/** operator[] will look up an entry and return the value. A new entry
will be created (using the default ctor for T) if one doesn't exist.
*/
T& operator[](const char* key);
/// Returns an iterator referencing the beginning of the table
iterator begin()
{
iterator iter;
iter._d = this;
for (iter._b = 0; iter._b < _numBuckets; iter._b++) {
iter._e = &_buckets[iter._b];
if (*iter._e) return iter;
}
iter._e = 0;
return iter;
}
/// Returns an iterator referencing the end of the table.
inline iterator end() { return iterator( 0, this, 0 ); }
/// Const access to the beginning of the list
const_iterator begin() const
{
const_iterator iter;
iter._d = this;
for (iter._b = 0; iter._b < _numBuckets; iter._b++) {
iter._e = &_buckets[iter._b];
if (*iter._e) return iter;
}
iter._e = 0;
return iter;
}
/// Const access to the end of the list
inline const_iterator end() const { return const_iterator( 0, this, 0 ); }
/// Locates an entry, without creating a new one.
/** find will locate an entry, but won't create a new one. The result is
returned as a pair of key and value. The returned key points to the
internal key string and will remain valid until the entry is deleted.
If the key is not found, the returned iterator will be equal to the
value returned by end(), and the iterator will be equal to false. O(1)
*/
iterator find(const char* key);
/// works the same as find above, but returns a constant iterator.
const_iterator find(const char* key) const;
/// Will remove an entry. It will return TRUE if an entry was found.
bool erase(const char* key);
/// Removes the entry referenced by the iterator, from the dictionary.
/** It will return a iterator to the next element, or will equal the
return value of end() if there is nothing else to erase. O(1) */
iterator erase(iterator iter);
/// clear will remove all entries from the dictionary. O(n)
void clear();
/// Returns the number of entries in the dictionary. O(1) time to call.
int size() const { return _numEntries; }
private: // Private Member Interface
/// @brief This internal structure is used to store the dictionary elements
struct Entry {
public: // Public Member Interface
/// Default constructor initiaizes val with the defaul value
Entry() : _next(0), _hashval(0), _keylen(0),
_val(_key,T()), _pad(0) {}
private: // Private Member Interface
/// Copy constructor prohibited by design.
Entry(const Entry&);
/// Assignment operator prohibited by design.
Entry& operator=(const Entry&);
public:
Entry* _next; ///< Pointer to the next element in the structure
int _hashval; ///< cached hashval of key
int _keylen; ///< cached length of key
value_type _val; ///< The stored value of the hash table
union {
int _pad; ///< for integer align of _key, for fast compares
char _key[1];///< 1 is dummy length - actual size will be allocated
};
};
/// Copy constructor prohibited by design.
PtexDict(const PtexDict&);
/// Assignment operator prohibited by design.
PtexDict& operator=(const PtexDict&);
/// Returns the integer hash index for the key and length of the key.
int hash(const char* key, int& keylen) const
{
// this is similar to perl's hash function
int hashval = 0;
const char* cp = key;
char c;
while ((c = *cp++)) hashval = hashval * 33 + c;
keylen = int(cp-key)-1;
return hashval;
}
/// Returns a pointer to the desired entry, based on the key.
Entry** locate(const char* key, int& keylen, int& hashval) const
{
hashval = hash(key, keylen);
if (!_buckets) return 0;
for (Entry** e = &_buckets[hashval & _bucketMask]; *e; e=&(*e)->_next)
if ((*e)->_hashval == hashval && (*e)->_keylen == keylen &&
streq(key, (*e)->_key, keylen))
return e;
return 0;
}
/// Used for string compares, much faster then strcmp
/** This is MUCH faster than strcmp and even memcmp, partly because
it is inline and partly because it can do 4 chars at a time
*/
static inline bool streq(const char* s1, const char* s2, int len)
{
// first make sure s1 is quad-aligned (s2 is always aligned)
if (((intptr_t)s1 & 3) == 0) {
int len4 = len >> 2;
while (len4--) {
if (*(int*)s1 != *(int*)s2) return 0;
s1 += 4; s2 += 4;
}
len &= 3;
}
while (len--) if (*s1++ != *s2++) return 0;
return 1;
}
/// Used to increase the size of the table if necessary
void grow();
private: // Private Member data
int _numEntries; ///< The number of entries in the dictionary
int _numBuckets; ///< The number of buckets in use
int _bucketMask; ///< The mask for the buckets
Entry** _buckets; ///< The pointer to the bucket structure
};
/**
@class PtexDict::iterator
@brief Internal class used to provide iteration through the dictionary
This works on non-const types, and provides type safe modification access
@author brentb
@author longson
@version <B>1.0 brentb 11/01/2000:</B> Initial version
@version <B>1.1 longson 06/26/2001:</B> Added file and class comment headers
@version <B>1.2 longson 01/16/2002:</B> Made const-safe with const_iterator
*/
template<class T>
class PtexDict<T>::iterator {
public:
/// Default Constructor
iterator() : _d(0), _e(0), _b(0) {}
/// Proper copy constructor implementation
iterator(const iterator& iter) :
_d(iter._d), _e(iter._e), _b(iter._b) {}
/// Proper assignment operator
inline iterator& operator=(const iterator& iter)
{ _e = iter._e; _d = iter._d; _b = iter._b; return *this; }
/// Operator for obtaining the value that the iterator references
inline value_type& operator*() const { return getValue(); }
/// Pointer reference operator
inline value_type* operator->() const { return &getValue(); }
/// For determining whether or not an iterator is valid
inline operator bool() { return _e != 0; }
/// For comparing equality of iterators
inline bool operator==(const iterator& iter) const
{ return iter._e == _e; }
/// For comparing inequality of iterators
inline bool operator!=(const iterator& iter) const
{ return iter._e != _e; }
/// For comparing equality of iterators
inline bool operator==(const const_iterator& iter) const
{ return iter._e == _e; }
/// For comparing inequality of iterators
inline bool operator!=(const const_iterator& iter) const
{ return iter._e != _e; }
/// For advancing the iterator to the next element
iterator& operator++(int);
private: // Private interface
/// Constructor Helper for inline creation.
iterator( Entry** e, const PtexDict* d, int b): _d(d), _e(e), _b(b) {}
/// simple helper function for retrieving the value from the Entry
inline value_type& getValue() const{
if (_e) return (*_e)->_val;
else return _defaultVal;
}
friend class PtexDict;
friend class const_iterator;
const PtexDict* _d; ///< dictionary back reference
Entry** _e; ///< pointer to entry in table this iterator refs
int _b; ///< bucket number this references
static value_type _defaultVal; ///< Default value
};
// define the static type for the iterator
template<class T> typename PtexDict<T>::value_type PtexDict<T>::iterator::_defaultVal;
/**
@class PtexDict::const_iterator
@brief Internal class used to provide iteration through the dictionary
This works on const data types, and provides const safe access.
This class can also be created from a PtexDict::iterator class instance.
@author longson
@version <B>1.2 longson 01/16/2002:</B> Initial version based on iterator
*/
template<class T>
class PtexDict<T>::const_iterator {
public:
/// Default Constructor
const_iterator() : _d(0), _e(0), _b(0) {}
/// Proper copy constructor implementation for const_iterator
const_iterator(const const_iterator& iter) :
_d(iter._d), _e(iter._e), _b(iter._b) {}
/// Conversion constructor for iterator
const_iterator(const iterator& iter) :
_d(iter._d), _e(iter._e), _b(iter._b) {}
/// Proper assignment operator for const_iterator
inline const_iterator& operator=(const const_iterator& iter)
{ _e = iter._e; _d = iter._d; _b = iter._b; return *this; }
/// Proper assignment operator for iterator
inline const_iterator& operator=(iterator& iter)
{ _e = iter._e; _d = iter._d; _b = iter._b; return *this; }
/// Operator for obtaining the value that the const_iterator references
inline const value_type& operator*() const { return getValue(); }
/// Pointer reference operator
inline const value_type* operator->() const { return &getValue(); }
/// For determining whether or not an iterator is valid
inline operator bool() { return _e != 0; }
/// For comparing equality of iterators
inline bool operator==(const iterator& iter) const
{ return iter._e == _e; }
/// For comparing inequality of iterators
inline bool operator!=(const iterator& iter) const
{ return iter._e != _e; }
/// For comparing equality of const_iterators
inline bool operator==(const const_iterator& iter) const
{ return iter._e == _e; }
/// For comparing inequality of iterators
inline bool operator!=(const const_iterator& iter) const
{ return iter._e != _e; }
/// For advancing the iterator to the next element
const_iterator& operator++(int);
private: // Private interface
/// Constructor Helper for inline creation.
const_iterator( Entry** e, const PtexDict* d, int b): _d(d),_e(e),_b(b) {}
/// simple helper function for retrieving the value from the Entry
inline const value_type& getValue() const{
if (_e) return (*_e)->_val;
else return _defaultVal;
}
friend class PtexDict;
friend class iterator;
const PtexDict* _d; ///< dictionary back reference
Entry** _e; ///< pointer to entry in table this iterator refs
int _b; ///< bucket number this references
static value_type _defaultVal; ///< Default value
};
// define the static type for the iterator
template<class T> typename PtexDict<T>::value_type PtexDict<T>::const_iterator::_defaultVal;
template<class T>
typename PtexDict<T>::iterator& PtexDict<T>::iterator::operator++(int)
{
if (_e) {
// move to next entry
_e = &(*_e)->_next;
if (!*_e) {
// move to next non-empty bucket
for (_b++; _b < _d->_numBuckets; _b++) {
_e = &_d->_buckets[_b];
if (*_e) return *this;
}
_e = 0;
}
}
return *this;
}
template<class T>
typename PtexDict<T>::const_iterator& PtexDict<T>::const_iterator::operator++(int)
{
if (_e) {
// move to next entry
_e = &(*_e)->_next;
if (!*_e) {
// move to next non-empty bucket
for (_b++; _b < _d->_numBuckets; _b++) {
_e = &_d->_buckets[_b];
if (*_e) return *this;
}
_e = 0;
}
}
return *this;
}
template<class T>
typename PtexDict<T>::iterator PtexDict<T>::find(const char* key)
{
int keylen, hashval;
Entry** e = locate(key, keylen, hashval);
/// return a valid iterator if we found an entry, else return end()
if (e) return iterator( e, this, hashval & _bucketMask );
else return end();
}
template<class T>
typename PtexDict<T>::const_iterator PtexDict<T>::find(const char* key) const
{
int keylen, hashval;
Entry** e = locate(key, keylen, hashval);
/// return a valid iterator if we found an entry, else return end()
if (e) return const_iterator( e, this, hashval & _bucketMask );
else return end();
}
template<class T>
T& PtexDict<T>::operator[](const char* key)
{
int keylen, hashval;
Entry** e = locate(key, keylen, hashval);
if (e) return (*e)->_val.second;
// create a new entry
_numEntries++;
if (_numEntries*2 >= _numBuckets) grow();
// allocate a buffer big enough to hold Entry + (the key length )
// Note: the NULL character is already accounted for by Entry::_key's size
void* ebuf = malloc( sizeof(Entry) + (keylen) * sizeof(char) );
Entry* ne = new(ebuf) Entry; // note: placement new
// Store the values in the Entry structure
Entry** slot = &_buckets[hashval & _bucketMask];
ne->_next = *slot; *slot = ne;
ne->_hashval = hashval;
ne->_keylen = keylen;
// copy the string given into the new location
memcpy(ne->_key, key, keylen);
ne->_key[keylen] = '\0';
return ne->_val.second;
}
template<class T>
void PtexDict<T>::grow()
{
if (!_buckets) {
_numBuckets = 16;
_bucketMask = _numBuckets - 1;
_buckets = (Entry**) calloc(_numBuckets, sizeof(Entry*));
} else {
int newsize = _numBuckets * 2;
_bucketMask = newsize - 1;
Entry** newbuckets = (Entry**) calloc(newsize, sizeof(Entry*));
for (int i = 0; i < _numBuckets; i++) {
for (Entry* e = _buckets[i]; e;) {
Entry* _next = e->_next;
Entry** slot = &newbuckets[e->_hashval & _bucketMask];
e->_next = *slot; *slot = e;
e = _next;
}
}
free(_buckets);
_buckets = newbuckets;
_numBuckets = newsize;
}
}
template<class T>
bool PtexDict<T>::erase(const char* key)
{
iterator iter = find(key);
if (!iter) return false;
erase(iter);
return true; // valid entry to remove
}
template<class T>
typename PtexDict<T>::iterator PtexDict<T>::erase(iterator iter)
{
Entry** eptr = iter._e;
if (!eptr) return iter;
// patch around deleted entry
Entry* e = *eptr;
Entry* next = e->_next;
if (!next) iter++; // advance iterator if at end of chain
*eptr = next;
// destroy entry. This is a strange destroy but is necessary because of
// the way Entry() is allocated by using malloc above.
e->~Entry(); // note: explicit dtor call
free(e); // free memory allocated.
_numEntries--;
return iter;
}
template<class T>
void PtexDict<T>::clear()
{
for (iterator i=begin(); i != end(); i = erase(i));
free(_buckets);
_buckets = 0;
_numEntries = 0;
_numBuckets = 0;
}
#endif //PtexDict_h

455
extern/ptex/src/ptex/PtexFilters.cpp vendored Normal file
View File

@@ -0,0 +1,455 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "PtexPlatform.h"
#include "Ptexture.h"
#include "PtexSeparableFilter.h"
#include "PtexSeparableKernel.h"
#include "PtexTriangleFilter.h"
namespace {
/** Point-sampling filter for rectangular textures */
class PtexPointFilter : public PtexFilter, public Ptex
{
public:
PtexPointFilter(PtexTexture* tx) : _tx(tx) {}
virtual void release() { delete this; }
virtual void eval(float* result, int firstchan, int nchannels,
int faceid, float u, float v,
float /*uw1*/, float /*vw1*/, float /*uw2*/, float /*vw2*/,
float /*width*/, float /*blur*/)
{
if (!_tx || nchannels <= 0) return;
if (faceid < 0 || faceid >= _tx->numFaces()) return;
const FaceInfo& f = _tx->getFaceInfo(faceid);
int resu = f.res.u(), resv = f.res.v();
int ui = PtexUtils::clamp(int(u*resu), 0, resu-1);
int vi = PtexUtils::clamp(int(v*resv), 0, resv-1);
_tx->getPixel(faceid, ui, vi, result, firstchan, nchannels);
}
private:
PtexTexture* _tx;
};
/** Point-sampling filter for triangular textures */
class PtexPointFilterTri : public PtexFilter, public Ptex
{
public:
PtexPointFilterTri(PtexTexture* tx) : _tx(tx) {}
virtual void release() { delete this; }
virtual void eval(float* result, int firstchan, int nchannels,
int faceid, float u, float v,
float /*uw1*/, float /*vw1*/, float /*uw2*/, float /*vw2*/,
float /*width*/, float /*blur*/)
{
if (!_tx || nchannels <= 0) return;
if (faceid < 0 || faceid >= _tx->numFaces()) return;
const FaceInfo& f = _tx->getFaceInfo(faceid);
int res = f.res.u();
int resm1 = res - 1;
float ut = u * res, vt = v * res;
int ui = PtexUtils::clamp(int(ut), 0, resm1);
int vi = PtexUtils::clamp(int(vt), 0, resm1);
float uf = ut - ui, vf = vt - vi;
if (uf + vf <= 1.0) {
// "even" triangles are stored in lower-left half-texture
_tx->getPixel(faceid, ui, vi, result, firstchan, nchannels);
}
else {
// "odd" triangles are stored in upper-right half-texture
_tx->getPixel(faceid, resm1-vi, resm1-ui, result, firstchan, nchannels);
}
}
private:
PtexTexture* _tx;
};
/** Separable filter with width=4 support.
The kernel width is calculated as a multiple of 4 times the filter
width and the texture resolution is chosen such that each kernel
axis has between 4 and 8.
For kernel widths too large to handle (because the kernel would
extend significantly beyond both sides of the face), a special
Hermite smoothstep is used to interpolate the two nearest 2 samples
along the affected axis (or axes).
*/
class PtexWidth4Filter : public PtexSeparableFilter
{
public:
typedef double KernelFn(double x, const double* c);
PtexWidth4Filter(PtexTexture* tx, const PtexFilter::Options& opts, KernelFn k, const double* c = 0)
: PtexSeparableFilter(tx, opts), _k(k), _c(c) {}
virtual void buildKernel(PtexSeparableKernel& k, float u, float v, float uw, float vw,
Res faceRes)
{
buildKernelAxis(k.res.ulog2, k.u, k.uw, k.ku, u, uw, faceRes.ulog2);
buildKernelAxis(k.res.vlog2, k.v, k.vw, k.kv, v, vw, faceRes.vlog2);
}
private:
double blur(double x)
{
// 2-unit (x in -1..1) cubic hermite kernel
// this produces a blur roughly 1.5 times that of the 4-unit b-spline kernel
x = fabs(x);
return x < 1 ? (2*x-3)*x*x+1 : 0;
}
void buildKernelAxis(int8_t& k_ureslog2, int& k_u, int& k_uw, double* ku,
float u, float uw, int f_ureslog2)
{
// build 1 axis (note: "u" labels may repesent either u or v axis)
// clamp filter width to no smaller than a texel
uw = PtexUtils::max(uw, 1.0f/(1<<f_ureslog2));
// compute desired texture res based on filter width
k_ureslog2 = int(ceil(log2(1.0/uw)));
int resu = 1 << k_ureslog2;
double uwlo = 1.0/resu; // smallest filter width for this res
// compute lerp weights (amount to blend towards next-lower res)
double lerp2 = _options.lerp ? (uw-uwlo)/uwlo : 0;
double lerp1 = 1-lerp2;
// adjust for large filter widths
if (uw >= .25) {
if (uw < .5) {
k_ureslog2 = 2;
double upix = u * 4 - 0.5;
int u1 = int(ceil(upix - 2)), u2 = int(ceil(upix + 2));
u1 = u1 & ~1; // round down to even pair
u2 = (u2 + 1) & ~1; // round up to even pair
k_u = u1;
k_uw = u2-u1;
double x1 = u1-upix;
for (int i = 0; i < k_uw; i+=2) {
double xa = x1 + i, xb = xa + 1, xc = (xa+xb)*0.25;
// spread the filter gradually to approach the next-lower-res width
// at uw = .5, s = 1.0; at uw = 1, s = 0.8
double s = 1.0/(uw + .75);
double ka = _k(xa, _c), kb = _k(xb, _c), kc = blur(xc*s);
ku[i] = ka * lerp1 + kc * lerp2;
ku[i+1] = kb * lerp1 + kc * lerp2;
}
return;
}
else if (uw < 1) {
k_ureslog2 = 1;
double upix = u * 2 - 0.5;
k_u = int(floor(u - .5))*2;
k_uw = 4;
double x1 = k_u-upix;
for (int i = 0; i < k_uw; i+=2) {
double xa = x1 + i, xb = xa + 1, xc = (xa+xb)*0.5;
// spread the filter gradually to approach the next-lower-res width
// at uw = .5, s = .8; at uw = 1, s = 0.5
double s = 1.0/(uw*1.5 + .5);
double ka = blur(xa*s), kb = blur(xb*s), kc = blur(xc*s);
ku[i] = ka * lerp1 + kc * lerp2;
ku[i+1] = kb * lerp1 + kc * lerp2;
}
return;
}
else {
// use res 0 (1 texel per face) w/ no lerping
// (future: use face-blended values for filter > 2)
k_ureslog2 = 0;
double upix = u - .5;
k_uw = 2;
double ui = floor(upix);
k_u = int(ui);
ku[0] = blur(upix-ui);
ku[1] = 1-ku[0];
return;
}
}
// convert from normalized coords to pixel coords
double upix = u * resu - 0.5;
double uwpix = uw * resu;
// find integer pixel extent: [u,v] +/- [2*uw,2*vw]
// (kernel width is 4 times filter width)
double dupix = 2*uwpix;
int u1 = int(ceil(upix - dupix)), u2 = int(ceil(upix + dupix));
if (lerp2) {
// lerp kernel weights towards next-lower res
// extend kernel width to cover even pairs
u1 = u1 & ~1;
u2 = (u2 + 1) & ~1;
k_u = u1;
k_uw = u2-u1;
// compute kernel weights
double step = 1.0/uwpix, x1 = (u1-upix)*step;
for (int i = 0; i < k_uw; i+=2) {
double xa = x1 + i*step, xb = xa + step, xc = (xa+xb)*0.5;
double ka = _k(xa, _c), kb = _k(xb, _c), kc = _k(xc, _c);
ku[i] = ka * lerp1 + kc * lerp2;
ku[i+1] = kb * lerp1 + kc * lerp2;
}
}
else {
k_u = u1;
k_uw = u2-u1;
// compute kernel weights
double x1 = (u1-upix)/uwpix, step = 1.0/uwpix;
for (int i = 0; i < k_uw; i++) ku[i] = _k(x1 + i*step, _c);
}
}
KernelFn* _k; // kernel function
const double* _c; // kernel coefficients (if any)
};
/** Separable bicubic filter */
class PtexBicubicFilter : public PtexWidth4Filter
{
public:
PtexBicubicFilter(PtexTexture* tx, const PtexFilter::Options& opts, float sharpness)
: PtexWidth4Filter(tx, opts, kernelFn, _coeffs)
{
// compute Cubic filter coefficients:
// abs(x) < 1:
// 1/6 * ((12 - 9*B - 6*C)*x^3 + (-18 + 12*B + 6*C)*x^2 + (6 - 2*B))
// == c[0]*x^3 + c[1]*x^2 + c[2]
// abs(x) < 2:
// 1/6 * ((-B - 6*C)*x^3 + (6*B + 30*C)*x^2 + (-12*B - 48*C)*x + (8*B + 24*C))
// == c[3]*x^3 + c[4]*x^2 + c[5]*x + c[6]
// else: 0
float B = 1 - sharpness; // choose C = (1-B)/2
_coeffs[0] = 1.5 - B;
_coeffs[1] = 1.5 * B - 2.5;
_coeffs[2] = 1 - (1./3) * B;
_coeffs[3] = (1./3) * B - 0.5;
_coeffs[4] = 2.5 - 1.5 * B;
_coeffs[5] = 2 * B - 4;
_coeffs[6] = 2 - (2./3) * B;
}
private:
static double kernelFn(double x, const double* c)
{
x = fabs(x);
if (x < 1) return (c[0]*x + c[1])*x*x + c[2];
else if (x < 2) return ((c[3]*x + c[4])*x + c[5])*x + c[6];
else return 0;
}
double _coeffs[7]; // filter coefficients for current sharpness
};
/** Separable gaussian filter */
class PtexGaussianFilter : public PtexWidth4Filter
{
public:
PtexGaussianFilter(PtexTexture* tx, const PtexFilter::Options& opts)
: PtexWidth4Filter(tx, opts, kernelFn) {}
private:
static double kernelFn(double x, const double*)
{
return exp(-2*x*x);
}
};
/** Rectangular box filter.
The box is convolved with the texels as area samples and thus the kernel function is
actually trapezoidally shaped.
*/
class PtexBoxFilter : public PtexSeparableFilter
{
public:
PtexBoxFilter(PtexTexture* tx, const PtexFilter::Options& opts)
: PtexSeparableFilter(tx, opts) {}
protected:
virtual void buildKernel(PtexSeparableKernel& k, float u, float v, float uw, float vw,
Res faceRes)
{
// clamp filter width to no larger than 1.0
uw = PtexUtils::min(uw, 1.0f);
vw = PtexUtils::min(vw, 1.0f);
// clamp filter width to no smaller than a texel
uw = PtexUtils::max(uw, 1.0f/(faceRes.u()));
vw = PtexUtils::max(vw, 1.0f/(faceRes.v()));
// compute desired texture res based on filter width
int ureslog2 = int(ceil(log2(1.0/uw))),
vreslog2 = int(ceil(log2(1.0/vw)));
Res res(ureslog2, vreslog2);
k.res = res;
// convert from normalized coords to pixel coords
u = u * k.res.u();
v = v * k.res.v();
uw *= k.res.u();
vw *= k.res.v();
// find integer pixel extent: [u,v] +/- [uw/2,vw/2]
// (box is 1 unit wide for a 1 unit filter period)
double u1 = u - 0.5*uw, u2 = u + 0.5*uw;
double v1 = v - 0.5*vw, v2 = v + 0.5*vw;
double u1floor = floor(u1), u2ceil = ceil(u2);
double v1floor = floor(v1), v2ceil = ceil(v2);
k.u = int(u1floor);
k.v = int(v1floor);
k.uw = int(u2ceil)-k.u;
k.vw = int(v2ceil)-k.v;
// compute kernel weights along u and v directions
computeWeights(k.ku, k.uw, 1-(u1-u1floor), 1-(u2ceil-u2));
computeWeights(k.kv, k.vw, 1-(v1-v1floor), 1-(v2ceil-v2));
}
private:
void computeWeights(double* kernel, int size, double f1, double f2)
{
assert(size >= 1 && size <= 3);
if (size == 1) {
kernel[0] = f1 + f2 - 1;
}
else {
kernel[0] = f1;
for (int i = 1; i < size-1; i++) kernel[i] = 1.0;
kernel[size-1] = f2;
}
}
};
/** Bilinear filter (for rectangular textures) */
class PtexBilinearFilter : public PtexSeparableFilter
{
public:
PtexBilinearFilter(PtexTexture* tx, const PtexFilter::Options& opts)
: PtexSeparableFilter(tx, opts) {}
protected:
virtual void buildKernel(PtexSeparableKernel& k, float u, float v, float uw, float vw,
Res faceRes)
{
// clamp filter width to no larger than 1.0
uw = PtexUtils::min(uw, 1.0f);
vw = PtexUtils::min(vw, 1.0f);
// clamp filter width to no smaller than a texel
uw = PtexUtils::max(uw, 1.0f/(faceRes.u()));
vw = PtexUtils::max(vw, 1.0f/(faceRes.v()));
// choose resolution closest to filter res
// there are three choices of "closest" that come to mind:
// 1) closest in terms of filter width, i.e. period of signal
// 2) closest in terms of texel resolution, (1 / filter width), i.e. freq of signal
// 3) closest in terms of resolution level (log2(1/filter width))
// Choice (1) probably makes the most sense. In log2 terms, that means you should
// use the next higher level when the fractional part of the log2 res is > log2(1/.75),
// and you should add 1-log2(1/.75) to round up.
const double roundWidth = 0.5849625007211563; // 1-log2(1/.75)
int ureslog2 = int(log2(1.0/uw) + roundWidth);
int vreslog2 = int(log2(1.0/vw) + roundWidth);
Res res(ureslog2, vreslog2);
k.res = res;
// convert from normalized coords to pixel coords
double upix = u * k.res.u() - 0.5;
double vpix = v * k.res.v() - 0.5;
float ufloor = floor(upix);
float vfloor = floor(vpix);
k.u = int(ufloor);
k.v = int(vfloor);
k.uw = 2;
k.vw = 2;
// compute kernel weights
float ufrac = upix-ufloor, vfrac = vpix-vfloor;
k.ku[0] = 1 - ufrac;
k.ku[1] = ufrac;
k.kv[0] = 1 - vfrac;
k.kv[1] = vfrac;
}
};
} // end local namespace
PtexFilter* PtexFilter::getFilter(PtexTexture* tex, const PtexFilter::Options& opts)
{
switch (tex->meshType()) {
case Ptex::mt_quad:
switch (opts.filter) {
case f_point: return new PtexPointFilter(tex);
case f_bilinear: return new PtexBilinearFilter(tex, opts);
default:
case f_box: return new PtexBoxFilter(tex, opts);
case f_gaussian: return new PtexGaussianFilter(tex, opts);
case f_bicubic: return new PtexBicubicFilter(tex, opts, opts.sharpness);
case f_bspline: return new PtexBicubicFilter(tex, opts, 0.0);
case f_catmullrom: return new PtexBicubicFilter(tex, opts, 1.0);
case f_mitchell: return new PtexBicubicFilter(tex, opts, 2.0/3.0);
}
break;
case Ptex::mt_triangle:
switch (opts.filter) {
case f_point: return new PtexPointFilterTri(tex);
default: return new PtexTriangleFilter(tex, opts);
}
break;
}
return 0;
}

105
extern/ptex/src/ptex/PtexHalf.cpp vendored Normal file
View File

@@ -0,0 +1,105 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <math.h>
#include "PtexHalf.h"
uint16_t PtexHalf::f2hTable[512];
uint32_t PtexHalf::h2fTable[65536];
/** Table initializations. */
static bool PtexHalfInit()
{
union { int i; float f; } u;
for (int h = 0; h < 65536; h++) {
int s = (h & 0x8000)<<16;
int m = h & 0x03ff;
int e = h&0x7c00;
if (unsigned(e-1) < ((31<<10)-1)) {
// normal case
u.i = s|(((e+0x1c000)|m)<<13);
}
else if (e == 0) {
// denormalized
if (!(h&0x8000)) u.f = float(5.9604644775390625e-08*m);
else u.f = float(-5.9604644775390625e-08*m);
}
else {
// inf/nan, preserve low bits of m for nan code
u.i = s|0x7f800000|(m<<13);
}
PtexHalf::h2fTable[h] = u.i;
}
for (int i = 0; i < 512; i++) {
int f = i << 23;
int e = (f & 0x7f800000) - 0x38000000;
// normalized iff (0 < e < 31)
if (unsigned(e-1) < ((31<<23)-1)) {
int s = ((f>>16) & 0x8000);
int m = f & 0x7fe000;
// add bit 12 to round
PtexHalf::f2hTable[i] = (s|((e|m)>>13))+((f>>12)&1);
}
}
return 1;
}
static bool PtexHalfInitialized = PtexHalfInit();
/** Handle exceptional cases for half-to-float conversion */
uint16_t PtexHalf::fromFloat_except(uint32_t i)
{
uint32_t s = ((i>>16) & 0x8000);
int32_t e = ((i>>13) & 0x3fc00) - 0x1c000;
if (e <= 0) {
// denormalized
union { uint32_t i; float f; } u;
u.i = i;
return s | int(fabs(u.f)*1.6777216e7 + .5);
}
if (e == 0x23c00)
// inf/nan, preserve msb bits of m for nan code
return s|0x7c00|((i&0x7fffff)>>13);
else
// overflow - convert to inf
return s|0x7c00;
}

118
extern/ptex/src/ptex/PtexHalf.h vendored Normal file
View File

@@ -0,0 +1,118 @@
#ifndef PtexHalf_h
#define PtexHalf_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/**
@file PtexHalf.h
@brief Half-precision floating-point type.
*/
#if defined(_WIN32) || defined(_WINDOWS) || defined(_MSC_VER)
# ifndef PTEX_STATIC
# ifdef PTEX_EXPORTS
# define PTEXAPI __declspec(dllexport)
# else
# define PTEXAPI __declspec(dllimport)
# endif
# else
# define PTEXAPI
# endif
#else
# define PTEXAPI
#endif
#include "PtexInt.h"
/**
@class PtexHalf
@brief Half-precision (16-bit) floating-point type.
This type should be compatible with opengl, openexr, and IEEE 754r.
The range is [-65504.0, 65504.0] and the precision is about 1 part
in 2000 (3.3 decimal places).
From OpenGL spec 2.1.2:
A 16-bit floating-point number has a 1-bit sign (S), a 5-bit
exponent (E), and a 10-bit mantissa (M). The value of a 16-bit
floating-point number is determined by the following:
\verbatim
(-1)^S * 0.0, if E == 0 and M == 0,
(-1)^S * 2^-14 * (M/2^10), if E == 0 and M != 0,
(-1)^S * 2^(E-15) * (1 + M/2^10), if 0 < E < 31,
(-1)^S * INF, if E == 31 and M == 0, or
NaN, if E == 31 and M != 0 \endverbatim
*/
struct PtexHalf {
uint16_t bits;
/// Default constructor, value is undefined
PtexHalf() {}
PtexHalf(float val) : bits(fromFloat(val)) {}
PtexHalf(double val) : bits(fromFloat(float(val))) {}
operator float() const { return toFloat(bits); }
PtexHalf& operator=(float val) { bits = fromFloat(val); return *this; }
static float toFloat(uint16_t h)
{
union { uint32_t i; float f; } u;
u.i = h2fTable[h];
return u.f;
}
static uint16_t fromFloat(float val)
{
if (val==0) return 0;
union { uint32_t i; float f; } u;
u.f = val;
int e = f2hTable[(u.i>>23)&0x1ff];
if (e) return e + (((u.i&0x7fffff) + 0x1000) >> 13);
return fromFloat_except(u.i);
}
private:
PTEXAPI static uint16_t fromFloat_except(uint32_t val);
#ifndef DOXYGEN
/* internal */ public:
#endif
PTEXAPI static uint32_t h2fTable[65536];
PTEXAPI static uint16_t f2hTable[512];
};
#endif

352
extern/ptex/src/ptex/PtexHashMap.h vendored Normal file
View File

@@ -0,0 +1,352 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/**
@file PtexHashMap.h
@brief Contains PtexHashMap, a lightweight hash table.
*/
#ifndef PtexHashMap_h
#define PtexHashMap_h
/**
@class PtexHashMap
@brief A lightweight hash table.
<P>
The hash table automatically doubles in size when it is more than 50% full.
<P>
The interface is mostely compatible with std::hash_map<>, though not all methods
are provided. Methods provided:
<UL>
<LI>iterator begin();
<LI>iterator end();
<LI>DataType& operator[] (KeyType key);
<LI>iterator find(KeyType key) const;
<LI>bool erase(KeyType key);
<LI>iterator erase(iterator);
<LI>void clear();
<LI>int size() const;
</UL>
@author brentb
@version <B>1.0 brentb 11/01/2000:</B> Initial version
@version <B>1.1 longson 06/26/2001:</B> Added file and class comment headers
@version <B>1.2 brentb 105/2006:</B> Generalized IntDict into general hash map
*/
/**
@class PtexHashMap::iterator
@brief Internal class used to provide iteration through the hash table
@author brentb
@version <B>1.0 brentb 11/01/2000:</B> Initial version
@version <B>1.1 longson 06/26/2001:</B> Added file and class comment headers
*/
template<typename KeyType, typename DataType, typename HashFn>
class PtexHashMap
{
struct Entry; // forward decl
public:
typedef KeyType key_type;
typedef DataType data_type;
typedef HashFn hash_fn;
struct value_type {
key_type first;
data_type second;
value_type() : first(), second() {}
value_type(const KeyType& first, const DataType& second)
: first(first), second(second) {}
};
class iterator {
public:
/// Default Constructor
iterator() : e(0), h(0), b(0) {}
/// Proper copy constructor implementation
iterator(const iterator& iter) : e(iter.e), h(iter.h), b(iter.b) {}
/// Operator for obtaining the value that the iterator references
value_type operator*() const {
if (e) return value_type((*e)->key, (*e)->val);
return value_type();
}
/// Pointer reference operator
value_type* operator->() const {
static value_type v;
v = operator*();
return &v;
}
/// Proper assignment operator
iterator& operator=(const iterator& iter) {
e = iter.e; h = iter.h; b = iter.b; return *this;
}
/// For comparing equality of iterators
bool operator==(const iterator& iter) const { return iter.e == e; }
/// For comparing inequality of iterators
bool operator!=(const iterator& iter) const { return iter.e != e; }
/// For advancing the iterator to the next element
iterator& operator++(int);
private:
friend class PtexHashMap;
Entry** e; // pointer to prev entry or hash entry
const PtexHashMap* h;
int b; // bucket number
};
/// Returns an iterator referencing the beginning of the table
iterator begin() const
{
iterator iter;
iter.h = this;
for (iter.b = 0; iter.b < _numBuckets; iter.b++) {
iter.e = &_buckets[iter.b];
if (*iter.e) return iter;
}
iter.e = 0;
return iter;
}
/// Returns an iteraot referencing the location just beyond the table.
iterator end() const
{
iterator iter;
iter.h = this; iter.b = 0; iter.e = 0;
return iter;
}
/// Default contructor initializes the hash table.
PtexHashMap() : _numEntries(0), _numBuckets(0), _bucketMask(0), _buckets(0) {}
/// Non-Virtual destructor by design, clears the entries in the hash table
~PtexHashMap() { clear(); }
/// Locates an entry, creating a new one if necessary.
/** operator[] will look up an entry and return the value. A new entry
will be created (using the default ctor for DataType) if one doesn't exist.
*/
DataType& operator[](const KeyType& key);
/// Locates an entry, without creating a new one.
/** find will locate an entry, but won't create a new one. The result is
returned as a pair of key and value. The returned key points to the
internal key string and will remain valid until the entry is deleted.
If the key is not found, both the returned key and value pointers will
be NULL.
*/
iterator find(const KeyType& key) const;
/// Will remove an entry. It will return TRUE if an entry was found.
bool erase(const KeyType& key);
/// Will remove an entry. It will return a iterator to the next element
iterator erase(iterator iter);
/// clear will remove all entries and free the table
void clear();
/// number of entries in the hash
int size() const { return _numEntries; }
private:
/// Copy constructor prohibited by design.
PtexHashMap(const PtexHashMap&); // disallow
/// Assignment operator prohibited by design.
bool operator=(const PtexHashMap&); // disallow
friend class iterator;
struct Entry {
Entry() : val() {}
Entry* next;
KeyType key;
DataType val;
};
/// Returns a pointer to the desired entry, based on the key.
Entry** locate(const KeyType& key) const
{
if (!_buckets) return 0;
for (Entry** e = &_buckets[hash(key) & _bucketMask]; *e; e = &(*e)->next)
if ((*e)->key == key)
return e;
return 0;
}
/// Used to increase the size of the table if necessary
void grow();
int _numEntries;
int _numBuckets;
int _bucketMask;
Entry** _buckets;
HashFn hash;
};
template<class KeyType, class DataType, class HashFn>
typename PtexHashMap<KeyType, DataType, HashFn>::iterator&
PtexHashMap<KeyType, DataType, HashFn>::iterator::operator++(int)
{
if (e) {
// move to next entry
e = &(*e)->next;
if (!*e) {
// move to next non-empty bucket
for (b++; b < h->_numBuckets; b++) {
e = &h->_buckets[b];
if (*e) return *this;
}
e = 0;
}
}
return *this;
}
template<class KeyType, class DataType, class HashFn>
typename PtexHashMap<KeyType, DataType, HashFn>::iterator
PtexHashMap<KeyType, DataType, HashFn>::find(const KeyType& key) const
{
iterator iter;
Entry** e = locate(key);
if (e) {
iter.h = this;
iter.e = e;
iter.b = hash(key) & _bucketMask;
} else iter = end();
return iter;
}
template<class KeyType, class DataType, class HashFn>
DataType& PtexHashMap<KeyType, DataType, HashFn>::operator[](const KeyType& key)
{
Entry** e = locate(key);
if (e) return (*e)->val;
// create a new entry
_numEntries++;
if (_numEntries*2 >= _numBuckets) grow();
void* ebuf = malloc(sizeof(Entry));
Entry* ne = new(ebuf) Entry; // note: placement new
Entry** slot = &_buckets[hash(key) & _bucketMask];
ne->next = *slot; *slot = ne;
ne->key = key;
return ne->val;
}
template<class KeyType, class DataType, class HashFn>
void PtexHashMap<KeyType, DataType, HashFn>::grow()
{
if (!_buckets) {
_numBuckets = 16;
_bucketMask = _numBuckets - 1;
_buckets = (Entry**) calloc(_numBuckets, sizeof(Entry*));
} else {
int newsize = _numBuckets * 2;
_bucketMask = newsize - 1;
Entry** newbuckets = (Entry**) calloc(newsize, sizeof(Entry*));
for (int i = 0; i < _numBuckets; i++) {
for (Entry* e = _buckets[i]; e;) {
Entry* next = e->next;
Entry** slot = &newbuckets[hash(e->key) & _bucketMask];
e->next = *slot; *slot = e;
e = next;
}
}
free(_buckets);
_buckets = newbuckets;
_numBuckets = newsize;
}
}
template<class KeyType, class DataType, class HashFn>
bool PtexHashMap<KeyType, DataType, HashFn>::erase(const KeyType& key)
{
iterator iter = find(key);
if (iter == end()) return 0;
erase(iter);
return 1;
}
template<class KeyType, class DataType, class HashFn>
typename PtexHashMap<KeyType, DataType, HashFn>::iterator
PtexHashMap<KeyType, DataType, HashFn>::erase(iterator iter)
{
Entry** eptr = iter.e;
if (!eptr) return iter;
// patch around deleted entry
Entry* e = *eptr;
Entry* next = e->next;
if (!next) iter++; // advance iterator if at end of chain
*eptr = next;
// destroy entry
e->~Entry(); // note: explicit dtor call
free(e);
_numEntries--;
return iter;
}
template<class KeyType, class DataType, class HashFn>
void PtexHashMap<KeyType, DataType, HashFn>::clear()
{
for (iterator i = begin(); i != end(); i = erase(i));
free(_buckets);
_buckets = 0;
_numEntries = 0;
_numBuckets = 0;
}
#endif

119
extern/ptex/src/ptex/PtexIO.h vendored Normal file
View File

@@ -0,0 +1,119 @@
#ifndef PtexIO_h
#define PtexIO_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "Ptexture.h"
struct PtexIO : public Ptex {
struct Header {
uint32_t magic;
uint32_t version;
MeshType meshtype:32;
DataType datatype:32;
int32_t alphachan;
uint16_t nchannels;
uint16_t nlevels;
uint32_t nfaces;
uint32_t extheadersize;
uint32_t faceinfosize;
uint32_t constdatasize;
uint32_t levelinfosize;
uint32_t minorversion;
uint64_t leveldatasize;
uint32_t metadatazipsize;
uint32_t metadatamemsize;
int pixelSize() const { return DataSize(datatype) * nchannels; }
bool hasAlpha() const { return alphachan >= 0 && alphachan < nchannels; }
};
struct ExtHeader {
BorderMode ubordermode:32;
BorderMode vbordermode:32;
uint32_t lmdheaderzipsize;
uint32_t lmdheadermemsize;
uint64_t lmddatasize;
uint64_t editdatasize;
uint64_t editdatapos;
};
struct LevelInfo {
uint64_t leveldatasize;
uint32_t levelheadersize;
uint32_t nfaces;
LevelInfo() : leveldatasize(0), levelheadersize(0), nfaces(0) {}
};
enum Encoding { enc_constant, enc_zipped, enc_diffzipped, enc_tiled };
struct FaceDataHeader {
uint32_t data; // bits 0..29 = blocksize, bits 30..31 = encoding
uint32_t blocksize() const { return data & 0x3fffffff; }
Encoding encoding() const { return Encoding((data >> 30) & 0x3); }
uint32_t& val() { return *(uint32_t*) this; }
const uint32_t& val() const { return *(uint32_t*) this; }
void set(uint32_t blocksize, Encoding encoding)
{ data = (blocksize & 0x3fffffff) | ((encoding & 0x3) << 30); }
FaceDataHeader() : data(0) {}
};
enum EditType { et_editfacedata, et_editmetadata };
struct EditFaceDataHeader {
uint32_t faceid;
FaceInfo faceinfo;
FaceDataHeader fdh;
};
struct EditMetaDataHeader {
uint32_t metadatazipsize;
uint32_t metadatamemsize;
};
static const uint32_t Magic = 'P' | ('t'<<8) | ('e'<<16) | ('x'<<24);
static const int HeaderSize = sizeof(Header);
static const int ExtHeaderSize = sizeof(ExtHeader);
static const int LevelInfoSize = sizeof(LevelInfo);
static const int FaceDataHeaderSize = sizeof(FaceDataHeader);
static const int EditFaceDataHeaderSize = sizeof(EditFaceDataHeader);
static const int EditMetaDataHeaderSize = sizeof(EditMetaDataHeader);
// these constants can be tuned for performance
static const int BlockSize = 16384; // target block size for file I/O
static const int TileSize = 65536; // target tile size (uncompressed)
static const int AllocaMax = 16384; // max size for using alloca
static const int MetaDataThreshold = 1024; // cutoff for large meta data
static bool LittleEndian() {
short word = 0x0201;
return *(char*)&word == 1;
}
};
#endif

57
extern/ptex/src/ptex/PtexInt.h vendored Normal file
View File

@@ -0,0 +1,57 @@
#ifndef PtexInt_h
#define PtexInt_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/**
@file PtexInt.h
@brief Portable fixed-width integer types
*/
#if defined(_WIN32) || defined(_WINDOWS) || defined(_MSC_VER)
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#else
#include <stdint.h>
#endif
#endif

79
extern/ptex/src/ptex/PtexMutex.h vendored Normal file
View File

@@ -0,0 +1,79 @@
#ifndef PtexMutex_h
#define PtexMutex_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
// #define DEBUG_THREADING
/** For internal use only */
namespace PtexInternal {
#ifndef NDEBUG
template <class T>
class DebugLock : public T {
public:
DebugLock() : _locked(0) {}
void lock() { T::lock(); _locked = 1; }
void unlock() { assert(_locked); _locked = 0; T::unlock(); }
bool locked() { return _locked != 0; }
private:
int _locked;
};
#endif
/** Automatically acquire and release lock within enclosing scope. */
template <class T>
class AutoLock {
public:
AutoLock(T& m) : _m(m) { _m.lock(); }
~AutoLock() { _m.unlock(); }
private:
T& _m;
};
#ifndef NDEBUG
// add debug wrappers to mutex and spinlock
typedef DebugLock<_Mutex> Mutex;
typedef DebugLock<_SpinLock> SpinLock;
#else
typedef _Mutex Mutex;
typedef _SpinLock SpinLock;
#endif
typedef AutoLock<Mutex> AutoMutex;
typedef AutoLock<SpinLock> AutoSpin;
}
#endif

160
extern/ptex/src/ptex/PtexPlatform.h vendored Normal file
View File

@@ -0,0 +1,160 @@
#ifndef PtexPlatform_h
#define PtexPlatform_h
#define PtexPlatform_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/** @file PtexPlatform.h
@brief Platform-specific classes, functions, and includes.
*/
// platform-specific includes
#if defined(_WIN32) || defined(_WINDOWS) || defined(_MSC_VER)
#ifndef WINDOWS
#define WINDOWS
#endif
#define _CRT_NONSTDC_NO_DEPRECATE 1
#define _CRT_SECURE_NO_DEPRECATE 1
#define NOMINMAX 1
// windows - defined for both Win32 and Win64
#include <Windows.h>
#include <malloc.h>
#include <io.h>
#include <tchar.h>
#include <process.h>
#else
// linux/unix/posix
#include <stdlib.h>
#include <alloca.h>
#include <string.h>
#include <pthread.h>
// OS for spinlock
#ifdef __APPLE__
#include <libkern/OSAtomic.h>
#include <sys/types.h>
#endif
#endif
// general includes
#include <stdio.h>
#include <math.h>
#include <assert.h>
// missing functions on Windows
#ifdef WINDOWS
#define snprintf sprintf_s
#define strtok_r strtok_s
typedef __int64 FilePos;
#define fseeko _fseeki64
#define ftello _ftelli64
inline double log2(double x) {
return log(x) * 1.4426950408889634;
}
#else
typedef off_t FilePos;
#endif
namespace PtexInternal {
/*
* Mutex/SpinLock classes
*/
#ifdef WINDOWS
class _Mutex {
public:
_Mutex() { _mutex = CreateMutex(NULL, FALSE, NULL); }
~_Mutex() { CloseHandle(_mutex); }
void lock() { WaitForSingleObject(_mutex, INFINITE); }
void unlock() { ReleaseMutex(_mutex); }
private:
HANDLE _mutex;
};
class _SpinLock {
public:
_SpinLock() { InitializeCriticalSection(&_spinlock); }
~_SpinLock() { DeleteCriticalSection(&_spinlock); }
void lock() { EnterCriticalSection(&_spinlock); }
void unlock() { LeaveCriticalSection(&_spinlock); }
private:
CRITICAL_SECTION _spinlock;
};
#else
// assume linux/unix/posix
class _Mutex {
public:
_Mutex() { pthread_mutex_init(&_mutex, 0); }
~_Mutex() { pthread_mutex_destroy(&_mutex); }
void lock() { pthread_mutex_lock(&_mutex); }
void unlock() { pthread_mutex_unlock(&_mutex); }
private:
pthread_mutex_t _mutex;
};
#ifdef __APPLE__
class _SpinLock {
public:
_SpinLock() { _spinlock = 0; }
~_SpinLock() { }
void lock() { OSSpinLockLock(&_spinlock); }
void unlock() { OSSpinLockUnlock(&_spinlock); }
private:
OSSpinLock _spinlock;
};
#else
class _SpinLock {
public:
_SpinLock() { pthread_spin_init(&_spinlock, PTHREAD_PROCESS_PRIVATE); }
~_SpinLock() { pthread_spin_destroy(&_spinlock); }
void lock() { pthread_spin_lock(&_spinlock); }
void unlock() { pthread_spin_unlock(&_spinlock); }
private:
pthread_spinlock_t _spinlock;
};
#endif // __APPLE__
#endif
}
#endif // PtexPlatform_h

1357
extern/ptex/src/ptex/PtexReader.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

613
extern/ptex/src/ptex/PtexReader.h vendored Normal file
View File

@@ -0,0 +1,613 @@
#ifndef PtexReader_h
#define PtexReader_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <stdio.h>
#include <zlib.h>
#include <vector>
#include <string>
#include <map>
#include "Ptexture.h"
#include "PtexIO.h"
#include "PtexCache.h"
#include "PtexUtils.h"
#include "PtexHashMap.h"
using namespace PtexInternal;
#ifndef NDEBUG
#include <assert.h>
template<typename T> class safevector : public std::vector<T>
{
public:
safevector() : std::vector<T>() {}
safevector(size_t n, const T& val = T()) : std::vector<T>(n, val) {}
const T& operator[] (size_t n) const {
assert(n < std::vector<T>::size());
return std::vector<T>::operator[](n);
}
T& operator[] (size_t n) {
assert(n < std::vector<T>::size());
return std::vector<T>::operator[](n);
}
};
#else
#define safevector std::vector
#endif
class PtexReader : public PtexCachedFile, public PtexTexture, public PtexIO {
public:
PtexReader(void** parent, PtexCacheImpl* cache, bool premultiply,
PtexInputHandler* handler);
bool open(const char* path, Ptex::String& error);
void setOwnsCache() { _ownsCache = true; }
virtual void release();
virtual const char* path() { return _path.c_str(); }
virtual Ptex::MeshType meshType() { return MeshType(_header.meshtype); }
virtual Ptex::DataType dataType() { return DataType(_header.datatype); }
virtual Ptex::BorderMode uBorderMode() { return BorderMode(_extheader.ubordermode); };
virtual Ptex::BorderMode vBorderMode() { return BorderMode(_extheader.vbordermode); };
virtual int alphaChannel() { return _header.alphachan; }
virtual int numChannels() { return _header.nchannels; }
virtual int numFaces() { return _header.nfaces; }
virtual bool hasEdits() { return _hasEdits; }
virtual bool hasMipMaps() { return _header.nlevels > 1; }
virtual PtexMetaData* getMetaData();
virtual const Ptex::FaceInfo& getFaceInfo(int faceid);
virtual void getData(int faceid, void* buffer, int stride);
virtual void getData(int faceid, void* buffer, int stride, Res res);
virtual PtexFaceData* getData(int faceid);
virtual PtexFaceData* getData(int faceid, Res res);
virtual void getPixel(int faceid, int u, int v,
float* result, int firstchan, int nchannels);
virtual void getPixel(int faceid, int u, int v,
float* result, int firstchan, int nchannels,
Ptex::Res res);
DataType datatype() const { return _header.datatype; }
int nchannels() const { return _header.nchannels; }
int pixelsize() const { return _pixelsize; }
const Header& header() const { return _header; }
const ExtHeader& extheader() const { return _extheader; }
const LevelInfo& levelinfo(int level) const { return _levelinfo[level]; }
class MetaData : public PtexCachedData, public PtexMetaData {
public:
MetaData(MetaData** parent, PtexCacheImpl* cache, int size, PtexReader* reader)
: PtexCachedData((void**)parent, cache, sizeof(*this) + size),
_reader(reader) {}
virtual void release() {
AutoLockCache lock(_cache->cachelock);
// first, unref all lmdData refs
for (int i = 0, n = _lmdRefs.size(); i < n; i++)
_lmdRefs[i]->unref();
_lmdRefs.resize(0);
// finally, unref self
unref();
}
virtual int numKeys() { return int(_entries.size()); }
virtual void getKey(int n, const char*& key, MetaDataType& type)
{
Entry* e = _entries[n];
key = e->key;
type = e->type;
}
virtual void getValue(const char* key, const char*& value)
{
Entry* e = getEntry(key);
if (e) value = (const char*) e->data;
else value = 0;
}
virtual void getValue(const char* key, const int8_t*& value, int& count)
{
Entry* e = getEntry(key);
if (e) { value = (const int8_t*) e->data; count = e->datasize; }
else { value = 0; count = 0; }
}
virtual void getValue(const char* key, const int16_t*& value, int& count)
{
Entry* e = getEntry(key);
if (e) {
value = (const int16_t*) e->data;
count = int(e->datasize/sizeof(int16_t));
}
else { value = 0; count = 0; }
}
virtual void getValue(const char* key, const int32_t*& value, int& count)
{
Entry* e = getEntry(key);
if (e) {
value = (const int32_t*) e->data;
count = int(e->datasize/sizeof(int32_t));
}
else { value = 0; count = 0; }
}
virtual void getValue(const char* key, const float*& value, int& count)
{
Entry* e = getEntry(key);
if (e) {
value = (const float*) e->data;
count = int(e->datasize/sizeof(float));
}
else { value = 0; count = 0; }
}
virtual void getValue(const char* key, const double*& value, int& count)
{
Entry* e = getEntry(key);
if (e) {
value = (const double*) e->data;
count = int(e->datasize/sizeof(double));
}
else { value = 0; count = 0; }
}
void addEntry(uint8_t keysize, const char* key, uint8_t datatype,
uint32_t datasize, void* data)
{
Entry* e = newEntry(keysize, key, datatype, datasize);
e->data = malloc(datasize);
memcpy(e->data, data, datasize);
}
void addLmdEntry(uint8_t keysize, const char* key, uint8_t datatype,
uint32_t datasize, FilePos filepos, uint32_t zipsize)
{
Entry* e = newEntry(keysize, key, datatype, datasize);
e->isLmd = true;
e->lmdData = 0;
e->lmdPos = filepos;
e->lmdZipSize = zipsize;
}
protected:
class LargeMetaData : public PtexCachedData
{
public:
LargeMetaData(void** parent, PtexCacheImpl* cache, int size)
: PtexCachedData(parent, cache, size), _data(malloc(size)) {}
void* data() { return _data; }
private:
virtual ~LargeMetaData() { free(_data); }
void* _data;
};
struct Entry {
const char* key; // ptr to map key string
MetaDataType type; // meta data type
uint32_t datasize; // size of data in bytes
void* data; // if lmd, data only valid when lmd is loaded and ref'ed
bool isLmd; // true if data is a large meta data block
LargeMetaData* lmdData; // large meta data (lazy-loaded, lru-cached)
FilePos lmdPos; // large meta data file position
uint32_t lmdZipSize; // large meta data size on disk
Entry() :
key(0), type(MetaDataType(0)), datasize(0), data(0),
isLmd(0), lmdData(0), lmdPos(0), lmdZipSize(0) {}
~Entry() { clear(); }
void clear() {
if (isLmd) {
isLmd = 0;
if (lmdData) { lmdData->orphan(); lmdData = 0; }
lmdPos = 0;
lmdZipSize = 0;
}
else {
free(data);
}
data = 0;
}
};
Entry* newEntry(uint8_t keysize, const char* key, uint8_t datatype, uint32_t datasize)
{
std::pair<MetaMap::iterator,bool> result =
_map.insert(std::make_pair(std::string(key, keysize), Entry()));
Entry* e = &result.first->second;
bool newEntry = result.second;
if (newEntry) _entries.push_back(e);
else e->clear();
e->key = result.first->first.c_str();
e->type = MetaDataType(datatype);
e->datasize = datasize;
return e;
}
Entry* getEntry(const char* key);
PtexReader* _reader;
typedef std::map<std::string, Entry> MetaMap;
MetaMap _map;
safevector<Entry*> _entries;
std::vector<LargeMetaData*> _lmdRefs;
};
class ConstDataPtr : public PtexFaceData {
public:
ConstDataPtr(void* data, int pixelsize)
: _data(data), _pixelsize(pixelsize) {}
virtual void release() { delete this; }
virtual Ptex::Res res() { return 0; }
virtual bool isConstant() { return true; }
virtual void getPixel(int, int, void* result)
{ memcpy(result, _data, _pixelsize); }
virtual void* getData() { return _data; }
virtual bool isTiled() { return false; }
virtual Ptex::Res tileRes() { return 0; }
virtual PtexFaceData* getTile(int) { return 0; }
protected:
void* _data;
int _pixelsize;
};
class FaceData : public PtexCachedData, public PtexFaceData {
public:
FaceData(void** parent, PtexCacheImpl* cache, Res res, int size)
: PtexCachedData(parent, cache, size), _res(res) {}
virtual void release() { AutoLockCache lock(_cache->cachelock); unref(); }
virtual Ptex::Res res() { return _res; }
virtual void reduce(FaceData*&, PtexReader*,
Res newres, PtexUtils::ReduceFn) = 0;
protected:
Res _res;
};
class PackedFace : public FaceData {
public:
PackedFace(void** parent, PtexCacheImpl* cache, Res res, int pixelsize, int size)
: FaceData(parent, cache, res, sizeof(*this)+size),
_pixelsize(pixelsize), _data(malloc(size)) {}
void* data() { return _data; }
virtual bool isConstant() { return false; }
virtual void getPixel(int u, int v, void* result)
{
memcpy(result, (char*)_data + (v*_res.u() + u) * _pixelsize, _pixelsize);
}
virtual void* getData() { return _data; };
virtual bool isTiled() { return false; }
virtual Ptex::Res tileRes() { return _res; };
virtual PtexFaceData* getTile(int) { return 0; };
virtual void reduce(FaceData*&, PtexReader*,
Res newres, PtexUtils::ReduceFn);
protected:
virtual ~PackedFace() { free(_data); }
int _pixelsize;
void* _data;
};
class ConstantFace : public PackedFace {
public:
ConstantFace(void** parent, PtexCacheImpl* cache, int pixelsize)
: PackedFace(parent, cache, 0, pixelsize, pixelsize) {}
virtual bool isConstant() { return true; }
virtual void getPixel(int, int, void* result) { memcpy(result, _data, _pixelsize); }
virtual void reduce(FaceData*&, PtexReader*,
Res newres, PtexUtils::ReduceFn);
};
class TiledFaceBase : public FaceData {
public:
TiledFaceBase(void** parent, PtexCacheImpl* cache, Res res,
Res tileres, DataType dt, int nchan)
: FaceData(parent, cache, res, sizeof(*this)),
_tileres(tileres),
_dt(dt),
_nchan(nchan),
_pixelsize(DataSize(dt)*nchan)
{
_ntilesu = _res.ntilesu(tileres);
_ntilesv = _res.ntilesv(tileres);
_ntiles = _ntilesu*_ntilesv;
_tiles.resize(_ntiles);
incSize(sizeof(FaceData*)*_ntiles);
}
virtual void release() {
// Tiled faces ref the reader (directly or indirectly) and
// thus may trigger cache deletion on release. Call cache
// to check for pending delete.
// Note: release() may delete "this", so save _cache in
// local var.
PtexCacheImpl* cache = _cache;
FaceData::release();
cache->handlePendingDelete();
}
virtual bool isConstant() { return false; }
virtual void getPixel(int u, int v, void* result);
virtual void* getData() { return 0; }
virtual bool isTiled() { return true; }
virtual Ptex::Res tileRes() { return _tileres; };
virtual void reduce(FaceData*&, PtexReader*,
Res newres, PtexUtils::ReduceFn);
Res tileres() const { return _tileres; }
int ntilesu() const { return _ntilesu; }
int ntilesv() const { return _ntilesv; }
int ntiles() const { return _ntiles; }
protected:
virtual ~TiledFaceBase() { orphanList(_tiles); }
Res _tileres;
DataType _dt;
int _nchan;
int _ntilesu;
int _ntilesv;
int _ntiles;
int _pixelsize;
safevector<FaceData*> _tiles;
};
class TiledFace : public TiledFaceBase {
public:
TiledFace(void** parent, PtexCacheImpl* cache, Res res, Res tileres,
int levelid, PtexReader* reader)
: TiledFaceBase(parent, cache, res, tileres,
reader->datatype(), reader->nchannels()),
_reader(reader),
_levelid(levelid)
{
_fdh.resize(_ntiles),
_offsets.resize(_ntiles);
incSize((sizeof(FaceDataHeader)+sizeof(FilePos))*_ntiles);
}
virtual PtexFaceData* getTile(int tile)
{
AutoLockCache locker(_cache->cachelock);
FaceData*& f = _tiles[tile];
if (!f) readTile(tile, f);
else f->ref();
return f;
}
void readTile(int tile, FaceData*& data);
protected:
friend class PtexReader;
PtexReader* _reader;
int _levelid;
safevector<FaceDataHeader> _fdh;
safevector<FilePos> _offsets;
};
class TiledReducedFace : public TiledFaceBase {
public:
TiledReducedFace(void** parent, PtexCacheImpl* cache, Res res,
Res tileres, DataType dt, int nchan,
TiledFaceBase* parentface, PtexUtils::ReduceFn reducefn)
: TiledFaceBase(parent, cache, res, tileres, dt, nchan),
_parentface(parentface),
_reducefn(reducefn)
{
AutoLockCache locker(_cache->cachelock);
_parentface->ref();
}
~TiledReducedFace()
{
_parentface->unref();
}
virtual PtexFaceData* getTile(int tile);
protected:
TiledFaceBase* _parentface;
PtexUtils::ReduceFn* _reducefn;
};
class Level : public PtexCachedData {
public:
safevector<FaceDataHeader> fdh;
safevector<FilePos> offsets;
safevector<FaceData*> faces;
Level(void** parent, PtexCacheImpl* cache, int nfaces)
: PtexCachedData(parent, cache,
sizeof(*this) + nfaces * (sizeof(FaceDataHeader) +
sizeof(FilePos) +
sizeof(FaceData*))),
fdh(nfaces),
offsets(nfaces),
faces(nfaces) {}
protected:
virtual ~Level() { orphanList(faces); }
};
Mutex readlock;
Mutex reducelock;
protected:
virtual ~PtexReader();
void setError(const char* error)
{
_error = error; _error += " PtexFile: "; _error += _path;
_ok = 0;
}
FilePos tell() { return _pos; }
void seek(FilePos pos)
{
if (pos != _pos) {
_io->seek(_fp, pos);
_pos = pos;
STATS_INC(nseeks);
}
}
bool readBlock(void* data, int size, bool reportError=true);
bool readZipBlock(void* data, int zipsize, int unzipsize);
Level* getLevel(int levelid)
{
Level*& level = _levels[levelid];
if (!level) readLevel(levelid, level);
else level->ref();
return level;
}
uint8_t* getConstData() { if (!_constdata) readConstData(); return _constdata; }
FaceData* getFace(int levelid, Level* level, int faceid)
{
FaceData*& face = level->faces[faceid];
if (!face) readFace(levelid, level, faceid);
else face->ref();
return face;
}
Res getRes(int levelid, int faceid)
{
if (levelid == 0) return _faceinfo[faceid].res;
else {
// for reduction level, look up res via rfaceid
Res res = _res_r[faceid];
// and adjust for number of reductions
return Res(res.ulog2 - levelid, res.vlog2 - levelid);
}
}
int unpackedSize(FaceDataHeader fdh, int levelid, int faceid)
{
if (fdh.encoding() == enc_constant)
// level 0 constant faces are not stored
return levelid == 0 ? 0 : _pixelsize;
else
return getRes(levelid, faceid).size() * _pixelsize;
}
void readFaceInfo();
void readLevelInfo();
void readConstData();
void readLevel(int levelid, Level*& level);
void readFace(int levelid, Level* level, int faceid);
void readFaceData(FilePos pos, FaceDataHeader fdh, Res res, int levelid, FaceData*& face);
void readMetaData();
void readMetaDataBlock(MetaData* metadata, FilePos pos, int zipsize, int memsize);
void readLargeMetaDataHeaders(MetaData* metadata, FilePos pos, int zipsize, int memsize);
void readEditData();
void readEditFaceData();
void readEditMetaData();
void computeOffsets(FilePos pos, int noffsets, const FaceDataHeader* fdh, FilePos* offsets)
{
FilePos* end = offsets + noffsets;
while (offsets != end) { *offsets++ = pos; pos += fdh->blocksize(); fdh++; }
}
void blendFaces(FaceData*& face, int faceid, Res res, bool blendu);
PtexInputHandler* _io; // IO handler
bool _premultiply; // true if reader should premultiply the alpha chan
bool _ownsCache; // true if reader owns the cache
bool _ok; // flag set if read error occurred)
std::string _error; // error string (if !_ok)
PtexInputHandler::Handle _fp; // file pointer
FilePos _pos; // current seek position
std::string _path; // current file path
Header _header; // the header
ExtHeader _extheader; // extended header
FilePos _faceinfopos; // file positions of data sections
FilePos _constdatapos; // ...
FilePos _levelinfopos;
FilePos _leveldatapos;
FilePos _metadatapos;
FilePos _lmdheaderpos;
FilePos _lmddatapos;
FilePos _editdatapos;
int _pixelsize; // size of a pixel in bytes
uint8_t* _constdata; // constant pixel value per face
MetaData* _metadata; // meta data (read on demand)
bool _hasEdits; // has edit blocks
safevector<FaceInfo> _faceinfo; // per-face header info
safevector<uint32_t> _rfaceids; // faceids sorted in reduction order
safevector<Res> _res_r; // face res indexed by rfaceid
safevector<LevelInfo> _levelinfo; // per-level header info
safevector<FilePos> _levelpos; // file position of each level's data
safevector<Level*> _levels; // level data (read on demand)
struct MetaEdit
{
FilePos pos;
int zipsize;
int memsize;
};
safevector<MetaEdit> _metaedits;
struct FaceEdit
{
FilePos pos;
int faceid;
FaceDataHeader fdh;
};
safevector<FaceEdit> _faceedits;
struct ReductionKey {
int faceid;
Res res;
ReductionKey() : faceid(0), res(0,0) {}
ReductionKey(uint32_t faceid, Res res) : faceid(faceid), res(res) {}
bool operator==(const ReductionKey& k) const
{ return k.faceid == faceid && k.res == res; }
struct Hasher {
uint32_t operator() (const ReductionKey& key) const
{
// constants from Knuth
static uint32_t M = 1664525, C = 1013904223;
uint32_t val = (key.res.ulog2 * M + key.res.vlog2 + C) * M + key.faceid;
return val;
}
};
};
typedef PtexHashMap<ReductionKey, FaceData*, ReductionKey::Hasher> ReductionMap;
ReductionMap _reductions;
z_stream_s _zstream;
};
#endif

View File

@@ -0,0 +1,389 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "PtexPlatform.h"
#include <math.h>
#include <assert.h>
#include "PtexSeparableFilter.h"
#include "PtexSeparableKernel.h"
#include "PtexUtils.h"
//#define NOEDGEBLEND // uncomment to disable filtering across edges (for debugging)
void PtexSeparableFilter::eval(float* result, int firstChan, int nChannels,
int faceid, float u, float v,
float uw1, float vw1, float uw2, float vw2,
float width, float blur)
{
// init
if (!_tx || nChannels <= 0) return;
if (faceid < 0 || faceid >= _tx->numFaces()) return;
_ntxchan = _tx->numChannels();
_dt = _tx->dataType();
_firstChanOffset = firstChan*DataSize(_dt);
_nchan = PtexUtils::min(nChannels, _ntxchan-firstChan);
// get face info
const FaceInfo& f = _tx->getFaceInfo(faceid);
// if neighborhood is constant, just return constant value of face
if (f.isNeighborhoodConstant()) {
PtexPtr<PtexFaceData> data ( _tx->getData(faceid, 0) );
if (data) {
char* d = (char*) data->getData() + _firstChanOffset;
Ptex::ConvertToFloat(result, d, _dt, _nchan);
}
return;
}
// find filter width as bounding box of vectors w1 and w2
float uw = fabs(uw1) + fabs(uw2), vw = fabs(vw1) + fabs(vw2);
// handle border modes
switch (_uMode) {
case m_clamp: u = PtexUtils::clamp(u, 0.0f, 1.0f); break;
case m_periodic: u = u-floor(u); break;
case m_black: break; // do nothing
}
switch (_vMode) {
case m_clamp: v = PtexUtils::clamp(v, 0.0f, 1.0f); break;
case m_periodic: v = v-floor(v);
case m_black: break; // do nothing
}
// build kernel
PtexSeparableKernel k;
if (f.isSubface()) {
// for a subface, build the kernel as if it were on a main face and then downres
uw = uw * width + blur * 2;
vw = vw * width + blur * 2;
buildKernel(k, u*.5, v*.5, uw*.5, vw*.5, f.res);
if (k.res.ulog2 == 0) k.upresU();
if (k.res.vlog2 == 0) k.upresV();
k.res.ulog2--; k.res.vlog2--;
}
else {
uw = uw * width + blur;
vw = vw * width + blur;
buildKernel(k, u, v, uw, vw, f.res);
}
k.stripZeros();
// check kernel (debug only)
assert(k.uw > 0 && k.vw > 0);
assert(k.uw <= PtexSeparableKernel::kmax && k.vw <= PtexSeparableKernel::kmax);
_weight = k.weight();
// allocate temporary double-precision result
_result = (double*) alloca(sizeof(double)*_nchan);
memset(_result, 0, sizeof(double)*_nchan);
// apply to faces
splitAndApply(k, faceid, f);
// normalize (both for data type and cumulative kernel weight applied)
// and output result
double scale = 1.0 / (_weight * OneValue(_dt));
for (int i = 0; i < _nchan; i++) result[i] = float(_result[i] * scale);
// clear temp result
_result = 0;
}
void PtexSeparableFilter::splitAndApply(PtexSeparableKernel& k, int faceid, const Ptex::FaceInfo& f)
{
// do we need to split? (i.e. does kernel span an edge?)
bool splitR = (k.u+k.uw > k.res.u()), splitL = (k.u < 0);
bool splitT = (k.v+k.vw > k.res.v()), splitB = (k.v < 0);
#ifdef NOEDGEBLEND
// for debugging only
if (splitR) k.mergeR(_uMode);
if (splitL) k.mergeL(_uMode);
if (splitT) k.mergeT(_vMode);
if (splitB) k.mergeB(_vMode);
#else
if (splitR || splitL || splitT || splitB) {
PtexSeparableKernel ka, kc;
if (splitR) {
if (f.adjface(e_right) >= 0) {
k.splitR(ka);
if (splitT) {
if (f.adjface(e_top) >= 0) {
ka.splitT(kc);
applyToCorner(kc, faceid, f, e_top);
}
else ka.mergeT(_vMode);
}
if (splitB) {
if (f.adjface(e_bottom) >= 0) {
ka.splitB(kc);
applyToCorner(kc, faceid, f, e_right);
}
else ka.mergeB(_vMode);
}
applyAcrossEdge(ka, faceid, f, e_right);
}
else k.mergeR(_uMode);
}
if (splitL) {
if (f.adjface(e_left) >= 0) {
k.splitL(ka);
if (splitT) {
if (f.adjface(e_top) >= 0) {
ka.splitT(kc);
applyToCorner(kc, faceid, f, e_left);
}
else ka.mergeT(_vMode);
}
if (splitB) {
if (f.adjface(e_bottom) >= 0) {
ka.splitB(kc);
applyToCorner(kc, faceid, f, e_bottom);
}
else ka.mergeB(_vMode);
}
applyAcrossEdge(ka, faceid, f, e_left);
}
else k.mergeL(_uMode);
}
if (splitT) {
if (f.adjface(e_top) >= 0) {
k.splitT(ka);
applyAcrossEdge(ka, faceid, f, e_top);
}
else k.mergeT(_vMode);
}
if (splitB) {
if (f.adjface(e_bottom) >= 0) {
k.splitB(ka);
applyAcrossEdge(ka, faceid, f, e_bottom);
}
else k.mergeB(_vMode);
}
}
#endif
// do local face
apply(k, faceid, f);
}
void PtexSeparableFilter::applyAcrossEdge(PtexSeparableKernel& k,
int faceid, const Ptex::FaceInfo& f, int eid)
{
int afid = f.adjface(eid), aeid = f.adjedge(eid);
const Ptex::FaceInfo* af = &_tx->getFaceInfo(afid);
int rot = eid - aeid + 2;
// adjust uv coord and res for face/subface boundary
bool fIsSubface = f.isSubface(), afIsSubface = af->isSubface();
if (fIsSubface != afIsSubface) {
if (afIsSubface) {
// main face to subface transition
// adjust res and offset uv coord for primary subface
bool primary = k.adjustMainToSubface(eid);
if (!primary) {
// advance ajacent face and edge id to secondary subface
int neid = (aeid + 3) % 4;
afid = af->adjface(neid);
aeid = af->adjedge(neid);
af = &_tx->getFaceInfo(afid);
rot += neid - aeid + 2;
}
}
else {
// subface to main face transition
// Note: the transform depends on which subface the kernel is
// coming from. The "primary" subface is the one the main
// face is pointing at. The secondary subface adjustment
// happens to be the same as for the primary subface for the
// next edge, so the cases can be combined.
bool primary = (af->adjface(aeid) == faceid);
k.adjustSubfaceToMain(eid - primary);
}
}
// rotate and apply (resplit if going to a subface)
k.rotate(rot);
if (afIsSubface) splitAndApply(k, afid, *af);
else apply(k, afid, *af);
}
void PtexSeparableFilter::applyToCorner(PtexSeparableKernel& k, int faceid,
const Ptex::FaceInfo& f, int eid)
{
// traverse clockwise around corner vertex and gather corner faces
int afid = faceid, aeid = eid;
const FaceInfo* af = &f;
bool prevIsSubface = af->isSubface();
const int MaxValence = 10;
int cfaceId[MaxValence];
int cedgeId[MaxValence];
const FaceInfo* cface[MaxValence];
int numCorners = 0;
for (int i = 0; i < MaxValence; i++) {
// advance to next face
int prevFace = afid;
afid = af->adjface(aeid);
aeid = (af->adjedge(aeid) + 1) % 4;
// we hit a boundary or reached starting face
// note: we need to check edge id too because we might have
// a periodic texture (w/ toroidal topology) where all 4 corners
// are from the same face
if (afid < 0 || (afid == faceid && aeid == eid)) {
numCorners = i - 2;
break;
}
// record face info
af = &_tx->getFaceInfo(afid);
cfaceId[i] = afid;
cedgeId[i] = aeid;
cface[i] = af;
// check to see if corner is a subface "tee"
bool isSubface = af->isSubface();
if (prevIsSubface && !isSubface && af->adjface((aeid+3)%4) == prevFace)
{
// adjust the eid depending on whether we started from
// the primary or secondary subface.
bool primary = (i==1);
k.adjustSubfaceToMain(eid + primary * 2);
k.rotate(eid - aeid + 3 - primary);
splitAndApply(k, afid, *af);
return;
}
prevIsSubface = isSubface;
}
if (numCorners == 1) {
// regular case (valence 4)
applyToCornerFace(k, f, eid, cfaceId[1], *cface[1], cedgeId[1]);
}
else if (numCorners > 1) {
// valence 5+, make kernel symmetric and apply equally to each face
// first, rotate to standard orientation, u=v=0
k.rotate(eid + 2);
double initialWeight = k.weight();
double newWeight = k.makeSymmetric(initialWeight);
for (int i = 1; i <= numCorners; i++) {
PtexSeparableKernel kc = k;
applyToCornerFace(kc, f, 2, cfaceId[i], *cface[i], cedgeId[i]);
}
// adjust weight for symmetrification and for additional corners
_weight += newWeight * numCorners - initialWeight;
}
else {
// valence 2 or 3, ignore corner face (just adjust weight)
_weight -= k.weight();
}
}
void PtexSeparableFilter::applyToCornerFace(PtexSeparableKernel& k, const Ptex::FaceInfo& f, int eid,
int cfid, const Ptex::FaceInfo& cf, int ceid)
{
// adjust uv coord and res for face/subface boundary
bool fIsSubface = f.isSubface(), cfIsSubface = cf.isSubface();
if (fIsSubface != cfIsSubface) {
if (cfIsSubface) k.adjustMainToSubface(eid + 3);
else k.adjustSubfaceToMain(eid + 3);
}
// rotate and apply (resplit if going to a subface)
k.rotate(eid - ceid + 2);
if (cfIsSubface) splitAndApply(k, cfid, cf);
else apply(k, cfid, cf);
}
void PtexSeparableFilter::apply(PtexSeparableKernel& k, int faceid, const Ptex::FaceInfo& f)
{
assert(k.u >= 0 && k.u + k.uw <= k.res.u());
assert(k.v >= 0 && k.v + k.vw <= k.res.v());
if (k.uw <= 0 || k.vw <= 0) return;
// downres kernel if needed
while (k.res.u() > f.res.u()) k.downresU();
while (k.res.v() > f.res.v()) k.downresV();
// get face data, and apply
PtexPtr<PtexFaceData> dh ( _tx->getData(faceid, k.res) );
if (!dh) return;
if (dh->isConstant()) {
k.applyConst(_result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan);
}
else if (dh->isTiled()) {
Ptex::Res tileres = dh->tileRes();
PtexSeparableKernel kt;
kt.res = tileres;
int tileresu = tileres.u();
int tileresv = tileres.v();
int ntilesu = k.res.u() / tileresu;
for (int v = k.v, vw = k.vw; vw > 0; vw -= kt.vw, v += kt.vw) {
int tilev = v / tileresv;
kt.v = v % tileresv;
kt.vw = PtexUtils::min(vw, tileresv - kt.v);
kt.kv = k.kv + v - k.v;
for (int u = k.u, uw = k.uw; uw > 0; uw -= kt.uw, u += kt.uw) {
int tileu = u / tileresu;
kt.u = u % tileresu;
kt.uw = PtexUtils::min(uw, tileresu - kt.u);
kt.ku = k.ku + u - k.u;
PtexPtr<PtexFaceData> th ( dh->getTile(tilev * ntilesu + tileu) );
if (th) {
if (th->isConstant())
kt.applyConst(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan);
else
kt.apply(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan, _ntxchan);
}
}
}
}
else {
k.apply(_result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan, _ntxchan);
}
}

View File

@@ -0,0 +1,80 @@
#ifndef PtexSeparableFilter_h
#define PtexSeparableFilter_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "Ptexture.h"
class PtexSeparableKernel;
class PtexSeparableFilter : public PtexFilter, public Ptex
{
public:
virtual void release() { delete this; }
virtual void eval(float* result, int firstchan, int nchannels,
int faceid, float u, float v,
float uw1, float vw1, float uw2, float vw2,
float width, float blur);
protected:
PtexSeparableFilter(PtexTexture* tx, const PtexFilter::Options& opts ) :
_tx(tx), _options(opts), _result(0), _weight(0),
_firstChanOffset(0), _nchan(0), _ntxchan(0),
_dt((DataType)0), _uMode(tx->uBorderMode()), _vMode(tx->vBorderMode()) {}
virtual ~PtexSeparableFilter() {}
virtual void buildKernel(PtexSeparableKernel& k, float u, float v, float uw, float vw,
Res faceRes) = 0;
void splitAndApply(PtexSeparableKernel& k, int faceid, const Ptex::FaceInfo& f);
void applyAcrossEdge(PtexSeparableKernel& k, int faceid, const Ptex::FaceInfo& f, int eid);
void applyToCorner(PtexSeparableKernel& k, int faceid, const Ptex::FaceInfo& f, int eid);
void applyToCornerFace(PtexSeparableKernel& k, const Ptex::FaceInfo& f, int eid,
int cfaceid, const Ptex::FaceInfo& cf, int ceid);
void apply(PtexSeparableKernel& k, int faceid, const Ptex::FaceInfo& f);
PtexTexture* _tx; // texture being evaluated
Options _options; // options
double* _result; // temp result
double _weight; // accumulated weight of data in _result
int _firstChanOffset; // byte offset of first channel to eval
int _nchan; // number of channels to eval
int _ntxchan; // number of channels in texture
DataType _dt; // data type of texture
BorderMode _uMode, _vMode; // border modes (clamp,black,periodic)
};
#endif

View File

@@ -0,0 +1,149 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "PtexPlatform.h"
#include "PtexUtils.h"
#include "PtexHalf.h"
#include "PtexSeparableKernel.h"
namespace {
// apply to 1..4 channels (unrolled channel loop) of packed data (nTxChan==nChan)
template<class T, int nChan>
void Apply(PtexSeparableKernel& k, double* result, void* data, int /*nChan*/, int /*nTxChan*/)
{
double* rowResult = (double*) alloca(nChan*sizeof(double));
int rowlen = k.res.u() * nChan;
int datalen = k.uw * nChan;
int rowskip = rowlen - datalen;
double* kvp = k.kv;
T* p = (T*)data + (k.v * k.res.u() + k.u) * nChan;
T* pEnd = p + k.vw * rowlen;
while (p != pEnd)
{
double* kup = k.ku;
T* pRowEnd = p + datalen;
// just mult and copy first element
PtexUtils::VecMult<T,nChan>()(rowResult, p, *kup++);
p += nChan;
// accumulate remaining elements
while (p != pRowEnd) {
// rowResult[i] = p[i] * ku[u] for i in {0..n-1}
PtexUtils::VecAccum<T,nChan>()(rowResult, p, *kup++);
p += nChan;
}
// result[i] += rowResult[i] * kv[v] for i in {0..n-1}
PtexUtils::VecAccum<double,nChan>()(result, rowResult, *kvp++);
p += rowskip;
}
}
// apply to 1..4 channels (unrolled channel loop) w/ pixel stride
template<class T, int nChan>
void ApplyS(PtexSeparableKernel& k, double* result, void* data, int /*nChan*/, int nTxChan)
{
double* rowResult = (double*) alloca(nChan*sizeof(double));
int rowlen = k.res.u() * nTxChan;
int datalen = k.uw * nTxChan;
int rowskip = rowlen - datalen;
double* kvp = k.kv;
T* p = (T*)data + (k.v * k.res.u() + k.u) * nTxChan;
T* pEnd = p + k.vw * rowlen;
while (p != pEnd)
{
double* kup = k.ku;
T* pRowEnd = p + datalen;
// just mult and copy first element
PtexUtils::VecMult<T,nChan>()(rowResult, p, *kup++);
p += nTxChan;
// accumulate remaining elements
while (p != pRowEnd) {
// rowResult[i] = p[i] * ku[u] for i in {0..n-1}
PtexUtils::VecAccum<T,nChan>()(rowResult, p, *kup++);
p += nTxChan;
}
// result[i] += rowResult[i] * kv[v] for i in {0..n-1}
PtexUtils::VecAccum<double,nChan>()(result, rowResult, *kvp++);
p += rowskip;
}
}
// apply to N channels (general case)
template<class T>
void ApplyN(PtexSeparableKernel& k, double* result, void* data, int nChan, int nTxChan)
{
double* rowResult = (double*) alloca(nChan*sizeof(double));
int rowlen = k.res.u() * nTxChan;
int datalen = k.uw * nTxChan;
int rowskip = rowlen - datalen;
double* kvp = k.kv;
T* p = (T*)data + (k.v * k.res.u() + k.u) * nTxChan;
T* pEnd = p + k.vw * rowlen;
while (p != pEnd)
{
double* kup = k.ku;
T* pRowEnd = p + datalen;
// just mult and copy first element
PtexUtils::VecMultN<T>()(rowResult, p, nChan, *kup++);
p += nTxChan;
// accumulate remaining elements
while (p != pRowEnd) {
// rowResult[i] = p[i] * ku[u] for i in {0..n-1}
PtexUtils::VecAccumN<T>()(rowResult, p, nChan, *kup++);
p += nTxChan;
}
// result[i] += rowResult[i] * kv[v] for i in {0..n-1}
PtexUtils::VecAccumN<double>()(result, rowResult, nChan, *kvp++);
p += rowskip;
}
}
}
PtexSeparableKernel::ApplyFn
PtexSeparableKernel::applyFunctions[] = {
// nChan == nTxChan
ApplyN<uint8_t>, ApplyN<uint16_t>, ApplyN<PtexHalf>, ApplyN<float>,
Apply<uint8_t,1>, Apply<uint16_t,1>, Apply<PtexHalf,1>, Apply<float,1>,
Apply<uint8_t,2>, Apply<uint16_t,2>, Apply<PtexHalf,2>, Apply<float,2>,
Apply<uint8_t,3>, Apply<uint16_t,3>, Apply<PtexHalf,3>, Apply<float,3>,
Apply<uint8_t,4>, Apply<uint16_t,4>, Apply<PtexHalf,4>, Apply<float,4>,
// nChan != nTxChan (need pixel stride)
ApplyN<uint8_t>, ApplyN<uint16_t>, ApplyN<PtexHalf>, ApplyN<float>,
ApplyS<uint8_t,1>, ApplyS<uint16_t,1>, ApplyS<PtexHalf,1>, ApplyS<float,1>,
ApplyS<uint8_t,2>, ApplyS<uint16_t,2>, ApplyS<PtexHalf,2>, ApplyS<float,2>,
ApplyS<uint8_t,3>, ApplyS<uint16_t,3>, ApplyS<PtexHalf,3>, ApplyS<float,3>,
ApplyS<uint8_t,4>, ApplyS<uint16_t,4>, ApplyS<PtexHalf,4>, ApplyS<float,4>,
};

View File

@@ -0,0 +1,473 @@
#ifndef PtexSeparableKernel_h
#define PtexSeparableKernel_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <assert.h>
#include <algorithm>
#include <numeric>
#include "Ptexture.h"
#include "PtexUtils.h"
// Separable convolution kernel
class PtexSeparableKernel : public Ptex {
public:
Res res; // resolution that kernel was built for
int u, v; // uv offset within face data
int uw, vw; // kernel width
double* ku; // kernel weights in u
double* kv; // kernel weights in v
static const int kmax = 10; // max kernel width
double kubuff[kmax];
double kvbuff[kmax];
PtexSeparableKernel()
: res(0), u(0), v(0), uw(0), vw(0), ku(kubuff), kv(kvbuff) {}
PtexSeparableKernel(const PtexSeparableKernel& k)
{
set(k.res, k.u, k.v, k.uw, k.vw, k.ku, k.kv);
}
PtexSeparableKernel& operator= (const PtexSeparableKernel& k)
{
set(k.res, k.u, k.v, k.uw, k.vw, k.ku, k.kv);
return *this;
}
void set(Res resVal,
int uVal, int vVal,
int uwVal, int vwVal,
const double* kuVal, const double* kvVal)
{
assert(uwVal <= kmax && vwVal <= kmax);
res = resVal;
u = uVal;
v = vVal;
uw = uwVal;
vw = vwVal;
memcpy(kubuff, kuVal, sizeof(*ku)*uw);
memcpy(kvbuff, kvVal, sizeof(*kv)*vw);
ku = kubuff;
kv = kvbuff;
}
void stripZeros()
{
while (ku[0] == 0) { ku++; u++; uw--; }
while (ku[uw-1] == 0) { uw--; }
while (kv[0] == 0) { kv++; v++; vw--; }
while (kv[vw-1] == 0) { vw--; }
assert(uw > 0 && vw > 0);
}
double weight() const
{
return accumulate(ku, uw) * accumulate(kv, vw);
}
void mergeL(BorderMode mode)
{
int w = -u;
if (mode != m_black)
ku[w] += accumulate(ku, w);
ku += w;
uw -= w;
u = 0;
}
void mergeR(BorderMode mode)
{
int w = uw + u - res.u();
double* kp = ku + uw - w;
if (mode != m_black)
kp[-1] += accumulate(kp, w);
uw -= w;
}
void mergeB(BorderMode mode)
{
int w = -v;
if (mode != m_black)
kv[w] += accumulate(kv, w);
kv += w;
vw -= w;
v = 0;
}
void mergeT(BorderMode mode)
{
int w = vw + v - res.v();
double* kp = kv + vw - w;
if (mode != m_black)
kp[-1] += accumulate(kp, w);
vw -= w;
}
void splitL(PtexSeparableKernel& k)
{
// split off left piece of width w into k
int w = -u;
if (w < uw) {
// normal case - split off a portion
// res u v uw vw ku kv
k.set(res, res.u()-w, v, w, vw, ku, kv);
// update local
u = 0;
uw -= w;
ku += w;
}
else {
// entire kernel is split off
k = *this;
k.u += res.u();
u = 0; uw = 0;
}
}
void splitR(PtexSeparableKernel& k)
{
// split off right piece of width w into k
int w = u + uw - res.u();
if (w < uw) {
// normal case - split off a portion
// res u v uw vw ku kv
k.set(res, 0, v, w, vw, ku + uw - w, kv);
// update local
uw -= w;
}
else {
// entire kernel is split off
k = *this;
k.u -= res.u();
u = 0; uw = 0;
}
}
void splitB(PtexSeparableKernel& k)
{
// split off bottom piece of width w into k
int w = -v;
if (w < vw) {
// normal case - split off a portion
// res u v uw vw ku kv
k.set(res, u, res.v()-w, uw, w, ku, kv);
// update local
v = 0;
vw -= w;
kv += w;
}
else {
// entire kernel is split off
k = *this;
k.v += res.v();
v = 0; vw = 0;
}
}
void splitT(PtexSeparableKernel& k)
{
// split off top piece of width w into k
int w = v + vw - res.v();
if (w < vw) {
// normal case - split off a portion
// res u v uw vw ku kv
k.set(res, u, 0, uw, w, ku, kv + vw - w);
// update local
vw -= w;
}
else {
// entire kernel is split off
k = *this;
k.v -= res.v();
v = 0; vw = 0;
}
}
void flipU()
{
u = res.u() - u - uw;
std::reverse(ku, ku+uw);
}
void flipV()
{
v = res.v() - v - vw;
std::reverse(kv, kv+vw);
}
void swapUV()
{
res.swapuv();
std::swap(u, v);
std::swap(uw, vw);
std::swap(ku, kv);
}
void rotate(int rot)
{
// rotate kernel 'rot' steps ccw
switch (rot & 3) {
default: return;
case 1: flipU(); swapUV(); break;
case 2: flipU(); flipV(); break;
case 3: flipV(); swapUV(); break;
}
}
bool adjustMainToSubface(int eid)
{
// to adjust the kernel for the subface, we must adjust the res down and offset the uv coords
// however, if the res is already zero, we must upres the kernel first
if (res.ulog2 == 0) upresU();
if (res.vlog2 == 0) upresV();
if (res.ulog2 > 0) res.ulog2--;
if (res.vlog2 > 0) res.vlog2--;
// offset uv coords and determine whether target subface is the primary one
bool primary = 0;
int resu = res.u(), resv = res.v();
switch (eid&3) {
case e_bottom:
primary = (u < resu);
v -= resv;
if (!primary) u -= resu;
break;
case e_right:
primary = (v < resv);
if (!primary) v -= resv;
break;
case e_top:
primary = (u >= resu);
if (primary) u -= resu;
break;
case e_left:
primary = (v >= resv);
u -= resu;
if (primary) v -= resv;
break;
}
return primary;
}
void adjustSubfaceToMain(int eid)
{
switch (eid&3) {
case e_bottom: v += res.v(); break;
case e_right: break;
case e_top: u += res.u(); break;
case e_left: u += res.u(); v += res.v(); break;
}
res.ulog2++; res.vlog2++;
}
void downresU()
{
double* src = ku;
double* dst = ku;
// skip odd leading sample (if any)
if (u & 1) {
dst++;
src++;
uw--;
}
// combine even pairs
for (int i = uw/2; i > 0; i--) {
*dst++ = src[0] + src[1];
src += 2;
}
// copy odd trailing sample (if any)
if (uw & 1) {
*dst++ = *src++;
}
// update state
u /= 2;
uw = int(dst - ku);
res.ulog2--;
}
void downresV()
{
double* src = kv;
double* dst = kv;
// skip odd leading sample (if any)
if (v & 1) {
dst++;
src++;
vw--;
}
// combine even pairs
for (int i = vw/2; i > 0; i--) {
*dst++ = src[0] + src[1];
src += 2;
}
// copy odd trailing sample (if any)
if (vw & 1) {
*dst++ = *src++;
}
// update state
v /= 2;
vw = int(dst - kv);
res.vlog2--;
}
void upresU()
{
double* src = ku + uw-1;
double* dst = ku + uw*2-2;
for (int i = uw; i > 0; i--) {
dst[0] = dst[1] = *src-- / 2;
dst -=2;
}
uw *= 2;
u *= 2;
res.ulog2++;
}
void upresV()
{
double* src = kv + vw-1;
double* dst = kv + vw*2-2;
for (int i = vw; i > 0; i--) {
dst[0] = dst[1] = *src-- / 2;
dst -=2;
}
vw *= 2;
v *= 2;
res.vlog2++;
}
double makeSymmetric(double initialWeight)
{
assert(u == 0 && v == 0);
// downres higher-res dimension until equal
if (res.ulog2 > res.vlog2) {
do { downresU(); } while(res.ulog2 > res.vlog2);
}
else if (res.vlog2 > res.ulog2) {
do { downresV(); } while (res.vlog2 > res.ulog2);
}
// truncate excess samples in longer dimension
uw = vw = PtexUtils::min(uw, vw);
// combine corresponding u and v samples and compute new kernel weight
double newWeight = 0;
for (int i = 0; i < uw; i++) {
double sum = ku[i] + kv[i];
ku[i] = kv[i] = sum;
newWeight += sum;
}
newWeight *= newWeight; // equivalent to k.weight() ( = sum(ku)*sum(kv) )
// compute scale factor to compensate for weight change
double scale = newWeight == 0 ? 1.0 : initialWeight / newWeight;
// Note: a sharpening kernel (like Mitchell) can produce
// negative weights which may cancel out when adding the two
// kernel axes together, and this can cause the compensation
// scale factor to spike up. We expect the scale factor to be
// less than one in "normal" cases (i.e. ku*kv <= (ku+kv)^2 if ku
// and kv are both positive), so clamping to -1..1 will have
// no effect on positive kernels. If there are negative
// weights, the clamping will just limit the amount of
// sharpening happening at the corners, and the result will
// still be smooth.
// clamp scale factor to -1..1 range
if (scale >= 1) {
// scale by 1 (i.e. do nothing)
}
else {
if (scale < -1) {
// a negative scale means the original kernel had an overall negative weight
// after making symmetric, the kernel will always be positive
// scale ku by -1
// note: choice of u is arbitrary; we could have scaled u or v (but not both)
for (int i = 0; i < uw; i++) ku[i] *= -1;
newWeight = -newWeight;
}
else {
// scale ku to restore initialWeight (again, choice of u instead of v is arbitrary)
for (int i = 0; i < uw; i++) ku[i] *= scale;
newWeight = initialWeight;
}
}
return newWeight;
}
void apply(double* dst, void* data, DataType dt, int nChan, int nTxChan)
{
// dispatch specialized apply function
ApplyFn fn = applyFunctions[(nChan!=nTxChan)*20 + ((unsigned)nChan<=4)*nChan*4 + dt];
fn(*this, dst, data, nChan, nTxChan);
}
void applyConst(double* dst, void* data, DataType dt, int nChan)
{
PtexUtils::applyConst(weight(), dst, data, dt, nChan);
}
private:
typedef void (*ApplyFn)(PtexSeparableKernel& k, double* dst, void* data, int nChan, int nTxChan);
typedef void (*ApplyConstFn)(double weight, double* dst, void* data, int nChan);
static ApplyFn applyFunctions[40];
static ApplyConstFn applyConstFunctions[20];
static inline double accumulate(const double* p, int n)
{
double result = 0;
for (const double* e = p + n; p != e; p++) result += *p;
return result;
}
};
#endif

View File

@@ -0,0 +1,261 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "PtexPlatform.h"
#include <math.h>
#include <assert.h>
#include "PtexTriangleFilter.h"
#include "PtexTriangleKernel.h"
#include "PtexUtils.h"
namespace {
inline double squared(double x) { return x*x; }
}
void PtexTriangleFilter::eval(float* result, int firstChan, int nChannels,
int faceid, float u, float v,
float uw1, float vw1, float uw2, float vw2,
float width, float blur)
{
// init
if (!_tx || nChannels <= 0) return;
if (faceid < 0 || faceid >= _tx->numFaces()) return;
_ntxchan = _tx->numChannels();
_dt = _tx->dataType();
_firstChanOffset = firstChan*DataSize(_dt);
_nchan = PtexUtils::min(nChannels, _ntxchan-firstChan);
// get face info
const FaceInfo& f = _tx->getFaceInfo(faceid);
// if neighborhood is constant, just return constant value of face
if (f.isNeighborhoodConstant()) {
PtexPtr<PtexFaceData> data ( _tx->getData(faceid, 0) );
if (data) {
char* d = (char*) data->getData() + _firstChanOffset;
Ptex::ConvertToFloat(result, d, _dt, _nchan);
}
return;
}
// clamp u and v
u = PtexUtils::clamp(u, 0.0f, 1.0f);
v = PtexUtils::clamp(v, 0.0f, 1.0f);
// build kernel
PtexTriangleKernel k;
buildKernel(k, u, v, uw1, vw1, uw2, vw2, width, blur, f.res);
// accumulate the weight as we apply
_weight = 0;
// allocate temporary double-precision result
_result = (double*) alloca(sizeof(double)*_nchan);
memset(_result, 0, sizeof(double)*_nchan);
// apply to faces
splitAndApply(k, faceid, f);
// normalize (both for data type and cumulative kernel weight applied)
// and output result
double scale = 1.0 / (_weight * OneValue(_dt));
for (int i = 0; i < _nchan; i++) result[i] = float(_result[i] * scale);
// clear temp result
_result = 0;
}
void PtexTriangleFilter::buildKernel(PtexTriangleKernel& k, float u, float v,
float uw1, float vw1, float uw2, float vw2,
float width, float blur, Res faceRes)
{
const double sqrt3 = 1.7320508075688772;
// compute ellipse coefficients, A*u^2 + B*u*v + C*v^2 == AC - B^2/4
double scaleAC = 0.25 * width*width;
double scaleB = -2 * scaleAC;
double A = (vw1*vw1 + vw2*vw2) * scaleAC;
double B = (uw1*vw1 + uw2*vw2) * scaleB;
double C = (uw1*uw1 + uw2*uw2) * scaleAC;
// convert to cartesian domain
double Ac = 0.75 * A;
double Bc = (sqrt3/2) * (B-A);
double Cc = 0.25 * A - 0.5 * B + C;
// compute min blur for eccentricity clamping
const double maxEcc = 15; // max eccentricity
const double eccRatio = (maxEcc*maxEcc + 1) / (maxEcc*maxEcc - 1);
double X = sqrt(squared(Ac - Cc) + squared(Bc));
double b_e = 0.5 * (eccRatio * X - (Ac + Cc));
// compute min blur for texel clamping
// (ensure that ellipse is no smaller than a texel)
double b_t = squared(0.5 / faceRes.u());
// add blur
double b_b = 0.25 * blur * blur;
double b = PtexUtils::max(b_b, PtexUtils::max(b_e, b_t));
Ac += b;
Cc += b;
// compute minor radius
double m = sqrt(2*(Ac*Cc - 0.25*Bc*Bc) / (Ac + Cc + X));
// choose desired resolution
int reslog2 = PtexUtils::max(0, int(ceil(log2(0.5/m))));
// convert back to triangular domain
A = (4/3.0) * Ac;
B = (2/sqrt3) * Bc + A;
C = -0.25 * A + 0.5 * B + Cc;
// scale by kernel width
double scale = PtexTriangleKernelWidth * PtexTriangleKernelWidth;
A *= scale;
B *= scale;
C *= scale;
// find u,v,w extents
double uw = PtexUtils::min(sqrt(C), 1.0);
double vw = PtexUtils::min(sqrt(A), 1.0);
double ww = PtexUtils::min(sqrt(A-B+C), 1.0);
// init kernel
double w = 1 - u - v;
k.set(Res(reslog2, reslog2), u, v, u-uw, v-vw, w-ww, u+uw, v+vw, w+ww, A, B, C);
}
void PtexTriangleFilter::splitAndApply(PtexTriangleKernel& k, int faceid, const Ptex::FaceInfo& f)
{
// do we need to split? if so, split kernel and apply across edge(s)
if (k.u1 < 0 && f.adjface(2) >= 0) {
PtexTriangleKernel ka;
k.splitU(ka);
applyAcrossEdge(ka, f, 2);
}
if (k.v1 < 0 && f.adjface(0) >= 0) {
PtexTriangleKernel ka;
k.splitV(ka);
applyAcrossEdge(ka, f, 0);
}
if (k.w1 < 0 && f.adjface(1) >= 0) {
PtexTriangleKernel ka;
k.splitW(ka);
applyAcrossEdge(ka, f, 1);
}
// apply to local face
apply(k, faceid, f);
}
void PtexTriangleFilter::applyAcrossEdge(PtexTriangleKernel& k,
const Ptex::FaceInfo& f, int eid)
{
int afid = f.adjface(eid), aeid = f.adjedge(eid);
const Ptex::FaceInfo& af = _tx->getFaceInfo(afid);
k.reorient(eid, aeid);
splitAndApply(k, afid, af);
}
void PtexTriangleFilter::apply(PtexTriangleKernel& k, int faceid, const Ptex::FaceInfo& f)
{
// clamp kernel face (resolution and extent)
k.clampRes(f.res);
k.clampExtent();
// build kernel iterators
PtexTriangleKernelIter keven, kodd;
k.getIterators(keven, kodd);
if (!keven.valid && !kodd.valid) return;
// get face data, and apply
PtexPtr<PtexFaceData> dh ( _tx->getData(faceid, k.res) );
if (!dh) return;
if (keven.valid) applyIter(keven, dh);
if (kodd.valid) applyIter(kodd, dh);
}
void PtexTriangleFilter::applyIter(PtexTriangleKernelIter& k, PtexFaceData* dh)
{
if (dh->isConstant()) {
k.applyConst(_result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan);
_weight += k.weight;
}
else if (dh->isTiled()) {
Ptex::Res tileres = dh->tileRes();
PtexTriangleKernelIter kt = k;
int tileresu = tileres.u();
int tileresv = tileres.v();
kt.rowlen = tileresu;
int ntilesu = k.rowlen / kt.rowlen;
int wOffsetBase = k.rowlen - tileresu;
for (int tilev = k.v1 / tileresv, tilevEnd = (k.v2-1) / tileresv; tilev <= tilevEnd; tilev++) {
int vOffset = tilev * tileresv;
kt.v = k.v - vOffset;
kt.v1 = PtexUtils::max(0, k.v1 - vOffset);
kt.v2 = PtexUtils::min(k.v2 - vOffset, tileresv);
for (int tileu = k.u1 / tileresu, tileuEnd = (k.u2-1) / tileresu; tileu <= tileuEnd; tileu++) {
int uOffset = tileu * tileresu;
int wOffset = wOffsetBase - uOffset - vOffset;
kt.u = k.u - uOffset;
kt.u1 = PtexUtils::max(0, k.u1 - uOffset);
kt.u2 = PtexUtils::min(k.u2 - uOffset, tileresu);
kt.w1 = k.w1 - wOffset;
kt.w2 = k.w2 - wOffset;
PtexPtr<PtexFaceData> th ( dh->getTile(tilev * ntilesu + tileu) );
if (th) {
kt.weight = 0;
if (th->isConstant())
kt.applyConst(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan);
else
kt.apply(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan, _ntxchan);
_weight += kt.weight;
}
}
}
}
else {
k.apply(_result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan, _ntxchan);
_weight += k.weight;
}
}

View File

@@ -0,0 +1,78 @@
#ifndef PtexTriangleFilter_h
#define PtexTriangleFilter_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "Ptexture.h"
class PtexTriangleKernel;
class PtexTriangleKernelIter;
class PtexTriangleFilter : public PtexFilter, public Ptex
{
public:
PtexTriangleFilter(PtexTexture* tx, const PtexFilter::Options& opts ) :
_tx(tx), _options(opts), _result(0), _weight(0),
_firstChanOffset(0), _nchan(0), _ntxchan(0),
_dt((DataType)0) {}
virtual void release() { delete this; }
virtual void eval(float* result, int firstchan, int nchannels,
int faceid, float u, float v,
float uw1, float vw1, float uw2, float vw2,
float width, float blur);
protected:
void buildKernel(PtexTriangleKernel& k, float u, float v,
float uw1, float vw1, float uw2, float vw2,
float width, float blur, Res faceRes);
void splitAndApply(PtexTriangleKernel& k, int faceid, const Ptex::FaceInfo& f);
void applyAcrossEdge(PtexTriangleKernel& k, const Ptex::FaceInfo& f, int eid);
void apply(PtexTriangleKernel& k, int faceid, const Ptex::FaceInfo& f);
void applyIter(PtexTriangleKernelIter& k, PtexFaceData* dh);
virtual ~PtexTriangleFilter() {}
PtexTexture* _tx; // texture being evaluated
Options _options; // options
double* _result; // temp result
double _weight; // accumulated weight of data in _result
int _firstChanOffset; // byte offset of first channel to eval
int _nchan; // number of channels to eval
int _ntxchan; // number of channels in texture
DataType _dt; // data type of texture
};
#endif

View File

@@ -0,0 +1,179 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "PtexPlatform.h"
#include "PtexUtils.h"
#include "PtexHalf.h"
#include "PtexTriangleKernel.h"
namespace {
inline double gaussian(double x_squared)
{
static const double scale = -0.5 * (PtexTriangleKernelWidth * PtexTriangleKernelWidth);
return exp(scale * x_squared);
}
}
namespace {
// apply to 1..4 channels (unrolled channel loop) of packed data (nTxChan==nChan)
// the ellipse equation, Q, is calculated via finite differences (Heckbert '89 pg 57)
template<class T, int nChan>
void Apply(PtexTriangleKernelIter& k, double* result, void* data, int /*nChan*/, int /*nTxChan*/)
{
int nTxChan = nChan;
double DDQ = 2*k.A;
for (int vi = k.v1; vi != k.v2; vi++) {
int xw = k.rowlen - vi;
int x1 = PtexUtils::max(k.u1, xw-k.w2);
int x2 = PtexUtils::min(k.u2, xw-k.w1);
double U = x1 - k.u;
double V = vi - k.v;
double DQ = k.A*(2*U+1)+k.B*V;
double Q = k.A*U*U + (k.B*U + k.C*V)*V;
T* p = (T*)data + (vi * k.rowlen + x1) * nTxChan;
T* pEnd = p + (x2-x1)*nTxChan;
for (; p < pEnd; p += nTxChan) {
if (Q < 1) {
double weight = gaussian(Q)*k.wscale;
k.weight += weight;
PtexUtils::VecAccum<T,nChan>()(result, p, weight);
}
Q += DQ;
DQ += DDQ;
}
}
}
// apply to 1..4 channels (unrolled channel loop) w/ pixel stride
template<class T, int nChan>
void ApplyS(PtexTriangleKernelIter& k, double* result, void* data, int /*nChan*/, int nTxChan)
{
double DDQ = 2*k.A;
for (int vi = k.v1; vi != k.v2; vi++) {
int xw = k.rowlen - vi;
int x1 = PtexUtils::max(k.u1, xw-k.w2);
int x2 = PtexUtils::min(k.u2, xw-k.w1);
double U = x1 - k.u;
double V = vi - k.v;
double DQ = k.A*(2*U+1)+k.B*V;
double Q = k.A*U*U + (k.B*U + k.C*V)*V;
T* p = (T*)data + (vi * k.rowlen + x1) * nTxChan;
T* pEnd = p + (x2-x1)*nTxChan;
for (; p < pEnd; p += nTxChan) {
if (Q < 1) {
double weight = gaussian(Q)*k.wscale;
k.weight += weight;
PtexUtils::VecAccum<T,nChan>()(result, p, weight);
}
Q += DQ;
DQ += DDQ;
}
}
}
// apply to N channels (general case)
template<class T>
void ApplyN(PtexTriangleKernelIter& k, double* result, void* data, int nChan, int nTxChan)
{
double DDQ = 2*k.A;
for (int vi = k.v1; vi != k.v2; vi++) {
int xw = k.rowlen - vi;
int x1 = PtexUtils::max(k.u1, xw-k.w2);
int x2 = PtexUtils::min(k.u2, xw-k.w1);
double U = x1 - k.u;
double V = vi - k.v;
double DQ = k.A*(2*U+1)+k.B*V;
double Q = k.A*U*U + (k.B*U + k.C*V)*V;
T* p = (T*)data + (vi * k.rowlen + x1) * nTxChan;
T* pEnd = p + (x2-x1)*nTxChan;
for (; p < pEnd; p += nTxChan) {
if (Q < 1) {
double weight = gaussian(Q)*k.wscale;
k.weight += weight;
PtexUtils::VecAccumN<T>()(result, p, nChan, weight);
}
Q += DQ;
DQ += DDQ;
}
}
}
}
PtexTriangleKernelIter::ApplyFn
PtexTriangleKernelIter::applyFunctions[] = {
// nChan == nTxChan
ApplyN<uint8_t>, ApplyN<uint16_t>, ApplyN<PtexHalf>, ApplyN<float>,
Apply<uint8_t,1>, Apply<uint16_t,1>, Apply<PtexHalf,1>, Apply<float,1>,
Apply<uint8_t,2>, Apply<uint16_t,2>, Apply<PtexHalf,2>, Apply<float,2>,
Apply<uint8_t,3>, Apply<uint16_t,3>, Apply<PtexHalf,3>, Apply<float,3>,
Apply<uint8_t,4>, Apply<uint16_t,4>, Apply<PtexHalf,4>, Apply<float,4>,
// nChan != nTxChan (need pixel stride)
ApplyN<uint8_t>, ApplyN<uint16_t>, ApplyN<PtexHalf>, ApplyN<float>,
ApplyS<uint8_t,1>, ApplyS<uint16_t,1>, ApplyS<PtexHalf,1>, ApplyS<float,1>,
ApplyS<uint8_t,2>, ApplyS<uint16_t,2>, ApplyS<PtexHalf,2>, ApplyS<float,2>,
ApplyS<uint8_t,3>, ApplyS<uint16_t,3>, ApplyS<PtexHalf,3>, ApplyS<float,3>,
ApplyS<uint8_t,4>, ApplyS<uint16_t,4>, ApplyS<PtexHalf,4>, ApplyS<float,4>,
};
void PtexTriangleKernelIter::applyConst(double* dst, void* data, DataType dt, int nChan)
{
// iterate over texel locations and calculate weight as if texture weren't const
double DDQ = 2*A;
for (int vi = v1; vi != v2; vi++) {
int xw = rowlen - vi;
int x1 = PtexUtils::max(u1, xw-w2);
int x2 = PtexUtils::min(u2, xw-w1);
double U = x1 - u;
double V = vi - v;
double DQ = A*(2*U+1)+B*V;
double Q = A*U*U + (B*U + C*V)*V;
for (int x = x1; x < x2; x++) {
if (Q < 1) {
weight += gaussian(Q)*wscale;
}
Q += DQ;
DQ += DDQ;
}
}
// apply weight to single texel value
PtexUtils::applyConst(weight, dst, data, dt, nChan);
}

View File

@@ -0,0 +1,227 @@
#ifndef PtexTriangleKernel_h
#define PtexTriangleKernel_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <assert.h>
#include <algorithm>
#include <numeric>
#include "Ptexture.h"
#include "PtexUtils.h"
// kernel width as a multiple of filter width (should be between 3 and 4)
// for values below 3, the gaussian is not close to zero and a contour will be formed
// larger values are more expensive (proportional to width-squared)
static const float PtexTriangleKernelWidth = 3.5;
/// Triangle filter kernel iterator (in texel coords)
class PtexTriangleKernelIter : public Ptex {
public:
int rowlen; // row length (in u)
double u, v; // uv center in texels
int u1, v1, w1; // uvw lower bounds
int u2, v2, w2; // uvw upper bounds
double A,B,C; // ellipse coefficients (F = 1)
bool valid; // footprint is valid (non-empty)
double wscale; // amount to scale weights by (proportional to texel area)
double weight; // accumulated weight
void apply(double* dst, void* data, DataType dt, int nChan, int nTxChan)
{
// dispatch specialized apply function
ApplyFn fn = applyFunctions[(nChan!=nTxChan)*20 + ((unsigned)nChan<=4)*nChan*4 + dt];
fn(*this, dst, data, nChan, nTxChan);
}
void applyConst(double* dst, void* data, DataType dt, int nChan);
private:
typedef void (*ApplyFn)(PtexTriangleKernelIter& k, double* dst, void* data, int nChan, int nTxChan);
static ApplyFn applyFunctions[40];
};
/// Triangle filter kernel (in normalized triangle coords)
class PtexTriangleKernel : public Ptex {
public:
Res res; // desired resolution
double u, v; // uv filter center
double u1, v1, w1; // uvw lower bounds
double u2, v2, w2; // uvw upper bounds
double A,B,C; // ellipse coefficients (F = A*C-B*B/4)
void set(Res resVal, double uVal, double vVal,
double u1Val, double v1Val, double w1Val,
double u2Val, double v2Val, double w2Val,
double AVal, double BVal, double CVal)
{
res = resVal;
u = uVal; v = vVal;
u1 = u1Val; v1 = v1Val; w1 = w1Val;
u2 = u2Val; v2 = v2Val; w2 = w2Val;
A = AVal; B = BVal; C = CVal;
}
void set(double uVal, double vVal,
double u1Val, double v1Val, double w1Val,
double u2Val, double v2Val, double w2Val)
{
u = uVal; v = vVal;
u1 = u1Val; v1 = v1Val; w1 = w1Val;
u2 = u2Val; v2 = v2Val; w2 = w2Val;
}
void setABC(double AVal, double BVal, double CVal)
{
A = AVal; B = BVal; C = CVal;
}
void splitU(PtexTriangleKernel& ka)
{
ka = *this;
u1 = 0;
ka.u2 = 0;
}
void splitV(PtexTriangleKernel& ka)
{
ka = *this;
v1 = 0;
ka.v2 = 0;
}
void splitW(PtexTriangleKernel& ka)
{
ka = *this;
w1 = 0;
ka.w2 = 0;
}
void rotate1()
{
// rotate ellipse where u'=w, v'=u, w'=v
// (derived by converting to Barycentric form, rotating, and converting back)
setABC(C, 2*C-B, A+C-B);
}
void rotate2()
{
// rotate ellipse where u'=v, v'=w, w'=u
// (derived by converting to Barycentric form, rotating, and converting back)
setABC(A+C-B, 2*A-B, A);
}
void reorient(int eid, int aeid)
{
double w = 1-u-v;
#define C(eid, aeid) (eid*3 + aeid)
switch (C(eid, aeid)) {
case C(0, 0): set(1-u, -v, 1-u2, -v2, 1-w2, 1-u1, -v1, 1-w1); break;
case C(0, 1): set(1-w, 1-u, 1-w2, 1-u2, -v2, 1-w1, 1-u1, -v1); rotate1(); break;
case C(0, 2): set( -v, 1-w, -v2, 1-w2, 1-u2, -v1, 1-w1, 1-u1); rotate2(); break;
case C(1, 0): set(1-v, -w, 1-v2, -w2, 1-u2, 1-v1, -w1, 1-u1); rotate2(); break;
case C(1, 1): set(1-u, 1-v, 1-u2, 1-v2, -w2, 1-u1, 1-v1, -w1); break;
case C(1, 2): set( -w, 1-u, -w2, 1-u2, 1-v2, -w1, 1-u1, 1-v1); rotate1(); break;
case C(2, 0): set(1-w, -u, 1-w2, -u2, 1-v2, 1-w1, -u1, 1-v1); rotate1(); break;
case C(2, 1): set(1-v, 1-w, 1-v2, 1-w2, -u2, 1-v1, 1-w1, -u1); rotate2(); break;
case C(2, 2): set( -u, 1-v, -u2, 1-v2, 1-w2, -u1, 1-v1, 1-w1); break;
#undef C
}
}
void clampRes(Res fres)
{
res.ulog2 = PtexUtils::min(res.ulog2, fres.ulog2);
res.vlog2 = res.ulog2;
}
void clampExtent()
{
u1 = PtexUtils::max(u1, 0.0);
v1 = PtexUtils::max(v1, 0.0);
w1 = PtexUtils::max(w1, 0.0);
u2 = PtexUtils::min(u2, 1-(v1+w1));
v2 = PtexUtils::min(v2, 1-(w1+u1));
w2 = PtexUtils::min(w2, 1-(u1+v1));
}
void getIterators(PtexTriangleKernelIter& ke, PtexTriangleKernelIter& ko)
{
int resu = res.u();
// normalize coefficients for texel units
double Finv = 1.0/(resu*resu*(A*C - 0.25 * B * B));
double Ak = A*Finv, Bk = B*Finv, Ck = C*Finv;
// build even iterator
ke.rowlen = resu;
ke.wscale = 1.0/(resu*resu);
double scale = ke.rowlen;
ke.u = u * scale - 1/3.0;
ke.v = v * scale - 1/3.0;
ke.u1 = int(ceil(u1 * scale - 1/3.0));
ke.v1 = int(ceil(v1 * scale - 1/3.0));
ke.w1 = int(ceil(w1 * scale - 1/3.0));
ke.u2 = int(ceil(u2 * scale - 1/3.0));
ke.v2 = int(ceil(v2 * scale - 1/3.0));
ke.w2 = int(ceil(w2 * scale - 1/3.0));
ke.A = Ak; ke.B = Bk; ke.C = Ck;
ke.valid = (ke.u2 > ke.u1 && ke.v2 > ke.v1 && ke.w2 > ke.w1);
ke.weight = 0;
// build odd iterator: flip kernel across diagonal (u = 1-v, v = 1-u, w = -w)
ko.rowlen = ke.rowlen;
ko.wscale = ke.wscale;
ko.u = (1-v) * scale - 1/3.0;
ko.v = (1-u) * scale - 1/3.0;
ko.u1 = int(ceil((1-v2) * scale - 1/3.0));
ko.v1 = int(ceil((1-u2) * scale - 1/3.0));
ko.w1 = int(ceil(( -w2) * scale - 1/3.0));
ko.u2 = int(ceil((1-v1) * scale - 1/3.0));
ko.v2 = int(ceil((1-u1) * scale - 1/3.0));
ko.w2 = int(ceil(( -w1) * scale - 1/3.0));
ko.A = Ck; ko.B = Bk; ko.C = Ak;
ko.valid = (ko.u2 > ko.u1 && ko.v2 > ko.v1 && ko.w2 > ko.w1);
ko.weight = 0;
}
};
#endif

677
extern/ptex/src/ptex/PtexUtils.cpp vendored Normal file
View File

@@ -0,0 +1,677 @@
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "PtexPlatform.h"
#include <algorithm>
#include <vector>
#include <stdlib.h>
#include <string.h>
#include "PtexHalf.h"
#include "PtexUtils.h"
const char* Ptex::MeshTypeName(MeshType mt)
{
static const char* names[] = { "triangle", "quad" };
if (mt < 0 || mt >= int(sizeof(names)/sizeof(const char*)))
return "(invalid mesh type)";
return names[mt];
}
const char* Ptex::DataTypeName(DataType dt)
{
static const char* names[] = { "uint8", "uint16", "float16", "float32" };
if (dt < 0 || dt >= int(sizeof(names)/sizeof(const char*)))
return "(invalid data type)";
return names[dt];
}
const char* Ptex::BorderModeName(BorderMode m)
{
static const char* names[] = { "clamp", "black", "periodic" };
if (m < 0 || m >= int(sizeof(names)/sizeof(const char*)))
return "(invalid border mode)";
return names[m];
}
const char* Ptex::EdgeIdName(EdgeId eid)
{
static const char* names[] = { "bottom", "right", "top", "left" };
if (eid < 0 || eid >= int(sizeof(names)/sizeof(const char*)))
return "(invalid edge id)";
return names[eid];
}
const char* Ptex::MetaDataTypeName(MetaDataType mdt)
{
static const char* names[] = { "string", "int8", "int16", "int32", "float", "double" };
if (mdt < 0 || mdt >= int(sizeof(names)/sizeof(const char*)))
return "(invalid meta data type)";
return names[mdt];
}
namespace {
template<typename DST, typename SRC>
void ConvertArrayClamped(DST* dst, SRC* src, int numChannels, double scale, double round=0)
{
for (int i = 0; i < numChannels; i++)
dst[i] = DST(PtexUtils::clamp(src[i], 0.0f, 1.0f) * scale + round);
}
template<typename DST, typename SRC>
void ConvertArray(DST* dst, SRC* src, int numChannels, double scale, double round=0)
{
for (int i = 0; i < numChannels; i++) dst[i] = DST(src[i] * scale + round);
}
}
void Ptex::ConvertToFloat(float* dst, const void* src, Ptex::DataType dt, int numChannels)
{
switch (dt) {
case dt_uint8: ConvertArray(dst, (uint8_t*)src, numChannels, 1/255.0); break;
case dt_uint16: ConvertArray(dst, (uint16_t*)src, numChannels, 1/65535.0); break;
case dt_half: ConvertArray(dst, (PtexHalf*)src, numChannels, 1.0); break;
case dt_float: memcpy(dst, src, sizeof(float)*numChannels); break;
}
}
void Ptex::ConvertFromFloat(void* dst, const float* src, Ptex::DataType dt, int numChannels)
{
switch (dt) {
case dt_uint8: ConvertArrayClamped((uint8_t*)dst, src, numChannels, 255.0, 0.5); break;
case dt_uint16: ConvertArrayClamped((uint16_t*)dst, src, numChannels, 65535.0, 0.5); break;
case dt_half: ConvertArray((PtexHalf*)dst, src, numChannels, 1.0); break;
case dt_float: memcpy(dst, src, sizeof(float)*numChannels); break;
}
}
bool PtexUtils::isConstant(const void* data, int stride, int ures, int vres,
int pixelSize)
{
int rowlen = pixelSize * ures;
const char* p = (const char*) data + stride;
// compare each row with the first
for (int i = 1; i < vres; i++, p += stride)
if (0 != memcmp(data, p, rowlen)) return 0;
// make sure first row is constant
p = (const char*) data + pixelSize;
for (int i = 1; i < ures; i++, p += pixelSize)
if (0 != memcmp(data, p, pixelSize)) return 0;
return 1;
}
namespace {
template<typename T>
inline void interleave(const T* src, int sstride, int uw, int vw,
T* dst, int dstride, int nchan)
{
sstride /= sizeof(T);
dstride /= sizeof(T);
// for each channel
for (T* dstend = dst + nchan; dst != dstend; dst++) {
// for each row
T* drow = dst;
for (const T* rowend = src + sstride*vw; src != rowend;
src += sstride, drow += dstride) {
// copy each pixel across the row
T* dp = drow;
for (const T* sp = src, * end = sp + uw; sp != end; dp += nchan)
*dp = *sp++;
}
}
}
}
void PtexUtils::interleave(const void* src, int sstride, int uw, int vw,
void* dst, int dstride, DataType dt, int nchan)
{
switch (dt) {
case dt_uint8: ::interleave((const uint8_t*) src, sstride, uw, vw,
(uint8_t*) dst, dstride, nchan); break;
case dt_half:
case dt_uint16: ::interleave((const uint16_t*) src, sstride, uw, vw,
(uint16_t*) dst, dstride, nchan); break;
case dt_float: ::interleave((const float*) src, sstride, uw, vw,
(float*) dst, dstride, nchan); break;
}
}
namespace {
template<typename T>
inline void deinterleave(const T* src, int sstride, int uw, int vw,
T* dst, int dstride, int nchan)
{
sstride /= sizeof(T);
dstride /= sizeof(T);
// for each channel
for (const T* srcend = src + nchan; src != srcend; src++) {
// for each row
const T* srow = src;
for (const T* rowend = srow + sstride*vw; srow != rowend;
srow += sstride, dst += dstride) {
// copy each pixel across the row
const T* sp = srow;
for (T* dp = dst, * end = dp + uw; dp != end; sp += nchan)
*dp++ = *sp;
}
}
}
}
void PtexUtils::deinterleave(const void* src, int sstride, int uw, int vw,
void* dst, int dstride, DataType dt, int nchan)
{
switch (dt) {
case dt_uint8: ::deinterleave((const uint8_t*) src, sstride, uw, vw,
(uint8_t*) dst, dstride, nchan); break;
case dt_half:
case dt_uint16: ::deinterleave((const uint16_t*) src, sstride, uw, vw,
(uint16_t*) dst, dstride, nchan); break;
case dt_float: ::deinterleave((const float*) src, sstride, uw, vw,
(float*) dst, dstride, nchan); break;
}
}
namespace {
template<typename T>
void encodeDifference(T* data, int size)
{
size /= sizeof(T);
T* p = (T*) data, * end = p + size, tmp, prev = 0;
while (p != end) { tmp = prev; prev = *p; *p++ -= tmp; }
}
}
void PtexUtils::encodeDifference(void* data, int size, DataType dt)
{
switch (dt) {
case dt_uint8: ::encodeDifference((uint8_t*) data, size); break;
case dt_uint16: ::encodeDifference((uint16_t*) data, size); break;
default: break; // skip other types
}
}
namespace {
template<typename T>
void decodeDifference(T* data, int size)
{
size /= sizeof(T);
T* p = (T*) data, * end = p + size, prev = 0;
while (p != end) { *p += prev; prev = *p++; }
}
}
void PtexUtils::decodeDifference(void* data, int size, DataType dt)
{
switch (dt) {
case dt_uint8: ::decodeDifference((uint8_t*) data, size); break;
case dt_uint16: ::decodeDifference((uint16_t*) data, size); break;
default: break; // skip other types
}
}
namespace {
template<typename T>
inline void reduce(const T* src, int sstride, int uw, int vw,
T* dst, int dstride, int nchan)
{
sstride /= sizeof(T);
dstride /= sizeof(T);
int rowlen = uw*nchan;
int srowskip = 2*sstride - rowlen;
int drowskip = dstride - rowlen/2;
for (const T* end = src + vw*sstride; src != end;
src += srowskip, dst += drowskip)
for (const T* rowend = src + rowlen; src != rowend; src += nchan)
for (const T* pixend = src+nchan; src != pixend; src++)
*dst++ = T(0.25 * (src[0] + src[nchan] +
src[sstride] + src[sstride+nchan]));
}
}
void PtexUtils::reduce(const void* src, int sstride, int uw, int vw,
void* dst, int dstride, DataType dt, int nchan)
{
switch (dt) {
case dt_uint8: ::reduce((const uint8_t*) src, sstride, uw, vw,
(uint8_t*) dst, dstride, nchan); break;
case dt_half: ::reduce((const PtexHalf*) src, sstride, uw, vw,
(PtexHalf*) dst, dstride, nchan); break;
case dt_uint16: ::reduce((const uint16_t*) src, sstride, uw, vw,
(uint16_t*) dst, dstride, nchan); break;
case dt_float: ::reduce((const float*) src, sstride, uw, vw,
(float*) dst, dstride, nchan); break;
}
}
namespace {
template<typename T>
inline void reduceu(const T* src, int sstride, int uw, int vw,
T* dst, int dstride, int nchan)
{
sstride /= sizeof(T);
dstride /= sizeof(T);
int rowlen = uw*nchan;
int srowskip = sstride - rowlen;
int drowskip = dstride - rowlen/2;
for (const T* end = src + vw*sstride; src != end;
src += srowskip, dst += drowskip)
for (const T* rowend = src + rowlen; src != rowend; src += nchan)
for (const T* pixend = src+nchan; src != pixend; src++)
*dst++ = T(0.5 * (src[0] + src[nchan]));
}
}
void PtexUtils::reduceu(const void* src, int sstride, int uw, int vw,
void* dst, int dstride, DataType dt, int nchan)
{
switch (dt) {
case dt_uint8: ::reduceu((const uint8_t*) src, sstride, uw, vw,
(uint8_t*) dst, dstride, nchan); break;
case dt_half: ::reduceu((const PtexHalf*) src, sstride, uw, vw,
(PtexHalf*) dst, dstride, nchan); break;
case dt_uint16: ::reduceu((const uint16_t*) src, sstride, uw, vw,
(uint16_t*) dst, dstride, nchan); break;
case dt_float: ::reduceu((const float*) src, sstride, uw, vw,
(float*) dst, dstride, nchan); break;
}
}
namespace {
template<typename T>
inline void reducev(const T* src, int sstride, int uw, int vw,
T* dst, int dstride, int nchan)
{
sstride /= sizeof(T);
dstride /= sizeof(T);
int rowlen = uw*nchan;
int srowskip = 2*sstride - rowlen;
int drowskip = dstride - rowlen;
for (const T* end = src + vw*sstride; src != end;
src += srowskip, dst += drowskip)
for (const T* rowend = src + rowlen; src != rowend; src++)
*dst++ = T(0.5 * (src[0] + src[sstride]));
}
}
void PtexUtils::reducev(const void* src, int sstride, int uw, int vw,
void* dst, int dstride, DataType dt, int nchan)
{
switch (dt) {
case dt_uint8: ::reducev((const uint8_t*) src, sstride, uw, vw,
(uint8_t*) dst, dstride, nchan); break;
case dt_half: ::reducev((const PtexHalf*) src, sstride, uw, vw,
(PtexHalf*) dst, dstride, nchan); break;
case dt_uint16: ::reducev((const uint16_t*) src, sstride, uw, vw,
(uint16_t*) dst, dstride, nchan); break;
case dt_float: ::reducev((const float*) src, sstride, uw, vw,
(float*) dst, dstride, nchan); break;
}
}
namespace {
// generate a reduction of a packed-triangle texture
// note: this method won't work for tiled textures
template<typename T>
inline void reduceTri(const T* src, int sstride, int w, int /*vw*/,
T* dst, int dstride, int nchan)
{
sstride /= sizeof(T);
dstride /= sizeof(T);
int rowlen = w*nchan;
const T* src2 = src + (w-1) * sstride + rowlen - nchan;
int srowinc2 = -2*sstride - nchan;
int srowskip = 2*sstride - rowlen;
int srowskip2 = w*sstride - 2 * nchan;
int drowskip = dstride - rowlen/2;
for (const T* end = src + w*sstride; src != end;
src += srowskip, src2 += srowskip2, dst += drowskip)
for (const T* rowend = src + rowlen; src != rowend; src += nchan, src2 += srowinc2)
for (const T* pixend = src+nchan; src != pixend; src++, src2++)
*dst++ = T(0.25 * (src[0] + src[nchan] + src[sstride] + src2[0]));
}
}
void PtexUtils::reduceTri(const void* src, int sstride, int w, int /*vw*/,
void* dst, int dstride, DataType dt, int nchan)
{
switch (dt) {
case dt_uint8: ::reduceTri((const uint8_t*) src, sstride, w, 0,
(uint8_t*) dst, dstride, nchan); break;
case dt_half: ::reduceTri((const PtexHalf*) src, sstride, w, 0,
(PtexHalf*) dst, dstride, nchan); break;
case dt_uint16: ::reduceTri((const uint16_t*) src, sstride, w, 0,
(uint16_t*) dst, dstride, nchan); break;
case dt_float: ::reduceTri((const float*) src, sstride, w, 0,
(float*) dst, dstride, nchan); break;
}
}
void PtexUtils::fill(const void* src, void* dst, int dstride,
int ures, int vres, int pixelsize)
{
// fill first row
int rowlen = ures*pixelsize;
char* ptr = (char*) dst;
char* end = ptr + rowlen;
for (; ptr != end; ptr += pixelsize) memcpy(ptr, src, pixelsize);
// fill remaining rows from first row
ptr = (char*) dst + dstride;
end = (char*) dst + vres*dstride;
for (; ptr != end; ptr += dstride) memcpy(ptr, dst, rowlen);
}
void PtexUtils::copy(const void* src, int sstride, void* dst, int dstride,
int vres, int rowlen)
{
// regular non-tiled case
if (sstride == rowlen && dstride == rowlen) {
// packed case - copy in single block
memcpy(dst, src, vres*rowlen);
} else {
// copy a row at a time
char* sptr = (char*) src;
char* dptr = (char*) dst;
for (char* end = sptr + vres*sstride; sptr != end;) {
memcpy(dptr, sptr, rowlen);
dptr += dstride;
sptr += sstride;
}
}
}
namespace {
template<typename T>
inline void blend(const T* src, float weight, T* dst, int rowlen, int nchan)
{
for (const T* end = src + rowlen * nchan; src != end; dst++)
*dst = *dst + T(weight * *src++);
}
template<typename T>
inline void blendflip(const T* src, float weight, T* dst, int rowlen, int nchan)
{
dst += (rowlen-1) * nchan;
for (const T* end = src + rowlen * nchan; src != end;) {
for (int i = 0; i < nchan; i++, dst++)
*dst = *dst + T(weight * *src++);
dst -= nchan*2;
}
}
}
void PtexUtils::blend(const void* src, float weight, void* dst, bool flip,
int rowlen, DataType dt, int nchan)
{
switch ((dt<<1) | int(flip)) {
case (dt_uint8<<1): ::blend((const uint8_t*) src, weight,
(uint8_t*) dst, rowlen, nchan); break;
case (dt_uint8<<1 | 1): ::blendflip((const uint8_t*) src, weight,
(uint8_t*) dst, rowlen, nchan); break;
case (dt_half<<1): ::blend((const PtexHalf*) src, weight,
(PtexHalf*) dst, rowlen, nchan); break;
case (dt_half<<1 | 1): ::blendflip((const PtexHalf*) src, weight,
(PtexHalf*) dst, rowlen, nchan); break;
case (dt_uint16<<1): ::blend((const uint16_t*) src, weight,
(uint16_t*) dst, rowlen, nchan); break;
case (dt_uint16<<1 | 1): ::blendflip((const uint16_t*) src, weight,
(uint16_t*) dst, rowlen, nchan); break;
case (dt_float<<1): ::blend((const float*) src, weight,
(float*) dst, rowlen, nchan); break;
case (dt_float<<1 | 1): ::blendflip((const float*) src, weight,
(float*) dst, rowlen, nchan); break;
}
}
namespace {
template<typename T>
inline void average(const T* src, int sstride, int uw, int vw,
T* dst, int nchan)
{
float* buff = (float*) alloca(nchan*sizeof(float));
memset(buff, 0, nchan*sizeof(float));
sstride /= sizeof(T);
int rowlen = uw*nchan;
int rowskip = sstride - rowlen;
for (const T* end = src + vw*sstride; src != end; src += rowskip)
for (const T* rowend = src + rowlen; src != rowend;)
for (int i = 0; i < nchan; i++) buff[i] += *src++;
double scale = 1.0/(uw*vw);
for (int i = 0; i < nchan; i++) dst[i] = T(buff[i]*scale);
}
}
void PtexUtils::average(const void* src, int sstride, int uw, int vw,
void* dst, DataType dt, int nchan)
{
switch (dt) {
case dt_uint8: ::average((const uint8_t*) src, sstride, uw, vw,
(uint8_t*) dst, nchan); break;
case dt_half: ::average((const PtexHalf*) src, sstride, uw, vw,
(PtexHalf*) dst, nchan); break;
case dt_uint16: ::average((const uint16_t*) src, sstride, uw, vw,
(uint16_t*) dst, nchan); break;
case dt_float: ::average((const float*) src, sstride, uw, vw,
(float*) dst, nchan); break;
}
}
namespace {
struct CompareRfaceIds {
const Ptex::FaceInfo* faces;
CompareRfaceIds(const Ptex::FaceInfo* faces) : faces(faces) {}
bool operator() (uint32_t faceid1, uint32_t faceid2)
{
const Ptex::FaceInfo& f1 = faces[faceid1];
const Ptex::FaceInfo& f2 = faces[faceid2];
int min1 = f1.isConstant() ? 1 : PtexUtils::min(f1.res.ulog2, f1.res.vlog2);
int min2 = f2.isConstant() ? 1 : PtexUtils::min(f2.res.ulog2, f2.res.vlog2);
return min1 > min2;
}
};
}
namespace {
template<typename T>
inline void multalpha(T* data, int npixels, int nchannels, int alphachan, double scale)
{
int alphaoffset; // offset to alpha chan from data ptr
int nchanmult; // number of channels to alpha-multiply
if (alphachan == 0) {
// first channel is alpha chan: mult the rest of the channels
data++;
alphaoffset = -1;
nchanmult = nchannels - 1;
}
else {
// mult all channels up to alpha chan
alphaoffset = alphachan;
nchanmult = alphachan;
}
for (T* end = data + npixels*nchannels; data != end; data += nchannels) {
double aval = scale * data[alphaoffset];
for (int i = 0; i < nchanmult; i++) data[i] = T(data[i] * aval);
}
}
}
void PtexUtils::multalpha(void* data, int npixels, DataType dt, int nchannels, int alphachan)
{
double scale = OneValueInv(dt);
switch(dt) {
case dt_uint8: ::multalpha((uint8_t*) data, npixels, nchannels, alphachan, scale); break;
case dt_uint16: ::multalpha((uint16_t*) data, npixels, nchannels, alphachan, scale); break;
case dt_half: ::multalpha((PtexHalf*) data, npixels, nchannels, alphachan, scale); break;
case dt_float: ::multalpha((float*) data, npixels, nchannels, alphachan, scale); break;
}
}
namespace {
template<typename T>
inline void divalpha(T* data, int npixels, int nchannels, int alphachan, double scale)
{
int alphaoffset; // offset to alpha chan from data ptr
int nchandiv; // number of channels to alpha-divide
if (alphachan == 0) {
// first channel is alpha chan: div the rest of the channels
data++;
alphaoffset = -1;
nchandiv = nchannels - 1;
}
else {
// div all channels up to alpha chan
alphaoffset = alphachan;
nchandiv = alphachan;
}
for (T* end = data + npixels*nchannels; data != end; data += nchannels) {
T alpha = data[alphaoffset];
if (!alpha) continue; // don't divide by zero!
double aval = scale / alpha;
for (int i = 0; i < nchandiv; i++) data[i] = T(data[i] * aval);
}
}
}
void PtexUtils::divalpha(void* data, int npixels, DataType dt, int nchannels, int alphachan)
{
double scale = OneValue(dt);
switch(dt) {
case dt_uint8: ::divalpha((uint8_t*) data, npixels, nchannels, alphachan, scale); break;
case dt_uint16: ::divalpha((uint16_t*) data, npixels, nchannels, alphachan, scale); break;
case dt_half: ::divalpha((PtexHalf*) data, npixels, nchannels, alphachan, scale); break;
case dt_float: ::divalpha((float*) data, npixels, nchannels, alphachan, scale); break;
}
}
void PtexUtils::genRfaceids(const FaceInfo* faces, int nfaces,
uint32_t* rfaceids, uint32_t* faceids)
{
// stable_sort faceids by smaller dimension (u or v) in descending order
// treat const faces as having res of 1
// init faceids
for (int i = 0; i < nfaces; i++) faceids[i] = i;
// sort faceids by rfaceid
std::stable_sort(faceids, faceids + nfaces, CompareRfaceIds(faces));
// generate mapping from faceid to rfaceid
for (int i = 0; i < nfaces; i++) {
// note: i is the rfaceid
rfaceids[faceids[i]] = i;
}
}
namespace {
// apply to 1..4 channels, unrolled
template<class T, int nChan>
void ApplyConst(double weight, double* dst, void* data, int /*nChan*/)
{
// dst[i] += data[i] * weight for i in {0..n-1}
PtexUtils::VecAccum<T,nChan>()(dst, (T*) data, weight);
}
// apply to N channels (general case)
template<class T>
void ApplyConstN(double weight, double* dst, void* data, int nChan)
{
// dst[i] += data[i] * weight for i in {0..n-1}
PtexUtils::VecAccumN<T>()(dst, (T*) data, nChan, weight);
}
}
PtexUtils::ApplyConstFn
PtexUtils::applyConstFunctions[20] = {
ApplyConstN<uint8_t>, ApplyConstN<uint16_t>, ApplyConstN<PtexHalf>, ApplyConstN<float>,
ApplyConst<uint8_t,1>, ApplyConst<uint16_t,1>, ApplyConst<PtexHalf,1>, ApplyConst<float,1>,
ApplyConst<uint8_t,2>, ApplyConst<uint16_t,2>, ApplyConst<PtexHalf,2>, ApplyConst<float,2>,
ApplyConst<uint8_t,3>, ApplyConst<uint16_t,3>, ApplyConst<PtexHalf,3>, ApplyConst<float,3>,
ApplyConst<uint8_t,4>, ApplyConst<uint16_t,4>, ApplyConst<PtexHalf,4>, ApplyConst<float,4>,
};
#ifndef PTEX_USE_STDSTRING
Ptex::String::~String()
{
if (_str) free(_str);
}
Ptex::String& Ptex::String::operator=(const char* str)
{
if (_str) free(_str);
_str = str ? strdup(str) : 0;
return *this;
}
std::ostream& operator << (std::ostream& stream, const Ptex::String& str)
{
stream << str.c_str();
return stream;
}
#endif

199
extern/ptex/src/ptex/PtexUtils.h vendored Normal file
View File

@@ -0,0 +1,199 @@
#ifndef PtexUtils_h
#define PtexUtils_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "Ptexture.h"
struct PtexUtils : public Ptex {
static bool isPowerOfTwo(int x)
{
return !(x&(x-1));
}
static uint32_t ones(uint32_t x)
{
// count number of ones
x = (x & 0x55555555) + ((x >> 1) & 0x55555555); // add pairs of bits
x = (x & 0x33333333) + ((x >> 2) & 0x33333333); // add bit pairs
x = (x & 0x0f0f0f0f) + ((x >> 4) & 0x0f0f0f0f); // add nybbles
x += (x >> 8); // add bytes
x += (x >> 16); // add words
return(x & 0xff);
}
static uint32_t floor_log2(uint32_t x)
{
// floor(log2(n))
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return ones(x>>1);
}
static uint32_t ceil_log2(uint32_t x)
{
// ceil(log2(n))
bool isPow2 = isPowerOfTwo(x);
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return ones(x>>1) + !isPow2;
}
static double smoothstep(double x, double a, double b)
{
if ( x < a ) return 0;
if ( x >= b ) return 1;
x = (x - a)/(b - a);
return x*x * (3 - 2*x);
}
static double qsmoothstep(double x, double a, double b)
{
// quintic smoothstep (cubic is only C1)
if ( x < a ) return 0;
if ( x >= b ) return 1;
x = (x - a)/(b - a);
return x*x*x * (10 + x * (-15 + x*6));
}
template<typename T>
static T cond(bool c, T a, T b) { return c * a + (!c)*b; }
template<typename T>
static T min(T a, T b) { return cond(a < b, a, b); }
template<typename T>
static T max(T a, T b) { return cond(a >= b, a, b); }
template<typename T>
static T clamp(T x, T lo, T hi) { return cond(x < lo, lo, cond(x > hi, hi, x)); }
static bool isConstant(const void* data, int stride, int ures, int vres,
int pixelSize);
static void interleave(const void* src, int sstride, int ures, int vres,
void* dst, int dstride, DataType dt, int nchannels);
static void deinterleave(const void* src, int sstride, int ures, int vres,
void* dst, int dstride, DataType dt, int nchannels);
static void encodeDifference(void* data, int size, DataType dt);
static void decodeDifference(void* data, int size, DataType dt);
typedef void ReduceFn(const void* src, int sstride, int ures, int vres,
void* dst, int dstride, DataType dt, int nchannels);
static void reduce(const void* src, int sstride, int ures, int vres,
void* dst, int dstride, DataType dt, int nchannels);
static void reduceu(const void* src, int sstride, int ures, int vres,
void* dst, int dstride, DataType dt, int nchannels);
static void reducev(const void* src, int sstride, int ures, int vres,
void* dst, int dstride, DataType dt, int nchannels);
static void reduceTri(const void* src, int sstride, int ures, int vres,
void* dst, int dstride, DataType dt, int nchannels);
static void average(const void* src, int sstride, int ures, int vres,
void* dst, DataType dt, int nchannels);
static void fill(const void* src, void* dst, int dstride,
int ures, int vres, int pixelsize);
static void copy(const void* src, int sstride, void* dst, int dstride,
int nrows, int rowlen);
static void blend(const void* src, float weight, void* dst, bool flip,
int rowlen, DataType dt, int nchannels);
static void multalpha(void* data, int npixels, DataType dt, int nchannels, int alphachan);
static void divalpha(void* data, int npixels, DataType dt, int nchannels, int alphachan);
static void genRfaceids(const FaceInfo* faces, int nfaces,
uint32_t* rfaceids, uint32_t* faceids);
// fixed length vector accumulator: dst[i] += val[i] * weight
template<typename T, int n>
struct VecAccum {
VecAccum() {}
void operator()(double* dst, const T* val, double weight)
{
*dst += *val * weight;
// use template to unroll loop
VecAccum<T,n-1>()(dst+1, val+1, weight);
}
};
template<typename T>
struct VecAccum<T,0> { void operator()(double*, const T*, double) {} };
// variable length vector accumulator: dst[i] += val[i] * weight
template<typename T>
struct VecAccumN {
void operator()(double* dst, const T* val, int nchan, double weight)
{
for (int i = 0; i < nchan; i++) dst[i] += val[i] * weight;
}
};
// fixed length vector multiplier: dst[i] += val[i] * weight
template<typename T, int n>
struct VecMult {
VecMult() {}
void operator()(double* dst, const T* val, double weight)
{
*dst = *val * weight;
// use template to unroll loop
VecMult<T,n-1>()(dst+1, val+1, weight);
}
};
template<typename T>
struct VecMult<T,0> { void operator()(double*, const T*, double) {} };
// variable length vector multiplier: dst[i] = val[i] * weight
template<typename T>
struct VecMultN {
void operator()(double* dst, const T* val, int nchan, double weight)
{
for (int i = 0; i < nchan; i++) dst[i] = val[i] * weight;
}
};
typedef void (*ApplyConstFn)(double weight, double* dst, void* data, int nChan);
static ApplyConstFn applyConstFunctions[20];
static void applyConst(double weight, double* dst, void* data, Ptex::DataType dt, int nChan)
{
// dispatch specialized apply function
ApplyConstFn fn = applyConstFunctions[((unsigned)nChan<=4)*nChan*4 + dt];
fn(weight, dst, data, nChan);
}
};
#endif

1400
extern/ptex/src/ptex/PtexWriter.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

193
extern/ptex/src/ptex/PtexWriter.h vendored Normal file
View File

@@ -0,0 +1,193 @@
#ifndef PtexWriter_h
#define PtexWriter_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include "PtexPlatform.h"
#include <zlib.h>
#include <map>
#include <vector>
#include <stdio.h>
#include "Ptexture.h"
#include "PtexIO.h"
#include "PtexReader.h"
class PtexWriterBase : public PtexWriter, public PtexIO {
public:
virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode)
{
_extheader.ubordermode = uBorderMode;
_extheader.vbordermode = vBorderMode;
}
virtual void writeMeta(const char* key, const char* value);
virtual void writeMeta(const char* key, const int8_t* value, int count);
virtual void writeMeta(const char* key, const int16_t* value, int count);
virtual void writeMeta(const char* key, const int32_t* value, int count);
virtual void writeMeta(const char* key, const float* value, int count);
virtual void writeMeta(const char* key, const double* value, int count);
virtual void writeMeta(PtexMetaData* data);
virtual bool close(Ptex::String& error);
virtual void release();
bool ok(Ptex::String& error) {
if (!_ok) getError(error);
return _ok;
}
void getError(Ptex::String& error) {
error = (_error + "\nPtex file: " + _path).c_str();
}
protected:
struct MetaEntry {
std::string key;
MetaDataType datatype;
std::vector<uint8_t> data;
MetaEntry() : datatype(MetaDataType(0)), data() {}
};
virtual void finish() = 0;
PtexWriterBase(const char* path,
Ptex::MeshType mt, Ptex::DataType dt,
int nchannels, int alphachan, int nfaces,
bool compress);
virtual ~PtexWriterBase();
int writeBlank(FILE* fp, int size);
int writeBlock(FILE* fp, const void* data, int size);
int writeZipBlock(FILE* fp, const void* data, int size, bool finish=true);
int readBlock(FILE* fp, void* data, int size);
int copyBlock(FILE* dst, FILE* src, FilePos pos, int size);
Res calcTileRes(Res faceres);
virtual void addMetaData(const char* key, MetaDataType t, const void* value, int size);
void writeConstFaceBlock(FILE* fp, const void* data, FaceDataHeader& fdh);
void writeFaceBlock(FILE* fp, const void* data, int stride, Res res,
FaceDataHeader& fdh);
void writeFaceData(FILE* fp, const void* data, int stride, Res res,
FaceDataHeader& fdh);
void writeReduction(FILE* fp, const void* data, int stride, Res res);
int writeMetaDataBlock(FILE* fp, MetaEntry& val);
void setError(const std::string& error) { _error = error; _ok = false; }
bool storeFaceInfo(int faceid, FaceInfo& dest, const FaceInfo& src, int flags=0);
bool _ok; // true if no error has occurred
std::string _error; // the error text (if any)
std::string _path; // file path
std::string _tilepath; // temp tile file path ("<path>.tiles.tmp")
FILE* _tilefp; // temp tile file handle
Header _header; // the file header
ExtHeader _extheader; // extended header
int _pixelSize; // size of a pixel in bytes
std::vector<MetaEntry> _metadata; // meta data waiting to be written
std::map<std::string,int> _metamap; // for preventing duplicate keys
z_stream_s _zstream; // libzip compression stream
PtexUtils::ReduceFn* _reduceFn;
};
class PtexMainWriter : public PtexWriterBase {
public:
PtexMainWriter(const char* path, PtexTexture* tex,
Ptex::MeshType mt, Ptex::DataType dt,
int nchannels, int alphachan, int nfaces, bool genmipmaps);
virtual bool close(Ptex::String& error);
virtual bool writeFace(int faceid, const FaceInfo& f, const void* data, int stride);
virtual bool writeConstantFace(int faceid, const FaceInfo& f, const void* data);
protected:
virtual ~PtexMainWriter();
virtual void addMetaData(const char* key, MetaDataType t, const void* value, int size)
{
PtexWriterBase::addMetaData(key, t, value, size);
_hasNewData = true;
}
private:
virtual void finish();
void generateReductions();
void flagConstantNeighorhoods();
void storeConstValue(int faceid, const void* data, int stride, Res res);
void writeMetaData(FILE* fp);
std::string _newpath; // path to ".new" file
std::string _tmppath; // temp file path ("<path>.tmp")
FILE* _tmpfp; // temp file handle
bool _hasNewData; // true if data has been written
bool _genmipmaps; // true if mipmaps should be generated
std::vector<FaceInfo> _faceinfo; // info about each face
std::vector<uint8_t> _constdata; // constant data for each face
std::vector<uint32_t> _rfaceids; // faceid reordering for reduction levels
std::vector<uint32_t> _faceids_r; // faceid indexed by rfaceid
static const int MinReductionLog2 =2; // log2(minimum reduction size) - can tune
struct LevelRec {
// note: level 0 is ordered by faceid
// levels 1+ are reduction levels (half res in both u and v) and
// are ordered by rfaceid[faceid]. Also, faces with a minimum
// dimension (the smaller of u or v) smaller than MinReductionLog2
// are omitted from subsequent levels.
std::vector<FilePos> pos; // position of data blocks within _tmp file
std::vector<FaceDataHeader> fdh; // face data headers
};
std::vector<LevelRec> _levels; // info about each level
std::vector<FilePos> _rpos; // reduction file positions
PtexReader* _reader; // reader for accessing existing data in file
};
class PtexIncrWriter : public PtexWriterBase {
public:
PtexIncrWriter(const char* path, FILE* fp,
Ptex::MeshType mt, Ptex::DataType dt,
int nchannels, int alphachan, int nfaces);
virtual bool close(Ptex::String& error);
virtual bool writeFace(int faceid, const FaceInfo& f, const void* data, int stride);
virtual bool writeConstantFace(int faceid, const FaceInfo& f, const void* data);
protected:
void writeMetaDataEdit();
virtual void finish();
virtual ~PtexIncrWriter();
private:
FILE* _fp; // the file being edited
};
#endif

984
extern/ptex/src/ptex/Ptexture.h vendored Normal file
View File

@@ -0,0 +1,984 @@
#ifndef Ptexture_h
#define Ptexture_h
/*
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc. All rights reserved
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
Studios" or the names of its contributors may NOT be used to
endorse or promote products derived from this software without
specific prior written permission from Walt Disney Pictures.
Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
/**
@file Ptexture.h
@brief Public API classes for reading, writing, caching, and filtering Ptex files.
*/
#if defined(_WIN32) || defined(_WINDOWS) || defined(_MSC_VER)
# ifndef PTEX_STATIC
# ifdef PTEX_EXPORTS
# define PTEXAPI __declspec(dllexport)
# else
# define PTEXAPI __declspec(dllimport)
# endif
# else
# define PTEXAPI
# endif
#else
# define PTEXAPI
# ifndef DOXYGEN
# define PTEX_USE_STDSTRING
# endif
#endif
#include "PtexInt.h"
#include <ostream>
#define PtexAPIVersion 2
#define PtexFileMajorVersion 1
#define PtexFileMinorVersion 3
/** Common data structures and enums used throughout the API. */
struct Ptex {
/** Type of base mesh for which the textures are defined. A mesh
can be triangle-based (with triangular textures) or quad-based
(with rectangular textures). */
enum MeshType {
mt_triangle, ///< Mesh is triangle-based.
mt_quad ///< Mesh is quad-based.
};
/** Type of data stored in texture file. */
enum DataType {
dt_uint8, ///< Unsigned, 8-bit integer.
dt_uint16, ///< Unsigned, 16-bit integer.
dt_half, ///< Half-precision (16-bit) floating point.
dt_float ///< Single-precision (32-bit) floating point.
};
/** How to handle mesh border when filtering. */
enum BorderMode {
m_clamp, ///< texel access is clamped to border
m_black, ///< texel beyond border are assumed to be black
m_periodic ///< texel access wraps to other side of face
};
/** Edge IDs used in adjacency data in the Ptex::FaceInfo struct.
Edge ID usage for triangle meshes is TBD. */
enum EdgeId {
e_bottom, ///< Bottom edge, from UV (0,0) to (1,0)
e_right, ///< Right edge, from UV (1,0) to (1,1)
e_top, ///< Top edge, from UV (1,1) to (0,1)
e_left ///< Left edge, from UV (0,1) to (0,0)
};
/** Type of meta data entry. */
enum MetaDataType {
mdt_string, ///< Null-terminated string.
mdt_int8, ///< Signed 8-bit integer.
mdt_int16, ///< Signed 16-bit integer.
mdt_int32, ///< Signed 32-bit integer.
mdt_float, ///< Single-precision (32-bit) floating point.
mdt_double ///< Double-precision (32-bit) floating point.
};
/** Look up name of given mesh type. */
PTEXAPI static const char* MeshTypeName(MeshType mt);
/** Look up name of given data type. */
PTEXAPI static const char* DataTypeName(DataType dt);
/** Look up name of given border mode. */
PTEXAPI static const char* BorderModeName(BorderMode m);
/** Look up name of given edge ID. */
PTEXAPI static const char* EdgeIdName(EdgeId eid);
/** Look up name of given meta data type. */
PTEXAPI static const char* MetaDataTypeName(MetaDataType mdt);
/** Look up size of given data type (in bytes). */
static int DataSize(DataType dt) {
static const int sizes[] = { 1,2,2,4 };
return sizes[dt];
}
/** Look up value of given data type that corresponds to the normalized value of 1.0. */
static double OneValue(DataType dt) {
static const double one[] = { 255.0, 65535.0, 1.0, 1.0 };
return one[dt];
}
/** Lookup up inverse value of given data type that corresponds to the normalized value of 1.0. */
static double OneValueInv(DataType dt) {
static const double one[] = { 1.0/255.0, 1.0/65535.0, 1.0, 1.0 };
return one[dt];
}
/** Convert a number of data values from the given data type to float. */
PTEXAPI static void ConvertToFloat(float* dst, const void* src,
Ptex::DataType dt, int numChannels);
/** Convert a number of data values from float to the given data type. */
PTEXAPI static void ConvertFromFloat(void* dst, const float* src,
Ptex::DataType dt, int numChannels);
/** Pixel resolution of a given texture.
The resolution is stored in log form: ulog2 = log2(ures), vlog2 = log2(vres)).
Note: negative ulog2 or vlog2 values are reserved for internal use.
*/
struct Res {
int8_t ulog2; ///< log base 2 of u resolution, in texels
int8_t vlog2; ///< log base 2 of v resolution, in texels
/// Default constructor, sets res to 0 (1x1 texel).
Res() : ulog2(0), vlog2(0) {}
/// Constructor.
Res(int8_t ulog2, int8_t vlog2) : ulog2(ulog2), vlog2(vlog2) {}
/// Constructor from 16-bit integer
Res(uint16_t value) {
ulog2 = *(uint8_t *)&value;
vlog2 = *((uint8_t *)&value + 1);
}
/// U resolution in texels.
int u() const { return 1<<(unsigned)ulog2; }
/// V resolution in texels.
int v() const { return 1<<(unsigned)vlog2; }
/// Resolution as a single 16-bit integer value.
uint16_t& val() { return *(uint16_t*)this; }
/// Resolution as a single 16-bit integer value.
const uint16_t& val() const { return *(uint16_t*)this; }
/// Total size of specified texture in texels (u * v).
int size() const { return u() * v(); }
/// Comparison operator.
bool operator==(const Res& r) const { return val() == r.val(); }
/// Comparison operator.
bool operator!=(const Res& r) const { return val() != r.val(); }
/// True if res is >= given res in both u and v directions.
bool operator>=(const Res& r) const { return ulog2 >= r.ulog2 && vlog2 >= r.vlog2; }
/// Get value of resolution with u and v swapped.
Res swappeduv() const { return Res(vlog2, ulog2); }
/// Swap the u and v resolution values in place.
void swapuv() { *this = swappeduv(); }
/// Clamp the resolution value against the given value.
void clamp(const Res& r) {
if (ulog2 > r.ulog2) ulog2 = r.ulog2;
if (vlog2 > r.vlog2) vlog2 = r.vlog2;
}
/// Determine the number of tiles in the u direction for the given tile res.
int ntilesu(Res tileres) const { return 1<<(ulog2-tileres.ulog2); }
/// Determine the number of tiles in the v direction for the given tile res.
int ntilesv(Res tileres) const { return 1<<(vlog2-tileres.vlog2); }
/// Determine the total number of tiles for the given tile res.
int ntiles(Res tileres) const { return ntilesu(tileres) * ntilesv(tileres); }
};
/** Information about a face, as stored in the Ptex file header.
The FaceInfo data contains the face resolution and neighboring face
adjacency information as well as a set of flags describing the face.
The adjfaces data member contains the face ids of the four neighboring faces.
The neighbors are accessed in EdgeId order, CCW, starting with the bottom edge.
The adjedges data member contains the corresponding edge id for each neighboring face.
If a face has no neighbor for a given edge, the adjface id should be -1, and the
adjedge id doesn't matter (but is typically zero).
If an adjacent face is a pair of subfaces, the id of the first subface as encountered
in a CCW traversal should be stored as the adjface id.
*/
struct FaceInfo {
Res res; ///< Resolution of face.
uint8_t adjedges; ///< Adjacent edges, 2 bits per edge.
uint8_t flags; ///< Flags.
int32_t adjfaces[4]; ///< Adjacent faces (-1 == no adjacent face).
/// Default constructor, sets all members to zero.
FaceInfo() : res(), adjedges(0), flags(0)
{
adjfaces[0] = adjfaces[1] = adjfaces[2] = adjfaces[3] = -1;
}
/// Constructor.
FaceInfo(Res res) : res(res), adjedges(0), flags(0)
{
adjfaces[0] = adjfaces[1] = adjfaces[2] = adjfaces[3] = -1;
}
/// Constructor.
FaceInfo(Res res, int adjfaces[4], int adjedges[4], bool isSubface=false)
: res(res), flags(isSubface ? flag_subface : 0)
{
setadjfaces(adjfaces[0], adjfaces[1], adjfaces[2], adjfaces[3]);
setadjedges(adjedges[0], adjedges[1], adjedges[2], adjedges[3]);
}
/// Access an adjacent edge id. The eid value must be 0..3.
EdgeId adjedge(int eid) const { return EdgeId((adjedges >> (2*eid)) & 3); }
/// Access an adjacent face id. The eid value must be 0..3.
int adjface(int eid) const { return adjfaces[eid]; }
/// Determine if face is constant (by checking a flag).
bool isConstant() const { return (flags & flag_constant) != 0; }
/// Determine if neighborhood of face is constant (by checking a flag).
bool isNeighborhoodConstant() const { return (flags & flag_nbconstant) != 0; }
/// Determine if face has edits in the file (by checking a flag).
bool hasEdits() const { return (flags & flag_hasedits) != 0; }
/// Determine if face is a subface (by checking a flag).
bool isSubface() const { return (flags & flag_subface) != 0; }
/// Set the adjfaces data.
void setadjfaces(int f0, int f1, int f2, int f3)
{ adjfaces[0] = f0, adjfaces[1] = f1, adjfaces[2] = f2; adjfaces[3] = f3; }
/// Set the adjedges data.
void setadjedges(int e0, int e1, int e2, int e3)
{ adjedges = (e0&3) | ((e1&3)<<2) | ((e2&3)<<4) | ((e3&3)<<6); }
/// Flag bit values (for internal use).
enum { flag_constant = 1, flag_hasedits = 2, flag_nbconstant = 4, flag_subface = 8 };
};
/** Memory-managed string. Used for returning error messages from
API functions. On most platforms, this is a typedef to
std::string. For Windows, this is a custom class that
implements a subset of std::string. (Note: std::string cannot
be passed through a Windows DLL interface).
*/
#ifdef PTEX_USE_STDSTRING
typedef std::string String;
#else
class String
{
public:
String() : _str(0) {}
String(const String& str) : _str(0) { *this = str; }
PTEXAPI ~String();
PTEXAPI String& operator=(const char* str);
String& operator=(const String& str) { *this = str._str; return *this; }
const char* c_str() const { return _str ? _str : ""; }
bool empty() const { return _str == 0; }
private:
char* _str;
};
#endif
}
#ifndef DOXYGEN
;
#endif
/// std::stream output operator. \relates Ptex::String
#ifndef PTEX_USE_STDSTRING
std::ostream& operator << (std::ostream& stream, const Ptex::String& str);
#endif
/**
@class PtexMetaData
@brief Meta data accessor
Meta data is acquired from PtexTexture and accessed through this interface.
*/
class PtexMetaData {
protected:
/// Destructor not for public use. Use release() instead.
virtual ~PtexMetaData() {}
public:
/// Release resources held by this pointer (pointer becomes invalid).
virtual void release() = 0;
/// Query number of meta data entries stored in file.
virtual int numKeys() = 0;
/// Query the name and type of a meta data entry.
virtual void getKey(int n, const char*& key, Ptex::MetaDataType& type) = 0;
/** Query the value of a given meta data entry.
If the key doesn't exist or the type doesn't match, value is set to null */
virtual void getValue(const char* key, const char*& value) = 0;
/** Query the value of a given meta data entry.
If the key doesn't exist or the type doesn't match, value is set to null */
virtual void getValue(const char* key, const int8_t*& value, int& count) = 0;
/** Query the value of a given meta data entry.
If the key doesn't exist or the type doesn't match, value is set to null */
virtual void getValue(const char* key, const int16_t*& value, int& count) = 0;
/** Query the value of a given meta data entry.
If the key doesn't exist or the type doesn't match, value is set to null */
virtual void getValue(const char* key, const int32_t*& value, int& count) = 0;
/** Query the value of a given meta data entry.
If the key doesn't exist or the type doesn't match, value is set to null */
virtual void getValue(const char* key, const float*& value, int& count) = 0;
/** Query the value of a given meta data entry.
If the key doesn't exist or the type doesn't match, value is set to null */
virtual void getValue(const char* key, const double*& value, int& count) = 0;
};
/**
@class PtexFaceData
@brief Per-face texture data accessor
Per-face texture data is acquired from PtexTexture and accessed
through this interface. This interface provides low-level access
to the data as stored on disk for maximum efficiency. If this
isn't needed, face data can be more conveniently read directly
from PtexTexture.
*/
class PtexFaceData {
protected:
/// Destructor not for public use. Use release() instead.
virtual ~PtexFaceData() {}
public:
/// Release resources held by this pointer (pointer becomes invalid).
virtual void release() = 0;
/** True if this data block is constant. */
virtual bool isConstant() = 0;
/** Resolution of the texture held by this data block. Note: the
indicated texture res may be larger than 1x1 even if the
texture data is constant. */
virtual Ptex::Res res() = 0;
/** Read a single texel from the data block. The texel coordinates, u and v, have
a range of [0..ures-1, 0..vres-1]. Note: this method will work correctly even if
the face is constant or tiled. */
virtual void getPixel(int u, int v, void* result) = 0;
/** Access the data from this data block.
If the data block is constant, getData will return a pointer to a single texel's data value.
If the data block is tiled, then getData will return null and
the data must be accessed per-tile via the getTile() function. */
virtual void* getData() = 0;
/** True if this data block is tiled.
If tiled, the data must be access per-tile via getTile(). */
virtual bool isTiled() = 0;
/** Resolution of each tile in this data block. */
virtual Ptex::Res tileRes() = 0;
/** Access a tile from the data block. Tiles are accessed in v-major order. */
virtual PtexFaceData* getTile(int tile) = 0;
};
/**
@class PtexTexture
@brief Interface for reading data from a ptex file
PtexTexture instances can be acquired via the static open() method, or via
the PtexCache interface.
Data access through this interface is returned in v-major order with all data channels interleaved per texel.
*/
class PtexTexture {
protected:
/// Destructor not for public use. Use release() instead.
virtual ~PtexTexture() {}
public:
/** Open a ptex file for reading.
If an error occurs, an error message will be stored in the
error string param and the a pointer will be returned.
If the premultiply param is set to true and the texture file has a specified alpha channel,
then all data stored in the file will be multiplied by alpha when read from disk. If premultiply
is false, then the full-resolution textures will be returned as stored on disk which is assumed
to be unmultiplied. Reductions (both stored mip-maps and dynamically generated reductions) are
always premultiplied with alpha. See PtexWriter for more information about alpha channels.
*/
PTEXAPI static PtexTexture* open(const char* path, Ptex::String& error, bool premultiply=0);
/// Release resources held by this pointer (pointer becomes invalid).
virtual void release() = 0;
/** Path that file was opened with. If the file was opened using a search path (via PtexCache),
the the path will be the path as found in the search path. Otherwise, the path will be
the path as supplied to open. */
virtual const char* path() = 0;
/** Type of mesh for which texture data is defined. */
virtual Ptex::MeshType meshType() = 0;
/** Type of data stored in file. */
virtual Ptex::DataType dataType() = 0;
/** Mode for filtering texture access beyond mesh border. */
virtual Ptex::BorderMode uBorderMode() = 0;
/** Mode for filtering texture access beyond mesh border. */
virtual Ptex::BorderMode vBorderMode() = 0;
/** Index of alpha channel (if any). One channel in the file can be flagged to be the alpha channel.
If no channel is acting as the alpha channel, -1 is returned.
See PtexWriter for more details. */
virtual int alphaChannel() = 0;
/** Number of channels stored in file. */
virtual int numChannels() = 0;
/** Number of faces stored in file. */
virtual int numFaces() = 0;
/** True if the file has edit blocks. See PtexWriter for more details. */
virtual bool hasEdits() = 0;
/** True if the file has mipmaps. See PtexWriter for more details. */
virtual bool hasMipMaps() = 0;
/** Access meta data. */
virtual PtexMetaData* getMetaData() = 0;
/** Access resolution and adjacency information about a face. */
virtual const Ptex::FaceInfo& getFaceInfo(int faceid) = 0;
/** Access texture data for a face at highest-resolution.
The texture data is copied into the user-supplied buffer.
The buffer must be at least this size (in bytes):
DataSize(dataType()) * numChannels() * getFaceInfo(faceid).res.size().
If a stride is given, then (stride-row_length) bytes will be
skipped after each row. If stride is zero, then no bytes will
be skipped. Note: the image can be flipped vertically by using
an appropriate negative stride value.
@param faceid Face index [0..numFaces-1]
@param buffer User-supplied buffer
@param stride Size of each row in user buffer (in bytes)
*/
virtual void getData(int faceid, void* buffer, int stride) = 0;
/** Access texture data for a face at a specific resolution.
The specified resolution may be lower than the full resolution
for the face. If it is lower, then the texture data is
accessed from the stored mip-maps. If the requested
resolution doesn't match a stored resolution, the desired
resolution will be generated from the nearest available
resolution.
See previous getData() method for interface details.
*/
virtual void getData(int faceid, void* buffer, int stride, Ptex::Res res) = 0;
/** Access texture data for a face at highest-resolution as stored on disk. */
virtual PtexFaceData* getData(int faceid) = 0;
/** Access texture data for a face at a specific resolution as stored on disk.
The specified resolution may be lower (but not higher) than
the full resolution for the face. If it is lower, then the
texture data is accessed from the stored mip-maps. If the
requested resolution doesn't match a stored resolution, the
desired resolution will be generated from the nearest
available resolution.
*/
virtual PtexFaceData* getData(int faceid, Ptex::Res res) = 0;
/** Access a single texel from the highest resolution texture .
The texel data is converted to floating point (integer types
are normalized 0.0 to 1.0). A subset of the available
channels may be accessed.
@param faceid Face index [0..numFaces-1]
@param u U coordinate [0..ures-1]
@param v V coordinate [0..vres-1]
@param result Result data
@param firstchan First channel to access [0..numChannels-1]
@param nchannels Number of channels to access.
*/
virtual void getPixel(int faceid, int u, int v,
float* result, int firstchan, int nchannels) = 0;
/** Access a single texel for a face at a particular resolution.
The specified resolution may be lower (but not higher) than
the full resolution for the face. If it is lower, then the
texture data is accessed from the stored mip-maps. If the
requested resolution doesn't match a stored resolution, the
desired resolution will be generated from the nearest
available resolution.
See previous getPixel() method for details.
*/
virtual void getPixel(int faceid, int u, int v,
float* result, int firstchan, int nchannels,
Ptex::Res res) = 0;
};
/** @class PtexInputHandler
@brief Custom handler interface for intercepting and redirecting Ptex input stream calls
A custom instance of this class can be defined and supplied to the PtexCache class.
Files accessed through the cache will have their input streams redirected through this
interface.
*/
class PtexInputHandler {
protected:
virtual ~PtexInputHandler() {}
public:
typedef void* Handle;
/** Open a file in read mode.
Returns null if there was an error.
If an error occurs, the error string is available via lastError().
*/
virtual Handle open(const char* path) = 0;
/** Seek to an absolute byte position in the input stream. */
virtual void seek(Handle handle, int64_t pos) = 0;
/** Read a number of bytes from the file.
Returns the number of bytes successfully read.
If less than the requested number of bytes is read, the error string
is available via lastError().
*/
virtual size_t read(void* buffer, size_t size, Handle handle) = 0;
/** Close a file. Returns false if an error occurs, and the error
string is available via lastError(). */
virtual bool close(Handle handle) = 0;
/** Return the last error message encountered. */
virtual const char* lastError() = 0;
};
/**
@class PtexCache
@brief File-handle and memory cache for reading ptex files
The PtexCache class allows cached read access to multiple ptex
files while constraining the open file count and memory usage to
specified limits. File and data objects accessed via the cache
are added back to the cache when their release method is called.
Released objects are maintained in an LRU list and only destroyed
when the specified resource limits are exceeded.
The cache is fully multi-threaded. Cached data will be shared among
all threads that have access to the cache, and the data are protected
with internal locks. See PtexCache.cpp for details about the caching
and locking implementation.
*/
class PtexCache {
protected:
/// Destructor not for public use. Use release() instead.
virtual ~PtexCache() {}
public:
/** Create a cache with the specified limits.
@param maxFiles Maximum open file handles. If unspecified,
limit is set to 100 open files.
@param maxMem Maximum allocated memory, in bytes. If unspecified,
limit is set to 100MB.
@param premultiply If true, textures will be premultiplied by the alpha
channel (if any) when read from disk. See PtexTexture and PtexWriter
for more details.
@param handler If specified, all input calls made through this cache will
be directed through the handler.
*/
PTEXAPI static PtexCache* create(int maxFiles=0,
int maxMem=0,
bool premultiply=false,
PtexInputHandler* handler=0);
/// Release resources held by this pointer (pointer becomes invalid).
virtual void release() = 0;
/** Set a search path for finding textures.
Note: if an input handler is installed the search path will be ignored.
@param path colon-delimited search path.
*/
virtual void setSearchPath(const char* path) = 0;
/** Query the search path. Returns string set via setSearchPath. */
virtual const char* getSearchPath() = 0;
/** Open a texture. If the specified path was previously opened, and the
open file limit hasn't been exceeded, then a pointer to the already
open file will be returned.
If the specified path hasn't been opened yet or was closed,
either to maintain the open file limit or because the file was
explicitly purged from the cache, then the file will be newly
opened. If the path is relative (i.e. doesn't begin with a
'/') then the search path will be used to locate the file.
The texture file will stay open until the PtexTexture::release
method is called, at which point the texture will be returned
to the cache. Once released, the file will be closed when
either the file handle limit is reached, the cached is
released, or when the texture is purged (see purge methods
below).
If texture could not be opened, null will be returned and
an error string will be set.
@param path File path. If path is relative, search path will
be used to find the file.
@param error Error string set if texture could not be
opened.
*/
virtual PtexTexture* get(const char* path, Ptex::String& error) = 0;
/** Remove a texture file from the cache. The texture file will remain
open and accessible until the file handle is released, but any
future cache accesses for that file will open the file anew.
*/
virtual void purge(PtexTexture* texture) = 0;
/** Remove a texture file from the cache by pathname. The path must
match the full path as opened. This function will not search
for the file, but if a search path was used, the path must
match the path as found by the search path.
*/
virtual void purge(const char* path) = 0;
/** Remove all texture files from the cache. Open files with
active PtexTexture* handles remain open until released.
*/
virtual void purgeAll() = 0;
};
/**
@class PtexWriter
@brief Interface for writing data to a ptex file.
Note: if an alpha channel is specified, then the textures being
written to the file are expected to have unmultiplied-alpha data.
Generated mipmaps will be premultiplied by the Ptex library. On
read, PtexTexture will (if requested) premultiply all textures by
alpha when getData is called; by default only reductions are
premultiplied. If the source textures are already premultiplied,
then alphachan can be set to -1 and the library will just leave all
the data as-is. The only reason to store unmultiplied-alpha
textures in the file is to preserve the original texture data for
later editing.
*/
class PtexWriter {
protected:
/// Destructor not for public use. Use release() instead.
virtual ~PtexWriter() {}
public:
/** Open a new texture file for writing.
@param path Path to file.
@param mt Type of mesh for which the textures are defined.
@param dt Type of data stored within file.
@param nchannels Number of data channels.
@param alphachan Index of alpha channel, [0..nchannels-1] or -1 if no alpha channel is present.
@param nfaces Number of faces in mesh.
@param error String containing error message if open failed.
@param genmipmaps Specify true if mipmaps should be generated.
*/
PTEXAPI
static PtexWriter* open(const char* path,
Ptex::MeshType mt, Ptex::DataType dt,
int nchannels, int alphachan, int nfaces,
Ptex::String& error, bool genmipmaps=true);
/** Open an existing texture file for writing.
If the incremental param is specified as true, then data
values written to the file are appended to the file as "edit
blocks". This is the fastest way to write data to the file, but
edit blocks are slower to read back, and they have no mipmaps so
filtering can be inefficient.
If incremental is false, then the edits are applied to the
file and the entire file is regenerated on close as if it were
written all at once with open().
If the file doesn't exist it will be created and written as if
open() were used. If the file exists, the mesh type, data
type, number of channels, alpha channel, and number of faces
must agree with those stored in the file.
*/
PTEXAPI
static PtexWriter* edit(const char* path, bool incremental,
Ptex::MeshType mt, Ptex::DataType dt,
int nchannels, int alphachan, int nfaces,
Ptex::String& error, bool genmipmaps=true);
/** Apply edits to a file.
If a file has pending edits, the edits will be applied and the
file will be regenerated with no edits. This is equivalent to
calling edit() with incremental set to false. The advantage
is that the file attributes such as mesh type, data type,
etc., don't need to be known in advance.
*/
PTEXAPI
static bool applyEdits(const char* path, Ptex::String& error);
/** Release resources held by this pointer (pointer becomes invalid). */
virtual void release() = 0;
/** Set border modes */
virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode) = 0;
/** Write a string as meta data. Both the key and string params must be null-terminated strings. */
virtual void writeMeta(const char* key, const char* string) = 0;
/** Write an array of signed 8-bit integers as meta data. The key must be a null-terminated string. */
virtual void writeMeta(const char* key, const int8_t* value, int count) = 0;
/** Write an array of signed 16-bit integers as meta data. The key must be a null-terminated string. */
virtual void writeMeta(const char* key, const int16_t* value, int count) = 0;
/** Write an array of signed 32-bit integers as meta data. The key must be a null-terminated string. */
virtual void writeMeta(const char* key, const int32_t* value, int count) = 0;
/** Write an array of signed 32-bit floats as meta data. The key must be a null-terminated string. */
virtual void writeMeta(const char* key, const float* value, int count) = 0;
/** Write an array of signed 32-bit doubles as meta data. The key must be a null-terminated string. */
virtual void writeMeta(const char* key, const double* value, int count) = 0;
/** Copy meta data from an existing meta data block. */
virtual void writeMeta(PtexMetaData* data) = 0;
/** Write texture data for a face.
The data is assumed to be channel-interleaved per texel and stored in v-major order.
@param faceid Face index [0..nfaces-1].
@param info Face resolution and adjacency information.
@param data Texel data.
@param stride Distance between rows, in bytes (if zero, data is assumed packed).
If an error is encountered while writing, false is returned and an error message can be
when close is called.
*/
virtual bool writeFace(int faceid, const Ptex::FaceInfo& info, const void* data, int stride=0) = 0;
/** Write constant texture data for a face.
The data is written as a single constant texel value. Note: the resolution specified in the
info param may indicate a resolution greater than 1x1 and the value will be preserved when
reading. This is useful to indicate a texture's logical resolution even when the data is
constant. */
virtual bool writeConstantFace(int faceid, const Ptex::FaceInfo& info, const void* data) = 0;
/** Close the file. This operation can take some time if mipmaps are being generated or if there
are many edit blocks. If an error occurs while writing, false is returned and an error string
is written into the error parameter. */
virtual bool close(Ptex::String& error) = 0;
#if NEW_API
virtual bool writeFaceReduction(int faceid, const Ptex::Res& res, const void* data, int stride=0) = 0;
virtual bool writeConstantFaceReduction(int faceid, const Ptex::Res& res, const void* data) = 0;
#endif
};
/**
@class PtexFilter
@brief Interface for filtered sampling of ptex data files.
PtexFilter instances are obtained by calling one of the particular static methods. When finished using
the filter, it must be returned to the library using release().
To apply the filter to a ptex data file, use the eval() method.
*/
class PtexFilter {
protected:
/// Destructor not for public use. Use release() instead.
virtual ~PtexFilter() {};
public:
/// Filter types
enum FilterType {
f_point, ///< Point-sampled (no filtering)
f_bilinear, ///< Bi-linear interpolation
f_box, ///< Box filter
f_gaussian, ///< Gaussian filter
f_bicubic, ///< General bi-cubic filter (uses sharpness option)
f_bspline, ///< BSpline (equivalent to bi-cubic w/ sharpness=0)
f_catmullrom, ///< Catmull-Rom (equivalent to bi-cubic w/ sharpness=1)
f_mitchell ///< Mitchell (equivalent to bi-cubic w/ sharpness=2/3)
};
/// Choose filter options
struct Options {
int __structSize; ///< (for internal use only)
FilterType filter; ///< Filter type.
bool lerp; ///< Interpolate between mipmap levels.
float sharpness; ///< Filter sharpness, 0..1 (for general bi-cubic filter only).
/// Constructor - sets defaults
Options(FilterType filter=f_box, bool lerp=0, float sharpness=0) :
__structSize(sizeof(Options)),
filter(filter), lerp(lerp), sharpness(sharpness) {}
};
/* Construct a filter for the given texture.
*/
PTEXAPI static PtexFilter* getFilter(PtexTexture* tx, const Options& opts);
/** Release resources held by this pointer (pointer becomes invalid). */
virtual void release() = 0;
/** Apply filter to a ptex data file.
The filter region is a parallelogram centered at the given
(u,v) coordinate with sides defined by two vectors [uw1, vw1]
and [uw2, vw2]. For an axis-aligned rectangle, the vectors
are [uw, 0] and [0, vw]. See \link filterfootprint Filter
Footprint \endlink for details.
@param result Buffer to hold filter result. Must be large enough to hold nchannels worth of data.
@param firstchan First channel to evaluate [0..tx->numChannels()-1]
@param nchannels Number of channels to evaluate
@param faceid Face index [0..tx->numFaces()-1]
@param u U coordinate, normalized [0..1]
@param v V coordinate, normalized [0..1]
@param uw1 U filter width 1, normalized [0..1]
@param vw1 V filter width 1, normalized [0..1]
@param uw2 U filter width 2, normalized [0..1]
@param vw2 V filter width 2, normalized [0..1]
@param width scale factor for filter width
@param blur amount to add to filter width [0..1]
*/
virtual void eval(float* result, int firstchan, int nchannels,
int faceid, float u, float v, float uw1, float vw1, float uw2, float vw2,
float width=1, float blur=0) = 0;
};
/**
@class PtexPtr
@brief Smart-pointer for acquiring and releasing API objects
All public API objects must be released back to the Ptex library
via the release() method. This smart-pointer class can wrap any of
the Ptex API objects and will automatically release the object when
the pointer goes out of scope. Usage of PtexPtr is optional, but
recommended.
Note: for efficiency and safety, PtexPtr is noncopyable. However,
ownership can be transferred between PtexPtr instances via the
PtexPtr::swap member function.
Example:
\code
{
Ptex::String error;
PtexPtr<PtexTexture> inptx(PtexTexture::open(inptxname, error));
if (!inptx) {
std::cerr << error << std::endl;
}
else {
// read some data
inptx->getData(faceid, buffer, stride);
}
}
\endcode
*/
template <class T> class PtexPtr {
T* _ptr;
public:
/// Constructor.
PtexPtr(T* ptr=0) : _ptr(ptr) {}
/// Destructor, calls ptr->release().
~PtexPtr() { if (_ptr) _ptr->release(); }
/// Use as pointer value.
operator T* () { return _ptr; }
/// Access members of pointer.
T* operator-> () { return _ptr; }
/// Get pointer value.
T* get() { return _ptr; }
/// Swap pointer values.
void swap(PtexPtr& p)
{
T* tmp = p._ptr;
p._ptr = _ptr;
_ptr = tmp;
}
private:
/// Copying prohibited
PtexPtr(const PtexPtr& p);
/// Assignment prohibited
void operator= (PtexPtr& p);
};
#endif

View File

@@ -1,386 +0,0 @@
# Configuration Maya
import bpy
wm = bpy.context.window_manager
kc = wm.keyconfigs.new('maya')
# Map 3D View
km = kc.keymaps.new('3D View', space_type='VIEW_3D', region_type='WINDOW', modal=False)
kmi = km.items.new('view3d.manipulator', 'LEFTMOUSE', 'PRESS', any=True)
kmi.properties.release_confirm = True
kmi = km.items.new('view3d.cursor3d', 'ACTIONMOUSE', 'PRESS')
kmi = km.items.new('view3d.rotate', 'LEFTMOUSE', 'PRESS', alt=True)
kmi = km.items.new('view3d.move', 'MIDDLEMOUSE', 'PRESS', alt=True)
kmi = km.items.new('view3d.zoom', 'RIGHTMOUSE', 'PRESS', alt=True)
kmi = km.items.new('view3d.view_selected', 'NUMPAD_PERIOD', 'PRESS')
kmi = km.items.new('view3d.view_center_cursor', 'NUMPAD_PERIOD', 'PRESS', ctrl=True)
kmi = km.items.new('view3d.fly', 'F', 'PRESS', shift=True)
kmi = km.items.new('view3d.smoothview', 'TIMER1', 'ANY', any=True)
kmi = km.items.new('view3d.rotate', 'TRACKPADPAN', 'ANY', alt=True)
kmi = km.items.new('view3d.rotate', 'MOUSEROTATE', 'ANY')
kmi = km.items.new('view3d.move', 'TRACKPADPAN', 'ANY')
kmi = km.items.new('view3d.zoom', 'TRACKPADZOOM', 'ANY')
kmi = km.items.new('view3d.zoom', 'NUMPAD_PLUS', 'PRESS')
kmi.properties.delta = 1
kmi = km.items.new('view3d.zoom', 'NUMPAD_MINUS', 'PRESS')
kmi.properties.delta = -1
kmi = km.items.new('view3d.zoom', 'EQUAL', 'PRESS', ctrl=True)
kmi.properties.delta = 1
kmi = km.items.new('view3d.zoom', 'MINUS', 'PRESS', ctrl=True)
kmi.properties.delta = -1
kmi = km.items.new('view3d.zoom', 'WHEELINMOUSE', 'PRESS')
kmi.properties.delta = 1
kmi = km.items.new('view3d.zoom', 'WHEELOUTMOUSE', 'PRESS')
kmi.properties.delta = -1
kmi = km.items.new('view3d.view_all', 'HOME', 'PRESS')
kmi.properties.center = False
kmi = km.items.new('view3d.view_all', 'C', 'PRESS', shift=True)
kmi.properties.center = True
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_0', 'PRESS')
kmi.properties.type = 'CAMERA'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_1', 'PRESS')
kmi.properties.type = 'FRONT'
kmi = km.items.new('view3d.view_orbit', 'NUMPAD_2', 'PRESS')
kmi.properties.type = 'ORBITDOWN'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_3', 'PRESS')
kmi.properties.type = 'RIGHT'
kmi = km.items.new('view3d.view_orbit', 'NUMPAD_4', 'PRESS')
kmi.properties.type = 'ORBITLEFT'
kmi = km.items.new('view3d.view_persportho', 'NUMPAD_5', 'PRESS')
kmi = km.items.new('view3d.view_orbit', 'NUMPAD_6', 'PRESS')
kmi.properties.type = 'ORBITRIGHT'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_7', 'PRESS')
kmi.properties.type = 'TOP'
kmi = km.items.new('view3d.view_orbit', 'NUMPAD_8', 'PRESS')
kmi.properties.type = 'ORBITUP'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_1', 'PRESS', ctrl=True)
kmi.properties.type = 'BACK'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_3', 'PRESS', ctrl=True)
kmi.properties.type = 'LEFT'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_7', 'PRESS', ctrl=True)
kmi.properties.type = 'BOTTOM'
kmi = km.items.new('view3d.view_pan', 'NUMPAD_2', 'PRESS', ctrl=True)
kmi.properties.type = 'PANDOWN'
kmi = km.items.new('view3d.view_pan', 'NUMPAD_4', 'PRESS', ctrl=True)
kmi.properties.type = 'PANLEFT'
kmi = km.items.new('view3d.view_pan', 'NUMPAD_6', 'PRESS', ctrl=True)
kmi.properties.type = 'PANRIGHT'
kmi = km.items.new('view3d.view_pan', 'NUMPAD_8', 'PRESS', ctrl=True)
kmi.properties.type = 'PANUP'
kmi = km.items.new('view3d.view_pan', 'WHEELUPMOUSE', 'PRESS', ctrl=True)
kmi.properties.type = 'PANRIGHT'
kmi = km.items.new('view3d.view_pan', 'WHEELDOWNMOUSE', 'PRESS', ctrl=True)
kmi.properties.type = 'PANLEFT'
kmi = km.items.new('view3d.view_pan', 'WHEELUPMOUSE', 'PRESS', shift=True)
kmi.properties.type = 'PANUP'
kmi = km.items.new('view3d.view_pan', 'WHEELDOWNMOUSE', 'PRESS', shift=True)
kmi.properties.type = 'PANDOWN'
kmi = km.items.new('view3d.view_orbit', 'WHEELUPMOUSE', 'PRESS', ctrl=True, alt=True)
kmi.properties.type = 'ORBITLEFT'
kmi = km.items.new('view3d.view_orbit', 'WHEELDOWNMOUSE', 'PRESS', ctrl=True, alt=True)
kmi.properties.type = 'ORBITRIGHT'
kmi = km.items.new('view3d.view_orbit', 'WHEELUPMOUSE', 'PRESS', shift=True, alt=True)
kmi.properties.type = 'ORBITUP'
kmi = km.items.new('view3d.view_orbit', 'WHEELDOWNMOUSE', 'PRESS', shift=True, alt=True)
kmi.properties.type = 'ORBITDOWN'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_1', 'PRESS', shift=True)
kmi.properties.align_active = True
kmi.properties.type = 'FRONT'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_3', 'PRESS', shift=True)
kmi.properties.align_active = True
kmi.properties.type = 'RIGHT'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_7', 'PRESS', shift=True)
kmi.properties.align_active = True
kmi.properties.type = 'TOP'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_1', 'PRESS', shift=True, ctrl=True)
kmi.properties.align_active = True
kmi.properties.type = 'BACK'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_3', 'PRESS', shift=True, ctrl=True)
kmi.properties.align_active = True
kmi.properties.type = 'LEFT'
kmi = km.items.new('view3d.viewnumpad', 'NUMPAD_7', 'PRESS', shift=True, ctrl=True)
kmi.properties.align_active = True
kmi.properties.type = 'BOTTOM'
kmi = km.items.new('view3d.localview', 'NUMPAD_SLASH', 'PRESS')
kmi = km.items.new('view3d.layers', 'ACCENT_GRAVE', 'PRESS')
kmi.properties.nr = 0
kmi = km.items.new('view3d.layers', 'ONE', 'PRESS', any=True)
kmi.properties.nr = 1
kmi = km.items.new('view3d.layers', 'TWO', 'PRESS', any=True)
kmi.properties.nr = 2
kmi = km.items.new('view3d.layers', 'THREE', 'PRESS', any=True)
kmi.properties.nr = 3
kmi = km.items.new('view3d.layers', 'FOUR', 'PRESS', any=True)
kmi.properties.nr = 4
kmi = km.items.new('view3d.layers', 'FIVE', 'PRESS', any=True)
kmi.properties.nr = 5
kmi = km.items.new('view3d.layers', 'SIX', 'PRESS', any=True)
kmi.properties.nr = 6
kmi = km.items.new('view3d.layers', 'SEVEN', 'PRESS', any=True)
kmi.properties.nr = 7
kmi = km.items.new('view3d.layers', 'EIGHT', 'PRESS', any=True)
kmi.properties.nr = 8
kmi = km.items.new('view3d.layers', 'NINE', 'PRESS', any=True)
kmi.properties.nr = 9
kmi = km.items.new('view3d.layers', 'ZERO', 'PRESS', any=True)
kmi.properties.nr = 10
kmi = km.items.new('wm.context_toggle_enum', 'Z', 'PRESS')
kmi.properties.data_path = 'space_data.viewport_shade'
kmi.properties.value_1 = 'SOLID'
kmi.properties.value_2 = 'WIREFRAME'
kmi = km.items.new('wm.context_toggle_enum', 'Z', 'PRESS', alt=True)
kmi.properties.data_path = 'space_data.viewport_shade'
kmi.properties.value_1 = 'TEXTURED'
kmi.properties.value_2 = 'SOLID'
kmi = km.items.new('view3d.select', 'SELECTMOUSE', 'PRESS')
kmi = km.items.new('view3d.select', 'SELECTMOUSE', 'PRESS', shift=True)
kmi.properties.extend = True
kmi = km.items.new('view3d.select', 'SELECTMOUSE', 'PRESS', ctrl=True)
kmi.properties.center = True
kmi = km.items.new('view3d.select', 'SELECTMOUSE', 'PRESS', alt=True)
kmi.properties.enumerate = True
kmi = km.items.new('view3d.select', 'SELECTMOUSE', 'PRESS', shift=True, ctrl=True)
kmi.properties.center = True
kmi.properties.extend = True
kmi = km.items.new('view3d.select', 'SELECTMOUSE', 'PRESS', ctrl=True, alt=True)
kmi.properties.center = True
kmi.properties.enumerate = True
kmi = km.items.new('view3d.select', 'SELECTMOUSE', 'PRESS', shift=True, alt=True)
kmi.properties.enumerate = True
kmi.properties.extend = True
kmi = km.items.new('view3d.select', 'SELECTMOUSE', 'PRESS', shift=True, ctrl=True, alt=True)
kmi.properties.center = True
kmi.properties.enumerate = True
kmi.properties.extend = True
kmi = km.items.new('view3d.select_border', 'EVT_TWEAK_S', 'ANY')
kmi.properties.extend = False
kmi = km.items.new('view3d.select_lasso', 'EVT_TWEAK_A', 'ANY', ctrl=True)
kmi = km.items.new('view3d.select_lasso', 'EVT_TWEAK_A', 'ANY', shift=True, ctrl=True)
kmi.properties.deselect = True
kmi = km.items.new('view3d.select_circle', 'C', 'PRESS')
kmi = km.items.new('view3d.clip_border', 'B', 'PRESS', alt=True)
kmi = km.items.new('view3d.zoom_border', 'B', 'PRESS', shift=True)
kmi = km.items.new('view3d.render_border', 'B', 'PRESS', shift=True)
kmi = km.items.new('view3d.camera_to_view', 'NUMPAD_0', 'PRESS', ctrl=True, alt=True)
kmi = km.items.new('view3d.object_as_camera', 'NUMPAD_0', 'PRESS', ctrl=True)
kmi = km.items.new('wm.call_menu', 'S', 'PRESS', shift=True)
kmi.properties.name = 'VIEW3D_MT_snap'
kmi = km.items.new('wm.context_set_enum', 'COMMA', 'PRESS')
kmi.properties.data_path = 'space_data.pivot_point'
kmi.properties.value = 'BOUNDING_BOX_CENTER'
kmi = km.items.new('wm.context_set_enum', 'COMMA', 'PRESS', ctrl=True)
kmi.properties.data_path = 'space_data.pivot_point'
kmi.properties.value = 'MEDIAN_POINT'
kmi = km.items.new('wm.context_toggle', 'COMMA', 'PRESS', alt=True)
kmi.properties.data_path = 'space_data.use_pivot_point_align'
kmi = km.items.new('wm.context_toggle', 'Q', 'PRESS')
kmi.properties.data_path = 'space_data.show_manipulator'
kmi = km.items.new('wm.context_set_enum', 'PERIOD', 'PRESS')
kmi.properties.data_path = 'space_data.pivot_point'
kmi.properties.value = 'CURSOR'
kmi = km.items.new('wm.context_set_enum', 'PERIOD', 'PRESS', ctrl=True)
kmi.properties.data_path = 'space_data.pivot_point'
kmi.properties.value = 'INDIVIDUAL_ORIGINS'
kmi = km.items.new('wm.context_set_enum', 'PERIOD', 'PRESS', alt=True)
kmi.properties.data_path = 'space_data.pivot_point'
kmi.properties.value = 'ACTIVE_ELEMENT'
kmi = km.items.new('transform.translate', 'G', 'PRESS', shift=True)
kmi = km.items.new('transform.translate', 'EVT_TWEAK_S', 'ANY')
kmi = km.items.new('transform.rotate', 'R', 'PRESS', shift=True)
kmi = km.items.new('transform.resize', 'S', 'PRESS', shift=True)
kmi = km.items.new('transform.warp', 'W', 'PRESS', shift=True)
kmi = km.items.new('transform.tosphere', 'S', 'PRESS', shift=True, alt=True)
kmi = km.items.new('transform.shear', 'S', 'PRESS', shift=True, ctrl=True, alt=True)
kmi = km.items.new('transform.select_orientation', 'SPACE', 'PRESS', alt=True)
kmi = km.items.new('transform.create_orientation', 'SPACE', 'PRESS', ctrl=True, alt=True)
kmi.properties.use = True
kmi = km.items.new('transform.mirror', 'M', 'PRESS', ctrl=True)
kmi = km.items.new('wm.context_toggle', 'TAB', 'PRESS', shift=True)
kmi.properties.data_path = 'tool_settings.use_snap'
kmi = km.items.new('transform.snap_type', 'TAB', 'PRESS', shift=True, ctrl=True)
kmi = km.items.new('view3d.enable_manipulator', 'W', 'PRESS')
kmi.properties.translate = True
kmi = km.items.new('view3d.enable_manipulator', 'E', 'PRESS')
kmi.properties.rotate = True
kmi = km.items.new('view3d.enable_manipulator', 'R', 'PRESS')
kmi.properties.scale = True
kmi = km.items.new('view3d.select_border', 'EVT_TWEAK_S', 'ANY', shift=True)
kmi.properties.extend = True
# Map Object Mode
km = kc.keymaps.new('Object Mode', space_type='EMPTY', region_type='WINDOW', modal=False)
kmi = km.items.new('wm.context_cycle_enum', 'O', 'PRESS', shift=True)
kmi.properties.data_path = 'tool_settings.proportional_edit_falloff'
kmi = km.items.new('wm.context_toggle_enum', 'O', 'PRESS')
kmi.properties.data_path = 'tool_settings.proportional_edit'
kmi.properties.value_1 = 'DISABLED'
kmi.properties.value_2 = 'ENABLED'
kmi = km.items.new('view3d.game_start', 'P', 'PRESS')
kmi = km.items.new('object.select_all', 'A', 'PRESS')
kmi = km.items.new('object.select_inverse', 'I', 'PRESS', ctrl=True)
kmi = km.items.new('object.select_linked', 'L', 'PRESS', shift=True)
kmi = km.items.new('object.select_grouped', 'G', 'PRESS', shift=True)
kmi = km.items.new('object.select_mirror', 'M', 'PRESS', shift=True, ctrl=True)
kmi = km.items.new('object.select_hierarchy', 'LEFT_BRACKET', 'PRESS')
kmi.properties.direction = 'PARENT'
kmi = km.items.new('object.select_hierarchy', 'LEFT_BRACKET', 'PRESS', shift=True)
kmi.properties.direction = 'PARENT'
kmi.properties.extend = True
kmi = km.items.new('object.select_hierarchy', 'RIGHT_BRACKET', 'PRESS')
kmi.properties.direction = 'CHILD'
kmi = km.items.new('object.select_hierarchy', 'RIGHT_BRACKET', 'PRESS', shift=True)
kmi.properties.direction = 'CHILD'
kmi.properties.extend = True
kmi = km.items.new('object.parent_set', 'P', 'PRESS', ctrl=True)
kmi = km.items.new('object.parent_no_inverse_set', 'P', 'PRESS', shift=True, ctrl=True)
kmi = km.items.new('object.parent_clear', 'P', 'PRESS', alt=True)
kmi = km.items.new('object.track_set', 'T', 'PRESS', ctrl=True)
kmi = km.items.new('object.track_clear', 'T', 'PRESS', alt=True)
kmi = km.items.new('object.constraint_add_with_targets', 'C', 'PRESS', shift=True, ctrl=True)
kmi = km.items.new('object.constraints_clear', 'C', 'PRESS', ctrl=True, alt=True)
kmi = km.items.new('object.location_clear', 'G', 'PRESS', alt=True)
kmi = km.items.new('object.rotation_clear', 'R', 'PRESS', alt=True)
kmi = km.items.new('object.scale_clear', 'S', 'PRESS', alt=True)
kmi = km.items.new('object.origin_clear', 'O', 'PRESS', alt=True)
kmi = km.items.new('object.hide_view_clear', 'H', 'PRESS', alt=True)
kmi = km.items.new('object.hide_view_set', 'H', 'PRESS')
kmi = km.items.new('object.hide_view_set', 'H', 'PRESS', shift=True)
kmi.properties.unselected = True
kmi = km.items.new('object.move_to_layer', 'M', 'PRESS')
kmi = km.items.new('object.delete', 'X', 'PRESS')
kmi = km.items.new('object.delete', 'DEL', 'PRESS')
kmi = km.items.new('wm.call_menu', 'A', 'PRESS', shift=True)
kmi.properties.name = 'INFO_MT_add'
kmi = km.items.new('object.duplicates_make_real', 'A', 'PRESS', shift=True, ctrl=True)
kmi = km.items.new('wm.call_menu', 'A', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_object_apply'
kmi = km.items.new('wm.call_menu', 'U', 'PRESS')
kmi.properties.name = 'VIEW3D_MT_make_single_user'
kmi = km.items.new('wm.call_menu', 'L', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_make_links'
kmi = km.items.new('object.duplicate_move', 'D', 'PRESS', shift=True)
kmi = km.items.new('object.duplicate_move_linked', 'D', 'PRESS', alt=True)
kmi = km.items.new('object.join', 'J', 'PRESS', ctrl=True)
kmi = km.items.new('object.convert', 'C', 'PRESS', alt=True)
kmi = km.items.new('object.proxy_make', 'P', 'PRESS', ctrl=True, alt=True)
kmi = km.items.new('object.make_local', 'L', 'PRESS')
kmi = km.items.new('anim.keyframe_insert_menu', 'I', 'PRESS')
kmi = km.items.new('anim.keyframe_delete_v3d', 'I', 'PRESS', alt=True)
kmi = km.items.new('anim.keying_set_active_set', 'I', 'PRESS', shift=True, ctrl=True, alt=True)
kmi = km.items.new('group.create', 'G', 'PRESS', ctrl=True)
kmi = km.items.new('group.objects_remove', 'G', 'PRESS', ctrl=True, alt=True)
kmi = km.items.new('group.objects_add_active', 'G', 'PRESS', shift=True, ctrl=True)
kmi = km.items.new('group.objects_remove_active', 'G', 'PRESS', shift=True, alt=True)
kmi = km.items.new('wm.call_menu', 'W', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_object_specials'
kmi = km.items.new('object.subdivision_set', 'ZERO', 'PRESS', ctrl=True)
kmi.properties.level = 0
kmi = km.items.new('object.subdivision_set', 'ONE', 'PRESS', ctrl=True)
kmi.properties.level = 1
kmi = km.items.new('object.subdivision_set', 'TWO', 'PRESS', ctrl=True)
kmi.properties.level = 2
kmi = km.items.new('object.subdivision_set', 'THREE', 'PRESS', ctrl=True)
kmi.properties.level = 3
kmi = km.items.new('object.subdivision_set', 'FOUR', 'PRESS', ctrl=True)
kmi.properties.level = 4
kmi = km.items.new('object.subdivision_set', 'FIVE', 'PRESS', ctrl=True)
kmi.properties.level = 5
kmi = km.items.new('object.select_all', 'SELECTMOUSE', 'CLICK')
kmi.properties.action = 'DESELECT'
# Map Mesh
km = kc.keymaps.new('Mesh', space_type='EMPTY', region_type='WINDOW', modal=False)
kmi = km.items.new('mesh.loopcut_slide', 'R', 'PRESS', ctrl=True)
kmi = km.items.new('mesh.loop_select', 'SELECTMOUSE', 'PRESS', ctrl=True, alt=True)
kmi = km.items.new('mesh.loop_select', 'SELECTMOUSE', 'PRESS', shift=True, alt=True)
kmi.properties.extend = True
kmi = km.items.new('mesh.edgering_select', 'SELECTMOUSE', 'PRESS', ctrl=True, alt=True)
kmi = km.items.new('mesh.edgering_select', 'SELECTMOUSE', 'PRESS', shift=True, ctrl=True, alt=True)
kmi.properties.extend = True
kmi = km.items.new('mesh.select_shortest_path', 'SELECTMOUSE', 'PRESS', ctrl=True)
kmi = km.items.new('mesh.select_all', 'A', 'PRESS')
kmi = km.items.new('mesh.select_more', 'NUMPAD_PLUS', 'PRESS', ctrl=True)
kmi = km.items.new('mesh.select_less', 'NUMPAD_MINUS', 'PRESS', ctrl=True)
kmi = km.items.new('mesh.select_inverse', 'I', 'PRESS', ctrl=True)
kmi = km.items.new('mesh.select_non_manifold', 'M', 'PRESS', shift=True, ctrl=True, alt=True)
kmi = km.items.new('mesh.select_linked', 'L', 'PRESS', ctrl=True)
kmi = km.items.new('mesh.select_linked_pick', 'L', 'PRESS')
kmi = km.items.new('mesh.select_linked_pick', 'L', 'PRESS', shift=True)
kmi.properties.deselect = True
kmi = km.items.new('mesh.faces_select_linked_flat', 'F', 'PRESS', shift=True, ctrl=True, alt=True)
kmi.properties.sharpness = 135.0
kmi = km.items.new('mesh.select_similar', 'G', 'PRESS', shift=True)
kmi = km.items.new('wm.call_menu', 'TAB', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_edit_mesh_selection_mode'
kmi = km.items.new('mesh.hide', 'H', 'PRESS')
kmi = km.items.new('mesh.hide', 'H', 'PRESS', shift=True)
kmi.properties.unselected = True
kmi = km.items.new('mesh.reveal', 'H', 'PRESS', alt=True)
kmi = km.items.new('mesh.normals_make_consistent', 'N', 'PRESS', ctrl=True)
kmi = km.items.new('mesh.normals_make_consistent', 'N', 'PRESS', shift=True, ctrl=True)
kmi.properties.inside = True
kmi = km.items.new('view3d.edit_mesh_extrude_move_normal', 'E', 'PRESS', ctrl=True)
kmi = km.items.new('view3d.edit_mesh_extrude_individual_move', 'E', 'PRESS', shift=True)
kmi = km.items.new('wm.call_menu', 'E', 'PRESS', alt=True)
kmi.properties.name = 'VIEW3D_MT_edit_mesh_extrude'
kmi = km.items.new('mesh.spin', 'R', 'PRESS', alt=True)
kmi = km.items.new('mesh.fill', 'F', 'PRESS', alt=True)
kmi = km.items.new('mesh.beautify_fill', 'F', 'PRESS', shift=True, alt=True)
kmi = km.items.new('mesh.quads_convert_to_tris', 'T', 'PRESS', ctrl=True)
kmi = km.items.new('mesh.tris_convert_to_quads', 'J', 'PRESS', alt=True)
kmi = km.items.new('mesh.edge_flip', 'F', 'PRESS', shift=True, ctrl=True)
kmi = km.items.new('mesh.rip_move', 'V', 'PRESS')
kmi = km.items.new('mesh.merge', 'M', 'PRESS', alt=True)
kmi = km.items.new('transform.shrink_fatten', 'S', 'PRESS', ctrl=True, alt=True)
kmi = km.items.new('mesh.edge_face_add', 'F', 'PRESS')
kmi = km.items.new('mesh.duplicate_move', 'D', 'PRESS', shift=True)
kmi = km.items.new('wm.call_menu', 'A', 'PRESS', shift=True)
kmi.properties.name = 'INFO_MT_mesh_add'
kmi = km.items.new('mesh.separate', 'P', 'PRESS')
kmi = km.items.new('mesh.split', 'Y', 'PRESS')
kmi = km.items.new('mesh.dupli_extrude_cursor', 'ACTIONMOUSE', 'CLICK', ctrl=True)
kmi = km.items.new('mesh.delete', 'X', 'PRESS')
kmi = km.items.new('mesh.delete', 'DEL', 'PRESS')
kmi = km.items.new('mesh.knife_cut', 'LEFTMOUSE', 'PRESS', key_modifier='K')
kmi = km.items.new('mesh.knife_cut', 'LEFTMOUSE', 'PRESS', shift=True, key_modifier='K')
kmi.properties.type = 'MIDPOINTS'
kmi = km.items.new('object.vertex_parent_set', 'P', 'PRESS', ctrl=True)
kmi = km.items.new('wm.call_menu', 'W', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_edit_mesh_specials'
kmi = km.items.new('wm.call_menu', 'F', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_edit_mesh_faces'
kmi = km.items.new('wm.call_menu', 'E', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_edit_mesh_edges'
kmi = km.items.new('wm.call_menu', 'V', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_edit_mesh_vertices'
kmi = km.items.new('wm.call_menu', 'H', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_hook'
kmi = km.items.new('wm.call_menu', 'U', 'PRESS')
kmi.properties.name = 'VIEW3D_MT_uv_map'
kmi = km.items.new('wm.call_menu', 'G', 'PRESS', ctrl=True)
kmi.properties.name = 'VIEW3D_MT_vertex_group'
kmi = km.items.new('wm.context_cycle_enum', 'O', 'PRESS', shift=True)
kmi.properties.data_path = 'tool_settings.proportional_edit_falloff'
kmi = km.items.new('wm.context_toggle_enum', 'O', 'PRESS')
kmi.properties.data_path = 'tool_settings.proportional_edit'
kmi.properties.value_1 = 'DISABLED'
kmi.properties.value_2 = 'ENABLED'
kmi = km.items.new('wm.context_toggle_enum', 'O', 'PRESS', alt=True)
kmi.properties.data_path = 'tool_settings.proportional_edit'
kmi.properties.value_1 = 'DISABLED'
kmi.properties.value_2 = 'CONNECTED'
kmi = km.items.new('mesh.select_all', 'SELECTMOUSE', 'CLICK')
kmi.properties.action = 'DESELECT'
wm.keyconfigs.active = kc
bpy.context.user_preferences.edit.use_drag_immediately = True
bpy.context.user_preferences.edit.use_insertkey_xyz_to_rgb = False
bpy.context.user_preferences.inputs.select_mouse = 'LEFT'
bpy.context.user_preferences.inputs.view_zoom_method = 'DOLLY'
bpy.context.user_preferences.inputs.view_zoom_axis = 'HORIZONTAL'
bpy.context.user_preferences.inputs.view_rotate_method = 'TURNTABLE'
bpy.context.user_preferences.inputs.invert_mouse_wheel_zoom = True

View File

@@ -254,6 +254,27 @@ class DATA_PT_shape_keys(MeshButtonsPanel, bpy.types.Panel):
row.prop(key, "slurph")
class DATA_PT_ptex(MeshButtonsPanel, bpy.types.Panel):
bl_label = "PTex"
COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
me = context.mesh
row = layout.row()
row.template_list(me, "ptex_layers", me, "active_ptex_index", rows=2)
col = row.column(align=True)
col.operator("ptex.layer_remove", icon='ZOOMOUT', text="")
layout.operator_menu_enum("ptex.layer_convert", "type")
layout.operator_menu_enum("ptex.layer_add", "type")
row = layout.row()
row.operator("ptex.open")
row.operator("ptex.layer_save")
class DATA_PT_uv_texture(MeshButtonsPanel, bpy.types.Panel):
bl_label = "UV Texture"
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
@@ -344,6 +365,10 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, bpy.types.Panel):
lay = me.vertex_colors.active
if lay:
layout.prop(lay, "name")
if lay.multiresolution:
layout.operator("mesh.vertex_color_multiresolution_toggle", text="Remove Multires")
else:
layout.operator("mesh.vertex_color_multiresolution_toggle", text="Add Multires")
class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, bpy.types.Panel):

View File

@@ -394,8 +394,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel):
split = layout.split()
col = split.column()
col.prop(md, "levels", text="Preview")
col.prop(md, "sculpt_levels", text="Sculpt")
col.prop(md, "edit_levels", text="Edit")
col.prop(md, "render_levels", text="Render")
col.prop(md, "show_only_control_edges")
col = split.column()
@@ -403,7 +404,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel):
col.operator("object.multires_subdivide", text="Subdivide")
col.operator("object.multires_higher_levels_delete", text="Delete Higher")
col.operator("object.multires_reshape", text="Reshape")
col.prop(md, "show_only_control_edges")
col.operator("object.multires_base_apply", text="Apply Base")
layout.separator()

View File

@@ -30,6 +30,7 @@ class TEXTURE_MT_specials(bpy.types.Menu):
layout.operator("texture.slot_copy", icon='COPYDOWN')
layout.operator("texture.slot_paste", icon='PASTEDOWN')
layout.operator("paint.mask_from_texture")
class TEXTURE_MT_envmap_specials(bpy.types.Menu):

View File

@@ -957,6 +957,23 @@ class VIEW3D_MT_paint_vertex(bpy.types.Menu):
layout.operator("paint.vertex_color_set")
layout.operator("paint.vertex_color_dirt")
# hiding
prop = layout.operator("ptex.subface_flag_set", text="Hide Selected")
prop.flag = 'HIDDEN'
prop = layout.operator("ptex.subface_flag_set", text="Show All")
prop.flag = 'HIDDEN'
prop.set = 0
prop.ignore_hidden = 0
prop.ignore_unselected = 0
# masking
prop = layout.operator("ptex.subface_flag_set", text="Mask Selected")
prop.flag = 'MASKED'
prop = layout.operator("ptex.subface_flag_set", text="Unmask Selected")
prop.flag = 'MASKED'
prop.set = 0
class VIEW3D_MT_hook(bpy.types.Menu):
bl_label = "Hooks"
@@ -1037,6 +1054,11 @@ class VIEW3D_MT_sculpt(bpy.types.Menu):
sculpt = tool_settings.sculpt
brush = tool_settings.sculpt.brush
layout.operator("sculpt.area_hide", text="Show Hidden").show_all = True
layout.operator("sculpt.area_hide", text="Hide Exterior Area")
layout.operator("sculpt.area_hide", text="Hide Interior Area").hide_inside = True
layout.separator()
layout.operator("ed.undo")
layout.operator("ed.redo")
@@ -1045,6 +1067,7 @@ class VIEW3D_MT_sculpt(bpy.types.Menu):
layout.prop(sculpt, "use_symmetry_x")
layout.prop(sculpt, "use_symmetry_y")
layout.prop(sculpt, "use_symmetry_z")
layout.separator()
layout.prop(sculpt, "lock_x")
layout.prop(sculpt, "lock_y")

View File

@@ -475,7 +475,7 @@ class PaintPanel():
if context.sculpt_object:
return ts.sculpt
elif context.vertex_paint_object:
elif context.vertex_paint_object and (not context.vertex_paint_object.data.ptex_edit_mode):
return ts.vertex_paint
elif context.weight_paint_object:
return ts.weight_paint
@@ -487,6 +487,39 @@ class PaintPanel():
return None
class VIEW3D_PT_tools_masking(PaintPanel, bpy.types.Panel):
bl_label = "Masking"
bl_default_closed = False
@classmethod
def poll(cls, context):
return cls.paint_settings(context) and (context.sculpt_object or context.vertex_paint_object)
def draw(self, context):
layout = self.layout
settings = self.paint_settings(context)
mesh = context.object.data
row = layout.row()
col = row.column()
col.template_list(mesh, "paint_mask_layers", mesh, "active_paint_mask_index", rows=2)
col = row.column(align=True)
col.operator("paint.mask_layer_add", icon='ZOOMIN', text="")
col.operator("paint.mask_layer_remove", icon='ZOOMOUT', text="")
row = layout.row(align=True)
row.active = mesh.active_paint_mask_index != -1
row.operator("paint.mask_set", text="Clear").mode = 'CLEAR'
row.operator("paint.mask_set", text="Fill").mode = 'FILL'
row.operator("paint.mask_set", text="Invert").mode = 'INVERT'
if row.active:
layout.prop(mesh.paint_mask_layers[mesh.active_paint_mask_index], "strength", slider=True)
class VIEW3D_PT_tools_brush(PaintPanel, bpy.types.Panel):
bl_label = "Brush"
@@ -622,6 +655,8 @@ class VIEW3D_PT_tools_brush(PaintPanel, bpy.types.Panel):
col.prop(brush, "use_accumulate")
col.prop(brush, "mask")
if brush.sculpt_tool == 'LAYER':
col.separator()
@@ -695,11 +730,17 @@ class VIEW3D_PT_tools_brush(PaintPanel, bpy.types.Panel):
row.prop(brush, "strength", text="Strength", slider=True)
row.prop(brush, "use_pressure_strength", toggle=True, text="")
if brush.vertexpaint_tool == 'ALPHA':
row = col.row(align=True)
row.prop(brush, "direction", expand=True)
# XXX - TODO
#row = col.row(align=True)
#row.prop(brush, "jitter", slider=True)
#row.prop(brush, "use_pressure_jitter", toggle=True, text="")
col.prop(brush, "mask")
class VIEW3D_PT_tools_brush_texture(PaintPanel, bpy.types.Panel):
bl_label = "Texture"
@@ -709,6 +750,7 @@ class VIEW3D_PT_tools_brush_texture(PaintPanel, bpy.types.Panel):
def poll(cls, context):
settings = cls.paint_settings(context)
return (settings and settings.brush and (context.sculpt_object or
context.vertex_paint_object or
context.texture_paint_object))
def draw(self, context):
@@ -722,7 +764,7 @@ class VIEW3D_PT_tools_brush_texture(PaintPanel, bpy.types.Panel):
col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
if context.sculpt_object:
if context.sculpt_object or context.vertex_paint_object:
#XXX duplicated from properties_texture.py
col.separator()
@@ -854,7 +896,7 @@ class VIEW3D_PT_tools_brush_stroke(PaintPanel, bpy.types.Panel):
col = layout.column()
if context.sculpt_object:
if context.sculpt_object or context.vertex_paint_object:
col.label(text="Stroke Method:")
col.prop(brush, "stroke_method", text="")
@@ -944,7 +986,6 @@ class VIEW3D_PT_tools_brush_curve(PaintPanel, bpy.types.Panel):
layout = self.layout
settings = self.paint_settings(context)
brush = settings.brush
layout.template_curve_mapping(brush, "curve", brush=True)
@@ -994,20 +1035,23 @@ class VIEW3D_PT_sculpt_options(PaintPanel, bpy.types.Panel):
row.prop(sculpt, "lock_y", text="Y", toggle=True)
row.prop(sculpt, "lock_z", text="Z", toggle=True)
class VIEW3D_PT_sculpt_symmetry(PaintPanel, bpy.types.Panel):
class VIEW3D_PT_tools_paint_symmetry(PaintPanel, bpy.types.Panel):
bl_label = "Symmetry"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
return (context.sculpt_object and context.tool_settings.sculpt)
return cls.paint_settings(context) and (context.sculpt_object or context.vertex_paint_object)
def draw(self, context):
layout = self.layout
sculpt = context.tool_settings.sculpt
if context.sculpt_object:
paint = context.tool_settings.sculpt
elif context.vertex_paint_object:
paint = context.tool_settings.vertex_paint
settings = __class__.paint_settings(context)
brush = settings.brush
@@ -1016,19 +1060,19 @@ class VIEW3D_PT_sculpt_symmetry(PaintPanel, bpy.types.Panel):
col = split.column()
col.label(text="Mirror:")
col.prop(sculpt, "use_symmetry_x", text="X")
col.prop(sculpt, "use_symmetry_y", text="Y")
col.prop(sculpt, "use_symmetry_z", text="Z")
col.prop(paint, "use_symmetry_x", text="X")
col.prop(paint, "use_symmetry_y", text="Y")
col.prop(paint, "use_symmetry_z", text="Z")
col = split.column()
col.prop(sculpt, "radial_symmetry", text="Radial")
col.prop(paint, "radial_symmetry", text="Radial")
col = layout.column()
col.separator()
col.prop(sculpt, "use_symmetry_feather", text="Feather")
col.prop(paint, "use_symmetry_feather", text="Feather")
class VIEW3D_PT_tools_brush_appearance(PaintPanel, bpy.types.Panel):
@@ -1037,7 +1081,7 @@ class VIEW3D_PT_tools_brush_appearance(PaintPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
return (context.sculpt_object and context.tool_settings.sculpt) or (context.vertex_paint_object and context.tool_settings.vertex_paint) or (context.weight_paint_object and context.tool_settings.weight_paint) or (context.texture_paint_object and context.tool_settings.image_paint)
return cls.paint_settings(context) and ((context.sculpt_object and context.tool_settings.sculpt) or (context.vertex_paint_object and context.tool_settings.vertex_paint) or (context.weight_paint_object and context.tool_settings.weight_paint) or (context.texture_paint_object and context.tool_settings.image_paint))
def draw(self, context):
layout = self.layout
@@ -1122,10 +1166,14 @@ class VIEW3D_PT_tools_weightpaint_options(View3DPanel, bpy.types.Panel):
# ********** default tools for vertexpaint ****************
class VIEW3D_PT_tools_vertexpaint(View3DPanel, bpy.types.Panel):
bl_context = "vertexpaint"
class VIEW3D_PT_tools_vertexpaint(PaintPanel, bpy.types.Panel):
bl_label = "Options"
@classmethod
def poll(cls, context):
settings = cls.paint_settings(context)
return settings and context.vertex_paint_object
def draw(self, context):
layout = self.layout
@@ -1138,6 +1186,8 @@ class VIEW3D_PT_tools_vertexpaint(View3DPanel, bpy.types.Panel):
col.prop(vpaint, "use_normal")
col.prop(vpaint, "use_spray")
col.prop(vpaint, "fast_navigate")
col.label(text="Unified Settings:")
col.prop(tool_settings, "sculpt_paint_use_unified_size", text="Size")
col.prop(tool_settings, "sculpt_paint_use_unified_strength", text="Strength")
@@ -1329,6 +1379,74 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, bpy.types.Panel):
sub.prop(pe, "fade_frames", slider=True)
class VIEW3D_PT_paint_overlay(PaintPanel, bpy.types.Panel):
bl_label = "Source Image"
bl_default_closed = True
@classmethod
def poll(cls, context):
settings = cls.paint_settings(context)
return settings and context.vertex_paint_object
def draw(self, context):
layout = self.layout
overlay = context.tool_settings.paint_overlay
layout.prop(overlay, "enabled")
layout.template_ID(overlay, "image", open="image.open")
layout.prop(overlay, "transparency_color")
layout.prop(overlay, "transparency_tolerance")
class VIEW3D_PT_ptex_edit(View3DPanel, bpy.types.Panel):
bl_label = "Ptex"
bl_default_closed = False
@classmethod
def poll(cls, context):
ob = context.vertex_paint_object
return ob and ob.data.ptex_edit_mode
def draw(self, context):
layout = self.layout
mesh = context.active_object.data
active_ptex = mesh.active_ptex_index
if active_ptex != -1:
ts = context.tool_settings
layout.operator("ptex.face_resolution_set", text="Double Selected").operation = 'DOUBLE'
layout.operator("ptex.face_resolution_set", text="Half Selected").operation = 'HALF'
prop = layout.operator("ptex.face_resolution_set")
prop.operation = 'NUMERIC'
layout.prop(ts, "ptex_u_resolution", text="U")
layout.prop(ts, "ptex_v_resolution", text="V")
active_face = mesh.faces.active
active_subface = mesh.faces.active_subface
# display active [sub]face's resolution
if active_face >= 0 and active_subface >= 0:
box = layout.box()
box.label("Current Resolution:")
ptex_layer = mesh.ptex_layers[active_ptex]
ptex = ptex_layer.data[active_face]
subface = ptex.subfaces[active_subface]
ures = subface.resolution[0];
vres = subface.resolution[1];
if len(ptex.subfaces) == 4:
ures *= 2
vres *= 2
box.label(str(ures) + " x " + str(vres))
def register():
pass

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

View File

@@ -68,10 +68,7 @@ struct PBVH;
#define SUB_ELEMS_EDGE 2
#define SUB_ELEMS_FACE 4
typedef struct DMGridData {
float co[3];
float no[3];
} DMGridData;
typedef struct DMGridData DMGridData;
typedef struct DMGridAdjacency {
int index[4];
@@ -84,6 +81,23 @@ typedef enum DerivedMeshType {
DM_TYPE_CCGDM
} DerivedMeshType;
typedef enum DMDrawFlags {
/* fast navigation for multires */
DM_DRAW_LOWEST_SUBDIVISION_LEVEL = 1,
/* draw mask for sculpt mode */
DM_DRAW_PAINT_MASK = 2,
/* draw ptex textures */
DM_DRAW_PTEX = 4,
/* mcol, weight colors, etc. */
DM_DRAW_VERTEX_COLORS = 8,
/* visually show ptex texel density */
DM_DRAW_PTEX_TEXELS = 16,
/* mainly for sculpting, use smooth normals */
DM_DRAW_FULLY_SMOOTH = 32,
/* back-buffer selection mode */
DM_DRAW_BACKBUF_SELECTION = 64,
} DMDrawFlags;
typedef struct DerivedMesh DerivedMesh;
struct DerivedMesh {
/* Private DerivedMesh data, only for internal DerivedMesh use */
@@ -158,6 +172,8 @@ struct DerivedMesh {
DMGridData **(*getGridData)(DerivedMesh *dm);
DMGridAdjacency *(*getGridAdjacency)(DerivedMesh *dm);
int *(*getGridOffset)(DerivedMesh *dm);
struct GridKey *(*getGridKey)(DerivedMesh *dm);
struct GridToFace *(*getGridFaceMap)(DerivedMesh *dm);
/* Iterate over each mapped vertex in the derived mesh, calling the
* given function with the original vert and the mapped vert's new
@@ -240,7 +256,8 @@ struct DerivedMesh {
* Also called for *final* editmode DerivedMeshes
*/
void (*drawFacesSolid)(DerivedMesh *dm, float (*partial_redraw_planes)[4],
int fast, int (*setMaterial)(int, void *attribs));
int (*setMaterial)(int, void *attribs),
DMDrawFlags flags);
/* Draw all faces
* o If useTwoSided, draw front and back using col arrays
@@ -278,10 +295,12 @@ struct DerivedMesh {
* smooth shaded.
*/
void (*drawMappedFaces)(DerivedMesh *dm,
int (*setDrawOptions)(void *userData, int index,
int *drawSmooth_r),
void *userData, int useColors,
int (*setMaterial)(int, void *attribs));
float (*partial_redraw_planes)[4],
int (*setDrawOptions)(void *userData, int index,
int *drawSmooth_r),
void *userData,
int (*setMaterial)(int, void *attribs),
DMDrawFlags flags);
/* Draw mapped faces using MTFace
* o Drawing options too complicated to enumerate, look at code.

View File

@@ -39,6 +39,7 @@ extern "C" {
struct ID;
struct CustomData;
struct CustomDataLayer;
struct CustomDataMultires;
typedef unsigned int CustomDataMask;
extern const CustomDataMask CD_MASK_BAREMESH;
@@ -94,14 +95,18 @@ void *CustomData_add_layer(struct CustomData *data, int type, int alloctype,
void *CustomData_add_layer_named(struct CustomData *data, int type, int alloctype,
void *layer, int totelem, const char *name);
/* frees the active or first data layer with the give type.
/* adds a layer and puts it at the specified offset */
void *CustomData_add_layer_at_offset(struct CustomData *data, int type, int alloctype,
void *layerdata, int totelem, int offset);
/* frees the layer at index.
* returns 1 on succes, 0 if no layer with the given type is found
*
* in editmode, use EM_free_data_layer instead of this function
*/
int CustomData_free_layer(struct CustomData *data, int type, int totelem, int index);
/* frees the layer index with the give type.
/* frees the active layer of the give type.
* returns 1 on succes, 0 if no layer with the given type is found
*
* in editmode, use EM_free_data_layer instead of this function
@@ -189,20 +194,46 @@ void *CustomData_em_get_n(const struct CustomData *data, void *block, int type,
void *CustomData_bmesh_get(const struct CustomData *data, void *block, int type);
void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int type, int n);
/* gets a pointer to the active or first layer of type
* returns NULL if there is no layer of type
*/
/************************** Get layer data ***********************/
/* return the data from the first layer matching the parameters */
/* these all return NULL if no such layer is found */
/* returns the data from the active layer matching type */
void *CustomData_get_layer(const struct CustomData *data, int type);
/* returns the data from the nth layer matching type */
void *CustomData_get_layer_n(const struct CustomData *data, int type, int n);
/* returns the data from the first layer matching type and name */
void *CustomData_get_layer_named(const struct CustomData *data, int type,
char *name);
/********************************* Get layer index *********************************/
/* return the index within data.layers of the first layer matching the parameters */
/* these all return -1 if no such layer is found */
/* returns the index of the first layer matching type */
int CustomData_get_layer_index(const struct CustomData *data, int type);
/* returns the index of the first layer matching type and name */
int CustomData_get_named_layer_index(const struct CustomData *data, int type, char *name);
/* returns the index of the active layer */
int CustomData_get_active_layer_index(const struct CustomData *data, int type);
/* returns the index of the render layer */
int CustomData_get_render_layer_index(const struct CustomData *data, int type);
/* returns the index of the clone layer */
int CustomData_get_clone_layer_index(const struct CustomData *data, int type);
/* returns the index of the stencil/mask layer */
int CustomData_get_stencil_layer_index(const struct CustomData *data, int type);
/************************************ Get layer offset ***********************************/
/* return the offset of the layer from the first layer of the specified type */
/* to find the index of that layer, add it to the index of the first layer of that type */
/* these all return -1 if no layer of the specified type is found */
int CustomData_get_active_layer(const struct CustomData *data, int type);
int CustomData_get_render_layer(const struct CustomData *data, int type);
int CustomData_get_clone_layer(const struct CustomData *data, int type);
@@ -245,6 +276,7 @@ void CustomData_set_layer_stencil_index(struct CustomData *data, int type, int n
/* adds flag to the layer flags */
void CustomData_set_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_set_layer_offset_flag(struct CustomData *data, int type, int offset, int flag);
/* alloc/free a block of custom data attached to one element in editmode */
void CustomData_em_set_default(struct CustomData *data, void **block);
@@ -284,6 +316,45 @@ void CustomData_to_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata,
void CustomData_from_bmeshpoly(struct CustomData *fdata, struct CustomData *pdata, struct CustomData *ldata, int total);
void CustomData_bmesh_init_pool(struct CustomData *data, int allocsize);
/* Subsurf grids */
/* return the number of layers of type that have multires data */
int CustomData_get_multires_count(struct CustomData *cd, int type);
/* allocates a list of names of layers that have multires data */
void *CustomData_get_multires_names(struct CustomData *cd, int type);
/* number of floats used per-element for the multires of a customdata type */
int CustomData_multires_type_totfloat(int type);
/* returns the multires data for a layer matching name and type,
or NULL if no such layer found */
float *CustomData_multires_get_data(struct CustomDataMultires *cdm, int type,
char *name);
/* if layer matching type and name exists, free and replace its griddata
otherwise create the layer and set its griddata */
void CustomData_multires_sync_layer(struct CustomDataMultires *cdm, int type,
char *name);
/* insert a multires layer of the specified type and assign griddata */
void CustomData_multires_add_layer_data(struct CustomDataMultires *cdm, int type,
char *name, float *griddata);
/* insert a multires layer of the specified type int each
cdm in the array of length count */
void CustomData_multires_add_layers(struct CustomDataMultires *cdm, int count,
int type, char *name);
/* remove the multires layer with matching source name from the cdm
array of length count, returns 1 if succesful, 0 otherwise */
int CustomData_multires_remove_layers(struct CustomDataMultires *cdm, int count,
int type, char *name);
/* rename a layer matching type and old_name */
void CustomData_multires_rename(struct CustomDataMultires *cdm, int type,
char *old_name, char *name);
/* External file storage */
void CustomData_external_add(struct CustomData *data,
@@ -304,4 +375,3 @@ void CustomData_external_reload(struct CustomData *data,
#endif
#endif

View File

@@ -0,0 +1,59 @@
#ifndef BKE_DMGRID_H
#define BKE_DMGRID_H
struct CustomData;
/* Each grid element can contain zero or more layers of coordinates,
paint masks, and normals; these numbers are stored in the GridKey
The name arrays are the unique names of the source customdata layer
*/
typedef struct GridKey {
int co;
int color;
int mask;
int no;
/* key to identify the source layer */
char (*color_names)[32];
char (*mask_names)[32];
} GridKey;
#define GRIDELEM_KEY_INIT(_key, _totco, _totcolor, _totmask, _totno) \
((_key)->co = _totco, (_key)->color = _totcolor, \
(_key)->mask = _totmask, (_key)->no = _totno, \
(_key)->color_names = NULL, (_key)->mask_names = NULL)
#define GRIDELEM_SIZE(_key) ((3*(_key)->co + 4*(_key)->color + (_key)->mask + 3*(_key)->no) * sizeof(float))
#define GRIDELEM_INTERP_COUNT(_key) (3*(_key)->co + 4*(_key)->color + (_key)->mask)
#define GRIDELEM_COLOR_OFFSET(_key) (3*(_key)->co*sizeof(float))
#define GRIDELEM_MASK_OFFSET(_key) (GRIDELEM_COLOR_OFFSET(_key) + 4*(_key)->color*sizeof(float))
#define GRIDELEM_NO_OFFSET(_key) (GRIDELEM_MASK_OFFSET(_key) + (_key)->mask*sizeof(float))
#define GRIDELEM_AT(_grid, _elem, _key) ((struct DMGridData*)(((char*)(_grid)) + (_elem) * GRIDELEM_SIZE(_key)))
#define GRIDELEM_INC(_grid, _inc, _key) ((_grid) = GRIDELEM_AT(_grid, _inc, _key))
/* I can't figure out how to cast this type without a typedef,
having the array length is useful to directly index layers */
typedef float (*gridelem_f4)[4];
#define GRIDELEM_CO(_grid, _key) ((float*)(_grid))
#define GRIDELEM_COLOR(_grid, _key) ((gridelem_f4)((char*)(_grid) + GRIDELEM_COLOR_OFFSET(_key)))
#define GRIDELEM_MASK(_grid, _key) ((float*)((char*)(_grid) + GRIDELEM_MASK_OFFSET(_key)))
#define GRIDELEM_NO(_grid, _key) ((float*)((char*)(_grid) + GRIDELEM_NO_OFFSET(_key)))
#define GRIDELEM_CO_AT(_grid, _elem, _key) GRIDELEM_CO(GRIDELEM_AT(_grid, _elem, _key), _key)
#define GRIDELEM_COLOR_AT(_grid, _elem, _key) GRIDELEM_COLOR(GRIDELEM_AT(_grid, _elem, _key), _key)
#define GRIDELEM_MASK_AT(_grid, _elem, _key) GRIDELEM_MASK(GRIDELEM_AT(_grid, _elem, _key), _key)
#define GRIDELEM_NO_AT(_grid, _elem, _key) GRIDELEM_NO(GRIDELEM_AT(_grid, _elem, _key), _key)
/* returns the active gridelem layer offset for either colors
or masks, -1 if not found */
int gridelem_active_offset(struct CustomData *data, GridKey *gridkey, int type);
typedef struct GridToFace {
int face;
char offset;
} GridToFace;
#endif

View File

@@ -31,6 +31,7 @@
#define BKE_MULTIRES_H
struct DerivedMesh;
struct GridKey;
struct Mesh;
struct MFace;
struct Multires;
@@ -46,8 +47,9 @@ void multires_force_external_reload(struct Object *ob);
void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, struct Object *ob);
/* note: gridkey can be NULL, will provide a context-sensitive default */
struct DerivedMesh *multires_dm_create_from_derived(struct MultiresModifierData*,
int local_mmd, struct DerivedMesh*, struct Object *, int, int);
int local_mmd, struct DerivedMesh*, struct Object *, struct GridKey *, int, int);
struct MultiresModifierData *find_multires_modifier_before(struct Scene *scene,
struct ModifierData *lastmd);
@@ -63,6 +65,7 @@ int multiresModifier_reshapeFromDM(struct Scene *scene, struct MultiresModifierD
struct Object *ob, struct DerivedMesh *srcdm);
int multiresModifier_reshapeFromDeformMod(struct Scene *scene, struct MultiresModifierData *mmd,
struct Object *ob, struct ModifierData *md);
void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Object *ob);
void multires_stitch_grids(struct Object *);

View File

@@ -31,6 +31,9 @@
#include "DNA_vec_types.h"
struct Brush;
struct CustomData;
struct DMGridData;
struct GridKey;
struct MFace;
struct MultireModifierData;
struct MVert;
@@ -58,31 +61,26 @@ void paint_brush_set(struct Paint *paint, struct Brush *br);
* however hiding faces is useful */
int paint_facesel_test(struct Object *ob);
/* Session data (mode-specific) */
void paint_refresh_mask_display(struct Object *ob);
float paint_mask_from_gridelem(struct DMGridData *elem, struct GridKey *gridkey,
struct CustomData *vdata);
float paint_mask_from_vertex(struct CustomData *vdata, int vertex_index,
int pmask_totlayer, int pmask_first_layer);
typedef struct SculptSession {
struct ProjVert *projverts;
/* Mesh data (not copied) can come either directly from a Mesh, or from a MultiresDM */
struct MultiresModifierData *multires; /* Special handling for multires meshes */
struct MVert *mvert;
struct MFace *mface;
int totvert, totface;
float *face_normals;
struct Object *ob;
struct KeyBlock *kb;
/* Mesh connectivity */
struct ListBase *fmap;
/* PBVH acceleration structure */
struct PBVH *pbvh;
/* Used temporarily per-stroke */
float *vertexcosnos;
/* Partial redraw */
int partial_redraw;
/* Area hiding */
ListBase hidden_areas;
/* Used to cache the render of the active texture */
unsigned int texcache_side, *texcache, texcache_actual;
@@ -93,13 +91,23 @@ typedef struct SculptSession {
struct SculptStroke *stroke;
struct StrokeCache *cache;
struct GPUDrawObject *drawobject;
int modifiers_active;
rcti previous_r;
} SculptSession;
void free_sculptsession(struct Object *ob);
typedef struct PaintSession {
/* mode-specific data (just sculpt for now */
SculptSession *sculpt;
/* PBVH acceleration structure */
struct PBVH *pbvh;
/* Partial redraw */
int partial_redraw;
} PaintSession;
void create_paintsession(struct Object *ob);
void free_paintsession(struct Object *ob);
#endif

View File

@@ -0,0 +1,42 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2010 by Nicholas Bishop
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
struct DerivedMesh;
struct Mesh;
struct MPtex;
struct MPtexSubface;
struct PtexTextureHandle;
void ptex_elem_to_floats(int type, int channels, void *data, float *out);
void ptex_elem_from_floats(int type, int channels, void *data, float *in);
struct DerivedMesh *quad_dm_create_from_derived(struct DerivedMesh *dm);
void ptex_subface_scale(struct MPtex *pt, struct MPtexSubface *subface, int ures, int vres);
void ptex_layer_from_file(struct Mesh *me, struct PtexTextureHandle *ptex_texture);
int ptex_layer_save_file(struct Mesh *me, const char *filename);

View File

@@ -32,6 +32,7 @@ struct DMGridAdjacency;
struct DMGridData;
struct DerivedMesh;
struct EditMesh;
struct GridKey;
struct IndexNode;
struct ListBase;
struct Mesh;
@@ -49,6 +50,7 @@ struct _CCGVert;
struct DerivedMesh *subsurf_make_derived_from_derived(
struct DerivedMesh *dm,
struct SubsurfModifierData *smd,
struct GridKey *gridkey,
int useRenderParams, float (*vertCos)[3],
int isFinalCalc, int editMode);
@@ -80,6 +82,7 @@ typedef struct CCGDerivedMesh {
struct DMGridAdjacency *gridAdjacency;
int *gridOffset;
struct _CCGFace **gridFaces;
struct GridToFace *gridFaceMap;
struct {
struct MultiresModifierData *mmd;

View File

@@ -48,6 +48,7 @@ struct PluginTex;
struct PointDensity;
struct Tex;
struct TexMapping;
struct TexResult;
struct VoxelData;
struct World;
@@ -116,6 +117,8 @@ struct VoxelData *BKE_copy_voxeldata(struct VoxelData *vd);
int BKE_texture_dependsOnTime(const struct Tex *texture);
void get_texture_value(struct Tex *texture, float *tex_co, struct TexResult *texres);
#ifdef __cplusplus
}
#endif

View File

@@ -50,6 +50,7 @@ SET(INC
../../../intern/memutil
../../../intern/opennl/extern
../../../intern/smoke/extern
../../../extern/ptex
../../../source/blender/windowmanager # XXX - BAD LEVEL CALL WM_api.h
${ZLIB_INC}
)

View File

@@ -11,6 +11,7 @@ incs += ' #/intern/iksolver/extern ../blenloader'
incs += ' #/extern/bullet2/src'
incs += ' #/intern/opennl/extern #/intern/bsp/extern'
incs += ' ../gpu #/extern/glew/include'
incs += ' #/extern/ptex'
incs += ' #/intern/smoke/extern'
incs += ' #/intern/audaspace/intern'

View File

@@ -218,6 +218,8 @@ static CCGAllocatorIFC *_getStandardAllocatorIFC(void) {
static int VertDataEqual(float *a, float *b) {
return a[0]==b[0] && a[1]==b[1] && a[2]==b[2];
}
#if 0
#define VertDataZero(av) { float *_a = (float*) av; _a[0] = _a[1] = _a[2] = 0.0f; }
#define VertDataCopy(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0] =_b[0]; _a[1] =_b[1]; _a[2] =_b[2]; }
#define VertDataAdd(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0]+=_b[0]; _a[1]+=_b[1]; _a[2]+=_b[2]; }
@@ -230,6 +232,51 @@ static int VertDataEqual(float *a, float *b) {
_t[1] = (_a[1]+_b[1]+_c[1]+_d[1])*.25; \
_t[2] = (_a[2]+_b[2]+_c[2]+_d[2])*.25; \
}
#else
CCG_INLINE void VertDataZero(void *a, const int n)
{
int i;
for(i = 0; i < n; ++i)
((float*)a)[i] = 0;
}
CCG_INLINE void VertDataCopy(void *a, void *b, int n)
{
int i;
for(i = 0; i < n; ++i)
((float*)a)[i] = ((float*)b)[i];
}
CCG_INLINE void VertDataAdd(void *a, void *b, int n)
{
int i;
for(i = 0; i < n; ++i)
((float*)a)[i] += ((float*)b)[i];
}
CCG_INLINE void VertDataSub(void *a, void *b, int n)
{
int i;
for(i = 0; i < n; ++i)
((float*)a)[i] -= ((float*)b)[i];
}
CCG_INLINE void VertDataMulN(void *a, float b, int n)
{
int i;
for(i = 0; i < n; ++i)
((float*)a)[i] *= b;
}
CCG_INLINE void VertDataAvg4(void *t, void *a, void *b, void *c, void *d, int n)
{
int i;
for(i = 0; i < n; ++i)
((float*)t)[i] = (((float*)a)[i] + ((float*)b)[i] + ((float*)c)[i] + ((float*)d)[i]) * 0.25f;
}
#endif
#define NormZero(av) { float *_a = (float*) av; _a[0] = _a[1] = _a[2] = 0.0f; }
#define NormCopy(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0] =_b[0]; _a[1] =_b[1]; _a[2] =_b[2]; }
#define NormAdd(av, bv) { float *_a = (float*) av, *_b = (float*) bv; _a[0]+=_b[0]; _a[1]+=_b[1]; _a[2]+=_b[2]; }
@@ -321,7 +368,7 @@ struct _CCGSubSurf {
void *q, *r;
// data for calc vert normals
// data for calc vert normals
int calcVertNormals;
int normalDataOffset;
@@ -709,6 +756,15 @@ void ccgSubSurf_free(CCGSubSurf *ss) {
_ehash_free(ss->eMap, (EHEntryFreeFP) _edge_free, ss);
_ehash_free(ss->vMap, (EHEntryFreeFP) _vert_free, ss);
/* free gridkey */
if(ss->meshIFC.gridkey.color_names)
MEM_freeN(ss->meshIFC.gridkey.color_names);
if(ss->meshIFC.gridkey.mask_names)
MEM_freeN(ss->meshIFC.gridkey.mask_names);
ss->meshIFC.gridkey.color_names = NULL;
ss->meshIFC.gridkey.mask_names = NULL;
CCGSUBSURF_free(ss, ss);
if (allocatorIFC.release) {
@@ -906,13 +962,13 @@ CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, in
v = _ehash_lookupWithPrev(ss->vMap, vHDL, &prevp);
if (!v) {
v = _vert_new(vHDL, ss);
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData, ss->meshIFC.finterpCount);
_ehash_insert(ss->vMap, (EHEntry*) v);
v->flags = Vert_eEffected|seamflag;
} else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
int i, j;
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData, ss->meshIFC.finterpCount);
v->flags = Vert_eEffected|seamflag;
for (i=0; i<v->numEdges; i++) {
@@ -935,13 +991,13 @@ CCGError ccgSubSurf_syncVert(CCGSubSurf *ss, CCGVertHDL vHDL, void *vertData, in
v = _ehash_lookupWithPrev(ss->oldVMap, vHDL, &prevp);
if (!v) {
v = _vert_new(vHDL, ss);
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData, ss->meshIFC.finterpCount);
_ehash_insert(ss->vMap, (EHEntry*) v);
v->flags = Vert_eEffected|seamflag;
} else if (!VertDataEqual(vertData, _vert_getCo(v, 0, ss->meshIFC.vertDataSize)) || ((v->flags & Vert_eSeam) != seamflag)) {
*prevp = v->next;
_ehash_insert(ss->vMap, (EHEntry*) v);
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData);
VertDataCopy(_vert_getCo(v,0,ss->meshIFC.vertDataSize), vertData, ss->meshIFC.finterpCount);
v->flags = Vert_eEffected|Vert_eChanged|seamflag;
} else {
*prevp = v->next;
@@ -1320,7 +1376,7 @@ static void ccgSubSurf__calcVertNormals(CCGSubSurf *ss,
}
VertDataCopy((float*)((byte*)FACE_getCenterData(f) + normalDataOffset),
FACE_getIFNo(f, lvl, S, 0, 0));
FACE_getIFNo(f, lvl, S, 0, 0), 3);
for (x=1; x<gridSize-1; x++)
NormCopy(FACE_getIENo(f, lvl, S, x),
@@ -1356,6 +1412,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
int nextLvl = curLvl+1;
int ptrIdx, cornerIdx, i;
int vertDataSize = ss->meshIFC.vertDataSize;
int finterpCount = ss->meshIFC.finterpCount;
void *q = ss->q, *r = ss->r;
#pragma omp parallel for private(ptrIdx) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
@@ -1377,7 +1434,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co3 = FACE_getIFCo(f, curLvl, S, x+0, y+1);
void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
VertDataAvg4(co, co0, co1, co2, co3);
VertDataAvg4(co, co0, co1, co2, co3, finterpCount);
}
}
}
@@ -1395,7 +1452,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co3 = FACE_getIFCo(f, nextLvl, S, fx, 1);
void *co = FACE_getIECo(f, nextLvl, S, fx);
VertDataAvg4(co, co0, co1, co2, co3);
VertDataAvg4(co, co0, co1, co2, co3, finterpCount);
}
/* interior face interior edge midpoints
@@ -1414,7 +1471,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co3 = FACE_getIFCo(f, nextLvl, S, fx+1, fy);
void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
VertDataAvg4(co, co0, co1, co2, co3);
VertDataAvg4(co, co0, co1, co2, co3, finterpCount);
}
}
@@ -1429,7 +1486,7 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co3 = FACE_getIFCo(f, nextLvl, S, fx, fy+1);
void *co = FACE_getIFCo(f, nextLvl, S, fx, fy);
VertDataAvg4(co, co0, co1, co2, co3);
VertDataAvg4(co, co0, co1, co2, co3, finterpCount);
}
}
}
@@ -1451,9 +1508,9 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co1 = EDGE_getCo(e, curLvl, x+1);
void *co = EDGE_getCo(e, nextLvl, fx);
VertDataCopy(co, co0);
VertDataAdd(co, co1);
VertDataMulN(co, 0.5);
VertDataCopy(co, co0, finterpCount);
VertDataAdd(co, co1, finterpCount);
VertDataMulN(co, 0.5, finterpCount);
}
} else {
for (x=0; x<edgeSize-1; x++) {
@@ -1463,25 +1520,25 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *co = EDGE_getCo(e, nextLvl, fx);
int numFaces = 0;
VertDataCopy(q, co0);
VertDataAdd(q, co1);
VertDataCopy(q, co0, finterpCount);
VertDataAdd(q, co1, finterpCount);
for (j=0; j<e->numFaces; j++) {
CCGFace *f = e->faces[j];
VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize));
VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx, 1, subdivLevels, vertDataSize), finterpCount);
numFaces++;
}
VertDataMulN(q, 1.0f/(2.0f+numFaces));
VertDataMulN(q, 1.0f/(2.0f+numFaces), finterpCount);
VertDataCopy(r, co0);
VertDataAdd(r, co1);
VertDataMulN(r, 0.5);
VertDataCopy(r, co0, finterpCount);
VertDataAdd(r, co1, finterpCount);
VertDataMulN(r, 0.5, finterpCount);
VertDataCopy(co, q);
VertDataSub(r, q);
VertDataMulN(r, sharpness);
VertDataAdd(co, r);
VertDataCopy(co, q, finterpCount);
VertDataSub(r, q, finterpCount);
VertDataMulN(r, sharpness, finterpCount);
VertDataAdd(co, r, finterpCount);
}
}
}
@@ -1525,51 +1582,51 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
seam = 0;
if (!v->numEdges) {
VertDataCopy(nCo, co);
VertDataCopy(nCo, co, finterpCount);
} else if (_vert_isBoundary(v)) {
int numBoundary = 0;
VertDataZero(r);
VertDataZero(r, finterpCount);
for (j=0; j<v->numEdges; j++) {
CCGEdge *e = v->edges[j];
if (_edge_isBoundary(e)) {
VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), finterpCount);
numBoundary++;
}
}
VertDataCopy(nCo, co);
VertDataMulN(nCo, 0.75);
VertDataMulN(r, 0.25f/numBoundary);
VertDataAdd(nCo, r);
VertDataCopy(nCo, co, finterpCount);
VertDataMulN(nCo, 0.75, finterpCount);
VertDataMulN(r, 0.25f/numBoundary, finterpCount);
VertDataAdd(nCo, r, finterpCount);
} else {
int cornerIdx = (1 + (1<<(curLvl))) - 2;
int numEdges = 0, numFaces = 0;
VertDataZero(q);
VertDataZero(q, finterpCount);
for (j=0; j<v->numFaces; j++) {
CCGFace *f = v->faces[j];
VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx));
VertDataAdd(q, FACE_getIFCo(f, nextLvl, _face_getVertIndex(f,v), cornerIdx, cornerIdx), finterpCount);
numFaces++;
}
VertDataMulN(q, 1.0f/numFaces);
VertDataZero(r);
VertDataMulN(q, 1.0f/numFaces, finterpCount);
VertDataZero(r, finterpCount);
for (j=0; j<v->numEdges; j++) {
CCGEdge *e = v->edges[j];
VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize));
VertDataAdd(r, _edge_getCoVert(e, v, curLvl, 1,vertDataSize), finterpCount);
numEdges++;
}
VertDataMulN(r, 1.0f/numEdges);
VertDataMulN(r, 1.0f/numEdges, finterpCount);
VertDataCopy(nCo, co);
VertDataMulN(nCo, numEdges-2.0f);
VertDataAdd(nCo, q);
VertDataAdd(nCo, r);
VertDataMulN(nCo, 1.0f/numEdges);
VertDataCopy(nCo, co, finterpCount);
VertDataMulN(nCo, numEdges-2.0f, finterpCount);
VertDataAdd(nCo, q, finterpCount);
VertDataAdd(nCo, r, finterpCount);
VertDataMulN(nCo, 1.0f/numEdges, finterpCount);
}
if ((sharpCount>1 && v->numFaces) || seam) {
VertDataZero(q);
VertDataZero(q, finterpCount);
if (seam) {
avgSharpness = 1.0f;
@@ -1583,32 +1640,32 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
if (seam) {
if (_edge_isBoundary(e))
VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), finterpCount);
} else if (sharpness != 0.0) {
VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize));
VertDataAdd(q, _edge_getCoVert(e, v, curLvl, 1, vertDataSize), finterpCount);
}
}
VertDataMulN(q, (float) 1/sharpCount);
VertDataMulN(q, (float) 1/sharpCount, finterpCount);
if (sharpCount!=2 || allSharp) {
// q = q + (co-q)*avgSharpness
VertDataCopy(r, co);
VertDataSub(r, q);
VertDataMulN(r, avgSharpness);
VertDataAdd(q, r);
VertDataCopy(r, co, finterpCount);
VertDataSub(r, q, finterpCount);
VertDataMulN(r, avgSharpness, finterpCount);
VertDataAdd(q, r, finterpCount);
}
// r = co*.75 + q*.25
VertDataCopy(r, co);
VertDataMulN(r, .75);
VertDataMulN(q, .25);
VertDataAdd(r, q);
VertDataCopy(r, co, finterpCount);
VertDataMulN(r, .75, finterpCount);
VertDataMulN(q, .25, finterpCount);
VertDataAdd(r, q, finterpCount);
// nCo = nCo + (r-nCo)*avgSharpness
VertDataSub(r, nCo);
VertDataMulN(r, avgSharpness);
VertDataAdd(nCo, r);
VertDataSub(r, nCo, finterpCount);
VertDataMulN(r, avgSharpness, finterpCount);
VertDataAdd(nCo, r, finterpCount);
}
}
@@ -1641,13 +1698,13 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
int fx = x*2;
void *co = EDGE_getCo(e, curLvl, x);
void *nCo = EDGE_getCo(e, nextLvl, fx);
VertDataCopy(r, EDGE_getCo(e, curLvl, x-1));
VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
VertDataMulN(r, 0.5);
VertDataCopy(nCo, co);
VertDataMulN(nCo, 0.75);
VertDataMulN(r, 0.25);
VertDataAdd(nCo, r);
VertDataCopy(r, EDGE_getCo(e, curLvl, x-1), finterpCount);
VertDataAdd(r, EDGE_getCo(e, curLvl, x+1), finterpCount);
VertDataMulN(r, 0.5, finterpCount);
VertDataCopy(nCo, co, finterpCount);
VertDataMulN(nCo, 0.75, finterpCount);
VertDataMulN(r, 0.25, finterpCount);
VertDataAdd(nCo, r, finterpCount);
}
} else {
for (x=1; x<edgeSize-1; x++) {
@@ -1656,37 +1713,37 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *nCo = EDGE_getCo(e, nextLvl, fx);
int numFaces = 0;
VertDataZero(q);
VertDataZero(r);
VertDataAdd(r, EDGE_getCo(e, curLvl, x-1));
VertDataAdd(r, EDGE_getCo(e, curLvl, x+1));
VertDataZero(q, finterpCount);
VertDataZero(r, finterpCount);
VertDataAdd(r, EDGE_getCo(e, curLvl, x-1), finterpCount);
VertDataAdd(r, EDGE_getCo(e, curLvl, x+1), finterpCount);
for (j=0; j<e->numFaces; j++) {
CCGFace *f = e->faces[j];
VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize));
VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize));
VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx-1, 1, subdivLevels, vertDataSize), finterpCount);
VertDataAdd(q, _face_getIFCoEdge(f, e, nextLvl, fx+1, 1, subdivLevels, vertDataSize), finterpCount);
VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize));
VertDataAdd(r, _face_getIFCoEdge(f, e, curLvl, x, 1, subdivLevels, vertDataSize), finterpCount);
numFaces++;
}
VertDataMulN(q, 1.0/(numFaces*2.0f));
VertDataMulN(r, 1.0/(2.0f + numFaces));
VertDataMulN(q, 1.0/(numFaces*2.0f), finterpCount);
VertDataMulN(r, 1.0/(2.0f + numFaces), finterpCount);
VertDataCopy(nCo, co);
VertDataMulN(nCo, (float) numFaces);
VertDataAdd(nCo, q);
VertDataAdd(nCo, r);
VertDataMulN(nCo, 1.0f/(2+numFaces));
VertDataCopy(nCo, co, finterpCount);
VertDataMulN(nCo, (float) numFaces, finterpCount);
VertDataAdd(nCo, q, finterpCount);
VertDataAdd(nCo, r, finterpCount);
VertDataMulN(nCo, 1.0f/(2+numFaces), finterpCount);
if (sharpCount==2) {
VertDataCopy(q, co);
VertDataMulN(q, 6.0f);
VertDataAdd(q, EDGE_getCo(e, curLvl, x-1));
VertDataAdd(q, EDGE_getCo(e, curLvl, x+1));
VertDataMulN(q, 1/8.0f);
VertDataCopy(q, co, finterpCount);
VertDataMulN(q, 6.0f, finterpCount);
VertDataAdd(q, EDGE_getCo(e, curLvl, x-1), finterpCount);
VertDataAdd(q, EDGE_getCo(e, curLvl, x+1), finterpCount);
VertDataMulN(q, 1/8.0f, finterpCount);
VertDataSub(q, nCo);
VertDataMulN(q, avgSharpness);
VertDataAdd(nCo, q);
VertDataSub(q, nCo, finterpCount);
VertDataMulN(q, avgSharpness, finterpCount);
VertDataAdd(nCo, q, finterpCount);
}
}
}
@@ -1712,21 +1769,21 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
* o old interior edge points
* o new interior face midpoints
*/
VertDataZero(q);
VertDataZero(q, finterpCount);
for (S=0; S<f->numVerts; S++) {
VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1));
VertDataAdd(q, FACE_getIFCo(f, nextLvl, S, 1, 1), finterpCount);
}
VertDataMulN(q, 1.0f/f->numVerts);
VertDataZero(r);
VertDataMulN(q, 1.0f/f->numVerts, finterpCount);
VertDataZero(r, finterpCount);
for (S=0; S<f->numVerts; S++) {
VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1));
VertDataAdd(r, FACE_getIECo(f, curLvl, S, 1), finterpCount);
}
VertDataMulN(r, 1.0f/f->numVerts);
VertDataMulN(r, 1.0f/f->numVerts, finterpCount);
VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f);
VertDataAdd(FACE_getCenterData(f), q);
VertDataAdd(FACE_getCenterData(f), r);
VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
VertDataMulN(FACE_getCenterData(f), f->numVerts-2.0f, finterpCount);
VertDataAdd(FACE_getCenterData(f), q, finterpCount);
VertDataAdd(FACE_getCenterData(f), r, finterpCount);
VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts, finterpCount);
for (S=0; S<f->numVerts; S++) {
/* interior face shift
@@ -1742,19 +1799,19 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *nCo = FACE_getIFCo(f, nextLvl, S, fx, fy);
VertDataAvg4(q, FACE_getIFCo(f, nextLvl, S, fx-1, fy-1),
FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
FACE_getIFCo(f, nextLvl, S, fx-1, fy+1));
FACE_getIFCo(f, nextLvl, S, fx+1, fy-1),
FACE_getIFCo(f, nextLvl, S, fx+1, fy+1),
FACE_getIFCo(f, nextLvl, S, fx-1, fy+1), finterpCount);
VertDataAvg4(r, FACE_getIFCo(f, nextLvl, S, fx-1, fy+0),
FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
FACE_getIFCo(f, nextLvl, S, fx+0, fy+1));
FACE_getIFCo(f, nextLvl, S, fx+1, fy+0),
FACE_getIFCo(f, nextLvl, S, fx+0, fy-1),
FACE_getIFCo(f, nextLvl, S, fx+0, fy+1), finterpCount);
VertDataCopy(nCo, co);
VertDataSub(nCo, q);
VertDataMulN(nCo, 0.25f);
VertDataAdd(nCo, r);
VertDataCopy(nCo, co, finterpCount);
VertDataSub(nCo, q, finterpCount);
VertDataMulN(nCo, 0.25f, finterpCount);
VertDataAdd(nCo, r, finterpCount);
}
}
@@ -1769,19 +1826,19 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
void *nCo = FACE_getIECo(f, nextLvl, S, fx);
VertDataAvg4(q, FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx-1),
FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
FACE_getIFCo(f, nextLvl, S, fx+1, +1),
FACE_getIFCo(f, nextLvl, S, fx-1, +1));
FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx+1),
FACE_getIFCo(f, nextLvl, S, fx+1, +1),
FACE_getIFCo(f, nextLvl, S, fx-1, +1), finterpCount);
VertDataAvg4(r, FACE_getIECo(f, nextLvl, S, fx-1),
FACE_getIECo(f, nextLvl, S, fx+1),
FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
FACE_getIFCo(f, nextLvl, S, fx, 1));
FACE_getIECo(f, nextLvl, S, fx+1),
FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 1, fx),
FACE_getIFCo(f, nextLvl, S, fx, 1), finterpCount);
VertDataCopy(nCo, co);
VertDataSub(nCo, q);
VertDataMulN(nCo, 0.25f);
VertDataAdd(nCo, r);
VertDataCopy(nCo, co, finterpCount);
VertDataSub(nCo, q, finterpCount);
VertDataMulN(nCo, 0.25f, finterpCount);
VertDataAdd(nCo, r, finterpCount);
}
}
}
@@ -1801,8 +1858,8 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
#pragma omp parallel for private(i) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
for (i=0; i<numEffectedE; i++) {
CCGEdge *e = effectedE[i];
VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl));
VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), finterpCount);
VertDataCopy(EDGE_getCo(e, nextLvl, edgeSize-1), VERT_getCo(e->v1, nextLvl), finterpCount);
}
#pragma omp parallel for private(i) if(numEffectedF*edgeSize*edgeSize*4 >= CCG_OMP_LIMIT)
@@ -1814,19 +1871,19 @@ static void ccgSubSurf__calcSubdivLevel(CCGSubSurf *ss,
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx));
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f), finterpCount);
VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f), finterpCount);
VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], nextLvl), finterpCount);
VertDataCopy(FACE_getIECo(f, nextLvl, S, cornerIdx), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, cornerIdx), finterpCount);
for (x=1; x<gridSize-1; x++) {
void *co = FACE_getIECo(f, nextLvl, S, x);
VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co);
VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co);
VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, 0), co, finterpCount);
VertDataCopy(FACE_getIFCo(f, nextLvl, (S+1)%f->numVerts, 0, x), co, finterpCount);
}
for (x=0; x<gridSize-1; x++) {
int eI = gridSize-1-x;
VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize));
VertDataCopy(FACE_getIFCo(f, nextLvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize), finterpCount);
VertDataCopy(FACE_getIFCo(f, nextLvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, eI,vertDataSize), finterpCount);
}
}
}
@@ -1840,6 +1897,7 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
int numEffectedV, numEffectedE, numEffectedF;
int subdivLevels = ss->subdivLevels;
int vertDataSize = ss->meshIFC.vertDataSize;
int finterpCount = ss->meshIFC.finterpCount;
int i, j, ptrIdx, S;
int curLvl, nextLvl;
void *q = ss->q, *r = ss->r;
@@ -1879,11 +1937,11 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
for (ptrIdx=0; ptrIdx<numEffectedF; ptrIdx++) {
CCGFace *f = effectedF[ptrIdx];
void *co = FACE_getCenterData(f);
VertDataZero(co);
VertDataZero(co, finterpCount);
for (i=0; i<f->numVerts; i++) {
VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl));
VertDataAdd(co, VERT_getCo(FACE_getVerts(f)[i], curLvl), finterpCount);
}
VertDataMulN(co, 1.0f/f->numVerts);
VertDataMulN(co, 1.0f/f->numVerts, finterpCount);
f->flags = 0;
}
@@ -1893,28 +1951,28 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
float sharpness = EDGE_getSharpness(e, curLvl);
if (_edge_isBoundary(e) || sharpness>=1.0) {
VertDataCopy(co, VERT_getCo(e->v0, curLvl));
VertDataAdd(co, VERT_getCo(e->v1, curLvl));
VertDataMulN(co, 0.5f);
VertDataCopy(co, VERT_getCo(e->v0, curLvl), finterpCount);
VertDataAdd(co, VERT_getCo(e->v1, curLvl), finterpCount);
VertDataMulN(co, 0.5f, finterpCount);
} else {
int numFaces = 0;
VertDataCopy(q, VERT_getCo(e->v0, curLvl));
VertDataAdd(q, VERT_getCo(e->v1, curLvl));
VertDataCopy(q, VERT_getCo(e->v0, curLvl), finterpCount);
VertDataAdd(q, VERT_getCo(e->v1, curLvl), finterpCount);
for (i=0; i<e->numFaces; i++) {
CCGFace *f = e->faces[i];
VertDataAdd(q, FACE_getCenterData(f));
VertDataAdd(q, FACE_getCenterData(f), finterpCount);
numFaces++;
}
VertDataMulN(q, 1.0f/(2.0f+numFaces));
VertDataMulN(q, 1.0f/(2.0f+numFaces), finterpCount);
VertDataCopy(r, VERT_getCo(e->v0, curLvl));
VertDataAdd(r, VERT_getCo(e->v1, curLvl));
VertDataMulN(r, 0.5f);
VertDataCopy(r, VERT_getCo(e->v0, curLvl), finterpCount);
VertDataAdd(r, VERT_getCo(e->v1, curLvl), finterpCount);
VertDataMulN(r, 0.5f, finterpCount);
VertDataCopy(co, q);
VertDataSub(r, q);
VertDataMulN(r, sharpness);
VertDataAdd(co, r);
VertDataCopy(co, q, finterpCount);
VertDataSub(r, q, finterpCount);
VertDataMulN(r, sharpness, finterpCount);
VertDataAdd(co, r, finterpCount);
}
// edge flags cleared later
@@ -1953,49 +2011,49 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
seam = 0;
if (!v->numEdges) {
VertDataCopy(nCo, co);
VertDataCopy(nCo, co, finterpCount);
} else if (_vert_isBoundary(v)) {
int numBoundary = 0;
VertDataZero(r);
VertDataZero(r, finterpCount);
for (i=0; i<v->numEdges; i++) {
CCGEdge *e = v->edges[i];
if (_edge_isBoundary(e)) {
VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), finterpCount);
numBoundary++;
}
}
VertDataCopy(nCo, co);
VertDataMulN(nCo, 0.75);
VertDataMulN(r, 0.25f/numBoundary);
VertDataAdd(nCo, r);
VertDataCopy(nCo, co, finterpCount);
VertDataMulN(nCo, 0.75, finterpCount);
VertDataMulN(r, 0.25f/numBoundary, finterpCount);
VertDataAdd(nCo, r, finterpCount);
} else {
int numEdges = 0, numFaces = 0;
VertDataZero(q);
VertDataZero(q, finterpCount);
for (i=0; i<v->numFaces; i++) {
CCGFace *f = v->faces[i];
VertDataAdd(q, FACE_getCenterData(f));
VertDataAdd(q, FACE_getCenterData(f), finterpCount);
numFaces++;
}
VertDataMulN(q, 1.0f/numFaces);
VertDataZero(r);
VertDataMulN(q, 1.0f/numFaces, finterpCount);
VertDataZero(r, finterpCount);
for (i=0; i<v->numEdges; i++) {
CCGEdge *e = v->edges[i];
VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl));
VertDataAdd(r, VERT_getCo(_edge_getOtherVert(e, v), curLvl), finterpCount);
numEdges++;
}
VertDataMulN(r, 1.0f/numEdges);
VertDataMulN(r, 1.0f/numEdges, finterpCount);
VertDataCopy(nCo, co);
VertDataMulN(nCo, numEdges-2.0f);
VertDataAdd(nCo, q);
VertDataAdd(nCo, r);
VertDataMulN(nCo, 1.0f/numEdges);
VertDataCopy(nCo, co, finterpCount);
VertDataMulN(nCo, numEdges-2.0f, finterpCount);
VertDataAdd(nCo, q, finterpCount);
VertDataAdd(nCo, r, finterpCount);
VertDataMulN(nCo, 1.0f/numEdges, finterpCount);
}
if (sharpCount>1 || seam) {
VertDataZero(q);
VertDataZero(q, finterpCount);
if (seam) {
avgSharpness = 1.0f;
@@ -2010,34 +2068,34 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
if (seam) {
if (_edge_isBoundary(e)) {
CCGVert *oV = _edge_getOtherVert(e, v);
VertDataAdd(q, VERT_getCo(oV, curLvl));
VertDataAdd(q, VERT_getCo(oV, curLvl), finterpCount);
}
} else if (sharpness != 0.0) {
CCGVert *oV = _edge_getOtherVert(e, v);
VertDataAdd(q, VERT_getCo(oV, curLvl));
VertDataAdd(q, VERT_getCo(oV, curLvl), finterpCount);
}
}
VertDataMulN(q, (float) 1/sharpCount);
VertDataMulN(q, (float) 1/sharpCount, finterpCount);
if (sharpCount!=2 || allSharp) {
// q = q + (co-q)*avgSharpness
VertDataCopy(r, co);
VertDataSub(r, q);
VertDataMulN(r, avgSharpness);
VertDataAdd(q, r);
VertDataCopy(r, co, finterpCount);
VertDataSub(r, q, finterpCount);
VertDataMulN(r, avgSharpness, finterpCount);
VertDataAdd(q, r, finterpCount);
}
// r = co*.75 + q*.25
VertDataCopy(r, co);
VertDataMulN(r, .75);
VertDataMulN(q, .25);
VertDataAdd(r, q);
VertDataCopy(r, co, finterpCount);
VertDataMulN(r, .75, finterpCount);
VertDataMulN(q, .25, finterpCount);
VertDataAdd(r, q, finterpCount);
// nCo = nCo + (r-nCo)*avgSharpness
VertDataSub(r, nCo);
VertDataMulN(r, avgSharpness);
VertDataAdd(nCo, r);
VertDataSub(r, nCo, finterpCount);
VertDataMulN(r, avgSharpness, finterpCount);
VertDataAdd(nCo, r, finterpCount);
}
// vert flags cleared later
@@ -2065,8 +2123,8 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
for (i=0; i<numEffectedE; i++) {
CCGEdge *e = effectedE[i];
VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl));
VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl));
VertDataCopy(EDGE_getCo(e, nextLvl, 0), VERT_getCo(e->v0, nextLvl), finterpCount);
VertDataCopy(EDGE_getCo(e, nextLvl, 2), VERT_getCo(e->v1, nextLvl), finterpCount);
}
for (i=0; i<numEffectedF; i++) {
CCGFace *f = effectedF[i];
@@ -2074,13 +2132,13 @@ static void ccgSubSurf__sync(CCGSubSurf *ss) {
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f));
VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f));
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl));
VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1));
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 0), FACE_getCenterData(f), finterpCount);
VertDataCopy(FACE_getIECo(f, nextLvl, S, 0), FACE_getCenterData(f), finterpCount);
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 1), VERT_getCo(FACE_getVerts(f)[S], nextLvl), finterpCount);
VertDataCopy(FACE_getIECo(f, nextLvl, S, 1), EDGE_getCo(FACE_getEdges(f)[S], nextLvl, 1), finterpCount);
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize));
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 1, 0), _edge_getCoVert(e, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), finterpCount);
VertDataCopy(FACE_getIFCo(f, nextLvl, S, 0, 1), _edge_getCoVert(prevE, FACE_getVerts(f)[S], nextLvl, 1, vertDataSize), finterpCount);
}
}
@@ -2188,6 +2246,7 @@ CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
int vertDataSize = ss->meshIFC.vertDataSize, freeF;
int finterpCount = ss->meshIFC.finterpCount;
subdivLevels = ss->subdivLevels;
lvl = (lvl)? lvl: subdivLevels;
@@ -2203,16 +2262,16 @@ CCGError ccgSubSurf_updateFromFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[(S+f->numVerts-1)%f->numVerts];
VertDataCopy(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
VertDataCopy(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
VertDataCopy(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), finterpCount);
VertDataCopy(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), finterpCount);
for (x=0; x<gridSize; x++)
VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
VertDataCopy(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), finterpCount);
for (x=0; x<gridSize; x++) {
int eI = gridSize-1-x;
VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
VertDataCopy(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x), finterpCount);
VertDataCopy(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx), finterpCount);
}
}
}
@@ -2227,6 +2286,7 @@ CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF,
{
int i, S, x, gridSize, cornerIdx, subdivLevels;
int vertDataSize = ss->meshIFC.vertDataSize, freeF;
int finterpCount = ss->meshIFC.finterpCount;
subdivLevels = ss->subdivLevels;
lvl = (lvl)? lvl: subdivLevels;
@@ -2245,17 +2305,17 @@ CCGError ccgSubSurf_updateToFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF,
for (x=0; x<gridSize; x++) {
int eI = gridSize-1-x;
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), finterpCount);
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), finterpCount);
}
for (x=1; x<gridSize-1; x++) {
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x));
VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x));
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), finterpCount);
VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), finterpCount);
}
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f));
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl));
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f), finterpCount);
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), finterpCount);
}
}
@@ -2273,6 +2333,7 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
int numEffectedV, numEffectedE, freeF;
int i, S, x, gridSize, cornerIdx, subdivLevels, edgeSize;
int vertDataSize = ss->meshIFC.vertDataSize;
int finterpCount = ss->meshIFC.finterpCount;
subdivLevels = ss->subdivLevels;
lvl = (lvl)? lvl: subdivLevels;
@@ -2287,47 +2348,47 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
/* zero */
for (i=0; i<numEffectedV; i++) {
CCGVert *v = effectedV[i];
VertDataZero(VERT_getCo(v, lvl));
VertDataZero(VERT_getCo(v, lvl), finterpCount);
}
for (i=0; i<numEffectedE; i++) {
CCGEdge *e = effectedE[i];
for (x=0; x<edgeSize; x++)
VertDataZero(EDGE_getCo(e, lvl, x));
VertDataZero(EDGE_getCo(e, lvl, x), finterpCount);
}
/* add */
for (i=0; i<numEffectedF; i++) {
CCGFace *f = effectedF[i];
VertDataZero(FACE_getCenterData(f));
VertDataZero(FACE_getCenterData(f), finterpCount);
for (S=0; S<f->numVerts; S++)
for (x=0; x<gridSize; x++)
VertDataZero(FACE_getIECo(f, lvl, S, x));
VertDataZero(FACE_getIECo(f, lvl, S, x), finterpCount);
for (S=0; S<f->numVerts; S++) {
int prevS = (S+f->numVerts-1)%f->numVerts;
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[prevS];
VertDataAdd(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0));
VertDataAdd(FACE_getCenterData(f), FACE_getIFCo(f, lvl, S, 0, 0), finterpCount);
if (FACE_getVerts(f)[S]->flags&Vert_eEffected)
VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx));
VertDataAdd(VERT_getCo(FACE_getVerts(f)[S], lvl), FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), finterpCount);
for (x=1; x<gridSize-1; x++) {
VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0));
VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x));
VertDataAdd(FACE_getIECo(f, lvl, S, x), FACE_getIFCo(f, lvl, S, x, 0), finterpCount);
VertDataAdd(FACE_getIECo(f, lvl, prevS, x), FACE_getIFCo(f, lvl, S, 0, x), finterpCount);
}
for (x=0; x<gridSize-1; x++) {
int eI = gridSize-1-x;
if (FACE_getEdges(f)[S]->flags&Edge_eEffected)
VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x));
VertDataAdd(_edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, cornerIdx, x), finterpCount);
if (FACE_getEdges(f)[prevS]->flags&Edge_eEffected)
if(x != 0)
VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx));
VertDataAdd(_edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), FACE_getIFCo(f, lvl, S, x, cornerIdx), finterpCount);
}
}
}
@@ -2335,50 +2396,50 @@ CCGError ccgSubSurf_stitchFaces(CCGSubSurf *ss, int lvl, CCGFace **effectedF, in
/* average */
for (i=0; i<numEffectedV; i++) {
CCGVert *v = effectedV[i];
VertDataMulN(VERT_getCo(v, lvl), 1.0f/v->numFaces);
VertDataMulN(VERT_getCo(v, lvl), 1.0f/v->numFaces, finterpCount);
}
for (i=0; i<numEffectedE; i++) {
CCGEdge *e = effectedE[i];
VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl));
VertDataCopy(EDGE_getCo(e, lvl, edgeSize-1), VERT_getCo(e->v1, lvl));
VertDataCopy(EDGE_getCo(e, lvl, 0), VERT_getCo(e->v0, lvl), finterpCount);
VertDataCopy(EDGE_getCo(e, lvl, edgeSize-1), VERT_getCo(e->v1, lvl), finterpCount);
for (x=1; x<edgeSize-1; x++)
VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f/e->numFaces);
VertDataMulN(EDGE_getCo(e, lvl, x), 1.0f/e->numFaces, finterpCount);
}
/* copy */
for (i=0; i<numEffectedF; i++) {
CCGFace *f = effectedF[i];
VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts);
VertDataMulN(FACE_getCenterData(f), 1.0f/f->numVerts, finterpCount);
for (S=0; S<f->numVerts; S++)
for (x=1; x<gridSize-1; x++)
VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f);
VertDataMulN(FACE_getIECo(f, lvl, S, x), 0.5f, finterpCount);
for (S=0; S<f->numVerts; S++) {
int prevS = (S+f->numVerts-1)%f->numVerts;
CCGEdge *e = FACE_getEdges(f)[S];
CCGEdge *prevE = FACE_getEdges(f)[prevS];
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f));
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl));
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, 0), FACE_getCenterData(f), finterpCount);
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, cornerIdx), VERT_getCo(FACE_getVerts(f)[S], lvl), finterpCount);
for (x=1; x<gridSize-1; x++) {
VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x));
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x));
VertDataCopy(FACE_getIFCo(f, lvl, S, x, 0), FACE_getIECo(f, lvl, S, x), finterpCount);
VertDataCopy(FACE_getIFCo(f, lvl, S, 0, x), FACE_getIECo(f, lvl, prevS, x), finterpCount);
}
for (x=0; x<gridSize-1; x++) {
int eI = gridSize-1-x;
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize));
VertDataCopy(FACE_getIFCo(f, lvl, S, cornerIdx, x), _edge_getCoVert(e, FACE_getVerts(f)[S], lvl, eI,vertDataSize), finterpCount);
VertDataCopy(FACE_getIFCo(f, lvl, S, x, cornerIdx), _edge_getCoVert(prevE, FACE_getVerts(f)[S], lvl, eI,vertDataSize), finterpCount);
}
VertDataCopy(FACE_getIECo(f, lvl, S, 0), FACE_getCenterData(f));
VertDataCopy(FACE_getIECo(f, lvl, S, gridSize-1), FACE_getIFCo(f, lvl, S, gridSize-1, 0));
VertDataCopy(FACE_getIECo(f, lvl, S, 0), FACE_getCenterData(f), finterpCount);
VertDataCopy(FACE_getIECo(f, lvl, S, gridSize-1), FACE_getIFCo(f, lvl, S, gridSize-1, 0), finterpCount);
}
}
@@ -2510,6 +2571,10 @@ int ccgSubSurf_getGridLevelSize(CCGSubSurf *ss, int level) {
}
}
struct GridKey *ccgSubSurf_getGridKey(CCGSubSurf *ss) {
return &ss->meshIFC.gridkey;
}
/* Vert accessors */
CCGVertHDL ccgSubSurf_getVertVertHandle(CCGVert *v) {

View File

@@ -1,5 +1,7 @@
/* $Id$ */
#include "BKE_dmgrid.h"
typedef void* CCGMeshHDL;
typedef void* CCGVertHDL;
typedef void* CCGEdgeHDL;
@@ -12,8 +14,14 @@ typedef struct _CCGFace CCGFace;
typedef struct _CCGMeshIFC CCGMeshIFC;
struct _CCGMeshIFC {
int vertUserSize, edgeUserSize, faceUserSize;
int vertDataSize;
/* How many floats to interpolate per-vertex.
example: if interpolating coordinates and paint masks,
that would be (3+1) floats, so finterpCount would be 4. */
int finterpCount;
struct GridKey gridkey;
};
/***/
@@ -90,6 +98,7 @@ int ccgSubSurf_getEdgeSize (CCGSubSurf *ss);
int ccgSubSurf_getEdgeLevelSize (CCGSubSurf *ss, int level);
int ccgSubSurf_getGridSize (CCGSubSurf *ss);
int ccgSubSurf_getGridLevelSize (CCGSubSurf *ss, int level);
struct GridKey* ccgSubSurf_getGridKey (CCGSubSurf *ss);
CCGVert* ccgSubSurf_getVert (CCGSubSurf *ss, CCGVertHDL v);
CCGVertHDL ccgSubSurf_getVertVertHandle (CCGVert *v);

View File

@@ -46,11 +46,14 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_displist.h"
#include "BKE_DerivedMesh.h"
#include "BKE_dmgrid.h"
#include "BKE_key.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_ptex.h"
#include "BKE_texture.h"
#include "BKE_utildefines.h"
@@ -628,7 +631,11 @@ static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *use
}
/* note, material function is ignored for now. */
static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int UNUSED(useColors), int (*setMaterial)(int, void *attribs))
static void emDM_drawMappedFaces(DerivedMesh *dm, float (*partial_redraw_planes)[4],
int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r),
void *userData,
int (*setMaterial)(int, void *attribs),
DMDrawFlags flags)
{
EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
EditFace *efa;
@@ -1960,6 +1967,13 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
add_weight_mcol_dm(ob, finaldm);
}
/* hack: for ptex paint use all quads */
if((ob->mode & OB_MODE_VERTEX_PAINT) && finaldm->type != DM_TYPE_CCGDM) {
dm = finaldm;
finaldm = quad_dm_create_from_derived(finaldm);
dm->release(dm);
}
/* add an orco layer if needed */
if(dataMask & CD_MASK_ORCO) {
add_orco_dm(ob, NULL, finaldm, orcodm, CD_ORCO);
@@ -2222,13 +2236,13 @@ static void clear_mesh_caches(Object *ob)
ob->derivedDeform->release(ob->derivedDeform);
ob->derivedDeform= NULL;
}
/* we free pbvh on changes, except during sculpt since it can't deal with
/* we free pbvh on changes, except during paint since it can't deal with
changing PVBH node organization, we hope topology does not change in
the meantime .. weak */
if(ob->sculpt && ob->sculpt->pbvh) {
if(!ob->sculpt->cache) {
BLI_pbvh_free(ob->sculpt->pbvh);
ob->sculpt->pbvh= NULL;
if(ob->paint && ob->paint->pbvh) {
if(!ob->paint->sculpt || !ob->paint->sculpt->cache) {
BLI_pbvh_free(ob->paint->pbvh);
ob->paint->pbvh= NULL;
}
}
}
@@ -2238,7 +2252,7 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask)
Object *obact = scene->basact?scene->basact->object:NULL;
int editing = paint_facesel_test(ob);
/* weight paint and face select need original indicies because of selection buffer drawing */
int needMapping = (ob==obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT|OB_MODE_VERTEX_PAINT)));
int needMapping = (ob==obact) && (editing || (ob->mode & OB_MODE_WEIGHT_PAINT));
clear_mesh_caches(ob);
@@ -2251,6 +2265,10 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask)
ob->derivedFinal->needsFree = 0;
ob->derivedDeform->needsFree = 0;
ob->lastDataMask = dataMask;
/* update the pbvh for paint */
if((ob->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT)) && ob->paint)
ob->paint->pbvh= ob->derivedFinal->getPBVH(ob, ob->derivedFinal);
}
static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask)

View File

@@ -37,6 +37,7 @@
#include "BIF_gl.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_mesh.h"
#include "BKE_paint.h"
@@ -191,13 +192,15 @@ static int can_pbvh_draw(Object *ob, DerivedMesh *dm)
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
Mesh *me= (ob)? ob->data: NULL;
if(ob->sculpt->modifiers_active) return 0;
if(ob->paint->sculpt && ob->paint->sculpt->modifiers_active) return 0;
//if(paint_facesel_test(ob)) return 0;
return (cddm->mvert == me->mvert) || ob->sculpt->kb;
return (cddm->mvert == me->mvert) || (ob->paint->sculpt && ob->paint->sculpt->kb) || (ob->mode & OB_MODE_VERTEX_PAINT);
}
static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
{
SculptSession *ss;
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
Mesh *me= (ob)? ob->data: NULL;
@@ -206,10 +209,12 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
return NULL;
}
if(!ob->sculpt)
if(!ob->paint)
return NULL;
if(ob->sculpt->pbvh) {
cddm->pbvh= ob->sculpt->pbvh;
ss = ob->paint->sculpt;
if(ob->paint->pbvh) {
cddm->pbvh= ob->paint->pbvh;
cddm->pbvh_draw = can_pbvh_draw(ob, dm);
}
@@ -217,10 +222,35 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
this derivedmesh is just original mesh. it's the multires subsurf dm
that this is actually for, to support a pbvh on a modified mesh */
if(!cddm->pbvh && ob->type == OB_MESH) {
cddm->pbvh = BLI_pbvh_new();
MFace *mface;
MVert *mvert;
int totvert, totface;
int leaf_limit = PBVH_DEFAULT_LEAF_LIMIT;
/* TODO: set leaf limit more intelligently */
if(ob->mode & OB_MODE_VERTEX_PAINT)
leaf_limit = 1;
cddm->pbvh = BLI_pbvh_new(leaf_limit);
cddm->pbvh_draw = can_pbvh_draw(ob, dm);
BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert,
me->totface, me->totvert);
if(ob->mode & OB_MODE_VERTEX_PAINT) {
mface = cddm->mface;
mvert = cddm->mvert;
totvert = cdDM_getNumVerts(&cddm->dm);
totface = cdDM_getNumFaces(&cddm->dm);
}
else {
mface = me->mface;
mvert = me->mvert;
totvert = me->totvert;
totface = me->totface;
}
BLI_pbvh_build_mesh(cddm->pbvh, mface, mvert,
&me->vdata, &me->fdata,
totface, totvert,
ss ? &ss->hidden_areas : NULL);
}
return cddm->pbvh;
@@ -416,9 +446,39 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm)
}
}
/* draw using the PBVH; returns true if drawing is done,
false if regular drawing should be used */
static int cddm_draw_pbvh(DerivedMesh *dm, float (*partial_redraw_planes)[4],
int (*setMaterial)(int, void *attribs),
DMDrawFlags flags)
{
CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
MFace *mface = cddm->mface;
float (*face_nors)[3];
if(!(flags & DM_DRAW_BACKBUF_SELECTION) && cddm->pbvh && cddm->pbvh_draw) {
if(dm->numFaceData) {
face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
/* should be per face */
if(setMaterial && !setMaterial(mface->mat_nr+1, NULL))
return 1;
if(mface->flag & ME_SMOOTH)
flags |= DM_DRAW_FULLY_SMOOTH;
BLI_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, flags);
}
return 1;
}
return 0;
}
static void cdDM_drawFacesSolid(DerivedMesh *dm,
float (*partial_redraw_planes)[4],
int UNUSED(fast), int (*setMaterial)(int, void *attribs))
int (*setMaterial)(int, void *attribs),
DMDrawFlags flags)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
MVert *mvert = cddm->mvert;
@@ -426,30 +486,17 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1;
#define PASSVERT(index) { \
if(shademodel == GL_SMOOTH) { \
short *no = mvert[index].no; \
glNormal3sv(no); \
} \
glVertex3fv(mvert[index].co); \
}
if(cddm->pbvh && cddm->pbvh_draw) {
if(dm->numFaceData) {
float (*face_nors)[3] = CustomData_get_layer(&dm->faceData, CD_NORMAL);
/* should be per face */
if(!setMaterial(mface->mat_nr+1, NULL))
return;
glShadeModel((mface->flag & ME_SMOOTH)? GL_SMOOTH: GL_FLAT);
BLI_pbvh_draw(cddm->pbvh, partial_redraw_planes, face_nors, (mface->flag & ME_SMOOTH));
glShadeModel(GL_FLAT);
}
return;
#define PASSVERT(index) { \
if(shademodel == GL_SMOOTH) { \
short *no = mvert[index].no; \
glNormal3sv(no); \
} \
glVertex3fv(mvert[index].co); \
}
if(cddm_draw_pbvh(dm, partial_redraw_planes, setMaterial, flags))
return;
if( GPU_buffer_legacy(dm) ) {
DEBUG_VBO( "Using legacy code. cdDM_drawFacesSolid\n" );
glBegin(glmode = GL_QUADS);
@@ -777,7 +824,9 @@ static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tfa
cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
}
static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs))
static void cdDM_drawMappedFaces(DerivedMesh *dm, float (*partial_redraw_planes)[4],
int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r),
void *userData, int (*setMaterial)(int, void *attribs), DMDrawFlags flags)
{
CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
MVert *mv = cddm->mvert;
@@ -786,6 +835,9 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
if(cddm_draw_pbvh(dm, partial_redraw_planes, NULL, flags))
return;
mc = DM_get_face_data_layer(dm, CD_ID_MCOL);
if(!mc)
mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
@@ -810,7 +862,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
if(draw) {
unsigned char *cp = NULL;
if(useColors && mc)
if((flags & DM_DRAW_VERTEX_COLORS) && mc)
cp = (unsigned char *)&mc[i * 4];
glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
@@ -867,7 +919,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
int prevstart = 0;
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
if( useColors && mc )
if((flags & DM_DRAW_VERTEX_COLORS) && mc )
GPU_color_setup(dm);
if( !GPU_buffer_legacy(dm) ) {
int tottri = dm->drawObject->nelements/3;

View File

@@ -51,6 +51,8 @@
#include "BKE_main.h"
#include "BKE_utildefines.h"
#include "ptex.h"
/* number of layers to add when growing a CustomData object */
#define CUSTOMDATA_GROW 5
@@ -777,7 +779,7 @@ static void layerSwap_mcol(void *data, const int *corner_indices)
static void layerDefault_mcol(void *data, int count)
{
static MCol default_mcol = {255, 255, 255, 255};
static MCol default_mcol = {0, 255, 255, 255}; /* abgr */
MCol *mcol = (MCol*)data;
int i;
@@ -785,9 +787,74 @@ static void layerDefault_mcol(void *data, int count)
mcol[i] = default_mcol;
}
/* Grid */
static void layerCopy_grid(const void *source_v, void *dest_v, int count)
{
const CustomDataMultires *source = source_v;
CustomDataMultires *dest = dest_v;
int i, j;
for(i = 0; i < count; ++i) {
dest[i].totlayer = source[i].totlayer;
dest[i].layers = MEM_callocN(sizeof(CustomDataMultiresLayer) *
dest[i].totlayer,
"CustomDataMultiresLayers");
for(j = 0; j < source[i].totlayer; ++j) {
CustomDataMultiresLayer *dl = dest[i].layers + j;
CustomDataMultiresLayer *sl = source[i].layers + j;
dl->type = sl->type;
dl->griddata = MEM_dupallocN(sl->griddata);
BLI_strncpy(dl->name, sl->name, sizeof(dl->name));
}
}
}
static void layerFree_grid(void *data_v, int count, int size)
{
CustomDataMultires *data = data_v;
int i, j;
for(i = 0; i < count; ++i) {
for(j = 0; j < data[i].totlayer; ++j) {
if(data[i].layers[j].griddata)
MEM_freeN(data[i].layers[j].griddata);
}
if(data[i].layers)
MEM_freeN(data[i].layers);
}
}
static void layerCopy_mptex(const void *source_v, void *dest_v, int count)
{
const MPtex *source = source_v;
MPtex *dest = dest_v;
int i, j;
for(i = 0; i < count; ++i) {
dest[i] = source[i];
for(j = 0; j < source[i].totsubface; ++j)
dest[i].subfaces[j].data = MEM_dupallocN(source[i].subfaces[j].data);
}
}
static void layerFree_mptex(void *data_v, int count, int size)
{
MPtex *data = data_v;
int i, j;
for(i = 0; i < count; ++i) {
for(j = 0; j < data[i].totsubface; ++j) {
if(data[i].subfaces[j].data)
MEM_freeN(data[i].subfaces[j].data);
}
}
}
const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 0 */
{sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(MSticky), "MSticky", 1, NULL, NULL, NULL, layerInterp_msticky, NULL,
NULL},
@@ -804,6 +871,8 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 3 floats per normal vector */
{sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 10 */
{sizeof(MFloatProperty), "MFloatProperty",1,"Float",NULL,NULL,NULL,NULL},
{sizeof(MIntProperty), "MIntProperty",1,"Int",NULL,NULL,NULL,NULL},
{sizeof(MStringProperty), "MStringProperty",1,"String",NULL,NULL,NULL,NULL},
@@ -816,13 +885,22 @@ const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(float)*3*4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
{sizeof(MDisps), "MDisps", 1, NULL, layerCopy_mdisps,
layerFree_mdisps, layerInterp_mdisps, layerSwap_mdisps, NULL, layerRead_mdisps, layerWrite_mdisps, layerFilesize_mdisps},
/* 20 */
{sizeof(MCol)*4, "MCol", 4, "WeightCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
{sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
{sizeof(MCol)*4, "MCol", 4, "IDCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
{sizeof(MCol)*4, "MCol", 4, "TexturedCol", NULL, NULL, layerInterp_mcol,
{sizeof(MCol)*4, "MCol", 4, "TexturedCol", NULL, NULL, layerInterp_mcol,
layerSwap_mcol, layerDefault_mcol},
{sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL}
/* CD_CLOTH_ORCO */
{sizeof(float)*3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* CD_GRID */
{sizeof(CustomDataMultires), "CustomDataMultires", 1, "Grid", layerCopy_grid, layerFree_grid, NULL, NULL, NULL},
/* CD_PAINTMASK */
{sizeof(float), "", 0, "Mask", NULL, NULL, NULL, NULL, NULL},
/* CD_MPTEX */
{sizeof(MPtex), "MPtex", 1, "Ptex", layerCopy_mptex, layerFree_mptex, NULL, NULL, NULL},
};
const char *LAYERTYPENAMES[CD_NUMTYPES] = {
@@ -830,7 +908,8 @@ const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 5-9 */ "CDMTFace", "CDMCol", "CDOrigIndex", "CDNormal", "CDFlags",
/* 10-14 */ "CDMFloatProperty", "CDMIntProperty","CDMStringProperty", "CDOrigSpace", "CDOrco",
/* 15-19 */ "CDMTexPoly", "CDMLoopUV", "CDMloopCol", "CDTangent", "CDMDisps",
/* 20-23 */"CDWeightMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco"
/* 20-24 */ "CDWeightMCol", "CDIDMCol", "CDTextureMCol", "CDClothOrco", "CDGrid",
/* 25-26 */ "CDPaintMask", "CD_PTEX"
};
const CustomDataMask CD_MASK_BAREMESH =
@@ -838,14 +917,17 @@ const CustomDataMask CD_MASK_BAREMESH =
const CustomDataMask CD_MASK_MESH =
CD_MASK_MVERT | CD_MASK_MEDGE | CD_MASK_MFACE |
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MCOL |
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
CD_MASK_GRIDS | CD_MASK_PAINTMASK | CD_MASK_MPTEX;
const CustomDataMask CD_MASK_EDITMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS;
CD_MASK_MCOL|CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR |
CD_MASK_MDISPS | CD_MASK_GRIDS | CD_MASK_PAINTMASK | CD_MASK_MPTEX;
const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL | CD_MASK_ORIGINDEX | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL;
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORCO | CD_MASK_TANGENT | CD_MASK_WEIGHT_MCOL |
CD_MASK_PAINTMASK;
const CustomDataMask CD_MASK_BMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR;
const CustomDataMask CD_MASK_FACECORNERS =
@@ -915,6 +997,8 @@ void CustomData_merge(const struct CustomData *source, struct CustomData *dest,
newlayer->active_clone = lastclone;
newlayer->active_mask = lastmask;
newlayer->flag |= lastflag & (CD_FLAG_EXTERNAL|CD_FLAG_IN_MEMORY);
if(layer->flag & CD_FLAG_MULTIRES)
newlayer->flag |= CD_FLAG_MULTIRES;
}
}
}
@@ -1093,6 +1177,20 @@ int CustomData_get_stencil_layer(const CustomData *data, int type)
return -1;
}
char *CustomData_get_layer_name_at_offset(const CustomData *data, int type, int offset)
{
int first;
first = CustomData_get_layer_index(data, type);
if((first != -1) &&
(first + offset < data->totlayer) &&
(data->layers[first + offset].type == type))
return data->layers[first + offset].name;
else
return NULL;
}
void CustomData_set_layer_active(CustomData *data, int type, int n)
{
int i;
@@ -1175,6 +1273,17 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag)
data->layers[i].flag |= flag;
}
void CustomData_set_layer_offset_flag(struct CustomData *data, int type, int offset, int flag)
{
int first = CustomData_get_layer_index(data, type);
if((first != -1) &&
(first+offset < data->totlayer) &&
(data->layers[first+offset].type == type)) {
data->layers[first+offset].flag |= flag;
}
}
static int customData_resize(CustomData *data, int amount)
{
CustomDataLayer *tmp = MEM_callocN(sizeof(*tmp)*(data->maxlayer + amount),
@@ -1238,8 +1347,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data,
data->layers[index] = data->layers[index - 1];
data->layers[index].type = type;
data->layers[index].flag = flag;
data->layers[index].flag = flag | CD_FLAG_ENABLED;
data->layers[index].data = newlayerdata;
data->layers[index].strength = 1;
if(name || (name=typeInfo->defaultname)) {
strcpy(data->layers[index].name, name);
@@ -1272,7 +1382,7 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype,
const LayerTypeInfo *typeInfo= layerType_getInfo(type);
layer = customData_add_layer__internal(data, type, alloctype, layerdata,
totelem, typeInfo->defaultname);
totelem, typeInfo->defaultname);
if(layer)
return layer->data;
@@ -1280,6 +1390,32 @@ void *CustomData_add_layer(CustomData *data, int type, int alloctype,
return NULL;
}
void *CustomData_add_layer_at_offset(CustomData *cd, int type, int alloctype,
void *layerdata, int totelem, int offset)
{
int type_first_layer, type_totlayer, i;
CustomDataLayer copy_of_new;
/* add the new layer as normal */
CustomData_add_layer(cd, type, alloctype, layerdata, totelem);
type_first_layer = CustomData_get_layer_index(cd, type);
type_totlayer = CustomData_number_of_layers(cd, type);
/* make a copy of the new layer */
copy_of_new = cd->layers[type_first_layer + type_totlayer - 1];
/* move the old layers up to make room for the new layer */
for(i = type_first_layer + type_totlayer - 1;
i > type_first_layer + offset; --i)
cd->layers[i] = cd->layers[i-1];
/* copy the new layer into the correct offset */
cd->layers[type_first_layer + offset] = copy_of_new;
return copy_of_new.data;
}
/*same as above but accepts a name*/
void *CustomData_add_layer_named(CustomData *data, int type, int alloctype,
void *layerdata, int totelem, const char *name)
@@ -2340,6 +2476,250 @@ int CustomData_verify_versions(struct CustomData *data, int index)
return keeplayer;
}
/* Multires */
int CustomData_multires_type_totfloat(int type)
{
switch(type) {
case CD_MVERT:
return 3;
case CD_MCOL:
return 4;
case CD_PAINTMASK:
return 1;
default:
return 0;
}
}
static int customdata_multires_find_first_layer_index(CustomDataMultires *cdm, int type)
{
int i;
for(i = 0; i < cdm->totlayer; ++i) {
if(cdm->layers[i].type == type)
return i;
}
return -1;
}
static int customdata_multires_find_named_layer_index(CustomDataMultires *cdm,
int type, char *name)
{
int first, i;
first = customdata_multires_find_first_layer_index(cdm, type);
if(first != -1) {
for(i = first; first < cdm->totlayer; ++i) {
if(cdm->layers[i].type != type)
break;
else if(!strcmp(name, cdm->layers[i].name))
return i;
}
}
return -1;
}
int CustomData_get_multires_count(CustomData *cd, int type)
{
int first, tot, i;
first = CustomData_get_layer_index(cd, type);
tot = 0;
if(first != -1) {
for(i = first; i < cd->totlayer; ++i) {
if(cd->layers[i].type != type)
break;
if(cd->layers[i].flag & CD_FLAG_MULTIRES)
++tot;
}
}
return tot;
}
void *CustomData_get_multires_names(CustomData *cd, int type)
{
char (*names)[32] = NULL;
int count, first;
count = CustomData_get_multires_count(cd, type);
if(count) {
int layer_ndx, names_ndx;
names = MEM_callocN(32*count, "CustomData_get_multires_names");
first = CustomData_get_layer_index(cd, type);
names_ndx = 0;
for(layer_ndx = first; layer_ndx < cd->totlayer; ++layer_ndx) {
CustomDataLayer *cdl = cd->layers + layer_ndx;
if(cdl->type != type)
break;
else if(cdl->flag & CD_FLAG_MULTIRES) {
BLI_strncpy(names[names_ndx], cdl->name, 32);
++names_ndx;
}
}
}
return names;
}
float *CustomData_multires_get_data(CustomDataMultires *cdm, int type,
char *name)
{
int layer;
layer = customdata_multires_find_named_layer_index(cdm, type, name);
if(layer == -1)
return NULL;
else
return cdm->layers[layer].griddata;
}
static float *customdata_multires_alloc_griddata(int type, int totelem)
{
return MEM_callocN(sizeof(float) * totelem *
CustomData_multires_type_totfloat(type),
"CustomDataMultiresLayer.griddata");
}
void CustomData_multires_sync_layer(CustomDataMultires *cdm, int type,
char *name)
{
int layer;
layer = customdata_multires_find_named_layer_index(cdm, type, name);
if(layer == -1)
CustomData_multires_add_layer_data(cdm, type, name, NULL);
else {
if(cdm->layers[layer].griddata)
MEM_freeN(cdm->layers[layer].griddata);
cdm->layers[layer].griddata =
customdata_multires_alloc_griddata(type, cdm->totelem);
}
}
void CustomData_multires_add_layer_data(CustomDataMultires *cdm, int type,
char *name, float *griddata)
{
CustomDataMultiresLayer *old = cdm->layers;
int first, layer, i;
cdm->layers = MEM_callocN(sizeof(CustomDataMultiresLayer) *
(cdm->totlayer + 1),
"customdata multires add layer");
first = customdata_multires_find_first_layer_index(cdm, type);
/* if no layers of type yet, add new layer at end
otherwise add layer at the beginning of the type's segment */
if(first == -1)
layer = cdm->totlayer;
else
layer = first;
/* create griddata if none given */
if(!griddata) {
griddata =
customdata_multires_alloc_griddata(type, cdm->totelem);
}
for(i = 0; i <= cdm->totlayer; ++i) {
if(i < layer)
cdm->layers[i] = old[i];
else if(i == layer) {
cdm->layers[i].griddata = griddata;
cdm->layers[i].type = type;
BLI_strncpy(cdm->layers[i].name, name,
sizeof(cdm->layers[i].name));
}
else if(i > layer)
cdm->layers[i] = old[i-1];
}
++cdm->totlayer;
if(old) MEM_freeN(old);
}
void CustomData_multires_add_layers(CustomDataMultires *cdm, int count,
int type, char *name)
{
int i;
if(!cdm)
return;
for(i = 0; i < count; ++i, ++cdm)
CustomData_multires_add_layer_data(cdm, type, name, NULL);
}
static int CustomData_multires_layer_delete(CustomDataMultires *cdm, int type,
char *name)
{
CustomDataMultiresLayer *old = cdm->layers;
int layer, i;
layer = customdata_multires_find_named_layer_index(cdm, type, name);
if(layer == -1)
return 0;
cdm->layers = MEM_callocN(sizeof(CustomDataMultiresLayer) *
(cdm->totlayer - 1),
"customdata multires remove layer");
/* copy over layer data, skipping the removed layer */
for(i = 0; i < cdm->totlayer; ++i) {
if(i < layer)
cdm->layers[i] = old[i];
else if(i == layer && old[i].griddata)
MEM_freeN(old[i].griddata);
else if(i > layer)
cdm->layers[i - 1] = old[i];
}
--cdm->totlayer;
MEM_freeN(old);
return 1;
}
int CustomData_multires_remove_layers(CustomDataMultires *cdm, int count,
int type, char *name)
{
int i;
if(!cdm)
return 0;
for(i = 0; i < count; ++i, ++cdm) {
if(!CustomData_multires_layer_delete(cdm, type, name))
return 0;
}
return 1;
}
void CustomData_multires_rename(CustomDataMultires *cdm, int type,
char *old_name, char *name)
{
int layer;
layer = customdata_multires_find_named_layer_index(cdm, type, old_name);
if(layer != -1) {
BLI_strncpy(cdm->layers[layer].name, name,
sizeof(cdm->layers[layer].name));
}
}
/****************************** External Files *******************************/
static void customdata_external_filename(char filename[FILE_MAX], ID *id, CustomDataExternal *external)

View File

@@ -57,8 +57,14 @@ static const int multires_max_levels = 13;
static const int multires_grid_tot[] = {0, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
static const int multires_side_tot[] = {0, 2, 3, 5, 9, 17, 33, 65, 129, 257, 513, 1025, 2049, 4097};
typedef enum {
APPLY_DISPS,
CALC_DISPS,
ADD_DISPS,
} DispOp;
static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert);
static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl);
static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DispOp op, DMGridData **oldGridData, int totlvl);
DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
{
@@ -93,7 +99,7 @@ static int multires_get_level(Object *ob, MultiresModifierData *mmd, int render)
{
if(render)
return (mmd->modifier.scene)? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl): mmd->renderlvl;
else if(ob->mode == OB_MODE_SCULPT)
else if(ob->mode & OB_MODE_SCULPT)
return mmd->sculptlvl;
else
return (mmd->modifier.scene)? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl): mmd->lvl;
@@ -118,8 +124,10 @@ static void multires_dm_mark_as_modified(DerivedMesh *dm)
void multires_mark_as_modified(Object *ob)
{
if(ob && ob->derivedFinal)
multires_dm_mark_as_modified(ob->derivedFinal);
DerivedMesh *dm = ob->derivedFinal;
if(ob && dm && dm->type == DM_TYPE_CCGDM)
multires_dm_mark_as_modified(dm);
}
void multires_force_update(Object *ob)
@@ -130,9 +138,9 @@ void multires_force_update(Object *ob)
ob->derivedFinal->release(ob->derivedFinal);
ob->derivedFinal = NULL;
}
if(ob->sculpt && ob->sculpt->pbvh) {
BLI_pbvh_free(ob->sculpt->pbvh);
ob->sculpt->pbvh= NULL;
if(ob->paint && ob->paint->pbvh) {
BLI_pbvh_free(ob->paint->pbvh);
ob->paint->pbvh= NULL;
}
}
}
@@ -324,10 +332,43 @@ static void multires_set_tot_mdisps(Mesh *me, int lvl)
}
}
/* ensure all the layers needed by the gridkey have
a matching multires layer
clear and resize the all griddata to match the level
*/
static void multires_sync_customdata(Mesh *me, GridKey *gridkey,
int lvl)
{
CustomDataMultires *cd_grids;
int i, j;
cd_grids = CustomData_get_layer(&me->fdata, CD_GRIDS);
if(!cd_grids)
cd_grids = CustomData_add_layer(&me->fdata, CD_GRIDS,
CD_CALLOC, NULL, me->totface);
for(i = 0; i < me->totface; ++i) {
int nvert = (me->mface[i].v4)? 4: 3;
int totelem = multires_grid_tot[lvl]*nvert;
cd_grids[i].totelem = totelem;
for(j = 0; j < gridkey->mask; ++j) {
CustomData_multires_sync_layer(cd_grids+i,
CD_PAINTMASK,
gridkey->mask_names[j]);
}
}
}
/* TODO: removed this in favor of sync_customdata */
static void multires_reallocate_mdisps(Mesh *me, MDisps *mdisps, int lvl)
{
int i;
/* This will be replaced when we do CD_DISPS */
/* reallocate displacements to be filled in */
for(i = 0; i < me->totface; ++i) {
int nvert = (me->mface[i].v4)? 4: 3;
@@ -369,23 +410,24 @@ static void multires_copy_grid(float (*gridA)[3], float (*gridB)[3], int sizeA,
}
}
static void multires_copy_dm_grid(DMGridData *gridA, DMGridData *gridB, int sizeA, int sizeB)
static void multires_copy_dm_grid(DMGridData *gridA, DMGridData *gridB, GridKey *gridkey, int sizeA, int sizeB)
{
int x, y, j, skip;
int size = sizeof(float)*GRIDELEM_INTERP_COUNT(gridkey);
if(sizeA > sizeB) {
skip = (sizeA-1)/(sizeB-1);
for(j = 0, y = 0; y < sizeB; y++)
for(x = 0; x < sizeB; x++, j++)
copy_v3_v3(gridA[y*skip*sizeA + x*skip].co, gridB[j].co);
memcpy(GRIDELEM_AT(gridA, y*skip*sizeA + x*skip, gridkey), GRIDELEM_AT(gridB, j, gridkey), size);
}
else {
skip = (sizeB-1)/(sizeA-1);
for(j = 0, y = 0; y < sizeA; y++)
for(x = 0; x < sizeA; x++, j++)
copy_v3_v3(gridA[j].co, gridB[y*skip*sizeB + x*skip].co);
memcpy(GRIDELEM_AT(gridA, j, gridkey), GRIDELEM_AT(gridB, y*skip*sizeB + x*skip, gridkey), size);
}
}
@@ -442,7 +484,9 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire
multires_set_tot_level(ob, mmd, lvl);
}
static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple)
static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm,
GridKey *gridkey, int lvl,
int totlvl, int simple)
{
MultiresModifierData mmd;
@@ -453,13 +497,32 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv
mmd.totlvl = totlvl;
mmd.simple = simple;
return multires_dm_create_from_derived(&mmd, 1, dm, ob, 0, 0);
return multires_dm_create_from_derived(&mmd, 1, dm, ob, gridkey, 0, 0);
}
static DerivedMesh *subsurf_dm_create_local(Object *UNUSED(ob), DerivedMesh *dm, int lvl, int simple, int optimal)
static void init_gridkey_from_customdata(GridKey *gridkey,
CustomData *vdata,
CustomData *UNUSED(fdata))
{
SubsurfModifierData smd;
GRIDELEM_KEY_INIT(gridkey, 1, 0,
CustomData_get_multires_count(vdata, CD_PAINTMASK),
1);
gridkey->mask_names = CustomData_get_multires_names(vdata,
CD_PAINTMASK);
}
static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm,
GridKey *gridkey, int lvl,
int simple, int optimal)
{
DerivedMesh *result;
Mesh *me = get_mesh(ob);
SubsurfModifierData smd;
GridKey default_gridkey;
memset(&default_gridkey, 0, sizeof(GridKey));
memset(&smd, 0, sizeof(SubsurfModifierData));
smd.levels = smd.renderLevels = lvl;
smd.flags |= eSubsurfModifierFlag_SubsurfUv;
@@ -468,7 +531,149 @@ static DerivedMesh *subsurf_dm_create_local(Object *UNUSED(ob), DerivedMesh *dm,
if(optimal)
smd.flags |= eSubsurfModifierFlag_ControlEdges;
return subsurf_make_derived_from_derived(dm, &smd, 0, NULL, 0, 0);
if(!gridkey) {
init_gridkey_from_customdata(&default_gridkey,
&me->vdata, &me->fdata);
gridkey = &default_gridkey;
}
result = subsurf_make_derived_from_derived(dm, &smd, gridkey, 0, NULL, 0, 0);
if(default_gridkey.color_names) MEM_freeN(default_gridkey.color_names);
if(default_gridkey.mask_names) MEM_freeN(default_gridkey.mask_names);
return result;
}
/* assumes no is normalized; return value's sign is negative if v is on
the other side of the plane */
static float v3_dist_from_plane(float v[3], float center[3], float no[3])
{
float s[3];
sub_v3_v3v3(s, v, center);
return dot_v3v3(s, no);
}
void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob)
{
DerivedMesh *cddm, *dispdm, *origdm;
GridKey gridkey;
Mesh *me;
ListBase *fmap;
float (*origco)[3];
int i, j, offset, totlvl;
multires_force_update(ob);
me = get_mesh(ob);
totlvl = mmd->totlvl;
/* only need vert/norm grid data */
GRIDELEM_KEY_INIT(&gridkey, 1, 0, 0, 1);
/* XXX - probably not necessary to regenerate the cddm so much? */
/* generate highest level with displacements */
cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
dispdm = multires_dm_create_local(ob, cddm, &gridkey, totlvl, totlvl, 0);
cddm->release(cddm);
/* copy the new locations of the base verts into the mesh */
offset = dispdm->getNumVerts(dispdm) - me->totvert;
for(i = 0; i < me->totvert; ++i) {
dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co);
}
/* heuristic to produce a better-fitting base mesh */
cddm = CDDM_from_mesh(me, NULL);
fmap = cddm->getFaceMap(ob, cddm);
origco = MEM_callocN(sizeof(float)*3*me->totvert, "multires apply base origco");
for(i = 0; i < me->totvert ;++i)
copy_v3_v3(origco[i], me->mvert[i].co);
for(i = 0; i < me->totvert; ++i) {
IndexNode *n;
float avg_no[3] = {0,0,0}, center[3] = {0,0,0}, push[3];
float dist;
int tot;
/* Don't adjust verts not used by at least one face */
if(!fmap[i].first)
continue;
/* find center */
for(n = fmap[i].first, tot = 0; n; n = n->next) {
MFace *f = &me->mface[n->index];
int S = f->v4 ? 4 : 3;
/* this double counts, not sure if that's bad or good */
for(j = 0; j < S; ++j) {
int vndx = (&f->v1)[j];
if(vndx != i) {
add_v3_v3(center, origco[vndx]);
++tot;
}
}
}
mul_v3_fl(center, 1.0f / tot);
/* find normal */
for(n = fmap[i].first; n; n = n->next) {
MFace *f = &me->mface[n->index];
int S = f->v4 ? 4 : 3;
float v[4][3], no[3];
for(j = 0; j < S; ++j) {
int vndx = (&f->v1)[j];
if(vndx == i)
copy_v3_v3(v[j], center);
else
copy_v3_v3(v[j], origco[vndx]);
}
if(S == 4)
normal_quad_v3(no, v[0], v[1], v[2], v[3]);
else
normal_tri_v3(no, v[0], v[1], v[2]);
add_v3_v3(avg_no, no);
}
normalize_v3(avg_no);
/* push vertex away from the plane */
dist = v3_dist_from_plane(me->mvert[i].co, center, avg_no);
copy_v3_v3(push, avg_no);
mul_v3_fl(push, dist);
add_v3_v3(me->mvert[i].co, push);
}
MEM_freeN(origco);
cddm->release(cddm);
/* subdivide the mesh to highest level without displacements */
cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
origdm = subsurf_dm_create_local(ob, cddm, &gridkey, totlvl, 0, 0);
cddm->release(cddm);
multiresModifier_disp_run(dispdm, me, CALC_DISPS, origdm->getGridData(origdm), totlvl);
origdm->release(origdm);
dispdm->release(dispdm);
}
static DMGridData **copy_grids(DMGridData **grids, int totgrid, int gridsize, GridKey *gridkey)
{
DMGridData **grids_copy = MEM_callocN(sizeof(DMGridData*) * totgrid, "subgrids");
int i;
for(i = 0; i < totgrid; ++i) {
grids_copy[i] = MEM_callocN(GRIDELEM_SIZE(gridkey)*gridsize*gridsize, "subgrid");
memcpy(grids_copy[i], grids[i], GRIDELEM_SIZE(gridkey)*gridsize*gridsize);
}
return grids_copy;
}
void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple)
@@ -493,14 +698,16 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
DMGridData **highGridData, **lowGridData, **subGridData;
CCGSubSurf *ss;
int i, numGrids, highGridSize, lowGridSize;
GridKey *gridkey;
/* create subsurf DM from original mesh at high level */
cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0);
highdm = subsurf_dm_create_local(ob, cddm, NULL, totlvl, simple, 0);
gridkey = highdm->getGridKey(highdm);
/* create multires DM from original mesh at low level */
lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple);
lowdm = multires_dm_create_local(ob, cddm, NULL, lvl, lvl, simple);
cddm->release(cddm);
/* copy subsurf grids and replace them with low displaced grids */
@@ -510,16 +717,12 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
lowGridSize = lowdm->getGridSize(lowdm);
lowGridData = lowdm->getGridData(lowdm);
subGridData = MEM_callocN(sizeof(float*)*numGrids, "subGridData*");
/* backup subsurf grids */
subGridData = copy_grids(highGridData, numGrids, highGridSize, gridkey);
for(i = 0; i < numGrids; ++i) {
/* backup subsurf grids */
subGridData[i] = MEM_callocN(sizeof(DMGridData)*highGridSize*highGridSize, "subGridData");
memcpy(subGridData[i], highGridData[i], sizeof(DMGridData)*highGridSize*highGridSize);
/* overwrite with current displaced grids */
multires_copy_dm_grid(highGridData[i], lowGridData[i], highGridSize, lowGridSize);
}
/* overwrite with current displaced grids */
for(i = 0; i < numGrids; ++i)
multires_copy_dm_grid(highGridData[i], lowGridData[i], gridkey, highGridSize, lowGridSize);
/* low lower level dm no longer needed at this point */
lowdm->release(lowdm);
@@ -531,9 +734,10 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
/* reallocate displacements */
multires_reallocate_mdisps(me, mdisps, totlvl);
multires_sync_customdata(me, gridkey, totlvl);
/* compute displacements */
multiresModifier_disp_run(highdm, me, 1, 0, subGridData, totlvl);
multiresModifier_disp_run(highdm, me, CALC_DISPS, subGridData, totlvl);
/* free */
highdm->release(highdm);
@@ -542,48 +746,107 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
MEM_freeN(subGridData);
}
else {
/* XXX: I think this can be safely removed, we already check in
disp run for unallocated disps -- nicholas */
/* only reallocate, nothing to upsample */
multires_reallocate_mdisps(me, mdisps, totlvl);
//multires_reallocate_mdisps(me, mdisps, totlvl);
}
multires_set_tot_level(ob, mmd, totlvl);
}
static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3])
static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, GridKey *gridkey, float t[3])
{
DMGridData *grid = gridData[index];
if(axis == 0) {
if(x == gridSize - 1) {
if(y == gridSize - 1)
sub_v3_v3v3(t, gridData[index][x + gridSize*(y - 1)].co, gridData[index][x - 1 + gridSize*(y - 1)].co);
sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + gridSize*(y - 1), gridkey), GRIDELEM_CO_AT(grid, x - 1 + gridSize*(y - 1), gridkey));
else
sub_v3_v3v3(t, gridData[index][x + gridSize*y].co, gridData[index][x - 1 + gridSize*y].co);
sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + gridSize*y, gridkey), GRIDELEM_CO_AT(grid, x - 1 + gridSize*y, gridkey));
}
else
sub_v3_v3v3(t, gridData[index][x + 1 + gridSize*y].co, gridData[index][x + gridSize*y].co);
sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + 1 + gridSize*y, gridkey), GRIDELEM_CO_AT(grid, x + gridSize*y, gridkey));
}
else if(axis == 1) {
if(y == gridSize - 1) {
if(x == gridSize - 1)
sub_v3_v3v3(t, gridData[index][x - 1 + gridSize*y].co, gridData[index][x - 1 + gridSize*(y - 1)].co);
sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x - 1 + gridSize*y, gridkey), GRIDELEM_CO_AT(grid, x - 1 + gridSize*(y - 1), gridkey));
else
sub_v3_v3v3(t, gridData[index][x + gridSize*y].co, gridData[index][x + gridSize*(y - 1)].co);
sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + gridSize*y, gridkey), GRIDELEM_CO_AT(grid, x + gridSize*(y - 1), gridkey));
}
else
sub_v3_v3v3(t, gridData[index][x + gridSize*(y + 1)].co, gridData[index][x + gridSize*y].co);
sub_v3_v3v3(t, GRIDELEM_CO_AT(grid, x + gridSize*(y + 1), gridkey), GRIDELEM_CO_AT(grid, x + gridSize*y, gridkey));
}
}
static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl)
#if 0
static void debug_print_paintmask_grids(CustomData *grids, int gridsize)
{
float *pmask;
int x, y;
printf("debug_print_paintmask_grids:\n");
pmask = CustomData_get_layer(grids, CD_PAINTMASK);
for(y = 0; y < gridsize; ++y) {
for(x = 0; x < gridsize; ++x, ++pmask)
printf("%.2f ", *pmask);
printf("\n");
}
printf("\n");
}
#endif
/* XXX - move these to blenlib? */
void add_v4_v4v4(float v[4], float a[4], float b[4])
{
v[0] = a[0] + b[0];
v[1] = a[1] + b[1];
v[2] = a[2] + b[2];
v[3] = a[3] + b[3];
}
void add_v4_v4(float v[4], float a[4])
{
v[0] += a[0];
v[1] += a[1];
v[2] += a[2];
v[3] += a[3];
}
void sub_v4_v4v4(float v[4], float a[4], float b[4])
{
v[0] = a[0] - b[0];
v[1] = a[1] - b[1];
v[2] = a[2] - b[2];
v[3] = a[3] - b[3];
}
void clamp_v4_fl(float v[4], float min, float max)
{
CLAMP(v[0], min, max);
CLAMP(v[1], min, max);
CLAMP(v[2], min, max);
CLAMP(v[3], min, max);
}
static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DispOp op, DMGridData **oldGridData, int totlvl)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)dm;
DMGridData **gridData, **subGridData;
MFace *mface = me->mface;
MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
CustomDataMultires *stored_grids;
int *gridOffset;
GridKey *gridkey;
int i, numGrids, gridSize, dGridSize, dSkip;
if(!mdisps) {
if(invert)
if(op == CALC_DISPS)
mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
else
return;
@@ -594,15 +857,18 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int
gridData = dm->getGridData(dm);
gridOffset = dm->getGridOffset(dm);
subGridData = (oldGridData)? oldGridData: gridData;
gridkey = dm->getGridKey(dm);
dGridSize = multires_side_tot[totlvl];
dSkip = (dGridSize-1)/(gridSize-1);
stored_grids = CustomData_get_layer(&me->fdata, CD_GRIDS);
#pragma omp parallel for private(i) if(me->totface*gridSize*gridSize*4 >= CCG_OMP_LIMIT)
for(i = 0; i < me->totface; ++i) {
const int numVerts = mface[i].v4 ? 4 : 3;
MDisps *mdisp = &mdisps[i];
int S, x, y, gIndex = gridOffset[i];
int S, x, y, j, gIndex = gridOffset[i];
/* when adding new faces in edit mode, need to allocate disps */
if(!mdisp->disps)
@@ -610,56 +876,99 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int
{
multires_reallocate_mdisps(me, mdisps, totlvl);
}
/* XXX: this doesn't cover all the cases */
if((gridkey->mask || gridkey->color) && !stored_grids)
#pragma omp critical
{
multires_sync_customdata(me, gridkey, totlvl);
stored_grids = CustomData_get_layer(&me->fdata, CD_GRIDS);
}
for(S = 0; S < numVerts; ++S, ++gIndex) {
DMGridData *grid = gridData[gIndex];
DMGridData *subgrid = subGridData[gIndex];
float (*dispgrid)[3] = &mdisp->disps[S*dGridSize*dGridSize];
int stored_index = S*dGridSize*dGridSize;
float (*dispgrid)[3] = &mdisp->disps[stored_index];
for(y = 0; y < gridSize; y++) {
for(x = 0; x < gridSize; x++) {
float *co = grid[x + y*gridSize].co;
float *sco = subgrid[x + y*gridSize].co;
float *no = subgrid[x + y*gridSize].no;
float *data = dispgrid[dGridSize*y*dSkip + x*dSkip];
float mat[3][3], tx[3], ty[3], disp[3], d[3];
int ccgdm_offset = x + y*gridSize;
int stored_offset = dGridSize*y*dSkip + x*dSkip;
float *co = GRIDELEM_CO_AT(grid, ccgdm_offset, gridkey);
float *sco = GRIDELEM_CO_AT(subgrid, ccgdm_offset, gridkey);
float *no = GRIDELEM_NO_AT(subgrid, ccgdm_offset, gridkey);
float *data = dispgrid[stored_offset];
float tan_to_ob_mat[3][3], tx[3], ty[3], disp[3], d[3];
/* construct tangent space matrix */
grid_tangent(gridSize, gIndex, x, y, 0, subGridData, tx);
grid_tangent(gridSize, gIndex, x, y, 0, subGridData, gridkey, tx);
normalize_v3(tx);
grid_tangent(gridSize, gIndex, x, y, 1, subGridData, ty);
grid_tangent(gridSize, gIndex, x, y, 1, subGridData, gridkey, ty);
normalize_v3(ty);
//mul_v3_fl(tx, 1.0f/(gridSize-1));
//mul_v3_fl(ty, 1.0f/(gridSize-1));
//cross_v3_v3v3(no, tx, ty);
column_vectors_to_mat3(mat, tx, ty, no);
column_vectors_to_mat3(tan_to_ob_mat, tx, ty, no);
if(!invert) {
/* convert to object space and add */
mul_v3_m3v3(disp, mat, data);
switch(op) {
case APPLY_DISPS:
/* Convert displacement to object space
and add to grid points */
mul_v3_m3v3(disp, tan_to_ob_mat, data);
add_v3_v3v3(co, sco, disp);
}
else if(!add) {
/* convert difference to tangent space */
break;
case CALC_DISPS:
/* Calculate displacement between new and old
grid points and convert to tangent space. */
sub_v3_v3v3(disp, co, sco);
invert_m3(mat);
mul_v3_m3v3(data, mat, disp);
}
else {
/* convert difference to tangent space */
invert_m3(mat);
mul_v3_m3v3(d, mat, co);
invert_m3(tan_to_ob_mat);
mul_v3_m3v3(data, tan_to_ob_mat, disp);
break;
case ADD_DISPS:
/* Convert subdivided displacements to tangent
space and add to the original displacements */
invert_m3(tan_to_ob_mat);
mul_v3_m3v3(d, tan_to_ob_mat, co);
add_v3_v3(data, d);
break;
}
/* Paint Masks */
for(j = 0; j < gridkey->mask; ++j) {
float *mask = &GRIDELEM_MASK_AT(grid, ccgdm_offset, gridkey)[j];
float *smask = &GRIDELEM_MASK_AT(subgrid, ccgdm_offset, gridkey)[j];
float *stored_mask_layer =
CustomData_multires_get_data(&stored_grids[i],
CD_PAINTMASK,
gridkey->mask_names[j]);
float *stored_mask = &stored_mask_layer[stored_index];
switch(op) {
case APPLY_DISPS:
*mask = *smask + stored_mask[stored_offset];
break;
case CALC_DISPS:
stored_mask[stored_offset] = *mask - *smask;
CLAMP(stored_mask[stored_offset], 0, 1);
break;
case ADD_DISPS:
stored_mask[stored_offset] += *mask;
CLAMP(stored_mask[stored_offset], 0, 1);
break;
}
}
}
}
}
}
if(!invert) {
if(op == APPLY_DISPS) {
ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0);
ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0);
}
@@ -672,6 +981,7 @@ static void multiresModifier_update(DerivedMesh *dm)
Mesh *me;
MDisps *mdisps;
MultiresModifierData *mmd;
GridKey *gridkey;
ob = ccgdm->multires.ob;
me = ccgdm->multires.ob->data;
@@ -680,6 +990,10 @@ static void multiresModifier_update(DerivedMesh *dm)
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
/* use the same gridkey as the dm so that we don't try
to update layers that didn't exist before */
gridkey = dm->getGridKey(dm);
if(mdisps) {
int lvl = ccgdm->multires.lvl;
int totlvl = ccgdm->multires.totlvl;
@@ -696,10 +1010,10 @@ static void multiresModifier_update(DerivedMesh *dm)
else cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0);
highdm = subsurf_dm_create_local(ob, cddm, gridkey, totlvl, mmd->simple, 0);
/* create multires DM from original mesh and displacements */
lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple);
lowdm = multires_dm_create_local(ob, cddm, gridkey, lvl, totlvl, mmd->simple);
cddm->release(cddm);
/* gather grid data */
@@ -710,19 +1024,20 @@ static void multiresModifier_update(DerivedMesh *dm)
lowGridData = lowdm->getGridData(lowdm);
gridData = dm->getGridData(dm);
subGridData = MEM_callocN(sizeof(DMGridData*)*numGrids, "subGridData*");
diffGrid = MEM_callocN(sizeof(DMGridData)*lowGridSize*lowGridSize, "diff");
/* backup subsurf grids */
subGridData = copy_grids(highGridData, numGrids, highGridSize, gridkey);
diffGrid = MEM_callocN(GRIDELEM_SIZE(gridkey)*lowGridSize*lowGridSize, "diff");
/* write difference of subsurf and displaced low level into high subsurf */
for(i = 0; i < numGrids; ++i) {
/* backup subsurf grids */
subGridData[i] = MEM_callocN(sizeof(DMGridData)*highGridSize*highGridSize, "subGridData");
memcpy(subGridData[i], highGridData[i], sizeof(DMGridData)*highGridSize*highGridSize);
for(j = 0; j < lowGridSize*lowGridSize; ++j) {
int k;
for(k = 0; k < GRIDELEM_INTERP_COUNT(gridkey); ++k)
((float*)GRIDELEM_AT(diffGrid, j, gridkey))[k] = ((float*)GRIDELEM_AT(gridData[i], j, gridkey))[k] - ((float*)GRIDELEM_AT(lowGridData[i], j, gridkey))[k];
}
/* write difference of subsurf and displaced low level into high subsurf */
for(j = 0; j < lowGridSize*lowGridSize; ++j)
sub_v3_v3v3(diffGrid[j].co, gridData[i][j].co, lowGridData[i][j].co);
multires_copy_dm_grid(highGridData[i], diffGrid, highGridSize, lowGridSize);
multires_copy_dm_grid(highGridData[i], diffGrid, gridkey, highGridSize, lowGridSize);
}
/* lower level dm no longer needed at this point */
@@ -735,7 +1050,7 @@ static void multiresModifier_update(DerivedMesh *dm)
ccgSubSurf_updateLevels(ss, lvl, NULL, 0);
/* add to displacements */
multiresModifier_disp_run(highdm, me, 1, 1, subGridData, mmd->totlvl);
multiresModifier_disp_run(highdm, me, ADD_DISPS, subGridData, mmd->totlvl);
/* free */
highdm->release(highdm);
@@ -750,10 +1065,10 @@ static void multiresModifier_update(DerivedMesh *dm)
else cddm = CDDM_from_mesh(me, NULL);
DM_set_only_copy(cddm, CD_MASK_BAREMESH);
subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0);
subdm = subsurf_dm_create_local(ob, cddm, gridkey, mmd->totlvl, mmd->simple, 0);
cddm->release(cddm);
multiresModifier_disp_run(dm, me, 1, 0, subdm->getGridData(subdm), mmd->totlvl);
multiresModifier_disp_run(dm, me, CALC_DISPS, subdm->getGridData(subdm), mmd->totlvl);
subdm->release(subdm);
}
@@ -762,8 +1077,15 @@ static void multiresModifier_update(DerivedMesh *dm)
void multires_stitch_grids(Object *ob)
{
/* utility for smooth brush */
if(ob && ob->derivedFinal) {
DerivedMesh *dm;
if(!ob)
return;
dm = ob->derivedFinal;
/* utility for smooth/blur brushes */
if(dm && dm->type == DM_TYPE_CCGDM) {
CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)ob->derivedFinal;
CCGFace **faces;
int totface;
@@ -772,6 +1094,7 @@ void multires_stitch_grids(Object *ob)
BLI_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void***)&faces, &totface);
if(totface) {
/* TODO: could improve performance by limiting to e.g. just coords or just colors */
ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface);
MEM_freeN(faces);
}
@@ -780,7 +1103,7 @@ void multires_stitch_grids(Object *ob)
}
DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int local_mmd, DerivedMesh *dm, Object *ob,
int useRenderParams, int UNUSED(isFinalCalc))
GridKey *gridkey, int useRenderParams, int UNUSED(isFinalCalc))
{
Mesh *me= ob->data;
DerivedMesh *result;
@@ -792,7 +1115,7 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca
if(lvl == 0)
return dm;
result = subsurf_dm_create_local(ob, dm, lvl,
result = subsurf_dm_create_local(ob, dm, gridkey, lvl,
mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges);
if(!local_mmd) {
@@ -810,17 +1133,19 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca
numGrids = result->getNumGrids(result);
gridSize = result->getGridSize(result);
gridData = result->getGridData(result);
/* null gridkey can be passed in, so update it here */
gridkey = result->getGridKey(result);
subGridData = MEM_callocN(sizeof(DMGridData*)*numGrids, "subGridData*");
for(i = 0; i < numGrids; i++) {
subGridData[i] = MEM_callocN(sizeof(DMGridData)*gridSize*gridSize, "subGridData");
memcpy(subGridData[i], gridData[i], sizeof(DMGridData)*gridSize*gridSize);
subGridData[i] = MEM_callocN(GRIDELEM_SIZE(gridkey)*gridSize*gridSize, "subGridData");
memcpy(subGridData[i], gridData[i], GRIDELEM_SIZE(gridkey)*gridSize*gridSize);
}
multires_set_tot_mdisps(me, mmd->totlvl);
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
multiresModifier_disp_run(result, ob->data, 0, 0, subGridData, mmd->totlvl);
multiresModifier_disp_run(result, ob->data, APPLY_DISPS, subGridData, mmd->totlvl);
for(i = 0; i < numGrids; i++)
MEM_freeN(subGridData[i]);
@@ -829,6 +1154,7 @@ DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int loca
return result;
}
/**** Old Multires code ****
***************************/
@@ -1109,13 +1435,13 @@ static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
vd= ccgSubSurf_getFaceCenterData(f);
copy_v3_v3(vd->co, mvert[i].co);
copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
i++;
for(S = 0; S < numVerts; S++) {
for(x = 1; x < gridSize - 1; x++, i++) {
vd= ccgSubSurf_getFaceGridEdgeData(ss, f, S, x);
copy_v3_v3(vd->co, mvert[i].co);
copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
}
}
@@ -1123,7 +1449,7 @@ static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
for(y = 1; y < gridSize - 1; y++) {
for(x = 1; x < gridSize - 1; x++, i++) {
vd= ccgSubSurf_getFaceGridData(ss, f, S, x, y);
copy_v3_v3(vd->co, mvert[i].co);
copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
}
}
}
@@ -1136,7 +1462,7 @@ static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
for(x = 1; x < edgeSize - 1; x++, i++) {
vd= ccgSubSurf_getEdgeData(ss, e, x);
copy_v3_v3(vd->co, mvert[i].co);
copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
}
}
@@ -1145,7 +1471,7 @@ static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
CCGVert *v = ccgdm->vertMap[index].vert;
vd= ccgSubSurf_getVertData(ss, v);
copy_v3_v3(vd->co, mvert[i].co);
copy_v3_v3(GRIDELEM_CO(vd, gridkey), mvert[i].co);
i++;
}
@@ -1364,7 +1690,7 @@ void multires_load_old(Object *ob, Mesh *me)
mmd->lvl = mmd->totlvl;
orig = CDDM_from_mesh(me, NULL);
dm = multires_dm_create_from_derived(mmd, 0, orig, ob, 0, 0);
dm = multires_dm_create_from_derived(mmd, 0, orig, ob, NULL, 0, 0);
multires_load_old_dm(dm, me, mmd->totlvl+1);

View File

@@ -228,29 +228,6 @@ void object_free_display(Object *ob)
freedisplist(&ob->disp);
}
void free_sculptsession(Object *ob)
{
if(ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
DerivedMesh *dm= ob->derivedFinal;
if(ss->pbvh)
BLI_pbvh_free(ss->pbvh);
if(dm && dm->getPBVH)
dm->getPBVH(NULL, dm); /* signal to clear */
if(ss->texcache)
MEM_freeN(ss->texcache);
if(ss->layer_co)
MEM_freeN(ss->layer_co);
MEM_freeN(ss);
ob->sculpt = NULL;
}
}
/* do not free object itself */
void free_object(Object *ob)
{
@@ -305,7 +282,7 @@ void free_object(Object *ob)
if(ob->bsoft) bsbFree(ob->bsoft);
if(ob->gpulamp.first) GPU_lamp_free(ob);
free_sculptsession(ob);
free_paintsession(ob);
if(ob->pc_ids.first) BLI_freelistN(&ob->pc_ids);
}
@@ -1319,7 +1296,7 @@ Object *copy_object(Object *ob)
copy_constraints(&obn->constraints, &ob->constraints, TRUE);
obn->mode = 0;
obn->sculpt = NULL;
obn->paint = NULL;
/* increase user numbers */
id_us_plus((ID *)obn->data);

View File

@@ -25,6 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
@@ -33,9 +34,16 @@
#include "BKE_utildefines.h"
#include "BKE_brush.h"
#include "BKE_DerivedMesh.h"
#include "BKE_dmgrid.h"
#include "BKE_library.h"
#include "BKE_paint.h"
#include "BKE_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_pbvh.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -110,3 +118,104 @@ void copy_paint(Paint *src, Paint *tar)
{
tar->brush= src->brush;
}
/* Update the mask without doing a full object recalc */
void paint_refresh_mask_display(Object *ob)
{
if(ob && ob->paint && ob->paint->pbvh) {
BLI_pbvh_search_callback(ob->paint->pbvh, NULL, NULL,
BLI_pbvh_node_set_flags,
SET_INT_IN_POINTER(PBVH_UpdateColorBuffers));
}
}
float paint_mask_from_gridelem(DMGridData *elem, GridKey *gridkey,
CustomData *vdata)
{
CustomDataLayer *cdl;
float mask = 0;
int i, ndx;
for(i=0; i < gridkey->mask; ++i) {
ndx = CustomData_get_named_layer_index(vdata,
CD_PAINTMASK,
gridkey->mask_names[i]);
cdl = &vdata->layers[ndx];
if(!(cdl->flag & CD_FLAG_ENABLED))
continue;
mask += GRIDELEM_MASK(elem, gridkey)[i] * cdl->strength;
}
CLAMP(mask, 0, 1);
return mask;
}
float paint_mask_from_vertex(CustomData *vdata, int vertex_index,
int pmask_totlayer, int pmask_first_layer)
{
float mask = 0;
int i;
for(i = 0; i < pmask_totlayer; ++i) {
CustomDataLayer *cdl= vdata->layers + pmask_first_layer + i;
if(!(cdl->flag & CD_FLAG_ENABLED))
continue;
mask += ((float*)cdl->data)[vertex_index] * cdl->strength;
}
CLAMP(mask, 0, 1);
return mask;
}
void create_paintsession(Object *ob)
{
if(ob->paint)
free_paintsession(ob);
ob->paint = MEM_callocN(sizeof(PaintSession), "PaintSession");
}
static void free_sculptsession(PaintSession *ps)
{
if(ps && ps->sculpt) {
SculptSession *ss = ps->sculpt;
BLI_freelistN(&ss->hidden_areas);
if(ss->texcache)
MEM_freeN(ss->texcache);
if(ss->layer_co)
MEM_freeN(ss->layer_co);
MEM_freeN(ss);
ps->sculpt = NULL;
}
}
void free_paintsession(Object *ob)
{
if(ob && ob->paint) {
PaintSession *ps = ob->paint;
DerivedMesh *dm= ob->derivedFinal;
free_sculptsession(ps);
if(ps->pbvh)
BLI_pbvh_free(ps->pbvh);
if(dm && dm->getPBVH)
dm->getPBVH(NULL, dm); /* signal to clear PBVH */
MEM_freeN(ps);
ob->paint = NULL;
}
}

View File

@@ -0,0 +1,445 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2010 by Nicholas Bishop
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "MEM_guardedalloc.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "BKE_DerivedMesh.h"
#include "BKE_dmgrid.h"
#include "BKE_mesh.h"
#include "BKE_subsurf.h"
#include "BLI_math.h"
#include "ptex.h"
#include <assert.h>
DerivedMesh *quad_dm_create_from_derived(DerivedMesh *dm)
{
DerivedMesh *ccgdm;
SubsurfModifierData smd;
GridKey gridkey;
memset(&smd, 0, sizeof(SubsurfModifierData));
smd.levels = 1;
smd.subdivType = ME_SIMPLE_SUBSURF;
GRIDELEM_KEY_INIT(&gridkey, 1, 0, 0, 1);
ccgdm = subsurf_make_derived_from_derived(dm, &smd, &gridkey,
0, NULL, 0, 0);
return ccgdm;
}
void ptex_elem_to_floats(int type, int channels, void *data, float *out)
{
int i;
switch(type) {
case PTEX_DT_UINT8:
for(i = 0; i < channels; ++i)
out[i] = ((unsigned char*)data)[i] / 255.0;
break;
case PTEX_DT_UINT16:
for(i = 0; i < channels; ++i)
out[i] = ((unsigned char*)data)[i] / 65535.0;
break;
case PTEX_DT_FLOAT:
for(i = 0; i < channels; ++i)
out[i] = ((float*)data)[i];
break;
default:
break;
}
}
void ptex_elem_from_floats(int type, int channels, void *data, float *in)
{
int i;
switch(type) {
case PTEX_DT_UINT8:
for(i = 0; i < channels; ++i)
((unsigned char*)data)[i] = in[i] * 255;
break;
case PTEX_DT_UINT16:
for(i = 0; i < channels; ++i)
((unsigned short*)data)[i] = in[i] * 65535;
break;
case PTEX_DT_FLOAT:
for(i = 0; i < channels; ++i)
((float*)data)[i] = in[i];
break;
default:
break;
}
}
static void ptex_elem_to_floats_mul_add(MPtex *pt, void *data, float *out, float fac)
{
int i;
switch(pt->type) {
case PTEX_DT_UINT8:
for(i = 0; i < pt->channels; ++i)
out[i] += (((unsigned char*)data)[i] / 255.0) * fac;
break;
case PTEX_DT_UINT16:
for(i = 0; i < pt->channels; ++i)
out[i] += (((unsigned char*)data)[i] / 65535.0) * fac;
break;
case PTEX_DT_FLOAT:
for(i = 0; i < pt->channels; ++i)
out[i] += ((float*)data)[i] * fac;
break;
default:
break;
}
}
/* get interpolated value for one texel */
static void ptex_bilinear_interp(MPtex *pt, MPtexSubface *subface,
void *out, int layersize,
float x, float y, float *tmp)
{
char *input_start = subface->data;
int rowlen = subface->res[0];
int xi = (int)x;
int yi = (int)y;
int xt = xi+1, yt = yi+1;
float s = x - xi;
float t = y - yi;
float u = 1 - s;
float v = 1 - t;
if(xt == subface->res[0])
--xt;
if(yt == subface->res[1])
--yt;
memset(tmp, 0, sizeof(float)*pt->channels);
ptex_elem_to_floats_mul_add(pt, input_start + layersize * (yi*rowlen+xi), tmp, u*v);
ptex_elem_to_floats_mul_add(pt, input_start + layersize * (yi*rowlen+xt), tmp, s*v);
ptex_elem_to_floats_mul_add(pt, input_start + layersize * (yt*rowlen+xt), tmp, s*t);
ptex_elem_to_floats_mul_add(pt, input_start + layersize * (yt*rowlen+xi), tmp, u*t);
ptex_elem_from_floats(pt->type, pt->channels, out, tmp);
}
/* interpolate subface to new resolution */
void ptex_subface_scale(MPtex *pt, MPtexSubface *subface, int ures, int vres)
{
float ui, vi, ui_step, vi_step;
float *tmp;
char *new_data, *new_data_start;
int u, v, layersize;
layersize = pt->channels * ptex_data_size(pt->type);
new_data_start = new_data =
MEM_callocN(layersize * ures * vres, "ptex_subface_scale.new_data");
/* tmp buffer used in interpolation */
tmp = MEM_callocN(sizeof(float) * pt->channels, "ptex_subface_scale.tmp");
ui_step = subface->res[0] / (float)ures;
vi_step = subface->res[1] / (float)vres;
for(v = 0, vi = 0; v < vres; ++v, vi += vi_step) {
for(u = 0, ui = 0; u < ures; ++u, ui += ui_step, new_data += layersize) {
ptex_bilinear_interp(pt, subface, new_data, layersize, ui, vi, tmp);
}
}
MEM_freeN(subface->data);
subface->data = new_data_start;
subface->res[0] = ures;
subface->res[1] = vres;
MEM_freeN(tmp);
}
/* copy data to/from ptex file format and internal MPtex format */
static void ptex_transfer_filedata(MPtex *pt, int offset, char *file_data_start, int from_file)
{
char *mptex_data, *file_data;
char **src, **dest;
int file_res[2], file_half_res[2];
int i, u, v, layersize;
layersize = pt->channels * ptex_data_size(pt->type);
if(pt->totsubface == 4) {
file_res[0] = pt->subfaces[1].res[0] << 1;
file_res[1] = pt->subfaces[1].res[1] << 1;
}
else {
file_res[0] = pt->subfaces[offset].res[1];
file_res[1] = pt->subfaces[offset].res[0];
}
file_half_res[0] = file_res[0] >> 1;
file_half_res[1] = file_res[1] >> 1;
if(from_file) {
src = &file_data;
dest = &mptex_data;
}
else {
src = &mptex_data;
dest = &file_data;
}
if(pt->totsubface == 4) {
/* save quad subfaces as one face */
for(i = 0; i < 4; ++i) {
MPtexSubface *subface = &pt->subfaces[i];
int file_center_offset[2], file_step, file_row_step;
switch(i) {
case 0:
file_center_offset[0] = -1;
file_center_offset[1] = -1;
file_step = -file_res[0];
file_row_step = file_res[0] * file_half_res[1] - 1;
break;
case 1:
file_center_offset[0] = 0;
file_center_offset[1] = -1;
file_step = 1;
file_row_step = -file_res[0] - file_half_res[0];
break;
case 2:
file_center_offset[0] = 0;
file_center_offset[1] = 0;
file_step = file_res[0];
file_row_step = -file_res[0] * file_half_res[1] + 1;
break;
case 3:
file_center_offset[0] = -1;
file_center_offset[1] = 0;
file_step = -1;
file_row_step = file_res[0] + file_half_res[0];
break;
}
mptex_data = subface->data;
file_data = file_data_start +
layersize * (file_res[0] * (file_half_res[1]+file_center_offset[1]) +
file_half_res[0]+file_center_offset[0]);
for(v = 0; v < subface->res[1]; ++v) {
for(u = 0; u < subface->res[0]; ++u) {
memcpy(*dest, *src, layersize);
mptex_data += layersize;
file_data += layersize * file_step;
}
file_data += layersize * file_row_step;
}
}
}
else {
mptex_data = pt->subfaces[offset].data;
file_data = file_data_start;
for(v = 0; v < file_res[1]; ++v) {
for(u = 0; u < file_res[0]; ++u) {
mptex_data = (char*)pt->subfaces[offset].data +
layersize * ((file_res[0] - u - 1) * file_res[1] +
(file_res[1] - v - 1));
file_data = file_data_start + layersize * (v*file_res[0]+u);
memcpy(*dest, *src, layersize);
}
}
}
}
/* creates a new CD_MPTEX layer and loads ptex_texture into it */
void ptex_layer_from_file(Mesh *me, PtexTextureHandle *ptex_texture)
{
MPtex *mptex;
PtexDataType ptex_data_type;
int channels;
int i, j, layersize, active_offset;
channels = ptex_texture_num_channels(ptex_texture);
ptex_data_type = ptex_texture_data_type(ptex_texture);
/* number of bytes for one ptex element */
layersize = ptex_data_size(ptex_data_type) * channels;
active_offset = CustomData_number_of_layers(&me->fdata, CD_MPTEX);
mptex = CustomData_add_layer(&me->fdata, CD_MPTEX, CD_CALLOC,
NULL, me->totface);
CustomData_set_layer_active(&me->fdata, CD_MPTEX, active_offset);
for(i = 0, j = 0; i < me->totface; ++i) {
int S = me->mface[i].v4 ? 4 : 3;
int k, file_totsubface;
mptex[i].type = ptex_data_type;
mptex[i].channels = channels;
mptex[i].totsubface = S;
/* quads don't have subfaces in ptex files */
file_totsubface = (S==4)? 1 : S;
for(k = 0; k < file_totsubface; ++k) {
PtexFaceInfoHandle *ptex_face;
PtexResHandle *ptex_res;
int l, file_res[2], file_half_res[2], faceid;
char *filedata;
faceid = j+k;
ptex_face = ptex_texture_get_face_info(ptex_texture, faceid);
ptex_res = ptex_face_info_get_res(ptex_face);
file_res[0] = ptex_res_u(ptex_res);
file_res[1] = ptex_res_v(ptex_res);
file_half_res[0] = file_res[0] >> 1;
file_half_res[1] = file_res[1] >> 1;
filedata = MEM_callocN(layersize * file_res[0] * file_res[1], "Ptex data from file");
ptex_texture_get_data(ptex_texture, faceid, filedata, 0, ptex_res);
/* allocate mem for ptex data, set subface resolutions */
if(S==4) {
int ures, vres;
/* use quarter resolution for quad subfaces */
ures = file_half_res[0];
vres = file_half_res[1];
/* TODO: handle 1xV and Ux1 inputs */
assert(ures > 0 && vres > 0);
for(l = 0; l < 4; ++l) {
SWAP(int, ures, vres);
mptex[i].subfaces[l].res[0] = ures;
mptex[i].subfaces[l].res[1] = vres;
mptex[i].subfaces[l].data =
MEM_callocN(layersize * ures * vres,
"Ptex quad data from file");
}
}
else {
mptex[i].subfaces[k].res[0] = file_res[1];
mptex[i].subfaces[k].res[1] = file_res[0];
mptex[i].subfaces[k].data =
MEM_callocN(layersize * file_res[0] * file_res[1],
"Ptex tri data from file");
}
ptex_transfer_filedata(&mptex[i], k, filedata, 1);
MEM_freeN(filedata);
}
j += file_totsubface;
}
/* data is all copied, can release ptex file */
ptex_texture_release(ptex_texture);
}
int ptex_layer_save_file(struct Mesh *me, const char *filename)
{
MPtex *mptex;
PtexWriterHandle *ptex_writer;
char *file_data;
int i, j, totface, faceid;
mptex = CustomData_get_layer(&me->fdata, CD_MPTEX);
for(i = 0, totface = 0; i < me->totface; ++i)
totface += (me->mface[i].v4 ? 4 : 3);
ptex_writer = ptex_writer_open(filename, mptex->type, mptex->channels, 0, totface, 1);
if(!ptex_writer)
return -1;
for(i = 0, faceid = 0; i < me->totface; ++i, ++mptex) {
PtexFaceInfoHandle *face_info;
int adjfaces[4] = {0,0,0,0}, adjedges[4] = {0,0,0,0};
int layersize;
layersize = ptex_data_size(mptex->type) * mptex->channels;
/* TODO: adjacency data (needed for filtering) */
if(mptex->totsubface == 4) {
int res[2];
res[0] = mptex->subfaces[1].res[0]*2;
res[1] = mptex->subfaces[1].res[1]*2;
file_data = MEM_callocN(res[0] * res[1] * layersize,
"mptex save quad data");
ptex_transfer_filedata(mptex, 0, file_data, 0);
face_info = ptex_face_info_new(res[0], res[1],
adjfaces, adjedges, 0);
ptex_writer_write_face(ptex_writer, faceid, face_info, file_data, 0);
faceid += 1;
MEM_freeN(file_data);
}
else if(mptex->totsubface == 3) {
for(j = 0; j < mptex->totsubface; ++j, ++faceid) {
MPtexSubface *subface = &mptex->subfaces[j];
file_data =
MEM_callocN(subface->res[0] * subface->res[1] * layersize,
"mptex save subface data");
ptex_transfer_filedata(mptex, j, file_data, 0);
face_info = ptex_face_info_new(subface->res[1],
subface->res[0],
adjfaces, adjedges, 1);
ptex_writer_write_face(ptex_writer, faceid, face_info,
file_data, 0);
MEM_freeN(file_data);
}
}
}
ptex_writer_release(ptex_writer);
return 0;
}

View File

@@ -564,7 +564,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Scene *scene, Object
ssmd.subdivType = ME_CC_SUBSURF; //catmull clark
ssmd.levels = smd->subsurfLevels; //levels
ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, FALSE, NULL, 0, 0);
ss_mesh = subsurf_make_derived_from_derived(dm, &ssmd, NULL, FALSE, NULL, 0, 0);
if(ss_mesh)
{

File diff suppressed because it is too large Load Diff

View File

@@ -69,6 +69,8 @@
#include "BKE_node.h"
#include "BKE_animsys.h"
#include "RE_shader_ext.h"
/* ------------------------------------------------------------------------- */
@@ -1348,3 +1350,20 @@ int BKE_texture_dependsOnTime(const struct Tex *texture)
}
/* ------------------------------------------------------------------------- */
void get_texture_value(Tex *texture, float *tex_co, TexResult *texres)
{
int result_type;
result_type = multitex_ext(texture, tex_co, NULL, NULL, 0, texres);
/* if the texture gave an RGB value, we assume it didn't give a valid
* intensity, so calculate one (formula from do_material_tex).
* if the texture didn't give an RGB value, copy the intensity across
*/
if(result_type & TEX_RGB)
texres->tin = (0.35f * texres->tr + 0.45f * texres->tg
+ 0.2f * texres->tb);
else
texres->tr = texres->tg = texres->tb = texres->tin;
}

View File

@@ -40,6 +40,8 @@ extern "C" {
#include <stdlib.h>
#include <string.h>
#include "MEM_guardedalloc.h"
#include "BKE_utildefines.h"
#include "BLI_mempool.h"

View File

@@ -96,7 +96,6 @@ int isect_ray_tri_epsilon_v3(float p1[3], float d[3],
float v0[3], float v1[3], float v2[3], float *lambda, float *uv, float epsilon);
/* point in polygon */
int isect_point_tri_v2(float p[2], float a[2], float b[2], float c[2]);
int isect_point_quad_v2(float p[2], float a[2], float b[2], float c[2], float d[2]);
int isect_point_tri_v2(float v1[2], float v2[2], float v3[2], float pt[2]);

View File

@@ -25,17 +25,29 @@
#ifndef BLI_PBVH_H
#define BLI_PBVH_H
#include <assert.h>
struct BoundBox;
struct CustomData;
struct MFace;
struct MVert;
struct GridKey;
struct DMGridAdjacency;
struct DMGridData;
struct PBVH;
struct PBVHNode;
struct GridToFace;
struct ListBase;
typedef struct PBVH PBVH;
typedef struct PBVHNode PBVHNode;
typedef struct PBVHHiddenArea {
struct PBVHHiddenArea *next, *prev;
float clip_planes[4][4];
int hide_inside;
} HiddenArea;
typedef struct {
float (*co)[3];
} PBVHProxyNode;
@@ -48,14 +60,26 @@ typedef int (*BLI_pbvh_SearchCallback)(PBVHNode *node, void *data);
typedef void (*BLI_pbvh_HitCallback)(PBVHNode *node, void *data);
typedef void (*BLI_pbvh_HitOccludedCallback)(PBVHNode *node, void *data, float* tmin);
/* Building */
/* test AABB against sphere */
typedef struct {
float *center;
float radius_squared;
int original;
} PBVHSearchSphereData;
int BLI_pbvh_search_sphere_cb(PBVHNode *node, void *data);
PBVH *BLI_pbvh_new(void);
/* Building */
#define PBVH_DEFAULT_LEAF_LIMIT 10000
PBVH *BLI_pbvh_new(int leaf_limit);
void BLI_pbvh_build_mesh(PBVH *bvh, struct MFace *faces, struct MVert *verts,
int totface, int totvert);
struct CustomData *vdata, struct CustomData *fdata,
int totface, int totvert, ListBase *hidden_areas);
void BLI_pbvh_build_grids(PBVH *bvh, struct DMGridData **grids,
struct DMGridAdjacency *gridadj, int totgrid,
int gridsize, void **gridfaces);
struct DMGridAdjacency *gridadj, int totgrid,
int gridsize, struct GridKey *gridkey, void **gridfaces,
struct GridToFace *grid_face_map,
struct CustomData *vdata, struct CustomData *fdata,
ListBase *hidden_areas);
void BLI_pbvh_free(PBVH *bvh);
/* Hierarchical Search in the BVH, two methods:
@@ -78,13 +102,14 @@ void BLI_pbvh_search_gather(PBVH *bvh,
void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data,
float ray_start[3], float ray_normal[3], int original);
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
float ray_start[3], float ray_normal[3], float *dist);
float ray_start[3], float ray_normal[3], float *dist,
int *hit_index, int *grid_hit_index);
/* Drawing */
void BLI_pbvh_node_draw(PBVHNode *node, void *data);
int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data);
void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int smooth);
void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int flags);
/* Node Access */
@@ -94,19 +119,44 @@ typedef enum {
PBVH_UpdateNormals = 2,
PBVH_UpdateBB = 4,
PBVH_UpdateOriginalBB = 8,
PBVH_UpdateDrawBuffers = 16,
PBVH_UpdateRedraw = 32
/* Update vertex data (coord + normal */
PBVH_UpdateVertBuffers = 16,
/* Update color data (used for masks) */
PBVH_UpdateColorBuffers = 32,
PBVH_UpdateRedraw = 64,
PBVH_UpdateAll = PBVH_UpdateNormals |
PBVH_UpdateBB |
PBVH_UpdateOriginalBB |
PBVH_UpdateVertBuffers |
PBVH_UpdateColorBuffers |
PBVH_UpdateRedraw,
} PBVHNodeFlags;
void BLI_pbvh_node_mark_update(PBVHNode *node);
void BLI_pbvh_node_set_flags(PBVHNode *node, void *data);
/* returns true if the pbvh is using grids rather than faces */
int BLI_pbvh_uses_grids(PBVH *bvh);
void BLI_pbvh_get_customdata(PBVH *pbvh, struct CustomData **vdata, struct CustomData **fdata);
struct GridToFace *BLI_pbvh_get_grid_face_map(PBVH *pbvh);
void BLI_pbvh_node_get_faces(PBVH *bvh, PBVHNode *node,
struct MFace **faces,
int **face_indices, int **face_vert_indices,
int *totface);
void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node,
int **grid_indices, int *totgrid, int *maxgrid, int *gridsize,
struct DMGridData ***griddata, struct DMGridAdjacency **gridadj);
struct DMGridData ***griddata, struct DMGridAdjacency **gridadj,
struct GridKey **gridkey);
void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node,
int *uniquevert, int *totvert);
void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node,
int **vert_indices, struct MVert **verts);
int **vert_indices, struct MVert **verts);
void BLI_pbvh_node_get_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
void BLI_pbvh_node_get_original_BB(PBVHNode *node, float bb_min[3], float bb_max[3]);
@@ -119,7 +169,7 @@ void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface);
void BLI_pbvh_grids_update(PBVH *bvh, struct DMGridData **grids,
struct DMGridAdjacency *gridadj, void **gridfaces);
struct DMGridAdjacency *gridadj, void **gridfaces, struct GridKey *gridkey);
/* vertex deformer */
float (*BLI_pbvh_get_vertCos(struct PBVH *pbvh))[3];
@@ -148,22 +198,30 @@ typedef struct PBVHVertexIter {
/* grid */
struct DMGridData **grids;
struct DMGridData *grid;
struct DMGridData *grid, *elem;
int *grid_indices;
int totgrid;
int gridsize;
struct GridKey *gridkey;
/* mesh */
struct MVert *mverts;
int totvert;
int *vert_indices;
/* mask layers */
struct CustomData *vdata;
int pmask_first_layer, pmask_layer_count, pmask_active_layer;
/* result: these are all computed in the macro, but we assume
that compiler optimizations will skip the ones we don't use */
struct MVert *mvert;
float *co;
short *no;
float *fno;
float *mask_active;
float mask_combined; /* not editable */
} PBVHVertexIter;
#ifdef _MSC_VER
@@ -175,21 +233,20 @@ typedef struct PBVHVertexIter {
struct DMGridData **grids; \
struct MVert *verts; \
int *grid_indices, totgrid, gridsize, *vert_indices, uniq_verts, totvert; \
struct GridKey *gridkey; \
\
vi.grid= 0; \
vi.no= 0; \
vi.fno= 0; \
vi.mvert= 0; \
vi.skip= 0; \
memset(&vi, 0, sizeof(PBVHVertexIter)); \
\
BLI_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL); \
BLI_pbvh_node_get_grids(bvh, node, &grid_indices, &totgrid, NULL, &gridsize, &grids, NULL, &gridkey); \
BLI_pbvh_node_num_verts(bvh, node, &uniq_verts, &totvert); \
BLI_pbvh_node_get_verts(bvh, node, &vert_indices, &verts); \
BLI_pbvh_get_customdata(bvh, &vi.vdata, NULL); \
\
vi.grids= grids; \
vi.grid_indices= grid_indices; \
vi.totgrid= (grids)? totgrid: 1; \
vi.gridsize= gridsize; \
vi.gridkey= gridkey; \
\
if(mode == PBVH_ITER_ALL) \
vi.totvert = totvert; \
@@ -197,6 +254,16 @@ typedef struct PBVHVertexIter {
vi.totvert= uniq_verts; \
vi.vert_indices= vert_indices; \
vi.mverts= verts; \
vi.mask_active= NULL; \
assert(!gridkey || gridkey->mask == 0 || vi.vdata); \
vi.pmask_layer_count = CustomData_number_of_layers(vi.vdata, CD_PAINTMASK); \
assert(!gridkey || gridkey->mask == 0 || gridkey->mask == vi.pmask_layer_count); \
if(vi.pmask_layer_count) { \
vi.pmask_first_layer = CustomData_get_layer_index(vi.vdata, CD_PAINTMASK); \
vi.pmask_active_layer = CustomData_get_active_layer_index(vi.vdata, CD_PAINTMASK); \
if(vi.pmask_active_layer != -1 && !(vi.vdata->layers[vi.pmask_active_layer].flag & CD_FLAG_ENABLED)) \
vi.pmask_active_layer = -1; \
} \
}\
\
for(vi.i=0, vi.g=0; vi.g<vi.totgrid; vi.g++) { \
@@ -218,24 +285,45 @@ typedef struct PBVHVertexIter {
} \
\
for(vi.gy=0; vi.gy<vi.height; vi.gy++) { \
if(vi.grid) vi.grid += vi.skip; \
if(vi.grid) GRIDELEM_INC(vi.grid, vi.skip, vi.gridkey); \
\
for(vi.gx=0; vi.gx<vi.width; vi.gx++, vi.i++) { \
if(vi.grid) { \
vi.co= vi.grid->co; \
vi.fno= vi.grid->no; \
vi.grid++; \
vi.co= GRIDELEM_CO(vi.grid, vi.gridkey); \
vi.fno= GRIDELEM_NO(vi.grid, vi.gridkey); \
\
if(vi.gridkey->mask) { \
vi.mask_combined = \
paint_mask_from_gridelem(vi.grid, vi.gridkey, vi.vdata); \
\
if(vi.pmask_active_layer != -1) \
vi.mask_active= &GRIDELEM_MASK(vi.grid, \
vi.gridkey)[vi.pmask_active_layer - \
vi.pmask_first_layer]; \
} \
\
vi.elem= vi.grid; \
GRIDELEM_INC(vi.grid, 1, vi.gridkey); \
} \
else { \
vi.mvert= &vi.mverts[vi.vert_indices[vi.gx]]; \
vi.co= vi.mvert->co; \
vi.no= vi.mvert->no; \
if(vi.pmask_layer_count) { \
vi.mask_combined = \
paint_mask_from_vertex(vi.vdata, vi.vert_indices[vi.gx], \
vi.pmask_layer_count, \
vi.pmask_first_layer); \
\
if(vi.pmask_active_layer != -1) \
vi.mask_active = &((float*)vi.vdata->layers[vi.pmask_active_layer].data)[vi.vert_indices[vi.gx]]; \
} \
} \
#define BLI_pbvh_vertex_iter_end \
} \
} \
}
} \
void BLI_pbvh_node_get_proxies(PBVHNode* node, PBVHProxyNode** proxies, int* proxy_count);
void BLI_pbvh_node_free_proxies(PBVHNode* node);

View File

@@ -20,9 +20,9 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "MEM_guardedalloc.h"
@@ -31,12 +31,14 @@
#include "BLI_pbvh.h"
#include "BKE_DerivedMesh.h"
#include "BKE_dmgrid.h"
#include "BKE_mesh.h" /* for mesh_calc_normals */
#include "BKE_global.h" /* for mesh_calc_normals */
#include "BKE_paint.h"
#include "GPU_buffers.h"
#define LEAF_LIMIT 10000
static void pbvh_free_nodes(PBVH *bvh);
//#define PERFCNTRS
@@ -121,6 +123,14 @@ struct PBVH {
void **gridfaces;
int totgrid;
int gridsize;
struct GridKey *gridkey;
struct GridToFace *grid_face_map;
/* Used by both mesh and grid type */
CustomData *vdata;
/* For vertex paint */
CustomData *fdata;
/* Only used during BVH build and update,
don't need to remain valid after */
@@ -153,6 +163,62 @@ typedef struct PBVHIter {
int stackspace;
} PBVHIter;
/* Test AABB against sphere */
int BLI_pbvh_search_sphere_cb(PBVHNode *node, void *data_v)
{
PBVHSearchSphereData *data = data_v;
float nearest[3];
float t[3], bb_min[3], bb_max[3];
int i;
if(data->original)
BLI_pbvh_node_get_original_BB(node, bb_min, bb_max);
else
BLI_pbvh_node_get_BB(node, bb_min, bb_max);
for(i = 0; i < 3; ++i) {
if(bb_min[i] > data->center[i])
nearest[i] = bb_min[i];
else if(bb_max[i] < data->center[i])
nearest[i] = bb_max[i];
else
nearest[i] = data->center[i];
}
sub_v3_v3v3(t, data->center, nearest);
return t[0] * t[0] + t[1] * t[1] + t[2] * t[2] < data->radius_squared;
}
/* Adapted from:
http://www.gamedev.net/community/forums/topic.asp?topic_id=512123
Returns true if the AABB is at least partially within the frustum
(ok, not a real frustum), false otherwise.
*/
static int pbvh_planes_contain_AABB(float bb_min[3], float bb_max[3], float (*planes)[4])
{
int i, axis;
float vmin[3], vmax[3];
for(i = 0; i < 4; ++i) {
for(axis = 0; axis < 3; ++axis) {
if(planes[i][axis] > 0) {
vmin[axis] = bb_min[axis];
vmax[axis] = bb_max[axis];
}
else {
vmin[axis] = bb_max[axis];
vmax[axis] = bb_min[axis];
}
}
if(dot_v3v3(planes[i], vmin) + planes[i][3] > 0)
return 0;
}
return 1;
}
static void BB_reset(BB *bb)
{
bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX;
@@ -372,13 +438,15 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
if(!G.background) {
node->draw_buffers =
GPU_build_mesh_buffers(map, bvh->verts, bvh->faces,
node->prim_indices,
node->totprim, node->vert_indices,
node->uniq_verts,
node->uniq_verts + node->face_verts);
bvh->vdata,
bvh->fdata,
node->prim_indices,
node->totprim, node->vert_indices,
node->uniq_verts,
node->uniq_verts + node->face_verts);
}
node->flag |= PBVH_UpdateDrawBuffers;
node->flag |= PBVH_UpdateVertBuffers|PBVH_UpdateColorBuffers;
BLI_ghash_free(map, NULL, NULL);
}
@@ -387,10 +455,9 @@ static void build_grids_leaf_node(PBVH *bvh, PBVHNode *node)
{
if(!G.background) {
node->draw_buffers =
GPU_build_grid_buffers(bvh->grids, node->prim_indices,
node->totprim, bvh->gridsize);
GPU_build_grid_buffers(bvh->gridsize);
}
node->flag |= PBVH_UpdateDrawBuffers;
node->flag |= PBVH_UpdateVertBuffers|PBVH_UpdateColorBuffers;
}
/* Recursively build a node in the tree
@@ -472,119 +539,175 @@ void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc,
prim_bbc, end, offset + count - end);
}
static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim)
/* Returns 0 if the primitive should be hidden, 1 otherwise */
static int test_prim_against_hidden_areas(BBC *prim_bbc, ListBase *hidden_areas)
{
int i;
HiddenArea *area;
for(area = hidden_areas->first; area; area = area->next) {
int prim_inside_planes = pbvh_planes_contain_AABB(prim_bbc->bmin, prim_bbc->bmax, area->clip_planes);
if((prim_inside_planes && area->hide_inside) || (!prim_inside_planes && !area->hide_inside))
return 0;
}
return 1;
}
/* Initially, the root node contains all primitives in
their original order.
If we are clipping, exclude primitives outside the
clip planes from the primitive list
*/
static int pbvh_initialize_prim_indices(PBVH *bvh, BBC *prim_bbc, int totprim, ListBase *hidden_areas)
{
int prim, index;
int *prim_indices;
prim_indices = MEM_callocN(sizeof(int) * totprim, "bvh prim indices");
for(prim= 0, index = 0; prim < totprim; ++prim) {
if(!hidden_areas || test_prim_against_hidden_areas(&prim_bbc[prim], hidden_areas)) {
prim_indices[index] = prim;
++index;
}
}
if(index == prim) {
bvh->prim_indices = prim_indices;
return totprim;
}
else {
bvh->prim_indices = MEM_callocN(sizeof(int) * index, "bvh prim indices");
memcpy(bvh->prim_indices, prim_indices, sizeof(int) * index);
MEM_freeN(prim_indices);
return index;
}
}
static void pbvh_build(PBVH *bvh, BB *cb, BBC *prim_bbc, int totprim, ListBase *hidden_areas)
{
int max_prim_index;
if(totprim != bvh->totprim) {
/* Initialize the nodes */
bvh->totprim = totprim;
if(bvh->nodes) MEM_freeN(bvh->nodes);
if(bvh->nodes)
pbvh_free_nodes(bvh);
if(bvh->prim_indices) MEM_freeN(bvh->prim_indices);
bvh->prim_indices = MEM_callocN(sizeof(int) * totprim,
"bvh prim indices");
for(i = 0; i < totprim; ++i)
bvh->prim_indices[i] = i;
max_prim_index = pbvh_initialize_prim_indices(bvh, prim_bbc, totprim, hidden_areas);
bvh->totnode = 0;
if(bvh->node_mem_count < 100) {
if(bvh->node_mem_count < 100)
bvh->node_mem_count = 100;
bvh->nodes = MEM_callocN(sizeof(PBVHNode) *
bvh->node_mem_count,
"bvh initial nodes");
}
bvh->nodes = MEM_callocN(sizeof(PBVHNode) *
bvh->node_mem_count,
"bvh initial nodes");
}
bvh->totnode = 1;
build_sub(bvh, 0, cb, prim_bbc, 0, totprim);
build_sub(bvh, 0, cb, prim_bbc, 0, max_prim_index);
}
/* Do a full rebuild with on Mesh data structure */
void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts, int totface, int totvert)
void pbvh_begin_build(PBVH *bvh, int totprim, ListBase *hidden_areas)
{
BBC *prim_bbc = NULL;
BB cb;
int i, j;
int totgridelem;
BBC *prim_bbc;
BB cb;
bvh->faces = faces;
bvh->verts = verts;
bvh->vert_bitmap = BLI_bitmap_new(totvert);
bvh->totvert = totvert;
bvh->leaf_limit = LEAF_LIMIT;
/* cb will be the bounding box around all primitives' centroids */
BB_reset(&cb);
/* For each face, store the AABB and the AABB centroid */
prim_bbc = MEM_mallocN(sizeof(BBC) * totface, "prim_bbc");
if(bvh->faces)
bvh->vert_bitmap = BLI_bitmap_new(bvh->totvert);
else
totgridelem = bvh->gridsize*bvh->gridsize;
for(i = 0; i < totface; ++i) {
MFace *f = faces + i;
const int sides = f->v4 ? 4 : 3;
/* For each primitive, store the AABB and the AABB centroid */
prim_bbc = MEM_mallocN(sizeof(BBC) * totprim, "prim_bbc");
for(i = 0; i < totprim; ++i) {
BBC *bbc = prim_bbc + i;
BB_reset((BB*)bbc);
for(j = 0; j < sides; ++j)
BB_expand((BB*)bbc, verts[(&f->v1)[j]].co);
if(bvh->faces) {
/* For regular mesh */
MFace *f = bvh->faces + i;
const int sides = f->v4 ? 4 : 3;
for(j = 0; j < sides; ++j)
BB_expand((BB*)bbc, bvh->verts[(&f->v1)[j]].co);
}
else {
/* For multires */
DMGridData *grid= bvh->grids[i];
for(j = 0; j < totgridelem; ++j)
BB_expand((BB*)bbc, GRIDELEM_CO_AT(grid, j, bvh->gridkey));
}
BBC_update_centroid(bbc);
BB_expand(&cb, bbc->bcentroid);
}
if(totface)
pbvh_build(bvh, &cb, prim_bbc, totface);
pbvh_build(bvh, &cb, prim_bbc, totprim, hidden_areas);
MEM_freeN(prim_bbc);
MEM_freeN(bvh->vert_bitmap);
if(bvh->faces)
MEM_freeN(bvh->vert_bitmap);
}
/* Do a full rebuild with on Mesh data structure */
void BLI_pbvh_build_mesh(PBVH *bvh, MFace *faces, MVert *verts,
CustomData *vdata, CustomData *fdata,
int totface, int totvert,
ListBase *hidden_areas)
{
bvh->faces = faces;
bvh->verts = verts;
bvh->vdata = vdata;
bvh->fdata = fdata;
bvh->totvert = totvert;
if(totface)
pbvh_begin_build(bvh, totface, hidden_areas);
}
/* Do a full rebuild with on Grids data structure */
void BLI_pbvh_build_grids(PBVH *bvh, DMGridData **grids, DMGridAdjacency *gridadj,
int totgrid, int gridsize, void **gridfaces)
void BLI_pbvh_build_grids(PBVH *bvh, DMGridData **grids,
DMGridAdjacency *gridadj,
int totgrid, int gridsize, GridKey *gridkey,
void **gridfaces, GridToFace *grid_face_map,
CustomData *vdata, CustomData *fdata,
ListBase *hidden_areas)
{
BBC *prim_bbc = NULL;
BB cb;
int i, j;
bvh->grids= grids;
bvh->gridadj= gridadj;
bvh->gridfaces= gridfaces;
bvh->totgrid= totgrid;
bvh->gridsize= gridsize;
bvh->leaf_limit = MAX2(LEAF_LIMIT/((gridsize-1)*(gridsize-1)), 1);
BB_reset(&cb);
/* For each grid, store the AABB and the AABB centroid */
prim_bbc = MEM_mallocN(sizeof(BBC) * totgrid, "prim_bbc");
for(i = 0; i < totgrid; ++i) {
DMGridData *grid= grids[i];
BBC *bbc = prim_bbc + i;
BB_reset((BB*)bbc);
for(j = 0; j < gridsize*gridsize; ++j)
BB_expand((BB*)bbc, grid[j].co);
BBC_update_centroid(bbc);
BB_expand(&cb, bbc->bcentroid);
}
bvh->gridkey= gridkey;
bvh->vdata= vdata;
bvh->fdata= fdata;
bvh->leaf_limit = MAX2(bvh->leaf_limit/((gridsize-1)*(gridsize-1)), 1);
bvh->grid_face_map = grid_face_map;
if(totgrid)
pbvh_build(bvh, &cb, prim_bbc, totgrid);
MEM_freeN(prim_bbc);
pbvh_begin_build(bvh, totgrid, hidden_areas);
}
PBVH *BLI_pbvh_new(void)
PBVH *BLI_pbvh_new(int leaf_limit)
{
PBVH *bvh = MEM_callocN(sizeof(PBVH), "pbvh");
bvh->leaf_limit = leaf_limit;
return bvh;
}
void BLI_pbvh_free(PBVH *bvh)
static void pbvh_free_nodes(PBVH *bvh)
{
PBVHNode *node;
int i;
@@ -612,6 +735,12 @@ void BLI_pbvh_free(PBVH *bvh)
}
MEM_freeN(bvh->nodes);
}
void BLI_pbvh_free(PBVH *bvh)
{
pbvh_free_nodes(bvh);
MEM_freeN(bvh->prim_indices);
MEM_freeN(bvh);
}
@@ -1011,7 +1140,7 @@ static void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes,
}
}
static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, int smooth)
static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, DMDrawFlags flags)
{
PBVHNode *node;
int n;
@@ -1020,24 +1149,55 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode, i
for(n = 0; n < totnode; n++) {
node= nodes[n];
if(node->flag & PBVH_UpdateDrawBuffers) {
if(node->flag & PBVH_UpdateVertBuffers) {
if(bvh->grids) {
GPU_update_grid_buffers(node->draw_buffers,
bvh->grids,
node->prim_indices,
node->totprim,
bvh->gridsize,
smooth);
GPU_update_grid_vert_buffers(node->draw_buffers,
bvh->grids,
node->prim_indices,
node->totprim,
bvh->gridsize,
bvh->gridkey,
flags & DM_DRAW_FULLY_SMOOTH);
}
else {
GPU_update_mesh_buffers(node->draw_buffers,
bvh->verts,
node->vert_indices,
node->uniq_verts +
node->face_verts);
GPU_update_mesh_vert_buffers(node->draw_buffers,
bvh->verts,
node->vert_indices,
node->uniq_verts +
node->face_verts);
}
node->flag &= ~PBVH_UpdateDrawBuffers;
node->flag &= ~PBVH_UpdateVertBuffers;
}
if(node->flag & PBVH_UpdateColorBuffers) {
if(bvh->grids) {
if(flags & DM_DRAW_PTEX) {
GPU_update_ptex(node->draw_buffers, bvh, node);
/* TODO: should only do this after ptex
res change */
GPU_update_grid_uv_buffer(node->draw_buffers,
bvh, node, flags);
}
else if(flags & DM_DRAW_PAINT_MASK) {
GPU_update_grid_color_buffers(node->draw_buffers,
bvh->grids,
node->prim_indices,
node->totprim,
bvh->gridsize,
bvh->gridkey,
bvh->vdata,
flags);
}
}
else {
if(flags & DM_DRAW_PAINT_MASK) {
GPU_update_mesh_color_buffers(node->draw_buffers,
bvh, node, flags);
}
}
node->flag &= ~PBVH_UpdateColorBuffers;
}
}
}
@@ -1093,6 +1253,8 @@ void BLI_pbvh_update(PBVH *bvh, int flag, float (*face_nors)[3])
if(nodes) MEM_freeN(nodes);
}
/* get the object-space bounding box containing all the nodes that
have been marked with PBVH_UpdateRedraw */
void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3])
{
PBVHIter iter;
@@ -1128,7 +1290,7 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *tot
pbvh_iter_begin(&iter, bvh, NULL, NULL);
while((node=pbvh_iter_next(&iter))) {
if(node->flag & PBVH_UpdateNormals) {
if(node->flag & (PBVH_UpdateNormals)) {
for(i = 0; i < node->totprim; ++i) {
face= bvh->gridfaces[node->prim_indices[i]];
if(!BLI_ghash_lookup(map, face))
@@ -1165,11 +1327,34 @@ void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *tot
*gridfaces= faces;
}
/**** Access to mesh/grid data ****/
int BLI_pbvh_uses_grids(PBVH *bvh)
{
return !!bvh->grids;
}
void BLI_pbvh_get_customdata(PBVH *bvh, CustomData **vdata, CustomData **fdata)
{
if(vdata) *vdata = bvh->vdata;
if(fdata) *fdata = bvh->fdata;
}
GridToFace *BLI_pbvh_get_grid_face_map(PBVH *pbvh)
{
return pbvh->grid_face_map;
}
/***************************** Node Access ***********************************/
void BLI_pbvh_node_mark_update(PBVHNode *node)
{
node->flag |= PBVH_UpdateNormals|PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateDrawBuffers|PBVH_UpdateRedraw;
node->flag |= PBVH_UpdateNormals|PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateVertBuffers|PBVH_UpdateRedraw;
}
void BLI_pbvh_node_set_flags(PBVHNode *node, void *data)
{
node->flag |= GET_INT_FROM_POINTER(data);
}
void BLI_pbvh_node_get_verts(PBVH *bvh, PBVHNode *node, int **vert_indices, MVert **verts)
@@ -1182,7 +1367,7 @@ void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to
{
if(bvh->grids) {
if(totvert) *totvert= node->totprim*bvh->gridsize*bvh->gridsize;
if(uniquevert) *uniquevert= *totvert;
if(uniquevert) *uniquevert= node->totprim*bvh->gridsize*bvh->gridsize;
}
else {
if(totvert) *totvert= node->uniq_verts + node->face_verts;
@@ -1190,7 +1375,26 @@ void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to
}
}
void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, DMGridData ***griddata, DMGridAdjacency **gridadj)
void BLI_pbvh_node_get_faces(PBVH *bvh, PBVHNode *node,
MFace **mface,
int **face_indices, int **face_vert_indices,
int *totnode)
{
if(bvh->grids) {
if(mface) *mface= NULL;
if(face_indices) *face_indices= NULL;
if(face_vert_indices) *face_vert_indices= NULL;
if(totnode) *totnode= 0;
}
else {
if(mface) *mface= bvh->faces;
if(face_indices) *face_indices= node->prim_indices;
if(face_vert_indices) *face_vert_indices= node->face_vert_indices;
if(totnode) *totnode= node->totprim;
}
}
void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int *totgrid, int *maxgrid, int *gridsize, DMGridData ***griddata, DMGridAdjacency **gridadj, GridKey **gridkey)
{
if(bvh->grids) {
if(grid_indices) *grid_indices= node->prim_indices;
@@ -1199,6 +1403,7 @@ void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if(gridsize) *gridsize= bvh->gridsize;
if(griddata) *griddata= bvh->grids;
if(gridadj) *gridadj= bvh->gridadj;
if(gridkey) *gridkey= bvh->gridkey;
}
else {
if(grid_indices) *grid_indices= NULL;
@@ -1207,6 +1412,7 @@ void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if(gridsize) *gridsize= 0;
if(griddata) *griddata= NULL;
if(gridadj) *gridadj= NULL;
if(gridkey) *gridkey= NULL;
}
}
@@ -1324,10 +1530,14 @@ static int ray_face_intersection(float ray_start[3], float ray_normal[3],
}
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
float ray_start[3], float ray_normal[3], float *dist)
float ray_start[3], float ray_normal[3], float *dist,
int *hit_index, int *grid_hit_index)
{
int hit= 0;
if(hit_index) *hit_index = -1;
if(grid_hit_index) *grid_hit_index = -1;
if(bvh->faces) {
MVert *vert = bvh->verts;
int *faces= node->prim_indices;
@@ -1337,10 +1547,11 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
for(i = 0; i < totface; ++i) {
MFace *f = bvh->faces + faces[i];
int lhit = 0;
if(origco) {
/* intersect with backuped original coordinates */
hit |= ray_face_intersection(ray_start, ray_normal,
lhit = ray_face_intersection(ray_start, ray_normal,
origco[face_verts[i*4+0]],
origco[face_verts[i*4+1]],
origco[face_verts[i*4+2]],
@@ -1349,13 +1560,18 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
}
else {
/* intersect with current coordinates */
hit |= ray_face_intersection(ray_start, ray_normal,
lhit = ray_face_intersection(ray_start, ray_normal,
vert[f->v1].co,
vert[f->v2].co,
vert[f->v3].co,
f->v4 ? vert[f->v4].co : NULL,
dist);
}
if(lhit && hit_index)
*hit_index = i;
hit |= lhit;
}
}
else {
@@ -1365,13 +1581,16 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
for(i = 0; i < totgrid; ++i) {
DMGridData *grid= bvh->grids[node->prim_indices[i]];
if (!grid)
continue;
for(y = 0; y < gridsize-1; ++y) {
for(x = 0; x < gridsize-1; ++x) {
int lhit = 0;
if(origco) {
hit |= ray_face_intersection(ray_start, ray_normal,
lhit |= ray_face_intersection(ray_start, ray_normal,
origco[y*gridsize + x],
origco[y*gridsize + x+1],
origco[(y+1)*gridsize + x+1],
@@ -1379,13 +1598,20 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
dist);
}
else {
hit |= ray_face_intersection(ray_start, ray_normal,
grid[y*gridsize + x].co,
grid[y*gridsize + x+1].co,
grid[(y+1)*gridsize + x+1].co,
grid[(y+1)*gridsize + x].co,
lhit |= ray_face_intersection(ray_start, ray_normal,
GRIDELEM_CO_AT(grid, y*gridsize + x, bvh->gridkey),
GRIDELEM_CO_AT(grid, y*gridsize + x+1, bvh->gridkey),
GRIDELEM_CO_AT(grid, (y+1)*gridsize + x+1, bvh->gridkey),
GRIDELEM_CO_AT(grid, (y+1)*gridsize + x, bvh->gridkey),
dist);
}
if(lhit) {
if(hit_index) *hit_index = i;
if(grid_hit_index) *grid_hit_index = y*gridsize + x;
}
hit |= lhit;
}
}
@@ -1399,7 +1625,12 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
//#include <GL/glew.h>
void BLI_pbvh_node_draw(PBVHNode *node, void *UNUSED(data))
typedef struct {
PBVH *pbvh;
DMDrawFlags flags;
} PBVHDrawData;
void BLI_pbvh_node_draw(PBVHNode *node, void *data_v)
{
#if 0
/* XXX: Just some quick code to show leaf nodes in different colors */
@@ -1417,68 +1648,52 @@ void BLI_pbvh_node_draw(PBVHNode *node, void *UNUSED(data))
glColor3f(1, 0, 0);
#endif
GPU_draw_buffers(node->draw_buffers);
PBVHDrawData *data = data_v;
GPU_draw_buffers(node->draw_buffers, data->pbvh, node, data->flags);
}
/* Adapted from:
http://www.gamedev.net/community/forums/topic.asp?topic_id=512123
Returns true if the AABB is at least partially within the frustum
(ok, not a real frustum), false otherwise.
*/
int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data)
{
float (*planes)[4] = data;
int i, axis;
float vmin[3], vmax[3], bb_min[3], bb_max[3];
float bb_min[3], bb_max[3];
BLI_pbvh_node_get_BB(node, bb_min, bb_max);
for(i = 0; i < 4; ++i) {
for(axis = 0; axis < 3; ++axis) {
if(planes[i][axis] > 0) {
vmin[axis] = bb_min[axis];
vmax[axis] = bb_max[axis];
}
else {
vmin[axis] = bb_max[axis];
vmax[axis] = bb_min[axis];
}
}
if(dot_v3v3(planes[i], vmin) + planes[i][3] > 0)
return 0;
}
return 1;
return pbvh_planes_contain_AABB(bb_min, bb_max, data);
}
void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int smooth)
void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int flags)
{
PBVHNode **nodes;
PBVHDrawData draw_data = {bvh, flags};
int totnode;
BLI_pbvh_search_gather(bvh, update_search_cb, SET_INT_IN_POINTER(PBVH_UpdateNormals|PBVH_UpdateDrawBuffers),
BLI_pbvh_search_gather(bvh, update_search_cb,
SET_INT_IN_POINTER(PBVH_UpdateNormals|PBVH_UpdateVertBuffers|PBVH_UpdateColorBuffers),
&nodes, &totnode);
pbvh_update_normals(bvh, nodes, totnode, face_nors);
pbvh_update_draw_buffers(bvh, nodes, totnode, smooth);
pbvh_update_draw_buffers(bvh, nodes, totnode, flags);
if(nodes) MEM_freeN(nodes);
if(planes) {
BLI_pbvh_search_callback(bvh, BLI_pbvh_node_planes_contain_AABB,
planes, BLI_pbvh_node_draw, NULL);
planes, BLI_pbvh_node_draw, &draw_data);
}
else {
BLI_pbvh_search_callback(bvh, NULL, NULL, BLI_pbvh_node_draw, NULL);
BLI_pbvh_search_callback(bvh, NULL, NULL, BLI_pbvh_node_draw, &draw_data);
}
}
void BLI_pbvh_grids_update(PBVH *bvh, DMGridData **grids, DMGridAdjacency *gridadj, void **gridfaces)
void BLI_pbvh_grids_update(PBVH *bvh, DMGridData **grids,
DMGridAdjacency *gridadj, void **gridfaces,
struct GridKey *gridkey)
{
bvh->grids= grids;
bvh->gridadj= gridadj;
bvh->gridfaces= gridfaces;
bvh->gridkey= gridkey;
}
float (*BLI_pbvh_get_vertCos(PBVH *pbvh))[3]

View File

@@ -35,6 +35,7 @@ SET(INC
../include
../makesrna
../render/extern/include
../../../extern/ptex
../../../intern/guardedalloc
${ZLIB_INC}
)

View File

@@ -6,6 +6,7 @@ sources = env.Glob('intern/*.c')
incs = '. #/intern/guardedalloc ../blenlib ../blenkernel'
incs += ' ../makesdna ../readblenfile ../editors/include'
incs += ' ../render/extern/include ../makesrna'
incs += ' #/extern/ptex'
incs += ' ' + env['BF_ZLIB_INC']

View File

@@ -3257,6 +3257,34 @@ static void direct_link_mdisps(FileData *fd, int count, MDisps *mdisps, int exte
}
}
static void direct_link_customdata_multires(FileData *fd, int count,
CustomDataMultires *cdm)
{
if(cdm) {
int i, j;
for(i = 0; i < count; ++i, ++cdm) {
cdm->layers = newdataadr(fd, cdm->layers);
for(j = 0; j < cdm->totlayer; ++j) {
CustomDataMultiresLayer *l = cdm->layers + j;
l->griddata = newdataadr(fd, l->griddata);
}
}
}
}
static void direct_link_customdata_mptex(FileData *fd, int count, MPtex *mptex)
{
if(mptex) {
int i, j;
for(i = 0; i < count; ++i, ++mptex) {
for(j = 0; j < mptex->totsubface; ++j)
mptex->subfaces[j].data = newdataadr(fd, mptex->subfaces[j].data);
}
}
}
static void direct_link_customdata(FileData *fd, CustomData *data, int count)
{
int i = 0;
@@ -3274,6 +3302,10 @@ static void direct_link_customdata(FileData *fd, CustomData *data, int count)
layer->data = newdataadr(fd, layer->data);
if(layer->type == CD_MDISPS)
direct_link_mdisps(fd, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
if(layer->type == CD_GRIDS)
direct_link_customdata_multires(fd, count, layer->data);
if(layer->type == CD_MPTEX)
direct_link_customdata_mptex(fd, count, layer->data);
i++;
}
}
@@ -4100,9 +4132,10 @@ static void direct_link_object(FileData *fd, Object *ob)
ob->gpulamp.first= ob->gpulamp.last= NULL;
link_list(fd, &ob->pc_ids);
if(ob->sculpt) {
ob->sculpt= MEM_callocN(sizeof(SculptSession), "reload sculpt session");
ob->sculpt->ob= ob;
if(ob->paint) {
ob->paint = MEM_callocN(sizeof(PaintSession), "PaintSession");
if(ob->mode & OB_MODE_SCULPT)
ob->paint->sculpt= MEM_callocN(sizeof(SculptSession), "reload sculpt session");
}
}
@@ -4137,6 +4170,8 @@ static void lib_link_scene(FileData *fd, Main *main)
sce= main->scene.first;
while(sce) {
if(sce->id.flag & LIB_NEEDLINK) {
ToolSettings *ts;
/*Link ID Properties -- and copy this comment EXACTLY for easy finding
of library blocks that implement this.*/
if (sce->id.properties) IDP_LibLinkProperty(sce->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
@@ -4150,10 +4185,18 @@ static void lib_link_scene(FileData *fd, Main *main)
sce->ima= newlibadr_us(fd, sce->id.lib, sce->ima);
sce->gpd= newlibadr_us(fd, sce->id.lib, sce->gpd);
link_paint(fd, sce, &sce->toolsettings->sculpt->paint);
link_paint(fd, sce, &sce->toolsettings->vpaint->paint);
link_paint(fd, sce, &sce->toolsettings->wpaint->paint);
link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
ts = sce->toolsettings;
link_paint(fd, sce, &ts->sculpt->paint);
link_paint(fd, sce, &ts->vpaint->paint);
link_paint(fd, sce, &ts->wpaint->paint);
link_paint(fd, sce, &ts->imapaint.paint);
if(ts) {
if(ts->paint_overlay.img)
ts->paint_overlay.img = newlibadr_us(fd, sce->id.lib, ts->paint_overlay.img);
ts->paint_overlay.gltex = 0;
if(!ts->ptex_ures) ts->ptex_ures = 128;
if(!ts->ptex_vres) ts->ptex_vres = 128;
}
sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);

View File

@@ -150,6 +150,8 @@ Any case: direct data is ALWAYS after the lib block
#include "readfile.h"
#include "ptex.h"
#include <errno.h>
/* ********* my write, buffered writing with minimum size chunks ************ */
@@ -1463,6 +1465,44 @@ static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external)
}
}
static void write_customdata_multires(WriteData *wd, int count,
CustomDataMultires *grids)
{
int i, j;
writestruct(wd, DATA, "CustomDataMultires", count, grids);
for(i = 0; i < count; ++i) {
writestruct(wd, DATA, "CustomDataMultiresLayer",
grids[i].totlayer, grids[i].layers);
for(j = 0; j < grids[i].totlayer; ++j) {
CustomDataMultiresLayer *l = &grids[i].layers[j];
writedata(wd, DATA, sizeof(float) * grids[i].totelem *
CustomData_multires_type_totfloat(l->type),
l->griddata);
}
}
}
static void write_customdata_mptex(WriteData *wd, int count,
MPtex *mptex)
{
int i, j;
writestruct(wd, DATA, "MPtex", count, mptex);
for(i = 0; i < count; ++i, ++mptex) {
int layersize = mptex->channels * ptex_data_size(mptex->type);
for(j = 0; j < mptex->totsubface; ++j)
writedata(wd, DATA,
layersize * (mptex->subfaces[j].res[0] * mptex->subfaces[j].res[1]),
mptex->subfaces[j].data);
}
}
static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data, int partial_type, int partial_count)
{
int i;
@@ -1485,6 +1525,15 @@ static void write_customdata(WriteData *wd, ID *id, int count, CustomData *data,
else if (layer->type == CD_MDISPS) {
write_mdisps(wd, count, layer->data, layer->flag & CD_FLAG_EXTERNAL);
}
else if (layer->type == CD_PAINTMASK) {
writedata(wd, DATA, sizeof(float)*count, layer->data);
}
else if (layer->type == CD_GRIDS) {
write_customdata_multires(wd, count, layer->data);
}
else if (layer->type == CD_MPTEX) {
write_customdata_mptex(wd, count, layer->data);
}
else {
CustomData_file_write_info(layer->type, &structname, &structnum);
if (structnum) {

View File

@@ -58,6 +58,7 @@ struct CustomData;
struct Material;
struct Object;
struct rcti;
struct CustomDataLayer;
#define EM_FGON_DRAW 1 // face flag
#define EM_FGON 2 // edge and face flag both
@@ -220,6 +221,10 @@ void ED_mesh_faces_add(struct Mesh *mesh, struct ReportList *reports, int count)
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_delete_customdata_layer(struct bContext *C, struct Object *ob, struct CustomDataLayer *layer);
void ED_mesh_geometry_add(struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces);
void ED_mesh_transform(struct Mesh *me, float *mat);
void ED_mesh_calc_normals(struct Mesh *me);
void ED_mesh_material_link(struct Mesh *me, struct Material *ma);
@@ -230,6 +235,8 @@ int ED_mesh_uv_texture_remove(struct bContext *C, struct Object *ob, struct Mesh
int ED_mesh_color_add(struct bContext *C, struct Scene *scene, struct Object *ob, struct Mesh *me, const char *name, int active_set);
int ED_mesh_color_remove(struct bContext *C, struct Object *ob, struct Mesh *me);
int ED_mesh_layers_poll(struct bContext *C);
#ifdef __cplusplus
}
#endif

View File

@@ -30,16 +30,16 @@
struct ARegion;
struct bContext;
struct MultiresModifierData;
struct Object;
struct PaintOverlay;
struct RegionView3D;
struct Scene;
struct wmKeyConfig;
struct wmWindowManager;
/* sculpt.c */
void ED_operatortypes_sculpt(void);
void sculpt_get_redraw_planes(float planes[4][4], struct ARegion *ar,
struct RegionView3D *rv3d, struct Object *ob);
void ED_sculpt_force_update(struct bContext *C);
/* paint_ops.c */
void ED_operatortypes_paint(void);
@@ -52,4 +52,21 @@ void ED_keymap_paint(struct wmKeyConfig *keyconf);
int ED_undo_paint_step(struct bContext *C, int type, int step, const char *name);
void ED_undo_paint_free(void);
typedef struct PaintLayerUndoNode PaintLayerUndoNode;
PaintLayerUndoNode *paint_layer_undo_push(int type, char *description);
void paint_layer_undo_set_add(PaintLayerUndoNode *unode, char *name);
void paint_layer_undo_set_remove(PaintLayerUndoNode *unode, char *name,
struct CustomData *data, struct CustomData *fdata,
int totvert, int totface);
/* paint_util.c */
struct MultiresModifierData *ED_paint_multires_active(struct Scene *scene, struct Object *ob);
void paint_get_redraw_planes(float planes[4][4], struct ARegion *ar,
struct RegionView3D *rv3d, struct Object *ob);
void ED_paint_force_update(struct bContext *C);
/* paint_vertex.c */
void ED_paint_overlay_draw(const struct bContext *C, struct ARegion *ar);
void ED_paint_update_overlay(struct PaintOverlay *overlay);
#endif

View File

@@ -2013,6 +2013,11 @@ static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, Pointe
//uiItemR(row, itemptr, "mute", 0, "", ICON_MUTE_IPO_OFF);
uiBlockSetEmboss(block, UI_EMBOSS);
}
else if(itemptr->type == &RNA_MeshPaintMaskLayer) {
uiItemL(sub, name, icon);
uiBlockSetEmboss(block, UI_EMBOSS);
uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "enabled", 0, 0, 0, 0, 0, NULL);
}
else
uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */

View File

@@ -45,6 +45,7 @@
#include "BKE_library.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_report.h"
#include "BLI_math.h"
@@ -59,6 +60,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_sculpt.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -66,7 +68,7 @@
#include "mesh_intern.h"
static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *layer)
void ED_mesh_delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *layer)
{
Mesh *me = ob->data;
CustomData *data= (me->edit_mesh)? &me->edit_mesh->fdata: &me->fdata;
@@ -207,7 +209,7 @@ int ED_mesh_uv_texture_remove(bContext *C, Object *ob, Mesh *me)
if(!cdl)
return 0;
delete_customdata_layer(C, ob, cdl);
ED_mesh_delete_customdata_layer(C, ob, cdl);
DAG_id_flush_update(&me->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
@@ -270,7 +272,7 @@ int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me)
if(!cdl)
return 0;
delete_customdata_layer(C, ob, cdl);
ED_mesh_delete_customdata_layer(C, ob, cdl);
DAG_id_flush_update(&me->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
@@ -279,7 +281,7 @@ int ED_mesh_color_remove(bContext *C, Object *ob, Mesh *me)
/*********************** UV texture operators ************************/
static int layers_poll(bContext *C)
int ED_mesh_layers_poll(bContext *C)
{
Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data;
ID *data= (ob)? ob->data: NULL;
@@ -305,7 +307,7 @@ void MESH_OT_uv_texture_add(wmOperatorType *ot)
ot->idname= "MESH_OT_uv_texture_add";
/* api callbacks */
ot->poll= layers_poll;
ot->poll= ED_mesh_layers_poll;
ot->exec= uv_texture_add_exec;
/* flags */
@@ -379,7 +381,7 @@ void MESH_OT_drop_named_image(wmOperatorType *ot)
ot->idname= "MESH_OT_drop_named_image";
/* api callbacks */
ot->poll= layers_poll;
ot->poll= ED_mesh_layers_poll;
ot->invoke= drop_named_image_invoke;
/* flags */
@@ -409,7 +411,7 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot)
ot->idname= "MESH_OT_uv_texture_remove";
/* api callbacks */
ot->poll= layers_poll;
ot->poll= ED_mesh_layers_poll;
ot->exec= uv_texture_remove_exec;
/* flags */
@@ -418,6 +420,37 @@ void MESH_OT_uv_texture_remove(wmOperatorType *ot)
/*********************** vertex color operators ************************/
static int vertex_color_multires_toggle(Object *ob)
{
Mesh *me= ob->data;
CustomDataMultires *cdm;
CustomDataLayer *cdl;
int active;
/* so that dm is recalculated correctly after */
multires_force_update(ob);
active = CustomData_get_active_layer_index(&me->fdata, CD_MCOL);
cdm = CustomData_get_layer(&me->fdata, CD_GRIDS);
if(active == -1)
return 1;
cdl = &me->fdata.layers[active];
if(cdm) {
if(cdl->flag & CD_FLAG_MULTIRES)
CustomData_multires_remove_layers(cdm, me->totface, CD_MCOL, cdl->name);
else
CustomData_multires_add_layers(cdm, me->totface, CD_MCOL, cdl->name);
}
/* note - if there's no griddata, it can still be synced up later */
cdl->flag ^= CD_FLAG_MULTIRES;
return 1;
}
static int vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene= CTX_data_scene(C);
@@ -427,6 +460,10 @@ static int vertex_color_add_exec(bContext *C, wmOperator *UNUSED(op))
if(!ED_mesh_color_add(C, scene, ob, me, NULL, TRUE))
return OPERATOR_CANCELLED;
if((ob->mode & OB_MODE_VERTEX_PAINT) &&
ED_paint_multires_active(scene, ob))
vertex_color_multires_toggle(ob);
return OPERATOR_FINISHED;
}
@@ -438,7 +475,7 @@ void MESH_OT_vertex_color_add(wmOperatorType *ot)
ot->idname= "MESH_OT_vertex_color_add";
/* api callbacks */
ot->poll= layers_poll;
ot->poll= ED_mesh_layers_poll;
ot->exec= vertex_color_add_exec;
/* flags */
@@ -465,7 +502,30 @@ void MESH_OT_vertex_color_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec= vertex_color_remove_exec;
ot->poll= layers_poll;
ot->poll= ED_mesh_layers_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
static int vertex_color_multires_toggle_exec(bContext *C, wmOperator *op)
{
if(vertex_color_multires_toggle(CTX_data_active_object(C)))
return OPERATOR_FINISHED;
else
return OPERATOR_CANCELLED;
}
void MESH_OT_vertex_color_multiresolution_toggle(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Vertex Color Multiresolution Toggle";
ot->description= "Add or remove multiresolution data from this layer";
ot->idname= "MESH_OT_vertex_color_multiresolution_toggle";
/* api callbacks */
ot->exec= vertex_color_multires_toggle_exec;
ot->poll= ED_mesh_layers_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -499,7 +559,7 @@ void MESH_OT_sticky_add(wmOperatorType *ot)
ot->idname= "MESH_OT_sticky_add";
/* api callbacks */
ot->poll= layers_poll;
ot->poll= ED_mesh_layers_poll;
ot->exec= sticky_add_exec;
/* flags */
@@ -531,7 +591,7 @@ void MESH_OT_sticky_remove(wmOperatorType *ot)
ot->idname= "MESH_OT_sticky_remove";
/* api callbacks */
ot->poll= layers_poll;
ot->poll= ED_mesh_layers_poll;
ot->exec= sticky_remove_exec;
/* flags */

View File

@@ -249,6 +249,7 @@ void MESH_OT_uv_texture_add(struct wmOperatorType *ot);
void MESH_OT_uv_texture_remove(struct wmOperatorType *ot);
void MESH_OT_vertex_color_add(struct wmOperatorType *ot);
void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
void MESH_OT_vertex_color_multiresolution_toggle(struct wmOperatorType *ot);
void MESH_OT_sticky_add(struct wmOperatorType *ot);
void MESH_OT_sticky_remove(struct wmOperatorType *ot);
void MESH_OT_drop_named_image(struct wmOperatorType *ot);

View File

@@ -133,6 +133,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_uv_texture_remove);
WM_operatortype_append(MESH_OT_vertex_color_add);
WM_operatortype_append(MESH_OT_vertex_color_remove);
WM_operatortype_append(MESH_OT_vertex_color_multiresolution_toggle);
WM_operatortype_append(MESH_OT_sticky_add);
WM_operatortype_append(MESH_OT_sticky_remove);
WM_operatortype_append(MESH_OT_drop_named_image);

View File

@@ -153,6 +153,7 @@ void OBJECT_OT_multires_reshape(struct wmOperatorType *ot);
void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_save(struct wmOperatorType *ot);
void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot);
void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot);
void OBJECT_OT_meshdeform_bind(struct wmOperatorType *ot);
void OBJECT_OT_explode_refresh(struct wmOperatorType *ot);

View File

@@ -1147,6 +1147,47 @@ void OBJECT_OT_multires_external_pack(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/********************* multires apply base ***********************/
static int multires_base_apply_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_active_context(C);
MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get(op, ob, eModifierType_Multires);
if (!mmd)
return OPERATOR_CANCELLED;
multiresModifier_base_apply(mmd, ob);
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
return OPERATOR_FINISHED;
}
static int multires_base_apply_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
{
if (edit_modifier_invoke_properties(C, op))
return multires_base_apply_exec(C, op);
else
return OPERATOR_CANCELLED;
}
void OBJECT_OT_multires_base_apply(wmOperatorType *ot)
{
ot->name= "Multires Apply Base";
ot->description= "Modify the base mesh to conform to the displaced mesh";
ot->idname= "OBJECT_OT_multires_base_apply";
ot->poll= multires_poll;
ot->invoke= multires_base_apply_invoke;
ot->exec= multires_base_apply_exec;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
edit_modifier_properties(ot);
}
/************************ mdef bind operator *********************/
static int meshdeform_poll(bContext *C)

View File

@@ -136,6 +136,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete);
WM_operatortype_append(OBJECT_OT_multires_external_save);
WM_operatortype_append(OBJECT_OT_multires_external_pack);
WM_operatortype_append(OBJECT_OT_multires_base_apply);
WM_operatortype_append(OBJECT_OT_meshdeform_bind);
WM_operatortype_append(OBJECT_OT_explode_refresh);

View File

@@ -27,6 +27,7 @@ SET(INC
../../imbuf
../../gpu
../../blenlib
../../../../extern/ptex
../../makesdna
../../makesrna
../../windowmanager

View File

@@ -9,6 +9,7 @@ incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
incs += ' ../../render/extern/include'
incs += ' ../../gpu ../../makesrna'
incs += ' #/extern/ptex'
if env['OURPLATFORM'] == 'linux2':
cflags='-pthread'

View File

@@ -29,10 +29,17 @@
#ifndef ED_PAINT_INTERN_H
#define ED_PAINT_INTERN_H
#include "BLI_pbvh.h"
struct bContext;
struct Brush;
struct Scene;
struct Object;
struct Mesh;
struct Multires;
struct Object;
struct Paint;
struct PaintOverlay;
struct PaintStroke;
struct PointerRNA;
struct ViewContext;
@@ -44,24 +51,83 @@ struct VPaint;
struct ListBase;
/* paint_stroke.c */
typedef int (*StrokeGetLocation)(struct bContext *C, struct PaintStroke *stroke, float location[3], float mouse[2]);
typedef struct PaintStroke PaintStroke;
typedef int (*StrokeGetLocation)(struct bContext *C, PaintStroke *stroke, float location[3], float mouse[2]);
typedef int (*StrokeTestStart)(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke, struct PointerRNA *itemptr);
typedef void (*StrokeDone)(struct bContext *C, struct PaintStroke *stroke);
typedef void (*StrokeUpdateStep)(struct bContext *C, PaintStroke *stroke, struct PointerRNA *itemptr);
typedef void (*StrokeUpdateSymmetry)(struct bContext *C, PaintStroke *stroke,
char symmetry, char axis, float angle,
int mirror_symmetry_pass, int radial_symmetry_pass,
float (*symmetry_rot_mat)[4]);
typedef void (*StrokeBrushAction)(struct bContext *C, PaintStroke *stroke);
typedef void (*StrokeDone)(struct bContext *C, PaintStroke *stroke);
struct PaintStroke *paint_stroke_new(struct bContext *C,
StrokeGetLocation get_location, StrokeTestStart test_start,
StrokeUpdateStep update_step, StrokeDone done);
void paint_stroke_free(struct PaintStroke *stroke);
PaintStroke *paint_stroke_new(struct bContext *C,
StrokeGetLocation get_location,
StrokeTestStart test_start,
StrokeUpdateStep update_step,
StrokeUpdateSymmetry update_symmetry,
StrokeBrushAction brush_action,
StrokeDone done);
void paint_stroke_free(PaintStroke *stroke);
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, struct wmEvent *event);
void paint_stroke_apply_brush(struct bContext *C, PaintStroke *stroke, struct Paint *paint);
float paint_stroke_combined_strength(PaintStroke *stroke,
float dist, float co[3], float mask);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke);
void *paint_stroke_mode_data(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
void *paint_stroke_mode_data(PaintStroke *stroke);
void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data);
/* paint stroke cache access */
struct ViewContext *paint_stroke_view_context(PaintStroke *stroke);
float paint_stroke_feather(PaintStroke *stroke);
void paint_stroke_mouse_location(PaintStroke *stroke, float mouse[2]);
void paint_stroke_initial_mouse_location(PaintStroke *stroke, float initial_mouse[2]);
void paint_stroke_location(PaintStroke *stroke, float location[3]);
float paint_stroke_pressure(PaintStroke *stroke);
float paint_stroke_radius(PaintStroke *stroke);
float paint_stroke_radius_squared(PaintStroke *stroke);
void paint_stroke_symmetry_location(PaintStroke *stroke, float loc[3]);
int paint_stroke_first_dab(PaintStroke *stroke);
void paint_stroke_project(PaintStroke *stroke, float loc[3], float out[2]);
void paint_stroke_symmetry_unflip(PaintStroke *stroke, float out[3], float vec[3]);
/* paint stroke modifiers */
void paint_stroke_set_modifier_use_original_location(PaintStroke *stroke);
void paint_stroke_set_modifier_initial_radius_factor(PaintStroke *stroke, float initial_radius_factor);
void paint_stroke_set_modifier_use_original_texture_coords(PaintStroke *stroke);
typedef struct {
void *mode_data;
struct Object *ob;
float *ray_start, *ray_normal;
int hit;
float dist;
int original;
} PaintStrokeRaycastData;
int paint_stroke_over_mesh(struct bContext *C, PaintStroke *stroke, int x, int y);
int paint_stroke_get_location(struct bContext *C, PaintStroke *stroke,
BLI_pbvh_HitOccludedCallback hit_cb, void *mode_data,
float out[3], float mouse[2], int original);
int paint_poll(struct bContext *C);
void paint_cursor_start(struct bContext *C, int (*poll)(struct bContext *C));
typedef struct PaintStrokeTest {
float radius_squared;
float location[3];
float dist;
} PaintStrokeTest;
void paint_stroke_test_init(PaintStrokeTest *test, PaintStroke *stroke);
int paint_stroke_test(PaintStrokeTest *test, float co[3]);
int paint_stroke_test_sq(PaintStrokeTest *test, float co[3]);
int paint_stroke_test_fast(PaintStrokeTest *test, float co[3]);
int paint_stroke_test_cube(PaintStrokeTest *test, float co[3],
float local[4][4]);
float paint_stroke_test_dist(PaintStrokeTest *test);
/* paint_vertex.c */
int weight_paint_poll(struct bContext *C);
int weight_paint_mode_poll(struct bContext *C);
@@ -80,7 +146,6 @@ void PAINT_OT_weight_from_bones(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint_radial_control(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
unsigned int vpaint_get_current_col(struct VPaint *vp);
/* paint_image.c */
@@ -110,6 +175,24 @@ void PAINT_OT_face_select_all(struct wmOperatorType *ot);
int facemask_paint_poll(struct bContext *C);
float paint_calc_object_space_radius(struct ViewContext *vc,
float center[3],
float pixel_radius);
void paint_tag_partial_redraw(struct bContext *C, struct Object *ob);
void paint_flip_coord(float out[3], float in[3], const char symm);
float brush_tex_strength(struct ViewContext *vc,
float pmat[4][4], struct Brush *br,
float co[3], float mask, const float len,
float pixel_radius, float radius3d,
float special_rotation, float tex_mouse[2]);
int paint_util_raycast(struct ViewContext *vc,
BLI_pbvh_HitOccludedCallback hit_cb, void *mode_data,
float out[3], float mouse[2], int original);
/* stroke operator */
typedef enum wmBrushStrokeMode {
WM_BRUSHSTROKE_NORMAL,
@@ -126,5 +209,69 @@ struct ListBase *undo_paint_push_get_list(int type);
void undo_paint_push_count_alloc(int type, int size);
void undo_paint_push_end(int type);
/* paint_mask.c */
void paintmask_brush_apply(struct Paint *paint, PaintStroke *stroke,
struct PBVHNode **nodes,
int totnode, float bstrength);
void PAINT_OT_mask_layer_add(struct wmOperatorType *ot);
void PAINT_OT_mask_layer_remove(struct wmOperatorType *ot);
typedef enum {
MASKING_CLEAR,
MASKING_FILL,
MASKING_INVERT,
MASKING_RANDOM,
} MaskSetMode;
void PAINT_OT_mask_set(struct wmOperatorType *ot);
void PAINT_OT_mask_from_texture(struct wmOperatorType *ot);
/* pbvh_undo.c */
typedef enum {
PBVH_UNDO_CO_NO = (1<<0),
PBVH_UNDO_PMASK = (1<<1),
PBVH_UNDO_PTEX = (1<<2)
} PBVHUndoFlag;
typedef struct PBVHUndoNode PBVHUndoNode;
PBVHUndoNode *pbvh_undo_push_node(PBVHNode *node, PBVHUndoFlag flag,
struct Object *ob, struct Scene *scene);
void pbvh_undo_push_begin(char *name);
void pbvh_undo_push_end(void);
/* undo node access */
PBVHUndoNode *pbvh_undo_get_node(struct PBVHNode *node);
typedef float (*pbvh_undo_f3)[3];
typedef short (*pbvh_undo_s3)[3];
int pbvh_undo_node_totvert(PBVHUndoNode *unode);
pbvh_undo_f3 pbvh_undo_node_co(PBVHUndoNode *unode);
pbvh_undo_s3 pbvh_undo_node_no(PBVHUndoNode *unode);
float *pbvh_undo_node_layer_disp(PBVHUndoNode *unode);
void pbvh_undo_node_set_layer_disp(PBVHUndoNode *unode, float *layer_disp);
const char *pbvh_undo_node_mptex_name(PBVHUndoNode *unode);
void *pbvh_undo_node_mptex_data(PBVHUndoNode *unode, int ndx);
/* paint_ptex.c */
void PTEX_OT_layer_add(struct wmOperatorType *ot);
void PTEX_OT_layer_remove(struct wmOperatorType *ot);
void PTEX_OT_layer_save(struct wmOperatorType *ot);
void PTEX_OT_layer_convert(struct wmOperatorType *ot);
void PTEX_OT_open(struct wmOperatorType *ot);
void PTEX_OT_face_resolution_set(struct wmOperatorType *ot);
void PTEX_OT_subface_select(struct wmOperatorType *ot);
void PTEX_OT_select_all(struct wmOperatorType *ot);
void PTEX_OT_subface_flag_set(struct wmOperatorType *ot);
/* paint_overlay.c */
int paint_sample_overlay(PaintStroke *stroke, float col[3], float co[2]);
typedef enum {
PAINT_MANIP_GRAB,
PAINT_MANIP_SCALE,
PAINT_MANIP_ROTATE
} PaintManipAction;
void paint_overlay_transform(struct PaintOverlay *overlay, struct ARegion *ar, struct ImBuf *ibuf,
int out[2], float vec[2], int scale, int rotate);
void PAINT_OT_overlay_manipulate(struct wmOperatorType *ot);
#endif /* ED_PAINT_INTERN_H */

View File

@@ -0,0 +1,555 @@
#include "MEM_guardedalloc.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_dmgrid.h"
#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_pbvh.h"
#include "BLI_string.h"
#include "ED_mesh.h"
#include "ED_sculpt.h"
#include "ED_view3d.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
/* for redraw, just need to update the pbvh's vbo buffers */
static void paintmask_redraw(bContext *C)
{
Object *ob = CTX_data_active_object(C);
paint_refresh_mask_display(ob);
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
}
static int mask_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
return ob && get_mesh(ob) && ob->paint &&
(ob->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT));
}
static int mask_active_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if(mask_poll(C)) {
Mesh *me = get_mesh(ob);
return CustomData_get_active_layer_index(&me->vdata, CD_PAINTMASK) != -1;
}
return 0;
}
void paintmask_brush_apply(Paint *paint, PaintStroke *stroke, PBVHNode **nodes, int totnode,
float bstrength)
{
Object *ob = paint_stroke_view_context(stroke)->obact;
int n;
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
PaintStrokeTest test;
pbvh_undo_push_node(nodes[n], PBVH_UNDO_PMASK, ob, NULL);
paint_stroke_test_init(&test, stroke);
BLI_pbvh_vertex_iter_begin(ob->paint->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
/* TODO: should add a mask layer if needed */
if(vd.mask_active) {
if(paint_stroke_test(&test, vd.co)) {
float fade;
fade = paint_stroke_combined_strength(stroke,
test.dist,
vd.co,
0) *
bstrength;
*vd.mask_active += fade;
CLAMP(*vd.mask_active, 0, 1);
if(vd.mvert) vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
}
}
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_set_flags(nodes[n], SET_INT_IN_POINTER(PBVH_UpdateColorBuffers|PBVH_UpdateRedraw));
}
}
static float get_tex_mask_strength(MTex *tex_slot, float *uv, float vco[3])
{
float texvec[3] = {0, 0, 0};
TexResult texres;
int mapping = tex_slot->texco;
if(mapping == TEXCO_UV && !uv)
mapping = TEXCO_ORCO;
switch(tex_slot->texco) {
case TEXCO_UV:
texvec[0] = uv[0] * 2 - 1;
texvec[1] = uv[1] * 2 - 1;
break;
default:
copy_v3_v3(texvec, vco);
}
memset(&texres, 0, sizeof(TexResult));
get_texture_value(tex_slot->tex, texvec, &texres);
return texres.tin;
}
/* Set the value of a single mask element from either a UV or a coord */
#define SET_MASK(elem, uv) \
GRIDELEM_MASK(elem, gridkey)[active] = \
get_tex_mask_strength(tex_slot, uv, \
GRIDELEM_CO(elem, gridkey)) \
/* Fill active mask layer of entire grid from either MTFaces or coords */
static void mask_grid_from_tex(DMGridData *grid, int gridsize,
GridKey *gridkey, MTFace *mtface,
MTex *tex_slot, int active)
{
int x, y, boundary;
boundary = gridsize - 2;
for(y = 0; y <= boundary; ++y) {
for(x = 0; x <= boundary; ++x) {
SET_MASK(GRIDELEM_AT(grid, y*gridsize+x, gridkey),
mtface ? mtface->uv[0] : NULL);
/* Do the edge of the grid separately because the UV
grid is one element smaller on each side compared
to the vert-data grid */
if(x == boundary && y == boundary) {
SET_MASK(GRIDELEM_AT(grid, (y+1)*gridsize+x+1, gridkey),
mtface ? mtface->uv[2] : NULL);
}
if(x == boundary) {
SET_MASK(GRIDELEM_AT(grid, y*gridsize+x+1, gridkey),
mtface ? mtface->uv[3] : NULL);
}
if(y == boundary) {
SET_MASK(GRIDELEM_AT(grid, (y+1)*gridsize+x, gridkey),
mtface ? mtface->uv[1] : NULL);
}
if(mtface) ++mtface;
}
}
}
static void mask_face_from_tex(MFace *f, MVert *mvert, MTFace *mtface,
float *pmask, MTex *tex_slot, int active)
{
int S = f->v4 ? 4 : 3;
int i;
/* Masks are per-vertex, not per-face-corner, so the mask
value at each vertex comes from one arbitrary face
corner; not averaged or otherwise combined yet */
for(i = 0; i < S; ++i) {
int vndx = (&f->v1)[i];
float *vco = mvert[vndx].co;
pmask[vndx] = get_tex_mask_strength(tex_slot,
mtface ? mtface->uv[i] : NULL, vco);
}
}
static int paint_mask_from_texture_exec(bContext *C, wmOperator *op)
{
struct Scene *scene;
Object *ob;
Mesh *me;
struct MultiresModifierData *mmd;
PaintSession *ps;
MTex *tex_slot;
DerivedMesh *dm = NULL;
PBVH *pbvh;
MTFace *mtfaces = NULL;
PBVHNode **nodes;
int totnode, n, i, active;
tex_slot = CTX_data_pointer_get_type(C, "texture_slot",
&RNA_TextureSlot).data;
scene = CTX_data_scene(C);
ob = CTX_data_active_object(C);
ps = ob->paint;
me = get_mesh(ob);
mmd = ED_paint_multires_active(scene, ob);
pbvh_undo_push_begin("Paint mask from texture");
active = CustomData_get_active_layer(&me->vdata, CD_PAINTMASK);
/* if using UV mapping, check for a matching MTFace layer */
if(tex_slot->texco == TEXCO_UV) {
mtfaces = CustomData_get_layer_named(&me->fdata, CD_MTFACE,
tex_slot->uvname);
}
/* the MTFace mask is needed only for multires+UV */
dm = mesh_get_derived_final(scene, ob,
(mtfaces && mmd) ? CD_MASK_MTFACE : 0);
/* use the subdivided UVs for multires */
if(mtfaces && mmd) {
mtfaces = CustomData_get_layer_named(&dm->faceData,
CD_MTFACE,
tex_slot->uvname);
}
/* update the pbvh */
ps->pbvh = pbvh = dm->getPBVH(ob, dm);
/* get all nodes in the pbvh */
BLI_pbvh_search_gather(pbvh,
NULL, NULL,
&nodes, &totnode);
if(mmd) {
/* For all grids, find offset into mtfaces and apply
the texture to the grid */
for(n = 0; n < totnode; ++n) {
DMGridData **grids;
GridKey *gridkey;
int *grid_indices, totgrid, gridsize;
pbvh_undo_push_node(nodes[n], PBVH_UNDO_PMASK, ob, scene);
BLI_pbvh_node_get_grids(pbvh, nodes[n], &grid_indices,
&totgrid, NULL, &gridsize,
&grids, NULL, &gridkey);
for(i = 0; i < totgrid; ++i) {
int grid_index = grid_indices[i];
MTFace *mtface = NULL;
if(mtfaces) {
mtface = &mtfaces[grid_index *
((gridsize-1) *
(gridsize-1))];
}
mask_grid_from_tex(grids[grid_index],
gridsize, gridkey,
mtface, tex_slot, active);
}
BLI_pbvh_node_set_flags(nodes[n],
SET_INT_IN_POINTER(PBVH_UpdateColorBuffers));
}
multires_mark_as_modified(ob);
}
else {
float *pmask = CustomData_get_layer(&me->vdata, CD_PAINTMASK);
for(n = 0; n < totnode; ++n) {
MFace *mface;
int *face_indices, totface;
pbvh_undo_push_node(nodes[n], PBVH_UNDO_PMASK, ob, scene);
BLI_pbvh_node_get_faces(pbvh, nodes[n], &mface,
&face_indices, NULL, &totface);
for(i = 0; i < totface; ++i) {
int face_index = face_indices[i];
MTFace *mtface = NULL;
if(mtfaces)
mtface = mtfaces + face_index;
mask_face_from_tex(me->mface + face_index,
me->mvert, mtface,
pmask, tex_slot, active);
}
BLI_pbvh_node_set_flags(nodes[n],
SET_INT_IN_POINTER(PBVH_UpdateColorBuffers));
}
}
MEM_freeN(nodes);
pbvh_undo_push_end();
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
return OPERATOR_FINISHED;
}
/* fills a mask with intensity values from a texture, using an
mtex to provide mapping */
void PAINT_OT_mask_from_texture(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Mask From Texture";
ot->idname= "PAINT_OT_mask_from_texture";
/* api callbacks */
ot->exec= paint_mask_from_texture_exec;
ot->poll= mask_active_poll;
/* flags */
ot->flag= OPTYPE_REGISTER;
}
static void set_mask_value(MaskSetMode mode, float *m)
{
*m = (mode == MASKING_CLEAR ? 0 :
mode == MASKING_FILL ? 1 :
mode == MASKING_INVERT ? (1 - *m) :
mode == MASKING_RANDOM ? (float)rand() / RAND_MAX : 0);
}
static int paint_mask_set_exec(bContext *C, wmOperator *op)
{
MaskSetMode mode = RNA_enum_get(op->ptr, "mode");
struct Scene *scene;
Object *ob;
DerivedMesh *dm;
struct MultiresModifierData *mmd;
PaintSession *ps;
Mesh *me;
PBVH *pbvh;
scene = CTX_data_scene(C);
ob = CTX_data_active_object(C);
ps = ob->paint;
me = get_mesh(ob);
mmd = ED_paint_multires_active(scene, ob);
dm = mesh_get_derived_final(scene, ob, 0);
ps->pbvh = pbvh = dm->getPBVH(ob, dm);
if(pbvh) {
PBVHNode **nodes;
int n, totnode;
BLI_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
pbvh_undo_push_begin("Paint mask fill");
for(n=0; n<totnode; n++) {
PBVHVertexIter vd;
pbvh_undo_push_node(nodes[n], PBVH_UNDO_PMASK, ob, scene);
BLI_pbvh_vertex_iter_begin(pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if(vd.mask_active)
set_mask_value(mode, vd.mask_active);
}
BLI_pbvh_vertex_iter_end;
BLI_pbvh_node_set_flags(nodes[n], SET_INT_IN_POINTER(PBVH_UpdateColorBuffers|PBVH_UpdateRedraw));
}
if(nodes)
MEM_freeN(nodes);
if(mmd)
multires_mark_as_modified(ob);
pbvh_undo_push_end();
WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob);
}
return OPERATOR_FINISHED;
}
/* fills up a mask for the entire object, setting each vertex to
either 0, 1, or a random value */
void PAINT_OT_mask_set(wmOperatorType *ot)
{
static EnumPropertyItem mask_items[] = {
{MASKING_CLEAR, "CLEAR", 0, "Clear", ""},
{MASKING_FILL, "FILL", 0, "Fill", ""},
{MASKING_INVERT, "INVERT", 0, "Invert", ""},
{MASKING_RANDOM, "RANDOM", 0, "Random", ""},
{0, NULL, 0, NULL, NULL}};
/* identifiers */
ot->name= "Set Mask";
ot->idname= "PAINT_OT_mask_set";
/* api callbacks */
ot->exec= paint_mask_set_exec;
ot->poll= mask_active_poll;
/* flags */
ot->flag= OPTYPE_REGISTER;
/* properties */
RNA_def_enum(ot->srna, "mode", mask_items, MASKING_CLEAR, "Mode", "");
}
/* if this is a multires mesh, update it and free the DM.
returns 1 if this is a multires mesh, 0 otherwise */
static int paintmask_check_multires(bContext *C)
{
struct Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
if(ED_paint_multires_active(scene, ob)) {
multires_force_update(ob);
return 1;
}
return 0;
}
static int mask_layer_poll(bContext *C)
{
return mask_poll(C) && ED_mesh_layers_poll(C);
}
static int mask_layer_add_exec(bContext *C, wmOperator *op)
{
Object *ob= CTX_data_active_object(C);
Mesh *me= ob->data;
int multires, top, first;
char *layer_name;
PaintLayerUndoNode *unode;
unode = paint_layer_undo_push(CD_PAINTMASK, "Add mask layer");
multires = paintmask_check_multires(C);
top= CustomData_number_of_layers(&me->vdata, CD_PAINTMASK);
CustomData_add_layer(&me->vdata, CD_PAINTMASK, CD_DEFAULT,
NULL, me->totvert);
first = CustomData_get_layer_index(&me->vdata, CD_PAINTMASK);
assert(first >= 0);
me->vdata.layers[first + top].flag |= CD_FLAG_MULTIRES;
CustomData_set_layer_active(&me->vdata, CD_PAINTMASK, top);
layer_name = me->vdata.layers[first + top].name;
/* now that we have correct name, update multires and finish undo push */
if(multires) {
CustomDataMultires *cdm;
cdm = CustomData_get_layer(&me->fdata, CD_GRIDS);
CustomData_multires_add_layers(cdm, me->totface,
CD_PAINTMASK, layer_name);
}
paint_layer_undo_set_add(unode, layer_name);
paintmask_redraw(C);
return OPERATOR_FINISHED;
}
static int mask_layer_remove_exec(bContext *C, wmOperator *op)
{
Object *ob= CTX_data_active_object(C);
Mesh *me= ob->data;
int active_offset, first;
active_offset = CustomData_get_active_layer(&me->vdata, CD_PAINTMASK);
if(active_offset >= 0) {
PaintLayerUndoNode *unode;
int multires = paintmask_check_multires(C);
char *layer_name;
unode = paint_layer_undo_push(CD_PAINTMASK,
"Remove mask layer");
first = CustomData_get_layer_index(&me->vdata, CD_PAINTMASK);
layer_name = me->vdata.layers[first + active_offset].name;
paint_layer_undo_set_remove(unode, layer_name,
&me->vdata, &me->fdata,
me->totvert, me->totface);
if(multires) {
CustomDataMultires *cdm;
cdm = CustomData_get_layer(&me->fdata, CD_GRIDS);
CustomData_multires_remove_layers(cdm, me->totface,
CD_PAINTMASK,
layer_name);
}
CustomData_free_layer_active(&me->vdata, CD_PAINTMASK,
me->totvert);
paintmask_redraw(C);
}
else
return OPERATOR_CANCELLED;
return OPERATOR_FINISHED;
}
void PAINT_OT_mask_layer_add(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Add Mask Layer";
ot->description= "Add a paint mask layer";
ot->idname= "PAINT_OT_mask_layer_add";
/* api callbacks */
ot->poll= mask_layer_poll;
ot->exec= mask_layer_add_exec;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
void PAINT_OT_mask_layer_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Remove Mask Layer";
ot->description= "Remove the active paint mask layer";
ot->idname= "PAINT_OT_mask_layer_remove";
/* api callbacks */
ot->poll= mask_layer_poll;
ot->exec= mask_layer_remove_exec;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}

View File

@@ -19,6 +19,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -216,11 +217,29 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);
WM_operatortype_append(PAINT_OT_vertex_paint);
WM_operatortype_append(PAINT_OT_vertex_color_set);
WM_operatortype_append(PAINT_OT_overlay_manipulate);
/* ptex */
WM_operatortype_append(PTEX_OT_layer_add);
WM_operatortype_append(PTEX_OT_layer_remove);
WM_operatortype_append(PTEX_OT_layer_save);
WM_operatortype_append(PTEX_OT_layer_convert);
WM_operatortype_append(PTEX_OT_open);
WM_operatortype_append(PTEX_OT_face_resolution_set);
WM_operatortype_append(PTEX_OT_subface_select);
WM_operatortype_append(PTEX_OT_select_all);
WM_operatortype_append(PTEX_OT_subface_flag_set);
/* face-select */
WM_operatortype_append(PAINT_OT_face_select_linked);
WM_operatortype_append(PAINT_OT_face_select_linked_pick);
WM_operatortype_append(PAINT_OT_face_select_all);
/* mask */
WM_operatortype_append(PAINT_OT_mask_layer_add);
WM_operatortype_append(PAINT_OT_mask_layer_remove);
WM_operatortype_append(PAINT_OT_mask_set);
WM_operatortype_append(PAINT_OT_mask_from_texture);
}
@@ -301,6 +320,19 @@ static void ed_keymap_paint_brush_size(wmKeyMap *keymap, const char *UNUSED(path
RNA_float_set(kmi->ptr, "scalar", 10.0/9.0); // 1.1111....
}
static void ed_keymap_paint_overlay(wmKeyMap *keymap)
{
wmKeyMapItem *kmi;
kmi = WM_keymap_add_item(keymap, "PAINT_OT_overlay_manipulate", GKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "action", PAINT_MANIP_GRAB);
kmi = WM_keymap_add_item(keymap, "PAINT_OT_overlay_manipulate", SKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "action", PAINT_MANIP_SCALE);
kmi = WM_keymap_add_item(keymap, "PAINT_OT_overlay_manipulate", RKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "action", PAINT_MANIP_ROTATE);
kmi= WM_keymap_add_item(keymap, "WM_OT_context_toggle", IKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.paint_overlay.enabled");
}
void ED_keymap_paint(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
@@ -318,6 +350,12 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", WM_BRUSHSTROKE_NORMAL);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", WM_BRUSHSTROKE_INVERT);
RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_BRUSHSTROKE_SMOOTH);
WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", EVT_TWEAK_L, KM_ANY, KM_CTRL|KM_SHIFT, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", EVT_TWEAK_L, KM_ANY, KM_CTRL|KM_ALT, 0)->ptr, "hide_inside", 1);
RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", LEFTMOUSE, KM_RELEASE, KM_CTRL|KM_SHIFT, 0)->ptr, "show_all", 1);
RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", LEFTMOUSE, KM_RELEASE, KM_CTRL|KM_ALT, 0)->ptr, "show_all", 1);
RNA_boolean_set(WM_keymap_add_item(keymap, "SCULPT_OT_area_hide", HKEY, KM_PRESS, KM_ALT, 0)->ptr, "show_all", 1);
//stroke_mode_modal_keymap(keyconf);
@@ -394,16 +432,41 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_vertex_paint_radial_control", FKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", WM_RADIALCONTROL_STRENGTH);
WM_keymap_verify_item(keymap, "PAINT_OT_vertex_paint", LEFTMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_sample_color", RIGHTMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap,
"PAINT_OT_vertex_color_set",KKEY, KM_PRESS, KM_SHIFT, 0);
/* ptex edit mode */
WM_keymap_add_item(keymap, "PTEX_OT_subface_select", RIGHTMOUSE, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_select", RIGHTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", 1);
WM_keymap_add_item(keymap, "PTEX_OT_select_all", AKEY, KM_PRESS, 0, 0);
/* ptex subface hiding */
kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_flag_set", HKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "flag", MPTEX_SUBFACE_HIDDEN);
kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_flag_set", HKEY, KM_PRESS, KM_ALT, 0);
RNA_enum_set(kmi->ptr, "flag", MPTEX_SUBFACE_HIDDEN);
RNA_boolean_set(kmi->ptr, "ignore_unselected", 0);
RNA_boolean_set(kmi->ptr, "ignore_hidden", 0);
RNA_boolean_set(kmi->ptr, "set", 0);
/* ptex subface mask */
kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_flag_set", MKEY, KM_PRESS, 0, 0);
RNA_enum_set(kmi->ptr, "flag", MPTEX_SUBFACE_MASKED);
kmi = WM_keymap_add_item(keymap, "PTEX_OT_subface_flag_set", MKEY, KM_PRESS, KM_ALT, 0);
RNA_enum_set(kmi->ptr, "flag", MPTEX_SUBFACE_MASKED);
RNA_boolean_set(kmi->ptr, "ignore_unselected", 0);
RNA_boolean_set(kmi->ptr, "ignore_hidden", 0);
RNA_boolean_set(kmi->ptr, "set", 0);
ed_keymap_paint_brush_switch(keymap, "tool_settings.vertex_paint.active_brush_index");
ed_keymap_paint_brush_size(keymap, "tool_settings.vertex_paint.brush.size");
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */
RNA_string_set(kmi->ptr, "data_path", "vertex_paint_object.data.use_paint_mask");
ed_keymap_paint_overlay(keymap);
/* Weight Paint mode */
keymap= WM_keymap_find(keyconf, "Weight Paint", 0, 0);
keymap->poll= weight_paint_mode_poll;
@@ -442,6 +505,8 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* mask toggle */
RNA_string_set(kmi->ptr, "data_path", "texture_paint_object.data.use_paint_mask");
ed_keymap_paint_overlay(keymap);
/* face-mask mode */
keymap= WM_keymap_find(keyconf, "Face Mask", 0, 0);
keymap->poll= facemask_paint_poll;

View File

@@ -0,0 +1,427 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2010 by Nicholas Bishop
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): None
*
* ***** END GPL LICENSE BLOCK *****
*
*/
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "BLI_math.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_view3d.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "UI_resources.h"
#include "paint_intern.h"
#include <math.h>
int paint_sample_overlay(PaintStroke *stroke, float col[3], float co[2])
{
ViewContext *vc = paint_stroke_view_context(stroke);
PaintOverlay *overlay = &vc->scene->toolsettings->paint_overlay;
col[0] = col[1] = col[2] = col[3] = 0;
if(overlay->use && overlay->img) {
ImBuf *ibuf = BKE_image_get_ibuf(overlay->img, NULL);
if(ibuf) {
int x, y;
int offset, trans[2];
float uco[3], proj[2];
paint_stroke_symmetry_unflip(stroke, uco, co);
paint_stroke_project(stroke, uco, proj);
paint_overlay_transform(overlay, vc->ar, ibuf,
trans, proj, 1, 1);
x = trans[0];
y = trans[1];
if(x >= 0 && x < ibuf->x && y >= 0 && y < ibuf->y) {
offset = y*ibuf->x + x;
if(ibuf->rect) {
char *ccol = ((char*)ibuf->rect) + offset*4;
col[0] = ccol[0] / 255.0;
col[1] = ccol[1] / 255.0;
col[2] = ccol[2] / 255.0;
col[3] = ccol[3] / 255.0;
}
}
}
return 1;
}
return 0;
}
static int paint_overlay_poll(bContext *C)
{
PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
if(vertex_paint_poll(C) || image_texture_paint_poll(C))
return overlay->img && overlay->use;
return 0;
}
void ED_paint_update_overlay(PaintOverlay *overlay)
{
if(overlay->gltex) {
glDeleteTextures(1, &overlay->gltex);
overlay->gltex = 0;
}
}
void ED_paint_overlay_draw(const bContext *C, ARegion *ar)
{
PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
ImBuf *ibuf;
int center[2];
int sx, sy;
if(!paint_overlay_poll((bContext*)C))
return;
ibuf = BKE_image_get_ibuf(overlay->img, NULL);
if(!ibuf)
return;
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
if(!overlay->gltex) {
/* update gl texture */
/* doing this manually because it looks like the GPU
Image stuff is customized on mesh tex? */
glGenTextures(1, (GLuint*)&overlay->gltex);
glBindTexture(GL_TEXTURE_2D, overlay->gltex);
if ((ibuf->rect==NULL) && ibuf->rect_float)
IMB_rect_from_float(ibuf);
{
char *bc = (char*)ibuf->rect;
char transp[3] = {overlay->transp_col[0] * 255,
overlay->transp_col[1] * 255,
overlay->transp_col[2] * 255};
int i;
for(i = 0; i < ibuf->y*ibuf->x; ++i, bc+=4) {
float d[3] = {fabs(bc[2]-transp[0]),
fabs(bc[1]-transp[1]),
fabs(bc[0]-transp[2])};
if(d[0] < overlay->transp_tol &&
d[1] < overlay->transp_tol &&
d[2] < overlay->transp_tol)
bc[3] = 0;
else
bc[3] = 255;
}
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ibuf->x, ibuf->y,
0, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
}
glBindTexture(GL_TEXTURE_2D, overlay->gltex);
glColor4f(1, 1, 1, 0.5);
glPushMatrix();
center[0] = ar->winx/2 + overlay->offset[0];
center[1] = ar->winy/2 + overlay->offset[1];
sx = overlay->size[0] / 2;
sy = overlay->size[1] / 2;
glTranslatef(center[0], center[1], 0);
glRotatef(overlay->angle * 180/M_PI, 0, 0, 1);
/* draw textured quad */
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex2f(-sx, -sy);
glTexCoord2f(1, 0);
glVertex2f(+sx, -sy);
glTexCoord2f(1, 1);
glVertex2f(+sx, +sy);
glTexCoord2f(0, 1);
glVertex2f(-sx, +sy);
glEnd();
glPopMatrix();
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
/* convert screen-space coords to ibuf coords */
void paint_overlay_transform(PaintOverlay *overlay, ARegion *ar, ImBuf *ibuf,
int out[2], float vec[2], int scale, int rotate)
{
float center[2], size[2], org[2], t1[2], t2[2];
float sina, cosa;
center[0] = ar->winx/2 + overlay->offset[0];
center[1] = ar->winy/2 + overlay->offset[1];
size[0] = overlay->size[0];
size[1] = overlay->size[1];
org[0] = center[0] - size[0]/2;
org[1] = center[1] - size[1]/2;
sina = sin(overlay->angle);
cosa = cos(overlay->angle);
/* make overlay center origin */
sub_v2_v2v2(t1, vec, center);
/* apply rotation */
if(rotate) {
t2[0] = cosa*t1[0] + sina*t1[1];
t2[1] = -sina*t1[0] + cosa*t1[1];
}
else {
out[0] = t1[0];
out[1] = t1[1];
t2[0] = t1[0];
t2[1] = t1[1];
}
/* translation */
if(scale) {
out[0] = t2[0] + size[0]/2;
out[1] = t2[1] + size[1]/2;
/* scale */
out[0] *= (ibuf->x / size[0]);
out[1] *= (ibuf->y / size[1]);
}
else {
out[0] = t2[0];
out[1] = t2[1];
}
}
typedef struct {
int x, y;
int offset[2];
int size[2];
float orig_angle, start_angle;
ImBuf *ibuf;
int ibuf_mouse[2];
void *draw_cb_handle;
struct ARegionType *draw_cb_type;
/* data needed for manip draw */
PaintManipAction action;
int cur_mouse[2];
} VPaintManipData;
/* when rotating or scaling, draw hashed line to center */
static void paint_overlay_manip_draw(const bContext *C, ARegion *ar, void *data_v)
{
PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
VPaintManipData *data = data_v;
if(data->action != PAINT_MANIP_GRAB) {
UI_ThemeColor(TH_WIRE);
setlinestyle(3);
glBegin(GL_LINES);
glVertex2i(data->cur_mouse[0] - ar->winrct.xmin,
data->cur_mouse[1] - ar->winrct.ymin);
glVertex2i(ar->winx/2 + overlay->offset[0],
ar->winy/2 + overlay->offset[1]);
glEnd();
setlinestyle(0);
}
}
static int paint_overlay_manip_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
ARegion *ar = CTX_wm_region(C);
VPaintManipData *data;
float mouse[2] = {event->x - ar->winrct.xmin,
mouse[1] = event->y - ar->winrct.ymin};
int angle_mouse[2];
op->customdata = data = MEM_callocN(sizeof(VPaintManipData), "VPaintManipData");
data->x = event->x;
data->y = event->y;
data->offset[0] = overlay->offset[0];
data->offset[1] = overlay->offset[1];
data->size[0] = overlay->size[0];
data->size[1] = overlay->size[1];
data->orig_angle = overlay->angle;
data->ibuf = BKE_image_get_ibuf(overlay->img, NULL);
data->action = RNA_enum_get(op->ptr, "action");
data->cur_mouse[0] = event->x;
data->cur_mouse[1] = event->y;
paint_overlay_transform(overlay, ar, data->ibuf, data->ibuf_mouse, mouse, 0, 1);
paint_overlay_transform(overlay, ar, data->ibuf, angle_mouse, mouse, 0, 0);
data->start_angle = atan2(angle_mouse[0], angle_mouse[1]);
data->draw_cb_type = ar->type;
data->draw_cb_handle = ED_region_draw_cb_activate(ar->type,
paint_overlay_manip_draw,
data,
REGION_DRAW_POST_PIXEL);
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int paint_overlay_manip_modal(bContext *C, wmOperator *op, wmEvent *event)
{
PaintOverlay *overlay = &CTX_data_tool_settings(C)->paint_overlay;
ARegion *ar = CTX_wm_region(C);
float mouse[2] = {event->x - ar->winrct.xmin,
event->y - ar->winrct.ymin};
int ibuf_mouse[2];
int *co = overlay->offset;
int *size = overlay->size;
float *angle = &overlay->angle;
VPaintManipData *data = op->customdata;
int dx, dy;
dx = event->x - data->x;
dy = event->y - data->y;
data->cur_mouse[0] = event->x;
data->cur_mouse[1] = event->y;
switch(data->action) {
case PAINT_MANIP_GRAB:
co[0] = data->offset[0] + dx;
co[1] = data->offset[1] + dy;
break;
case PAINT_MANIP_SCALE:
{
float d[2];
paint_overlay_transform(overlay, ar, data->ibuf, ibuf_mouse, mouse, 0, 1);
d[0] = fabs(ibuf_mouse[0]) - fabs(data->ibuf_mouse[0]);
d[1] = fabs(ibuf_mouse[1]) - fabs(data->ibuf_mouse[1]);
size[0] = data->size[0] + d[0];
size[1] = data->size[1] + d[1];
}
break;
case PAINT_MANIP_ROTATE:
paint_overlay_transform(overlay, ar, data->ibuf, ibuf_mouse, mouse, 0, 0);
*angle = data->orig_angle + data->start_angle - atan2(ibuf_mouse[0], ibuf_mouse[1]);
break;
}
ED_region_tag_redraw(CTX_wm_region(C));
if(event->type == LEFTMOUSE) {
ED_region_draw_cb_exit(data->draw_cb_type, data->draw_cb_handle);
MEM_freeN(data);
return OPERATOR_FINISHED;
}
else if(event->type == RIGHTMOUSE) {
co[0] = data->offset[0];
co[1] = data->offset[1];
size[0] = data->size[0];
size[1] = data->size[1];
*angle = data->orig_angle;
ED_region_draw_cb_exit(data->draw_cb_type, data->draw_cb_handle);
MEM_freeN(data);
return OPERATOR_CANCELLED;
}
else
return OPERATOR_RUNNING_MODAL;
}
void PAINT_OT_overlay_manipulate(wmOperatorType *ot)
{
static EnumPropertyItem action_items[]= {
{PAINT_MANIP_GRAB, "GRAB", 0, "Grab", ""},
{PAINT_MANIP_SCALE, "SCALE", 0, "Scale", ""},
{PAINT_MANIP_ROTATE, "Rotate", 0, "Rotate", ""},
{0, NULL, 0, NULL, NULL}};
/* identifiers */
ot->name= "Paint Overlay Manipulate";
ot->idname= "PAINT_OT_overlay_manipulate";
/* api callbacks */
ot->invoke= paint_overlay_manip_invoke;
ot->modal= paint_overlay_manip_modal;
ot->poll= paint_overlay_poll;
/* flags */
ot->flag= OPTYPE_BLOCKING;
/* properties */
ot->prop= RNA_def_enum(ot->srna, "action", action_items, 0, "Action", "");
}

File diff suppressed because it is too large Load Diff

View File

@@ -34,15 +34,19 @@
#include "RNA_access.h"
#include "BKE_context.h"
#include "BKE_paint.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "WM_api.h"
#include "WM_types.h"
#include "BLI_math.h"
#include "BLI_rand.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -57,28 +61,62 @@
#include <float.h>
#include <math.h>
typedef struct PaintStroke {
struct PaintStroke {
void *mode_data;
void *smooth_stroke_cursor;
wmTimer *timer;
/* Cached values */
ViewContext vc;
float project_mat[4][4];
bglMats mats;
Brush *brush;
/* brush location (object space) */
float location[3], symmetry_location[3];
/* screen-space brush location */
float mouse[2], initial_mouse[2], last_mouse_position[2];
/* not always the same as brush_size() */
int pixel_radius;
/* tablet pressure, or 1 if using mouse */
float pressure;
/* 3d brush radius */
float radius, radius_squared, initial_radius;
/* previous location of updating rake rotation */
float last_rake[2];
/* this value is added to the brush's rotation in calculations */
float rotation;
/* mouse location used for texturing */
float tex_mouse[2];
/* symmetry */
/* current symmetry pass (0-7) */
int mirror_symmetry_pass;
int radial_symmetry_pass;
float symm_rot_mat[4][4];
float symm_rot_mat_inv[4][4];
/* decrease brush strength if symmetry overlaps */
float feather;
float last_mouse_position[2];
/* anything special that sculpt or other paint modes need
to do should go through these modifiers */
float modifier_initial_radius_factor;
int modifier_use_original_texture_coords;
int modifier_use_original_location;
/* Set whether any stroke step has yet occurred
e.g. in sculpt mode, stroke doesn't start until cursor
passes over the mesh */
int stroke_started;
/* 1 if this is the first paint dab, 0 otherwise */
int first_dab;
/* callbacks */
StrokeGetLocation get_location;
StrokeTestStart test_start;
StrokeUpdateStep update_step;
StrokeUpdateSymmetry update_symmetry;
StrokeBrushAction brush_action;
StrokeDone done;
} PaintStroke;
};
/*** Cursor ***/
static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata)
@@ -323,7 +361,7 @@ static int load_tex(Sculpt *sd, Brush* br, ViewContext* vc)
buffer = MEM_mallocN(sizeof(GLubyte)*size*size, "load_tex");
#pragma omp parallel for schedule(static) if (sd->flags & SCULPT_USE_OPENMP)
#pragma omp parallel for schedule(static) if (sd->paint.flags & PAINT_USE_OPENMP)
for (j= 0; j < size; j++) {
int i;
float y;
@@ -436,7 +474,7 @@ static void projectf(bglMats *mats, const float v[3], float p[2])
p[1]= uy;
}
static int project_brush_radius(RegionView3D* rv3d, float radius, float location[3], bglMats* mats)
int project_brush_radius(RegionView3D* rv3d, float radius, float location[3], bglMats* mats)
{
float view[3], nonortho[3], ortho[3], offset[3], p1[2], p2[2];
@@ -476,8 +514,10 @@ static int project_brush_radius(RegionView3D* rv3d, float radius, float location
return len_v2v2(p1, p2);
}
#if 0
int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, float location[3], float modelview[16], float projection[16], int viewport[4])
{
Object *ob = CTX_data_active_object(C);
struct PaintStroke *stroke;
float window[2];
int hit;
@@ -491,13 +531,13 @@ int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, floa
memcpy(projection, stroke->vc.rv3d->winmat, sizeof(float[16]));
memcpy(viewport, stroke->mats.viewport, sizeof(int[4]));
if (stroke->vc.obact->sculpt && stroke->vc.obact->sculpt->pbvh && sculpt_stroke_get_location(C, stroke, location, window)) {
if (ob && ob->paint && ob->paint->sculpt && ob->paint->pbvh && sculpt_stroke_get_location(C, stroke, location, window)) {
*pixel_radius = project_brush_radius(stroke->vc.rv3d, brush_unprojected_radius(stroke->brush), location, &stroke->mats);
if (*pixel_radius == 0)
*pixel_radius = brush_size(stroke->brush);
mul_m4_v3(stroke->vc.obact->sculpt->ob->obmat, location);
mul_m4_v3(ob->obmat, location);
hit = 1;
}
@@ -513,6 +553,7 @@ int sculpt_get_brush_geometry(bContext* C, int x, int y, int* pixel_radius, floa
return hit;
}
#endif
// XXX duplicated from sculpt.c
float unproject_brush_radius(Object *ob, ViewContext *vc, float center[3], float offset)
@@ -543,14 +584,16 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
(void)unused;
view3d_set_viewcontext(C, &vc);
if (vc.obact->sculpt) {
// XXX
#if 0
if (vc.obact->paint && vc.obact->paint->sculpt) {
Paint *paint = paint_get_active(CTX_data_scene(C));
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = paint_brush(paint);
int pixel_radius, viewport[4];
float location[3], modelview[16], projection[16];
int pixel_radius = 0, viewport[4];
float location[3]; // XXX: modelview[16], projection[16];
int hit;
@@ -585,7 +628,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
if(!brush_use_locked_size(brush) && !(paint->flags & PAINT_SHOW_BRUSH))
return;
hit = sculpt_get_brush_geometry(C, x, y, &pixel_radius, location, modelview, projection, viewport);
hit = 0;
if (brush_use_locked_size(brush))
brush_set_size(brush, pixel_radius);
@@ -625,7 +668,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) {
glTranslatef(0.5f, 0.5f, 0);
@@ -767,7 +810,11 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
glPopAttrib();
}
else {
//else
#endif
{
Paint *paint = paint_get_active(CTX_data_scene(C));
Brush *brush = paint_brush(paint);
@@ -787,73 +834,271 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *unused)
}
}
/**** Symmetry ****/
float calc_overlap(PaintStroke *stroke, float location[3], char symm, char axis, float angle)
{
float mirror[3];
float distsq;
float mat[4][4];
//paint_flip_coord(mirror, cache->traced_location, symm);
paint_flip_coord(mirror, location, symm);
unit_m4(mat);
rotate_m4(mat, axis, angle);
mul_m4_v3(mat, mirror);
//distsq = len_squared_v3v3(mirror, cache->traced_location);
distsq = len_squared_v3v3(mirror, location);
if (distsq <= 4*stroke->radius_squared)
return (2*stroke->radius - sqrt(distsq)) / (2*stroke->radius);
else
return 0;
}
static float calc_radial_symmetry_feather(PaintStroke *stroke, Paint *paint,
float location[3], char symm, char axis)
{
int i;
float overlap;
overlap = 0;
for(i = 1; i < paint->radial_symm[axis-'X']; ++i) {
const float angle = 2*M_PI*i / paint->radial_symm[axis-'X'];
overlap += calc_overlap(stroke, location, symm, axis, angle);
}
return overlap;
}
static float calc_symmetry_feather(PaintStroke *stroke, Paint *paint, float location[3], char symm)
{
if(paint->flags & PAINT_SYMMETRY_FEATHER) {
float overlap;
int i;
overlap = 0;
for (i = 0; i <= symm; i++) {
if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
overlap += calc_overlap(stroke, location, i, 0, 0);
overlap += calc_radial_symmetry_feather(stroke, paint, location, i, 'X');
overlap += calc_radial_symmetry_feather(stroke, paint, location, i, 'Y');
overlap += calc_radial_symmetry_feather(stroke, paint, location, i, 'Z');
}
}
return 1/overlap;
}
else {
return 1;
}
}
/* flip data across the axes specified by symm */
static void calc_symm(bContext *C, PaintStroke *stroke, float location[3], char symm,
char axis, float angle)
{
/* radial symmetry */
unit_m4(stroke->symm_rot_mat);
rotate_m4(stroke->symm_rot_mat, axis, angle);
unit_m4(stroke->symm_rot_mat_inv);
rotate_m4(stroke->symm_rot_mat_inv, axis, -angle);
/* symmetry_location */
paint_flip_coord(location, location, symm);
mul_m4_v3(stroke->symm_rot_mat, location);
copy_v3_v3(stroke->symmetry_location, location);
/* callback */
if(stroke->update_symmetry) {
stroke->update_symmetry(C, stroke, symm, axis,
angle,
stroke->mirror_symmetry_pass,
stroke->radial_symmetry_pass,
stroke->symm_rot_mat);
}
}
static void do_radial_symmetry(bContext *C, PaintStroke *stroke, Paint *paint, char symm, int axis, float feather)
{
int i;
for(i = 1; i < paint->radial_symm[axis-'X']; ++i) {
const float angle = 2*M_PI*i / paint->radial_symm[axis-'X'];
float location[3];
stroke->radial_symmetry_pass= i;
copy_v3_v3(location, stroke->location);
calc_symm(C, stroke, location, symm, axis, angle);
stroke->brush_action(C, stroke);
}
}
static void paint_stroke_update_cache(bContext *C, PaintStroke *stroke, Paint *paint)
{
ViewContext *vc = &stroke->vc;
if(stroke->first_dab) {
copy_v2_v2(stroke->initial_mouse, stroke->mouse);
copy_v2_v2(stroke->tex_mouse, stroke->initial_mouse);
if(!brush_use_locked_size(stroke->brush)) {
stroke->initial_radius =
paint_calc_object_space_radius(vc,
stroke->location,
brush_size(stroke->brush));
brush_set_unprojected_radius(stroke->brush, stroke->initial_radius);
}
else
stroke->initial_radius= brush_unprojected_radius(stroke->brush);
stroke->initial_radius *= stroke->modifier_initial_radius_factor;
}
stroke->pixel_radius = brush_size(stroke->brush);
stroke->radius = stroke->initial_radius;
stroke->feather = calc_symmetry_feather(stroke, paint, stroke->location, paint->flags & 7);
if(brush_use_size_pressure(stroke->brush)) {
stroke->pixel_radius *= stroke->pressure;
stroke->radius *= stroke->pressure;
}
if(!((stroke->brush->flag & BRUSH_ANCHORED) ||
stroke->modifier_use_original_texture_coords)) {
copy_v2_v2(stroke->tex_mouse, stroke->mouse);
if((stroke->brush->mtex.brush_map_mode == MTEX_MAP_MODE_FIXED) &&
(stroke->brush->flag & BRUSH_RANDOM_ROTATION) &&
!(stroke->brush->flag & BRUSH_RAKE)) {
stroke->rotation = 2*M_PI*BLI_frand();
}
}
if(stroke->brush->flag & BRUSH_ANCHORED) {
int dx, dy;
dx = stroke->mouse[0] - stroke->initial_mouse[0];
dy = stroke->mouse[1] - stroke->initial_mouse[1];
stroke->pixel_radius = sqrt(dx*dx + dy*dy);
stroke->rotation = atan2(dx, dy) + M_PI;
if(stroke->brush->flag & BRUSH_EDGE_TO_EDGE) {
float d[3];
float halfway[3];
float out[3];
d[0] = dx;
d[1] = dy;
d[2] = 0;
mul_v3_v3fl(halfway, d, 0.5f);
add_v3_v3(halfway, stroke->initial_mouse);
if(stroke->get_location(C, stroke, out, halfway)) {
copy_v2_v2(stroke->tex_mouse, halfway);
copy_v3_v3(stroke->location, out);
stroke->pixel_radius /= 2.0f;
}
}
stroke->radius= paint_calc_object_space_radius(&stroke->vc,
stroke->location,
stroke->pixel_radius);
}
else if(stroke->brush->flag & BRUSH_RAKE) {
const float u = 0.5f;
const float r = 20;
const float dx = stroke->last_rake[0] - stroke->mouse[0];
const float dy = stroke->last_rake[1] - stroke->mouse[1];
if(stroke->first_dab) {
copy_v2_v2(stroke->last_rake, stroke->mouse);
}
else if (dx*dx + dy*dy >= r*r) {
stroke->rotation = atan2(dx, dy);
interp_v2_v2v2(stroke->last_rake, stroke->mouse, stroke->last_rake, u);
}
}
stroke->radius_squared = stroke->radius*stroke->radius;
}
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, wmEvent *event, float mouse_in[2])
{
Paint *paint = paint_get_active(CTX_data_scene(C)); // XXX
Brush *brush = paint_brush(paint); // XXX
float mouse[3];
PointerRNA itemptr;
float location[3];
float pressure;
int pen_flip;
ViewContext vc; // XXX
Paint *paint = paint_get_active(CTX_data_scene(C));
PaintStroke *stroke = op->customdata;
PointerRNA itemptr;
int pen_flip;
view3d_set_viewcontext(C, &vc); // XXX
view3d_get_object_project_mat(stroke->vc.rv3d, stroke->vc.obact, stroke->project_mat);
/* Tablet */
if(event->custom == EVT_DATA_TABLET) {
wmTabletData *wmtab= event->customdata;
pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
stroke->pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
pen_flip = (wmtab->Active == EVT_TABLET_ERASER);
}
else {
pressure = 1;
stroke->pressure = 1;
pen_flip = 0;
}
// XXX: temporary check for sculpt mode until things are more unified
if (vc.obact->sculpt) {
if(stroke->vc.obact->paint && stroke->vc.obact->paint->sculpt) {
float delta[3];
brush_jitter_pos(brush, mouse_in, mouse);
brush_jitter_pos(stroke->brush, mouse_in, stroke->mouse);
// XXX: meh, this is round about because brush_jitter_pos isn't written in the best way to be reused here
if (brush->flag & BRUSH_JITTER_PRESSURE) {
sub_v3_v3v3(delta, mouse, mouse_in);
mul_v3_fl(delta, pressure);
add_v3_v3v3(mouse, mouse_in, delta);
if(stroke->brush->flag & BRUSH_JITTER_PRESSURE) {
sub_v3_v3v3(delta, stroke->mouse, mouse_in);
mul_v3_fl(delta, stroke->pressure);
add_v3_v3v3(stroke->mouse, mouse_in, delta);
}
}
else
copy_v3_v3(mouse, mouse_in);
copy_v2_v2(stroke->mouse, mouse_in);
/* XXX: can remove the if statement once all modes have this */
if(stroke->get_location)
stroke->get_location(C, stroke, location, mouse);
else
zero_v3(location);
if(stroke->first_dab ||
!((stroke->brush->flag & BRUSH_ANCHORED) ||
stroke->modifier_use_original_location)) {
/* XXX: can remove the following if statement once all modes have this */
if(stroke->get_location)
stroke->get_location(C, stroke, stroke->location, stroke->mouse);
else
zero_v3(stroke->location);
}
/* Add to stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
RNA_float_set_array(&itemptr, "location", location);
RNA_float_set_array(&itemptr, "mouse", mouse);
RNA_float_set_array(&itemptr, "location", stroke->location);
RNA_float_set_array(&itemptr, "mouse", stroke->mouse);
RNA_boolean_set (&itemptr, "pen_flip", pen_flip);
RNA_float_set (&itemptr, "pressure", pressure);
RNA_float_set(&itemptr, "pressure", stroke->pressure);
stroke->last_mouse_position[0] = mouse[0];
stroke->last_mouse_position[1] = mouse[1];
copy_v2_v2(stroke->last_mouse_position, stroke->mouse);
paint_stroke_update_cache(C, stroke, paint);
stroke->update_step(C, stroke, &itemptr);
stroke->first_dab = 0;
}
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
@@ -862,7 +1107,7 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], wmEvent *ev
output[0] = event->x;
output[1] = event->y;
if ((stroke->brush->flag & BRUSH_SMOOTH_STROKE) &&
if((stroke->brush->flag & BRUSH_SMOOTH_STROKE) &&
!ELEM4(stroke->brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_THUMB, SCULPT_TOOL_ROTATE, SCULPT_TOOL_SNAKE_HOOK) &&
!(stroke->brush->flag & BRUSH_ANCHORED) &&
!(stroke->brush->flag & BRUSH_RESTORE_MESH))
@@ -919,7 +1164,7 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
pressure = brush_use_size_pressure(stroke->brush) ? wmtab->Pressure : 1;
}
scale = (brush_size(stroke->brush)*pressure*stroke->brush->spacing/50.0f) / length;
scale = (brush_size(stroke->brush) * pressure * stroke->brush->spacing/50.0f) / length;
mul_v2_fl(vec, scale);
steps = (int)(1.0f / scale);
@@ -937,20 +1182,25 @@ static int paint_space_stroke(bContext *C, wmOperator *op, wmEvent *event, const
/**** Public API ****/
PaintStroke *paint_stroke_new(bContext *C,
StrokeGetLocation get_location,
StrokeTestStart test_start,
StrokeUpdateStep update_step,
StrokeDone done)
StrokeGetLocation get_location,
StrokeTestStart test_start,
StrokeUpdateStep update_step,
StrokeUpdateSymmetry update_symmetry,
StrokeBrushAction brush_action,
StrokeDone done)
{
PaintStroke *stroke = MEM_callocN(sizeof(PaintStroke), "PaintStroke");
stroke->brush = paint_brush(paint_get_active(CTX_data_scene(C)));
view3d_set_viewcontext(C, &stroke->vc);
view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
stroke->modifier_initial_radius_factor = 1;
stroke->get_location = get_location;
stroke->test_start = test_start;
stroke->update_step = update_step;
stroke->update_symmetry = update_symmetry;
stroke->brush_action = brush_action;
stroke->done = done;
return stroke;
@@ -965,7 +1215,6 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
{
PaintStroke *stroke = op->customdata;
float mouse[2];
int first= 0;
if(!stroke->stroke_started) {
stroke->last_mouse_position[0] = event->x;
@@ -978,9 +1227,10 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
if(stroke->brush->flag & BRUSH_AIRBRUSH)
stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
stroke->first_dab = 1;
}
first= 1;
//ED_region_tag_redraw(ar);
}
@@ -993,11 +1243,12 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
if(stroke->timer)
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), stroke->timer);
stroke->done(C, stroke);
if(stroke->stroke_started)
stroke->done(C, stroke);
MEM_freeN(stroke);
return OPERATOR_FINISHED;
}
else if(first || ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (event->type == TIMER && (event->customdata == stroke->timer))) {
else if(stroke->first_dab || ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) || (event->type == TIMER && (event->customdata == stroke->timer))) {
if(stroke->stroke_started) {
if(paint_smooth_stroke(stroke, mouse, event)) {
if(paint_space_stroke_enabled(stroke->brush)) {
@@ -1016,7 +1267,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
}
/* we want the stroke to have the first daub at the start location instead of waiting till we have moved the space distance */
if(first &&
if(stroke->first_dab &&
stroke->stroke_started &&
paint_space_stroke_enabled(stroke->brush) &&
!(stroke->brush->flag & BRUSH_ANCHORED) &&
@@ -1028,12 +1279,66 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
void paint_stroke_apply_brush(bContext *C, PaintStroke *stroke, Paint *paint)
{
char symm = paint->flags & 7;
float location[3];
int i;
/* symm is a bitwise combination of XYZ:
1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
for(i = 0; i <= symm; ++i) {
if(i == 0 || (symm & i && (symm != 5 || i != 3) && (symm != 6 || (i != 3 && i != 5)))) {
stroke->mirror_symmetry_pass= i;
stroke->radial_symmetry_pass= 0;
copy_v3_v3(location, stroke->location);
calc_symm(C, stroke, location, i, 0, 0);
stroke->brush_action(C, stroke);
do_radial_symmetry(C, stroke, paint, i, 'X', stroke->feather);
do_radial_symmetry(C, stroke, paint, i, 'Y', stroke->feather);
do_radial_symmetry(C, stroke, paint, i, 'Z', stroke->feather);
}
}
}
/* combines mask, curve, and texture strengths */
float paint_stroke_combined_strength(PaintStroke *stroke, float dist, float co[3], float mask)
{
float mco[3];
/* if the active area is being applied for symmetry, flip it
across the symmetry axis and rotate it back to the orignal
position in order to project it. This insures that the
brush texture will be oriented correctly. */
if(stroke->brush->mtex.tex) {
paint_stroke_symmetry_unflip(stroke, mco, co);
co = mco;
}
return brush_tex_strength(&stroke->vc,
stroke->project_mat, stroke->brush, co, mask, dist,
stroke->pixel_radius, stroke->radius,
stroke->rotation,
stroke->tex_mouse);
}
int paint_stroke_exec(bContext *C, wmOperator *op)
{
Paint *paint = paint_get_active(CTX_data_scene(C));
PaintStroke *stroke = op->customdata;
RNA_BEGIN(op->ptr, itemptr, "stroke") {
RNA_float_get_array(&itemptr, "location", stroke->location);
RNA_float_get_array(&itemptr, "mouse", stroke->mouse);
stroke->pressure = RNA_float_get(&itemptr, "pressure");
paint_stroke_update_cache(C, stroke, paint);
stroke->update_step(C, stroke, &itemptr);
stroke->first_dab = 0;
}
RNA_END;
@@ -1043,10 +1348,7 @@ int paint_stroke_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
ViewContext *paint_stroke_view_context(PaintStroke *stroke)
{
return &stroke->vc;
}
/**** mode data ****/
void *paint_stroke_mode_data(struct PaintStroke *stroke)
{
@@ -1058,6 +1360,106 @@ void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
stroke->mode_data = mode_data;
}
/**** cache access ***/
ViewContext *paint_stroke_view_context(PaintStroke *stroke)
{
return &stroke->vc;
}
float paint_stroke_feather(struct PaintStroke *stroke)
{
return stroke->feather;
}
void paint_stroke_mouse_location(PaintStroke *stroke, float mouse[2])
{
copy_v2_v2(mouse, stroke->mouse);
}
void paint_stroke_initial_mouse_location(PaintStroke *stroke, float initial_mouse[2])
{
copy_v2_v2(initial_mouse, stroke->initial_mouse);
}
void paint_stroke_location(PaintStroke *stroke, float location[3])
{
copy_v3_v3(location, stroke->location);
}
float paint_stroke_pressure(struct PaintStroke *stroke)
{
return stroke->pressure;
}
void paint_stroke_symmetry_location(struct PaintStroke *stroke, float loc[3])
{
copy_v3_v3(loc, stroke->symmetry_location);
}
float paint_stroke_radius(struct PaintStroke *stroke)
{
return stroke->radius;
}
float paint_stroke_radius_squared(struct PaintStroke *stroke)
{
return stroke->radius_squared;
}
int paint_stroke_first_dab(PaintStroke *stroke)
{
return stroke->first_dab;
}
void paint_stroke_project(PaintStroke *stroke, float loc[3], float out[2])
{
view3d_project_float(stroke->vc.ar, loc, out, stroke->project_mat);
}
void paint_stroke_symmetry_unflip(PaintStroke *stroke, float out[3], float vec[3])
{
paint_flip_coord(out, vec, stroke->mirror_symmetry_pass);
if(stroke->radial_symmetry_pass)
mul_m4_v3(stroke->symm_rot_mat_inv, out);
}
/**** stroke modifiers ****/
void paint_stroke_set_modifier_use_original_location(PaintStroke *stroke)
{
stroke->modifier_use_original_location = 1;
}
void paint_stroke_set_modifier_initial_radius_factor(PaintStroke *stroke,
float initial_radius_factor)
{
stroke->modifier_initial_radius_factor = initial_radius_factor;
}
void paint_stroke_set_modifier_use_original_texture_coords(PaintStroke *stroke)
{
stroke->modifier_use_original_texture_coords = 1;
}
/* returns 1 if the mouse is over the mesh, 0 otherwise */
int paint_stroke_over_mesh(bContext *C, PaintStroke *stroke, int x, int y)
{
float mouse[2] = {x, y}, co[3];
return stroke->get_location(C, stroke, co, mouse);
}
/* Do a raycast in the tree to find the 3d brush location
(This allows us to ignore the GL depth buffer)
Returns 0 if the ray doesn't hit the mesh, non-zero otherwise
*/
int paint_stroke_get_location(bContext *C, PaintStroke *stroke,
BLI_pbvh_HitOccludedCallback hit_cb, void *mode_data,
float out[3], float mouse[2], int original)
{
ViewContext *vc = paint_stroke_view_context(stroke);
return paint_util_raycast(vc, hit_cb, mode_data, out, mouse, original);
}
int paint_poll(bContext *C)
{
Paint *p = paint_get_active(CTX_data_scene(C));
@@ -1076,3 +1478,88 @@ void paint_cursor_start(bContext *C, int (*poll)(bContext *C))
p->paint_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), poll, paint_draw_cursor, NULL);
}
/* Optimization for testing if a coord is within the brush area */
void paint_stroke_test_init(PaintStrokeTest *test, PaintStroke *stroke)
{
test->radius_squared= stroke->radius_squared;
copy_v3_v3(test->location, stroke->symmetry_location);
}
int paint_stroke_test(PaintStrokeTest *test, float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
if(distsq <= test->radius_squared) {
test->dist = sqrt(distsq);
return 1;
}
else {
return 0;
}
}
int paint_stroke_test_sq(PaintStrokeTest *test, float co[3])
{
float distsq = len_squared_v3v3(co, test->location);
if(distsq <= test->radius_squared) {
test->dist = distsq;
return 1;
}
else {
return 0;
}
}
int paint_stroke_test_fast(PaintStrokeTest *test, float co[3])
{
return len_squared_v3v3(co, test->location) <= test->radius_squared;
}
int paint_stroke_test_cube(PaintStrokeTest *test, float co[3], float local[4][4])
{
const static float side = 0.70710678118654752440084436210485; // sqrt(.5);
float local_co[3];
mul_v3_m4v3(local_co, local, co);
local_co[0] = fabs(local_co[0]);
local_co[1] = fabs(local_co[1]);
local_co[2] = fabs(local_co[2]);
if (local_co[0] <= side && local_co[1] <= side && local_co[2] <= side) {
test->dist = MAX3(local_co[0], local_co[1], local_co[2]) / side;
return 1;
}
else {
return 0;
}
}
#if 0
static int paint_stroke_test_cyl(SculptBrushTest *test, float co[3], float location[3], float an[3])
{
if (paint_stroke_test_fast(test, co)) {
float t1[3], t2[3], t3[3], dist;
sub_v3_v3v3(t1, location, co);
sub_v3_v3v3(t2, x2, location);
cross_v3_v3v3(t3, an, t1);
dist = len_v3(t3)/len_v3(t2);
test->dist = dist;
return 1;
}
return 0;
}
#endif

View File

@@ -27,13 +27,20 @@
#include "MEM_guardedalloc.h"
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_userdef_types.h"
#include "BLI_listbase.h"
#include "BKE_mesh.h"
#include "BLI_string.h"
#include "BKE_utildefines.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_multires.h"
#include "ED_sculpt.h"
@@ -188,6 +195,242 @@ static void undo_stack_free(UndoStack *stack)
stack->current= NULL;
}
/**** paint undo for layers (mcol, paintmask) ****/
typedef enum {
LAYER_ADDED,
LAYER_REMOVED
} PaintLayerUndoOp;
struct PaintLayerUndoNode {
struct PaintLayerUndoNode *next, *prev;
/* customdata type */
int type;
/* add/remove */
PaintLayerUndoOp op;
/* only for restoring into its original location */
int layer_offset;
/* for identifying layer, don't use layer_offset for that */
char layer_name[32];
/* copy of a removed layer's data */
void *layer_data;
void **multires_layer_data;
float strength;
/* length of multires_layer_data array */
int totface;
/* whether layer has multires data */
int flag_multires;
};
void paint_layer_undo_set_add(PaintLayerUndoNode *unode, char *name)
{
unode->op = LAYER_ADDED;
/* check for restore */
if(unode->layer_name != name) {
BLI_strncpy(unode->layer_name, name,
sizeof(unode->layer_name));
}
unode->totface = 0;
}
void paint_layer_undo_set_remove(PaintLayerUndoNode *unode, char *name,
CustomData *data, CustomData *fdata,
int totvert, int totface)
{
CustomDataMultires *cdm;
int ndx;
unode->op = LAYER_REMOVED;
/* check for restore */
if(unode->layer_name != name) {
BLI_strncpy(unode->layer_name, name,
sizeof(unode->layer_name));
}
unode->totface = totface;
ndx = CustomData_get_named_layer_index(data, unode->type, name);
assert(ndx >= 0);
/* store the layer offset so we can re-insert layer at the
same location on undo */
unode->layer_offset =
ndx - CustomData_get_layer_index(data, unode->type);
/* backup layer data */
unode->layer_data = MEM_dupallocN(data->layers[ndx].data);
unode->strength = data->layers[ndx].strength;
unode->flag_multires = data->layers[ndx].flag & CD_FLAG_MULTIRES;
if(!unode->flag_multires)
return;
/* back multires data */
cdm = CustomData_get_layer(fdata, CD_GRIDS);
if(cdm && totface) {
int i;
/* check first cdm to see if this layer has multires data */
if(!CustomData_multires_get_data(cdm, unode->type, name))
return;
unode->multires_layer_data =
MEM_callocN(sizeof(void*) * totface,
"PaintLayerUndoNode.multires_layer_data");
for(i = 0; i < totface; ++i, ++cdm) {
float *f;
f = CustomData_multires_get_data(cdm, unode->type,
name);
assert(f);
unode->multires_layer_data[i] = MEM_dupallocN(f);
}
}
}
void paint_layer_undo_restore(bContext *C, ListBase *lb)
{
PaintLayerUndoNode *unode = lb->first; /* only one undo node */
Object *ob;
Mesh *me;
CustomData *data, *fdata;
CustomDataMultires *cdm;
int i, ndx, offset, active, totelem;
ob = CTX_data_active_object(C);
me = get_mesh(ob);
fdata = &me->fdata;
switch(unode->type) {
case CD_MCOL:
data = &me->fdata;
totelem = me->totface;
break;
case CD_PAINTMASK:
data = &me->vdata;
totelem = me->totface;
break;
default:
assert(0);
}
/* update multires before making changes */
if(ED_paint_multires_active(CTX_data_scene(C), ob))
multires_force_update(ob);
switch(unode->op) {
case LAYER_ADDED:
/* backup current layer data for redo */
paint_layer_undo_set_remove(unode, unode->layer_name, data,
fdata, me->totvert, me->totface);
active = CustomData_get_active_layer(data, unode->type);
/* remove layer */
ndx = CustomData_get_named_layer_index(data, unode->type,
unode->layer_name);
CustomData_free_layer(data, unode->type, totelem, ndx);
/* set active layer */
offset = CustomData_number_of_layers(data, unode->type) - 1;
if(active > offset)
active = offset;
CustomData_set_layer_active(data, unode->type, active);
/* remove layer's multires data */
cdm = CustomData_get_layer(fdata, CD_GRIDS);
if(!cdm)
break;
CustomData_multires_remove_layers(cdm, me->totface,
unode->type,
unode->layer_name);
break;
case LAYER_REMOVED:
paint_layer_undo_set_add(unode, unode->layer_name);
/* add layer */
CustomData_add_layer_at_offset(data, unode->type, CD_ASSIGN,
unode->layer_data, totelem,
unode->layer_offset);
ndx = CustomData_get_named_layer_index(data, unode->type,
unode->layer_name);
offset = ndx - CustomData_get_layer_index(data, unode->type);
CustomData_set_layer_active(data, unode->type, offset);
BLI_strncpy(data->layers[ndx].name, unode->layer_name,
sizeof(data->layers[ndx].name));
data->layers[ndx].strength = unode->strength;
if(!unode->flag_multires)
break;
/* add multires layer */
CustomData_set_layer_offset_flag(data, unode->type,
offset, CD_FLAG_MULTIRES);
cdm = CustomData_get_layer(fdata, CD_GRIDS);
if(!cdm)
break;
for(i = 0; i < me->totface; ++i, ++cdm) {
void *griddata = unode->multires_layer_data[i];
CustomData_multires_add_layer_data(cdm, unode->type,
unode->layer_name,
griddata);
}
unode->layer_data = NULL;
if(unode->multires_layer_data)
MEM_freeN(unode->multires_layer_data);
unode->multires_layer_data = NULL;
break;
}
}
static void paint_layer_undo_node_free(ListBase *lb)
{
PaintLayerUndoNode *unode = lb->first;
if(unode->layer_data)
MEM_freeN(unode->layer_data);
if(unode->multires_layer_data) {
int i;
for(i = 0; i < unode->totface; ++i)
MEM_freeN(unode->multires_layer_data[i]);
MEM_freeN(unode->multires_layer_data);
}
}
PaintLayerUndoNode *paint_layer_undo_push(int type, char *description)
{
PaintLayerUndoNode *unode;
undo_paint_push_begin(UNDO_PAINT_MESH, description,
paint_layer_undo_restore,
paint_layer_undo_node_free);
unode = MEM_callocN(sizeof(PaintLayerUndoNode), "PaintLayerUndoNode");
unode->type = type;
BLI_addtail(undo_paint_push_get_list(UNDO_PAINT_MESH), unode);
undo_paint_push_end(UNDO_PAINT_MESH);
return unode;
}
/* Exported Functions */
void undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free)
@@ -243,4 +486,3 @@ void ED_undo_paint_free(void)
undo_stack_free(&ImageUndoStack);
undo_stack_free(&MeshUndoStack);
}

View File

@@ -4,6 +4,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -17,10 +18,13 @@
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "ED_view3d.h"
#include "ED_screen.h"
@@ -31,10 +35,21 @@
#include "WM_api.h"
#include "WM_types.h"
#include "RE_render_ext.h"
#include "RE_shader_ext.h"
#include "paint_intern.h"
/* 3D Paint */
void ED_paint_force_update(bContext *C)
{
Object *ob= CTX_data_active_object(C);
if(ob && (ob->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT)))
multires_force_update(ob);
}
static void imapaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
{
VECCOPY(pco, co);
@@ -296,3 +311,319 @@ void PAINT_OT_face_select_all(wmOperatorType *ot)
WM_operator_properties_select_all(ot);
}
float paint_calc_object_space_radius(ViewContext *vc, float center[3],
float pixel_radius)
{
Object *ob = vc->obact;
float delta[3], scale, loc[3];
mul_v3_m4v3(loc, ob->obmat, center);
initgrabz(vc->rv3d, loc[0], loc[1], loc[2]);
window_to_3d_delta(vc->ar, delta, pixel_radius, 0);
scale= fabsf(mat4_to_scale(ob->obmat));
scale= (scale == 0.0f)? 1.0f: scale;
return len_v3(delta)/scale;
}
/* Paint modes can handle multires differently from regular meshes, but only
if it's the last modifier on the stack and it is not on level zero */
struct MultiresModifierData *ED_paint_multires_active(Scene *scene, Object *ob)
{
Mesh *me= (Mesh*)ob->data;
ModifierData *md, *nmd;
if(!CustomData_get_layer(&me->fdata, CD_MDISPS)) {
/* multires can't work without displacement layer */
return NULL;
}
for(md= modifiers_getVirtualModifierList(ob); md; md= md->next) {
if(md->type == eModifierType_Multires) {
MultiresModifierData *mmd= (MultiresModifierData*)md;
/* Check if any of the modifiers after multires are active
* if not it can use the multires struct */
for(nmd= md->next; nmd; nmd= nmd->next)
if(modifier_isEnabled(scene, nmd, eModifierMode_Realtime))
break;
if(!nmd && mmd->sculptlvl > 0)
return mmd;
}
}
return NULL;
}
/*** BVH Tree ***/
/* Get a screen-space rectangle of the modified area */
static int paint_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
Object *ob, rcti *rect)
{
PBVH *pbvh= ob->paint->pbvh;
float bb_min[3], bb_max[3], pmat[4][4];
int i, j, k;
view3d_get_object_project_mat(rv3d, ob, pmat);
if(!pbvh)
return 0;
BLI_pbvh_redraw_BB(pbvh, bb_min, bb_max);
rect->xmin = rect->ymin = INT_MAX;
rect->xmax = rect->ymax = INT_MIN;
if(bb_min[0] > bb_max[0] || bb_min[1] > bb_max[1] || bb_min[2] > bb_max[2])
return 0;
for(i = 0; i < 2; ++i) {
for(j = 0; j < 2; ++j) {
for(k = 0; k < 2; ++k) {
float vec[3], proj[2];
vec[0] = i ? bb_min[0] : bb_max[0];
vec[1] = j ? bb_min[1] : bb_max[1];
vec[2] = k ? bb_min[2] : bb_max[2];
view3d_project_float(ar, vec, proj, pmat);
rect->xmin = MIN2(rect->xmin, proj[0]);
rect->xmax = MAX2(rect->xmax, proj[0]);
rect->ymin = MIN2(rect->ymin, proj[1]);
rect->ymax = MAX2(rect->ymax, proj[1]);
}
}
}
return rect->xmin < rect->xmax && rect->ymin < rect->ymax;
}
void paint_tag_partial_redraw(bContext *C, Object *ob)
{
RegionView3D *rv3d = CTX_wm_region_view3d(C);
ARegion *ar = CTX_wm_region(C);
rcti r;
if(paint_get_redraw_rect(ar, rv3d, ob, &r)) {
//rcti tmp;
r.xmin += ar->winrct.xmin + 1;
r.xmax += ar->winrct.xmin - 1;
r.ymin += ar->winrct.ymin + 1;
r.ymax += ar->winrct.ymin - 1;
//tmp = r;
//if (!BLI_rcti_is_empty(&ss->previous_r))
// BLI_union_rcti(&r, &ss->previous_r);
//ss->previous_r= tmp;
ob->paint->partial_redraw = 1;
ED_region_tag_redraw_partial(ar, &r);
}
}
void paint_get_redraw_planes(float planes[4][4], ARegion *ar,
RegionView3D *rv3d, Object *ob)
{
PBVH *pbvh= ob->paint->pbvh;
BoundBox bb;
bglMats mats;
rcti rect;
memset(&bb, 0, sizeof(BoundBox));
view3d_get_transformation(ar, rv3d, ob, &mats);
paint_get_redraw_rect(ar, rv3d,ob, &rect);
#if 1
/* use some extra space just in case */
rect.xmin -= 2;
rect.xmax += 2;
rect.ymin -= 2;
rect.ymax += 2;
#else
/* it was doing this before, allows to redraw a smaller
part of the screen but also gives artifaces .. */
rect.xmin += 2;
rect.xmax -= 2;
rect.ymin += 2;
rect.ymax -= 2;
#endif
view3d_calculate_clipping(&bb, planes, &mats, &rect);
mul_m4_fl(planes, -1.0f);
/* clear redraw flag from nodes */
if(pbvh)
BLI_pbvh_update(pbvh, PBVH_UpdateRedraw, NULL);
}
float get_tex_pixel(Brush* br, float u, float v)
{
TexResult texres;
float co[3];
int hasrgb;
co[0] = u;
co[1] = v;
co[2] = 0;
memset(&texres, 0, sizeof(TexResult));
hasrgb = multitex_ext(br->mtex.tex, co, NULL, NULL, 1, &texres);
if (hasrgb & TEX_RGB)
texres.tin = (0.35*texres.tr + 0.45*texres.tg + 0.2*texres.tb)*texres.ta;
return texres.tin;
}
/* selectively flip any axis of a coordinate */
void paint_flip_coord(float out[3], float in[3], const char symm)
{
if(symm & PAINT_SYMM_X)
out[0]= -in[0];
else
out[0]= in[0];
if(symm & PAINT_SYMM_Y)
out[1]= -in[1];
else
out[1]= in[1];
if(symm & PAINT_SYMM_Z)
out[2]= -in[2];
else
out[2]= in[2];
}
/* return a multiplier for brush strength at a coordinate,
incorporating texture, curve control, and masking
TODO: pulled almost directly from sculpt, still needs
to be prettied up
*/
float brush_tex_strength(ViewContext *vc,
float pmat[4][4], Brush *br,
float co[3], float mask, const float len,
float pixel_radius, float radius3d,
float special_rotation, float tex_mouse[2])
{
MTex *mtex = &br->mtex;
float avg= 1;
if(!mtex->tex) {
avg= 1;
}
else if(mtex->brush_map_mode == MTEX_MAP_MODE_3D) {
float jnk;
/* Get strength by feeding the vertex
location directly into a texture */
externtex(mtex, co, &avg,
&jnk, &jnk, &jnk, &jnk, 0);
}
else {
float rotation = -mtex->rot;
float x, y, point_2d[3];
float radius;
view3d_project_float(vc->ar, co, point_2d, pmat);
/* if fixed mode, keep coordinates relative to mouse */
if(mtex->brush_map_mode == MTEX_MAP_MODE_FIXED) {
rotation += special_rotation;
point_2d[0] -= tex_mouse[0];
point_2d[1] -= tex_mouse[1];
radius = pixel_radius; // use pressure adjusted size for fixed mode
x = point_2d[0];
y = point_2d[1];
}
else /* else (mtex->brush_map_mode == MTEX_MAP_MODE_TILED),
leave the coordinates relative to the screen */
{
radius = brush_size(br); // use unadjusted size for tiled mode
x = point_2d[0] - vc->ar->winrct.xmin;
y = point_2d[1] - vc->ar->winrct.ymin;
}
x /= vc->ar->winx;
y /= vc->ar->winy;
if (mtex->brush_map_mode == MTEX_MAP_MODE_TILED) {
x -= 0.5f;
y -= 0.5f;
}
x *= vc->ar->winx / radius;
y *= vc->ar->winy / radius;
/* it is probably worth optimizing for those cases where
the texture is not rotated by skipping the calls to
atan2, sqrtf, sin, and cos. */
if (rotation > 0.001 || rotation < -0.001) {
const float angle = atan2(y, x) + rotation;
const float flen = sqrtf(x*x + y*y);
x = flen * cos(angle);
y = flen * sin(angle);
}
x *= br->mtex.size[0];
y *= br->mtex.size[1];
x += br->mtex.ofs[0];
y += br->mtex.ofs[1];
avg = get_tex_pixel(br, x, y);
}
avg += br->texture_sample_bias;
avg *= brush_curve_strength(br, len, radius3d); /* Falloff curve */
avg*= 1 - mask;
return avg;
}
int paint_util_raycast(ViewContext *vc,
BLI_pbvh_HitOccludedCallback hit_cb, void *mode_data,
float out[3], float mouse[2], int original)
{
float ray_start[3], ray_end[3], ray_normal[3], dist;
float obimat[4][4];
float mval[2] = {mouse[0] - vc->ar->winrct.xmin,
mouse[1] - vc->ar->winrct.ymin};
PaintStrokeRaycastData hit_data;
viewline(vc->ar, vc->v3d, mval, ray_start, ray_end);
invert_m4_m4(obimat, vc->obact->obmat);
mul_m4_v3(obimat, ray_start);
mul_m4_v3(obimat, ray_end);
sub_v3_v3v3(ray_normal, ray_end, ray_start);
dist= normalize_v3(ray_normal);
hit_data.mode_data = mode_data;
hit_data.ob = vc->obact;
hit_data.ray_start = ray_start;
hit_data.ray_normal = ray_normal;
hit_data.dist = dist;
hit_data.hit = 0;
hit_data.original = original;
BLI_pbvh_raycast(vc->obact->paint->pbvh, hit_cb, &hit_data,
ray_start, ray_normal, original);
copy_v3_v3(out, ray_normal);
mul_v3_fl(out, hit_data.dist);
add_v3_v3(out, ray_start);
return hit_data.hit;
}

View File

@@ -22,7 +22,7 @@
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
* Contributor(s): Nicholas Bishop
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -62,30 +62,29 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_dmgrid.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_subsurf.h"
#include "BKE_utildefines.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_armature.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "paint_intern.h"
#include "ptex.h"
/* brush->vertexpaint_tool */
#define VP_MIX 0
#define VP_ADD 1
#define VP_SUB 2
#define VP_MUL 3
#define VP_BLUR 4
#define VP_LIGHTEN 5
#define VP_DARKEN 6
#include "paint_intern.h"
/* polling - retrieve whether cursor should be set or operator should be done */
@@ -102,8 +101,10 @@ int vertex_paint_poll(bContext *C)
{
if(vertex_paint_mode_poll(C) &&
paint_brush(&CTX_data_tool_settings(C)->vpaint->paint)) {
Object *ob = CTX_data_active_object(C);
ScrArea *sa= CTX_wm_area(C);
if(sa->spacetype==SPACE_VIEW3D) {
if(!(get_mesh(ob)->editflag & ME_EDIT_PTEX) &&
sa->spacetype==SPACE_VIEW3D) {
ARegion *ar= CTX_wm_region(C);
if(ar->regiontype==RGN_TYPE_WINDOW)
return 1;
@@ -187,72 +188,6 @@ unsigned int vpaint_get_current_col(VPaint *vp)
return rgba_to_mcol(brush->rgb[0], brush->rgb[1], brush->rgb[2], 1.0f);
}
static void do_shared_vertexcol(Mesh *me)
{
/* if no mcol: do not do */
/* if tface: only the involved faces, otherwise all */
MFace *mface;
MTFace *tface;
int a;
short *scolmain, *scol;
char *mcol;
if(me->mcol==0 || me->totvert==0 || me->totface==0) return;
scolmain= MEM_callocN(4*sizeof(short)*me->totvert, "colmain");
tface= me->mtface;
mface= me->mface;
mcol= (char *)me->mcol;
for(a=me->totface; a>0; a--, mface++, mcol+=16) {
if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) {
scol= scolmain+4*mface->v1;
scol[0]++; scol[1]+= mcol[1]; scol[2]+= mcol[2]; scol[3]+= mcol[3];
scol= scolmain+4*mface->v2;
scol[0]++; scol[1]+= mcol[5]; scol[2]+= mcol[6]; scol[3]+= mcol[7];
scol= scolmain+4*mface->v3;
scol[0]++; scol[1]+= mcol[9]; scol[2]+= mcol[10]; scol[3]+= mcol[11];
if(mface->v4) {
scol= scolmain+4*mface->v4;
scol[0]++; scol[1]+= mcol[13]; scol[2]+= mcol[14]; scol[3]+= mcol[15];
}
}
if(tface) tface++;
}
a= me->totvert;
scol= scolmain;
while(a--) {
if(scol[0]>1) {
scol[1]/= scol[0];
scol[2]/= scol[0];
scol[3]/= scol[0];
}
scol+= 4;
}
tface= me->mtface;
mface= me->mface;
mcol= (char *)me->mcol;
for(a=me->totface; a>0; a--, mface++, mcol+=16) {
if((tface && tface->mode & TF_SHAREDCOL) || (me->editflag & ME_EDIT_PAINT_MASK)==0) {
scol= scolmain+4*mface->v1;
mcol[1]= scol[1]; mcol[2]= scol[2]; mcol[3]= scol[3];
scol= scolmain+4*mface->v2;
mcol[5]= scol[1]; mcol[6]= scol[2]; mcol[7]= scol[3];
scol= scolmain+4*mface->v3;
mcol[9]= scol[1]; mcol[10]= scol[2]; mcol[11]= scol[3];
if(mface->v4) {
scol= scolmain+4*mface->v4;
mcol[13]= scol[1]; mcol[14]= scol[2]; mcol[15]= scol[3];
}
}
if(tface) tface++;
}
MEM_freeN(scolmain);
}
static void make_vertexcol(Object *ob) /* single ob */
{
Mesh *me;
@@ -272,24 +207,6 @@ static void make_vertexcol(Object *ob) /* single ob */
//else
memset(me->mcol, 255, 4*sizeof(MCol)*me->totface);
DAG_id_flush_update(&me->id, OB_RECALC_DATA);
}
static void copy_vpaint_prev(VPaint *vp, unsigned int *mcol, int tot)
{
if(vp->vpaint_prev) {
MEM_freeN(vp->vpaint_prev);
vp->vpaint_prev= NULL;
}
vp->tot= tot;
if(mcol==NULL || tot==0) return;
vp->vpaint_prev= MEM_mallocN(4*sizeof(int)*tot, "vpaint_prev");
memcpy(vp->vpaint_prev, mcol, 4*sizeof(int)*tot);
}
static void copy_wpaint_prev (VPaint *wp, MDeformVert *dverts, int dcount)
@@ -494,197 +411,6 @@ void vpaint_dogamma(Scene *scene)
}
*/
static unsigned int mcol_blend(unsigned int col1, unsigned int col2, int fac)
{
char *cp1, *cp2, *cp;
int mfac;
unsigned int col=0;
if(fac==0) return col1;
if(fac>=255) return col2;
mfac= 255-fac;
cp1= (char *)&col1;
cp2= (char *)&col2;
cp= (char *)&col;
cp[0]= 255;
cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
return col;
}
static unsigned int mcol_add(unsigned int col1, unsigned int col2, int fac)
{
char *cp1, *cp2, *cp;
int temp;
unsigned int col=0;
if(fac==0) return col1;
cp1= (char *)&col1;
cp2= (char *)&col2;
cp= (char *)&col;
cp[0]= 255;
temp= cp1[1] + ((fac*cp2[1])/255);
if(temp>254) cp[1]= 255; else cp[1]= temp;
temp= cp1[2] + ((fac*cp2[2])/255);
if(temp>254) cp[2]= 255; else cp[2]= temp;
temp= cp1[3] + ((fac*cp2[3])/255);
if(temp>254) cp[3]= 255; else cp[3]= temp;
return col;
}
static unsigned int mcol_sub(unsigned int col1, unsigned int col2, int fac)
{
char *cp1, *cp2, *cp;
int temp;
unsigned int col=0;
if(fac==0) return col1;
cp1= (char *)&col1;
cp2= (char *)&col2;
cp= (char *)&col;
cp[0]= 255;
temp= cp1[1] - ((fac*cp2[1])/255);
if(temp<0) cp[1]= 0; else cp[1]= temp;
temp= cp1[2] - ((fac*cp2[2])/255);
if(temp<0) cp[2]= 0; else cp[2]= temp;
temp= cp1[3] - ((fac*cp2[3])/255);
if(temp<0) cp[3]= 0; else cp[3]= temp;
return col;
}
static unsigned int mcol_mul(unsigned int col1, unsigned int col2, int fac)
{
char *cp1, *cp2, *cp;
int mfac;
unsigned int col=0;
if(fac==0) return col1;
mfac= 255-fac;
cp1= (char *)&col1;
cp2= (char *)&col2;
cp= (char *)&col;
/* first mul, then blend the fac */
cp[0]= 255;
cp[1]= (mfac*cp1[1] + fac*((cp2[1]*cp1[1])/255) )/255;
cp[2]= (mfac*cp1[2] + fac*((cp2[2]*cp1[2])/255) )/255;
cp[3]= (mfac*cp1[3] + fac*((cp2[3]*cp1[3])/255) )/255;
return col;
}
static unsigned int mcol_lighten(unsigned int col1, unsigned int col2, int fac)
{
char *cp1, *cp2, *cp;
int mfac;
unsigned int col=0;
if(fac==0) return col1;
if(fac>=255) return col2;
mfac= 255-fac;
cp1= (char *)&col1;
cp2= (char *)&col2;
cp= (char *)&col;
/* See if are lighter, if so mix, else dont do anything.
if the paint col is darker then the original, then ignore */
if (cp1[1]+cp1[2]+cp1[3] > cp2[1]+cp2[2]+cp2[3])
return col1;
cp[0]= 255;
cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
return col;
}
static unsigned int mcol_darken(unsigned int col1, unsigned int col2, int fac)
{
char *cp1, *cp2, *cp;
int mfac;
unsigned int col=0;
if(fac==0) return col1;
if(fac>=255) return col2;
mfac= 255-fac;
cp1= (char *)&col1;
cp2= (char *)&col2;
cp= (char *)&col;
/* See if were darker, if so mix, else dont do anything.
if the paint col is brighter then the original, then ignore */
if (cp1[1]+cp1[2]+cp1[3] < cp2[1]+cp2[2]+cp2[3])
return col1;
cp[0]= 255;
cp[1]= (mfac*cp1[1]+fac*cp2[1])/255;
cp[2]= (mfac*cp1[2]+fac*cp2[2])/255;
cp[3]= (mfac*cp1[3]+fac*cp2[3])/255;
return col;
}
static void vpaint_blend(VPaint *vp, unsigned int *col, unsigned int *colorig, unsigned int paintcol, int alpha)
{
Brush *brush = paint_brush(&vp->paint);
if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) *col= mcol_blend( *col, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_ADD) *col= mcol_add( *col, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_SUB) *col= mcol_sub( *col, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_MUL) *col= mcol_mul( *col, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_LIGHTEN) *col= mcol_lighten( *col, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_DARKEN) *col= mcol_darken( *col, paintcol, alpha);
/* if no spray, clip color adding with colorig & orig alpha */
if((vp->flag & VP_SPRAY)==0) {
unsigned int testcol=0, a;
char *cp, *ct, *co;
alpha= (int)(255.0*brush_alpha(brush));
if(brush->vertexpaint_tool==VP_MIX || brush->vertexpaint_tool==VP_BLUR) testcol= mcol_blend( *colorig, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_ADD) testcol= mcol_add( *colorig, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_SUB) testcol= mcol_sub( *colorig, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_MUL) testcol= mcol_mul( *colorig, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_LIGHTEN) testcol= mcol_lighten( *colorig, paintcol, alpha);
else if(brush->vertexpaint_tool==VP_DARKEN) testcol= mcol_darken( *colorig, paintcol, alpha);
cp= (char *)col;
ct= (char *)&testcol;
co= (char *)colorig;
for(a=0; a<4; a++) {
if( ct[a]<co[a] ) {
if( cp[a]<ct[a] ) cp[a]= ct[a];
else if( cp[a]>co[a] ) cp[a]= co[a];
}
else {
if( cp[a]<co[a] ) cp[a]= co[a];
else if( cp[a]>ct[a] ) cp[a]= ct[a];
}
}
}
}
static int sample_backbuf_area(ViewContext *vc, int *indexar, int totface, int x, int y, float size)
{
struct ImBuf *ibuf;
@@ -774,32 +500,32 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float
if (flip) {
switch(tool) {
case VP_MIX:
case IMB_BLEND_MIX:
paintval = 1.f - paintval; break;
case VP_ADD:
tool= VP_SUB; break;
case VP_SUB:
tool= VP_ADD; break;
case VP_LIGHTEN:
tool= VP_DARKEN; break;
case VP_DARKEN:
tool= VP_LIGHTEN; break;
case IMB_BLEND_ADD:
tool= IMB_BLEND_SUB; break;
case IMB_BLEND_SUB:
tool= IMB_BLEND_ADD; break;
case IMB_BLEND_LIGHTEN:
tool= IMB_BLEND_DARKEN; break;
case IMB_BLEND_DARKEN:
tool= IMB_BLEND_LIGHTEN; break;
}
}
if(tool==VP_MIX || tool==VP_BLUR)
if(tool==IMB_BLEND_MIX || tool==VERTEX_PAINT_BLUR)
dw->weight = paintval*alpha + dw->weight*(1.0-alpha);
else if(tool==VP_ADD)
else if(tool==IMB_BLEND_ADD)
dw->weight += paintval*alpha;
else if(tool==VP_SUB)
else if(tool==IMB_BLEND_SUB)
dw->weight -= paintval*alpha;
else if(tool==VP_MUL)
else if(tool==IMB_BLEND_MUL)
/* first mul, then blend the fac */
dw->weight = ((1.0-alpha) + alpha*paintval)*dw->weight;
else if(tool==VP_LIGHTEN) {
else if(tool==IMB_BLEND_LIGHTEN) {
if (dw->weight < paintval)
dw->weight = paintval*alpha + dw->weight*(1.0-alpha);
} else if(tool==VP_DARKEN) {
} else if(tool==IMB_BLEND_DARKEN) {
if (dw->weight > paintval)
dw->weight = paintval*alpha + dw->weight*(1.0-alpha);
}
@@ -810,21 +536,21 @@ static void wpaint_blend(VPaint *wp, MDeformWeight *dw, MDeformWeight *uw, float
float testw=0.0f;
alpha= brush_alpha(brush);
if(tool==VP_MIX || tool==VP_BLUR)
if(tool==IMB_BLEND_MIX || tool==VERTEX_PAINT_BLUR)
testw = paintval*alpha + uw->weight*(1.0-alpha);
else if(tool==VP_ADD)
else if(tool==IMB_BLEND_ADD)
testw = uw->weight + paintval*alpha;
else if(tool==VP_SUB)
else if(tool==IMB_BLEND_SUB)
testw = uw->weight - paintval*alpha;
else if(tool==VP_MUL)
else if(tool==IMB_BLEND_MUL)
/* first mul, then blend the fac */
testw = ((1.0-alpha) + alpha*paintval)*uw->weight;
else if(tool==VP_LIGHTEN) {
else if(tool==IMB_BLEND_LIGHTEN) {
if (uw->weight < paintval)
testw = paintval*alpha + uw->weight*(1.0-alpha);
else
testw = uw->weight;
} else if(tool==VP_DARKEN) {
} else if(tool==IMB_BLEND_DARKEN) {
if (uw->weight > paintval)
testw = paintval*alpha + uw->weight*(1.0-alpha);
else
@@ -1413,7 +1139,7 @@ static int wpaint_stroke_test_start(bContext *C, wmOperator *op, wmEvent *UNUSED
wpd->vgroup_mirror= actdef;
}
}
return 1;
}
@@ -1496,7 +1222,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* make sure each vertex gets treated only once */
/* and calculate filter weight */
totw= 0;
if(brush->vertexpaint_tool==VP_BLUR)
if(brush->vertexpaint_tool==VERTEX_PAINT_BLUR)
paintweight= 0.0f;
else
paintweight= ts->vgroup_weight;
@@ -1510,7 +1236,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
(me->dvert+mface->v3)->flag= 1;
if(mface->v4) (me->dvert+mface->v4)->flag= 1;
if(brush->vertexpaint_tool==VP_BLUR) {
if(brush->vertexpaint_tool==VERTEX_PAINT_BLUR) {
MDeformWeight *dw, *(*dw_func)(MDeformVert *, int);
if(wp->flag & VP_ONLYVGROUP)
@@ -1532,7 +1258,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
}
}
if(brush->vertexpaint_tool==VP_BLUR)
if(brush->vertexpaint_tool==VERTEX_PAINT_BLUR)
paintweight/= (float)totw;
for(index=0; index<totindex; index++) {
@@ -1633,7 +1359,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
wpaint_stroke_update_step,
wpaint_stroke_update_step, NULL, NULL,
wpaint_stroke_done);
/* add modal handler */
@@ -1689,6 +1415,10 @@ void PAINT_OT_weight_set(wmOperatorType *ot)
/* ************ set / clear vertex paint mode ********** */
struct VPaintSession {
unsigned int src_image_gltex;
};
static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
{
@@ -1704,11 +1434,10 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
return OPERATOR_PASS_THROUGH;
}
if(me && me->mcol==NULL) make_vertexcol(ob);
/* toggle: end vpaint */
if(ob->mode & OB_MODE_VERTEX_PAINT) {
free_paintsession(ob);
ob->mode &= ~OB_MODE_VERTEX_PAINT;
}
else {
@@ -1716,18 +1445,25 @@ static int set_vpaint(bContext *C, wmOperator *op) /* toggle */
/* Turn off weight painting */
if (ob->mode & OB_MODE_WEIGHT_PAINT)
set_wpaint(C, op);
if(vp==NULL)
vp= scene->toolsettings->vpaint= new_vpaint(0);
if(me->mcol==NULL)
make_vertexcol(ob);
if(!CustomData_get_layer(&me->fdata, CD_MPTEX))
WM_operator_name_call(C, "PTEX_OT_layer_add", WM_OP_INVOKE_REGION_WIN, NULL);
create_paintsession(ob);
paint_cursor_start(C, vertex_paint_poll);
paint_init(&vp->paint, PAINT_CURSOR_VERTEX_PAINT);
}
if (me)
/* update modifier stack for mapping requirements */
DAG_id_flush_update(&me->id, OB_RECALC_DATA);
/* create pbvh */
if(ob->mode & OB_MODE_VERTEX_PAINT) {
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH|CD_MASK_MCOL);
ob->paint->pbvh = dm->getPBVH(ob, dm);
}
WM_event_add_notifier(C, NC_SCENE|ND_MODE, scene);
@@ -1749,211 +1485,6 @@ void PAINT_OT_vertex_paint_toggle(wmOperatorType *ot)
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* ********************** vertex paint operator ******************* */
/* Implementation notes:
Operator->invoke()
- validate context (add mcol)
- create customdata storage
- call paint once (mouse click)
- add modal handler
Operator->modal()
- for every mousemove, apply vertex paint
- exit on mouse release, free customdata
(return OPERATOR_FINISHED also removes handler and operator)
For future:
- implement a stroke event (or mousemove with past positons)
- revise whether op->customdata should be added in object, in set_vpaint
*/
typedef struct VPaintData {
ViewContext vc;
unsigned int paintcol;
int *indexar;
float *vertexcosnos;
float vpimat[3][3];
} VPaintData;
static int vpaint_stroke_test_start(bContext *C, struct wmOperator *op, wmEvent *UNUSED(event))
{
ToolSettings *ts= CTX_data_tool_settings(C);
struct PaintStroke *stroke = op->customdata;
VPaint *vp= ts->vpaint;
struct VPaintData *vpd;
Object *ob= CTX_data_active_object(C);
Mesh *me;
float mat[4][4], imat[4][4];
/* context checks could be a poll() */
me= get_mesh(ob);
if(me==NULL || me->totface==0) return OPERATOR_PASS_THROUGH;
if(me->mcol==NULL) make_vertexcol(ob);
if(me->mcol==NULL) return OPERATOR_CANCELLED;
/* make mode data storage */
vpd= MEM_callocN(sizeof(struct VPaintData), "VPaintData");
paint_stroke_set_mode_data(stroke, vpd);
view3d_set_viewcontext(C, &vpd->vc);
vpd->vertexcosnos= mesh_get_mapped_verts_nors(vpd->vc.scene, ob);
vpd->indexar= get_indexarray(me);
vpd->paintcol= vpaint_get_current_col(vp);
/* for filtering */
copy_vpaint_prev(vp, (unsigned int *)me->mcol, me->totface);
/* some old cruft to sort out later */
mul_m4_m4m4(mat, ob->obmat, vpd->vc.rv3d->viewmat);
invert_m4_m4(imat, mat);
copy_m3_m4(vpd->vpimat, imat);
return 1;
}
static void vpaint_paint_face(VPaint *vp, VPaintData *vpd, Object *ob, int index, float mval[2], float pressure, int UNUSED(flip))
{
ViewContext *vc = &vpd->vc;
Brush *brush = paint_brush(&vp->paint);
Mesh *me = get_mesh(ob);
MFace *mface= ((MFace*)me->mface) + index;
unsigned int *mcol= ((unsigned int*)me->mcol) + 4*index;
unsigned int *mcolorig= ((unsigned int*)vp->vpaint_prev) + 4*index;
float alpha;
int i;
if((vp->flag & VP_COLINDEX && mface->mat_nr!=ob->actcol-1) ||
((me->editflag & ME_EDIT_PAINT_MASK) && !(mface->flag & ME_FACE_SEL)))
return;
if(brush->vertexpaint_tool==VP_BLUR) {
unsigned int fcol1= mcol_blend( mcol[0], mcol[1], 128);
if(mface->v4) {
unsigned int fcol2= mcol_blend( mcol[2], mcol[3], 128);
vpd->paintcol= mcol_blend( fcol1, fcol2, 128);
}
else {
vpd->paintcol= mcol_blend( mcol[2], fcol1, 170);
}
}
for(i = 0; i < (mface->v4 ? 4 : 3); ++i) {
alpha= calc_vp_alpha_dl(vp, vc, vpd->vpimat, vpd->vertexcosnos+6*(&mface->v1)[i], mval, pressure);
if(alpha)
vpaint_blend(vp, mcol+i, mcolorig+i, vpd->paintcol, (int)(alpha*255.0));
}
}
static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
ToolSettings *ts= CTX_data_tool_settings(C);
struct VPaintData *vpd = paint_stroke_mode_data(stroke);
VPaint *vp= ts->vpaint;
Brush *brush = paint_brush(&vp->paint);
ViewContext *vc= &vpd->vc;
Object *ob= vc->obact;
Mesh *me= ob->data;
float mat[4][4];
int *indexar= vpd->indexar;
int totindex, index, flip;
float pressure, mval[2];
RNA_float_get_array(itemptr, "mouse", mval);
flip = RNA_boolean_get(itemptr, "pen_flip");
pressure = RNA_float_get(itemptr, "pressure");
view3d_operator_needs_opengl(C);
/* load projection matrix */
mul_m4_m4m4(mat, ob->obmat, vc->rv3d->persmat);
mval[0]-= vc->ar->winrct.xmin;
mval[1]-= vc->ar->winrct.ymin;
/* which faces are involved */
if(vp->flag & VP_AREA) {
totindex= sample_backbuf_area(vc, indexar, me->totface, mval[0], mval[1], brush_size(brush));
}
else {
indexar[0]= view3d_sample_backbuf(vc, mval[0], mval[1]);
if(indexar[0]) totindex= 1;
else totindex= 0;
}
swap_m4m4(vc->rv3d->persmat, mat);
for(index=0; index<totindex; index++) {
if(indexar[index] && indexar[index]<=me->totface)
vpaint_paint_face(vp, vpd, ob, indexar[index]-1, mval, pressure, flip);
}
swap_m4m4(vc->rv3d->persmat, mat);
/* was disabled because it is slow, but necessary for blur */
if(brush->vertexpaint_tool == VP_BLUR)
do_shared_vertexcol(me);
ED_region_tag_redraw(vc->ar);
DAG_id_flush_update(ob->data, OB_RECALC_DATA);
}
static void vpaint_stroke_done(bContext *C, struct PaintStroke *stroke)
{
ToolSettings *ts= CTX_data_tool_settings(C);
struct VPaintData *vpd= paint_stroke_mode_data(stroke);
if(vpd->vertexcosnos)
MEM_freeN(vpd->vertexcosnos);
MEM_freeN(vpd->indexar);
/* frees prev buffer */
copy_vpaint_prev(ts->vpaint, NULL, 0);
MEM_freeN(vpd);
}
static int vpaint_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
vpaint_stroke_update_step,
vpaint_stroke_done);
/* add modal handler */
WM_event_add_modal_handler(C, op);
op->type->modal(C, op, event);
return OPERATOR_RUNNING_MODAL;
}
void PAINT_OT_vertex_paint(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Vertex Paint";
ot->idname= "PAINT_OT_vertex_paint";
/* api callbacks */
ot->invoke= vpaint_invoke;
ot->modal= paint_stroke_modal;
/* ot->exec= vpaint_exec; <-- needs stroke property */
ot->poll= vertex_paint_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
}
/* ********************** weight from bones operator ******************* */
static int weight_from_bones_poll(bContext *C)
@@ -2001,4 +1532,3 @@ void PAINT_OT_weight_from_bones(wmOperatorType *ot)
/* properties */
ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "Method to use for assigning weights.");
}

View File

@@ -0,0 +1,570 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2006 by Nicholas Bishop
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*
*/
#include "BLI_math.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
#include "DNA_key_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_dmgrid.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_mesh.h"
#include "BKE_key.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_sculpt.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
#include "ptex.h"
/************************** Undo *************************/
struct PBVHUndoNode {
struct PBVHUndoNode *next, *prev;
/* object id name */
char idname[MAX_ID_NAME];
/* only during push, not valid afterwards! */
struct PBVHNode *node;
/* total unique verts in node */
int totvert;
/* actual undo data */
float (*co)[3];
/* paint mask */
float *pmask;
char pmask_name[32];
/* ptex */
void **mptex_data;
char mptex_name[32];
/* non-multires */
/* to verify if me->totvert it still the same */
int maxvert;
/* to restore into the right location */
int *vert_indices;
int *face_indices;
/* multires */
/* to verify total number of grids is still the same */
int maxgrid;
int gridsize;
int totgrid;
/* to restore into the right location */
int *grid_indices;
/* shape keys */
char *shapeName[32]; /* keep size in sync with keyblock dna */
/* only during push, not stored */
short (*no)[3];
/* layer brush */
float *layer_disp;
};
static void pbvh_undo_restore_mesh_co(PBVHUndoNode *unode, bContext *C, Scene *scene, Object *ob)
{
SculptSession *ss = ob->paint->sculpt;
Mesh *me = ob->data;
MVert *mvert;
char *shapeName= (char*)unode->shapeName;
int *index, i;
if(ss && ss->kb && strcmp(ss->kb->name, shapeName)) {
/* shape key has been changed before calling undo operator */
Key *key= ob_get_key(ob);
KeyBlock *kb= key_get_named_keyblock(key, shapeName);
if (kb) {
ob->shapenr= BLI_findindex(&key->block, kb) + 1;
ob->shapeflag|= OB_SHAPE_LOCK;
sculpt_update_mesh_elements(scene, ob, 0);
WM_event_add_notifier(C, NC_OBJECT|ND_DATA, ob);
} else {
/* key has been removed -- skip this undo node */
return;
}
}
mvert= me->mvert;
index= unode->vert_indices;
if(ss && ss->kb) {
float (*vertCos)[3];
vertCos= key_to_vertcos(ob, ss->kb);
for(i=0; i<unode->totvert; i++)
swap_v3_v3(vertCos[index[i]], unode->co[i]);
/* propagate new coords to keyblock */
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
/* pbvh uses it's own mvert array, so coords should be */
/* propagated to pbvh here */
BLI_pbvh_apply_vertCos(ob->paint->pbvh, vertCos);
MEM_freeN(vertCos);
}
else {
for(i=0; i<unode->totvert; i++) {
swap_v3_v3(mvert[index[i]].co, unode->co[i]);
mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
static void pbvh_undo_restore(bContext *C, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
PBVH *pbvh;
PBVHUndoNode *unode;
MultiresModifierData *mmd;
GridToFace *grid_face_map;
int i, j, update_co= 0, update_ptex= 0, update_mask= 0;
// XXX: sculpt_update_mesh_elements(scene, ob, 0);
pbvh = dm->getPBVH(ob, dm);
grid_face_map = dm->getGridFaceMap(dm);
for(unode=lb->first; unode; unode=unode->next) {
CustomData *vdata, *fdata;
if(!(strcmp(unode->idname, ob->id.name)==0))
continue;
BLI_pbvh_get_customdata(pbvh, &vdata, &fdata);
if(unode->maxvert) {
/* regular mesh restore */
if(dm->getNumVerts(dm) != unode->maxvert)
continue;
update_co |= !!unode->co;
update_ptex |= !!unode->mptex_data;
update_mask |= !!unode->pmask;
if(unode->co) {
pbvh_undo_restore_mesh_co(unode, C, scene, ob);
}
if(unode->pmask) {
float *pmask;
pmask = CustomData_get_layer_named(vdata,
CD_PAINTMASK,
unode->pmask_name);
for(i=0; i<unode->totvert; i++)
SWAP(float, pmask[unode->vert_indices[i]],
unode->pmask[i]);
}
}
else if(unode->maxgrid && dm->getGridData) {
/* multires restore */
DMGridData **grids, *grid;
GridKey *gridkey;
float (*co)[3] = NULL, *pmask = NULL;
int gridsize, active_pmask;
if(dm->getNumGrids(dm) != unode->maxgrid)
continue;
/* do ptex restore before checking gridsize */
for(j=0; j<unode->totgrid; j++) {
if(unode->mptex_data) {
GridToFace *gtf = &grid_face_map[unode->grid_indices[j]];
MPtex *mptex;
mptex = CustomData_get_layer_named(fdata,
CD_MPTEX,
unode->mptex_name);
SWAP(void*, unode->mptex_data[j],
mptex[gtf->face].subfaces[gtf->offset].data);
}
}
update_ptex |= !!unode->mptex_data;
if(dm->getGridSize(dm) != unode->gridsize)
continue;
update_co |= !!unode->co;
update_mask |= !!unode->pmask;
grids= dm->getGridData(dm);
gridsize= dm->getGridSize(dm);
gridkey= dm->getGridKey(dm);
if(unode->co) {
co = unode->co;
}
if(unode->pmask) {
pmask = unode->pmask;
active_pmask = gridelem_active_offset(vdata, gridkey, CD_PAINTMASK);
}
for(j=0; j<unode->totgrid; j++) {
grid= grids[unode->grid_indices[j]];
for(i=0; i<gridsize*gridsize; i++) {
DMGridData *elem = GRIDELEM_AT(grid, i, gridkey);
if(co) {
swap_v3_v3(GRIDELEM_CO(elem, gridkey), co[0]);
++co;
}
if(pmask) {
SWAP(float, GRIDELEM_MASK(elem, gridkey)[active_pmask],
*pmask);
++pmask;
}
}
}
}
}
if(update_co || update_ptex || update_mask) {
SculptSession *ss = ob->paint->sculpt;
int update_flags = PBVH_UpdateRedraw;
/* we update all nodes still, should be more clever, but also
needs to work correct when exiting/entering sculpt mode and
the nodes get recreated, though in that case it could do all */
BLI_pbvh_search_callback(ob->paint->pbvh, NULL, NULL, BLI_pbvh_node_set_flags,
SET_INT_IN_POINTER(PBVH_UpdateAll));
if(update_co)
update_flags |= PBVH_UpdateBB|PBVH_UpdateOriginalBB;
if(update_ptex || update_mask)
update_flags |= PBVH_UpdateColorBuffers|PBVH_UpdateRedraw;
BLI_pbvh_update(ob->paint->pbvh, update_flags, NULL);
if((mmd=ED_paint_multires_active(scene, ob)))
multires_mark_as_modified(ob);
/* TODO: should work with other paint modes too */
if(ss && (ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1))
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
}
}
static void pbvh_undo_free(ListBase *lb)
{
PBVHUndoNode *unode;
for(unode=lb->first; unode; unode=unode->next) {
if(unode->co)
MEM_freeN(unode->co);
if(unode->no)
MEM_freeN(unode->no);
if(unode->pmask)
MEM_freeN(unode->pmask);
if(unode->mptex_data) {
int i;
for(i = 0; i < unode->totgrid; ++i)
MEM_freeN(unode->mptex_data[i]);
MEM_freeN(unode->mptex_data);
}
if(unode->vert_indices)
MEM_freeN(unode->vert_indices);
if(unode->face_indices)
MEM_freeN(unode->face_indices);
if(unode->grid_indices)
MEM_freeN(unode->grid_indices);
if(unode->layer_disp)
MEM_freeN(unode->layer_disp);
}
}
PBVHUndoNode *pbvh_undo_get_node(PBVHNode *node)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
PBVHUndoNode *unode;
if(!lb)
return NULL;
for(unode=lb->first; unode; unode=unode->next)
if(unode->node == node)
return unode;
return NULL;
}
PBVHUndoNode *pbvh_undo_push_node(PBVHNode *node, PBVHUndoFlag flag,
Object *ob, Scene *scene)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
PBVHUndoNode *unode;
PBVH *pbvh = ob->paint->pbvh;
PBVHVertexIter vd;
int totbytes= 0;
CustomData *vdata, *fdata;
SculptSession *ss = NULL; /* for shapekey */
GridKey *gridkey;
int uses_grids, totgrid, *grid_indices;
GridToFace *grid_face_map;
/* list is manipulated by multiple threads, so we lock */
BLI_lock_thread(LOCK_CUSTOM1);
if((unode= pbvh_undo_get_node(node))) {
BLI_unlock_thread(LOCK_CUSTOM1);
return unode;
}
unode= MEM_callocN(sizeof(PBVHUndoNode), "PBVHUndoNode");
strcpy(unode->idname, ob->id.name);
unode->node= node;
/* XXX: changed this to just use unique verts rather than all,
seems like only unique are restored from anyway? -nicholas */
BLI_pbvh_node_num_verts(pbvh, node, &unode->totvert, NULL);
BLI_pbvh_get_customdata(pbvh, &vdata, &fdata);
uses_grids = BLI_pbvh_uses_grids(pbvh);
if(uses_grids) {
/* multires */
BLI_pbvh_node_get_grids(pbvh, node, &grid_indices,
&totgrid, &unode->maxgrid, &unode->gridsize,
NULL, NULL, &gridkey);
unode->totgrid= totgrid;
unode->grid_indices= MEM_mapallocN(sizeof(int)*totgrid, "PBVHUndoNode.grid_indices");
totbytes += sizeof(int) * totgrid;
}
else {
/* regular mesh */
if(scene) {
DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
unode->maxvert= dm->getNumVerts(dm);
}
else
unode->maxvert= get_mesh(ob)->totvert;
if(flag & (PBVH_UNDO_CO_NO|PBVH_UNDO_PMASK)) {
unode->vert_indices= MEM_mapallocN(sizeof(int)*unode->totvert,
"PBVHUndoNode.vert_indices");
totbytes += sizeof(int) * unode->totvert;
}
}
/* allocate only the necessary undo data
XXX: we will use this while sculpting, is mapalloc slow to access then? */
if(flag & PBVH_UNDO_CO_NO) {
unode->co= MEM_mapallocN(sizeof(float)*3*unode->totvert, "PBVHUndoNode.co");
unode->no= MEM_mapallocN(sizeof(short)*3*unode->totvert, "PBVHUndoNode.no");
totbytes += (sizeof(float)*3 + sizeof(short)*3) * unode->totvert;
}
if(flag & PBVH_UNDO_PMASK) {
int active;
active= CustomData_get_active_layer_index(vdata, CD_PAINTMASK);
if(active == -1)
flag &= ~PBVH_UNDO_PMASK;
else {
BLI_strncpy(unode->pmask_name,
vdata->layers[active].name,
sizeof(unode->pmask_name));
unode->pmask= MEM_mapallocN(sizeof(float)*unode->totvert, "PBVHUndoNode.pmask");
totbytes += sizeof(float) * unode->totvert;
}
}
if(flag & PBVH_UNDO_PTEX) {
int i, active;
active= CustomData_get_active_layer_index(fdata, CD_MPTEX);
if(active == -1)
flag &= ~PBVH_UNDO_PTEX;
assert(uses_grids);
BLI_strncpy(unode->mptex_name,
fdata->layers[active].name,
sizeof(unode->mptex_name));
grid_face_map= BLI_pbvh_get_grid_face_map(pbvh);
for(i = 0; i < unode->totgrid; ++i) {
GridToFace *gtf= &grid_face_map[grid_indices[i]];
MPtex *pt= ((MPtex*)fdata->layers[active].data) + gtf->face;
MPtexSubface *subface= &pt->subfaces[gtf->offset];
totbytes+= (pt->channels * ptex_data_size(pt->type) *
subface->res[0] * subface->res[1]);
}
unode->mptex_data= MEM_mapallocN(sizeof(void*)*unode->totgrid, "PBVHUndoNode.mptex_data");
totbytes+= sizeof(void*)*unode->totgrid;
}
/* push undo node onto paint undo list */
undo_paint_push_count_alloc(UNDO_PAINT_MESH, totbytes);
BLI_addtail(lb, unode);
BLI_unlock_thread(LOCK_CUSTOM1);
/* the rest is threaded, hopefully this is the performance critical part */
if(uses_grids || (flag & (PBVH_UNDO_CO_NO|PBVH_UNDO_PMASK))) {
BLI_pbvh_vertex_iter_begin(pbvh, node, vd, PBVH_ITER_UNIQUE) {
if(flag & PBVH_UNDO_CO_NO) {
copy_v3_v3(unode->co[vd.i], vd.co);
if(vd.no) VECCOPY(unode->no[vd.i], vd.no)
else normal_float_to_short_v3(unode->no[vd.i], vd.fno);
}
if(flag & PBVH_UNDO_PMASK) {
if(vd.mask_active)
unode->pmask[vd.i]= *vd.mask_active;
}
if(vd.vert_indices)
unode->vert_indices[vd.i]= vd.vert_indices[vd.i];
}
BLI_pbvh_vertex_iter_end;
}
if(unode->grid_indices)
memcpy(unode->grid_indices, grid_indices, sizeof(int)*totgrid);
/* copy ptex data (doesn't handle res changes yet) */
if(flag & PBVH_UNDO_PTEX) {
MPtex *mptex;
int i;
mptex= CustomData_get_layer(fdata, CD_MPTEX);
for(i = 0; i < unode->totgrid; ++i) {
GridToFace *gtf= &grid_face_map[grid_indices[i]];
MPtex *pt= &mptex[gtf->face];
MPtexSubface *subface= &pt->subfaces[gtf->offset];
unode->mptex_data[i]= MEM_dupallocN(subface->data);
}
}
/* store active shape key */
ss= ob->paint->sculpt;
if(ss && ss->kb)
BLI_strncpy((char*)unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
else
unode->shapeName[0]= '\0';
return unode;
}
void pbvh_undo_push_begin(char *name)
{
undo_paint_push_begin(UNDO_PAINT_MESH, name,
pbvh_undo_restore, pbvh_undo_free);
}
void pbvh_undo_push_end(void)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
PBVHUndoNode *unode;
if(!lb || !lb->first)
return;
/* remove data that's only used during stroke */
for(unode=lb->first; unode; unode=unode->next) {
if(unode->no) {
MEM_freeN(unode->no);
unode->no= NULL;
}
if(unode->layer_disp) {
MEM_freeN(unode->layer_disp);
unode->layer_disp= NULL;
}
}
undo_paint_push_end(UNDO_PAINT_MESH);
}
int pbvh_undo_node_totvert(PBVHUndoNode *unode)
{
return unode->totvert;
}
pbvh_undo_f3 pbvh_undo_node_co(PBVHUndoNode *unode)
{
return unode->co;
}
pbvh_undo_s3 pbvh_undo_node_no(PBVHUndoNode *unode)
{
return unode->no;
}
float *pbvh_undo_node_layer_disp(PBVHUndoNode *unode)
{
return unode->layer_disp;
}
void pbvh_undo_node_set_layer_disp(PBVHUndoNode *unode, float *layer_disp)
{
unode->layer_disp = layer_disp;
}
const char *pbvh_undo_node_mptex_name(PBVHUndoNode *unode)
{
return unode->mptex_name;
}
void *pbvh_undo_node_mptex_data(PBVHUndoNode *unode, int ndx)
{
return unode->mptex_data[ndx];
}

File diff suppressed because it is too large Load Diff

View File

@@ -37,79 +37,18 @@
#include "BLI_pbvh.h"
struct bContext;
struct Brush;
struct KeyBlock;
struct Mesh;
struct MultiresModifierData;
struct Object;
struct Scene;
struct Sculpt;
struct SculptStroke;
/* Interface */
void sculptmode_selectbrush_menu(void);
void sculptmode_draw_mesh(int);
void sculpt_paint_brush(char clear);
void sculpt_stroke_draw(struct SculptStroke *);
void sculpt_radialcontrol_start(int mode);
struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob);
struct Brush *sculptmode_brush(void);
//void do_symmetrical_brush_actions(struct Sculpt *sd, struct wmOperator *wm, struct BrushAction *a, short *, short *);
void sculpt(Sculpt *sd);
struct PBVHNode;
struct SculptUndoNode;
int sculpt_poll(struct bContext *C);
void sculpt_update_mesh_elements(struct Scene *scene, struct Object *ob, int need_fmap);
/* Stroke */
struct SculptStroke *sculpt_stroke_new(const int max);
void sculpt_stroke_free(struct SculptStroke *);
void sculpt_stroke_add_point(struct SculptStroke *, const short x, const short y);
void sculpt_stroke_apply(struct Sculpt *sd, struct SculptStroke *);
void sculpt_stroke_apply_all(struct Sculpt *sd, struct SculptStroke *);
int sculpt_stroke_get_location(bContext *C, struct PaintStroke *stroke, float out[3], float mouse[2]);
/* Partial Mesh Visibility */
void sculptmode_pmv(int mode);
/* Undo */
typedef struct SculptUndoNode {
struct SculptUndoNode *next, *prev;
char idname[MAX_ID_NAME]; /* name instead of pointer*/
void *node; /* only during push, not valid afterwards! */
float (*co)[3];
short (*no)[3];
int totvert;
/* non-multires */
int maxvert; /* to verify if totvert it still the same */
int *index; /* to restore into right location */
/* multires */
int maxgrid; /* same for grid */
int gridsize; /* same for grid */
int totgrid; /* to restore into right location */
int *grids; /* to restore into right location */
/* layer brush */
float *layer_disp;
/* shape keys */
char *shapeName[32]; /* keep size in sync with keyblock dna */
} SculptUndoNode;
SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node);
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node);
void sculpt_undo_push_begin(char *name);
void sculpt_undo_push_end(void);
struct MultiresModifierData *sculpt_multires_active(struct Scene *scene, struct Object *ob);
int sculpt_modifiers_active(Scene *scene, Object *ob);
void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
int sculpt_modifiers_active(struct Scene *scene, struct Object *ob);
void sculpt_vertcos_to_key(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]);
void brush_jitter_pos(struct Brush *brush, float *pos, float *jitterpos);

View File

@@ -1,302 +0,0 @@
/*
* $Id$
*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2006 by Nicholas Bishop
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*
* Implements the Sculpt Mode tools
*
*/
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_mesh_types.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_key.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_sculpt.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
/************************** Undo *************************/
static void update_cb(PBVHNode *node, void *unused)
{
(void)unused;
BLI_pbvh_node_mark_update(node);
}
static void sculpt_undo_restore(bContext *C, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
DerivedMesh *dm = mesh_get_derived_final(scene, ob, 0);
SculptSession *ss = ob->sculpt;
SculptUndoNode *unode;
MVert *mvert;
MultiresModifierData *mmd;
int *index;
int i, j, update= 0;
sculpt_update_mesh_elements(scene, ob, 0);
for(unode=lb->first; unode; unode=unode->next) {
if(!(strcmp(unode->idname, ob->id.name)==0))
continue;
if(unode->maxvert) {
char *shapeName= (char*)unode->shapeName;
/* regular mesh restore */
if(ss->totvert != unode->maxvert)
continue;
if (ss->kb && strcmp(ss->kb->name, shapeName)) {
/* shape key has been changed before calling undo operator */
Key *key= ob_get_key(ob);
KeyBlock *kb= key_get_named_keyblock(key, shapeName);
if (kb) {
ob->shapenr= BLI_findindex(&key->block, kb) + 1;
ob->shapeflag|= OB_SHAPE_LOCK;
sculpt_update_mesh_elements(scene, ob, 0);
WM_event_add_notifier(C, NC_OBJECT|ND_DATA, ob);
} else {
/* key has been removed -- skip this undo node */
continue;
}
}
index= unode->index;
mvert= ss->mvert;
if (ss->kb) {
float (*vertCos)[3];
vertCos= key_to_vertcos(ob, ss->kb);
for(i=0; i<unode->totvert; i++)
swap_v3_v3(vertCos[index[i]], unode->co[i]);
/* propagate new coords to keyblock */
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
/* pbvh uses it's own mvert array, so coords should be */
/* propagated to pbvh here */
BLI_pbvh_apply_vertCos(ss->pbvh, vertCos);
MEM_freeN(vertCos);
} else {
for(i=0; i<unode->totvert; i++) {
swap_v3_v3(mvert[index[i]].co, unode->co[i]);
mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
}
else if(unode->maxgrid && dm->getGridData) {
/* multires restore */
DMGridData **grids, *grid;
float (*co)[3];
int gridsize;
if(dm->getNumGrids(dm) != unode->maxgrid)
continue;
if(dm->getGridSize(dm) != unode->gridsize)
continue;
grids= dm->getGridData(dm);
gridsize= dm->getGridSize(dm);
co = unode->co;
for(j=0; j<unode->totgrid; j++) {
grid= grids[unode->grids[j]];
for(i=0; i<gridsize*gridsize; i++, co++)
swap_v3_v3(grid[i].co, co[0]);
}
}
update= 1;
}
if(update) {
/* we update all nodes still, should be more clever, but also
needs to work correct when exiting/entering sculpt mode and
the nodes get recreated, though in that case it could do all */
BLI_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb, NULL);
BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB|PBVH_UpdateOriginalBB|PBVH_UpdateRedraw, NULL);
if((mmd=sculpt_multires_active(scene, ob)))
multires_mark_as_modified(ob);
if(ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1)
DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
}
}
static void sculpt_undo_free(ListBase *lb)
{
SculptUndoNode *unode;
for(unode=lb->first; unode; unode=unode->next) {
if(unode->co)
MEM_freeN(unode->co);
if(unode->no)
MEM_freeN(unode->no);
if(unode->index)
MEM_freeN(unode->index);
if(unode->grids)
MEM_freeN(unode->grids);
if(unode->layer_disp)
MEM_freeN(unode->layer_disp);
}
}
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
SculptUndoNode *unode;
if(!lb)
return NULL;
for(unode=lb->first; unode; unode=unode->next)
if(unode->node == node)
return unode;
return NULL;
}
SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
Object *ob= ss->ob;
SculptUndoNode *unode;
int totvert, allvert, totgrid, maxgrid, gridsize, *grids;
/* list is manipulated by multiple threads, so we lock */
BLI_lock_thread(LOCK_CUSTOM1);
if((unode= sculpt_undo_get_node(node))) {
BLI_unlock_thread(LOCK_CUSTOM1);
return unode;
}
unode= MEM_callocN(sizeof(SculptUndoNode), "SculptUndoNode");
strcpy(unode->idname, ob->id.name);
unode->node= node;
BLI_pbvh_node_num_verts(ss->pbvh, node, &totvert, &allvert);
BLI_pbvh_node_get_grids(ss->pbvh, node, &grids, &totgrid,
&maxgrid, &gridsize, NULL, NULL);
unode->totvert= totvert;
/* we will use this while sculpting, is mapalloc slow to access then? */
unode->co= MEM_mapallocN(sizeof(float)*3*allvert, "SculptUndoNode.co");
unode->no= MEM_mapallocN(sizeof(short)*3*allvert, "SculptUndoNode.no");
undo_paint_push_count_alloc(UNDO_PAINT_MESH, (sizeof(float)*3 + sizeof(short)*3 + sizeof(int))*allvert);
BLI_addtail(lb, unode);
if(maxgrid) {
/* multires */
unode->maxgrid= maxgrid;
unode->totgrid= totgrid;
unode->gridsize= gridsize;
unode->grids= MEM_mapallocN(sizeof(int)*totgrid, "SculptUndoNode.grids");
}
else {
/* regular mesh */
unode->maxvert= ss->totvert;
unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index");
}
BLI_unlock_thread(LOCK_CUSTOM1);
/* copy threaded, hopefully this is the performance critical part */
{
PBVHVertexIter vd;
BLI_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL) {
copy_v3_v3(unode->co[vd.i], vd.co);
if(vd.no) VECCOPY(unode->no[vd.i], vd.no)
else normal_float_to_short_v3(unode->no[vd.i], vd.fno);
if(vd.vert_indices) unode->index[vd.i]= vd.vert_indices[vd.i];
}
BLI_pbvh_vertex_iter_end;
}
if(unode->grids)
memcpy(unode->grids, grids, sizeof(int)*totgrid);
/* store active shape key */
if(ss->kb) BLI_strncpy((char*)unode->shapeName, ss->kb->name, sizeof(ss->kb->name));
else unode->shapeName[0]= '\0';
return unode;
}
void sculpt_undo_push_begin(char *name)
{
undo_paint_push_begin(UNDO_PAINT_MESH, name,
sculpt_undo_restore, sculpt_undo_free);
}
void sculpt_undo_push_end(void)
{
ListBase *lb= undo_paint_push_get_list(UNDO_PAINT_MESH);
SculptUndoNode *unode;
/* we don't need normals in the undo stack */
for(unode=lb->first; unode; unode=unode->next) {
if(unode->no) {
MEM_freeN(unode->no);
unode->no= NULL;
}
if(unode->layer_disp) {
MEM_freeN(unode->layer_disp);
unode->layer_disp= NULL;
}
}
undo_paint_push_end(UNDO_PAINT_MESH);
}

View File

@@ -648,7 +648,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o
dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_mesh);
} else if(faceselect) {
if(ob->mode & OB_MODE_WEIGHT_PAINT)
dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1, GPU_enable_material);
dm->drawMappedFaces(dm, NULL, wpaint__setSolidDrawOptions, me, GPU_enable_material, DM_DRAW_VERTEX_COLORS);
else
dm->drawMappedFacesTex(dm, draw_tface_mapped__set_draw, me);
}

View File

@@ -1872,7 +1872,7 @@ static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned
data.cols[2] = actCol;
data.efa_act = efa_act;
dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material);
dm->drawMappedFaces(dm, NULL, draw_dm_faces_sel__setDrawOptions, &data, GPU_enable_material, 0);
}
static int draw_dm_creases__setDrawOptions(void *UNUSED(userData), int index)
@@ -2292,7 +2292,7 @@ static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object
glEnable(GL_LIGHTING);
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, 0, 0, GPU_enable_material);
finalDM->drawMappedFaces(finalDM, NULL, draw_em_fancy__setFaceOpts, NULL, GPU_enable_material, 0);
glFrontFace(GL_CCW);
glDisable(GL_LIGHTING);
@@ -2425,7 +2425,7 @@ static void draw_mesh_object_outline(View3D *v3d, Object *ob, DerivedMesh *dm)
drawFacesSolid() doesn't draw the transparent faces */
if(ob->dtx & OB_DRAWTRANSP) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
dm->drawFacesSolid(dm, NULL, GPU_enable_material, 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
GPU_disable_material();
}
@@ -2454,6 +2454,9 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
int totvert, totedge, totface;
DispList *dl;
DerivedMesh *dm= mesh_get_derived_final(scene, ob, v3d->customdata_mask);
Paint *p;
float planes[4][4], (*paint_redraw_planes)[4] = NULL;
DMDrawFlags fast_navigate = 0;
if(!dm)
return;
@@ -2465,6 +2468,24 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
totface = dm->getNumFaces(dm);
/* setup for fast paint/sculpt drawing */
if((ob->mode & (OB_MODE_SCULPT|OB_MODE_VERTEX_PAINT)) &&
(p=paint_get_active(scene))) {
/* drop down to a low multires level during navigation */
fast_navigate = ((p->flags & PAINT_FAST_NAVIGATE) &&
(rv3d->rflag & RV3D_NAVIGATING))? DM_DRAW_LOWEST_SUBDIVISION_LEVEL : 0;
if(ob->paint && ob->paint->partial_redraw) {
if(ar->do_draw & RGN_DRAW_PARTIAL) {
paint_get_redraw_planes(planes, ar, rv3d, ob);
paint_redraw_planes = planes;
ob->paint->partial_redraw = 0;
}
}
}
/* vertexpaint, faceselect wants this, but it doesnt work for shaded? */
if(dt!=OB_SHADED)
@@ -2485,7 +2506,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
else if(dt==OB_WIRE || totface==0) {
draw_wire = 1; /* draw wire only, no depth buffer stuff */
}
else if( (ob==OBACT && (ob->mode & OB_MODE_TEXTURE_PAINT || paint_facesel_test(ob))) ||
else if( (ob==OBACT && (ob->mode & OB_MODE_TEXTURE_PAINT)) ||
CHECK_OB_DRAWTEXTURE(v3d, dt))
{
int faceselect= (ob==OBACT && paint_facesel_test(ob));
@@ -2522,8 +2543,11 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
/* weight paint in solid mode, special case. focus on making the weights clear
* rather then the shading, this is also forced in wire view */
GPU_enable_material(0, NULL);
dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material);
dm->drawMappedFaces(dm, NULL, wpaint__setSolidDrawOptions,
me->mface, GPU_enable_material,
DM_DRAW_VERTEX_COLORS);
bglPolygonOffset(rv3d->dist, 1.0);
glDepthMask(0); // disable write in zbuffer, selected edge wires show better
@@ -2544,9 +2568,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
draw_wire= 0;
}
else {
Paint *p;
if((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !draw_wire && !ob->sculpt)
if((v3d->flag&V3D_SELECT_OUTLINE) && ((v3d->flag2 & V3D_RENDER_OVERRIDE)==0) && (base->flag&SELECT) && !draw_wire && !ob->paint)
draw_mesh_object_outline(v3d, ob, dm);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED );
@@ -2554,23 +2576,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glEnable(GL_LIGHTING);
glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
if(ob->sculpt && (p=paint_get_active(scene))) {
float planes[4][4];
float (*fpl)[4] = NULL;
int fast= (p->flags & PAINT_FAST_NAVIGATE) && (rv3d->rflag & RV3D_NAVIGATING);
if(ob->sculpt->partial_redraw) {
if(ar->do_draw & RGN_DRAW_PARTIAL) {
sculpt_get_redraw_planes(planes, ar, rv3d, ob);
fpl = planes;
ob->sculpt->partial_redraw = 0;
}
}
dm->drawFacesSolid(dm, fpl, fast, GPU_enable_material);
}
else
dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
dm->drawFacesSolid(dm, paint_redraw_planes, GPU_enable_material, fast_navigate|DM_DRAW_PAINT_MASK);
GPU_disable_material();
@@ -2582,7 +2588,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
} else {
UI_ThemeColor(TH_WIRE);
}
if(!ob->sculpt && (v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
if(!ob->paint && (v3d->flag2 & V3D_RENDER_OVERRIDE)==0)
dm->drawLooseEdges(dm);
}
}
@@ -2605,18 +2611,36 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me->mface, 1, GPU_enable_material);
dm->drawMappedFaces(dm, NULL, wpaint__setSolidDrawOptions,
me->mface, GPU_enable_material,
DM_DRAW_VERTEX_COLORS);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_LIGHTING);
GPU_disable_material();
}
else if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_TEXTURE_PAINT)) {
if(me->mcol)
dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 1, GPU_enable_material);
if(me->mcol) {
MFace *mface = get_mesh(ob)->mface;
DMDrawFlags dm_flags = DM_DRAW_PTEX;
/* XXX - temporary - set up nicer drawing for new vpaint */
GPU_enable_material(mface->mat_nr+1, NULL);
glEnable(GL_LIGHTING);
dm_flags |= fast_navigate;
if(me->editflag & ME_EDIT_PTEX)
dm_flags |= DM_DRAW_PTEX_TEXELS;
dm->drawMappedFaces(dm, paint_redraw_planes,
wpaint__setSolidDrawOptions, NULL,
GPU_enable_material,
dm_flags);
glDisable(GL_LIGHTING);
}
else {
glColor3f(1.0f, 1.0f, 1.0f);
dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, NULL, 0, GPU_enable_material);
dm->drawMappedFaces(dm, NULL, wpaint__setSolidDrawOptions, NULL, GPU_enable_material, 0);
}
}
else do_draw= 1;
@@ -3082,7 +3106,7 @@ static int drawCurveDerivedMesh(Scene *scene, View3D *v3d, RegionView3D *rv3d, B
if(!glsl) {
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
glEnable(GL_LIGHTING);
dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
dm->drawFacesSolid(dm, NULL, GPU_enable_material, 0);
glDisable(GL_LIGHTING);
}
else
@@ -6334,7 +6358,7 @@ static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh
cpack(0);
if (facecol) {
dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, 0, GPU_enable_material);
dm->drawMappedFaces(dm, NULL, bbs_mesh_solid__setSolidDrawOptions, (void*)(intptr_t) 1, GPU_enable_material, 0);
if(check_ob_drawface_dot(scene, v3d, ob->dt)) {
glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
@@ -6345,7 +6369,7 @@ static void bbs_mesh_solid_EM(Scene *scene, View3D *v3d, Object *ob, DerivedMesh
}
} else {
dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, 0, GPU_enable_material);
dm->drawMappedFaces(dm, NULL, bbs_mesh_solid__setSolidDrawOptions, (void*) 0, GPU_enable_material, 0);
}
}
@@ -6375,8 +6399,14 @@ static void bbs_mesh_solid(Scene *scene, View3D *v3d, Object *ob)
glColor3ub(0, 0, 0);
if(face_sel_mode) dm->drawMappedFaces(dm, bbs_mesh_solid_hide__setDrawOpts, me, 0, GPU_enable_material);
else dm->drawMappedFaces(dm, bbs_mesh_solid__setDrawOpts, me, 0, GPU_enable_material);
if(face_sel_mode)
dm->drawMappedFaces(dm, NULL, bbs_mesh_solid_hide__setDrawOpts,
me, GPU_enable_material,
DM_DRAW_BACKBUF_SELECTION);
else
dm->drawMappedFaces(dm, NULL, bbs_mesh_solid__setDrawOpts,
me, GPU_enable_material,
DM_DRAW_BACKBUF_SELECTION);
dm->release(dm);
}
@@ -6479,11 +6509,11 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r
glEnable(GL_LIGHTING);
if(dm) {
dm->drawFacesSolid(dm, NULL, 0, GPU_enable_material);
dm->drawFacesSolid(dm, NULL, GPU_enable_material, 0);
GPU_end_object_materials();
}
else if(edm)
edm->drawMappedFaces(edm, NULL, NULL, 0, GPU_enable_material);
edm->drawMappedFaces(edm, NULL, NULL, NULL, GPU_enable_material, 0);
glDisable(GL_LIGHTING);
}

View File

@@ -74,6 +74,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
#include "ED_screen_types.h"
#include "ED_sculpt.h"
#include "ED_transform.h"
#include "UI_interface.h"
@@ -2205,6 +2206,37 @@ static void draw_viewport_fps(Scene *scene, ARegion *ar)
BLF_draw_default(22, ar->winy-17, 0.0f, printable);
}
void debug_draw_redraw_area(ARegion *ar)
{
rcti winrct;
if(G.rt != 444)
return;
/* do nothing if it looks like this isn't a partial redraw */
region_scissor_winrct(ar, &winrct);
if(ar->drawrct.xmin == winrct.xmin &&
ar->drawrct.xmax == winrct.xmax &&
ar->drawrct.ymin == winrct.ymin &&
ar->drawrct.ymax == winrct.ymax)
return;
/* choose a nice pastel color so that debugging is kept cheerful */
glColor3f((rand() / (float)RAND_MAX) * 0.3 + 0.7,
(rand() / (float)RAND_MAX) * 0.3 + 0.7,
(rand() / (float)RAND_MAX) * 0.3 + 0.7);
/* draw the redraw area, pull in by 2px so it doesn't get
clipped by the scissor */
glBegin(GL_LINE_LOOP);
glVertex2i(ar->drawrct.xmin-winrct.xmin+2, ar->drawrct.ymin-winrct.ymin+2);
glVertex2i(ar->drawrct.xmax-winrct.xmin-2, ar->drawrct.ymin-winrct.ymin+2);
glVertex2i(ar->drawrct.xmax-winrct.xmin-2, ar->drawrct.ymax-winrct.ymin-2);
glVertex2i(ar->drawrct.xmin-winrct.xmin+2, ar->drawrct.ymax-winrct.ymin-2);
glEnd();
}
void view3d_main_area_draw(const bContext *C, ARegion *ar)
{
Scene *scene= CTX_data_scene(C);
@@ -2404,12 +2436,12 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
}
ED_region_pixelspace(ar);
// retopo_paint_view_update(v3d);
// retopo_draw_paint_lines();
/* Draw particle edit brush XXX (removed) */
debug_draw_redraw_area(ar);
/* would be nicer to have as a region callback, but
can't get the right context then? -nicholas */
ED_paint_overlay_draw(C, ar);
if(rv3d->persp==RV3D_CAMOB)
drawviewborder(scene, ar, v3d);

View File

@@ -471,7 +471,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
PointerRNA meshptr;
RNA_pointer_create(&ob->id, &RNA_Mesh, ob->data, &meshptr);
uiItemR(layout, &meshptr, "use_paint_mask", UI_ITEM_R_ICON_ONLY, "", 0);
uiItemR(layout, &meshptr, "ptex_edit_mode", UI_ITEM_R_ICON_ONLY, "", 0);
} else {
char *str_menu;

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