/
Color To Material.pyp
418 lines (348 loc) · 13.7 KB
/
Color To Material.pyp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# -*- coding: utf-8 -*-
#
# Color To Material
# CINEMA 4D Python Plugins
#
# Created by André Berg on 2011-03-22.
# Copyright 2011 Berg Media. All rights reserved.
#
# Version 1.0
# Updated: 2013-07-29
#
# (license details see end of file)
#
# Summary: Convert an object's layer or object color to
# a newly assigned material with that same color.
#
# Modus Operandi
#
# First, loop through all the objects that are selected
# in the object manager and get the layer the object belongs to.
# Then, create a new material and set the material's color channel to
# the same RGB color as the color of the layer.
# Create a new texture tag on the object and assign the corresponding
# material.
# Do not create a new material if a material with name "RGB x,y,z"
# already exists. Use existing material instead.
#
# Tip: If you want all the new materials that will be created added to
# an existing material layer, in the Material Manager switch to that layer
# before running the script. Any materials created will be assigned to this
# layer automatically.
#
# TODO: in the future the material layer new materials are assigned to
# should be choosable in the interface).
#
#
import re
import os
import math
import time
import c4d
from c4d import plugins, bitmaps, gui, documents
# from c4d.utils import *
#from c4d import *
DEBUG = True
if DEBUG:
import pprint
pp = pprint.PrettyPrinter(width=200)
PP = pp.pprint
PF = pp.pformat
CR_YEAR = time.strftime("%Y")
# -------------------------------------------
# PLUGING IDS
# -------------------------------------------
# unique ID
ID_COLORTOMATERIAL = 1026870
# Element IDs
IDD_DIALOG_SETTINGS = 10001
IDC_GROUP_WRAPPER = 10002
IDC_GROUP_SETTINGS = 10003
IDC_STATIC_CHANNEL = 10004
IDC_COMBO_CHANNEL = 10005
IDC_STATIC_SOURCE = 10006
IDC_COMBO_SOURCE = 10007
IDC_CHECK_CLEARPREV = 10008
IDC_GROUP_BUTTONS = 10009
IDC_BUTTON_CANCEL = 10010
IDC_BUTTON_DOIT = 10011
IDC_CHECK_CHILDREN = 10012
IDC_GROUP_SETTINGS2 = 10013
IDC_MENU_ABOUT = 30001
# String IDs
IDS_PLUGIN_VERSION = 1.0
IDS_PLUGIN_NAME = "Color To Material"
IDS_HELP_STRING = "Create and assign a material with the same color as an object's layer or viewport color"
IDS_DIALOG_TITLE = "Color To Material"
IDS_BUTTON_CANCEL = "Cancel"
IDS_BUTTON_DOIT = "Do It!"
IDS_STATIC_CHANNEL = "Material Channel"
IDS_STATIC_SOURCE = "Color Source"
IDS_GROUP_SETTINGS = "Settings"
IDS_CHECK_CLEARPREV= "Clear previous tags"
IDS_MENU_INFO = "Info"
IDS_MENU_ABOUT = "About..."
IDS_ABOUT = """(C) %s Andre Berg (Berg Media)
All rights reserved.
Version %s
Color To Material is a Python plugin that allows
for making the Display > Layer Color viewport,
as well as the Basic > Use Color object settings
renderable by assigning materials with the target
material channel set to the object or layer color.
Use at your own risk!
It is recommended to try out the plugin
on a spare copy of your data first.
""" % (CR_YEAR, IDS_PLUGIN_VERSION)
# --------------------------------------------------------
# Defaults
# --------------------------------------------------------
RGB_8BIT_MULT = 255
# no idea why these symbols are there in console and otherwise in scripts
# but for plugins the c4d module doesn't have attributes called MATERIAL_COLOR_COLOR etc.
# so I need to hardcode the values :(
MATERIAL_COLOR_COLOR = 2100
MATERIAL_LUMINANCE_COLOR = 2300
TARGET_CHANNEL = MATERIAL_COLOR_COLOR
COLOR_SOURCE = 0 # 0 = LAYER, 1 = OBJECT
# "Enum"
COLOR_SOURCE_LAYER = 1
COLOR_SOURCE_OBJECT = 2
TARGET_CHANNEL_COLOR = 1
TARGET_CHANNEL_LUMINANCE = 2
# ----------------------------------------------------------------
# Helper Functions
# ----------------------------------------------------------------
def ColorToString(col):
return "RGB " \
+ str(int(math.floor(col.x * RGB_8BIT_MULT))) + "," \
+ str(int(math.floor(col.y * RGB_8BIT_MULT))) + "," \
+ str(int(math.floor(col.z * RGB_8BIT_MULT)))
def FindLastTag(op):
ttag = op.GetFirstTag()
ttag1 = None
while(ttag):
ttag1 = ttag;
ttag = ttag.GetNext()
if ttag1 is not None:
return ttag1
else:
return None
def OpHasTextureTagWithMaterialName(op, str, isregex=False):
ttag = op.GetFirstTag()
while (ttag):
if isinstance(ttag, c4d.TextureTag):
mname = ttag.GetMaterial().GetName()
if isregex:
match = re.match(str, mname)
if match: return True
else:
if mname == str: return True
ttag = ttag.GetNext()
if ttag is None:
break
return False
def FindMaterial(str, isregex=False, doc=None):
if doc is None:
doc = c4d.documents.GetActiveDocument()
mats = doc.GetMaterials()
if mats:
if isregex:
for mat in mats:
mname = mat.GetName()
match = re.match(str, mname)
if match: return mat
else:
for mat in mats:
if mat.GetName() == str:
return mat
return None
# ------------------------------------------------------
# User Interface
# ------------------------------------------------------
# Snippets
# self.AddStaticText(ID, c4d.BFH_CENTER | c4d.BFV_CENTER, name=IDS) # id, flags[, initw=0][, inith=0][, name=""][, borderstyle=0]
class ColorToMaterialDialog(gui.GeDialog):
def CreateLayout(self):
plugins.GeResource().Init(os.path.dirname(os.path.abspath(__file__)))
self.LoadDialogResource(IDD_DIALOG_SETTINGS, flags=c4d.BFH_SCALEFIT)
# Menu
self.MenuFlushAll()
self.MenuSubBegin(IDS_MENU_INFO)
self.MenuAddString(IDC_MENU_ABOUT, IDS_MENU_ABOUT)
self.MenuSubEnd()
self.MenuFinished()
return True
def InitValues(self):
self.SetLong(IDC_COMBO_CHANNEL, 1)
self.SetLong(IDC_COMBO_SOURCE, 1)
self.SetLong(IDC_CHECK_CLEARPREV, 1)
self.SetLong(IDC_CHECK_CHILDREN, 1)
return True
def Command(self, id, msg):
if id == IDC_BUTTON_DOIT:
cursrc = self.GetLong(IDC_COMBO_SOURCE)
curchan = self.GetLong(IDC_COMBO_CHANNEL)
clear = self.GetLong(IDC_CHECK_CLEARPREV)
children = self.GetLong(IDC_CHECK_CHILDREN)
scriptvars = {
'source': cursrc,
'channel': curchan,
'clearprev': clear,
'children': children
}
script = ColorToMaterialScript(scriptvars)
if DEBUG:
print "do it: %r" % msg
print "script = %r" % script
print "scriptvars = %r" % scriptvars
return script.run()
elif id == IDC_BUTTON_CANCEL:
if DEBUG:
print "cancel: %r" % msg
self.Close()
elif id == IDC_MENU_ABOUT:
c4d.gui.MessageDialog(IDS_ABOUT)
else:
if DEBUG:
print "id = %s" % id
return True
# ------------------------------------------------------
# Command Script
# ------------------------------------------------------
class ColorToMaterialScript(object):
"""Run when the user clicks the DoIt! button."""
def __init__(self, scriptvars=None):
super(ColorToMaterialScript, self).__init__()
self.data = scriptvars
def run(self):
doc = documents.GetActiveDocument()
doc.StartUndo()
chan = self.data['channel']
src = self.data['source']
clr = self.data['clearprev'] == 1
chld = self.data['children'] == 1
if chan == TARGET_CHANNEL_COLOR:
TARGET_CHANNEL = MATERIAL_COLOR_COLOR
elif chan == TARGET_CHANNEL_LUMINANCE:
TARGET_CHANNEL = MATERIAL_LUMINANCE_COLOR
if src == COLOR_SOURCE_LAYER:
COLOR_SOURCE = 0
elif src == COLOR_SOURCE_OBJECT:
COLOR_SOURCE = 1
if chld:
c4d.CallCommand(100004768) # Select Children
sel = doc.GetSelection()
if sel is None: return False
for op in sel:
lay = op[c4d.ID_LAYER_LINK]
opusescolor = op[c4d.ID_BASEOBJECT_USECOLOR]
col = None
layname = None
if COLOR_SOURCE == 1 and (opusescolor > 0 and opusescolor < 3): # 0 = off, 1 = auto, 2 = always, 3 = layer
# use the object's color as color source
col = op[c4d.ID_BASEOBJECT_COLOR]
elif COLOR_SOURCE == 0 or opusescolor == 3:
# use the layer the object belongs to as color source
if lay is None: continue # if the object has no layer get the next selected object
col = lay[c4d.ID_LAYER_COLOR]
layname = lay.GetName()
else:
# continue with next object
continue
colstr = ColorToString(col)
if col:
# see if a material with name "RGB x,y,z" already exists
mat = FindMaterial(colstr, False, doc)
if mat is None:
# if not create a new material
c4d.StopAllThreads()
c4d.CallCommand(13015) # New Material
mat = doc.GetFirstMaterial()
if mat is None: return False
doc.AddUndo(c4d.UNDO_NEW, mat)
else:
if DEBUG: print "material %s already exists" % mat.GetName()
# set material name to "RGB x,y,z"
mat.SetName(colstr)
# set the color channel to the RGB values of the layer
mat[TARGET_CHANNEL] = col
# determine channel to switch off (everything other than chosen)
if TARGET_CHANNEL == MATERIAL_COLOR_COLOR:
onchan = c4d.MATERIAL_USE_COLOR
offchans = [c4d.MATERIAL_USE_LUMINANCE]
elif TARGET_CHANNEL == MATERIAL_LUMINANCE_COLOR:
onchan = c4d.MATERIAL_USE_LUMINANCE
offchans = [c4d.MATERIAL_USE_COLOR]
# enable material channel, disable other(s)
mat[onchan] = True
for offchan in offchans:
mat[offchan] = False
# find out if the object already has a tag which references the proper layer material
if not OpHasTextureTagWithMaterialName(op, colstr):
if DEBUG: print "colstr = %s" % colstr
c4d.StopAllThreads()
if clr:
for tag in op.GetTags():
if tag.GetType() == c4d.Ttexture:
n = tag.GetMaterial().GetName()
if n != colstr and re.match(r'RGB \d+,\d+,\d+', n):
if DEBUG:
print "removing previous tag with name %s" % n
tag.Remove()
c4d.EventAdd()
textag = c4d.TextureTag() # was: op.MakeTag(c4d.Ttexture)
if textag is None: return False
lasttag = FindLastTag(op)
if lasttag is not None:
if DEBUG: print "lasttag = %s" % lasttag.GetName()
doc.AddUndo(c4d.UNDO_TAG_NEW, textag);
doc.AddUndo(c4d.UNDO_TAG_DATA, textag);
textag.SetMaterial(mat)
if lasttag is not None:
op.InsertTag(textag, lasttag)
else:
op.InsertTag(textag)
#textag[TEXTURETAG_PROJECTION] = 6 # Set projection to UVW
c4d.EventAdd()
doc.EndUndo()
return True
# ----------------------------------------------------
# Main
# ----------------------------------------------------
class ColorToMaterialMain(plugins.CommandData):
dialog = None
def Execute(self, doc):
# create the dialog
if self.dialog is None:
self.dialog = ColorToMaterialDialog()
return self.dialog.Open(c4d.DLG_TYPE_ASYNC, pluginid=ID_COLORTOMATERIAL)
def RestoreLayout(self, secref):
# manage nonmodal dialog
if self.dialog is None:
self.dialog = ColorToMaterialDialog()
return self.dialog.Restore(pluginid=ID_COLORTOMATERIAL, secret=secref)
if __name__ == "__main__":
thispath = os.path.dirname(os.path.abspath(__file__))
icon = bitmaps.BaseBitmap()
icon.InitWith(os.path.join(thispath, "res/", "icon.tif"))
plugins.RegisterCommandPlugin(
ID_COLORTOMATERIAL,
IDS_PLUGIN_NAME,
0,
icon,
IDS_HELP_STRING,
ColorToMaterialMain()
)
print "%s v%.1f loaded. (C) %s Andre Berg" % (IDS_PLUGIN_NAME, IDS_PLUGIN_VERSION, CR_YEAR)
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.