-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathVicarLoader.js
160 lines (113 loc) · 3.59 KB
/
VicarLoader.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import { VicarLoaderBase } from './VicarLoaderBase.js';
import { DataTexture, RGBAFormat, DefaultLoadingManager, LinearFilter, LinearMipMapLinearFilter } from 'three';
/**
* @typedef {Object} VicarTextureResult
* @extends VicarTextureResult
*
* @param {DataTexture} texture
*/
/**
* Three.js implementation of VicarLoaderBase.
*/
export class VicarLoader extends VicarLoaderBase {
/**
* @param {LoadingManager} manager
*/
constructor( manager = DefaultLoadingManager ) {
super();
/**
* @member {LoadingManager}
* @default DefaultLoadingManager
*/
this.manager = manager;
}
/**
* Loads and parses the Vicar file and returns a DataTexture. If a DataTexture is passed into
* the function the data is applied to it.
* @param {String} url
* @param {DataTexture} texture
* @returns {Promise<VicarTextureResult>}
*/
load( url, texture = new DataTexture() ) {
const manager = this.manager;
manager.itemStart( url );
return super.load( url ).then( result => {
return this.parse( result, texture );
} ).catch( err => {
manager.itemError( url, err );
throw err;
} ).finally( result => {
manager.itemEnd( url );
} );
}
/**
* Parses the contents of the given Vicar file and returns a texture with the
* contents. The content of the arrays is mapped to a 255 bit color value
* based on the max values.
* @param {Uint8Array | ArrayBuffer} buffer
* @param {DataTexture} texture
* @returns {DataTexture}
*/
parse( buffer, texture = new DataTexture() ) {
let result = buffer;
if ( buffer instanceof ArrayBuffer || buffer instanceof Uint8Array ) {
result = super.parse( buffer );
}
// find the min and max value
// TODO: figure this out?
let max = - Infinity;
const stride = result.width * result.height;
for ( let i = 0; i < stride; i ++ ) {
const r = result.data[ stride * 0 + i ];
const g = result.data[ stride * 1 + i ];
const b = result.data[ stride * 2 + i ];
// max = Math.max( max, r, g, b );
if ( r ) max = Math.max( max, r );
if ( g ) max = Math.max( max, g );
if ( b ) max = Math.max( max, b );
}
// Assume BSQ organization
const ORG = result.labels.find( label => label.name === 'ORG' ).value;
if ( ORG !== 'BSQ' ) {
throw new Error( 'VicarLoader: File is not in BSQ order which is the only supported organization for the file at the moment.' );
}
let maxValue = max;
if ( ! ( result.data instanceof Float32Array ) || ! ( result.data instanceof Float64Array ) ) {
const usefulBits = Math.ceil( Math.log( max ) / Math.LN2 );
maxValue = 2 ** usefulBits;
} else if ( result.data instanceof Uint8Array ) {
maxValue = 255;
}
const data = new Uint8ClampedArray( stride * 4 );
for ( let i = 0; i < stride; i ++ ) {
const r = result.data[ stride * 0 + i ] / maxValue;
let g, b;
if ( result.depth === 1 ) {
g = r;
b = r;
} else if ( result.depth === 2 ) {
g = result.data[ stride * 1 + i ] / maxValue;
b = 0;
} else {
g = result.data[ stride * 1 + i ] / maxValue;
b = result.data[ stride * 2 + i ] / maxValue;
}
data[ i * 4 + 0 ] = r * 255;
data[ i * 4 + 1 ] = g * 255;
data[ i * 4 + 2 ] = b * 255;
data[ i * 4 + 3 ] = 255;
}
// Vicar files always have 3 dimensions
texture.image.width = result.width;
texture.image.height = result.height;
texture.image.data = data;
texture.minFilter = LinearMipMapLinearFilter;
texture.magFilter = LinearFilter;
texture.format = RGBAFormat;
texture.flipY = true;
texture.generateMipmaps = true;
texture.needsUpdate = true;
result.texture = texture;
return result;
}
}