def convert_png_to_jpg_rgb(self, tex_path): tex_basename = os.path.splitext(tex_path)[0] img = PNMImage() self.load_img_with_retry(img, tex_path) jpg_path = tex_basename + '.jpg' x_size = img.get_x_size() y_size = img.get_y_size() output_img = PNMImage(x_size, y_size, 3) output_img.copy_sub_image(img, 0, 0, 0, 0, x_size, y_size) jpg_path = tex_basename + '.jpg' print(f'Writing JPG {jpg_path}...') output_img.write(Filename.from_os_specific(jpg_path)) if img.num_channels == 4: alpha_image = PNMImage(x_size, y_size, 1) alpha_image.set_type(RGB_TYPE) # Copy alpha channel from source image for i in range(x_size): for j in range(y_size): alpha_image.set_gray(i, j, img.get_alpha(i, j)) rgb_path = tex_basename + '_a.rgb' print(f'Writing RGB {rgb_path}...') alpha_image.write(Filename.from_os_specific(rgb_path))
def make_star(name='star', scale=1, color=Vec3(1), texture_size=64, debug=False): card_maker = CardMaker(name) card_maker.set_frame(-1, 1, -1, 1) node_path = NodePath(name) node = card_maker.generate() final_node_path = node_path.attach_new_node(node) final_node_path.set_billboard_point_eye() from panda3d.core import Filename shaders = Shader.load(Shader.SL_GLSL, Filename('Shader/Star/vertex.glsl'), Filename('Shader/Star/fragment.glsl'), Filename(''), Filename(''), Filename('')) if not shaders: print("WARNING. STAR SHADER FAILED TO LOAD", type(shaders)) else: final_node_path.set_shader_input('cameraSpherePos', 1, 1, 1) final_node_path.set_shader_input('sphereRadius', 1.0) final_node_path.set_shader_input('myCamera', base.camera) final_node_path.set_shader(shaders) final_node_path.set_shader_input('blackbody', color) material = Material() material.set_emission(VBase4(color, 1.0)) final_node_path.set_material(material) xn = PerlinNoise3(0.5, 0.5, 0.5) #yn = PerlinNoise3(0.5, 0.5, 0.5) texture = Texture('star') texture.setup_3d_texture() for z in range(texture_size): p = PNMImage(texture_size, texture_size) for y in range(texture_size): for x in range(texture_size): p.set_gray(x, y, abs(xn.noise(x, y, z))) texture.load(p, z, 0) diffuse = texture diffuse.setMinfilter(Texture.FTLinearMipmapLinear) diffuse.setAnisotropicDegree(4) final_node_path.set_texture(diffuse) normal = sandbox.base.loader.loadTexture('data/empty_textures/empty_normal.png') normalts = TextureStage('normalts') final_node_path.set_texture(normalts, normal) specular = sandbox.base.loader.loadTexture('data/empty_textures/empty_specular.png') spects = TextureStage('spects') final_node_path.set_texture(spects, specular) roughness = sandbox.base.loader.loadTexture('data/empty_textures/empty_roughness.png') roughts= TextureStage('roughts') final_node_path.set_texture(roughts, roughness) return final_node_path
def create_stray_texture(self, texture_img, create_rgb=True): """ Converts a TextureImage into actual PNMImages. Creates an RGB version of the texture if requested. :texture_img: The TextureImage you want to process. :create_rgb: Would you like to create an RGB variant of the texture? True by default. """ if not texture_img.dest_ids: # This texture image is not a stray image. return source = texture_img.sources[0] dest = texture_img.dests[0] # Extrapolate the phase folder from the first assigned group phase_folder = texture_img.actual_assigned_groups.groups[0].dirname # Extrapolate the base name from the destination image basename = os.path.splitext(os.path.basename(dest.filename))[0] # Is this an RGB only texture? # Some textures, like fonts, are saved as grayscale RGB. rgb_only = texture_img.properties.format == TextureGlobals.F_alpha # Read the texture from Pandora! image = self.read_texture(source.filename) # Let's save the texture as a power of two resolution. x_size, y_size = self.scale_power_of_2(image.get_x_size(), image.get_y_size()) alpha_image = None # Resize our image to the desired size. image = self.resize_image(image, x_size, y_size) has_alpha = source.properties.effective_channels in (2, 4) if dest.alpha_filename and has_alpha and create_rgb and not rgb_only: alpha_image = PNMImage(x_size, y_size, 1) alpha_image.set_type(PalettizeGlobals.RGB_TYPE) # Copy alpha channel from source image for i in range(x_size): for j in range(y_size): alpha_image.set_gray(i, j, image.get_alpha(i, j)) return image, alpha_image, has_alpha, phase_folder, basename, rgb_only
def make_star(name='star', scale=1, color=Vec3(1), texture_size=64, debug=False): card_maker = CardMaker(name) card_maker.set_frame(-1, 1, -1, 1) node_path = NodePath(name) node = card_maker.generate() final_node_path = node_path.attach_new_node(node) final_node_path.set_billboard_point_eye() shaders = Shader.load(Shader.SLGLSL, 'Shader/Star/vertex.glsl', 'Shader/Star/fragment.glsl') final_node_path.set_shader_input(b'cameraSpherePos', 1, 1, 1) final_node_path.set_shader_input(b'sphereRadius', 1.0) final_node_path.set_shader_input(b'myCamera', base.camera) final_node_path.set_shader(shaders) final_node_path.set_shader_input(b'blackbody', color) material = Material() material.set_emission(VBase4(color, 1.0)) final_node_path.set_material(material) xn = PerlinNoise3(0.5, 0.5, 0.5) #yn = PerlinNoise3(0.5, 0.5, 0.5) texture = Texture('star') texture.setup_3d_texture() for z in range(texture_size): p = PNMImage(texture_size, texture_size) for y in range(texture_size): for x in range(texture_size): p.set_gray(x, y, abs(xn.noise(x, y, z))) texture.load(p, z, 0) diffuse = texture diffuse.setMinfilter(Texture.FTLinearMipmapLinear) diffuse.setAnisotropicDegree(4) final_node_path.set_texture(diffuse) normal = base.loader.loadTexture('Data/Textures/EmptyNormalTexture.png') normalts = TextureStage('normalts') final_node_path.set_texture(normalts, normal) specular = base.loader.loadTexture('Data/Textures/EmptySpecularTexture.png') spects = TextureStage('spects') final_node_path.set_texture(spects, specular) roughness = base.loader.loadTexture('Data/Textures/EmptyRoughnessTexture.png') roughts= TextureStage('roughts') final_node_path.set_texture(roughts, roughness) return final_node_path
def palettize(self, palette_img, create_rgb=True): """ Runs all palettization procedures on the given PaletteImage. Creates an RGB version of the palette if requested. :palette_img: The PaletteImage you want to palettize. :create_rgb: Would you like to create an RGB variant of the palette? True by default. """ # We need to know the palette's prior size if not palette_img.size_known: raise PalettizerException( "Palette image's size is not known, this is a fatal error!") palette_name = palette_img.basename if self.debug: print( f'[{palette_img.page.group.dirname}] Compiling {palette_name}..' ) # Our max distortion is 1, as we do not want to resize the palette to be smaller accidentally max_distortion = 1 # This array holds all of our PNMImage source textures imgs = [] # We're going to check all of the source textures # so that we can load all of them and determine our palette's final size for placement in palette_img.placements: sources = placement.texture.sources # We need to know the size of all source textures # If a source texture's size is not known, that means that it has been defined but did not exist on the disk when creating textures.boo for source in sources: if not source.size_known: print( f'Warning: Size is not known for source {source.filename}, please consider fixing the texture path and re-running egg-palettize' ) # Source (original) full resolution texture size source = sources[0] x_size = source.x_size y_size = source.y_size # Prior texture position and size tex_position = placement.position tex_x_size = tex_position.x_size tex_y_size = tex_position.y_size # DISTORTER # Fold the points until they scream out # DISTORTER # Change the way it sounds # We need to calculate the maximum distortion for both our X and Y (U/V) coordinates if x_size != tex_x_size: x_distortion = x_size / tex_x_size if x_distortion > max_distortion: max_distortion = x_distortion if y_size != tex_y_size: y_distortion = y_size / tex_y_size if y_distortion > max_distortion: max_distortion = y_distortion # If we have more than one source, that means our texture # has been defined multiple times for the same group... # Panda3D uses the first source texture only, so that's what we'll do. # But we'll make sure to print a warning either way! if len(sources) > 1: source2 = sources[1] if source2.x_size != x_size or source2.y_size != y_size: print( f'Two different source textures are defined for {palette_name}: {source.filename} ({x_size} {y_size}) vs {source2.filename} ({source2.x_size} {source2.y_size})' ) # Time to load the source file from Pandora! img = self.read_texture(source.filename) # Add the source image to our list imgs.append(img) # Well, time to calculate the palette's final size! # We will multiply the current size with the highest distortion. # We do NOT calculate X and Y distortion separately. # Doing so would destroy the aspect ratio of the palette. current_x_size = palette_img.x_size current_y_size = palette_img.y_size new_x_size = round(current_x_size * max_distortion) new_y_size = round(current_y_size * max_distortion) # Power of two time! # It's easier for the game engine to load, as it does not have to scale it automatically. new_x_size, new_y_size = self.scale_power_of_2(new_x_size, new_y_size) # We've changed the palette size. It is necessary to recalculate our texture distortion. x_distortion = new_x_size / current_x_size y_distortion = new_y_size / current_y_size # Create our palette image with four channels. # We will cut down the last channel when necessary. # Having a fourth, empty channel would only increase the file size. new_image = PNMImage(new_x_size, new_y_size, 4) new_image.alpha_fill(1) # Textures with alpha always have four channels set (three for RGB and one for Alpha). has_alpha = palette_img.properties.effective_channels in (2, 4) rgb_only = palette_img.properties.format == TextureGlobals.F_alpha alpha_image = None # If necessary and possible, create an alpha image as well. # Textures with alpha always have four channels set (three for RGB and one for Alpha). if create_rgb and has_alpha and not rgb_only: alpha_image = PNMImage(new_x_size, new_y_size, 1) alpha_image.set_type(PalettizeGlobals.RGB_TYPE) for i, placement in enumerate(palette_img.placements): # Find the loaded source image from before... texture_img = imgs[i] # Calculate the placement of our image! tex_position = placement.placed # Determine the upper left and lower right corners # with some matrix magic. transform = placement.compute_tex_matrix() ul = transform.xform_point(LTexCoordd(0.0, 1.0)) lr = transform.xform_point(LTexCoordd(1.0, 0.0)) # Calculate the top, left, bottom and right corners. top = int(math.floor((1.0 - ul[1]) * new_y_size + 0.5)) left = int(math.floor(ul[0] * new_x_size + 0.5)) bottom = int(math.floor((1.0 - lr[1]) * new_y_size + 0.5)) right = int(math.floor(lr[0] * new_x_size + 0.5)) tex_x_size = right - left tex_y_size = bottom - top org_x_size = round(tex_position.x_size * x_distortion) org_y_size = round(tex_position.y_size * y_distortion) tex_x = round(tex_position.x * x_distortion) tex_y = round(tex_position.y * y_distortion) # Resize our image to the desired size. texture_img = self.resize_image(texture_img, tex_x_size, tex_y_size) for y in range(tex_y, tex_y + org_y_size): sy = y - top # UV wrapping modes - V component (for Y texture coordinate) if placement.placed.wrap_v == TextureGlobals.WM_clamp: sy = max(min(sy, tex_y_size - 1), 0) elif placement.placed.wrap_v == TextureGlobals.WM_mirror: sy = (tex_y_size * 2) - 1 - ( (-sy - 1) % (tex_y_size * 2)) if sy < 0 else sy % (tex_y_size * 2) sy = sy if sy < tex_y_size else 2 * tex_y_size - sy - 1 elif placement.placed.wrap_v == TextureGlobals.WM_mirror_once: sy = sy if sy < tex_y_size else 2 * tex_y_size - sy - 1 # Repeat texture sy = tex_y_size - 1 - ( (-sy - 1) % tex_y_size) if sy < 0 else sy % tex_y_size elif placement.placed.wrap_v == TextureGlobals.WM_border_color: if sy < 0 or sy >= tex_y_size: continue else: # Repeat texture sy = tex_y_size - 1 - ( (-sy - 1) % tex_y_size) if sy < 0 else sy % tex_y_size for x in range(tex_x, tex_x + org_x_size): sx = x - left # UV wrapping modes - U component (for X texture coordinate) if placement.placed.wrap_u == TextureGlobals.WM_clamp: sx = max(min(sx, tex_x_size - 1), 0) elif placement.placed.wrap_u == TextureGlobals.WM_mirror: sx = (tex_x_size * 2) - 1 - ( (-sx - 1) % (tex_x_size * 2)) if sx < 0 else sx % (tex_x_size * 2) sx = sx if sx < tex_x_size else 2 * tex_x_size - sx - 1 elif placement.placed.wrap_u == TextureGlobals.WM_mirror_once: sx = sx if sx >= 0 else ~sx # Repeat texture sx = tex_x_size - 1 - ( (-sx - 1) % tex_x_size) if sx < 0 else sx % tex_x_size elif placement.placed.wrap_u == TextureGlobals.WM_border_color: if sx < 0 or sx >= tex_x_size: continue else: # Repeat texture sx = tex_x_size - 1 - ( (-sx - 1) % tex_x_size) if sx < 0 else sx % tex_x_size new_image.set_xel(x, y, texture_img.get_xel(sx, sy)) new_image.set_alpha(x, y, texture_img.get_alpha(sx, sy)) if alpha_image: alpha_image.set_gray(x, y, texture_img.get_alpha(sx, sy)) return new_image, alpha_image, has_alpha, rgb_only