texturePropertyTabComponent.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. import * as React from "react";
  2. import { GlobalState } from '../../../globalState';
  3. import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture';
  4. import { FileButtonLineComponent } from '../../../sharedComponents/fileButtonLineComponent';
  5. import { Tools } from 'babylonjs/Misc/tools';
  6. import { TextureNodeModel } from './textureNodeModel';
  7. import { TextLineComponent } from '../../../sharedComponents/textLineComponent';
  8. import { LineContainerComponent } from '../../../sharedComponents/lineContainerComponent';
  9. import { TextInputLineComponent } from '../../../sharedComponents/textInputLineComponent';
  10. import { CheckBoxLineComponent } from '../../../sharedComponents/checkBoxLineComponent';
  11. import { Texture } from 'babylonjs/Materials/Textures/texture';
  12. import { SliderLineComponent } from '../../../sharedComponents/sliderLineComponent';
  13. import { FloatLineComponent } from '../../../sharedComponents/floatLineComponent';
  14. import { ButtonLineComponent } from '../../../sharedComponents/buttonLineComponent';
  15. interface ITexturePropertyTabComponentProps {
  16. globalState: GlobalState;
  17. node: TextureNodeModel;
  18. }
  19. export class TexturePropertyTabComponent extends React.Component<ITexturePropertyTabComponentProps, {isEmbedded: boolean}> {
  20. constructor(props: ITexturePropertyTabComponentProps) {
  21. super(props);
  22. let texture = this.props.node.texture as BaseTexture;
  23. this.state = {isEmbedded: !texture || texture.name.substring(0, 4) !== "http"};
  24. }
  25. UNSAFE_componentWillUpdate(nextProps: ITexturePropertyTabComponentProps, nextState: {isEmbedded: boolean}) {
  26. if (nextProps.node !== this.props.node) {
  27. let texture = nextProps.node.texture as BaseTexture;
  28. nextState.isEmbedded = !texture || texture.name.substring(0, 4) !== "http";
  29. }
  30. }
  31. private _generateRandomForCache() {
  32. return 'xxxxxxxxxxxxxxxxxxxx'.replace(/[x]/g, (c) => {
  33. var r = Math.random() * 10 | 0;
  34. return r.toString();
  35. });
  36. }
  37. updateAftertextureLoad() {
  38. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  39. this.props.globalState.onRebuildRequiredObservable.notifyObservers();
  40. }
  41. /**
  42. * Replaces the texture of the node
  43. * @param file the file of the texture to use
  44. */
  45. replaceTexture(file: File) {
  46. if (!this.props.node) {
  47. return;
  48. }
  49. let texture = this.props.node.texture as BaseTexture;
  50. if (!texture) {
  51. this.props.node.texture = new Texture(null, this.props.globalState.nodeMaterial.getScene(), false, false);
  52. texture = this.props.node.texture;
  53. }
  54. Tools.ReadFile(file, (data) => {
  55. var blob = new Blob([data], { type: "octet/stream" });
  56. var reader = new FileReader();
  57. reader.readAsDataURL(blob);
  58. reader.onloadend = () => {
  59. let base64data = reader.result as string;
  60. if (texture.isCube) {
  61. let extension: string | undefined = undefined;
  62. if (file.name.toLowerCase().indexOf(".dds") > 0) {
  63. extension = ".dds";
  64. } else if (file.name.toLowerCase().indexOf(".env") > 0) {
  65. extension = ".env";
  66. }
  67. (texture as Texture).updateURL(base64data, extension, () => this.updateAftertextureLoad());
  68. } else {
  69. (texture as Texture).updateURL(base64data, null, () => this.updateAftertextureLoad());
  70. }
  71. }
  72. }, undefined, true);
  73. }
  74. replaceTextureWithUrl(url: string) {
  75. let texture = this.props.node.texture as BaseTexture;
  76. if (!texture) {
  77. this.props.node.texture = new Texture(url, this.props.globalState.nodeMaterial.getScene(), false, false, undefined, () => {
  78. this.updateAftertextureLoad();
  79. });
  80. return;
  81. }
  82. (texture as Texture).updateURL(url, null, () => this.updateAftertextureLoad());
  83. }
  84. render() {
  85. let url = "";
  86. let texture = this.props.node.texture as BaseTexture;
  87. if (texture && texture.name && texture.name.substring(0, 4) === "http") {
  88. url = texture.name;
  89. }
  90. url = url.replace(/\?nocache=\d+/, "");
  91. return (
  92. <div>
  93. <LineContainerComponent title="GENERAL">
  94. <TextLineComponent label="Type" value="Texture" />
  95. <TextInputLineComponent globalState={this.props.globalState} label="Name" propertyName="name" target={this.props.node.block!} onChange={() => this.props.globalState.onUpdateRequiredObservable.notifyObservers()} />
  96. </LineContainerComponent>
  97. <LineContainerComponent title="PROPERTIES">
  98. <CheckBoxLineComponent label="Auto select UV" propertyName="autoSelectUV" target={this.props.node.block!} onValueChanged={() => {
  99. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  100. }}/> {
  101. texture &&
  102. <CheckBoxLineComponent label="Gamma space" propertyName="gammaSpace" target={texture} onValueChanged={() => {
  103. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  104. }}/>
  105. }
  106. {
  107. texture &&
  108. <CheckBoxLineComponent label="Clamp U" isSelected={() => texture.wrapU === Texture.CLAMP_ADDRESSMODE} onSelect={(value) => {
  109. texture.wrapU = value ? Texture.CLAMP_ADDRESSMODE : Texture.WRAP_ADDRESSMODE;
  110. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  111. }} />
  112. }
  113. {
  114. texture &&
  115. <CheckBoxLineComponent label="Clamp V" isSelected={() => texture.wrapV === Texture.CLAMP_ADDRESSMODE} onSelect={(value) => {
  116. texture.wrapV = value ? Texture.CLAMP_ADDRESSMODE : Texture.WRAP_ADDRESSMODE;
  117. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  118. }} />
  119. }
  120. {
  121. texture &&
  122. <FloatLineComponent label="Offset U" target={texture} propertyName="uOffset"
  123. onChange={() => {
  124. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  125. }}
  126. />
  127. }
  128. {
  129. texture &&
  130. <FloatLineComponent label="Offset V" target={texture} propertyName="vOffset"
  131. onChange={() => {
  132. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  133. }}
  134. />
  135. }
  136. {
  137. texture &&
  138. <FloatLineComponent label="Scale U" target={texture} propertyName="uScale"
  139. onChange={() => {
  140. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  141. }} />
  142. }
  143. {
  144. texture &&
  145. <FloatLineComponent label="Scale V" target={texture} propertyName="vScale"
  146. onChange={() => {
  147. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  148. }} />
  149. }
  150. {
  151. texture &&
  152. <SliderLineComponent label="Rotation U" target={texture} propertyName="uAng" minimum={0} maximum={Math.PI * 2} useEuler={true} step={0.1}
  153. onChange={() => {
  154. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  155. }}
  156. />
  157. }
  158. {
  159. texture &&
  160. <SliderLineComponent label="Rotation V" target={texture} propertyName="vAng" minimum={0} maximum={Math.PI * 2} useEuler={true} step={0.1}
  161. onChange={() => {
  162. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  163. }}
  164. />
  165. }
  166. {
  167. texture &&
  168. <SliderLineComponent label="Rotation W" target={texture} propertyName="wAng" minimum={0} maximum={Math.PI * 2} useEuler={true} step={0.1}
  169. onChange={() => {
  170. this.props.globalState.onUpdateRequiredObservable.notifyObservers();
  171. }}
  172. />
  173. }
  174. </LineContainerComponent>
  175. <LineContainerComponent title="SOURCE">
  176. <CheckBoxLineComponent label="Embed texture" isSelected={() => this.state.isEmbedded} onSelect={value => {
  177. this.setState({isEmbedded: value});
  178. this.props.node.texture = null;
  179. this.updateAftertextureLoad();
  180. }}/>
  181. {
  182. this.state.isEmbedded &&
  183. <FileButtonLineComponent label="Upload" onClick={(file) => this.replaceTexture(file)} accept=".jpg, .png, .tga, .dds, .env" />
  184. }
  185. {
  186. !this.state.isEmbedded &&
  187. <TextInputLineComponent label="Link" globalState={this.props.globalState} value={url} onChange={newUrl => this.replaceTextureWithUrl(newUrl)}/>
  188. }
  189. {
  190. !this.state.isEmbedded && url &&
  191. <ButtonLineComponent label="Refresh" onClick={() => this.replaceTextureWithUrl(url + "?nocache=" + this._generateRandomForCache())}/>
  192. }
  193. </LineContainerComponent>
  194. </div>
  195. );
  196. }
  197. }