class Cube: def __init__(self, settings, face_rotation_ease_type, sticker_texture_id, size=3): default_color = (0, 0, 0) self.padding = settings.cube_padding self.draw_cubies = settings.cube_draw_cubies self.draw_sphere = settings.cube_draw_sphere self.draw_lines = settings.cube_draw_lines self.line_width = settings.cube_line_width self.inner_color = LittleHelpers.convert_hex_color_to_floats( settings.cube_inner_color, default_color) self.sphere_color = LittleHelpers.convert_hex_color_to_floats( settings.cube_sphere_color, default_color) self.angular_drag = settings.cube_angular_drag self.scale_drag = settings.cube_scale_drag self.min_scale = settings.cube_min_scale / size self.max_scale = settings.cube_max_scale self.size = size self.rot_x = 0 self.rot_y = 0 self.accum = (1, 0, 0, 0) self.scale = 1 / (self.size / 3) self.scale_speed = 0 self.sphere_radius = 3 self.sphere_slices = 16 self.sphere_stacks = 16 self.face_rotation_tween_time = settings.cube_face_rotation_tween_time self.face_rotation_ease_type = face_rotation_ease_type self.texture_mapping_enabled = settings.texture_mapping_enabled self.sticker_texture_id = sticker_texture_id self.geometry = Geometry(self.size) self.face_colors = ( (0, 154 / 255, 74 / 255), # Front: Green (1, 86 / 255, 35 / 255), # Left: Orange (0, 75 / 255, 171 / 255), # Back: Blue (190 / 255, 15 / 255, 56 / 255), # Right: Red (1, 1, 1), # Up: White (1, 210 / 255, 44 / 255), # Down: Yellow ) self.reset() rx = settings.cube_initial_rotation_x * Mathf.DEG_TO_RAD ry = settings.cube_initial_rotation_y * Mathf.DEG_TO_RAD self.apply_rotation(rx, ry, settings.rotate_y_before_x_initially) # auto-rotation repeat = True repetion_count = -1 if settings.cube_auto_rot_x_enabled: begin = settings.cube_auto_rot_x_begin end = settings.cube_auto_rot_x_end jump_start = settings.cube_auto_rot_x_jump_start ease = Tween.get_ease_type_by_name( settings.cube_auto_rot_x_ease_type) self.auto_rot_x = Tween() self.auto_rot_x.tween(begin, end, time, ease, repeat, repetition_count, jump_start) else: self.auto_rot_x = False if settings.cube_auto_rot_y_enabled: begin = settings.cube_auto_rot_y_begin end = settings.cube_auto_rot_y_end time = settings.cube_auto_rot_y_time jump_start = settings.cube_auto_rot_y_jump_start ease = Tween.get_ease_type_by_name( settings.cube_auto_rot_y_ease_type) self.auto_rot_y = Tween() self.auto_rot_y.tween(begin, end, time, ease, repeat, repetition_count, jump_start) else: self.auto_rot_y = False def reset(self): self.geometry = Geometry(self.size) self.geometry.add_padding(self.padding) self.queued_face_rotations = Queue(0) self.tween = Tween() self.state = State.IDLE self.current_face_rotation = None def apply_rotation(self, x, y, rotate_y_before_x=False): qx = normalize(axisangle_to_q((1, 0, 0), x)) qy = normalize(axisangle_to_q((0, 1, 0), y)) if rotate_y_before_x: self.accum = q_mult(self.accum, qy) self.accum = q_mult(self.accum, qx) else: self.accum = q_mult(self.accum, qx) self.accum = q_mult(self.accum, qy) def update(self, elapsed_time): self.rot_x -= abs( self.rot_x) * self.angular_drag * elapsed_time * np.sign( self.rot_x) self.rot_y -= abs( self.rot_y) * self.angular_drag * elapsed_time * np.sign( self.rot_y) qx = normalize(axisangle_to_q((1, 0, 0), self.rot_x)) qy = normalize(axisangle_to_q((0, 1, 0), self.rot_y)) self.accum = q_mult(self.accum, qx) self.accum = q_mult(self.accum, qy) self.scale_speed -= abs( self.scale_speed) * self.scale_drag * elapsed_time * np.sign( self.scale_speed) self.scale += self.scale_speed if self.scale < self.min_scale: self.scale = self.min_scale self.scale_speed = 0 if self.scale > self.max_scale: self.scale = self.max_scale self.scale_speed = 0 self.update_queue() self.update_tween(elapsed_time) self.update_face_tweening() if self.auto_rot_x: self.auto_rot_x.update(elapsed_time) if self.auto_rot_y: self.auto_rot_y.update(elapsed_time) def render(self): # glPushMatrix() glLoadMatrixf(q_to_mat4(self.accum)) glScalef(self.scale, self.scale, self.scale) if self.auto_rot_x: rot_x = self.auto_rot_x.get_current() glRotatef(rot_x, 1, 0, 0) if self.auto_rot_y: rot_y = self.auto_rot_y.get_current() glRotatef(rot_y, 0, 1, 0) if self.draw_sphere: self.render_sphere() if self.draw_cubies: if self.texture_mapping_enabled: self.render_cubies_with_textures() else: self.render_cubies() if self.draw_lines: self.render_lines() # glPopMatrix() def add_rotate_x(self, value): self.rot_x += value def add_rotate_y(self, value): self.rot_y += value def add_scale(self, value): self.scale_speed += value def reset_rotation(self): self.rot_x = 0 self.rot_y = 0 self.accum = (1, 0, 0, 0) def reset_scale(self): self.scale = 1 def stop_rotation(self): self.rot_x = 0 self.rot_y = 0 def append_face_rotation(self, face_rotation): if type(face_rotation) == FaceRotation: self.queued_face_rotations.put(face_rotation) def scramble(self, face_rotations): theta = math.pi / 2 for face in face_rotations: self.rotate_face(face, theta) def map_colors(self, front_color, back_color, left_color, right_color, up_color, down_color): self.face_colors = (front_color, left_color, back_color, right_color, up_color, down_color) def update_queue(self): if self.state == State.TWEENING or self.queued_face_rotations.empty(): return self.current_face_rotation = self.queued_face_rotations.get_nowait() self.state = State.TWEENING self.tween.tween(0, math.pi / 2, self.face_rotation_tween_time, self.face_rotation_ease_type) def update_tween(self, elapsed_time): if self.state != State.TWEENING: return if self.tween.is_done(): self.state = State.IDLE self.current_face_rotation = None else: self.tween.update(elapsed_time) def update_face_tweening(self): theta = self.tween.get_delta() self.rotate_face(self.current_face_rotation, theta) def rotate_face(self, face, theta): if (face == FaceRotation.FRONT_CW or face == FaceRotation.BACK_CCW or face == FaceRotation.LEFT_CCW or face == FaceRotation.RIGHT_CW or face == FaceRotation.UP_CW or face == FaceRotation.DOWN_CCW): theta *= -1 if face == FaceRotation.FRONT_CW or face == FaceRotation.FRONT_CCW: self.rotate_front_face(theta) if face == FaceRotation.BACK_CW or face == FaceRotation.BACK_CCW: self.rotate_back_face(theta) if face == FaceRotation.LEFT_CW or face == FaceRotation.LEFT_CCW: self.rotate_left_face(theta) if face == FaceRotation.RIGHT_CW or face == FaceRotation.RIGHT_CCW: self.rotate_right_face(theta) if face == FaceRotation.UP_CW or face == FaceRotation.UP_CCW: self.rotate_up_face(theta) if face == FaceRotation.DOWN_CW or face == FaceRotation.DOWN_CCW: self.rotate_down_face(theta) def rotate_front_face(self, theta, layer=1): for pieces in self.geometry.center_pieces[0]: for piece in pieces: for i in range(8): piece[i] = z_rot(piece[i], theta) #self.geometry.center_pieces[0][i] = z_rot(self.geometry.center_pieces[0][i], theta) for axis in self.geometry.edge_pieces: for pieces in axis: for piece in pieces: flag = True for vertex in piece: if vertex[2] < (self.size - 1) - (layer * 2): #if vertex[2] < 0: flag = False break if flag: for i in range(8): piece[i] = z_rot(piece[i], theta) for piece in self.geometry.corner_pieces: flag = True for vertex in piece: if vertex[2] < 0: flag = False break if flag: for i in range(8): piece[i] = z_rot(piece[i], theta) def rotate_back_face(self, theta, layer=1): for pieces in self.geometry.center_pieces[2]: for piece in pieces: for i in range(8): piece[i] = z_rot(piece[i], theta) #self.geometry.center_pieces[2][i] = z_rot(self.geometry.center_pieces[2][i], theta) for axis in self.geometry.edge_pieces: for pieces in axis: for piece in pieces: flag = True for vertex in piece: #if vertex[2] > 0: if vertex[2] > (-self.size + 1) + ( layer * 2 ): # or vertex[2] > (-self.size-1) + (layer*2): flag = False break if flag: for i in range(8): piece[i] = z_rot(piece[i], theta) for piece in self.geometry.corner_pieces: flag = True for vertex in piece: if vertex[2] > 0: flag = False break if flag: for i in range(8): piece[i] = z_rot(piece[i], theta) def rotate_left_face(self, theta, layer=1): for pieces in self.geometry.center_pieces[1]: for piece in pieces: for i in range(8): piece[i] = x_rot(piece[i], theta) #self.geometry.center_pieces[1][i] = x_rot(self.geometry.center_pieces[1][i], theta) for axis in self.geometry.edge_pieces: for pieces in axis: for piece in pieces: flag = True for vertex in piece: #if vertex[0] > 0: if vertex[0] > (-self.size + 1) + (layer * 2): flag = False break if flag: for i in range(8): piece[i] = x_rot(piece[i], theta) for piece in self.geometry.corner_pieces: flag = True for vertex in piece: if vertex[0] > 0: flag = False break if flag: for i in range(8): piece[i] = x_rot(piece[i], theta) def rotate_right_face(self, theta, layer=1): for pieces in self.geometry.center_pieces[3]: for piece in pieces: for i in range(8): piece[i] = x_rot(piece[i], theta) #self.geometry.center_pieces[3][i] = x_rot(self.geometry.center_pieces[3][i], theta) for axis in self.geometry.edge_pieces: for pieces in axis: for piece in pieces: flag = True for vertex in piece: #if vertex[0] < 0: if vertex[0] < (self.size - 1) - (layer * 2): flag = False break if flag: for i in range(8): piece[i] = x_rot(piece[i], theta) for piece in self.geometry.corner_pieces: flag = True for vertex in piece: if vertex[0] < 0: flag = False if flag: for i in range(8): piece[i] = x_rot(piece[i], theta) def rotate_up_face(self, theta, layer=1): for pieces in self.geometry.center_pieces[4]: for piece in pieces: for i in range(8): piece[i] = y_rot(piece[i], theta) #self.geometry.center_pieces[4][i] = y_rot(self.geometry.center_pieces[4][i], theta) for axis in self.geometry.edge_pieces: for pieces in axis: for piece in pieces: flag = True for vertex in piece: #if vertex[1] < 0: if vertex[1] < (self.size - 1) - (layer * 2): #if vertex[1] < self.size - layer*2: flag = False break if flag: for i in range(8): piece[i] = y_rot(piece[i], theta) for piece in self.geometry.corner_pieces: flag = True for vertex in piece: if vertex[1] < 0: flag = False break if flag: for i in range(8): piece[i] = y_rot(piece[i], theta) def rotate_down_face(self, theta, layer=1): for pieces in self.geometry.center_pieces[5]: for piece in pieces: for i in range(8): piece[i] = y_rot(piece[i], theta) #self.geometry.center_pieces[5][i] = y_rot(self.geometry.center_pieces[5][i], theta) for axis in self.geometry.edge_pieces: for pieces in axis: for piece in pieces: flag = True for vertex in piece: #if vertex[1] > 0: if vertex[1] > (-self.size + 1) + (layer * 2): #if vertex[1] > -self.size + layer*2: flag = False break if flag: for i in range(8): piece[i] = y_rot(piece[i], theta) for piece in self.geometry.corner_pieces: flag = True for vertex in piece: if vertex[1] > 0: flag = False break if flag: for i in range(8): piece[i] = y_rot(piece[i], theta) def render_sphere(self): glColor3f(self.sphere_color[0], self.sphere_color[1], self.sphere_color[2]) glutSolidSphere(self.sphere_radius, self.sphere_slices, self.sphere_stacks) def render_axes(self): glLineWidth(1) glBegin(GL_LINES) for color, axis in zip(self.geometry.axis_colors, self.geometry.axes): glColor3f(color[0], color[1], color[2]) for point in axis: p = self.geometry.axis_verts[point] glVertex3f(p[0], p[1], p[2]) glEnd() def render_lines(self): print('render lines') glLineWidth(self.line_width) glColor3f(0, 0, 0) glBegin(GL_LINES) for axis in self.geometry.edge_pieces: for piece in axis: for edge in self.geometry.cube_edges: for vertex in edge: v = piece[vertex] glVertex3f(v[0], v[1], v[2]) for piece in self.geometry.center_pieces: for edge in self.geometry.cube_edges: for vertex in edge: v = piece[vertex] glVertex3f(v[0], v[1], v[2]) glEnd() def render_cubies(self): inner_color = self.inner_color glBegin(GL_QUADS) # render center pieces i = 0 for color, surface in zip(self.face_colors, self.geometry.cube_surfaces): glColor3f(color[0], color[1], color[2]) for vertex in surface: v = self.geometry.center_pieces[i][vertex] glVertex3f(v[0], v[1], v[2]) j = 0 for piece in self.geometry.center_pieces: glColor3f(inner_color[0], inner_color[1], inner_color[2]) for vertex in surface: v = self.geometry.center_pieces[j][vertex] glVertex3f(v[0], v[1], v[2]) j += 1 i += 1 # render edge pieces for color, surface, face in zip(self.face_colors, self.geometry.cube_surfaces, self.geometry.edges): glColor3f(color[0], color[1], color[2]) for piece_index in face: for piece in self.geometry.edge_pieces[piece_index[0]][ piece_index[1]]: for vertex in surface: p = piece[vertex] #p = self.geometry.edge_pieces[piece[0]][piece[1]][vertex] glVertex3f(p[0], p[1], p[2]) glColor3f(inner_color[0], inner_color[1], inner_color[2]) for i in range(len(self.geometry.edge_black_pat)): for face in self.geometry.edge_black_pat[i]: for pieces in self.geometry.edge_pieces[i]: for piece in pieces: for vertex in self.geometry.cube_surfaces[face]: v = piece[vertex] glVertex3f(v[0], v[1], v[2]) # render corner pieces for i in range(len(self.geometry.corner_black_pat)): for face in self.geometry.corner_color_pat[i]: color = self.face_colors[face] glColor3f(color[0], color[1], color[2]) for vertex in self.geometry.cube_surfaces[face]: v = self.geometry.corner_pieces[i][vertex] glVertex3f(v[0], v[1], v[2]) glColor3f(inner_color[0], inner_color[1], inner_color[2]) for i in range(len(self.geometry.corner_black_pat)): for face in self.geometry.corner_black_pat[i]: for vertex in self.geometry.cube_surfaces[face]: v = self.geometry.corner_pieces[i][vertex] glVertex3f(v[0], v[1], v[2]) glEnd() def render_cubies_with_textures(self): tex_coords = self.geometry.tex_coords inner_color = self.inner_color # render outer faces with an applied texture glBindTexture(GL_TEXTURE_2D, self.sticker_texture_id) glBegin(GL_QUADS) # render center pieces i = 0 for color, surface in zip(self.face_colors, self.geometry.cube_surfaces): glColor3f(color[0], color[1], color[2]) #ti = 0 for pieces in self.geometry.center_pieces[i]: for piece in pieces: ti = 0 for vertex in surface: v = piece[vertex] glVertex3f(v[0], v[1], v[2]) glTexCoord2f(tex_coords[ti][0], tex_coords[ti][1]) ti += 1 i += 1 # render edge pieces for color, surface, face in zip(self.face_colors, self.geometry.cube_surfaces, self.geometry.edges): glColor3f(color[0], color[1], color[2]) for piece_index in face: # ti = 0 for piece in self.geometry.edge_pieces[piece_index[0]][ piece_index[1]]: ti = 0 for vertex in surface: p = piece[vertex] #p = self.geometry.edge_pieces[piece[0]][piece[1]][vertex] glVertex3f(p[0], p[1], p[2]) glTexCoord2f(tex_coords[ti][0], tex_coords[ti][1]) ti += 1 # render corner pieces for i in range(len(self.geometry.corner_color_pat)): for face in self.geometry.corner_color_pat[i]: color = self.face_colors[face] glColor3f(color[0], color[1], color[2]) ti = 0 for vertex in self.geometry.cube_surfaces[face]: v = self.geometry.corner_pieces[i][vertex] glVertex3f(v[0], v[1], v[2]) glTexCoord2f(tex_coords[ti][0], tex_coords[ti][1]) ti += 1 glEnd() # render inner faces without texture using only the inner color glBindTexture(GL_TEXTURE_2D, 0) glBegin(GL_QUADS) # render center pieces i = 0 for color, surface in zip(self.face_colors, self.geometry.cube_surfaces): j = 0 for pieces in self.geometry.center_pieces[i]: j = 0 for piece in pieces: glColor3f(inner_color[0], inner_color[1], inner_color[2]) for vertex in surface: v = piece[vertex] glVertex3f(v[0], v[1], v[2]) j += 1 i += 1 # render edge pieces glColor3f(inner_color[0], inner_color[1], inner_color[2]) for i in range(len(self.geometry.edge_black_pat)): for face in self.geometry.edge_black_pat[i]: for pieces in self.geometry.edge_pieces[i]: for piece in pieces: for vertex in self.geometry.cube_surfaces[face]: v = piece[vertex] glVertex3f(v[0], v[1], v[2]) # render corner pieces glColor3f(inner_color[0], inner_color[1], inner_color[2]) for i in range(len(self.geometry.corner_black_pat)): for face in self.geometry.corner_black_pat[i]: for vertex in self.geometry.cube_surfaces[face]: v = self.geometry.corner_pieces[i][vertex] glVertex3f(v[0], v[1], v[2]) glEnd()