@archvisioninc/canvas 3.0.0 → 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.
@@ -142,26 +142,32 @@ const applyUVSettings = args => {
142
142
 
143
143
  // TODO: Future uses should support red, green, blue, and alpha channels with defaults for each
144
144
  const combineMetallicRoughnessTextures = (metallicImage, roughnessImage) => {
145
- const roughnessHeight = roughnessImage.naturalHeight;
146
- const roughnessWidth = roughnessImage.naturalWidth;
147
- const metallicHeight = metallicImage.naturalHeight;
148
- const metallicWidth = metallicImage.naturalWidth;
149
- const maxHeight = Math.max(roughnessHeight, metallicHeight);
150
- const maxWidth = Math.max(roughnessWidth, metallicWidth);
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]);
151
153
  const canvas = document.createElement('canvas');
152
154
  const ctx = canvas.getContext('2d');
153
155
  canvas.width = maxWidth;
154
156
  canvas.height = maxHeight;
155
- ctx.drawImage(roughnessImage, 0, 0, maxWidth, maxHeight);
156
- const roughnessData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
157
- ctx.drawImage(metallicImage, 0, 0, maxWidth, maxHeight);
158
- const metallicData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
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
+ }
159
165
  const combinedImageData = ctx.createImageData(maxWidth, maxHeight);
160
166
  const combinedData = combinedImageData.data;
161
167
  for (let i = 0; i < combinedData.length; i += 4) {
162
168
  combinedData[i] = 255;
163
- combinedData[i + 1] = roughnessData[i + 1];
164
- combinedData[i + 2] = metallicData[i + 2];
169
+ combinedData[i + 1] = roughnessData ? roughnessData[i + 1] : 255;
170
+ combinedData[i + 2] = metallicData ? metallicData[i + 2] : 255;
165
171
  combinedData[i + 3] = 255;
166
172
  }
167
173
  ctx.putImageData(combinedImageData, 0, 0);
