-> Color Fixing tool in FLT toolbar
authorGeoffrey Bantle <hairbat@yahoo.com>
Wed, 19 Mar 2008 21:14:49 +0000 (21:14 +0000)
committerGeoffrey Bantle <hairbat@yahoo.com>
Wed, 19 Mar 2008 21:14:49 +0000 (21:14 +0000)
A new tool for for fixing colors on meshes imported from other files with
conflicting color palettes has been added to the FLT toolbar script. This
will find the closest match for all the colors in the faces of selected
meshes and update their baked vertex color representation.

Also added a small tweak to the 'update all' tool which will fix black faces

release/scripts/flt_toolbar.py

index 213fac1bb3c9b0e5b4a0e5ac962224dbecff64f9..249c3f83dfccd72ec7d0c4a867ea288f1d383b0e 100644 (file)
@@ -76,7 +76,8 @@ evcode = {
        "IDPROP_COPY" : 501,
        "IDPROP_KILL" : 502,
        "CLIGHT_MAKE" : 700,
-       "DFROMACT" : 701
+       "DFROMACT" : 701,
+       "FIXCOL" : 702
 }
 
 XREF_PREFIX = None
@@ -92,6 +93,44 @@ IDPROP_COPY = None
 SCENE_UPDATE = None
 CLIGHT_MAKE = None
 DFROMACT = None
+FIXCOL = None
+
+
+def RGBtoHSV( r, g, b):
+       cmin = min( r, g, b )
+       cmax = max( r, g, b )
+       v = cmax                                
+
+       if(cmax!=0.0):
+               s = (cmax-cmin)/cmax
+       else:
+               s = 0.0
+               h = 0.0
+       
+       if(s == 0.0):
+               h = -1.0
+       else:
+               cdelta = cmax-cmin
+               rc = (cmax-r)/cdelta
+               gc = (cmax-g)/cdelta
+               bc = (cmax-b)/cdelta
+               if(r==cmax):
+                       h = bc-gc
+               else:
+                       if(g==cmax):
+                               h = 2.0+rc-bc
+                       else:
+                               h = 4.0+gc-rc
+               h = h*60.0
+               if(h<0.0):
+                       h += 360.0
+                       
+               
+       h = h/360.0
+       if(h < 0.0): 
+               h = 0.0
+       return (h,s,v)
+
 
 def update_state():
        state = dict()
@@ -141,24 +180,130 @@ def idprops_copy(source):
                                for key in source.properties['FLT']:
                                        object.properties['FLT'][key] = source.properties['FLT'][key]
 
-def update_all():
+def unpack_color(color):
+       return struct.unpack('>BBBB',struct.pack('>I',color))
+
+
+def findColorKey(colordict, hsv):
+       hdelta = 0.001
+       for key in colordict:
+               if not (((hsv[0] < (key[0] + hdelta)) and (hsv[0] > (key[0] - hdelta))) and ((hsv[1] < (key[1] + hdelta)) and (hsv[1] > (key[1] - hdelta)))):
+                       return key
+       return None
+
+def hsvsort(a, b):
+       (index1, mag1) = a
+       (index2, mag2) = b
+       if mag1 > mag2:
+               return 1
+       elif mag1 < mag2:
+               return -1
+       return 0
+
+def fix_colors():
+       
+       editmode = 0
+       if Blender.Window.EditMode():
+               Blender.Window.EditMode(0)
+               editmode = 1
        state = update_state()
-       #update the baked FLT colors for all meshes.
-       for object in state["activeScene"].objects:
-               if object.type == "Mesh":
+       
+       scene = state["activeScene"]
+       colors = None
+       if state["activeScene"].properties.has_key('FLT'):
+               try:
+                       colors = state["activeScene"].properties['FLT']['Color Palette']
+               except:
+                       pass
+       if not colors:
+               return
+       
+       #first build a HSV version of our palette
+       hsvpalette = list()
+       for swatch in colors:
+               color = unpack_color(swatch)
+               hsv = RGBtoHSV(color[0] / 255.0, color[1] / 255.0, color[2] / 255.0)
+               hsvpalette.append(hsv)
+               
+       #collect all of our meshes
+       meshes = list()
+       for object in scene.objects.context:
+               if object.sel and object.type == 'Mesh':
                        mesh = object.getData(mesh=True)
-                       if 'FLT_COL' in mesh.faces.properties:
-                               mesh.activeColorLayer = "FLT_Fcol"
-                               for face in mesh.faces:
-                                       (index,intensity) = unpack_face_index(face.getProperty('FLT_COL'))
-                                       color = struct.unpack('>BBBB',struct.pack('>I',state["colors"][index]))
-                                       #update the vertex colors for this face
-                                       for col in face.col:
-                                               col.r = int(color[0] * intensity)
-                                               col.g = int(color[1] * intensity)
-                                               col.b = int(color[2] * intensity)
-                                               col.a = 255
+                       if "FLT_COL" in mesh.faces.properties:
+                               meshes.append(mesh)
+                               
+                               
+       #Now go through our meshes, and build a dictionary of face lists keyed according to (hue,saturation) of the baked color
+       colordict = dict()
+       for mesh in meshes:
+               for face in mesh.faces:
+                       hsv = RGBtoHSV(face.col[0].r/255.0, face.col[0].g/255.0, face.col[0].b/255.0) #retrieve baked color
+                       if colordict.has_key((hsv[0],hsv[1])):
+                               colordict[(hsv[0],hsv[1])].append(face)
+                       else:
+                               colordict[(hsv[0],hsv[1])] = [face]                             
+       
 
