export_texture.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. let export_texture_gamma: f32 = 1.0 / 2.2;
  2. function export_texture_run(path: string, bake_material: bool = false) {
  3. ///if is_paint
  4. if (bake_material) {
  5. export_texture_run_bake_material(path);
  6. }
  7. else if (context_raw.layers_export == export_mode_t.PER_UDIM_TILE) {
  8. let udim_tiles: string[] = [];
  9. for (let i: i32 = 0; i < project_layers.length; ++i) {
  10. let l: slot_layer_t = project_layers[i];
  11. if (slot_layer_get_object_mask(l) > 0) {
  12. let name: string = project_paint_objects[slot_layer_get_object_mask(l) - 1].base.name;
  13. if (substring(name, name.length - 5, 2) == ".1") { // tile.1001
  14. array_push(udim_tiles, substring(name, name.length - 5, name.length));
  15. }
  16. }
  17. }
  18. if (udim_tiles.length > 0) {
  19. for (let i: i32 = 0; i < udim_tiles.length; ++i) {
  20. let udim_tile: string = udim_tiles[i];
  21. export_texture_run_layers(path, project_layers, udim_tile);
  22. }
  23. }
  24. else {
  25. export_texture_run_layers(path, project_layers);
  26. }
  27. }
  28. else if (context_raw.layers_export == export_mode_t.PER_OBJECT) {
  29. let object_names: string[] = [];
  30. for (let i: i32 = 0; i < project_layers.length; ++i) {
  31. let l: slot_layer_t = project_layers[i];
  32. if (slot_layer_get_object_mask(l) > 0) {
  33. let name: string = project_paint_objects[slot_layer_get_object_mask(l) - 1].base.name;
  34. if (array_index_of(object_names, name) == -1) {
  35. array_push(object_names, name);
  36. }
  37. }
  38. }
  39. if (object_names.length > 0) {
  40. for (let i: i32 = 0; i < object_names.length; ++i) {
  41. let name: string = object_names[i];
  42. export_texture_run_layers(path, project_layers, name);
  43. }
  44. }
  45. else {
  46. export_texture_run_layers(path, project_layers);
  47. }
  48. }
  49. else { // Visible or selected
  50. let atlas_export: bool = false;
  51. if (project_atlas_objects != null) {
  52. for (let i: i32 = 1; i < project_atlas_objects.length; ++i) {
  53. if (project_atlas_objects[i - 1] != project_atlas_objects[i]) {
  54. atlas_export = true;
  55. break;
  56. }
  57. }
  58. }
  59. if (atlas_export) {
  60. for (let atlas_index: i32 = 0; atlas_index < project_atlas_objects.length; ++atlas_index) {
  61. let layers: slot_layer_t[] = [];
  62. for (let object_index: i32 = 0; object_index < project_atlas_objects.length; ++object_index) {
  63. if (project_atlas_objects[object_index] == atlas_index) {
  64. for (let i: i32 = 0; i < project_layers.length; ++i) {
  65. let l: slot_layer_t = project_layers[i];
  66. if (slot_layer_get_object_mask(l) == 0 || // shared object
  67. slot_layer_get_object_mask(l) - 1 == object_index) {
  68. array_push(layers, l);
  69. }
  70. }
  71. }
  72. }
  73. if (layers.length > 0) {
  74. export_texture_run_layers(path, layers, project_atlas_names[atlas_index]);
  75. }
  76. }
  77. }
  78. else {
  79. let layers: slot_layer_t[];
  80. if (context_raw.layers_export == export_mode_t.SELECTED) {
  81. if (slot_layer_is_group(context_raw.layer)) {
  82. layers = slot_layer_get_children(context_raw.layer);
  83. }
  84. else {
  85. layers = [context_raw.layer];
  86. }
  87. }
  88. else {
  89. layers = project_layers;
  90. }
  91. export_texture_run_layers(path, layers);
  92. }
  93. }
  94. ///end
  95. ///if is_lab
  96. let layers: slot_layer_t[] = [context_raw.brush_output_node_inst];
  97. export_texture_run_layers(path, layers);
  98. ///end
  99. ///if arm_ios
  100. console_info(tr("Textures exported") + " (\"Files/On My iPad/" + manifest_title + "\")");
  101. ///elseif arm_android
  102. console_info(tr("Textures exported") + " (\"Files/Internal storage/Pictures/" + manifest_title + "\")");
  103. ///else
  104. console_info(tr("Textures exported"));
  105. ///end
  106. ui_files_last_path = "";
  107. }
  108. function export_texture_run_bake_material(path: string) {
  109. if (render_path_paint_live_layer == null) {
  110. render_path_paint_live_layer = slot_layer_create("_live");
  111. }
  112. let _tool: workspace_tool_t = context_raw.tool;
  113. context_raw.tool = workspace_tool_t.FILL;
  114. make_material_parse_paint_material();
  115. let _paint_object: mesh_object_t = context_raw.paint_object;
  116. let planeo: mesh_object_t = scene_get_child(".Plane").ext;
  117. planeo.base.visible = true;
  118. context_raw.paint_object = planeo;
  119. context_raw.pdirty = 1;
  120. let _visibles: bool[] = [];
  121. for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
  122. let p: mesh_object_t = project_paint_objects[i];
  123. array_push(_visibles, p.base.visible);
  124. p.base.visible = false;
  125. }
  126. render_path_paint_use_live_layer(true);
  127. render_path_paint_commands_paint(false);
  128. render_path_paint_use_live_layer(false);
  129. context_raw.tool = _tool;
  130. make_material_parse_paint_material();
  131. context_raw.pdirty = 0;
  132. planeo.base.visible = false;
  133. context_raw.paint_object = _paint_object;
  134. for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
  135. project_paint_objects[i].base.visible = _visibles[i];
  136. }
  137. let layers: slot_layer_t[] = [render_path_paint_live_layer];
  138. export_texture_run_layers(path, layers, "", true);
  139. }
  140. function export_texture_run_layers(path: string, layers: slot_layer_t[], object_name: string = "", bake_material: bool = false) {
  141. let texture_size_x: i32 = config_get_texture_res_x();
  142. let texture_size_y: i32 = config_get_texture_res_y();
  143. ///if (arm_android || arm_ios)
  144. let f: string = sys_title();
  145. ///else
  146. let f: string = ui_files_filename;
  147. ///end
  148. if (f == "") {
  149. f = tr("untitled");
  150. }
  151. let format_type: texture_ldr_format_t = context_raw.format_type;
  152. let bits: i32 = base_bits_handle.position == texture_bits_t.BITS8 ? 8 : 16;
  153. let ext: string = bits == 16 ? ".exr" : format_type == texture_ldr_format_t.PNG ? ".png" : ".jpg";
  154. if (ends_with(f, ext)) {
  155. f = substring(f, 0, f.length - 4);
  156. }
  157. ///if is_paint
  158. let is_udim: bool = context_raw.layers_export == export_mode_t.PER_UDIM_TILE;
  159. if (is_udim) {
  160. ext = object_name + ext;
  161. }
  162. layers_make_temp_img();
  163. layers_make_export_img();
  164. let rt: render_target_t = map_get(render_path_render_targets, "empty_white");
  165. let empty: image_t = rt._image;
  166. // Append object mask name
  167. let export_selected: bool = context_raw.layers_export == export_mode_t.SELECTED;
  168. if (export_selected && slot_layer_get_object_mask(layers[0]) > 0) {
  169. f += "_" + project_paint_objects[slot_layer_get_object_mask(layers[0]) - 1].base.name;
  170. }
  171. if (!is_udim && !export_selected && object_name != "") {
  172. f += "_" + object_name;
  173. }
  174. // Clear export layer
  175. g4_begin(layers_expa);
  176. g4_clear(color_from_floats(0.0, 0.0, 0.0, 0.0));
  177. g4_end();
  178. g4_begin(layers_expb);
  179. g4_clear(color_from_floats(0.5, 0.5, 1.0, 0.0));
  180. g4_end();
  181. g4_begin(layers_expc);
  182. g4_clear(color_from_floats(1.0, 0.0, 0.0, 0.0));
  183. g4_end();
  184. // Flatten layers
  185. for (let i: i32 = 0; i < layers.length; ++i) {
  186. let l1: slot_layer_t = layers[i];
  187. if (!export_selected && !slot_layer_is_visible(l1)) {
  188. continue;
  189. }
  190. if (!slot_layer_is_layer(l1)) {
  191. continue;
  192. }
  193. if (object_name != "" && slot_layer_get_object_mask(l1) > 0) {
  194. if (is_udim && !ends_with(project_paint_objects[slot_layer_get_object_mask(l1) - 1].base.name, object_name)) {
  195. continue;
  196. }
  197. let per_object: bool = context_raw.layers_export == export_mode_t.PER_OBJECT;
  198. if (per_object && project_paint_objects[slot_layer_get_object_mask(l1) - 1].base.name != object_name) {
  199. continue;
  200. }
  201. }
  202. let mask: image_t = empty;
  203. let l1masks: slot_layer_t[] = slot_layer_get_masks(l1);
  204. if (l1masks != null && !bake_material) {
  205. if (l1masks.length > 1) {
  206. layers_make_temp_mask_img();
  207. g2_begin(pipes_temp_mask_image);
  208. g2_clear(0x00000000);
  209. g2_end();
  210. let l1: slot_layer_t = {
  211. texpaint: pipes_temp_mask_image
  212. };
  213. for (let i: i32 = 0; i < l1masks.length; ++i) {
  214. layers_merge_layer(l1, l1masks[i]);
  215. }
  216. mask = pipes_temp_mask_image;
  217. }
  218. else {
  219. mask = l1masks[0].texpaint;
  220. }
  221. }
  222. if (l1.paint_base) {
  223. g2_begin(layers_temp_image); // Copy to temp
  224. g2_set_pipeline(pipes_copy);
  225. g2_draw_image(layers_expa, 0, 0);
  226. g2_set_pipeline(null);
  227. g2_end();
  228. g4_begin(layers_expa);
  229. g4_set_pipeline(pipes_merge);
  230. g4_set_tex(pipes_tex0, l1.texpaint);
  231. g4_set_tex(pipes_tex1, empty);
  232. g4_set_tex(pipes_texmask, mask);
  233. g4_set_tex(pipes_texa, layers_temp_image);
  234. g4_set_float(pipes_opac, slot_layer_get_opacity(l1));
  235. g4_set_int(pipes_blending, layers.length > 1 ? l1.blending : 0);
  236. g4_set_vertex_buffer(const_data_screen_aligned_vb);
  237. g4_set_index_buffer(const_data_screen_aligned_ib);
  238. g4_draw();
  239. g4_end();
  240. }
  241. if (l1.paint_nor) {
  242. g2_begin(layers_temp_image);
  243. g2_set_pipeline(pipes_copy);
  244. g2_draw_image(layers_expb, 0, 0);
  245. g2_set_pipeline(null);
  246. g2_end();
  247. g4_begin(layers_expb);
  248. g4_set_pipeline(pipes_merge);
  249. g4_set_tex(pipes_tex0, l1.texpaint);
  250. g4_set_tex(pipes_tex1, l1.texpaint_nor);
  251. g4_set_tex(pipes_texmask, mask);
  252. g4_set_tex(pipes_texa, layers_temp_image);
  253. g4_set_float(pipes_opac, slot_layer_get_opacity(l1));
  254. g4_set_int(pipes_blending, l1.paint_nor_blend ? -2 : -1);
  255. g4_set_vertex_buffer(const_data_screen_aligned_vb);
  256. g4_set_index_buffer(const_data_screen_aligned_ib);
  257. g4_draw();
  258. g4_end();
  259. }
  260. if (l1.paint_occ || l1.paint_rough || l1.paint_met || l1.paint_height) {
  261. g2_begin(layers_temp_image);
  262. g2_set_pipeline(pipes_copy);
  263. g2_draw_image(layers_expc, 0, 0);
  264. g2_set_pipeline(null);
  265. g2_end();
  266. if (l1.paint_occ && l1.paint_rough && l1.paint_met && l1.paint_height) {
  267. layers_commands_merge_pack(pipes_merge, layers_expc, l1.texpaint, l1.texpaint_pack, slot_layer_get_opacity(l1), mask, l1.paint_height_blend ? -3 : -1);
  268. }
  269. else {
  270. if (l1.paint_occ) layers_commands_merge_pack(pipes_merge_r, layers_expc, l1.texpaint, l1.texpaint_pack, slot_layer_get_opacity(l1), mask);
  271. if (l1.paint_rough) layers_commands_merge_pack(pipes_merge_g, layers_expc, l1.texpaint, l1.texpaint_pack, slot_layer_get_opacity(l1), mask);
  272. if (l1.paint_met) layers_commands_merge_pack(pipes_merge_b, layers_expc, l1.texpaint, l1.texpaint_pack, slot_layer_get_opacity(l1), mask);
  273. }
  274. }
  275. }
  276. ///if arm_metal
  277. // Flush command list
  278. g2_begin(layers_expa);
  279. g2_end();
  280. g2_begin(layers_expb);
  281. g2_end();
  282. g2_begin(layers_expc);
  283. g2_end();
  284. ///end
  285. ///end
  286. let texpaint: image_t = layers_expa;
  287. let texpaint_nor: image_t = layers_expb;
  288. let texpaint_pack: image_t = layers_expc;
  289. ///if is_lab
  290. texpaint = context_raw.brush_output_node_inst.texpaint;
  291. texpaint_nor = context_raw.brush_output_node_inst.texpaint_nor;
  292. texpaint_pack = context_raw.brush_output_node_inst.texpaint_pack;
  293. ///end
  294. let pixpaint: buffer_t = null;
  295. let pixpaint_nor: buffer_t = null;
  296. let pixpaint_pack: buffer_t = null;
  297. let preset: export_preset_t = box_export_preset;
  298. let pix: buffer_t = null;
  299. for (let i: i32 = 0; i < preset.textures.length; ++i) {
  300. let t: export_preset_texture_t = preset.textures[i];
  301. for (let i: i32 = 0; i < t.channels.length; ++i) {
  302. let c: string = t.channels[i];
  303. if ((c == "base_r" || c == "base_g" || c == "base_b" || c == "opac") && pixpaint == null) {
  304. pixpaint = image_get_pixels(texpaint);
  305. }
  306. else if ((c == "nor_r" || c == "nor_g" || c == "nor_g_directx" || c == "nor_b" || c == "emis" || c == "subs") && pixpaint_nor == null) {
  307. pixpaint_nor = image_get_pixels(texpaint_nor);
  308. }
  309. else if ((c == "occ" || c == "rough" || c == "metal" || c == "height" || c == "smooth") && pixpaint_pack == null) {
  310. pixpaint_pack = image_get_pixels(texpaint_pack);
  311. }
  312. }
  313. }
  314. for (let i: i32 = 0; i < preset.textures.length; ++i) {
  315. let t: export_preset_texture_t = preset.textures[i];
  316. let c: string[] = t.channels;
  317. let tex_name: string = t.name != "" ? "_" + t.name : "";
  318. let single_channel: bool = c[0] == c[1] && c[1] == c[2] && c[3] == "1.0";
  319. if (c[0] == "base_r" && c[1] == "base_g" && c[2] == "base_b" && c[3] == "1.0" && t.color_space == "linear") {
  320. export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint, 1);
  321. }
  322. else if (c[0] == "nor_r" && c[1] == "nor_g" && c[2] == "nor_b" && c[3] == "1.0" && t.color_space == "linear") {
  323. export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_nor, 1);
  324. }
  325. else if (c[0] == "occ" && c[1] == "rough" && c[2] == "metal" && c[3] == "1.0" && t.color_space == "linear") {
  326. export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 1);
  327. }
  328. else if (single_channel && c[0] == "occ" && t.color_space == "linear") {
  329. export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 0);
  330. }
  331. else if (single_channel && c[0] == "rough" && t.color_space == "linear") {
  332. export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 1);
  333. }
  334. else if (single_channel && c[0] == "metal" && t.color_space == "linear") {
  335. export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 2);
  336. }
  337. else if (single_channel && c[0] == "height" && t.color_space == "linear") {
  338. export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 3);
  339. }
  340. else if (single_channel && c[0] == "opac" && t.color_space == "linear") {
  341. export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint, 2, 3);
  342. }
  343. else {
  344. if (pix == null) {
  345. pix = buffer_create(texture_size_x * texture_size_y * 4 * math_floor(bits / 8));
  346. }
  347. for (let i: i32 = 0; i < 4; ++i) {
  348. let c: string = t.channels[i];
  349. if (c == "base_r") {
  350. export_texture_copy_channel(pixpaint, 0, pix, i, t.color_space == "linear");
  351. }
  352. else if (c == "base_g") {
  353. export_texture_copy_channel(pixpaint, 1, pix, i, t.color_space == "linear");
  354. }
  355. else if (c == "base_b") {
  356. export_texture_copy_channel(pixpaint, 2, pix, i, t.color_space == "linear");
  357. }
  358. else if (c == "height") {
  359. export_texture_copy_channel(pixpaint_pack, 3, pix, i, t.color_space == "linear");
  360. }
  361. else if (c == "metal") {
  362. export_texture_copy_channel(pixpaint_pack, 2, pix, i, t.color_space == "linear");
  363. }
  364. else if (c == "nor_r") {
  365. export_texture_copy_channel(pixpaint_nor, 0, pix, i, t.color_space == "linear");
  366. }
  367. else if (c == "nor_g") {
  368. export_texture_copy_channel(pixpaint_nor, 1, pix, i, t.color_space == "linear");
  369. }
  370. else if (c == "nor_g_directx") {
  371. export_texture_copy_channel_inv(pixpaint_nor, 1, pix, i, t.color_space == "linear");
  372. }
  373. else if (c == "nor_b") {
  374. export_texture_copy_channel(pixpaint_nor, 2, pix, i, t.color_space == "linear");
  375. }
  376. else if (c == "occ") {
  377. export_texture_copy_channel(pixpaint_pack, 0, pix, i, t.color_space == "linear");
  378. }
  379. else if (c == "opac") {
  380. export_texture_copy_channel(pixpaint, 3, pix, i, t.color_space == "linear");
  381. }
  382. else if (c == "rough") {
  383. export_texture_copy_channel(pixpaint_pack, 1, pix, i, t.color_space == "linear");
  384. }
  385. else if (c == "smooth") {
  386. export_texture_copy_channel_inv(pixpaint_pack, 1, pix, i, t.color_space == "linear");
  387. }
  388. else if (c == "emis") {
  389. export_texture_extract_channel(pixpaint_nor, 3, pix, i, 3, 1, t.color_space == "linear");
  390. }
  391. else if (c == "subs") {
  392. export_texture_extract_channel(pixpaint_nor, 3, pix, i, 3, 2, t.color_space == "linear");
  393. }
  394. else if (c == "0.0") {
  395. export_texture_set_channel(0, pix, i);
  396. }
  397. else if (c == "1.0") {
  398. export_texture_set_channel(255, pix, i);
  399. }
  400. }
  401. export_texture_write_texture(path + path_sep + f + tex_name + ext, pix, 3);
  402. }
  403. }
  404. // Release staging memory allocated in image_get_pixels()
  405. texpaint.pixels = null;
  406. texpaint_nor.pixels = null;
  407. texpaint_pack.pixels = null;
  408. }
  409. function export_texture_write_texture(file: string, pixels: buffer_t, type: i32 = 1, off: i32 = 0) {
  410. let res_x: i32 = config_get_texture_res_x();
  411. let res_y: i32 = config_get_texture_res_y();
  412. let bits_handle: i32 = base_bits_handle.position;
  413. let bits: i32 = bits_handle == texture_bits_t.BITS8 ? 8 : bits_handle == texture_bits_t.BITS16 ? 16 : 32;
  414. let format: i32 = 0; // RGBA
  415. if (type == 1) {
  416. format = 2; // RGB1
  417. }
  418. if (type == 2 && off == 0) {
  419. format = 3; // RRR1
  420. }
  421. if (type == 2 && off == 1) {
  422. format = 4; // GGG1
  423. }
  424. if (type == 2 && off == 2) {
  425. format = 5; // BBB1
  426. }
  427. if (type == 2 && off == 3) {
  428. format = 6; // AAA1
  429. }
  430. if (context_raw.layers_destination == export_destination_t.PACKED) {
  431. let image: image_t = image_from_bytes(pixels, res_x, res_y);
  432. map_set(data_cached_images, file, image);
  433. let ar: string[] = string_split(file, path_sep);
  434. let name: string = ar[ar.length - 1];
  435. let asset: asset_t = {
  436. name: name,
  437. file: file,
  438. id: project_asset_id++
  439. };
  440. array_push(project_assets, asset);
  441. if (project_raw.assets == null) {
  442. project_raw.assets = [];
  443. }
  444. array_push(project_raw.assets, asset.file);
  445. array_push(project_asset_names, asset.name);
  446. map_set(project_asset_map, asset.id, image);
  447. let assets: asset_t[] = [asset];
  448. export_arm_pack_assets(project_raw, assets);
  449. return;
  450. }
  451. if (bits == 8 && context_raw.format_type == texture_ldr_format_t.PNG) {
  452. iron_write_png(file, pixels, res_x, res_y, format);
  453. }
  454. else if (bits == 8 && context_raw.format_type == texture_ldr_format_t.JPG) {
  455. iron_write_jpg(file, pixels, res_x, res_y, format, math_floor(context_raw.format_quality));
  456. }
  457. else { // Exr
  458. let b: buffer_t = parser_exr_run(res_x, res_y, pixels, bits, type, off);
  459. iron_file_save_bytes(file, b, b.length);
  460. }
  461. }
  462. ///if (arm_metal || arm_vulkan)
  463. function _export_texture_channel_bgra_swap(c: i32): i32 {
  464. return c == 0 ? 2 : c == 2 ? 0 : c;
  465. }
  466. ///end
  467. function export_texture_copy_channel(from: buffer_t, from_channel: i32, to: buffer_t, to_channel: i32, linear: bool = true) {
  468. ///if (arm_metal || arm_vulkan)
  469. from_channel = _export_texture_channel_bgra_swap(from_channel);
  470. ///end
  471. for (let i: i32 = 0; i < math_floor((to.length) / 4); ++i) {
  472. buffer_set_u8(to, i * 4 + to_channel, buffer_get_u8(from, i * 4 + from_channel));
  473. }
  474. if (!linear) {
  475. export_texture_to_srgb(to, to_channel);
  476. }
  477. }
  478. function export_texture_copy_channel_inv(from: buffer_t, from_channel: i32, to: buffer_t, to_channel: i32, linear: bool = true) {
  479. ///if (arm_metal || arm_vulkan)
  480. from_channel = _export_texture_channel_bgra_swap(from_channel);
  481. ///end
  482. for (let i: i32 = 0; i < math_floor((to.length) / 4); ++i) {
  483. buffer_set_u8(to, i * 4 + to_channel, 255 - buffer_get_u8(from, i * 4 + from_channel));
  484. }
  485. if (!linear) {
  486. export_texture_to_srgb(to, to_channel);
  487. }
  488. }
  489. function export_texture_extract_channel(from: buffer_t, from_channel: i32, to: buffer_t, to_channel: i32, step: i32, mask: i32, linear: bool = true) {
  490. ///if (arm_metal || arm_vulkan)
  491. from_channel = _export_texture_channel_bgra_swap(from_channel);
  492. ///end
  493. for (let i: i32 = 0; i < math_floor((to.length) / 4); ++i) {
  494. buffer_set_u8(to, i * 4 + to_channel, buffer_get_u8(from, i * 4 + from_channel) % step == mask ? 255 : 0);
  495. }
  496. if (!linear) {
  497. export_texture_to_srgb(to, to_channel);
  498. }
  499. }
  500. function export_texture_set_channel(value: i32, to: buffer_t, to_channel: i32, linear: bool = true) {
  501. for (let i: i32 = 0; i < math_floor((to.length) / 4); ++i) {
  502. buffer_set_u8(to, i * 4 + to_channel, value);
  503. }
  504. if (!linear) {
  505. export_texture_to_srgb(to, to_channel);
  506. }
  507. }
  508. function export_texture_to_srgb(to: buffer_t, to_channel: i32) {
  509. for (let i: i32 = 0; i < math_floor((to.length) / 4); ++i) {
  510. buffer_set_u8(to, i * 4 + to_channel, math_floor(math_pow(buffer_get_u8(to, i * 4 + to_channel) / 255, export_texture_gamma) * 255));
  511. }
  512. }
  513. type export_preset_t = {
  514. textures?: export_preset_texture_t[];
  515. };
  516. type export_preset_texture_t = {
  517. name?: string;
  518. channels?: string[];
  519. color_space?: string;
  520. };