with collada.Document, collada.Library.geometries, collada.Library.controllers, ada.Text_IO; package body openGL.IO.collada is package std_Collada renames Standard.Collada; function to_Model (model_Path : in String) return IO.Model is use std_Collada.Library, std_Collada.Library.geometries, ada.Text_IO; use type std_Collada.Library.controllers.Controller_array_view; which_Geometry : constant := 1; -- Select which gemometry, just for testing. the_Document : constant std_Collada.Document.item := std_Collada.Document.to_Document (model_Path); the_Mesh : constant geometries.Mesh := the_Document.Libraries.Geometries.Contents (which_Geometry).Mesh; the_Primitive : constant geometries.Primitive := the_Mesh.Primitives (1); collada_Positions : constant access std_Collada.Float_array := Positions_of (the_Mesh); collada_Normals : constant access std_Collada.Float_array := Normals_of (the_Mesh, the_Primitive); collada_Coords : constant access std_Collada.Float_array := Coords_of (the_Mesh, the_Primitive); function get_coord_Count return long_Index_t is begin if collada_Coords = null then return 0; else return collada_Coords'Length / 2; end if; end get_coord_Count; site_Count : constant long_Index_t := collada_Positions'Length / 3; normal_Count : constant long_Index_t := collada_Normals 'Length / 3; coord_Count : constant long_Index_t := get_coord_Count; the_Sites : constant many_Sites_view := new many_Sites (1 .. site_Count); the_Normals : constant many_Normals_view := new many_Normals (1 .. normal_Count); the_Coords : many_Coords_view; the_Weights : bone_Weights_array_view; the_Faces : IO.Faces_view := new IO.Faces (1 .. 50_000); face_Count : long_Index_t := 0; begin if coord_Count > 0 then the_Coords := new many_Coordinates_2D (1 .. coord_Count); end if; for i in 1 .. Integer (site_Count) loop the_Sites (long_Index_t (i)) := [collada_Positions (3 * (i - 1) + 1), collada_Positions (3 * (i - 1) + 2), collada_Positions (3 * (i - 1) + 3)]; end loop; for i in 1 .. Integer (normal_Count) loop the_Normals (long_Index_t (i)) := [collada_Normals (3 * (i - 1) + 1), collada_Normals (3 * (i - 1) + 2), collada_Normals (3 * (i - 1) + 3)]; end loop; if collada_Coords /= null then for i in 1 .. Integer (coord_Count) loop the_Coords (long_Index_t (i)) := (collada_Coords (2 * (i - 1) + 1), collada_Coords (2 * (i - 1) + 2)); end loop; end if; -- Skinning -- if the_Document.Libraries.Controllers.Contents /= null and then the_Document.Libraries.Controllers.Contents'Length > 0 then declare use std_Collada.Library.controllers; the_Controller : constant controllers.Controller := the_Document.Libraries.Controllers.Contents (which_Geometry); the_Skin : constant controllers.Skin := the_Controller.Skin; collada_Weights : constant access std_Collada.Float_array := Weights_of (the_Skin); V : std_Collada.Int_array renames the_Skin.vertex_Weights.V .all; v_Count : std_Collada.Int_array renames the_Skin.vertex_Weights.v_Count.all; v_Cursor : math.Index := 0; inputs_Count : constant math.Index := the_Skin.vertex_Weights.Inputs'Length; begin the_Weights := new bone_Weights_array (1 .. long_Index_t (the_Skin.vertex_Weights.Count)); for each_Vertex in v_Count'Range loop declare the_Count : constant long_Index_t := long_Index_t (v_Count (each_Vertex)); these_Weights : bone_Weights_view renames the_Weights (long_Index_t (each_Vertex)); Base : Math.Index; begin these_Weights := new bone_Weights (1 .. the_Count); for i in 1 .. the_Count loop v_Cursor := v_Cursor + 1; Base := (v_Cursor - 1) * inputs_Count + 1; these_Weights (i).Bone := bone_Id ( 1 + V (Base + joint_Offset_of (the_Skin.vertex_weights))); these_Weights (i).Weight := Real (collada_Weights ( 1 + math.Index (V ( Base + weight_Offset_of (the_Skin.vertex_Weights))))); end loop; end; end loop; end; end if; -- Primitives -- case the_Primitive.Kind is when polyList => parse_polyList : declare P : std_Collada.Int_array renames the_Primitive.P_List (1).all; inputs_Count : constant Natural := the_Primitive.Inputs'Length; p_First : math.Index := 1; p_Last : math.Index; vertex_Count : Natural; begin for Each in the_Primitive.vCount'Range loop vertex_Count := the_Primitive.vCount (Each); p_Last := p_First + math.Index (inputs_Count * vertex_Count) - 1; declare the_Vertices : Vertices (1 .. long_Index_t (vertex_Count)); P_Indices : constant std_Collada.Int_array (1 .. p_Last - p_First + 1) := P (p_First .. p_Last); the_Face : IO.Face; Base : math.Index; begin for vertex_Id in the_Vertices'Range loop Base := math.Index (vertex_Id - 1) * math.Index (inputs_Count) + 1; the_Vertices (vertex_Id).site_Id := 1 + long_Index_t (P_Indices ( Base + vertex_Offset_of (the_Primitive))); the_Vertices (vertex_Id).normal_Id := 1 + long_Index_t (P_Indices ( Base + normal_Offset_of (the_Primitive))); if collada_Coords /= null then the_Vertices (vertex_Id).coord_Id := 1 + long_Index_t ( P_Indices (Base + coord_Offset_of (the_Primitive))); else the_Vertices (vertex_Id).coord_Id := null_Id; end if; the_Vertices (vertex_Id).weights_Id := the_Vertices (vertex_Id).site_Id; end loop; case vertex_Count is when 3 => the_Face := (Triangle, the_Vertices); when 4 => the_Face := (Quad, the_Vertices); when others => put_Line ("parse_polyList ~ unhandled vertex count:" & vertex_Count'Image); end case; face_Count := face_Count + 1; the_Faces (face_Count) := the_Face; end; p_First := p_Last + 1; end loop; end parse_polyList; when Polygons => parse_Polygons: declare inputs_Count : constant Natural := the_Primitive.Inputs'Length; begin for Each in the_Primitive.P_List'Range loop declare P_Indices : std_Collada.Int_array renames the_Primitive.P_List (Each).all; vertex_Count : constant Natural := P_Indices'Length / inputs_Count; the_Vertices : Vertices (1 .. long_Index_t (vertex_Count)); the_Face : IO.Face; Base : math.Index; begin for vertex_Id in the_Vertices'Range loop Base := math.Index ( (Integer (vertex_Id) - 1) * inputs_Count + 1); the_Vertices (vertex_Id).site_Id := 1 + long_Index_t (P_Indices ( Base + vertex_Offset_of (the_Primitive))); the_Vertices (vertex_Id).normal_Id := 1 + long_Index_t (P_Indices ( Base + normal_Offset_of (the_Primitive))); if collada_Coords /= null then the_Vertices (vertex_Id).coord_Id := 1 + long_Index_t (P_Indices ( Base + coord_Offset_of (the_Primitive))); else the_Vertices (vertex_Id).coord_Id := null_Id; end if; the_Vertices (vertex_Id).weights_Id := the_Vertices (vertex_Id).site_Id; end loop; case vertex_Count is when 3 => the_Face := (Triangle, the_Vertices); when 4 => the_Face := (Quad, the_Vertices); when others => put_Line ("parse_Polygons ~ unhandled vertex count:" & vertex_Count'Image); end case; face_Count := face_Count + 1; the_Faces (face_Count) := the_Face; end; end loop; end parse_Polygons; when Triangles => parse_Triangles: declare inputs_Count : constant Natural := the_Primitive.Inputs'Length; P_Indices : std_Collada.Int_array renames the_Primitive.P_List (1).all; Base : math.Index := 1; begin for each_Tri in 1 .. the_Primitive.Count loop declare vertex_Count : constant := 3; the_Vertices : Vertices (1 .. vertex_Count); the_Face : IO.Face; begin for vertex_Id in the_Vertices'Range loop the_Vertices (vertex_Id).site_Id := 1 + long_Index_t (P_Indices ( Base + vertex_Offset_of (the_Primitive))); the_Vertices (vertex_Id).normal_Id := 1 + long_Index_t (P_Indices ( Base + normal_Offset_of (the_Primitive))); if collada_Coords /= null then the_Vertices (vertex_Id).coord_Id := 1 + long_Index_t (P_Indices ( Base + coord_Offset_of (the_Primitive))); else the_Vertices (vertex_Id).coord_Id := null_Id; end if; the_Vertices (vertex_Id).weights_Id := the_Vertices (vertex_Id).site_Id; Base := Base + inputs_Count; end loop; the_Face := (Triangle, the_Vertices); face_Count := face_Count + 1; the_Faces (face_Count) := the_Face; end; end loop; end parse_Triangles; when others => put_Line ("Warning: ignoring unimplemented primitive kind: " & the_Primitive.Kind'Image); end case; declare used_Faces : constant IO.Faces_view := new IO.Faces' (the_Faces (1 .. face_Count)); begin free (the_Faces); return (Sites => the_Sites, Coords => the_Coords, Normals => the_Normals, Weights => the_Weights, Faces => used_Faces); end; end to_Model; end openGL.IO.collada;