loon4tic

toontownclothingpreviewer

Oct 14th, 2021
2,132
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. from direct.showbase.ShowBase import ShowBase
  2. from pathlib import Path
  3. from tkinter.filedialog import askopenfilename
  4. from panda3d.core import Filename, GraphicsOutput, WindowProperties, Texture, GraphicsPipe, FrameBufferProperties
  5. from direct.gui.DirectGui import *
  6. import sys, os
  7.  
  8. # We need to import the tkinter library to
  9. # disable the tk window that pops up.
  10. # We use tk for the file path selector.
  11. import tkinter as tk
  12. root = tk.Tk()
  13. root.withdraw()
  14.  
  15. # Force high quality for our render
  16. from panda3d.core import loadPrcFileData
  17. loadPrcFileData('', 'default-antialias-enable 1')
  18. loadPrcFileData('', 'framebuffer-multisample 1')
  19. loadPrcFileData('', 'win-size 1920 1080')
  20.  
  21. """
  22. Controls:
  23. s = Take screenshot
  24. o = toggle oobe/free camera
  25. r = reload loaded textures
  26. e = reset rotation
  27. 1 = toggle shirt
  28. 2 = toggle bottoms
  29. 3 = load dogs body
  30. 4 = load dogm body
  31. 5 = load dogl body
  32. mouse wheel up = zoom in
  33. mouse wheel down = zoom out
  34. mouse3(middle mouse click) = reset zoom
  35. left arrow = rotate negative heading
  36. right arrow = rotate positive heading
  37. up arrow = rotate positive pitch
  38. down arrow = rotate negative pitch
  39.  
  40. """
  41.  
  42. """
  43. Todo:
  44. Add onscreen text that displays the offset (camers zoom, clothing rotation, etc.) <-- will be hidden in screenshots
  45. """
  46.  
  47.  
  48. class previewClothing(ShowBase):
  49.  
  50.     def __init__(self):
  51.         ShowBase.__init__(self)
  52.         self.fileName = "output" # Output file name
  53.         self.fileFormat = ".png"
  54.         self.topTex = None
  55.         self.sleeveTex = None
  56.         self.bottomTex = None
  57.         self.loadedTextures = [None, None, None]
  58.         self.shirtVisible = True
  59.         self.bottomsVisible = True
  60.         self.torso = None
  61.         self.type = 'm'
  62.         self.botType = 'shorts' # just shorts/skirt
  63.         self.defaultCamPos = base.cam.getPos()
  64.         base.camera.hide()
  65.         self.i = 1
  66.         self.defaultH = 190 # todo: hotkey to reset all transformations
  67.         self.currentH = self.defaultH
  68.         self.defaultP = 0
  69.         self.currentP = self.defaultP
  70.  
  71.         # Just in case we have these enabled in the config...
  72.         base.setFrameRateMeter(False)
  73.         base.setSceneGraphAnalyzerMeter(False)
  74.  
  75.         base.disableMouse()
  76.  
  77.         self.loadBody()
  78.         self.loadGUI()
  79.  
  80.         """
  81.        If you want to change the default outfit texture (not desat), you can either
  82.        change the texture path of the egg model(s) itself, or, alternatively, you can
  83.        directly call to load specific textures, e.g.:
  84.            self.loadTopTexture("path/to/texture.png")
  85.        """
  86.  
  87.         self.accept('s', self.aspect2d.hide) # Hacky b/c hiding and showing in same method no work
  88.         self.accept('s-up', self.saveScreenshot)
  89.         self.accept('o', base.oobe)
  90.         self.accept('r', self.reloadTextures)
  91.         self.accept('e', self.defaultRotation)
  92.         self.accept('wheel_up', self.zoomCamera, [0.1])
  93.         self.accept('wheel_down', self.zoomCamera, [-0.1])
  94.         self.accept('mouse2', self.defaultCam)
  95.         self.accept('arrow_left', self.rotateClothingH, [-5])
  96.         self.accept('arrow_left-repeat', self.rotateClothingH, [-5])
  97.         self.accept('arrow_right', self.rotateClothingH, [5])
  98.         self.accept('arrow_right-repeat', self.rotateClothingH, [5])
  99.         self.accept('arrow_up', self.rotateClothingP, [5])
  100.         self.accept('arrow_up-repeat', self.rotateClothingP, [5])
  101.         self.accept('arrow_down', self.rotateClothingP, [-5])
  102.         self.accept('arrow_down-repeat', self.rotateClothingP, [-5])
  103.         self.accept('1', self.toggleShirt)
  104.         self.accept('2', self.toggleBottoms)
  105.         self.accept('3', self.loadBody, ['s', self.botType])
  106.         self.accept('4', self.loadBody, ['m', self.botType])
  107.         self.accept('5', self.loadBody, ['l', self.botType])
  108.         #self.accept('b', self.torso.showTightBounds)
  109.  
  110.  
  111.     """
  112.    ("tt_a_chr_dgX_Y_torso_1000.egg")
  113.    X = s, m, l
  114.    Y = shorts, skirt
  115.    """
  116.     def loadBody(self, type='m', gender='shorts'): # default: dogM_shorts
  117.         self.clearBody()
  118.         self.type = type
  119.         self.botType = gender
  120.         torsoModel = loader.loadModel("tt_a_chr_dg{}_{}_torso_1000.egg".format(type, gender)) # can rename this later
  121.         self.torso = torsoModel.getChild(0)
  122.         self.torso.reparentTo(render)
  123.         #print(self.torso)
  124.  
  125.  
  126.         #torsoModel.hide()
  127.         for node in self.torso.getChildren():
  128.             if (node.getName() != 'torso-top')\
  129.             and (node.getName() != "torso-bot")\
  130.             and (node.getName() != 'sleeves'):
  131.                 node.stash()
  132.         # note: Z-up
  133.         self.torso.setPos(0.00, 4.69, -0.235)
  134.         self.torso.setH(self.currentH)
  135.         self.torso.setP(self.currentP)
  136.         if(type == 'l'):
  137.             self.torso.setPos(self.torso.getX(), self.torso.getY()+ 0.91, self.torso.getZ() - 0.46)
  138.         self.torso.setTwoSided(True)
  139.         #print(self.topTex)
  140.         if self.topTex is not None:
  141.             self.torso.find('**/torso-top').setTexture(self.loadedTextures[0], 1)
  142.         if self.sleeveTex is not None:
  143.             self.torso.find('**/sleeves').setTexture(self.loadedTextures[1], 1)
  144.         if self.bottomTex is not None:
  145.             self.torso.find('**/torso-bot').setTexture(self.loadedTextures[2], 1)
  146.  
  147.     def clearBody(self):
  148.         if self.torso is not None:
  149.             self.torso.removeNode()
  150.             self.torso = None
  151.  
  152.  
  153.     def changeBotType(self):
  154.         if self.botType == 'shorts':
  155.             self.botType = 'skirt'
  156.         elif self.botType == 'skirt':
  157.             self.botType = 'shorts'
  158.         else:
  159.             self.botType = 'shorts' # Should never hit this but have a failsafe
  160.         self.loadBody(self.type, self.botType)
  161.  
  162.  
  163.     def loadGUI(self):
  164.         # Todo: figure out how to reposition buttons when window changes size
  165.         #guiFrame = DirectFrame(frameColor=(0, 0, 0, 1),
  166.         #              frameSize=(-1, 1, -1, 1),
  167.         #              pos=(1, -1, -1))
  168.         self.topButton = DirectButton(text=("Change Top"),
  169.                  scale=0.05, pos=(-1.6, 0, -0.4), command=self.openTop)
  170.         self.sleeveButton = DirectButton(text=("Change Sleeve"),
  171.                  scale=0.05, pos=(-1.6, 0, -0.5), command=self.openSleeves)
  172.         self.shortsButton = DirectButton(text=("Change Bottoms"),
  173.                  scale=0.05, pos=(-1.6, 0, -0.6), command=self.openBottom)
  174.  
  175.         self.loadSButton = DirectButton(text=("dogs"),
  176.                  scale=0.05, pos=(1.6, 0, -0.4),  command=self.loadBody, extraArgs=['s'])
  177.         self.loadMButton = DirectButton(text=("dogm"),
  178.                  scale=0.05, pos=(1.6, 0, -0.5),  command=self.loadBody, extraArgs=['m'])
  179.         self.loadLButton = DirectButton(text=("dogl"),
  180.                  scale=0.05, pos=(1.6, 0, -0.6),  command=self.loadBody, extraArgs=['l'])
  181.         self.changeGenderButton = DirectButton(text=("Change gender"),
  182.                  scale=0.05, pos=(1.6, 0, -0.7),  command=self.changeBotType)
  183.  
  184.     def saveScreenshot(self):
  185.         # intent: Image number would increment if the file already exists just so it doesn't overwrite
  186.         self.newfileName = self.fileName
  187.         if not (os.path.isfile(self.newfileName)): # wip
  188.             self.newfileName = self.fileName+str(self.i)
  189.             self.i +=1
  190.  
  191.         filename = self.newfileName +self.fileFormat
  192.         base.win.saveScreenshot(Filename(filename))
  193.         self.aspect2d.show()
  194.         print("Screenshot saved! {}".format(filename))
  195.  
  196.  
  197.     def reloadTextures(self):
  198.         for tex in self.loadedTextures:
  199.             if tex: tex.reload()
  200.  
  201.     # temporary until i have a better way to do this lol
  202.     def toggleShirt(self):
  203.         if self.torso is None:
  204.             return
  205.         if (self.shirtVisible):
  206.             self.torso.find('**/torso-top').hide()
  207.             self.torso.find('**/sleeves').hide()
  208.             self.shirtVisible = False
  209.         else:
  210.             self.torso.find('**/torso-top').show()
  211.             self.torso.find('**/sleeves').show()
  212.             self.shirtVisible = True
  213.  
  214.     def toggleBottoms(self):
  215.         if self.torso is None:
  216.             return
  217.         if (self.bottomsVisible):
  218.             self.torso.find('**/torso-bot').hide()
  219.             self.bottomsVisible = False
  220.         else:
  221.             self.torso.find('**/torso-bot').show()
  222.             self.bottomsVisible = True
  223.  
  224.  
  225.     # Rotate clothing
  226.  
  227.     def rotateClothingH(self, value):
  228.         self.currentH = self.torso.getH() + value
  229.         self.torso.setH(self.currentH)
  230.  
  231.  
  232.     def rotateClothingP(self, value):
  233.         self.currentP = self.torso.getP() + value
  234.         self.torso.setP(self.currentP)
  235.  
  236.     def defaultRotation(self):
  237.         self.currentH = self.defaultH
  238.         self.torso.setH(self.currentH)
  239.         self.currentP = self.defaultP
  240.         self.torso.setP(self.currentP)
  241.  
  242.     # Camera Modifiers
  243.     def defaultCam(self):
  244.         base.cam.setPos(self.defaultCamPos)
  245.  
  246.     def zoomCamera(self, value):
  247.         base.cam.setPos(base.cam.getX(), base.cam.getY() + value, base.cam.getZ())
  248.     ###
  249.  
  250.     def browseForImage(self):
  251.         path = Path(askopenfilename(filetypes = (
  252.             ("Image Files", "*.jpg;*.jpeg;*.png;*.psd;*.tga"),
  253.             ("JPEG", "*.jpg;*.jpeg"),
  254.             ("PNG", "*.png"),
  255.             ("Photoshop File", "*.psd"),
  256.             ("Targa", "*.tga"))))
  257.  
  258.         return path
  259.  
  260.     def loadTopTexture(self, file: str):
  261.         tex = loader.loadTexture(file)
  262.         self.topTex = file
  263.         self.loadedTextures[0] = tex
  264.         self.torso.find('**/torso-top').setTexture(tex, 1)
  265.  
  266.     def loadSleeveTexture(self, file: str):
  267.         tex = loader.loadTexture(file)
  268.         self.sleeveTex = file
  269.         self.loadedTextures[1] = tex
  270.         self.torso.find('**/sleeves').setTexture(tex, 1)
  271.  
  272.     def loadBottomTexture(self, file: str):
  273.         tex = loader.loadTexture(file)
  274.         self.bottomTex = file
  275.         self.loadedTextures[2] = tex
  276.         self.torso.find('**/torso-bot').setTexture(tex, 1)
  277.  
  278.     def openTop(self):
  279.         filename = self.browseForImage()
  280.         if str(filename) == ".":
  281.             return
  282.         try:
  283.             self.loadTopTexture(filename)
  284.         except:
  285.             print(str(filename) + " could not be loaded!")
  286.  
  287.     def openSleeves(self):
  288.         filename = self.browseForImage()
  289.         if str(filename) == ".":
  290.             return
  291.         try:
  292.             self.loadSleeveTexture(filename)
  293.         except:
  294.             print(str(filename) + " could not be loaded!")
  295.  
  296.     def openBottom(self):
  297.         filename = self.browseForImage()
  298.         if str(filename) == ".":
  299.             return
  300.         try:
  301.             self.loadBottomTexture(filename)
  302.         except:
  303.             print(str(filename) + " could not be loaded!")
  304.  
  305.  
  306. app = previewClothing()
  307. app.run()
  308.  
RAW Paste Data