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
//a Imports
use std::cell::RefCell;

use crate::{ByteBuffer, Renderable};

//a BufferData
//tp BufferData
/// A data buffer for use with vertex data. It may be indices
/// or vertex coordinates etc.
///
/// A data buffer may contain a lot of data per vertex, such as
/// position, normal, tangent, color etc.  a `BufferView` on the data is
/// then a subset of this data - perhaps picking out just the
/// position, for example, for a set of vertices
///
/// The data buffer may, indeed, contain data for more than one object
/// - and the objects may have different data per vertex. The data
/// buffer is pretty free-form, it is a `BufferView` on the [BufferData] which
/// identifies the object it applies to, and the vertex attributes
/// required.
///
/// A data buffer may then be used by many `BufferView`s. Each `BufferView` may be
/// used by many primitives for a single model; alternatively,
/// primitives may have their own individual `BufferViews`.
///
/// A client may have one copy of the data for all the primitives and models.
pub struct BufferData<'a, R: Renderable> {
    /// Data buffer itself
    data: &'a [u8],
    /// Offset in to the data buffer for the first byte
    pub byte_offset: u32,
    /// Length of data used in the buffer
    pub byte_length: u32,
    /// The client bound to data\[byte_offset\] .. + byte_length
    ///
    /// This must be held as a [RefCell] as the [BufferData] is
    /// created early in the process, prior to any `BufferView`s using
    /// it - which then have shared references to the data - but the
    /// client is created afterwards
    rc_client: RefCell<R::Buffer>,
}

//ip Debug for BufferData
impl<'a, R: Renderable> std::fmt::Debug for BufferData<'a, R> {
    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        let (data, cont) = {
            if self.data.len() < 8 {
                (self.data, "")
            } else {
                (&self.data[0..8], "...")
            }
        };
        write!(
            fmt,
            "BufferData {{{0:?}{cont}#{4}, byte_offset:{1}, byte_length:{2}, client:{3:?}}}",
            data,
            self.byte_offset,
            self.byte_length,
            self.rc_client,
            self.data.len(),
        )
    }
}

//ip BufferData
impl<'a, R: Renderable> BufferData<'a, R> {
    //fp new
    /// Create a new [BufferData] given a buffer, offset and length; if the
    /// length is zero then the whole of the data buffer post offset
    /// is used
    ///
    /// If offset and length are both zero, then all the data is used
    pub fn new<B: ByteBuffer + ?Sized>(data: &'a B, byte_offset: u32, byte_length: u32) -> Self {
        let byte_length = {
            if byte_length == 0 {
                (data.byte_length() as u32) - byte_offset
            } else {
                byte_length
            }
        };
        let rc_client = RefCell::new(R::Buffer::default());
        let data = data.borrow_bytes();
        assert!(
            byte_offset + byte_length <= data.len() as u32,
            "Buffer is not large enough for data {} + #{} [ got {}]",
            byte_offset,
            byte_length,
            data.len()
        );
        Self {
            data,
            byte_offset,
            byte_length,
            rc_client,
        }
    }

    //mp create_client
    /// Replace the client data with one of this data
    pub fn create_client(&self, renderable: &mut R) {
        use std::ops::DerefMut;
        renderable.init_buffer_data_client(self.rc_client.borrow_mut().deref_mut(), self);
    }

    //ap borrow_client
    /// Borrow the client
    pub fn borrow_client(&self) -> std::cell::Ref<R::Buffer> {
        self.rc_client.borrow()
    }

    //mp as_ptr
    /// Get a const u8 ptr to the data itself
    pub fn as_ptr(&self) -> *const u8 {
        unsafe { self.data.as_ptr().add(self.byte_offset as usize) }
    }

    //mp as_slice
    /// Get the slice that is the data itself
    pub fn as_slice(&self) -> &[u8] {
        let start = self.byte_offset as usize;
        let end = (self.byte_offset + self.byte_length) as usize;
        self.data.get(start..end).unwrap()
    }

    //zz All done
}

//ip Display for BufferData
impl<'a, R: Renderable + ?Sized> std::fmt::Display for BufferData<'a, R> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        let data_ptr = self.data.as_ptr();
        write!(
            f,
            "BufferData[{:?}+{}#{}]:GL({})",
            data_ptr,
            self.byte_offset,
            self.byte_length,
            self.rc_client.borrow()
        )
    }
}

//ip DefaultIndentedDisplay for BufferData
impl<'a, R: Renderable + ?Sized> indent_display::DefaultIndentedDisplay for BufferData<'a, R> {}