@@ -170,22 +176,28 @@ const combineMetallicRoughnessTextures = (metallicImage, roughnessImage) => {
170
176
 
171
177
  // eslint-disable-next-line
172
178
  const loadImage = async file => {
173
- return new Promise((resolve, reject) => {
179
+ return new Promise(resolve => {
174
180
  const reader = new FileReader();
175
181
  reader.onload = event => {
176
182
  const img = new Image();
177
- img.onload = () => {
178
- resolve(img);
183
+ img.onload = () => resolve(img);
184
+ img.onerror = () => {
185
+ resolve(null);
179
186
  };
180
- img.onerror = reject;
181
187
  img.src = event.target.result;
182
188
  };
183
- reader.onerror = reject;
189
+ reader.onerror = () => {
190
+ resolve(null);
191
+ };
184
192
  reader.readAsDataURL(file);
185
193
  });
186
194
  };
187
- const textureToImage = (texture, textureName) => {
188
- return new Promise((resolve, reject) => {
195
+ const textureToImage = texture => {
196
+ return new Promise(resolve => {
197
+ if (!texture.readPixels()) {
198
+ resolve(null);
199
+ return;
200
+ }
189
201
  texture.readPixels().then(pixels => {
190
202
  const canvas = document.createElement('canvas');
191
203
  const ctx = canvas.getContext('2d');
@@ -202,11 +214,12 @@ const textureToImage = (texture, textureName) => {
202
214
  img.onload = () => {
203
215
  resolve(img);
204
216
  };
205
- img.onerror = event => {
206
- console.log(`Error loading image: ${textureName}`);
207
- reject(event);
217
+ img.onerror = () => {
218
+ resolve(null);
208
219
  };
209
220
  img.src = canvas.toDataURL();
221
+ }).catch(() => {
222
+ resolve(null);
210
223
  });
211
224
  });
212
225
  };
@@ -255,6 +268,9 @@ export const updateMaterial = inboundData => {
255
268
  metallicTexture,
256
269
  roughness,
257
270
  roughnessTexture,
271
+ ambientColor,
272
+ ambientTextureStrength,
273
+ ambientTexture,
258
274
  microSurfaceTexture,
259
275
  emissiveColor,
260
276
  emissiveIntensity,
@@ -363,10 +379,11 @@ export const updateMaterial = inboundData => {
363
379
  let currentTexture = material.metallicTexture;
364
380
  if (!currentTexture) {
365
381
  material.metallicTexture = newTexture();
382
+ material.metallicTexture.name = `${material.name} (Metallic-Roughness)`;
366
383
  currentTexture = material.metallicTexture;
367
384
  }
368
385
  const metallicBlob = dataUrlToBlob(texture.url);
369
- Promise.all([loadImage(metallicBlob), textureToImage(currentTexture, 'metallic')]).then(data => {
386
+ Promise.all([loadImage(metallicBlob), textureToImage(currentTexture)]).then(data => {
370
387
  const [metallicImage, currentImage] = data;
371
388
  const combinedTexture = combineMetallicRoughnessTextures(metallicImage, currentImage);
372
389
  currentTexture.updateURL(combinedTexture);
@@ -375,7 +392,14 @@ export const updateMaterial = inboundData => {
375
392
  texture: material.metallicTexture,
376
393
  material
377
394
  });
378
- }).catch(() => console.log(`Error updating the metallic texture of material: ${material.name}`));
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
+ });
402
+ });
379
403
  }
380
404
 
381
405
  // Roughness
@@ -394,10 +418,11 @@ export const updateMaterial = inboundData => {
394
418
  let currentTexture = material.metallicTexture;
395
419
  if (!currentTexture) {
396
420
  material.metallicTexture = newTexture();
421
+ material.metallicTexture.name = `${material.name} (Metallic-Roughness)`;
397
422
  currentTexture = material.metallicTexture;
398
423
  }
399
424
  const roughnessBlob = dataUrlToBlob(texture.url);
400
- Promise.all([loadImage(roughnessBlob), textureToImage(currentTexture, 'metallic')]).then(data => {
425
+ Promise.all([loadImage(roughnessBlob), textureToImage(currentTexture)]).then(data => {
401
426
  const [roughnessImage, metallicImage] = data;
402
427
  const combinedTexture = combineMetallicRoughnessTextures(metallicImage, roughnessImage);
403
428
  currentTexture.updateURL(combinedTexture);
@@ -406,7 +431,26 @@ export const updateMaterial = inboundData => {
406
431
  texture: material.metallicTexture,
407
432
  material
408
433
  });
409
- }).catch(() => console.log(`Error updating the roughness texture of material: ${material.name}`));
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
+ });
410
454
  }
411
455
 
412
456
  // Emissive
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archvisioninc/canvas",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "private": false,
5
5
  "main": "dist/Canvas.js",
6
6
  "module": "dist/Canvas.js",
@@ -179,13 +179,16 @@ const applyUVSettings = args => {
179
179
 
180
180
  // TODO: Future uses should support red, green, blue, and alpha channels with defaults for each
181
181
  const combineMetallicRoughnessTextures = (metallicImage, roughnessImage) => {
182
- const roughnessHeight = roughnessImage.naturalHeight;
183
- const roughnessWidth = roughnessImage.naturalWidth;
184
- const metallicHeight = metallicImage.naturalHeight;
185
- const metallicWidth = metallicImage.naturalWidth;
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
186
 
187
- const maxHeight = Math.max(roughnessHeight, metallicHeight);
188
- const maxWidth = Math.max(roughnessWidth, metallicWidth);
187
+ let roughnessData;
188
+ let metallicData;
189
+
190
+ const maxHeight = Math.max(...[ roughnessHeight, metallicHeight, 1024 ]);
191
+ const maxWidth = Math.max(...[ roughnessWidth, metallicWidth, 1024 ]);
189
192
 
190
193
  const canvas = document.createElement('canvas');
191
194
 
@@ -194,19 +197,23 @@ const combineMetallicRoughnessTextures = (metallicImage, roughnessImage) => {
194
197
  canvas.width = maxWidth;
195
198
  canvas.height = maxHeight;
196
199
 
197
- ctx.drawImage(roughnessImage, 0, 0, maxWidth, maxHeight);
198
- const roughnessData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
200
+ if (roughnessImage) {
201
+ ctx.drawImage(roughnessImage, 0, 0, maxWidth, maxHeight);
202
+ roughnessData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
203
+ }
199
204
 
200
- ctx.drawImage(metallicImage, 0, 0, maxWidth, maxHeight);
201
- const metallicData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
205
+ if (metallicImage) {
206
+ ctx.drawImage(metallicImage, 0, 0, maxWidth, maxHeight);
207
+ metallicData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
208
+ }
202
209
 
203
210
  const combinedImageData = ctx.createImageData(maxWidth, maxHeight);
204
211
  const combinedData = combinedImageData.data;
205
212
 
206
213
  for (let i = 0; i < combinedData.length; i += 4) {
207
214
  combinedData[i] = 255;
208
- combinedData[i + 1] = roughnessData[i + 1];
209
- combinedData[i + 2] = metallicData[i + 2];
215
+ combinedData[i + 1] = roughnessData ? roughnessData[i + 1] : 255;
216
+ combinedData[i + 2] = metallicData ? metallicData[i + 2] : 255;
210
217
  combinedData[i + 3] = 255;
211
218
  }
212
219
 
@@ -218,23 +225,29 @@ const combineMetallicRoughnessTextures = (metallicImage, roughnessImage) => {
218
225
 
219
226
  // eslint-disable-next-line
220
227
  const loadImage = async file => {
221
- return new Promise((resolve, reject) => {
228
+ return new Promise(resolve => {
222
229
  const reader = new FileReader();
223
230
  reader.onload = event => {
224
231
  const img = new Image();
225
- img.onload = () => {
226
- resolve(img);
232
+ img.onload = () => resolve(img);
233
+ img.onerror = () => {
234
+ resolve(null);
227
235
  };
228
- img.onerror = reject;
229
236
  img.src = event.target.result;
230
237
  };
231
- reader.onerror = reject;
238
+ reader.onerror = () => {
239
+ resolve(null);
240
+ };
232
241
  reader.readAsDataURL(file);
233
242
  });
234
243
  };
235
244
 
236
- const textureToImage = (texture, textureName) => {
237
- return new Promise((resolve, reject) => {
245
+ const textureToImage = texture => {
246
+ return new Promise(resolve => {
247
+ if (!texture.readPixels()) {
248
+ resolve(null);
249
+ return;
250
+ }
238
251
  texture.readPixels()
239
252
  .then(pixels => {
240
253
  const canvas = document.createElement('canvas');
@@ -254,13 +267,15 @@ const textureToImage = (texture, textureName) => {
254
267
  resolve(img);
255
268
  };
256
269
 
257
- img.onerror = event => {
258
- console.log(`Error loading image: ${textureName}`);
259
- reject(event);
270
+ img.onerror = () => {
271
+ resolve(null);
260
272
  };
261
273
 
262
274
 
263
275
  img.src = canvas.toDataURL();
276
+ })
277
+ .catch(() => {
278
+ resolve(null);
264
279
  });
265
280
 
266
281
  });
@@ -308,6 +323,9 @@ export const updateMaterial = inboundData => {
308
323
  metallicTexture,
309
324
  roughness,
310
325
  roughnessTexture,
326
+ ambientColor,
327
+ ambientTextureStrength,
328
+ ambientTexture,
311
329
  microSurfaceTexture,
312
330
  emissiveColor,
313
331
  emissiveIntensity,
@@ -412,12 +430,16 @@ export const updateMaterial = inboundData => {
412
430
  let currentTexture = material.metallicTexture;
413
431
  if (!currentTexture) {
414
432
  material.metallicTexture = newTexture();
433
+ material.metallicTexture.name = `${material.name} (Metallic-Roughness)`;
415
434
  currentTexture = material.metallicTexture;
416
435
  }
417
436
 
418
437
  const metallicBlob = dataUrlToBlob(texture.url);
419
438
 
420
- Promise.all([ loadImage(metallicBlob), textureToImage(currentTexture, 'metallic') ])
439
+ Promise.all([
440
+ loadImage(metallicBlob),
441
+ textureToImage(currentTexture),
442
+ ])
421
443
  .then(data => {
422
444
  const [ metallicImage, currentImage ] = data;
423
445
  const combinedTexture = combineMetallicRoughnessTextures(metallicImage, currentImage);
@@ -425,8 +447,13 @@ export const updateMaterial = inboundData => {
425
447
 
426
448
  texture.dispose();
427
449
  applyUVSettings({ texture: material.metallicTexture, material });
450
+ newMetaDataEntry('materials', buildMaterialsArray());
451
+ newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
428
452
  })
429
- .catch(() => console.log(`Error updating the metallic texture of material: ${material.name}`));
453
+ .catch(err => {
454
+ console.log(`Error updating the roughness texture of material: ${material.name}`);
455
+ console.log({ err });
456
+ });
430
457
  }
431
458
 
432
459
  // Roughness
@@ -444,12 +471,13 @@ export const updateMaterial = inboundData => {
444
471
  let currentTexture = material.metallicTexture;
445
472
  if (!currentTexture) {
446
473
  material.metallicTexture = newTexture();
474
+ material.metallicTexture.name = `${material.name} (Metallic-Roughness)`;
447
475
  currentTexture = material.metallicTexture;
448
476
  }
449
477
 
450
478
  const roughnessBlob = dataUrlToBlob(texture.url);
451
479
 
452
- Promise.all([ loadImage(roughnessBlob), textureToImage(currentTexture, 'metallic') ])
480
+ Promise.all([ loadImage(roughnessBlob), textureToImage(currentTexture) ])
453
481
  .then(data => {
454
482
  const [ roughnessImage, metallicImage ] = data;
455
483
  const combinedTexture = combineMetallicRoughnessTextures(metallicImage, roughnessImage);
@@ -457,8 +485,24 @@ export const updateMaterial = inboundData => {
457
485
 
458
486
  texture.dispose();
459
487
  applyUVSettings({ texture: material.metallicTexture, material });
488
+ newMetaDataEntry('materials', buildMaterialsArray());
489
+ newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
460
490
  })
461
- .catch(() => console.log(`Error updating the roughness texture of material: ${material.name}`));
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 });
462
506
 
463
507
  }
464
508
 
@@ -143,7 +143,10 @@ const App = () => {
143
143
  const file = e.currentTarget.files[0];
144
144
  const reader = new FileReader();
145
145
  reader.readAsDataURL(file);
146
- reader.onload = () => onImageLoad({ name: file.name, src: reader.result });
146
+ reader.onload = () => onImageLoad({
147
+ name: file.name,
148
+ src: reader.result,
149
+ });
147
150
  };
148
151
 
149
152
  useEffect(() => {
@@ -207,7 +210,11 @@ const App = () => {
207
210
  Import material
208
211
  </Button>
209
212
 
210
- <input type={'file'} onChange={handleUpload} accept={'image/*'} />
213
+ <input
214
+ type={'file'}
215
+ onChange={handleUpload}
216
+ accept={'image/*'}
217
+ />
211
218
 
212
219
  <Button
213
220
  theme={theme}