+       #for each color key in the color dict, build a list of distances from it to the values in hsvpalette and then quicksort them for closest match
+       for key in colordict:
+               maglist = list()
+               for i, hsv in enumerate(hsvpalette):
+                       norm = Blender.Mathutils.Vector(hsv[0], hsv[1]) - Blender.Mathutils.Vector(key[0],key[1])
+                       maglist.append((i,norm.length))
+               maglist.sort(hsvsort)
+               print maglist[0]
+               for face in colordict[key]:
+                       (index, intensity) = unpack_face_index(face.getProperty("FLT_COL"))
+                       newfindex = pack_face_index(maglist[0][0],intensity)
+                       face.setProperty("FLT_COL", int(newfindex))
+       
+       for mesh in meshes:
+               update_mesh_colors(colors,mesh) 
+       
+       if editmode:
+               Blender.Window.EditMode(1)      
+       
+
+def update_mesh_colors(colors, mesh):
+       if 'FLT_COL' in mesh.faces.properties:
+               mesh.activeColorLayer = "FLT_Fcol"
+               for face in mesh.faces:
+                       (index,intensity) = unpack_face_index(face.getProperty('FLT_COL'))
+                       color = struct.unpack('>BBBB',struct.pack('>I',colors[index]))
+                       
+                       if index == 0 and intensity == 0:
+                               color = (255,255,255)
+                               intensity  = 1.0
+                       #update the vertex colors for this face
+                       for col in face.col:
+                               col.r = int(color[0] * intensity)
+                               col.g = int(color[1] * intensity)
+                               col.b = int(color[2] * intensity)
+                               col.a = 255
+       
+               
+def update_all():
+       
+       editmode = 0
+       if Blender.Window.EditMode():
+               Blender.Window.EditMode(0)
+               editmode = 1
+       state = update_state()
+       
+       if state["activeScene"].properties.has_key('FLT'):
+               try:
+                       colors = state["activeScene"].properties['FLT']['Color Palette']
+               except:
+                       colors = None
+       if colors:
+               #update the baked FLT colors for all meshes.
+               for object in state["activeScene"].objects:
+                       if object.type == "Mesh":
+                               mesh = object.getData(mesh=True)
+                               update_mesh_colors(colors,mesh)
+       if editmode:
+               Blender.Window.EditMode(1)
 
 #Change this to find the deep parent
 def xref_create():
@@ -528,6 +673,8 @@ def but_event(evt):
                clight_make()
        if evt == evcode["DFROMACT"]:
                dfromact()
+       if evt == evcode["FIXCOL"]:
+               fix_colors()
        Draw.Redraw(1)
        Blender.Window.RedrawAll()
 
@@ -582,17 +729,20 @@ def draw_postcommon(x,y,finaly):
 
 
 def draw_propsheet(x,y):
-        global XREF_PREFIX
-        global XREF_MAKE
-        global XREF_EDIT
-        global XREF_SELECT
-        global XREF_POP
-        global FACE_MAKESUB
-        global FACE_SELSUB
-        global FACE_KILLSUB
-        global IDPROP_KILL
-        global IDPROP_COPY
-        global SCENE_UPDATE
+       global XREF_PREFIX
+       global XREF_MAKE
+       global XREF_EDIT
+       global XREF_SELECT
+       global XREF_POP
+       global FACE_MAKESUB
+       global FACE_SELSUB
+       global FACE_KILLSUB
+       global IDPROP_KILL
+       global IDPROP_COPY
+       global SCENE_UPDATE
+       global DFROMACT
+       global FIXCOL
+               
        global CLIGHT_MAKE
        global xrefprefix
        global xrefstack
@@ -643,11 +793,13 @@ def draw_propsheet(x,y):
        
        y=y-20
        DFROMACT = Blender.Draw.PushButton("Dof from Active", evcode["DFROMACT"],x,y,width,20,"Get Dof origin from active object")
-        draw_postcommon(origx, origy,y)
+       y=y-20
+       FIXCOL = Blender.Draw.PushButton("Fix Colors", evcode["FIXCOL"],x,y,width,20,"Fix baked FLT colors of selected meshes")         
+       draw_postcommon(origx, origy,y)
                
 def gui():
        #draw the propsheet/toolbox.
-       psheety = 280
+       psheety = 300
        #psheetx = psheety + 10
        draw_propsheet(0,psheety)
 Draw.Register(gui,event,but_event)