@archvisioninc/canvas 2.8.7 → 3.1.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/README.md CHANGED
@@ -1,2 +1,2 @@
1
- ## GET STARTED
1
+ ## GET STARTED
2
2
  Please see [developer documentation](https://github.com/ArchvisionInc/archvision-canvas/blob/main/README_DEV.md), in the repository.
@@ -139,6 +139,115 @@ const applyUVSettings = args => {
139
139
  texture.vScale = uvYScale;
140
140
  }
141
141
  };
142
+
143
+ // TODO: Future uses should support red, green, blue, and alpha channels with defaults for each
144
+ const combineMetallicRoughnessTextures = (metallicImage, roughnessImage) => {
145
+ const roughnessHeight = roughnessImage?.naturalHeight ?? 0;
146
+ const roughnessWidth = roughnessImage?.naturalWidth ?? 0;
147
+ const metallicHeight = metallicImage?.naturalHeight ?? 0;
148
+ const metallicWidth = metallicImage?.naturalWidth ?? 0;
149
+ let roughnessData;
150
+ let metallicData;
151
+ const maxHeight = Math.max(...[roughnessHeight, metallicHeight, 1024]);
152
+ const maxWidth = Math.max(...[roughnessWidth, metallicWidth, 1024]);
153
+ const canvas = document.createElement('canvas');
154
+ const ctx = canvas.getContext('2d');
155
+ canvas.width = maxWidth;
156
+ canvas.height = maxHeight;
157
+ if (roughnessImage) {
158
+ ctx.drawImage(roughnessImage, 0, 0, maxWidth, maxHeight);
159
+ roughnessData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
160
+ }
161
+ if (metallicImage) {
162
+ ctx.drawImage(metallicImage, 0, 0, maxWidth, maxHeight);
163
+ metallicData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
164
+ }
165
+ const combinedImageData = ctx.createImageData(maxWidth, maxHeight);
166
+ const combinedData = combinedImageData.data;
167
+ for (let i = 0; i < combinedData.length; i += 4) {
168
+ combinedData[i] = 255;
169
+ combinedData[i + 1] = roughnessData ? roughnessData[i + 1] : 255;
170
+ combinedData[i + 2] = metallicData ? metallicData[i + 2] : 255;
171
+ combinedData[i + 3] = 255;
172
+ }
173
+ ctx.putImageData(combinedImageData, 0, 0);
174
+ return canvas.toDataURL('image/png');
175
+ };
176
+
177
+ // eslint-disable-next-line
178
+ const loadImage = async file => {
179
+ return new Promise(resolve => {
180
+ const reader = new FileReader();
181
+ reader.onload = event => {
182
+ const img = new Image();
183
+ img.onload = () => resolve(img);
184
+ img.onerror = () => {
185
+ resolve(null);
186
+ };
187
+ img.src = event.target.result;
188
+ };
189
+ reader.onerror = () => {
190
+ resolve(null);
191
+ };
192
+ reader.readAsDataURL(file);
193
+ });
194
+ };
195
+ const textureToImage = texture => {
196
+ return new Promise(resolve => {
197
+ if (!texture.readPixels()) {
198
+ resolve(null);
199
+ return;
200
+ }
201
+ texture.readPixels().then(pixels => {
202
+ const canvas = document.createElement('canvas');
203
+ const ctx = canvas.getContext('2d');
204
+ const {
205
+ width,
206
+ height
207
+ } = texture.getSize();
208
+ canvas.width = width;
209
+ canvas.height = height;
210
+ const img = new Image();
211
+ const imageData = ctx.createImageData(width, height);
212
+ imageData.data.set(new Uint8ClampedArray(pixels));
213
+ ctx.putImageData(imageData, 0, 0);
214
+ img.onload = () => {
215
+ resolve(img);
216
+ };
217
+ img.onerror = () => {
218
+ resolve(null);
219
+ };
220
+ img.src = canvas.toDataURL();
221
+ }).catch(() => {
222
+ resolve(null);
223
+ });
224
+ });
225
+ };
226
+ const dataUrlToBlob = dataURI => {
227
+ // convert base64 to raw binary data held in a string
228
+ // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
229
+ const byteString = atob(dataURI.split(',')[1]);
230
+
231
+ // separate out the mime component
232
+ const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
233
+
234
+ // write the bytes of the string to an ArrayBuffer
235
+ const ab = new ArrayBuffer(byteString.length);
236
+
237
+ // create a view into the buffer
238
+ const ia = new Uint8Array(ab);
239
+
240
+ // set the bytes of the buffer to the correct values
241
+ for (let i = 0; i < byteString.length; i++) {
242
+ ia[i] = byteString.charCodeAt(i);
243
+ }
244
+
245
+ // write the ArrayBuffer to a blob, and you're done
246
+ const blob = new Blob([ab], {
247
+ type: mimeString
248
+ });
249
+ return blob;
250
+ };
142
251
  export const updateMaterial = inboundData => {
143
252
  const {
144
253
  payload
@@ -158,6 +267,10 @@ export const updateMaterial = inboundData => {
158
267
  metallic,
159
268
  metallicTexture,
160
269
  roughness,
270
+ roughnessTexture,
271
+ ambientColor,
272
+ ambientTextureStrength,
273
+ ambientTexture,
161
274
  microSurfaceTexture,
162
275
  emissiveColor,
163
276
  emissiveIntensity,
@@ -261,11 +374,31 @@ export const updateMaterial = inboundData => {
261
374
  // Metallic
262
375
  if (metallic !== undefined) material.metallic = metallic;
263
376
  if (!_.isEmpty(metallicTexture?.src || metallicTexture?.url)) {
264
- material.metallicTexture = newTexture(metallicTexture?.src || metallicTexture?.url);
265
- material.metallicTexture.name = metallicTexture.name;
266
- applyUVSettings({
267
- texture: material.metallicTexture,
268
- material
377
+ // Metallic Texture uses the B channel of the metallicTexture for a PBRMaterial
378
+ const texture = newTexture(metallicTexture?.src || metallicTexture?.url);
379
+ let currentTexture = material.metallicTexture;
380
+ if (!currentTexture) {
381
+ material.metallicTexture = newTexture();
382
+ material.metallicTexture.name = `${material.name} (Metallic-Roughness)`;
383
+ currentTexture = material.metallicTexture;
384
+ }
385
+ const metallicBlob = dataUrlToBlob(texture.url);
386
+ Promise.all([loadImage(metallicBlob), textureToImage(currentTexture)]).then(data => {
387
+ const [metallicImage, currentImage] = data;
388
+ const combinedTexture = combineMetallicRoughnessTextures(metallicImage, currentImage);
389
+ currentTexture.updateURL(combinedTexture);
390
+ texture.dispose();
391
+ applyUVSettings({
392
+ texture: material.metallicTexture,
393
+ material
394
+ });
395
+ newMetaDataEntry('materials', buildMaterialsArray());
396
+ newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
397
+ }).catch(err => {
398
+ console.log(`Error updating the roughness texture of material: ${material.name}`);
399
+ console.log({
400
+ err
401
+ });
269
402
  });
270
403
  }
271
404
 
@@ -279,6 +412,46 @@ export const updateMaterial = inboundData => {
279
412
  material
280
413
  });
281
414
  }
415
+ if (!_.isEmpty(roughnessTexture?.src || roughnessTexture?.url)) {
416
+ // Roughness Texture uses the G channel of the metallicTexture for a PBRMaterial
417
+ const texture = newTexture(roughnessTexture?.src || roughnessTexture?.url);
418
+ let currentTexture = material.metallicTexture;
419
+ if (!currentTexture) {
420
+ material.metallicTexture = newTexture();
421
+ material.metallicTexture.name = `${material.name} (Metallic-Roughness)`;
422
+ currentTexture = material.metallicTexture;
423
+ }
424
+ const roughnessBlob = dataUrlToBlob(texture.url);
425
+ Promise.all([loadImage(roughnessBlob), textureToImage(currentTexture)]).then(data => {
426
+ const [roughnessImage, metallicImage] = data;
427
+ const combinedTexture = combineMetallicRoughnessTextures(metallicImage, roughnessImage);
428
+ currentTexture.updateURL(combinedTexture);
429
+ texture.dispose();
430
+ applyUVSettings({
431
+ texture: material.metallicTexture,
432
+ material
433
+ });
434
+ newMetaDataEntry('materials', buildMaterialsArray());
435
+ newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
436
+ }).catch(err => {
437
+ console.log(`Error updating the roughness texture of material: ${material.name}`);
438
+ console.log({
439
+ err
440
+ });
441
+ });
442
+ }
443
+
444
+ // Ambient
445
+ if (ambientColor) material.ambientColor = newColor(emissiveColor);
446
+ if (ambientTextureStrength !== undefined) material.ambientTextureStrength = ambientTextureStrength;
447
+ if (!_.isEmpty(ambientTexture?.src || ambientTexture?.url)) {
448
+ material.ambientTexture = newTexture(ambientTexture?.src || ambientTexture?.url);
449
+ material.ambientTexture.name = ambientTexture.name;
450
+ applyUVSettings({
451
+ texture: material.ambientTexture,
452
+ material
453
+ });
454
+ }
282
455
 
283
456
  // Emissive
284
457
  if (emissiveColor) material.emissiveColor = newColor(emissiveColor);
package/jsconfig.json CHANGED
@@ -1,6 +1,6 @@
1
- {
2
- "compilerOptions": {
3
- "baseUrl": "src"
4
- },
5
- "include": ["src"]
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": "src"
4
+ },
5
+ "include": ["src"]
6
6
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archvisioninc/canvas",
3
- "version": "2.8.7",
3
+ "version": "3.1.0",
4
4
  "private": false,
5
5
  "main": "dist/Canvas.js",
6
6
  "module": "dist/Canvas.js",
package/public/index.html CHANGED
@@ -1,21 +1,21 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- <meta name="theme-color" content="#000000" />
8
- <meta
9
- name="description"
10
- content="Web site created using create-react-app"
11
- />
12
- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13
- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
14
- <title>React App</title>
15
- </head>
16
-
17
- <body>
18
- <noscript>You need to enable JavaScript to run this app.</noscript>
19
- <div id="root"></div>
20
- </body>
21
- </html>
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <meta name="theme-color" content="#000000" />
8
+ <meta
9
+ name="description"
10
+ content="Web site created using create-react-app"
11
+ />
12
+ <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13
+ <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
14
+ <title>React App</title>
15
+ </head>
16
+
17
+ <body>
18
+ <noscript>You need to enable JavaScript to run this app.</noscript>
19
+ <div id="root"></div>
20
+ </body>
21
+ </html>
@@ -1,25 +1,25 @@
1
- {
2
- "short_name": "React App",
3
- "name": "Create React App Sample",
4
- "icons": [
5
- {
6
- "src": "favicon.ico",
7
- "sizes": "64x64 32x32 24x24 16x16",
8
- "type": "image/x-icon"
9
- },
10
- {
11
- "src": "logo192.png",
12
- "type": "image/png",
13
- "sizes": "192x192"
14
- },
15
- {
16
- "src": "logo512.png",
17
- "type": "image/png",
18
- "sizes": "512x512"
19
- }
20
- ],
21
- "start_url": ".",
22
- "display": "standalone",
23
- "theme_color": "#000000",
24
- "background_color": "#ffffff"
25
- }
1
+ {
2
+ "short_name": "React App",
3
+ "name": "Create React App Sample",
4
+ "icons": [
5
+ {
6
+ "src": "favicon.ico",
7
+ "sizes": "64x64 32x32 24x24 16x16",
8
+ "type": "image/x-icon"
9
+ },
10
+ {
11
+ "src": "logo192.png",
12
+ "type": "image/png",
13
+ "sizes": "192x192"
14
+ },
15
+ {
16
+ "src": "logo512.png",
17
+ "type": "image/png",
18
+ "sizes": "512x512"
19
+ }
20
+ ],
21
+ "start_url": ".",
22
+ "display": "standalone",
23
+ "theme_color": "#000000",
24
+ "background_color": "#ffffff"
25
+ }
package/public/robots.txt CHANGED
@@ -1,3 +1,3 @@
1
- # https://www.robotstxt.org/robotstxt.html
2
- User-agent: *
3
- Disallow:
1
+ # https://www.robotstxt.org/robotstxt.html
2
+ User-agent: *
3
+ Disallow:
@@ -14,7 +14,7 @@ export const fetchDownloadURL = async args => {
14
14
  if (!_.isEmpty(rpcGuid)) {
15
15
  const servicesURL = `https://api.archvision.services/rpc/v1/integration/${rpcGuid}/download/${format}`;
16
16
  // eslint-disable-next-line
17
- const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2FyY2h2aXNpb24uY29tIiwic3ViIjozOTUxNTcsInRva2VuX3R5cGUiOiJiZWFyZXIiLCJzY29wZSI6ImJhc2ljIiwiYXVkIjoiNDVFUnF3SEV5SWRqbXhkaUU4MUxMbDlFYTN2SzZZQ3dLNWE2R2xEMyIsImlhdCI6MTcwOTY1MDM5OSwiZXhwIjoxNzE0ODM0Mzk5fQ.aCtOw3h-BTTiIEcvb0FeA_XhRpEmzQTfyerRUu4JGuU';
17
+ const token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjE2MDAyMDc3ODQifQ.eyJpZCI6ImowbzVobDJkdXc5ZXZ4bXJubGIxZWh6a3lhYmJmN3d6ZzN3Z2g3c2kiLCJqdGkiOiJqMG81aGwyZHV3OWV2eG1ybmxiMWVoemt5YWJiZjd3emczd2doN3NpIiwiaXNzIjoiaHR0cHM6XC9cL2FyY2h2aXNpb24uY29tIiwiYXVkIjoiNDVFUnF3SEV5SWRqbXhkaUU4MUxMbDlFYTN2SzZZQ3dLNWE2R2xEMyIsInN1YiI6IjM5MDQxOSIsImV4cCI6MTc0ODI3ODEwNiwiaWF0IjoxNzE3MTc4MTA2LCJ0b2tlbl90eXBlIjoiYmVhcmVyIiwic2NvcGUiOiJiYXNpYyJ9.xKpX0xCEdoVpn-GGdmRWcMPp3pEa7PUbMxlhuAsNjL1ZoFIbxwTrAoXDnvozxjdxomxM7nFw05I1caGtfJARPipOSLFgzD1ANYvogmAImg1zXUV8RsHEVaApxhdwUS7IPO13K3QJMGmn-NgqpYly9ZF9XYxZ7twT4JneGmc_WzeairT9qqGLhKXuU_tkJ49tKAXfCSHAFFBkb93nnsrpd-RlsIeQnc7puTqxlKTREzvmW3_RdqO_1X9ohlnn3wWBEFo_a0W770lfWoF1JlJIqd9NIPrgVRG5inRmYNEz6gw5yLHcDDG-Z5DrQExVUJkYV81wBK2krr0AgX45CWTEdQ';
18
18
  const options = {
19
19
  method: 'GET',
20
20
  headers: {
@@ -42,4 +42,4 @@ export const fetchDownloadURL = async args => {
42
42
  clearExisting,
43
43
  );
44
44
  }
45
- };
45
+ };
@@ -177,6 +177,134 @@ const applyUVSettings = args => {
177
177
  }
178
178
  };
179
179
 
180
+ // TODO: Future uses should support red, green, blue, and alpha channels with defaults for each
181
+ const combineMetallicRoughnessTextures = (metallicImage, roughnessImage) => {
182
+ const roughnessHeight = roughnessImage?.naturalHeight ?? 0;
183
+ const roughnessWidth = roughnessImage?.naturalWidth ?? 0;
184
+ const metallicHeight = metallicImage?.naturalHeight ?? 0;
185
+ const metallicWidth = metallicImage?.naturalWidth ?? 0;
186
+
187
+ let roughnessData;
188
+ let metallicData;
189
+
190
+ const maxHeight = Math.max(...[ roughnessHeight, metallicHeight, 1024 ]);
191
+ const maxWidth = Math.max(...[ roughnessWidth, metallicWidth, 1024 ]);
192
+
193
+ const canvas = document.createElement('canvas');
194
+
195
+ const ctx = canvas.getContext('2d');
196
+
197
+ canvas.width = maxWidth;
198
+ canvas.height = maxHeight;
199
+
200
+ if (roughnessImage) {
201
+ ctx.drawImage(roughnessImage, 0, 0, maxWidth, maxHeight);
202
+ roughnessData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
203
+ }
204
+
205
+ if (metallicImage) {
206
+ ctx.drawImage(metallicImage, 0, 0, maxWidth, maxHeight);
207
+ metallicData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
208
+ }
209
+
210
+ const combinedImageData = ctx.createImageData(maxWidth, maxHeight);
211
+ const combinedData = combinedImageData.data;
212
+
213
+ for (let i = 0; i < combinedData.length; i += 4) {
214
+ combinedData[i] = 255;
215
+ combinedData[i + 1] = roughnessData ? roughnessData[i + 1] : 255;
216
+ combinedData[i + 2] = metallicData ? metallicData[i + 2] : 255;
217
+ combinedData[i + 3] = 255;
218
+ }
219
+
220
+ ctx.putImageData(combinedImageData, 0, 0);
221
+
222
+ return canvas.toDataURL('image/png');
223
+
224
+ };
225
+
226
+ // eslint-disable-next-line
227
+ const loadImage = async file => {
228
+ return new Promise(resolve => {
229
+ const reader = new FileReader();
230
+ reader.onload = event => {
231
+ const img = new Image();
232
+ img.onload = () => resolve(img);
233
+ img.onerror = () => {
234
+ resolve(null);
235
+ };
236
+ img.src = event.target.result;
237
+ };
238
+ reader.onerror = () => {
239
+ resolve(null);
240
+ };
241
+ reader.readAsDataURL(file);
242
+ });
243
+ };
244
+
245
+ const textureToImage = texture => {
246
+ return new Promise(resolve => {
247
+ if (!texture.readPixels()) {
248
+ resolve(null);
249
+ return;
250
+ }
251
+ texture.readPixels()
252
+ .then(pixels => {
253
+ const canvas = document.createElement('canvas');
254
+ const ctx = canvas.getContext('2d');
255
+ const { width, height } = texture.getSize();
256
+
257
+ canvas.width = width;
258
+ canvas.height = height;
259
+
260
+ const img = new Image();
261
+ const imageData = ctx.createImageData(width, height);
262
+ imageData.data.set(new Uint8ClampedArray(pixels));
263
+
264
+ ctx.putImageData(imageData, 0, 0);
265
+
266
+ img.onload = () => {
267
+ resolve(img);
268
+ };
269
+
270
+ img.onerror = () => {
271
+ resolve(null);
272
+ };
273
+
274
+
275
+ img.src = canvas.toDataURL();
276
+ })
277
+ .catch(() => {
278
+ resolve(null);
279
+ });
280
+
281
+ });
282
+ };
283
+
284
+ const dataUrlToBlob = dataURI => {
285
+ // convert base64 to raw binary data held in a string
286
+ // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
287
+ const byteString = atob(dataURI.split(',')[1]);
288
+
289
+ // separate out the mime component
290
+ const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
291
+
292
+ // write the bytes of the string to an ArrayBuffer
293
+ const ab = new ArrayBuffer(byteString.length);
294
+
295
+ // create a view into the buffer
296
+ const ia = new Uint8Array(ab);
297
+
298
+ // set the bytes of the buffer to the correct values
299
+ for (let i = 0; i < byteString.length; i++) {
300
+ ia[i] = byteString.charCodeAt(i);
301
+ }
302
+
303
+ // write the ArrayBuffer to a blob, and you're done
304
+ const blob = new Blob([ ab ], { type: mimeString });
305
+ return blob;
306
+ };
307
+
180
308
  export const updateMaterial = inboundData => {
181
309
  const { payload } = inboundData;
182
310
  const {
@@ -194,6 +322,10 @@ export const updateMaterial = inboundData => {
194
322
  metallic,
195
323
  metallicTexture,
196
324
  roughness,
325
+ roughnessTexture,
326
+ ambientColor,
327
+ ambientTextureStrength,
328
+ ambientTexture,
197
329
  microSurfaceTexture,
198
330
  emissiveColor,
199
331
  emissiveIntensity,
@@ -293,10 +425,35 @@ export const updateMaterial = inboundData => {
293
425
  // Metallic
294
426
  if (metallic !== undefined) material.metallic = metallic;
295
427
  if (!_.isEmpty(metallicTexture?.src || metallicTexture?.url)) {
296
- material.metallicTexture = newTexture(metallicTexture?.src || metallicTexture?.url);
297
- material.metallicTexture.name = metallicTexture.name;
428
+ // Metallic Texture uses the B channel of the metallicTexture for a PBRMaterial
429
+ const texture = newTexture(metallicTexture?.src || metallicTexture?.url);
430
+ let currentTexture = material.metallicTexture;
431
+ if (!currentTexture) {
432
+ material.metallicTexture = newTexture();
433
+ material.metallicTexture.name = `${material.name} (Metallic-Roughness)`;
434
+ currentTexture = material.metallicTexture;
435
+ }
298
436
 
299
- applyUVSettings({ texture: material.metallicTexture, material });
437
+ const metallicBlob = dataUrlToBlob(texture.url);
438
+
439
+ Promise.all([
440
+ loadImage(metallicBlob),
441
+ textureToImage(currentTexture),
442
+ ])
443
+ .then(data => {
444
+ const [ metallicImage, currentImage ] = data;
445
+ const combinedTexture = combineMetallicRoughnessTextures(metallicImage, currentImage);
446
+ currentTexture.updateURL(combinedTexture);
447
+
448
+ texture.dispose();
449
+ applyUVSettings({ texture: material.metallicTexture, material });
450
+ newMetaDataEntry('materials', buildMaterialsArray());
451
+ newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
452
+ })
453
+ .catch(err => {
454
+ console.log(`Error updating the roughness texture of material: ${material.name}`);
455
+ console.log({ err });
456
+ });
300
457
  }
301
458
 
302
459
  // Roughness
@@ -308,6 +465,47 @@ export const updateMaterial = inboundData => {
308
465
  applyUVSettings({ texture: material.microSurfaceTexture, material });
309
466
  }
310
467
 
468
+ if (!_.isEmpty(roughnessTexture?.src || roughnessTexture?.url)) {
469
+ // Roughness Texture uses the G channel of the metallicTexture for a PBRMaterial
470
+ const texture = newTexture(roughnessTexture?.src || roughnessTexture?.url);
471
+ let currentTexture = material.metallicTexture;
472
+ if (!currentTexture) {
473
+ material.metallicTexture = newTexture();
474
+ material.metallicTexture.name = `${material.name} (Metallic-Roughness)`;
475
+ currentTexture = material.metallicTexture;
476
+ }
477
+
478
+ const roughnessBlob = dataUrlToBlob(texture.url);
479
+
480
+ Promise.all([ loadImage(roughnessBlob), textureToImage(currentTexture) ])
481
+ .then(data => {
482
+ const [ roughnessImage, metallicImage ] = data;
483
+ const combinedTexture = combineMetallicRoughnessTextures(metallicImage, roughnessImage);
484
+ currentTexture.updateURL(combinedTexture);
485
+
486
+ texture.dispose();
487
+ applyUVSettings({ texture: material.metallicTexture, material });
488
+ newMetaDataEntry('materials', buildMaterialsArray());
489
+ newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
490
+ })
491
+ .catch(err => {
492
+ console.log(`Error updating the roughness texture of material: ${material.name}`);
493
+ console.log({ err });
494
+ });
495
+
496
+ }
497
+
498
+ // Ambient
499
+ if (ambientColor) material.ambientColor = newColor(emissiveColor);
500
+ if (ambientTextureStrength !== undefined) material.ambientTextureStrength = ambientTextureStrength;
501
+ if (!_.isEmpty(ambientTexture?.src || ambientTexture?.url)) {
502
+ material.ambientTexture = newTexture(ambientTexture?.src || ambientTexture?.url);
503
+ material.ambientTexture.name = ambientTexture.name;
504
+
505
+ applyUVSettings({ texture: material.ambientTexture, material });
506
+
507
+ }
508
+
311
509
  // Emissive
312
510
  if (emissiveColor) material.emissiveColor = newColor(emissiveColor);
313
511
  if (emissiveIntensity !== undefined) material.emissiveIntensity = emissiveIntensity;
@@ -948,4 +1146,4 @@ export const updatePublish = inboundData => {
948
1146
  };
949
1147
 
950
1148
  newMetaDataEntry('publish', withOptimizationValues);
951
- };
1149
+ };
@@ -9,7 +9,7 @@ import { updateMaterial, scene } from 'package/helpers';
9
9
  import Canvas from 'package/Canvas';
10
10
  import _ from 'lodash';
11
11
 
12
- const materialMode = true;
12
+ const materialMode = false;
13
13
  const previewMode = false;
14
14
  const demoScene = false;
15
15
  const shaderballGuid = '21-791A-0D8D-F8A0-63F7-5086-471F-69A7-7AB0-00';
@@ -127,6 +127,27 @@ const App = () => {
127
127
  const updatedArray = notifications.filter((item, i) => index !== i);
128
128
  setNotifications(updatedArray);
129
129
  };
130
+ const onImageLoad = args => {
131
+ const inboundData = {
132
+ payload: {
133
+ id: 'Material Metal PBR Rich',
134
+ metallicTexture: args,
135
+ },
136
+ };
137
+
138
+ updateMaterial(inboundData);
139
+
140
+ };
141
+
142
+ const handleUpload = e => {
143
+ const file = e.currentTarget.files[0];
144
+ const reader = new FileReader();
145
+ reader.readAsDataURL(file);
146
+ reader.onload = () => onImageLoad({
147
+ name: file.name,
148
+ src: reader.result,
149
+ });
150
+ };
130
151
 
131
152
  useEffect(() => {
132
153
  getPreviewURL();
@@ -189,6 +210,12 @@ const App = () => {
189
210
  Import material
190
211
  </Button>
191
212
 
213
+ <input
214
+ type={'file'}
215
+ onChange={handleUpload}
216
+ accept={'image/*'}
217
+ />
218
+
192
219
  <Button
193
220
  theme={theme}
194
221
  $selectedTheme={selectedTheme}
@@ -249,4 +276,4 @@ const App = () => {
249
276
  );
250
277
  };
251
278
 
252
- export default App;
279
+ export default App;
@@ -1,8 +1,8 @@
1
- import { render, screen } from '@testing-library/react';
2
- import App from './App';
3
-
4
- test('renders learn react link', () => {
5
- render(<App />);
6
- const linkElement = screen.getByText(/learn react/i);
7
- expect(linkElement).toBeInTheDocument();
8
- });
1
+ import { render, screen } from '@testing-library/react';
2
+ import App from './App';
3
+
4
+ test('renders learn react link', () => {
5
+ render(<App />);
6
+ const linkElement = screen.getByText(/learn react/i);
7
+ expect(linkElement).toBeInTheDocument();
8
+ });
package/src/setupTests.js CHANGED
@@ -1,5 +1,5 @@
1
- // jest-dom adds custom jest matchers for asserting on DOM nodes.
2
- // allows you to do things like:
3
- // expect(element).toHaveTextContent(/react/i)
4
- // learn more: https://github.com/testing-library/jest-dom
5
- import '@testing-library/jest-dom';
1
+ // jest-dom adds custom jest matchers for asserting on DOM nodes.
2
+ // allows you to do things like:
3
+ // expect(element).toHaveTextContent(/react/i)
4
+ // learn more: https://github.com/testing-library/jest-dom
5
+ import '@testing-library/jest-dom';