326 lines
14 KiB
Ada
326 lines
14 KiB
Ada
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;
|