| 23 | ) |
| 24 | |
| 25 | func convertSharedExponent(dst, src *Format, data []byte) ([]byte, error) { |
| 26 | // This only covers the bias of GL_EXT_texture_shared_exponent. If we find |
| 27 | // more shared-exponent formats, then we'll need to parameterize this. |
| 28 | const exponentBias = 24 |
| 29 | |
| 30 | // Create an intermediate format that expands the shared exponent to U32 bits |
| 31 | // and all other components to F32. |
| 32 | format := &Format{ |
| 33 | Components: []*Component{ |
| 34 | &Component{ |
| 35 | Channel: Channel_SharedExponent, |
| 36 | DataType: &U32, |
| 37 | Sampling: Linear, |
| 38 | }, |
| 39 | }, |
| 40 | } |
| 41 | for _, c := range dst.Components { |
| 42 | if c.Channel != Channel_SharedExponent && src.Channels().Contains(c.Channel) { |
| 43 | format.Components = append(format.Components, &Component{ |
| 44 | Channel: c.Channel, |
| 45 | DataType: &F32, |
| 46 | Sampling: Linear, |
| 47 | }) |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | // Convert the data to this intermediate format. |
| 52 | data, err := Convert(format, src, data) |
| 53 | if err != nil { |
| 54 | return nil, err |
| 55 | } |
| 56 | |
| 57 | // All components are 4 bytes long. |
| 58 | count := len(data) / (4 * len(format.Components)) |
| 59 | |
| 60 | // In-place scale all non-exponent components by the exponent. |
| 61 | r := endian.Reader(bytes.NewReader(data), device.LittleEndian) |
| 62 | w := endian.Writer(bytes.NewBuffer(data[:0]), device.LittleEndian) |
| 63 | for i := 0; i < count; i++ { |
| 64 | exp := r.Uint32() |
| 65 | scale := float32(math.Pow(2, float64(exp)-exponentBias)) |
| 66 | w.Uint32(0) // padding for exponent |
| 67 | for c := 0; c < len(format.Components)-1; c++ { |
| 68 | v := r.Float32() |
| 69 | w.Float32(v * scale) |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | // Replace the exponent component with padding, and convert to the target |
| 74 | // format. |
| 75 | format.Components[0].Channel = Channel_Undefined |
| 76 | return Convert(dst, format, data) |
| 77 | } |