You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
7.5 KiB
Python
124 lines
7.5 KiB
Python
import os, time, zipfile
|
|
from pymxs import runtime as rt
|
|
try: from PySide6 import QtWidgets
|
|
except ImportError: from PySide2 import QtWidgets
|
|
|
|
def mock_connect_api(ui):
|
|
if len(ui.e_hash.text()) < 5: QtWidgets.QMessageBox.warning(ui, "Acesso Negado", "Hash inválida."); return
|
|
ui.b_conn.setText("Conectando..."); QtWidgets.QApplication.processEvents(); time.sleep(1)
|
|
for w in [ui.c_chn, ui.c_pst, ui.e_tit, ui.e_mp3, ui.b_mp3]: w.setEnabled(True); w.setStyleSheet("background: white; color: black; font-weight: bold;")
|
|
ui.c_chn.clear(); ui.c_chn.addItems(["Canal: Imóveis Virtuais", "Canal: Showroom Zombisco"])
|
|
ui.c_pst.clear(); ui.c_pst.addItems(["[ + Cadastrar Nova Postagem ]", "Editar: Apartamento V1"])
|
|
ui.chk_up.setEnabled(True); ui.chk_up.setStyleSheet("color: #FFD700; font-weight: bold;"); ui.chk_up.setChecked(True)
|
|
ui.b_conn.setText("✅ Conectado!"); ui.b_conn.setStyleSheet("background: #000; color: #0F0; font-weight: bold; border: 1px solid #0F0;")
|
|
on_post_changed(ui, 0)
|
|
|
|
def on_post_changed(ui, idx):
|
|
if idx == 0:
|
|
ui.e_tit.setText(""); ui.e_tit.setPlaceholderText("Título do projeto...")
|
|
ui.chk_tmb.setChecked(True); ui.chk_tmb.setEnabled(False); ui.chk_tmb.setStyleSheet("color: #00FF00; font-weight: bold;")
|
|
else:
|
|
ui.e_tit.setText(ui.c_pst.currentText().replace("Editar: ", ""))
|
|
ui.chk_tmb.setEnabled(True); ui.chk_tmb.setStyleSheet("color: white; font-weight: bold;")
|
|
|
|
def finalize_export(ui, p_bk, p_glb):
|
|
if not os.path.exists(p_glb): os.makedirs(p_glb)
|
|
fo = []; rt.execute("max modify mode"); tgs = ui.get_processable_items()
|
|
|
|
ui.pb.setFormat("Preparando materiais VR (Multi-ID)..."); QtWidgets.QApplication.processEvents()
|
|
|
|
for d in tgs:
|
|
if ui._is_cancelled: break
|
|
if "Bake" in d['item'].text(1) or "Já existe" in d['item'].text(1) or "Mat" in d['item'].text(1):
|
|
try:
|
|
max_id = rt.execute(f"""(local o = getNodeByName "{d['name']}"; local mid = 1; if o != undefined and isKindOf o Editable_Poly do ( for f = 1 to (polyop.getNumFaces o) do ( local id = polyop.getFaceMatID o f; if id > mid do mid = id ) ); mid)""")
|
|
|
|
if max_id > 1:
|
|
# CONSTRUTOR DE MULTI-MATERIAL (Para objetos que foram processados pelo P4: Multi-UV)
|
|
ms_mat = f"""(
|
|
local o = getNodeByName "{d['name']}"
|
|
local mm = MultiMaterial numsubs:{int(max_id)} name:(o.name + "_MultiMat")
|
|
for i = 1 to {int(max_id)} do (
|
|
local ip = @"{p_bk}/{d['name']}_B_ID" + (i as string) + ".jpg"
|
|
if doesFileExist ip do (
|
|
local m = PhysicalMaterial name:(o.name + "_MatID_" + (i as string))
|
|
m.base_color_map = BitmapTexture filename:ip
|
|
m.roughness = 1.0; m.metalness = 0.0; try(m.reflectivity = 0.0; m.reflection_weight = 0.0)catch()
|
|
mm[i] = m
|
|
)
|
|
)
|
|
o.material = mm
|
|
)"""
|
|
rt.execute(ms_mat)
|
|
d['item'].setText(1, "Mat OK (Multi)")
|
|
fo.append(rt.getNodeByName(d['name']))
|
|
|
|
else:
|
|
# MATERIAL PADRÃO (Para objetos normais que cabem numa textura só)
|
|
ip = os.path.join(p_bk, f"{d['name']}_B.jpg").replace("\\", "/")
|
|
if os.path.exists(ip):
|
|
rt.execute(f"""(
|
|
local o = getNodeByName "{d['name']}"
|
|
if o != undefined do (
|
|
local m = PhysicalMaterial name:(o.name + "_Mat"); m.base_color_map = BitmapTexture filename:@"{ip}"
|
|
m.roughness = 1.0; m.metalness = 0.0; try(m.reflectivity = 0.0; m.reflection_weight = 0.0)catch()
|
|
o.material = m
|
|
)
|
|
)""")
|
|
fo.append(rt.getNodeByName(d['name'])); d['item'].setText(1, "Mat OK")
|
|
except Exception as e:
|
|
d['item'].setText(1, "Erro Mat"); print(f"Erro Material em {d['name']}: {e}")
|
|
|
|
if not fo and not ui._is_cancelled:
|
|
QtWidgets.QMessageBox.warning(ui, "Exportação Interrompida", "Nenhum objeto validado para exportação.")
|
|
ui.pb.setFormat("Pronto"); ui.pb.setValue(0)
|
|
return
|
|
|
|
if fo and not ui._is_cancelled:
|
|
rt.select(fo); sn = rt.maxFileName.split(".")[0] if rt.maxFileName else "Cena_VR4LIFE"
|
|
og = os.path.join(p_glb, f"{sn}.glb").replace("\\", "/"); oz = os.path.join(p_glb, f"{sn}.zip").replace("\\", "/")
|
|
tp = os.path.join(p_glb, f"{sn}_Thumb.jpg").replace("\\", "/"); mp = ui.e_mp3.text(); hm = os.path.exists(mp)
|
|
|
|
to = False
|
|
if ui.chk_tmb.isChecked() and ui.chk_tmb.isEnabled():
|
|
ui.pb.setFormat("📸 Thumbnail (1280x720)..."); QtWidgets.QApplication.processEvents()
|
|
rt.execute(f"""( local c = getActiveCamera(); if c == undefined do ( local ac = for cam in cameras where (classof cam != TargetObject) collect cam; if ac.count > 0 do c = ac[1] ); try ( if c != undefined then ( render camera:c outputwidth:1280 outputheight:720 outputfile:@"{tp}" vfb:false quiet:true ) else ( render outputwidth:1280 outputheight:720 outputfile:@"{tp}" vfb:false quiet:true ) ) catch() )""")
|
|
if os.path.exists(tp): to = True
|
|
|
|
ui.pb.setFormat("Limpando Hierarquia e XForm..."); QtWidgets.QApplication.processEvents()
|
|
|
|
rt.execute("""
|
|
(
|
|
local sel = selection as array
|
|
for o in sel do (
|
|
o.parent = undefined
|
|
ResetXForm o
|
|
collapseStack o
|
|
if not isKindOf o Editable_Poly do try(convertToPoly o)catch()
|
|
)
|
|
)
|
|
""")
|
|
|
|
ui.pb.setFormat("Montando GLB..."); QtWidgets.QApplication.processEvents()
|
|
try: rt.exportFile(og, rt.name("noPrompt"), selectedOnly=True, using=rt.GLTFExporter)
|
|
except: rt.execute(f'exportFile "{og}" #noPrompt selectedOnly:true')
|
|
|
|
zo = False
|
|
if os.path.exists(og):
|
|
ui.pb.setFormat("🗜️ ZIPando GLB..."); QtWidgets.QApplication.processEvents()
|
|
try:
|
|
with zipfile.ZipFile(oz, 'w', zipfile.ZIP_DEFLATED) as zf: zf.write(og, os.path.basename(og))
|
|
zo = True
|
|
except: pass
|
|
|
|
if ui.chk_up.isChecked() and ui.chk_up.isEnabled() and zo:
|
|
cs = ui.c_chn.currentText(); ac = "NOVO" if ui.c_pst.currentIndex() == 0 else "ATUALIZAR"; tit = ui.e_tit.text()
|
|
ui.pb.setFormat(f"📡 API: Enviando..."); QtWidgets.QApplication.processEvents(); time.sleep(1.5)
|
|
msg = f"Sincronizado!\n\n📡 Canal: {cs}\n📝 Ação: {ac}\n🏷️ Titulo: {tit}\n\n📦 ZIP: {os.path.basename(oz)}\n📸 Thumb: {'Sim' if to else 'Não'}\n🎵 Áudio: {'Sim' if hm else 'Não'}"
|
|
QtWidgets.QMessageBox.information(ui, "Cloud API", msg)
|
|
else:
|
|
msg = f"Exportado:\n{og}";
|
|
if zo: msg += f"\n\n🗜️ ZIP:\n{oz}"
|
|
if to: msg += f"\n\n📸 Thumb:\n{tp}"
|
|
QtWidgets.QMessageBox.information(ui, "Sucesso", msg)
|
|
ui.pb.setFormat("Pronto"); ui.pb.setValue(0) |