1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 **************************************************************************/
26 // File: vogl_matrix_state.cpp
27 #include "vogl_matrix_state.h"
29 vogl_matrix_state::vogl_matrix_state()
35 vogl_matrix_state::~vogl_matrix_state()
40 bool vogl_matrix_state::save_matrix_stack(const vogl_context_info &context_info, GLenum matrix, uint index, GLenum depth_get, GLenum matrix_get)
44 VOGL_NOTE_UNUSED(context_info);
46 GL_ENTRYPOINT(glMatrixMode)(matrix);
47 if (vogl_check_gl_error())
51 GL_ENTRYPOINT(glGetIntegerv)(depth_get, &depth);
52 if (vogl_check_gl_error())
54 // This *should* work on AMD because it supports the ARB_imaging subset on compat contexts, and it supports the GL_COLOR matrix and the max stack depth is reported as 10.
55 if (depth_get == GL_COLOR_MATRIX_STACK_DEPTH)
57 vogl_warning_printf("%s: Using GL_COLOR_MATRIX_STACK_DEPTH workaround for AMD drivers - this will purposely force a stack underflow!\n", VOGL_METHOD_NAME);
59 vogl::vector<matrix44D> matrices;
63 GL_ENTRYPOINT(glGetDoublev)(matrix_get, matrix.get_ptr());
64 if (vogl_check_gl_error())
67 matrices.push_back(matrix);
69 GL_ENTRYPOINT(glPopMatrix)();
70 bool failed_popping = vogl_check_gl_error();
72 GL_ENTRYPOINT(glGetDoublev)(matrix_get, matrix.get_ptr());
73 // AMD fails with a stack underflow on the get, not the pop - at least during tracing?
74 if (vogl_check_gl_error())
75 failed_popping = true;
81 for (int i = matrices.size() - 1; i >= 0; i--)
83 if (i != static_cast<int>(matrices.size()) - 1)
85 GL_ENTRYPOINT(glPushMatrix)();
86 if (vogl_check_gl_error())
90 GL_ENTRYPOINT(glLoadMatrixd)(matrices[i].get_ptr());
91 if (vogl_check_gl_error())
95 depth = matrices.size();
106 matrix_vec &vec = m_matrices[matrix_key(matrix, index)];
109 // deepest .. current
112 for (int i = 0; i < depth; i++)
115 GL_ENTRYPOINT(glGetDoublev)(matrix_get, mat.get_ptr());
116 if (vogl_check_gl_error())
119 vec[depth - 1 - i] = mat;
121 if (i != (depth - 1))
123 GL_ENTRYPOINT(glPopMatrix)();
124 if (vogl_check_gl_error())
129 for (int i = 1; i < depth; i++)
131 GL_ENTRYPOINT(glPushMatrix)();
132 if (vogl_check_gl_error())
135 GL_ENTRYPOINT(glLoadMatrixd)(vec[i].get_ptr());
136 if (vogl_check_gl_error())
143 bool vogl_matrix_state::restore_matrix_stack(const vogl_context_info &context_info, GLenum matrix, uint index) const
147 VOGL_NOTE_UNUSED(context_info);
149 const matrix_vec *pVec = m_matrices.find_value(matrix_key(matrix, index));
150 if ((!pVec) || (pVec->size() < 1))
153 GL_ENTRYPOINT(glMatrixMode)(matrix);
154 if (vogl_check_gl_error())
157 // deepest .. current
160 for (uint i = 0; i < pVec->size(); i++)
164 GL_ENTRYPOINT(glPushMatrix)();
165 if (vogl_check_gl_error())
169 GL_ENTRYPOINT(glLoadMatrixd)((*pVec)[i].get_ptr());
170 if (vogl_check_gl_error())
177 bool vogl_matrix_state::snapshot(const vogl_context_info &context_info)
183 bool any_errors = false;
187 vogl_scoped_state_saver state_saver(cGSTActiveTexture, cGSTMatrixMode);
189 if (vogl_check_gl_error())
192 if (!save_matrix_stack(context_info, GL_PROJECTION, 0, GL_PROJECTION_STACK_DEPTH, GL_PROJECTION_MATRIX))
195 if (!save_matrix_stack(context_info, GL_MODELVIEW, 0, GL_MODELVIEW_STACK_DEPTH, GL_MODELVIEW_MATRIX))
198 if (!save_matrix_stack(context_info, GL_COLOR, 0, GL_COLOR_MATRIX_STACK_DEPTH, GL_COLOR_MATRIX))
201 for (uint texcoord_index = 0; texcoord_index < context_info.get_max_texture_coords(); texcoord_index++)
203 GL_ENTRYPOINT(glActiveTexture)(GL_TEXTURE0 + texcoord_index);
205 if (vogl_check_gl_error())
208 if (!save_matrix_stack(context_info, GL_TEXTURE, texcoord_index, GL_TEXTURE_STACK_DEPTH, GL_TEXTURE_MATRIX))
212 for (uint i = 0; i < context_info.get_max_arb_program_matrices(); i++)
214 if (!save_matrix_stack(context_info, GL_MATRIX0_ARB + i, 0, GL_CURRENT_MATRIX_STACK_DEPTH_ARB, GL_CURRENT_MATRIX_ARB))
226 bool vogl_matrix_state::restore(const vogl_context_info &context_info) const
233 bool any_errors = false;
237 vogl_scoped_state_saver state_saver(cGSTActiveTexture, cGSTMatrixMode);
239 if (vogl_check_gl_error())
242 if (!restore_matrix_stack(context_info, GL_PROJECTION, 0))
245 if (!restore_matrix_stack(context_info, GL_MODELVIEW, 0))
248 if (!restore_matrix_stack(context_info, GL_COLOR, 0))
251 // TODO: Check to make sure we can actually restore the proper # of matrices
252 for (uint texcoord_index = 0; texcoord_index < context_info.get_max_texture_coords(); texcoord_index++)
254 GL_ENTRYPOINT(glActiveTexture)(GL_TEXTURE0 + texcoord_index);
256 if (vogl_check_gl_error())
259 restore_matrix_stack(context_info, GL_TEXTURE, texcoord_index);
262 // TODO: Check to make sure we can actually restore the proper # of matrices
263 for (uint i = 0; i < context_info.get_max_arb_program_matrices(); i++)
265 restore_matrix_stack(context_info, GL_MATRIX0_ARB + i, 0);
271 void vogl_matrix_state::clear()
279 bool vogl_matrix_state::serialize(json_node &node, vogl_blob_manager &blob_manager) const
283 VOGL_NOTE_UNUSED(blob_manager);
290 for (matrix_map::const_iterator it = m_matrices.begin(); it != m_matrices.end(); ++it)
292 json_node &obj_node = node.add_object();
293 obj_node.add_key_value("matrix", g_gl_enums.find_gl_name(it->first.m_target));
294 if (it->first.m_index)
295 obj_node.add_key_value("index", it->first.m_index);
297 json_node &matrices_node = obj_node.add_array("matrices");
298 for (uint i = 0; i < it->second.size(); i++)
300 json_node &matrix_node = matrices_node.add_array();
301 for (uint j = 0; j < 4 * 4; j++)
302 matrix_node.add_value(it->second[i].get_ptr()[j]);
309 bool vogl_matrix_state::deserialize(const json_node &node, const vogl_blob_manager &blob_manager)
313 VOGL_NOTE_UNUSED(blob_manager);
317 if (!node.is_array() || !node.are_all_children_objects())
323 for (uint i = 0; i < node.size(); i++)
325 const json_node &obj_node = *node.get_child(i);
327 GLenum matrix = vogl_get_json_value_as_enum(obj_node, "matrix", GL_NONE);
328 if (matrix == GL_NONE)
334 uint index = obj_node.value_as_uint32("index");
335 if ((index) && (matrix != GL_TEXTURE))
341 const json_node *pMatrices = obj_node.find_child_array("matrices");
342 if ((!pMatrices) || (!pMatrices->are_all_children_arrays()))
348 matrix_vec &matrices = m_matrices[matrix_key(matrix, index)];
349 matrices.resize(pMatrices->size());
351 for (uint i = 0; i < matrices.size(); i++)
353 const json_node *pMatrix = pMatrices->get_value_as_array(i);
354 if ((!pMatrix) || (!pMatrix->is_array()) || (pMatrix->size() != 4 * 4))
357 for (uint j = 0; j < 4 * 4; j++)
358 matrices[i].get_ptr()[j] = pMatrix->value_as_double(j);
367 uint vogl_matrix_state::get_matrix_stack_depth(GLenum target, uint index) const
369 matrix_map::const_iterator iter = m_matrices.find(matrix_key(target, index));
370 if (iter == m_matrices.end())
375 return iter->second.size();
378 const matrix44D *vogl_matrix_state::get_matrix(GLenum target, uint index, uint depth) const
380 matrix_map::const_iterator iter = m_matrices.find(matrix_key(target, index));
381 if (iter == m_matrices.end())
386 if (depth >= iter->second.size())
391 return &(iter->second[depth]);