Skip to content

Commit f0bfe24

Browse files
committed
[riistudio_blender] Don't require wimgt for full functionality
1 parent 26581af commit f0bfe24

File tree

1 file changed

+129
-35
lines changed

1 file changed

+129
-35
lines changed

source/blender/riistudio_blender.py

Lines changed: 129 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import mmap
3030
import cProfile
3131
import json
32+
from enum import Enum
3233

3334
BLENDER_30 = bpy.app.version[0] >= 3
3435
BLENDER_29 = (bpy.app.version[0] == 2 and bpy.app.version[1] >= 90) \
@@ -167,39 +168,124 @@ def get_filename_without_extension(file_path):
167168

168169
# src\helpers\export_tex.py
169170

170-
def export_tex(texture, out_folder, use_wimgt):
171-
if not texture.image:
172-
return
171+
# Enum for selecting the export mode
172+
class ExportMode(Enum):
173+
LEGACY = 1
174+
WIMGT = 2
175+
RSZST = 3
176+
177+
# Doesn't support encoding settings. Just passes a PNG in
178+
def export_tex_legacy(texture, out_folder):
179+
if not texture.image:
180+
return
181+
182+
tex_name = get_filename_without_extension(texture.image.name) if BLENDER_28 else texture.name
183+
print("ExportTex: %s" % tex_name)
184+
185+
# Force PNG
186+
texture.image.file_format = 'PNG'
187+
188+
# Save image as PNG
189+
texture_outpath = os.path.join(out_folder, tex_name) + ".png"
190+
texture.image.save_render(texture_outpath)
191+
192+
# Uses WIMGT to encode the PNG first, with some settings
193+
def export_tex_wimgt(texture, out_folder):
194+
if not texture.image:
195+
return
173196

174-
tex_name = get_filename_without_extension(texture.image.name) if BLENDER_28 else texture.name
175-
print("ExportTex: %s" % tex_name)
176-
# Force PNG
177-
texture.image.file_format = 'PNG'
178-
# save image as PNNG
179-
texture_outpath = os.path.join(out_folder, tex_name) + ".png"
180-
if use_wimgt:
197+
tex_name = get_filename_without_extension(texture.image.name) if BLENDER_28 else texture.name
198+
print("ExportTex: %s" % tex_name)
199+
200+
# Force PNG
201+
texture.image.file_format = 'PNG'
202+
203+
# Save image as PNG with a temporary name
181204
temp_output_name = str(binascii.b2a_hex(os.urandom(15)))
182205
texture_outpath = os.path.join(out_folder, temp_output_name) + ".png"
183-
tex0_outpath = os.path.join(out_folder, tex_name) + ".tex0"
184-
texture.image.save_render(texture_outpath)
185-
# determine format
186-
# print(best_tex_format(texture))
187-
tformat_string = (
188-
texture.brres_manual_format if texture.brres_mode == 'manual' else best_tex_format(
189-
texture)).upper()
190-
# determine mipmaps
191-
mm_string = "--mipmap-size=%s" % texture.brres_mipmap_minsize
192-
if texture.brres_mipmap_mode == 'manual':
193-
mm_string = "--n-mm=%s" % texture.brres_mipmap_manual
194-
elif texture.brres_mipmap_mode == 'none':
195-
mm_string = "--n-mm=0"
196-
#Encode textures
197-
if use_wimgt:
206+
tex0_outpath = os.path.join(out_folder, tex_name) + ".tex0"
207+
texture.image.save_render(texture_outpath)
208+
209+
# Determine format
210+
tformat_string = (
211+
texture.brres_manual_format if texture.brres_mode == 'manual' else best_tex_format(
212+
texture)).upper()
213+
214+
# Determine mipmaps
215+
mm_string = "--mipmap-size=%s" % texture.brres_mipmap_minsize
216+
if texture.brres_mipmap_mode == 'manual':
217+
mm_string = "--n-mm=%s" % texture.brres_mipmap_manual
218+
elif texture.brres_mipmap_mode == 'none':
219+
mm_string = "--n-mm=0"
220+
221+
# Encode textures using wimgt
198222
print("EncodeTex: %s" % tex_name)
199223
wimgt = r'wimgt encode "{0}" --transform {1} {2} --dest "{3}" -o'.format(texture_outpath, tformat_string, mm_string, tex0_outpath)
200224
os.system(wimgt)
201225
os.remove(texture_outpath)
202226

