@nexrender/core 1.31.0 → 1.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/readme.md +7 -0
- package/src/assets/commandLineRenderer-2022.jsx +1130 -0
- package/src/assets/{commandLineRenderer.jsx → commandLineRenderer-default.jsx} +12 -12
- package/src/helpers/autofind.js +6 -0
- package/src/helpers/patch.js +9 -1
- package/src/index.js +1 -0
- package/src/tasks/actions.js +7 -3
- package/src/tasks/render.js +13 -3
|
@@ -0,0 +1,1130 @@
|
|
|
1
|
+
module.exports = /*syntax:js*/ `// Command line renderer for After Effects. (nexrender-patch-v1.0.3)
|
|
2
|
+
|
|
3
|
+
// This function constructs an AECommandLineRenderer object.
|
|
4
|
+
// One and only one of these will be created to perform rendering tasks
|
|
5
|
+
// at the end of this file.
|
|
6
|
+
//
|
|
7
|
+
// The constructor has 3 sections:
|
|
8
|
+
// [1] define all the variable-type attributes used by this class;
|
|
9
|
+
// [2] define all the functions used by this class;
|
|
10
|
+
// [3] assign all the functions to be method-type attributes.
|
|
11
|
+
//
|
|
12
|
+
function AECommandLineRenderer() {
|
|
13
|
+
// [1] define all the variable-type attributes used by this class
|
|
14
|
+
//
|
|
15
|
+
// Input before parsing
|
|
16
|
+
//
|
|
17
|
+
this.inArgs = null;
|
|
18
|
+
//
|
|
19
|
+
// Input after parsing
|
|
20
|
+
//
|
|
21
|
+
this.in_project_path = null;
|
|
22
|
+
this.in_teamproject_name = null;
|
|
23
|
+
this.in_comp_name = null;
|
|
24
|
+
this.in_rq_index = null;
|
|
25
|
+
this.in_RStemplate = null;
|
|
26
|
+
this.in_RSsettings = null;
|
|
27
|
+
this.in_OMtemplate = null;
|
|
28
|
+
this.in_OMsettings = null;
|
|
29
|
+
this.in_output_path = null;
|
|
30
|
+
this.in_logfile_path = null;
|
|
31
|
+
this.in_start_frame = null;
|
|
32
|
+
this.in_end_frame = null;
|
|
33
|
+
this.in_increment = null;
|
|
34
|
+
this.in_image_cache_percent = null;
|
|
35
|
+
this.in_max_mem_percent = null;
|
|
36
|
+
this.in_verbose_flag = null;
|
|
37
|
+
this.in_close_flag = null;
|
|
38
|
+
this.in_sound_flag = null;
|
|
39
|
+
this.in_port_address = null;
|
|
40
|
+
this.in_stop_on_missing_frame = true;
|
|
41
|
+
this.in_mfr_enable = null;
|
|
42
|
+
this.in_mfr_max_cpu_percent = null;
|
|
43
|
+
this.in_script_path = null;
|
|
44
|
+
//
|
|
45
|
+
// Exit codes:
|
|
46
|
+
//
|
|
47
|
+
this.EXIT_OK = 0;
|
|
48
|
+
this.EXIT_FAILURE_CODE_FROM_APP = 1;
|
|
49
|
+
this.EXIT_SHOW_USAGE = 2;
|
|
50
|
+
this.EXIT_SYNTAX_ERROR = 3;
|
|
51
|
+
this.EXIT_SYNTAX_ERROR_USER_LOG = 4;
|
|
52
|
+
this.EXIT_OTHER_SCRIPTING_ERROR = 5;
|
|
53
|
+
this.EXIT_OTHER_SCRIPTING_ERROR_USER_LOG = 6;
|
|
54
|
+
this.EXIT_AERENDER_RUNTIME = 7;
|
|
55
|
+
this.EXIT_AERENDER_RUNTIME_USER_LOG = 8;
|
|
56
|
+
this.EXIT_AE_RUNTIME = 9;
|
|
57
|
+
this.EXIT_AE_RUNTIME_USER_LOG = 10;
|
|
58
|
+
this.EXIT_CANNOT_OPEN_SOCKET = 11;
|
|
59
|
+
this.EXIT_CODE_NO_LONGER_IN_USE = 12;
|
|
60
|
+
//
|
|
61
|
+
// Exit code message prefixes:
|
|
62
|
+
//
|
|
63
|
+
this.EXIT_MSG_PREFIX = new Array(
|
|
64
|
+
"", // EXIT_OK
|
|
65
|
+
"ERROR: ", // EXIT_FAILURE_CODE_FROM_APP
|
|
66
|
+
"USAGE: ", // EXIT_SHOW_USAGE
|
|
67
|
+
"SYNTAX ERROR: ", // EXIT_SYNTAX_ERROR
|
|
68
|
+
"SYNTAX ERROR: ", // EXIT_SYNTAX_ERROR_USER_LOG
|
|
69
|
+
"ERROR: ", // EXIT_OTHER_SCRIPTING_ERROR
|
|
70
|
+
"ERROR: ", // EXIT_OTHER_SCRIPTING_ERROR_USER_LOG
|
|
71
|
+
"ERROR: ", // EXIT_AERENDER_ERROR
|
|
72
|
+
"ERROR: ", // EXIT_AERENDER_ERROR_USER_LOG
|
|
73
|
+
"ERROR: ", // EXIT_AE_RUNTIME
|
|
74
|
+
"ERROR: ", // EXIT_AE_RUNTIME_USER_LOG
|
|
75
|
+
"ERROR: ", // EXIT_CANNOT_OPEN_SOCKET
|
|
76
|
+
"", // EXIT_CODE_NO_LONGER_IN_USE
|
|
77
|
+
);
|
|
78
|
+
//
|
|
79
|
+
// Messages:
|
|
80
|
+
//
|
|
81
|
+
this.MSG_NONE = "";
|
|
82
|
+
this.MSG_NOT_HANDLED_HERE = "reported by another script or AE runtime.";
|
|
83
|
+
this.MSG_SHOW_USAGE = "";
|
|
84
|
+
this.MSG_TRIED_TO_PARSE_UNDEFINED = "aerender tried to parse an undefined argument.";
|
|
85
|
+
this.MSG_UNDEFINED_VALUE_FOR_FLAG = "no value given for flag: ";
|
|
86
|
+
this.MSG_BAD_FLAG = "Illegal argument flag: ";
|
|
87
|
+
this.MSG_NO_PROJECT = "No project provided and no project open.";
|
|
88
|
+
this.MSG_BAD_VERBOSE_FLAG = "Bad value for -verbose.";
|
|
89
|
+
this.MSG_BAD_CLOSE_FLAG = "Bad value for -close.";
|
|
90
|
+
this.MSG_BAD_SOUND_FLAG = "Bad value for -sound.";
|
|
91
|
+
this.MSG_BAD_MFR_FLAG = "Bad value for -mfr.";
|
|
92
|
+
this.MSG_BAD_INCREMENT = "Bad value for -increment. Must be between 1 and 100, inclusive.";
|
|
93
|
+
this.MSG_COMP_NOT_FOUND = "No comp was found with the given name.";
|
|
94
|
+
this.MSG_RQINDEX_NOT_FOUND = "No render queue item was found with the given index.";
|
|
95
|
+
this.MSG_AE_RUNTIME = "Runtime error in After Effects.";
|
|
96
|
+
this.MSG_ADDING_TO_RQ = "PROGRESS: Adding specified comp to Render Queue";
|
|
97
|
+
this.MSG_NEEDS_OUTPUT = "Specified render queue item needs output file but none provided.";
|
|
98
|
+
this.MSG_RS_TEMPLATE_NOT_FOUND = "No render settings template was found with the given name.";
|
|
99
|
+
this.MSG_OM_TEMPLATE_NOT_FOUND = "No output module template was found with the given name.";
|
|
100
|
+
this.MSG_RS_SETTINGS_NO_RQI = "Can't use -renderSettings because no render queue item was specified.";
|
|
101
|
+
this.MSG_OM_SETTINGS_NO_RQI = "Can't use -outputSettings because no render queue item was specified.";
|
|
102
|
+
this.MSG_CAN_NOT_OPEN_SOCKET = "Can not open socket.";
|
|
103
|
+
this.MSG_NO_COMP_YES_TEMPLATE = "WARNING: -RStemplate argument ignored since no -comp or -rqindex provided.";
|
|
104
|
+
this.MSG_NO_COMP_YES_OMTEMPLATE = "WARNING: -OMtemplate argument ignored since no -comp or -rqindex provided.";
|
|
105
|
+
this.MSG_NO_COMP_YES_OUTPUT = "WARNING: -output argument ignored since no -comp or -rqindex provided.";
|
|
106
|
+
this.MSG_NO_COMP_YES_START_OR_END = "WARNING: -s and/or -e arguments ignored since no -comp or -rqindex provided.";
|
|
107
|
+
this.MSG_NO_COMP_YES_INCREMENT = "WARNING: -i argument ignored since no -comp or -rqindex provided.";
|
|
108
|
+
this.MSG_SKIPPING_WILL_CONTINUE = "INFO: Skipping render queue item with correct comp name but marked to continue from a partly complete render.";
|
|
109
|
+
this.MSG_RENDER_ABORTED = "INFO: Render aborted.";
|
|
110
|
+
this.MSG_SCRIPT_CAN_NOT_EXEC = "aerender ERROR: Error executing script: ";
|
|
111
|
+
this.MSG_SCRIPT_CAN_NOT_OPEN = "aerender ERROR: Can not open script file. Make sure path is correct: ";
|
|
112
|
+
|
|
113
|
+
// These three don't get the prefix printed since they are not exit messages
|
|
114
|
+
this.MSG_LOG_DIR_NO_EXISTS = "aerender ERROR: Directory specified for log file does not exist: ";
|
|
115
|
+
this.MSG_LOG_DIR_NOT_A_DIR = "aerender ERROR: Directory specified for log file is a file, not a directory: ";
|
|
116
|
+
this.MSG_LOG_CAN_NOT_OPEN = "aerender ERROR: Can not open log file. Try checking write protection of directory: ";
|
|
117
|
+
//
|
|
118
|
+
// Variables for rendering
|
|
119
|
+
//
|
|
120
|
+
this.log_file = null;
|
|
121
|
+
this.has_user_log_file = false;
|
|
122
|
+
this.is_verbose_mode = true;
|
|
123
|
+
this.saved_sound_setting = null;
|
|
124
|
+
this.my_sound_setting = null;
|
|
125
|
+
|
|
126
|
+
// [2] define all the functions used by this class
|
|
127
|
+
//
|
|
128
|
+
// Report an error. This writes errors to the log file, if present.
|
|
129
|
+
// This is called from the context of the application, so we
|
|
130
|
+
// need to precede variable names with gAECommandLineRenderer
|
|
131
|
+
//
|
|
132
|
+
function checkParentDied() {
|
|
133
|
+
var result = false;
|
|
134
|
+
if (gAECommandLineRenderer.log_file instanceof Socket) {
|
|
135
|
+
if (!gAECommandLineRenderer.log_file.connected) {
|
|
136
|
+
app.project.renderQueue.stopRendering();
|
|
137
|
+
result = true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function my_onError(error_string, severity_string) {
|
|
144
|
+
// This method is called with a variety of types of messages.
|
|
145
|
+
// The severity_string tells us what kind.
|
|
146
|
+
// Choices are:
|
|
147
|
+
// NAKED, INFO, WARNING, PROBLEM, FATAL, PROGRESS, and DEBUG
|
|
148
|
+
|
|
149
|
+
// Two of these, PROBLEM and FATAL, are errors that should cause us to change
|
|
150
|
+
// the exit code:
|
|
151
|
+
checkParentDied();
|
|
152
|
+
|
|
153
|
+
if (severity_string == "PROBLEM" || severity_string == "FATAL") {
|
|
154
|
+
// These two errors cause us to change the exit code.
|
|
155
|
+
// We don't write an error or throw here, because we got here as part of a thrown
|
|
156
|
+
// error already, and the message will be printed as part of the catch.
|
|
157
|
+
gAECommandLineRenderer.SetExitCode(gAECommandLineRenderer.EXIT_AE_RUNTIME);
|
|
158
|
+
} else {
|
|
159
|
+
// PROBLEM and FATAL will throw exceptions, and so will be logged to the file
|
|
160
|
+
// when we catch the exception.
|
|
161
|
+
// All other errors (NAKED, INFO, WARNING, PROGRESS, and DEBUG) will not
|
|
162
|
+
// throw exceptions. So we log them to the file right here:
|
|
163
|
+
if (gAECommandLineRenderer.is_verbose_mode) {
|
|
164
|
+
if (gAECommandLineRenderer.log_file != null) {
|
|
165
|
+
if (severity_string == "NAKED") {
|
|
166
|
+
// everybody is confused by this category. Just use INFO instead.
|
|
167
|
+
gAECommandLineRenderer.log_file.writeln("INFO:" + error_string);
|
|
168
|
+
} else {
|
|
169
|
+
gAECommandLineRenderer.log_file.writeln(severity_string + ":" + error_string);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// call the error handler that was in place before we started rendering.
|
|
175
|
+
if (gAECommandLineRenderer.oldErrorHandler) {
|
|
176
|
+
gAECommandLineRenderer.oldErrorHandler(error_string, severity_string);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Report an error and throw an exception.
|
|
181
|
+
// Causes the script to exit.
|
|
182
|
+
function my_SetExitCodeAndThrowException(code, message) {
|
|
183
|
+
this.SetExitCode(code);
|
|
184
|
+
throw (this.EXIT_MSG_PREFIX[code] + message);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Report an error. This establishes exitCodes for reporting errors from AfterFX.
|
|
188
|
+
function my_SetExitCode(code) {
|
|
189
|
+
// Some codes are set differently depending on whether we have a custom user
|
|
190
|
+
// log file. Check for these and use the alternate if appropriate.
|
|
191
|
+
var real_code = code;
|
|
192
|
+
if (gAECommandLineRenderer.has_user_log_file) {
|
|
193
|
+
switch (real_code) {
|
|
194
|
+
case gAECommandLineRenderer.EXIT_SYNTAX_ERROR:
|
|
195
|
+
real_code = gAECommandLineRenderer.EXIT_SYNTAX_ERROR_USER_LOG;
|
|
196
|
+
break;
|
|
197
|
+
case gAECommandLineRenderer.EXIT_OTHER_SCRIPTING_ERROR:
|
|
198
|
+
real_code = gAECommandLineRenderer.EXIT_OTHER_SCRIPTING_ERROR_USER_LOG;
|
|
199
|
+
break;
|
|
200
|
+
case gAECommandLineRenderer.EXIT_AERENDER_RUNTIME:
|
|
201
|
+
real_code = gAECommandLineRenderer.EXIT_AERENDER_RUNTIME_USER_LOG;
|
|
202
|
+
break;
|
|
203
|
+
case gAECommandLineRenderer.EXIT_AE_RUNTIME:
|
|
204
|
+
real_code = gAECommandLineRenderer.EXIT_AE_RUNTIME_USER_LOG;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Always keep the first error. So only set if the exitCode is still EXIT_OK.
|
|
210
|
+
if (app.exitCode == gAECommandLineRenderer.EXIT_OK) {
|
|
211
|
+
app.exitCode = real_code;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Arguments may be enclosed in quotes. This
|
|
216
|
+
// will remove them and return the result.
|
|
217
|
+
function my_StripAnyEnclosingQuotes(inString) {
|
|
218
|
+
var result = inString;
|
|
219
|
+
if (inString &&
|
|
220
|
+
inString.charAt(0) == '"' &&
|
|
221
|
+
inString.charAt(inString.length - 1) == '"') {
|
|
222
|
+
result = inString.substring(1, inString.length - 1);
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Make sure the value is there, and returns it, stripping away any enclosing quotes.
|
|
228
|
+
//
|
|
229
|
+
function my_GetValueForFlag(arg_num, the_flag) {
|
|
230
|
+
if (!this.inArgs[arg_num]) {
|
|
231
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, (this.MSG_UNDEFINED_VALUE_FOR_FLAG + the_flag));
|
|
232
|
+
}
|
|
233
|
+
return this.StripAnyEnclosingQuotes(this.inArgs[arg_num]);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// this function takes a string like "key:value; key2:value2" and
|
|
237
|
+
// constructs an object {key:"value", key2: "value2"} which is
|
|
238
|
+
// the format expected by RQ scripting APIs
|
|
239
|
+
//
|
|
240
|
+
// you might reasonably wonder why this isn't JSON.parse?
|
|
241
|
+
//
|
|
242
|
+
// * ExtendScript's ES version doesn't include JSON
|
|
243
|
+
// * didn't want to pollute global space/aerender at startup with a
|
|
244
|
+
// possibly different copy of JSON
|
|
245
|
+
// * settings dictionary for RenderSettings and OutputModule use
|
|
246
|
+
// string values exclusively. escaping a real world RQ/OM settings
|
|
247
|
+
// JSON obj on the command line is alarmingly complicated and dangerous
|
|
248
|
+
// (2*N backslashes for every " where) N = total number of quotes to escape
|
|
249
|
+
// in the _entire_ command line
|
|
250
|
+
|
|
251
|
+
function my_settingsStringToObject(sTokens) {
|
|
252
|
+
var obj = {};
|
|
253
|
+
var keyValuePairs = sTokens.split(";");
|
|
254
|
+
|
|
255
|
+
// ExtendScript too old to have str.trim(), replace when it does
|
|
256
|
+
function trim(s) {
|
|
257
|
+
return s.replace(/^\s+|\s+$/g, '');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
for (var i in keyValuePairs) {
|
|
261
|
+
var kv_array = keyValuePairs[i].split(":");
|
|
262
|
+
var k = trim(kv_array[0]);
|
|
263
|
+
var v = trim(kv_array[1]);
|
|
264
|
+
obj[k] = v;
|
|
265
|
+
}
|
|
266
|
+
return obj;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Parse the parameter.
|
|
270
|
+
// Return the number of arguments used in parsing the parameter.
|
|
271
|
+
function my_ParseParamStartingAt(arg_num) {
|
|
272
|
+
if (!this.inArgs[arg_num]) {
|
|
273
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_TRIED_TO_PARSE_UNDEFINED);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
var num_args_parsed = 0;
|
|
277
|
+
|
|
278
|
+
// Check for a valid flag:
|
|
279
|
+
var my_flag = this.inArgs[arg_num];
|
|
280
|
+
if (my_flag == "-port") {
|
|
281
|
+
// -port is used by aerender to specify a port address for a socket.
|
|
282
|
+
//
|
|
283
|
+
// Note: this value is sought/parsed earlier, in the SetupDefaultLog method.
|
|
284
|
+
// We can just ignore here.
|
|
285
|
+
var dummy = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
286
|
+
num_args_parsed = 2;
|
|
287
|
+
}
|
|
288
|
+
if (my_flag == "-project") {
|
|
289
|
+
this.in_project_path = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
290
|
+
num_args_parsed = 2;
|
|
291
|
+
}
|
|
292
|
+
if (my_flag == "-teamproject") {
|
|
293
|
+
this.in_teamproject_name = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
294
|
+
num_args_parsed = 2;
|
|
295
|
+
}
|
|
296
|
+
if (my_flag == "-comp") {
|
|
297
|
+
this.in_comp_name = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
298
|
+
num_args_parsed = 2;
|
|
299
|
+
}
|
|
300
|
+
if (my_flag == "-rqindex") {
|
|
301
|
+
this.in_rq_index = parseInt(this.GetValueForFlag(arg_num + 1, my_flag));
|
|
302
|
+
num_args_parsed = 2;
|
|
303
|
+
}
|
|
304
|
+
if (my_flag == "-RStemplate") {
|
|
305
|
+
this.in_RStemplate = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
306
|
+
num_args_parsed = 2;
|
|
307
|
+
}
|
|
308
|
+
if (my_flag == "-OMtemplate") {
|
|
309
|
+
this.in_OMtemplate = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
310
|
+
num_args_parsed = 2;
|
|
311
|
+
}
|
|
312
|
+
if (my_flag == "-renderSettings") {
|
|
313
|
+
this.in_RSsettings = my_settingsStringToObject(this.GetValueForFlag(arg_num + 1, my_flag));
|
|
314
|
+
num_args_parsed = 2;
|
|
315
|
+
}
|
|
316
|
+
if (my_flag == "-outputSettings") {
|
|
317
|
+
this.in_OMsettings = my_settingsStringToObject(this.GetValueForFlag(arg_num + 1, my_flag));
|
|
318
|
+
num_args_parsed = 2;
|
|
319
|
+
}
|
|
320
|
+
if (my_flag == "-output") {
|
|
321
|
+
this.in_output_path = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
322
|
+
num_args_parsed = 2;
|
|
323
|
+
}
|
|
324
|
+
if (my_flag == "-log") {
|
|
325
|
+
this.in_logfile_path = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
326
|
+
num_args_parsed = 2;
|
|
327
|
+
}
|
|
328
|
+
if (my_flag == "-s") {
|
|
329
|
+
this.in_start_frame = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
330
|
+
num_args_parsed = 2;
|
|
331
|
+
}
|
|
332
|
+
if (my_flag == "-e") {
|
|
333
|
+
this.in_end_frame = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
334
|
+
num_args_parsed = 2;
|
|
335
|
+
}
|
|
336
|
+
if (my_flag == "-i") {
|
|
337
|
+
this.in_increment = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
338
|
+
num_args_parsed = 2;
|
|
339
|
+
}
|
|
340
|
+
if (my_flag == "-mem_usage") {
|
|
341
|
+
this.in_image_cache_percent = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
342
|
+
this.in_max_mem_percent = this.GetValueForFlag(arg_num + 2, my_flag);
|
|
343
|
+
num_args_parsed = 3;
|
|
344
|
+
}
|
|
345
|
+
if (my_flag == "-mfr") {
|
|
346
|
+
this.in_mfr_enable = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
347
|
+
this.in_mfr_max_cpu_percent = this.GetValueForFlag(arg_num + 2, my_flag);
|
|
348
|
+
num_args_parsed = 3;
|
|
349
|
+
}
|
|
350
|
+
if (my_flag == "-v") {
|
|
351
|
+
this.in_verbose_flag = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
352
|
+
num_args_parsed = 2;
|
|
353
|
+
}
|
|
354
|
+
if (my_flag == "-r") {
|
|
355
|
+
this.in_script_path = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
356
|
+
num_args_parsed = 2;
|
|
357
|
+
}
|
|
358
|
+
if (my_flag == "-close") {
|
|
359
|
+
this.in_close_flag = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
360
|
+
num_args_parsed = 2;
|
|
361
|
+
}
|
|
362
|
+
if (my_flag == "-sound") {
|
|
363
|
+
this.in_sound_flag = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
364
|
+
num_args_parsed = 2;
|
|
365
|
+
}
|
|
366
|
+
if (my_flag == "-doSavePrefsOnQuit") {
|
|
367
|
+
// The effect of this flag will be taken into account when we
|
|
368
|
+
// exit the app. See comment in the "finally" block.
|
|
369
|
+
// All we do here is increment the num_args_parsed count.
|
|
370
|
+
num_args_parsed = 1;
|
|
371
|
+
}
|
|
372
|
+
if (my_flag == "-continueOnMissingFootage") {
|
|
373
|
+
this.in_stop_on_missing_frame = false;
|
|
374
|
+
num_args_parsed = 1;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (num_args_parsed == 0) {
|
|
378
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, (this.MSG_BAD_FLAG + my_flag));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return num_args_parsed;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// This parses the inArgs array. Assumes
|
|
385
|
+
// the array has already been filled.
|
|
386
|
+
function my_ParseInArgs() {
|
|
387
|
+
// First, undefine all the inputs we're potentially looking for
|
|
388
|
+
this.in_project_path = null;
|
|
389
|
+
this.in_teamproject_name = null;
|
|
390
|
+
this.in_comp_name = null;
|
|
391
|
+
this.in_rq_index = null;
|
|
392
|
+
this.in_RStemplate = null;
|
|
393
|
+
this.in_RSsettings = null;
|
|
394
|
+
this.in_OMtemplate = null;
|
|
395
|
+
this.in_output_path = null;
|
|
396
|
+
this.in_logfile_path = null;
|
|
397
|
+
this.in_start_frame = null;
|
|
398
|
+
this.in_end_frame = null;
|
|
399
|
+
this.in_increment = null;
|
|
400
|
+
this.in_image_cache_percent = null;
|
|
401
|
+
this.in_max_mem_percent = null;
|
|
402
|
+
this.in_verbose_flag = null;
|
|
403
|
+
this.in_close_flag = null;
|
|
404
|
+
this.in_sound_flag = null;
|
|
405
|
+
this.in_mfr_enable = null;
|
|
406
|
+
this.in_mfr_max_cpu_percent = null;
|
|
407
|
+
this.in_script_path = null;
|
|
408
|
+
|
|
409
|
+
// Special case: check if any argument is "-help"
|
|
410
|
+
for (var i = 0; i < this.inArgs.length; i++) {
|
|
411
|
+
if (this.inArgs[i] == "-help") {
|
|
412
|
+
this.SetExitCodeAndThrowException(this.EXIT_SHOW_USAGE, this.MSG_SHOW_USAGE);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
var arg_num = 0;
|
|
417
|
+
while (arg_num < this.inArgs.length) {
|
|
418
|
+
// ParseParamStartingAt returns the number of arguments used up parsing the param.
|
|
419
|
+
arg_num += this.ParseParamStartingAt(arg_num);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// This arg is treated differently than others because it's extra important
|
|
424
|
+
// that we exit properly in the face of anything that might go wrong even
|
|
425
|
+
// during initialization. So we don't parse the standard way, we check this
|
|
426
|
+
// before exit...
|
|
427
|
+
function my_IsSavePrefsArgGiven(arglist) {
|
|
428
|
+
return this.IsInArray("-doSavePrefsOnQuit", arglist);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Returns true if the item equals an item in the array, false if otherwise.
|
|
432
|
+
function my_IsInArray(needle, haystack) {
|
|
433
|
+
result = false;
|
|
434
|
+
for (var i = 0; i < haystack.length; i++) {
|
|
435
|
+
if (needle == haystack[i]) {
|
|
436
|
+
result = true;
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return result;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function my_SetupDefaultLog(arg_list) {
|
|
444
|
+
this.has_user_log_file = false;
|
|
445
|
+
|
|
446
|
+
// Clean up after a potentially bad exit last time:
|
|
447
|
+
if (this.log_file && this.log_file != null) {
|
|
448
|
+
this.log_file.close();
|
|
449
|
+
this.log_file = null;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Open the socket.
|
|
453
|
+
// It is used:
|
|
454
|
+
// [a] to log errors if there is no user-specified log file (specified with a "-log" arg)
|
|
455
|
+
// [b] to log errors encountered while opening any user-specified log file.
|
|
456
|
+
|
|
457
|
+
// See if a -port argument was passed:
|
|
458
|
+
this.log_file = null;
|
|
459
|
+
for (var i = 0; i < arg_list.length; i++) {
|
|
460
|
+
if (arg_list[i] == "-port") {
|
|
461
|
+
if (arg_list.length > i + 1) {
|
|
462
|
+
// The argument value is the port address
|
|
463
|
+
this.in_port_address = arg_list[i + 1];
|
|
464
|
+
// Yes, the log_file variable is being used to hold a socket.
|
|
465
|
+
this.log_file = new Socket();
|
|
466
|
+
|
|
467
|
+
// cprosser [26961]
|
|
468
|
+
// could possibly use ISO-8856-1 for non japanese systems,
|
|
469
|
+
// but I am going for small changes now.
|
|
470
|
+
// and again cprosser 8/8/2005 [33884]
|
|
471
|
+
// CP_OEMCP means use the OEM code page, the default
|
|
472
|
+
// for the console.
|
|
473
|
+
// alas, it doens't understand that so we are hardcoding
|
|
474
|
+
// codepage 850. Not the default on windows for US systems
|
|
475
|
+
// but should be the default on european systems and will
|
|
476
|
+
// get the high ascii correct.
|
|
477
|
+
// Search for chcp at microsoft for info on changing
|
|
478
|
+
// the console.
|
|
479
|
+
// on the mac, leave as binary
|
|
480
|
+
|
|
481
|
+
/*
|
|
482
|
+
davec [DVAAE-4195268]
|
|
483
|
+
update: we now make everything utf8
|
|
484
|
+
and in aerender.cpp we cope with converting
|
|
485
|
+
that to whatever the console is expecting.
|
|
486
|
+
|
|
487
|
+
on mac, it's just utf8 (yay)
|
|
488
|
+
on windows, it's "oem codepage" which == 1
|
|
489
|
+
|
|
490
|
+
learn about JS Blob encodings here:
|
|
491
|
+
https://estk.aenhancers.com/3%20-%20File%20System%20Access/file-and-folder-supported-encoding-names.html#file-and-folder-supported-encoding-names
|
|
492
|
+
*/
|
|
493
|
+
|
|
494
|
+
if (!this.log_file.open(this.in_port_address, "UTF-8")) {
|
|
495
|
+
this.log_file = null;
|
|
496
|
+
this.SetExitCodeAndThrowException(this.EXIT_CANNOT_OPEN_SOCKET,
|
|
497
|
+
this.MSG_CAN_NOT_OPEN_SOCKET);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
this.is_verbose_mode = true;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function my_CleanupDefaultLog() {
|
|
506
|
+
// Close the log file
|
|
507
|
+
if (this.log_file != null) {
|
|
508
|
+
this.log_file.close();
|
|
509
|
+
this.log_file = null;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// This is the external entry point.
|
|
514
|
+
// Bat files or executables may call this method.
|
|
515
|
+
//
|
|
516
|
+
// This function assumes that it has been passed all the arguments.
|
|
517
|
+
// It parses the arguments and then renders.
|
|
518
|
+
function my_Render() {
|
|
519
|
+
app.beginSuppressDialogs();
|
|
520
|
+
|
|
521
|
+
if (checkParentDied()) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
try {
|
|
526
|
+
this.SetupDefaultLog(my_Render.arguments);
|
|
527
|
+
|
|
528
|
+
// start by assuming successful execution, exit code 0.
|
|
529
|
+
app.exitCode = 0;
|
|
530
|
+
|
|
531
|
+
// Check number of arguments
|
|
532
|
+
if (!my_Render.arguments || my_Render.arguments.length == 0) {
|
|
533
|
+
this.SetExitCodeAndThrowException(this.EXIT_SHOW_USAGE, this.MSG_SHOW_USAGE);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
var numArgs = my_Render.arguments.length;
|
|
537
|
+
// Allocate the array of arguments:
|
|
538
|
+
this.inArgs = new Array(numArgs);
|
|
539
|
+
|
|
540
|
+
// Load the input arguments into the inArgs array.
|
|
541
|
+
for (var i = 0; i < numArgs; i++) {
|
|
542
|
+
this.inArgs[i] = my_Render.arguments[i];
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Parse the arguments, and render
|
|
546
|
+
this.ParseInArgs();
|
|
547
|
+
|
|
548
|
+
if (checkParentDied()) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
this.ReallyRender();
|
|
553
|
+
} catch (error) {
|
|
554
|
+
// Add any errors to the log file.
|
|
555
|
+
if (this.log_file != null) {
|
|
556
|
+
this.log_file.writeln("aerender " + error.toString());
|
|
557
|
+
}
|
|
558
|
+
this.SetExitCode(this.EXIT_AE_RUNTIME);
|
|
559
|
+
} finally {
|
|
560
|
+
// This arg is treated differently than others because it's extra important
|
|
561
|
+
// that we exit properly in the face of anything that might go wrong even
|
|
562
|
+
// during initialization. So we don't parse the standard way, we check this
|
|
563
|
+
// before exit...
|
|
564
|
+
app.setSavePreferencesOnQuit(this.IsSavePrefsArgGiven(my_Render.arguments));
|
|
565
|
+
|
|
566
|
+
this.CleanupDefaultLog();
|
|
567
|
+
app.endSuppressDialogs(false);
|
|
568
|
+
app.reportErrorOnMissingFrame = false;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function my_ReallyRender() {
|
|
573
|
+
this.saved_sound_setting = null;
|
|
574
|
+
app.reportErrorOnMissingFrame = this.in_stop_on_missing_frame;
|
|
575
|
+
|
|
576
|
+
try {
|
|
577
|
+
// While rendering we'll report errors to the log file.
|
|
578
|
+
if (app.onError == this.onError) {
|
|
579
|
+
// If the previous error handler is just this one, don't store it.
|
|
580
|
+
// That can happen in extreme cases where this script does not get a
|
|
581
|
+
// chance to clean up and put back the oldErrorHandler when it's done.
|
|
582
|
+
this.oldErrorHandler = null;
|
|
583
|
+
} else {
|
|
584
|
+
this.oldErrorHandler = app.onError;
|
|
585
|
+
}
|
|
586
|
+
app.onError = this.onError;
|
|
587
|
+
// Open the user log file, if specified, and use it instead of the socket.
|
|
588
|
+
if (this.in_logfile_path) {
|
|
589
|
+
// Keep the socket open; errors we encounter while opening the
|
|
590
|
+
// user log file will be logged to the socket.
|
|
591
|
+
var user_log_file = new File(this.in_logfile_path);
|
|
592
|
+
var parent_dir = user_log_file.parent;
|
|
593
|
+
if (!parent_dir.exists) {
|
|
594
|
+
if (this.log_file) {
|
|
595
|
+
this.log_file.writeln(this.MSG_LOG_DIR_NO_EXISTS + this.in_logfile_path);
|
|
596
|
+
}
|
|
597
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
598
|
+
}
|
|
599
|
+
var test_folder = Folder(parent_dir);
|
|
600
|
+
if (!(test_folder instanceof Folder)) {
|
|
601
|
+
if (this.log_file) {
|
|
602
|
+
this.log_file.writeln(this.MSG_LOG_DIR_NOT_A_DIR + this.in_logfile_path);
|
|
603
|
+
}
|
|
604
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
605
|
+
}
|
|
606
|
+
if (!user_log_file.open("w", 'TEXT', 'ttxt')) {
|
|
607
|
+
if (this.log_file) {
|
|
608
|
+
this.log_file.writeln(this.MSG_LOG_CAN_NOT_OPEN + this.in_logfile_path);
|
|
609
|
+
}
|
|
610
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// no errors were encountered opening the file.
|
|
614
|
+
// Close the socket and use this one instead.
|
|
615
|
+
if (this.log_file != null) {
|
|
616
|
+
this.log_file.close();
|
|
617
|
+
}
|
|
618
|
+
this.log_file = user_log_file; // which is still open
|
|
619
|
+
this.has_user_log_file = true;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (this.in_verbose_flag) {
|
|
623
|
+
if (this.in_verbose_flag == "ERRORS") {
|
|
624
|
+
this.is_verbose_mode = false;
|
|
625
|
+
} else if (this.in_verbose_flag == "ERRORS_AND_PROGRESS") {
|
|
626
|
+
this.is_verbose_mode = true;
|
|
627
|
+
} else {
|
|
628
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_VERBOSE_FLAG);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (this.in_close_flag) {
|
|
632
|
+
if (this.in_close_flag != "DO_NOT_CLOSE" &&
|
|
633
|
+
this.in_close_flag != "DO_NOT_SAVE_CHANGES" &&
|
|
634
|
+
this.in_close_flag != "SAVE_CHANGES") {
|
|
635
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_CLOSE_FLAG);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
if (this.in_sound_flag) {
|
|
639
|
+
if (this.in_sound_flag != "ON" &&
|
|
640
|
+
this.in_sound_flag != "OFF" &&
|
|
641
|
+
this.in_sound_flag != "on" &&
|
|
642
|
+
this.in_sound_flag != "off") {
|
|
643
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_SOUND_FLAG);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Set the memory usage, if specified as an argument.
|
|
648
|
+
if (this.in_image_cache_percent && this.in_max_mem_percent) {
|
|
649
|
+
app.setMemoryUsageLimits(this.in_image_cache_percent, this.in_max_mem_percent);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// set the Multi-Frame Rendering and CPU Max Percent
|
|
653
|
+
// this.in_mfr_enable can be null, ON or OFF so as long as we arne't null...
|
|
654
|
+
if (this.in_mfr_enable != null && this.in_mfr_max_cpu_percent) {
|
|
655
|
+
if (this.in_mfr_enable != "ON" &&
|
|
656
|
+
this.in_mfr_enable != "OFF" &&
|
|
657
|
+
this.in_mfr_enable != "on" &&
|
|
658
|
+
this.in_mfr_enable != "off") {
|
|
659
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_MFR_FLAG);
|
|
660
|
+
} else {
|
|
661
|
+
if (this.in_mfr_enable == "ON" ||
|
|
662
|
+
this.in_mfr_enable == "on") {
|
|
663
|
+
this.in_mfr_enable = true;
|
|
664
|
+
} else {
|
|
665
|
+
this.in_mfr_enable = false;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// finally call the API
|
|
669
|
+
app.setMultiFrameRenderingConfig(this.in_mfr_enable, this.in_mfr_max_cpu_percent);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// If the user provided a project, close the current project and open the project specified.
|
|
674
|
+
// Else, leave the current project open.
|
|
675
|
+
if (this.in_project_path) {
|
|
676
|
+
// Close the current project
|
|
677
|
+
if (app.project != null) {
|
|
678
|
+
app.project.close(CloseOptions.DO_NOT_SAVE_CHANGES);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Open the specified project:
|
|
682
|
+
var proj_file = new File(this.in_project_path);
|
|
683
|
+
app.openFast(proj_file);
|
|
684
|
+
}
|
|
685
|
+
if (!app.project) {
|
|
686
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_NO_PROJECT);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// If the user provided a teamproject, close the current project and open the teamproject specified.
|
|
690
|
+
// Else, leave the current project open.
|
|
691
|
+
if (this.in_teamproject_name) {
|
|
692
|
+
// Close the current project
|
|
693
|
+
if (app.project != null) {
|
|
694
|
+
app.project.close(CloseOptions.DO_NOT_SAVE_CHANGES);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// Open the specified team project:
|
|
698
|
+
app.openTeamProject(this.in_teamproject_name);
|
|
699
|
+
}
|
|
700
|
+
if (!app.project) {
|
|
701
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_NO_PROJECT);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (this.in_script_path) {
|
|
705
|
+
this.log_file.writeln("Running Script: " + this.in_script_path);
|
|
706
|
+
var scriptFile = new File(this.in_script_path);
|
|
707
|
+
|
|
708
|
+
scriptFile.encoding = "UTF-8";
|
|
709
|
+
if (!scriptFile.open("r")) {
|
|
710
|
+
if (this.log_file) {
|
|
711
|
+
this.log_file.writeln(this.MSG_SCRIPT_CAN_NOT_OPEN + this.in_script_path);
|
|
712
|
+
}
|
|
713
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
try {
|
|
717
|
+
// Use evalFile instead of eval to make the script path context
|
|
718
|
+
// the same as the scriptFile
|
|
719
|
+
//
|
|
720
|
+
// For example using eval(), the $.fileName would be the commandLineRenderer's
|
|
721
|
+
// path and we want the executing scriptFile's path for our fallback
|
|
722
|
+
// Using evalFile evaluates the file in another context
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
// Update v1.0.2: returning back to eval
|
|
726
|
+
// since there are issues with encoding caused by $.evalFile
|
|
727
|
+
eval(scriptFile.read());
|
|
728
|
+
} catch (e) {
|
|
729
|
+
if (this.log_file) {
|
|
730
|
+
this.log_file.writeln(this.MSG_SCRIPT_CAN_NOT_EXEC + this.in_script_path);
|
|
731
|
+
this.log_file.writeln(e);
|
|
732
|
+
}
|
|
733
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
scriptFile.close();
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// Get the RenderQueueItem for the specified comp, if specified.
|
|
740
|
+
var rqi = null;
|
|
741
|
+
if (this.in_comp_name) {
|
|
742
|
+
rqi = this.GetFirstQueuedRQItemWithName(this.in_comp_name);
|
|
743
|
+
} else if (this.in_rq_index != null) {
|
|
744
|
+
this.log_file.writeln("rqindex " + this.in_rq_index + "num " + app.project.renderQueue.numItems);
|
|
745
|
+
if (this.in_rq_index >= 1 && this.in_rq_index <= app.project.renderQueue.numItems) {
|
|
746
|
+
rqi = app.project.renderQueue.item(this.in_rq_index);
|
|
747
|
+
} else {
|
|
748
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_RQINDEX_NOT_FOUND);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (this.in_comp_name && !rqi) {
|
|
752
|
+
// Try to find the comp in the project and add to the render queue:
|
|
753
|
+
rqi = this.AddCompToRenderQueue(this.in_comp_name);
|
|
754
|
+
if (rqi) {
|
|
755
|
+
if (this.log_file != null) {
|
|
756
|
+
this.log_file.writeln(this.MSG_ADDING_TO_RQ);
|
|
757
|
+
}
|
|
758
|
+
} else {
|
|
759
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_COMP_NOT_FOUND);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Apply the templates, if provided
|
|
764
|
+
if (this.in_RStemplate) {
|
|
765
|
+
if (!rqi) {
|
|
766
|
+
if (this.log_file != null) {
|
|
767
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_TEMPLATE);
|
|
768
|
+
}
|
|
769
|
+
} else {
|
|
770
|
+
if (!this.IsInArray(this.in_RStemplate, rqi.templates)) {
|
|
771
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_RS_TEMPLATE_NOT_FOUND);
|
|
772
|
+
}
|
|
773
|
+
rqi.applyTemplate(this.in_RStemplate);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function _setPropertiesFromObj(aeDOMObject, settingsDictionary) {
|
|
778
|
+
for (key in settingsDictionary) {
|
|
779
|
+
aeDOMObject.setSetting(key, settingsDictionary[key]);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// mutate new/existing RS with settings dictionary
|
|
784
|
+
if (this.in_RSsettings) {
|
|
785
|
+
if (!rqi) {
|
|
786
|
+
if (this.log_file != null) {
|
|
787
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_RS_SETTINGS_NO_RQI);
|
|
788
|
+
}
|
|
789
|
+
} else {
|
|
790
|
+
_setPropertiesFromObj(rqi, this.in_RSsettings);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (this.in_OMtemplate) {
|
|
795
|
+
if (!rqi) {
|
|
796
|
+
if (this.log_file != null) {
|
|
797
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_OMTEMPLATE);
|
|
798
|
+
}
|
|
799
|
+
} else {
|
|
800
|
+
if (!this.IsInArray(this.in_OMtemplate, rqi.outputModule(1).templates)) {
|
|
801
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_OM_TEMPLATE_NOT_FOUND);
|
|
802
|
+
}
|
|
803
|
+
rqi.outputModule(1).applyTemplate(this.in_OMtemplate);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
}
|
|
807
|
+
if (this.in_OMsettings) {
|
|
808
|
+
if (!rqi) {
|
|
809
|
+
if (this.log_file != null) {
|
|
810
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_OM_SETTINGS_NO_RQI);
|
|
811
|
+
}
|
|
812
|
+
} else {
|
|
813
|
+
_setPropertiesFromObj(rqi.outputModule(1), this.in_OMsettings);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
// If a comp was specified, make it the only one to render.
|
|
819
|
+
// If none was provided, leave everything alone so render queue renders as is.
|
|
820
|
+
if (rqi) {
|
|
821
|
+
this.EstablishAsOnlyQueuedItem(rqi);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (rqi) {
|
|
825
|
+
// If the user provided a path, set the output path on rqi's OutputModule
|
|
826
|
+
if (rqi.status == RQItemStatus.NEEDS_OUTPUT && !this.in_output_path) {
|
|
827
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_NEEDS_OUTPUT);
|
|
828
|
+
}
|
|
829
|
+
if (this.in_output_path) {
|
|
830
|
+
var om = rqi.outputModule(1);
|
|
831
|
+
om.file = new File(this.in_output_path);
|
|
832
|
+
}
|
|
833
|
+
} else {
|
|
834
|
+
if (this.in_output_path) {
|
|
835
|
+
if (this.log_file != null) {
|
|
836
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_OUTPUT);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// Set the start and end frames.
|
|
842
|
+
if (this.in_start_frame || this.in_end_frame) {
|
|
843
|
+
if (!rqi) {
|
|
844
|
+
if (this.log_file != null) {
|
|
845
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_START_OR_END);
|
|
846
|
+
}
|
|
847
|
+
} else {
|
|
848
|
+
// Render times are stored as timeSpanStart and timeSpanDuration.
|
|
849
|
+
// Setting only the timeSpanStart will not change the timeSpanDuration and
|
|
850
|
+
// so will move the end time, but we want the end time unchanged if
|
|
851
|
+
// it was not specified.
|
|
852
|
+
// So we must calculate both start_time and end_time,
|
|
853
|
+
// then set both timeSpanStart and timeSpanDuration.
|
|
854
|
+
// Note: frameDuration is stored in the comp.
|
|
855
|
+
var start_time = rqi.timeSpanStart;
|
|
856
|
+
var end_time = rqi.timeSpanStart + rqi.timeSpanDuration;
|
|
857
|
+
if (this.in_start_frame) {
|
|
858
|
+
start_time = -rqi.comp.displayStartTime + ((parseInt(this.in_start_frame, 10) - app.project.displayStartFrame) * rqi.comp.frameDuration);
|
|
859
|
+
}
|
|
860
|
+
if (this.in_end_frame) {
|
|
861
|
+
// The way AE works, final frame is not included.
|
|
862
|
+
// But aerender wants final frame included.
|
|
863
|
+
// So, just add 1 to end frame right here before setting
|
|
864
|
+
// duration for AE:
|
|
865
|
+
// Note: must call parseInt() here, or the 1 will be added as if it
|
|
866
|
+
// were a string. For example, 35 would become 351, not 36. Hoo boy!
|
|
867
|
+
var end_frame_plus_one = parseInt(this.in_end_frame, 10) + 1.0 - app.project.displayStartFrame;
|
|
868
|
+
end_time = -rqi.comp.displayStartTime + (end_frame_plus_one * rqi.comp.frameDuration);
|
|
869
|
+
}
|
|
870
|
+
rqi.timeSpanStart = start_time;
|
|
871
|
+
rqi.timeSpanDuration = end_time - start_time;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// Set the skipFrames (based on increment).
|
|
876
|
+
if (this.in_increment) {
|
|
877
|
+
if (this.in_increment < 1 || this.in_increment > 100) {
|
|
878
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_INCREMENT);
|
|
879
|
+
}
|
|
880
|
+
if (!rqi) {
|
|
881
|
+
if (this.log_file != null) {
|
|
882
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_INCREMENT);
|
|
883
|
+
}
|
|
884
|
+
} else {
|
|
885
|
+
// Set the skipFrames based on the increment.
|
|
886
|
+
//
|
|
887
|
+
// Increment as defined here is one greater then the
|
|
888
|
+
// the render queue item's skipFrames.
|
|
889
|
+
// skipFrames 0 is the same as increment of 1.
|
|
890
|
+
//
|
|
891
|
+
rqi.skipFrames = (this.in_increment - 1);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// If we are in verbose mode, set the log type to ERRORS_AND_PER_FRAME_INFO
|
|
896
|
+
// for all RQ items we are about to render.
|
|
897
|
+
if (this.is_verbose_mode) {
|
|
898
|
+
this.SetLogPerFrameInfoInRQ();
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
this.SaveAndSetRenderSoundSetting();
|
|
902
|
+
|
|
903
|
+
// Render!
|
|
904
|
+
// true skips the recursive check for footage files
|
|
905
|
+
// and will only check the one's used
|
|
906
|
+
|
|
907
|
+
if (checkParentDied()) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
app.project.renderQueue.render(true);
|
|
911
|
+
} catch (error) {
|
|
912
|
+
// Add any errors to the log file.
|
|
913
|
+
if (this.log_file != null) {
|
|
914
|
+
this.log_file.writeln("aerender " + error.toString());
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// It's possible that errors were encountered while trying to render.
|
|
918
|
+
// Stop the render if in progress for a clean exit from the application.
|
|
919
|
+
if (app.project && app.project.renderQueue && app.project.renderQueue.rendering) {
|
|
920
|
+
// This will prevent the message "render stopped by user" from showing up...
|
|
921
|
+
app.onError = null;
|
|
922
|
+
app.project.renderQueue.stopRendering();
|
|
923
|
+
// This will print a better message:
|
|
924
|
+
if (this.log_file != null) {
|
|
925
|
+
this.log_file.writeln(this.MSG_RENDER_ABORTED);
|
|
926
|
+
}
|
|
927
|
+
app.onError = this.onError;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
this.SetExitCode(this.EXIT_AE_RUNTIME);
|
|
931
|
+
} finally {
|
|
932
|
+
// Close the project.
|
|
933
|
+
this.CloseProjectIfDesired();
|
|
934
|
+
|
|
935
|
+
// Put back the old error handler
|
|
936
|
+
app.onError = this.oldErrorHandler;
|
|
937
|
+
|
|
938
|
+
// Restore the setting for hearing the render-done sound.
|
|
939
|
+
this.RestoreRenderSoundSetting()
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// Returns the first item on the render queue that:
|
|
944
|
+
// [a] contains a comp named comp_name
|
|
945
|
+
// [b] has a render status of QUEUED or UNQUEUED or NEEDS_OUTPUT
|
|
946
|
+
// Note that if the status is NEEDS_OUTPUT, one better be provided or
|
|
947
|
+
// an error will result.
|
|
948
|
+
//
|
|
949
|
+
// If not found, returns null.
|
|
950
|
+
//
|
|
951
|
+
function my_GetFirstQueuedRQItemWithName(comp_name) {
|
|
952
|
+
var result = null;
|
|
953
|
+
|
|
954
|
+
var rq = app.project.renderQueue;
|
|
955
|
+
if (rq && rq.numItems > 0) {
|
|
956
|
+
var cur_item;
|
|
957
|
+
// the items are indexed from 1 to numItems.
|
|
958
|
+
for (var i = 1; i <= rq.numItems; i++) {
|
|
959
|
+
cur_item = rq.item(i);
|
|
960
|
+
if (cur_item.comp.name == comp_name &&
|
|
961
|
+
cur_item.status == RQItemStatus.WILL_CONTINUE) {
|
|
962
|
+
if (this.log_file != null) {
|
|
963
|
+
this.log_file.writeln(this.MSG_SKIPPING_WILL_CONTINUE);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (cur_item.comp.name == comp_name &&
|
|
967
|
+
(cur_item.status == RQItemStatus.QUEUED ||
|
|
968
|
+
// pmi 9/24/03 -- do not render unqueued items. Let a new
|
|
969
|
+
// one be added instead.
|
|
970
|
+
// cur_item.status == RQItemStatus.UNQUEUED ||
|
|
971
|
+
cur_item.status == RQItemStatus.NEEDS_OUTPUT)) {
|
|
972
|
+
// We found it!
|
|
973
|
+
result = cur_item;
|
|
974
|
+
break;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
return result;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Find a comp with the given name, and adds it to the render queue.
|
|
983
|
+
// Returns the newly added render queue item
|
|
984
|
+
//
|
|
985
|
+
// If not found, returns null.
|
|
986
|
+
//
|
|
987
|
+
function my_AddCompToRenderQueue(comp_name) {
|
|
988
|
+
var result = null;
|
|
989
|
+
|
|
990
|
+
// Get the comp with the name we are after
|
|
991
|
+
var cur_item;
|
|
992
|
+
var desired_comp = null;
|
|
993
|
+
// the items in the project are indexed from 1 to numItems
|
|
994
|
+
for (var i = 1; i <= app.project.numItems; i++) {
|
|
995
|
+
cur_item = app.project.item(i);
|
|
996
|
+
if (cur_item instanceof CompItem && cur_item.name == comp_name) {
|
|
997
|
+
desired_comp = cur_item;
|
|
998
|
+
break;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// Add the desired_comp to the render queue. The add() method
|
|
1003
|
+
// returns the new render queue item.
|
|
1004
|
+
if (desired_comp) {
|
|
1005
|
+
result = app.project.renderQueue.items.add(desired_comp);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
return result;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Sets the render flag on all RenderQueueItems other than rqi to false,
|
|
1012
|
+
//
|
|
1013
|
+
function my_EstablishAsOnlyQueuedItem(rqi) {
|
|
1014
|
+
var rq = app.project.renderQueue;
|
|
1015
|
+
if (rq && rq.numItems > 0) {
|
|
1016
|
+
var cur_item;
|
|
1017
|
+
// the items are indexed from 1 to numItems.
|
|
1018
|
+
for (var i = 1; i <= rq.numItems; i++) {
|
|
1019
|
+
cur_item = rq.item(i);
|
|
1020
|
+
if (cur_item == rqi) {
|
|
1021
|
+
cur_item.render = true;
|
|
1022
|
+
} else {
|
|
1023
|
+
// You can only change the render flag when these are the current status value:
|
|
1024
|
+
if (cur_item.status == RQItemStatus.QUEUED ||
|
|
1025
|
+
cur_item.status == RQItemStatus.UNQUEUED ||
|
|
1026
|
+
cur_item.status == RQItemStatus.NEEDS_OUTPUT ||
|
|
1027
|
+
cur_item.status == RQItemStatus.WILL_CONTINUE) {
|
|
1028
|
+
cur_item.render = false;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// Sets the log type to be ERRORS_AND_PER_FRAME_INFO for all items that are going to render.
|
|
1036
|
+
//
|
|
1037
|
+
function my_SetLogPerFrameInfoInRQ() {
|
|
1038
|
+
var rq = app.project.renderQueue;
|
|
1039
|
+
if (rq && rq.numItems > 0) {
|
|
1040
|
+
var cur_item;
|
|
1041
|
+
// the items are indexed from 1 to numItems.
|
|
1042
|
+
for (var i = 1; i <= rq.numItems; i++) {
|
|
1043
|
+
cur_item = rq.item(i);
|
|
1044
|
+
if (cur_item.render == true) {
|
|
1045
|
+
if (cur_item.status != RQItemStatus.USER_STOPPED &&
|
|
1046
|
+
cur_item.status != RQItemStatus.ERR_STOPPED &&
|
|
1047
|
+
cur_item.status != RQItemStatus.RENDERING &&
|
|
1048
|
+
cur_item.status != RQItemStatus.DONE) {
|
|
1049
|
+
cur_item.logType = LogType.ERRORS_AND_PER_FRAME_INFO;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// Closes the project if the close flag specifies to do so
|
|
1057
|
+
//
|
|
1058
|
+
function my_CloseProjectIfDesired() {
|
|
1059
|
+
if (app.project) {
|
|
1060
|
+
// Close the project we just used, if desired
|
|
1061
|
+
if (!this.in_close_flag || this.in_close_flag == "DO_NOT_SAVE_CHANGES") {
|
|
1062
|
+
// If no flag provided, this is the default.
|
|
1063
|
+
app.project.close(CloseOptions.DO_NOT_SAVE_CHANGES);
|
|
1064
|
+
} else {
|
|
1065
|
+
if (this.in_close_flag == "SAVE_CHANGES") {
|
|
1066
|
+
app.project.close(CloseOptions.SAVE_CHANGES);
|
|
1067
|
+
}
|
|
1068
|
+
// otherwise, flag is DO_NOT_CLOSE, so we do nothing.
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
function my_SaveAndSetRenderSoundSetting() {
|
|
1074
|
+
// Save the current setting for hearing the render-done sound, we'll restore it later.
|
|
1075
|
+
if (app.preferences.havePref("Misc Section",
|
|
1076
|
+
"Play sound when render finishes", PREFType.PREF_Type_MACHINE_INDEPENDENT)) {
|
|
1077
|
+
// Get the current value if the pref exists.
|
|
1078
|
+
this.saved_sound_setting = app.preferences.getPrefAsLong("Misc Section",
|
|
1079
|
+
"Play sound when render finishes", PREFType.PREF_Type_MACHINE_INDEPENDENT);
|
|
1080
|
+
} else {
|
|
1081
|
+
// default is to play the sound, value of 1.
|
|
1082
|
+
// Use this if the pref does not yet exist.
|
|
1083
|
+
this.saved_sound_setting = 1;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// Set the setting for hearing the render-done sound, based on the input, default is off.
|
|
1087
|
+
this.my_sound_setting = 0; // 0 is off
|
|
1088
|
+
if (this.in_sound_flag && (this.in_sound_flag == "ON" || this.in_sound_flag == "on")) {
|
|
1089
|
+
this.my_sound_setting = 1; // 1 is on
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
app.preferences.savePrefAsLong("Misc Section",
|
|
1093
|
+
"Play sound when render finishes",
|
|
1094
|
+
this.my_sound_setting, PREFType.PREF_Type_MACHINE_INDEPENDENT);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
function my_RestoreRenderSoundSetting() {
|
|
1098
|
+
if (this.saved_sound_setting) {
|
|
1099
|
+
app.preferences.savePrefAsLong("Misc Section",
|
|
1100
|
+
"Play sound when render finishes",
|
|
1101
|
+
this.saved_sound_setting, PREFType.PREF_Type_MACHINE_INDEPENDENT);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// [3] assign all the functions to be method-type attributes.
|
|
1106
|
+
//
|
|
1107
|
+
this.onError = my_onError;
|
|
1108
|
+
this.SetExitCodeAndThrowException = my_SetExitCodeAndThrowException;
|
|
1109
|
+
this.SetExitCode = my_SetExitCode;
|
|
1110
|
+
this.StripAnyEnclosingQuotes = my_StripAnyEnclosingQuotes;
|
|
1111
|
+
this.GetValueForFlag = my_GetValueForFlag;
|
|
1112
|
+
this.ParseParamStartingAt = my_ParseParamStartingAt;
|
|
1113
|
+
this.ParseInArgs = my_ParseInArgs;
|
|
1114
|
+
this.IsInArray = my_IsInArray;
|
|
1115
|
+
this.SetupDefaultLog = my_SetupDefaultLog;
|
|
1116
|
+
this.CleanupDefaultLog = my_CleanupDefaultLog;
|
|
1117
|
+
this.Render = my_Render;
|
|
1118
|
+
this.ReallyRender = my_ReallyRender;
|
|
1119
|
+
this.GetFirstQueuedRQItemWithName = my_GetFirstQueuedRQItemWithName;
|
|
1120
|
+
this.AddCompToRenderQueue = my_AddCompToRenderQueue;
|
|
1121
|
+
this.EstablishAsOnlyQueuedItem = my_EstablishAsOnlyQueuedItem;
|
|
1122
|
+
this.SetLogPerFrameInfoInRQ = my_SetLogPerFrameInfoInRQ;
|
|
1123
|
+
this.CloseProjectIfDesired = my_CloseProjectIfDesired;
|
|
1124
|
+
this.SaveAndSetRenderSoundSetting = my_SaveAndSetRenderSoundSetting;
|
|
1125
|
+
this.RestoreRenderSoundSetting = my_RestoreRenderSoundSetting;
|
|
1126
|
+
this.IsSavePrefsArgGiven = my_IsSavePrefsArgGiven;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
var gAECommandLineRenderer = new AECommandLineRenderer();
|
|
1130
|
+
`;
|