Hello dudecon,
Thanks for the feedback. I’m not sure why I was having trouble posting the code. As I recall, I was bumping into a text limit, so I figured I could convert the code to an image and get around it. Then I couldn’t even post the small amount of code to decode it!! I gave up in frustration, but the new forum seems to be better behaved (one nice feature).
Here’s the little decoder that I wrote to extract “code.dat” from “code.png” (not really needed with the new forum and the updated version below):
import sys
import Image as img
def decode ( infile="code.png", outfile='code.dat' ):
ifile = img.open ( infile )
idata = ifile.getdata()
num_rows = ifile.size[0]
num_cols = ifile.size[1]
row = 0
col = 0
index = 0
pix = idata.getpixel ( (row,col) )
num_bytes = (pix[0] << 24) + (pix[1] << 16) + (pix[2] << 8) + pix[3]
print ( "File contains " + str(num_bytes) + " coded bytes" )
f = open ( outfile, "w" )
i = 0
while i < num_bytes:
pix_index = 1 + (i / 4)
row = pix_index / num_cols
col = pix_index % num_cols
pix_value = idata.getpixel ( (row,col) )
print ( "At row=" + str(row) + ", c=" + str(col) + " got " + str(pix_value) )
f.write ( chr(pix_value[0]) )
i += 1
if i < num_bytes:
f.write ( chr(pix_value[1]) )
i += 1
if i < num_bytes:
f.write ( chr(pix_value[2]) )
i += 1
if i < num_bytes:
f.write ( chr(pix_value[3]) )
i += 1
if __name__ == '__main__':
if len(sys.argv) == 3:
decode ( infile=sys.argv[1], outfile=sys.argv[2] )
else:
print ( "Provide 2 file names: input output" )
Thanks also for the suggestion for the animated rotation. That will be a neat trick to learn and it might justify cleaning up my code a bit (another good suggestion).
======================================================
UPDATE:
I added the lines you suggested, and it’s very slick. Thanks!!
I do, however, get a warning message from Blender (2.78c):
Warning: 1 x Draw Window and Swap: 22.0730 ms, average: 22.07303047 ms
Any thoughts on that?
Here’s the updated code (still not well functionalized, but works):
bl_info = {
"version": "0.1",
"name": "Rubiks Cube",
'author': 'Bob',
"category": "Games"
}
import bpy
from bpy.props import *
import os
import pickle
import math
import random
def update_blender ( context ):
# Rubik's Cube Color layout:
# W
# G R B O
# Y
# Red = +x Orange = -x
# Blue = +y Green = -y
# White = +z Yellow = -z
# Create materials as needed:
black_mat = None
if 'black' in bpy.data.materials:
# Use existing black material
black_mat = bpy.data.materials['black']
else:
# Add a new black material
black_mat = bpy.data.materials.new('black')
bpy.data.materials['black'].diffuse_color = [0,0,0]
bpy.data.materials['black'].diffuse_intensity = 1.0
bpy.data.materials['black'].emit = 0.0
red_mat = None
if 'red' in bpy.data.materials:
# Use existing red material
red_mat = bpy.data.materials['red']
else:
# Add a new red material
red_mat = bpy.data.materials.new('red')
bpy.data.materials['red'].diffuse_color = [1,0,0]
bpy.data.materials['red'].diffuse_intensity = 1.0
bpy.data.materials['red'].emit = 1.0
blue_mat = None
if 'blue' in bpy.data.materials:
# Use existing blue material
blue_mat = bpy.data.materials['blue']
else:
# Add a new blue material
blue_mat = bpy.data.materials.new('blue')
bpy.data.materials['blue'].diffuse_color = [0,0,1]
bpy.data.materials['blue'].diffuse_intensity = 1.0
bpy.data.materials['blue'].emit = 1.0
white_mat = None
if 'white' in bpy.data.materials:
# Use existing white material
white_mat = bpy.data.materials['white']
else:
# Add a new white material
white_mat = bpy.data.materials.new('white')
bpy.data.materials['white'].diffuse_color = [1,1,1]
bpy.data.materials['white'].diffuse_intensity = 1.0
bpy.data.materials['white'].emit = 1.0
orange_mat = None
if 'orange' in bpy.data.materials:
# Use existing orange material
orange_mat = bpy.data.materials['orange']
else:
# Add a new orange material
orange_mat = bpy.data.materials.new('orange')
bpy.data.materials['orange'].diffuse_color = [1,0.2,0]
bpy.data.materials['orange'].diffuse_intensity = 1.0
bpy.data.materials['orange'].emit = 1.0
green_mat = None
if 'green' in bpy.data.materials:
# Use existing green material
green_mat = bpy.data.materials['green']
else:
# Add a new green material
green_mat = bpy.data.materials.new('green')
bpy.data.materials['green'].diffuse_color = [0,0.5,0]
bpy.data.materials['green'].diffuse_intensity = 1.0
bpy.data.materials['green'].emit = 1.0
yellow_mat = None
if 'yellow' in bpy.data.materials:
# Use existing yellow material
yellow_mat = bpy.data.materials['yellow']
else:
# Add a new yellow material
yellow_mat = bpy.data.materials.new('yellow')
bpy.data.materials['yellow'].diffuse_color = [1,1,0]
bpy.data.materials['yellow'].diffuse_intensity = 1.0
bpy.data.materials['yellow'].emit = 1.0
# Start by deleting all objects
unlock_all()
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete(use_global=True)
# Build the sub-cubes that make up the game cube
for z in [-1,0,1]:
for y in [-1,0,1]:
for x in [-1,0,1]:
name = 'x' + str(x) + '_y' + str(y) + '_z' + str(z)
bpy.ops.mesh.primitive_cube_add()
bpy.ops.object.material_slot_add()
context.scene.objects.active.name = name
bpy.data.objects[name].location = (x,y,z)
s = 0.475 # 0.5 would leave no gaps between subsections of the cube
bpy.data.objects[name].scale = (s,s,s)
bpy.data.objects[name].material_slots[0].material = bpy.data.materials['black']
bpy.ops.object.mode_set ( mode="OBJECT" )
bpy.data.objects[name].select = False
ss = 0.9 # How much of each face is covered by the label
tl = 0.02 # Thickness of the label (times 2)
for side in [-1,1]:
if side == x:
delta = side * s
face_name = name+"_face_x_"+str(int(delta/abs(delta)))
bpy.ops.mesh.primitive_cube_add()
bpy.ops.object.material_slot_add()
context.scene.objects.active.name = face_name
bpy.data.objects[face_name].location = (x+delta,y,z)
bpy.data.objects[face_name].scale = (tl*ss*s,ss*s,ss*s)
if delta > 0:
bpy.data.objects[face_name].material_slots[0].material = bpy.data.materials['red']
else:
bpy.data.objects[face_name].material_slots[0].material = bpy.data.materials['orange']
bpy.ops.object.mode_set ( mode="OBJECT" )
bpy.data.objects[face_name].select = False
for side in [-1,1]:
if side == y:
delta = side * s
face_name = name+"_face_y_"+str(int(delta/abs(delta)))
bpy.ops.mesh.primitive_cube_add()
bpy.ops.object.material_slot_add()
context.scene.objects.active.name = face_name
bpy.data.objects[face_name].location = (x,y+delta,z)
bpy.data.objects[face_name].scale = (ss*s,tl*ss*s,ss*s)
if delta > 0:
bpy.data.objects[face_name].material_slots[0].material = bpy.data.materials['blue']
else:
bpy.data.objects[face_name].material_slots[0].material = bpy.data.materials['green']
bpy.ops.object.mode_set ( mode="OBJECT" )
bpy.data.objects[face_name].select = False
for side in [-1,1]:
if side == z:
delta = side * s
face_name = name+"_face_z_"+str(int(delta/abs(delta)))
bpy.ops.mesh.primitive_cube_add()
bpy.ops.object.material_slot_add()
context.scene.objects.active.name = face_name
bpy.data.objects[face_name].location = (x,y,z+delta)
bpy.data.objects[face_name].scale = (ss*s,ss*s,tl*ss*s)
if delta > 0:
bpy.data.objects[face_name].material_slots[0].material = bpy.data.materials['white']
else:
bpy.data.objects[face_name].material_slots[0].material = bpy.data.materials['yellow']
bpy.ops.object.mode_set ( mode="OBJECT" )
bpy.data.objects[face_name].select = False
# Set the center object as active so the "dot" will be centered
select_none()
context.scene.objects.active = bpy.data.objects['x0_y0_z0']
# Finish by selecting none and locking all objects
select_none()
lock_all()
def new_game ( self, context ):
game_cube = self
update_blender ( context )
class RubikProps(bpy.types.PropertyGroup):
show_settings = BoolProperty ( name = "Settings", default=False )
rotation_steps = IntProperty ( default = 1 )
scramble_steps = IntProperty ( default = 100 )
class SolvedGame(bpy.types.Operator):
bl_idname = "solved.game"
bl_label = "Solved Cube"
bl_description = ("New Game")
def execute(self, context):
game_cube = context.scene.Rubik3D
new_game ( game_cube, context )
return{'FINISHED'}
class RandomGame(bpy.types.Operator):
bl_idname = "random.game"
bl_label = "Random Cube"
bl_description = ("New Game")
def execute(self, context):
game_cube = context.scene.Rubik3D
new_game ( game_cube, context )
saved_rotation_steps = game_cube.rotation_steps
game_cube.rotation_steps = 1
# This is a simple method to keep a random move from reversing itself
inverses = { 0:1, 2:3, 4:5, 6:7, 8:9, 10:11, 1:0, 3:2, 5:4, 7:6, 9:8, 11:10 }
last_choice = 0
choice = 1
for i in range(game_cube.scramble_steps):
choice = random.randint(0,11)
# print ( "Chose first random choice " + str(choice) )
while choice == inverses[last_choice]:
choice = random.randint(0,11)
# print ( "Chose an additional random choice " + str(choice) )
last_choice = choice
# print ( "Using choice " + str(choice) )
if choice == 0:
bpy.ops.rotate.pxcw()
elif choice == 1:
bpy.ops.rotate.pxccw()
elif choice == 2:
bpy.ops.rotate.nxcw()
elif choice == 3:
bpy.ops.rotate.nxccw()
elif choice == 4:
bpy.ops.rotate.pycw()
elif choice == 5:
bpy.ops.rotate.pyccw()
elif choice == 6:
bpy.ops.rotate.nycw()
elif choice == 7:
bpy.ops.rotate.nyccw()
elif choice == 8:
bpy.ops.rotate.pzcw()
elif choice == 9:
bpy.ops.rotate.pzccw()
elif choice == 10:
bpy.ops.rotate.nzcw()
elif choice == 11:
bpy.ops.rotate.nzccw()
else:
print ( "Chose " + str(choice) + " on step " + str(i) )
pass
game_cube.rotation_steps = saved_rotation_steps
return{'FINISHED'}
def select_by_axis_sign ( axis_index, sign ):
objs = bpy.data.objects
unlock_all()
for o in objs:
o.hide_select = False
if sign >= 0:
if o.location[axis_index] > 0.5:
o.select = True
else:
o.select = False
else:
if o.location[axis_index] < -0.5:
o.select = True
else:
o.select = False
lock_all()
def lock_all():
objs = bpy.data.objects
for o in objs:
o.hide_select = True
def unlock_all():
objs = bpy.data.objects
for o in objs:
o.hide_select = False
def select_none():
objs = bpy.data.objects
for o in objs:
o.select = False
class UnlockAll(bpy.types.Operator):
bl_idname = "unlock.all"
bl_label = "Unlock All"
bl_description = ("Unlock all objects so they can be selected")
def execute(self, context):
unlock_all()
return{'FINISHED'}
class LockAll(bpy.types.Operator):
bl_idname = "lock.all"
bl_label = "Lock All"
bl_description = ("Lock all objects so none can be selected")
def execute(self, context):
lock_all()
return{'FINISHED'}
def rotate_cube_face ( game_cube, axis, direction ):
# bpy.ops.transform.rotate(value=direction*math.pi/(2*game_cube.rotation_steps),axis=axis)
rotation_amount = direction*math.pi/(2*game_cube.rotation_steps*7)
for i in range(7):
bpy.ops.transform.rotate(value=rotation_amount,axis=axis)
bpy.ops.wm.redraw_timer (type='DRAW_WIN_SWAP', iterations=1)
class Rotate_PosX_CW(bpy.types.Operator):
bl_idname = "rotate.pxcw"
bl_label = "CW"
bl_description = ("Rotate selected face clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 0, 1 )
rotate_cube_face ( game_cube, (1,0,0), -1 )
select_none()
return{'FINISHED'}
class Rotate_PosX_CCW(bpy.types.Operator):
bl_idname = "rotate.pxccw"
bl_label = "CCW"
bl_description = ("Rotate selected face counter-clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 0, 1 )
rotate_cube_face ( game_cube, (1,0,0), 1 )
select_none()
return{'FINISHED'}
class Rotate_NegX_CW(bpy.types.Operator):
bl_idname = "rotate.nxcw"
bl_label = "CW"
bl_description = ("Rotate selected face clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 0, -1 )
rotate_cube_face ( game_cube, (1,0,0), 1 )
select_none()
return{'FINISHED'}
class Rotate_NegX_CCW(bpy.types.Operator):
bl_idname = "rotate.nxccw"
bl_label = "CCW"
bl_description = ("Rotate selected face counter-clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 0, -1 )
rotate_cube_face ( game_cube, (1,0,0), -1 )
select_none()
return{'FINISHED'}
class Rotate_PosY_CW(bpy.types.Operator):
bl_idname = "rotate.pycw"
bl_label = "CW"
bl_description = ("Rotate selected face clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 1, 1 )
rotate_cube_face ( game_cube, (0,1,0), -1 )
select_none()
return{'FINISHED'}
class Rotate_PosY_CCW(bpy.types.Operator):
bl_idname = "rotate.pyccw"
bl_label = "CCW"
bl_description = ("Rotate selected face counter-clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 1, 1 )
rotate_cube_face ( game_cube, (0,1,0), 1 )
select_none()
return{'FINISHED'}
class Rotate_NegY_CW(bpy.types.Operator):
bl_idname = "rotate.nycw"
bl_label = "CW"
bl_description = ("Rotate selected face clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 1, -1 )
rotate_cube_face ( game_cube, (0,1,0), 1 )
select_none()
return{'FINISHED'}
class Rotate_NegY_CCW(bpy.types.Operator):
bl_idname = "rotate.nyccw"
bl_label = "CCW"
bl_description = ("Rotate selected face counter-clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 1, -1 )
rotate_cube_face ( game_cube, (0,1,0), -1 )
select_none()
return{'FINISHED'}
class Rotate_PosZ_CW(bpy.types.Operator):
bl_idname = "rotate.pzcw"
bl_label = "CW"
bl_description = ("Rotate selected face clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 2, 1 )
rotate_cube_face ( game_cube, (0,0,1), -1 )
select_none()
return{'FINISHED'}
class Rotate_PosZ_CCW(bpy.types.Operator):
bl_idname = "rotate.pzccw"
bl_label = "CCW"
bl_description = ("Rotate selected face counter-clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 2, 1 )
rotate_cube_face ( game_cube, (0,0,1), 1 )
select_none()
return{'FINISHED'}
class Rotate_NegZ_CW(bpy.types.Operator):
bl_idname = "rotate.nzcw"
bl_label = "CW"
bl_description = ("Rotate selected face clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 2, -1 )
rotate_cube_face ( game_cube, (0,0,1), 1 )
select_none()
return{'FINISHED'}
class Rotate_NegZ_CCW(bpy.types.Operator):
bl_idname = "rotate.nzccw"
bl_label = "CCW"
bl_description = ("Rotate selected face counter-clockwise")
def execute(self, context):
game_cube = context.scene.Rubik3D
#print ( "Rotate " + self.bl_idname )
select_by_axis_sign ( 2, -1 )
rotate_cube_face ( game_cube, (0,0,1), -1 )
select_none()
return{'FINISHED'}
class RubikPanel(bpy.types.Panel):
bl_label = "Rubik's Cube"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_category = "Rubik's Cube"
def draw(self, context):
game_cube = context.scene.Rubik3D
row = self.layout.row()
row.operator ( "solved.game" )
row = self.layout.row()
row.operator ( "random.game" )
row = self.layout.row()
face_names = [('red','px'), ('orange','nx'), ('blue','py'), ('green','ny'), ('white','pz'), ('yellow','nz')]
for f in face_names:
c = f[0]
if c in bpy.data.materials:
row = self.layout.row()
row.prop ( bpy.data.materials[c], 'diffuse_color', text="", )
row.operator ( "rotate." + f[1] + "cw" )
row.operator ( "rotate." + f[1] + "ccw" )
row = self.layout.row(align=True)
row.alignment = 'LEFT'
if not game_cube.show_settings:
row.prop ( game_cube, 'show_settings', icon = 'TRIA_RIGHT', text="Additional Settings", emboss=False )
else:
row.prop ( game_cube, 'show_settings', icon = 'TRIA_DOWN', text="Additional Settings", emboss=False )
row = self.layout.row()
row.prop(context.user_preferences.inputs, "view_rotate_method", expand=True)
areas = context.screen.areas
areas_3d = [ areas[i] for i in range(len(areas)) if areas[i].type == 'VIEW_3D' ]
for area in areas_3d:
for space in area.spaces:
if 'show_only_render' in dir(space):
row = self.layout.row()
row.prop ( space, 'show_only_render', text="Show Only Render" )
if 'cursor_location' in dir(space):
row = self.layout.row()
row.prop ( space, 'cursor_location', text="3D Cursor" )
if 'lens' in dir(space):
row = self.layout.row()
row.prop ( space, 'lens', text="View Lens" )
row = self.layout.row()
row.operator ( "view3d.snap_cursor_to_center" )
row = self.layout.row()
row.prop ( game_cube, 'rotation_steps', text="Steps per Rotation" )
row = self.layout.row()
row.prop ( game_cube, 'scramble_steps', text="Steps to Scramble" )
row = self.layout.row()
row.operator ( "unlock.all" )
row = self.layout.row()
row.operator ( "lock.all" )
def register():
print ("Registering ", __name__)
bpy.utils.register_module(__name__)
bpy.types.Scene.Rubik3D = bpy.props.PointerProperty(type=RubikProps)
def unregister():
print ("Unregistering ", __name__)
del bpy.types.Scene.Rubik3D
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
With the new animation, it’s fun just watching it scramble itself!!