@@ -164,13 +164,108 @@ function fromHalfFloat( val ) {
164164
165165}
166166
167+ // RGB9E5 packing/unpacking
168+
169+ const RGB9E5_MANTISSA_BITS = 9 ;
170+ const RGB9E5_EXP_BIAS = 15 ;
171+ const RGB9E5_MAX_VALID_BIASED_EXP = 31 ;
172+
173+ const MAX_RGB9E5_EXP = ( RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS ) ;
174+ const RGB9E5_MANTISSA_VALUES = ( 1 << RGB9E5_MANTISSA_BITS ) ;
175+ const MAX_RGB9E5_MANTISSA = ( RGB9E5_MANTISSA_VALUES - 1 ) ;
176+ const MAX_RGB9E5 = ( ( MAX_RGB9E5_MANTISSA ) / RGB9E5_MANTISSA_VALUES * ( 1 << MAX_RGB9E5_EXP ) ) ;
177+
178+ function ClampRange_for_rgb9e5 ( x ) {
179+
180+ if ( x > 0.0 ) {
181+
182+ if ( x >= MAX_RGB9E5 ) {
183+
184+ return MAX_RGB9E5 ;
185+
186+ } else {
187+
188+ return x ;
189+
190+ }
191+
192+ } else {
193+
194+ /* NaN gets here too since comparisons with NaN always fail! */
195+ return 0.0 ;
196+
197+ }
198+
199+ }
200+
201+ function FloorLog2 ( x ) {
202+
203+ return Math . floor ( Math . log2 ( x ) ) ;
204+
205+ }
206+
207+ // reference https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_shared_exponent.txt
208+
209+ function toRGB9E5 ( r , g , b , target ) {
210+
211+ const rc = ClampRange_for_rgb9e5 ( r ) ;
212+ const gc = ClampRange_for_rgb9e5 ( g ) ;
213+ const bc = ClampRange_for_rgb9e5 ( b ) ;
214+
215+ const maxrgb = Math . max ( rc , gc , bc ) ;
216+ let exp_shared = Math . max ( - RGB9E5_EXP_BIAS - 1 , FloorLog2 ( maxrgb ) ) + 1 + RGB9E5_EXP_BIAS ;
217+
218+ let denom = Math . pow ( 2 , exp_shared - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS ) ;
219+ const maxm = Math . floor ( maxrgb / denom + 0.5 ) ;
220+
221+ if ( maxm == MAX_RGB9E5_MANTISSA + 1 ) {
222+
223+ denom *= 2 ;
224+ exp_shared += 1 ;
225+
226+ }
227+
228+ const rm = Math . floor ( rc / denom + 0.5 ) ;
229+ const gm = Math . floor ( gc / denom + 0.5 ) ;
230+ const bm = Math . floor ( bc / denom + 0.5 ) ;
231+
232+ //
233+
234+ target [ 0 ] = ( rm << 0 ) | ( gm << 9 ) | ( bm << 18 ) | ( exp_shared << 27 ) ;
235+
236+ return target ;
237+
238+ }
239+
240+ function fromRGB9E5 ( val , target ) {
241+
242+ const r = ( val [ 0 ] >> 0 ) & 0x1FF ;
243+ const g = ( val [ 0 ] >> 9 ) & 0x1FF ;
244+ const b = ( val [ 0 ] >> 18 ) & 0x1FF ;
245+ const e = ( val [ 0 ] >> 27 ) & 0x01F ;
246+
247+ const exponent = e - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS ;
248+ const scale = Math . pow ( 2 , exponent ) ;
249+
250+ target [ 0 ] = r * scale ;
251+ target [ 1 ] = g * scale ;
252+ target [ 2 ] = b * scale ;
253+
254+ return target ;
255+
256+ }
257+
167258const DataUtils = {
168259 toHalfFloat : toHalfFloat ,
169260 fromHalfFloat : fromHalfFloat ,
261+ toRGB9E5 : toRGB9E5 ,
262+ fromRGB9E5 : fromRGB9E5
170263} ;
171264
172265export {
173266 toHalfFloat ,
174267 fromHalfFloat ,
268+ toRGB9E5 ,
269+ fromRGB9E5 ,
175270 DataUtils
176271} ;
0 commit comments