I started by testing how to read from and write to .json files in Houdini, but ultimately decided, that we needed an external tool for creating those files, which also adds the advantage of making it reusable in the future ( with some changes ).
The idea is, that in this tool you can create either a list of the entire modular kit, you want to import to Houdini or files for specific sets, e.g. ground floor, roof, etc. and also stores certain attributes of each piece, based on a list of keywords, so that in Houdini I can filter out corner, window, etc. pieces, instead of having to create separate files for all of those.
I plan to add an Editor option to the tool, so you can easily edit those .json files, for example appending or replacing pieces, maybe also based on piece type. Furthermore I need to make an executable file out of it.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
.json file generator for tile kits for the FMP procedural building tool | |
@author: Sophie Pette | |
""" | |
import tkinter.messagebox | |
import tkinter.filedialog | |
import tkinter.ttk | |
import tkinter as tk | |
from CreatorFrame import Creator | |
from EditorFrame import Editor | |
class JSONCreatorEditor(tk.Tk): | |
def __init__(self, *args, **kwargs): | |
tk.Tk.__init__(self, *args, **kwargs) | |
self.keywordlistType = ['wall','corner_90','corner_45','ww','pillar','unique','sw','window'] | |
self.keyworklistStyle = ['skirting','rd','sq','plain','artdeco'] | |
#GUI | |
screen_width = self.winfo_screenmmwidth() | |
screen_height = self.winfo_screenheight() | |
window_width = 250 | |
window_height = 350 | |
#Center window | |
x = screen_width/2 - window_width/2 | |
y = screen_height/2 - window_height/2 | |
self.geometry("%dx%d+%d+%d" % (window_width, window_height, x, y)) | |
self.title('Building Generator .json file Editor') | |
container = tk.Frame(self) | |
container.pack(side = 'top', fill = 'both', expand = True) | |
container.grid_rowconfigure(0, weight = 1) | |
container.grid_columnconfigure(0, weight = 1) | |
menu = tk.Menu(self) | |
self.config(menu = menu) | |
self.frames = {} | |
for F in (Creator, Editor): | |
frame = F(container, self, self.keywordlistType, self.keyworklistStyle) | |
self.frames[F] = frame | |
frame.grid(row = 0, column = 0, sticky = 'nsew') | |
self.show_frame(Creator) | |
#Menu | |
menu.add_command(label = 'Creator', command = lambda: self.show_frame(Creator)) | |
menu.add_command(label = 'Editor', command = lambda: self.show_frame(Editor)) | |
#display page | |
def show_frame(self, cont): | |
frame = self.frames[cont] | |
frame.tkraise() | |
if __name__ == '__main__': | |
app = JSONCreatorEditor() | |
app.mainloop() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tkinter as tk | |
import tkinter.messagebox | |
import tkinter.filedialog | |
import os, json | |
#Creator Window | |
class Creator(tk.Frame): | |
def __init__(self, parent, controller, kwListType, kwListStyle): | |
tk.Frame.__init__(self, parent) | |
self.keywordsType = kwListType | |
self.keywordsStyle = kwListStyle | |
self.rbState = 'disabled' | |
self.pieceList = [] | |
self.data = [] | |
#File Use | |
lblUse = tk.LabelFrame(self, text = 'File Use') | |
lblUse.pack(fill = 'both', expand = 'yes', padx = 2, pady = 2) | |
self.use = tk.StringVar() | |
self.use.set('importList') | |
rbImportList = tk.Radiobutton(lblUse, text = 'Import List', variable = self.use, value = 'importList', command = lambda: self.setUse('disabled')) | |
rbImportList.pack(anchor = 'w') | |
rbModuleKit = tk.Radiobutton(lblUse, text = 'Module Kit', variable = self.use, value = 'moduleKit', command = lambda: self.setUse('normal')) | |
rbModuleKit.pack(anchor = 'w') | |
#Kit type | |
lblType = tk.LabelFrame(self, text = 'Kit Type') | |
lblType.pack(fill = 'both', expand = 'yes', padx = 2, pady = 2) | |
self.kitType = tk.StringVar() | |
self.kitType.set('gfloor') | |
self.rbGFloor = tk.Radiobutton(lblType, text = 'Ground Floor', variable = self.kitType, value = 'gfloor', state = self.rbState, command = self.prntState) | |
self.rbGFloor.pack(anchor = 'w') | |
self.rbMFloor = tk.Radiobutton(lblType, text = 'Mid Floors', variable = self.kitType, value = 'mfloor', state = self.rbState, command = self.prntState) | |
self.rbMFloor.pack(anchor = 'w') | |
self.rbRoof = tk.Radiobutton(lblType, text = 'Roof', variable = self.kitType, value = 'roof', state = self.rbState, command = self.prntState) | |
self.rbRoof.pack(anchor = 'w') | |
self.rbFSep = tk.Radiobutton(lblType, text = 'Floor Seperators', variable = self.kitType, value = 'fseparation', state = self.rbState, command = self.prntState) | |
self.rbFSep.pack(anchor = 'w') | |
self.rbRSep = tk.Radiobutton(lblType, text = 'Roof Seperators', variable = self.kitType, value = 'rseparation', state = self.rbState, command = self.prntState) | |
self.rbRSep.pack(anchor = 'w') | |
#Buttons | |
lblButtons = tk.Label(self) | |
lblButtons.pack(fill = 'both', expand = 'yes') | |
btnCreateJSON = tk.Button(lblButtons, text = 'Create .json', command = self.selectFiles) | |
btnCreateJSON.pack(padx = 10, pady = 10) | |
#disable kitType buttons, if ImportList selected | |
def setUse(self, state): | |
for rb in (self.rbGFloor, self.rbMFloor, self.rbRoof, self.rbFSep, self.rbRSep): #go through all kit type ratiobuttons | |
rb.configure(state = str(state)) | |
self.rbState = state | |
print(self.rbState) | |
def prntState(self): | |
print(self.kitType.get()) | |
#select .FBX files | |
def selectFiles(self): | |
try: | |
self.data = [] | |
self.piece_list = tk.filedialog.askopenfilenames(title = 'Select files', filetypes = [("FBX Files", "*.fbx")]) | |
print(self.use.get()) | |
if (self.use.get() == 'moduleKit'): | |
for piece in self.piece_list: | |
name = os.path.basename(piece) | |
name = name[:-len(".FBX")] | |
t = self.kitType.get() | |
if (t in name.lower()): | |
path = piece | |
pieceType = self.checkKW(name, self.keywordsType, self.keywordsStyle)[0] | |
pieceStyle = self.checkKW(name, self.keywordsType, self.keywordsStyle)[1] | |
d = {'name': name, 'path': path, 'type': pieceType, 'style': pieceStyle} | |
print(d) | |
self.data.append(d.copy()) | |
else: | |
for piece in self.piece_list: | |
name = os.path.basename(piece) | |
name = name[:-len(".FBX")] | |
path = piece | |
d = {'name': name, 'path': path} | |
print(d) | |
self.data.append(d.copy()) | |
self.writeJSON(self.data) | |
except: | |
tk.messagebox.showerror('Error', 'File Creation interrupted') | |
#setting piece type and style | |
def checkKW(self, name, pTypeList, pStyleList): | |
t = '' | |
s = '' | |
for kwT in pTypeList: | |
if (kwT in name.lower()): | |
t = kwT | |
break | |
for kwS in pStyleList: | |
if (kwS in name.lower()): | |
s = kwS | |
return [t, s] | |
#writing data to .json file | |
def writeJSON(self, data): | |
#select save location | |
loc = tk.filedialog.asksaveasfilename(title = 'Save file location', filetypes = [(".json", "*.json")], defaultextension='.json') | |
json_name = loc | |
with open((json_name ), 'w') as outfile: | |
json.dump(data, outfile) | |
tk.messagebox.showinfo("Info", json_name.rstrip() + " created") | |
json_name = '' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tkinter as tk | |
class Editor(tk.Frame): | |
def __init__(self, parent, controller, kwListType, kwListStyle): | |
tk.Frame.__init__(self, parent) | |
self.keywords = kwListType | |
label = tk.Label(self, text = 'Editor') | |
label.pack(anchor = 'w', padx = 10, pady = 10) |
Here is how it works in its current state:
Current User Interface |
As for future plans I will now move on to properly implementing the use of those files in Houdini and also do some testing with how it translates to UE4. Whilst doing that I am sure I will have to adapt how exactly the tool works, improve and expand it.