import bpy import os import arm.log as log import arm.utils import arm.assets as assets import arm.material.mat_state as mat_state import arm.make_state as state import shutil def make(image_node, tex_name, matname=None): tex = {} tex['name'] = tex_name image = image_node.image if matname == None: matname = mat_state.material.name if image == None: return None if image.filepath == '': log.warn(matname + '/' + image.name + ' - file path not found') return None # Reference image name texpath = arm.utils.asset_path(image.filepath) texfile = arm.utils.extract_filename(image.filepath) tex['file'] = arm.utils.safestr(texfile) s = tex['file'].rsplit('.', 1) if len(s) == 1: log.warn(matname + '/' + image.name + ' - file extension required for image name') return None ext = s[1].lower() do_convert = ext != 'jpg' and ext != 'png' and ext != 'hdr' and ext != 'mp4' # Convert image if do_convert: tex['file'] = tex['file'].rsplit('.', 1)[0] + '.jpg' # log.warn(matname + '/' + image.name + ' - image format is not (jpg/png/hdr), converting to jpg.') if image.packed_file != None or not is_ascii(texfile): # Extract packed data / copy non-ascii texture unpack_path = arm.utils.get_fp_build() + '/compiled/Assets/unpacked' if not os.path.exists(unpack_path): os.makedirs(unpack_path) unpack_filepath = unpack_path + '/' + tex['file'] if do_convert: if not os.path.isfile(unpack_filepath): arm.utils.write_image(image, unpack_filepath) else: # Write bytes if size is different or file does not exist yet if image.packed_file != None: if not os.path.isfile(unpack_filepath) or os.path.getsize(unpack_filepath) != image.packed_file.size: with open(unpack_filepath, 'wb') as f: f.write(image.packed_file.data) # Copy non-ascii texture else: if not os.path.isfile(unpack_filepath) or os.path.getsize(unpack_filepath) != os.path.getsize(texpath): shutil.copy(texpath, unpack_filepath) assets.add(unpack_filepath) else: if not os.path.isfile(arm.utils.asset_path(image.filepath)): log.warn('Material ' + matname + '/' + image.name + ' - file not found(' + image.filepath + ')') return None if do_convert: converted_path = arm.utils.get_fp_build() + '/compiled/Assets/unpacked/' + tex['file'] # TODO: delete cache when file changes if not os.path.isfile(converted_path): arm.utils.write_image(image, converted_path) assets.add(converted_path) else: # Link image path to assets # TODO: Khamake converts .PNG to .jpg? Convert ext to lowercase on windows if arm.utils.get_os() == 'win': s = image.filepath.rsplit('.', 1) assets.add(arm.utils.asset_path(s[0] + '.' + s[1].lower())) else: assets.add(arm.utils.asset_path(image.filepath)) # if image_format != 'RGBA32': # tex['format'] = image_format interpolation = image_node.interpolation rpdat = arm.utils.get_rp() texfilter = rpdat.arm_texture_filter if texfilter == 'Anisotropic': interpolation = 'Smart' elif texfilter == 'Linear': interpolation = 'Linear' elif texfilter == 'Point': interpolation = 'Closest' # TODO: Blender seems to load full images on size request, cache size instead powimage = is_pow(image.size[0]) and is_pow(image.size[1]) if state.target == 'html5' and powimage == False and (image_node.interpolation == 'Cubic' or image_node.interpolation == 'Smart'): log.warn(matname + '/' + image.name + ' - non power of 2 texture using ' + image_node.interpolation + ' interpolation requires WebGL2') if interpolation == 'Cubic': # Mipmap linear tex['mipmap_filter'] = 'linear' tex['generate_mipmaps'] = True elif interpolation == 'Smart': # Mipmap anisotropic tex['min_filter'] = 'anisotropic' tex['mipmap_filter'] = 'linear' tex['generate_mipmaps'] = True elif interpolation == 'Closest': tex['min_filter'] = 'point' tex['mag_filter'] = 'point' # else defaults to linear if image_node.extension != 'REPEAT': # Extend or clip tex['u_addressing'] = 'clamp' tex['v_addressing'] = 'clamp' else: if state.target == 'html5' and powimage == False: log.warn(matname + '/' + image.name + ' - non power of 2 texture using repeat mode requires WebGL2') # tex['u_addressing'] = 'clamp' # tex['v_addressing'] = 'clamp' if image.source == 'MOVIE': # Just append movie texture trait for now movie_trait = {} movie_trait['type'] = 'Script' movie_trait['class_name'] = 'armory.trait.internal.MovieTexture' movie_trait['parameters'] = [tex['file']] for o in mat_state.mat_armusers[mat_state.material]: o['traits'].append(movie_trait) tex['source'] = 'movie' tex['file'] = '' # MovieTexture will load the video return tex def is_pow(num): return ((num & (num - 1)) == 0) and num != 0 def is_ascii(s): return len(s) == len(s.encode())