MaterialXWeb 0.0.2
Utilities for using MaterialX Packages with Web clients
Loading...
Searching...
No Matches
MaterialXGPUOpenApp.py
1'''
2@file app.py
3@brief A Flask application that connects with the GPUOpen MaterialX server to allow downloading and extracting of materials by regular expression.
4'''
5import argparse
6import sys
7from flask import Flask, render_template
8from flask_socketio import SocketIO, emit
9from materialxMaterials import GPUOpenLoader as gpuo
10have_mx = False
11try:
12 import MaterialX as mx
13 have_mx = True
14except ImportError as e:
15 print("MaterialX module not found.")
16
17# Not required unless performing MaterialX operations on data
18#import MaterialX as mx
19
21 def __init__(self, home):
22 self.home = home
23
24 # Initialize Flask and SocketIO
25 self.app = Flask(__name__)
26 self.socketio = SocketIO(self.app)
27
28 # Register routes and events
29 self._register_routes()
32
34 """
35 Register HTTP routes.
36 """
37 @self.app.route('/')
38 def home():
39 """
40 Render the home page.
41 """
42 status_message = f'Startup: Using MaterialX version: {mx.getVersionString()}'
43 #self._emit_status_message(status_message)
44 print(status_message)
45 return render_template(self.home)
46
48 """Pure virtual method: Must be implemented by subclasses."""
49 raise NotImplementedError("Subclasses must implement _setup_event_handler_map")
50
52 """
53 Register SocketIO events.
54 """
55 # Dynamically register event handlers
56 for event_name, handler in self.event_handlers.items():
57 self.socketio.on_event(event_name, handler)
58
59 def run(self, host, port, debug=True):
60 """
61 Run the Flask server with SocketIO.
62 """
63 self.socketio.run(self.app, host, port, debug=debug)
64
65
67 '''
68 A Flask application that connects with the GPUOpen MaterialX server to allow downloading
69 and extracting of materials by regular expression.
70 '''
71 def __init__(self, homePage):
72 """
73 Initialize the Flask application and the MaterialX loader.
74 """
75 super().__init__(homePage)
76
77 # Material loader and associated attributes
78 self.loader = None
79 self.materials = None
80 self.material_names = None
82
83 def _emit_status_message(self, message):
84 """
85 Emit a status message to the client.
86 """
87 emit('materialx_status', { 'message': message }, broadcast=True)
88 print('Python:', message)
89
91 """
92 Handle the 'download_materialx' event, initialize the loader, and send materials data to the client.
93 """
94 status_message = f'Downloaded materials...'
95 self._emit_status_message(status_message)
96
97 # Initialize the loader and fetch materials
98 self.loader = gpuo.GPUOpenMaterialLoader()
99 self.materials = self.loader.getMaterials()
100 self.material_names = self.loader.getMaterialNames()
101
102 # Convert materials to JSON and get the count
103 materials_list = self.loader.getMaterialsAsJsonString()
105
106 # Emit a status message
107 status_message = f'Downloaded {self.material_count} materials.'
108 self._emit_status_message(status_message)
109
110 # Emit the data back to the client
111 emit('materialx_downloaded', {
112 'materialCount': self.material_countmaterial_count,
113 'materialNames': self.material_names,
114 'materialsList': materials_list
115 }, broadcast=True)
116
117 def handle_extract_material(self, data):
118 """
119 Handle the 'extract_material' event, extract material data, and send it back to the client.
120 """
121 if self.loader is None:
122 self._emit_status_message('Loader is not initialized. Download materials first.')
123 return
124
125 self._emit_status_message('Extracting materials...')
126 expression = data.get('expression', 'Default Expression')
127 update_mtlx = data.get('update_materialx', False)
128 if not have_mx:
129 update_mtlx = False
130 data_items = self.loader.downloadPackageByExpression(expression)
131 return_list = []
132
133 for data_item in data_items:
134 status_message = f'Extracting material: {data_item[1]}'
135 self._emit_status_message(status_message)
136 package = data_item[0]
137 title = data_item[1]
138 extracted_data = self.loader.extractPackageData(package, None)
139 return_data = {}
140
141 if extracted_data:
142 for item in extracted_data:
143 file_name = item['file_name']
144 if item['type'] == 'mtlx':
145 self._emit_status_message(f'- MaterialX file {file_name}')
146 mx_string = item['data']
147 if update_mtlx:
148 self._emit_status_message(f'Updating MaterialX data to version: {mx.getVersionString()}')
149 doc = mx.createDocument()
150 readOptions = mx.XmlReadOptions()
151 readOptions.readComments = True
152 readOptions.readNewlines = True
153 readOptions.upgradeVersion = True
154 mx.readFromXmlString(doc, mx_string, mx.FileSearchPath(), readOptions)
155 mx_string = mx.writeToXmlString(doc)
156
157 return_data[file_name] = mx_string
158 elif item["type"] == 'image':
159 self._emit_status_message(f'- Image file {file_name}')
160 image = item["data"]
161 image_base64 = self.loader.convertPilImageToBase64(image)
162 return_data[file_name] = image_base64
163
164 if len(return_data) > 0:
165 return_list.append({'title': title, 'data': return_data})
166
167 if len(return_list) == 0:
168 self._emit_status_message('No materials extracted')
169 else:
170 status_message = f'Extracted {len(return_list)} materials'
171 self._emit_status_message(status_message)
172 emit('materialx_extracted', {'extractedData': return_list}, broadcast=True)
173
175 """
176 Set up dictionary of mapping event names to their handlers
177 """
178 self.event_handlers = {
179 'download_materialx': self.handle_download_materialx,
180 'extract_material': self.handle_extract_material,
181 }
182
183# Main entry point
184def main():
185 parser = argparse.ArgumentParser(description="GPUOpen MaterialX Application")
186 parser.add_argument('--host', type=str, default='127.0.0.1', help="Host address to run the server on (default: 127.0.0.1)")
187 parser.add_argument('--port', type=int, default=8080, help="Port to run the server on (default: 8080)")
188 parser.add_argument('--home', type=str, default='MaterialXGPUOpenApp.html', help="Home page.")
189
190 args = parser.parse_args()
191
192 app = MaterialXGPUOpenApp(args.home)
193 app_host = args.host
194 app_port = args.port
195 app.run(host=app_host, port=app_port)
196
197if __name__ == '__main__':
198 main()
run(self, host, port, debug=True)
Run the Flask server with SocketIO.
_register_socket_events(self)
Register SocketIO events.
_register_routes(self)
Register HTTP routes.
_setup_event_handler_map(self)
Pure virtual method: Must be implemented by subclasses.
A Flask application that connects with the GPUOpen MaterialX server to allow downloading and extracti...
__init__(self, homePage)
Initialize the Flask application and the MaterialX loader.
handle_extract_material(self, data)
Handle the 'extract_material' event, extract material data, and send it back to the client.
_emit_status_message(self, message)
Emit a status message to the client.
handle_download_materialx(self, data)
Handle the 'download_materialx' event, initialize the loader, and send materials data to the client.
_setup_event_handler_map(self)
Set up dictionary of mapping event names to their handlers.