Last active
October 11, 2022 21:12
-
-
Save mishuagopian/2be9bf3a792f496189f6525e1d4b1119 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-# TODO: Remove access with [] when proof of concept is finished | |
- if params[:modal] != 'true' | |
- if @model[:company].present? | |
.configurator-header | |
%h1.configurator-header-title | |
= @model[:name].humanize | |
.configurator-header-subtitle | |
.configurator-header-company | |
= @model[:company][:name] | |
- else | |
.configurator-header | |
%h1.configurator-header-title | |
= @model.name.humanize | |
.configurator-header-subtitle | |
.configurator-header-company | |
= @model.company.name | |
-# TODO: Remove access with [] when proof of concept is finished | |
- if @model[:company].present? | |
.configurator{ data: { model: @model.to_json } } | |
.options | |
- @model[:parts].each do |part| | |
.form-group | |
- default_shape = part[:shapes].find{ |s| s[:default] } | |
.option-title | |
= part[:name] | |
= select_tag 'shape', options_for_select(part[:shapes].map { |o| [o[:name], o[:ref_name]] }, default_shape[:name]), { class: "form-control custom-select shape-select shape-select-#{part[:name]}" } | |
= select_tag 'material', options_for_select([]), { class: 'form-control custom-select material-select' } | |
- else | |
.configurator{ data: { path: url_for(@model.glb), model: @model.to_json(:include => { :company => {}, :parts => { :include => { :shapes => { :include => { :materials => {} }}}} }) }} | |
.options | |
- @model.parts.each do |part| | |
.form-group | |
- default_shape = part.shapes.find{ |s| s.default } | |
.option-title | |
= part.name | |
= select_tag 'shape', options_for_select(part.shapes.map { |o| [o.name, o.ref_name] }, default_shape.name), { class: "form-control custom-select shape-select shape-select-#{part.name}" } | |
= select_tag 'material', options_for_select([]), { class: 'form-control custom-select material-select' } | |
.info | |
%strong Grab | |
to rotate. | |
%strong Scroll | |
to zoom. | |
%canvas#c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$(document).on('turbolinks:load', () => { | |
const configurator = $('.configurator'); | |
if (configurator[0]) { | |
const BACKGROUND_COLOR = 0xf1f1f1; | |
// Init the scene | |
const scene = new THREE.Scene(); | |
// Set background | |
scene.background = new THREE.Color(BACKGROUND_COLOR ); | |
scene.fog = new THREE.Fog(BACKGROUND_COLOR, 20, 100); | |
const canvas = document.querySelector('#c'); | |
// Init the renderer | |
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true }); | |
renderer.shadowMap.enabled = true; | |
renderer.gammaFactor = 2.2; | |
renderer.outputEncoding = THREE.sRGBEncoding; | |
renderer.setPixelRatio(window.devicePixelRatio); | |
// Init the environment | |
const rgbeLoader = new RGBELoader().setDataType(THREE.FloatType); | |
rgbeLoader.load('/lightroom_14b.hdr', (texture) => { | |
texture.mapping = THREE.EquirectangularRefractionMapping; | |
scene.environment = texture; | |
}); | |
document.body.appendChild(renderer.domElement); | |
// Add a camera | |
let camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 1000); | |
camera.position.z = 5; | |
camera.position.y = 3; | |
camera.position.x = 0; | |
// Create the model | |
const model = configurator.data('model'); | |
const path = model.path || configurator.data('path'); | |
const activeShapesByPartName = {}; | |
const shapes = {}; | |
const materials = {}; | |
model.parts.forEach(part => { | |
part.shapes.forEach(shape => { | |
shapes[shape.ref_name] = shape; | |
shapes[shape.ref_name].name = part.name; | |
shape.materials.forEach(material => { | |
const materialKey = `${material.ref_name}_${shape.ref_name}`; | |
materials[materialKey] = material; | |
materials[materialKey].shape = shape; | |
}); | |
}); | |
}); | |
const getMaterial = shape => { | |
if (shape.children) { | |
for (let i = 0; i < shape.children.length; i++) { | |
if (utils.js (shape.name, shape.children[i].name)) { | |
return shape.children[i].material; | |
} | |
} | |
} | |
return shape.material; | |
}; | |
const activateShape = (shape, shape3D) => { | |
const partName = shape.name; | |
activeShapesByPartName[partName] = shape; | |
const currentMaterial = getMaterial(shape3D); | |
const shapeSelect = document.getElementsByClassName(`shape-select-${partName}`)[0]; | |
const materialSelect = shapeSelect.parentElement.getElementsByClassName("material-select")[0]; | |
materialSelect.innerHTML = shape.materials.map(m => { | |
const selected = currentMaterial && nameMatch(m.ref_name, currentMaterial.name); | |
return `<option value='${m.ref_name}_${shape.ref_name}'${selected && 'selected=true'}>${m.name}</option>`; | |
}); | |
}; | |
const loadingSpinner = $("#loading_svg"); | |
loadingSpinner.toggleClass("d-none"); | |
let loader = new THREE.GLTFLoader(); | |
let theModel; | |
loader.load(path, (gltf) => { | |
theModel = gltf.scene; | |
theModel.traverse((o) => { | |
if (o.isMesh) { | |
o.castShadow = true; | |
o.receiveShadow = true; | |
} | |
if (nameMatch(o.name, model.configurator_ref_name)) { | |
o.traverse((shape) => { | |
const currentShape = shapes[shape.name]; | |
if (currentShape) { | |
if (!currentShape.default) { | |
shape.visible = false; | |
} else { | |
activateShape(currentShape, shape) | |
} | |
} | |
}); | |
} else if (nameMatch(o.name, 'materiales')) { | |
o.visible = false; | |
} | |
}); | |
theModel.scale.set(2, 2, 2); | |
theModel.rotation.y = Math.PI / 4; | |
theModel.position.y = -1; | |
scene.add(theModel); | |
loadingSpinner.toggleClass("d-none"); | |
}, undefined, console.error); | |
// Listener on shape changes | |
const shapesInput = document.getElementsByClassName("shape-select"); | |
for (shapeInput of shapesInput) { | |
shapeInput.addEventListener("change", (event) => { | |
const shapeName = event.target.value; | |
const partName = shapes[shapeName].name; | |
const currentShape = activeShapesByPartName[partName]; | |
const newShape = shapes[shapeName]; | |
const newShapeObject = theModel.getObjectByName(newShape.ref_name); | |
theModel.getObjectByName(currentShape.ref_name).visible = false; | |
newShapeObject.visible = true; | |
activateShape(newShape, newShapeObject); | |
}) | |
} | |
// Listener on material changes | |
const materialsInput = document.getElementsByClassName("material-select"); | |
for (materialInput of materialsInput) { | |
materialInput.addEventListener("change", (event) => { | |
const materialref_name = event.target.value; | |
const newMaterialMesh = theModel.getObjectByName(materials[materialref_name].ref_name); | |
const currentShape = theModel.getObjectByName(materials[materialref_name].shape.ref_name); | |
if (currentShape.isMesh) { | |
currentShape.material = newMaterialMesh.material; | |
currentShape.material.vertexColors = false; | |
} else { | |
currentShape.children.forEach(mesh => { | |
if (nameMatch(mesh.name, currentShape.name)) { | |
mesh.material = newMaterialMesh.material; | |
mesh.material.vertexColors = false; | |
} | |
}); | |
} | |
}) | |
} | |
// Add lights | |
const DIR_LIGHT_INTENSITY = 0.47; | |
const DIR_LIGHT_Y = 8; | |
const DIR_LIGHT_COORD = 8; | |
let dirLight1 = new THREE.DirectionalLight(0xffffff, DIR_LIGHT_INTENSITY); | |
dirLight1.position.set(-DIR_LIGHT_COORD, DIR_LIGHT_Y, DIR_LIGHT_COORD); | |
scene.add(dirLight1); | |
let dirLight2 = new THREE.DirectionalLight(0xffffff, DIR_LIGHT_INTENSITY); | |
dirLight2.position.set(DIR_LIGHT_COORD, DIR_LIGHT_Y, DIR_LIGHT_COORD); | |
scene.add(dirLight2); | |
let dirLight3 = new THREE.DirectionalLight(0xffffff, DIR_LIGHT_INTENSITY); | |
dirLight3.position.set(-DIR_LIGHT_COORD, DIR_LIGHT_Y, -DIR_LIGHT_COORD); | |
scene.add(dirLight3); | |
let dirLight4 = new THREE.DirectionalLight(0xffffff, DIR_LIGHT_INTENSITY); | |
dirLight4.position.set(DIR_LIGHT_COORD, DIR_LIGHT_Y, -DIR_LIGHT_COORD); | |
scene.add(dirLight4); | |
// Floor | |
let floorGeometry = new THREE.PlaneGeometry(5000, 5000, 1, 1); | |
let floorMaterial = new THREE.MeshPhongMaterial({ | |
color: 0xeeeeee, // This color is manually dialed in to match the background color | |
shininess: 0 | |
}); | |
let floor = new THREE.Mesh(floorGeometry, floorMaterial); | |
floor.rotation.x = -0.5 * Math.PI; | |
floor.receiveShadow = true; | |
floor.position.y = -1; | |
scene.add(floor); | |
// Add controls | |
let controls = new THREE.OrbitControls(camera, renderer.domElement); | |
controls.maxPolarAngle = Math.PI; | |
controls.minPolarAngle = -Math.PI; | |
controls.enableDamping = true; | |
controls.enablePan = false; | |
controls.dampingFactor = 0.1; | |
controls.autoRotate = false; | |
controls.autoRotateSpeed = 0.2; // 30 | |
// Function - New resizing method | |
const resizeRendererToDisplaySize = (renderer) => { | |
const canvas = renderer.domElement; | |
let width = window.innerWidth; | |
let height = window.innerHeight; | |
let canvasPixelWidth = canvas.width / window.devicePixelRatio; | |
let canvasPixelHeight = canvas.height / window.devicePixelRatio; | |
const needResize = canvasPixelWidth !== width || canvasPixelHeight !== height; | |
if (needResize) { | |
renderer.setSize(width, height, false); | |
} | |
return needResize; | |
} | |
const animate = () => { | |
controls.update(); | |
renderer.render(scene, camera); | |
requestAnimationFrame(animate); | |
if (resizeRendererToDisplaySize(renderer)) { | |
const canvas = renderer.domElement; | |
camera.aspect = canvas.clientWidth / canvas.clientHeight; | |
camera.updateProjectionMatrix(); | |
} | |
} | |
animate(); | |
// Disable scrolling | |
window.onscroll = () => { window.scrollTo(0, 0); }; | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { | |
DataTextureLoader, | |
DataUtils, | |
FloatType, | |
HalfFloatType, | |
LinearEncoding, | |
LinearFilter, | |
NearestFilter, | |
RGBEEncoding, | |
RGBEFormat, | |
RGBFormat, | |
UnsignedByteType | |
} = THREE; | |
// https://github.com/mrdoob/three.js/issues/5552 | |
// http://en.wikipedia.org/wiki/RGBE_image_format | |
class RGBELoader extends DataTextureLoader { | |
constructor( manager ) { | |
super( manager ); | |
this.type = UnsignedByteType; | |
} | |
// adapted from http://www.graphics.cornell.edu/~bjw/rgbe.html | |
parse( buffer ) { | |
const | |
/* return codes for rgbe routines */ | |
//RGBE_RETURN_SUCCESS = 0, | |
RGBE_RETURN_FAILURE = - 1, | |
/* default error routine. change this to change error handling */ | |
rgbe_read_error = 1, | |
rgbe_write_error = 2, | |
rgbe_format_error = 3, | |
rgbe_memory_error = 4, | |
rgbe_error = function ( rgbe_error_code, msg ) { | |
switch ( rgbe_error_code ) { | |
case rgbe_read_error: console.error( 'THREE.RGBELoader Read Error: ' + ( msg || '' ) ); | |
break; | |
case rgbe_write_error: console.error( 'THREE.RGBELoader Write Error: ' + ( msg || '' ) ); | |
break; | |
case rgbe_format_error: console.error( 'THREE.RGBELoader Bad File Format: ' + ( msg || '' ) ); | |
break; | |
default: | |
case rgbe_memory_error: console.error( 'THREE.RGBELoader: Error: ' + ( msg || '' ) ); | |
} | |
return RGBE_RETURN_FAILURE; | |
}, | |
/* offsets to red, green, and blue components in a data (float) pixel */ | |
//RGBE_DATA_RED = 0, | |
//RGBE_DATA_GREEN = 1, | |
//RGBE_DATA_BLUE = 2, | |
/* number of floats per pixel, use 4 since stored in rgba image format */ | |
//RGBE_DATA_SIZE = 4, | |
/* flags indicating which fields in an rgbe_header_info are valid */ | |
RGBE_VALID_PROGRAMTYPE = 1, | |
RGBE_VALID_FORMAT = 2, | |
RGBE_VALID_DIMENSIONS = 4, | |
NEWLINE = '\n', | |
fgets = function ( buffer, lineLimit, consume ) { | |
const chunkSize = 128; | |
lineLimit = ! lineLimit ? 1024 : lineLimit; | |
let p = buffer.pos, | |
i = - 1, len = 0, s = '', | |
chunk = String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) ); | |
while ( ( 0 > ( i = chunk.indexOf( NEWLINE ) ) ) && ( len < lineLimit ) && ( p < buffer.byteLength ) ) { | |
s += chunk; len += chunk.length; | |
p += chunkSize; | |
chunk += String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) ); | |
} | |
if ( - 1 < i ) { | |
/*for (i=l-1; i>=0; i--) { | |
byteCode = m.charCodeAt(i); | |
if (byteCode > 0x7f && byteCode <= 0x7ff) byteLen++; | |
else if (byteCode > 0x7ff && byteCode <= 0xffff) byteLen += 2; | |
if (byteCode >= 0xDC00 && byteCode <= 0xDFFF) i--; //trail surrogate | |
}*/ | |
if ( false !== consume ) buffer.pos += len + i + 1; | |
return s + chunk.slice( 0, i ); | |
} | |
return false; | |
}, | |
/* minimal header reading. modify if you want to parse more information */ | |
RGBE_ReadHeader = function ( buffer ) { | |
// regexes to parse header info fields | |
const magic_token_re = /^#\?(\S+)/, | |
gamma_re = /^\s*GAMMA\s*=\s*(\d+(\.\d+)?)\s*$/, | |
exposure_re = /^\s*EXPOSURE\s*=\s*(\d+(\.\d+)?)\s*$/, | |
format_re = /^\s*FORMAT=(\S+)\s*$/, | |
dimensions_re = /^\s*\-Y\s+(\d+)\s+\+X\s+(\d+)\s*$/, | |
// RGBE format header struct | |
header = { | |
valid: 0, /* indicate which fields are valid */ | |
string: '', /* the actual header string */ | |
comments: '', /* comments found in header */ | |
programtype: 'RGBE', /* listed at beginning of file to identify it after "#?". defaults to "RGBE" */ | |
format: '', /* RGBE format, default 32-bit_rle_rgbe */ | |
gamma: 1.0, /* image has already been gamma corrected with given gamma. defaults to 1.0 (no correction) */ | |
exposure: 1.0, /* a value of 1.0 in an image corresponds to <exposure> watts/steradian/m^2. defaults to 1.0 */ | |
width: 0, height: 0 /* image dimensions, width/height */ | |
}; | |
let line, match; | |
if ( buffer.pos >= buffer.byteLength || ! ( line = fgets( buffer ) ) ) { | |
return rgbe_error( rgbe_read_error, 'no header found' ); | |
} | |
/* if you want to require the magic token then uncomment the next line */ | |
if ( ! ( match = line.match( magic_token_re ) ) ) { | |
return rgbe_error( rgbe_format_error, 'bad initial token' ); | |
} | |
header.valid |= RGBE_VALID_PROGRAMTYPE; | |
header.programtype = match[ 1 ]; | |
header.string += line + '\n'; | |
while ( true ) { | |
line = fgets( buffer ); | |
if ( false === line ) break; | |
header.string += line + '\n'; | |
if ( '#' === line.charAt( 0 ) ) { | |
header.comments += line + '\n'; | |
continue; // comment line | |
} | |
if ( match = line.match( gamma_re ) ) { | |
header.gamma = parseFloat( match[ 1 ], 10 ); | |
} | |
if ( match = line.match( exposure_re ) ) { | |
header.exposure = parseFloat( match[ 1 ], 10 ); | |
} | |
if ( match = line.match( format_re ) ) { | |
header.valid |= RGBE_VALID_FORMAT; | |
header.format = match[ 1 ];//'32-bit_rle_rgbe'; | |
} | |
if ( match = line.match( dimensions_re ) ) { | |
header.valid |= RGBE_VALID_DIMENSIONS; | |
header.height = parseInt( match[ 1 ], 10 ); | |
header.width = parseInt( match[ 2 ], 10 ); | |
} | |
if ( ( header.valid & RGBE_VALID_FORMAT ) && ( header.valid & RGBE_VALID_DIMENSIONS ) ) break; | |
} | |
if ( ! ( header.valid & RGBE_VALID_FORMAT ) ) { | |
return rgbe_error( rgbe_format_error, 'missing format specifier' ); | |
} | |
if ( ! ( header.valid & RGBE_VALID_DIMENSIONS ) ) { | |
return rgbe_error( rgbe_format_error, 'missing image size specifier' ); | |
} | |
return header; | |
}, | |
RGBE_ReadPixels_RLE = function ( buffer, w, h ) { | |
const scanline_width = w; | |
if ( | |
// run length encoding is not allowed so read flat | |
( ( scanline_width < 8 ) || ( scanline_width > 0x7fff ) ) || | |
// this file is not run length encoded | |
( ( 2 !== buffer[ 0 ] ) || ( 2 !== buffer[ 1 ] ) || ( buffer[ 2 ] & 0x80 ) ) | |
) { | |
// return the flat buffer | |
return new Uint8Array( buffer ); | |
} | |
if ( scanline_width !== ( ( buffer[ 2 ] << 8 ) | buffer[ 3 ] ) ) { | |
return rgbe_error( rgbe_format_error, 'wrong scanline width' ); | |
} | |
const data_rgba = new Uint8Array( 4 * w * h ); | |
if ( ! data_rgba.length ) { | |
return rgbe_error( rgbe_memory_error, 'unable to allocate buffer space' ); | |
} | |
let offset = 0, pos = 0; | |
const ptr_end = 4 * scanline_width; | |
const rgbeStart = new Uint8Array( 4 ); | |
const scanline_buffer = new Uint8Array( ptr_end ); | |
let num_scanlines = h; | |
// read in each successive scanline | |
while ( ( num_scanlines > 0 ) && ( pos < buffer.byteLength ) ) { | |
if ( pos + 4 > buffer.byteLength ) { | |
return rgbe_error( rgbe_read_error ); | |
} | |
rgbeStart[ 0 ] = buffer[ pos ++ ]; | |
rgbeStart[ 1 ] = buffer[ pos ++ ]; | |
rgbeStart[ 2 ] = buffer[ pos ++ ]; | |
rgbeStart[ 3 ] = buffer[ pos ++ ]; | |
if ( ( 2 != rgbeStart[ 0 ] ) || ( 2 != rgbeStart[ 1 ] ) || ( ( ( rgbeStart[ 2 ] << 8 ) | rgbeStart[ 3 ] ) != scanline_width ) ) { | |
return rgbe_error( rgbe_format_error, 'bad rgbe scanline format' ); | |
} | |
// read each of the four channels for the scanline into the buffer | |
// first red, then green, then blue, then exponent | |
let ptr = 0, count; | |
while ( ( ptr < ptr_end ) && ( pos < buffer.byteLength ) ) { | |
count = buffer[ pos ++ ]; | |
const isEncodedRun = count > 128; | |
if ( isEncodedRun ) count -= 128; | |
if ( ( 0 === count ) || ( ptr + count > ptr_end ) ) { | |
return rgbe_error( rgbe_format_error, 'bad scanline data' ); | |
} | |
if ( isEncodedRun ) { | |
// a (encoded) run of the same value | |
const byteValue = buffer[ pos ++ ]; | |
for ( let i = 0; i < count; i ++ ) { | |
scanline_buffer[ ptr ++ ] = byteValue; | |
} | |
//ptr += count; | |
} else { | |
// a literal-run | |
scanline_buffer.set( buffer.subarray( pos, pos + count ), ptr ); | |
ptr += count; pos += count; | |
} | |
} | |
// now convert data from buffer into rgba | |
// first red, then green, then blue, then exponent (alpha) | |
const l = scanline_width; //scanline_buffer.byteLength; | |
for ( let i = 0; i < l; i ++ ) { | |
let off = 0; | |
data_rgba[ offset ] = scanline_buffer[ i + off ]; | |
off += scanline_width; //1; | |
data_rgba[ offset + 1 ] = scanline_buffer[ i + off ]; | |
off += scanline_width; //1; | |
data_rgba[ offset + 2 ] = scanline_buffer[ i + off ]; | |
off += scanline_width; //1; | |
data_rgba[ offset + 3 ] = scanline_buffer[ i + off ]; | |
offset += 4; | |
} | |
num_scanlines --; | |
} | |
return data_rgba; | |
}; | |
const RGBEByteToRGBFloat = function ( sourceArray, sourceOffset, destArray, destOffset ) { | |
const e = sourceArray[ sourceOffset + 3 ]; | |
const scale = Math.pow( 2.0, e - 128.0 ) / 255.0; | |
destArray[ destOffset + 0 ] = sourceArray[ sourceOffset + 0 ] * scale; | |
destArray[ destOffset + 1 ] = sourceArray[ sourceOffset + 1 ] * scale; | |
destArray[ destOffset + 2 ] = sourceArray[ sourceOffset + 2 ] * scale; | |
}; | |
const RGBEByteToRGBHalf = function ( sourceArray, sourceOffset, destArray, destOffset ) { | |
const e = sourceArray[ sourceOffset + 3 ]; | |
const scale = Math.pow( 2.0, e - 128.0 ) / 255.0; | |
destArray[ destOffset + 0 ] = DataUtils.toHalfFloat( sourceArray[ sourceOffset + 0 ] * scale ); | |
destArray[ destOffset + 1 ] = DataUtils.toHalfFloat( sourceArray[ sourceOffset + 1 ] * scale ); | |
destArray[ destOffset + 2 ] = DataUtils.toHalfFloat( sourceArray[ sourceOffset + 2 ] * scale ); | |
}; | |
const byteArray = new Uint8Array( buffer ); | |
byteArray.pos = 0; | |
const rgbe_header_info = RGBE_ReadHeader( byteArray ); | |
if ( RGBE_RETURN_FAILURE !== rgbe_header_info ) { | |
const w = rgbe_header_info.width, | |
h = rgbe_header_info.height, | |
image_rgba_data = RGBE_ReadPixels_RLE( byteArray.subarray( byteArray.pos ), w, h ); | |
if ( RGBE_RETURN_FAILURE !== image_rgba_data ) { | |
let data, format, type; | |
let numElements; | |
switch ( this.type ) { | |
case UnsignedByteType: | |
data = image_rgba_data; | |
format = RGBEFormat; // handled as THREE.RGBAFormat in shaders | |
type = UnsignedByteType; | |
break; | |
case FloatType: | |
numElements = ( image_rgba_data.length / 4 ) * 3; | |
const floatArray = new Float32Array( numElements ); | |
for ( let j = 0; j < numElements; j ++ ) { | |
RGBEByteToRGBFloat( image_rgba_data, j * 4, floatArray, j * 3 ); | |
} | |
data = floatArray; | |
format = RGBFormat; | |
type = FloatType; | |
break; | |
case HalfFloatType: | |
numElements = ( image_rgba_data.length / 4 ) * 3; | |
const halfArray = new Uint16Array( numElements ); | |
for ( let j = 0; j < numElements; j ++ ) { | |
RGBEByteToRGBHalf( image_rgba_data, j * 4, halfArray, j * 3 ); | |
} | |
data = halfArray; | |
format = RGBFormat; | |
type = HalfFloatType; | |
break; | |
default: | |
console.error( 'THREE.RGBELoader: unsupported type: ', this.type ); | |
break; | |
} | |
return { | |
width: w, height: h, | |
data: data, | |
header: rgbe_header_info.string, | |
gamma: rgbe_header_info.gamma, | |
exposure: rgbe_header_info.exposure, | |
format: format, | |
type: type | |
}; | |
} | |
} | |
return null; | |
} | |
setDataType( value ) { | |
this.type = value; | |
return this; | |
} | |
load( url, onLoad, onProgress, onError ) { | |
function onLoadCallback( texture, texData ) { | |
switch ( texture.type ) { | |
case UnsignedByteType: | |
texture.encoding = RGBEEncoding; | |
texture.minFilter = NearestFilter; | |
texture.magFilter = NearestFilter; | |
texture.generateMipmaps = false; | |
texture.flipY = true; | |
break; | |
case FloatType: | |
texture.encoding = LinearEncoding; | |
texture.minFilter = LinearFilter; | |
texture.magFilter = LinearFilter; | |
texture.generateMipmaps = false; | |
texture.flipY = true; | |
break; | |
case HalfFloatType: | |
texture.encoding = LinearEncoding; | |
texture.minFilter = LinearFilter; | |
texture.magFilter = LinearFilter; | |
texture.generateMipmaps = false; | |
texture.flipY = true; | |
break; | |
} | |
if ( onLoad ) onLoad( texture, texData ); | |
} | |
return super.load( url, onLoadCallback, onProgress, onError ); | |
} | |
} | |
window.RGBELoader = RGBELoader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.nameMatch = (name1 = '', name2 = '') => { | |
if (name1.length === 0 || name2.length === 0) { | |
return false; | |
} | |
const n1 = name1.toLowerCase().trim(); | |
const n2 = name2.toLowerCase().trim(); | |
const sanitizedN1 = n1.replaceAll('_', ' ').replace(/[(0-9)]/g, '').trim(); | |
const sanitizedN2 = n2.replaceAll('_', ' ').replace(/[(0-9)]/g, '').trim(); | |
return n1.includes(n2) || n2.includes(n1) || | |
sanitizedN1.includes(sanitizedN2) || sanitizedN2.includes(sanitizedN1); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment