def convert_texture(self, texture, model_path=None): if not self.model_path: self.print_exc('ERROR: No model path specified in ImageConverter.') return tex_path = texture[0] tex_basename = os.path.splitext(os.path.basename(tex_path))[0] if not os.path.isabs(tex_path): if '../' in tex_path and model_path: # This texture path is using relative paths. # We assume that the working directory is the model's directory tex_path = os.path.join(os.path.dirname(model_path), tex_path) else: tex_path = os.path.join(self.model_path, tex_path) tex_path = tex_path.replace('\\', os.sep).replace('/', os.sep) if not os.path.exists(tex_path): self.print_exc('ERROR: Could not convert {}: Missing RGB texture!'.format(tex_path)) return png_tex_path = os.path.join(os.path.dirname(tex_path), tex_basename + '.png') png_tex_path = png_tex_path.replace('\\', os.sep).replace('/', os.sep) print('Converting to PNG...', png_tex_path) if len(texture) == 1: # Only one texture, we can save this immediately if tex_path.lower().endswith('.rgb'): output_img = PNMImage() output_img.read(Filename.from_os_specific(tex_path)) if output_img.num_channels in (1, 2) and 'golf_ball' not in tex_path and 'roll-o-dex' not in tex_path: # HACK: Toontown output_img.set_color_type(4) for i in range(output_img.get_x_size()): for j in range(output_img.get_y_size()): output_img.set_alpha(i, j, output_img.get_gray(i, j)) else: output_img = self.read_texture(tex_path, alpha=False) elif len(texture) == 2: img = self.read_texture(tex_path, alpha=True) # Two textures: the second one should be a RGB file alpha_path = texture[1] if not os.path.isabs(alpha_path): if '../' in alpha_path and model_path: # This texture path is using relative paths. # We assume that the working directory is the model's directory alpha_path = os.path.join(os.path.dirname(model_path), alpha_path) else: alpha_path = os.path.join(self.model_path, alpha_path) alpha_path = alpha_path.replace('\\', os.sep).replace('/', os.sep) if not os.path.exists(alpha_path): self.print_exc('ERROR: Could not convert {} with alpha {}: Missing alpha texture!'.format(tex_path, alpha_path)) return alpha_img = PNMImage() alpha_img.read(Filename.from_os_specific(alpha_path)) alpha_img = self.resize_image(alpha_img, img.get_x_size(), img.get_y_size()) output_img = PNMImage(img.get_x_size(), img.get_y_size(), 4) output_img.alpha_fill(1) output_img.copy_sub_image(img, 0, 0, 0, 0, img.get_x_size(), img.get_y_size()) for i in range(img.get_x_size()): for j in range(img.get_y_size()): output_img.set_alpha(i, j, alpha_img.get_gray(i, j)) output_img.write(Filename.from_os_specific(png_tex_path))
class FloorBase: #(FSM): walkable_path = None music_path = None sound_names = [] walkable_y_offset = 0.0 free_hobot_z = None def __init__(self, parent): actor = Actor(self.model_path) actor.set_two_sided(True) actor.reparent_to(parent) #print(actor.get_anim_names()) #actor.list_joints() self.actor = actor self.actor.hide() if self.walkable_path: self.walk_map = PNMImage() self.load_walk_map(self.walkable_path) else: self.walk_map = None if self.music_path: self.music = base.loader.load_music(self.music_path) self.music.set_loop(True) self.music.set_volume(0.5) self.music.play() else: self.music = None self.sfx = {} for s in self.sound_names: self.sfx[s] = base.loader.load_sfx( Filename(self.sound_path, s + ".wav")) # Make subparts for hobot. actor.make_subpart('hobot', [ 'hobot root', 'chain_a', 'chain_b', 'hand', 'wheel', 'neck', 'head', 'tuit', 'eyes' ]) # Make a copy for inspection of the animations, specifically to be able # to obtain the starting position of hobot in each animation. self.shadow_actor = Actor(self.model_path) self.shadow_hobot_root = self.shadow_actor.expose_joint( None, 'modelRoot', 'hobot root') # Make sure hobot is in a defined state in the actor actor.pose('entrance', 0) self.hobot_root = actor.expose_joint(None, 'modelRoot', 'hobot root') self.hobot_hand = actor.expose_joint(None, 'modelRoot', 'hand') self.hobot = Hobot(self.hobot_root) shadow_texture = loader.load_texture('hobot/drop_shadow.png') shadow_texture.set_wrap_u(core.SamplerState.WM_clamp) shadow_texture.set_wrap_v(core.SamplerState.WM_clamp) cm = core.CardMaker('card') cm.set_frame(-0.35, 0.35, -0.45, -0.1) self.shadow = self.hobot_root.attach_new_node(cm.generate()) self.shadow.set_texture(shadow_texture) self.shadow.set_attrib( core.ColorBlendAttrib.make( core.ColorBlendAttrib.M_add, core.ColorBlendAttrib.O_zero, core.ColorBlendAttrib.O_one_minus_incoming_alpha)) self.shadow.set_p(-90) self.shadow.set_depth_write(False) self.shadow.set_x(0.2) self.shadow.set_billboard_point_eye() self.shadow.set_two_sided(True) self.shadow.set_bin('transparent', 0) self.shadow.set_alpha_scale(0) self.shadow_fade = None self.carrying_joint = None self.carrying_joint_name = None def destroy(self): self.actor.cleanup() self.hobot.destroy() if self.music: self.music.stop() self.actor.remove_node() for sound_name in self.sound_names: self.sfx[sound_name].stop() def start(self): pass def load_walk_map(self, path): path = Filename.expand_from('$MAIN_DIR/assets/' + path) if not self.walk_map.read(path): print("Failed to read {}".format(path)) def grab_joint(self, name): print("Grabbing {}".format(name)) self.carrying_joint_name = name self.hobot.model.set_pos(self.hobot.anim_root.get_pos()) transform = self.actor.get_joint_transform_state('modelRoot', name) parent = self.actor.attach_new_node('parent') self.carrying_joint = self.actor.control_joint( parent.attach_new_node('joint'), 'modelRoot', name) self.carrying_joint.set_transform(transform) self.carrying_joint_initial_transform = transform self.carrying_joint_initial_hobot_hand_pos = self.hobot.hand.get_pos( self.actor) def release_joint(self, name): print("Releasing {}".format(name)) self.actor.release_joint('modelRoot', name) self.carrying_joint = None self.carrying_joint_name = None def get_anim_starting_hobot_pos(self, anim): # Returns Hobot's starting position for a given animation. self.shadow_actor.pose(anim, 0) self.shadow_actor.update() return self.shadow_hobot_root.get_pos() def play(self, anim, parts=None, loop=False, extra_interval=None, from_frame=None, to_frame=None, callback=None, release_joint=None, sound=None): if parts is None: print("Playing {} on all parts".format(anim)) else: print("Playing {} on {}".format(anim, list(parts))) if parts is None or 'hobot' in parts: # Move hobot to the position first self.hobot.model.show() self.hobot.lock() hobot_pos = self.get_anim_starting_hobot_pos(anim) delta = hobot_pos.x - self.hobot.model.get_x() self.hobot.face(delta) time = abs(delta) * 4 anims = [] for part in parts or (None, ): anims.append( ActorInterval(self.actor, anim, startFrame=from_frame, endFrame=to_frame, partName=part)) if extra_interval: anims.append(extra_interval) if sound: anims.append(Func(sound.play)) if callback is None: callback = self.switch_to_free_hobot seq = Sequence( self.hobot.model.posInterval(time, hobot_pos, blendType='easeInOut'), Func(self.switch_to_scene_hobot), Parallel(*anims), Func(callback)) if loop: seq.loop() else: seq.start() elif loop: if sound: sound.play() if not parts: self.actor.loop(anim, fromFrame=from_frame, toFrame=to_frame) else: for part in parts: self.actor.loop(anim, fromFrame=from_frame, toFrame=to_frame, partName=part) else: if sound: sound.play() if callback: anims = [] for part in parts or (None, ): anims.append( ActorInterval(self.actor, anim, startFrame=from_frame, endFrame=to_frame, partName=part)) Sequence(Parallel(*anims), Func(callback)).start() else: if not parts: self.actor.play(anim) else: for part in parts: self.actor.play(anim, fromFrame=from_frame, toFrame=to_frame, partName=part) def switch_to_scene_hobot(self): self.hobot.lock() self.hobot.model.hide() self.hobot.lightbulb.hide() self.actor.release_joint('modelRoot', 'hobot root') if self.carrying_joint_name and self.carrying_joint: self.actor.release_joint('modelRoot', self.carrying_joint_name) self.carrying_joint = None if self.shadow_fade is not None: self.shadow_fade.pause() self.shadow.set_alpha_scale(self.hobot.shadow.get_color_scale()[3]) self.shadow_fade = self.shadow.colorScaleInterval( 5.0, (1, 1, 1, 0), blendType='easeInOut') self.shadow_fade.start() def switch_to_free_hobot(self): if self.hobot.model.is_empty(): return self.hobot.face(self.hobot_root.get_sz() * -1) self.hobot.model.show() bone = self.actor.control_joint(None, 'modelRoot', 'hobot root') bone.set_pos(-100, -100, -100) self.hobot.unlock() if self.hobot.shadow_fade is not None: self.hobot.shadow_fade.pause() self.hobot.shadow.set_alpha_scale(self.shadow.get_color_scale()[3]) self.hobot.shadow_fade = self.hobot.shadow.colorScaleInterval( 5.0, (1, 1, 1, 1), blendType='easeInOut') self.hobot.shadow_fade.start() if self.free_hobot_z is not None: self.hobot.model.set_z(self.free_hobot_z) if self.carrying_joint_name and not self.carrying_joint: self.grab_joint(self.carrying_joint_name) def hide_scene_hobot(self): print("Hiding hobot") self.actor.control_joint(None, 'modelRoot', 'hobot root').set_z(-10000) def adjust_move(self, pos, delta, slide=True): x = (pos[0] + 16 / 9 / 2) * (9 / 16.0) * self.walk_map.size.x y = -(pos[1] - self.walkable_y_offset) * 2 * self.walk_map.size.y new_pos = pos + delta new_x = (new_pos[0] + 16 / 9 / 2) * (9 / 16.0) * self.walk_map.size.x new_y = -(new_pos[1] - self.walkable_y_offset) * 2 * self.walk_map.size.y if new_x < 0 or round(new_x) >= self.walk_map.size.x: return pos elif new_y < 0 or round(new_y) >= self.walk_map.size.y: return pos x = int(round(x)) y = int(round(y)) new_x = int(round(new_x)) new_y = int(round(new_y)) if self.walk_map.get_gray(new_x, new_y) > 0.5: return new_pos if not slide: return pos if delta[0] != 0 and self.walk_map.get_gray(new_x, y) > 0.5: return (new_pos[0], pos[1]) elif delta[1] != 0 and self.walk_map.get_gray(x, new_y) > 0.5: return (pos[0], new_pos[1]) elif delta[0] != 0 and delta[1] == 0: # Try 45 degree angle down and up new_pos = self.adjust_move(pos, Vec2(delta[0] * 0.894, delta[0] * 0.447), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[0] * 0.894, delta[0] * -0.707), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[0] * 0.707, delta[0] * 0.707), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[0] * 0.707, delta[0] * -0.707), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[0] * 0.447, delta[0] * 0.894), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[0] * 0.447, delta[0] * -0.894), slide=False) return new_pos elif delta[0] == 0 and delta[1] != 0: # Try 45 degree angle left and right new_pos = self.adjust_move(pos, Vec2(delta[1] * 0.447, delta[1] * 0.894), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[1] * -0.447, delta[1] * 0.894), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[1] * 0.707, delta[1] * 0.707), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[1] * -0.707, delta[1] * 0.707), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[1] * 0.894, delta[1] * 0.447), slide=False) if new_pos == pos: new_pos = self.adjust_move(pos, Vec2(delta[1] * -0.894, delta[1] * 0.447), slide=False) return new_pos else: return pos def process_input(self, input, dt): if self.hobot.locked: return self.hobot.process_input(input, dt, self) if self.carrying_joint: pos = self.hobot.hand.get_pos( self.actor) - self.carrying_joint_initial_hobot_hand_pos self.carrying_joint.set_transform( TransformState.make_pos( (self.hobot.model.get_z(), pos[1], -pos[0])).compose(self.carrying_joint_initial_transform)) self.check_interactions() def check_interactions(self): pass