TextureEditor.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import { LabelElement, ToggleInput, SelectInput } from '../../libs/flow.module.js';
  2. import { BaseNode, onNodeValidElement } from '../core/BaseNode.js';
  3. import { TextureNode, UVNode } from 'three/nodes';
  4. import { Texture, TextureLoader, RepeatWrapping, ClampToEdgeWrapping, MirroredRepeatWrapping } from 'three';
  5. const fileTexture = new WeakMap();
  6. const fileURL = new WeakMap();
  7. const textureLoader = new TextureLoader();
  8. const defaultTexture = new Texture();
  9. const defaultUV = new UVNode();
  10. const getTexture = ( file ) => {
  11. let texture = fileTexture.get( file );
  12. if ( texture === undefined || file.getURL() !== fileURL.get( file ) ) {
  13. const url = file.getURL();
  14. if ( texture !== undefined ) {
  15. texture.dispose();
  16. }
  17. texture = textureLoader.load( url );
  18. fileTexture.set( file, texture );
  19. fileURL.set( file, url );
  20. }
  21. return texture;
  22. };
  23. export class TextureEditor extends BaseNode {
  24. constructor() {
  25. const node = new TextureNode( defaultTexture );
  26. super( 'Texture', 4, node, 250 );
  27. this.texture = null;
  28. this._initFile();
  29. this._initParams();
  30. this.onValidElement = () => {};
  31. }
  32. _initFile() {
  33. const fileElement = new LabelElement( 'File' ).setInputColor( 'aqua' ).setInput( 1 );
  34. fileElement.onValid( ( source, target, stage ) => {
  35. const object = target.getObject();
  36. if ( object && object.isDataFile !== true ) {
  37. if ( stage === 'dragged' ) {
  38. const name = target.node.getName();
  39. this.editor.tips.error( `"${name}" is not a File.` );
  40. }
  41. return false;
  42. }
  43. } ).onConnect( () => {
  44. const file = fileElement.getLinkedObject();
  45. const node = this.value;
  46. this.texture = file ? getTexture( file ) : null;
  47. node.value = this.texture || defaultTexture;
  48. this.update();
  49. }, true );
  50. this.add( fileElement );
  51. }
  52. _initParams() {
  53. const uvField = new LabelElement( 'UV' ).setInput( 2 );
  54. uvField.onValid( onNodeValidElement ).onConnect( () => {
  55. const node = this.value;
  56. node.uvNode = uvField.getLinkedObject() || defaultUV;
  57. } );
  58. this.wrapSInput = new SelectInput( [
  59. { name: 'Repeat Wrapping', value: RepeatWrapping },
  60. { name: 'Clamp To Edge Wrapping', value: ClampToEdgeWrapping },
  61. { name: 'Mirrored Repeat Wrapping', value: MirroredRepeatWrapping }
  62. ], RepeatWrapping ).onChange( () => {
  63. this.update();
  64. } );
  65. this.wrapTInput = new SelectInput( [
  66. { name: 'Repeat Wrapping', value: RepeatWrapping },
  67. { name: 'Clamp To Edge Wrapping', value: ClampToEdgeWrapping },
  68. { name: 'Mirrored Repeat Wrapping', value: MirroredRepeatWrapping }
  69. ], RepeatWrapping ).onChange( () => {
  70. this.update();
  71. } );
  72. this.flipYInput = new ToggleInput( false ).onChange( () => {
  73. this.update();
  74. } );
  75. this.add( uvField )
  76. .add( new LabelElement( 'Wrap S' ).add( this.wrapSInput ) )
  77. .add( new LabelElement( 'Wrap T' ).add( this.wrapTInput ) )
  78. .add( new LabelElement( 'Flip Y' ).add( this.flipYInput ) );
  79. }
  80. update() {
  81. const texture = this.texture;
  82. if ( texture ) {
  83. texture.wrapS = Number( this.wrapSInput.getValue() );
  84. texture.wrapT = Number( this.wrapTInput.getValue() );
  85. texture.flipY = this.flipYInput.getValue();
  86. texture.dispose();
  87. this.invalidate();
  88. }
  89. }
  90. }