From 93a3e7e6991d5d3143aba2ea42dfdf7bed52f431 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 8 Oct 2018 14:46:07 +0200 Subject: [PATCH 01/60] Changes to make ColorAttrib behavior more consistent: - T_off now actually properly disables vertex colours - T_vertex is now the default, to preserve the previous behaviour - ShaderGenerator behavior is now the same as in the FFP - tests are updated to verify new behavior - tests now properly use vertex colours, previously they accidentally only used flat colors - With color-scale-via-lighting off and no color scale, color is no longer munged - p3d_Color in GLSL shaders is now properly set to white instead of black with T_off mode - In DX9 shaders will now sample white color for absent or disabled vertex color Fixes #401 Also see #371 --- panda/src/display/graphicsStateGuardian.cxx | 13 +++- panda/src/display/standardMunger.cxx | 20 +------ panda/src/display/standardMunger.h | 5 +- panda/src/dxgsg9/dxGeomMunger9.I | 31 ---------- panda/src/dxgsg9/dxGeomMunger9.cxx | 60 +++++++++++++++++++ panda/src/dxgsg9/dxGeomMunger9.h | 2 +- panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 40 +++++++++++++ panda/src/dxgsg9/dxGraphicsStateGuardian9.h | 8 +-- panda/src/dxgsg9/dxShaderContext9.cxx | 23 +++++++ .../glstuff/glGraphicsStateGuardian_src.cxx | 11 +++- panda/src/glstuff/glShaderContext_src.cxx | 4 +- panda/src/pgraph/colorAttrib.cxx | 2 +- panda/src/pgraph/colorAttrib.h | 2 +- tests/display/test_color_buffer.py | 40 ++++++++++--- 14 files changed, 188 insertions(+), 73 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 1050f8372f..b76a7f751c 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -2722,7 +2722,7 @@ do_issue_color_scale() { } if (_alpha_scale_via_texture && !_has_scene_graph_color && - target_color_scale->has_alpha_scale()) { + _vertex_colors_enabled && target_color_scale->has_alpha_scale()) { // This color scale will set a special texture--so again, clear the // texture. _state_mask.clear_bit(TextureAttrib::get_class_slot()); @@ -3168,6 +3168,17 @@ determine_light_color_scale() { _scene_graph_color[3] * _current_color_scale[3]); } + } else if (!_vertex_colors_enabled) { + // We don't have a scene graph color, but we don't want to enable vertex + // colors either, so we still need to force a white material color in + // absence of any other color. + _has_material_force_color = true; + _material_force_color.set(1.0f, 1.0f, 1.0f, 1.0f); + _light_color_scale.set(1.0f, 1.0f, 1.0f, 1.0f); + if (!_color_blend_involves_color_scale && _color_scale_enabled) { + _material_force_color.componentwise_mult(_current_color_scale); + } + } else { // Otherise, leave the materials alone, but we might still scale the // lights. diff --git a/panda/src/display/standardMunger.cxx b/panda/src/display/standardMunger.cxx index 94f376e99b..4bb96fcfd5 100644 --- a/panda/src/display/standardMunger.cxx +++ b/panda/src/display/standardMunger.cxx @@ -55,24 +55,10 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state, const ColorScaleAttrib *color_scale_attrib; if (state->get_attrib(color_attrib) && - color_attrib->get_color_type() == ColorAttrib::T_flat) { + color_attrib->get_color_type() != ColorAttrib::T_vertex) { - if (!get_gsg()->get_color_scale_via_lighting()) { - // We only need to munge the color directly if the GSG says it can't - // cheat the color via lighting (presumably, in this case, by applying - // a material). - _color = color_attrib->get_color(); - if (state->get_attrib(color_scale_attrib) && - color_scale_attrib->has_scale()) { - const LVecBase4 &cs = color_scale_attrib->get_scale(); - _color.set(_color[0] * cs[0], - _color[1] * cs[1], - _color[2] * cs[2], - _color[3] * cs[3]); - } - _munge_color = true; - _should_munge_state = true; - } + // In this case, we don't need to munge anything as we can apply the + // color and color scale via glColor4f. } else if (state->get_attrib(color_scale_attrib) && color_scale_attrib->has_scale()) { diff --git a/panda/src/display/standardMunger.h b/panda/src/display/standardMunger.h index 5703fd01b5..d7c71e28e5 100644 --- a/panda/src/display/standardMunger.h +++ b/panda/src/display/standardMunger.h @@ -51,12 +51,13 @@ private: NumericType _numeric_type; Contents _contents; - bool _munge_color; - bool _munge_color_scale; bool _auto_shader; bool _shader_skinning; bool _remove_material; +protected: + bool _munge_color; + bool _munge_color_scale; LColor _color; LVecBase4 _color_scale; diff --git a/panda/src/dxgsg9/dxGeomMunger9.I b/panda/src/dxgsg9/dxGeomMunger9.I index cc972bf94b..2accff3b11 100644 --- a/panda/src/dxgsg9/dxGeomMunger9.I +++ b/panda/src/dxgsg9/dxGeomMunger9.I @@ -10,34 +10,3 @@ * @author drose * @date 2005-03-11 */ - -/** - * - */ -INLINE DXGeomMunger9:: -DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state) : - StandardMunger(gsg, state, 1, NT_packed_dabc, C_color), - _texture(nullptr), - _tex_gen(nullptr) -{ - const TextureAttrib *texture = nullptr; - const TexGenAttrib *tex_gen = nullptr; - state->get_attrib(texture); - state->get_attrib(tex_gen); - _texture = texture; - _tex_gen = tex_gen; - - _filtered_texture = nullptr; - _reffed_filtered_texture = false; - if (texture != nullptr) { - _filtered_texture = texture->filter_to_max(gsg->get_max_texture_stages()); - if (_filtered_texture != texture) { - _filtered_texture->ref(); - _reffed_filtered_texture = true; - } - } - // Set a callback to unregister ourselves when either the Texture or the - // TexGen object gets deleted. - _texture.add_callback(this); - _tex_gen.add_callback(this); -} diff --git a/panda/src/dxgsg9/dxGeomMunger9.cxx b/panda/src/dxgsg9/dxGeomMunger9.cxx index 638b121f27..0e95070c91 100644 --- a/panda/src/dxgsg9/dxGeomMunger9.cxx +++ b/panda/src/dxgsg9/dxGeomMunger9.cxx @@ -19,6 +19,66 @@ GeomMunger *DXGeomMunger9::_deleted_chain = nullptr; TypeHandle DXGeomMunger9::_type_handle; +/** + * + */ +DXGeomMunger9:: +DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state) : + StandardMunger(gsg, state, 1, NT_packed_dabc, C_color), + _texture(nullptr), + _tex_gen(nullptr) +{ + const TextureAttrib *texture = nullptr; + const TexGenAttrib *tex_gen = nullptr; + state->get_attrib(texture); + state->get_attrib(tex_gen); + _texture = texture; + _tex_gen = tex_gen; + + if (!gsg->get_color_scale_via_lighting()) { + // We might need to munge the colors, if we are overriding the vertex + // colors and the GSG can't cheat the color via lighting. + + const ColorAttrib *color_attrib; + const ShaderAttrib *shader_attrib; + state->get_attrib_def(shader_attrib); + + if (!shader_attrib->auto_shader() && + shader_attrib->get_shader() == nullptr && + state->get_attrib(color_attrib) && + color_attrib->get_color_type() != ColorAttrib::T_vertex) { + + if (color_attrib->get_color_type() == ColorAttrib::T_off) { + _color.set(1, 1, 1, 1); + } else { + _color = color_attrib->get_color(); + } + + const ColorScaleAttrib *color_scale_attrib; + if (state->get_attrib(color_scale_attrib) && + color_scale_attrib->has_scale()) { + _color.componentwise_mult(color_scale_attrib->get_scale()); + } + _munge_color = true; + _should_munge_state = true; + } + } + + _filtered_texture = nullptr; + _reffed_filtered_texture = false; + if (texture != nullptr) { + _filtered_texture = texture->filter_to_max(gsg->get_max_texture_stages()); + if (_filtered_texture != texture) { + _filtered_texture->ref(); + _reffed_filtered_texture = true; + } + } + // Set a callback to unregister ourselves when either the Texture or the + // TexGen object gets deleted. + _texture.add_callback(this); + _tex_gen.add_callback(this); +} + /** * */ diff --git a/panda/src/dxgsg9/dxGeomMunger9.h b/panda/src/dxgsg9/dxGeomMunger9.h index c0762e3cf3..c0cb8f8edd 100644 --- a/panda/src/dxgsg9/dxGeomMunger9.h +++ b/panda/src/dxgsg9/dxGeomMunger9.h @@ -28,7 +28,7 @@ */ class EXPCL_PANDADX DXGeomMunger9 : public StandardMunger, public WeakPointerCallback { public: - INLINE DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state); + DXGeomMunger9(GraphicsStateGuardian *gsg, const RenderState *state); virtual ~DXGeomMunger9(); ALLOC_DELETED_CHAIN(DXGeomMunger9); diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index 0921350629..b18c937d81 100644 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -140,6 +140,7 @@ DXGraphicsStateGuardian9(GraphicsEngine *engine, GraphicsPipe *pipe) : _last_fvf = 0; _num_bound_streams = 0; + _white_vbuffer = nullptr; _vertex_shader_version_major = 0; _vertex_shader_version_minor = 0; @@ -4545,6 +4546,11 @@ reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params, release_all_vertex_buffers(); release_all_index_buffers(); + if (_white_vbuffer != nullptr) { + _white_vbuffer->Release(); + _white_vbuffer = nullptr; + } + // must be called before reset Thread *current_thread = Thread::get_current_thread(); _prepared_objects->begin_frame(this, current_thread); @@ -5404,6 +5410,40 @@ set_cg_device(LPDIRECT3DDEVICE9 cg_device) { #endif // HAVE_CG } +/** + * Returns a vertex buffer containing only a full-white color. + */ +LPDIRECT3DVERTEXBUFFER9 DXGraphicsStateGuardian9:: +get_white_vbuffer() { + if (_white_vbuffer != nullptr) { + return _white_vbuffer; + } + + LPDIRECT3DVERTEXBUFFER9 vbuffer; + HRESULT hr; + hr = _screen->_d3d_device->CreateVertexBuffer(sizeof(D3DCOLOR), D3DUSAGE_WRITEONLY, D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &vbuffer, nullptr); + + if (FAILED(hr)) { + dxgsg9_cat.error() + << "CreateVertexBuffer failed" << D3DERRORSTRING(hr); + return nullptr; + } + + D3DCOLOR *local_pointer; + hr = vbuffer->Lock(0, sizeof(D3DCOLOR), (void **) &local_pointer, D3DLOCK_DISCARD); + if (FAILED(hr)) { + dxgsg9_cat.error() + << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr); + return false; + } + + *local_pointer = D3DCOLOR_ARGB(255, 255, 255, 255); + + vbuffer->Unlock(); + _white_vbuffer = vbuffer; + return vbuffer; +} + typedef std::string KEY; typedef struct _KEY_ELEMENT diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h index 66b2fb82d5..8852f413a7 100644 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.h +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.h @@ -168,6 +168,7 @@ public: static void set_cg_device(LPDIRECT3DDEVICE9 cg_device); virtual bool get_supports_cg_profile(const std::string &name) const; + LPDIRECT3DVERTEXBUFFER9 get_white_vbuffer(); protected: void do_issue_transform(); @@ -274,12 +275,6 @@ protected: RenderBuffer::Type _cur_read_pixel_buffer; // source for copy_pixel_buffer operation - PN_stdfloat _material_ambient; - PN_stdfloat _material_diffuse; - PN_stdfloat _material_specular; - PN_stdfloat _material_shininess; - PN_stdfloat _material_emission; - enum DxgsgFogType { None, PerVertexFog=D3DRS_FOGVERTEXMODE, @@ -320,6 +315,7 @@ protected: DWORD _last_fvf; int _num_bound_streams; + LPDIRECT3DVERTEXBUFFER9 _white_vbuffer; // Cache the data necessary to bind each particular light each frame, so if // we bind a given light multiple times, we only have to compute its data diff --git a/panda/src/dxgsg9/dxShaderContext9.cxx b/panda/src/dxgsg9/dxShaderContext9.cxx index 6513ce8a89..a737c342bf 100644 --- a/panda/src/dxgsg9/dxShaderContext9.cxx +++ b/panda/src/dxgsg9/dxShaderContext9.cxx @@ -390,6 +390,8 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) { // arrays ("streams"), and we repeatedly iterate the parameters to pull // out only those for a single stream. + bool apply_white_color = false; + int number_of_arrays = gsg->_data_reader->get_num_arrays(); for (int array_index = 0; array_index < number_of_arrays; ++array_index) { const GeomVertexArrayDataHandle* array_reader = @@ -423,6 +425,11 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) { } } + if (name == InternalName::get_color() && !gsg->_vertex_colors_enabled) { + apply_white_color = true; + continue; + } + const GeomVertexArrayDataHandle *param_array_reader; Geom::NumericType numeric_type; int num_values, start, stride; @@ -435,6 +442,9 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) { // shader parameter, which can cause Bad Things to happen so I'd // like to at least get a hint as to what's gone wrong. dxgsg9_cat.info() << "Geometry contains no data for shader parameter " << *name << "\n"; + if (name == InternalName::get_color()) { + apply_white_color = true; + } continue; } @@ -564,6 +574,19 @@ update_shader_vertex_arrays(DXShaderContext9 *prev, GSG *gsg, bool force) { _num_bound_streams = number_of_arrays; + if (apply_white_color) { + // The shader needs a vertex color, but vertex colors are disabled. + // Bind a vertex buffer containing only one white colour. + int array_index = number_of_arrays; + LPDIRECT3DVERTEXBUFFER9 vbuffer = gsg->get_white_vbuffer(); + hr = device->SetStreamSource(array_index, vbuffer, 0, 0); + if (FAILED(hr)) { + dxgsg9_cat.error() << "SetStreamSource failed" << D3DERRORSTRING(hr); + } + vertex_element_array->add_diffuse_color_vertex_element(array_index, 0); + ++_num_bound_streams; + } + if (_vertex_element_array != nullptr && _vertex_element_array->add_end_vertex_element()) { if (dxgsg9_cat.is_debug()) { diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 48b9112387..616784e0cc 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -4392,7 +4392,8 @@ update_standard_vertex_arrays(bool force) { GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f); } else #endif // NDEBUG - if (_data_reader->get_color_info(array_reader, num_values, numeric_type, + if (_vertex_colors_enabled && + _data_reader->get_color_info(array_reader, num_values, numeric_type, start, stride)) { if (!setup_array_data(client_pointer, array_reader, force)) { return false; @@ -4409,7 +4410,13 @@ update_standard_vertex_arrays(bool force) { glDisableClientState(GL_COLOR_ARRAY); // Since we don't have per-vertex color, the implicit color is white. - GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f); + if (_color_scale_via_lighting) { + GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f); + } else { + LColor color = _scene_graph_color; + color.componentwise_mult(_current_color_scale); + GLPf(Color4)(color[0], color[1], color[2], color[3]); + } } // Now set up each of the active texture coordinate stages--or at least diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index a96a07a2e8..64a5e77553 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -2440,9 +2440,9 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) { if (p == _color_attrib_index) { // Vertex colors are disabled or not present. Apply flat color. #ifdef STDFLOAT_DOUBLE - _glgsg->_glVertexAttrib4dv(p, color_attrib->get_color().get_data()); + _glgsg->_glVertexAttrib4dv(p, _glgsg->_scene_graph_color.get_data()); #else - _glgsg->_glVertexAttrib4fv(p, color_attrib->get_color().get_data()); + _glgsg->_glVertexAttrib4fv(p, _glgsg->_scene_graph_color.get_data()); #endif } } diff --git a/panda/src/pgraph/colorAttrib.cxx b/panda/src/pgraph/colorAttrib.cxx index 129f5a9184..f1d71845cd 100644 --- a/panda/src/pgraph/colorAttrib.cxx +++ b/panda/src/pgraph/colorAttrib.cxx @@ -68,7 +68,7 @@ make_off() { */ CPT(RenderAttrib) ColorAttrib:: make_default() { - return make_off(); + return make_vertex(); } /** diff --git a/panda/src/pgraph/colorAttrib.h b/panda/src/pgraph/colorAttrib.h index a92543c855..b652233a62 100644 --- a/panda/src/pgraph/colorAttrib.h +++ b/panda/src/pgraph/colorAttrib.h @@ -88,7 +88,7 @@ public: register_type(_type_handle, "ColorAttrib", RenderAttrib::get_class_type()); _attrib_slot = register_slot(_type_handle, 100, - new ColorAttrib(T_off, LColor(1, 1, 1, 1))); + new ColorAttrib(T_vertex, LColor::zero())); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/tests/display/test_color_buffer.py b/tests/display/test_color_buffer.py index dab73cbbb8..d95913b0f7 100644 --- a/tests/display/test_color_buffer.py +++ b/tests/display/test_color_buffer.py @@ -113,14 +113,38 @@ def render_color_pixel(region, state, vertex_color=None): camera.node().get_lens(0).set_near_far(1, 3) camera.node().set_cull_bounds(core.OmniBoundingVolume()) - cm = core.CardMaker("card") - cm.set_frame(-1, 1, -1, 1) + if vertex_color is not None: + format = core.GeomVertexFormat.get_v3cp() + else: + format = core.GeomVertexFormat.get_v3() + + vdata = core.GeomVertexData("card", format, core.Geom.UH_static) + vdata.unclean_set_num_rows(4) + + vertex = core.GeomVertexWriter(vdata, "vertex") + vertex.set_data3(core.Vec3.rfu(-1, 0, 1)) + vertex.set_data3(core.Vec3.rfu(-1, 0, -1)) + vertex.set_data3(core.Vec3.rfu(1, 0, 1)) + vertex.set_data3(core.Vec3.rfu(1, 0, -1)) if vertex_color is not None: - cm.set_color(vertex_color) + color = core.GeomVertexWriter(vdata, "color") + color.set_data4(vertex_color) + color.set_data4(vertex_color) + color.set_data4(vertex_color) + color.set_data4(vertex_color) - card = scene.attach_new_node(cm.generate()) - card.set_state(state) + strip = core.GeomTristrips(core.Geom.UH_static) + strip.set_shade_model(core.Geom.SM_uniform) + strip.add_next_vertices(4) + strip.close_primitive() + + geom = core.Geom(vdata) + geom.add_primitive(strip) + + gnode = core.GeomNode("card") + gnode.add_geom(geom, state) + card = scene.attach_new_node(gnode) card.set_pos(0, 2, 0) card.set_scale(60) @@ -197,14 +221,13 @@ def test_color_empty_vertex(color_region, shader_attrib, material_attrib): def test_color_off_vertex(color_region, shader_attrib, material_attrib): - #XXX This behaviour is really odd. state = core.RenderState.make( core.ColorAttrib.make_off(), shader_attrib, material_attrib, ) result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR) - assert result.almost_equal(TEST_COLOR, FUZZ) + assert result == (1, 1, 1, 1) def test_scaled_color_empty(color_region, shader_attrib, material_attrib): @@ -259,7 +282,6 @@ def test_scaled_color_empty_vertex(color_region, shader_attrib, material_attrib) def test_scaled_color_off_vertex(color_region, shader_attrib, material_attrib): - #XXX This behaviour is really odd. state = core.RenderState.make( core.ColorAttrib.make_off(), core.ColorScaleAttrib.make(TEST_COLOR_SCALE), @@ -267,5 +289,5 @@ def test_scaled_color_off_vertex(color_region, shader_attrib, material_attrib): material_attrib, ) result = render_color_pixel(color_region, state, vertex_color=TEST_COLOR) - assert result.almost_equal(TEST_SCALED_COLOR, FUZZ) + assert result.almost_equal(TEST_COLOR_SCALE, FUZZ) From 96860b88e041d5230f6823e201d913e535f4d415 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 8 Oct 2018 22:11:55 +0200 Subject: [PATCH 02/60] dxgsg9: fix problems with window without depth buffer --- panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 4 ++-- panda/src/dxgsg9/wdxGraphicsWindow9.cxx | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index b18c937d81..904f47afc3 100644 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -799,9 +799,9 @@ clear(DrawableRegion *clearable) { main_flags |= D3DCLEAR_TARGET; } - if (clearable->get_clear_depth_active()) { + if (clearable->get_clear_depth_active() && + _screen->_presentation_params.EnableAutoDepthStencil) { aux_flags |= D3DCLEAR_ZBUFFER; - nassertv(_screen->_presentation_params.EnableAutoDepthStencil); } if (clearable->get_clear_stencil_active()) { diff --git a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx index 3136d75fd0..3207c81189 100644 --- a/panda/src/dxgsg9/wdxGraphicsWindow9.cxx +++ b/panda/src/dxgsg9/wdxGraphicsWindow9.cxx @@ -1229,7 +1229,10 @@ init_resized_window() { DWORD flags; D3DCOLOR clear_color; - flags = D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER; + flags = D3DCLEAR_TARGET; + if (_fb_properties.get_depth_bits() > 0) { + flags |= D3DCLEAR_ZBUFFER; + } clear_color = 0x00000000; hr = _wcontext._d3d_device-> Clear (0, nullptr, flags, clear_color, 0.0f, 0); if (FAILED(hr)) { From 9061fd941648056d5a00069b5bc451907a6fda79 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 8 Oct 2018 22:13:08 +0200 Subject: [PATCH 03/60] dtoolutil: fix TextEncoder methods for Python 3 The no-arguments get_text() and set_text() will now return Unicode strings in Python 3, but passing in an encoding will make them return/take bytes objects. In Python 2, they all take regular strings, but Unicode is also accepted by the no-argument get_text() and set_text(). In the future we probably want to remove most of this interface for Python users, to whom all this is unnecessary since it duplicates functionality already in the standard library. --- .../dtoolutil/p3dtoolutil_ext_composite.cxx | 1 + dtool/src/dtoolutil/textEncoder.I | 25 ++- dtool/src/dtoolutil/textEncoder.cxx | 8 + dtool/src/dtoolutil/textEncoder.h | 24 +++ dtool/src/dtoolutil/textEncoder_ext.I | 30 ++++ dtool/src/dtoolutil/textEncoder_ext.cxx | 159 ++++++++++++++++++ dtool/src/dtoolutil/textEncoder_ext.h | 50 ++++++ makepanda/makepanda.py | 1 + panda/src/text/textNode.I | 77 --------- panda/src/text/textNode.cxx | 9 + panda/src/text/textNode.h | 17 +- 11 files changed, 305 insertions(+), 96 deletions(-) create mode 100644 dtool/src/dtoolutil/textEncoder_ext.I create mode 100644 dtool/src/dtoolutil/textEncoder_ext.cxx create mode 100644 dtool/src/dtoolutil/textEncoder_ext.h diff --git a/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx b/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx index 89a0ebcc30..2cd825ff58 100644 --- a/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx +++ b/dtool/src/dtoolutil/p3dtoolutil_ext_composite.cxx @@ -1,2 +1,3 @@ #include "filename_ext.cxx" #include "globPattern_ext.cxx" +#include "textEncoder_ext.cxx" diff --git a/dtool/src/dtoolutil/textEncoder.I b/dtool/src/dtoolutil/textEncoder.I index e07f489ab0..417ef386e2 100644 --- a/dtool/src/dtoolutil/textEncoder.I +++ b/dtool/src/dtoolutil/textEncoder.I @@ -90,6 +90,7 @@ set_text(const std::string &text) { if (!has_text() || _text != text) { _text = text; _flags = (_flags | F_got_text) & ~F_got_wtext; + text_changed(); } } @@ -101,7 +102,11 @@ set_text(const std::string &text) { */ INLINE void TextEncoder:: set_text(const std::string &text, TextEncoder::Encoding encoding) { - set_wtext(decode_text(text, encoding)); + if (encoding == _encoding) { + set_text(text); + } else { + set_wtext(decode_text(text, encoding)); + } } /** @@ -112,6 +117,7 @@ clear_text() { _text = std::string(); _wtext = std::wstring(); _flags |= (F_got_text | F_got_wtext); + text_changed(); } /** @@ -151,8 +157,11 @@ get_text(TextEncoder::Encoding encoding) const { */ INLINE void TextEncoder:: append_text(const std::string &text) { - _text = get_text() + text; - _flags = (_flags | F_got_text) & ~F_got_wtext; + if (!text.empty()) { + _text = get_text() + text; + _flags = (_flags | F_got_text) & ~F_got_wtext; + text_changed(); + } } /** @@ -163,6 +172,7 @@ INLINE void TextEncoder:: append_unicode_char(int character) { _wtext = get_wtext() + std::wstring(1, (wchar_t)character); _flags = (_flags | F_got_wtext) & ~F_got_text; + text_changed(); } /** @@ -200,6 +210,7 @@ set_unicode_char(size_t index, int character) { if (index < _wtext.length()) { _wtext[index] = character; _flags &= ~F_got_text; + text_changed(); } } @@ -418,6 +429,7 @@ set_wtext(const std::wstring &wtext) { if (!has_text() || _wtext != wtext) { _wtext = wtext; _flags = (_flags | F_got_wtext) & ~F_got_text; + text_changed(); } } @@ -439,8 +451,11 @@ get_wtext() const { */ INLINE void TextEncoder:: append_wtext(const std::wstring &wtext) { - _wtext = get_wtext() + wtext; - _flags = (_flags | F_got_wtext) & ~F_got_text; + if (!wtext.empty()) { + _wtext = get_wtext() + wtext; + _flags = (_flags | F_got_wtext) & ~F_got_text; + text_changed(); + } } /** diff --git a/dtool/src/dtoolutil/textEncoder.cxx b/dtool/src/dtoolutil/textEncoder.cxx index 1e1cd4bc61..da835b7bfb 100644 --- a/dtool/src/dtoolutil/textEncoder.cxx +++ b/dtool/src/dtoolutil/textEncoder.cxx @@ -35,6 +35,7 @@ make_upper() { (*si) = unicode_toupper(*si); } _flags &= ~F_got_text; + text_changed(); } /** @@ -49,6 +50,7 @@ make_lower() { (*si) = unicode_tolower(*si); } _flags &= ~F_got_text; + text_changed(); } /** @@ -314,6 +316,12 @@ expand_amp_sequence(StringDecoder &decoder) const { } */ +/** + * Called whenever the text has been changed. + */ +void TextEncoder:: +text_changed() { +} /** * diff --git a/dtool/src/dtoolutil/textEncoder.h b/dtool/src/dtoolutil/textEncoder.h index a7eaf395ff..baa0ef9b3e 100644 --- a/dtool/src/dtoolutil/textEncoder.h +++ b/dtool/src/dtoolutil/textEncoder.h @@ -48,17 +48,28 @@ PUBLISHED: INLINE static Encoding get_default_encoding(); MAKE_PROPERTY(default_encoding, get_default_encoding, set_default_encoding); +#ifdef CPPPARSER + EXTEND void set_text(PyObject *text); + EXTEND void set_text(PyObject *text, Encoding encoding); +#else INLINE void set_text(const std::string &text); INLINE void set_text(const std::string &text, Encoding encoding); +#endif INLINE void clear_text(); INLINE bool has_text() const; void make_upper(); void make_lower(); +#ifdef CPPPARSER + EXTEND PyObject *get_text() const; + EXTEND PyObject *get_text(Encoding encoding) const; + EXTEND void append_text(PyObject *text); +#else INLINE std::string get_text() const; INLINE std::string get_text(Encoding encoding) const; INLINE void append_text(const std::string &text); +#endif INLINE void append_unicode_char(int character); INLINE size_t get_num_chars() const; INLINE int get_unicode_char(size_t index) const; @@ -91,11 +102,24 @@ PUBLISHED: std::wstring get_wtext_as_ascii() const; bool is_wtext() const; +#ifdef CPPPARSER + EXTEND static PyObject *encode_wchar(wchar_t ch, Encoding encoding); + EXTEND INLINE PyObject *encode_wtext(const std::wstring &wtext) const; + EXTEND static PyObject *encode_wtext(const std::wstring &wtext, Encoding encoding); + EXTEND INLINE PyObject *decode_text(PyObject *text) const; + EXTEND static PyObject *decode_text(PyObject *text, Encoding encoding); +#else static std::string encode_wchar(wchar_t ch, Encoding encoding); INLINE std::string encode_wtext(const std::wstring &wtext) const; static std::string encode_wtext(const std::wstring &wtext, Encoding encoding); INLINE std::wstring decode_text(const std::string &text) const; static std::wstring decode_text(const std::string &text, Encoding encoding); +#endif + + MAKE_PROPERTY(text, get_text, set_text); + +protected: + virtual void text_changed(); private: enum Flags { diff --git a/dtool/src/dtoolutil/textEncoder_ext.I b/dtool/src/dtoolutil/textEncoder_ext.I new file mode 100644 index 0000000000..2924fda011 --- /dev/null +++ b/dtool/src/dtoolutil/textEncoder_ext.I @@ -0,0 +1,30 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file textEncoder_ext.I + * @author rdb + * @date 2018-10-08 + */ + +/** + * Encodes a wide-text string into a single-char string, according to the + * current encoding. + */ +INLINE PyObject *Extension:: +encode_wtext(const std::wstring &wtext) const { + return encode_wtext(wtext, _this->get_encoding()); +} + +/** + * Returns the given wstring decoded to a single-byte string, via the current + * encoding system. + */ +INLINE PyObject *Extension:: +decode_text(PyObject *text) const { + return decode_text(text, _this->get_encoding()); +} diff --git a/dtool/src/dtoolutil/textEncoder_ext.cxx b/dtool/src/dtoolutil/textEncoder_ext.cxx new file mode 100644 index 0000000000..b085b8a965 --- /dev/null +++ b/dtool/src/dtoolutil/textEncoder_ext.cxx @@ -0,0 +1,159 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file textEncoder_ext.cxx + * @author rdb + * @date 2018-09-29 + */ + +#include "textEncoder_ext.h" + +#ifdef HAVE_PYTHON + +/** + * Sets the text as a Unicode string. In Python 2, if a regular str is given, + * it is assumed to be in the TextEncoder's specified encoding. + */ +void Extension:: +set_text(PyObject *text) { + if (PyUnicode_Check(text)) { +#if PY_VERSION_HEX >= 0x03030000 + Py_ssize_t len; + const char *str = PyUnicode_AsUTF8AndSize(text, &len); + _this->set_text(std::string(str, len), TextEncoder::E_utf8); +#else + Py_ssize_t len = PyUnicode_GET_SIZE(text); + wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1)); + PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len); + _this->set_wtext(std::wstring(str, len)); +#endif + } else { +#if PY_MAJOR_VERSION >= 3 + Dtool_Raise_TypeError("expected string"); +#else + char *str; + Py_ssize_t len; + if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) { + _this->set_text(std::string(str, len)); + } +#endif + } +} + +/** + * Sets the text as an encoded byte string of the given encoding. + */ +void Extension:: +set_text(PyObject *text, TextEncoder::Encoding encoding) { + char *str; + Py_ssize_t len; + if (PyBytes_AsStringAndSize(text, &str, &len) >= 0) { + _this->set_text(std::string(str, len), encoding); + } +} + +/** + * Returns the text as a string. In Python 2, the returned string is in the + * TextEncoder's specified encoding. In Python 3, it is returned as unicode. + */ +PyObject *Extension:: +get_text() const { +#if PY_MAJOR_VERSION >= 3 + std::wstring text = _this->get_wtext(); + return PyUnicode_FromWideChar(text.data(), (Py_ssize_t)text.size()); +#else + std::string text = _this->get_text(); + return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size()); +#endif +} + +/** + * Returns the text as a bytes object in the given encoding. + */ +PyObject *Extension:: +get_text(TextEncoder::Encoding encoding) const { + std::string text = _this->get_text(encoding); +#if PY_MAJOR_VERSION >= 3 + return PyBytes_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size()); +#else + return PyString_FromStringAndSize((char *)text.data(), (Py_ssize_t)text.size()); +#endif +} + +/** + * Appends the text as a string (or Unicode object in Python 2). + */ +void Extension:: +append_text(PyObject *text) { + if (PyUnicode_Check(text)) { +#if PY_VERSION_HEX >= 0x03030000 + Py_ssize_t len; + const char *str = PyUnicode_AsUTF8AndSize(text, &len); + _this->append_text(std::string(str, len)); +#else + Py_ssize_t len = PyUnicode_GET_SIZE(text); + wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1)); + PyUnicode_AsWideChar((PyUnicodeObject *)text, str, len); + _this->append_wtext(std::wstring(str, len)); +#endif + } else { +#if PY_MAJOR_VERSION >= 3 + Dtool_Raise_TypeError("expected string"); +#else + char *str; + Py_ssize_t len; + if (PyString_AsStringAndSize(text, (char **)&str, &len) != -1) { + _this->append_text(std::string(str, len)); + } +#endif + } +} + +/** + * Encodes the given wide character as byte string in the given encoding. + */ +PyObject *Extension:: +encode_wchar(char32_t ch, TextEncoder::Encoding encoding) { + std::string value = TextEncoder::encode_wchar(ch, encoding); +#if PY_MAJOR_VERSION >= 3 + return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); +#else + return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); +#endif +} + +/** + * Encodes a wide-text string into a single-char string, according to the + * given encoding. + */ +PyObject *Extension:: +encode_wtext(const wstring &wtext, TextEncoder::Encoding encoding) { + std::string value = TextEncoder::encode_wtext(wtext, encoding); +#if PY_MAJOR_VERSION >= 3 + return PyBytes_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); +#else + return PyString_FromStringAndSize((char *)value.data(), (Py_ssize_t)value.size()); +#endif +} + +/** + * Returns the given wstring decoded to a single-byte string, via the given + * encoding system. + */ +PyObject *Extension:: +decode_text(PyObject *text, TextEncoder::Encoding encoding) { + char *str; + Py_ssize_t len; + if (PyBytes_AsStringAndSize(text, &str, &len) >= 0) { + return Dtool_WrapValue(TextEncoder::decode_text(std::string(str, len), encoding)); + } else { + return nullptr; + } +} + +#endif // HAVE_PYTHON diff --git a/dtool/src/dtoolutil/textEncoder_ext.h b/dtool/src/dtoolutil/textEncoder_ext.h new file mode 100644 index 0000000000..049c16e493 --- /dev/null +++ b/dtool/src/dtoolutil/textEncoder_ext.h @@ -0,0 +1,50 @@ +/** + * PANDA 3D SOFTWARE + * Copyright (c) Carnegie Mellon University. All rights reserved. + * + * All use of this software is subject to the terms of the revised BSD + * license. You should have received a copy of this license along + * with this source code in a file named "LICENSE." + * + * @file textEncoder_ext.h + * @author rdb + * @date 2018-09-29 + */ + +#ifndef TEXTENCODER_EXT_H +#define TEXTENCODER_EXT_H + +#include "dtoolbase.h" + +#ifdef HAVE_PYTHON + +#include "extension.h" +#include "textEncoder.h" +#include "py_panda.h" + +/** + * This class defines the extension methods for TextEncoder, which are called + * instead of any C++ methods with the same prototype. + */ +template<> +class Extension : public ExtensionBase { +public: + void set_text(PyObject *text); + void set_text(PyObject *text, TextEncoder::Encoding encoding); + + PyObject *get_text() const; + PyObject *get_text(TextEncoder::Encoding encoding) const; + void append_text(PyObject *text); + + static PyObject *encode_wchar(char32_t ch, TextEncoder::Encoding encoding); + INLINE PyObject *encode_wtext(const std::wstring &wtext) const; + static PyObject *encode_wtext(const std::wstring &wtext, TextEncoder::Encoding encoding); + INLINE PyObject *decode_text(PyObject *text) const; + static PyObject *decode_text(PyObject *text, TextEncoder::Encoding encoding); +}; + +#include "textEncoder_ext.I" + +#endif // HAVE_PYTHON + +#endif // TEXTENCODER_EXT_H diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index a81ea7fe56..0164278d1e 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -3551,6 +3551,7 @@ IGATEFILES += [ "dSearchPath.h", "executionEnvironment.h", "textEncoder.h", + "textEncoder_ext.h", "filename.h", "filename_ext.h", "globPattern.h", diff --git a/panda/src/text/textNode.I b/panda/src/text/textNode.I index 8070504c6b..1d02442451 100644 --- a/panda/src/text/textNode.I +++ b/panda/src/text/textNode.I @@ -1010,61 +1010,6 @@ clear_glyph_shift() { invalidate_with_measure(); } - -/** - * Changes the text that is displayed under the TextNode. - */ -INLINE void TextNode:: -set_text(const std::string &text) { - MutexHolder holder(_lock); - TextEncoder::set_text(text); - invalidate_with_measure(); -} - -/** - * The two-parameter version of set_text() accepts an explicit encoding; the - * text is immediately decoded and stored as a wide-character string. - * Subsequent calls to get_text() will return the same text re-encoded using - * whichever encoding is specified by set_encoding(). - */ -INLINE void TextNode:: -set_text(const std::string &text, TextNode::Encoding encoding) { - MutexHolder holder(_lock); - TextEncoder::set_text(text, encoding); - invalidate_with_measure(); -} - -/** - * Removes the text from the TextNode. - */ -INLINE void TextNode:: -clear_text() { - MutexHolder holder(_lock); - TextEncoder::clear_text(); - invalidate_with_measure(); -} - -/** - * Appends the indicates string to the end of the stored text. - */ -INLINE void TextNode:: -append_text(const std::string &text) { - MutexHolder holder(_lock); - TextEncoder::append_text(text); - invalidate_with_measure(); -} - -/** - * Appends a single character to the end of the stored text. This may be a - * wide character, up to 16 bits in Unicode. - */ -INLINE void TextNode:: -append_unicode_char(wchar_t character) { - MutexHolder holder(_lock); - TextEncoder::append_unicode_char(character); - invalidate_with_measure(); -} - /** * Returns a string that represents the contents of the text, as it has been * formatted by wordwrap rules. @@ -1086,28 +1031,6 @@ calc_width(const std::string &line) const { return calc_width(decode_text(line)); } -/** - * Changes the text that is displayed under the TextNode, with a wide text. - * This automatically sets the string reported by get_text() to the 8-bit - * encoded version of the same string. - */ -INLINE void TextNode:: -set_wtext(const std::wstring &wtext) { - MutexHolder holder(_lock); - TextEncoder::set_wtext(wtext); - invalidate_with_measure(); -} - -/** - * Appends the indicates string to the end of the stored wide-character text. - */ -INLINE void TextNode:: -append_wtext(const std::wstring &wtext) { - MutexHolder holder(_lock); - TextEncoder::append_wtext(wtext); - invalidate_with_measure(); -} - /** * Returns a wstring that represents the contents of the text, as it has been * formatted by wordwrap rules. diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index 1ecfc1ea65..5a0c0c7f7f 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -319,6 +319,15 @@ get_internal_geom() const { return do_get_internal_geom(); } +/** + * Called whenever the text has been changed. + */ +void TextNode:: +text_changed() { + MutexHolder holder(_lock); + invalidate_with_measure(); +} + /** * Returns the union of all attributes from SceneGraphReducer::AttribTypes * that may not safely be applied to the vertices of this node. If this is diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index ecf7dcafcf..02e1cb51c7 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -182,14 +182,6 @@ PUBLISHED: INLINE void set_glyph_shift(PN_stdfloat glyph_shift); INLINE void clear_glyph_shift(); - // These methods are inherited from TextEncoder, but we override here so we - // can flag the TextNode as dirty when they have been changed. - INLINE void set_text(const std::string &text); - INLINE void set_text(const std::string &text, Encoding encoding); - INLINE void clear_text(); - INLINE void append_text(const std::string &text); - INLINE void append_unicode_char(wchar_t character); - // After the text has been set, you can query this to determine how it will // be wordwrapped. INLINE std::string get_wordwrapped_text() const; @@ -203,10 +195,6 @@ PUBLISHED: bool has_character(wchar_t character) const; bool is_whitespace(wchar_t character) const; - // Direct support for wide-character strings. - INLINE void set_wtext(const std::wstring &wtext); - INLINE void append_wtext(const std::wstring &text); - INLINE std::wstring get_wordwrapped_wtext() const; PN_stdfloat calc_width(const std::wstring &line) const; @@ -245,8 +233,6 @@ PUBLISHED: MAKE_PROPERTY(usage_hint, get_usage_hint, set_usage_hint); MAKE_PROPERTY(flatten_flags, get_flatten_flags, set_flatten_flags); - MAKE_PROPERTY(text, get_text, set_text); - MAKE_PROPERTY2(font, has_font, get_font, set_font, clear_font); MAKE_PROPERTY2(small_caps, has_small_caps, get_small_caps, set_small_caps, clear_small_caps); @@ -281,6 +267,9 @@ PUBLISHED: set_text_scale, clear_text_scale); public: + // From parent class TextEncoder; + virtual void text_changed() final; + // From parent class PandaNode virtual int get_unsafe_to_apply_attribs() const; virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs, From 29b577971f71c0e6d2dfc07fb8eeeef6712d2f58 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 8 Oct 2018 22:33:54 +0200 Subject: [PATCH 04/60] dtoolutil: improve Unicode encoding/decoding, support non-BMP chars - Support encoding and decoding four-byte UTF-8 sequences - E_unicode supports surrogate pairs, renamed to E_utf16be for clarity - char32_t should be used for storing a Unicode code point --- dtool/src/dtoolutil/stringDecoder.I | 2 +- dtool/src/dtoolutil/stringDecoder.cxx | 79 +++++++++++++++++++++---- dtool/src/dtoolutil/stringDecoder.h | 15 +++-- dtool/src/dtoolutil/textEncoder.I | 17 +++++- dtool/src/dtoolutil/textEncoder.cxx | 84 +++++++++++++++++++++------ dtool/src/dtoolutil/textEncoder.h | 11 ++-- 6 files changed, 167 insertions(+), 41 deletions(-) diff --git a/dtool/src/dtoolutil/stringDecoder.I b/dtool/src/dtoolutil/stringDecoder.I index f7a3b14701..ce128833d0 100644 --- a/dtool/src/dtoolutil/stringDecoder.I +++ b/dtool/src/dtoolutil/stringDecoder.I @@ -53,5 +53,5 @@ StringUtf8Decoder(const std::string &input) : StringDecoder(input) { * */ INLINE StringUnicodeDecoder:: -StringUnicodeDecoder(const std::string &input) : StringDecoder(input) { +StringUtf16Decoder(const std::string &input) : StringDecoder(input) { } diff --git a/dtool/src/dtoolutil/stringDecoder.cxx b/dtool/src/dtoolutil/stringDecoder.cxx index e77e0c5e13..f9ecfdecd3 100644 --- a/dtool/src/dtoolutil/stringDecoder.cxx +++ b/dtool/src/dtoolutil/stringDecoder.cxx @@ -26,7 +26,7 @@ StringDecoder:: /** * Returns the next character in sequence. */ -int StringDecoder:: +char32_t StringDecoder:: get_next_character() { if (test_eof()) { return -1; @@ -57,19 +57,20 @@ get_notify_ptr() { /* In UTF-8, each 16-bit Unicode character is encoded as a sequence of -one, two, or three 8-bit bytes, depending on the value of the +one, two, three or four 8-bit bytes, depending on the value of the character. The following table shows the format of such UTF-8 byte sequences (where the "free bits" shown by x's in the table are combined in the order shown, and interpreted from most significant to least significant): Binary format of bytes in sequence: - Number of Maximum expressible - 1st byte 2nd byte 3rd byte free bits: Unicode value: + Number of Maximum expressible + 1st byte 2nd byte 3rd byte 4th byte free bits: Unicode value: - 0xxxxxxx 7 007F hex (127) - 110xxxxx 10xxxxxx (5+6)=11 07FF hex (2047) - 1110xxxx 10xxxxxx 10xxxxxx (4+6+6)=16 FFFF hex (65535) + 0xxxxxxx 7 007F hex (127) + 110xxxxx 10xxxxxx (5+6)=11 07FF hex (2047) + 1110xxxx 10xxxxxx 10xxxxxx (4+6+6)=16 FFFF hex (65535) + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (4+6*3)=21 10FFFF hex (1114111) The value of each individual byte indicates its UTF-8 function, as follows: @@ -77,12 +78,13 @@ The value of each individual byte indicates its UTF-8 function, as follows: 80 to BF hex (128 to 191): continuing byte in a multi-byte sequence. C2 to DF hex (194 to 223): first byte of a two-byte sequence. E0 to EF hex (224 to 239): first byte of a three-byte sequence. + F0 to F7 hex (240 to 247): first byte of a four-byte sequence. */ /** * Returns the next character in sequence. */ -int StringUtf8Decoder:: +char32_t StringUtf8Decoder:: get_next_character() { unsigned int result; while (!test_eof()) { @@ -125,6 +127,35 @@ get_next_character() { unsigned int three = (unsigned char)_input[_p++]; result = ((result & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f); return result; + + } else if ((result & 0xf8) == 0xf0) { + // First byte of four. + if (test_eof()) { + if (_notify_ptr != nullptr) { + (*_notify_ptr) + << "utf-8 encoded string '" << _input << "' ends abruptly.\n"; + } + return -1; + } + unsigned int two = (unsigned char)_input[_p++]; + if (test_eof()) { + if (_notify_ptr != nullptr) { + (*_notify_ptr) + << "utf-8 encoded string '" << _input << "' ends abruptly.\n"; + } + return -1; + } + unsigned int three = (unsigned char)_input[_p++]; + if (test_eof()) { + if (_notify_ptr != nullptr) { + (*_notify_ptr) + << "utf-8 encoded string '" << _input << "' ends abruptly.\n"; + } + return -1; + } + unsigned int four = (unsigned char)_input[_p++]; + result = ((result & 0x07) << 18) | ((two & 0x3f) << 12) | ((three & 0x3f) << 6) | (four & 0x3f); + return result; } // Otherwise--the high bit is set but it is not one of the introductory @@ -144,7 +175,7 @@ get_next_character() { /** * Returns the next character in sequence. */ -int StringUnicodeDecoder:: +char32_t StringUtf16Decoder:: get_next_character() { if (test_eof()) { return -1; @@ -159,5 +190,33 @@ get_next_character() { return -1; } unsigned int low = (unsigned char)_input[_p++]; - return ((high << 8) | low); + int ch = ((high << 8) | low); + + /* + using std::swap; + + if (ch == 0xfffe) { + // This is a byte-swapped byte-order-marker. That means we need to swap + // the endianness of the rest of the stream. + char *data = (char *)_input.data(); + for (size_t p = _p; p < _input.size() - 1; p += 2) { + std::swap(data[p], data[p + 1]); + } + ch = 0xfeff; + } + */ + + if (ch >= 0xd800 && ch < 0xdc00 && (_p + 1) < _input.size()) { + // This is a high surrogate. Look for a subsequent low surrogate. + unsigned int high = (unsigned char)_input[_p]; + unsigned int low = (unsigned char)_input[_p + 1]; + int ch2 = ((high << 8) | low); + if (ch2 >= 0xdc00 && ch2 < 0xe000) { + // Yes, this is a low surrogate. + _p += 2; + return 0x10000 + ((ch - 0xd800) << 10) + (ch2 - 0xdc00); + } + } + // No, this is just a regular character, or an unpaired surrogate. + return ch; } diff --git a/dtool/src/dtoolutil/stringDecoder.h b/dtool/src/dtoolutil/stringDecoder.h index c0b2534ee2..6885f77e08 100644 --- a/dtool/src/dtoolutil/stringDecoder.h +++ b/dtool/src/dtoolutil/stringDecoder.h @@ -26,7 +26,7 @@ public: INLINE StringDecoder(const std::string &input); virtual ~StringDecoder(); - virtual int get_next_character(); + virtual char32_t get_next_character(); INLINE bool is_eof(); static void set_notify_ptr(std::ostream *ptr); @@ -48,20 +48,23 @@ class StringUtf8Decoder : public StringDecoder { public: INLINE StringUtf8Decoder(const std::string &input); - virtual int get_next_character(); + virtual char32_t get_next_character(); }; /** * This decoder extracts characters two at a time to get a plain wide - * character sequence. + * character sequence. It supports surrogate pairs. */ -class StringUnicodeDecoder : public StringDecoder { +class StringUtf16Decoder : public StringDecoder { public: - INLINE StringUnicodeDecoder(const std::string &input); + INLINE StringUtf16Decoder(const std::string &input); - virtual int get_next_character(); + virtual char32_t get_next_character(); }; +// Deprecated alias of StringUtf16Encoder. +typedef StringUtf16Decoder StringUnicodeDecoder; + #include "stringDecoder.I" #endif diff --git a/dtool/src/dtoolutil/textEncoder.I b/dtool/src/dtoolutil/textEncoder.I index 417ef386e2..766319d6da 100644 --- a/dtool/src/dtoolutil/textEncoder.I +++ b/dtool/src/dtoolutil/textEncoder.I @@ -169,8 +169,23 @@ append_text(const std::string &text) { * wide character, up to 16 bits in Unicode. */ INLINE void TextEncoder:: -append_unicode_char(int character) { +append_unicode_char(char32_t character) { +#if WCHAR_MAX >= 0x10FFFF + // wchar_t might be UTF-32. _wtext = get_wtext() + std::wstring(1, (wchar_t)character); +#else + if ((character & ~0xffff) == 0) { + _wtext = get_wtext() + std::wstring(1, (wchar_t)character); + } else { + // Encode as a surrogate pair. + uint32_t v = (uint32_t)character - 0x10000u; + wchar_t wstr[2] = { + (wchar_t)((v >> 10u) | 0xd800u), + (wchar_t)((v & 0x3ffu) | 0xdc00u), + }; + _wtext = get_wtext() + std::wstring(wstr, 2); + } +#endif _flags = (_flags | F_got_wtext) & ~F_got_text; text_changed(); } diff --git a/dtool/src/dtoolutil/textEncoder.cxx b/dtool/src/dtoolutil/textEncoder.cxx index da835b7bfb..1065f21dcb 100644 --- a/dtool/src/dtoolutil/textEncoder.cxx +++ b/dtool/src/dtoolutil/textEncoder.cxx @@ -21,7 +21,7 @@ using std::ostream; using std::string; using std::wstring; -TextEncoder::Encoding TextEncoder::_default_encoding = TextEncoder::E_iso8859; +TextEncoder::Encoding TextEncoder::_default_encoding = TextEncoder::E_utf8; /** * Adjusts the text stored within the encoder to all uppercase letters @@ -109,11 +109,11 @@ is_wtext() const { } /** - * Encodes a single wide char into a one-, two-, or three-byte string, - * according to the given encoding system. + * Encodes a single Unicode character into a one-, two-, three-, or four-byte + * string, according to the given encoding system. */ string TextEncoder:: -encode_wchar(wchar_t ch, TextEncoder::Encoding encoding) { +encode_wchar(char32_t ch, TextEncoder::Encoding encoding) { switch (encoding) { case E_iso8859: if ((ch & ~0xff) == 0) { @@ -145,17 +145,38 @@ encode_wchar(wchar_t ch, TextEncoder::Encoding encoding) { return string(1, (char)((ch >> 6) | 0xc0)) + string(1, (char)((ch & 0x3f) | 0x80)); - } else { + } else if ((ch & ~0xffff) == 0) { return string(1, (char)((ch >> 12) | 0xe0)) + string(1, (char)(((ch >> 6) & 0x3f) | 0x80)) + string(1, (char)((ch & 0x3f) | 0x80)); + } else { + return + string(1, (char)((ch >> 18) | 0xf0)) + + string(1, (char)(((ch >> 12) & 0x3f) | 0x80)) + + string(1, (char)(((ch >> 6) & 0x3f) | 0x80)) + + string(1, (char)((ch & 0x3f) | 0x80)); } - case E_unicode: - return - string(1, (char)(ch >> 8)) + - string(1, (char)(ch & 0xff)); + case E_utf16be: + if ((ch & ~0xffff) == 0) { + // Note that this passes through surrogates and BOMs unharmed. + return + string(1, (char)(ch >> 8)) + + string(1, (char)(ch & 0xff)); + } else { + // Use a surrogate pair. + uint32_t v = (uint32_t)ch - 0x10000u; + uint16_t hi = (v >> 10u) | 0xd800u; + uint16_t lo = (v & 0x3ffu) | 0xdc00u; + char encoded[4] = { + (char)(hi >> 8), + (char)(hi & 0xff), + (char)(lo >> 8), + (char)(lo & 0xff), + }; + return string(encoded, 4); + } } return ""; @@ -169,8 +190,25 @@ string TextEncoder:: encode_wtext(const wstring &wtext, TextEncoder::Encoding encoding) { string result; - for (wstring::const_iterator pi = wtext.begin(); pi != wtext.end(); ++pi) { - result += encode_wchar(*pi, encoding); + for (size_t i = 0; i < wtext.size(); ++i) { + wchar_t ch = wtext[i]; + + // On some systems, wstring may be UTF-16, and contain surrogate pairs. +#if WCHAR_MAX < 0x10FFFF + if (ch >= 0xd800 && ch < 0xdc00 && (i + 1) < wtext.size()) { + // This is a high surrogate. Look for a subsequent low surrogate. + wchar_t ch2 = wtext[i + 1]; + if (ch2 >= 0xdc00 && ch2 < 0xe000) { + // Yes, this is a low surrogate. + char32_t code_point = 0x10000 + ((ch - 0xd800) << 10) + (ch2 - 0xdc00); + result += encode_wchar(code_point, encoding); + i++; + continue; + } + } +#endif + + result += encode_wchar(ch, encoding); } return result; @@ -189,9 +227,9 @@ decode_text(const string &text, TextEncoder::Encoding encoding) { return decode_text_impl(decoder); } - case E_unicode: + case E_utf16be: { - StringUnicodeDecoder decoder(text); + StringUtf16Decoder decoder(text); return decode_text_impl(decoder); } @@ -213,7 +251,7 @@ decode_text_impl(StringDecoder &decoder) { wstring result; // bool expand_amp = get_expand_amp(); - wchar_t character = decoder.get_next_character(); + char32_t character = decoder.get_next_character(); while (!decoder.is_eof()) { /* if (character == '&' && expand_amp) { @@ -221,7 +259,14 @@ decode_text_impl(StringDecoder &decoder) { character = expand_amp_sequence(decoder); } */ - result += character; + if (character <= WCHAR_MAX) { + result += character; + } else { + // We need to encode this as a surrogate pair. + uint32_t v = (uint32_t)character - 0x10000u; + result += (wchar_t)((v >> 10u) | 0xd800u); + result += (wchar_t)((v & 0x3ffu) | 0xdc00u); + } character = decoder.get_next_character(); } @@ -335,8 +380,8 @@ operator << (ostream &out, TextEncoder::Encoding encoding) { case TextEncoder::E_utf8: return out << "utf8"; - case TextEncoder::E_unicode: - return out << "unicode"; + case TextEncoder::E_utf16be: + return out << "utf16be"; }; return out << "**invalid TextEncoder::Encoding(" << (int)encoding << ")**"; @@ -354,8 +399,9 @@ operator >> (istream &in, TextEncoder::Encoding &encoding) { encoding = TextEncoder::E_iso8859; } else if (word == "utf8" || word == "utf-8") { encoding = TextEncoder::E_utf8; - } else if (word == "unicode") { - encoding = TextEncoder::E_unicode; + } else if (word == "unicode" || word == "utf16be" || word == "utf-16be" || + word == "utf16-be" || word == "utf-16-be") { + encoding = TextEncoder::E_utf16be; } else { ostream *notify_ptr = StringDecoder::get_notify_ptr(); if (notify_ptr != nullptr) { diff --git a/dtool/src/dtoolutil/textEncoder.h b/dtool/src/dtoolutil/textEncoder.h index baa0ef9b3e..71d93a71ca 100644 --- a/dtool/src/dtoolutil/textEncoder.h +++ b/dtool/src/dtoolutil/textEncoder.h @@ -35,7 +35,10 @@ PUBLISHED: enum Encoding { E_iso8859, E_utf8, - E_unicode + E_utf16be, + + // Deprecated alias for E_utf16be + E_unicode = E_utf16be, }; INLINE TextEncoder(); @@ -70,7 +73,7 @@ PUBLISHED: INLINE std::string get_text(Encoding encoding) const; INLINE void append_text(const std::string &text); #endif - INLINE void append_unicode_char(int character); + INLINE void append_unicode_char(char32_t character); INLINE size_t get_num_chars() const; INLINE int get_unicode_char(size_t index) const; INLINE void set_unicode_char(size_t index, int character); @@ -103,13 +106,13 @@ PUBLISHED: bool is_wtext() const; #ifdef CPPPARSER - EXTEND static PyObject *encode_wchar(wchar_t ch, Encoding encoding); + EXTEND static PyObject *encode_wchar(char32_t ch, Encoding encoding); EXTEND INLINE PyObject *encode_wtext(const std::wstring &wtext) const; EXTEND static PyObject *encode_wtext(const std::wstring &wtext, Encoding encoding); EXTEND INLINE PyObject *decode_text(PyObject *text) const; EXTEND static PyObject *decode_text(PyObject *text, Encoding encoding); #else - static std::string encode_wchar(wchar_t ch, Encoding encoding); + static std::string encode_wchar(char32_t ch, Encoding encoding); INLINE std::string encode_wtext(const std::wstring &wtext) const; static std::string encode_wtext(const std::wstring &wtext, Encoding encoding); INLINE std::wstring decode_text(const std::string &text) const; From 0561d7920f54900fa87238cbfb8abfb27e99b965 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 8 Oct 2018 23:19:29 +0200 Subject: [PATCH 05/60] tests: add unit tests for TextEncoder --- tests/dtoolutil/test_textencoder.py | 101 ++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 tests/dtoolutil/test_textencoder.py diff --git a/tests/dtoolutil/test_textencoder.py b/tests/dtoolutil/test_textencoder.py new file mode 100644 index 0000000000..ef03c7d826 --- /dev/null +++ b/tests/dtoolutil/test_textencoder.py @@ -0,0 +1,101 @@ +import sys +import pytest +from panda3d.core import TextEncoder + +if sys.version_info >= (3, 0): + unichr = chr + xrange = range + + +def valid_characters(): + """Generator yielding all valid Unicode code points.""" + + for i in xrange(0xd800): + yield unichr(i) + + for i in xrange(0xe000, sys.maxunicode + 1): + if i != 0xfeff and i & 0xfffe != 0xfffe: + yield unichr(i) + + +def test_text_decode_iso8859(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_iso8859) + + for i in xrange(255): + enc = unichr(i).encode('latin-1') + assert len(enc) == 1 + + dec = encoder.decode_text(enc) + assert len(dec) == 1 + assert ord(dec) == i + + +def test_text_decode_utf8(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_utf8) + + for c in valid_characters(): + enc = c.encode('utf-8') + assert len(enc) <= 4 + + dec = encoder.decode_text(enc) + assert len(dec) == 1 + assert dec == c + + +def test_text_decode_utf16be(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_utf16be) + + for c in valid_characters(): + enc = c.encode('utf-16be') + + dec = encoder.decode_text(enc) + assert len(c) == len(dec) + assert c == dec + + +def test_text_encode_iso8859(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_iso8859) + + for i in xrange(255): + c = unichr(i) + enc = encoder.encode_wtext(c) + assert enc == c.encode('latin-1') + + +def test_text_encode_utf8(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_utf8) + + for c in valid_characters(): + enc = encoder.encode_wtext(c) + assert enc == c.encode('utf-8') + + +def test_text_encode_utf16be(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_utf16be) + + for c in valid_characters(): + enc = encoder.encode_wtext(c) + assert enc == c.encode('utf-16-be') + + +def test_text_append_unicode_char(): + encoder = TextEncoder() + encoder.set_encoding(TextEncoder.E_iso8859) + + code_points = [] + for code_point in [0, 1, 127, 128, 255, 256, 0xfffd, 0x10000, 0x10ffff]: + if code_point <= sys.maxunicode: + code_points.append(code_point) + encoder.append_unicode_char(code_point) + + encoded = encoder.get_wtext() + assert len(encoded) == len(code_points) + + for a, b in zip(code_points, encoded): + assert a == ord(b) From 7bd8cbdeb6984673fff9ba0f56402208026a5f74 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 8 Oct 2018 23:20:04 +0200 Subject: [PATCH 06/60] windisplay: allow changing undecorated/fixed_size after window open Fixes #405 --- panda/src/windisplay/winGraphicsWindow.cxx | 38 ++++++++++++++++++---- panda/src/windisplay/winGraphicsWindow.h | 4 +-- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index 954d8aca41..be14041027 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -283,6 +283,25 @@ set_properties_now(WindowProperties &properties) { return; } + if (properties.has_undecorated() || + properties.has_fixed_size()) { + if (properties.has_undecorated()) { + _properties.set_undecorated(properties.get_undecorated()); + properties.clear_undecorated(); + } + if (properties.has_fixed_size()) { + _properties.set_fixed_size(properties.get_fixed_size()); + properties.clear_fixed_size(); + } + DWORD window_style = make_style(_properties); + SetWindowLong(_hWnd, GWL_STYLE, window_style); + + // We need to call this to ensure that the style change takes effect. + SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | + SWP_FRAMECHANGED | SWP_NOSENDCHANGING | SWP_SHOWWINDOW); + } + if (properties.has_title()) { std::string title = properties.get_title(); _properties.set_title(title); @@ -487,7 +506,7 @@ open_window() { // CreateWindow() and know which window it is sending events to even before // it gives us a handle. Warning: this is not thread safe! _creating_window = this; - bool opened = open_graphic_window(is_fullscreen()); + bool opened = open_graphic_window(); _creating_window = nullptr; if (!opened) { @@ -865,7 +884,9 @@ do_fullscreen_switch() { return false; } - DWORD window_style = make_style(true); + WindowProperties props(_properties); + props.set_fullscreen(true); + DWORD window_style = make_style(props); SetWindowLong(_hWnd, GWL_STYLE, window_style); WINDOW_METRICS metrics; @@ -885,7 +906,10 @@ do_fullscreen_switch() { bool WinGraphicsWindow:: do_windowed_switch() { do_fullscreen_disable(); - DWORD window_style = make_style(false); + + WindowProperties props(_properties); + props.set_fullscreen(false); + DWORD window_style = make_style(props); SetWindowLong(_hWnd, GWL_STYLE, window_style); WINDOW_METRICS metrics; @@ -928,7 +952,7 @@ support_overlay_window(bool) { * Constructs a dwStyle for the specified mode, be it windowed or fullscreen. */ DWORD WinGraphicsWindow:: -make_style(bool fullscreen) { +make_style(const WindowProperties &properties) { // from MSDN: An OpenGL window has its own pixel format. Because of this, // only device contexts retrieved for the client area of an OpenGL window // are allowed to draw into the window. As a result, an OpenGL window @@ -938,7 +962,7 @@ make_style(bool fullscreen) { DWORD window_style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; - if (fullscreen){ + if (_properties.get_fullscreen()) { window_style |= WS_SYSMENU; } else if (!_properties.get_undecorated()) { window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX); @@ -1015,8 +1039,8 @@ calculate_metrics(bool fullscreen, DWORD window_style, WINDOW_METRICS &metrics, * Creates a regular or fullscreen window. */ bool WinGraphicsWindow:: -open_graphic_window(bool fullscreen) { - DWORD window_style = make_style(fullscreen); +open_graphic_window() { + DWORD window_style = make_style(_properties); wstring title; if (_properties.has_title()) { diff --git a/panda/src/windisplay/winGraphicsWindow.h b/panda/src/windisplay/winGraphicsWindow.h index ff0340aa0d..5b0bb208c1 100644 --- a/panda/src/windisplay/winGraphicsWindow.h +++ b/panda/src/windisplay/winGraphicsWindow.h @@ -119,7 +119,7 @@ protected: virtual bool calculate_metrics(bool fullscreen, DWORD style, WINDOW_METRICS &metrics, bool &has_origin); - virtual DWORD make_style(bool fullscreen); + DWORD make_style(const WindowProperties &properties); virtual void reconsider_fullscreen_size(DWORD &x_size, DWORD &y_size, DWORD &bitdepth); @@ -127,7 +127,7 @@ protected: virtual void support_overlay_window(bool flag); private: - bool open_graphic_window(bool fullscreen); + bool open_graphic_window(); void adjust_z_order(); void adjust_z_order(WindowProperties::ZOrder last_z_order, WindowProperties::ZOrder this_z_order); From 6f623963735ed498e9bfcfa4ed887fc2e1adbe93 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Fri, 12 Oct 2018 15:37:18 -0600 Subject: [PATCH 07/60] general: Resolve a few compiler warnings - display: GraphicsWindowProc should have a virtual destructor, as it's meant to be subclassed. - express: set_matrix_view helper should always fail an assert when 'size' is wrong, even on release builds. - express: Fix filename capitalization on some #includes. They're normally Windows-only, where case doesn't matter, but it's better to be consistent. - gobj: Fix typo. - particlesystem: Remove BaseParticle::_last_position. Last position is tracked by PhysicsObject now. - windisplay: Heed warnings about casting bool to (PVOID). Also, per MSDN docs, SPI_SETMOUSETRAILS uses the uiParam argument and ignores pvParam, so pass the _saved_mouse_trails value in that way. --- panda/src/display/graphicsWindowProc.h | 1 + panda/src/express/pointerToArray_ext.I | 2 +- panda/src/express/pointerToArray_ext.h | 10 +++++----- panda/src/gobj/textureStage.cxx | 2 +- panda/src/particlesystem/baseParticle.cxx | 1 - panda/src/particlesystem/baseParticle.h | 2 -- panda/src/windisplay/winGraphicsWindow.cxx | 8 ++++---- 7 files changed, 12 insertions(+), 14 deletions(-) diff --git a/panda/src/display/graphicsWindowProc.h b/panda/src/display/graphicsWindowProc.h index c9c056eebd..a330c06a11 100644 --- a/panda/src/display/graphicsWindowProc.h +++ b/panda/src/display/graphicsWindowProc.h @@ -32,6 +32,7 @@ class GraphicsWindow; class EXPCL_PANDA_DISPLAY GraphicsWindowProc { public: GraphicsWindowProc(); + virtual ~GraphicsWindowProc() = default; #if defined(__WIN32__) || defined(_WIN32) virtual LONG wnd_proc(GraphicsWindow* graphicsWindow, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); diff --git a/panda/src/express/pointerToArray_ext.I b/panda/src/express/pointerToArray_ext.I index ee4c10e155..db14284e97 100644 --- a/panda/src/express/pointerToArray_ext.I +++ b/panda/src/express/pointerToArray_ext.I @@ -38,7 +38,7 @@ INLINE void set_matrix_view(Py_buffer &view, int flags, int length, int size, bo } else if (size == 4 && double_prec) { mat_size = sizeof(UnalignedLMatrix4d); } else { - assert(false); + nassertv_always(false); } view.len = length * mat_size; diff --git a/panda/src/express/pointerToArray_ext.h b/panda/src/express/pointerToArray_ext.h index 2daf885943..f17d1b634a 100644 --- a/panda/src/express/pointerToArray_ext.h +++ b/panda/src/express/pointerToArray_ext.h @@ -97,11 +97,11 @@ __getbuffer__(PyObject *self, Py_buffer *view, int flags) const; #ifdef _MSC_VER // Ugh... MSVC needs this because they still don't have a decent linker. -#include "PTA_uchar.h" -#include "PTA_ushort.h" -#include "PTA_float.h" -#include "PTA_double.h" -#include "PTA_int.h" +#include "pta_uchar.h" +#include "pta_ushort.h" +#include "pta_float.h" +#include "pta_double.h" +#include "pta_int.h" template class EXPORT_THIS Extension; template class EXPORT_THIS Extension; diff --git a/panda/src/gobj/textureStage.cxx b/panda/src/gobj/textureStage.cxx index 4fecd20999..0d6202d949 100644 --- a/panda/src/gobj/textureStage.cxx +++ b/panda/src/gobj/textureStage.cxx @@ -84,7 +84,7 @@ operator = (const TextureStage &other) { _combine_rgb_operand2 = other._combine_rgb_operand2; _combine_alpha_mode = other._combine_alpha_mode; _combine_alpha_source0 = other._combine_alpha_source0; - _combine_alpha_operand0 = _combine_alpha_operand0; + _combine_alpha_operand0 = other._combine_alpha_operand0; _combine_alpha_source1 = other._combine_alpha_source1; _combine_alpha_operand1 = other._combine_alpha_operand1; _combine_alpha_source2 = other._combine_alpha_source2; diff --git a/panda/src/particlesystem/baseParticle.cxx b/panda/src/particlesystem/baseParticle.cxx index 046b2dfb40..46e18179da 100644 --- a/panda/src/particlesystem/baseParticle.cxx +++ b/panda/src/particlesystem/baseParticle.cxx @@ -68,7 +68,6 @@ write(std::ostream &out, int indent) const { out.width(indent+2); out<<""; out<<"_lifespan "<<_lifespan<<"\n"; out.width(indent+2); out<<""; out<<"_alive "<<_alive<<"\n"; out.width(indent+2); out<<""; out<<"_index "<<_index<<"\n"; - out.width(indent+2); out<<""; out<<"_last_position "<<_last_position<<"\n"; PhysicsObject::write(out, indent+2); #endif //] NDEBUG } diff --git a/panda/src/particlesystem/baseParticle.h b/panda/src/particlesystem/baseParticle.h index 487f9ba476..834327bfec 100644 --- a/panda/src/particlesystem/baseParticle.h +++ b/panda/src/particlesystem/baseParticle.h @@ -62,8 +62,6 @@ private: PN_stdfloat _lifespan; bool _alive; int _index; - - LPoint3 _last_position; }; #include "baseParticle.I" diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index be14041027..b42ee43992 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -2210,12 +2210,12 @@ update_cursor_window(WinGraphicsWindow *to_window) { // We are leaving a graphics window; we should restore the Win2000 // effects. if (_got_saved_params) { - SystemParametersInfo(SPI_SETMOUSETRAILS, 0, - (PVOID)_saved_mouse_trails, 0); + SystemParametersInfo(SPI_SETMOUSETRAILS, _saved_mouse_trails, + 0, 0); SystemParametersInfo(SPI_SETCURSORSHADOW, 0, - (PVOID)_saved_cursor_shadow, 0); + _saved_cursor_shadow ? (PVOID)1 : nullptr, 0); SystemParametersInfo(SPI_SETMOUSEVANISH, 0, - (PVOID)_saved_mouse_vanish, 0); + _saved_mouse_vanish ? (PVOID)1 : nullptr, 0); _got_saved_params = false; } From 84ed19e8a7d34d78060c1215aebbfede5082cca8 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Fri, 12 Oct 2018 21:49:49 -0600 Subject: [PATCH 08/60] display: Add two missing includes (lightAttrib.h and materialAttrib.h) --- panda/src/display/standardMunger.cxx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/panda/src/display/standardMunger.cxx b/panda/src/display/standardMunger.cxx index 4bb96fcfd5..2dba4aa6c0 100644 --- a/panda/src/display/standardMunger.cxx +++ b/panda/src/display/standardMunger.cxx @@ -12,10 +12,14 @@ */ #include "standardMunger.h" -#include "renderState.h" -#include "graphicsStateGuardian.h" + #include "config_gobj.h" + #include "displayRegion.h" +#include "graphicsStateGuardian.h" +#include "lightAttrib.h" +#include "materialAttrib.h" +#include "renderState.h" TypeHandle StandardMunger::_type_handle; From 602ea6ebf4678150531ad1520d3b7b1666b7760f Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Sat, 13 Oct 2018 15:18:05 -0600 Subject: [PATCH 09/60] general: Fix a couple more compiler warnings - express: Fix a warning when compiling for debug - dtoolutil: Give TextEncoder a virtual destructor --- dtool/src/dtoolutil/textEncoder.h | 2 ++ panda/src/express/pointerToArray_ext.I | 1 + 2 files changed, 3 insertions(+) diff --git a/dtool/src/dtoolutil/textEncoder.h b/dtool/src/dtoolutil/textEncoder.h index 71d93a71ca..30004ef5d3 100644 --- a/dtool/src/dtoolutil/textEncoder.h +++ b/dtool/src/dtoolutil/textEncoder.h @@ -44,6 +44,8 @@ PUBLISHED: INLINE TextEncoder(); INLINE TextEncoder(const TextEncoder ©); + virtual ~TextEncoder() = default; + INLINE void set_encoding(Encoding encoding); INLINE Encoding get_encoding() const; diff --git a/panda/src/express/pointerToArray_ext.I b/panda/src/express/pointerToArray_ext.I index db14284e97..5bcd1b77e9 100644 --- a/panda/src/express/pointerToArray_ext.I +++ b/panda/src/express/pointerToArray_ext.I @@ -39,6 +39,7 @@ INLINE void set_matrix_view(Py_buffer &view, int flags, int length, int size, bo mat_size = sizeof(UnalignedLMatrix4d); } else { nassertv_always(false); + return; // Make sure compiler knows control flow doesn't proceed. } view.len = length * mat_size; From 2d80d6d063ef30d96d93bdd3683a634cce33b2b0 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Sun, 14 Oct 2018 15:50:06 -0600 Subject: [PATCH 10/60] general: Add missing includes and remove deprecated type Credit for missing includes to @treamology in Git commit 16cfac482923bc734447d234fd8eaaa99483847d CGTableCount removed; modern macOS seems to call this a uint32_t instead. I can find no reference to CGTableCount in any documentation, and the (very old) source code I dig up just typedefs it anyway. --- panda/src/cocoadisplay/cocoaPandaApp.mm | 1 + panda/src/display/subprocessWindow.cxx | 2 ++ panda/src/osxdisplay/osxGraphicsStateGuardian.h | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/panda/src/cocoadisplay/cocoaPandaApp.mm b/panda/src/cocoadisplay/cocoaPandaApp.mm index e7226786da..83f0b8ef42 100644 --- a/panda/src/cocoadisplay/cocoaPandaApp.mm +++ b/panda/src/cocoadisplay/cocoaPandaApp.mm @@ -12,6 +12,7 @@ */ #import "cocoaPandaApp.h" +#include "config_cocoadisplay.h" @implementation CocoaPandaApp - (void) sendEvent: (NSEvent *) event { diff --git a/panda/src/display/subprocessWindow.cxx b/panda/src/display/subprocessWindow.cxx index fe4b2eff5d..5ea85c3cc9 100644 --- a/panda/src/display/subprocessWindow.cxx +++ b/panda/src/display/subprocessWindow.cxx @@ -18,6 +18,8 @@ #include "graphicsEngine.h" #include "config_display.h" #include "nativeWindowHandle.h" +#include "mouseButton.h" +#include "throw_event.h" using std::string; diff --git a/panda/src/osxdisplay/osxGraphicsStateGuardian.h b/panda/src/osxdisplay/osxGraphicsStateGuardian.h index 038ba42055..96c86f28dd 100644 --- a/panda/src/osxdisplay/osxGraphicsStateGuardian.h +++ b/panda/src/osxdisplay/osxGraphicsStateGuardian.h @@ -64,7 +64,7 @@ private: CGGammaValue _gOriginalRedTable[ 256 ]; CGGammaValue _gOriginalGreenTable[ 256 ]; CGGammaValue _gOriginalBlueTable[ 256 ]; - CGTableCount _sampleCount; + uint32_t _sampleCount; CGDisplayErr _cgErr; public: From d7f19b73e0f903a6c7341716822d16219e0075e9 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Oct 2018 13:27:36 +0200 Subject: [PATCH 11/60] dtoolutil: minor fix to TextEncoder::append_text --- dtool/src/dtoolutil/textEncoder_ext.cxx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dtool/src/dtoolutil/textEncoder_ext.cxx b/dtool/src/dtoolutil/textEncoder_ext.cxx index b085b8a965..1947e6c749 100644 --- a/dtool/src/dtoolutil/textEncoder_ext.cxx +++ b/dtool/src/dtoolutil/textEncoder_ext.cxx @@ -94,7 +94,12 @@ append_text(PyObject *text) { #if PY_VERSION_HEX >= 0x03030000 Py_ssize_t len; const char *str = PyUnicode_AsUTF8AndSize(text, &len); - _this->append_text(std::string(str, len)); + std::string text_str(str, len); + if (_this->get_encoding() == TextEncoder::E_utf8) { + _this->append_text(text_str); + } else { + _this->append_wtext(TextEncoder::decode_text(text_str, TextEncoder::E_utf8)); + } #else Py_ssize_t len = PyUnicode_GET_SIZE(text); wchar_t *str = (wchar_t *)alloca(sizeof(wchar_t) * (len + 1)); From 02a72d4273dcd580b68c7332683303cdca200483 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Oct 2018 13:30:22 +0200 Subject: [PATCH 12/60] makepanda: remove reference to QuickTime framework Doesn't appear to be necessary, and QuickTime framework is removed in Mojave. Fixes #412 --- makepanda/makepanda.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 0164278d1e..dedd90b059 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -946,8 +946,6 @@ if (COMPILER=="GCC"): if GetTarget() == 'darwin': LibName("ALWAYS", "-framework AppKit") - if (PkgSkip("OPENCV")==0): - LibName("OPENCV", "-framework QuickTime") LibName("AGL", "-framework AGL") LibName("CARBON", "-framework Carbon") LibName("COCOA", "-framework Cocoa") From a765c32baef8da0185f4551945f27bd8ffa5f289 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Oct 2018 13:32:22 +0200 Subject: [PATCH 13/60] makepanda: don't use -fno-rtti on macOS, it fails to compile It appears that (included by ) uses RTTI, so we can't enable this for now. --- makepanda/makepanda.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index dedd90b059..540d9e86cf 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -1332,9 +1332,10 @@ def CompileCxx(obj,src,opts): # Work around Apple compiler bug. cmd += " -U__EXCEPTIONS" - if 'RTTI' not in opts: + target = GetTarget() + if 'RTTI' not in opts and target != "darwin": # We always disable RTTI on Android for memory usage reasons. - if optlevel >= 4 or GetTarget() == "android": + if optlevel >= 4 or target == "android": cmd += " -fno-rtti" if ('SSE2' in opts or not PkgSkip("SSE2")) and not arch.startswith("arm") and arch != 'aarch64': From 70f4c1cd4e08918c86d809316f14618e5560087e Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Oct 2018 14:09:25 +0200 Subject: [PATCH 14/60] glgsg: change missing Cg attrib error message to debug This can occur if a variable is optimized out by the GLSL compiler but not by the Cg compiler. So it should not be reported as an error. Fixes #417 --- panda/src/glstuff/glCgShaderContext_src.cxx | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 3a9b2fea6a..649208fb47 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -226,12 +226,14 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte if (!resource) { resource = "unknown"; } - GLCAT.error() - << "Could not find Cg varying " << cgGetParameterName(p); - if (attribname) { - GLCAT.error(false) << " : " << attribname; + if (GLCAT.is_debug()) { + GLCAT.debug() + << "Could not find Cg varying " << cgGetParameterName(p); + if (attribname) { + GLCAT.debug(false) << " : " << attribname; + } + GLCAT.debug(false) << " (" << resource << ") in the compiled GLSL program.\n"; } - GLCAT.error(false) << " (" << resource << ") in the compiled GLSL program.\n"; } else if (loc != 0 && bind._id._name == "vtx_position") { // We really have to bind the vertex position to attribute 0, since @@ -312,10 +314,10 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte GLCAT.debug(false) << " is bound to a conventional attribute (" << resource << ")\n"; } - } - if (loc == CA_unknown) { - // Suggest fix to developer. - GLCAT.error() << "Try using a different semantic.\n"; + if (loc == CA_unknown) { + // Suggest fix to developer. + GLCAT.debug() << "Try using a different semantic.\n"; + } } #endif From 6e370ebbdd63dc92dcdec7bc2575825a4a20c587 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Oct 2018 22:06:04 +0200 Subject: [PATCH 15/60] gobj: speed up GeomVertexData::get_num_rows() considerably --- panda/src/gobj/geomVertexArrayData.I | 4 +++- panda/src/gobj/geomVertexData.I | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/panda/src/gobj/geomVertexArrayData.I b/panda/src/gobj/geomVertexArrayData.I index cfe12f9013..30e5c590e8 100644 --- a/panda/src/gobj/geomVertexArrayData.I +++ b/panda/src/gobj/geomVertexArrayData.I @@ -45,7 +45,9 @@ has_column(const InternalName *name) const { */ INLINE int GeomVertexArrayData:: get_num_rows() const { - return get_handle()->get_num_rows(); + CDReader cdata(_cycler); + nassertr(_array_format->get_stride() != 0, 0); + return cdata->_buffer.get_size() / _array_format->get_stride(); } /** diff --git a/panda/src/gobj/geomVertexData.I b/panda/src/gobj/geomVertexData.I index bfea5a10ef..bd68fc4cf4 100644 --- a/panda/src/gobj/geomVertexData.I +++ b/panda/src/gobj/geomVertexData.I @@ -60,9 +60,20 @@ has_column(const InternalName *name) const { */ INLINE int GeomVertexData:: get_num_rows() const { - GeomVertexDataPipelineReader reader(this, Thread::get_current_thread()); - reader.check_array_readers(); - return reader.get_num_rows(); + CPT(GeomVertexArrayData) array; + { + CDReader cdata(_cycler); + nassertr(cdata->_format->get_num_arrays() == cdata->_arrays.size(), 0); + + if (cdata->_arrays.size() == 0) { + // No arrays means no rows. Weird but legal. + return 0; + } + + array = cdata->_arrays[0].get_read_pointer(); + } + + return array->get_num_rows(); } /** From 0131d1013bba9688001a7c5b95069b28117932ba Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Oct 2018 22:07:32 +0200 Subject: [PATCH 16/60] gobj: fix assert when enabling hw anim if blend has 5+ transforms Instead, we reduce the TransformBlend down to the 4 most-weighted joints. --- panda/src/gobj/geomVertexData.cxx | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index 5e5fa7a1d4..d97197e25c 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -621,13 +621,26 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, const TransformBlend &blend = blend_table->get_blend(from.get_data1i()); LVecBase4 weights = LVecBase4::zero(); LVecBase4i indices(0, 0, 0, 0); - nassertv(blend.get_num_transforms() <= 4); - for (size_t i = 0; i < blend.get_num_transforms(); i++) { - weights[i] = blend.get_weight(i); - indices[i] = add_transform(transform_table, blend.get_transform(i), - already_added); + if (blend.get_num_transforms() <= 4) { + for (size_t i = 0; i < blend.get_num_transforms(); i++) { + weights[i] = blend.get_weight(i); + indices[i] = add_transform(transform_table, blend.get_transform(i), + already_added); + } + } else { + // Limit the number of blends to the four with highest weights. + TransformBlend blend2(blend); + blend2.limit_transforms(4); + blend2.normalize_weights(); + + for (size_t i = 0; i < 4; i++) { + weights[i] = blend2.get_weight(i); + indices[i] = add_transform(transform_table, blend2.get_transform(i), + already_added); + } } + if (weight.has_column()) { weight.set_data4(weights); } From bcc2e3e4042c31b2fe18de863159197c68b2749d Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Oct 2018 22:11:54 +0200 Subject: [PATCH 17/60] gobj: add Geom::get_animated_vertex_data() short-hand This is a method for getting the animated vertex data that will keep working even if GeomVertexData::animate_vertices() gets deprecated due to #421 being fixed. --- panda/src/collide/collisionTraverser.cxx | 2 +- panda/src/distort/projectionScreen.cxx | 8 +++----- panda/src/gobj/geom.cxx | 25 ++++++++++++++++++++++-- panda/src/gobj/geom.h | 2 ++ panda/src/grutil/multitexReducer.cxx | 2 +- panda/src/pgraph/geomNode.cxx | 5 ++--- 6 files changed, 32 insertions(+), 12 deletions(-) diff --git a/panda/src/collide/collisionTraverser.cxx b/panda/src/collide/collisionTraverser.cxx index 6e8a01d68f..35f7966a3f 100644 --- a/panda/src/collide/collisionTraverser.cxx +++ b/panda/src/collide/collisionTraverser.cxx @@ -1254,7 +1254,7 @@ compare_collider_to_geom(CollisionEntry &entry, const Geom *geom, if (geom->get_primitive_type() == Geom::PT_polygons) { Thread *current_thread = Thread::get_current_thread(); - CPT(GeomVertexData) data = geom->get_vertex_data()->animate_vertices(true, current_thread); + CPT(GeomVertexData) data = geom->get_animated_vertex_data(true, current_thread); GeomVertexReader vertex(data, InternalName::get_vertex()); int num_primitives = geom->get_num_primitives(); diff --git a/panda/src/distort/projectionScreen.cxx b/panda/src/distort/projectionScreen.cxx index e3bed91e27..74314bce06 100644 --- a/panda/src/distort/projectionScreen.cxx +++ b/panda/src/distort/projectionScreen.cxx @@ -484,8 +484,7 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) { const LMatrix4 &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv; // Iterate through all the vertices in the Geom. - CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread); - vdata = vdata->animate_vertices(true, current_thread); + CPT(GeomVertexData) vdata = geom->get_animated_vertex_data(true, current_thread); CPT(GeomVertexFormat) vformat = vdata->get_format(); if (!vformat->has_column(_texcoord_name) || (_texcoord_3d && vformat->get_column(_texcoord_name)->get_num_components() < 3)) { @@ -507,7 +506,7 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) { PT(GeomVertexData) modify_vdata = geom->modify_vertex_data(); // Maybe the vdata has animation that we should consider. - CPT(GeomVertexData) animated_vdata = geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread); + CPT(GeomVertexData) animated_vdata = geom->get_animated_vertex_data(true, current_thread); GeomVertexWriter texcoord(modify_vdata, _texcoord_name, current_thread); GeomVertexWriter color(modify_vdata, current_thread); @@ -674,9 +673,8 @@ make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4 &rel_mat) { Thread *current_thread = Thread::get_current_thread(); PT(Geom) new_geom = geom->make_copy(); + new_geom->set_vertex_data(new_geom->get_animated_vertex_data(false, current_thread)); PT(GeomVertexData) vdata = new_geom->modify_vertex_data(); - new_geom->set_vertex_data(vdata->animate_vertices(false, current_thread)); - vdata = new_geom->modify_vertex_data(); GeomVertexRewriter vertex(vdata, InternalName::get_vertex()); while (!vertex.is_at_end()) { LVertex vert = vertex.get_data3(); diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 565f8c47b4..bafe523e0f 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -286,6 +286,28 @@ make_nonindexed(bool composite_only) { return num_changed; } +/** + * Returns a GeomVertexData that represents the results of computing the + * vertex animation on the CPU for this Geom's vertex data. + * + * If there is no CPU-defined vertex animation on this object, this just + * returns the original object. + * + * If there is vertex animation, but the VertexTransform values have not + * changed since last time, this may return the same pointer it returned + * previously. Even if the VertexTransform values have changed, it may still + * return the same pointer, but with its contents modified (this is preferred, + * since it allows the graphics backend to update vertex buffers optimally). + * + * If force is false, this method may return immediately with stale data, if + * the vertex data is not completely resident. If force is true, this method + * will never return stale data, but may block until the data is available. + */ +CPT(GeomVertexData) Geom:: +get_animated_vertex_data(bool force, Thread *current_thread) const { + return get_vertex_data()->animate_vertices(force, current_thread); +} + /** * Replaces the ith GeomPrimitive object stored within the Geom with the new * object. @@ -1311,8 +1333,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { int num_vertices = 0; // Get the vertex data, after animation. - CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(current_thread); - vertex_data = vertex_data->animate_vertices(true, current_thread); + CPT(GeomVertexData) vertex_data = get_animated_vertex_data(true, current_thread); // Now actually compute the bounding volume. We do this by using // calc_tight_bounds to determine our box first. diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 833ac3cd83..82aac75cfa 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -85,6 +85,8 @@ PUBLISHED: void offset_vertices(const GeomVertexData *data, int offset); int make_nonindexed(bool composite_only); + CPT(GeomVertexData) get_animated_vertex_data(bool force, Thread *current_thread) const; + INLINE bool is_empty() const; INLINE size_t get_num_primitives() const; diff --git a/panda/src/grutil/multitexReducer.cxx b/panda/src/grutil/multitexReducer.cxx index fdad25bb48..2fff484de3 100644 --- a/panda/src/grutil/multitexReducer.cxx +++ b/panda/src/grutil/multitexReducer.cxx @@ -866,7 +866,7 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name, PT(Geom) geom = orig_geom->make_copy(); // Ensure that any vertex animation has been applied. - geom->set_vertex_data(geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread)); + geom->set_vertex_data(geom->get_animated_vertex_data(true, current_thread)); // Now get a modifiable pointer to the vertex data in the new Geom. This // will actually perform a deep copy of the vertex data. diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index 16e95442c2..17d5555e5d 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -376,8 +376,7 @@ r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, geom = transformer.premunge_geom(geom, munger); // Prepare each of the vertex arrays in the munged Geom. - CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread); - vdata = vdata->animate_vertices(false, current_thread); + CPT(GeomVertexData) vdata = geom->get_animated_vertex_data(false, current_thread); GeomVertexDataPipelineReader vdata_reader(vdata, current_thread); int num_arrays = vdata_reader.get_num_arrays(); for (int i = 0; i < num_arrays; ++i) { @@ -474,7 +473,7 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any, for (gi = geoms->begin(); gi != geoms->end(); ++gi) { CPT(Geom) geom = (*gi)._geom.get_read_pointer(); geom->calc_tight_bounds(min_point, max_point, found_any, - geom->get_vertex_data(current_thread)->animate_vertices(true, current_thread), + geom->get_animated_vertex_data(true, current_thread), !next_transform->is_identity(), mat, current_thread); } From ebfb3702acf79a54ab3ce455ff6d0abfbcfd66e9 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Oct 2018 22:21:45 +0200 Subject: [PATCH 18/60] prc: work around macOS compiler error when making optimized build --- dtool/src/prc/notifyCategory.I | 20 -------------------- dtool/src/prc/notifyCategory.h | 4 ++-- dtool/src/prc/notifyCategoryProxy.I | 12 ------------ dtool/src/prc/notifyCategoryProxy.h | 4 ++-- 4 files changed, 4 insertions(+), 36 deletions(-) diff --git a/dtool/src/prc/notifyCategory.I b/dtool/src/prc/notifyCategory.I index 5793917d91..20678fbace 100644 --- a/dtool/src/prc/notifyCategory.I +++ b/dtool/src/prc/notifyCategory.I @@ -82,26 +82,6 @@ is_debug() const { // Instruct the compiler to optimize for the usual case. return UNLIKELY(is_on(NS_debug)); } -#else -/** - * When NOTIFY_DEBUG is not defined, the categories are never set to "spam" or - * "debug" severities, and these methods are redefined to be static to make it - * more obvious to the compiler. - */ -constexpr bool NotifyCategory:: -is_spam() { - return false; -} - -/** - * When NOTIFY_DEBUG is not defined, the categories are never set to "spam" or - * "debug" severities, and these methods are redefined to be static to make it - * more obvious to the compiler. - */ -constexpr bool NotifyCategory:: -is_debug() { - return false; -} #endif /** diff --git a/dtool/src/prc/notifyCategory.h b/dtool/src/prc/notifyCategory.h index f3e99b09ba..9a2a9fa4e2 100644 --- a/dtool/src/prc/notifyCategory.h +++ b/dtool/src/prc/notifyCategory.h @@ -55,8 +55,8 @@ PUBLISHED: INLINE bool is_spam() const; INLINE bool is_debug() const; #else - constexpr static bool is_spam(); - constexpr static bool is_debug(); + constexpr static bool is_spam() { return false; } + constexpr static bool is_debug() { return false; } #endif INLINE bool is_info() const; INLINE bool is_warning() const; diff --git a/dtool/src/prc/notifyCategoryProxy.I b/dtool/src/prc/notifyCategoryProxy.I index eaca9b6e33..fbdac1f0ca 100644 --- a/dtool/src/prc/notifyCategoryProxy.I +++ b/dtool/src/prc/notifyCategoryProxy.I @@ -72,12 +72,6 @@ is_spam() { // Instruct the compiler to optimize for the usual case. return UNLIKELY(get_unsafe_ptr()->is_spam()); } -#else -template -constexpr bool NotifyCategoryProxy:: -is_spam() { - return false; -} #endif /** @@ -90,12 +84,6 @@ is_debug() { // Instruct the compiler to optimize for the usual case. return UNLIKELY(get_unsafe_ptr()->is_debug()); } -#else -template -constexpr bool NotifyCategoryProxy:: -is_debug() { - return false; -} #endif /** diff --git a/dtool/src/prc/notifyCategoryProxy.h b/dtool/src/prc/notifyCategoryProxy.h index 06f38ec804..5465529583 100644 --- a/dtool/src/prc/notifyCategoryProxy.h +++ b/dtool/src/prc/notifyCategoryProxy.h @@ -75,8 +75,8 @@ public: INLINE bool is_spam(); INLINE bool is_debug(); #else - constexpr static bool is_spam(); - constexpr static bool is_debug(); + constexpr static bool is_spam() { return false; } + constexpr static bool is_debug() { return false; } #endif INLINE bool is_info(); INLINE bool is_warning(); From 51f5124048f8f50b3580cec0815cb358de8cd041 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 15 Oct 2018 22:23:45 +0200 Subject: [PATCH 19/60] dtoolutil: consistently use char32_t for Unicode code points Unlike wchar_t, char32_t is guaranteed to be able to hold a UTF-32 character. --- dtool/src/dtoolutil/textEncoder.I | 18 +++++++++--------- dtool/src/dtoolutil/textEncoder.h | 20 ++++++++++---------- dtool/src/dtoolutil/unicodeLatinMap.cxx | 2 +- dtool/src/dtoolutil/unicodeLatinMap.h | 10 +++++----- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/dtool/src/dtoolutil/textEncoder.I b/dtool/src/dtoolutil/textEncoder.I index 766319d6da..c9eeb0ec66 100644 --- a/dtool/src/dtoolutil/textEncoder.I +++ b/dtool/src/dtoolutil/textEncoder.I @@ -220,7 +220,7 @@ get_unicode_char(size_t index) const { * according to set_encoding(). */ INLINE void TextEncoder:: -set_unicode_char(size_t index, int character) { +set_unicode_char(size_t index, char32_t character) { get_wtext(); if (index < _wtext.length()) { _wtext[index] = character; @@ -283,7 +283,7 @@ reencode_text(const std::string &text, TextEncoder::Encoding from, * otherwise. This is akin to ctype's isalpha(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_isalpha(int character) { +unicode_isalpha(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return false; @@ -297,7 +297,7 @@ unicode_isalpha(int character) { * otherwise. This is akin to ctype's isdigit(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_isdigit(int character) { +unicode_isdigit(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { // The digits aren't actually listed in the map. @@ -312,7 +312,7 @@ unicode_isdigit(int character) { * otherwise. This is akin to ctype's ispunct(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_ispunct(int character) { +unicode_ispunct(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { // Some punctuation marks aren't listed in the map. @@ -326,7 +326,7 @@ unicode_ispunct(int character) { * otherwise. This is akin to ctype's isupper(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_isupper(int character) { +unicode_isupper(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return false; @@ -339,7 +339,7 @@ unicode_isupper(int character) { * otherwise. This is akin to ctype's isspace(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_isspace(int character) { +unicode_isspace(char32_t character) { switch (character) { case ' ': case '\t': @@ -356,7 +356,7 @@ unicode_isspace(int character) { * otherwise. This is akin to ctype's islower(), extended to Unicode. */ INLINE bool TextEncoder:: -unicode_islower(int character) { +unicode_islower(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return false; @@ -369,7 +369,7 @@ unicode_islower(int character) { * akin to ctype's toupper(), extended to Unicode. */ INLINE int TextEncoder:: -unicode_toupper(int character) { +unicode_toupper(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return character; @@ -382,7 +382,7 @@ unicode_toupper(int character) { * akin to ctype's tolower(), extended to Unicode. */ INLINE int TextEncoder:: -unicode_tolower(int character) { +unicode_tolower(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { return character; diff --git a/dtool/src/dtoolutil/textEncoder.h b/dtool/src/dtoolutil/textEncoder.h index 30004ef5d3..1e1d9eeda4 100644 --- a/dtool/src/dtoolutil/textEncoder.h +++ b/dtool/src/dtoolutil/textEncoder.h @@ -23,7 +23,7 @@ class StringDecoder; /** * This class can be used to convert text between multiple representations, - * e.g. utf-8 to Unicode. You may use it as a static class object, passing + * e.g. UTF-8 to UTF-16. You may use it as a static class object, passing * the encoding each time, or you may create an instance and use that object, * which will record the current encoding and retain the current string. * @@ -78,21 +78,21 @@ PUBLISHED: INLINE void append_unicode_char(char32_t character); INLINE size_t get_num_chars() const; INLINE int get_unicode_char(size_t index) const; - INLINE void set_unicode_char(size_t index, int character); + INLINE void set_unicode_char(size_t index, char32_t character); INLINE std::string get_encoded_char(size_t index) const; INLINE std::string get_encoded_char(size_t index, Encoding encoding) const; INLINE std::string get_text_as_ascii() const; INLINE static std::string reencode_text(const std::string &text, Encoding from, Encoding to); - INLINE static bool unicode_isalpha(int character); - INLINE static bool unicode_isdigit(int character); - INLINE static bool unicode_ispunct(int character); - INLINE static bool unicode_islower(int character); - INLINE static bool unicode_isupper(int character); - INLINE static bool unicode_isspace(int character); - INLINE static int unicode_toupper(int character); - INLINE static int unicode_tolower(int character); + INLINE static bool unicode_isalpha(char32_t character); + INLINE static bool unicode_isdigit(char32_t character); + INLINE static bool unicode_ispunct(char32_t character); + INLINE static bool unicode_islower(char32_t character); + INLINE static bool unicode_isupper(char32_t character); + INLINE static bool unicode_isspace(char32_t character); + INLINE static int unicode_toupper(char32_t character); + INLINE static int unicode_tolower(char32_t character); INLINE static std::string upper(const std::string &source); INLINE static std::string upper(const std::string &source, Encoding encoding); diff --git a/dtool/src/dtoolutil/unicodeLatinMap.cxx b/dtool/src/dtoolutil/unicodeLatinMap.cxx index 87c9cb5a7d..288b85a4ce 100644 --- a/dtool/src/dtoolutil/unicodeLatinMap.cxx +++ b/dtool/src/dtoolutil/unicodeLatinMap.cxx @@ -1378,7 +1378,7 @@ static const wchar_t combining_accent_map[] = { * Returns the Entry associated with the indicated character, if there is one. */ const UnicodeLatinMap::Entry *UnicodeLatinMap:: -look_up(wchar_t character) { +look_up(char32_t character) { if (!_initialized) { init(); } diff --git a/dtool/src/dtoolutil/unicodeLatinMap.h b/dtool/src/dtoolutil/unicodeLatinMap.h index fb94154f7f..6ed3c5f17c 100644 --- a/dtool/src/dtoolutil/unicodeLatinMap.h +++ b/dtool/src/dtoolutil/unicodeLatinMap.h @@ -112,17 +112,17 @@ public: class Entry { public: - wchar_t _character; + char32_t _character; CharType _char_type; char _ascii_equiv; char _ascii_additional; - wchar_t _tolower_character; - wchar_t _toupper_character; + char32_t _tolower_character; + char32_t _toupper_character; AccentType _accent_type; int _additional_flags; }; - static const Entry *look_up(wchar_t character); + static const Entry *look_up(char32_t character); static wchar_t get_combining_accent(AccentType accent); @@ -130,7 +130,7 @@ private: static void init(); static bool _initialized; - typedef phash_map > ByCharacter; + typedef phash_map > ByCharacter; static ByCharacter *_by_character; enum { max_direct_chars = 256 }; static const Entry *_direct_chars[max_direct_chars]; From 75826c9a517b43053529e9e233b8d20524e99e02 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 16 Oct 2018 15:20:45 +0200 Subject: [PATCH 20/60] glgsg: fix error with multisampled float depth buffer Fixes #416 --- panda/src/glstuff/glGraphicsBuffer_src.cxx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index eab850bdba..d5a8763fc8 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -1097,6 +1097,15 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, #endif glgsg->_glBindRenderbuffer(GL_RENDERBUFFER_EXT, _rbm[slot]); GLuint format = GL_DEPTH_COMPONENT; +#ifndef OPENGLES + if (_fb_properties.get_float_depth()) { + if (!glgsg->_use_remapped_depth_range) { + format = GL_DEPTH_COMPONENT32F; + } else { + format = GL_DEPTH_COMPONENT32F_NV; + } + } else +#endif if (tex) { switch (tex->get_format()) { case Texture::F_depth_component16: From bfeb5060b814d25282ad395e8ab2411c01932585 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 16 Oct 2018 15:23:52 +0200 Subject: [PATCH 21/60] gobj: don't create pointless future in TextureReloadRequest --- panda/src/gobj/textureReloadRequest.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/gobj/textureReloadRequest.cxx b/panda/src/gobj/textureReloadRequest.cxx index 4c17b550b7..b63acb6090 100644 --- a/panda/src/gobj/textureReloadRequest.cxx +++ b/panda/src/gobj/textureReloadRequest.cxx @@ -40,7 +40,7 @@ do_task() { // become a kind of a leak (if the texture is never rendered again on // this GSG, we'll just end up carrying the texture memory in RAM // forever, instead of dumping it as soon as it gets prepared). - _texture->prepare(_pgo); + _pgo->enqueue_texture(_texture); } } From b569875bf91dcb510daaef7880c36c70fb8cdb69 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 16 Oct 2018 16:31:46 +0200 Subject: [PATCH 22/60] windisplay: fix window size changing when switching undecorated --- panda/src/windisplay/winGraphicsWindow.cxx | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/panda/src/windisplay/winGraphicsWindow.cxx b/panda/src/windisplay/winGraphicsWindow.cxx index b42ee43992..703aba0149 100644 --- a/panda/src/windisplay/winGraphicsWindow.cxx +++ b/panda/src/windisplay/winGraphicsWindow.cxx @@ -293,13 +293,29 @@ set_properties_now(WindowProperties &properties) { _properties.set_fixed_size(properties.get_fixed_size()); properties.clear_fixed_size(); } + // When switching undecorated mode, Windows will keep the window at the + // current outer size, whereas we want to keep it with the configured + // inner size. Store the current size and origin. + LPoint2i top_left = _properties.get_origin(); + LPoint2i bottom_right = top_left + _properties.get_size(); + DWORD window_style = make_style(_properties); SetWindowLong(_hWnd, GWL_STYLE, window_style); + // Now calculate the proper size and origin with the new window style. + RECT view_rect; + SetRect(&view_rect, top_left[0], top_left[1], + bottom_right[0], bottom_right[1]); + WINDOWINFO wi; + GetWindowInfo(_hWnd, &wi); + AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle); + // We need to call this to ensure that the style change takes effect. - SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | - SWP_FRAMECHANGED | SWP_NOSENDCHANGING | SWP_SHOWWINDOW); + SetWindowPos(_hWnd, HWND_NOTOPMOST, view_rect.left, view_rect.top, + view_rect.right - view_rect.left, + view_rect.bottom - view_rect.top, + SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | + SWP_NOSENDCHANGING | SWP_SHOWWINDOW); } if (properties.has_title()) { From 82e2c391723e972f2d05d46fec28b88109cee6e9 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 16 Oct 2018 16:32:57 +0200 Subject: [PATCH 23/60] dtoolutil: fix tautological comparison compile warning --- dtool/src/dtoolutil/textEncoder.I | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtool/src/dtoolutil/textEncoder.I b/dtool/src/dtoolutil/textEncoder.I index c9eeb0ec66..aa6b42fdb5 100644 --- a/dtool/src/dtoolutil/textEncoder.I +++ b/dtool/src/dtoolutil/textEncoder.I @@ -316,7 +316,7 @@ unicode_ispunct(char32_t character) { const UnicodeLatinMap::Entry *entry = UnicodeLatinMap::look_up(character); if (entry == nullptr) { // Some punctuation marks aren't listed in the map. - return (character >= 0 && character < 128 && ispunct(character)); + return (character < 128 && ispunct(character)); } return entry->_char_type == UnicodeLatinMap::CT_punct; } From fbf939141b4a2bd472a40fe5caa85e356d8d2b4c Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 16 Oct 2018 21:13:27 +0200 Subject: [PATCH 24/60] gobj: fix typo causing crash when preparing shader --- panda/src/gobj/preparedGraphicsObjects.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index 4f6ecea1ed..96fcd80269 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -1619,8 +1619,8 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) { ++qsi) { Shader *shader = qsi->first; ShaderContext *sc = shader->prepare_now(this, gsg); - if (qti->second != nullptr) { - qti->second->set_result(sc); + if (qsi->second != nullptr) { + qsi->second->set_result(sc); } } From 0c9c698d136f3e8418c8356848e992ab9230f8b4 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 16 Oct 2018 21:18:02 +0200 Subject: [PATCH 25/60] pipeline: make BlockerSimple constexpr (needed by MutexSimpleImpl) --- panda/src/pipeline/blockerSimple.I | 8 -------- panda/src/pipeline/blockerSimple.h | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/panda/src/pipeline/blockerSimple.I b/panda/src/pipeline/blockerSimple.I index 0188281728..89be34a412 100644 --- a/panda/src/pipeline/blockerSimple.I +++ b/panda/src/pipeline/blockerSimple.I @@ -11,14 +11,6 @@ * @date 2007-06-20 */ -/** - * - */ -INLINE BlockerSimple:: -BlockerSimple() { - _flags = 0; -} - /** * */ diff --git a/panda/src/pipeline/blockerSimple.h b/panda/src/pipeline/blockerSimple.h index 71ae25c41d..d375d5dc16 100644 --- a/panda/src/pipeline/blockerSimple.h +++ b/panda/src/pipeline/blockerSimple.h @@ -28,7 +28,7 @@ */ class EXPCL_PANDA_PIPELINE BlockerSimple { protected: - INLINE BlockerSimple(); + constexpr BlockerSimple() = default; INLINE ~BlockerSimple(); protected: @@ -38,7 +38,7 @@ protected: F_has_waiters = 0x40000000, }; - unsigned int _flags; + unsigned int _flags = 0; friend class ThreadSimpleManager; }; From 88b0f3327ddf4cbbcf0c2af261daa658d4fee4d1 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 16 Oct 2018 21:19:06 +0200 Subject: [PATCH 26/60] Warning fixes and cleanups when building with SIMPLE_THREADS --- panda/src/net/connection.cxx | 2 +- .../src/pipeline/contextSwitch_longjmp_src.c | 19 ++++++------ panda/src/pipeline/contextSwitch_posix_src.c | 29 +++++++++---------- .../src/pipeline/contextSwitch_ucontext_src.c | 13 ++++----- .../src/pipeline/contextSwitch_windows_src.c | 19 ++++++------ panda/src/pipeline/pythonThread.cxx | 2 +- panda/src/pipeline/threadSimpleManager.cxx | 4 ++- 7 files changed, 43 insertions(+), 45 deletions(-) diff --git a/panda/src/net/connection.cxx b/panda/src/net/connection.cxx index aecfc111ac..27f5c8bb24 100644 --- a/panda/src/net/connection.cxx +++ b/panda/src/net/connection.cxx @@ -445,7 +445,7 @@ do_flush() { if (data_sent > 0) { total_sent += data_sent; } - double last_report = 0; + while (!okflag && tcp->Active() && (data_sent > 0 || tcp->GetLastError() == LOCAL_BLOCKING_ERROR)) { if (data_sent == 0) { diff --git a/panda/src/pipeline/contextSwitch_longjmp_src.c b/panda/src/pipeline/contextSwitch_longjmp_src.c index c3640b8f1f..5dec92804a 100644 --- a/panda/src/pipeline/contextSwitch_longjmp_src.c +++ b/panda/src/pipeline/contextSwitch_longjmp_src.c @@ -1,8 +1,4 @@ -/* Filename: contextSwitch_longjmp_src.c - * Created by: drose (15Apr10) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * +/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * @@ -10,7 +6,10 @@ * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * @file contextSwitch_longjmp_src.c + * @author drose + * @date 2010-04-15 + */ /* This is the implementation of user-space context switching using setmp() / longjmp(). This is the hackier implementation, @@ -90,14 +89,14 @@ void cs_longjmp(cs_jmp_buf env) { _asm { mov eax, env; - + mov ebx, [eax + 0]; mov edi, [eax + 4]; mov esi, [eax + 8]; mov ebp, [eax + 12]; mov esp, [eax + 16]; mov edx, [eax + 20]; - + frstor [eax + 24]; /* restore floating-point state */ mov eax, 1; /* return 1 from setjmp: pass 2 return */ @@ -251,7 +250,7 @@ setup_context_1(void) { } void -init_thread_context(struct ThreadContext *context, +init_thread_context(struct ThreadContext *context, unsigned char *stack, size_t stack_size, ThreadFunction *thread_func, void *data) { /* Copy all of the input parameters to static variables, then begin @@ -263,7 +262,7 @@ init_thread_context(struct ThreadContext *context, st_data = data; setup_context_1(); -} +} void save_thread_context(struct ThreadContext *context, diff --git a/panda/src/pipeline/contextSwitch_posix_src.c b/panda/src/pipeline/contextSwitch_posix_src.c index 6f5df46445..f553cefc45 100644 --- a/panda/src/pipeline/contextSwitch_posix_src.c +++ b/panda/src/pipeline/contextSwitch_posix_src.c @@ -1,8 +1,4 @@ -/* Filename: contextSwitch_posix_src.c - * Created by: drose (15Apr10) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * +/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * @@ -10,7 +6,10 @@ * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * @file contextSwitch_posix_src.c + * @author drose + * @date 2010-04-15 + */ /* This is the implementation of user-space context switching using posix threads to manage the different execution contexts. This @@ -44,7 +43,7 @@ struct ThreadContext { pthread_mutex_t _ready_mutex; pthread_cond_t _ready_cvar; int _ready_flag; - + /* This is set FALSE while the thread is alive, and TRUE if the thread is to be terminated when it next wakes up. */ int _terminated; @@ -83,19 +82,19 @@ thread_main(void *data) { } void -init_thread_context(struct ThreadContext *context, +init_thread_context(struct ThreadContext *context, unsigned char *stack, size_t stack_size, ThreadFunction *thread_func, void *data) { context->_thread_func = thread_func; context->_data = data; - pthread_attr_t attr; - pthread_attr_init(&attr); + pthread_attr_t attr; + pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, stack_size); - pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); - pthread_create(&(context->_thread), &attr, thread_main, context); - pthread_attr_destroy(&attr); + pthread_create(&(context->_thread), &attr, thread_main, context); + pthread_attr_destroy(&attr); } void @@ -142,7 +141,7 @@ switch_to_thread_context(struct ThreadContext *from_context, /* We've been rudely terminated. Exit gracefully. */ pthread_exit(NULL); } - + /* Now we have been signaled again, and we're ready to resume the thread. */ longjmp(from_context->_jmp_context, 1); @@ -164,7 +163,7 @@ alloc_thread_context() { pthread_mutexattr_init(&attr); // The symbol PTHREAD_MUTEX_DEFAULT isn't always available? // pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT); - int result = pthread_mutex_init(&context->_ready_mutex, &attr); + pthread_mutex_init(&context->_ready_mutex, &attr); pthread_mutexattr_destroy(&attr); pthread_cond_init(&context->_ready_cvar, NULL); diff --git a/panda/src/pipeline/contextSwitch_ucontext_src.c b/panda/src/pipeline/contextSwitch_ucontext_src.c index f589dbb5bf..f08c6d9afe 100644 --- a/panda/src/pipeline/contextSwitch_ucontext_src.c +++ b/panda/src/pipeline/contextSwitch_ucontext_src.c @@ -1,8 +1,4 @@ -/* Filename: contextSwitch_ucontext_src.c - * Created by: drose (15Apr10) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * +/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * @@ -10,7 +6,10 @@ * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * @file contextSwitch_ucontext_src.c + * @author drose + * @date 2010-04-15 + */ /* This is the implementation of user-space context switching using getcontext() / setcontext(). This is the preferred implementation, @@ -43,7 +42,7 @@ begin_context(ThreadFunction *thread_func, void *data) { } void -init_thread_context(struct ThreadContext *context, +init_thread_context(struct ThreadContext *context, unsigned char *stack, size_t stack_size, ThreadFunction *thread_func, void *data) { if (getcontext(&context->_ucontext) != 0) { diff --git a/panda/src/pipeline/contextSwitch_windows_src.c b/panda/src/pipeline/contextSwitch_windows_src.c index 9f157d8eec..727eef43b9 100644 --- a/panda/src/pipeline/contextSwitch_windows_src.c +++ b/panda/src/pipeline/contextSwitch_windows_src.c @@ -1,8 +1,4 @@ -/* Filename: contextSwitch_windows_src.c - * Created by: drose (15Apr10) - * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * +/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * @@ -10,7 +6,10 @@ * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + * @file contextSwitch_windows_src.c + * @author drose + * @date 2010-04-15 + */ /* This is the implementation of user-space context switching using native Windows threading constructs to manage the different @@ -37,7 +36,7 @@ struct ThreadContext { /* This event is in the signaled state when the thread is ready to roll. */ HANDLE _ready; - + /* This is set FALSE while the thread is alive, and TRUE if the thread is to be terminated when it next wakes up. */ int _terminated; @@ -71,13 +70,13 @@ thread_main(LPVOID data) { } void -init_thread_context(struct ThreadContext *context, +init_thread_context(struct ThreadContext *context, unsigned char *stack, size_t stack_size, ThreadFunction *thread_func, void *data) { context->_thread_func = thread_func; context->_data = data; - context->_thread = CreateThread(NULL, stack_size, + context->_thread = CreateThread(NULL, stack_size, thread_main, context, 0, NULL); } @@ -117,7 +116,7 @@ switch_to_thread_context(struct ThreadContext *from_context, /* We've been rudely terminated. Exit gracefully. */ ExitThread(1); } - + /* Now we have been signaled again, and we're ready to resume the thread. */ longjmp(from_context->_jmp_context, 1); diff --git a/panda/src/pipeline/pythonThread.cxx b/panda/src/pipeline/pythonThread.cxx index ab41070fb8..53a811401e 100644 --- a/panda/src/pipeline/pythonThread.cxx +++ b/panda/src/pipeline/pythonThread.cxx @@ -225,7 +225,7 @@ call_python_func(PyObject *function, PyObject *args) { } else { // No exception. Restore the thread state normally. - PyThreadState *state = PyThreadState_Swap(orig_thread_state); + PyThreadState_Swap(orig_thread_state); thread_states.push_back(new_thread_state); // PyThreadState_Clear(new_thread_state); // PyThreadState_Delete(new_thread_state); diff --git a/panda/src/pipeline/threadSimpleManager.cxx b/panda/src/pipeline/threadSimpleManager.cxx index 4d9890dfd4..10b599116b 100644 --- a/panda/src/pipeline/threadSimpleManager.cxx +++ b/panda/src/pipeline/threadSimpleManager.cxx @@ -20,7 +20,9 @@ #include "mainThread.h" #ifdef WIN32 -#define WIN32_LEAN_AND_MEAN +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif #include #endif From 90cc8fe385255a5cdefa9035b7abd1e227128f03 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 16 Oct 2018 22:15:36 +0200 Subject: [PATCH 27/60] Fix building with SIMPLE_THREADS=1 --- dtool/src/dtoolbase/dtoolbase.cxx | 8 ++++++++ dtool/src/dtoolbase/dtoolbase_cc.h | 9 +++++++++ dtool/src/interrogatedb/py_panda.cxx | 5 +++++ dtool/src/parser-inc/Python.h | 2 +- panda/src/pipeline/threadSimpleImpl.I | 8 -------- panda/src/pipeline/threadSimpleImpl.cxx | 14 +++++++++++--- panda/src/pipeline/threadSimpleImpl.h | 2 +- panda/src/pipeline/threadSimpleManager.cxx | 14 ++------------ 8 files changed, 37 insertions(+), 25 deletions(-) diff --git a/dtool/src/dtoolbase/dtoolbase.cxx b/dtool/src/dtoolbase/dtoolbase.cxx index a45a1de4e0..3bd34815c9 100644 --- a/dtool/src/dtoolbase/dtoolbase.cxx +++ b/dtool/src/dtoolbase/dtoolbase.cxx @@ -62,4 +62,12 @@ default_thread_consider_yield() { void (*global_thread_yield)() = default_thread_yield; void (*global_thread_consider_yield)() = default_thread_consider_yield; +#ifdef HAVE_PYTHON +static PyThreadState * +default_thread_state_swap(PyThreadState *state) { + return nullptr; +} +PyThreadState *(*global_thread_state_swap)(PyThreadState *tstate) = default_thread_state_swap; +#endif // HAVE_PYTHON + #endif // HAVE_THREADS && SIMPLE_THREADS diff --git a/dtool/src/dtoolbase/dtoolbase_cc.h b/dtool/src/dtoolbase/dtoolbase_cc.h index 36da6b2b0b..8894469422 100644 --- a/dtool/src/dtoolbase/dtoolbase_cc.h +++ b/dtool/src/dtoolbase/dtoolbase_cc.h @@ -233,6 +233,15 @@ INLINE void thread_consider_yield() { (*global_thread_consider_yield)(); } +#ifdef HAVE_PYTHON +typedef struct _ts PyThreadState; +extern EXPCL_DTOOL_DTOOLBASE PyThreadState *(*global_thread_state_swap)(PyThreadState *tstate); + +INLINE PyThreadState *thread_state_swap(PyThreadState *tstate) { + return (*global_thread_state_swap)(tstate); +} +#endif // HAVE_PYTHON + #else INLINE void thread_yield() { diff --git a/dtool/src/interrogatedb/py_panda.cxx b/dtool/src/interrogatedb/py_panda.cxx index 42bcdb9a35..dbb97ed0ff 100644 --- a/dtool/src/interrogatedb/py_panda.cxx +++ b/dtool/src/interrogatedb/py_panda.cxx @@ -752,6 +752,11 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) { ExecutionEnvironment::shadow_environment_variable("MAIN_DIR", main_dir.to_os_specific()); PyErr_Clear(); initialized_main_dir = true; + + // Also, while we are at it, initialize the thread swap hook. +#if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) + global_thread_state_swap = PyThreadState_Swap; +#endif } PyModule_AddIntConstant(module, "Dtool_PyNativeInterface", 1); diff --git a/dtool/src/parser-inc/Python.h b/dtool/src/parser-inc/Python.h index ddd660072d..5f1a98a825 100644 --- a/dtool/src/parser-inc/Python.h +++ b/dtool/src/parser-inc/Python.h @@ -28,7 +28,7 @@ typedef _typeobject PyTypeObject; typedef struct {} PyStringObject; typedef struct {} PyUnicodeObject; -class PyThreadState; +typedef struct _ts PyThreadState; typedef int Py_ssize_t; typedef struct bufferinfo Py_buffer; diff --git a/panda/src/pipeline/threadSimpleImpl.I b/panda/src/pipeline/threadSimpleImpl.I index 001f3037d4..d712892883 100644 --- a/panda/src/pipeline/threadSimpleImpl.I +++ b/panda/src/pipeline/threadSimpleImpl.I @@ -51,14 +51,6 @@ is_threading_supported() { return true; } -/** - * - */ -INLINE bool ThreadSimpleImpl:: -is_true_threads() { - return (is_os_threads != 0); -} - /** * */ diff --git a/panda/src/pipeline/threadSimpleImpl.cxx b/panda/src/pipeline/threadSimpleImpl.cxx index a631421503..14d6f7561f 100644 --- a/panda/src/pipeline/threadSimpleImpl.cxx +++ b/panda/src/pipeline/threadSimpleImpl.cxx @@ -141,8 +141,8 @@ start(ThreadPriority priority, bool joinable) { #ifdef HAVE_PYTHON // Query the current Python thread state. - _python_state = PyThreadState_Swap(nullptr); - PyThreadState_Swap(_python_state); + _python_state = thread_state_swap(nullptr); + thread_state_swap(_python_state); #endif // HAVE_PYTHON init_thread_context(_context, _stack, _stack_size, st_begin_thread, this); @@ -201,6 +201,14 @@ prepare_for_exit() { manager->prepare_for_exit(); } +/** + * + */ +bool ThreadSimpleImpl:: +is_true_threads() { + return (is_os_threads != 0); +} + /** * */ @@ -238,7 +246,7 @@ st_begin_thread(void *data) { void ThreadSimpleImpl:: begin_thread() { #ifdef HAVE_PYTHON - PyThreadState_Swap(_python_state); + thread_state_swap(_python_state); #endif // HAVE_PYTHON #ifdef HAVE_POSIX_THREADS diff --git a/panda/src/pipeline/threadSimpleImpl.h b/panda/src/pipeline/threadSimpleImpl.h index c552dd1357..5bd6af3fdc 100644 --- a/panda/src/pipeline/threadSimpleImpl.h +++ b/panda/src/pipeline/threadSimpleImpl.h @@ -63,7 +63,7 @@ public: INLINE static void bind_thread(Thread *thread); INLINE static bool is_threading_supported(); - INLINE static bool is_true_threads(); + static bool is_true_threads(); INLINE static bool is_simple_threads(); INLINE static void sleep(double seconds); INLINE static void yield(); diff --git a/panda/src/pipeline/threadSimpleManager.cxx b/panda/src/pipeline/threadSimpleManager.cxx index 10b599116b..861e19cd77 100644 --- a/panda/src/pipeline/threadSimpleManager.cxx +++ b/panda/src/pipeline/threadSimpleManager.cxx @@ -237,7 +237,7 @@ next_context() { #ifdef HAVE_PYTHON // Save the current Python thread state. - _current_thread->_python_state = PyThreadState_Swap(nullptr); + _current_thread->_python_state = thread_state_swap(nullptr); #endif // HAVE_PYTHON #ifdef DO_PSTATS @@ -258,7 +258,7 @@ next_context() { #endif // DO_PSTATS #ifdef HAVE_PYTHON - PyThreadState_Swap(_current_thread->_python_state); + thread_state_swap(_current_thread->_python_state); #endif // HAVE_PYTHON } @@ -470,16 +470,6 @@ init_pointers() { _pointers_initialized = true; _global_ptr = new ThreadSimpleManager; Thread::get_main_thread(); - -#ifdef HAVE_PYTHON - // Ensure that the Python threading system is initialized and ready to go. - -#if PY_VERSION_HEX >= 0x03020000 - Py_Initialize(); -#endif - - PyEval_InitThreads(); -#endif } } From d6efceb1ed5fe98f7e7032dcf7000e39ff1c1041 Mon Sep 17 00:00:00 2001 From: Younguk Kim Date: Wed, 17 Oct 2018 20:42:37 +0900 Subject: [PATCH 28/60] dtoolbase: fix NOMINMAX macro redefinition warning --- dtool/src/dtoolbase/dtoolbase.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dtool/src/dtoolbase/dtoolbase.h b/dtool/src/dtoolbase/dtoolbase.h index f21e653695..2f8e7ca05d 100644 --- a/dtool/src/dtoolbase/dtoolbase.h +++ b/dtool/src/dtoolbase/dtoolbase.h @@ -63,8 +63,10 @@ /* Windows likes to define min() and max() macros, which will conflict with std::min() and std::max() respectively, unless we do this: */ #ifdef WIN32 +#ifndef NOMINMAX #define NOMINMAX #endif +#endif #ifndef __has_builtin #define __has_builtin(x) 0 From 4bc0a1ef5e4f0ff330b6a9a1bfb88352bb909d97 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 17 Oct 2018 17:28:25 +0200 Subject: [PATCH 29/60] tests: fix futures test when building without true threading --- tests/event/test_futures.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/event/test_futures.py b/tests/event/test_futures.py index e120a2ab8e..adef5b33fc 100644 --- a/tests/event/test_futures.py +++ b/tests/event/test_futures.py @@ -1,6 +1,5 @@ from panda3d import core import pytest -import threading import time import sys @@ -39,7 +38,11 @@ def test_future_timeout(): fut.result(0.001) +@pytest.mark.skipif(not core.Thread.is_threading_supported(), + reason="Threading support disabled") def test_future_wait(): + threading = pytest.importorskip("direct.stdpy.threading") + fut = core.AsyncFuture() # Launch a thread to set the result value. @@ -59,7 +62,11 @@ def test_future_wait(): assert fut.result() is None +@pytest.mark.skipif(not core.Thread.is_threading_supported(), + reason="Threading support disabled") def test_future_wait_cancel(): + threading = pytest.importorskip("direct.stdpy.threading") + fut = core.AsyncFuture() # Launch a thread to cancel the future. From bea15cd39a9507a9cf572c6ff582c2e19a25307a Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 17 Oct 2018 17:29:08 +0200 Subject: [PATCH 30/60] pgraph: fix crash when cull_callback modifies node in some way --- panda/src/pgraph/cullTraverserData.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index 8d54308af8..a260dd3ebb 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -54,6 +54,9 @@ apply_transform_and_state(CullTraverser *trav) { CPT(TransformState) node_transform = _node_reader.get_transform(); node_effects->cull_callback(trav, *this, node_transform, node_state); apply_transform(node_transform); + + // The cull callback may have changed the node properties. + _node_reader.check_cached(false); } if (!node_state->is_empty()) { From 90c13cbd4e142ae0570a332431f3a5fea026518f Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 17 Oct 2018 17:32:19 +0200 Subject: [PATCH 31/60] glgsg: fix error downloading texture with WM_repeat --- panda/src/glstuff/glGraphicsStateGuardian_src.cxx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 616784e0cc..19594750c8 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -8925,6 +8925,9 @@ get_panda_wrap_mode(GLenum wm) { case GL_REPEAT: return SamplerState::WM_repeat; + case GL_MIRRORED_REPEAT: + return SamplerState::WM_mirror; + #ifndef OPENGLES case GL_MIRROR_CLAMP_EXT: case GL_MIRROR_CLAMP_TO_EDGE_EXT: From 6488e46cc71f93e392a2f2d0d7c94818043857d3 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 17 Oct 2018 17:33:27 +0200 Subject: [PATCH 32/60] Fix errors when building with --override DO_PIPELINING=UNDEF --- panda/src/gobj/geomVertexData.I | 2 + panda/src/pipeline/config_pipeline.cxx | 3 + panda/src/pipeline/cycleData.h | 5 +- .../src/pipeline/cycleDataLockedStageReader.I | 51 ++++++++++++----- panda/src/pipeline/cycleDataStageWriter.I | 57 +++++++++++++------ 5 files changed, 86 insertions(+), 32 deletions(-) diff --git a/panda/src/gobj/geomVertexData.I b/panda/src/gobj/geomVertexData.I index bd68fc4cf4..d0c6bba632 100644 --- a/panda/src/gobj/geomVertexData.I +++ b/panda/src/gobj/geomVertexData.I @@ -772,7 +772,9 @@ set_object(const GeomVertexData *object) { _cdata = (GeomVertexData::CData *)_object->_cycler.read_unlocked(_current_thread); _got_array_readers = false; +#ifdef DO_PIPELINING _cdata->ref(); +#endif // DO_PIPELINING } /** diff --git a/panda/src/pipeline/config_pipeline.cxx b/panda/src/pipeline/config_pipeline.cxx index 2e7bf6487e..4fd5214323 100644 --- a/panda/src/pipeline/config_pipeline.cxx +++ b/panda/src/pipeline/config_pipeline.cxx @@ -71,7 +71,10 @@ init_libpipeline() { } initialized = true; +#ifdef DO_PIPELINING CycleData::init_type(); +#endif + MainThread::init_type(); ExternalThread::init_type(); GenericThread::init_type(); diff --git a/panda/src/pipeline/cycleData.h b/panda/src/pipeline/cycleData.h index de90bdf226..bf0071ac67 100644 --- a/panda/src/pipeline/cycleData.h +++ b/panda/src/pipeline/cycleData.h @@ -50,10 +50,13 @@ class EXPCL_PANDA_PIPELINE CycleData { public: INLINE CycleData() = default; - INLINE CycleData(CycleData &&from) = default; + INLINE CycleData(CycleData &&from) noexcept = default; INLINE CycleData(const CycleData ©) = default; virtual ~CycleData(); + CycleData &operator = (CycleData &&from) noexcept = default; + CycleData &operator = (const CycleData ©) = default; + virtual CycleData *make_copy() const=0; virtual void write_datagram(BamWriter *, Datagram &) const; diff --git a/panda/src/pipeline/cycleDataLockedStageReader.I b/panda/src/pipeline/cycleDataLockedStageReader.I index 22b8785c82..a471aac0b7 100644 --- a/panda/src/pipeline/cycleDataLockedStageReader.I +++ b/panda/src/pipeline/cycleDataLockedStageReader.I @@ -47,6 +47,20 @@ CycleDataLockedStageReader(const CycleDataLockedStageReader © _cycler->increment_read(_pointer); } +/** + * + */ +template +INLINE CycleDataLockedStageReader:: +CycleDataLockedStageReader(CycleDataLockedStageReader &&from) noexcept : + _cycler(from._cycler), + _current_thread(from._current_thread), + _pointer(from._pointer), + _stage(from._stage) +{ + from._pointer = nullptr; +} + /** * */ @@ -64,20 +78,6 @@ operator = (const CycleDataLockedStageReader ©) { _cycler->increment_read(_pointer); } -/** - * - */ -template -INLINE CycleDataLockedStageReader:: -CycleDataLockedStageReader(CycleDataLockedStageReader &&from) noexcept : - _cycler(from._cycler), - _current_thread(from._current_thread), - _pointer(from._pointer), - _stage(from._stage) -{ - from._pointer = nullptr; -} - /** * */ @@ -174,6 +174,17 @@ CycleDataLockedStageReader(const CycleDataLockedStageReader © { } +/** + * + */ +template +INLINE CycleDataLockedStageReader:: +CycleDataLockedStageReader(CycleDataLockedStageReader &&from) noexcept : + _pointer(from._cycler) +{ + from._pointer = nullptr; +} + /** * */ @@ -183,6 +194,18 @@ operator = (const CycleDataLockedStageReader ©) { _pointer = copy._pointer; } +/** + * + */ +template +INLINE void CycleDataLockedStageReader:: +operator = (CycleDataLockedStageReader &&from) noexcept { + nassertv(_pointer == nullptr); + + _pointer = from._pointer; + from._pointer = nullptr; +} + /** * */ diff --git a/panda/src/pipeline/cycleDataStageWriter.I b/panda/src/pipeline/cycleDataStageWriter.I index a4c1851dde..cf25cf807a 100644 --- a/panda/src/pipeline/cycleDataStageWriter.I +++ b/panda/src/pipeline/cycleDataStageWriter.I @@ -62,23 +62,6 @@ CycleDataStageWriter(const CycleDataStageWriter ©) : _cycler->increment_write(_pointer); } -/** - * - */ -template -INLINE void CycleDataStageWriter:: -operator = (const CycleDataStageWriter ©) { - nassertv(_pointer == nullptr); - nassertv(_current_thread == copy._current_thread); - - _cycler = copy._cycler; - _pointer = copy._pointer; - _stage = copy._stage; - - nassertv(_pointer != nullptr); - _cycler->increment_write(_pointer); -} - /** * This flavor of the constructor elevates the pointer from the * CycleDataLockedStageReader from a read to a write pointer (and invalidates @@ -128,6 +111,23 @@ CycleDataStageWriter(CycleDataStageWriter &&from) noexcept : from._pointer = nullptr; } +/** + * + */ +template +INLINE void CycleDataStageWriter:: +operator = (const CycleDataStageWriter ©) { + nassertv(_pointer == nullptr); + nassertv(_current_thread == copy._current_thread); + + _cycler = copy._cycler; + _pointer = copy._pointer; + _stage = copy._stage; + + nassertv(_pointer != nullptr); + _cycler->increment_write(_pointer); +} + /** * */ @@ -227,6 +227,17 @@ CycleDataStageWriter(const CycleDataStageWriter ©) : { } +/** + * + */ +template +INLINE CycleDataStageWriter:: +CycleDataStageWriter(CycleDataStageWriter &&from) noexcept : + _pointer(from._pointer) +{ + from._pointer = nullptr; +} + /** * */ @@ -236,6 +247,18 @@ operator = (const CycleDataStageWriter ©) { _pointer = copy._pointer; } +/** + * + */ +template +INLINE void CycleDataStageWriter:: +operator = (CycleDataStageWriter &&from) noexcept { + nassertv(_pointer == nullptr); + + _pointer = from._pointer; + from._pointer = nullptr; +} + /** * This flavor of the constructor elevates the pointer from the * CycleDataLockedStageReader from a read to a write pointer (and invalidates From 775e4cecff88095155500bb29f3a240acfe64dec Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 17 Oct 2018 19:09:36 +0200 Subject: [PATCH 33/60] pgraph: fix freeze in garbage_collect(), esp. when rate-limit is on --- panda/src/pgraph/renderAttrib.cxx | 5 ++++- panda/src/pgraph/renderState.cxx | 3 +++ panda/src/pgraph/transformState.cxx | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 73b1e4b392..9bac4e666a 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -211,7 +211,7 @@ garbage_collect() { } num_this_pass = std::min(num_this_pass, size); - size_t stop_at_element = (_garbage_index + num_this_pass) % size; + size_t stop_at_element = (si + num_this_pass) % size; do { RenderAttrib *attrib = (RenderAttrib *)_attribs->get_key(si); @@ -229,6 +229,9 @@ garbage_collect() { // still need to visit. --size; --si; + if (stop_at_element > 0) { + --stop_at_element; + } } si = (si + 1) % size; diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index 927d1e7073..5ce1527247 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -950,6 +950,9 @@ garbage_collect() { // still need to visit. --size; --si; + if (stop_at_element > 0) { + --stop_at_element; + } } si = (si + 1) % size; diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 453fb505b4..4d02425683 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -1216,6 +1216,9 @@ garbage_collect() { // still need to visit. --size; --si; + if (stop_at_element > 0) { + --stop_at_element; + } } si = (si + 1) % size; From eac88fc64a22f483c23729f57c2d3e89d476cc62 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 17 Oct 2018 19:43:41 +0200 Subject: [PATCH 34/60] chan: disable AnimControl copy ctor and assignment operators --- panda/src/chan/animControl.cxx | 4 ++-- panda/src/chan/animControl.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/panda/src/chan/animControl.cxx b/panda/src/chan/animControl.cxx index aa47ea7486..df7fb26498 100644 --- a/panda/src/chan/animControl.cxx +++ b/panda/src/chan/animControl.cxx @@ -32,14 +32,14 @@ AnimControl(const std::string &name, PartBundle *part, Namable(name), _pending_lock(name), _pending_cvar(_pending_lock), - _bound_joints(BitArray::all_on()) + _bound_joints(BitArray::all_on()), + _part(part) { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); #endif _pending = true; - _part = part; _anim = nullptr; _channel_index = -1; set_frame_rate(frame_rate); diff --git a/panda/src/chan/animControl.h b/panda/src/chan/animControl.h index bee9f7223b..d52b2e4835 100644 --- a/panda/src/chan/animControl.h +++ b/panda/src/chan/animControl.h @@ -39,6 +39,8 @@ class EXPCL_PANDA_CHAN AnimControl : public TypedReferenceCount, public AnimInte public: AnimControl(const std::string &name, PartBundle *part, double frame_rate, int num_frames); + AnimControl(const AnimControl ©) = delete; + void setup_anim(PartBundle *part, AnimBundle *anim, int channel_index, const BitArray &bound_joints); void set_bound_joints(const BitArray &bound_joints); @@ -82,7 +84,7 @@ private: // This is a PT(PartGroup) instead of a PT(PartBundle), just because we // can't include partBundle.h for circular reasons. But it actually keeps a // pointer to a PartBundle. - PT(PartGroup) _part; + const PT(PartGroup) _part; PT(AnimBundle) _anim; int _channel_index; From a05e928a75ab34f58e11395b0bb3d7681b69b849 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 17 Oct 2018 19:44:39 +0200 Subject: [PATCH 35/60] chan: fix crash in certain cases after AnimControl destruction --- panda/src/chan/partBundle.cxx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index 966987995a..cd9fe3f5ce 100644 --- a/panda/src/chan/partBundle.cxx +++ b/panda/src/chan/partBundle.cxx @@ -558,6 +558,12 @@ control_removed(AnimControl *control) { if (cbi != cdata->_blend.end()) { cdata->_blend.erase(cbi); cdata->_anim_changed = true; + + // We need to make sure that any _effective_channel pointers that point + // to this control are cleared. + if (pipeline_stage == 0) { + determine_effective_channels(cdata); + } } } CLOSE_ITERATE_ALL_STAGES(_cycler); From 2cd5a04f3f862c9c3fcce1a2841ce4aa610b3303 Mon Sep 17 00:00:00 2001 From: rdb Date: Wed, 17 Oct 2018 19:54:29 +0200 Subject: [PATCH 36/60] pipeline: fix compiler error on older versions of GCC --- panda/src/pipeline/cycleData.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/panda/src/pipeline/cycleData.h b/panda/src/pipeline/cycleData.h index bf0071ac67..ef21ad7a33 100644 --- a/panda/src/pipeline/cycleData.h +++ b/panda/src/pipeline/cycleData.h @@ -50,11 +50,11 @@ class EXPCL_PANDA_PIPELINE CycleData { public: INLINE CycleData() = default; - INLINE CycleData(CycleData &&from) noexcept = default; + INLINE CycleData(CycleData &&from) = default; INLINE CycleData(const CycleData ©) = default; virtual ~CycleData(); - CycleData &operator = (CycleData &&from) noexcept = default; + CycleData &operator = (CycleData &&from) = default; CycleData &operator = (const CycleData ©) = default; virtual CycleData *make_copy() const=0; From e67d2a16c1733843e169543763c1bc05203ec449 Mon Sep 17 00:00:00 2001 From: loblao Date: Thu, 18 Oct 2018 12:14:20 -0300 Subject: [PATCH 37/60] Dtool_PyModuleInitHelper: Fix segfault --- dtool/src/interrogatedb/py_panda.cxx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dtool/src/interrogatedb/py_panda.cxx b/dtool/src/interrogatedb/py_panda.cxx index dbb97ed0ff..c29796def6 100644 --- a/dtool/src/interrogatedb/py_panda.cxx +++ b/dtool/src/interrogatedb/py_panda.cxx @@ -722,7 +722,10 @@ PyObject *Dtool_PyModuleInitHelper(LibraryDef *defs[], const char *modulename) { // Extract the __file__ attribute, if present. Filename main_dir; - PyObject *file_attr = PyObject_GetAttrString(main_module, "__file__"); + PyObject *file_attr = nullptr; + if (main_module != nullptr) { + file_attr = PyObject_GetAttrString(main_module, "__file__"); + } if (file_attr == nullptr) { // Must be running in the interactive interpreter. Use the CWD. main_dir = ExecutionEnvironment::get_cwd(); From f35c9e5d799617bc8636174fe4f9930a8e6a3d87 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 18 Oct 2018 22:03:16 +0200 Subject: [PATCH 38/60] chan: adjust _net_blend when AnimControl destructs --- panda/src/chan/partBundle.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index cd9fe3f5ce..9d960f3e7d 100644 --- a/panda/src/chan/partBundle.cxx +++ b/panda/src/chan/partBundle.cxx @@ -556,6 +556,7 @@ control_removed(AnimControl *control) { CDStageWriter cdata(_cycler, pipeline_stage); ChannelBlend::iterator cbi = cdata->_blend.find(control); if (cbi != cdata->_blend.end()) { + cdata->_net_blend -= cbi->second; cdata->_blend.erase(cbi); cdata->_anim_changed = true; From f8b47dc14c27b0189a9d8395efb09e7be0f846e3 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 18 Oct 2018 22:19:55 +0200 Subject: [PATCH 39/60] direct: fix slowness in big games with Func(messenger.send) --- direct/src/interval/FunctionInterval.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/direct/src/interval/FunctionInterval.py b/direct/src/interval/FunctionInterval.py index 8f84ca9df8..db626c404e 100644 --- a/direct/src/interval/FunctionInterval.py +++ b/direct/src/interval/FunctionInterval.py @@ -77,7 +77,10 @@ class FunctionInterval(Interval.Interval): @staticmethod def makeUniqueName(func, suffix = ''): - name = 'Func-%s-%d' % (getattr(func, '__name__', str(func)), FunctionInterval.functionIntervalNum) + func_name = getattr(func, '__name__', None) + if func_name is None: + func_name = str(func) + name = 'Func-%s-%d' % (func_name, FunctionInterval.functionIntervalNum) FunctionInterval.functionIntervalNum += 1 if suffix: name = '%s-%s' % (name, str(suffix)) From 30f1c8ba92df4ee1fc35d7b54ff716ef18272fa4 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 19 Oct 2018 00:12:53 +0200 Subject: [PATCH 40/60] display: slight cleanup of graphicsPipeSelection.cxx This seemed to halve the compile time of this file under MSVC. --- panda/src/display/graphicsPipeSelection.cxx | 42 +++++++-------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/panda/src/display/graphicsPipeSelection.cxx b/panda/src/display/graphicsPipeSelection.cxx index 9c4f52ff63..58866efef6 100644 --- a/panda/src/display/graphicsPipeSelection.cxx +++ b/panda/src/display/graphicsPipeSelection.cxx @@ -18,7 +18,6 @@ #include "load_dso.h" #include "config_display.h" #include "typeRegistry.h" -#include "pset.h" #include "config_putil.h" #include @@ -61,8 +60,8 @@ GraphicsPipeSelection() : _lock("GraphicsPipeSelection") { // Also get the set of modules named in the various aux-display Config // variables. We'll want to know this when we call load_modules() later. - int num_aux = aux_display.get_num_unique_values(); - for (int i = 0; i < num_aux; i++) { + size_t num_aux = aux_display.get_num_unique_values(); + for (size_t i = 0; i < num_aux; ++i) { string name = aux_display.get_unique_value(i); if (name != _default_display_module) { _display_modules.push_back(name); @@ -124,9 +123,7 @@ print_pipe_types() const { LightMutexHolder holder(_lock); nout << "Known pipe types:" << std::endl; - PipeTypes::const_iterator pi; - for (pi = _pipe_types.begin(); pi != _pipe_types.end(); ++pi) { - const PipeType &pipe_type = (*pi); + for (const PipeType &pipe_type : _pipe_types) { nout << " " << pipe_type._type << "\n"; } if (_display_modules.empty()) { @@ -187,11 +184,9 @@ make_pipe(const string &type_name, const string &module_name) { PT(GraphicsPipe) GraphicsPipeSelection:: make_pipe(TypeHandle type) { LightMutexHolder holder(_lock); - PipeTypes::const_iterator ti; // First, look for an exact match of the requested type. - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (ptype._type == type) { // Here's an exact match. PT(GraphicsPipe) pipe = (*ptype._constructor)(); @@ -202,8 +197,7 @@ make_pipe(TypeHandle type) { } // Now look for a more-specific type. - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (ptype._type.is_derived_from(type)) { // Here's an approximate match. PT(GraphicsPipe) pipe = (*ptype._constructor)(); @@ -215,8 +209,7 @@ make_pipe(TypeHandle type) { // Couldn't find any match; load the default module and try again. load_default_module(); - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (ptype._type.is_derived_from(type)) { // Here's an approximate match. PT(GraphicsPipe) pipe = (*ptype._constructor)(); @@ -260,13 +253,11 @@ make_default_pipe() { load_default_module(); LightMutexHolder holder(_lock); - PipeTypes::const_iterator ti; if (!_default_pipe_name.empty()) { // First, look for an exact match of the default type name from the // Configrc file (excepting case and hyphenunderscore). - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (cmp_nocase_uh(ptype._type.get_name(), _default_pipe_name) == 0) { // Here's an exact match. PT(GraphicsPipe) pipe = (*ptype._constructor)(); @@ -278,8 +269,7 @@ make_default_pipe() { // No match; look for a substring match. string preferred_name = downcase(_default_pipe_name); - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { string ptype_name = downcase(ptype._type.get_name()); if (ptype_name.find(preferred_name) != string::npos) { // Here's a substring match. @@ -292,8 +282,7 @@ make_default_pipe() { } // Couldn't find a matching pipe type; choose the first one on the list. - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { PT(GraphicsPipe) pipe = (*ptype._constructor)(); if (pipe != nullptr) { return pipe; @@ -310,9 +299,8 @@ make_default_pipe() { */ void GraphicsPipeSelection:: load_aux_modules() { - DisplayModules::iterator di; - for (di = _display_modules.begin(); di != _display_modules.end(); ++di) { - load_named_module(*di); + for (const string &module : _display_modules) { + load_named_module(module); } _display_modules.clear(); @@ -337,9 +325,7 @@ add_pipe_type(TypeHandle type, PipeConstructorFunc *func) { // First, make sure we don't already have a GraphicsPipe of this type. LightMutexHolder holder(_lock); - PipeTypes::const_iterator ti; - for (ti = _pipe_types.begin(); ti != _pipe_types.end(); ++ti) { - const PipeType &ptype = (*ti); + for (const PipeType &ptype : _pipe_types) { if (ptype._type == type) { display_cat->warning() << "Attempt to register GraphicsPipe type " << type @@ -375,8 +361,8 @@ do_load_default_module() { load_named_module(_default_display_module); DisplayModules::iterator di = - find(_display_modules.begin(), _display_modules.end(), - _default_display_module); + std::find(_display_modules.begin(), _display_modules.end(), + _default_display_module); if (di != _display_modules.end()) { _display_modules.erase(di); } From 175d7ff56bd1741ddaffd7f6702bc538bea20866 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 19 Oct 2018 00:30:14 +0200 Subject: [PATCH 41/60] display: significantly decrease p3display_composite2 compile time This applies to building with MSVC and Eigen specifically. Apparently, fetch_specified_part is taking up most of the compile time here. I have no idea why these changes in particular make it faster, but they just do. --- panda/src/display/graphicsStateGuardian.cxx | 86 +++++++++++---------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index b76a7f751c..0e82a23f88 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -24,7 +24,6 @@ #include "renderBuffer.h" #include "light.h" #include "planeNode.h" -#include "ambientLight.h" #include "throw_event.h" #include "clockObject.h" #include "pStatTimer.h" @@ -60,7 +59,6 @@ #include "fogAttrib.h" #include "config_pstatclient.h" -#include #include using std::string; @@ -932,12 +930,12 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, } case Shader::SMO_frame_time: { PN_stdfloat time = ClockObject::get_global_clock()->get_frame_time(); - t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, time, time, time, time); return &t; } case Shader::SMO_frame_delta: { PN_stdfloat dt = ClockObject::get_global_clock()->get_dt(); - t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dt, dt, dt, dt); return &t; } case Shader::SMO_texpad_x: { @@ -949,7 +947,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, double cx = (sx * 0.5) / tex->get_x_size(); double cy = (sy * 0.5) / tex->get_y_size(); double cz = (sz * 0.5) / tex->get_z_size(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,cx,cy,cz,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cx, cy, cz, 0); return &t; } case Shader::SMO_texpix_x: { @@ -958,7 +956,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, double px = 1.0 / tex->get_x_size(); double py = 1.0 / tex->get_y_size(); double pz = 1.0 / tex->get_z_size(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,px,py,pz,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, px, py, pz, 0); return &t; } case Shader::SMO_attr_material: { @@ -966,7 +964,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()); // Material matrix contains AMBIENT, DIFFUSE, EMISSION, SPECULAR+SHININESS if (target_material->is_off()) { - t = LMatrix4(1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0); + t.set(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0); return &t; } Material *m = target_material->get_material(); @@ -975,17 +973,17 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LVecBase4 const &emm = m->get_emission(); LVecBase4 spc = m->get_specular(); spc[3] = m->get_shininess(); - t = LMatrix4(amb[0],amb[1],amb[2],amb[3], - dif[0],dif[1],dif[2],dif[3], - emm[0],emm[1],emm[2],emm[3], - spc[0],spc[1],spc[2],spc[3]); + t.set(amb[0], amb[1], amb[2], amb[3], + dif[0], dif[1], dif[2], dif[3], + emm[0], emm[1], emm[2], emm[3], + spc[0], spc[1], spc[2], spc[3]); return &t; } case Shader::SMO_attr_material2: { const MaterialAttrib *target_material = (const MaterialAttrib *) _target_rs->get_attrib_def(MaterialAttrib::get_class_slot()); if (target_material->is_off()) { - t = LMatrix4(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); return &t; } Material *m = target_material->get_material(); @@ -1000,7 +998,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &LMatrix4::ones_mat(); } LVecBase4 c = target_color->get_color(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); return &t; } case Shader::SMO_attr_colorscale: { @@ -1010,7 +1008,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &LMatrix4::ones_mat(); } LVecBase4 cs = target_color->get_scale(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,cs[0],cs[1],cs[2],cs[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, cs[0], cs[1], cs[2], cs[3]); return &t; } case Shader::SMO_attr_fog: { @@ -1022,7 +1020,8 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, } PN_stdfloat start, end; fog->get_linear_range(start, end); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,fog->get_exp_density(),start,end,1.0f/(end-start)); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + fog->get_exp_density(), start, end, 1.0f / (end - start)); return &t; } case Shader::SMO_attr_fogcolor: { @@ -1033,7 +1032,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &LMatrix4::ones_mat(); } LVecBase4 c = fog->get_color(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); return &t; } case Shader::SMO_alight_x: { @@ -1042,7 +1041,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, AmbientLight *lt; DCAST_INTO_R(lt, np.node(), &LMatrix4::zeros_mat()); LColor const &c = lt->get_color(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,c[0],c[1],c[2],c[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, c[0], c[1], c[2], c[3]); return &t; } case Shader::SMO_satten_x: { @@ -1052,7 +1051,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, DCAST_INTO_R(lt, np.node(), &LMatrix4::ones_mat()); LVecBase3 const &a = lt->get_attenuation(); PN_stdfloat x = lt->get_exponent(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,a[0],a[1],a[2],x); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a[0], a[1], a[2], x); return &t; } case Shader::SMO_dlight_x: { @@ -1069,7 +1068,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, d.normalize(); LVecBase3 h = d + LVecBase3(0,-1,0); h.normalize(); - t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],c[3],d[0],d[1],d[2],0,h[0],h[1],h[2],0); + t.set(c[0], c[1], c[2], c[3], + s[0], s[1], s[2], c[3], + d[0], d[1], d[2], 0, + h[0], h[1], h[2], 0); return &t; } case Shader::SMO_plight_x: { @@ -1087,7 +1089,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, Lens *lens = lt->get_lens(0); PN_stdfloat lnear = lens->get_near(); PN_stdfloat lfar = lens->get_far(); - t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],lnear,a[0],a[1],a[2],lfar); + t.set(c[0], c[1], c[2], c[3], + s[0], s[1], s[2], s[3], + p[0], p[1], p[2], lnear, + a[0], a[1], a[2], lfar); return &t; } case Shader::SMO_slight_x: { @@ -1105,7 +1110,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, _scene_setup->get_world_transform()->get_mat(); LVecBase3 p = t.xform_point(lens->get_nodal_point()); LVecBase3 d = -(t.xform_vec(lens->get_view_vector())); - t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff); + t.set(c[0], c[1], c[2], c[3], + s[0], s[1], s[2], s[3], + p[0], p[1], p[2], 0, + d[0], d[1], d[2], cutoff); return &t; } case Shader::SMO_light_ambient: { @@ -1149,7 +1157,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, if (_target_rs->get_attrib(ta) && _target_rs->get_attrib(tma) && index < ta->get_num_on_stages()) { LVecBase3 scale = tma->get_transform(ta->get_on_stage(index))->get_scale(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,scale[0],scale[1],scale[2],0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, scale[0], scale[1], scale[2], 0); return &t; } else { return &LMatrix4::ident_mat(); @@ -1173,7 +1181,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, index < ta->get_num_on_stages()) { TextureStage *ts = ta->get_on_stage(index); PN_stdfloat v = (ta->get_on_texture(ts)->get_format() == Texture::F_alpha); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,v,v,v,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, v, v, v, 0); return &t; } else { return &LMatrix4::zeros_mat(); @@ -1185,7 +1193,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, const PlaneNode *plane_node; DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat()); LPlane p = plane_node->get_plane(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,p[0],p[1],p[2],p[3]); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, p[0], p[1], p[2], p[3]); return &t; } case Shader::SMO_clipplane_x: { @@ -1235,10 +1243,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_vec_constant_x: { const LVecBase4 &input = _target_shader->get_shader_input_vector(name); const PN_stdfloat *data = input.get_data(); - t = LMatrix4(data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3]); + t.set(data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3]); return &t; } case Shader::SMO_world_to_view: { @@ -1394,10 +1402,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, // There is an input specifying precisely this whole thing, with dot and // all. Support this, even if only for backward compatibility. const LVecBase4 &data = _target_shader->get_shader_input_vector(name); - t = LMatrix4(data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3], - data[0],data[1],data[2],data[3]); + t.set(data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3], + data[0], data[1], data[2], data[3]); return &t; } @@ -1578,11 +1586,11 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) } else if (attrib == IN_position) { if (np.is_empty()) { - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); return &t; } else if (node->is_ambient_light()) { // Ambient light has no position. - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); return &t; } else if (node->is_of_type(DirectionalLight::get_class_type())) { DirectionalLight *light; @@ -1591,7 +1599,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent()); LVector3 dir = -(light->get_direction() * transform->get_mat()); dir *= _scene_setup->get_cs_world_transform()->get_mat(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 0); return &t; } else { LightLensNode *light; @@ -1611,11 +1619,11 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) } else if (attrib == IN_halfVector) { if (np.is_empty()) { - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0); return &t; } else if (node->is_ambient_light()) { // Ambient light has no half-vector. - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); return &t; } else if (node->is_of_type(DirectionalLight::get_class_type())) { DirectionalLight *light; @@ -1627,7 +1635,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) dir.normalize(); dir += LVector3(0, 0, 1); dir.normalize(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],1); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, dir[0], dir[1], dir[2], 1); return &t; } else { LightLensNode *light; @@ -1644,7 +1652,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) pos.normalize(); pos += LVector3(0, 0, 1); pos.normalize(); - t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,pos[0],pos[1],pos[2],1); + t.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pos[0],pos[1],pos[2], 1); return &t; } From df77bacf06fa3a8e00f609621128872a3e05e1a2 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 19 Oct 2018 00:37:00 +0200 Subject: [PATCH 42/60] makepanda: compile graphicsStateGuardian.cxx separately, earlier Since this still takes a long time to build, even with the previous change, it would be better for one CPU to chew on this in the background while the rest of the build continues. --- makepanda/makepanda.py | 52 +++++++++++----------- panda/src/display/p3display_composite2.cxx | 1 - 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 540d9e86cf..caa5a164a9 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -3158,10 +3158,10 @@ CopyAllHeaders('panda/src/movies') CopyAllHeaders('panda/src/pgraphnodes') CopyAllHeaders('panda/src/pgraph') CopyAllHeaders('panda/src/cull') +CopyAllHeaders('panda/src/display') CopyAllHeaders('panda/src/chan') CopyAllHeaders('panda/src/char') CopyAllHeaders('panda/src/dgraph') -CopyAllHeaders('panda/src/display') CopyAllHeaders('panda/src/device') CopyAllHeaders('panda/src/pnmtext') CopyAllHeaders('panda/src/text') @@ -3874,6 +3874,31 @@ if (not RUNTIME): TargetAdd('libp3cull.in', opts=['IMOD:panda3d.core', 'ILIB:libp3cull', 'SRCDIR:panda/src/cull']) TargetAdd('libp3cull_igate.obj', input='libp3cull.in', opts=["DEPENDENCYONLY"]) +# +# DIRECTORY: panda/src/display/ +# + +if (not RUNTIME): + OPTS=['DIR:panda/src/display', 'BUILDING:PANDA'] + TargetAdd('p3display_graphicsStateGuardian.obj', opts=OPTS, input='graphicsStateGuardian.cxx') + TargetAdd('p3display_composite1.obj', opts=OPTS, input='p3display_composite1.cxx') + TargetAdd('p3display_composite2.obj', opts=OPTS, input='p3display_composite2.cxx') + + OPTS=['DIR:panda/src/display', 'PYTHON'] + IGATEFILES=GetDirectoryContents('panda/src/display', ["*.h", "*_composite*.cxx"]) + IGATEFILES.remove("renderBuffer.h") + TargetAdd('libp3display.in', opts=OPTS, input=IGATEFILES) + TargetAdd('libp3display.in', opts=['IMOD:panda3d.core', 'ILIB:libp3display', 'SRCDIR:panda/src/display']) + TargetAdd('libp3display_igate.obj', input='libp3display.in', opts=["DEPENDENCYONLY"]) + TargetAdd('p3display_graphicsStateGuardian_ext.obj', opts=OPTS, input='graphicsStateGuardian_ext.cxx') + TargetAdd('p3display_graphicsWindow_ext.obj', opts=OPTS, input='graphicsWindow_ext.cxx') + TargetAdd('p3display_pythonGraphicsWindowProc.obj', opts=OPTS, input='pythonGraphicsWindowProc.cxx') + + if RTDIST and GetTarget() == 'darwin': + OPTS=['DIR:panda/src/display'] + TargetAdd('subprocessWindowBuffer.obj', opts=OPTS, input='subprocessWindowBuffer.cxx') + TargetAdd('libp3subprocbuffer.ilb', input='subprocessWindowBuffer.obj') + # # DIRECTORY: panda/src/chan/ # @@ -3921,30 +3946,6 @@ if (not RUNTIME): TargetAdd('libp3dgraph.in', opts=['IMOD:panda3d.core', 'ILIB:libp3dgraph', 'SRCDIR:panda/src/dgraph']) TargetAdd('libp3dgraph_igate.obj', input='libp3dgraph.in', opts=["DEPENDENCYONLY"]) -# -# DIRECTORY: panda/src/display/ -# - -if (not RUNTIME): - OPTS=['DIR:panda/src/display', 'BUILDING:PANDA'] - TargetAdd('p3display_composite1.obj', opts=OPTS, input='p3display_composite1.cxx') - TargetAdd('p3display_composite2.obj', opts=OPTS, input='p3display_composite2.cxx') - - OPTS=['DIR:panda/src/display', 'PYTHON'] - IGATEFILES=GetDirectoryContents('panda/src/display', ["*.h", "*_composite*.cxx"]) - IGATEFILES.remove("renderBuffer.h") - TargetAdd('libp3display.in', opts=OPTS, input=IGATEFILES) - TargetAdd('libp3display.in', opts=['IMOD:panda3d.core', 'ILIB:libp3display', 'SRCDIR:panda/src/display']) - TargetAdd('libp3display_igate.obj', input='libp3display.in', opts=["DEPENDENCYONLY"]) - TargetAdd('p3display_graphicsStateGuardian_ext.obj', opts=OPTS, input='graphicsStateGuardian_ext.cxx') - TargetAdd('p3display_graphicsWindow_ext.obj', opts=OPTS, input='graphicsWindow_ext.cxx') - TargetAdd('p3display_pythonGraphicsWindowProc.obj', opts=OPTS, input='pythonGraphicsWindowProc.cxx') - - if RTDIST and GetTarget() == 'darwin': - OPTS=['DIR:panda/src/display'] - TargetAdd('subprocessWindowBuffer.obj', opts=OPTS, input='subprocessWindowBuffer.cxx') - TargetAdd('libp3subprocbuffer.ilb', input='subprocessWindowBuffer.obj') - # # DIRECTORY: panda/src/device/ # @@ -4166,6 +4167,7 @@ if (not RUNTIME): TargetAdd('libpanda.dll', input='p3device_composite2.obj') TargetAdd('libpanda.dll', input='p3dgraph_composite1.obj') TargetAdd('libpanda.dll', input='p3dgraph_composite2.obj') + TargetAdd('libpanda.dll', input='p3display_graphicsStateGuardian.obj') TargetAdd('libpanda.dll', input='p3display_composite1.obj') TargetAdd('libpanda.dll', input='p3display_composite2.obj') TargetAdd('libpanda.dll', input='p3pipeline_composite1.obj') diff --git a/panda/src/display/p3display_composite2.cxx b/panda/src/display/p3display_composite2.cxx index b3ba58995b..b9d33ab445 100644 --- a/panda/src/display/p3display_composite2.cxx +++ b/panda/src/display/p3display_composite2.cxx @@ -1,5 +1,4 @@ #include "graphicsPipeSelection.cxx" -#include "graphicsStateGuardian.cxx" #include "graphicsThreadingModel.cxx" #include "graphicsWindow.cxx" #include "graphicsWindowProc.cxx" From 3b7b9cd18cc3c4e7b1ba8979c525a9f25c4547ea Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Sat, 20 Oct 2018 17:54:54 -0600 Subject: [PATCH 43/60] tests: Enhance GLSL test - Don't assume GLSL 4.30 is available just because the driver supports compute shaders. Drivers before OpenGL 4.3 may still offer the extension. - Use GLSL 1.30 by default, and turn on additional features using extensions. Skip any tests requiring extensions that aren't supported by the driver. - Unsigned literal ints should have a 'u' suffix. - Clean up a few dead Python expressions --- tests/display/test_glsl_shader.py | 37 +++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/tests/display/test_glsl_shader.py b/tests/display/test_glsl_shader.py index 91816353f6..0a0a5f5737 100644 --- a/tests/display/test_glsl_shader.py +++ b/tests/display/test_glsl_shader.py @@ -10,6 +10,7 @@ from _pytest.outcomes import Failed # The reset() function serves to prevent the _triggered variable from being # optimized out in the case that the assertions are being optimized out. GLSL_COMPUTE_TEMPLATE = """#version {version} +{extensions} layout(local_size_x = 1, local_size_y = 1) in; @@ -37,7 +38,7 @@ void main() {{ """ -def run_glsl_test(gsg, body, preamble="", inputs={}, version=430): +def run_glsl_test(gsg, body, preamble="", inputs={}, version=130, exts=set()): """ Runs a GLSL test on the given GSG. The given body is executed in the main function and should call assert(). The preamble should contain all of the shader inputs. """ @@ -48,11 +49,20 @@ def run_glsl_test(gsg, body, preamble="", inputs={}, version=430): if not gsg.supports_buffer_texture: pytest.skip("buffer textures not supported") + exts = exts | {'GL_ARB_compute_shader', 'GL_ARB_shader_image_load_store'} + missing_exts = sorted(ext for ext in exts if not gsg.has_extension(ext)) + if missing_exts: + pytest.skip("missing extensions: " + ' '.join(missing_exts)) + + extensions = '' + for ext in exts: + extensions += '#extension {ext} : require\n'.format(ext=ext) + __tracebackhide__ = True preamble = preamble.strip() body = body.rstrip().lstrip('\n') - code = GLSL_COMPUTE_TEMPLATE.format(version=version, preamble=preamble, body=body) + code = GLSL_COMPUTE_TEMPLATE.format(version=version, extensions=extensions, preamble=preamble, body=body) line_offset = code[:code.find(body)].count('\n') + 1 shader = core.Shader.make_compute(core.Shader.SL_GLSL, code) assert shader, code @@ -122,7 +132,7 @@ def test_glsl_sampler(gsg): assert(texelFetch(tex1, 0, 0) == vec4(0, 2 / 255.0, 1, 1)); assert(texelFetch(tex2, ivec2(0, 0), 0) == vec4(1.0, 2.0, -3.14, 0.0)); """ - run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}), code + run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}) def test_glsl_image(gsg): @@ -142,7 +152,7 @@ def test_glsl_image(gsg): assert(imageLoad(tex1, 0) == vec4(0, 2 / 255.0, 1, 1)); assert(imageLoad(tex2, ivec2(0, 0)) == vec4(1.0, 2.0, -3.14, 0.0)); """ - run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}), code + run_glsl_test(gsg, code, preamble, {'tex1': tex1, 'tex2': tex2}) def test_glsl_ssbo(gsg): @@ -164,7 +174,10 @@ def test_glsl_ssbo(gsg): assert(value1 == 1234567); assert(value2 == -1234567); """ - run_glsl_test(gsg, code, preamble, {'buffer1': buffer1, 'buffer2': buffer2}), code + run_glsl_test(gsg, code, preamble, {'buffer1': buffer1, 'buffer2': buffer2}, + exts={'GL_ARB_shader_storage_buffer_object', + 'GL_ARB_uniform_buffer_object', + 'GL_ARB_shading_language_420pack'}) def test_glsl_int(gsg): @@ -197,8 +210,8 @@ def test_glsl_uint(gsg): uniform uint intmax; """ code = """ - assert(zero == 0); - assert(intmax == 0x7fffffff); + assert(zero == 0u); + assert(intmax == 0x7fffffffu); """ run_glsl_test(gsg, code, preamble, inputs) @@ -243,7 +256,7 @@ def test_glsl_pta_int(gsg): assert(pta[2] == 2); assert(pta[3] == 3); """ - run_glsl_test(gsg, code, preamble, {'pta': pta}), code + run_glsl_test(gsg, code, preamble, {'pta': pta}) def test_glsl_pta_ivec4(gsg): @@ -256,7 +269,7 @@ def test_glsl_pta_ivec4(gsg): assert(pta[0] == ivec4(0, 1, 2, 3)); assert(pta[1] == ivec4(4, 5, 6, 7)); """ - run_glsl_test(gsg, code, preamble, {'pta': pta}), code + run_glsl_test(gsg, code, preamble, {'pta': pta}) def test_glsl_pta_mat4(gsg): @@ -278,7 +291,7 @@ def test_glsl_pta_mat4(gsg): assert(pta[1][2] == vec4(24, 25, 26, 27)); assert(pta[1][3] == vec4(28, 29, 30, 31)); """ - run_glsl_test(gsg, code, preamble, {'pta': pta}), code + run_glsl_test(gsg, code, preamble, {'pta': pta}) def test_glsl_write_extract_image_buffer(gsg): @@ -299,12 +312,12 @@ def test_glsl_write_extract_image_buffer(gsg): layout(r32i) uniform iimageBuffer tex2; """ code = """ - assert(imageLoad(tex1, 0).r == 0); + assert(imageLoad(tex1, 0).r == 0u); assert(imageLoad(tex2, 0).r == 0); imageStore(tex1, 0, uvec4(123)); imageStore(tex2, 0, ivec4(-456)); memoryBarrier(); - assert(imageLoad(tex1, 0).r == 123); + assert(imageLoad(tex1, 0).r == 123u); assert(imageLoad(tex2, 0).r == -456); """ From b8b86dc2f283115ae8aea90ec9c3930c0ddd9eb2 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Sat, 27 Oct 2018 19:41:51 -0600 Subject: [PATCH 44/60] glesgsg: Only use the iOS GLES framework when "BUILD_IPHONE" is defined --- panda/src/gles2gsg/gles2gsg.h | 2 +- panda/src/glesgsg/glesgsg.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/panda/src/gles2gsg/gles2gsg.h b/panda/src/gles2gsg/gles2gsg.h index 8d80e690eb..363baad0ca 100644 --- a/panda/src/gles2gsg/gles2gsg.h +++ b/panda/src/gles2gsg/gles2gsg.h @@ -51,7 +51,7 @@ // OpenGL ES 2 has no fixed-function pipeline. #undef SUPPORT_FIXED_FUNCTION -#ifdef IS_OSX +#ifdef BUILD_IPHONE #include // #include #else diff --git a/panda/src/glesgsg/glesgsg.h b/panda/src/glesgsg/glesgsg.h index 64d64db216..b7c7348cb9 100644 --- a/panda/src/glesgsg/glesgsg.h +++ b/panda/src/glesgsg/glesgsg.h @@ -54,7 +54,7 @@ #define __glext_h_ #define ES1_GLEXT_H_GUARD -#ifdef IS_OSX +#ifdef BUILD_IPHONE #include // #include #else From 466a68a985c646ba8625dfdd933942d25204a3a5 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Sun, 28 Oct 2018 03:11:51 -0600 Subject: [PATCH 45/60] pandatool: Fix several missing includes --- pandatool/src/eggcharbase/eggBackPointer.cxx | 2 ++ pandatool/src/eggcharbase/eggCharacterDb.h | 1 + pandatool/src/eggcharbase/eggJointData.cxx | 2 ++ pandatool/src/eggcharbase/eggJointNodePointer.cxx | 3 ++- pandatool/src/eggcharbase/eggMatrixTablePointer.cxx | 2 ++ pandatool/src/palettizer/paletteGroup.cxx | 1 + pandatool/src/xfileegg/xFileMaterial.cxx | 1 + pandatool/src/xfileegg/xFileMesh.cxx | 2 ++ pandatool/src/xfileegg/xFileMesh.h | 2 ++ pandatool/src/xfileegg/xFileToEggConverter.cxx | 1 + 10 files changed, 16 insertions(+), 1 deletion(-) diff --git a/pandatool/src/eggcharbase/eggBackPointer.cxx b/pandatool/src/eggcharbase/eggBackPointer.cxx index 400d9e3b2f..b1e269624a 100644 --- a/pandatool/src/eggcharbase/eggBackPointer.cxx +++ b/pandatool/src/eggcharbase/eggBackPointer.cxx @@ -13,6 +13,8 @@ #include "eggBackPointer.h" +#include "pnotify.h" + TypeHandle EggBackPointer::_type_handle; diff --git a/pandatool/src/eggcharbase/eggCharacterDb.h b/pandatool/src/eggcharbase/eggCharacterDb.h index 037367dc8b..31af55f231 100644 --- a/pandatool/src/eggcharbase/eggCharacterDb.h +++ b/pandatool/src/eggcharbase/eggCharacterDb.h @@ -29,6 +29,7 @@ */ class EggJointPointer; +class LMatrix4d; /** * This class is used during joint optimization or restructuring to store the diff --git a/pandatool/src/eggcharbase/eggJointData.cxx b/pandatool/src/eggcharbase/eggJointData.cxx index 65ed9505a5..ebf656b113 100644 --- a/pandatool/src/eggcharbase/eggJointData.cxx +++ b/pandatool/src/eggcharbase/eggJointData.cxx @@ -12,6 +12,8 @@ */ #include "eggJointData.h" + +#include "eggCharacterDb.h" #include "eggJointNodePointer.h" #include "eggMatrixTablePointer.h" #include "pvector.h" diff --git a/pandatool/src/eggcharbase/eggJointNodePointer.cxx b/pandatool/src/eggcharbase/eggJointNodePointer.cxx index c9c891606b..23bf7ea480 100644 --- a/pandatool/src/eggcharbase/eggJointNodePointer.cxx +++ b/pandatool/src/eggcharbase/eggJointNodePointer.cxx @@ -14,8 +14,9 @@ #include "eggJointNodePointer.h" #include "dcast.h" -#include "eggObject.h" +#include "eggCharacterDb.h" #include "eggGroup.h" +#include "eggObject.h" #include "pointerTo.h" diff --git a/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx b/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx index 21c9c63516..267296483f 100644 --- a/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx +++ b/pandatool/src/eggcharbase/eggMatrixTablePointer.cxx @@ -12,7 +12,9 @@ */ #include "eggMatrixTablePointer.h" + #include "dcast.h" +#include "eggCharacterDb.h" #include "eggSAnimData.h" #include "eggXfmAnimData.h" #include "eggXfmSAnim.h" diff --git a/pandatool/src/palettizer/paletteGroup.cxx b/pandatool/src/palettizer/paletteGroup.cxx index 182479216f..5f231b2e14 100644 --- a/pandatool/src/palettizer/paletteGroup.cxx +++ b/pandatool/src/palettizer/paletteGroup.cxx @@ -17,6 +17,7 @@ #include "textureImage.h" #include "palettizer.h" #include "paletteImage.h" +#include "sourceTextureImage.h" #include "indent.h" #include "datagram.h" diff --git a/pandatool/src/xfileegg/xFileMaterial.cxx b/pandatool/src/xfileegg/xFileMaterial.cxx index 11457ebcd5..9eaac25fbd 100644 --- a/pandatool/src/xfileegg/xFileMaterial.cxx +++ b/pandatool/src/xfileegg/xFileMaterial.cxx @@ -18,6 +18,7 @@ #include "eggTexture.h" #include "eggPrimitive.h" #include "datagram.h" +#include "config_xfile.h" #include // for strcmp, strdup diff --git a/pandatool/src/xfileegg/xFileMesh.cxx b/pandatool/src/xfileegg/xFileMesh.cxx index 4fad113ed4..e253ee385d 100644 --- a/pandatool/src/xfileegg/xFileMesh.cxx +++ b/pandatool/src/xfileegg/xFileMesh.cxx @@ -12,6 +12,7 @@ */ #include "xFileMesh.h" +#include "xFileToEggConverter.h" #include "xFileFace.h" #include "xFileVertex.h" #include "xFileNormal.h" @@ -22,6 +23,7 @@ #include "eggVertexPool.h" #include "eggVertex.h" #include "eggPolygon.h" +#include "eggGroup.h" #include "eggGroupNode.h" using std::min; diff --git a/pandatool/src/xfileegg/xFileMesh.h b/pandatool/src/xfileegg/xFileMesh.h index 417d7c4253..339ba2038f 100644 --- a/pandatool/src/xfileegg/xFileMesh.h +++ b/pandatool/src/xfileegg/xFileMesh.h @@ -22,6 +22,8 @@ #include "namable.h" #include "coordinateSystem.h" +#include "luse.h" + class XFileNode; class XFileDataNode; class XFileMesh; diff --git a/pandatool/src/xfileegg/xFileToEggConverter.cxx b/pandatool/src/xfileegg/xFileToEggConverter.cxx index 130c42546e..91ba21ba97 100644 --- a/pandatool/src/xfileegg/xFileToEggConverter.cxx +++ b/pandatool/src/xfileegg/xFileToEggConverter.cxx @@ -19,6 +19,7 @@ #include "eggData.h" #include "eggGroup.h" +#include "eggTable.h" #include "eggXfmSAnim.h" #include "eggGroupUniquifier.h" #include "datagram.h" From 43142e4e80ea6d9ba1adab6e53fcce144de16e10 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Sun, 28 Oct 2018 04:08:15 -0600 Subject: [PATCH 46/60] pandatool: Delete softegg/softprogs These depend on "SAA" - a Softimage library so long gone I can't even find references to it on Google. --- pandatool/src/softegg/config_softegg.cxx | 55 - pandatool/src/softegg/config_softegg.h | 28 - pandatool/src/softegg/soft2Egg.c | 4751 ----------------- pandatool/src/softegg/softEggGroupUserData.I | 44 - .../src/softegg/softEggGroupUserData.cxx | 16 - pandatool/src/softegg/softEggGroupUserData.h | 53 - pandatool/src/softegg/softNodeDesc.cxx | 1310 ----- pandatool/src/softegg/softNodeDesc.h | 159 - pandatool/src/softegg/softNodeTree.cxx | 561 -- pandatool/src/softegg/softNodeTree.h | 78 - pandatool/src/softegg/softToEggConverter.cxx | 2122 -------- pandatool/src/softegg/softToEggConverter.h | 179 - pandatool/src/softprogs/softCVS.cxx | 588 -- pandatool/src/softprogs/softCVS.h | 70 - pandatool/src/softprogs/softFilename.cxx | 291 - pandatool/src/softprogs/softFilename.h | 73 - 16 files changed, 10378 deletions(-) delete mode 100644 pandatool/src/softegg/config_softegg.cxx delete mode 100644 pandatool/src/softegg/config_softegg.h delete mode 100644 pandatool/src/softegg/soft2Egg.c delete mode 100644 pandatool/src/softegg/softEggGroupUserData.I delete mode 100644 pandatool/src/softegg/softEggGroupUserData.cxx delete mode 100644 pandatool/src/softegg/softEggGroupUserData.h delete mode 100644 pandatool/src/softegg/softNodeDesc.cxx delete mode 100644 pandatool/src/softegg/softNodeDesc.h delete mode 100644 pandatool/src/softegg/softNodeTree.cxx delete mode 100644 pandatool/src/softegg/softNodeTree.h delete mode 100644 pandatool/src/softegg/softToEggConverter.cxx delete mode 100644 pandatool/src/softegg/softToEggConverter.h delete mode 100644 pandatool/src/softprogs/softCVS.cxx delete mode 100644 pandatool/src/softprogs/softCVS.h delete mode 100644 pandatool/src/softprogs/softFilename.cxx delete mode 100644 pandatool/src/softprogs/softFilename.h diff --git a/pandatool/src/softegg/config_softegg.cxx b/pandatool/src/softegg/config_softegg.cxx deleted file mode 100644 index 89ad412508..0000000000 --- a/pandatool/src/softegg/config_softegg.cxx +++ /dev/null @@ -1,55 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_softegg.cxx - * @author masad - * @date 2003-09-25 - */ - -#include "config_softegg.h" -#include "softEggGroupUserData.h" -#include "softNodeDesc.h" - -#include "dconfig.h" - -Configure(config_softegg); -NotifyCategoryDef(softegg, ":soft"); - -ConfigureFn(config_softegg) { - init_libsoftegg(); -} - -// These control the default behavior of the softegg converter, but not -// necessarily the default behavior of the soft2egg command-line tool (which -// has its own defaults). - -// Should we respect the Soft? double-sided flag (true) or ignore it and -// assume everything is single-sided (false)? -ConfigVariableBool soft_default_double_sided("soft-default-double-sided", false); - -// Should we apply vertex color even when a texture is applied (true) or only -// when no texture is applied or the vertex-color egg flag is set (false)? -ConfigVariableBool soft_default_vertex_color("soft-default-vertex-color", true); - -/** - * Initializes the library. This must be called at least once before any of - * the functions or classes in this library can be used. Normally it will be - * called by the static initializers and need not be called explicitly, but - * special cases exist. - */ -void -init_libsoftegg() { - static bool initialized = false; - if (initialized) { - return; - } - initialized = true; - - SoftEggGroupUserData::init_type(); - SoftNodeDesc::init_type(); -} diff --git a/pandatool/src/softegg/config_softegg.h b/pandatool/src/softegg/config_softegg.h deleted file mode 100644 index 8deb0cb7aa..0000000000 --- a/pandatool/src/softegg/config_softegg.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file config_softegg.h - * @author masad - * @date 2003-09-25 - */ - -#ifndef CONFIG_SOFTEGG_H -#define CONFIG_SOFTEGG_H - -#include "pandatoolbase.h" -#include "notifyCategoryProxy.h" -#include "configVariableBool.h" - -NotifyCategoryDeclNoExport(softegg); - -extern ConfigVariableBool soft_default_double_sided; -extern ConfigVariableBool soft_default_vertex_color; - -extern void init_libsoftegg(); - -#endif diff --git a/pandatool/src/softegg/soft2Egg.c b/pandatool/src/softegg/soft2Egg.c deleted file mode 100644 index 9e744b8655..0000000000 --- a/pandatool/src/softegg/soft2Egg.c +++ /dev/null @@ -1,4751 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file soft2Egg.c - * @author masad - * @date 2003-09-26 - */ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#include "pandatoolbase.h" - -int init_soft2egg(int, char **); - -#if 0 -// DWD includes -#include "eggBase.h" -#include -#include -#include - -// system includes -#include -#include -#include -#include -#include -#include - -// Performer includes -#include - -// SoftImage includes -#include -#include - -static const int TEX_PER_MAT = 1; -static FILE *outStream = stdout; -// static FILE *outStream = stderr; - -class soft2egg : public EggBase -{ - public: - - soft2egg() : EggBase("r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD") - { - rsrc_path = "/ful/ufs/soft371_mips2/3D/rsrc"; - database_name = NULL; - scene_name = NULL; - model_name = NULL; - animFileName = NULL; - eggFileName = NULL; - tex_path = NULL; - eggGroupName = NULL; - tex_filename = NULL; - search_prefix = NULL; - result = SI_SUCCESS; - - skeleton = new EggGroup(); - foundRoot = FALSE; - animRoot = NULL; - morphRoot = NULL; - geom_as_joint = 0; - make_anim = 0; - make_nurbs = 0; - make_poly = 0; - make_soft = 0; - make_morph = 1; - make_duv = 1; - make_dart = TRUE; - has_morph = 0; - make_pose = 0; - animData.is_z_up = FALSE; - nurbs_step = 1; - anim_start = -1000; - anim_end = -1000; - anim_rate = 24; - pose_frame = -1; - verbose = 0; - flatten = 0; - shift_textures = 0; - ignore_tex_offsets = 0; - use_prefix = 0; - } - - virtual void Help(); - virtual void Usage(); - virtual void ShowOpts(); - - virtual boolean UseOutputSwitch() const { - return false; - } - - virtual boolean - HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv); - - int isNum( float ); - char *GetRootName( const char * ); - char *RemovePathName( const char * ); - char *GetSliderName( const char * ); - char *GetFullName( SAA_Scene *, SAA_Elem * ); - char *GetName( SAA_Scene *, SAA_Elem * ); - char *GetModelNoteInfo( SAA_Scene *, SAA_Elem * ); - char *MakeTableName( const char *, int ); - char *DepointellizeName( char * ); - SAA_Elem *FindModelByName( char *, SAA_Scene *, SAA_Elem *, int ); - char *ConvertTexture( SAA_Scene *, SAA_Elem * ); - int *FindClosestTriVert( EggVertexPool *, SAA_DVector *, int ); - int *MakeIndexMap( int *, int, int ); - int findShapeVert( SAA_DVector, SAA_DVector *, int ); - void LoadSoft(); - void MakeEgg( EggGroup *, EggJoint *, AnimGroup *, SAA_Scene *, SAA_Elem * ); - void MakeSurfaceCurve( SAA_Scene *, SAA_Elem *, EggGroup *, - EggNurbsSurface *&, int , SAA_SubElem *, bool ); - - EggNurbsCurve *MakeUVNurbsCurve( int, long *, double *, double *, - EggGroup *, char * ); - - EggNurbsCurve *MakeNurbsCurve( SAA_Scene *, SAA_Elem *, EggGroup *, - float [4][4], char * ); - - void AddKnots( perf_vector &, double *, int, SAA_Boolean, int ); - void MakeJoint( SAA_Scene *, EggJoint *&, AnimGroup *&, SAA_Elem *, char * ); - void MakeSoftSkin( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char * ); - void CleanUpSoftSkin( SAA_Scene *, SAA_Elem *, char * ); - void MakeAnimTable( SAA_Scene *, SAA_Elem *, char * ); - void MakeVertexOffsets( SAA_Scene *, SAA_Elem *, SAA_ModelType type, - int, int, SAA_DVector *, float (*)[4], char * ); - void MakeMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, char *, - float ); - void MakeLinearMorphTable( SAA_Scene *, SAA_Elem *, int, char *, float ); - void MakeWeightedMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, - int, char *, float ); - void MakeExpressionMorphTable( SAA_Scene *, SAA_Elem *, SAA_Elem *, int, - int, char *, float ); - void MakeTexAnim( SAA_Scene *, SAA_Elem *, char * ); - - private: - - char *rsrc_path; - char *database_name; - char *scene_name; - char *model_name; - char *eggFileName; - char *animFileName; - char *eggGroupName; - char *tex_path; - char *tex_filename; - char *search_prefix; - - SI_Error result; - SAA_Scene scene; - SAA_Elem model; - SAA_Database database; - EggGroup *dart; - EggGroup *skeleton; - AnimGroup *rootAnim; - EggJoint *rootJnt; - AnimGroup *animRoot; - AnimGroup *morphRoot; - EggData animData; - - int nurbs_step; - int anim_start; - int anim_end; - int anim_rate; - int pose_frame; - int verbose; - int flatten; - int shift_textures; - int ignore_tex_offsets; - int use_prefix; - - bool foundRoot; - bool geom_as_joint; - bool make_anim; - bool make_nurbs; - bool make_poly; - bool make_soft; - bool make_morph; - bool make_duv; - bool make_dart; - bool has_morph; - bool make_pose; - - std::ofstream eggFile; - std::ofstream animFile; - std::ofstream texFile; -}; - - -/** - * Displays the "what is this program" message, along with the usage message. - * Should be overridden in base classes to describe the current program. - */ -void soft2egg:: -Help() -{ - cerr << - "soft2egg takes a SoftImage scene or model\n" - "and outputs its contents as an egg file\n"; - - Usage(); -} - -/** - * Displays the usage message. - */ -void soft2egg:: -Usage() { - cerr << "\nUsage:\n" - << _commandName << " [opts] (must specify -m or -s)\n\n" - << "Options:\n"; - - ShowOpts(); - cerr << "\n"; -} - - - -/** - * Displays the valid options. Should be extended in base classes to show - * additional options relevant to the current program. - */ -void soft2egg:: -ShowOpts() -{ - cerr << - " -r - Used to provide soft with the resource\n" - " Defaults to 'c:/Softimage/SOFT_3.9.2/3D/test'.\n" - // " Defaults to 'fulufssoft371_mips23Drsrc'.\n" - " -d - Database path.\n" - " -s - Indicates that a scene will be converted.\n" - " -m - Indicates that a model will be converted.\n" - " -t - Specify path to place converted textures.\n" - " -T - Specify filename for texture map listing.\n" - " -S - Specify step for nurbs surface triangulation.\n" - " -M - Specify model output filename. Defaults to scene name.\n" - " -A - Specify anim output filename. Defaults to scene name.\n" - " -N - Specify egg group name.\n" - " -k - Enable soft assignment for geometry.\n" - " -n - Specify egg NURBS representation instead of poly's.\n" - " -p - Specify egg polygon output for geometry.\n" - " -P - Specify frame number for static pose.\n" - " -b - Specify starting frame for animation (default = first).\n" - " -e - Specify ending frame for animation (default = last).\n" - " -f - Specify frame rate for animation playback.\n" - " -a - Compile animation tables if animation present.\n" - " -F - Ignore hierarchy and build a completely flat skeleton.\n" - " -v - Set debug level.\n" - " -x - Shift NURBS parameters to preserve Alias textures.\n" - " -i - Ignore Soft texture uv offsets.\n" - " -u - Use Soft prefix in model names.\n" - " -c - Cancel morph conversion.\n" - " -C - Cancel duv conversion.\n" - " -D - Don't make the output model a character.\n" - " -o - Convert only models with given prefix.\n"; - - EggBase::ShowOpts(); -} - - -/** - * - */ -boolean soft2egg:: -HandleGetopts(char flag, char *optarg, int &optind, int argc, char **argv) -{ - boolean okflag = true; - - switch (flag) - { - case 'r': // Set the resource path for soft. - if ( strcmp( optarg, "" ) ) - { - // Get the path. - rsrc_path = optarg; - fprintf( outStream, "using rsrc path %s\n", rsrc_path ); - } - break; - - case 'd': // Set the database path. - if ( strcmp( optarg, "" ) ) - { - // Get the path. - database_name = optarg; - fprintf( outStream, "using database %s\n", database_name ); - } - break; - - case 's': // Check if its a scene. - if ( strcmp( optarg, "" ) ) - { - // Get scene name. - scene_name = optarg; - fprintf( outStream, "loading scene %s\n", scene_name ); - } - break; - - case 'm': // Check if its a model. - if ( strcmp( optarg, "" ) ) - { - // Get model name. - model_name = optarg; - fprintf( outStream, "loading model %s\n", model_name ); - } - break; - - case 't': // Get converted texture path. - if ( strcmp( optarg, "" ) ) - { - // Get tex path name. - tex_path = optarg; - fprintf( outStream, "texture path: %s\n", tex_path ); - } - break; - - case 'T': // Specify texture list filename. - if ( strcmp( optarg, "") ) - { - // Get the name. - tex_filename = optarg; - fprintf( outStream, "creating texture list file: %s\n", - tex_filename ); - } - break; - case 'S': // Set NURBS step. - if ( strcmp( optarg, "" ) ) - { - nurbs_step = atoi(optarg); - fprintf( outStream, "NURBS step: %d\n", nurbs_step ); - } - break; - - case 'M': // Set model output file name. - if ( strcmp( optarg, "" ) ) - { - eggFileName = optarg; - fprintf( outStream, "Model output filename: %s\n", eggFileName ); - } - break; - - case 'A': // Set anim output file name. - if ( strcmp( optarg, "" ) ) - { - animFileName = optarg; - fprintf( outStream, "Anim output filename: %s\n", animFileName ); - } - break; - - case 'N': // Set egg model name. - if ( strcmp( optarg, "" ) ) - { - eggGroupName = optarg; - fprintf( outStream, "Egg group name: %s\n", eggGroupName ); - } - break; - - case 'o': // Set search_prefix. - if ( strcmp( optarg, "" ) ) - { - search_prefix = optarg; - fprintf( outStream, "Only converting models with prefix: %s\n", - search_prefix ); - } - break; - - case 'h': // print help message - Help(); - exit(1); - break; - - case 'c': // Cancel morph animation conversion - make_morph = FALSE; - fprintf( outStream, "canceling morph conversion\n" ); - break; - - case 'C': // Cancel uv animation conversion - make_duv = FALSE; - fprintf( outStream, "canceling uv animation conversion\n" ); - break; - - case 'D': // Omit the Dart flag - make_dart = FALSE; - fprintf( outStream, "making a non-character model\n" ); - break; - - case 'k': // Enable soft skinning - // make_soft = TRUE; fprintf( outStream, "enabling soft skinning\n" ); - fprintf( outStream, "-k flag no longer necessary\n" ); - break; - - case 'n': // Generate egg NURBS output - make_nurbs = TRUE; - fprintf( outStream, "outputting egg NURBS info\n" ); - break; - - case 'p': // Generate egg polygon output - make_poly = TRUE; - fprintf( outStream, "outputting egg polygon info\n" ); - break; - - case 'P': // Generate static pose from given frame - if ( strcmp( optarg, "" ) ) - { - make_pose = TRUE; - pose_frame = atoi(optarg); - fprintf( outStream, "generating static pose from frame %d\n", - pose_frame ); - } - break; - - case 'a': // Compile animation tables. - make_anim = TRUE; - fprintf( outStream, "attempting to compile anim tables\n" ); - break; - - case 'F': // Build a flat skeleton. - flatten = TRUE; - fprintf( outStream, "building a flat skeleton!!!\n" ); - break; - - case 'x': // Shift NURBS parameters to preserve Alias textures. - shift_textures = TRUE; - fprintf( outStream, "shifting NURBS parameters...\n" ); - break; - - case 'i': // Ignore Soft uv texture offsets - ignore_tex_offsets = TRUE; - fprintf( outStream, "ignoring texture offsets...\n" ); - break; - - case 'u': // Use Soft prefix in model names - use_prefix = TRUE; - fprintf( outStream, "using prefix in model names...\n" ); - break; - - - case 'v': // print debug messages. - if ( strcmp( optarg, "" ) ) - { - verbose = atoi(optarg); - fprintf( outStream, "using debug level %d\n", verbose ); - } - break; - - case 'b': // Set animation start frame. - if ( strcmp( optarg, "" ) ) - { - anim_start = atoi(optarg); - fprintf( outStream, "animation starting at frame: %d\n", - anim_start ); - } - break; - - case 'e': /// Set animation end frame. - if ( strcmp( optarg, "" ) ) - { - anim_end = atoi(optarg); - fprintf( outStream, "animation ending at frame: %d\n", anim_end ); - } - break; - - case 'f': /// Set animation frame rate. - if ( strcmp( optarg, "" ) ) - { - anim_rate = atoi(optarg); - fprintf( outStream, "animation frame rate: %d\n", anim_rate ); - } - break; - - default: - okflag = EggBase::HandleGetopts(flag, optarg, optind, argc, argv); - } - - return (okflag); -} - - - -/** - * Take a float and make sure it is of the body. - */ -int soft2egg:: -isNum( float num ) -{ - return( ( num < HUGE_VAL ) && finite( num ) ); -} - - -/** - * Given a string, return a copy of the string up to the first occurrence of - * '-'. - */ -char *soft2egg:: -GetRootName( const char *name ) -{ - char *hyphen; - char *root; - int len; - - hyphen = strchr( name, '-' ); - len = hyphen-name; - - if ( (hyphen != NULL) && len ) - { - root = (char *)malloc(sizeof(char)*(len+1)); - strncpy( root, name, len ); - root[sizeof(char)*(len)] = '\0'; - } - else - { - root = (char *)malloc( sizeof(char)*(strlen(name)+1)); - strcpy( root, name ); - } - - return( root ); -} - - -/** - * Given a string, return a copy of the string after the last occurence of ' - */ -char *soft2egg:: -RemovePathName( const char *name ) -{ - char *slash; - char *root; - - if ( *name != NULL ) - { - slash = strrchr( name, '/' ); - - root = (char *)malloc( sizeof(char)*(strlen(name)+1)); - - if ( slash != NULL ) - strcpy( root, ++slash ); - else - strcpy( root, name ); - - return( root ); - } - - fprintf( stderr, "Error: RemovePathName received NULL string!\n" ); - return ( (char *)name ); -} - -/** - * Given a string, return that part of the string after the first occurence of - * '-' and before the last occurance of '.' - */ -char *soft2egg:: -GetSliderName( const char *name ) -{ - if ( name != NULL ) - { - strstream newStr; - char *hyphen; - char *end; - - hyphen = strchr( name, '-' ); - - // pull off stuff before first hyphen - if (hyphen != NULL) - { - newStr << ++hyphen; - end = newStr.str(); - } - - char *lastPeriod; - - lastPeriod = strrchr( end, '.' ); - - // ignore stuff after last period - if ( lastPeriod != NULL ) - { - *lastPeriod = '\0'; - } - - if ( verbose >= 1 ) - fprintf( stdout, "slider name: '%s'\n", end ); - - return( end ); - } - - return( (char *)name ); -} - -/** - * Given an element, return a copy of the element's name WITHOUT prefix. - */ -char *soft2egg:: -GetName( SAA_Scene *scene, SAA_Elem *element ) -{ - int nameLen; - char *name; - - // get the name - SAA_elementGetNameLength( scene, element, &nameLen ); - name = (char *)malloc(sizeof(char)*++nameLen); - SAA_elementGetName( scene, element, nameLen, name ); - - return name; -} - -/** - * Given an element, return a copy of the element's name complete with prefix. - */ -char *soft2egg:: -GetFullName( SAA_Scene *scene, SAA_Elem *element ) -{ - int nameLen; - char *name; - - // get the name - SAA_elementGetNameLength( scene, element, &nameLen ); - name = (char *)malloc(sizeof(char)*++nameLen); - SAA_elementGetName( scene, element, nameLen, name ); - - int prefixLen; - char *prefix; - - // get the prefix - SAA_elementGetPrefixLength( scene, element, &prefixLen ); - prefix = (char *)malloc(sizeof(char)*++prefixLen); - SAA_elementGetPrefix( scene, element, prefixLen, prefix ); - - strstream fullNameStrm; - - // add 'em together - fullNameStrm << prefix << "-" << name << ends; - - // free( name ); free( prefix ); - - return fullNameStrm.str(); -} - -/** - * Given an element, return a string containing the contents of its MODEL NOTE - * entry - */ -char *soft2egg:: -GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model ) -{ - - int size; - char *modelNote = NULL; - SAA_Boolean bigEndian; - - - SAA_elementGetUserDataSize( scene, model, "MNOT", &size ); - - if ( size != 0 ) - { - // allocate modelNote string - modelNote = (char *)malloc(sizeof(char)*(size + 1)); - - // get ModelNote data from this model - SAA_elementGetUserData( scene, model, "MNOT", size, - &bigEndian, (void *)modelNote ); - - // strip off newline, if present - char *eol = strchr( modelNote, '\n' ); - if ( eol != NULL) - *eol = '\0'; - else - modelNote[size] = '\0'; - - if ( verbose >= 1 ) - fprintf( outStream, "\nmodelNote = %s\n", - modelNote ); - } - - return modelNote; -} - - -/** - * Given a string, and a number, return a new string consisting of - * "string.number". - */ -char *soft2egg:: -MakeTableName( const char *name, int number ) -{ - strstream namestrm; - - namestrm << name << "." << number << ends; - return namestrm.str(); -} - -/** - * Given a string, find the model in the scene whose name corresponds to the - * given string. - */ -SAA_Elem *soft2egg:: -FindModelByName( char *name, SAA_Scene *scene, SAA_Elem *models, - int numModels ) -{ - char *foundName; - SAA_Elem *foundModel = NULL; - - for ( int model = 0; model < numModels; model++ ) - { - foundName = GetName( scene, &models[model] ); - - if ( !strcmp( name, foundName ) ) - { - if ( verbose >= 1 ) - fprintf( outStream, "foundModel: '%s' = '%s'\n", - name, foundName ); - - foundModel = &models[model]; - return( foundModel ); - } - } - - fprintf( outStream, "findModelByName: failed to find model named: '%s'\n", - name ); - - return ( foundModel ); -} - - -/** - * Given a string, return the string up to the first period. - */ -char *soft2egg:: -DepointellizeName( char *name ) -{ - char *endPtr; - char *newName; - - newName = (char *)malloc(sizeof(char)*(strlen(name)+1)); - sprintf( newName, "%s", name ); - - endPtr = strchr( newName, '.' ); - if ( endPtr != NULL ) - *endPtr = '\0'; - - return ( newName ); -} - - -/** - * Given a string, return a copy of the string without the leading file path, - * and make an rgb file of the same name in the tex_path directory. - */ -char *soft2egg:: -ConvertTexture( SAA_Scene *scene, SAA_Elem *texture ) -{ - char *fileName = NULL; - int fileNameLen = 0; - - // get the texture's name - SAA_texture2DGetPicNameLength( scene, texture, &fileNameLen); - - if ( fileNameLen ) - { - fileName = (char *)malloc(sizeof(char)*++fileNameLen); - SAA_texture2DGetPicName( scene, texture, fileNameLen, fileName ); - } - - // make sure we are not being passed a NULL image, an empty image string or - // the default image created by egg2soft - if ( (fileName != NULL) && strlen( fileName ) && strcmp( fileName, - "/fat/people/gregw/new_test/PICTURES/default") && - ( strstr( fileName, "noIcon" ) == NULL) ) - { - char *texName = NULL; - char *texNamePath = NULL; - char *tmpName = NULL; - char *fileNameExt = NULL; - - // strip off path and add .rgb - tmpName = strrchr( fileName, '/' ); - - if ( tmpName == NULL ) - tmpName = fileName; - else - tmpName++; - - float transp; - - // check for alpha - SAA_texture2DGetTransparency( scene, texture, &transp ); - - if ( transp != 0.0f ) { - texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+6)); - sprintf( texName, "%s.rgba", tmpName ); - } else { - texName = (char *)malloc(sizeof(char)*(strlen(tmpName)+5)); - sprintf( texName, "%s.rgb", tmpName ); - } - - fileNameExt = (char *)malloc(sizeof(char)*(strlen(fileName)+5)); - sprintf( fileNameExt, "%s.pic", fileName ); - - if ( verbose >= 1 ) - fprintf( outStream, "Looking for texture file: '%s'\n", fileNameExt ); - - // try to make conversion of file - int found_file = ( access( fileNameExt, F_OK ) == 0); - - if ( found_file ) - { - if ( tex_path ) - { - texNamePath = (char *)malloc(sizeof(char)*(strlen(tex_path) + - strlen(texName) + 2)); - - sprintf( texNamePath, "%s/%s", tex_path, texName ); - - if ( texFile ) - texFile << texNamePath << ": " << fileNameExt << "\n"; - - // make sure conversion doesn't already exist - if ( (access( texNamePath, F_OK ) != 0) && !texFile ) - { - char *command = (char *)malloc(sizeof(char)* - (strlen(fileNameExt) + strlen(texNamePath) + 20)); - - sprintf( command, "image-resize -1 %s %s", - fileNameExt, texNamePath ); - - if ( verbose >=1 ) - fprintf( outStream, "executing %s\n", command ); - - system( command ); - - // free( command ); - } - else - if ( verbose >=1 ) - fprintf( outStream, "%s already exists!\n", texNamePath ); - } - else - { - if ( verbose >= 1 ) - { - fprintf( outStream, "Warning: No texture path defined" ); - fprintf( outStream, " - No automatic conversion performed\n" ); - } - } - } - else - { - fprintf( outStream, "Warning: Couldn't find texture file: %s\n", - fileNameExt ); - } - - // free( fileNameExt ); - - if (tex_path) - return( texNamePath ); - else - return( texName ); - } - else - { - fprintf( outStream, "Warning: ConvertTexture received NULL fileName\n" ); - return( NULL ); - } -} - -/** - * Given an egg vertex pool, map each vertex therein to a vertex within an - * array of SAA model vertices of size numVert. Mapping is done by closest - * proximity. - */ -int *soft2egg:: -FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert ) -{ - int *vertMap = NULL; - int vpoolSize = vpool->NumVertices(); - int i,j; - float thisDist; - float closestDist; - int closest; - - - vertMap = (int *)malloc(sizeof(int)*vpoolSize); - - // for each vertex in vpool - for ( i = 0; i < vpoolSize; i++ ) - { - // find closest model vertex - for ( j = 0; j < numVert-1; j++ ) - { - // calculate distance - thisDist = sqrtf( - powf( vpool->Vertex(i)->position[0] - vertices[j].x , 2 ) + - powf( vpool->Vertex(i)->position[1] - vertices[j].y , 2 ) + - powf( vpool->Vertex(i)->position[2] - vertices[j].z , 2 ) ); - - // remember this if its the closest so far - if ( !j || ( thisDist < closestDist ) ) - { - closest = j; - closestDist = thisDist; - } - } - vertMap[i] = closest; - - if ( verbose >= 2 ) - { - fprintf( outStream, "mapping v %d of %d:( %f, %f, %f )\n", i, - vpoolSize, vpool->Vertex(i)->position[0], - vpool->Vertex(i)->position[1], - vpool->Vertex(i)->position[2] ); - fprintf( outStream, "to cv %d of %d:( %f, %f, %f )\tdelta = %f\n", - closest, numVert-1, vertices[closest].x, vertices[closest].y, - vertices[closest].z, closestDist ); - } - } - - return( vertMap ); -} - - -/** - * Given an array of indices that is a map from one set of vertices to - * another, return an array that performs the reverse mapping of the indices - * array - */ -int *soft2egg:: -MakeIndexMap( int *indices, int numIndices, int mapSize ) -{ - int i, j; - - // allocate map array - int *map = (int *)malloc(sizeof(int)*mapSize); - - if ( map != NULL ) - { - for ( i = 0; i < mapSize; i++ ) - { - j = 0; - int found = 0; - while( j < numIndices ) - { - if ( indices[j] == i ) - { - map[i] = j; - if ( verbose >= 2 ) - fprintf( outStream, "map[%d] = %d\n", i, map[i] ); - found = 1; - break; - } - j++; - } - if ( !found) - { - if ( verbose >= 2 ) - fprintf( outStream, "Warning: orphan vertex (%d)\n", i ); - // default to -1 for now - map[i] = -1; - } - } - } - else - fprintf( outStream, "Not enough Memory for index Map...\n"); - - return( map ); -} - -/** - * given a vertex, find its corresponding shape vertex and return its index. - */ -int soft2egg:: -findShapeVert( SAA_DVector vertex, SAA_DVector *vertices, int numVert ) -{ - int i; - int found = 0; - - for ( i = 0; i < numVert && !found ; i++ ) - { - if ( ( vertex.x == vertices[i].x ) && - ( vertex.y == vertices[i].y ) && - ( vertex.z == vertices[i].z ) ) - { - found = 1; - - if ( verbose >= 2) - fprintf( outStream, "found shape vert at index %d\n", i ); - } - } - - if (!found ) - i = -1; - else - i--; - - return( i ); -} - - -/** - * Open the SI database and grab the scene & model info - */ -void soft2egg:: -LoadSoft() -{ - int i; - - if ( (scene_name == NULL && model_name == NULL) || database_name == NULL ) - { - Usage(); - exit( 1 ); - } - - if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS) - { - fprintf( outStream, "Error: Couldn't get resource path!\n"); - exit( 1 ); - } - - if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS) - { - fprintf( outStream, "Error: Couldn't load database!\n"); - exit( 1 ); - } - - if ((result = SAA_sceneGetCurrent(&scene)) == SI_SUCCESS) - { - // load scene if present - if ( scene_name != NULL ) - { - SAA_sceneLoad( &database, scene_name, &scene ); - - // if no egg filename specified, make up a name - if ( eggFileName == NULL ) - { - eggFileName = (char *)malloc(sizeof(char)* - (strlen( scene_name ) + 14 )); - sprintf( eggFileName, "%s", DepointellizeName(scene_name) ); - if ( make_nurbs ) - strcat( eggFileName, "-nurb" ); - strcat( eggFileName, "-mod.egg" ); - } - - // open an output file for the geometry if necessary - if ( make_poly || make_nurbs ) - { - unlink( eggFileName ); - eggFile.open( eggFileName, ios::out, 0666 ); - - if ( !eggFile ) - { - fprintf( outStream, "Couldn't open output file: %s\n", - eggFileName ); - exit( 1 ); - } - } - - // open an output file for texture list if specified - if ( tex_filename != NULL ) - { - unlink( tex_filename ); - texFile.open( tex_filename, ios::out, 0666 ); - - if ( !texFile ) - { - fprintf( outStream, "Couldn't open output file: %s\n", - tex_filename ); - exit( 1 ); - } - } - - if ( SAA_updatelistGet( &scene ) == SI_SUCCESS ) - { - float time; - - fprintf( outStream, "setting Scene to frame %d...\n", pose_frame ); - // SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame ); - SAA_frame2Seconds( &scene, pose_frame, &time ); - SAA_updatelistEvalScene( &scene, time ); - sginap( 100 ); - SAA_updatelistEvalScene( &scene, time ); - if ( make_pose ) - SAA_sceneFreeze( &scene ); - } - - int numModels; - SAA_Elem *models; - - SAA_sceneGetNbModels( &scene, &numModels ); - fprintf( outStream, "Scene has %d model(s)...\n", numModels ); - - if ( numModels ) - { - // allocate array of models - models = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numModels); - - if ( models != NULL ) - { - char *rootName = GetRootName( eggFileName ); - - if ( eggGroupName == NULL ) - dart = _data.CreateGroup( NULL, rootName ); - else - dart = _data.CreateGroup( NULL, eggGroupName ); - - if (make_dart) - dart->flags |= EF_DART; - - AnimGroup *rootTable; - - rootTable = animData.CreateTable( NULL, eggFileName ); - - if ( eggGroupName == NULL ) - animRoot = animData.CreateBundle( rootTable, rootName ); - else - animRoot = animData.CreateBundle( rootTable, - eggGroupName ); - - // propagate commet to anim data - animData.root_group.children.push_front( - new EggComment( _commandLine ) ); - - if ( verbose >= 1 ) - fprintf( outStream, "made animRoot: %s\n", rootName ); - - SAA_sceneGetModels( &scene, numModels, models ); - - for ( i = 0; i < numModels; i++ ) - { - int level; - - SAA_elementGetHierarchyLevel( &scene, &models[i], &level ); - if ( !level ) - { - if ( verbose >= 1 ) - fprintf( outStream, - "\negging scene model[%d]\n", i ); - - MakeEgg( dart, NULL, NULL, &scene, &models[i] ); - } - } - - if ( make_poly || make_nurbs ) - { - // generate soft skinning assignments if desired disabled 1199 - // to streamline joint assignments. all joint assignments now - // done here. Hard & Soft. if ( make_soft) - { - char *name; - char *fullname; - SAA_Boolean isSkeleton; - - // search through models and look for skeleton parts - for ( i = 0; i < numModels; i++ ) - { - SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton ); - - // get fullname for splitting files, but only use it - // in file if requested - fullname = GetFullName( &scene, &models[i] ); - if ( use_prefix ) - name = fullname; - else - name = GetName( &scene, &models[i] ); - - // split - if ( strstr( fullname, search_prefix ) != NULL ) - { - // for every skel part: get soft skin info - if ( isSkeleton ) - MakeSoftSkin( &scene, &models[i], models, - numModels, name ); - } - - // free( name ); - } - - // make sure all vertices were assigned via soft skinning - // - if not hard assign them - for ( i = 0; i < numModels; i++ ) - { - // get fullname for splitting files, but only use it - // in file if requested - fullname = GetFullName( &scene, &models[i] ); - if ( use_prefix ) - name = fullname; - else - name = GetName( &scene, &models[i] ); - - // split - if ( strstr( fullname, search_prefix ) != NULL ) - CleanUpSoftSkin( &scene, &models[i], name ); - - // free( name ); - } - - } - - - // put the skeleton data into the egg data - dart->StealChildren( *skeleton ); - - // make sure all elements have unique names - _data.UniquifyNames(); - - // write out the geometry data if requested if ( make_poly || - // make_nurbs ) { - eggFile << _data << "\n"; - fprintf( outStream, "\nwriting out %s...\n", eggFileName ); - eggFile.close(); - } - - // close texture list file if opened - if ( texFile ) - texFile.close(); - - // generate animation data if desired - if ( make_anim ) - { - if ( animFileName == NULL ) - { - animFileName = (char *)malloc(sizeof(char)* - (strlen(scene_name)+ 10 )); - sprintf( animFileName, "%s", DepointellizeName(scene_name) ); - strcat( animFileName, "-chan.egg" ); - } - - unlink( animFileName ); - animFile.open( animFileName, ios::out, 0666 ); - - if ( !animFile ) - { - fprintf( outStream, "Couldn't open output file: %s\n", - animFileName ); - exit( 1 ); - } - - int frame; - // int frameStep; - float time; - - // get all the animation frame info if not specified on the - // command line - if (anim_start == -1000) - SAA_sceneGetPlayCtrlStartFrame( &scene, &anim_start ); - - if (anim_end == -1000) - SAA_sceneGetPlayCtrlEndFrame( &scene, &anim_end ); - - // SAA_sceneGetPlayCtrlFrameStep( &scene, &frameStep ); - - fprintf( outStream, "\nframeStart = %d\n", anim_start ); - fprintf( outStream, "frameEnd = %d\n", anim_end ); - // fprintf( outStream, "frameStep = %d\n", frameStep ); - - // start at first frame and go to last - for ( frame = anim_start; frame <= anim_end; - frame += 1) - { - SAA_frame2Seconds( &scene, frame, &time ); - SAA_updatelistEvalScene( &scene, time ); - sginap( 100 ); - SAA_updatelistEvalScene( &scene, time ); - fprintf( outStream, "\n> animating frame %d\n", frame ); - - // for each model - for ( i = 0; i < numModels; i++ ) - { - char *name; - char *fullname; - SAA_Boolean isSkeleton; - SAA_ModelType type; - - SAA_modelIsSkeleton( &scene, &models[i], &isSkeleton ); - - // get fullname for splitting files, but only use it - // in file if requested - fullname = GetFullName( &scene, &models[i] ); - if ( use_prefix ) - name = fullname; - else - name = GetName( &scene, &models[i] ); - - // split - if ( strstr( fullname, search_prefix ) != NULL ) - { - // make the morph table for this critter - if ( make_morph ) - { - MakeMorphTable( &scene, &models[i], models, - numModels, name, time ); - } - } - - // find out what type of node we're dealing with - result = SAA_modelGetType( &scene, &models[i], &type ); - - int size; - - // check for uv texture animation - SAA_elementGetUserDataSize( &scene, &models[i], - "TEX_OFFSETS", &size ); - - // if so, update for this frame if desired - if ( ( size != 0 ) && make_duv ) - MakeTexAnim( &scene, &models[i], name ); - - // if we have a skeleton or something that acts like - // one - build anim tables - if ( isSkeleton || - ( strstr( name, "joint") != NULL ) ) - MakeAnimTable( &scene, &models[i], name ); - - // free( name ); - } - - if ( verbose >= 1 ) - fprintf( outStream, "\n" ); - } - - animFile << animData << "\n"; - fprintf( outStream, "\nwriting out %s...\n", animFileName ); - animFile.close(); - } - - // free( models ); - - } - else - fprintf( outStream, "Error: Not enough Memory for models...\n"); - } - } - // otherwise try to load a model - else if ( model_name != NULL ) - { - - if ( eggFileName == NULL ) - { - eggFileName = - (char *)malloc(sizeof(char)*(strlen( model_name )+13)); - sprintf( eggFileName, "%s", DepointellizeName( model_name ) ); - - if ( make_nurbs ) - strcat( eggFileName, "-nurb" ); - strcat( eggFileName, "-mod.egg" ); - } - - eggFile.open( eggFileName ); - - if ( !eggFile ) - { - fprintf( outStream, "Couldn't open output file: %s\n", - eggFileName ); - exit( 1 ); - } - - if ((result = - SAA_elementLoad(&database, &scene, model_name, &model)) - == SI_SUCCESS) - { - fprintf( outStream, "Loading single model...\n"); - MakeEgg( NULL, NULL, NULL, &scene, &model ); - } - - eggFile << _data << "\n"; - } - } - -} - -/** - * Make egg geometry from a given model. This include textures, tex coords, - * colors, normals, and joints. - */ -void soft2egg:: -MakeEgg( EggGroup *parent, EggJoint *lastJoint, AnimGroup *lastAnim, - SAA_Scene *scene, SAA_Elem *model ) -{ - char *name; - char *fullname; - SAA_ModelType type; - int id = 0; - int numShapes; - int numTri; - int numVert; - int numTexLoc = 0; - int numTexGlb = 0; - int i, j; - float matrix[4][4]; - float *uScale = NULL; - float *vScale = NULL; - float *uOffset = NULL; - float *vOffset = NULL; - SAA_Boolean uv_swap = FALSE; - void *relinfo; - SAA_SubElem *triangles = NULL; - SAA_Elem *materials = NULL; - SAA_SubElem *cvertices = NULL; - SAA_DVector *cvertPos = NULL; - SAA_DVector *vertices = NULL; - SAA_DVector *normals = NULL; - int *indices = NULL; - int *indexMap = NULL; - int *numTexTri = NULL; - SAA_Elem *textures = NULL; - char **texNameArray; - float *uCoords = NULL; - float *vCoords = NULL; - SAA_GeomType gtype = SAA_GEOM_ORIGINAL; - SAA_Boolean visible; - - // find out what type of node we're dealing with - result = SAA_modelGetType( scene, model, &type ); - - if ( verbose >= 1 ) - { - if ( type == SAA_MNILL ) - fprintf( outStream, "encountered null\n"); - else if ( type == SAA_MPTCH ) - fprintf( outStream, "encountered patch\n" ); - else if ( type == SAA_MFACE ) - fprintf( outStream, "encountered face\n" ); - else if ( type == SAA_MSMSH ) - fprintf( outStream, "encountered mesh\n" ); - else if ( type == SAA_MJNT ) - fprintf( outStream, "encountered joint\n" ); - else if ( type == SAA_MSPLN ) - fprintf( outStream, "encountered spline\n" ); - else if ( type == SAA_MMETA ) - fprintf( outStream, "encountered meta element\n" ); - else if ( type == SAA_MBALL ) - fprintf( outStream, "encountered metaball\n" ); - else if ( type == SAA_MNCRV ) - fprintf( outStream, "encountered nurb curve\n" ); - else if ( type == SAA_MNSRF ) - fprintf( outStream, "encountered nurbs surf\n" ); - else - fprintf( outStream, "encountered unknown type: %d\n", type ); - } - - // Get the name of the model - - // Get the FULL name of the model - fullname = GetFullName( scene, model ); - - if ( use_prefix ) - { - // Get the FULL name of the trim curve - name = fullname; - } - else - { - // Get the name of the trim curve - name = GetName( scene, model ); - } - - if ( verbose >= 1 ) - fprintf( outStream, "element name <%s>\n", name ); - - fflush( outStream ); - - // get the model's matrix - SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix ); - - if ( verbose >= 2 ) - { - fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[0][0], - matrix[0][1], matrix[0][2], matrix[0][3] ); - fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[1][0], - matrix[1][1], matrix[1][2], matrix[1][3] ); - fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[2][0], - matrix[2][1], matrix[2][2], matrix[2][3] ); - fprintf( outStream, "model matrix = %f %f %f %f\n", matrix[3][0], - matrix[3][1], matrix[3][2], matrix[3][3] ); - } - - // check to see if this is a branch we don't want to descend - this will - // prevent creating geometry for animation control structures - if ( (strstr( name, "con-" ) == NULL) && - (strstr( name, "con_" ) == NULL) && - (strstr( name, "fly_" ) == NULL) && - (strstr( name, "fly-" ) == NULL) && - (strstr( name, "camRIG" ) == NULL) && - (strstr( name, "bars" ) == NULL) && - // split - (strstr( fullname, search_prefix ) != NULL) ) - { - - // if making a pose - get deformed geometry - if ( make_pose ) - gtype = SAA_GEOM_DEFORMED; - - // Get the number of key shapes - SAA_modelGetNbShapes( scene, model, &numShapes ); - if ( verbose >= 1 ) - fprintf( outStream, "MakeEgg: num shapes: %d\n", numShapes); - - // if multiple key shapes exist create table entries for each - if ( (numShapes > 0) && make_morph ) - { - has_morph = 1; - - // make sure root morph table exists - if ( morphRoot == NULL ) - morphRoot = animData.CreateTable( animRoot, "morph" ); - - char *tableName; - - // create morph table entry for each key shape (start at second shape - // - as first is the original geometry) - for ( i = 1; i < numShapes; i++ ) - { - tableName = MakeTableName( name, i ); - SAnimTable *table = new SAnimTable( ); - table->name = tableName; - table->fps = anim_rate; - morphRoot->children.push_back( table ); - if ( verbose >= 1 ) - fprintf( outStream, "created table named: '%s'\n", tableName ); - } - - // free( tableName ); - } - - SAA_modelGetNodeVisibility( scene, model, &visible ); - if ( verbose >= 1 ) - fprintf( outStream, "model visibility: %d\n", visible ); - - // Only create egg polygon data if: the node is visible, and its not a - // NULL or a Joint, and we're outputing polys (or if we are outputing - // NURBS and the model is a poly mesh or a face) - if ( visible && - (type != SAA_MNILL) && - (type != SAA_MJNT) && - ((make_poly || - (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) - || (!make_poly && !make_nurbs && make_duv && - ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) - ) - { - // If the model is a NURBS in soft, set its step before tesselating - if ( type == SAA_MNSRF ) - SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step ); - - // If the model is a PATCH in soft, set its step before tesselating - else if ( type == SAA_MPTCH ) - SAA_patchSetStep( scene, model, nurbs_step, nurbs_step ); - - // Get the number of triangles - result = SAA_modelGetNbTriangles( scene, model, gtype, id, &numTri); - if ( verbose >= 1 ) - fprintf( outStream, "triangles: %d\n", numTri); - - if ( result != SI_SUCCESS ) - { - if ( verbose >= 1 ) { - fprintf( outStream, - "Error: couldn't get number of triangles!\n" ); - fprintf( outStream, "\tbailing on model: '%s'\n", name ); - } - return; - } - - // check to see if surface is also skeleton... - SAA_Boolean isSkeleton = FALSE; - - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // check to see if this surface is used as a skeleton or is animated via - // constraint only ( these nodes are tagged by the animator with the - // keyword "joint" somewhere in the nodes name) - if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) - { - if ( verbose >= 1 ) - fprintf( outStream, "animating Polys as joint!!!\n" ); - - MakeJoint( scene, lastJoint, lastAnim, model, name ); - } - - // model is not a null and has no triangles! - if ( !numTri ) - { - if ( verbose >= 1 ) - fprintf( outStream, "no triangles!\n"); - } - else - { - // allocate array of triangles - triangles = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri); - if ( triangles != NULL ) - { - // triangulate model and read the triangles into array - SAA_modelGetTriangles( scene, model, gtype, id, numTri, triangles ); - } - else - fprintf( outStream, "Not enough Memory for triangles...\n"); - - // allocate array of materials - materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri); - if ( materials != NULL ) - { - // read each triangle's material into array - SAA_triangleGetMaterials( scene, model, numTri, triangles, - materials ); - } - else - fprintf( outStream, "Not enough Memory for materials...\n"); - - // allocate array of textures per triangle - numTexTri = (int *)malloc(sizeof(int)*numTri); - - // find out how many local textures per triangle - for ( i = 0; i < numTri; i++ ) - { - result = SAA_materialRelationGetT2DLocNbElements( scene, - &materials[i], FALSE, &relinfo, &numTexTri[i] ); - - // polytex - if ( result == SI_SUCCESS ) - numTexLoc += numTexTri[i]; - } - - // don't need this anymore... free( numTexTri ); - - // get local textures if present - if ( numTexLoc ) - { - // ASSUME only one texture per material - textures = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTri); - - for ( i = 0; i < numTri; i++ ) - { - // and read all referenced local textures into array - SAA_materialRelationGetT2DLocElements( scene, &materials[i], - TEX_PER_MAT , &textures[i] ); - } - - if ( verbose >= 1 ) - fprintf( outStream, "numTexLoc = %d\n", numTexLoc); - } - // if no local textures, try to get global textures - else - { - SAA_modelRelationGetT2DGlbNbElements( scene, model, - FALSE, &relinfo, &numTexGlb ); - - if ( numTexGlb ) - { - // ASSUME only one texture per model - textures = (SAA_Elem *)malloc(sizeof(SAA_Elem)); - - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, model, - TEX_PER_MAT, textures ); - - if ( verbose >= 1 ) - fprintf( outStream, "numTexGlb = %d\n", numTexGlb); - } - } - - // allocate array of control vertices - cvertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTri*3); - if ( cvertices != NULL ) - { - // read each triangle's control vertices into array - SAA_triangleGetCtrlVertices( scene, model, gtype, id, - numTri, triangles, cvertices ); - - if ( verbose >= 2 ) - { - cvertPos = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3); - SAA_ctrlVertexGetPositions( scene, model, numTri*3, - cvertices, cvertPos); - - for ( i=0; i < numTri*3; i++ ) - { - fprintf( outStream, "cvert[%d] = %f %f %f %f\n", i, - cvertPos[i].x, cvertPos[i].y, cvertPos[i].z, - cvertPos[i].w ); - } - } - } - else - fprintf( outStream, "Not enough Memory for control vertices...\n"); - - // allocate array of control vertex indices this array maps from the - // redundant cvertices array into the unique vertices array - // (cvertices->vertices) - indices = (int *)malloc(sizeof(int)*numTri*3); - if ( indices != NULL ) - { - for ( i=0; i < numTri*3; i++ ) - indices[i] = 0; - - SAA_ctrlVertexGetIndices( scene, model, numTri*3, - cvertices, indices ); - - if ( verbose >= 2 ) - for ( i=0; i < numTri*3; i++ ) - fprintf( outStream, "indices[%d] = %d\n", i, indices[i] ); - } - else - fprintf( outStream, "Not enough Memory for indices...\n"); - - // get number of UNIQUE vertices in model - SAA_modelGetNbTriVertices( scene, model, &numVert ); - - if ( verbose >= 2 ) - fprintf( outStream, "num unique verts = %d\n", numVert ); - - // allocate array of vertices - vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert); - - // get the UNIQUE vertices of all triangles in model - SAA_modelGetTriVertices( scene, model, numVert, vertices ); - - if ( verbose >= 2 ) - { - for ( i=0; i < numVert; i++ ) - { - fprintf( outStream, "vertices[%d] = %f ", i, vertices[i].x ); - fprintf( outStream, "%f %f %f\n", vertices[i].y, - vertices[i].z, vertices[i].w ); - } - } - - // allocate indexMap array we contruct this array to map from the - // unique vertices array to the redundant cvertices array - it will - // save us from doing repetitive searches later - indexMap = MakeIndexMap( indices, numTri*3, numVert ); - - // allocate array of normals - normals = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numTri*3); - if ( normals != NULL ) - { - // read each control vertex's normals into an array - SAA_ctrlVertexGetNormals( scene, model, numTri*3, - cvertices, normals ); - } - else - fprintf( outStream, "Not enough Memory for normals...\n"); - - if ( verbose >= 2 ) - { - for ( i=0; i= 2 ) - { - for ( i=0; i= 2 ) - fprintf( outStream, " tritex[%d] named: %s\n", i, - texNameArray[i] ); - - SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap ); - - if ( verbose >= 2 ) - if ( uv_swap == TRUE ) - fprintf( outStream, " swapping u and v...\n" ); - - SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] ); - SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] ); - SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] ); - SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] ); - - if ( verbose >= 2 ) - { - fprintf(outStream, "tritex[%d] uScale: %f vScale: %f\n", i, uScale[i], vScale[i] ); - fprintf(outStream, " uOffset: %f vOffset: %f\n", - uOffset[i], vOffset[i] ); - } - - - SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat, - &vRepeat ); - - if ( verbose >= 2 ) - { - fprintf(outStream, "uRepeat = %d, vRepeat = %d\n", - uRepeat, vRepeat ); - } - } - else - { - if ( verbose >= 2 ) - { - fprintf( outStream, "Invalid texture...\n"); - fprintf( outStream, " tritex[%d] named: (null)\n", i ); - } - } - } - -/* - * debug for ( i = 0; i < numTri; i++ ) { if ( texNameArray[i] != NULL ) - * fprintf( outStream, " tritex[%d] named: %s\n", i, texNameArray[i] ); else - * fprintf( outStream, " tritex[%d] named: (null)\n", i ); } - */ - } - // make sure we have textures before we get t-coords - else if ( numTexGlb ) - { - SAA_Boolean valid; - - // check to see if texture is present - SAA_elementIsValid( scene, textures, &valid ); - - // texture present - get the name and uv info - if ( valid ) - { - SAA_texture2DGetUVSwap( scene, textures, &uv_swap ); - - if ( verbose >= 1 ) - if ( uv_swap == TRUE ) - fprintf( outStream, " swapping u and v...\n" ); - - // allocate arrays for u & v coords - uCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3); - vCoords = (float *)malloc(sizeof(float)*numTri*numTexGlb*3); - - for ( i = 0; i < numTri*numTexGlb*3; i++ ) - { - uCoords[i] = vCoords[i] = 0.0f; - } - - // read the u & v coords into the arrays - if ( uCoords != NULL && vCoords != NULL) - { - SAA_triCtrlVertexGetGlobalUVTxtCoords( scene, model, - numTri*3, cvertices, numTexGlb, textures, - uCoords, vCoords ); - } - else - fprintf( outStream, "Not enough Memory for texture coords...\n"); - - if ( verbose >= 2 ) - { - for ( i=0; i= 1 ) - fprintf( outStream, " global tex named: %s\n", - texNameArray ); - - // allocate arrays of texture info - uScale = ( float *)malloc(sizeof(float)); - vScale = ( float *)malloc(sizeof(float)); - uOffset = ( float *)malloc(sizeof(float)); - vOffset = ( float *)malloc(sizeof(float)); - - SAA_texture2DGetUScale( scene, textures, uScale ); - SAA_texture2DGetVScale( scene, textures, vScale ); - SAA_texture2DGetUOffset( scene, textures, uOffset ); - SAA_texture2DGetVOffset( scene, textures, vOffset ); - - if ( verbose >= 1 ) - { - fprintf( outStream, " global tex uScale: %f vScale: %f\n", - *uScale, *vScale ); - fprintf( outStream, " uOffset: %f vOffset: %f\n", - *uOffset, *vOffset ); - } - - SAA_texture2DGetRepeats( scene, textures, &uRepeat, - &vRepeat ); - - if ( verbose >= 2 ) - { - fprintf(outStream, "uRepeat = %d, vRepeat = %d\n", - uRepeat, vRepeat ); - } - } - else fprintf( outStream, "Invalid texture...\n"); - } - - // make the egg vertex pool - EggVertexPool *pool = _data.CreateVertexPool( parent, name ); - - for ( i = 0; i < numVert; i++ ) - { - pfVec3 eggVert; - pfVec3 eggNorm; - - // convert to global coords - SAA_DVector local = vertices[i]; - SAA_DVector global; - - _VCT_X_MAT( global, local, matrix ); - - // set vertices array to reflect global coords vertices[i].x = - // global.x; vertices[i].y = global.y; vertices[i].z = global.z; - - // eggVert.set( vertices[i].x, vertices[i].y, vertices[i].z ); - - // we'll preserve original verts for now - eggVert.set( global.x, global.y, global.z ); - - local = normals[indexMap[i]]; - - _VCT_X_MAT( global, local, matrix ); - - eggNorm.set( global.x, global.y, global.z ); - eggNorm.normalize(); - - pool->AddVertex( eggVert, i ); - pool->Vertex(i)->attrib.SetNormal( eggNorm ); - - // translate local uv's to global and add to vertex pool - if ( numTexLoc && (uCoords != NULL && vCoords !=NULL )) - { - float u, v; - - if ( ignore_tex_offsets ) { - u = uCoords[indexMap[i]]; - v = 1.0f - vCoords[indexMap[i]]; - } else { - u = (uCoords[indexMap[i]] - uOffset[indexMap[i]/3]) / - uScale[indexMap[i]/3]; - - v = 1.0f - ((vCoords[indexMap[i]] - vOffset[indexMap[i]/3]) / - vScale[indexMap[i]/3]); - } - - if ( isNum(u) && isNum(v) ) - { - if ( uv_swap == TRUE ) - pool->Vertex(i)->attrib.SetUV( v, u ); - else - pool->Vertex(i)->attrib.SetUV( u, v ); - } - } - else if ( numTexGlb && (uCoords != NULL && vCoords !=NULL ) ) - { - float u, v; - - if ( ignore_tex_offsets ) { - u = uCoords[indexMap[i]]; - v = 1.0f - vCoords[indexMap[i]]; - } else { - u = (uCoords[indexMap[i]] - *uOffset) / *uScale; - v = 1.0f - (( vCoords[indexMap[i]] - *vOffset ) / *vScale); - } - - if ( isNum(u) && isNum(v) ) - { - if ( uv_swap == TRUE ) - pool->Vertex(i)->attrib.SetUV( v, u ); - else - pool->Vertex(i)->attrib.SetUV( u, v ); - } - } - - // if we've encountered textures and we desire duv anims - if (( numTexLoc || numTexGlb ) && make_duv ) - { - int numExp; - SAA_Elem *tex; - - // grab the current texture - if ( numTexLoc ) - tex = &textures[0]; - else - tex = textures; - - // find how many expressions for this shape - SAA_elementGetNbExpressions( scene, tex, NULL, FALSE, - &numExp ); - - // if it has expressions we'll assume its animated - if ( numExp ) - { - // if animated object make base duv's, animtables for the - // duv's and store the original offsets - strstream uName, vName; - - // create duv target names - uName << name << ".u" << ends; - vName << name << ".v" << ends; - - // only create tables and store offsets on a per model - // basis (not per vertex) - if ( !i ) - { - - // make sure root morph table exists - if ( morphRoot == NULL ) - morphRoot = animData.CreateTable( animRoot, - "morph" ); - - // create morph table entry for each duv - SAnimTable *uTable = new SAnimTable( ); - uTable->name = uName.str(); - uTable->fps = anim_rate; - morphRoot->children.push_back( uTable ); - if ( verbose >= 1 ) - fprintf( outStream, "created duv table named: %s\n", uName.str() ); - - SAnimTable *vTable = new SAnimTable( ); - vTable->name = vName.str(); - vTable->fps = anim_rate; - morphRoot->children.push_back( vTable ); - if ( verbose >= 1 ) - fprintf( outStream, "created duv table named: %s\n", vName.str() ); - - float texOffsets[4]; - - if ( numTexGlb ) - { - texOffsets[0] = *uOffset; - texOffsets[1] = *vOffset; - texOffsets[2] = *uScale; - texOffsets[3] = *vScale; - } - else - { - texOffsets[0] = uOffset[indexMap[i]/3]; - texOffsets[1] = vOffset[indexMap[i]/3]; - texOffsets[2] = uScale[indexMap[i]/3]; - texOffsets[3] = vScale[indexMap[i]/3]; - } - - // remember original texture offsets future reference - SAA_elementSetUserData( scene, model, "TEX_OFFSETS", - sizeof( texOffsets ), TRUE, (void **)&texOffsets ); - } - - EggMorphOffset *duvU; - EggMorphOffset *duvV; - - // generate base duv's for this vertex - duvU = new EggMorphOffset( uName.str(), 1.0 , 0.0 ); - pool->Vertex(i)->attrib.uv_morphs.push_back( *duvU ); - - duvV = new EggMorphOffset( vName.str(), 0.0 , 1.0 ); - pool->Vertex(i)->attrib.uv_morphs.push_back( *duvV ); - - } // if ( numExp ) - - } // if ( numTexLoc || numTexGlb ) - - } // for ( i = 0; i < numVert; i++ ) - - // if model has key shapes, generate vertex offsets - if ( has_morph && make_morph ) - MakeVertexOffsets( scene, model, type, numShapes, numVert, - vertices, matrix, name ); - - - // create vertex ref list for all polygons in the model - EggVertexRef *vref; - - vref = new EggVertexRef( pool); - for ( i = 0; i < numVert; i++ ) - { - // add each vert in pool to last joint for hard skinning - vref->indices.push_back( EggVertexIndex( i ) ); - } - -/* - * hard assign poly geometry if no soft-skinning requested disabled 1199 to - * streamline joint assignments. all hard-skinning now done in - * CleanUpSoftSkin. if ( !make_soft ) { if ( lastJoint != NULL ) { - * lastJoint->vrefs.AddUniqueNode( *vref ); - */ - - // if ( verbose >= 1 ) fprintf( outStream, "hard-skinning %s - // (%d vertices)\n", name, i+1 ); } } - - // make an egg group to hold all triangles - EggGroup *group = _data.CreateGroup( parent, name); - - // make this group the current parent - parent = group; - - EggPolygon *poly = NULL; - EggColor *cref = NULL; - EggTexture *tref = NULL; - - // for each triangle - for ( i = 0; i < numTri*3; i+=3 ) - { - float r,g,b,a; - pfVec4 color; - - // make egg poly for each traingle and reference the appropriate - // vertex in the pool - poly = _data.CreatePolygon( group, pool ); - poly->AddVertex(indices[i]); - poly->AddVertex(indices[i+1]); - poly->AddVertex(indices[i+2]); - - // check for back face flag in model note info - char *modelNoteStr = GetModelNoteInfo( scene, model ); - - if ( modelNoteStr != NULL ) - { - if ( strstr( modelNoteStr, "bface" ) != NULL ) - poly->flags |= EG_BFACE; - } - - // check to see if material is present - SAA_Boolean valid; - SAA_elementIsValid( scene, &materials[i/3], &valid ); - - // material present - get the color - if ( valid ) - { - SAA_materialGetDiffuse( scene, &materials[i/3], &r, &g, &b ); - SAA_materialGetTransparency( scene, &materials[i/3], &a ); - color.set( r, g, b, 1.0f - a ); - } - // no material - default to white - else - color.set( 1.0, 1.0, 1.0, 1.0 ); - - cref = _data.CreateColor(color); - poly->attrib.SetCRef(cref); - - strstream uniqueTexName; - - if (numTexLoc) - { - // polytex - if ( (texNameArray[i/3] != NULL) && - (strcmp(texNameArray[i/3], "NULL") != 0) ) - { - // append unique identifier to texname for this particular - // object - uniqueTexName << name << "-" - << RemovePathName(texNameArray[i/3]); - - tref = _data.CreateTexture( texNameArray[i/3], - uniqueTexName.str() ); - - if ( verbose >= 1 ) - fprintf( outStream, " tritex[%d] named: %s\n", i/3, - texNameArray[i/3] ); - } - } - else if ( numTexGlb ) - { - if ( texNameArray != NULL ) - { - // append unique identifier to texname for this particular - // object - uniqueTexName << name << "-" - << RemovePathName(*texNameArray); - - tref = _data.CreateTexture( *texNameArray, - uniqueTexName.str() ); - - if ( verbose >= 1 ) - fprintf( outStream, " tritex named: %s\n", - *texNameArray ); - } - } - - // set the clamp on the texture - if ( tref != NULL ) - { - if ( uRepeat > 0 ) - tref->wrapu = EggTexture::WM_repeat; - else - tref->wrapu = EggTexture::WM_clamp; - - if ( vRepeat > 1 ) - tref->wrapv = EggTexture::WM_repeat; - else - tref->wrapv = EggTexture::WM_clamp; - - poly->attrib.SetTRef(tref); - } - - } - - // we're done - trash triangles... - SAA_modelClearTriangles( scene, model ); - -/* - * free molloc'd memory free( triangles ); free( materials ); free( normals ); - * free( cvertices ); free( vertices ); free( indices ); free( indexMap ); - */ - - // free these only if they were malloc'd for textures - if (numTexLoc || numTexGlb) - { -/* - * free( textures ); free( uCoords ); free( vCoords ); free( texNameArray ); - * free( uScale ); free( vScale ); free( uOffset ); free( vOffset ); - */ - } - } - } - else - { - // check to see if its a nurbs surface - if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs ) - || ( !make_nurbs && !make_poly && make_duv )) ) - { - // check to see if NURBS is also skeleton... - SAA_Boolean isSkeleton = FALSE; - - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // check to see if this NURBS is used as a skeleton or is animated - // via constraint only ( these nodes are tagged by the animator - // with the keyword "joint" somewhere in the nodes name) - if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - geom_as_joint = 1; - if ( verbose >= 1 ) - fprintf( outStream, "animating NURBS as joint!!!\n" ); - } - - EggNurbsSurface *eggNurbsSurf = new EggNurbsSurface( name ); - int uDegree, vDegree; - - // create nurbs representation of surface - SAA_nurbsSurfaceGetDegree( scene, model, &uDegree, &vDegree ); - eggNurbsSurf->u_order = uDegree + 1; - eggNurbsSurf->v_order = vDegree + 1; - if ( verbose >= 1 ) - { - fprintf( outStream, "nurbs degree: %d u, %d v\n", - uDegree, vDegree ); - fprintf( outStream, "nurbs order: %d u, %d v\n", - uDegree + 1, vDegree + 1 ); - } - - SAA_Boolean uClosed = FALSE; - SAA_Boolean vClosed = FALSE; - - SAA_nurbsSurfaceGetClosed( scene, model, &uClosed, &vClosed); - - if ( verbose >= 1 ) - { - if ( uClosed ) - fprintf( outStream, "nurbs is closed in u...\n"); - if ( vClosed ) - fprintf( outStream, "nurbs is closed in v...\n"); - } - - int uRows, vRows; - SAA_nurbsSurfaceGetNbVertices( scene, model, &uRows, &vRows ); - if ( verbose >= 1 ) - fprintf( outStream, "nurbs vertices: %d u, %d v\n", - uRows, vRows ); - - int uCurves, vCurves; - SAA_nurbsSurfaceGetNbCurves( scene, model, &uCurves, &vCurves ); - if ( verbose >= 1 ) - fprintf( outStream, "nurbs curves: %d u, %d v\n", - uCurves, vCurves ); - - if ( shift_textures ) - { - if ( uClosed ) - // shift starting point on NURBS surface for correct textures - SAA_nurbsSurfaceShiftParameterization( scene, model, -2, 0 ); - - if ( vClosed ) - // shift starting point on NURBS surface for correct textures - SAA_nurbsSurfaceShiftParameterization( scene, model, 0, -2 ); - } - - SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step ); - - // check for back face flag in model note info - char *modelNoteStr = GetModelNoteInfo( scene, model ); - - if ( modelNoteStr != NULL ) - { - if ( strstr( modelNoteStr, "bface" ) != NULL ) - eggNurbsSurf->flags |= EG_BFACE; - } - - int numKnotsU, numKnotsV; - - SAA_nurbsSurfaceGetNbKnots( scene, model, &numKnotsU, &numKnotsV ); - if ( verbose >= 1 ) - fprintf( outStream, "nurbs knots: %d u, %d v\n", - numKnotsU, numKnotsV ); - - double *knotsU, *knotsV; - knotsU = (double *)malloc(sizeof(double)*numKnotsU); - knotsV = (double *)malloc(sizeof(double)*numKnotsV); - SAA_nurbsSurfaceGetKnots( scene, model, gtype, 0, - numKnotsU, numKnotsV, knotsU, knotsV ); - - if ( verbose >= 2 ) - fprintf( outStream, "u knots:\n" ); - - AddKnots( eggNurbsSurf->u_knots, knotsU, numKnotsU, uClosed, uDegree ); - if ( verbose >= 2 ) - fprintf( outStream, "v knots:\n" ); - - AddKnots( eggNurbsSurf->v_knots, knotsV, numKnotsV, vClosed, vDegree); - - // free( knotsU ); free( knotsV ); - - // set sub_div so we can see it in perfly - eggNurbsSurf->u_subdiv = (uRows-1)*nurbs_step; - eggNurbsSurf->v_subdiv = (vRows-1)*nurbs_step; - - SAA_modelGetNbVertices( scene, model, &numVert ); - - if ( verbose >= 2 ) - fprintf( outStream, "%d CV's\n", numVert ); - - // get the CV's - vertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numVert); - SAA_modelGetVertices( scene, model, gtype, 0, - numVert, vertices ); - - // create pool of NURBS vertices - EggVertexPool *pool = _data.CreateVertexPool( parent, name ); - eggNurbsSurf->SetVertexPool( pool ); - - // create vertex ref list for all cv's in the model - EggVertexRef *vref; - - vref = new EggVertexRef( pool); - - for ( int k = 0; k= 2 ) - { - fprintf( outStream, "original cv[%d] = %f %f %f %f\n", k, - vertices[k].x, vertices[k].y, vertices[k].z, - vertices[k].w ); - } - - pfVec4 eggVert; - - // convert to global coords - SAA_DVector global; - - _VCT_X_MAT( global, vertices[k], matrix ); - - // preserve original weight - global.w = vertices[k].w; - - // normalize coords to weight - global.x *= global.w; - global.y *= global.w; - global.z *= global.w; - - // this code is commented out because I am no longer sending - // global data to the other routines (ie makevertexoffset) - - // set vertices array to reflect global coords vertices[k].x = - // global.x; vertices[k].y = global.y; vertices[k].z = - // global.z; vertices[k].w = global.w; - - // if ( verbose >= 2 ) { fprintf( outStream, "global cv[%d] = - // %f %f %f %f\n", k, vertices[k].x, vertices[k].y, - // vertices[k].z, vertices[k].w ); } - - // eggVert.set( vertices[k].x, vertices[k].y, vertices[k].z, - // vertices[k].w ); - - if ( verbose >= 2 ) - { - fprintf( outStream, "global cv[%d] = %f %f %f %f\n", k, - global.x, global.y, global.z, - global.w ); - } - - eggVert.set( global.x, global.y, global.z, - global.w ); - - // populate vertex pool - pool->AddVertex( eggVert, k ); - - // add vref's to NURBS info - eggNurbsSurf->AddVertex( k ); - - // add each vert in pool to vref for hard skinning - vref->indices.push_back( EggVertexIndex( k ) ); - - // check to see if the NURB is closed in u - if ( uClosed ) - { - // add first uDegree verts to end of row - if ( (k % uRows) == ( uRows - 1) ) - for ( int i = 0; i < uDegree; i++ ) - { - // add vref's to NURBS info - eggNurbsSurf->AddVertex( i+((k/uRows)*uRows) ); - - // add each vert to vref - vref->indices.push_back( - EggVertexIndex( i+((k/uRows)*uRows) ) ); - } - } - } - -/* - * if hard skinned or this nurb is also a joint disabled 1199 to streamline - * joint assignments. all hard skinning now done in CleanUpSoftSkin. if - * (!make_soft || geom_as_joint) { add the new cv references to the last joint - * for hard skinning only if ( lastJoint != NULL ) { - * lastJoint->vrefs.AddUniqueNode( *vref ); geom_as_joint = 0; if ( verbose >= - * 1 ) fprintf( outStream, "Doing NURBS hard skinning...\n"); } } - */ - - // check to see if the NURB is closed in v - if ( vClosed && !uClosed ) - { - // add first vDegree rows of verts to end of list - for ( int i = 0; i < vDegree*uRows; i++ ) - eggNurbsSurf->AddVertex( i ); - } - // check to see if the NURB is closed in u and v - else if ( vClosed && uClosed ) - { - // add the first (degree) v verts and a few extra - for good - // measure - for ( i = 0; i < vDegree; i++ ) - { - // add first vDegree rows of verts to end of list - for ( j = 0; j < uRows; j++ ) - eggNurbsSurf->AddVertex( j+(i*uRows) ); - - // if u is closed to we have added uDegree verts onto the - // ends of the rows - add them here too - for ( k = 0; k < uDegree; k++ ) - eggNurbsSurf->AddVertex( k+(i*uRows)+((k/uRows)*uRows) ); - } - - } - - // get the color of the NURBS surface - int numNurbMats; - EggColor *nurbCref; - pfVec4 nurbColor; - - SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo, - &numNurbMats ); - - if ( verbose >= 1 ) - fprintf( outStream, "nurbs surf has %d materials\n", - numNurbMats ); - - if ( numNurbMats ) - { - float r,g,b,a; - - materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numNurbMats); - - SAA_modelRelationGetMatElements( scene, model, relinfo, - numNurbMats, materials ); - - SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b ); - SAA_materialGetTransparency( scene, &materials[0], &a ); - nurbColor.set( r, g, b, 1.0f - a ); - // nurbColor.set( r, g, b, 1.0 ); - - nurbCref = _data.CreateColor(nurbColor); - eggNurbsSurf->attrib.SetCRef(nurbCref); - - // get the texture of the NURBS surface from the material - int numNurbTexLoc = 0; - int numNurbTexGlb = 0; - - // ASSUME only one texture per material - SAA_Elem nurbTex; - - // find out how many local textures per NURBS surface ASSUME - // it only has one material - SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], - FALSE, &relinfo, &numNurbTexLoc ); - - // if present, get local textures - if ( numNurbTexLoc ) - { - if ( verbose >= 1 ) - fprintf( outStream, "%s had %d local tex\n", name, - numNurbTexLoc ); - - // get the referenced texture - SAA_materialRelationGetT2DLocElements( scene, &materials[0], - TEX_PER_MAT, &nurbTex ); - - } - // if no locals, try to get globals - else - { - SAA_modelRelationGetT2DGlbNbElements( scene, model, - FALSE, &relinfo, &numNurbTexGlb ); - - if ( numNurbTexGlb ) - { - if ( verbose >= 1 ) - fprintf( outStream, "%s had %d global tex\n", name, - numNurbTexGlb ); - - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, - model, TEX_PER_MAT, &nurbTex ); - } - } - - // add tex ref's if we found any textures - if ( numNurbTexLoc || numNurbTexGlb) - { - char *texName = NULL; - char *uniqueTexName = NULL; - EggTexture *tref; - pfMatrix nurbTexMat; - - - // convert the texture to .rgb and adjust name - texName = ConvertTexture( scene, &nurbTex ); - - // append unique identifier to texname for this particular - // object - uniqueTexName = (char *)malloc(sizeof(char)* - (strlen(name)+strlen(texName)+3) ); - sprintf( uniqueTexName, "%s-%s", name, - RemovePathName(texName) ); - - if ( verbose >= 1 ) - { - fprintf( outStream, "creating tref %s\n", - uniqueTexName ); - } - - tref = _data.CreateTexture( texName, uniqueTexName ); - - uScale = ( float *)malloc(sizeof(float)); - vScale = ( float *)malloc(sizeof(float)); - uOffset = ( float *)malloc(sizeof(float)); - vOffset = ( float *)malloc(sizeof(float)); - - // get texture offset info - SAA_texture2DGetUScale( scene, &nurbTex, uScale ); - SAA_texture2DGetVScale( scene, &nurbTex, vScale ); - SAA_texture2DGetUOffset( scene, &nurbTex, uOffset ); - SAA_texture2DGetVOffset( scene, &nurbTex, vOffset ); - SAA_texture2DGetUVSwap( scene, &nurbTex, &uv_swap ); - - - if ( verbose >= 1 ) - { - fprintf( outStream, "nurbTex uScale: %f\n", *uScale ); - fprintf( outStream, "nurbTex vScale: %f\n", *vScale ); - fprintf( outStream, "nurbTex uOffset: %f\n", *uOffset ); - fprintf( outStream, "nurbTex vOffset: %f\n", *vOffset ); - if ( uv_swap ) - fprintf( outStream, "nurbTex u & v swapped!\n" ); - else - fprintf( outStream, "nurbTex u & v NOT swapped\n" ); - } - - nurbTexMat.makeIdent(); - - if ( !ignore_tex_offsets ) - { - if ( uv_swap ) - { - nurbTexMat[0][0] = 0.0f; - nurbTexMat[1][1] = 0.0f; - nurbTexMat[0][1] = 1 / *vScale; - nurbTexMat[1][0] = 1 / *uScale; - nurbTexMat[2][1] = -(*uOffset / *uScale); - nurbTexMat[2][0] = -(*vOffset / *vScale); - } - else - { - nurbTexMat[0][0] = 1 / *uScale; - nurbTexMat[1][1] = 1 / *vScale; - nurbTexMat[2][0] = -(*uOffset / *uScale); - nurbTexMat[2][1] = -(*vOffset / *vScale); - } - } - - - // call printMat - if ( verbose >= 2 ) - { - fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[0][0], - nurbTexMat[0][1], nurbTexMat[0][2], nurbTexMat[0][3] ); - fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[1][0], - nurbTexMat[1][1], nurbTexMat[1][2], nurbTexMat[1][3] ); - fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[2][0], - nurbTexMat[2][1], nurbTexMat[2][2], nurbTexMat[2][3] ); - fprintf( outStream, "nurb tex matrix = %f %f %f %f\n", nurbTexMat[3][0], - nurbTexMat[3][1], nurbTexMat[3][2], nurbTexMat[3][3] ); - } - - - tref->tex_mat = nurbTexMat; - tref->flags |= EFT_TRANSFORM; - - eggNurbsSurf->attrib.SetTRef(tref); - - } - - // if we've encountered textures and we desire duv anims - if (( numNurbTexLoc || numNurbTexGlb ) && make_duv ) - { - int numExp; - - // find how many expressions for this shape - SAA_elementGetNbExpressions( scene, &nurbTex, NULL, FALSE, - &numExp ); - - // if it has expressions we'll assume its animated - if ( numExp ) - { - if ( verbose > 1 ) - printf( "nurbTex has %d expressions...\n", numExp ); - - // if animated object make base duv's, animtables for - // the duv's and store the original offsets - strstream uName, vName; - - // create duv target names - uName << name << ".u" << ends; - vName << name << ".v" << ends; - - // make sure root morph table exists - if ( morphRoot == NULL ) - morphRoot = animData.CreateTable( animRoot, - "morph" ); - - // create morph table entry for each duv - SAnimTable *uTable = new SAnimTable( ); - uTable->name = uName.str(); - uTable->fps = anim_rate; - morphRoot->children.push_back( uTable ); - if ( verbose >= 1 ) - fprintf( outStream, "created duv table named: %s\n", uName.str() ); - - SAnimTable *vTable = new SAnimTable( ); - vTable->name = vName.str(); - vTable->fps = anim_rate; - morphRoot->children.push_back( vTable ); - if ( verbose >= 1 ) - fprintf( outStream, "created duv table named: %s\n", vName.str() ); - - float texOffsets[4]; - - texOffsets[0] = *uOffset; - texOffsets[1] = *vOffset; - texOffsets[2] = *uScale; - texOffsets[3] = *vScale; - - // remember original texture offsets future reference - SAA_elementSetUserData( scene, model, "TEX_OFFSETS", - sizeof( texOffsets ), TRUE, (void **)&texOffsets ); - - // create UV's and duv's for each vertex - for( i = 0; i < numVert; i++ ) - { - pfVec2 tmpUV; - EggMorphOffset *duvU; - EggMorphOffset *duvV; - - // create uv's so we can store duv's - eggNurbsSurf->CalcActualUV( i, tmpUV ); - pool->Vertex(i)->attrib.SetUV( tmpUV[0], tmpUV[1] ); - - // generate base duv's for this vertex - duvU = new EggMorphOffset(uName.str(), 1.0 , 0.0); - pool->Vertex(i)->attrib.uv_morphs.push_back(*duvU); - - duvV = new EggMorphOffset(vName.str(), 0.0 , 1.0); - pool->Vertex(i)->attrib.uv_morphs.push_back(*duvV); - } - - } // if ( numExp ) - } // if ( numTexLoc || numTexGlb ) - - // free( uScale ); free( vScale ); free( uOffset ); free( - // vOffset ); - - // free( materials ); - } - else - { - // no material present - default to white - nurbColor.set( 1.0, 1.0, 1.0, 1.0 ); - } - - // check NURBS surface for trim curves - int numTrims; - bool isTrim = TRUE; - SAA_SubElem *trims; - - SAA_nurbsSurfaceGetNbTrimCurves( scene, model, SAA_TRIMTYPE_TRIM, - &numTrims ); - - if ( verbose >= 1 ) - fprintf( outStream, "nurbs surf has %d trim curves\n", - numTrims ); - - if ( numTrims) - { - trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims); - - if ( trims ) - { - SAA_nurbsSurfaceGetTrimCurves( scene, model, - gtype, 0, SAA_TRIMTYPE_TRIM, numTrims, - trims ); - - MakeSurfaceCurve( scene, model, parent, eggNurbsSurf, - numTrims, trims, isTrim ); - } - - // free( trims ); - } - - // check NURBS surface for surface curves - isTrim = FALSE; - - SAA_nurbsSurfaceGetNbTrimCurves( scene, model, - SAA_TRIMTYPE_PROJECTION, &numTrims ); - - if ( verbose >= 1 ) - fprintf( outStream, "nurbs surf has %d surface curves\n", - numTrims ); - - if ( numTrims) - { - trims = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*numTrims); - - if ( trims ) - { - SAA_nurbsSurfaceGetTrimCurves( scene, model, - gtype, 0, SAA_TRIMTYPE_PROJECTION, - numTrims, trims ); - - MakeSurfaceCurve( scene, model, parent, eggNurbsSurf, - numTrims, trims, isTrim ); - } - - // free( trims ); - } - - // push the NURBS into the egg data - parent->children.push_back( eggNurbsSurf ); - - // if model has key shapes, generate vertex offsets - if ( has_morph && make_morph ) - MakeVertexOffsets( scene, model, type, numShapes, numVert, - vertices, matrix, name ); - - - // free( vertices ); - - } - - // check to see if its a NURBS curve - else if ( (type == SAA_MNCRV) && ( visible ) && ( make_nurbs ) ) - { - // ignore for now make the NURBS curve and push it into the egg - // data parent->children.push_back( MakeNurbsCurve( scene, model, - // parent, matrix, name ) ); - } - else if ( type == SAA_MJNT ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - if ( verbose >= 1 ) - fprintf( outStream, "encountered IK joint: %s\n", name ); - } - - // it must be a NULL - else - { - SAA_AlgorithmType algo; - - SAA_modelGetAlgorithm( scene, model, &algo ); - if ( verbose >= 1 ) - fprintf( outStream, "null algorithm: %d\n", algo ); - - if ( algo == SAA_ALG_INV_KIN ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - if ( verbose >= 1 ) - fprintf( outStream, "encountered IK root: %s\n", name ); - } - else if ( algo == SAA_ALG_INV_KIN_LEAF ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - if ( verbose >= 1 ) - fprintf( outStream, "encountered IK leaf: %s\n", name ); - } - else if ( algo == SAA_ALG_STANDARD ) - { - SAA_Boolean isSkeleton = FALSE; - - if ( verbose >= 1 ) - fprintf( outStream, "encountered Standard null: %s\n", name); - - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // check to see if this NULL is used as a skeleton or is - // animated via constraint only ( these nodes are tagged by - // the animator with the keyword "joint" somewhere in the - // nodes name) - if ( isSkeleton || (strstr( name, "joint" ) != NULL) ) - { - MakeJoint( scene, lastJoint, lastAnim, model, name ); - if ( verbose >= 1 ) - fprintf( outStream, "animating Standard null!!!\n" ); - } - } - else - if ( verbose >= 1 ) - fprintf( outStream, "encountered some other NULL: %d\n", - algo ); - } - } - - - // check for children... - int numChildren; - int thisChild; - SAA_Elem *children; - - SAA_modelGetNbChildren( scene, model, &numChildren ); - if ( verbose >= 1 ) - fprintf( outStream, "Model children: %d\n", numChildren ); - - if ( numChildren ) - { - children = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numChildren); - SAA_modelGetChildren( scene, model, numChildren, children ); - if ( children != NULL ) - { - for ( thisChild = 0; thisChild < numChildren; thisChild++ ) - { - if ( verbose >= 1 ) - fprintf( outStream, "\negging child %d...\n", thisChild); - MakeEgg( parent, lastJoint, lastAnim, scene, - &children[thisChild] ); - } - } - else - fprintf( outStream, "Not enough Memory for children...\n"); - // free( children ); - } - fflush( outStream ); - } - else - if ( verbose >= 1 ) - fprintf( outStream, "Don't descend this branch!\n" ); - - // we are done for the most part - start cleaning up memory free( name ); -} - - -/** - * Given a scene and lists of u and v samples create a an egg NURBS curve of - * degree two from the samples - */ -void soft2egg:: -MakeSurfaceCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent, - EggNurbsSurface *&nurbsSurf, int numTrims, SAA_SubElem *trims, - bool isTrim ) -{ - int i; - long totalSamples = 0; - long *numSamples; - double *uSamples; - double *vSamples; - SAA_Elem *trimCurves; - char *name; - - // get UV coord data - numSamples = (long *)malloc(sizeof(long)*numTrims); - - SAA_surfaceCurveGetNbLinearSamples( scene, model, numTrims, trims, - numSamples ); - - for ( i = 0; i < numTrims; i++ ) - { - totalSamples += numSamples[i]; - if ( verbose >= 2 ) - fprintf( outStream, "numSamples[%d] = %d\n", i, numSamples[i] ); - } - - if ( verbose >= 2 ) - fprintf( outStream, "total samples = %ld\n", totalSamples ); - - uSamples = (double *)malloc(sizeof(double)*totalSamples); - vSamples = (double *)malloc(sizeof(double)*totalSamples); - - SAA_surfaceCurveGetLinearSamples( scene, model, numTrims, trims, - numSamples, uSamples, vSamples ); - - if ( verbose >= 2 ) - for ( long li = 0; li < totalSamples; li++ ) - fprintf( outStream, "master list cv[%ld] = %f, %f\n", li, - uSamples[li], vSamples[li] ); - - trimCurves = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numTrims); - - SAA_surfaceCurveExtract( scene, model, numTrims, trims, trimCurves ); - - // if it's a trim create a trim to assign trim curves to - EggNurbsSurface::Trim *eggTrim = new EggNurbsSurface::Trim(); - - // for each trim curve, make an egg curve and add it to the trims of the - // NURBS surface - for ( i = 0; i < numTrims; i++ ) - { - if ( use_prefix ) - { - // Get the FULL name of the trim curve - name = GetFullName( scene, &trimCurves[i] ); - } - else - { - // Get the name of the trim curve - name = GetName( scene, &trimCurves[i] ); - } - - if ( isTrim ) - { - // add to trim list - EggNurbsSurface::Loop *eggLoop = new EggNurbsSurface::Loop(); - eggLoop->push_back( MakeUVNurbsCurve( i, numSamples, uSamples, - vSamples, parent, name ) ); - eggTrim->push_back( *eggLoop ); - } - else - // add to curve list - nurbsSurf->curves.push_back( MakeUVNurbsCurve( i, numSamples, uSamples, vSamples, parent, name ) ); - } - - if ( isTrim ) - // pus trim list onto trims list - nurbsSurf->trims.push_back( *eggTrim ); - - // free( name ); free( trimCurves ); free( uSamples ); free( vSamples ); -} - -/** - * Given a scene and lists of u and v samples create a an egg NURBS curve of - * degree two from the samples - */ -EggNurbsCurve *soft2egg:: -MakeUVNurbsCurve( int numCurve, long *numSamples, double *uSamples, - double *vSamples, EggGroup *parent, char *name ) -{ - EggNurbsCurve *eggNurbsCurve = new EggNurbsCurve( name ); - - eggNurbsCurve->order = 2; - - - if ( verbose >= 2 ) - fprintf( outStream, "nurbs UV curve %s:\n", name ); - - // set sub_div so we can see it in perfly eggNurbsCurve->subdiv = - // numSamples[numCurve]4; perfly chokes on big numbers - keep it - // reasonable - eggNurbsCurve->subdiv = 150; - - // create pool of NURBS vertices - EggVertexPool *pool = _data.CreateVertexPool( parent, name ); - eggNurbsCurve->SetVertexPool( pool ); - - // calculate offset to this curve's samples in list of all curve samples - int offset = 0; - - for ( int o = 0; o < numCurve; o++ ) - offset += numSamples[o]; - - for ( int k = 0; k= 2 ) - fprintf( outStream, "cv[%d] = %f %f %f\n", k, eggVert[0], - eggVert[1], eggVert[2] ); - - // populate vertex pool - pool->AddVertex( eggVert, k ); - - // add vref's to NURBS info - eggNurbsCurve->AddVertex( k ); - } - - // create numSamples[numCurve]+2 knots - eggNurbsCurve->knots.push_back( 0 ); - for ( k = 0; k < numSamples[numCurve]; k++ ) - eggNurbsCurve->knots.push_back( k ); - eggNurbsCurve->knots.push_back( numSamples[numCurve] - 1 ); - - // set color to bright green for now - EggColor *nurbCref; - pfVec4 nurbColor; - - nurbColor.set( 0.5, 1.0, 0.5, 1.0 ); - nurbCref = _data.CreateColor(nurbColor); - eggNurbsCurve->attrib.SetCRef(nurbCref); - - return( eggNurbsCurve ); -} - -/** - * Given a scene and a NURBS curve model create the the appropriate egg - * structures - */ -EggNurbsCurve *soft2egg:: -MakeNurbsCurve( SAA_Scene *scene, SAA_Elem *model, EggGroup *parent, - float matrix[4][4], char *name ) -{ - EggNurbsCurve *eggNurbsCurve = new EggNurbsCurve( name ); - int degree; - - if ( verbose >= 2 ) - fprintf( outStream, "nurbs curve %s:\n", name ); - - // create nurbs representation of surface - SAA_nurbsCurveGetDegree( scene, model, °ree ); - eggNurbsCurve->order = degree + 1; - if ( verbose >= 2 ) - fprintf( outStream, "nurbs curve order: %d\n", degree + 1 ); - - SAA_nurbsCurveSetStep( scene, model, nurbs_step ); - - SAA_Boolean closed = FALSE; - - SAA_nurbsCurveGetClosed( scene, model, &closed ); - if ( closed ) - if ( verbose >= 2 ) - fprintf( outStream, "nurbs curve is closed...\n"); - - int numKnots; - - SAA_nurbsCurveGetNbKnots( scene, model, &numKnots ); - if ( verbose >= 2 ) - fprintf( outStream, "nurbs curve knots: %d\n", numKnots ); - double *knots; - knots = (double *)malloc(sizeof(double)*numKnots); - SAA_nurbsCurveGetKnots( scene, model, SAA_GEOM_ORIGINAL, 0, - numKnots, knots ); - - AddKnots( eggNurbsCurve->knots, knots, numKnots, closed, degree ); - - // free( knots ); - - int numCV; - - SAA_modelGetNbVertices( scene, model, &numCV ); - if ( verbose >= 2 ) - fprintf( outStream, "%d CV's (=? %d)\n", numCV, (numKnots-(degree+1)) ); - - // set sub_div so we can see it in perfly - eggNurbsCurve->subdiv = (numCV-1)*nurbs_step; - - // get the CV's - SAA_DVector *cvArray; - cvArray = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV); - SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0, - numCV, cvArray ); - - // create pool of NURBS vertices - EggVertexPool *pool = _data.CreateVertexPool( parent, name ); - eggNurbsCurve->SetVertexPool( pool ); - - for ( int k = 0; k= 2 ) - fprintf( outStream, "cv[%d] = %f %f %f %f\n", k, cvArray[k].x, - cvArray[k].y, cvArray[k].z, cvArray[k].w ); - - pfVec4 eggVert; - - // convert to global coords - SAA_DVector local = cvArray[k]; - SAA_DVector global; - - _HVCT_X_MAT( global, local, matrix ); - - eggVert.set( global.x, global.y, global.z, global.w ); - - // populate vertex pool - pool->AddVertex( eggVert, k ); - - // add vref's to NURBS info - eggNurbsCurve->AddVertex( k ); - } - - if ( closed ) - { - // need to replicate first (degree) vertices - for ( k = 0; k < degree; k++ ) - { - eggNurbsCurve->AddVertex( k ); - if ( verbose >= 2 ) - fprintf( outStream, "adding cv[%d] = %f %f %f %f\n", k, - cvArray[k].x, cvArray[k].y, cvArray[k].z, cvArray[k].w ); - } - } - - // free( cvArray ); - - // set color to bright green for now - EggColor *nurbCref; - pfVec4 nurbColor; - - nurbColor.set( 0.5, 1.0, 0.5, 1.0 ); - nurbCref = _data.CreateColor(nurbColor); - eggNurbsCurve->attrib.SetCRef(nurbCref); - - return( eggNurbsCurve ); -} - -/** - * Given a parametric surface, and its knots, create the appropriate egg - * structure by filling in Soft's implicit knots and assigning the rest to - * eggKnots. - */ -void soft2egg:: -AddKnots( perf_vector &eggKnots, double *knots, int numKnots, - SAA_Boolean closed, int degree ) -{ - int k = 0; - double lastKnot = knots[0]; - double *newKnots; - - // add initial implicit knot(s) - if ( closed ) - { - int i = 0; - newKnots = (double *)malloc(sizeof(double)*degree); - - // need to add (degree) number of knots - for ( k = numKnots - 1; k >= numKnots - degree; k-- ) - { - // we have to know these in order to calculate next knot value so - // hold them in temp array - newKnots[i] = lastKnot - (knots[k] - knots[k-1]); - lastKnot = newKnots[i]; - i++; - } - for ( k = degree - 1; k >= 0; k-- ) - { - eggKnots.push_back( newKnots[k] ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k, newKnots[k] ); - } - - // free( newKnots ); - } - else - { - eggKnots.push_back( knots[k] ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k, knots[k] ); - } - - // add the regular complement of knots - for (k = 0; k < numKnots; k++) - { - eggKnots.push_back( knots[k] ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k] ); - } - - lastKnot = knots[numKnots-1]; - - // add trailing implicit knots - if ( closed ) - { - - // need to add (degree) number of knots - for ( k = 1; k <= degree; k++ ) - { - eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k, - lastKnot + (knots[k] - knots[k-1]) ); - lastKnot = lastKnot + (knots[k] - knots[k-1]); - } - } - else - { - eggKnots.push_back( knots[k-1] ); - if ( verbose >= 2 ) - fprintf( outStream, "knots[%d] = %f\n", k+1, knots[k-1] ); - } -} - -/** - * Given a name, a parent and a model create a new a new EggJoint for that - * model. - */ -void soft2egg:: -MakeJoint( SAA_Scene *scene, EggJoint *&lastJoint, AnimGroup *&lastAnim, - SAA_Elem *model, char *name ) -{ - float matrix[4][4]; - pfMatrix Matrix; - EggJoint *joint; - SAA_Boolean globalFlag = FALSE; - int scale_joint = 0; - - - // this is a quick fix to make scaled skeletons possible if the parent - // contains the keyword "scale" make this joint a global root joint - // instead of a child... - if (lastJoint != NULL) - { - if ( strstr( lastJoint->name.Str(), "scale" ) != NULL ) - { - scale_joint = 1; - if ( verbose >= 1 ) - fprintf( outStream, "scale joint flag set!\n" ); - } - } - - // if not root, flatten is false, and last joint had no scaling applied to - // it, then create joint in skeleton tree - if ( (lastJoint != NULL) && !flatten && !scale_joint ) - { - if ( verbose >= 1 ) - { - fprintf( outStream, "lastJoint = %s\n", lastJoint->name.Str() ); - fprintf( outStream, "getting local transform\n" ); - } - - SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ), - TRUE, (void **)&globalFlag ); - - // get the local matrix - SAA_modelGetMatrix( scene, model, SAA_COORDSYS_LOCAL, matrix ); - - // make this into a pfMatrix - Matrix[0][0] = matrix[0][0]; - Matrix[0][1] = matrix[0][1]; - Matrix[0][2] = matrix[0][2]; - Matrix[0][3] = matrix[0][3]; - Matrix[1][0] = matrix[1][0]; - Matrix[1][1] = matrix[1][1]; - Matrix[1][2] = matrix[1][2]; - Matrix[1][3] = matrix[1][3]; - Matrix[2][0] = matrix[2][0]; - Matrix[2][1] = matrix[2][1]; - Matrix[2][2] = matrix[2][2]; - Matrix[2][3] = matrix[2][3]; - Matrix[3][0] = matrix[3][0]; - Matrix[3][1] = matrix[3][1]; - Matrix[3][2] = matrix[3][2]; - Matrix[3][3] = matrix[3][3]; - - joint = _data.CreateJoint( lastJoint, name ); - joint->transform = Matrix; - } - // if we already have a root attach this joint to it - else if (foundRoot) - { - if ( verbose >= 1 ) - fprintf( outStream, "getting global transform\n" ); - - globalFlag = TRUE; - - SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ), - TRUE, (void *)&globalFlag ); - - // get the global matrix - SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix ); - - // make this into a pfMatrix - Matrix[0][0] = matrix[0][0]; - Matrix[0][1] = matrix[0][1]; - Matrix[0][2] = matrix[0][2]; - Matrix[0][3] = matrix[0][3]; - Matrix[1][0] = matrix[1][0]; - Matrix[1][1] = matrix[1][1]; - Matrix[1][2] = matrix[1][2]; - Matrix[1][3] = matrix[1][3]; - Matrix[2][0] = matrix[2][0]; - Matrix[2][1] = matrix[2][1]; - Matrix[2][2] = matrix[2][2]; - Matrix[2][3] = matrix[2][3]; - Matrix[3][0] = matrix[3][0]; - Matrix[3][1] = matrix[3][1]; - Matrix[3][2] = matrix[3][2]; - Matrix[3][3] = matrix[3][3]; - - if ( verbose >= 1 ) - fprintf( outStream, "attaching orphan chain to root\n" ); - - joint = _data.CreateJoint( rootJnt, name ); - joint->transform = Matrix; - lastAnim = rootAnim; - } - // if root, make a seperate tree for skeleton and create required Table - // for the Egg heirarchy - else - { - if ( verbose >= 1 ) - fprintf( outStream, "getting global transform\n" ); - - globalFlag = TRUE; - - SAA_elementSetUserData( scene, model, "GLOBAL", sizeof( SAA_Boolean ), - TRUE, (void *)&globalFlag ); - - // get the global matrix - SAA_modelGetMatrix( scene, model, SAA_COORDSYS_GLOBAL, matrix ); - - // make this into a pfMatrix - Matrix[0][0] = matrix[0][0]; - Matrix[0][1] = matrix[0][1]; - Matrix[0][2] = matrix[0][2]; - Matrix[0][3] = matrix[0][3]; - Matrix[1][0] = matrix[1][0]; - Matrix[1][1] = matrix[1][1]; - Matrix[1][2] = matrix[1][2]; - Matrix[1][3] = matrix[1][3]; - Matrix[2][0] = matrix[2][0]; - Matrix[2][1] = matrix[2][1]; - Matrix[2][2] = matrix[2][2]; - Matrix[2][3] = matrix[2][3]; - Matrix[3][0] = matrix[3][0]; - Matrix[3][1] = matrix[3][1]; - Matrix[3][2] = matrix[3][2]; - Matrix[3][3] = matrix[3][3]; - - rootJnt = _data.CreateJoint( skeleton, "root" ); - rootJnt->transform.makeIdent(); - if ( verbose >= 1 ) - fprintf( outStream, "setting skeleton root\n" ); - rootJnt->flags |= EF_TRANSFORM; - - joint = _data.CreateJoint( rootJnt, name ); - joint->transform = Matrix; - foundRoot = TRUE; - if ( verbose >= 1 ) - fprintf( outStream, "found first chain\n" ); - - // make skeleton table - AnimGroup *skeletonTable; - skeletonTable = animData.CreateTable( animRoot, "" ); - rootAnim = animData.CreateTable( skeletonTable, "root" ); - XfmSAnimTable *table = new XfmSAnimTable( ); - table->name = "xform"; - table->fps = anim_rate; - rootAnim->children.push_back( table ); - lastAnim = rootAnim; - } - - joint->flags |= EF_TRANSFORM; - - // if ( make_anim) { - AnimGroup *anim = animData.CreateTable( lastAnim, name ); - XfmSAnimTable *table = new XfmSAnimTable( ); - if ( verbose >= 1 ) - fprintf( outStream, "created anim table: %s\n", "xform" ); - table->name = "xform"; - table->fps = anim_rate; - anim->children.push_back( table ); - lastAnim = anim; - // } - - // make this joint current parent of chain - lastJoint = joint; -} - - -/** - * Given a skeleton part find its envelopes (if any) get the vertices - * associated with the envelopes and their weights and make vertex ref's for - * the joint - */ -void soft2egg:: -MakeSoftSkin( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, - int numModels, char *name ) -{ - int numEnv; - SAA_ModelType type; - SAA_Elem *envelopes; - - if ( verbose >= 1 ) - fprintf( outStream, "\n>found skeleton part( %s )!\n", name ); - - SAA_skeletonGetNbEnvelopes( scene, model, &numEnv ); - - if ( numEnv ) - { - // it's got envelopes - must be soft skinned - if ( verbose >= 1 ) - fprintf( outStream, "numEnv = %d\n", numEnv ); - - // allocate envelope array - envelopes = ( SAA_Elem *)malloc( sizeof( SAA_Elem )*numEnv ); - - if ( envelopes != NULL ) - { - int thisEnv; - SAA_EnvType envType; - bool hasEnvVertices = 0; - - SAA_skeletonGetEnvelopes( scene, model, numEnv, envelopes ); - - for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ ) - { - if ( verbose >= 1 ) - fprintf( outStream, "env[%d]: ", thisEnv ); - - SAA_envelopeGetType( scene, &envelopes[thisEnv], &envType ); - - if ( envType == SAA_ENVTYPE_NONE ) - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = none\n" ); - } - else if ( envType == SAA_ENVTYPE_FLXLCL ) - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = flexible, local\n" ); - hasEnvVertices = 1; - } - else if ( envType == SAA_ENVTYPE_FLXGLB ) - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = flexible, global\n" ); - hasEnvVertices = 1; - } - else if ( envType == SAA_ENVTYPE_RGDGLB ) - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = rigid, global\n" ); - hasEnvVertices = 1; - } - else - { - if ( verbose >= 1 ) - fprintf( outStream, "envType = unknown\n" ); - } - } - - if ( hasEnvVertices) - { - int *numEnvVertices; - SAA_SubElem *envVertices = NULL; - - numEnvVertices = (int *)malloc(sizeof(int)*numEnv); - - SAA_envelopeGetNbCtrlVertices( scene, model, numEnv, - envelopes, numEnvVertices ); - - if ( numEnvVertices != NULL ) - { - int totalEnvVertices = 0; - int i,j,k; - - for( i = 0; i < numEnv; i++ ) - { - totalEnvVertices += numEnvVertices[i]; - if ( verbose >= 1 ) - fprintf( outStream, "numEnvVertices[%d] = %d\n", - i, numEnvVertices[i] ); - } - - - if ( verbose >= 1 ) - fprintf( outStream, "total env verts = %d\n", - totalEnvVertices ); - - if ( totalEnvVertices ) - { - envVertices = (SAA_SubElem *)malloc(sizeof(SAA_SubElem)*totalEnvVertices); - - if ( envVertices != NULL ) - { - - SAA_envelopeGetCtrlVertices( scene, model, - numEnv, envelopes, numEnvVertices, envVertices); - - // loop through for each envelope - for ( i = 0; i < numEnv; i++ ) - { - float *weights = NULL; - int vertArrayOffset = 0; - - if ( verbose >= 2 ) - fprintf( outStream, "\nenvelope[%d]:\n", i ); - - weights = (float *)malloc(sizeof(float)*numEnvVertices[i]); - - if ( weights ) - { - char *envName; - int *vpoolMap = NULL; - - for ( j = 0; j < i; j++ ) - vertArrayOffset += numEnvVertices[j]; - - if ( verbose >= 1 ) - fprintf( outStream, - "envVertArray offset = %d\n", - vertArrayOffset ); - - // get the weights of the envelope vertices - SAA_ctrlVertexGetEnvelopeWeights( - scene, model, &envelopes[i], - numEnvVertices[i], - &envVertices[vertArrayOffset], weights ); - - // Get the name of the envelope model - if ( use_prefix ) - { - // Get the FULL name of the envelope - envName = GetFullName( scene, &envelopes[i] ); - } - else - { - // Get the name of the envelope - envName = GetName( scene, &envelopes[i] ); - } - - if ( verbose >= 1 ) - fprintf( outStream, "envelope name %s\n", envName ); - - // find out if envelope geometry is poly or nurb - // SAA_modelGetType( scene, FindModelByName( - // envName, scene, models, numModels ), &type ); - - SAA_modelGetType( scene, &envelopes[i], &type ); - - if ( verbose >= 1 ) - { - fprintf( outStream, "envelope model type "); - - if ( type == SAA_MSMSH ) - fprintf( outStream, "MESH\n" ); - else if ( type == SAA_MNSRF ) - fprintf( outStream, "NURBS\n" ); - else - fprintf( outStream, "OTHER\n" ); - } - - int *envVtxIndices = NULL; - envVtxIndices = (int *)malloc(sizeof(int)*numEnvVertices[i]); - - // Get the envelope vertex indices - SAA_ctrlVertexGetIndices( scene, &envelopes[i], numEnvVertices[i], - &envVertices[vertArrayOffset], envVtxIndices ); - - // find out how many vertices the model has - int modelNumVert; - - SAA_modelGetNbVertices( scene, &envelopes[i], &modelNumVert ); - - SAA_DVector *modelVertices = NULL; - modelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert); - - // get the model vertices - SAA_modelGetVertices( scene, &envelopes[i], - SAA_GEOM_ORIGINAL, 0, modelNumVert, - modelVertices ); - - // create array of global model coords - SAA_DVector *globalModelVertices = NULL; - globalModelVertices = (SAA_DVector *)malloc(sizeof(SAA_DVector)*modelNumVert); - float matrix[4][4]; - - // tranform local model vert coords to global - - // first get the global matrix - SAA_modelGetMatrix( scene, &envelopes[i], SAA_COORDSYS_GLOBAL, matrix ); - - // populate array of global model verts - for ( j = 0; j < modelNumVert; j++ ) - { - _VCT_X_MAT( globalModelVertices[j], - modelVertices[j], matrix ); - } - - // find the egg vertex pool that corresponds to - // this envelope model - EggVertexPool *envPool = - (EggVertexPool *)(_data.pools.FindName( envName )); - // If we are outputting triangles: create an array - // that maps from a referenced vertex in the - // envelope to a corresponding vertex in the egg - // vertex pool if ( (type == SAA_MNSRF) && - // !make_nurbs ) - if ( !make_nurbs || (type == SAA_MSMSH) ) - { - vpoolMap = FindClosestTriVert( envPool, - globalModelVertices, modelNumVert ); - } - - - if ( envPool != NULL ) - { - - // find the egg joint that corresponds to this - // model - EggJoint *joint = - (EggJoint *)(skeleton->FindDescendent( name )); - - // this doesn't seem to be necessary 4799 EggJoint - // *parent = (EggJoint *)joint->parent; - // assert(parent->IsA(NT_EggJoint)); - - // for every envelope vertex - for (j = 0; j < numEnvVertices[i]; j++) - { - double scaledWeight = weights[j]/ 100.0f; - - // make sure its in legal range - if (( envVtxIndices[j] < modelNumVert ) - && ( envVtxIndices[j] >= 0 )) - { - if ( (type == SAA_MNSRF) && make_nurbs ) - { - // assign all referenced control vertices - joint->AddVertex( envPool->Vertex(envVtxIndices[j]), scaledWeight ); - - if ( verbose >= 2 ) - fprintf( outStream, - "%d: adding vref to cv %d with weight %f\n", - j, envVtxIndices[j], scaledWeight ); - - envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight ); - // set flag to show this vertex has been - // assigned - envPool->Vertex(envVtxIndices[j])->multipleJoints = 1; - } - else - { - // assign all the tri verts associated - // with this control vertex to joint - for ( k = 0; k < envPool->NumVertices(); k++ ) - { - if ( vpoolMap[k] == envVtxIndices[j] ) - { - - // add each vert in pool to last joint - // for soft skinning - joint->AddVertex(envPool->Vertex(k), - scaledWeight); - - if ( verbose >= 2 ) - fprintf( outStream, - "%d: adding vref from cv %d to vert %d with weight %f(vpool)\n", - j, envVtxIndices[j], k, scaledWeight ); - - envPool->Vertex(k)->AddJoint( joint, scaledWeight ); - // set flag to show this vertex has - // been assigned - envPool->Vertex(k)->multipleJoints = 1; - } - } - } - } - else - if ( verbose >= 2 ) - fprintf( outStream, - "%d: Omitted vref from cv %d with weight %f (out of range 0 to %d )\n", - j, envVtxIndices[j], scaledWeight, modelNumVert ); - } - - } - else - if ( verbose >= 2 ) - fprintf( outStream, "Couldn't find vpool %s!\n", envName ); - - // free( modelVertices ); free( - // globalModelVertices ); free( envVtxIndices ); - // free( envName ); - } //if (weights) - // free( weights ); - - } // for i - - } // if (envVertices != NULL) - else - fprintf( outStream, "Not enough memory for envelope vertices...\n"); - // free( envVertices ); - } // if (totalEnvVertices) - else - if ( verbose >= 1 ) - fprintf( outStream, "No envelope vertices present...\n"); - - // free( numEnvVertices ); - - } // if (numEnvVertices != NULL) - - } // if (hasEnvVertices) - - } // if (envelopes != NULL) - else - fprintf( outStream, "Not enough memory for envelopes...\n" ); - - // free( envelopes ); - - } //if (numEnv) - - else - if ( verbose >= 1 ) - fprintf( outStream, "Skeleton member has no envelopes...\n" ); -} - - -/** - * Given a model, make sure all its vertices have been soft assigned. If not - * hard assign to the last joint we saw. - */ -void soft2egg:: -CleanUpSoftSkin( SAA_Scene *scene, SAA_Elem *model, char *name ) -{ - static EggJoint *joint; - SAA_Elem parent; - SAA_ModelType type; - SAA_Boolean skel; - - // find out what type of node we're dealing with - SAA_modelGetType( scene, model, &type ); - - char *parentName; - int level; - SAA_Elem *searchNode = model; - - if ( verbose >= 1 ) - fprintf( outStream, "\nCleaning up model %s\n", name ); - - // this step is weird - I think I want it here but it seems to break some - // models. Files like props-props_wh_cookietime.3-0 in - // fulrndpubvrmlchipchips_adventurecharzone1roomswarehouse_final need to - // do the "if (skel)" bit. - - // am I a skeleton too? - SAA_modelIsSkeleton( scene, model, &skel ); - - // if not look for the last skeleton part - if ( skel ) - parentName = name; - else do - { - SAA_elementGetHierarchyLevel( scene, searchNode, &level ); - - // make sure we don't try to get the root's parent - if ( level ) - { - SAA_modelGetParent( scene, searchNode, &parent ); - - if ( use_prefix ) - { - // Get the FULL name of the parent - parentName = GetFullName( scene, &parent ); - } - else - { - // Get the name of the parent - parentName = GetName( scene, &parent ); - } - - SAA_modelGetType( scene, &parent, &type ); - - SAA_modelIsSkeleton( scene, &parent, &skel ); - - if ( verbose >= 1 ) - fprintf( outStream, "model %s, level %d, type %d, skel %d\n", - parentName, level, type, skel ); - - searchNode = &parent; - } - else - { - // we reached the root of the tree - parentName = NULL; - if ( verbose >= 1 ) - fprintf( outStream, "at root of tree! level %d\n", level ); - break; - } - - // look until parent is a joint or acts like one - } while ( !skel && ( strstr( parentName,"joint") == NULL )); - - EggJoint *thisJoint = NULL; - - if ( parentName != NULL ) - { - if ( verbose >= 1 ) - { - fprintf( outStream, "found model parent joint %s\n", parentName); - fprintf( outStream, "looking for joint %s\n", parentName ); - } - thisJoint = (EggJoint *)(skeleton->FindDescendent( parentName )); - } - else - if ( verbose >= 1 ) - fprintf( outStream, "Couldn't find parent joint!\n"); - - if ( thisJoint != NULL ) - { - joint = thisJoint; - if ( verbose >= 1 ) - fprintf( outStream, "setting joint to %s\n", parentName ); - - // find the vpool for this model - EggVertexPool *vPool = - (EggVertexPool *)(_data.pools.FindName( name )); - - if (vPool != NULL) - { - int i; - double membership; - int numVerts = vPool->NumVertices() ; - - - if ( verbose >= 1 ) - fprintf( outStream, "found vpool %s w/ %d verts\n", - name, numVerts ); - - for ( i = 0; i < numVerts; i++ ) - { - if ( vPool->Vertex(i)->multipleJoints != 1 ) - { - if ( verbose >= 1 ) - { - fprintf( outStream, "vpool %s vert %d", name, i ); - fprintf( outStream, " not assigned!\n" ); - } - - // hard skin this vertex - joint->AddVertex( vPool->Vertex(i), 1.0f ); - } - else - { - membership = vPool->Vertex(i)->NetMembership(); - - - if ( verbose >= 1 ) - { - fprintf( outStream, "vpool %s vert %d", name, - i ); - fprintf( outStream, " has membership %f\n", - membership ); - } - - if ( membership == 0 ) - { - if ( verbose >= 1 ) - fprintf( outStream, "adding full weight..\n" ); - - // hard skin this vertex - joint->AddVertex( vPool->Vertex(i), 1.0f ); - } - } - } - } - else - if ( verbose >= 1 ) - fprintf( outStream, "couldn't find vpool %s\n", name ); - } - else - { - if ( parentName != NULL ) - if ( verbose >= 1 ) - fprintf( outStream, "Couldn't find joint %s\n", parentName ); - } -} - -/** - * Given a scene and a skeleton part ,get all the position, rotation, and - * scale for the skeleton part for this frame and write them out as Egg - * animation tables. - */ -void soft2egg:: -MakeAnimTable( SAA_Scene *scene, SAA_Elem *skeletonPart, char *name ) -{ - - if ( skeletonPart != NULL ) - { - float i,j,k; - float h,p,r; - float x,y,z; - int size; - SAA_Boolean globalFlag = FALSE; - SAA_Boolean bigEndian; - - if ( verbose >= 1 ) - fprintf( outStream, "\n\nanimating child %s\n", name ); - - SAA_elementGetUserDataSize( scene, skeletonPart, "GLOBAL", &size ); - - if ( size != 0 ) - SAA_elementGetUserData( scene, skeletonPart, "GLOBAL", - sizeof( SAA_Boolean), &bigEndian, (void *)&globalFlag ); - - if ( globalFlag ) - { - if ( verbose >= 1 ) - fprintf( outStream, " using global matrix\n" ); - - // get SAA orientation - SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &p, &h, &r ); - - // get SAA translation - SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &x, &y, &z ); - - // get SAA scaling - SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &i, &j, &k ); - } - else - { - if ( verbose >= 1 ) - fprintf( outStream, "using local matrix\n" ); - - // get SAA orientation - SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &p, &h, &r ); - - // get SAA translation - SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &x, &y, &z ); - - // get SAA scaling - SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &i, &j, &k ); - } - - - if ( verbose >= 2 ) - fprintf( outStream, "\nanim data: %f %f %f\n\t%f %f %f\n\t%f %f %f\n", - i, j, k, h, p, r, x, y, z ); - - // find the appropriate anim table for this skeleton part - AnimGroup *thisGroup; - XfmSAnimTable *thisTable; - - // find the anim table associated with this group - thisGroup = (AnimGroup *)(animRoot->FindDescendent( name )); - if ( verbose >= 2 ) - fprintf( outStream, "\nlooking for anim group %s\n", name ); - if ( thisGroup != NULL ) - { - thisTable = (XfmSAnimTable *)(thisGroup->FindDescendent( "xform" )); - - if ( thisTable != NULL ) - { - thisTable->sub_tables[0].AddElement( i ); - thisTable->sub_tables[1].AddElement( j ); - thisTable->sub_tables[2].AddElement( k ); - thisTable->sub_tables[3].AddElement( p ); - thisTable->sub_tables[4].AddElement( h ); - thisTable->sub_tables[5].AddElement( r ); - thisTable->sub_tables[6].AddElement( x ); - thisTable->sub_tables[7].AddElement( y ); - thisTable->sub_tables[8].AddElement( z ); - } - else - fprintf( outStream, "Couldn't allocate anim table\n" ); - } - else - if ( verbose >= 2 ) - fprintf( outStream, "Couldn't find anim group %s\n", name ); - } - else - { - if ( verbose >= 2 ) - fprintf( outStream, "Cannot build anim table - no skeleton\n" ); - } -} - -/** - * Given a scene, a model , the vertices of its original shape and its name - * find the difference between the geometry of its key shapes and the models - * original geometry and add morph vertices to the egg data to reflect these - * changes. - */ -void soft2egg:: -MakeVertexOffsets( SAA_Scene *scene, SAA_Elem *model, SAA_ModelType type, - int numShapes, int numOrigVert, SAA_DVector *originalVerts, float - matrix[4][4], char *name ) -{ - int i, j; - int offset; - int numCV; - char *mTableName; - SAA_DVector *shapeVerts = NULL; - SAA_DVector *uniqueVerts = NULL; - - if ( (type == SAA_MNSRF) && make_nurbs ) - SAA_nurbsSurfaceSetStep( scene, model, nurbs_step, nurbs_step ); - - SAA_modelGetNbVertices( scene, model, &numCV ); - - // get the shape verts - uniqueVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV); - SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0, - numCV, uniqueVerts ); - - if ( verbose >= 2 ) - fprintf( outStream, "%d CV's\n", numCV ); - - if ( verbose >= 2 ) - { - for ( i = 0; i < numCV; i++ ) - fprintf( outStream, "uniqueVerts[%d] = %f %f %f %f\n", i, - uniqueVerts[i].x, uniqueVerts[i].y, - uniqueVerts[i].z, uniqueVerts[i].w ); - } - - // iterate through for each key shape (except original) - for ( i = 1; i < numShapes; i++ ) - { - mTableName = MakeTableName( name, i ); - - if ( verbose >= 1 ) - { - fprintf( outStream, "\nMaking geometry offsets for %s...\n", - mTableName ); - - if ( (type == SAA_MNSRF) && make_nurbs ) - fprintf( outStream, "calculating NURBS morphs...\n" ); - else - fprintf( outStream, "calculating triangle morphs...\n" ); - } - - // get the shape verts - shapeVerts = (SAA_DVector *)malloc(sizeof(SAA_DVector)*numCV); - SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1, - numCV, shapeVerts ); - - if ( verbose >= 2 ) - { - for ( j=0; j < numCV; j++ ) - { - fprintf( outStream, "shapeVerts[%d] = %f %f %f\n", j, - shapeVerts[j].x, shapeVerts[j].y, shapeVerts[j].z ); - } - } - - // find the appropriate vertex pool - EggVertexPool *vPool = - (EggVertexPool *)(_data.pools.FindName( name )); - - // for every original vertex, compare to the corresponding key shape - // vertex and see if a vertex offset is needed - for ( j=0; j < numOrigVert; j++ ) - { - double dx, dy, dz; - - if ( (type == SAA_MNSRF) && make_nurbs ) - { - // dx = shapeVerts[j].x - - // (originalVerts[j].xoriginalVerts[j].w); dy = - // shapeVerts[j].y - (originalVerts[j].yoriginalVerts[j].w); - // dz = shapeVerts[j].z - - // (originalVerts[j].zoriginalVerts[j].w); - dx = shapeVerts[j].x - originalVerts[j].x; - dy = shapeVerts[j].y - originalVerts[j].y; - dz = shapeVerts[j].z - originalVerts[j].z; - } - else - { - // we need to map from original vertices to triangle shape - // vertices here - offset = findShapeVert( originalVerts[j], uniqueVerts, - numCV ); - - dx = shapeVerts[offset].x - originalVerts[j].x; - dy = shapeVerts[offset].y - originalVerts[j].y; - dz = shapeVerts[offset].z - originalVerts[j].z; - } - - if ( verbose >= 2 ) - { - fprintf( outStream, "oVert[%d] = %f %f %f %f\n", j, - originalVerts[j].x, originalVerts[j].y, - originalVerts[j].z, originalVerts[j].w ); - - if ( (type == SAA_MNSRF) && make_nurbs ) - { - fprintf( outStream, "global shapeVerts[%d] = %f %f %f %f\n", j, shapeVerts[j].x, shapeVerts[j].y, - shapeVerts[j].z, shapeVerts[j].w ); - } - else - { - fprintf( outStream, - "global shapeVerts[%d] = %f %f %f\n", offset, - shapeVerts[offset].x, - shapeVerts[offset].y, - shapeVerts[offset].z ); - } - - fprintf( outStream, "%d: dx = %f, dy = %f, dz = %f\n", j, - dx, dy, dz ); - } - - // if change isn't negligible, make a morph vertex entry - double total = fabs(dx)+fabs(dy)+fabs(dz); - if ( total > 0.00001 ) - { - if ( vPool != NULL ) - { - // create offset - EggMorphOffset *dxyz = - new EggMorphOffset( mTableName, dx, dy, dz ); - - EggVertex *eggVert; - - // get the appropriate egg vertex - eggVert = vPool->Vertex(j); - - // add the offset to the vertex - eggVert->morphs.push_back( *dxyz ); - } - else - fprintf( outStream, "Error: couldn't find vertex pool %s\n", name ); - } // if total - } //for j - } //for i -} - - -/** - * Given a scene, a model, a name and a frame time, determine what type of - * shape interpolation is used and call the appropriate function to extract - * the shape weight info for this frame... - */ -void soft2egg:: -MakeMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, - int numModels, char *name, float time ) -{ - int numShapes; - SAA_AnimInterpType type; - - // Get the number of key shapes - SAA_modelGetNbShapes( scene, model, &numShapes ); - - if ( numShapes > 0 ) - { - if ( verbose >= 1 ) - fprintf( outStream, "MakeMorphTable: %s: num shapes: %d\n", - name, numShapes); - - SAA_modelGetShapeInterpolation( scene, model, &type ); - - if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL ) - { - MakeLinearMorphTable( scene, model, numShapes, name, time ); - } - else // must be weighted... - { - // check first for expressions - MakeExpressionMorphTable( scene, model, models, numModels, - numShapes, name, time ); - } - - } -} - - -/** - * Given a scene, a model, its name, and the time, get the shape fcurve for - * the model and determine the shape weights for the given time and use them - * to populate the morph table. - */ -void soft2egg:: -MakeLinearMorphTable( SAA_Scene *scene, SAA_Elem *model, int numShapes, - char *name, float time ) -{ - int i; - SAA_Elem fcurve; - float curveVal; - SAnimTable *thisTable; - char *tableName; - - if ( verbose >= 1 ) - fprintf( outStream, "linear interp, getting fcurve\n" ); - - SAA_modelFcurveGetShape( scene, model, &fcurve ); - - SAA_fcurveEval( scene, &fcurve, time, &curveVal ); - - if ( verbose >= 2 ) - fprintf( outStream, "at time %f, fcurve for %s = %f\n", time, - name, curveVal ); - - float nextVal = 0.0f; - - // populate morph table values for this frame - for ( i = 1; i < numShapes; i++ ) - { - // derive table name from the model name - tableName = MakeTableName( name, i ); - - if ( verbose >= 2 ) - fprintf( outStream, "Linear: looking for table '%s'\n", tableName ); - - // find the morph table associated with this key shape - thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName )); - - if ( thisTable != NULL ) - { - if ( i == (int)curveVal ) - { - if ( curveVal - i == 0 ) - { - thisTable->AddElement( 1.0f ); - if ( verbose >= 2 ) - fprintf( outStream, "adding element 1.0f\n" ); - } - else - { - thisTable->AddElement( 1.0f - (curveVal - i) ); - nextVal = curveVal - i; - if ( verbose >= 2 ) - fprintf( outStream, "adding element %f\n", 1.0f - (curveVal - i) ); - } - } - else - { - if ( nextVal ) - { - thisTable->AddElement( nextVal ); - nextVal = 0.0f; - if ( verbose >= 2 ) - fprintf( outStream, "adding element %f\n", nextVal ); - } - else - { - thisTable->AddElement( 0.0f ); - if ( verbose >= 2 ) - fprintf( outStream, "adding element 0.0f\n" ); - } - } - - if ( verbose >= 2 ) - fprintf( outStream, " to '%s'\n", tableName ); - } - else - fprintf( outStream, "%d: Couldn't find table '%s'\n", - i, tableName ); - } - -} - -/** - * Given a scene, a model, a list of all models in the scene, the number of - * models in the scece, the number of key shapes for this model, the name of - * the model and the current time, determine what method of controlling the - * shape weights is used and call the appropriate routine. - */ -void soft2egg:: -MakeWeightedMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, - int numModels, int numShapes, char *name, float time ) -{ - SI_Error result; - SAA_Elem *weightCurves; - float curveVal; - SAnimTable *thisTable; - char *tableName; - - // allocate array of weight curves (one for each shape) - weightCurves = ( SAA_Elem *)malloc( sizeof( SAA_Elem ) * numShapes ); - - result = SAA_modelFcurveGetShapeWeights( - scene, model, numShapes, weightCurves ); - - if ( result == SI_SUCCESS ) - { - for ( int i = 1; i < numShapes; i++ ) - { - SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal ); - - // make sure soft gave us a - // reasonable number - if (!isNum(curveVal)) - curveVal = 0.0f; - - if ( verbose >= 2 ) - fprintf( outStream, "at time %f, weightCurve[%d] for %s = %f\n", time, i, name, curveVal ); - - - // derive table name from the model name - tableName = MakeTableName( name, i ); - - // find and populate shape - // table - if ( verbose >= 2 ) - fprintf( outStream, "Weight: looking for table '%s'\n", - tableName ); - - // find the morph table associated with this key shape - thisTable = (SAnimTable *)(morphRoot->FindDescendent( tableName )); - - if ( thisTable != NULL ) - { - thisTable->AddElement( curveVal ); - if ( verbose >= 2 ) - fprintf( outStream, "adding element %f\n", curveVal ); - } - else - fprintf( outStream, "%d: Couldn't find table '%s'\n", - i, tableName ); - } - } -} - - -/** - * Given a scene, a model and its number of key shapes generate a morph table - * describing transitions btwn the key shapes by evaluating the positions of - * the controlling sliders. - */ -void soft2egg:: -MakeExpressionMorphTable( SAA_Scene *scene, SAA_Elem *model, SAA_Elem *models, - int numModels, int numShapes, char *name, float time ) -{ - int j; - SAnimTable *thisTable; - char *tableName; - char *sliderName; - char *track; - int numExp; - SAA_Elem *expressions; - float expVal; - float sliderVal; - - // populate morph table values for this frame - - // compose track name - track = NULL; - - // find how many expressions for this shape - SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp ); - - if ( verbose >= 2 ) - fprintf( outStream, "%s has %d RHS expressions\n", name, numExp ); - - if ( numExp ) - { - // get the expressions for this shape - expressions = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numExp); - - if ( verbose >= 1 ) - fprintf( outStream, "getting %d RHS expressions...\n", numExp ); - - result = SAA_elementGetExpressions( scene, model, track, FALSE, - numExp, expressions ); - - if ( !result ) - { - for ( j = 1; j < numExp; j++ ) - { - if ( verbose >= 2 ) - { - // debug see what we got - int numvars; - - SAA_expressionGetNbVars( scene, &expressions[j], &numvars ); - - int *varnamelen; - int *varstrlen; - int expstrlen; - - varnamelen = (int *)malloc(sizeof(int)*numvars); - varstrlen = (int *)malloc(sizeof(int)*numvars); - - SAA_expressionGetStringLengths( scene, &expressions[j], - numvars, varnamelen, varstrlen, &expstrlen ); - - int *varnamesizes; - int *varstrsizes; - - varnamesizes = (int *)malloc(sizeof(int)*numvars); - varstrsizes = (int *)malloc(sizeof(int)*numvars); - - for ( int k = 0; k < numvars; k++ ) - { - varnamesizes[k] = varnamelen[k] + 1; - varstrsizes[k] = varstrlen[k] + 1; - } - - int expstrsize = expstrlen + 1; - - char **varnames; - char **varstrs; - - varnames = (char **)malloc(sizeof(char *)*numvars); - varstrs = (char **)malloc(sizeof(char *)*numvars); - - for ( k = 0; k < numvars; k++ ) - { - varnames[k] = (char *)malloc(sizeof(char)* - varnamesizes[k]); - - varstrs[k] = (char *)malloc(sizeof(char)* - varstrsizes[k]); - } - - char *expstr = (char *)malloc(sizeof(char)* expstrsize ); - - SAA_expressionGetStrings( scene, &expressions[j], numvars, - varnamesizes, varstrsizes, expstrsize, varnames, - varstrs, expstr ); - - if ( verbose >= 2 ) - { - fprintf( outStream, "expression = '%s'\n", expstr ); - fprintf( outStream, "has %d variables\n", numvars ); - } - } //if verbose - - if ( verbose >= 2 ) - fprintf( outStream, "evaling expression...\n" ); - - SAA_expressionEval( scene, &expressions[j], time, &expVal ); - - if ( verbose >= 2 ) - fprintf( outStream, "time %f: exp val %f\n", - time, expVal ); - - // derive table name from the model name - tableName = MakeTableName( name, j ); - - if ( verbose >= 2 ) - fprintf( outStream, "Exp: looking for table '%s'\n", - tableName ); - - // find the morph table associated with this key shape - thisTable = (SAnimTable *) - (morphRoot->FindDescendent( tableName )); - - if ( thisTable != NULL ) - { - thisTable->AddElement( expVal ); - if ( verbose >= 1 ) - fprintf( outStream, "%d: adding element %f to %s\n", - j, expVal, tableName ); - fflush( outStream ); - } - else - { - fprintf( outStream, "%d: Couldn't find table '%s'", j, - tableName ); - - fprintf( outStream, " for value %f\n", expVal ); - } - } - } - else - fprintf( outStream, "couldn't get expressions!!!\n" ); - } - else - // no expression, use weight curves - MakeWeightedMorphTable( scene, model, models, numModels, - numShapes, name, time ); - -} - - -/** - * Given a scene, a POLYGON model, and the name of the that model, get the u - * and v offsets for the current frame. - */ -void soft2egg:: -MakeTexAnim( SAA_Scene *scene, SAA_Elem *model, char *modelName ) -{ - if ( verbose >= 1 ) - fprintf( outStream, "\n\nmaking texture animation for %s...\n", - modelName ); - - // get the color of the surface - int numMats; - pfVec4 Color; - SAA_Elem *materials; - void *relinfo; - - SAA_modelRelationGetMatNbElements( scene, model, FALSE, &relinfo, - &numMats ); - - if ( verbose >= 2 ) - fprintf( outStream, "surface has %d materials\n", numMats ); - - if ( numMats ) - { - float r,g,b,a; - - materials = (SAA_Elem *)malloc(sizeof(SAA_Elem)*numMats); - - SAA_modelRelationGetMatElements( scene, model, relinfo, - numMats, materials ); - - SAA_materialGetDiffuse( scene, &materials[0], &r, &g, &b ); - SAA_materialGetTransparency( scene, &materials[0], &a ); - Color.set( r, g, b, 1.0f - a ); - - int numTexLoc = 0; - int numTexGlb = 0; - - // ASSUME only one texture per material - SAA_Elem tex; - - // find out how many local textures per surface ASSUME it only has one - // material - SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], - FALSE, &relinfo, &numTexLoc ); - - // if present, get local textures - if ( numTexLoc ) - { - if ( verbose >= 1 ) - fprintf( outStream, "%s had %d local tex\n", modelName, - numTexLoc ); - - // get the referenced texture - SAA_materialRelationGetT2DLocElements( scene, &materials[0], - TEX_PER_MAT, &tex ); - - } - // if no locals, try to get globals - else - { - SAA_modelRelationGetT2DGlbNbElements( scene, model, - FALSE, &relinfo, &numTexGlb ); - - if ( numTexGlb ) - { - if ( verbose >= 1 ) - fprintf( outStream, "%s had %d global tex\n", modelName, numTexGlb ); - - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, - model, TEX_PER_MAT, &tex ); - } - } - - // add tex ref's if we found any textures - if ( numTexLoc || numTexGlb) - { - char *fullTexName = NULL; - char *texName = NULL; - char *uniqueTexName = NULL; - int texNameLen; - - // get its name - SAA_texture2DGetPicNameLength( scene, &tex, &texNameLen); - fullTexName = (char *)malloc(sizeof(char)*++texNameLen); - SAA_texture2DGetPicName( scene, &tex, texNameLen, - fullTexName ); - - // append unique identifier to texname for this particular object - uniqueTexName = (char *)malloc(sizeof(char)* - (strlen(modelName)+strlen(texName)+3) ); - sprintf( uniqueTexName, "%s-%s", modelName, texName ); - if ( verbose >= 2 ) - fprintf( outStream, "referencing tref %s\n", - uniqueTexName ); - - float uScale; - float vScale; - float uOffset; - float vOffset; - SAA_Boolean uv_swap = FALSE; - - // get texture offset info - SAA_texture2DGetUScale( scene, &tex, &uScale ); - SAA_texture2DGetVScale( scene, &tex, &vScale ); - SAA_texture2DGetUOffset( scene, &tex, &uOffset ); - SAA_texture2DGetVOffset( scene, &tex, &vOffset ); - SAA_texture2DGetUVSwap( scene, &tex, &uv_swap ); - - - if ( verbose >= 2 ) - { - fprintf( outStream, "tex uScale: %f\n", uScale ); - fprintf( outStream, "tex vScale: %f\n", vScale ); - fprintf( outStream, "tex uOffset: %f\n", uOffset ); - fprintf( outStream, "tex vOffset: %f\n", vOffset ); - if ( uv_swap ) - fprintf( outStream, "nurbTex u & v swapped!\n" ); - else - fprintf( outStream, "nurbTex u & v NOT swapped\n" ); - } - - - // find the vpool for this model - EggVertexPool *vPool = - (EggVertexPool *)(_data.pools.FindName( modelName )); - - // if we found the pool - if ( vPool != NULL ) - { - // generate duv's for model - float oldOffsets[4]; - double u, v, du, dv; - int size; - SAA_Boolean bigEndian; - - SAA_elementGetUserDataSize( scene, model, "TEX_OFFSETS", &size ); - - if ( size != 0 ) - { - // remember original texture offsets future reference - SAA_elementGetUserData( scene, model, "TEX_OFFSETS", - size, &bigEndian, (void *)&oldOffsets ); - - // get the original scales and offsets - u = oldOffsets[0]; - v = oldOffsets[1]; - - du = u - uOffset; - dv = v - vOffset; - - if ( verbose >= 1 ) - { - fprintf( outStream, "original u = %f, v = %f\n", - u, v ); - fprintf( outStream, "u = %f, v = %f\n", - uOffset, vOffset ); - fprintf( outStream, "du = %f, dv = %f\n", - du, dv ); - } - - strstream uName, vName; - - // create duv target names - uName << modelName << ".u" << ends; - vName << modelName << ".v" << ends; - - // find the appropriate table to store the duv animation - // info into - SAnimTable *thisTable; - - // find the duv U table associated with this model - thisTable = (SAnimTable *)(morphRoot->FindDescendent( - uName.str() )); - - if ( thisTable != NULL ) - { - thisTable->AddElement( du ); - if ( verbose >= 1 ) - fprintf( outStream, "adding element %f to %s\n", - du, uName.str() ); - } - else - fprintf( outStream, "Couldn't find uTable %s\n", - uName.str() ); - - // find the duv V table associated with this model - thisTable = (SAnimTable *)(morphRoot->FindDescendent( - vName.str() )); - - if ( thisTable != NULL ) - { - thisTable->AddElement( dv ); - if ( verbose >= 1 ) - fprintf( outStream, "adding element %f to %s\n", - dv, uName.str() ); - } - else - fprintf( outStream, "Couldn't find vTable %s\n", - uName.str() ); - } - } - else - if ( verbose >= 2 ) - fprintf( outStream, "Couldn't find vpool %s\n", modelName ); - } - - // free( materials ); - } -} -#endif - -/** - * Instantiate converter and process a file - */ -EXPCL_MISC SI_Error soft2egg(int argc, char *argv[]) { - // pass control to the c++ system - init_soft2egg(argc, argv); - return SI_SUCCESS; -} -#ifdef __cplusplus -} -#endif diff --git a/pandatool/src/softegg/softEggGroupUserData.I b/pandatool/src/softegg/softEggGroupUserData.I deleted file mode 100644 index c6d2a5082c..0000000000 --- a/pandatool/src/softegg/softEggGroupUserData.I +++ /dev/null @@ -1,44 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softEggGroupUserData.I - * @author masad - * @date 2003-09-25 - */ - -/** - * - */ -INLINE SoftEggGroupUserData:: -SoftEggGroupUserData() { - _vertex_color = false; - _double_sided = false; -} - - -/** - * - */ -INLINE SoftEggGroupUserData:: -SoftEggGroupUserData(const SoftEggGroupUserData ©) : - EggUserData(copy), - _vertex_color(copy._vertex_color), - _double_sided(copy._double_sided) -{ -} - - -/** - * - */ -INLINE void SoftEggGroupUserData:: -operator = (const SoftEggGroupUserData ©) { - EggUserData::operator = (copy); - _vertex_color = copy._vertex_color; - _double_sided = copy._double_sided; -} diff --git a/pandatool/src/softegg/softEggGroupUserData.cxx b/pandatool/src/softegg/softEggGroupUserData.cxx deleted file mode 100644 index 1705b2b285..0000000000 --- a/pandatool/src/softegg/softEggGroupUserData.cxx +++ /dev/null @@ -1,16 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softEggGroupUserData.cxx - * @author masad - * @date 2003-09-25 - */ - -#include "softEggGroupUserData.h" - -TypeHandle SoftEggGroupUserData::_type_handle; diff --git a/pandatool/src/softegg/softEggGroupUserData.h b/pandatool/src/softegg/softEggGroupUserData.h deleted file mode 100644 index b8aa6ca892..0000000000 --- a/pandatool/src/softegg/softEggGroupUserData.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softEggGroupUserData.h - * @author masad - * @date 2003-09-25 - */ - -#ifndef SOFTEGGGROUPUSERDATA_H -#define SOFTEGGGROUPUSERDATA_H - -#include "pandatoolbase.h" -#include "eggUserData.h" - -/** - * This class contains extra user data which is piggybacked onto EggGroup - * objects for the purpose of the softimage converter. - */ -class SoftEggGroupUserData : public EggUserData { -public: - INLINE SoftEggGroupUserData(); - INLINE SoftEggGroupUserData(const SoftEggGroupUserData ©); - INLINE void operator = (const SoftEggGroupUserData ©); - - bool _vertex_color; - bool _double_sided; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - EggUserData::init_type(); - register_type(_type_handle, "SoftEggGroupUserData", - EggUserData::get_class_type()); - } - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - -private: - static TypeHandle _type_handle; -}; - -#include "softEggGroupUserData.I" - -#endif diff --git a/pandatool/src/softegg/softNodeDesc.cxx b/pandatool/src/softegg/softNodeDesc.cxx deleted file mode 100644 index ff0f624a20..0000000000 --- a/pandatool/src/softegg/softNodeDesc.cxx +++ /dev/null @@ -1,1310 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softNodeDesc.cxx - * @author masad - * @date 2003-10-03 - */ - -#include "softNodeDesc.h" -#include "config_softegg.h" -#include "eggGroup.h" -#include "eggXfmSAnim.h" -#include "eggSAnimData.h" -#include "softToEggConverter.h" -#include "dcast.h" - -using std::endl; - -TypeHandle SoftNodeDesc::_type_handle; - -/** - * - */ -SoftNodeDesc:: -SoftNodeDesc(SoftNodeDesc *parent, const std::string &name) : - Namable(name), - _parent(parent) -{ - _model = nullptr; - _egg_group = nullptr; - _egg_table = nullptr; - _anim = nullptr; - _joint_type = JT_none; - - // Add ourselves to our parent. - if (_parent != nullptr) { - softegg_cat.spam() << "parent name " << _parent->get_name(); - _parent->_children.push_back(this); - } - - // set the _parentJoint to Null - _parentJoint = nullptr; - - fullname = nullptr; - - numTexLoc = 0; - numTexGlb = 0; - - uScale = nullptr; - vScale = nullptr; - uOffset = nullptr; - vOffset = nullptr; - - valid; - uv_swap; - // SAA_Boolean visible; - numTexTri = nullptr; - textures = nullptr; - materials = nullptr; - triangles = nullptr; - gtype = SAA_GEOM_ORIGINAL; -} - -/** - * - */ -SoftNodeDesc:: -~SoftNodeDesc() { - // I think it is a mistake to try to delete this. This was one member of an - // entire array allocated at once; you can't delete individual elements of - // an array. - - // Screw cleanup, anyway--we'll just let the array leak. - /* - if (_model != (SAA_Elem *)NULL) { - delete _model; - } - */ -} - -/** - * Indicates an associated between the SoftNodeDesc and some SAA_Elem - * instance. - */ -void SoftNodeDesc:: -set_model(SAA_Elem *model) { - _model = model; -} - -/** - * Sometimes, parent is not known at node creation As soon as it is known, set - * the parent - */ -void SoftNodeDesc:: -set_parent(SoftNodeDesc *parent) { - if (_parent) { - softegg_cat.spam() << endl; - /* - softegg_cat.spam() << " expected _parent to be null!?\n"; - if (_parent == parent) - softegg_cat.spam() << " parent already set\n"; - else { - softegg_cat.spam() << " current parent " << _parent->get_name() << " new parent " - << parent << endl; - } - */ - return; - } - _parent = parent; - softegg_cat.spam() << " set parent to " << _parent->get_name() << endl; - - // Add ourselves to our parent. - _parent->_children.push_back(this); -} - -/** - * Sometimes, parent is not known at node creation As soon as it is known, set - * the parent - */ -void SoftNodeDesc:: -force_set_parent(SoftNodeDesc *parent) { - if (_parent) - softegg_cat.spam() << " current parent " << _parent->get_name(); - - _parent = parent; - - if (_parent) - softegg_cat.spam() << " new parent " << _parent->get_name() << endl; - - // Add ourselves to our parent. - _parent->_children.push_back(this); -} - -/** - * Returns true if a Soft dag path has been associated with this node, false - * otherwise. - */ -bool SoftNodeDesc:: -has_model() const { - return (_model != nullptr); -} - -/** - * Returns the SAA_Elem * associated with this node. It is an error to call - * this unless has_model() returned true. - */ -SAA_Elem *SoftNodeDesc:: -get_model() const { - nassertr(_model != nullptr, _model); - return _model; -} - -/** - * Returns true if the node should be treated as a joint by the converter. - */ -bool SoftNodeDesc:: -is_joint() const { - // return _joint_type == JT_joint || _joint_type == JT_pseudo_joint; - return _joint_type == JT_joint; -} - -/** - * Returns true if the node should be treated as a junk by the converter. - */ -bool SoftNodeDesc:: -is_junk() const { - return _joint_type == JT_junk; -} - -/** - * sets the _joint_type to JT_joint - */ -void SoftNodeDesc:: -set_joint() { - _joint_type = JT_joint; -} -/** - * Returns true if the node is the parent or ancestor of a joint. - */ -bool SoftNodeDesc:: -is_joint_parent() const { - return _joint_type == JT_joint_parent; -} - -/** - * Recursively clears the egg pointers from this node and all children. - */ -void SoftNodeDesc:: -clear_egg() { - _egg_group = nullptr; - _egg_table = nullptr; - _anim = nullptr; - - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - child->clear_egg(); - } -} - -/** - * Indicates that this node has at least one child that is a joint or a - * pseudo-joint. - */ -void SoftNodeDesc:: -mark_joint_parent() { - if (_joint_type == JT_none) { - _joint_type = JT_joint_parent; - softegg_cat.spam() << " marked parent " << get_name(); - } - else - softegg_cat.spam() << " ?parent " << get_name() << " joint type " << _joint_type; - - if (_parent != nullptr) { - _parent->mark_joint_parent(); - } - softegg_cat.spam() << endl; -} - -/** - * Walks the hierarchy, if a node is joint, make sure all its parents are - * marked JT_joint_parent - */ -void SoftNodeDesc:: -check_joint_parent() { - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - if (child->is_joint()) { - softegg_cat.spam() << "child " << child->get_name(); - mark_joint_parent(); - } - child->check_joint_parent(); - } -} - -/** - * check to see if this is a branch we don't want to descend - this will - * prevent creating geometry for animation control structures - */ -void SoftNodeDesc:: -check_junk(bool parent_junk) { - const char *name = get_name().c_str(); - - if (parent_junk) { - _joint_type = JT_junk; - softegg_cat.spam() << "junk node " << get_name() << endl; - } - if ( (strstr(name, "con-") != nullptr) || - (strstr(name, "con_") != nullptr) || - (strstr(name, "fly_") != nullptr) || - (strstr(name, "fly-") != nullptr) || - (strstr(name, "camRIG") != nullptr) || - (strstr(name, "cam_rig") != nullptr) || - (strstr(name, "bars") != nullptr) ) - { - _joint_type = JT_junk; - softegg_cat.spam() << "junk node " << get_name() << endl; - parent_junk = true; - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - softegg_cat.spam() << child->get_name() << ","; - } - softegg_cat.spam() << endl; - } - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - child->check_junk(parent_junk); - } -} - -/** - * check to see if this is a selected branch we want to descend - this will - * prevent creating geometry for other parts - */ -bool SoftNodeDesc:: -is_partial(char *search_prefix) { - const char *name = fullname; - - // if no search prefix then return false - if (!search_prefix) - return false; - // if name is search_prefix, return false - if (strstr(name, search_prefix) != nullptr) { - softegg_cat.debug() << "matched " << name << " "; - return false; - } - // if name is not search_prefix, look in its parent - if (strstr(name, search_prefix) == nullptr) { - softegg_cat.debug() << "node " << name << " "; - if (_parent) - return _parent->is_partial(search_prefix); - } - // neither name nor its parent is search_prefix - return true; -} - -/** - * Go through the ancestors and figure out who is the immediate _parentJoint - * of this node - */ -void SoftNodeDesc:: -set_parentJoint(SAA_Scene *scene, SoftNodeDesc *lastJoint) { - if (is_junk()) - return; - // set its parent joint to the lastJoint - _parentJoint = lastJoint; - softegg_cat.spam() << get_name() << ": parent joint set to :" << lastJoint; - if (lastJoint) - softegg_cat.spam() << "(" << lastJoint->get_name() << ")"; - softegg_cat.spam() << endl; - - // is this node a joint? - SAA_Boolean isSkeleton = false; - if (has_model()) - SAA_modelIsSkeleton( scene, get_model(), &isSkeleton ); - - // if already a joint or name has "joint" in it - const char *name = get_name().c_str(); - if (is_joint() || isSkeleton || strstr(name, "joint") != nullptr) { - lastJoint = this; - } - if ( _parentJoint && strstr( _parentJoint->get_name().c_str(), "scale" ) != nullptr ) { - // make sure _parentJoint didn't have the name "joint" in it - if (strstr(_parentJoint->get_name().c_str(), "joint") == nullptr) { - _parentJoint = nullptr; - // _parentJoint = lastJoint = NULL; - softegg_cat.spam() << "scale joint flag set!\n"; - } - } - - // look in the children - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - child->set_parentJoint(scene, lastJoint); - } -} - -/** - * Walks the hierarchy, looking for non-joint nodes that are both children and - * parents of a joint. These nodes are deemed to be pseudo joints, since the - * converter must treat them as joints. - */ -void SoftNodeDesc:: -check_pseudo_joints(bool joint_above) { - if (_joint_type == JT_joint_parent && joint_above) { - // This is one such node: it is the parent of a joint (JT_joint_parent is - // set), and it is the child of a joint (joint_above is set). - _joint_type = JT_pseudo_joint; - softegg_cat.debug() << "pseudo " << get_name() << " case1\n"; - } - - if (_joint_type == JT_joint) { - // If this node is itself a joint, then joint_above is true for all child - // nodes. - joint_above = true; - } - - // Don't bother traversing further if _joint_type is none or junk, since - // that means this node has no joint children. - if (_joint_type != JT_none && _joint_type != JT_junk) { - - bool any_joints = false; - Children::const_iterator ci; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - child->check_pseudo_joints(joint_above); - if (child->is_joint()) { - softegg_cat.spam() << get_name() << " any_joint true by " << child->get_name() << endl; - any_joints = true; - } - } - - // If any children qualify as joints, then any sibling nodes that are - // parents of joints are also elevated to joints. - if (any_joints) { - bool all_joints = true; - for (ci = _children.begin(); ci != _children.end(); ++ci) { - SoftNodeDesc *child = (*ci); - if (child->_joint_type == JT_joint_parent) { - child->_joint_type = JT_pseudo_joint; - softegg_cat.debug() << "pseudo " << child->get_name() << " case2 by parent " << get_name() << "\n"; - } else if (child->_joint_type == JT_none || child->_joint_type == JT_junk) { - all_joints = false; - } - } - - if (all_joints || any_joints) { - // Finally, if all children or at least one is a joint, then we are - // too. - if (_joint_type == JT_joint_parent) { - _joint_type = JT_pseudo_joint; - softegg_cat.debug() << "pseudo " << get_name() << " case3\n"; - } - } - } - } - else - softegg_cat.spam() << "found null joint " << get_name() << endl; -} - -/** - * Extracts the transform on the indicated Soft node, and applies it to the - * corresponding Egg node. - */ -void SoftNodeDesc:: -get_transform(SAA_Scene *scene, EggGroup *egg_group, bool global) { - // Get the model's matrix - int scale_joint = 0; - - if (!global && _parentJoint && !stec.flatten && !scale_joint) { - - SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_LOCAL, matrix ); - softegg_cat.debug() << get_name() << " using local matrix :parent "; - - } else { - - SAA_modelGetMatrix( scene, get_model(), SAA_COORDSYS_GLOBAL, matrix ); - softegg_cat.debug() << get_name() << " using global matrix :parent "; - - } - - if (_parentJoint && !stec.flatten) - softegg_cat.debug() << _parentJoint->get_name() << endl; - else - softegg_cat.debug() << _parentJoint << endl; - - - softegg_cat.spam() << "model matrix = " << matrix[0][0] << " " << matrix[0][1] << " " << matrix[0][2] << " " << matrix[0][3] << "\n"; - softegg_cat.spam() << "model matrix = " << matrix[1][0] << " " << matrix[1][1] << " " << matrix[1][2] << " " << matrix[1][3] << "\n"; - softegg_cat.spam() << "model matrix = " << matrix[2][0] << " " << matrix[2][1] << " " << matrix[2][2] << " " << matrix[2][3] << "\n"; - softegg_cat.spam() << "model matrix = " << matrix[3][0] << " " << matrix[3][1] << " " << matrix[3][2] << " " << matrix[3][3] << "\n"; - - if (!global && is_joint()) { - LMatrix4d m4d(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3], - matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3], - matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3], - matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]); - if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) { - egg_group->set_transform3d(m4d); - softegg_cat.spam() << "set transform in egg_group\n"; - } - } - return; -} - -/** - * Extracts the transform on the indicated Soft node, as appropriate for a - * joint in an animated character, and applies it to the indicated node. This - * is different from get_transform() in that it does not respect the - * _transform_type flag, and it does not consider the relative transforms - * within the egg file. more added functionality: now fills in components of - * anim (EffXfmSAnim) class (masad). - */ -void SoftNodeDesc:: -get_joint_transform(SAA_Scene *scene, EggGroup *egg_group, EggXfmSAnim *anim, bool global) { - // SI_Error result; - SAA_Elem *skeletonPart = _model; - const char *name = get_name().c_str(); - - if ( skeletonPart != nullptr ) { - PN_stdfloat i,j,k; - PN_stdfloat h,p,r; - PN_stdfloat x,y,z; - int scale_joint = 0; - - softegg_cat.spam() << "\n\nanimating child " << name << endl; - - if (_parentJoint && !stec.flatten && !scale_joint ) { - softegg_cat.debug() << "using local matrix\n"; - - // get SAA orientation - SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &p, &h, &r ); - - // get SAA translation - SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &x, &y, &z ); - - // get SAA scaling - SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_LOCAL, - &i, &j, &k ); - } else { - softegg_cat.debug() << " using global matrix\n"; - - // get SAA orientation - SAA_modelGetRotation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &p, &h, &r ); - - // get SAA translation - SAA_modelGetTranslation( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &x, &y, &z ); - - // get SAA scaling - SAA_modelGetScaling( scene, skeletonPart, SAA_COORDSYS_GLOBAL, - &i, &j, &k ); - } - - softegg_cat.spam() << "\nanim data: " << i << " " << j << " " << k << endl; - softegg_cat.spam() << "\t" << p << " " << h << " " << r << endl; - softegg_cat.spam() << "\t" << x << " " << y << " " << z << endl; - - // Encode the component multiplication ordering in the egg file. - // SoftImage always uses this order, regardless of the setting of temp- - // hpr-fix. - anim->set_order("sphrt"); - - // Add each component by their names - anim->add_component_data("i", i); - anim->add_component_data("j", j); - anim->add_component_data("k", k); - anim->add_component_data("p", p); - anim->add_component_data("h", h); - anim->add_component_data("r", r); - anim->add_component_data("x", x); - anim->add_component_data("y", y); - anim->add_component_data("z", z); - } - else { - softegg_cat.debug() << "Cannot build anim table - no skeleton\n"; - } -} - -/** - * Converts the indicated Soft polyset to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void SoftNodeDesc:: -load_poly_model(SAA_Scene *scene, SAA_ModelType type) { - SI_Error result; - const char *name = get_name().c_str(); - - int i; - int id = 0; - - // if making a pose - get deformed geometry - if ( stec.make_pose ) - gtype = SAA_GEOM_DEFORMED; - - // If the model is a PATCH in soft, set its step before tesselating - else if ( type == SAA_MPTCH ) - SAA_patchSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step ); - - // Get the number of triangles - result = SAA_modelGetNbTriangles( scene, _model, gtype, id, &numTri); - softegg_cat.spam() << "triangles: " << numTri << "\n"; - - if ( result != SI_SUCCESS ) { - softegg_cat.spam() << "Error: couldn't get number of triangles!\n"; - softegg_cat.debug() << "\tbailing on model: " << name << "\n"; - return; - } - - // check to see if surface is also skeleton... - SAA_Boolean isSkeleton = FALSE; - - SAA_modelIsSkeleton( scene, _model, &isSkeleton ); - - // check to see if this surface is used as a skeleton or is animated via - // constraint only ( these nodes are tagged by the animator with the keyword - // "joint" somewhere in the nodes name) - softegg_cat.spam() << "is Skeleton? " << isSkeleton << "\n"; - - /*************************************************************************************/ - - // model is not a null and has no triangles! - if ( !numTri ) { - softegg_cat.spam() << "no triangles!\n"; - } - else { - // allocate array of triangles - triangles = (SAA_SubElem *) new SAA_SubElem[numTri]; - if (!triangles) { - softegg_cat.info() << "Not enough Memory for triangles...\n"; - exit(1); - } - // triangulate model and read the triangles into array - SAA_modelGetTriangles( scene, _model, gtype, id, numTri, triangles ); - softegg_cat.spam() << "got triangles\n"; - - /***********************************************************************************/ - - // allocate array of materials (Asad: it gives a warning if try to get one - // triangle at a time...investigate later read each triangle's material - // into array - materials = (SAA_Elem*) new SAA_Elem[numTri]; - SAA_triangleGetMaterials( scene, _model, numTri, triangles, materials ); - if (!materials) { - softegg_cat.info() << "Not enough Memory for materials...\n"; - exit(1); - } - softegg_cat.spam() << "got materials\n"; - - /***********************************************************************************/ - - // allocate array of textures per triangle - numTexTri = new int[numTri]; - const void *relinfo; - - // find out how many local textures per triangle - for (i = 0; i < numTri; i++) { - result = SAA_materialRelationGetT2DLocNbElements( scene, &materials[i], FALSE, - &relinfo, &numTexTri[i] ); - // polytex - if ( result == SI_SUCCESS ) - numTexLoc += numTexTri[i]; - } - - // don't need this anymore... free( numTexTri ); - - // get local textures if present - if ( numTexLoc ) { - softegg_cat.spam() << "numTexLoc = " << numTexLoc << endl; - - // allocate arrays of texture info - uScale = new PN_stdfloat[numTri]; - vScale = new PN_stdfloat[numTri]; - uOffset = new PN_stdfloat[numTri]; - vOffset = new PN_stdfloat[numTri]; - texNameArray = new char *[numTri]; - uRepeat = new int[numTri]; - vRepeat = new int[numTri]; - - // ASSUME only one texture per material - textures = new SAA_Elem[numTri]; - - for ( i = 0; i < numTri; i++ ) { - // and read all referenced local textures into array - SAA_materialRelationGetT2DLocElements( scene, &materials[i], - TEX_PER_MAT , &textures[i] ); - - // initialize the array value - texNameArray[i] = nullptr; - // initialize the repeats - uRepeat[i] = vRepeat[i] = 0; - - // see if this triangle has texture info - if (numTexTri[i] == 0) - continue; - - // check to see if texture is present - result = SAA_elementIsValid( scene, &textures[i], &valid ); - - if ( result != SI_SUCCESS ) - softegg_cat.spam() << "SAA_elementIsValid failed!!!!\n"; - - // texture present - get the name and uv info - if ( valid ) { - // according to drose, we don't need to convert .pic files to .rgb, - // panda can now read the .pic files. - texNameArray[i] = stec.GetTextureName(scene, &textures[i]); - - softegg_cat.spam() << " tritex[" << i << "] named: " << texNameArray[i] << endl; - - SAA_texture2DGetUVSwap( scene, &textures[i], &uv_swap ); - - if ( uv_swap == TRUE ) - softegg_cat.spam() << " swapping u and v...\n" ; - - SAA_texture2DGetUScale( scene, &textures[i], &uScale[i] ); - SAA_texture2DGetVScale( scene, &textures[i], &vScale[i] ); - SAA_texture2DGetUOffset( scene, &textures[i], &uOffset[i] ); - SAA_texture2DGetVOffset( scene, &textures[i], &vOffset[i] ); - - softegg_cat.spam() << "tritex[" << i << "] uScale: " << uScale[i] << " vScale: " << vScale[i] << endl; - softegg_cat.spam() << " uOffset: " << uOffset[i] << " vOffset: " << vOffset[i] << endl; - - SAA_texture2DGetRepeats( scene, &textures[i], &uRepeat[i], &vRepeat[i] ); - softegg_cat.spam() << "uRepeat = " << uRepeat[i] << ", vRepeat = " << vRepeat[i] << endl; - } - else { - softegg_cat.spam() << "Invalid texture...\n"; - softegg_cat.spam() << " tritex[" << i << "] named: (null)\n"; - } - } - } - else { // if no local textures, try to get global textures - SAA_modelRelationGetT2DGlbNbElements( scene, _model, - FALSE, &relinfo, &numTexGlb ); - if ( numTexGlb ) { - // ASSUME only one texture per model - textures = new SAA_Elem; - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, _model, - TEX_PER_MAT, textures ); - softegg_cat.spam() << "numTexGlb = " << numTexGlb << endl; - // check to see if texture is present - SAA_elementIsValid( scene, textures, &valid ); - if ( valid ) { // texture present - get the name and uv info - SAA_texture2DGetUVSwap( scene, textures, &uv_swap ); - - if ( uv_swap == TRUE ) - softegg_cat.spam() << " swapping u and v...\n"; - - // according to drose, we don't need to convert .pic files to .rgb, - // panda can now read the .pic files. - texNameArray = new char *[1]; - *texNameArray = stec.GetTextureName(scene, textures); - - uRepeat = new int; - vRepeat = new int; - - softegg_cat.spam() << " global tex named: " << *texNameArray << endl; - - // allocate arrays of texture info - uScale = new PN_stdfloat; - vScale = new PN_stdfloat; - uOffset = new PN_stdfloat; - vOffset = new PN_stdfloat; - - SAA_texture2DGetUScale( scene, textures, uScale ); - SAA_texture2DGetVScale( scene, textures, vScale ); - SAA_texture2DGetUOffset( scene, textures, uOffset ); - SAA_texture2DGetVOffset( scene, textures, vOffset ); - - softegg_cat.spam() << " global tex uScale: " << *uScale << " vScale: " << *vScale << endl; - softegg_cat.spam() << " uOffset: " << *uOffset << " vOffset: " << *vOffset << endl; - - SAA_texture2DGetRepeats( scene, textures, uRepeat, vRepeat ); - softegg_cat.spam() << "uRepeat = " << *uRepeat << ", vRepeat = " << *vRepeat << endl; - } - else { - softegg_cat.spam() << "Invalid Texture...\n"; - } - } - } - } - softegg_cat.spam() << "got textures" << endl; -} - -/** - * Converts the indicated Soft polyset to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void SoftNodeDesc:: -load_nurbs_model(SAA_Scene *scene, SAA_ModelType type) { - SI_Error result; - const char *name = get_name().c_str(); - - // if making a pose - get deformed geometry - if ( stec.make_pose ) - gtype = SAA_GEOM_DEFORMED; - - // If the model is a NURBS in soft, set its step before tesselating - if ( type == SAA_MNSRF ) - SAA_nurbsSurfaceSetStep( scene, _model, stec.nurbs_step, stec.nurbs_step ); - - // get the materials - /***********************************************************************************/ - const void *relinfo; - - SAA_modelRelationGetMatNbElements( scene, get_model(), FALSE, &relinfo, - &numNurbMats ); - - softegg_cat.spam() << "nurbs surf has " << numNurbMats << " materials\n"; - - if ( numNurbMats ) { - materials = new SAA_Elem[numNurbMats]; - if (!materials) { - softegg_cat.info() << "Out Of Memory on allocating materials\n"; - exit(1); - } - - SAA_modelRelationGetMatElements( scene, get_model(), relinfo, - numNurbMats, materials ); - - softegg_cat.spam() << "got materials\n"; - - // get the textures - /***********************************************************************************/ - numNurbTexLoc = 0; - numNurbTexGlb = 0; - - // find out how many local textures per NURBS surface ASSUME it only has - // one material - SAA_materialRelationGetT2DLocNbElements( scene, &materials[0], FALSE, &relinfo, &numNurbTexLoc ); - - // if present, get local textures - if ( numNurbTexLoc ) { - softegg_cat.spam() << name << " had " << numNurbTexLoc << " local tex\n"; - nassertv(numNurbTexLoc == 1); - - textures = new SAA_Elem[numNurbTexLoc]; - - // get the referenced texture - SAA_materialRelationGetT2DLocElements( scene, &materials[0], TEX_PER_MAT, &textures[0] ); - - } - // if no locals, try to get globals - else { - SAA_modelRelationGetT2DGlbNbElements( scene, get_model(), FALSE, &relinfo, &numNurbTexGlb ); - - if ( numNurbTexGlb ) { - softegg_cat.spam() << name << " had " << numNurbTexGlb << " global tex\n"; - nassertv(numNurbTexGlb == 1); - - textures = new SAA_Elem[numNurbTexGlb]; - - // get the referenced texture - SAA_modelRelationGetT2DGlbElements( scene, get_model(), TEX_PER_MAT, &textures[0] ); - } - } - - if ( numNurbTexLoc || numNurbTexGlb) { - - // allocate the texture name array - texNameArray = new char *[1]; - // allocate arrays of texture info - uScale = new PN_stdfloat; - vScale = new PN_stdfloat; - uOffset = new PN_stdfloat; - vOffset = new PN_stdfloat; - uRepeat = new int; - vRepeat = new int; - - // check to see if texture is present - result = SAA_elementIsValid( scene, &textures[0], &valid ); - - if ( result != SI_SUCCESS ) - softegg_cat.spam() << "SAA_elementIsValid failed!!!!\n"; - - // texture present - get the name and uv info - if ( valid ) { - // according to drose, we don't need to convert .pic files to .rgb, - // panda can now read the .pic files. - texNameArray[0] = stec.GetTextureName(scene, &textures[0]); - - softegg_cat.spam() << " tritex[0] named: " << texNameArray[0] << endl; - - SAA_texture2DGetUVSwap( scene, &textures[0], &uv_swap ); - - if ( uv_swap == TRUE ) - softegg_cat.spam() << " swapping u and v...\n" ; - - SAA_texture2DGetUScale( scene, &textures[0], uScale ); - SAA_texture2DGetVScale( scene, &textures[0], vScale ); - SAA_texture2DGetUOffset( scene, &textures[0], uOffset ); - SAA_texture2DGetVOffset( scene, &textures[0], vOffset ); - - softegg_cat.spam() << "tritex[0] uScale: " << *uScale << " vScale: " << *vScale << endl; - softegg_cat.spam() << " uOffset: " << *uOffset << " vOffset: " << *vOffset << endl; - - SAA_texture2DGetRepeats( scene, &textures[0], uRepeat, vRepeat ); - softegg_cat.spam() << "uRepeat = " << *uRepeat << ", vRepeat = " << *vRepeat << endl; - } - else { - softegg_cat.spam() << "Invalid texture...\n"; - softegg_cat.spam() << " tritex[0] named: (null)\n"; - } - } - - softegg_cat.spam() << "got textures\n"; - } -} - -/** - * given a vertex, find its corresponding shape vertex and return its index. - */ -int SoftNodeDesc:: -find_shape_vert(LPoint3d p3d, SAA_DVector *vertices, int numVert) { - int i, found = 0; - - for (i = 0; i < numVert && !found ; i++) { - if ((p3d[0] == vertices[i].x) && - (p3d[1] == vertices[i].y) && - (p3d[2] == vertices[i].z)) { - found = 1; - softegg_cat.spam() << "found shape vert at index " << i << endl; - } - } - - if (!found ) - i = -1; - else - i--; - - return i; -} - -/** - * Given a scene, a model , the vertices of its original shape and its name - * find the difference between the geometry of its key shapes and the models - * original geometry and add morph vertices to the egg data to reflect these - * changes. - */ -void SoftNodeDesc:: -make_vertex_offsets(int numShapes) { - int i, j; - int offset; - int numCV; - char tableName[_MAX_PATH]; - SAA_DVector *shapeVerts = nullptr; - SAA_DVector *uniqueVerts = nullptr; - SAA_Elem *model = get_model(); - SAA_Scene *scene = &stec.scene; - - EggVertexPool *vpool = nullptr; - std::string vpool_name = get_name() + ".verts"; - EggNode *t = stec._tree.get_egg_root()->find_child(vpool_name); - if (t) - DCAST_INTO_V(vpool, t); - - int numOrigVert = (int) vpool->size(); - EggVertexPool::iterator vi; - - if ((type == SAA_MNSRF) && stec.make_nurbs) - SAA_nurbsSurfaceSetStep( scene, model, stec.nurbs_step, stec.nurbs_step ); - - SAA_modelGetNbVertices( scene, model, &numCV ); - - // get the shape verts - uniqueVerts = new SAA_DVector[numCV]; - SAA_modelGetVertices( scene, model, SAA_GEOM_ORIGINAL, 0, - numCV, uniqueVerts ); - - softegg_cat.spam() << numCV << " CV's\n"; - - for ( i = 0; i < numCV; i++ ) - // convert vertices to global - _VCT_X_MAT( uniqueVerts[i], uniqueVerts[i], matrix); - softegg_cat.spam() << "uniqueVerts[" << i << "] = " << uniqueVerts[i].x << " " << uniqueVerts[i].y - << " " << uniqueVerts[i].z << " " << uniqueVerts[i].w << endl; - - // iterate through for each key shape (except original) - for ( i = 1; i < numShapes; i++ ) { - - sprintf(tableName, "%s.%d", get_name().c_str(), i); - - softegg_cat.spam() << "\nMaking geometry offsets for " << tableName << "...\n"; - - if ((type == SAA_MNSRF) && stec.make_nurbs) - softegg_cat.spam() << "calculating NURBS morphs...\n"; - else - softegg_cat.spam() << "calculating triangle morphs...\n"; - - // get the shape verts - shapeVerts = new SAA_DVector[numCV]; - SAA_modelGetVertices( scene, model, SAA_GEOM_SHAPE, i+1, numCV, shapeVerts ); - - for ( j=0; j < numCV; j++ ) { - // convert vertices to global - _VCT_X_MAT( shapeVerts[j], shapeVerts[j], matrix); - - softegg_cat.spam() << "shapeVerts[" << j << "] = " << shapeVerts[j].x << " " - << shapeVerts[j].y << " " << shapeVerts[j].z << endl; - } - softegg_cat.spam() << endl; - - // for every original vertex, compare to the corresponding key shape - // vertex and see if a vertex offset is needed - j = 0; - for (vi = vpool->begin(); vi != vpool->end(); ++vi, ++j) { - - double dx, dy, dz; - EggVertex *vert = (*vi); - LPoint3d p3d = vert->get_pos3(); - - softegg_cat.spam() << "oVert[" << j << "] = " << p3d[0] << " " << p3d[1] << " " << p3d[2] << endl; - if ((type == SAA_MNSRF) && stec.make_nurbs) { - dx = shapeVerts[j].x - p3d[0]; - dy = shapeVerts[j].y - p3d[1]; - dz = shapeVerts[j].z - p3d[2]; - - softegg_cat.spam() << "global shapeVerts[" << j << "] = " << shapeVerts[j].x << " " - << shapeVerts[j].y << " " << shapeVerts[j].z << " " << shapeVerts[j].w << endl; - } - else { - // we need to map from original vertices to triangle shape vertices - // here - offset = find_shape_vert(p3d, uniqueVerts, numCV); - - dx = shapeVerts[offset].x - p3d[0]; - dy = shapeVerts[offset].y - p3d[1]; - dz = shapeVerts[offset].z - p3d[2]; - - softegg_cat.spam() << "global shapeVerts[" << offset << "] = " << shapeVerts[offset].x << " " - << shapeVerts[offset].y << " " << shapeVerts[offset].z << endl; - } - - softegg_cat.spam() << j << ": dx = " << dx << ", dy = " << dy << ", dz = " << dz << endl; - - // if change isn't negligible, make a morph vertex entry - double total = fabs(dx)+fabs(dy)+fabs(dz); - if ( total > 0.00001 ) { - if ( vpool != nullptr ) { - // create offset - LVector3d p(dx, dy, dz); - EggMorphVertex *dxyz = new EggMorphVertex(tableName, p); - // add the offset to the vertex - vert->_dxyzs.insert(*dxyz); - } - else - softegg_cat.spam() << "Error: couldn't find vertex pool " << vpool_name << endl; - - } // if total - } //for j - } //for i -} - -/** - * Given a scene, a model, a name and a frame time, determine what type of - * shape interpolation is used and call the appropriate function to extract - * the shape weight info for this frame... - */ -void SoftNodeDesc:: -make_morph_table( PN_stdfloat time ) { - int numShapes; - SAA_Elem *model = nullptr; - SAA_AnimInterpType type; - SAA_Scene *scene = &stec.scene; - - if (has_model()) - model = get_model(); - else - return; - - // Get the number of key shapes - SAA_modelGetNbShapes( scene, model, &numShapes ); - - if ( numShapes <= 0 ) { - return; - } - - stec.has_morph = true; - - softegg_cat.spam() << "make_morph_table: " << get_name() << " : num shapes: " << numShapes << endl; - - SAA_modelGetShapeInterpolation( scene, model, &type ); - - if ( type == SAA_ANIM_LINEAR || type == SAA_ANIM_CARDINAL ) { - softegg_cat.spam() << "linear morph" << endl; - make_linear_morph_table( numShapes, time ); - } - else { // must be weighted... - // check first for expressions - softegg_cat.spam() << "expression morph" << endl; - make_expression_morph_table( numShapes, time ); - } -} - -/** - * Given a scene, a model, its name, and the time, get the shape fcurve for - * the model and determine the shape weights for the given time and use them - * to populate the morph table. - */ -void SoftNodeDesc:: -make_linear_morph_table(int numShapes, PN_stdfloat time) { - int i; - PN_stdfloat curveVal; - char tableName[_MAX_PATH]; - SAA_Elem fcurve; - // SAnimTable *thisTable; - EggSAnimData *anim; - SAA_Elem *model = get_model(); - SAA_Scene *scene = &stec.scene; - - softegg_cat.spam() << "linear interp, getting fcurve\n"; - - SAA_modelFcurveGetShape( scene, model, &fcurve ); - - SAA_fcurveEval( scene, &fcurve, time, &curveVal ); - - softegg_cat.spam() << "at time " << time << ", fcurve for " << get_name() << " = " << curveVal << endl; - - PN_stdfloat nextVal = 0.0f; - - // populate morph table values for this frame - for ( i = 1; i < numShapes; i++ ) { - // derive table name from the model name - sprintf(tableName, "%s.%d", get_name().c_str(), i); - - softegg_cat.spam() << "Linear: looking for table '" << tableName << "'\n"; - - // find the morph table associated with this key shape - anim = stec.find_morph_table(tableName); - - if ( anim != nullptr ) { - if ( i == (int)curveVal ) { - if ( curveVal - i == 0 ) { - anim->add_data(1.0f ); - softegg_cat.spam() << "adding element 1.0f\n"; - } - else { - anim->add_data(1.0f - (curveVal - i)); - nextVal = curveVal - i; - softegg_cat.spam() << "adding element " << 1.0f - (curveVal - i) << endl; - } - } - else { - if ( nextVal ) { - anim->add_data(nextVal ); - nextVal = 0.0f; - softegg_cat.spam() << "adding element " << nextVal << endl; - } - else { - anim->add_data(0.0f); - softegg_cat.spam() << "adding element 0.0f\n"; - } - } - - softegg_cat.spam() <<" to '" << tableName << "'\n"; - } - else - softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n"; - } -} - -/** - * Given a scene, a model, a list of all models in the scene, the number of - * models in the scece, the number of key shapes for this model, the name of - * the model and the current time, determine what method of controlling the - * shape weights is used and call the appropriate routine. - */ -void SoftNodeDesc:: -make_weighted_morph_table(int numShapes, PN_stdfloat time) { - PN_stdfloat curveVal; - SI_Error result; - char tableName[_MAX_PATH]; - SAA_Elem *weightCurves; - // SAnimTable *thisTable; - EggSAnimData *anim; - SAA_Elem *model = get_model(); - SAA_Scene *scene = &stec.scene; - - // allocate array of weight curves (one for each shape) - weightCurves = new SAA_Elem[numShapes]; - - result = SAA_modelFcurveGetShapeWeights(scene, model, numShapes, weightCurves); - - if ( result == SI_SUCCESS ) { - for ( int i = 1; i < numShapes; i++ ) { - SAA_fcurveEval( scene, &weightCurves[i], time, &curveVal ); - - // make sure soft gave us a reasonable number if (!isNum(curveVal)) - // curveVal = 0.0f; - - softegg_cat.spam() << "at time " << time << ", weightCurve[" << i << "] for " << get_name() << " = " << curveVal << endl; - - // derive table name from the model name - sprintf(tableName, "%s.%d", get_name().c_str(), i); - - // find and populate shape table - softegg_cat.spam() << "Weight: looking for table '" << tableName << "'\n"; - - // find the morph table associated with this key shape - anim = stec.find_morph_table(tableName); - - if ( anim != nullptr ) { - anim->add_data(curveVal); - softegg_cat.spam() << "adding element " << curveVal << endl; - } - else - softegg_cat.spam() << i << " : Couldn't find table '" << tableName << "'\n"; - } - } -} - -/** - * Given a scene, a model and its number of key shapes generate a morph table - * describing transitions btwn the key shapes by evaluating the positions of - * the controlling sliders. - */ -void SoftNodeDesc:: -make_expression_morph_table(int numShapes, PN_stdfloat time) -{ - // int j; - int numExp; - char *track; - // PN_stdfloat expVal; PN_stdfloat sliderVal; char *tableName; char - // *sliderName; SAnimTable *thisTable; - SAA_Elem *expressions; - SI_Error result; - - SAA_Elem *model = get_model(); - SAA_Scene *scene = &stec.scene; - - // populate morph table values for this frame - - // compose track name - track = nullptr; - - // find how many expressions for this shape - SAA_elementGetNbExpressions( scene, model, track, FALSE, &numExp ); - - softegg_cat.spam() << get_name() << " has " << numExp << " RHS expressions\n"; - - if ( numExp ) { - // get the expressions for this shape - expressions = new SAA_Elem[numExp]; - softegg_cat.spam() << "getting " << numExp << " RHS expressions...\n"; - - result = SAA_elementGetExpressions( scene, model, track, FALSE, - numExp, expressions ); - /* - if ( !result ) { - for ( j = 1; j < numExp; j++ ) { - if ( verbose >= 2 ) - { - // debug see what we got - int numvars; - - SAA_expressionGetNbVars( scene, &expressions[j], &numvars ); - - int *varnamelen; - int *varstrlen; - int expstrlen; - - varnamelen = (int *)malloc(sizeof(int)*numvars); - varstrlen = (int *)malloc(sizeof(int)*numvars); - - SAA_expressionGetStringLengths( scene, &expressions[j], - numvars, varnamelen, varstrlen, &expstrlen ); - - int *varnamesizes; - int *varstrsizes; - - varnamesizes = (int *)malloc(sizeof(int)*numvars); - varstrsizes = (int *)malloc(sizeof(int)*numvars); - - for ( int k = 0; k < numvars; k++ ) - { - varnamesizes[k] = varnamelen[k] + 1; - varstrsizes[k] = varstrlen[k] + 1; - } - - int expstrsize = expstrlen + 1; - - char **varnames; - char **varstrs; - - varnames = (char **)malloc(sizeof(char *)*numvars); - varstrs = (char **)malloc(sizeof(char *)*numvars); - - for ( k = 0; k < numvars; k++ ) - { - varnames[k] = (char *)malloc(sizeof(char)* - varnamesizes[k]); - - varstrs[k] = (char *)malloc(sizeof(char)* - varstrsizes[k]); - } - - char *expstr = (char *)malloc(sizeof(char)* expstrsize ); - - SAA_expressionGetStrings( scene, &expressions[j], numvars, - varnamesizes, varstrsizes, expstrsize, varnames, - varstrs, expstr ); - - if ( verbose >= 2 ) - { - fprintf( outStream, "expression = '%s'\n", expstr ); - fprintf( outStream, "has %d variables\n", numvars ); - } - } //if verbose - - if ( verbose >= 2 ) - fprintf( outStream, "evaling expression...\n" ); - - SAA_expressionEval( scene, &expressions[j], time, &expVal ); - - if ( verbose >= 2 ) - fprintf( outStream, "time %f: exp val %f\n", - time, expVal ); - - // derive table name from the model name - tableName = MakeTableName( name, j ); - - if ( verbose >= 2 ) - fprintf( outStream, "Exp: looking for table '%s'\n", - tableName ); - - // find the morph table associated with this key shape - anim = (SAnimTable *) - (morphRoot->FindDescendent( tableName )); - - if ( anim != NULL ) - { - anim->AddElement( expVal ); - if ( verbose >= 1 ) - fprintf( outStream, "%d: adding element %f to %s\n", - j, expVal, tableName ); - fflush( outStream ); - } - else - { - fprintf( outStream, "%d: Couldn't find table '%s'", j, - tableName ); - - fprintf( outStream, " for value %f\n", expVal ); - } - } - } - else - fprintf( outStream, "couldn't get expressions!!!\n" ); - */ - } - else { - softegg_cat.spam() << "weighted morph" << endl; - // no expression, use weight curves - make_weighted_morph_table(numShapes, time ); - } -} diff --git a/pandatool/src/softegg/softNodeDesc.h b/pandatool/src/softegg/softNodeDesc.h deleted file mode 100644 index c6512b7dda..0000000000 --- a/pandatool/src/softegg/softNodeDesc.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softNodeDesc.h - * @author masad - * @date 2003-10-03 - */ - -#ifndef SOFTNODEDESC_H -#define SOFTNODEDESC_H - -#ifdef _MIN -#undef _MIN -#endif -#ifdef _MAX -#undef _MAX -#endif - -#include "pandatoolbase.h" - -#include "eggVertex.h" -#include "eggVertexPool.h" -#include "referenceCount.h" -#include "pointerTo.h" -#include "namable.h" - -#include - -class EggGroup; -class EggTable; -class EggXfmSAnim; - -/** - * Describes a single instance of a node aka element in the Soft scene graph, - * relating it to the corresponding egg structures (e.g. node, group, or - * table entry) that will be created. - */ -class SoftNodeDesc : public ReferenceCount, public Namable { -public: - SoftNodeDesc(SoftNodeDesc *parent=nullptr, const std::string &name = std::string()); - ~SoftNodeDesc(); - - void set_parent(SoftNodeDesc *parent); - void force_set_parent(SoftNodeDesc *parent); - void set_model(SAA_Elem *model); - bool has_model() const; - SAA_Elem *get_model() const; - - bool is_joint() const; - bool is_junk() const; - void set_joint(); - bool is_joint_parent() const; - bool is_partial(char *search_prefix); - - SoftNodeDesc *_parent; - SoftNodeDesc *_parentJoint; // keep track of who is your parent joint - typedef pvector< PT(SoftNodeDesc) > Children; - Children _children; - -private: - void clear_egg(); - void mark_joint_parent(); - void check_joint_parent(); - void check_junk(bool parent_junk); - void check_pseudo_joints(bool joint_above); - - void set_parentJoint(SAA_Scene *scene, SoftNodeDesc *lastJoint); - - SAA_ModelType type; - - SAA_Elem *_model; - - EggGroup *_egg_group; - EggTable *_egg_table; - EggXfmSAnim *_anim; - - enum JointType { - JT_none, // Not a joint. - JT_joint, // An actual joint in Soft. - JT_pseudo_joint, // Not a joint in Soft, but treated just like a - // joint for the purposes of the converter. - JT_joint_parent, // A parent or ancestor of a joint or pseudo joint. - JT_junk, // originated from con-/fly-/car_rig/bars etc. - }; - JointType _joint_type; - -public: - - char **texNameArray; - int *uRepeat, *vRepeat; - PN_stdfloat matrix[4][4]; - - const char *fullname; - - int numTri; - // int numShapes; - int numTexLoc; - int numTexGlb; - int *numTexTri; - - // if the node is a MNSRF - int numNurbTexLoc; - int numNurbTexGlb; - int numNurbMats; - - PN_stdfloat *uScale; - PN_stdfloat *vScale; - PN_stdfloat *uOffset; - PN_stdfloat *vOffset; - - SAA_Boolean valid; - SAA_Boolean uv_swap; - // SAA_Boolean visible; - SAA_Elem *textures; - SAA_Elem *materials; - SAA_SubElem *triangles; - SAA_GeomType gtype; - - EggGroup *get_egg_group()const {return _egg_group;} - - void get_transform(SAA_Scene *scene, EggGroup *egg_group, bool global); - void get_joint_transform(SAA_Scene *scene, EggGroup *egg_group, EggXfmSAnim *anim, bool global); - void load_poly_model(SAA_Scene *scene, SAA_ModelType type); - void load_nurbs_model(SAA_Scene *scene, SAA_ModelType type); - - void make_morph_table(PN_stdfloat time); - void make_linear_morph_table(int numShapes, PN_stdfloat time); - void make_weighted_morph_table(int numShapes, PN_stdfloat time); - void make_expression_morph_table(int numShapes, PN_stdfloat time); - - void make_vertex_offsets(int numShapes); - int find_shape_vert(LPoint3d p3d, SAA_DVector *vertices, int numVert); - - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - ReferenceCount::init_type(); - Namable::init_type(); - register_type(_type_handle, "SoftNodeDesc", - ReferenceCount::get_class_type(), - Namable::get_class_type()); - } - -private: - static TypeHandle _type_handle; - - friend class SoftNodeTree; -}; - -class SoftToEggConverter; -extern SoftToEggConverter stec; - -#endif diff --git a/pandatool/src/softegg/softNodeTree.cxx b/pandatool/src/softegg/softNodeTree.cxx deleted file mode 100644 index 3b5be3252b..0000000000 --- a/pandatool/src/softegg/softNodeTree.cxx +++ /dev/null @@ -1,561 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softNodeTree.cxx - * @author masad - * @date 2003-09-26 - */ - -// Includes - -#include "softNodeTree.h" -#include "softEggGroupUserData.h" -#include "config_softegg.h" -#include "eggGroup.h" -#include "eggTable.h" -#include "eggXfmSAnim.h" -#include "eggData.h" -#include "softToEggConverter.h" -#include "dcast.h" - -#include - -using std::endl; - -/** - * - */ -SoftNodeTree:: -SoftNodeTree() { - _root = new SoftNodeDesc(nullptr, "----root"); - _root->fullname = "----root"; - _fps = 0.0; - _use_prefix = 0; - _search_prefix = nullptr; - _egg_data = nullptr; - _egg_root = nullptr; - _skeleton_node = nullptr; -} -/** - * Given an element, return a copy of the element's name WITHOUT prefix. - */ -char *SoftNodeTree:: -GetName( SAA_Scene *scene, SAA_Elem *element ) { - int nameLen; - char *name; - - // get the name - SAA_elementGetNameLength( scene, element, &nameLen ); - name = new char[++nameLen]; - SAA_elementGetName( scene, element, nameLen, name ); - - return name; -} - -/** - * Given an element, return a copy of the element's name complete with prefix. - */ -char *SoftNodeTree:: -GetFullName( SAA_Scene *scene, SAA_Elem *element ) -{ - int nameLen, prefixLen; - char *name, *prefix; - - // get the name length - SAA_elementGetNameLength( scene, element, &nameLen ); - // get the prefix length - SAA_elementGetPrefixLength( scene, element, &prefixLen ); - // allocate the array to hold name - name = new char[++nameLen]; - // allocate the array to hold prefix and length + hyphen - prefix = new char[++prefixLen + nameLen + 4]; - // get the name - SAA_elementGetName( scene, element, nameLen, name ); - // get the prefix - SAA_elementGetPrefix( scene, element, prefixLen, prefix ); - // add 'em together - strcat(prefix, "-"); - strcat(prefix, name); - - // return string - return prefix; -} - -/** - * Given an element, return a string containing the contents of its MODEL NOTE - * entry - */ -char *SoftNodeTree:: -GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model ) { - int size; - char *modelNote = nullptr; - SAA_Boolean bigEndian; - - SAA_elementGetUserDataSize( scene, model, "MNOT", &size ); - - if ( size != 0 ) { - // allocate modelNote string - modelNote = new char[size + 1]; - - // get ModelNote data from this model - SAA_elementGetUserData( scene, model, "MNOT", size, - &bigEndian, (void *)modelNote ); - - // strip off newline, if present - char *eol = (char *)memchr( modelNote, '\n', size ); - if ( eol != nullptr) - *eol = '\0'; - else - modelNote[size] = '\0'; - - softegg_cat.spam() << "\nmodelNote = " << modelNote << endl; - } - - return modelNote; -} - -/** - * Given a string, return a copy of the string up to the first occurence of - * '-'. - */ -char *SoftNodeTree:: -GetRootName( const char *name ) { - const char *hyphen; - char *root; - int len; - - hyphen = strchr( name, '-' ); - len = hyphen-name; - - if ( (hyphen != nullptr) && len ) { - root = new char[len+1]; - strncpy( root, name, len ); - root[len] = '\0'; - } - else { - root = new char[strlen(name)+1]; - strcpy( root, name ); - } - return( root ); -} - -/** - * Walks through the complete Soft hierarchy and builds up the corresponding - * tree. - */ -bool SoftNodeTree:: -build_complete_hierarchy(SAA_Scene &scene, SAA_Database &database) { - SI_Error status; - SoftNodeDesc *node; - - // Get the entire Soft scene. - int numModels; - SAA_Elem *models; - - SAA_sceneGetNbModels( &scene, &numModels ); - softegg_cat.spam() << "Scene has " << numModels << " model(s)...\n"; - - // This while loop walks through the entire Soft hierarchy, one node at a - // time. - bool all_ok = true; - if ( numModels ) { - // allocate array of models - models = (SAA_Elem *) new SAA_Elem[numModels]; - if ( models != nullptr ) { - if ((status = SAA_sceneGetModels( &scene, numModels, models )) != SI_SUCCESS) { - return false; - } - for ( int i = 0; i < numModels; i++ ) { - int level; - status = SAA_elementGetHierarchyLevel( &scene, &models[i], &level ); - softegg_cat.spam() << "model[" << i << "]" << endl; - softegg_cat.spam() << " level " << level << endl; - softegg_cat.spam() << " status is " << status << "\n"; - - node = build_node(&scene, &models[i]); - if (!level && node) - node->set_parent(_root); - } - } - } - - softegg_cat.spam() << "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj\n"; - - // check the nodes that are junk for animationartist control purposes - _root->check_junk(false); - - softegg_cat.spam() << "jpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjpjp\n"; - - // check the nodes that are parent of ancestors of a joint - _root->check_joint_parent(); - - softegg_cat.spam() << "pppppppppppppppppppppppppppppppppppppppppppppppppppppppp\n"; - - // check the nodes that are pseudo joints - _root->check_pseudo_joints(false); - - softegg_cat.spam() << "========================================================\n"; - - // find _parentJoint for each node - _root->set_parentJoint(&scene, nullptr); - - return all_ok; -} -#if 0 -/** - * Walks through the selected subset of the Soft hierarchy (or the complete - * hierarchy, if nothing is selected) and builds up the corresponding tree. - */ -bool SoftNodeTree:: -build_selected_hierarchy(char *scene_name) { - MStatus status; - - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (!status) { - status.perror("MItDag constructor"); - return false; - } - - // Get only the selected geometry. - MSelectionList selection; - status = MGlobal::getActiveSelectionList(selection); - if (!status) { - status.perror("MGlobal::getActiveSelectionList"); - return false; - } - - // Get the selected geometry only if the selection is nonempty; otherwise, - // get the whole scene anyway. - if (selection.isEmpty()) { - softegg_cat.info() - << "Selection list is empty.\n"; - return build_complete_hierarchy(); - } - - bool all_ok = true; - unsigned int length = selection.length(); - for (unsigned int i = 0; i < length; i++) { - MDagPath root_path; - status = selection.getDagPath(i, root_path); - if (!status) { - status.perror("MSelectionList::getDagPath"); - } else { - // Now traverse through the selected dag path and all nested dag paths. - dag_iterator.reset(root_path); - while (!dag_iterator.isDone()) { - MDagPath dag_path; - status = dag_iterator.getPath(dag_path); - if (!status) { - status.perror("MItDag::getPath"); - } else { - build_node(dag_path); - } - - dag_iterator.next(); - } - } - } - - if (all_ok) { - _root->check_pseudo_joints(false); - } - - return all_ok; -} -#endif -/** - * Returns the total number of nodes in the hierarchy, not counting the root - * node. - */ -int SoftNodeTree:: -get_num_nodes() const { - return _nodes.size(); -} - -/** - * Returns the nth node in the hierarchy, in an arbitrary ordering. - */ -SoftNodeDesc *SoftNodeTree:: -get_node(int n) const { - nassertr(n >= 0 && n < (int)_nodes.size(), nullptr); - return _nodes[n]; -} - -/** - * Returns the node named 'name' in the hierarchy, in an arbitrary ordering. - */ -SoftNodeDesc *SoftNodeTree:: -get_node(std::string name) const { - NodesByName::const_iterator ni = _nodes_by_name.find(name); - if (ni != _nodes_by_name.end()) - return (*ni).second; - return nullptr; -} - -/** - * Removes all of the references to generated egg structures from the tree, - * and prepares the tree for generating new egg structures. - */ -void SoftNodeTree:: -clear_egg(EggData *egg_data, EggGroupNode *egg_root, - EggGroupNode *skeleton_node) { - _root->clear_egg(); - _egg_data = egg_data; - _egg_root = egg_root; - _skeleton_node = skeleton_node; -} - -/** - * Returns the EggGroupNode corresponding to the group or joint for the - * indicated node. Creates the group node if it has not already been created. - */ -EggGroup *SoftNodeTree:: -get_egg_group(SoftNodeDesc *node_desc) { - nassertr(_egg_root != nullptr, nullptr); - - // lets print some relationship - softegg_cat.spam() << " group " << node_desc->get_name() << "(" << node_desc->_egg_group << ")"; - if (node_desc->_parent) - softegg_cat.spam() << " parent " << node_desc->_parent->get_name() << "(" << node_desc->_parent << ")"; - else - softegg_cat.spam() << " parent " << node_desc->_parent; - softegg_cat.spam() << endl; - - if (node_desc->_egg_group == nullptr) { - // We need to make a new group node. - EggGroup *egg_group; - - egg_group = new EggGroup(node_desc->get_name()); - if (node_desc->is_joint()) { - egg_group->set_group_type(EggGroup::GT_joint); - } - - if (stec.flatten || (!node_desc->_parentJoint || node_desc->_parentJoint == _root)) { - // The parent is the root. - softegg_cat.spam() << "came hereeeee\n"; - _egg_root->add_child(egg_group); - } else { - // The parent is another node. - EggGroup *parent_egg_group = get_egg_group(node_desc->_parentJoint); - parent_egg_group->add_child(egg_group); - } - - node_desc->_egg_group = egg_group; - } - - return node_desc->_egg_group; -} - -/** - * Returns the EggTable corresponding to the joint for the indicated node. - * Creates the table node if it has not already been created. - */ -EggTable *SoftNodeTree:: -get_egg_table(SoftNodeDesc *node_desc) { - nassertr(_skeleton_node != nullptr, nullptr); - nassertr(node_desc->is_joint(), nullptr); - - // lets print some relationship - softegg_cat.spam() << " group " << node_desc->get_name() << "(" << node_desc->_egg_group << ")"; - if (node_desc->_parent) - softegg_cat.spam() << " parent " << node_desc->_parent->get_name() << "(" << node_desc->_parent << ")"; - else - softegg_cat.spam() << " parent " << node_desc->_parent; - softegg_cat.spam() << endl; - - if (node_desc->_egg_table == nullptr) { - softegg_cat.spam() << "creating a new table\n"; - // We need to make a new table node. nassertr(node_desc->_parent != - // (SoftNodeDesc *)NULL, NULL); - - EggTable *egg_table = new EggTable(node_desc->get_name()); - node_desc->_anim = new EggXfmSAnim("xform", _egg_data->get_coordinate_system()); - node_desc->_anim->set_fps(_fps); - egg_table->add_child(node_desc->_anim); - - if (stec.flatten || (!node_desc->_parentJoint || node_desc->_parentJoint == _root)) { - // if (!node_desc->_parent->is_joint()) { The parent is not a joint; put - // it at the top. - _skeleton_node->add_child(egg_table); - } else { - // The parent is another joint. - EggTable *parent_egg_table = get_egg_table(node_desc->_parentJoint); - parent_egg_table->add_child(egg_table); - } - - node_desc->_egg_table = egg_table; - } - - return node_desc->_egg_table; -} - -/** - * Returns the anim table corresponding to the joint for the indicated node. - * Creates the table node if it has not already been created. - */ -EggXfmSAnim *SoftNodeTree:: -get_egg_anim(SoftNodeDesc *node_desc) { - get_egg_table(node_desc); - return node_desc->_anim; -} - -/** - * Sets joint information for MNILL node - */ -void SoftNodeTree:: -handle_null(SAA_Scene *scene, SoftNodeDesc *node_desc, const char *node_name) { - const char *name = node_name; - SAA_AlgorithmType algo; - SAA_Elem *model = node_desc->get_model(); - - SAA_modelGetAlgorithm( scene, model, &algo ); - softegg_cat.spam() << " null algorithm: " << algo << endl; - - if ( algo == SAA_ALG_INV_KIN ) { - // MakeJoint( &scene, lastJoint, lastAnim, model, name ); - node_desc->set_joint(); - softegg_cat.spam() << " encountered IK root: " << name << endl; - } - else if ( algo == SAA_ALG_INV_KIN_LEAF ) { - // MakeJoint( &scene, lastJoint, lastAnim, model, name ); - node_desc->set_joint(); - softegg_cat.spam() << " encountered IK leaf: " << name << endl; - } - else if ( algo == SAA_ALG_STANDARD ) { - SAA_Boolean isSkeleton = FALSE; - softegg_cat.spam() << " encountered Standard null: " << name << endl; - - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // check to see if this NULL is used as a skeleton or is animated via - // constraint only ( these nodes are tagged by the animator with the - // keyword "joint" somewhere in the nodes name) - if ( isSkeleton || (strstr( name, "joint" ) != nullptr) ) { - // MakeJoint( &scene, lastJoint, lastAnim, model, name ); - node_desc->set_joint(); - softegg_cat.spam() << " animating Standard null!!!\n"; - softegg_cat.spam() << "isSkeleton: " << isSkeleton << endl; - } - } - else - softegg_cat.spam() << " encountered some other NULL: " << algo << endl; -} - -/** - * Returns a pointer to the node corresponding to the indicated dag_path - * object, creating it first if necessary. - */ -SoftNodeDesc *SoftNodeTree:: -build_node(SAA_Scene *scene, SAA_Elem *model) { - char *name, *fullname; - std::string node_name; - int numChildren; - int thisChild; - SAA_Elem *children; - SAA_ModelType type; - SAA_Boolean isSkeleton = FALSE; - - fullname = GetFullName(scene, model); - if (_use_prefix) - name = fullname; - else - name = GetName(scene, model); - - node_name = name; - - SoftNodeDesc *node_desc = r_build_node(nullptr, node_name); - - node_desc->fullname = fullname; - node_desc->set_model(model); - SAA_modelIsSkeleton( scene, model, &isSkeleton ); - - // find out what type of node we're dealing with - SAA_modelGetType( scene, node_desc->get_model(), &type ); - - if (type == SAA_MJNT || isSkeleton || (strstr(node_desc->get_name().c_str(), "joint") != nullptr)) - node_desc->set_joint(); - - // treat the MNILL differently, because it needs to detect and set some - // joints - if (type == SAA_MNILL) - handle_null(scene, node_desc, name); - - if (node_desc->is_joint()) - softegg_cat.spam() << "type: " << type << " isSkeleton: " << isSkeleton << endl; - - // get to the children - SAA_modelGetNbChildren( scene, model, &numChildren ); - softegg_cat.spam() << " Model " << node_name << " children: " << numChildren << endl; - - if ( numChildren ) { - children = new SAA_Elem[numChildren]; - SAA_modelGetChildren( scene, model, numChildren, children ); - if (!children) - softegg_cat.info() << "Not enough Memory for children...\n"; - - for ( thisChild = 0; thisChild < numChildren; thisChild++ ) { - fullname = GetFullName(scene, &children[thisChild]); - if (_use_prefix) - node_name = fullname; - else - node_name = GetName(scene, &children[thisChild]); - - softegg_cat.spam() << " building child " << thisChild << "..."; - - SoftNodeDesc *node_child = r_build_node(node_desc, node_name); - - node_child->fullname = fullname; - node_child->set_model(&children[thisChild]); - SAA_modelIsSkeleton( scene, &children[thisChild], &isSkeleton ); - - // find out what type of node we're dealing with - SAA_modelGetType( scene, node_child->get_model(), &type ); - - if (type == SAA_MJNT || isSkeleton || (strstr(node_child->get_name().c_str(), "joint") != nullptr)) - node_child->set_joint(); - - // treat the MNILL differently, because it needs to detect and set some - // joints - if (type == SAA_MNILL) - handle_null(scene, node_child, node_name.c_str()); - - if (node_child->is_joint()) - softegg_cat.spam() << "type: " << type << " isSkeleton: " << isSkeleton << endl; - } - } - return node_desc; -} - -/** - * The recursive implementation of build_node(). - */ -SoftNodeDesc *SoftNodeTree:: -r_build_node(SoftNodeDesc *parent_node, const std::string &name) { - SoftNodeDesc *node_desc; - - // If we have already encountered this pathname, return the corresponding - // SoftNodeDesc immediately. - NodesByName::const_iterator ni = _nodes_by_name.find(name); - if (ni != _nodes_by_name.end()) { - softegg_cat.spam() << " already built node " << (*ni).first; - node_desc = (*ni).second; - node_desc->set_parent(parent_node); - return node_desc; - } - - // Otherwise, we have to create it. Do this recursively, so we create each - // node along the path. - node_desc = new SoftNodeDesc(parent_node, name); - - softegg_cat.spam() << " node name : " << name << endl; - _nodes.push_back(node_desc); - - _nodes_by_name.insert(NodesByName::value_type(name, node_desc)); - - return node_desc; -} diff --git a/pandatool/src/softegg/softNodeTree.h b/pandatool/src/softegg/softNodeTree.h deleted file mode 100644 index afbef5877b..0000000000 --- a/pandatool/src/softegg/softNodeTree.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softNodeTree.h - * @author masad - * @date 2003-10-03 - */ - -#ifndef SOFTNODETREE_H -#define SOFTNODETREE_H - -#include "pandatoolbase.h" -#include "softNodeDesc.h" - -#include - -class EggGroup; -class EggTable; -class EggXfmSAnim; -class EggData; -class EggGroupNode; - - -/** - * Describes a complete tree of soft nodes for conversion. - */ -class SoftNodeTree { -public: - SoftNodeTree(); - SoftNodeDesc *build_node(SAA_Scene *scene, SAA_Elem *model); - bool build_complete_hierarchy(SAA_Scene &scene, SAA_Database &database); - void handle_null(SAA_Scene *scene, SoftNodeDesc *node_desc, const char *node_name); - // bool build_selected_hierarchy(SAA_Scene *s, SAA_Database *d, char - // *scene_name); - - int get_num_nodes() const; - SoftNodeDesc *get_node(int n) const; - SoftNodeDesc *get_node(std::string name) const; - - char *GetRootName(const char *); - char *GetModelNoteInfo(SAA_Scene *, SAA_Elem *); - char *GetName(SAA_Scene *scene, SAA_Elem *element); - char *GetFullName(SAA_Scene *scene, SAA_Elem *element); - - EggGroupNode *get_egg_root() {return _egg_root;} - EggGroup *get_egg_group(SoftNodeDesc *node_desc); - EggTable *get_egg_table(SoftNodeDesc *node_desc); - EggXfmSAnim *get_egg_anim(SoftNodeDesc *node_desc); - - void clear_egg(EggData *egg_data, EggGroupNode *egg_root, EggGroupNode *skeleton_node); - - PT(SoftNodeDesc) _root; - PN_stdfloat _fps; - int _use_prefix; - char *_search_prefix; - - -private: - - EggData *_egg_data; - EggGroupNode *_egg_root; - EggGroupNode *_skeleton_node; - - SoftNodeDesc *r_build_node(SoftNodeDesc *parent_node, const std::string &path); - - typedef pmap NodesByName; - NodesByName _nodes_by_name; - - typedef pvector Nodes; - Nodes _nodes; -}; - -#endif diff --git a/pandatool/src/softegg/softToEggConverter.cxx b/pandatool/src/softegg/softToEggConverter.cxx deleted file mode 100644 index 44dafefb62..0000000000 --- a/pandatool/src/softegg/softToEggConverter.cxx +++ /dev/null @@ -1,2122 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softToEggConverter.cxx - * @author masad - * @date 2003-09-25 - */ - -#include "softToEggConverter.h" -#include "config_softegg.h" -#include "softEggGroupUserData.h" - -#include "eggData.h" -#include "eggGroup.h" -#include "eggTable.h" -#include "eggVertex.h" -#include "eggComment.h" -#include "eggVertexPool.h" -#include "eggNurbsSurface.h" -#include "eggNurbsCurve.h" -#include "eggPolygon.h" -#include "eggPrimitive.h" -#include "eggTexture.h" -#include "eggTextureCollection.h" -#include "eggXfmSAnim.h" -#include "eggSAnimData.h" -#include "string_utils.h" -#include "dcast.h" - -using std::endl; -using std::string; - -SoftToEggConverter stec; - -const int TEX_PER_MAT = 1; - -/** - * - */ -SoftToEggConverter:: -SoftToEggConverter(const string &program_name) : - _program_name(program_name) -{ - _from_selection = false; - _polygon_output = false; - _polygon_tolerance = 0.01; - /* - _respect_maya_double_sided = maya_default_double_sided; - _always_show_vertex_color = maya_default_vertex_color; - */ - _transform_type = TT_model; - - database_name = nullptr; - scene_name = nullptr; - model_name = nullptr; - animFileName = nullptr; - eggFileName = nullptr; - tex_path = nullptr; - eggGroupName = nullptr; - tex_filename = nullptr; - search_prefix = nullptr; - result = SI_SUCCESS; - - // skeleton = new EggGroup(); - foundRoot = FALSE; - // animRoot = NULL; morphRoot = NULL; - geom_as_joint = 0; - make_anim = 0; - make_nurbs = 0; - make_poly = 0; - make_soft = 0; - make_morph = 1; - make_duv = 1; - make_dart = TRUE; - has_morph = 0; - make_pose = 0; - // animData.is_z_up = FALSE; - nurbs_step = 1; - anim_start = -1000; - anim_end = -1000; - anim_rate = 24; - pose_frame = -1; - verbose = 0; - flatten = 0; - shift_textures = 0; - ignore_tex_offsets = 0; - use_prefix = 0; -} - -/** - * - */ -SoftToEggConverter:: -SoftToEggConverter(const SoftToEggConverter ©) : - _from_selection(copy._from_selection), - /* - _maya(copy._maya), - */ - _polygon_output(copy._polygon_output), - _polygon_tolerance(copy._polygon_tolerance), - /* - _respect_maya_double_sided(copy._respect_maya_double_sided), - _always_show_vertex_color(copy._always_show_vertex_color), - */ - _transform_type(copy._transform_type) -{ -} - -/** - * - */ -SoftToEggConverter:: -~SoftToEggConverter() { - /* - close_api(); - */ -} -/** - * Displays the "what is this program" message, along with the usage message. - * Should be overridden in base classes to describe the current program. - */ -void SoftToEggConverter:: -Help() -{ - softegg_cat.info() << - "soft2egg takes a SoftImage scene or model\n" - "and outputs its contents as an egg file\n"; - - Usage(); -} - -/** - * Displays the usage message. - */ -void SoftToEggConverter:: -Usage() { - softegg_cat.info() - << "\nUsage:\n" - // << _commandName << " [opts] (must specify -m or -s)\n\n" - << "soft" << " [opts] (must specify -m or -s)\n\n" - << "Options:\n"; - - ShowOpts(); - softegg_cat.info() << "\n"; -} - -/** - * Displays the valid options. Should be extended in base classes to show - * additional options relevant to the current program. - */ -void SoftToEggConverter:: -ShowOpts() -{ - softegg_cat.info() << - " -r - Used to provide soft with the resource\n" - " Defaults to '/ful/ufs/soft371_mips2/3D/rsrc'.\n" - " -d - Database path.\n" - " -s - Indicates that a scene will be converted.\n" - " -m - Indicates that a model will be converted.\n" - " -t - Specify path to place converted textures.\n" - " -T - Specify filename for texture map listing.\n" - " -S - Specify step for nurbs surface triangulation.\n" - " -M - Specify model output filename. Defaults to scene name.\n" - " -A - Specify anim output filename. Defaults to scene name.\n" - " -N - Specify egg group name.\n" - " -k - Enable soft assignment for geometry.\n" - " -n - Specify egg NURBS representation instead of poly's.\n" - " -p - Specify egg polygon output for geometry.\n" - " -P - Specify frame number for static pose.\n" - " -b - Specify starting frame for animation (default = first).\n" - " -e - Specify ending frame for animation (default = last).\n" - " -f - Specify frame rate for animation playback.\n" - " -a - Compile animation tables if animation present.\n" - " -F - Ignore hierarchy and build a completely flat skeleton.\n" - " -v - Set debug level.\n" - " -x - Shift NURBS parameters to preserve Alias textures.\n" - " -i - Ignore Soft texture uv offsets.\n" - " -u - Use Soft prefix in model names.\n" - " -c - Cancel morph conversion.\n" - " -C - Cancel duv conversion.\n" - " -D - Don't make the output model a character.\n" - " -o - Convert only models with given prefix.\n"; - - // EggBase::ShowOpts(); -} - -/** - * Calls getopt() to parse the command-line switches. Calls HandleGetopts() - * to interpret each switch. Returns true if the parsing was successful; - * false if there was an error. Adjusts argc and argv to remove the switches - * from the parameter list. - */ -bool SoftToEggConverter:: -DoGetopts(int &argc, char **&argv) { - bool okflag = true; - int i = 0; - softegg_cat.info() << "argc " << argc << "\n"; - if (argc <2) { - Usage(); - okflag = false; - } - while( i < argc ) { - strcat(_commandLine, argv[i]); - strcat(_commandLine, " "); - ++i; - } - softegg_cat.info() << endl << _commandLine << endl; - - i = 1; - while ((i < argc) && (argv[i][0] == '-') && okflag) { - softegg_cat.info() << "arg " << i << " is " << argv[i] << "\n"; - okflag = HandleGetopts(i, argc, argv); - } - return okflag; -} - -/** - * increment idx based on what kind of option parsed Supported options are as - * follows: r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD - */ -bool SoftToEggConverter:: -HandleGetopts(int &idx, int argc, char **argv) -{ - bool okflag = true; - - char flag = argv[idx][1]; // skip the '-' from option - - switch (flag) - { - case 'r': // Set the resource path for soft. - if ( strcmp( argv[idx+1], "" ) ) { - // Get the path. - rsrc_path = argv[idx+1]; - softegg_cat.info() << "using rsrc path " << rsrc_path << "\n"; - } - ++idx; - break; - - case 'd': // Set the database path. - if ( strcmp( argv[idx+1], "" ) ) { - // Get the path. - database_name = argv[idx+1]; - softegg_cat.info() << "using database " << database_name << "\n"; - } - ++idx; - break; - - case 's': // Check if its a scene. - if ( strcmp( argv[idx+1], "" ) ) { - // Get scene name. - scene_name = argv[idx+1]; - softegg_cat.info() << "loading scene " << scene_name << "\n"; - } - ++idx; - break; - - case 'm': // Check if its a model. - if ( strcmp( argv[idx+1], "" ) ) { - // Get model name. - model_name = argv[idx+1]; - softegg_cat.info() << "loading model " << model_name << endl; - } - ++idx; - break; - - case 't': // Get converted texture path. - if ( strcmp( argv[idx+1], "" ) ) { - // Get tex path name. - tex_path = argv[idx+1]; - softegg_cat.info() << "texture path: " << tex_path << endl; - } - ++idx; - break; - - case 'T': // Specify texture list filename. - if ( strcmp( argv[idx+1], "") ) { - // Get the name. - tex_filename = argv[idx+1]; - softegg_cat.info() << "creating texture list file: " << tex_filename << endl; - } - ++idx; - break; - - case 'S': // Set NURBS step. - if ( strcmp( argv[idx+1], "" ) ) { - nurbs_step = atoi(argv[idx+1]); - softegg_cat.info() << "NURBS step: " << nurbs_step << endl; - } - ++idx; - break; - - case 'M': // Set model output file name. - if ( strcmp( argv[idx+1], "" ) ) { - eggFileName = argv[idx+1]; - softegg_cat.info() << "Model output filename: " << eggFileName << endl; - } - ++idx; - break; - - case 'A': // Set anim output file name. - if ( strcmp( argv[idx+1], "" ) ) { - animFileName = argv[idx+1]; - softegg_cat.info() << "Anim output filename: " << animFileName << endl; - } - ++idx; - break; - - case 'N': // Set egg model name. - if ( strcmp( argv[idx+1], "" ) ) { - eggGroupName = argv[idx+1]; - softegg_cat.info() << "Egg group name: " << eggGroupName << endl; - } - ++idx; - break; - - case 'o': // Set search_prefix. - if ( strcmp( argv[idx+1], "" ) ) { - search_prefix = argv[idx+1]; - softegg_cat.info() << "Only converting models with prefix: " << search_prefix << endl; - } - ++idx; - break; - - case 'h': // print help message - Help(); - exit(1); - break; - - case 'c': // Cancel morph animation conversion - make_morph = FALSE; - softegg_cat.info() << "canceling morph conversion\n"; - break; - - case 'C': // Cancel uv animation conversion - make_duv = FALSE; - softegg_cat.info() << "canceling uv animation conversion\n"; - break; - - case 'D': // Omit the Dart flag - make_dart = FALSE; - softegg_cat.info() << "making a non-character model\n"; - break; - - case 'k': // Enable soft skinning - // make_soft = TRUE; fprintf( outStream, "enabling soft skinning\n" ); - softegg_cat.info() << "-k flag no longer necessary\n"; - break; - - case 'n': // Generate egg NURBS output - make_nurbs = TRUE; - softegg_cat.info() << "outputting egg NURBS info\n"; - break; - - case 'p': // Generate egg polygon output - make_poly = TRUE; - softegg_cat.info() << "outputting egg polygon info\n"; - break; - - case 'P': // Generate static pose from given frame - if ( strcmp( argv[idx+1], "" ) ) { - make_pose = TRUE; - pose_frame = atoi(argv[idx+1]); - softegg_cat.info() << "generating static pose from frame " << pose_frame << endl; - } - ++idx; - break; - - case 'a': // Compile animation tables. - make_anim = TRUE; - softegg_cat.info() << "attempting to compile anim tables\n"; - break; - - case 'F': // Build a flat skeleton. - flatten = TRUE; - softegg_cat.info() << "building a flat skeleton!!!\n"; - break; - - case 'x': // Shift NURBS parameters to preserve Alias textures. - shift_textures = TRUE; - softegg_cat.info() << "shifting NURBS parameters...\n"; - break; - - case 'i': // Ignore Soft uv texture offsets - ignore_tex_offsets = TRUE; - softegg_cat.info() << "ignoring texture offsets...\n"; - break; - - case 'u': // Use Soft prefix in model names - use_prefix = TRUE; - softegg_cat.info() << "using prefix in model names...\n"; - break; - - - case 'v': // print debug messages. - if ( strcmp( argv[idx+1], "" ) ) { - verbose = atoi(argv[idx+1]); - softegg_cat.info() << "using debug level " << verbose << endl; - } - ++idx; - break; - - case 'b': // Set animation start frame. - anim_start = atoi(argv[idx]+2); - softegg_cat.info() << "animation starting at frame: " << anim_start << endl; - break; - - case 'e': /// Set animation end frame. - anim_end = atoi(argv[idx]+2); - softegg_cat.info() << "animation ending at frame: " << anim_end << endl; - break; - - case 'f': /// Set animation frame rate. - if ( strcmp( argv[idx+1], "" ) ) { - anim_rate = atoi(argv[idx+1]); - softegg_cat.info() << "animation frame rate: " << anim_rate << endl; - } - ++idx; - break; - - default: - softegg_cat.info() << flag << " flag not supported\n"; - okflag = false; - } - idx++; - return (okflag); -} - -/** - * Allocates and returns a new copy of the converter. - */ -SomethingToEggConverter *SoftToEggConverter:: -make_copy() { - return new SoftToEggConverter(*this); -} - -/** - * Returns the English name of the file type this converter supports. - */ -string SoftToEggConverter:: -get_name() const { - return "Soft"; -} - -/** - * Returns the common extension of the file type this converter supports. - */ -string SoftToEggConverter:: -get_extension() const { - return "mb"; -} - -/** - * Returns the English name of the file type this converter supports. - */ -SoftNodeDesc *SoftToEggConverter:: -find_node(string name) { - return _tree.get_node(name); -} - -/** - * Given a texture element, return texture name with given tex_path - */ -char *SoftToEggConverter:: -GetTextureName( SAA_Scene *scene, SAA_Elem *texture ) { - char *fileName = new char[_MAX_PATH]; - char tempName[_MAX_PATH]; - SAA_texture2DGetPicName( scene, texture, _MAX_PATH, tempName ); - - if (tex_path) { - // softegg_cat.spam() << "tempName :" << tempName << endl; - strcpy(fileName, tex_path); - - // do some processing on the name string - char *tmpName = nullptr; - tmpName = strrchr(tempName, '/'); - if (tmpName) - tmpName++; - else - tmpName = tempName; - - // softegg_cat.spam() << "tmpName : " << tmpName << endl; - strcat(fileName, "/"); - strcat(fileName, tmpName); - } - else { - strcpy(fileName, tempName); - } - - strcat(fileName, ".pic"); - // softegg_cat.spam() << "fileName : " << fileName << endl; - - return fileName; -} - -/** - * Handles the reading of the input file and converting it to egg. Returns - * true if successful, false otherwise. - * - * This is designed to be as generic as possible, generally in support of run- - * time loading. Also see convert_soft(). - */ -bool SoftToEggConverter:: -convert_file(const Filename &filename) { - if (!open_api()) { - softegg_cat.error() - << "Soft is not available.\n"; - return false; - } - if (_character_name.empty()) { - _character_name = filename.get_basename_wo_extension(); - } - return convert_soft(false); -} - -/** - * Fills up the egg_data structure according to the global soft model data. - * Returns true if successful, false if there is an error. If from_selection - * is true, the converted geometry is based on that which is selected; - * otherwise, it is the entire Soft scene. - */ -bool SoftToEggConverter:: -convert_soft(bool from_selection) { - bool all_ok = true; - - _from_selection = from_selection; - _textures.clear(); - - PT(EggData) egg_data = new EggData; - set_egg_data(egg_data); - softegg_cat.spam() << "eggData " << get_egg_data() << "\n"; - - // append the command line - softegg_cat.info() << _commandLine << endl; - get_egg_data()->insert(get_egg_data()->begin(), new EggComment("", _commandLine)); - - if (_egg_data->get_coordinate_system() != CS_default) { - softegg_cat.spam() << "coordinate system is not default\n"; - exit(1); - } - - _tree._use_prefix = use_prefix; - _tree._search_prefix = search_prefix; - all_ok = _tree.build_complete_hierarchy(scene, database); - - // Lets see if we have gotten the hierarchy right _tree.print_hierarchy(); - // exit(1); - - char *root_name = _tree.GetRootName( eggFileName ); - - softegg_cat.debug() << "main group name: " << root_name << endl; - if (root_name) - _character_name = root_name; - - if (make_poly || make_nurbs) { - // Specify that the texture names should be relative to the output file. - Filename output_filename(eggFileName); - _path_replace->_path_store = PS_relative; - _path_replace->_path_directory = output_filename.get_dirname(); - - if (!convert_char_model()) { - all_ok = false; - } - - // generate soft skinning assignments if desired - if (!make_soft_skin()) { - all_ok = false; - } - - // sometimes you need to hard assign some vertices - if (!cleanup_soft_skin()) { - all_ok = false; - } - - // reparent_decals(get_egg_data()); - softegg_cat.info() << "Converted Softimage file\n"; - - // write out the egg model file - _egg_data->write_egg(output_filename); - softegg_cat.info() << "Wrote Egg file " << output_filename << endl; - } - if (make_anim) { - if (!convert_char_chan()) { - all_ok = false; - } - - // reparent_decals(get_egg_data()); - softegg_cat.info() << "Converted Softimage file\n"; - - // write out the egg model file - _egg_data->write_egg(Filename(animFileName)); - softegg_cat.info() << "Wrote Anim file " << animFileName << endl; - } - return all_ok; -} - -/** - * Attempts to open the Soft API if it was not already open, and returns true - * if successful, or false if there is an error. - */ -bool SoftToEggConverter:: -open_api() { - if ((scene_name == nullptr && model_name == nullptr) || database_name == nullptr) { - Usage(); - exit( 1 ); - } - if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS) { - softegg_cat.info() << "Error: Couldn't get resource path!\n"; - exit( 1 ); - } - // cout << "got past init" << endl; - if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS) { - softegg_cat.info() << "Error: Couldn't load database!\n"; - exit( 1 ); - } - // cout << "got past database load" << endl; - if ((result = SAA_sceneGetCurrent(&scene)) != SI_SUCCESS) { - softegg_cat.info() << "Error: Couldn't get current scene!\n"; - exit( 1 ); - } - // cout << "got past get current" << endl; - if ((result = SAA_sceneLoad( &database, scene_name, &scene )) != SI_SUCCESS) { - softegg_cat.info() << "Error: Couldn't load scene " << scene_name << "!\n"; - exit( 1 ); - } - // cout << "got past scene load" << endl; - if ( SAA_updatelistGet( &scene ) == SI_SUCCESS ) { - PN_stdfloat time; - - softegg_cat.info() << "setting Scene to frame " << pose_frame << "...\n"; - // SAA_sceneSetPlayCtrlCurrentFrame( &scene, pose_frame ); - SAA_frame2Seconds( &scene, pose_frame, &time ); - SAA_updatelistEvalScene( &scene, time ); - if ( make_pose ) - SAA_sceneFreeze(&scene); - } - - // if no egg filename specified, make up a name - if ( eggFileName == nullptr ) { - string madeName; - string tempName(scene_name); - string::size_type end = tempName.find(".dsc"); - if (end != string::npos) { - madeName.assign(tempName.substr(0,end)); - if ( make_nurbs ) - madeName.insert(madeName.size(), "-nurb"); - madeName.insert(madeName.size(), ".egg" ); - } - eggFileName = new char[madeName.size()+1]; - strcpy(eggFileName, madeName.c_str()); - - // if no anim filename specified, make up a name - if ( animFileName == nullptr ) { - madeName.assign(tempName.substr(0,end)); - madeName.insert(madeName.size(), "-chan.egg"); - animFileName = new char[strlen(scene_name)+ 10]; - strcpy(animFileName, madeName.c_str()); - } - } - - return true; -} - -/** - * Closes the Soft API, if it was previously opened. Caution! Soft appears - * to call exit() when its API is closed. - */ -void SoftToEggConverter:: -close_api() { - // don't know yet -} - -/** - * Converts the file as an animatable character model, with joints and vertex - * membership. - */ -bool SoftToEggConverter:: -convert_char_model() { - softegg_cat.spam() << "character name " << _character_name << "\n"; - EggGroup *char_node = new EggGroup(eggGroupName); - get_egg_data()->add_child(char_node); - char_node->set_dart_type(EggGroup::DT_default); - - return convert_hierarchy(char_node); -} - -/** - * Given a tablename, it either creates a new eggSAnimData structure (if - * doesn't exist) or locates it. - */ -EggSAnimData *SoftToEggConverter:: -find_morph_table(char *name) { - EggSAnimData *anim = nullptr; - MorphTable::iterator mt; - for (mt = _morph_table.begin(); mt != _morph_table.end(); ++mt) { - anim = (*mt); - if (!strcmp(anim->get_name().c_str(), name)) - return anim; - } - - // create an entry - anim = new EggSAnimData(name); - anim->set_fps(_tree._fps); - _morph_table.push_back(anim); - morph_node->add_child(anim); - return anim; -} - -/** - * Converts the animation as a series of tables to apply to the character - * model, as retrieved earlier via AC_model. - */ -bool SoftToEggConverter:: -convert_char_chan() { - int start_frame = -1; - int end_frame = -1; - int frame_inc, frame; - double output_frame_rate = anim_rate; - - PN_stdfloat time; - - EggTable *root_table_node = new EggTable(); - get_egg_data()->add_child(root_table_node); - EggTable *bundle_node = new EggTable(eggGroupName); - bundle_node->set_table_type(EggTable::TT_bundle); - root_table_node->add_child(bundle_node); - EggTable *skeleton_node = new EggTable(""); - bundle_node->add_child(skeleton_node); - - morph_node = new EggTable("morph"); - - // Set the frame rate before we start asking for anim tables to be created. - SAA_sceneGetPlayCtrlStartFrame(&scene, &start_frame); - SAA_sceneGetPlayCtrlEndFrame(&scene, &end_frame); - SAA_sceneGetPlayCtrlFrameStep( &scene, &frame_inc ); - if (frame_inc != 1) // Hmmm...some files gave me frame_inc of 0, that can't be good - frame_inc = 1; - - softegg_cat.info() << "animation start frame: " << start_frame << " end frame: " << end_frame << endl; - softegg_cat.info() << "animation frame inc: " << frame_inc << endl; - - _tree._fps = output_frame_rate / frame_inc; - // _tree.clear_egg(get_egg_data(), NULL, root_node); - _tree.clear_egg(get_egg_data(), nullptr, skeleton_node); - - // Now we can get the animation data by walking through all of the frames, - // one at a time, and getting the joint angles at each frame. - - // This is just a temporary EggGroup to receive the transform for each joint - // each frame. - PT(EggGroup) tgroup = new EggGroup; - - int num_nodes = _tree.get_num_nodes(); - int i; - - // MTime frame(start_frame, MTime::uiUnit()); MTime frame_stop(end_frame, - // MTime::uiUnit()); start at first frame and go to last - if (make_pose) { - start_frame = pose_frame; - end_frame = pose_frame; - } - if (anim_start > 0) - start_frame = anim_start; - if (anim_end > 0) - end_frame = anim_end; - for ( frame = start_frame; frame <= end_frame; frame += frame_inc) { - SAA_frame2Seconds( &scene, frame, &time ); - // softegg_cat.spam() << "got time " << time << endl; - if (!make_pose) { - SAA_updatelistEvalScene( &scene, time ); - } - softegg_cat.spam() << "\n> animating frame " << frame << endl; - - // if (softegg_cat.is_debug()) { softegg_cat.debug(false) - softegg_cat.info() << "frame " << time << "\n"; - // } else { We have to write to cerr instead of softegg_cat to allow - // flushing without writing a newline. std::cerr << "." << std::flush; } - // MGlobal::viewFrame(frame); - - for (i = 0; i < num_nodes; i++) { - SoftNodeDesc *node_desc = _tree.get_node(i); - - if (node_desc->is_partial(search_prefix)) { - softegg_cat.debug() << endl; - continue; - } - if (make_morph) { - node_desc->make_morph_table(time); - } - if (node_desc->is_joint()) { - softegg_cat.spam() << "-----joint " << node_desc->get_name() << "\n"; - EggXfmSAnim *anim = _tree.get_egg_anim(node_desc); - // following function fills in the anim structure - node_desc->get_joint_transform(&scene, tgroup, anim, TRUE); - } - } - - // frame += frame_inc; - } - - if (has_morph) - bundle_node->add_child(morph_node); - - // Now optimize all of the tables we just filled up, for no real good - // reason, except that it makes the resulting egg file a little easier to - // read. - for (i = 0; i < num_nodes; i++) { - SoftNodeDesc *node_desc = _tree.get_node(i); - if (node_desc->is_partial(search_prefix)) - continue; - - if (node_desc->is_joint()) { - _tree.get_egg_anim(node_desc)->optimize(); - } - } - - softegg_cat.info(false) - << "\n"; - - return true; -} - -/** - * Generates egg structures for each node in the Soft hierarchy. - */ -bool SoftToEggConverter:: -convert_hierarchy(EggGroupNode *egg_root) { - int num_nodes = _tree.get_num_nodes(); - - _tree.clear_egg(get_egg_data(), egg_root, nullptr); - softegg_cat.spam() << "num_nodes = " << num_nodes << endl; - for (int i = 0; i < num_nodes; i++) { - if (!process_model_node(_tree.get_node(i))) { - return false; - } - softegg_cat.debug() << i << endl; - } - return true; -} - -/** - * Converts the indicated Soft node (given a MDagPath, similar in concept to - * Panda's NodePath) to the corresponding Egg structure. Returns true if - * successful, false if an error was encountered. - */ -bool SoftToEggConverter:: -process_model_node(SoftNodeDesc *node_desc) { - EggGroup *egg_group = nullptr; - const char *name = nullptr; - char *fullname = nullptr; - SAA_ModelType type; - - name = node_desc->get_name().c_str(); - softegg_cat.debug() << "element name <" << name << ">\n"; - - if (node_desc->is_junk()) { - softegg_cat.spam() << "no processing, it is junk\n"; - return true; - } - - // split - if (node_desc->is_partial(search_prefix)) { - softegg_cat.debug() << endl; - return true; - } - else - softegg_cat.debug() << endl << name << ":being processed" << endl; - - egg_group = _tree.get_egg_group(node_desc); - - // find out what type of node we're dealing with - SAA_modelGetType( &scene, node_desc->get_model(), &type ); - - softegg_cat.debug() << "encountered "; - switch(type){ - case SAA_MNILL: - softegg_cat.debug() << "null\n"; - break; - case SAA_MPTCH: - softegg_cat.debug() << "patch\n"; - break; - case SAA_MFACE: - softegg_cat.debug() << "face\n"; - // break; - case SAA_MSMSH: - softegg_cat.debug() << "mesh\n"; - node_desc->get_transform(&scene, egg_group, TRUE); - make_polyset(node_desc, egg_group, type); - break; - case SAA_MJNT: - softegg_cat.debug() << "joint"; - softegg_cat.debug() << " joint type " << node_desc->is_joint() << endl; - break; - case SAA_MSPLN: - softegg_cat.debug() << "spline\n"; - break; - case SAA_MMETA: - softegg_cat.debug() << "meta element\n"; - break; - case SAA_MBALL: - softegg_cat.debug() << "meta ball\n"; - break; - case SAA_MNCRV: - softegg_cat.debug() << "nurbs curve\n"; - break; - case SAA_MNSRF: - softegg_cat.debug() << "nurbs surf\n"; - node_desc->get_transform(&scene, egg_group, TRUE); - make_nurb_surface(node_desc, egg_group, type); - break; - default: - softegg_cat.debug() << "unknown type: " << type << "\n"; - } - - if (node_desc->is_joint()) - node_desc->get_transform(&scene, egg_group, FALSE); - - return true; -} - -/** - * Converts the indicated Soft polyset to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void SoftToEggConverter:: -make_polyset(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type) { - int id = 0; - int i, idx; - int numShapes; - SAA_Boolean valid; - SAA_Boolean visible; - PN_stdfloat *uCoords = nullptr; - PN_stdfloat *vCoords = nullptr; - string name = node_desc->get_name(); - - SAA_modelGetNodeVisibility( &scene, node_desc->get_model(), &visible ); - softegg_cat.spam() << "model visibility: " << visible << endl; - - // Only create egg polygon data if: the node is visible, and its not a NULL - // or a Joint, and we're outputing polys (or if we are outputing NURBS and - // the model is a poly mesh or a face) - if ( visible && - (type != SAA_MNILL) && - (type != SAA_MJNT) && - ((make_poly || - (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) || - (!make_poly && !make_nurbs && make_duv && - ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) - ) - { - // Get the number of key shapes - SAA_modelGetNbShapes( &scene, node_desc->get_model(), &numShapes ); - softegg_cat.spam() << "process_model_node: num shapes: " << numShapes << endl; - - // load all node data from soft for this node_desc - node_desc->load_poly_model(&scene, type); - - string vpool_name = name + ".verts"; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - vpool->set_highest_index(0); - - // add the vertices in the _tree._root node, so that they will be - // written out first in egg file. This solves a problem of soft- - // skinning trying to access vertex pool before it is defined. - - _tree.get_egg_root()->insert(_tree.get_egg_root()->begin(), vpool); - - // We will need to transform all vertices from world coordinate space - // into the vertex space appropriate to this node. Usually, this is the - // same thing as world coordinate space, and this matrix will be - // identity; but if the node is under an instance (particularly, for - // instance, a billboard) then the vertex space will be different from - // world space. - LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); - - // Asad: change from soft2egg.c. Here I am trying to get one triangles - // vertices not all - for (idx=0; idxnumTri; ++idx) { - EggPolygon *egg_poly = new EggPolygon; - egg_group->add_child(egg_poly); - - softegg_cat.spam() << "processing polygon " << idx << endl; - - // Is this a double sided polygon? meaning check for back face flag - char *modelNoteStr = _tree.GetModelNoteInfo( &scene, node_desc->get_model() ); - if ( modelNoteStr != nullptr ) { - if ( strstr( modelNoteStr, "bface" ) != nullptr ) - egg_poly->set_bface_flag(TRUE); - } - - // read each triangle's control vertices into array - SAA_SubElem cvertices[3]; - SAA_triangleGetCtrlVertices( &scene, node_desc->get_model(), node_desc->gtype, id, 1, node_desc->triangles+idx, cvertices ); - - // read control vertices in this triangle - SAA_DVector cvertPos[3]; - SAA_ctrlVertexGetPositions( &scene, node_desc->get_model(), 3, cvertices, cvertPos); - - // read indices of each vertices in this triangle - int indices[3]; - indices[0] = indices[1] = indices[2] = 0; - SAA_ctrlVertexGetIndices( &scene, node_desc->get_model(), 3, cvertices, indices ); - - // read each control vertex's normals into an array - SAA_DVector normals[3]; - SAA_ctrlVertexGetNormals( &scene, node_desc->get_model(), 3, cvertices, normals ); - for (i=0; i<3; ++i) - softegg_cat.spam() << "normals[" << i <<"] = " << normals[i].x << " " << normals[i].y - << " " << normals[i].z << " " << normals[i].w << "\n"; - - // allocate arrays for u & v coords - if (node_desc->textures) { - if (node_desc->numTexLoc && node_desc->numTexTri[idx]) { - // allocate arrays for u & v coords I think there are one texture - // per triangle hence we need only 3 corrdinates - uCoords = new PN_stdfloat[3]; - vCoords = new PN_stdfloat[3]; - - // read the u & v coords into the arrays - if ( uCoords != nullptr && vCoords != nullptr) { - for ( i = 0; i < 3; i++ ) - uCoords[i] = vCoords[i] = 0.0f; - - // TODO: investigate the coord_cnt parameter... - SAA_ctrlVertexGetUVTxtCoords( &scene, node_desc->get_model(), 3, cvertices, - 3, uCoords, vCoords ); - } - else - softegg_cat.info() << "Not enough Memory for texture coords...\n"; - -#if 1 - for ( i=0; i<3; i++ ) - softegg_cat.spam() << "texcoords[" << i << "] = ( " << uCoords[i] << " , " << vCoords[i] <<" )\n"; -#endif - } - else if (node_desc->numTexGlb) { - // allocate arrays for u & v coords - uCoords = new PN_stdfloat[node_desc->numTexGlb*3]; - vCoords = new PN_stdfloat[node_desc->numTexGlb*3]; - - for ( i = 0; i < node_desc->numTexGlb*3; i++ ) { - uCoords[i] = vCoords[i] = 0.0f; - } - - // read the u & v coords into the arrays - if ( uCoords != nullptr && vCoords != nullptr) { - SAA_triCtrlVertexGetGlobalUVTxtCoords( &scene, node_desc->get_model(), 3, cvertices, - node_desc->numTexGlb, node_desc->textures, uCoords, vCoords ); - } - else - softegg_cat.info() << "Not enough Memory for texture coords...\n"; - } - } - - for ( i=0; i < 3; i++ ) { - EggVertex vert; - - // There are some conversions needed from local matrix to global - // coords - SAA_DVector local = cvertPos[i]; - SAA_DVector global = {0}; - - _VCT_X_MAT( global, local, node_desc->matrix ); - - softegg_cat.spam() << "indices[" << i << "] = " << indices[i] << "\n"; - softegg_cat.spam() << "cvert[" << i << "] = " << cvertPos[i].x << " " << cvertPos[i].y - << " " << cvertPos[i].z << " " << cvertPos[i].w << "\n"; - softegg_cat.spam() << " global cvert[" << i << "] = " << global.x << " " << global.y - << " " << global.z << " " << global.w << "\n"; - - // LPoint3d p3d(cvertPos[i].x, cvertPos[i].y, cvertPos[i].z); - LPoint3d p3d(global.x, global.y, global.z); - p3d = p3d * vertex_frame_inv; - vert.set_pos(p3d); - - local = normals[i]; - _VCT_X_MAT( global, local, node_desc->matrix ); - - softegg_cat.spam() << "normals[" << i <<"] = " << normals[i].x << " " << normals[i].y - << " " << normals[i].z << " " << normals[i].w << "\n"; - softegg_cat.spam() << " global normals[" << i <<"] = " << global.x << " " << global.y - << " " << global.z << " " << global.w << "\n"; - - LVector3d n3d(global.x, global.y, global.z); - n3d = n3d * vertex_frame_inv; - vert.set_normal(n3d); - - // if texture present set the texture coordinates - if (node_desc->textures) { - PN_stdfloat u, v; - - if (uCoords && vCoords) { - u = uCoords[i]; - v = 1.0f - vCoords[i]; - softegg_cat.spam() << "texcoords[" << i << "] = " << u << " " - << v << endl; - - vert.set_uv(LTexCoordd(u, v)); - // vert.set_uv(LTexCoordd(uCoords[i], vCoords[i])); - } - } - vert.set_external_index(indices[i]); - egg_poly->add_vertex(vpool->create_unique_vertex(vert)); - - // check to see if material is present - PN_stdfloat r,g,b,a; - SAA_elementIsValid( &scene, &node_desc->materials[idx], &valid ); - // material present - get the color - if ( valid ) { - SAA_materialGetDiffuse( &scene, &node_desc->materials[idx], &r, &g, &b ); - SAA_materialGetTransparency( &scene, &node_desc->materials[idx], &a ); - egg_poly->set_color(LColor(r, g, b, 1.0f - a)); - softegg_cat.spam() << "color r = " << r << " g = " << g << " b = " << b << " a = " << 1.0f - a << "\n"; - } - else { // no material - default to white - egg_poly->set_color(LColor(1.0, 1.0, 1.0, 1.0)); - softegg_cat.spam() << "default color\n"; - } - - /* - // keep a one to one copy in this node's vpool - EggVertex *t_vert = new EggVertex(vert); - if (!t_vert) { - softegg_cat.spam() << "out of memeory " << endl; - nassertv(t_vert != NULL); - } - node_desc->get_vpool()->add_vertex(t_vert, indices[i]); - */ - - softegg_cat.spam() << "\n"; - } - - // Now apply the shader. - if (node_desc->textures != nullptr) { - if (node_desc->numTexLoc && node_desc->numTexTri[idx]) { - if (!strstr(node_desc->texNameArray[idx], "noIcon")) - set_shader_attributes(node_desc, *egg_poly, idx); - else - softegg_cat.spam() << "texname :" << node_desc->texNameArray[idx] << endl; - } - else { - if (!strstr(node_desc->texNameArray[0], "noIcon")) - set_shader_attributes(node_desc, *egg_poly, 0); - else - softegg_cat.spam() << "texname :" << node_desc->texNameArray[0] << endl; - } - } - } - // if model has key shapes, generate vertex offsets - if ( numShapes > 0 && make_morph ) - node_desc->make_vertex_offsets( numShapes); - } -} - -/** - * Converts the indicated Soft nurbs set to a bunch of EggPolygons and parents - * them to the indicated egg group. - */ -void SoftToEggConverter:: -make_nurb_surface(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type) { - int id = 0; - int i, j, k; - int numShapes; - SAA_Boolean valid; - SAA_Boolean visible; - PN_stdfloat *uCoords = nullptr; - PN_stdfloat *vCoords = nullptr; - string name = node_desc->get_name(); - - SAA_modelGetNodeVisibility( &scene, node_desc->get_model(), &visible ); - softegg_cat.spam() << "model visibility: " << visible << endl; - softegg_cat.spam() << "nurbs!!!surface!!!" << endl; - - // check to see if its a nurbs surface - if ( (type == SAA_MNSRF) && ( visible ) && (( make_nurbs ) - || ( !make_nurbs && !make_poly && make_duv )) ) - { - // Get the number of key shapes - SAA_modelGetNbShapes( &scene, node_desc->get_model(), &numShapes ); - softegg_cat.spam() << "process_model_node: num shapes: " << numShapes << endl; - - // load all node data from soft for this node_desc - node_desc->load_nurbs_model(&scene, type); - - string vpool_name = name + ".verts"; - EggVertexPool *vpool = new EggVertexPool(vpool_name); - vpool->set_highest_index(0); - - // add the vertices in the _tree._egg_root node, so that they will be - // written out first in egg file. This solves a problem of soft- - // skinning trying to access vertex pool before it is defined. - - // _tree.get_egg_root()->add_child(vpool); - _tree.get_egg_root()->insert(_tree.get_egg_root()->begin(), vpool); - - // egg_group->add_child(vpool); - - /* - // create a copy of vpool in node_desc which will be used later for - // soft_skinning - node_desc->create_vpool(vpool_name); - */ - - int uRows, vRows; - int uKnots, vKnots; - int uExtra, vExtra; - int uDegree, vDegree; - int uCurves, vCurves; - - vector Knots; - - EggNurbsSurface *eggNurbs = new EggNurbsSurface( name ); - - // create nurbs representation of surface - SAA_nurbsSurfaceGetDegree( &scene, node_desc->get_model(), &uDegree, &vDegree ); - softegg_cat.spam() << "nurbs degree: " << uDegree << " u, " << vDegree << " v\n"; - - SAA_nurbsSurfaceGetNbKnots( &scene, node_desc->get_model(), &uKnots, &vKnots ); - softegg_cat.spam() << "nurbs knots: " << uKnots << " u, " << vKnots << " v\n"; - - SAA_Boolean uClosed = FALSE; - SAA_Boolean vClosed = FALSE; - - SAA_nurbsSurfaceGetClosed( &scene, node_desc->get_model(), &uClosed, &vClosed); - - uExtra = vExtra = 2; - if ( uClosed ) { - softegg_cat.spam() << "nurbs is closed in u...\n"; - uExtra += 4; - } - if ( vClosed ) { - softegg_cat.spam() << "nurbs is closed in v...\n"; - vExtra += 4; - } - eggNurbs->setup(uDegree+1, vDegree+1, - uKnots + uExtra, vKnots + vExtra); - - softegg_cat.spam() << "from eggNurbs: num u knots " << eggNurbs->get_num_u_knots() << endl; - softegg_cat.spam() << "from eggNurbs: num v knots " << eggNurbs->get_num_v_knots() << endl; - softegg_cat.spam() << "from eggNurbs: num u cvs " << eggNurbs->get_num_u_cvs() << endl; - softegg_cat.spam() << "from eggNurbs: num v cvs " << eggNurbs->get_num_v_cvs() << endl; - - SAA_nurbsSurfaceGetNbVertices( &scene, node_desc->get_model(), &uRows, &vRows ); - softegg_cat.spam() << "nurbs vertices: " << uRows << " u, " << vRows << " v\n"; - - SAA_nurbsSurfaceGetNbCurves( &scene, node_desc->get_model(), &uCurves, &vCurves ); - softegg_cat.spam() << "nurbs curves: " << uCurves << " u, " << vCurves << " v\n"; - - if ( shift_textures ) { - if ( uClosed ) - // shift starting point on NURBS surface for correct textures - SAA_nurbsSurfaceShiftParameterization( &scene, node_desc->get_model(), -2, 0 ); - - if ( vClosed ) - // shift starting point on NURBS surface for correct textures - SAA_nurbsSurfaceShiftParameterization( &scene, node_desc->get_model(), 0, -2 ); - } - - SAA_nurbsSurfaceSetStep( &scene, node_desc->get_model(), nurbs_step, nurbs_step ); - - // Is this a double sided polygon? meaning check for back face flag - char *modelNoteStr = _tree.GetModelNoteInfo( &scene, node_desc->get_model() ); - if ( modelNoteStr != nullptr ) { - if ( strstr( modelNoteStr, "bface" ) != nullptr ) { - eggNurbs->set_bface_flag(TRUE); - softegg_cat.spam() << "Set backface flag\n"; - } - } - - double *uKnotArray = new double[uKnots]; - double *vKnotArray = new double[vKnots]; - result = SAA_nurbsSurfaceGetKnots( &scene, node_desc->get_model(), node_desc->gtype, 0, - uKnots, vKnots, uKnotArray, vKnotArray ); - - if (result != SI_SUCCESS) { - softegg_cat.spam() << "Couldn't get knots\n"; - exit(1); - } - - // Lets prepare the softimage knots and then assign to eggKnots - add_knots( Knots, uKnotArray, uKnots, uClosed, uDegree ); - softegg_cat.spam() << "u knots: "; - for (i = 0; i < (int)Knots.size(); i++) { - softegg_cat.spam() << Knots[i] << " "; - eggNurbs->set_u_knot(i, Knots[i]); - } - softegg_cat.spam() << endl; - - Knots.resize(0); - add_knots( Knots, vKnotArray, vKnots, vClosed, vDegree ); - softegg_cat.spam() << "v knots: "; - for (i = 0; i < (int)Knots.size(); i++) { - softegg_cat.spam() << Knots[i] << " "; - eggNurbs->set_v_knot(i, Knots[i]); - } - softegg_cat.spam() << endl; - - // lets get the number of vertices from softimage - int numVert; - SAA_modelGetNbVertices( &scene, node_desc->get_model(), &numVert ); - - softegg_cat.spam() << numVert << " CV's\n"; - - // get the CV's - SAA_DVector *vertices = nullptr; - vertices = new SAA_DVector[numVert]; - - SAA_modelGetVertices( &scene, node_desc->get_model(), node_desc->gtype, 0, numVert, vertices ); - - LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv(); - - // create the buffer for EggVertices - EggVertex *verts = new EggVertex[numVert]; - - softegg_cat.spam() << endl << eggNurbs->get_num_cvs() << endl << endl; - - // for ( i = 0; iget_num_cvs(); i++ ) { - for ( k = 0; kget_u_index(i); - int vi = eggNurbs->get_v_index(i); - - int k = vRows * ui + vi; - - softegg_cat.spam() << i << ": ui " << ui << ", vi " << vi << ", k " << k << endl; - - softegg_cat.spam() << "original cv[" << k << "] = " - << vertices[k].x << " " << vertices[k].y << " " - << vertices[k].z << " " << vertices[k].w << endl; - */ - - // convert to global coords - _VCT_X_MAT( global, vertices[k], node_desc->matrix ); - - // preserve original weight - global.w = vertices[k].w; - - // normalize coords to weight - global.x *= global.w; - global.y *= global.w; - global.z *= global.w; - - /* - softegg_cat.spam() << "global cv[" << k << "] = " - << global.x << " " << global.y << " " - << global.x << " " << global.w << endl; - */ - - LPoint4d p4d(global.x, global.y, global.z, global.w); - p4d = p4d * vertex_frame_inv; - verts[k].set_pos(p4d); - - // check to see if material is present - if (node_desc->numNurbMats) { - PN_stdfloat r,g,b,a; - SAA_elementIsValid( &scene, &node_desc->materials[0], &valid ); - // material present - get the color - if ( valid ) { - SAA_materialGetDiffuse( &scene, &node_desc->materials[0], &r, &g, &b ); - SAA_materialGetTransparency( &scene, &node_desc->materials[0], &a ); - verts[k].set_color(LColor(r, g, b, 1.0f - a)); - // softegg_cat.spam() << "color r = " << r << " g = " << g << " b - // = " << b << " a = " << a << "\n"; - } - else { // no material - default to white - verts[k].set_color(LColor(1.0, 1.0, 1.0, 1.0)); - softegg_cat.spam() << "default color\n"; - } - } - vpool->add_vertex(verts+k, k); - eggNurbs->add_vertex(vpool->get_vertex(k)); - - if ( uClosed ) { - // add first uDegree verts to end of row - if ( (k % uRows) == ( uRows - 1) ) { - for ( i = 0; i < uDegree; i++ ) { - // add vref's to NURBS info - eggNurbs->add_vertex( vpool->get_vertex(i+((k/uRows)*uRows)) ); - } - } - } - } - - // check to see if the NURB is closed in v - if ( vClosed && !uClosed ) { - // add first vDegree rows of verts to end of list - for ( int i = 0; i < vDegree*uRows; i++ ) - eggNurbs->add_vertex( vpool->get_vertex(i) ); - } - // check to see if the NURB is closed in u and v - else if ( vClosed && uClosed ) { - // add the first (degree) v verts and a few extra - for good measure - for ( i = 0; i < vDegree; i++ ) { - // add first vDegree rows of verts to end of list - for ( j = 0; j < uRows; j++ ) - eggNurbs->add_vertex( vpool->get_vertex(j+(i*uRows)) ); - - // if u is closed to we have added uDegree verts onto the ends of - // the rows - add them here too - for ( k = 0; k < uDegree; k++ ) - eggNurbs->add_vertex( vpool->get_vertex(k+(i*uRows)+((k/uRows)*uRows)) ); - } - } - - // We add the NURBS to the group down here, after all of the vpools for - // the trim curves have been added. - egg_group->add_child(eggNurbs); - - // Now apply the shader. - if (node_desc->textures != nullptr) { - if (!strstr(node_desc->texNameArray[0], "noIcon")) - set_shader_attributes(node_desc, *eggNurbs, 0); - else - softegg_cat.spam() << "texname :" << node_desc->texNameArray[0] << endl; - } - - // if model has key shapes, generate vertex offsets - if ( numShapes > 0 && make_morph ) - node_desc->make_vertex_offsets( numShapes); - } -} - -/** - * Given a parametric surface, and its knots, create the appropriate egg - * structure by filling in Soft's implicit knots and assigning the rest to - * eggKnots. - */ -void SoftToEggConverter:: -add_knots( vector &eggKnots, double *knots, int numKnots, SAA_Boolean closed, int degree ) { - - int k = 0; - double lastKnot = knots[0]; - double *newKnots; - - // add initial implicit knot(s) - if ( closed ) { - int i = 0; - newKnots = new double[degree]; - - // need to add (degree) number of knots - for ( k = numKnots - 1; k >= numKnots - degree; k-- ) { - // we have to know these in order to calculate next knot value so hold - // them in temp array - newKnots[i] = lastKnot - (knots[k] - knots[k-1]); - lastKnot = newKnots[i]; - i++; - } - for ( k = degree - 1; k >= 0; k-- ) { - eggKnots.push_back( newKnots[k] ); - softegg_cat.spam() << "knots[" << k << "] = " << newKnots[k] << endl; - } - } - else { - eggKnots.push_back( knots[k] ); - softegg_cat.spam() << "knots[" << k << "] = " << knots[k] << endl; - } - - // add the regular complement of knots - for (k = 0; k < numKnots; k++) { - eggKnots.push_back( knots[k] ); - softegg_cat.spam() << "knots[" << k+1 << "] = " << knots[k] << endl; - } - - lastKnot = knots[numKnots-1]; - - // add trailing implicit knots - if ( closed ) { - // need to add (degree) number of knots - for ( k = 1; k <= degree; k++ ) { - eggKnots.push_back( lastKnot + (knots[k] - knots[k-1]) ); - softegg_cat.spam() << "knots[" << k << "] = " << lastKnot + (knots[k] - knots[k-1]) << endl; - lastKnot = lastKnot + (knots[k] - knots[k-1]); - } - } - else { - eggKnots.push_back( knots[k-1] ); - softegg_cat.spam() << "knots[" << k+1 << "] = " << knots[k-1] << endl; - } -} - -/** - * Given an egg vertex pool, map each vertex therein to a vertex within an - * array of SAA model vertices of size numVert. Mapping is done by closest - * proximity. - */ -int *SoftToEggConverter:: -FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert ) { - int i,j; - int *vertMap = nullptr; - int vpoolSize = (int)vpool->size(); - PN_stdfloat closestDist; - PN_stdfloat thisDist; - int closest; - - vertMap = new int[vpoolSize]; - i = 0; - EggVertexPool::iterator vi; - for (vi = vpool->begin(); vi != vpool->end(); ++vi, ++i) { - EggVertex *vert = (*vi); - softegg_cat.spam() << "vert external index = " << vert->get_external_index() << endl; - // softegg_cat.spam() << "found vert " << vert << endl; softegg_cat.spam() - // << "vert [" << i << "] " << vpool->get_vertex(i+1); - LPoint3d p3d = vert->get_pos3(); - - // find closest model vertex - for ( j = 0; j < numVert; j++ ) { - // calculate distance - thisDist = sqrtf( - powf( p3d[0] - vertices[j].x , 2 ) + - powf( p3d[1] - vertices[j].y , 2 ) + - powf( p3d[2] - vertices[j].z , 2 ) ); - - // remember this if its the closest so far - if ( !j || ( thisDist < closestDist ) ) { - closest = j; - closestDist = thisDist; - } - } - - vertMap[i] = closest; - softegg_cat.spam() << "mapping v " << i << " of " << vpoolSize-1 << ":( " - << p3d[0] << " " - << p3d[1] << " " - << p3d[2] << ")\n"; - - softegg_cat.spam() << " to cv " << closest << " of " << numVert-1 << ":( " - << vertices[closest].x << " " - << vertices[closest].y << " " - << vertices[closest].z << " )\tdelta = " << closestDist << endl; - } - return vertMap; -} - -/** - * make soft skin assignments to the mesh finally call cleanup_soft_skin to - * clean it up - */ -bool SoftToEggConverter:: -make_soft_skin() { - int num_nodes = _tree.get_num_nodes(); - SoftNodeDesc *node_desc; - SAA_Boolean isSkeleton; - - softegg_cat.spam() << endl << "----------------------------------------------------------------" << endl; - - for (int i = 0; i < num_nodes; i++) { - node_desc = _tree.get_node(i); - SAA_modelIsSkeleton( &scene, node_desc->get_model(), &isSkeleton ); - - softegg_cat.spam() << "??checking node " << node_desc->get_name() << " isSkel " << isSkeleton << " isJoint " << node_desc->is_joint() << endl; - if (isSkeleton && node_desc->is_joint()) { - - if (node_desc->is_partial(search_prefix)) - continue; - - // Now that we've added all the polygons (and created all the vertices), - // go back through the vertex pool and set up the appropriate joint - // membership for each of the vertices. - - // check for envelops - int numEnv; - SAA_ModelType type; - SAA_Elem *envelopes; - SAA_Elem *model = node_desc->get_model(); - EggGroup *joint = nullptr; - EggVertexPool *vpool; - - SAA_skeletonGetNbEnvelopes( &scene, model, &numEnv ); - if ( numEnv == 0 ) { - softegg_cat.spam() << "no soft skinning for joint " << node_desc->get_name() << endl; - continue; - } - - // it's got envelopes - must be soft skinned - softegg_cat.spam() << endl << "found skeleton part( " << node_desc->get_name() << ")!\n"; - softegg_cat.spam() << "numEnv = " << numEnv << endl; - // allocate envelope array - envelopes = new SAA_Elem[numEnv]; - if ( envelopes == nullptr ) { - softegg_cat.info() << "Out Of Memory" << endl; - exit(1); - } - int thisEnv; - SAA_EnvType envType; - bool hasEnvVertices = 0; - - SAA_skeletonGetEnvelopes( &scene, model, numEnv, envelopes ); - for ( thisEnv = 0; thisEnv < numEnv; thisEnv++ ) { - softegg_cat.spam() << "env[" << thisEnv << "]: "; - SAA_envelopeGetType( &scene, &envelopes[thisEnv], &envType ); - - if ( envType == SAA_ENVTYPE_NONE ) { - softegg_cat.spam() << "envType = none\n"; - } - else if ( envType == SAA_ENVTYPE_FLXLCL ) { - softegg_cat.spam() << "envType = flexible, local\n"; - hasEnvVertices = 1; - } - else if ( envType == SAA_ENVTYPE_FLXGLB ) { - softegg_cat.spam() << "envType = flexible, global\n"; - hasEnvVertices = 1; - } - else if ( envType == SAA_ENVTYPE_RGDGLB ) { - softegg_cat.spam() << "envType = rigid, global\n"; - hasEnvVertices = 1; - } - else { - softegg_cat.spam() << "envType = unknown\n"; - } - - } - if ( !hasEnvVertices ) - continue; - - SAA_SubElem *envVertices = nullptr; - int *numEnvVertices; - int i,j,k; - - numEnvVertices = new int[numEnv]; - - if ( numEnvVertices != nullptr ) { - SAA_envelopeGetNbCtrlVertices( &scene, model, numEnv, envelopes, numEnvVertices ); - int totalEnvVertices = 0; - for( i = 0; i < numEnv; i++ ) { - totalEnvVertices += numEnvVertices[i]; - softegg_cat.spam() << "numEnvVertices[" << i << "] = " << numEnvVertices[i] << endl; - } - softegg_cat.spam() << "total env verts = " << totalEnvVertices << endl; - if ( totalEnvVertices == 0 ) - continue; - - envVertices = new SAA_SubElem[totalEnvVertices]; - if ( envVertices != nullptr ) { - result = SAA_envelopeGetCtrlVertices( &scene, model, - numEnv, envelopes, numEnvVertices, envVertices); - if (result != SI_SUCCESS) { - softegg_cat.spam() << "error: GetCtrlVertices\n"; - exit(1); - } - // loop through for each envelope - for ( i = 0; i < numEnv; i++ ) { - PN_stdfloat *weights = nullptr; - int vertArrayOffset = 0; - softegg_cat.spam() << "envelope[" << i << "]: "; - weights = new PN_stdfloat[numEnvVertices[i]]; - if ( weights ) { - char *envName; - int *vpoolMap = nullptr; - for ( j = 0; j < i; j++ ) - vertArrayOffset += numEnvVertices[j]; - softegg_cat.spam() << "envVertArray offset = " << vertArrayOffset; - - /* - if (vertArrayOffset == totalEnvVertices) { - softegg_cat.spam() << endl; vpoolMap = FindClosestTriVert( vpool, globalModelVertices, modelNumVert ); - - break; - } - */ - - // get the weights of the envelope vertices - result = SAA_ctrlVertexGetEnvelopeWeights( &scene, model, &envelopes[i], - numEnvVertices[i], - &envVertices[vertArrayOffset], weights ); - - // Get the name of the envelope model - if ( use_prefix ) { - // Get the FULL name of the envelope - envName = _tree.GetFullName( &scene, &envelopes[i] ); - } - else { - // Get the name of the envelope - envName = _tree.GetName( &scene, &envelopes[i] ); - } - - softegg_cat.spam() << " envelop name is [" << envName << "]" << endl; - - if (result != SI_SUCCESS) { - softegg_cat.spam() << "warning: this envelop doesn't have any weights\n"; - continue; - } - - result = SAA_modelGetType( &scene, &envelopes[i], &type ); - if (result != SI_SUCCESS) { - softegg_cat.debug() << "choked on get type\n"; - exit(1); - } - - softegg_cat.spam() << "envelope model type "; - if ( type == SAA_MSMSH ) - softegg_cat.spam() << "MESH\n"; - else if ( type == SAA_MNSRF ) - softegg_cat.spam() << "NURBS\n"; - else - softegg_cat.spam() << "OTHER\n"; - - int *envVtxIndices = nullptr; - envVtxIndices = new int[numEnvVertices[i]]; - - // Get the envelope vertex indices - result = SAA_ctrlVertexGetIndices( &scene, &envelopes[i], numEnvVertices[i], - &envVertices[vertArrayOffset], envVtxIndices ); - - if (result != SI_SUCCESS) { - softegg_cat.debug() << "error: choked on get indices\n"; - exit(1); - } - - // find out how many vertices the model has - int modelNumVert; - - SAA_modelGetNbVertices( &scene, &envelopes[i], &modelNumVert ); - - SAA_DVector *modelVertices = nullptr; - modelVertices = new SAA_DVector[modelNumVert]; - - // get the model vertices - SAA_modelGetVertices( &scene, &envelopes[i], - SAA_GEOM_ORIGINAL, 0, modelNumVert, - modelVertices ); - - // create array of global model coords - SAA_DVector *globalModelVertices = nullptr; - globalModelVertices = new SAA_DVector[modelNumVert]; - PN_stdfloat matrix[4][4]; - - // tranform local model vert coords to global - - // first get the global matrix - SAA_modelGetMatrix( &scene, &envelopes[i], SAA_COORDSYS_GLOBAL, matrix ); - - // populate array of global model verts - for ( j = 0; j < modelNumVert; j++ ) { - _VCT_X_MAT( globalModelVertices[j], - modelVertices[j], matrix ); - } - - // Get the vpool - string s_name = envName; - SoftNodeDesc *mesh_node = find_node(s_name); - if (!mesh_node) { - softegg_cat.debug() << "error: node " << s_name << " not found in tree\n"; - exit(1); - } - string vpool_name = s_name + ".verts"; - EggNode *t = _tree.get_egg_root()->find_child(vpool_name); - if (t) - DCAST_INTO_R(vpool, t, nullptr); - - // find the mapping of the vertices that match this envelop - if (vpool) { - softegg_cat.spam() << "found vpool of size " << vpool->size() << endl; - if ( !make_nurbs || (type == SAA_MSMSH) ) { - vpoolMap = FindClosestTriVert( vpool, globalModelVertices, modelNumVert ); - } - } - else { - softegg_cat.debug() << "warning: vpool " << vpool_name << " not found\n"; - continue; // could be because of not visible - } - - joint = node_desc->get_egg_group(); - // for every envelope vertex - for (j = 0; j < numEnvVertices[i]; j++) { - double scaledWeight = weights[j]/ 100.0f; - - // make sure its in legal range - if (( envVtxIndices[j] < modelNumVert ) - && ( envVtxIndices[j] >= 0 )) { - if ( (type == SAA_MNSRF) && make_nurbs ) { - // assign all referenced control vertices - EggVertex *vert = vpool->get_vertex(envVtxIndices[j]); - if (!vert) { - softegg_cat.debug() << "possible error: index " << envVtxIndices[j] << ": vert is " << vert << endl; - continue; - } - joint->ref_vertex( vert, scaledWeight ); - softegg_cat.spam() << j << ": adding vref to cv " << envVtxIndices[j] - << " with weight " << scaledWeight << endl; - - /* - envPool->Vertex(envVtxIndices[j])->AddJoint( joint, scaledWeight ); - // set flag to show this vertex has been assigned - envPool->Vertex(envVtxIndices[j])->multipleJoints = 1; - */ - } - else { - // assign all the tri verts associated with this control - // vertex to joint - softegg_cat.spam() << j << "--trying to find " << envVtxIndices[j] << endl; - for ( k = 0; k < (int)vpool->size(); k++ ) { - if ( vpoolMap[k] == envVtxIndices[j] ) { - EggVertex *vert = vpool->get_vertex(k+1); - // EggVertex *vert = - // mesh_node->get_vpool()->get_vertex(vpoolMap[k]+1); - if (!vert) { - softegg_cat.debug() << "possible error: index " << k+1 << ": vert is " << vert << endl; - break; - } - - joint->ref_vertex(vert, scaledWeight); - softegg_cat.spam() << j << ": adding vref from cv " << envVtxIndices[j] - << " to vert " << k+1 << " with weight " << scaledWeight - << "(vpool)\n"; - /* - envPool->Vertex(k)->AddJoint( joint, scaledWeight ); - // set flag to show this vertex has been assigned - envPool->Vertex(k)->multipleJoints = 1; - */ - } - } - } - } - } - } - } - } - } - } - } - return true; -} -/** - * Given a model, make sure all its vertices have been soft assigned. If not - * hard assign to the last joint we saw. - */ -bool SoftToEggConverter:: -cleanup_soft_skin() -{ - int num_nodes = _tree.get_num_nodes(); - SoftNodeDesc *node_desc; - - softegg_cat.spam() << endl << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl; - - for (int i = 0; i < num_nodes; i++) { - node_desc = _tree.get_node(i); - if (node_desc->is_partial(search_prefix)) - continue; - - SAA_Elem *model = node_desc->get_model(); - EggGroup *joint = nullptr; - EggVertexPool *vpool = nullptr; - SAA_ModelType type; - - // find out what type of node we're dealing with - - SAA_modelGetType( &scene, model, &type ); - - softegg_cat.debug() << "Cleaning up model------- " << node_desc->get_name() << endl; - - // this step is weird - I think I want it here but it seems to break some - // models. Files like props-props_wh_cookietime.3-0 in - // fulrndpubvrmlchipchips_adventurecharzone1roomswarehouse_final need to - // do the "if (skel)" bit. - - // find the vpool for this model - string vpool_name = node_desc->get_name() + ".verts"; - EggNode *t = _tree.get_egg_root()->find_child(vpool_name); - if (t) - DCAST_INTO_R(vpool, t, nullptr); - - if (!vpool) { - // softegg_cat.spam() << "couldn't find vpool " << vpool_name << endl; - continue; - } - - int numVerts = (int)vpool->size(); - softegg_cat.spam() << "found vpool " << vpool_name << " w/ " << numVerts << " verts\n"; - - // if this node is a joint, then these vertices belong to this joint - if (node_desc->is_joint()) - joint = node_desc->get_egg_group(); - else { - // find the closest _parentJoint - SoftNodeDesc *parentJ = node_desc; - while( parentJ && !parentJ->_parentJoint) { - if ( parentJ->_parent) { - SAA_Boolean isSkeleton; - // softegg_cat.spam() << " checking parent " << - // parentJ->_parent->get_name() << endl; - if (parentJ->_parent->has_model()) - SAA_modelIsSkeleton( &scene, parentJ->_parent->get_model(), &isSkeleton ); - - if (isSkeleton) { - joint = parentJ->_parent->get_egg_group(); - softegg_cat.spam() << "parent to " << parentJ->_parent->get_name() << endl; - break; - } - - parentJ = parentJ->_parent; - } - else - break; - } - if (!joint && (!parentJ || !parentJ->_parentJoint)) { - softegg_cat.spam() << node_desc->get_name() << " has no _parentJoint?!" << endl; - continue; - } - - if (!joint) { - softegg_cat.spam() << "parent joint to " << parentJ->_parentJoint->get_name() << endl; - joint = parentJ->_parentJoint->get_egg_group(); - } - } - EggVertexPool::iterator vi; - double membership = 1.0f; - for ( vi = vpool->begin(); vi != vpool->end(); ++vi) { - EggVertex *vert = (*vi); - - // if this vertex has not been soft assigned, then hard assign it to the - // parentJoint - if ( vert->gref_size() == 0 ) { - - softegg_cat.spam() << "vert " << vert->get_external_index() << " not assigned!\n"; - - // hard skin this vertex - joint->ref_vertex( vert, 1.0f ); - } - } - } - return true; -} - -/** - * Applies the known shader attributes to the indicated egg primitive. - */ -void SoftToEggConverter:: -set_shader_attributes(SoftNodeDesc *node_desc, EggPrimitive &primitive, int idx) { - char *texName = node_desc->texNameArray[idx]; - EggTexture tex(texName, ""); - - Filename filename = Filename::from_os_specific(texName); - Filename fullpath = _path_replace->match_path(filename, get_model_path()); - tex.set_filename(_path_replace->store_path(fullpath)); - tex.set_fullpath(fullpath); - // tex.set_format(EggTexture::F_rgb); - apply_texture_properties(tex, node_desc->uRepeat[idx], node_desc->vRepeat[idx]); - - EggTexture *new_tex = _textures.create_unique_texture(tex, ~EggTexture::E_tref_name); - primitive.set_texture(new_tex); -} - -/** - * Applies all the appropriate texture properties to the EggTexture object, - * including wrap modes and texture matrix. - */ -void SoftToEggConverter:: -apply_texture_properties(EggTexture &tex, int uRepeat, int vRepeat) { - // Let's mipmap all textures by default. - tex.set_minfilter(EggTexture::FT_linear_mipmap_linear); - tex.set_magfilter(EggTexture::FT_linear); - - EggTexture::WrapMode wrap_u = uRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp; - EggTexture::WrapMode wrap_v = vRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp; - - tex.set_wrap_u(wrap_u); - tex.set_wrap_v(wrap_v); - /* - LMatrix3d mat = color_def.compute_texture_matrix(); - if (!mat.almost_equal(LMatrix3d::ident_mat())) { - tex.set_transform(mat); - } - */ -} -#if 0 -/** - * Compares the texture properties already on the texture (presumably set by a - * previous call to apply_texture_properties()) and returns false if they - * differ from that specified by the indicated color_def object, or true if - * they match. - */ -bool SoftToEggConverter:: -compare_texture_properties(EggTexture &tex, - const SoftShaderColorDef &color_def) { - bool okflag = true; - - EggTexture::WrapMode wrap_u = color_def._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp; - EggTexture::WrapMode wrap_v = color_def._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp; - - if (wrap_u != tex.determine_wrap_u()) { - // Choose the more general of the two. - if (wrap_u == EggTexture::WM_repeat) { - tex.set_wrap_u(wrap_u); - } - okflag = false; - } - if (wrap_v != tex.determine_wrap_v()) { - if (wrap_v == EggTexture::WM_repeat) { - tex.set_wrap_v(wrap_v); - } - okflag = false; - } - - LMatrix3d mat = color_def.compute_texture_matrix(); - if (!mat.almost_equal(tex.get_transform())) { - okflag = false; - } - - return okflag; -} -#endif -/** - * Recursively walks the egg hierarchy, reparenting "decal" type nodes below - * their corresponding "decalbase" type nodes, and setting the flags. - * - * Returns true on success, false if some nodes were incorrect. - */ -bool SoftToEggConverter:: -reparent_decals(EggGroupNode *egg_parent) { - bool okflag = true; - - // First, walk through all children of this node, looking for the one decal - // base, if any. - EggGroup *decal_base = nullptr; - pvector decal_children; - - EggGroupNode::iterator ci; - for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { - EggNode *child = (*ci); - if (child->is_of_type(EggGroup::get_class_type())) { - EggGroup *child_group = DCAST(EggGroup, child); - if (child_group->has_object_type("decalbase")) { - if (decal_base != nullptr) { - softegg_cat.error() - << "Two children of " << egg_parent->get_name() - << " both have decalbase set: " << decal_base->get_name() - << " and " << child_group->get_name() << "\n"; - okflag = false; - } - child_group->remove_object_type("decalbase"); - decal_base = child_group; - - } else if (child_group->has_object_type("decal")) { - child_group->remove_object_type("decal"); - decal_children.push_back(child_group); - } - } - } - - if (decal_base == nullptr) { - if (!decal_children.empty()) { - softegg_cat.warning() - << decal_children.front()->get_name() - << " has decal, but no sibling node has decalbase.\n"; - } - - } else { - if (decal_children.empty()) { - softegg_cat.warning() - << decal_base->get_name() - << " has decalbase, but no sibling nodes have decal.\n"; - - } else { - // All the decal children get moved to be a child of decal base. This - // usually will not affect the vertex positions, but it could if the - // decal base has a transform and the decal child is an instance node. - // So don't do that. - pvector::iterator di; - for (di = decal_children.begin(); di != decal_children.end(); ++di) { - EggGroup *child_group = (*di); - decal_base->add_child(child_group); - } - - // Also set the decal state on the base. - decal_base->set_decal_flag(true); - } - } - - // Now recurse on each of the child nodes. - for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) { - EggNode *child = (*ci); - if (child->is_of_type(EggGroupNode::get_class_type())) { - EggGroupNode *child_group = DCAST(EggGroupNode, child); - if (!reparent_decals(child_group)) { - okflag = false; - } - } - } - - return okflag; -} - -/** - * Returns the TransformType value corresponding to the indicated string, or - * TT_invalid. - */ -SoftToEggConverter::TransformType SoftToEggConverter:: -string_transform_type(const string &arg) { - if (cmp_nocase(arg, "all") == 0) { - return TT_all; - } else if (cmp_nocase(arg, "model") == 0) { - return TT_model; - } else if (cmp_nocase(arg, "dcs") == 0) { - return TT_dcs; - } else if (cmp_nocase(arg, "none") == 0) { - return TT_none; - } else { - return TT_invalid; - } -} - -/** - * Invokes the softToEggConverter class - */ -extern "C" int init_soft2egg(int argc, char **argv) { - stec._commandName = argv[0]; - stec.rsrc_path = "c:\\Softimage\\SOFT3D_3.9.2\\3D\\rsrc"; - - if (stec.DoGetopts(argc, argv)) { - // Create a Filename object and convert the file - Filename softFile(argv[1]); - stec.convert_file(softFile); - } - - return 0; -} diff --git a/pandatool/src/softegg/softToEggConverter.h b/pandatool/src/softegg/softToEggConverter.h deleted file mode 100644 index 05c26fa60f..0000000000 --- a/pandatool/src/softegg/softToEggConverter.h +++ /dev/null @@ -1,179 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softToEggConverter.h - * @author masad - * @date 2003-09-25 - */ - -#ifndef SOFTTOEGGCONVERTER_H -#define SOFTTOEGGCONVERTER_H - -#include "pandatoolbase.h" -#include "somethingToEggConverter.h" -#include "softNodeTree.h" - -#include "eggTextureCollection.h" -#include "distanceUnit.h" -#include "coordinateSystem.h" - -#ifdef _MIN -#undef _MIN -#endif -#ifdef _MAX -#undef _MAX -#endif - -#include -#include - -class EggData; -class EggGroup; -class EggTable; -class EggVertexPool; -class EggNurbsCurve; -class EggPrimitive; -class EggXfmSAnim; -class EggSAnimData; - - -/** - * This class supervises the construction of an EggData structure from a - * single Softimage file, or from the data already in th cout << "egg name - * = " << eggFilename << endl;e global Softimage model space. - * - */ -class SoftToEggConverter : public SomethingToEggConverter { -public: - SoftToEggConverter(const std::string &program_name = ""); - SoftToEggConverter(const SoftToEggConverter ©); - virtual ~SoftToEggConverter(); - - void Help(); - void Usage(); - void ShowOpts(); - - bool HandleGetopts(int &idx, int argc, char **argv); - bool DoGetopts(int &argc, char **&argv); - - SoftNodeDesc *find_node(std::string name); - int *FindClosestTriVert( EggVertexPool *vpool, SAA_DVector *vertices, int numVert ); - - virtual SomethingToEggConverter *make_copy(); - virtual std::string get_name() const; - virtual std::string get_extension() const; - - virtual bool convert_file(const Filename &filename); - bool convert_soft(bool from_selection); - bool open_api(); - void close_api(); - -private: - bool convert_flip(double start_frame, double end_frame, - double frame_inc, double output_frame_rate); - - bool make_soft_skin(); - bool cleanup_soft_skin(); - bool convert_char_chan(); - bool convert_char_model(); - bool convert_hierarchy(EggGroupNode *egg_root); - bool process_model_node(SoftNodeDesc *node_desc); - - void make_polyset(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type); - void make_nurb_surface(SoftNodeDesc *node_desc, EggGroup *egg_group, SAA_ModelType type); - void add_knots( vector &eggKnots, double *knots, int numKnots, SAA_Boolean closed, int degree ); - - void set_shader_attributes(SoftNodeDesc *node_desc, EggPrimitive &primitive, int idx); - void apply_texture_properties(EggTexture &tex, int uRepeat, int vRepeat); - - bool reparent_decals(EggGroupNode *egg_parent); - - std::string _program_name; - bool _from_selection; - - SI_Error result; - SAA_Elem model; - SAA_Database database; - -public: - - SoftNodeTree _tree; - - SAA_Scene scene; - - char *_getopts; - - // This is argv[0]. - const char *_commandName; - - // This is the entire command line. - char _commandLine[4096]; - - char *rsrc_path; - char *database_name; - char *scene_name; - char *model_name; - char *eggFileName; - char *animFileName; - char *eggGroupName; - char *tex_path; - char *tex_filename; - char *search_prefix; - - int nurbs_step; - int anim_start; - int anim_end; - int anim_rate; - int pose_frame; - int verbose; - int flatten; - int shift_textures; - int ignore_tex_offsets; - int use_prefix; - - bool foundRoot; - bool geom_as_joint; - bool make_anim; - bool make_nurbs; - bool make_poly; - bool make_soft; - bool make_morph; - bool make_duv; - bool make_dart; - bool has_morph; - bool make_pose; - - - char *GetTextureName( SAA_Scene *scene, SAA_Elem *texture ); - - EggTextureCollection _textures; - - bool _polygon_output; - double _polygon_tolerance; - - enum TransformType { - TT_invalid, - TT_all, - TT_model, - TT_dcs, - TT_none, - }; - TransformType _transform_type; - - static TransformType string_transform_type(const std::string &arg); - - typedef pvector MorphTable; - MorphTable _morph_table; - - EggTable *morph_node; - EggSAnimData *find_morph_table(char *name); -}; - -extern const int TEX_PER_MAT; - -#endif diff --git a/pandatool/src/softprogs/softCVS.cxx b/pandatool/src/softprogs/softCVS.cxx deleted file mode 100644 index 478aa682d2..0000000000 --- a/pandatool/src/softprogs/softCVS.cxx +++ /dev/null @@ -1,588 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softCVS.cxx - * @author drose - * @date 2000-11-10 - */ - -#include "softCVS.h" - -#include "pnotify.h" -#include "multifile.h" - -#include - -using std::string; - -/** - * - */ -SoftCVS:: -SoftCVS() { - _cvs_binary = "cvs"; - - set_program_brief("prepare a SoftImage database directory for adding to CVS"); - set_program_description - ("softcvs is designed to prepare a directory hierarchy " - "representing a SoftImage database for adding to CVS. " - "First, it eliminates SoftImage's silly filename-based " - "versioning system by renaming versioned filenames higher " - "than 1-0 back to version 1-0. Then, it rolls up all the " - "files for each scene except the texture images into a Panda " - "multifile, which is added to CVS; the texture images are " - "directly added to CVS where they are.\n\n" - - "The reduction of hundreds of SoftImage files per scene down to one " - "multifile and a handle of texture images should greatly improve " - "the update and commit times of CVS.\n\n" - - "You must run this from within the root of a SoftImage database " - "directory; e.g. the directory that contains SCENES, PICTURES, MODELS, " - "and so on."); - - clear_runlines(); - add_runline("[opts]"); - - add_option - ("nc", "", 80, - "Do not attempt to add newly-created files to CVS. The default " - "is to add them.", - &SoftCVS::dispatch_none, &_no_cvs); - - add_option - ("cvs", "cvs_binary", 80, - "Specify how to run the cvs program for adding newly-created files. " - "The default is simply \"cvs\".", - &SoftCVS::dispatch_string, nullptr, &_cvs_binary); -} - - -/** - * - */ -void SoftCVS:: -run() { - // First, check for the scenes directory. If it doesn't exist, we must not - // be in the root of a soft database. - Filename scenes = "SCENES/."; - if (!scenes.exists()) { - nout << "No SCENES directory found; you are not in the root of a " - "SoftImage database.\n"; - exit(1); - } - - // Also, if we're expecting to use CVS, make sure the CVS directory exists. - Filename cvs_entries = "CVS/Entries"; - if (!_no_cvs && !cvs_entries.exists()) { - nout << "You do not appear to be within a CVS-controlled source " - "directory.\n"; - exit(1); - } - - // Scan all the files in the database. - traverse_root(); - - // Collapse out the higher-versioned scene files. - collapse_scene_files(); - - // Now determine which element files are actually referenced by at least one - // of the scene files. - if (!get_scenes()) { - exit(1); - } - - // Finally, remove all the element files that are no longer referenced by - // any scenes. - remove_unused_elements(); - - // Now do all the cvs adding and removing we need. - if (!_no_cvs) { - cvs_add_or_remove("remove", _cvs_remove); - cvs_add_or_remove("add -kb", _cvs_add); - } -} - -/** - * Reads all of the toplevel directory names, e.g. SCENES, MATERIALS, etc., - * and traverses them. - */ -void SoftCVS:: -traverse_root() { - Filename root("."); - - // Get the list of subdirectories. - vector_string subdirs; - if (!root.scan_directory(subdirs)) { - nout << "Unable to scan directory.\n"; - return; - } - - vector_string::const_iterator di; - for (di = subdirs.begin(); di != subdirs.end(); ++di) { - Filename subdir = (*di); - if (subdir.is_directory() && subdir != "CVS") { - traverse_subdir(subdir); - } - } -} - -/** - * Reads the directory indicated by prefix and identifies all of the SoftImage - * files stored there. - */ -void SoftCVS:: -traverse_subdir(const Filename &directory) { - // Get the list of files in the directory. - vector_string files; - if (!directory.scan_directory(files)) { - nout << "Unable to scan directory " << directory << "\n"; - return; - } - - // We need to know the set of files in this directory that are CVS elements. - pset cvs_elements; - bool in_cvs = false; - if (!_no_cvs) { - in_cvs = scan_cvs(directory, cvs_elements); - } - - bool is_scenes = false; - bool keep_all = false; - bool wants_cvs = false; - - // Now make some special-case behavior based on the particular SoftImage - // subdirectory we're in. - string dirname = directory.get_basename(); - if (dirname == "SCENES") { - is_scenes = true; - - } else if (dirname == "CAMERAS") { - // We don't want anything in the cameras directory. These may change - // arbitrarily and have no bearing on the model or animation that we will - // extract, so avoid them altogether. - return; - - } else if (dirname == "PICTURES") { - // In the pictures directory, we must keep everything, since the scene - // files don't explicitly reference these but they're still important. - // Textures that are no longer used will pile up; we leave this as the - // user's problem. - - // We not only keep the textures, but we also move them into CVS, since - // (again) they're not part of the scene files and thus won't get added to - // the multifiles. Also, some textures are shared between different - // scenes, and it would be wasteful to add them to each scene multifile; - // furthermore, some scenes are used for animation only, and we don't want - // to modify these multifiles when the textures change. - - keep_all = true; - wants_cvs = !_no_cvs; - } - - vector_string::const_iterator fi; - for (fi = files.begin(); fi != files.end(); ++fi) { - const string &filename = (*fi); - if (filename == "CVS") { - // This special filename is not to be considered. - - } else if (filename == "Chapter.rsrc") { - // This special filename should not be considered, except to add it to - // the multifiles. - _global_files.push_back(Filename(directory, filename)); - - } else { - SoftFilename soft(directory, filename); - - if (cvs_elements.count(filename) != 0) { - // This file is known to be in CVS. - soft.set_in_cvs(true); - } - - if (keep_all) { - soft.increment_use_count(); - } - if (wants_cvs && !in_cvs) { - // Try to CVSify the directory. - cvs_add(directory); - in_cvs = true; - } - soft.set_wants_cvs(wants_cvs); - - if (is_scenes && soft.has_version() && soft.get_extension() == ".dsc") { - _scene_files.push_back(soft); - } else { - _element_files.insert(soft); - } - } - } -} - -/** - * Walks through the list of scene files found, and renames the higher- - * versioned ones to version 1-0, removing the intervening versions. - */ -void SoftCVS:: -collapse_scene_files() { - // Get a copy of the scene files vector so we can modify it. Also empty out - // the _scene_files at the same time so we can fill it up again. - SceneFiles versions; - versions.swap(_scene_files); - - // And sort them into order so we can easily compare higher and lower - // versions. - sort(versions.begin(), versions.end()); - - SceneFiles::iterator vi; - vi = versions.begin(); - while (vi != versions.end()) { - SoftFilename &file = (*vi); - - if (!file.is_1_0()) { - // Here's a file that needs to be renamed. But first, identify all the - // other versions of the same file. - SceneFiles::iterator start_vi; - start_vi = vi; - while (vi != versions.end() && (*vi).is_same_file(file)) { - ++vi; - } - - rename_file(start_vi, vi); - - } else { - ++vi; - } - - file.make_1_0(); - _scene_files.push_back(file); - } -} - -/** - * Walks through the list of scene files and looks for the set of element - * files referenced by each one, updating multifile accordingly. - */ -bool SoftCVS:: -get_scenes() { - bool okflag = true; - - // We will be added the multifiles to CVS if they're not already added, so - // we have to know which files are in CVS already. - pset cvs_elements; - if (!_no_cvs) { - scan_cvs(".", cvs_elements); - } - - SceneFiles::const_iterator vi; - for (vi = _scene_files.begin(); vi != _scene_files.end(); ++vi) { - const SoftFilename &sf = (*vi); - Filename file(sf.get_dirname(), sf.get_filename()); - - file.set_text(); - std::ifstream in; - if (!file.open_read(in)) { - nout << "Unable to read " << file << "\n"; - } else { - nout << "Scanning " << file << "\n"; - - Multifile multifile; - Filename multifile_name = sf.get_base() + "mf"; - - if (!multifile.open_read_write(multifile_name)) { - nout << "Unable to open " << multifile_name << " for updating.\n"; - okflag = false; - - } else { - if (!scan_scene_file(in, multifile)) { - okflag = false; - } - - // Add all the global files to the multifile too. These probably - // can't take compression (since in SoftImage they're just the - // Chapter.rsrc files, each very tiny). - vector_string::const_iterator gi; - for (gi = _global_files.begin(); gi != _global_files.end(); ++gi) { - if (multifile.update_subfile((*gi), (*gi), 0).empty()) { - nout << "Unable to add " << (*gi) << "\n"; - okflag = false; - } - } - - // Also add the scene file itself. - if (multifile.update_subfile(file, file, 6).empty()) { - nout << "Unable to add " << file << "\n"; - okflag = false; - } - - bool flushed = false; - if (multifile.needs_repack()) { - flushed = multifile.repack(); - } else { - flushed = multifile.flush(); - } - if (!flushed) { - nout << "Failed to write " << multifile_name << ".\n"; - okflag = false; - } else { - nout << "Wrote " << multifile_name << ".\n"; - - if (!_no_cvs && cvs_elements.count(multifile_name) == 0) { - // Add the multifile to CVS. - _cvs_add.push_back(multifile_name); - } - } - } - } - } - - return okflag; -} - - -/** - * Remove all the element files that weren't referenced by any scene file. - * Also plan to cvs add all those that were referenced. - */ -void SoftCVS:: -remove_unused_elements() { - ElementFiles::const_iterator fi; - for (fi = _element_files.begin(); fi != _element_files.end(); ++fi) { - const SoftFilename &sf = (*fi); - Filename file(sf.get_dirname(), sf.get_filename()); - - if (sf.get_use_count() == 0) { - nout << file << " is unused.\n"; - - if (!file.unlink()) { - nout << "Unable to remove " << file << ".\n"; - - } else if (sf.get_in_cvs()) { - _cvs_remove.push_back(file); - } - - } else if (sf.get_wants_cvs() && !sf.get_in_cvs()) { - _cvs_add.push_back(file); - } - } -} - - -/** - * Renames the first file in the indicated list to a version 1-0 filename, - * superceding all the other files in the list. Returns true if the file is - * renamed, false otherwise. - */ -bool SoftCVS:: -rename_file(SoftCVS::SceneFiles::iterator begin, - SoftCVS::SceneFiles::iterator end) { - int length = end - begin; - nassertr(length > 0, false); - - SoftFilename &orig = (*begin); - - string dirname = orig.get_dirname(); - string source_filename = orig.get_filename(); - string dest_filename = orig.get_1_0_filename(); - - if (length > 2) { - nout << source_filename << " supercedes:\n"; - SceneFiles::const_iterator p; - for (p = begin + 1; p != end; ++p) { - nout << " " << (*p).get_filename() << "\n"; - } - - } else if (length == 2) { - nout << source_filename << " supercedes " - << (*(begin + 1)).get_filename() << ".\n"; - - } else { - nout << source_filename << " renamed.\n"; - } - - // Now remove all of the "wrong" files. - - SceneFiles::const_iterator p; - for (p = begin + 1; p != end; ++p) { - Filename file((*p).get_dirname(), (*p).get_filename()); - if (!file.unlink()) { - nout << "Unable to remove " << file << ".\n"; - } - } - - // And rename the good one. - Filename source(dirname, source_filename); - Filename dest(dirname, dest_filename); - - if (!source.rename_to(dest)) { - nout << "Unable to rename " << source << " to " << dest_filename << ".\n"; - exit(1); - } - - return true; -} - -/** - * Scans the CVS repository in the indicated directory to determine which - * files are already versioned elements. Returns true if the directory is - * CVS-controlled, false otherwise. - */ -bool SoftCVS:: -scan_cvs(const string &dirname, pset &cvs_elements) { - Filename cvs_entries = dirname + "/CVS/Entries"; - if (!cvs_entries.exists()) { - return false; - } - - std::ifstream in; - cvs_entries.set_text(); - if (!cvs_entries.open_read(in)) { - nout << "Unable to read CVS directory.\n"; - return true; - } - - string line; - std::getline(in, line); - while (!in.fail() && !in.eof()) { - if (!line.empty() && line[0] == '/') { - size_t slash = line.find('/', 1); - if (slash != string::npos) { - string filename = line.substr(1, slash - 1); - - if (line.substr(slash + 1, 2) == "-1") { - // If the first number after the slash is -1, the file used to be - // here but was recently cvs removed. It counts as no longer being - // an element. - } else { - cvs_elements.insert(filename); - } - } - } - - std::getline(in, line); - } - - return true; -} - -/** - * Reads a scene file, looking for references to element files. For each - * reference found, increments the appropriate element file's reference count. - */ -bool SoftCVS:: -scan_scene_file(std::istream &in, Multifile &multifile) { - bool okflag = true; - - int c = in.get(); - while (!in.eof() && !in.fail()) { - // Skip whitespace. - while (isspace(c) && !in.eof() && !in.fail()) { - c = in.get(); - } - - // Now begin a word. - string word; - while (!isspace(c) && !in.eof() && !in.fail()) { - word += c; - c = in.get(); - } - - if (!word.empty()) { - SoftFilename v("", word); - - // Increment the use count on all matching elements of the multiset. - std::pair range; - range = _element_files.equal_range(v); - - ElementFiles::iterator ei; - for (ei = range.first; ei != range.second; ++ei) { - // We cheat and get a non-const reference to the filename out of the - // set. We can safely do this because incrementing the use count - // won't change its position in the set. - SoftFilename &sf = (SoftFilename &)(*ei); - sf.increment_use_count(); - - Filename file(sf.get_dirname(), sf.get_filename()); - if (multifile.update_subfile(file, file, 6).empty()) { - nout << "Unable to add " << file << "\n"; - okflag = false; - } - } - } - } - - return okflag; -} - -/** - * Invokes CVS to add just the named file to the repository. Returns true on - * success, false on failure. - */ -bool SoftCVS:: -cvs_add(const string &path) { - string command = _cvs_binary + " add -kb " + path; - nout << command << "\n"; - int result = system(command.c_str()); - - if (result != 0) { - nout << "Failure invoking cvs.\n"; - return false; - } - return true; -} - -/** - * Invokes CVS to add (or remove) all of the files in the indicated vector. - * Returns true on success, false on failure. - */ -bool SoftCVS:: -cvs_add_or_remove(const string &cvs_command, const vector_string &paths) { - static const int max_command = 4096; - - if (!paths.empty()) { - string command = _cvs_binary + " " + cvs_command; - vector_string::const_iterator pi; - pi = paths.begin(); - while (pi != paths.end()) { - const string &path = (*pi); - - if ((int)command.length() + 1 + (int)path.length() >= max_command) { - // Fire off the command now. - nout << command << "\n"; - int result = system(command.c_str()); - - if (result != 0) { - nout << "Failure invoking cvs.\n"; - return false; - } - - command = _cvs_binary + " " + cvs_command; - } - - command += ' '; - command += path; - - ++pi; - } - nout << command << "\n"; - int result = system(command.c_str()); - - if (result != 0) { - nout << "Failure invoking cvs.\n"; - return false; - } - } - return true; -} - - -int main(int argc, char *argv[]) { - SoftCVS prog; - prog.parse_command_line(argc, argv); - prog.run(); - return 0; -} diff --git a/pandatool/src/softprogs/softCVS.h b/pandatool/src/softprogs/softCVS.h deleted file mode 100644 index adbd89efa6..0000000000 --- a/pandatool/src/softprogs/softCVS.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softCVS.h - * @author drose - * @date 2000-11-10 - */ - -#ifndef SOFTCVS_H -#define SOFTCVS_H - -#include "pandatoolbase.h" - -#include "softFilename.h" - -#include "programBase.h" -#include "vector_string.h" -#include "filename.h" - -#include "pvector.h" -#include "pset.h" - -class Multifile; - -/** - * This program prepares a SoftImage database for CVS by renaming everything - * to version 1-0, and adding new files to CVS. - */ -class SoftCVS : public ProgramBase { -public: - SoftCVS(); - - void run(); - -private: - typedef pvector SceneFiles; - typedef pmultiset ElementFiles; - - void traverse_root(); - void traverse_subdir(const Filename &directory); - - void collapse_scene_files(); - bool get_scenes(); - void remove_unused_elements(); - - bool rename_file(SceneFiles::iterator begin, SceneFiles::iterator end); - bool scan_cvs(const std::string &dirname, pset &cvs_elements); - bool scan_scene_file(std::istream &in, Multifile &multifile); - - bool cvs_add(const std::string &path); - bool cvs_add_or_remove(const std::string &cvs_command, - const vector_string &paths); - - SceneFiles _scene_files; - ElementFiles _element_files; - vector_string _global_files; - - vector_string _cvs_add; - vector_string _cvs_remove; - - bool _no_cvs; - std::string _cvs_binary; -}; - -#endif diff --git a/pandatool/src/softprogs/softFilename.cxx b/pandatool/src/softprogs/softFilename.cxx deleted file mode 100644 index 4c099c56be..0000000000 --- a/pandatool/src/softprogs/softFilename.cxx +++ /dev/null @@ -1,291 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softFilename.cxx - * @author drose - * @date 2000-11-10 - */ - -#include "softFilename.h" - -#include "pnotify.h" - -using std::string; - -/** - * - */ -SoftFilename:: -SoftFilename(const string &dirname, const string &filename) : - _dirname(dirname), - _filename(filename) -{ - _has_version = false; - _major = 0; - _minor = 0; - _in_cvs = false; - _wants_cvs = false; - _use_count = 0; - - _base = _filename; - - // Scan for a version number and an optional extension after each dot in the - // filename. - size_t dot = _filename.find('.'); - while (dot != string::npos) { - size_t m = dot + 1; - const char *fstr = _filename.c_str(); - char *endptr; - // Check for a numeric version number. - int major = strtol(fstr + m , &endptr, 10); - if (endptr != fstr + m && *endptr == '-') { - // We got a major number, is there a minor number? - m = (endptr - fstr) + 1; - int minor = strtol(fstr + m, &endptr, 10); - if (endptr != fstr + m && (*endptr == '.' || *endptr == '\0')) { - // We got a minor number too! - _has_version = true; - _base = _filename.substr(0, dot + 1); - _major = major; - _minor = minor; - _ext = endptr; - return; - } - } - - // That wasn't a version number. Is there more? - dot = _filename.find('.', dot + 1); - } -} - -/** - * - */ -SoftFilename:: -SoftFilename(const SoftFilename ©) : - _dirname(copy._dirname), - _filename(copy._filename), - _has_version(copy._has_version), - _base(copy._base), - _major(copy._major), - _minor(copy._minor), - _ext(copy._ext), - _in_cvs(copy._in_cvs), - _wants_cvs(copy._wants_cvs), - _use_count(copy._use_count) -{ -} - -/** - * - */ -void SoftFilename:: -operator = (const SoftFilename ©) { - _dirname = copy._dirname; - _filename = copy._filename; - _has_version = copy._has_version; - _base = copy._base; - _major = copy._major; - _minor = copy._minor; - _ext = copy._ext; - _in_cvs = copy._in_cvs; - _wants_cvs = copy._wants_cvs; - _use_count = copy._use_count; -} - -/** - * Returns the name of the directory this file was found in. - */ -const string &SoftFilename:: -get_dirname() const { - return _dirname; -} - -/** - * Returns the actual filename as found in the directory. - */ -const string &SoftFilename:: -get_filename() const { - return _filename; -} - -/** - * Returns true if the filename had a version number, false otherwise. - */ -bool SoftFilename:: -has_version() const { - return _has_version; -} - -/** - * Returns what the filename would be if it were version 1-0. - */ -string SoftFilename:: -get_1_0_filename() const { - nassertr(_has_version, string()); - return _base + "1-0" + _ext; -} - -/** - * Returns the base part of the filename. This is everything before the - * version number. - */ -const string &SoftFilename:: -get_base() const { - nassertr(_has_version, _filename); - return _base; -} - -/** - * Returns the major version number. - */ -int SoftFilename:: -get_major() const { - nassertr(_has_version, 0); - return _major; -} - -/** - * Returns the minor version number. - */ -int SoftFilename:: -get_minor() const { - nassertr(_has_version, 0); - return _minor; -} - -/** - * Returns the extension part of the filename. This is everything after the - * version number. - */ -const string &SoftFilename:: -get_extension() const { - nassertr(_has_version, _ext); - return _ext; -} - -/** - * Returns the filename part, without the extension. - */ -string SoftFilename:: -get_non_extension() const { - nassertr(_has_version, _filename); - nassertr(_ext.length() < _filename.length(), _filename); - return _filename.substr(0, _filename.length() - _ext.length()); -} - -/** - * Returns true if this is a version 1_0 filename, false otherwise. - */ -bool SoftFilename:: -is_1_0() const { - nassertr(_has_version, false); - return (_major == 1 && _minor == 0); -} - -/** - * Makes this a 1_0 filename. - */ -void SoftFilename:: -make_1_0() { - _has_version = true; - _major = 1; - _minor = 0; - _filename = get_1_0_filename(); -} - -/** - * Returns true if this file has the same base and extension as the other, - * disregarding the version number; false otherwise. - */ -bool SoftFilename:: -is_same_file(const SoftFilename &other) const { - return _base == other._base && _ext == other._ext; -} - -/** - * Puts filenames in order such that the files with the same base are sorted - * together, ignoring extension; and within files with the same base, files - * are sorted in decreasing version number order so that the most recent - * version appears first. - */ -bool SoftFilename:: -operator < (const SoftFilename &other) const { - if (_base != other._base) { - return _base < other._base; - } - - if (_has_version != other._has_version) { - // If one has a version and the other one doesn't, the one without a - // version comes first. - return _has_version < other._has_version; - } - - if (_has_version) { - if (_major != other._major) { - return _major > other._major; - } - if (_minor != other._minor) { - return _minor > other._minor; - } - } - - return false; -} - -/** - * Sets the flag that indicates whether this file is known to be entered into - * the CVS database. - */ -void SoftFilename:: -set_in_cvs(bool in_cvs) { - _in_cvs = in_cvs; -} - -/** - * Returns true if this file is known to be entered in the CVS database, false - * if it is not. - */ -bool SoftFilename:: -get_in_cvs() const { - return _in_cvs; -} - -/** - * Sets the flag that indicates whether this file should be entered into the - * CVS database. - */ -void SoftFilename:: -set_wants_cvs(bool wants_cvs) { - _wants_cvs = wants_cvs; -} - -/** - * Returns true if this file should be entered into the CVS database, false - * otherwise. - */ -bool SoftFilename:: -get_wants_cvs() const { - return _wants_cvs; -} - -/** - * Indicates that this filename is referenced by one more scene file. - */ -void SoftFilename:: -increment_use_count() { - _use_count++; -} - -/** - * Returns the number of scene files that referenced this filename. - */ -int SoftFilename:: -get_use_count() const { - return _use_count; -} diff --git a/pandatool/src/softprogs/softFilename.h b/pandatool/src/softprogs/softFilename.h deleted file mode 100644 index 0565eabf89..0000000000 --- a/pandatool/src/softprogs/softFilename.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file softFilename.h - * @author drose - * @date 2000-11-10 - */ - -#ifndef SOFTFILENAME_H -#define SOFTFILENAME_H - -#include "pandatoolbase.h" - -/** - * This encapsulates a SoftImage versioned filename, of the form base.v-v.ext: - * it consists of a directory name, a base, a major and minor version number, - * and an optional extension. - * - * It also keeps track of whether the named file has been added to CVS, and - * how many scene files it is referenced by, - */ -class SoftFilename { -public: - SoftFilename(const std::string &dirname, const std::string &filename); - SoftFilename(const SoftFilename ©); - void operator = (const SoftFilename ©); - - const std::string &get_dirname() const; - const std::string &get_filename() const; - bool has_version() const; - - std::string get_1_0_filename() const; - - const std::string &get_base() const; - int get_major() const; - int get_minor() const; - const std::string &get_extension() const; - std::string get_non_extension() const; - - bool is_1_0() const; - void make_1_0(); - - bool is_same_file(const SoftFilename &other) const; - bool operator < (const SoftFilename &other) const; - - void set_in_cvs(bool in_cvs); - bool get_in_cvs() const; - - void set_wants_cvs(bool wants_cvs); - bool get_wants_cvs() const; - - void increment_use_count(); - int get_use_count() const; - -private: - std::string _dirname; - std::string _filename; - bool _has_version; - std::string _base; - int _major; - int _minor; - std::string _ext; - bool _in_cvs; - bool _wants_cvs; - int _use_count; -}; - -#endif From 6b00fe79878d2eeb443890b17908810a863c4062 Mon Sep 17 00:00:00 2001 From: Younguk Kim Date: Sun, 28 Oct 2018 00:29:32 +0900 Subject: [PATCH 47/60] makepanda: fix link error of assimp tool Closes #432 --- makepanda/makepanda.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index caa5a164a9..89aec0e0f6 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -680,6 +680,9 @@ if (COMPILER == "MSVC"): IncDirectory("FCOLLADA", GetThirdpartyDir() + "fcollada/include/FCollada") if (PkgSkip("ASSIMP")==0): LibName("ASSIMP", GetThirdpartyDir() + "assimp/lib/assimp.lib") + path = GetThirdpartyDir() + "assimp/lib/IrrXML.lib" + if os.path.isfile(path): + LibName("ASSIMP", GetThirdpartyDir() + "assimp/lib/IrrXML.lib") IncDirectory("ASSIMP", GetThirdpartyDir() + "assimp/include/assimp") if (PkgSkip("SQUISH")==0): if GetOptimize() <= 2: From bb71cd68e1b3879122669d5cd1be93467a689bea Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Oct 2018 11:40:28 +0100 Subject: [PATCH 48/60] makepanda: use /BIGOBJ flag when compiling p3gobj_composite2.cxx --- makepanda/makepanda.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 89aec0e0f6..1087ce1aff 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -3818,7 +3818,7 @@ if (not RUNTIME): if (not RUNTIME): OPTS=['DIR:panda/src/gobj', 'BUILDING:PANDA', 'NVIDIACG', 'ZLIB', 'SQUISH'] TargetAdd('p3gobj_composite1.obj', opts=OPTS, input='p3gobj_composite1.cxx') - TargetAdd('p3gobj_composite2.obj', opts=OPTS, input='p3gobj_composite2.cxx') + TargetAdd('p3gobj_composite2.obj', opts=OPTS+['BIGOBJ'], input='p3gobj_composite2.cxx') OPTS=['DIR:panda/src/gobj', 'NVIDIACG', 'ZLIB', 'SQUISH', 'PYTHON'] IGATEFILES=GetDirectoryContents('panda/src/gobj', ["*.h", "*_composite*.cxx"]) From fb52a8e15efd0d358f4b2ba29237b8cc25ddeb54 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Oct 2018 11:41:05 +0100 Subject: [PATCH 49/60] text: fix deadlock in TextNode::write Fixes #431 --- panda/src/text/textNode.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index 5a0c0c7f7f..4a77acd6d3 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -291,8 +291,8 @@ output(std::ostream &out) const { */ void TextNode:: write(std::ostream &out, int indent_level) const { - MutexHolder holder(_lock); PandaNode::write(out, indent_level); + MutexHolder holder(_lock); TextProperties::write(out, indent_level + 2); indent(out, indent_level + 2) << "transform is: " << *TransformState::make_mat(_transform) << "\n"; From 35d095c2cf69faf7ed2a068a092915ec4b5bc46c Mon Sep 17 00:00:00 2001 From: TLOPOOperations Date: Mon, 22 Oct 2018 16:16:17 -0700 Subject: [PATCH 50/60] GSG: Fix symbol name conflict --- panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 10 +++++----- panda/src/wgldisplay/wglGraphicsStateGuardian.cxx | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index 904f47afc3..b7b0f7d3e7 100644 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -5240,9 +5240,9 @@ calc_fb_properties(DWORD cformat, DWORD dformat, #define GAMMA_1 (255.0 * 256.0) static bool _gamma_table_initialized = false; -static unsigned short _orignial_gamma_table [256 * 3]; +static unsigned short _original_gamma_table [256 * 3]; -void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) { +void _create_gamma_table_dx9 (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) { int i; double gamma_correction; @@ -5304,7 +5304,7 @@ get_gamma_table(void) { HDC hdc = GetDC(nullptr); if (hdc) { - if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) { + if (GetDeviceGammaRamp (hdc, (LPVOID) _original_gamma_table)) { _gamma_table_initialized = true; get = true; } @@ -5329,10 +5329,10 @@ static_set_gamma(bool restore, PN_stdfloat gamma) { unsigned short ramp [256 * 3]; if (restore && _gamma_table_initialized) { - _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]); + _create_gamma_table_dx9 (gamma, &_original_gamma_table [0], &_original_gamma_table [256], &_original_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]); } else { - _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]); + _create_gamma_table_dx9 (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]); } if (SetDeviceGammaRamp (hdc, ramp)) { diff --git a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx index 735f7fc409..c98f12cf48 100644 --- a/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx +++ b/panda/src/wgldisplay/wglGraphicsStateGuardian.cxx @@ -778,9 +778,9 @@ register_twindow_class() { #define GAMMA_1 (255.0 * 256.0) static bool _gamma_table_initialized = false; -static unsigned short _orignial_gamma_table [256 * 3]; +static unsigned short _original_gamma_table [256 * 3]; -void _create_gamma_table (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) { +void _create_gamma_table_wgl (PN_stdfloat gamma, unsigned short *original_red_table, unsigned short *original_green_table, unsigned short *original_blue_table, unsigned short *red_table, unsigned short *green_table, unsigned short *blue_table) { int i; double gamma_correction; @@ -842,7 +842,7 @@ get_gamma_table(void) { HDC hdc = GetDC(nullptr); if (hdc) { - if (GetDeviceGammaRamp (hdc, (LPVOID) _orignial_gamma_table)) { + if (GetDeviceGammaRamp (hdc, (LPVOID) _original_gamma_table)) { _gamma_table_initialized = true; get = true; } @@ -867,10 +867,10 @@ static_set_gamma(bool restore, PN_stdfloat gamma) { unsigned short ramp [256 * 3]; if (restore && _gamma_table_initialized) { - _create_gamma_table (gamma, &_orignial_gamma_table [0], &_orignial_gamma_table [256], &_orignial_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]); + _create_gamma_table_wgl (gamma, &_original_gamma_table [0], &_original_gamma_table [256], &_original_gamma_table [512], &ramp [0], &ramp [256], &ramp [512]); } else { - _create_gamma_table (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]); + _create_gamma_table_wgl (gamma, 0, 0, 0, &ramp [0], &ramp [256], &ramp [512]); } if (SetDeviceGammaRamp (hdc, ramp)) { From e5c3ce19958dedd5d8100875daaae5829097d9da Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Oct 2018 11:44:24 +0100 Subject: [PATCH 51/60] pipeline: fix missing symbols for CycleDataLockedReader --- panda/src/pipeline/cycleDataLockedReader.I | 38 ++++++++++++++-------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/panda/src/pipeline/cycleDataLockedReader.I b/panda/src/pipeline/cycleDataLockedReader.I index a622b9a2c0..882d8f600e 100644 --- a/panda/src/pipeline/cycleDataLockedReader.I +++ b/panda/src/pipeline/cycleDataLockedReader.I @@ -45,6 +45,19 @@ CycleDataLockedReader(const CycleDataLockedReader ©) : _cycler->increment_read(_pointer); } +/** + * + */ +template +INLINE CycleDataLockedReader:: +CycleDataLockedReader(CycleDataLockedReader &&from) noexcept : + _cycler(from._cycler), + _current_thread(from._current_thread), + _pointer(from._pointer) +{ + from._pointer = nullptr; +} + /** * */ @@ -61,19 +74,6 @@ operator = (const CycleDataLockedReader ©) { _cycler->increment_read(_pointer); } -/** - * - */ -template -INLINE CycleDataLockedReader:: -CycleDataLockedReader(CycleDataLockedReader &&from) noexcept : - _cycler(from._cycler), - _current_thread(from._current_thread), - _pointer(from._pointer) -{ - from._pointer = nullptr; -} - /** * */ @@ -177,6 +177,18 @@ operator = (const CycleDataLockedReader ©) { _pointer = copy._pointer; } +/** + * + */ +template +INLINE void CycleDataLockedReader:: +operator = (CycleDataLockedReader &&from) noexcept { + nassertv(_pointer == nullptr); + + _pointer = from._pointer; + from._pointer = nullptr; +} + /** * */ From da820877357e5242850487b90bc96f7caf214048 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Oct 2018 11:45:14 +0100 Subject: [PATCH 52/60] tests: add unit test for TextNode::write, see #431 --- tests/text/test_textnode.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/text/test_textnode.py b/tests/text/test_textnode.py index e96c9e5371..bedc91b0da 100644 --- a/tests/text/test_textnode.py +++ b/tests/text/test_textnode.py @@ -1,6 +1,13 @@ from panda3d import core +def test_textnode_write(): + out = core.StringStream() + text = core.TextNode("test") + text.write(out, 0) + assert out.data.startswith(b"TextNode test") + + def test_textnode_card_as_margin(): text = core.TextNode("test") text.text = "Test" From afc994b2fb6ed6258be8529e8e9ecd43d11948f7 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Oct 2018 11:47:16 +0100 Subject: [PATCH 53/60] display: fix crash when removing DisplayRegion in pipelined render Maybe not a perfect solution; we should consider keeping the DisplayRegions around until they have gone through the entire pipeline. Fixes #427 --- panda/src/display/graphicsEngine.cxx | 10 +++++----- panda/src/display/graphicsOutput.cxx | 26 +++++++++++++------------- panda/src/display/graphicsOutput.h | 1 + 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 57a592f05d..496a05e273 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -753,7 +753,7 @@ render_frame() { // frames, so we won't have to recompute it each frame. int num_drs = win->get_num_active_display_regions(); for (int i = 0; i < num_drs; ++i) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { NodePath camera_np = dr->get_camera(current_thread); if (!camera_np.is_empty()) { @@ -1359,7 +1359,7 @@ is_scene_root(const PandaNode *node) { if (win->is_active() && win->get_gsg()->is_active()) { int num_display_regions = win->get_num_active_display_regions(); for (int i = 0; i < num_display_regions; i++) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { NodePath camera = dr->get_camera(); if (camera.is_empty()) { @@ -1435,7 +1435,7 @@ cull_and_draw_together(GraphicsEngine::Windows wlist, int num_display_regions = win->get_num_active_display_regions(); for (int i = 0; i < num_display_regions; i++) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { cull_and_draw_together(win, dr, current_thread); } @@ -1539,7 +1539,7 @@ cull_to_bins(GraphicsEngine::Windows wlist, Thread *current_thread) { PStatTimer timer(win->get_cull_window_pcollector(), current_thread); int num_display_regions = win->get_num_active_display_regions(); for (int i = 0; i < num_display_regions; ++i) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { PT(SceneSetup) scene_setup; PT(CullResult) cull_result; @@ -1659,7 +1659,7 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) { } int num_display_regions = win->get_num_active_display_regions(); for (int i = 0; i < num_display_regions; ++i) { - DisplayRegion *dr = win->get_active_display_region(i); + PT(DisplayRegion) dr = win->get_active_display_region(i); if (dr != nullptr) { do_draw(win, gsg, dr, current_thread); } diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index 7c6cef51cb..c8237059b8 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -697,9 +697,6 @@ void GraphicsOutput:: remove_all_display_regions() { LightMutexHolder holder(_lock); - CDWriter cdata(_cycler, true); - cdata->_active_display_regions_stale = true; - TotalDisplayRegions::iterator dri; for (dri = _total_display_regions.begin(); dri != _total_display_regions.end(); @@ -713,6 +710,12 @@ remove_all_display_regions() { } _total_display_regions.clear(); _total_display_regions.push_back(_overlay_display_region); + + OPEN_ITERATE_ALL_STAGES(_cycler) { + CDStageWriter cdata(_cycler, pipeline_stage); + cdata->_active_display_regions_stale = true; + } + CLOSE_ITERATE_ALL_STAGES(_cycler); } /** @@ -740,13 +743,8 @@ set_overlay_display_region(DisplayRegion *display_region) { */ int GraphicsOutput:: get_num_display_regions() const { - determine_display_regions(); - int result; - { - LightMutexHolder holder(_lock); - result = _total_display_regions.size(); - } - return result; + LightMutexHolder holder(_lock); + return _total_display_regions.size(); } /** @@ -1504,13 +1502,15 @@ do_remove_display_region(DisplayRegion *display_region) { find(_total_display_regions.begin(), _total_display_regions.end(), drp); if (dri != _total_display_regions.end()) { // Let's aggressively clean up the display region too. - CDWriter cdata(_cycler, true); display_region->cleanup(); display_region->_window = nullptr; _total_display_regions.erase(dri); - cdata->_active_display_regions_stale = true; - + OPEN_ITERATE_ALL_STAGES(_cycler) { + CDStageWriter cdata(_cycler, pipeline_stage); + cdata->_active_display_regions_stale = true; + } + CLOSE_ITERATE_ALL_STAGES(_cycler); return true; } diff --git a/panda/src/display/graphicsOutput.h b/panda/src/display/graphicsOutput.h index acd41e8289..f426b41bee 100644 --- a/panda/src/display/graphicsOutput.h +++ b/panda/src/display/graphicsOutput.h @@ -394,6 +394,7 @@ protected: typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; + typedef CycleDataStageWriter CDStageWriter; protected: int _creation_flags; From 99aa598de00e7c1d748fa6f20dc85d031ea1622c Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Oct 2018 11:51:25 +0100 Subject: [PATCH 54/60] makepanda: don't try to link static libs into static library --- makepanda/makepanda.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 1087ce1aff..7573e89606 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -1598,6 +1598,8 @@ def CompileLib(lib, obj, opts): else: cmd = GetAR() + ' cru ' + BracketNameWithQuotes(lib) for x in obj: + if GetLinkAllStatic() and x.endswith('.a'): + continue cmd += ' ' + BracketNameWithQuotes(x) oscmd(cmd) From e92777619cf33895b3faa56352d4d245b131eb58 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Oct 2018 11:53:55 +0100 Subject: [PATCH 55/60] doc: remove two outdated documents --- doc/INSTALLING-PLUGINS.TXT | 20 ---- doc/InstallerNotes | 183 ------------------------------------- 2 files changed, 203 deletions(-) delete mode 100644 doc/INSTALLING-PLUGINS.TXT delete mode 100644 doc/InstallerNotes diff --git a/doc/INSTALLING-PLUGINS.TXT b/doc/INSTALLING-PLUGINS.TXT deleted file mode 100644 index 994e164936..0000000000 --- a/doc/INSTALLING-PLUGINS.TXT +++ /dev/null @@ -1,20 +0,0 @@ -HOW TO INSTALL MAX PANDA PLUGINS. - -Step 1. Install the visual studio 2008 runtime by -running "vcredist_x86-sp1.exe" as administrator. -As a convenience, this installer is included with panda. - -Step 2. Make sure that there is only one copy of panda -in your system PATH. If you only have one copy of panda -installed, you can skip this step. - -Step 3. Copy the relevant DLLs for your version -of max from the panda plugins directory to the -max plugins directory. For instance, if you are -using Max 9, copy maxegg9.dlo and maxeggimport9.dlo - -HOW TO INSTALL MAYA PANDA PLUGINS. - -(To be written) - - diff --git a/doc/InstallerNotes b/doc/InstallerNotes deleted file mode 100644 index cf57b15cc1..0000000000 --- a/doc/InstallerNotes +++ /dev/null @@ -1,183 +0,0 @@ ------------------------- RELEASE 1.0.0 --------------------------------- - - * We now have working exporters for Max5, Max6, Max7, Maya5, Maya6 - - * The Max exporter is dramatically improved: - - - it now includes support for character studio. - - the polygon winding bug has been fixed. - - * Panda no longer requires any registry keys or environment - variables. This means it is now possible to: - - - run panda directly from a compact disc - - install multiple copies of panda on a single machine - - install panda by copying the tree from another computer - - Note that the installer does add the panda 'bin' directory to - your PATH, and it does store an uninstall key in the registry, - but neither of these is needed for panda to function. - - * The 'makepanda' build system is now capable of building - prepackaged games for Windows. These prepackaged games are simply - copies of panda with the game code included, some of the - unnecessary stuff stripped out, and some changes to the start - menu. See "Airblade - Installer" on the panda downloads page - for an example. - - * All of the sample programs have been tested. The ones that didn't - work have been removed, the ones that do work have been (lightly) - documented. - - * This is the first release to include not just a binary installer - for windows, but: - - - a binary installer (RPM) for Fedora 2 - - a binary installer (RPM) for Fedora 3 - - a binary installer (RPM) for Redhat 9 - - a binary installer for windows, as always - - a source tar-ball for linux - - a source zip-file for windows - ------------------------- RELEASE 2004-12-13 --------------------------------- - - * Basic server-client networking support is back in Panda3D. There is a - networking sample in the samples directory. This uses the Panda3d - distributed object system.The README file will explain how to run this. - Documentation of this if forthcoming. - - * Panda3d now reduces the number of environment variables such that only 2 - are needed now - PRC_PATH and PLAYER. - - * GraphicsChannel and GraphicsLayer class have been removed from the - panda/src/display directory. Most Panda applications won't need to be - changed, since most applications simply use ShowBase.py (which has been - adjustedappropriately) to open a window and do the initial setup. For - those rare applications where you need to create your own DisplayRegions, - the makeDisplayRegion() interface has been moved from GraphicsLayer to - GraphicsWindow (actually, to GraphicsOutput, which is the base class of - GraphicsWindow). You can modify your application to call - base.win.makeDisplayRegion() accordingly. If you have something like - displayRegion.getLayer(), replace it with displayRegion.getWindow() - instead. - - * Effective with the current version of Panda, the way that HPR angles are - calculated will be changing. The change will make a difference to existing - code or databases that store a hard-coded rotation as a HPR, but only when - R is involved, or both H and P are involved together. That is to say more - precisely, HPR angles with (R != 0 || (H != 0 && P != 0)) now represent a - different rotation than they used to. If you find some legacy code that no - longer works correctly (e.g. it introduces crazy rotations), try putting - the following in your Config.prc file: - - temp-hpr-fix 0 - - To turn off the correct behavior and return to the old, broken behavior. - Note that a longer-term solution will be to represent the HPR angles - correctly in all legacy code. The function oldToNewHpr() is provided to - aid this transition. - - * PandaNode definition has been changed to support setting an - into_collide_mask for any arbitrary node, in particular for any GeomNode. - It used to be that only CollisionNodes had an into_collide_mask. This - change obviates the need for CollisionNode::set_collide_geom(), which is - now a deprecated interface and will be removed at some point in the future. - - Details: - There's now a NodePath::set_collide_mask() and - NodePath::get_collide_mask(), which operate on all CollisionNodes and - GeomNodes at and below the current node. By default, set_collide_mask() - will replace the entire collide mask, but you may also specify (via a - second parameter) the subset of bits that are to be changed; other bits - will be left alone. You can also specify a particular type of node to - modify via a third parameter, e.g. you can adjust the masks for GeomNodes - or CollisionNodes only. - - The NodePath set_collide_mask() interface changes the into_collide_mask. - Those familiar with the collision system will recall that a CollisionNode - (but only a CollisionNode) also has a from_collide_mask. The - from_collide_mask of the active mover is compared with the into_collide_mask - of each object in the world; a collision is only possible if there are some - bits in common. - - It used to be that only other CollisionNodes had an into_collide_mask. A - mover would only test for collisions with CollisionNodes that matched its - collide_mask. If you wanted to make your mover detect collisions with - visible geometry which had no into_collide_mask, you had to call - set_collide_geom(1). This allowed the mover to detect collisions with *all* - visible geometry; it was either an all-or-none thing. - - Now that GeomNodes also have an into_collide_mask, there's no longer a need - for set_collide_geom(). A mover will detect collisions with any - CollisionNodes or GeomNodes that match its collide_mask. This means, for - the purposes of collision detection, you can use CollisionNodes and - GeomNodes pretty much interchangeably; simply set the appropriate bits on - the objects you want to collide with, regardless of whether they are - invisible collision solids or visible geometry. - - (This should not be taken as a license to avoid using CollisionNodes - altogether. The intersection computation with visible geometry is still - less efficient than the same computation with collision solids. And visible - geometry tends to be many times more complex than is strictly necessary for - collisions.) - - There's one more detail: every GeomNode, by default, has one bit set on in - its collide_mask, unless it is explicitly turned off. This bit is - GeomNode::get_default_collide_mask(). This bit is provided for the - convenience of programmers who still want the old behavior of - set_collide_geom(): it allows you to easily create a CollisionNode that - will collide with all visible geometry in the world. - - Along the same lines, there's also CollisionNode::get_default_collide_mask(), - which is 0x000fffff. This is the default mask that is created for a new - CollisionNode (and it does not include the bit reserved for GeomNodes, - above). Previously, a new CollisionNode would have all bits on by default. - - - ------------------------- RELEASE 2004-11-11 ----------------------------------- - - * Multiple mice can now be used with Panda3D. showbase has a list called - pointerWatcherNodes. The first mouse on this list is the system mouse. The - getMouseX() and getMouseY() will return coordinates relative to the - application window. The rest of the mice on the list will give raw mouse - positions and will change when they are moved on the screen. - - In addition there are new events for mouse buttons. Each mouse will be have - a corresponding event. mouse1 will send mousedev1-mouse1, mousedev1-mouse2 - and mousedev1-mouse3 events. mouse2 and any other mouse attached - will send similar events mousedev2-mouse1 etc. - - The old mouse buttons work too. mouse1, mouse2, mouse3 events will be - triggered if that button is pressed on any mouse - ------------------------- RELEASE 2004-10-13 ----------------------------------- - -General - - * Release notes: Each release will now have an entry associated with - it in this document. This will be updated in reverse-chronological order. - -Panda3D - * Distributed with this release is a working version of the SceneEditor - created in Spring 2004 at the ETC. Documentation will be forthcoming on the - website. This can be found in /SceneEditor - - * The latest version of FMOD is distributed with this release. The latest - version is 3.73. - - * AudioSound object now allows more types of sound. These include wma and - ogg vorbis formats. This is valid when using the fmod sound system. Midi, - Mod, s3m, it, xm and such sequencer type file formats are not supported. - Exception - Midi files can be played. This is not fully implemented. - - * A bug in SoundInterval is fixed. SoundInterval looping would incorrectly - add a minimum of 1.5 seconds to the sound. This has been fixed. Sound - looping problems in general should be fixed. Midi's still don't support - looping through the AudioSound object. They should loop through - SoundIntervals though. - - * Cg support has been added to Panda3D. Documentation for this is - forthcoming. - - From 733c7f2352ba269f712e211fc770e5789c3ca4bb Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Oct 2018 11:59:18 +0100 Subject: [PATCH 56/60] makepanda: remove mention of removed softprogs/softcvs --- makepanda/makepanda.py | 16 ---------------- makepanda/makepanda.vcproj | 20 -------------------- 2 files changed, 36 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 7573e89606..7f82da5b80 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -3299,7 +3299,6 @@ if (PkgSkip("PANDATOOL")==0): CopyAllHeaders('pandatool/src/ptloader') CopyAllHeaders('pandatool/src/miscprogs') CopyAllHeaders('pandatool/src/pstatserver') - CopyAllHeaders('pandatool/src/softprogs') CopyAllHeaders('pandatool/src/text-stats') CopyAllHeaders('pandatool/src/vrmlprogs') CopyAllHeaders('pandatool/src/win-stats') @@ -6352,21 +6351,6 @@ if (PkgSkip("PANDATOOL")==0): TargetAdd('p3pstatserver_composite1.obj', opts=OPTS, input='p3pstatserver_composite1.cxx') TargetAdd('libp3pstatserver.lib', input='p3pstatserver_composite1.obj') -# -# DIRECTORY: pandatool/src/softprogs/ -# - -if (PkgSkip("PANDATOOL")==0): - OPTS=['DIR:pandatool/src/softprogs', 'OPENSSL'] - TargetAdd('softcvs_softCVS.obj', opts=OPTS, input='softCVS.cxx') - TargetAdd('softcvs_softFilename.obj', opts=OPTS, input='softFilename.cxx') - TargetAdd('softcvs.exe', input='softcvs_softCVS.obj') - TargetAdd('softcvs.exe', input='softcvs_softFilename.obj') - TargetAdd('softcvs.exe', input='libp3progbase.lib') - TargetAdd('softcvs.exe', input='libp3pandatoolbase.lib') - TargetAdd('softcvs.exe', input=COMMON_PANDA_LIBS) - TargetAdd('softcvs.exe', opts=['ADVAPI']) - # # DIRECTORY: pandatool/src/text-stats/ # diff --git a/makepanda/makepanda.vcproj b/makepanda/makepanda.vcproj index 6be22d7d1a..c4c34db4e3 100644 --- a/makepanda/makepanda.vcproj +++ b/makepanda/makepanda.vcproj @@ -4770,12 +4770,6 @@ - - - - - - @@ -5305,20 +5299,6 @@ - - - - - - - - - - - - - - From ed96a5270333c5344c9757393939c1a02a4dd1cc Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 28 Oct 2018 20:40:55 +0100 Subject: [PATCH 57/60] cocoa: cautiously enable sRGB framebuffers on macOS [skip ci] --- panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm b/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm index 26d4dbdf71..b584d02a2c 100644 --- a/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm +++ b/panda/src/cocoadisplay/cocoaGraphicsStateGuardian.mm @@ -134,6 +134,12 @@ get_properties(FrameBufferProperties &properties, NSOpenGLPixelFormat* pixel_for if (accelerated) { properties.set_force_hardware(1); } + + // Cautiously setting this to true. It appears that macOS framebuffers are + // sRGB-capable, but I don't really know how to verify this. + if (color_size == 32 && !color_float) { + properties.set_srgb_color(true); + } } /** From 33385facfbf469817fcdd80e8de0eddc6989fd88 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Mon, 29 Oct 2018 15:29:41 -0600 Subject: [PATCH 58/60] dxgsg9: Delete dead dxInput9.{cxx,h} files This file isn't compiled, and I'm pretty sure never has been compiled. The dependence on "config_wdxdisplay9.h" (which has never existed) and absence of any commits that address its functionality reinforce the idea that this is actually just dead code. This seems like an artifact copied over from the DX8 code, that nobody cared enough to get working or delete. --- panda/src/dxgsg9/dxInput9.cxx | 269 -------------------------- panda/src/dxgsg9/dxInput9.h | 40 ---- panda/src/dxgsg9/wdxGraphicsWindow9.h | 1 - 3 files changed, 310 deletions(-) delete mode 100644 panda/src/dxgsg9/dxInput9.cxx delete mode 100644 panda/src/dxgsg9/dxInput9.h diff --git a/panda/src/dxgsg9/dxInput9.cxx b/panda/src/dxgsg9/dxInput9.cxx deleted file mode 100644 index 17d5b2f88e..0000000000 --- a/panda/src/dxgsg9/dxInput9.cxx +++ /dev/null @@ -1,269 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file dxInput9.cxx - * @author angelina jolie - * @date 1999-10-07 - */ - -#include "config_wdxdisplay9.h" -#include "dxInput9.h" - -#define AXIS_RESOLUTION 2000 // use this many levels of resolution by default (could be more if needed and device supported it) -#define AXIS_RANGE_CENTERED // if defined, axis range is centered on 0, instead of starting on 0 - -using std::endl; - -BOOL CALLBACK EnumGameCtrlsCallback( const DIDEVICEINSTANCE* pdidInstance, - VOID* pContext ) { - DI_DeviceInfos *pDevInfos = (DI_DeviceInfos *)pContext; - - (*pDevInfos).push_back(*pdidInstance); - - if(wdxdisplay_cat.is_debug()) - wdxdisplay_cat.debug() << "Found DevType 0x" << (void*)pdidInstance->dwDevType << ": " << pdidInstance->tszInstanceName << ": " << pdidInstance->tszProductName <Unacquire(); - SAFE_RELEASE(_DeviceList[i]); - } - - // bugbug: need to handle this if(_JoystickPollTimer!=NULL) KillTimer(...) - - SAFE_RELEASE(_pDInput9); - if(_hDInputDLL) { - FreeLibrary(_hDInputDLL); - _hDInputDLL=nullptr; - } -} - -bool DInput9Info::InitDirectInput() { - HRESULT hr; - - // assumes dx9 exists use dynamic load so non-dinput programs don't have - // to load dinput - #define DLLNAME "dinput9.dll" - #define DINPUTCREATE "DirectInput9Create" - - HINSTANCE _hDInputDLL = LoadLibrary(DLLNAME); - if(_hDInputDLL == 0) { - wdxdisplay_cat.fatal() << "LoadLibrary(" << DLLNAME <<") failed!, error=" << GetLastError() << endl; - exit(1); - } - - typedef HRESULT (WINAPI * LPDIRECTINPUT9CREATE)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter); - LPDIRECTINPUT9CREATE pDInputCreate9; - - pDInputCreate9 = (LPDIRECTINPUT9CREATE) GetProcAddress(_hDInputDLL,DINPUTCREATE); - if(pDInputCreate9 == nullptr) { - wdxdisplay_cat.fatal() << "GetProcAddr failed for " << DINPUTCREATE << endl; - exit(1); - } - - // Register with the DirectInput subsystem and get a pointer to a - // IDirectInput interface we can use. Create a DInput object - if( FAILED( hr = (*pDInputCreate9)(GetModuleHandle(nullptr), DIRECTINPUT_VERSION, - IID_IDirectInput9, (VOID**)&_pDInput9, nullptr ) ) ) { - wdxdisplay_cat.error() << DINPUTCREATE << "failed" << D3DERRORSTRING(hr); - return false; - } - - // enum all the joysticks,etc (but not keybdmouse) - if( FAILED( hr = _pDInput9->EnumDevices(DI9DEVCLASS_GAMECTRL, - EnumGameCtrlsCallback, - (LPVOID)&_DevInfos, DIEDFL_ATTACHEDONLY ) ) ) { - wdxdisplay_cat.error() << "EnumDevices failed" << D3DERRORSTRING(hr); - return false; - } - - return true; -} - -bool DInput9Info::CreateJoystickOrPad(HWND _window) { - bool bFoundDev = false; - UINT devnum=0; - char *errstr=nullptr; - - // look through the list for the first joystick or gamepad - for(;devnum<_DevInfos.size();devnum++) { - DWORD devType = GET_DIDEVICE_TYPE(_DevInfos[devnum].dwDevType); - if((devType==DI9DEVTYPE_GAMEPAD) ||(devType==DI9DEVTYPE_JOYSTICK)) { - bFoundDev=true; - break; - } - } - - if(!bFoundDev) { - wdxdisplay_cat.error() << "Cant find an attached Joystick or GamePad!\n"; - return false; - } - - LPDIRECTINPUTDEVICE9 pJoyDevice; - - // Obtain an interface to the enumerated joystick. - HRESULT hr = _pDInput9->CreateDevice(_DevInfos[devnum].guidInstance, &pJoyDevice, nullptr ); - if(FAILED(hr)) { - errstr="CreateDevice"; - goto handle_error; - } - - assert(pJoyDevice!=nullptr); - _DeviceList.push_back(pJoyDevice); - - // Set the data format to "simple joystick" - a predefined data format A - // data format specifies which controls on a device we are interested in, - // and how they should be reported. This tells DInput that we will be - // passing a DIJOYSTATE2 structure to - // IDirectInputDevice::GetDeviceState(). - hr = pJoyDevice->SetDataFormat(&c_dfDIJoystick2); - if(FAILED(hr)) { - errstr="SetDataFormat"; - goto handle_error; - } - - // must be called AFTER SetDataFormat to get all the proper flags - DX_DECLARE_CLEAN(DIDEVCAPS, DIDevCaps); - hr = pJoyDevice->GetCapabilities(&DIDevCaps); - assert(SUCCEEDED(hr)); - - _DevCaps.push_back(DIDevCaps); - - if(wdxdisplay_cat.is_debug()) - wdxdisplay_cat.debug() << "Joy/Pad has " << DIDevCaps.dwAxes << " Axes, " << DIDevCaps.dwButtons << " Buttons, " << DIDevCaps.dwPOVs << " POVs" << endl; - - // Set the cooperative level to let DInput know how this device should - // interact with the system and with other DInput applications. - hr = pJoyDevice->SetCooperativeLevel( _window, DISCL_EXCLUSIVE | DISCL_FOREGROUND); - if(FAILED(hr)) { - errstr="SetCooperativeLevel"; - goto handle_error; - } - - // set the minmax values property for discovered axes. - hr = pJoyDevice->EnumObjects(EnumObjectsCallbackJoystick, (LPVOID)pJoyDevice, DIDFT_AXIS); - if(FAILED(hr)) { - errstr="EnumObjects"; - goto handle_error; - } - - return true; - - handle_error: - wdxdisplay_cat.error() << errstr << " failed for (" << _DevInfos[devnum].tszInstanceName << ":" << _DevInfos[devnum].tszProductName << ")" << D3DERRORSTRING(hr); - return false; -} - -// --------------------------------------------------------------------------- -// -- Name: EnumObjectsCallback() Desc: Callback function for enumerating -// objects (axes, buttons, POVs) on a joystick. This function enables user -// interface elements for objects that are found to exist, and scales axes -// minmax values. ----------------------------------------------------------- -// ------------------ -BOOL CALLBACK EnumObjectsCallbackJoystick( const DIDEVICEOBJECTINSTANCE* pdidoi, - VOID* pContext ) { - - LPDIRECTINPUTDEVICE9 pJoyDevice = (LPDIRECTINPUTDEVICE9) pContext; - HRESULT hr; - - // For axes that are returned, set the DIPROP_RANGE property for the - // enumerated axis in order to scale minmax values. - if( pdidoi->dwType & DIDFT_AXIS ) { - DIPROPRANGE diprg; - diprg.diph.dwSize = sizeof(DIPROPRANGE); - diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); - diprg.diph.dwHow = DIPH_BYID; - diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis - - #ifdef AXIS_RANGE_CENTERED - diprg.lMin = -AXIS_RESOLUTION/2; - diprg.lMax = +AXIS_RESOLUTION/2; - #else - diprg.lMin = 0; - diprg.lMax = +AXIS_RESOLUTION; - #endif - - // Set the range for the axis - hr = pJoyDevice->SetProperty( DIPROP_RANGE, &diprg.diph); - if(FAILED(hr)) { - wdxdisplay_cat.error() << "SetProperty on axis failed" << D3DERRORSTRING(hr); - return DIENUM_STOP; - } - } - - return DIENUM_CONTINUE; -} - -bool DInput9Info::ReadJoystick(int devnum, DIJOYSTATE2 &js) { - LPDIRECTINPUTDEVICE9 pJoystick = _DeviceList[devnum]; - assert(pJoystick!=nullptr); - HRESULT hr; - char *errstr; - - // Poll the device to read the current state - - hr = pJoystick->Poll(); - - if( FAILED(hr) ) { - // DInput is telling us that the input stream has been interrupted. - // We aren't tracking any state between polls, so we don't have any - // special reset that needs to be done. We just re-acquire and try - // again. - - if((hr==DIERR_NOTACQUIRED)||(hr == DIERR_INPUTLOST)) { - hr = pJoystick->Acquire(); - - if(FAILED(hr)) { - if(wdxdisplay_cat.is_spam()) - wdxdisplay_cat.spam() << "Acquire failed" << D3DERRORSTRING(hr); - - // hr may be DIERR_OTHERAPPHASPRIO or other errors. This may - // occur when the app is minimized or in the process of - // switching, so just try again later - return false; - } - - hr = pJoystick->Poll(); - if(FAILED(hr)) { - // should never happen! - errstr = "Poll after successful Acquire failed"; - goto handle_error; - } - } else { - errstr = "Unknown Poll failure"; - goto handle_error; - } - } - - // should we make a vector of devstate dataformats to generalize this fn - // for all device types? - - // Get the input's device state - hr = pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js); - if(FAILED(hr)) { - errstr = "GetDeviceState failed"; - goto handle_error; - } - - return true; - - handle_error: - wdxdisplay_cat.fatal() << errstr << D3DERRORSTRING(hr); - return false; -} diff --git a/panda/src/dxgsg9/dxInput9.h b/panda/src/dxgsg9/dxInput9.h deleted file mode 100644 index 9614a2627d..0000000000 --- a/panda/src/dxgsg9/dxInput9.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * PANDA 3D SOFTWARE - * Copyright (c) Carnegie Mellon University. All rights reserved. - * - * All use of this software is subject to the terms of the revised BSD - * license. You should have received a copy of this license along - * with this source code in a file named "LICENSE." - * - * @file dxInput9.h - * @author blllyjo - * @date 1999-10-07 - */ - -#ifndef DXINPUT9_H -#define DXINPUT9_H - -#define DIRECTINPUT_VERSION 0x900 -#include -typedef std::vector DI_DeviceInfos; -typedef std::vector DI_DeviceObjInfos; - -class DInput9Info { -public: - DInput9Info(); - ~DInput9Info(); - bool InitDirectInput(); - bool CreateJoystickOrPad(HWND _window); - bool ReadJoystick(int devnum, DIJOYSTATE2 &js); - - HINSTANCE _hDInputDLL; - UINT_PTR _JoystickPollTimer; - LPDIRECTINPUT8 _pDInput9; - DI_DeviceInfos _DevInfos; - // arrays for all created devices. Should probably put these together in a - // struct, along with the data fmt info - std::vector _DeviceList; - std::vector _DevCaps; -}; - -#endif diff --git a/panda/src/dxgsg9/wdxGraphicsWindow9.h b/panda/src/dxgsg9/wdxGraphicsWindow9.h index 391fb9d7e9..42a6fe6763 100644 --- a/panda/src/dxgsg9/wdxGraphicsWindow9.h +++ b/panda/src/dxgsg9/wdxGraphicsWindow9.h @@ -17,7 +17,6 @@ #include "pandabase.h" #include "winGraphicsWindow.h" #include "dxGraphicsStateGuardian9.h" -#include "dxInput9.h" #include "wdxGraphicsPipe9.h" class wdxGraphicsPipe9; From 2ed4cd7ce6359e608f3bbd3a3a348ab88d1f7bff Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 29 Oct 2018 22:38:00 +0100 Subject: [PATCH 59/60] cppparser: fix CPPStructType::is_trivial() for eg. ButtonHandle --- dtool/src/cppparser/cppStructType.cxx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dtool/src/cppparser/cppStructType.cxx b/dtool/src/cppparser/cppStructType.cxx index d0707c4404..745abab586 100644 --- a/dtool/src/cppparser/cppStructType.cxx +++ b/dtool/src/cppparser/cppStructType.cxx @@ -306,7 +306,6 @@ is_trivial() const { } // Now look for functions that are virtual or con/destructors. - bool is_default_constructible = true; CPPScope::Functions::const_iterator fi; for (fi = _scope->_functions.begin(); fi != _scope->_functions.end(); ++fi) { CPPFunctionGroup *fgroup = (*fi).second; @@ -343,9 +342,6 @@ is_trivial() const { // Same for the default constructor. return false; } - // The presence of a non-default constructor makes the class not - // default-constructible. - is_default_constructible = false; } if (fgroup->_name == "operator =") { @@ -356,7 +352,7 @@ is_trivial() const { } // Finally, the class must be default-constructible. - return is_default_constructible; + return is_default_constructible(V_public); } /** From ad3b145951654a76c90bd001c0b1e10dc02d3e87 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 29 Oct 2018 22:39:17 +0100 Subject: [PATCH 60/60] interrogate: generated property getter should copy in some cases This is to fix eg. public ButtonHandle members from being returned as const reference, which means they won't outlive the struct they are accessed on, a recipe for obscure crashes. The is_trivial() criterium for this to apply is admittedly really arbitrary; I haven't really figured out what the right criterium should be, but it's better than hardcoding ButtonHandle. --- dtool/src/interrogate/interrogateBuilder.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dtool/src/interrogate/interrogateBuilder.cxx b/dtool/src/interrogate/interrogateBuilder.cxx index 15607c95ea..b740d59e1a 100644 --- a/dtool/src/interrogate/interrogateBuilder.cxx +++ b/dtool/src/interrogate/interrogateBuilder.cxx @@ -1389,7 +1389,8 @@ scan_element(CPPInstance *element, CPPStructType *struct_type, // We can only generate a getter and a setter if we can talk about the // type it is. - if (parameter_type->as_struct_type() != nullptr) { + if (parameter_type->as_struct_type() != nullptr && + !parameter_type->is_trivial()) { // Wrap the type in a const reference. parameter_type = TypeManager::wrap_const_reference(parameter_type); }