-
Notifications
You must be signed in to change notification settings - Fork 0
/
FrameState.cpp
325 lines (283 loc) · 13.1 KB
/
FrameState.cpp
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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#include "FrameState.h"
namespace virtualpy {
PositionState::PositionState() {
location = { { 0.0f, 0.0f, 0.0f } };
scale = { { 1.0f, 1.0f, 1.0f } };
orientation = { { 0.0f, 0.0f, 0.0f, 1.0f } };
}
EntityState::EntityState() : entity_id(-1), render_bundle_id(-1), position() {
}
RenderBundleState::RenderBundleState() {
}
RenderBundleState::RenderBundleState(int num_const_buff) {
constant_buffers.resize(num_const_buff);
}
FrameState::FrameState() : color({ { 0.0f, 0.0f, 0.0f } }), entities(), camera_position(), render_bundles() {
}
FrameState::FrameState(std::array<float, 3> col) : color(col), entities(), camera_position(), render_bundles() {
}
FrameStateBuffer::FrameStateBuffer() {
num_valid_states = 0;
}
void FrameStateBuffer::PushState(FrameState new_state) {
write_permission.lock();
LARGE_INTEGER frame_time;
QueryPerformanceCounter(&frame_time);
states.push_back(std::make_pair(frame_time, new_state));
num_valid_states++;
write_permission.unlock();
}
void FrameStateBuffer::PopState() {
states.pop_front();
num_valid_states--;
}
void FrameStateBuffer::PopStates(int num_states_to_remove) {
if (num_states_to_remove > 0) {
int current_num_valid_states = num_valid_states;
if (num_states_to_remove > current_num_valid_states) {
num_states_to_remove = current_num_valid_states;
}
auto first_element_to_remove = states.begin();
auto last_element_to_remove = states.begin();
for (int i = 0; i < num_states_to_remove; i++) {
last_element_to_remove++;
}
states.erase(first_element_to_remove, last_element_to_remove);
num_valid_states.fetch_sub(num_states_to_remove);
}
}
int FrameStateBuffer::GetNumberOfStates() {
return num_valid_states;
}
std::list<std::pair<LARGE_INTEGER, FrameState>>::iterator FrameStateBuffer::GetFirstState() {
return states.begin();
}
EntityState* FrameState::GetEntityStateForId(int entity_id) {
for (std::pair<const int, EntityState>& entity_state : entities) {
if (entity_state.second.entity_id == entity_id) {
return &entity_state.second;
}
}
return NULL;
}
FrameState FrameStateInterpolater::InterpolateBetweenFrameStates(FrameState state_0, FrameState state_1, float weight) {
FrameState new_state;
new_state.color = InterpolateBetweenArrays(state_0.color, state_1.color, weight);
new_state.camera_position = InterpolateBetweenPositionStates(state_0.camera_position, state_1.camera_position, weight);
for (const std::pair<int, EntityState>& state_1_num_entity : state_1.entities) {
const EntityState& state_1_entity = state_1_num_entity.second;
EntityState* state_0_entity = state_0.GetEntityStateForId(state_1_entity.entity_id);
if (state_0_entity == NULL) {
new_state.entities[state_1_entity.entity_id] = state_1_entity;
}
else {
new_state.entities[state_1_entity.entity_id] = InterpolateBetweenEntityStates(*state_0_entity, state_1_entity, weight);
}
}
for (auto render_bundle_iter : state_1.render_bundles) {
auto prev_iter = state_0.render_bundles.find(render_bundle_iter.first);
if (prev_iter == state_0.render_bundles.end()) {
new_state.render_bundles.insert(render_bundle_iter);
}
else {
new_state.render_bundles.insert(std::make_pair(
render_bundle_iter.first,
InterpolateBetweenRenderBundleStates(prev_iter->second, render_bundle_iter.second, weight)));
}
}
return new_state;
}
EntityState FrameStateInterpolater::InterpolateBetweenEntityStates(EntityState state_0, EntityState state_1, float weight) {
EntityState new_state;
new_state.entity_id = state_1.entity_id;
new_state.render_bundle_id = state_1.render_bundle_id;
new_state.position = InterpolateBetweenPositionStates(state_0.position, state_1.position, weight);
return new_state;
}
RenderBundleState FrameStateInterpolater::InterpolateBetweenRenderBundleStates(RenderBundleState state_0, RenderBundleState state_1, float weight) {
if (state_0.constant_buffers.size() != state_1.constant_buffers.size()) {
printf("ERROR: TRYING TO MERGE RENDER BUFFERS WITH DIFFERENT NUMBERS OF VALUES\n");
return RenderBundleState();
}
RenderBundleState new_state;
new_state.constant_buffers.resize(state_0.constant_buffers.size());
for (int i = 0; i < new_state.constant_buffers.size(); i++) {
new_state.constant_buffers[i] = InterpolateBetweenConstantBufferStates(state_0.constant_buffers[i], state_1.constant_buffers[i], weight);
}
return new_state;
}
ConstantBufferState FrameStateInterpolater::InterpolateBetweenConstantBufferStates(ConstantBufferState state_0, ConstantBufferState state_1, float weight) {
ConstantBufferState new_state;
new_state.data = InterpolateBetweenArrays(state_0.data, state_1.data, weight);
return new_state;
}
PositionState FrameStateInterpolater::InterpolateBetweenPositionStates(PositionState state_0, PositionState state_1, float weight) {
PositionState new_state;
new_state.location = InterpolateBetweenArrays(state_0.location, state_1.location, weight);
new_state.scale = InterpolateBetweenArrays(state_0.scale, state_1.scale, weight);
new_state.orientation = Quaternion::Slerp(Quaternion(state_0.orientation), Quaternion(state_1.orientation), weight).GetArray();
//printf("%f %f %f %f\n\t%f %f %f %f\n\t%f %f %f %f\n",
// new_state.orientation[0], new_state.orientation[1], new_state.orientation[2], new_state.orientation[3],
// state_0.orientation[0], state_0.orientation[1], state_0.orientation[2], state_0.orientation[3],
// state_1.orientation[0], state_1.orientation[1], state_1.orientation[2], state_1.orientation[3]);
return new_state;
}
FrameState FrameStateInterpolater::InterpolateCurrentState() {
int number_of_active_states = frame_state_buffer->GetNumberOfStates();
int number_unused_states = 0;
LARGE_INTEGER interpolate_time;
QueryPerformanceCounter(&interpolate_time);
FrameState interpolated_state = this->InterpolateStateFromBuffer(number_of_active_states, &number_unused_states, (long long)interpolate_time.QuadPart);
frame_state_buffer->PopStates(number_unused_states);
// Performance logging code
performance_file << (interpolate_time.QuadPart - prev_count.QuadPart) * seconds_per_count << std::endl;
prev_count = interpolate_time;
// End performance logging code
return interpolated_state;
}
ConstantDelayInterpolater::ConstantDelayInterpolater(FrameStateBuffer* fsb, float num_seconds)
: FrameStateInterpolater(fsb) {
QueryPerformanceFrequency(&frame_timing_prediction);
frame_timing_prediction.QuadPart = frame_timing_prediction.QuadPart * num_seconds;
}
FrameState ConstantDelayPreemptingNoPredictInterpolater::InterpolateStateFromBuffer(int num_available_states, int* number_states_unused, long long interpolate_time) {
//printf("FSNP: ");
if (num_available_states >= 2) {
//printf("n states\n");
auto first_frame = frame_state_buffer->GetFirstState();
auto second_frame = first_frame;
second_frame++;
for (int i = 0; i < num_available_states - 2; i++) {
auto third_frame = second_frame;
third_frame++;
long long dummy_interpolate_time = third_frame->first.QuadPart;
long long time_into_frame = dummy_interpolate_time - second_frame->first.QuadPart;
if (time_into_frame < frame_timing_prediction.QuadPart) {
second_frame->second = InterpolateBetweenFrameStates(first_frame->second, second_frame->second, ((float)time_into_frame) / frame_timing_prediction.QuadPart);
}
second_frame->first.QuadPart = dummy_interpolate_time - frame_timing_prediction.QuadPart;
first_frame = second_frame;
second_frame++;
}
// Now should have two iterators, first_frame and second_frame.
// The current time is some time after both
assert(interpolate_time >= first_frame->first.QuadPart);
assert(interpolate_time >= second_frame->first.QuadPart);
long long time_into_frame = interpolate_time - second_frame->first.QuadPart;
if (time_into_frame >= frame_timing_prediction.QuadPart) {
*number_states_unused = num_available_states - 1;
return second_frame->second;
}
*number_states_unused = num_available_states - 2;
return InterpolateBetweenFrameStates(first_frame->second, second_frame->second, ((float)time_into_frame) / frame_timing_prediction.QuadPart);
}
else if (num_available_states == 1) {
//printf("one state\n");
*number_states_unused = num_available_states - 1;
return frame_state_buffer->GetFirstState()->second;
}
else {
//printf("no states\n");
*number_states_unused = num_available_states - 0;
return FrameState({ { 0.0f, 0.0f, 0.0f } });
}
}
FrameState ConstantDelayNoPreemptingNoPredictInterpolater::InterpolateStateFromBuffer(int num_available_states, int* number_states_unused, long long interpolate_time) {
//printf("FSNP: ");
if (num_available_states >= 2) {
//printf("n states\n");
// The goal is to find the first frame whose display time has not yet
// passed. Then interpolate from the previous frame's display time to
// that frame at that time.
// If no frame has a display time in the future, just display the last frame
// There should always be an old frame whose display time has passed
auto future_frame = frame_state_buffer->GetFirstState();
std::list<std::pair<LARGE_INTEGER, FrameState>>::iterator past_frame;
bool found_future_frame = false;
*number_states_unused = -1;
for (int i = 0; i < num_available_states - 1; i++) {
*number_states_unused += 1;
past_frame = future_frame;
future_frame++;
long long future_frame_display_time = future_frame->first.QuadPart + frame_timing_prediction.QuadPart;
if (future_frame_display_time >= interpolate_time) {
found_future_frame = true;
break;
}
}
// If found_future_frame is false, just display the future_frame as it is
// the latest past frame
// Otherwise future_frame and past_frame are adjacent frames with display
// times stradling the current interpolation time
if (!found_future_frame) {
frame_state_buffer->GetFirstState()->first.QuadPart = max(
interpolate_time - frame_timing_prediction.QuadPart,
frame_state_buffer->GetFirstState()->first.QuadPart);
*number_states_unused = num_available_states - 1;
return future_frame->second;
}
else {
long long time_into_frame = interpolate_time - (past_frame->first.QuadPart + frame_timing_prediction.QuadPart);
long long time_between_frames = future_frame->first.QuadPart - past_frame->first.QuadPart;
return InterpolateBetweenFrameStates(past_frame->second, future_frame->second, ((float)time_into_frame) / time_between_frames);
}
}
else if (num_available_states == 1) {
// If a frame is being displayed by itself after it was intended to be
// displayed then update its intended display time to new frames will
// still smoothly interpolate
frame_state_buffer->GetFirstState()->first.QuadPart = max(
interpolate_time - frame_timing_prediction.QuadPart,
frame_state_buffer->GetFirstState()->first.QuadPart);
*number_states_unused = num_available_states - 1;
return frame_state_buffer->GetFirstState()->second;
}
else {
//printf("no states\n");
*number_states_unused = num_available_states - 0;
return FrameState({ { 0.0f, 0.0f, 0.0f } });
}
}
FrameState ConstantDelayNoPreemeptingExtrapolateInterpolater::InterpolateStateFromBuffer(int num_available_states, int* number_states_unused, long long interpolate_time) {
//printf("FSNP: ");
if (num_available_states >= 2) {
//printf("n states\n");
// The goal is to find the first frame whose display time has not yet
// passed. Then interpolate from the previous frame's display time to
// that frame at that time.
// If no frame has a display time in the future, just display the last frame
// There should always be an old frame whose display time has passed
auto future_frame = frame_state_buffer->GetFirstState();
std::list<std::pair<LARGE_INTEGER, FrameState>>::iterator past_frame;
bool found_future_frame = false;
*number_states_unused = -1;
for (int i = 0; i < num_available_states - 1; i++) {
*number_states_unused += 1;
past_frame = future_frame;
future_frame++;
long long future_frame_display_time = future_frame->first.QuadPart + frame_timing_prediction.QuadPart;
if (future_frame_display_time >= interpolate_time) {
found_future_frame = true;
break;
}
}
// If found_future_frame is false, just display the future_frame as it is
// the latest past frame
// Otherwise future_frame and past_frame are adjacent frames with display
// times stradling the current interpolation time
long long time_into_frame = interpolate_time - (past_frame->first.QuadPart + frame_timing_prediction.QuadPart);
long long time_between_frames = future_frame->first.QuadPart - past_frame->first.QuadPart;
return InterpolateBetweenFrameStates(past_frame->second, future_frame->second, ((float)time_into_frame) / time_between_frames);
}
else if (num_available_states == 1) {
//printf("one state\n");
*number_states_unused = num_available_states - 1;
return frame_state_buffer->GetFirstState()->second;
}
else {
//printf("no states\n");
*number_states_unused = num_available_states - 0;
return FrameState({ { 0.0f, 0.0f, 0.0f } });
}
}
} // virtualpy