/src/alembic/lib/Alembic/AbcCoreOgawa/SpwImpl.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //-***************************************************************************** |
2 | | // |
3 | | // Copyright (c) 2013, |
4 | | // Sony Pictures Imageworks, Inc. and |
5 | | // Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd. |
6 | | // |
7 | | // All rights reserved. |
8 | | // |
9 | | // Redistribution and use in source and binary forms, with or without |
10 | | // modification, are permitted provided that the following conditions are |
11 | | // met: |
12 | | // * Redistributions of source code must retain the above copyright |
13 | | // notice, this list of conditions and the following disclaimer. |
14 | | // * Redistributions in binary form must reproduce the above |
15 | | // copyright notice, this list of conditions and the following disclaimer |
16 | | // in the documentation and/or other materials provided with the |
17 | | // distribution. |
18 | | // * Neither the name of Sony Pictures Imageworks, nor |
19 | | // Industrial Light & Magic nor the names of their contributors may be used |
20 | | // to endorse or promote products derived from this software without specific |
21 | | // prior written permission. |
22 | | // |
23 | | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
24 | | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
25 | | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
26 | | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
27 | | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
28 | | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
29 | | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
30 | | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
31 | | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
32 | | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
33 | | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 | | // |
35 | | //-***************************************************************************** |
36 | | |
37 | | #include <Alembic/AbcCoreOgawa/SpwImpl.h> |
38 | | #include <Alembic/AbcCoreOgawa/CpwImpl.h> |
39 | | #include <Alembic/AbcCoreOgawa/WriteUtil.h> |
40 | | |
41 | | namespace Alembic { |
42 | | namespace AbcCoreOgawa { |
43 | | namespace ALEMBIC_VERSION_NS { |
44 | | |
45 | | //-***************************************************************************** |
46 | | SpwImpl::SpwImpl( AbcA::CompoundPropertyWriterPtr iParent, |
47 | | Ogawa::OGroupPtr iGroup, |
48 | | PropertyHeaderPtr iHeader, |
49 | | size_t iIndex ) : |
50 | | m_parent( iParent ), m_header( iHeader ), m_group( iGroup ), |
51 | | m_index( iIndex ) |
52 | 0 | { |
53 | 0 | ABCA_ASSERT( m_parent, "Invalid parent" ); |
54 | 0 | ABCA_ASSERT( m_header, "Invalid property header" ); |
55 | 0 | ABCA_ASSERT( m_group, "Invalid group" ); |
56 | | |
57 | 0 | if ( m_header->header.getPropertyType() != AbcA::kScalarProperty ) |
58 | 0 | { |
59 | 0 | ABCA_THROW( "Attempted to create a ScalarPropertyWriter from a " |
60 | 0 | "non-scalar property type" ); |
61 | 0 | } |
62 | 0 | } |
63 | | |
64 | | |
65 | | //-***************************************************************************** |
66 | | SpwImpl::~SpwImpl() |
67 | 0 | { |
68 | 0 | AbcA::ArchiveWriterPtr archive = m_parent->getObject()->getArchive(); |
69 | |
|
70 | 0 | index_t maxSamples = archive->getMaxNumSamplesForTimeSamplingIndex( |
71 | 0 | m_header->timeSamplingIndex ); |
72 | |
|
73 | 0 | Util::uint32_t numSamples = m_header->nextSampleIndex; |
74 | | |
75 | | // a constant property, we wrote the same sample over and over |
76 | 0 | if ( m_header->lastChangedIndex == 0 && numSamples > 0 ) |
77 | 0 | { |
78 | 0 | numSamples = 1; |
79 | 0 | } |
80 | |
|
81 | 0 | if ( maxSamples < numSamples ) |
82 | 0 | { |
83 | 0 | archive->setMaxNumSamplesForTimeSamplingIndex( |
84 | 0 | m_header->timeSamplingIndex, numSamples ); |
85 | 0 | } |
86 | |
|
87 | 0 | Util::SpookyHash hash; |
88 | 0 | hash.Init(0, 0); |
89 | 0 | HashPropertyHeader( m_header->header, hash ); |
90 | | |
91 | | // mix in the accumulated hash if we have samples |
92 | 0 | if ( numSamples != 0 ) |
93 | 0 | { |
94 | 0 | hash.Update( m_hash.d, 16 ); |
95 | 0 | } |
96 | |
|
97 | 0 | Util::uint64_t hash0, hash1; |
98 | 0 | hash.Final( &hash0, &hash1 ); |
99 | 0 | Util::shared_ptr< CpwImpl > parent = |
100 | 0 | Alembic::Util::dynamic_pointer_cast< CpwImpl, |
101 | 0 | AbcA::CompoundPropertyWriter > ( m_parent ); |
102 | 0 | parent->fillHash( m_index, hash0, hash1 ); |
103 | 0 | } |
104 | | |
105 | | //-***************************************************************************** |
106 | | void SpwImpl::setFromPreviousSample() |
107 | 0 | { |
108 | | |
109 | | // Make sure we aren't writing more samples than we have times for |
110 | | // This applies to acyclic sampling only |
111 | 0 | ABCA_ASSERT( |
112 | 0 | !m_header->header.getTimeSampling()->getTimeSamplingType().isAcyclic() |
113 | 0 | || m_header->header.getTimeSampling()->getNumStoredTimes() > |
114 | 0 | m_header->nextSampleIndex, |
115 | 0 | "Can not set more samples than we have times for when using " |
116 | 0 | "Acyclic sampling." ); |
117 | | |
118 | 0 | ABCA_ASSERT( m_header->nextSampleIndex > 0, |
119 | 0 | "Can't set from previous sample before any samples have been written" ); |
120 | | |
121 | 0 | Util::Digest digest = m_previousWrittenSampleID->getKey().digest; |
122 | 0 | Util::SpookyHash::ShortEnd(m_hash.words[0], m_hash.words[1], |
123 | 0 | digest.words[0], digest.words[1]); |
124 | 0 | m_header->nextSampleIndex ++; |
125 | 0 | } |
126 | | |
127 | | //-***************************************************************************** |
128 | | void SpwImpl::setSample( const void *iSamp ) |
129 | 0 | { |
130 | | // Make sure we aren't writing more samples than we have times for |
131 | | // This applies to acyclic sampling only |
132 | 0 | ABCA_ASSERT( |
133 | 0 | !m_header->header.getTimeSampling()->getTimeSamplingType().isAcyclic() |
134 | 0 | || m_header->header.getTimeSampling()->getNumStoredTimes() > |
135 | 0 | m_header->nextSampleIndex, |
136 | 0 | "Can not write more samples than we have times for when using " |
137 | 0 | "Acyclic sampling." ); |
138 | | |
139 | 0 | AbcA::ArraySample samp( iSamp, m_header->header.getDataType(), |
140 | 0 | AbcA::Dimensions(1) ); |
141 | | |
142 | | // The Key helps us analyze the sample. |
143 | 0 | AbcA::ArraySample::Key key = samp.getKey(); |
144 | | |
145 | | // mask out the non-string POD since Ogawa can safely share the same data |
146 | | // even if it originated from a different POD |
147 | | // the non-fixed sizes of our strings (plus added null characters) makes |
148 | | // determing the sie harder so strings are handled seperately |
149 | 0 | if ( key.origPOD != Alembic::Util::kStringPOD && |
150 | 0 | key.origPOD != Alembic::Util::kWstringPOD ) |
151 | 0 | { |
152 | 0 | key.origPOD = Alembic::Util::kInt8POD; |
153 | 0 | key.readPOD = Alembic::Util::kInt8POD; |
154 | 0 | } |
155 | | |
156 | | // We need to write the sample |
157 | 0 | if ( m_header->nextSampleIndex == 0 || |
158 | 0 | !( m_previousWrittenSampleID && |
159 | 0 | key == m_previousWrittenSampleID->getKey() ) ) |
160 | 0 | { |
161 | | |
162 | | // we only need to repeat samples if this is not the first change |
163 | 0 | if (m_header->firstChangedIndex != 0) |
164 | 0 | { |
165 | | // copy the samples from after the last change to the latest index |
166 | 0 | for ( index_t smpI = m_header->lastChangedIndex + 1; |
167 | 0 | smpI < m_header->nextSampleIndex; ++smpI ) |
168 | 0 | { |
169 | 0 | assert( smpI > 0 ); |
170 | 0 | CopyWrittenData( m_group, m_previousWrittenSampleID ); |
171 | 0 | } |
172 | 0 | } |
173 | | |
174 | | // Write this sample, which will update its internal |
175 | | // cache of what the previously written sample was. |
176 | 0 | AbcA::ArchiveWriterPtr awp = this->getObject()->getArchive(); |
177 | | |
178 | | // Write the sample. |
179 | | // This distinguishes between string, wstring, and regular arrays. |
180 | 0 | m_previousWrittenSampleID = |
181 | 0 | WriteData( GetWrittenSampleMap( awp ), m_group, samp, key ); |
182 | |
|
183 | 0 | if (m_header->firstChangedIndex == 0) |
184 | 0 | { |
185 | 0 | m_header->firstChangedIndex = m_header->nextSampleIndex; |
186 | 0 | } |
187 | | // this index is now the last change |
188 | 0 | m_header->lastChangedIndex = m_header->nextSampleIndex; |
189 | 0 | } |
190 | |
|
191 | 0 | if ( m_header->nextSampleIndex == 0 ) |
192 | 0 | { |
193 | 0 | m_hash = m_previousWrittenSampleID->getKey().digest; |
194 | 0 | } |
195 | 0 | else |
196 | 0 | { |
197 | 0 | Util::Digest digest = m_previousWrittenSampleID->getKey().digest; |
198 | 0 | Util::SpookyHash::ShortEnd( m_hash.words[0], m_hash.words[1], |
199 | 0 | digest.words[0], digest.words[1] ); |
200 | 0 | } |
201 | |
|
202 | 0 | m_header->nextSampleIndex ++; |
203 | 0 | } |
204 | | |
205 | | //-***************************************************************************** |
206 | | AbcA::ScalarPropertyWriterPtr SpwImpl::asScalarPtr() |
207 | 0 | { |
208 | 0 | return shared_from_this(); |
209 | 0 | } |
210 | | |
211 | | //-***************************************************************************** |
212 | | size_t SpwImpl::getNumSamples() |
213 | 0 | { |
214 | 0 | return ( size_t )m_header->nextSampleIndex; |
215 | 0 | } |
216 | | |
217 | | //-***************************************************************************** |
218 | | void SpwImpl::setTimeSamplingIndex( Util::uint32_t iIndex ) |
219 | 0 | { |
220 | | // will assert if TimeSamplingPtr not found |
221 | 0 | AbcA::TimeSamplingPtr ts = |
222 | 0 | m_parent->getObject()->getArchive()->getTimeSampling( iIndex ); |
223 | |
|
224 | 0 | ABCA_ASSERT( !ts->getTimeSamplingType().isAcyclic() || |
225 | 0 | ts->getNumStoredTimes() >= m_header->nextSampleIndex, |
226 | 0 | "Already have written more samples than we have times for when using " |
227 | 0 | "Acyclic sampling." ); |
228 | | |
229 | 0 | m_header->header.setTimeSampling(ts); |
230 | 0 | m_header->timeSamplingIndex = iIndex; |
231 | 0 | } |
232 | | |
233 | | //-***************************************************************************** |
234 | | const AbcA::PropertyHeader & SpwImpl::getHeader() const |
235 | 0 | { |
236 | 0 | ABCA_ASSERT( m_header, "Invalid header" ); |
237 | 0 | return m_header->header; |
238 | 0 | } |
239 | | |
240 | | //-***************************************************************************** |
241 | | AbcA::ObjectWriterPtr SpwImpl::getObject() |
242 | 0 | { |
243 | 0 | ABCA_ASSERT( m_parent, "Invalid parent" ); |
244 | 0 | return m_parent->getObject(); |
245 | 0 | } |
246 | | |
247 | | //-***************************************************************************** |
248 | | AbcA::CompoundPropertyWriterPtr SpwImpl::getParent() |
249 | 0 | { |
250 | 0 | ABCA_ASSERT( m_parent, "Invalid parent" ); |
251 | 0 | return m_parent; |
252 | 0 | } |
253 | | |
254 | | } // End namespace ALEMBIC_VERSION_NS |
255 | | } // End namespace AbcCoreOgawa |
256 | | } // End namespace Alembic |