227+
# Uses RSZST to encode the PNG first, with options for mipmaps and format
228+
def export_tex_rszst(texture, out_folder):
229+
if not texture.image:
230+
return
231+
232+
tex_name = get_filename_without_extension(texture.image.name) if BLENDER_28 else texture.name
233+
print("ExportTex: %s" % tex_name)
234+
235+
# Force PNG
236+
texture.image.file_format = 'PNG'
237+
238+
# Save image as PNG with a temporary name
239+
temp_output_name = str(binascii.b2a_hex(os.urandom(15)))
240+
texture_outpath = os.path.join(out_folder, temp_output_name) + ".png"
241+
tex0_outpath = os.path.join(out_folder, tex_name) + ".tex0"
242+
texture.image.save_render(texture_outpath)
243+
244+
# Determine format
245+
tformat_string = (
246+
texture.brres_manual_format if texture.brres_mode == 'manual' else best_tex_format(
247+
texture)).upper()
248+
249+
tformat_idx = str({
250+
'I4': 0,
251+
'I8': 1,
252+
'IA4': 2,
253+
'IA8': 3,
254+
'RGB565': 4,
255+
'RGB5A3': 5,
256+
'RGBA8': 6,
257+
'C4': 8,
258+
'C8': 9,
259+
# C14 not supported by NW4R g3d
260+
'CMPR': 14,
261+
}[tformat_string])
262+
263+
# Determine mipmaps
264+
mipmaps_flag = "--mipmaps" if texture.brres_mipmap_mode != 'none' else ""
265+
min_mip = "--min-mip=%s" % texture.brres_mipmap_minsize
266+
max_mip = "--max-mip=%s" % texture.brres_mipmap_manual if texture.brres_mipmap_mode == 'manual' else "--max-mip=5"
267+
268+
# Construct the RSZST command
269+
print("EncodeTex: %s" % tex_name)
270+
context = bpy.context
271+
bin_root = os.path.abspath(get_rs_prefs(context).riistudio_directory)
272+
rszst = os.path.join(bin_root, "rszst.exe")
273+
rszst_command = f'{rszst} import-tex0 {mipmaps_flag} {min_mip} {max_mip} --format {tformat_idx} "{texture_outpath}" "{tex0_outpath}"'
274+
os.system(rszst_command)
275+
276+
# Clean up the temporary PNG file
277+
os.remove(texture_outpath)
278+
279+
def export_tex(texture, out_folder, mode):
280+
if mode == ExportMode.LEGACY:
281+
export_tex_legacy(texture, out_folder)
282+
elif mode == ExportMode.WIMGT:
283+
export_tex_wimgt(texture, out_folder)
284+
elif mode == ExportMode.RSZST:
285+
export_tex_rszst(texture, out_folder)
286+
else:
287+
raise ValueError("Invalid export mode selected")
288+
203289
# src\panels\BRRESTexturePanel.py
204290

205291
class BRRESTexturePanel(bpy.types.Panel):
@@ -944,8 +1030,13 @@ def export_textures(textures_path,selection,params):
9441030
os.makedirs(textures_path)
9451031

9461032
for tex in all_textures(selection):
947-
use_wimgt = wimgt_installed and params.flags.texture_encoder == 'wimgt'
948-
export_tex(tex, textures_path, use_wimgt)
1033+
if params.flags.texture_encoder == 'rszst':
1034+
mode = ExportMode.RSZST
1035+
elif wimgt_installed and params.flags.texture_encoder == 'wimgt':
1036+
mode = ExportMode.WIMGT
1037+
else:
1038+
mode = ExportMode.LEGACY
1039+
export_tex(tex, textures_path, mode)
9491040

9501041
def build_rs_mat(mat, texture_name):
9511042
# Swap Table
@@ -1305,7 +1396,7 @@ def __init__(self, pos="float", nrm="float", uv="float", clr="auto"):
13051396

13061397
class ConverterFlags:
13071398
def __init__(self, split_mesh_by_material=True, mesh_conversion_mode='PREVIEW',
1308-
add_dummy_colors = True, ignore_cache = False, texture_encoder='wimgt', write_metadata = False):
1399+
add_dummy_colors = True, ignore_cache = False, texture_encoder='rszst', write_metadata = False):
13091400

13101401
self.split_mesh_by_material = split_mesh_by_material
13111402
self.mesh_conversion_mode = mesh_conversion_mode
@@ -1575,12 +1666,13 @@ class RHST_RNA:
15751666
if BLENDER_29: verbose : verbose
15761667

15771668
texture_encoder = EnumProperty(
1578-
name="Encoder",
1669+
name="Texture Codec",
15791670
items=(
1580-
('wimgt',"wimgt","Use wimgt to encode textures"),
1581-
('rs',"RiiStudio","Use RiiStudio to encode textures")
1671+
('rszst', "rszst (RiiStudio)", "Use RiiStudio CLI to encode textures"),
1672+
('wimgt', "wimgt (Wiimm)", "Use wimgt to encode textures"),
1673+
('rs', "Legacy", "Don't pre-encode textures")
15821674
),
1583-
default="wimgt",
1675+
default="rszst",
15841676
description="Select which encoder to use",
15851677
)
15861678
if BLENDER_29: texture_encoder : texture_encoder
@@ -1663,9 +1755,11 @@ def draw_rhst_options(self, context):
16631755
box.prop(self, 'verbose')
16641756

16651757
# Textures
1666-
if(self.get_wimgt_installed):
1758+
# This method was never actually called, replacing with True
1759+
# if(self.get_wimgt_installed):
1760+
if True:
16671761
box = layout.box()
1668-
box.label(text="Textures", icon='TEXTURE')
1762+
box.label(text="Texture Codec", icon='TEXTURE')
16691763
row = box.row(align=True)
16701764
row.label(text="Encoder")
16711765
row.prop(self, "texture_encoder", expand=True)
@@ -2529,7 +2623,7 @@ def register_tex():
25292623
)
25302624
tex_type.brres_mipmap_mode = EnumProperty(
25312625
items=(
2532-
('auto', "Auto", "Allow the conversion tool to determine best mipmapping level (currently wimgt)"),
2626+
('auto', "Auto", "Allow the conversion tool to determine best mipmapping level"),
25332627
('manual', "Manual", "Specify the number of mipmaps"),
25342628
('none', "None", "Do not perform mipmapping (the same as manual > 0)")
25352629
),

0 commit comments

Comments
 (0)