├── AnimRef.zip
├── AnimRef
├── Contents
│ ├── 2020
│ │ └── animref.py
│ ├── 2021
│ │ └── animref.py
│ ├── 2025
│ │ └── animref.py
│ ├── 2020.ms
│ ├── 2021.ms
│ ├── 2025.ms
│ ├── converter
│ │ └── video_to_sequence.exe
│ ├── icons
│ │ ├── e_frame.png
│ │ ├── icon.png
│ │ ├── load_images.png
│ │ ├── loop.png
│ │ ├── n_frame.png
│ │ ├── no_data.png
│ │ ├── p_frame.png
│ │ ├── pause.png
│ │ ├── play.png
│ │ ├── s_frame.png
│ │ ├── seq.png
│ │ └── soft-icon.png
│ └── interface
│ │ └── interface.ui
└── PackageContents.xml
├── LICENSE
├── One-Click Installation.bat
├── README.md
└── screen
├── converter.gif
└── interface.jpg
/AnimRef.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef.zip
--------------------------------------------------------------------------------
/AnimRef/Contents/2020.ms:
--------------------------------------------------------------------------------
1 | python.Init()
2 |
3 | macroScript AnimRef category:"CGcenter" buttonText: "AnimRef"
4 | (
5 | python.ExecuteFile(getDir #publicExchangeStoreInstallPath + "\AnimRef\Contents\2020\animref.py")
6 | )
7 |
--------------------------------------------------------------------------------
/AnimRef/Contents/2020/animref.py:
--------------------------------------------------------------------------------
1 | import os
2 | import subprocess
3 | import urllib
4 |
5 | import MaxPlus
6 | from PySide2 import QtCore, QtGui
7 | from PySide2 import QtWidgets
8 | from PySide2.QtCore import QFile
9 | from PySide2.QtGui import QIcon, QColor
10 | from PySide2.QtUiTools import QUiLoader
11 | from PySide2.QtWidgets import QMessageBox, QVBoxLayout, QSizePolicy, QFileDialog, QPushButton, QDialog, QWidget, QLabel
12 | from pymxs import runtime as mxs
13 |
14 |
15 | # Define Dialog Window
16 | class AnimRef(QDialog):
17 | def __init__(self, parent=MaxPlus.GetQMaxMainWindow()):
18 | super(AnimRef, self).__init__(parent)
19 |
20 | self.init()
21 |
22 | self.setWindowFlags(QtCore.Qt.WindowType.Window)
23 | self.resize(720, 460)
24 | self.setWindowTitle("AnimRef v1.5.2")
25 |
26 | self.defineVariables()
27 | self.defineSignals()
28 | self.defineIcons()
29 | self.start()
30 |
31 | self.setWindowIcon(self.icon)
32 | self.timer = QtCore.QTimer(self)
33 |
34 | def downloadConverter(self):
35 |
36 | converter_path = os.path.join(self.dir, 'AnimRef', 'Contents', 'converter', 'video_to_sequence.exe')
37 | download_path = "https://raw.githubusercontent.com/ShirzadBh/AnimRef/main/AnimRef/Contents/converter/video_to_sequence.exe"
38 |
39 | try:
40 |
41 | # urllib.request.urlretrieve(download_path, converter_path)
42 | urllib.urlretrieve(download_path, converter_path)
43 |
44 | self.ui.state.setStyleSheet('''color : #98fc03;
45 | font-size: 12px;
46 | font-family:"Comic Sans MS", cursive, sans-serif;''')
47 |
48 | self.ui.state.setText("video_to_sequence.exe is ready!")
49 | self.time_counting = True
50 | self.startTime()
51 | except:
52 | self.ui.state.setStyleSheet('''color : #fc5203;
53 | font-size: 12px;
54 | font-family:"Comic Sans MS", cursive, sans-serif;''')
55 |
56 | self.ui.state.setText("Download failed...")
57 | self.time_counting = True
58 | self.startTime()
59 |
60 | def convertedExist(self):
61 |
62 | FILEBROWSER_PATH = os.path.join(os.getenv('WINDIR'), 'explorer.exe')
63 | path = os.path.join(self.dir, 'AnimRef', 'Contents', 'converter', 'video_to_sequence.exe')
64 | converterPath = os.path.join(self.dir, 'AnimRef', 'Contents', 'converter')
65 |
66 | if os.path.exists(path):
67 | subprocess.call([FILEBROWSER_PATH, converterPath])
68 | else:
69 | msgBox = QMessageBox()
70 | msgBox.setText("Do You Want To Download video_to_sequence.exe")
71 | msgBox.setWindowTitle("Sequence Converter")
72 | msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
73 |
74 | returnValue = msgBox.exec_()
75 |
76 | if returnValue == QMessageBox.Ok:
77 | self.downloadConverter()
78 |
79 | def startTime(self):
80 | if self.time_counting:
81 | self.timer.timeout.connect(self.stopTime)
82 | self.timer.start(3000)
83 |
84 | def stopTime(self):
85 | self.ui.state.clear()
86 | self.timer.stop()
87 | self.time_counting = False
88 |
89 | def init(self):
90 |
91 | self.dir = mxs.getDir(mxs.name('publicExchangeStoreInstallPath'))
92 | ui_file = QFile(
93 | os.path.join(self.dir, 'AnimRef', 'Contents', 'interface', 'interface.ui'))
94 | ui_file.open(QFile.ReadOnly)
95 | self.ui = QUiLoader().load(ui_file, self)
96 | ui_file.close()
97 | layout = QtWidgets.QHBoxLayout()
98 | layout.addWidget(self.ui)
99 | layout.setMargin(4)
100 | self.setLayout(layout)
101 |
102 | def start(self):
103 | self.ui.viewer.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
104 | self.pixmap = self.no_image.scaled(400, 200, QtCore.Qt.KeepAspectRatio, QtCore.Qt.FastTransformation)
105 | self.ui.viewer.setPixmap(self.pixmap)
106 | mxs.registerTimeCallback(self.changeTime)
107 |
108 | def changeOpacity(self):
109 | self.opacity = float(self.ui.sl_opacity.value())
110 | self.setWindowOpacity(self.opacity / 100)
111 |
112 | def defineVariables(self):
113 | self.last_valid_frame = 0
114 | self.time_counting = False
115 | self.out_of_range = False
116 | self.pixmap = None
117 | self.isLoaded = False
118 | self.current_time = int(mxs.currentTime)
119 | self.time_shift = self.ui.sb_time_shift.value()
120 | self.time = self.current_time + self.time_shift
121 | self.height = self.ui.viewer.height()
122 | self.width = self.ui.viewer.width()
123 | self.images_backup = {}
124 | self.images = {}
125 | self.opacity = 1
126 | self.images_path = None
127 | self.last_frame = 0
128 | self.previous_frame = 0
129 | self.no_image = QtGui.QPixmap(
130 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'no_data.png'))
131 |
132 | def defineSignals(self):
133 | # self.ui.timeSlider.valueChanged.connect(self.goToFrame)
134 | self.ui.btn_converter.clicked.connect(self.convertedExist)
135 |
136 | self.ui.sl_opacity.valueChanged.connect(self.changeOpacity)
137 | self.ui.btn_load_seq.clicked.connect(self.load_seq)
138 | self.ui.sb_time_shift.valueChanged.connect(self.updateTimeShift)
139 | self.ui.btn_n_frame.clicked.connect(self.nextFrame)
140 | self.ui.btn_p_frame.clicked.connect(self.previousFrame)
141 | self.ui.btn_play.clicked.connect(self.playFrame)
142 | self.ui.btn_s_frame.clicked.connect(self.startFrame)
143 | self.ui.btn_e_frame.clicked.connect(self.endFrame)
144 |
145 | def nextFrame(self):
146 | mxs.stopAnimation()
147 | self.ui.btn_play.setChecked(False)
148 | mxs.sliderTime += 1
149 | self.ui.sb_time_shift.setEnabled(True)
150 |
151 | def previousFrame(self):
152 | mxs.stopAnimation()
153 | self.ui.btn_play.setChecked(False)
154 | mxs.sliderTime -= 1
155 | self.ui.sb_time_shift.setEnabled(True)
156 |
157 | def playFrame(self):
158 | if mxs.isAnimPlaying():
159 | self.ui.sb_time_shift.setEnabled(True)
160 | mxs.stopAnimation()
161 |
162 | elif not mxs.isAnimPlaying():
163 | self.ui.sb_time_shift.setEnabled(False)
164 | mxs.playAnimation()
165 |
166 | def startFrame(self):
167 | # mxs.execute("max time start")
168 | mxs.stopAnimation()
169 | mxs.sliderTime = self.time_shift
170 | self.ui.btn_play.setIcon(self.play_icon)
171 | self.ui.btn_play.setChecked(False)
172 | self.ui.sb_time_shift.setEnabled(True)
173 |
174 | def endFrame(self):
175 | # mxs.execute("max time end")
176 | mxs.stopAnimation()
177 | mxs.sliderTime = self.time_shift + (self.last_frame - 1)
178 | self.ui.btn_play.setIcon(self.play_icon)
179 | self.ui.btn_play.setChecked(False)
180 | self.ui.sb_time_shift.setEnabled(True)
181 |
182 | def updateTimeShift(self):
183 | self.time_shift = self.ui.sb_time_shift.value()
184 | self.changeTime()
185 |
186 | def load_seq(self):
187 | self.height = self.ui.viewer.height()
188 | self.width = self.ui.viewer.width()
189 |
190 | try:
191 |
192 | fname = list(QFileDialog.getOpenFileNames(self, 'Select Range OF Sequences',
193 | filter="Images (*.jpeg *.jpg *.png *.bmp)", ))
194 |
195 | if len(fname[0]) > 0:
196 | self.images = {}
197 | self.images_path = os.path.dirname(os.path.realpath(fname[0][0]))
198 |
199 | self.test = {}
200 | for i in range(int(len(fname[0]))):
201 | self.images[i] = QtGui.QPixmap(fname[0][i])
202 | self.test[i] = fname[0][i]
203 |
204 | self.last_frame = len(fname[0])
205 | self.isLoaded = True
206 | self.ui.btn_play.setEnabled(True)
207 | self.ui.btn_s_frame.setEnabled(True)
208 | self.ui.btn_p_frame.setEnabled(True)
209 | self.ui.btn_n_frame.setEnabled(True)
210 | self.ui.btn_e_frame.setEnabled(True)
211 | self.ui.sb_time_shift.setEnabled(True)
212 | self.ui.btn_loop.setEnabled(True)
213 | self.status_1()
214 | self.changeTime()
215 |
216 | else:
217 | self.status_3()
218 | self.changeTime()
219 |
220 | except:
221 | self.status_3()
222 | self.changeTime()
223 |
224 | def changeTime(self):
225 | if self.isLoaded:
226 |
227 | self.ui.maxframe.setText(str(int(mxs.currentTime)))
228 | self.ui.refframe.setText(str(int(mxs.currentTime) - self.time_shift))
229 |
230 | try:
231 | self.pixmap = self.images[int(mxs.currentTime) - self.time_shift].scaled(self.width, self.height,
232 | QtCore.Qt.KeepAspectRatio,
233 | QtCore.Qt.FastTransformation)
234 | self.ui.viewer.setPixmap(self.pixmap)
235 | self.ui.viewer.repaint()
236 | self.ui.maxframe.setText(str(int(mxs.currentTime)))
237 | self.ui.refframe.setText(str(int(mxs.currentTime) - self.time_shift))
238 | self.out_of_range = False
239 | self.last_valid_frame = int(mxs.currentTime) - self.time_shift
240 | except:
241 | out = True
242 | is_playing = mxs.isAnimPlaying()
243 | if self.isLoaded and not self.ui.btn_loop.isChecked():
244 | self.status_2()
245 |
246 | if self.isLoaded:
247 |
248 | if self.ui.btn_loop.isChecked():
249 | mxs.stopAnimation()
250 | mxs.sliderTime = self.time_shift
251 | if is_playing and out:
252 | mxs.playAnimation()
253 | self.out_of_range = True
254 |
255 | def defineIcons(self):
256 | self.icon = QtGui.QIcon(
257 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'icon.png'))
258 | self.play_icon = QtGui.QIcon(
259 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'play.png'))
260 | self.n_frame_icon = QtGui.QIcon(
261 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'n_frame.png'))
262 | self.p_frame_icon = QtGui.QIcon(
263 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'p_frame.png'))
264 | self.s_frame_icon = QtGui.QIcon(
265 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 's_frame.png'))
266 | self.e_frame_icon = QtGui.QIcon(
267 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'e_frame.png'))
268 | self.load_images_icon = QtGui.QIcon(
269 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'load_images.png'))
270 | self.loop_icon = QtGui.QIcon(
271 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'loop.png'))
272 | self.pause_icon = QtGui.QIcon(
273 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'pause.png'))
274 | self.seq_icon = QtGui.QIcon(
275 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'seq.png'))
276 |
277 | self.ui.btn_play.setIcon(self.play_icon)
278 | self.ui.btn_n_frame.setIcon(self.n_frame_icon)
279 | self.ui.btn_p_frame.setIcon(self.p_frame_icon)
280 | self.ui.btn_s_frame.setIcon(self.s_frame_icon)
281 | self.ui.btn_e_frame.setIcon(self.e_frame_icon)
282 | self.ui.btn_load_seq.setIcon(self.load_images_icon)
283 | self.ui.btn_loop.setIcon(self.loop_icon)
284 | self.ui.btn_converter.setIcon(self.seq_icon)
285 |
286 | def wheelEvent(self, event):
287 | if self.isLoaded:
288 | mxs.sliderTime += (event.delta() / 120)
289 |
290 | def resizeEvent(self, event):
291 | self.updateFrame()
292 | self.changeTime()
293 |
294 | def closeEvent(self, event):
295 | mxs.unregisterTimeCallback(self.changeTime)
296 | self.timer.stop()
297 |
298 | def updateFrame(self):
299 | if self.isLoaded:
300 | self.height = self.ui.viewer.height()
301 | self.width = self.ui.viewer.width()
302 |
303 | self.pixmap = self.images[self.last_valid_frame].scaled(self.width, self.height, QtCore.Qt.KeepAspectRatio,
304 | QtCore.Qt.FastTransformation)
305 | self.ui.viewer.setPixmap(self.pixmap)
306 |
307 | def status_1(self):
308 | self.ui.state.clear()
309 | self.ui.state.setStyleSheet('''color : #98fc03;
310 | font-size: 12px;
311 | font-family:"Comic Sans MS", cursive, sans-serif;''')
312 |
313 | self.ui.state.setText("{0} images were imported".format(self.last_frame))
314 | self.time_counting = True
315 | self.startTime()
316 |
317 | def status_2(self):
318 | self.ui.state.clear()
319 | self.ui.state.setStyleSheet('''color : #fcbe03;
320 | font-size: 12px;
321 | font-family:"Comic Sans MS", cursive, sans-serif;''')
322 |
323 | self.ui.state.setText("Out of range")
324 | self.time_counting = True
325 | self.startTime()
326 |
327 | def status_3(self):
328 | self.ui.state.clear()
329 | self.ui.state.setStyleSheet('''color : #fc5203;
330 | font-size: 12px;
331 | font-family:"Comic Sans MS", cursive, sans-serif;''')
332 |
333 | self.ui.state.setText("Import was canceled")
334 | self.time_counting = True
335 | self.startTime()
336 |
337 |
338 | def main():
339 | dlg = AnimRef()
340 | dlg.show()
341 |
342 |
343 | if __name__ == '__main__':
344 | main()
345 |
--------------------------------------------------------------------------------
/AnimRef/Contents/2021.ms:
--------------------------------------------------------------------------------
1 | python.Init()
2 |
3 | macroScript AnimRef category:"CGcenter" buttonText: "AnimRef"
4 | (
5 | python.ExecuteFile(getDir #publicExchangeStoreInstallPath + "\AnimRef\Contents\2021\animref.py")
6 | )
7 |
--------------------------------------------------------------------------------
/AnimRef/Contents/2021/animref.py:
--------------------------------------------------------------------------------
1 | import os
2 | import subprocess
3 | import urllib.request
4 |
5 | from PySide2 import QtCore, QtGui
6 | from PySide2.QtCore import QFile
7 | from PySide2.QtGui import QIcon, QColor
8 | from PySide2.QtUiTools import QUiLoader
9 | from PySide2.QtWidgets import QMessageBox, QVBoxLayout, QSizePolicy, QFileDialog, QPushButton, QDialog, QWidget, QLabel
10 | from pymxs import runtime as mxs
11 |
12 |
13 | class AnimRef(QDialog):
14 | def __init__(self, parent=QWidget.find(mxs.windows.getMAXHWND())):
15 | QDialog.__init__(self, parent)
16 |
17 | self.init()
18 |
19 | self.setWindowFlags(QtCore.Qt.WindowType.Window)
20 | self.resize(720, 460)
21 | self.setWindowTitle("AnimRef v1.5.2")
22 |
23 | self.defineVariables()
24 | self.defineSignals()
25 | self.defineIcons()
26 | self.start()
27 |
28 | self.setWindowIcon(self.icon)
29 |
30 | self.timer = QtCore.QTimer(self)
31 |
32 | def downloadConverter(self):
33 |
34 | converter_path = os.path.join(self.dir, 'ApplicationPlugins', 'AnimRef', 'Contents', 'converter',
35 | 'video_to_sequence.exe')
36 | download_path = "https://raw.githubusercontent.com/ShirzadBh/AnimRef/main/AnimRef/Contents/converter/video_to_sequence.exe"
37 |
38 | try:
39 | urllib.request.urlretrieve(download_path, converter_path)
40 | self.ui.state.setStyleSheet('''color : #98fc03;
41 | font-size: 12px;
42 | font-family:"Comic Sans MS", cursive, sans-serif;''')
43 |
44 | self.ui.state.setText("video_to_sequence.exe is ready!")
45 | self.time_counting = True
46 | self.startTime()
47 | except:
48 | self.ui.state.setStyleSheet('''color : #fc5203;
49 | font-size: 12px;
50 | font-family:"Comic Sans MS", cursive, sans-serif;''')
51 |
52 | self.ui.state.setText("Download failed...")
53 | self.time_counting = True
54 | self.startTime()
55 |
56 | def convertedExist(self):
57 |
58 | FILEBROWSER_PATH = os.path.join(os.getenv('WINDIR'), 'explorer.exe')
59 | path = os.path.join(self.dir, 'AnimRef', 'Contents', 'converter', 'video_to_sequence.exe')
60 | converterPath = os.path.join(self.dir, 'AnimRef', 'Contents', 'converter')
61 |
62 | if os.path.exists(path):
63 | subprocess.run([FILEBROWSER_PATH, converterPath])
64 | else:
65 | msgBox = QMessageBox()
66 | msgBox.setText("Do You Want To Download video_to_sequence.exe")
67 | msgBox.setWindowTitle("Sequence Converter")
68 | msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
69 |
70 | returnValue = msgBox.exec()
71 | if returnValue == QMessageBox.Ok:
72 | self.downloadConverter()
73 |
74 | def startTime(self):
75 | if self.time_counting:
76 | self.timer.timeout.connect(self.stopTime)
77 | self.timer.start(3000)
78 |
79 | def stopTime(self):
80 | self.ui.state.clear()
81 | self.timer.stop()
82 | self.time_counting = False
83 |
84 | def init(self):
85 |
86 | self.dir = mxs.getDir(mxs.name('publicExchangeStoreInstallPath'))
87 | loader = QUiLoader()
88 | ui_file_path = os.path.join(self.dir, 'AnimRef', 'Contents', 'interface', 'interface.ui')
89 | ui_file = QFile(ui_file_path)
90 | ui_file.open(QFile.ReadOnly)
91 | self.ui = loader.load(ui_file, self)
92 | ui_file.close()
93 | layout = QVBoxLayout()
94 | layout.addWidget(self.ui)
95 | layout.setMargin(4)
96 | self.setLayout(layout)
97 |
98 | def start(self):
99 | self.ui.viewer.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
100 | self.pixmap = self.no_image.scaled(400, 200, QtCore.Qt.KeepAspectRatio, QtCore.Qt.FastTransformation)
101 | self.ui.viewer.setPixmap(self.pixmap)
102 | mxs.registerTimeCallback(self.changeTime)
103 |
104 | def changeOpacity(self):
105 | self.opacity = self.ui.sl_opacity.value() / 100
106 | self.setWindowOpacity(self.opacity)
107 |
108 | def defineVariables(self):
109 | self.last_valid_frame = 0
110 | self.time_counting = False
111 | self.out_of_range = False
112 | self.pixmap = None
113 | self.isLoaded = False
114 | self.current_time = int(mxs.currentTime)
115 | self.time_shift = self.ui.sb_time_shift.value()
116 | self.time = self.current_time + self.time_shift
117 | self.height = self.ui.viewer.height()
118 | self.width = self.ui.viewer.width()
119 | self.images_backup = {}
120 | self.images = {}
121 | self.opacity = 1
122 | self.images_path = None
123 | self.last_frame = 0
124 | self.previous_frame = 0
125 | self.no_image = QtGui.QPixmap(
126 | os.path.join(os.path.dirname(os.path.realpath(__file__)) + "\\icons\\no_data.png"))
127 |
128 | def defineSignals(self):
129 | self.ui.btn_converter.clicked.connect(self.convertedExist)
130 |
131 | # self.ui.timeSlider.valueChanged.connect(self.goToFrame)
132 | self.ui.sl_opacity.valueChanged.connect(self.changeOpacity)
133 | self.ui.btn_load_seq.clicked.connect(self.load_seq)
134 | self.ui.sb_time_shift.valueChanged.connect(self.updateTimeShift)
135 | self.ui.btn_n_frame.clicked.connect(self.nextFrame)
136 | self.ui.btn_p_frame.clicked.connect(self.previousFrame)
137 | self.ui.btn_play.clicked.connect(self.playFrame)
138 | self.ui.btn_s_frame.clicked.connect(self.startFrame)
139 | self.ui.btn_e_frame.clicked.connect(self.endFrame)
140 |
141 | def nextFrame(self):
142 | mxs.stopAnimation()
143 | self.ui.btn_play.setChecked(False)
144 | mxs.sliderTime += 1
145 | self.ui.sb_time_shift.setEnabled(True)
146 |
147 | def previousFrame(self):
148 | mxs.stopAnimation()
149 | self.ui.btn_play.setChecked(False)
150 | mxs.sliderTime -= 1
151 | self.ui.sb_time_shift.setEnabled(True)
152 |
153 | def playFrame(self):
154 | if mxs.isAnimPlaying():
155 | self.ui.sb_time_shift.setEnabled(True)
156 | mxs.stopAnimation()
157 |
158 | elif not mxs.isAnimPlaying():
159 | self.ui.sb_time_shift.setEnabled(False)
160 | mxs.playAnimation()
161 |
162 | def startFrame(self):
163 | # mxs.execute("max time start")
164 | mxs.stopAnimation()
165 | mxs.sliderTime = self.time_shift
166 | self.ui.btn_play.setIcon(self.play_icon)
167 | self.ui.btn_play.setChecked(False)
168 | self.ui.sb_time_shift.setEnabled(True)
169 |
170 | def endFrame(self):
171 | # mxs.execute("max time end")
172 | mxs.stopAnimation()
173 | mxs.sliderTime = self.time_shift + (self.last_frame - 1)
174 | self.ui.btn_play.setIcon(self.play_icon)
175 | self.ui.btn_play.setChecked(False)
176 | self.ui.sb_time_shift.setEnabled(True)
177 |
178 | def updateTimeShift(self):
179 | self.time_shift = self.ui.sb_time_shift.value()
180 | self.changeTime()
181 |
182 | def load_seq(self):
183 | self.height = self.ui.viewer.height()
184 | self.width = self.ui.viewer.width()
185 |
186 | try:
187 |
188 | fname = list(QFileDialog.getOpenFileNames(self, 'Select Range OF Sequences',
189 | filter="Images (*.jpeg *.jpg *.png *.bmp)", ))
190 |
191 | if len(fname[0]) > 0:
192 | self.images = {}
193 | self.images_path = os.path.dirname(os.path.realpath(fname[0][0]))
194 |
195 | self.test = {}
196 | for i in range(int(len(fname[0]))):
197 | self.images[i] = QtGui.QPixmap(fname[0][i])
198 | self.test[i] = fname[0][i]
199 |
200 | self.last_frame = len(fname[0])
201 | self.isLoaded = True
202 | self.ui.btn_play.setEnabled(True)
203 | self.ui.btn_s_frame.setEnabled(True)
204 | self.ui.btn_p_frame.setEnabled(True)
205 | self.ui.btn_n_frame.setEnabled(True)
206 | self.ui.btn_e_frame.setEnabled(True)
207 | self.ui.sb_time_shift.setEnabled(True)
208 | self.ui.btn_loop.setEnabled(True)
209 | self.status_1()
210 | self.changeTime()
211 |
212 | else:
213 | self.status_3()
214 | self.changeTime()
215 |
216 | except:
217 | self.status_3()
218 | self.changeTime()
219 |
220 | def changeTime(self):
221 | if self.isLoaded:
222 |
223 | self.ui.maxframe.setText(str(int(mxs.currentTime)))
224 | self.ui.refframe.setText(str(int(mxs.currentTime) - self.time_shift))
225 |
226 | try:
227 | self.pixmap = self.images[int(mxs.currentTime) - self.time_shift].scaled(self.width, self.height,
228 | QtCore.Qt.KeepAspectRatio,
229 | QtCore.Qt.FastTransformation)
230 | self.ui.viewer.setPixmap(self.pixmap)
231 | self.ui.viewer.repaint()
232 | self.ui.maxframe.setText(str(int(mxs.currentTime)))
233 | self.ui.refframe.setText(str(int(mxs.currentTime) - self.time_shift))
234 | self.out_of_range = False
235 | self.last_valid_frame = int(mxs.currentTime) - self.time_shift
236 | except:
237 | out = True
238 | is_playing = mxs.isAnimPlaying()
239 | if self.isLoaded and not self.ui.btn_loop.isChecked():
240 | self.status_2()
241 |
242 | if self.isLoaded:
243 |
244 | if self.ui.btn_loop.isChecked():
245 | mxs.stopAnimation()
246 | mxs.sliderTime = self.time_shift
247 | if is_playing and out:
248 | mxs.playAnimation()
249 | self.out_of_range = True
250 |
251 | def defineIcons(self):
252 | self.icon = QtGui.QIcon(
253 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'icon.png'))
254 | self.play_icon = QtGui.QIcon(
255 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'play.png'))
256 | self.n_frame_icon = QtGui.QIcon(
257 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'n_frame.png'))
258 | self.p_frame_icon = QtGui.QIcon(
259 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'p_frame.png'))
260 | self.s_frame_icon = QtGui.QIcon(
261 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 's_frame.png'))
262 | self.e_frame_icon = QtGui.QIcon(
263 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'e_frame.png'))
264 | self.load_images_icon = QtGui.QIcon(
265 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'load_images.png'))
266 | self.loop_icon = QtGui.QIcon(
267 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'loop.png'))
268 | self.pause_icon = QtGui.QIcon(
269 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'pause.png'))
270 | self.seq_icon = QtGui.QIcon(
271 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'seq.png'))
272 |
273 | self.ui.btn_play.setIcon(self.play_icon)
274 | self.ui.btn_n_frame.setIcon(self.n_frame_icon)
275 | self.ui.btn_p_frame.setIcon(self.p_frame_icon)
276 | self.ui.btn_s_frame.setIcon(self.s_frame_icon)
277 | self.ui.btn_e_frame.setIcon(self.e_frame_icon)
278 | self.ui.btn_load_seq.setIcon(self.load_images_icon)
279 | self.ui.btn_loop.setIcon(self.loop_icon)
280 | self.ui.btn_converter.setIcon(self.seq_icon)
281 |
282 | def wheelEvent(self, event):
283 | if self.isLoaded:
284 | mxs.sliderTime += (event.delta() / 120)
285 |
286 | def resizeEvent(self, event):
287 | self.updateFrame()
288 | self.changeTime()
289 |
290 | def closeEvent(self, event):
291 | mxs.unregisterTimeCallback(self.changeTime)
292 | self.timer.stop()
293 |
294 | def updateFrame(self):
295 | if self.isLoaded:
296 | self.height = self.ui.viewer.height()
297 | self.width = self.ui.viewer.width()
298 |
299 | self.pixmap = self.images[self.last_valid_frame].scaled(self.width, self.height,
300 | QtCore.Qt.KeepAspectRatio,
301 | QtCore.Qt.FastTransformation)
302 | self.ui.viewer.setPixmap(self.pixmap)
303 |
304 | def status_1(self):
305 | self.ui.state.clear()
306 | self.ui.state.setStyleSheet('''color : #98fc03;
307 | font-size: 12px;
308 | font-family:"Comic Sans MS", cursive, sans-serif;''')
309 |
310 | self.ui.state.setText(f"{self.last_frame} images were imported")
311 | self.time_counting = True
312 | self.startTime()
313 |
314 | def status_2(self):
315 | self.ui.state.clear()
316 | self.ui.state.setStyleSheet('''color : #fcbe03;
317 | font-size: 12px;
318 | font-family:"Comic Sans MS", cursive, sans-serif;''')
319 |
320 | self.ui.state.setText(f"Out of range")
321 | self.time_counting = True
322 | self.startTime()
323 |
324 | def status_3(self):
325 | self.ui.state.clear()
326 | self.ui.state.setStyleSheet('''color : #fc5203;
327 | font-size: 12px;
328 | font-family:"Comic Sans MS", cursive, sans-serif;''')
329 |
330 | self.ui.state.setText(f"Import was canceled")
331 | self.time_counting = True
332 | self.startTime()
333 |
334 |
335 | def main():
336 | dlg = AnimRef()
337 | dlg.show()
338 |
339 |
340 | if __name__ == '__main__':
341 | main()
342 |
--------------------------------------------------------------------------------
/AnimRef/Contents/2025.ms:
--------------------------------------------------------------------------------
1 | python.Init()
2 |
3 | macroScript AnimRef category:"CGcenter" buttonText: "AnimRef"
4 | (
5 | python.ExecuteFile(getDir #publicExchangeStoreInstallPath + "\AnimRef\Contents\2025\animref.py")
6 | )
7 |
--------------------------------------------------------------------------------
/AnimRef/Contents/2025/animref.py:
--------------------------------------------------------------------------------
1 | import os
2 | import subprocess
3 | import urllib.request
4 |
5 | from PySide6 import QtCore, QtGui
6 | from PySide6.QtCore import QFile
7 | from PySide6.QtGui import QIcon, QColor
8 | from PySide6.QtUiTools import QUiLoader
9 | from PySide6.QtWidgets import QMessageBox, QVBoxLayout, QSizePolicy, QFileDialog, QPushButton, QDialog, QWidget, QLabel
10 | from pymxs import runtime as mxs
11 |
12 |
13 | class AnimRef(QDialog):
14 | def __init__(self, parent=QWidget.find(mxs.windows.getMAXHWND())):
15 | QDialog.__init__(self, parent)
16 |
17 | self.init()
18 |
19 | self.setWindowFlags(QtCore.Qt.WindowType.Window)
20 | self.resize(720, 460)
21 | self.setWindowTitle("AnimRef v1.5.2")
22 |
23 | self.defineVariables()
24 | self.defineSignals()
25 | self.defineIcons()
26 | self.start()
27 |
28 | self.setWindowIcon(self.icon)
29 |
30 | self.timer = QtCore.QTimer(self)
31 |
32 | def downloadConverter(self):
33 |
34 | converter_path = os.path.join(self.dir, 'ApplicationPlugins', 'AnimRef', 'Contents', 'converter',
35 | 'video_to_sequence.exe')
36 | download_path = "https://raw.githubusercontent.com/ShirzadBh/AnimRef/main/AnimRef/Contents/converter/video_to_sequence.exe"
37 |
38 | try:
39 | urllib.request.urlretrieve(download_path, converter_path)
40 | self.ui.state.setStyleSheet('''color : #98fc03;
41 | font-size: 12px;
42 | font-family:"Comic Sans MS", cursive, sans-serif;''')
43 |
44 | self.ui.state.setText("video_to_sequence.exe is ready!")
45 | self.time_counting = True
46 | self.startTime()
47 | except:
48 | self.ui.state.setStyleSheet('''color : #fc5203;
49 | font-size: 12px;
50 | font-family:"Comic Sans MS", cursive, sans-serif;''')
51 |
52 | self.ui.state.setText("Download failed...")
53 | self.time_counting = True
54 | self.startTime()
55 |
56 | def convertedExist(self):
57 |
58 | FILEBROWSER_PATH = os.path.join(os.getenv('WINDIR'), 'explorer.exe')
59 | path = os.path.join(self.dir, 'AnimRef', 'Contents', 'converter', 'video_to_sequence.exe')
60 | converterPath = os.path.join(self.dir, 'AnimRef', 'Contents', 'converter')
61 |
62 | if os.path.exists(path):
63 | subprocess.run([FILEBROWSER_PATH, converterPath])
64 | else:
65 | msgBox = QMessageBox()
66 | msgBox.setText("Do You Want To Download video_to_sequence.exe")
67 | msgBox.setWindowTitle("Sequence Converter")
68 | msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
69 |
70 | returnValue = msgBox.exec()
71 | if returnValue == QMessageBox.Ok:
72 | self.downloadConverter()
73 |
74 | def startTime(self):
75 | if self.time_counting:
76 | self.timer.timeout.connect(self.stopTime)
77 | self.timer.start(3000)
78 |
79 | def stopTime(self):
80 | self.ui.state.clear()
81 | self.timer.stop()
82 | self.time_counting = False
83 |
84 | def init(self):
85 |
86 | self.dir = mxs.getDir(mxs.name('publicExchangeStoreInstallPath'))
87 | loader = QUiLoader()
88 | ui_file_path = os.path.join(self.dir, 'AnimRef', 'Contents', 'interface', 'interface.ui')
89 | ui_file = QFile(ui_file_path)
90 | ui_file.open(QFile.ReadOnly)
91 | self.ui = loader.load(ui_file, self)
92 | ui_file.close()
93 | layout = QVBoxLayout()
94 | layout.addWidget(self.ui)
95 | layout.setContentsMargins(4, 4, 4, 4)
96 | self.setLayout(layout)
97 |
98 | def start(self):
99 | self.ui.viewer.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
100 | self.pixmap = self.no_image.scaled(400, 200, QtCore.Qt.KeepAspectRatio, QtCore.Qt.FastTransformation)
101 | self.ui.viewer.setPixmap(self.pixmap)
102 | mxs.registerTimeCallback(self.changeTime)
103 |
104 | def changeOpacity(self):
105 | self.opacity = self.ui.sl_opacity.value() / 100
106 | self.setWindowOpacity(self.opacity)
107 |
108 | def defineVariables(self):
109 | self.last_valid_frame = 0
110 | self.time_counting = False
111 | self.out_of_range = False
112 | self.pixmap = None
113 | self.isLoaded = False
114 | self.current_time = int(mxs.currentTime)
115 | self.time_shift = self.ui.sb_time_shift.value()
116 | self.time = self.current_time + self.time_shift
117 | self.height = self.ui.viewer.height()
118 | self.width = self.ui.viewer.width()
119 | self.images_backup = {}
120 | self.images = {}
121 | self.opacity = 1
122 | self.images_path = None
123 | self.last_frame = 0
124 | self.previous_frame = 0
125 | self.no_image = QtGui.QPixmap(
126 | os.path.join(os.path.dirname(os.path.realpath(__file__)) + "\\icons\\no_data.png"))
127 |
128 | def defineSignals(self):
129 | self.ui.btn_converter.clicked.connect(self.convertedExist)
130 |
131 | # self.ui.timeSlider.valueChanged.connect(self.goToFrame)
132 | self.ui.sl_opacity.valueChanged.connect(self.changeOpacity)
133 | self.ui.btn_load_seq.clicked.connect(self.load_seq)
134 | self.ui.sb_time_shift.valueChanged.connect(self.updateTimeShift)
135 | self.ui.btn_n_frame.clicked.connect(self.nextFrame)
136 | self.ui.btn_p_frame.clicked.connect(self.previousFrame)
137 | self.ui.btn_play.clicked.connect(self.playFrame)
138 | self.ui.btn_s_frame.clicked.connect(self.startFrame)
139 | self.ui.btn_e_frame.clicked.connect(self.endFrame)
140 |
141 | def nextFrame(self):
142 | mxs.stopAnimation()
143 | self.ui.btn_play.setChecked(False)
144 | mxs.sliderTime += 1
145 | self.ui.sb_time_shift.setEnabled(True)
146 |
147 | def previousFrame(self):
148 | mxs.stopAnimation()
149 | self.ui.btn_play.setChecked(False)
150 | mxs.sliderTime -= 1
151 | self.ui.sb_time_shift.setEnabled(True)
152 |
153 | def playFrame(self):
154 | if mxs.isAnimPlaying():
155 | self.ui.sb_time_shift.setEnabled(True)
156 | mxs.stopAnimation()
157 |
158 | elif not mxs.isAnimPlaying():
159 | self.ui.sb_time_shift.setEnabled(False)
160 | mxs.playAnimation()
161 |
162 | def startFrame(self):
163 | # mxs.execute("max time start")
164 | mxs.stopAnimation()
165 | mxs.sliderTime = self.time_shift
166 | self.ui.btn_play.setIcon(self.play_icon)
167 | self.ui.btn_play.setChecked(False)
168 | self.ui.sb_time_shift.setEnabled(True)
169 |
170 | def endFrame(self):
171 | # mxs.execute("max time end")
172 | mxs.stopAnimation()
173 | mxs.sliderTime = self.time_shift + (self.last_frame - 1)
174 | self.ui.btn_play.setIcon(self.play_icon)
175 | self.ui.btn_play.setChecked(False)
176 | self.ui.sb_time_shift.setEnabled(True)
177 |
178 | def updateTimeShift(self):
179 | self.time_shift = self.ui.sb_time_shift.value()
180 | self.changeTime()
181 |
182 | def load_seq(self):
183 | self.height = self.ui.viewer.height()
184 | self.width = self.ui.viewer.width()
185 |
186 | try:
187 |
188 | fname = list(QFileDialog.getOpenFileNames(self, 'Select Range OF Sequences',
189 | filter="Images (*.jpeg *.jpg *.png *.bmp)", ))
190 |
191 | if len(fname[0]) > 0:
192 | self.images = {}
193 | self.images_path = os.path.dirname(os.path.realpath(fname[0][0]))
194 |
195 | self.test = {}
196 | for i in range(int(len(fname[0]))):
197 | self.images[i] = QtGui.QPixmap(fname[0][i])
198 | self.test[i] = fname[0][i]
199 |
200 | self.last_frame = len(fname[0])
201 | self.isLoaded = True
202 | self.ui.btn_play.setEnabled(True)
203 | self.ui.btn_s_frame.setEnabled(True)
204 | self.ui.btn_p_frame.setEnabled(True)
205 | self.ui.btn_n_frame.setEnabled(True)
206 | self.ui.btn_e_frame.setEnabled(True)
207 | self.ui.sb_time_shift.setEnabled(True)
208 | self.ui.btn_loop.setEnabled(True)
209 | self.status_1()
210 | self.changeTime()
211 |
212 | else:
213 | self.status_3()
214 | self.changeTime()
215 |
216 | except:
217 | self.status_3()
218 | self.changeTime()
219 |
220 | def changeTime(self):
221 | if self.isLoaded:
222 |
223 | self.ui.maxframe.setText(str(int(mxs.currentTime)))
224 | self.ui.refframe.setText(str(int(mxs.currentTime) - self.time_shift))
225 |
226 | try:
227 | self.pixmap = self.images[int(mxs.currentTime) - self.time_shift].scaled(self.width, self.height,
228 | QtCore.Qt.KeepAspectRatio,
229 | QtCore.Qt.FastTransformation)
230 | self.ui.viewer.setPixmap(self.pixmap)
231 | self.ui.viewer.repaint()
232 | self.ui.maxframe.setText(str(int(mxs.currentTime)))
233 | self.ui.refframe.setText(str(int(mxs.currentTime) - self.time_shift))
234 | self.out_of_range = False
235 | self.last_valid_frame = int(mxs.currentTime) - self.time_shift
236 | except:
237 | out = True
238 | is_playing = mxs.isAnimPlaying()
239 | if self.isLoaded and not self.ui.btn_loop.isChecked():
240 | self.status_2()
241 |
242 | if self.isLoaded:
243 |
244 | if self.ui.btn_loop.isChecked():
245 | mxs.stopAnimation()
246 | mxs.sliderTime = self.time_shift
247 | if is_playing and out:
248 | mxs.playAnimation()
249 | self.out_of_range = True
250 |
251 | def defineIcons(self):
252 | self.icon = QtGui.QIcon(
253 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'icon.png'))
254 | self.play_icon = QtGui.QIcon(
255 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'play.png'))
256 | self.n_frame_icon = QtGui.QIcon(
257 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'n_frame.png'))
258 | self.p_frame_icon = QtGui.QIcon(
259 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'p_frame.png'))
260 | self.s_frame_icon = QtGui.QIcon(
261 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 's_frame.png'))
262 | self.e_frame_icon = QtGui.QIcon(
263 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'e_frame.png'))
264 | self.load_images_icon = QtGui.QIcon(
265 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'load_images.png'))
266 | self.loop_icon = QtGui.QIcon(
267 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'loop.png'))
268 | self.pause_icon = QtGui.QIcon(
269 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'pause.png'))
270 | self.seq_icon = QtGui.QIcon(
271 | os.path.join(self.dir, 'AnimRef', 'Contents', 'icons', 'seq.png'))
272 |
273 | self.ui.btn_play.setIcon(self.play_icon)
274 | self.ui.btn_n_frame.setIcon(self.n_frame_icon)
275 | self.ui.btn_p_frame.setIcon(self.p_frame_icon)
276 | self.ui.btn_s_frame.setIcon(self.s_frame_icon)
277 | self.ui.btn_e_frame.setIcon(self.e_frame_icon)
278 | self.ui.btn_load_seq.setIcon(self.load_images_icon)
279 | self.ui.btn_loop.setIcon(self.loop_icon)
280 | self.ui.btn_converter.setIcon(self.seq_icon)
281 |
282 | def wheelEvent(self, event):
283 | if self.isLoaded:
284 | mxs.sliderTime += (event.delta() / 120)
285 |
286 | def resizeEvent(self, event):
287 | self.updateFrame()
288 | self.changeTime()
289 |
290 | def closeEvent(self, event):
291 | mxs.unregisterTimeCallback(self.changeTime)
292 | self.timer.stop()
293 |
294 | def updateFrame(self):
295 | if self.isLoaded:
296 | self.height = self.ui.viewer.height()
297 | self.width = self.ui.viewer.width()
298 |
299 | self.pixmap = self.images[self.last_valid_frame].scaled(self.width, self.height,
300 | QtCore.Qt.KeepAspectRatio,
301 | QtCore.Qt.FastTransformation)
302 | self.ui.viewer.setPixmap(self.pixmap)
303 |
304 | def status_1(self):
305 | self.ui.state.clear()
306 | self.ui.state.setStyleSheet('''color : #98fc03;
307 | font-size: 12px;
308 | font-family:"Comic Sans MS", cursive, sans-serif;''')
309 |
310 | self.ui.state.setText(f"{self.last_frame} images were imported")
311 | self.time_counting = True
312 | self.startTime()
313 |
314 | def status_2(self):
315 | self.ui.state.clear()
316 | self.ui.state.setStyleSheet('''color : #fcbe03;
317 | font-size: 12px;
318 | font-family:"Comic Sans MS", cursive, sans-serif;''')
319 |
320 | self.ui.state.setText(f"Out of range")
321 | self.time_counting = True
322 | self.startTime()
323 |
324 | def status_3(self):
325 | self.ui.state.clear()
326 | self.ui.state.setStyleSheet('''color : #fc5203;
327 | font-size: 12px;
328 | font-family:"Comic Sans MS", cursive, sans-serif;''')
329 |
330 | self.ui.state.setText(f"Import was canceled")
331 | self.time_counting = True
332 | self.startTime()
333 |
334 |
335 | def main():
336 | dlg = AnimRef()
337 | dlg.show()
338 |
339 |
340 | if __name__ == '__main__':
341 | main()
342 |
--------------------------------------------------------------------------------
/AnimRef/Contents/converter/video_to_sequence.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/converter/video_to_sequence.exe
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/e_frame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/e_frame.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/icon.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/load_images.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/load_images.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/loop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/loop.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/n_frame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/n_frame.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/no_data.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/no_data.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/p_frame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/p_frame.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/pause.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/play.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/s_frame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/s_frame.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/seq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/seq.png
--------------------------------------------------------------------------------
/AnimRef/Contents/icons/soft-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/AnimRef/Contents/icons/soft-icon.png
--------------------------------------------------------------------------------
/AnimRef/Contents/interface/interface.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 722
10 | 617
11 |
12 |
13 |
14 |
15 | 340
16 | 240
17 |
18 |
19 |
20 | Form
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | QTabWidget::pane { /* The tab widget frame */
41 | }
42 |
43 | QTabWidget::tab-bar {
44 | /* move to the right by 5px */
45 | background: black;
46 |
47 | }
48 |
49 | /* Style the tab using the tab sub-control. Note that
50 | it reads QTabBar _not_ QTabWidget */
51 | QTabBar::tab {
52 | color: white;
53 | background: #363636;
54 | padding: 6px 26px 6px 26px;
55 | }
56 |
57 |
58 | QTabBar::tab:selected, QTabBar::tab:hover {
59 | background: #5b5b5b;
60 | }
61 |
62 | QTabBar::tab:selected {
63 | border-color: #9B9B9B;
64 | }
65 |
66 | QTabBar::tab:!selected {
67 | border-color: #474747;
68 |
69 | }
70 |
71 | /* make use of negative margins for overlapping tabs */
72 | QTabBar::tab:selected {
73 | background: 474747;
74 |
75 | /* expand/overlap to the left and right by 4px */
76 |
77 | }
78 |
79 | QTabBar::tab:first:selected {
80 | margin-left: 0; /* the first selected tab has nothing to overlap with on the left */
81 | }
82 |
83 | QTabBar::tab:last:selected {
84 | margin-right: 0; /* the last selected tab has nothing to overlap with on the right */
85 | }
86 |
87 | QTabBar::tab:only-one {
88 | margin: 0; /* if there is only one tab, we don't want overlapping margins */
89 | }
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | QMenuBar
107 | {
108 | color: #fff;
109 |
110 | background-color: #363636;
111 | }
112 |
113 | QMenuBar::item
114 | {
115 | color: #fff;
116 |
117 | background-color: #474747;
118 | }
119 |
120 | QMenuBar::item:selected
121 | {
122 | color: #fff;
123 |
124 | background-color: #363636;
125 | }
126 |
127 | QMenu
128 | {
129 | background-color: #363636;
130 | color: #fff;
131 |
132 | }
133 |
134 |
135 | QMenu::item:selected
136 | {
137 | background-color: #fff;
138 | color: #34495e;
139 |
140 | }
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | QToolBar {
159 | background: #363636;
160 | spacing: 3px; /* spacing between items in the tool bar */
161 | }
162 |
163 | QToolBar::handle {
164 | /*
165 | background: #363636;
166 | */
167 | }
168 |
169 |
170 |
171 |
172 | -
173 |
174 |
175 |
176 | 0
177 | 0
178 |
179 |
180 |
181 | background-color: #333333
182 |
183 |
184 |
185 |
186 |
187 | false
188 |
189 |
190 | Qt::AlignCenter
191 |
192 |
193 |
194 | -
195 |
196 |
-
197 |
198 |
-
199 |
200 |
201 | false
202 |
203 |
204 |
205 | 0
206 | 26
207 |
208 |
209 |
210 |
211 | 16777215
212 | 26
213 |
214 |
215 |
216 | QPushButton
217 | {
218 | color: white;
219 | font-size: 12px;
220 | padding: 20px 4px 20px 4px;
221 | border-radius: 2px;
222 | background-color: #5b5b5b;
223 | }
224 |
225 | QPushButton::hover
226 | {
227 | background-color: #888888;
228 | }
229 |
230 | QPushButton::pressed
231 | {
232 | background-color: #4b4b4b;
233 | }
234 |
235 |
236 |
237 | QPushButton::checked
238 | {
239 | background-color: #E84A5F;
240 | }
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 | -
255 |
256 |
257 | false
258 |
259 |
260 |
261 | 0
262 | 26
263 |
264 |
265 |
266 |
267 | 16777215
268 | 26
269 |
270 |
271 |
272 | QPushButton
273 | {
274 | color: white;
275 | font-size: 12px;
276 | padding: 20px 4px 20px 4px;
277 | border-radius: 2px;
278 | background-color: #5b5b5b;
279 | }
280 |
281 | QPushButton::hover
282 | {
283 | background-color: #888888;
284 | }
285 |
286 | QPushButton::pressed
287 | {
288 | background-color: #4b4b4b;
289 | }
290 |
291 |
292 |
293 | QPushButton::checked
294 | {
295 | background-color: #E84A5F;
296 | }
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 | -
311 |
312 |
313 | false
314 |
315 |
316 |
317 | 0
318 | 26
319 |
320 |
321 |
322 |
323 | 16777215
324 | 26
325 |
326 |
327 |
328 | QPushButton
329 | {
330 | color: white;
331 | font-size: 12px;
332 | padding: 20px 4px 20px 4px;
333 | border-radius: 2px;
334 | background-color: #5b5b5b;
335 | }
336 |
337 | QPushButton::hover
338 | {
339 | background-color: #888888;
340 | }
341 |
342 | QPushButton::pressed
343 | {
344 | background-color: #4b4b4b;
345 | }
346 |
347 |
348 |
349 | QPushButton::checked
350 | {
351 | background-color: #E84A5F;
352 | }
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 | false
366 |
367 |
368 |
369 | -
370 |
371 |
372 | false
373 |
374 |
375 |
376 | 0
377 | 26
378 |
379 |
380 |
381 |
382 | 16777215
383 | 26
384 |
385 |
386 |
387 | QPushButton
388 | {
389 | color: white;
390 | font-size: 12px;
391 | padding: 20px 4px 20px 4px;
392 | border-radius: 2px;
393 | background-color: #5b5b5b;
394 | }
395 |
396 | QPushButton::hover
397 | {
398 | background-color: #888888;
399 | }
400 |
401 | QPushButton::pressed
402 | {
403 | background-color: #4b4b4b;
404 | }
405 |
406 |
407 |
408 | QPushButton::checked
409 | {
410 | background-color: #E84A5F;
411 | }
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 | -
426 |
427 |
428 | false
429 |
430 |
431 |
432 | 0
433 | 26
434 |
435 |
436 |
437 |
438 | 16777215
439 | 26
440 |
441 |
442 |
443 | QPushButton
444 | {
445 | color: white;
446 | font-size: 12px;
447 | padding: 20px 4px 20px 4px;
448 | border-radius: 2px;
449 | background-color: #5b5b5b;
450 | }
451 |
452 | QPushButton::hover
453 | {
454 | background-color: #888888;
455 | }
456 |
457 | QPushButton::pressed
458 | {
459 | background-color: #4b4b4b;
460 | }
461 |
462 |
463 |
464 | QPushButton::checked
465 | {
466 | background-color: #E84A5F;
467 | }
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 | -
482 |
483 |
484 | false
485 |
486 |
487 |
488 | 0
489 | 26
490 |
491 |
492 |
493 |
494 | 16777215
495 | 26
496 |
497 |
498 |
499 | QPushButton
500 | {
501 | color: white;
502 | font-size: 12px;
503 | padding: 20px 4px 20px 4px;
504 | border-radius: 2px;
505 | background-color: #5b5b5b;
506 | }
507 |
508 | QPushButton::hover
509 | {
510 | background-color: #888888;
511 | }
512 |
513 | QPushButton::pressed
514 | {
515 | background-color: #424242;
516 | }
517 |
518 |
519 |
520 | QPushButton::checked
521 | {
522 | background-color:#333333;
523 | }
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 | true
537 |
538 |
539 |
540 | -
541 |
542 |
543 | false
544 |
545 |
546 |
547 | 46
548 | 26
549 |
550 |
551 |
552 |
553 | 46
554 | 26
555 |
556 |
557 |
558 | Set Start Frame Of Reference
559 |
560 |
561 | QSpinBox {
562 | background-color: #333333;
563 |
564 | font-size: 12px;
565 | font-family:"Comic Sans MS", cursive, sans-serif;
566 | }
567 |
568 |
569 |
570 | QSpinBox::selected {
571 | background-color: #333333;
572 | border-radius: 5px;
573 | }
574 |
575 |
576 |
577 |
578 |
579 | false
580 |
581 |
582 | Qt::AlignCenter
583 |
584 |
585 | QAbstractSpinBox::NoButtons
586 |
587 |
588 |
589 |
590 |
591 | -10000000
592 |
593 |
594 | 10000000
595 |
596 |
597 |
598 | -
599 |
600 |
-
601 |
602 |
603 |
604 | 0
605 | 0
606 |
607 |
608 |
609 | font-size: 12px;
610 | font-family:"Comic Sans MS", cursive, sans-serif;
611 |
612 | padding-left: 4px;
613 |
614 |
615 | 0
616 |
617 |
618 |
619 | -
620 |
621 |
622 |
623 | 0
624 | 0
625 |
626 |
627 |
628 | font-size: 12px;
629 | font-family:"Comic Sans MS", cursive, sans-serif;
630 |
631 |
632 | :
633 |
634 |
635 |
636 | -
637 |
638 |
639 |
640 | 0
641 | 0
642 |
643 |
644 |
645 | font-size: 12px;
646 | font-family:"Comic Sans MS", cursive, sans-serif;
647 |
648 |
649 | padding-right: 4px;
650 |
651 |
652 |
653 | 0
654 |
655 |
656 |
657 | -
658 |
659 |
660 |
661 | 40
662 | 0
663 |
664 |
665 |
666 | font-size: 14px;
667 | font-family:"Comic Sans MS", cursive, sans-serif;
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 | -
677 |
678 |
679 | Qt::Horizontal
680 |
681 |
682 |
683 | 80
684 | 20
685 |
686 |
687 |
688 |
689 | -
690 |
691 |
692 |
693 | 50
694 | 26
695 |
696 |
697 |
698 |
699 | 100
700 | 26
701 |
702 |
703 |
704 | Change The Window Opacity
705 |
706 |
707 | QSlider::groove:horizontal {
708 | background: #333333;
709 | }
710 |
711 | QSlider::handle:horizontal {
712 | background: #5b5b5b;
713 | width: 16px;
714 |
715 | }
716 |
717 |
718 | 30
719 |
720 |
721 | 100
722 |
723 |
724 | 2
725 |
726 |
727 | 100
728 |
729 |
730 | Qt::Horizontal
731 |
732 |
733 |
734 | -
735 |
736 |
737 | true
738 |
739 |
740 |
741 | 0
742 | 26
743 |
744 |
745 |
746 |
747 | 16777215
748 | 26
749 |
750 |
751 |
752 | QPushButton
753 | {
754 | color: white;
755 | font-size: 12px;
756 | padding: 20px 4px 20px 4px;
757 | border-radius: 2px;
758 | background-color: #5b5b5b;
759 | }
760 |
761 | QPushButton::hover
762 | {
763 | background-color: #888888;
764 | }
765 |
766 | QPushButton::pressed
767 | {
768 | background-color: #4b4b4b;
769 | }
770 |
771 |
772 |
773 | QPushButton::checked
774 | {
775 | background-color: #E84A5F;
776 | }
777 |
778 |
779 |
780 |
781 |
782 |
783 |
784 |
785 |
786 |
787 |
788 |
789 |
790 | -
791 |
792 |
793 | true
794 |
795 |
796 |
797 | 0
798 | 26
799 |
800 |
801 |
802 |
803 | 16777215
804 | 26
805 |
806 |
807 |
808 | QPushButton
809 | {
810 | color: white;
811 | font-size: 12px;
812 | padding: 20px 4px 20px 4px;
813 | border-radius: 2px;
814 | background-color: #5b5b5b;
815 | }
816 |
817 | QPushButton::hover
818 | {
819 | background-color: #888888;
820 | }
821 |
822 | QPushButton::pressed
823 | {
824 | background-color: #4b4b4b;
825 | }
826 |
827 |
828 |
829 | QPushButton::checked
830 | {
831 | background-color: #E84A5F;
832 | }
833 |
834 |
835 |
836 |
837 |
838 |
839 |
840 |
841 |
842 |
843 |
844 |
845 | false
846 |
847 |
848 |
849 | -
850 |
851 |
852 |
853 |
854 |
855 |
856 |
857 |
858 |
859 |
860 |
861 |
--------------------------------------------------------------------------------
/AnimRef/PackageContents.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Shirzad Bahrami
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/One-Click Installation.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | set productName=AnimRef
4 | set developerName=Shirzad Bahrami
5 | set websiteAddress=www.shirzadbahrami.com
6 |
7 | set minVersion=2018
8 | set maxVersion=2025
9 |
10 | set productVer=1.5.2
11 |
12 | set releaseDate=2020-10-17
13 | set lastUpdate=2024-09-02
14 |
15 | set fileName=AnimRef.zip
16 | set installationPath=/Autodesk/ApplicationPlugins
17 |
18 | echo %productName% Developed By: %developerName%
19 | echo Version: %productVer%
20 | echo Website: %websiteAddress%
21 | echo.
22 | echo Supported Version: %minVersion% - %maxVersion%
23 | echo Release: %releaseDate%
24 | echo Update: %lastUpdate%
25 |
26 | echo.
27 | pause>nul|set/p =Press Any Key To Install "%productName%" On 3Ds Max From "%minVersion%" to "%maxVersion%"...
28 | echo.
29 | cls
30 |
31 | powershell -Command "Expand-Archive -Force "%batdir%%fileName% "%ProgramData%%installationPath%" "
32 |
33 | echo "%productName%" Installed successfully, Hope You Enjoy...
34 | ping -n 4 localhost >nul
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## AnimRef - Sequence Loader For 3Ds Max
2 |
3 |
4 | 
5 |
6 | ---
7 |
8 | With AnimRef you can load and play image sequences directly in the 3Ds Max user-interface. There are a few parameters to keep it simple and fast for animators:
9 |
10 | ---
11 | ### AnimRef
12 | - Video to Sequence Converter:
13 | 
14 | - Viewer Update
15 | - New UI design
16 | - MessageBox Timer
17 | - Load image sequences in the desired range
18 | - Time shift value
19 | - 3Ds Max synced time slider
20 | - Window opacity slider
21 | ---
22 |
23 | | Supported Formats | Description |
24 | | ----------- | ----------- |
25 | | BMP | Windows Bitmap |
26 | | JPG | Joint Photographic Experts Group |
27 | | JPEG | Joint Photographic Experts Group |
28 | | PNG | Portable Network Graphics |
29 |
30 |
31 | >Easy installation:
32 | Run "One-Click Installation.bat".
33 |
34 | >installation:
35 | Unzip the "AnimRef.zip" inside "C://ProgramData//Autodesk//ApplicationPlugins".
36 |
37 |
38 | >How To Run:
39 | Now, it's a MacroScript, which you can assign a shortcut to it or search it using "X" in 3Ds Max.
40 |
41 | >Supported Version:
42 |
43 | 2018 - 2019 - 2020 - 2021 - 2022 - 2023 - 2024 - 2025
44 |
--------------------------------------------------------------------------------
/screen/converter.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/screen/converter.gif
--------------------------------------------------------------------------------
/screen/interface.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ShirzadBh/AnimRef/c1a1d9088f804ad9913951613542a61f6cd98f30/screen/interface.jpg
--------------------------------------------------------------------------------