############################
Creating Stream Cache Models
############################

Please be sure to first review the :doc:`Stream Cache format </prog_guide/viewing/data_model/stream_cache/overview>`. The StreamCache API is used to author your own StreamCache models, and support is provided for :doc:`C++ </api_ref/data_import/libsc/classes>` and :doc:`Java </api_ref/data_import/libsc_java/classcom_1_1techsoft3d_1_1communicator_1_1authoring_1_1SC>`.

You can take advantage of the Stream Cache API when authoring your own models. If you are using the C++ library you will need to include *sc_store.h* and link to *sc.lib*. If you are using Java you will need to include *scj.jar* and corresponding shared library *sc_java.dll*.

.. note::
	
   For more information on the location of these files in your HOOPS Communicator package, consult our :doc:`Package Description </overview/package-description>` page.
License
.......

Before using any SC functions, you must initialize the ``SC::Store::Database`` with your :doc:`license key </overview/license>`. The easiest way to accomplish this is to use the ``HOOPS_LICENSE`` definition which is available by including *hoops_license.h*.

``SC::Store::Database::SetLicense(HOOPS_LICENSE);``


Models
......

The first thing to do is open a read/write view of a stream cache based on the path that you supply. The directory must exist beforehand; otherwise, an exception is thrown. This function takes a path and a logger as parameters. The logger must be derived 
from ``SC::Store::Logger``.

.. code-block:: cpp

	Logger sLogger(true);
	SC::Store::Cache cache = SC::Store::Database::Open(sLogger);

Here is a basic implementation of the logger function::
	
	class Logger : public SC::Store::Logger {
	public:
	  Logger(bool sc_logging) : sc_logging(sc_logging) {};
	  virtual void Message(const char * message) const {
		if (sc_logging)
		  printf("SC: %s", message);
	  }
	  bool sc_logging;
	};

Next, create and open the model, and declare some variables we'll use later::

	SC::Store::Model model = cache.Open(file_path_string.c_str());
	SC::Store::InclusionKey include_key = model.Include(model);


Creating geometric data
.......................

To actually create geometric data (in this case, just a single triangle), we'll define a mesh in our model. The ``SC::Store::Mesh`` object contains all the raw float data associated with the mesh (for example, the x-y-z coordinates of the points). Below are examples of how to create and store this data in the ``Mesh`` object::

	SC::Store::Mesh mesh;
	float point_data[] = {
	  0.0f, 0.0f, 0.0f, // Point 0
	  1.0f, 0.0f, 0.0f, // Point 1
	  1.0f, 1.0f, 0.0f, // Point 2
	};
	mesh.point_count = 3;
	mesh.points = (SC::Store::Point const *)point_data;
	// (Alternatively a SC::Store::Point could be made directly instead of being cast from a float array.)


Normals::
	
	float normal_data[] = {
	  0.5f, 0.5f, 0.5f, // Point normal 0
	  0.5f, 0.5f, 0.5f, // Point normal 1
	  0.5f, 0.5f, 0.5f, // Point normal 2
	};
	mesh.normal_count = 3;
	mesh.normals = (SC::Store::Normal const *)normal_data;
	// (Alternatively a SC::Store::Normal could be made directly instead of being cast from a float array.)

	
UV parameters::
	
	float uv_data[] = {
	  0.75f, 0.75f, // UV parameter 0
	  0.75f, 0.75f, // UV parameter 1
	  0.75f, 0.75f, // UV parameter 2
	};
	mesh.uv_count = 3;
	mesh.uvs = (SC::Store::UV const *)uv_data;
	// (Alternatively a SC::Store::UV could be made directly instead of being cast from a float array.)

Color channels:
Each channel in an RGBA32 is an unsigned byte, with values in the inclusive range [0, 255]. ``RGBA32`` arrays are for colors local to a specific mesh. To add colors to instanced meshes, use :ref:`materials <prog_guide/data_import/authoring/data-import-stream-cache-models:materials>`.
	
.. code-block:: cpp

	SC::Store::RGBA32 rgba32[] = {
	  SC::Store::RGBA32(0xFF, 0x00, 0x00, 0xFF), // Color 0 (Red)
	  SC::Store::RGBA32(0x00, 0xFF, 0x00, 0xFF), // Color 1 (Green)
	  SC::Store::RGBA32(0x00, 0x00, 0xFF, 0xFF), // Color 2 (Blue)
	};
	mesh.rgba32_count = 3;
	mesh.rgba32s = rgba32;


Assigning parameters
....................

In this fragment, we are assigning the points, normals, UV parameters, and colors that we defined previously to a ``SC::Store::MeshElement`` object:
	
.. code-block:: cpp

	// Add a single face that consists of a single triangle.
	{
	  mesh.face_elements.resize(1);
	  SC::Store::MeshElement & face_mesh_element = mesh.face_elements[0];
	  
	  // Indices for vertex 0
	  face_mesh_element.indices.push_back(0); // Point 0
	  face_mesh_element.indices.push_back(0); // Normal 0
	  face_mesh_element.indices.push_back(0); // UV parameter 0
	  face_mesh_element.indices.push_back(0); // Color 0
	  // Indices for vertex 1
	  face_mesh_element.indices.push_back(1); // Point 1
	  face_mesh_element.indices.push_back(1); // Normal 1
	  face_mesh_element.indices.push_back(1); // UV parameter 1
	  face_mesh_element.indices.push_back(1); // Color 1
	  
	  // Indices for vertex 2
	  face_mesh_element.indices.push_back(2); // Point 2
	  face_mesh_element.indices.push_back(2); // Normal 2
	  face_mesh_element.indices.push_back(2); // UV parameter 2
	  face_mesh_element.indices.push_back(2); // Color 2
	}

The code fragment above defines a face and would result in a rendered triangle. If you also want the edges and points of the triangle to appear, you should define them as follows:
	
.. code-block:: cpp

	// Add a single polygonal line around our triangle.
	mesh.polyline_elements.resize(1);
	SC::Store::MeshElement & polyline_mesh_element = mesh.polyline_elements[0];
	polyline_mesh_element.indices.push_back(0); // Point 0
	polyline_mesh_element.indices.push_back(1); // Point 1
	polyline_mesh_element.indices.push_back(2); // Point 2
	polyline_mesh_element.indices.push_back(0); // Point 0

	// Add in vertices for our triangle mesh.
	mesh.point_elements.resize(1);
	SC::Store::MeshElement & point_mesh_element = mesh.point_elements[0];
	point_mesh_element.indices.push_back(0); // Point 0
	point_mesh_element.indices.push_back(1); // Point 1
	point_mesh_element.indices.push_back(2); // Point 2


Inserting geometry
..................

Once all the mesh parameters have been assigned, we can add the mesh to the opened model. After insertion, the data that was used to create the cache is no longer needed and can be disposed.

.. code-block:: cpp

	SC::Store::MeshKey mesh_key = model.Insert(mesh);

After the geometry is created, it must then be :ref:`instanced <prog_guide/data_import/authoring/data-import-stream-cache-models:Creating geometry instances>` before it can be rendered. Geometry that has not been instanced is ignored by the Stream Cache.


Materials
.........

Stream Cache supports materials. Here, we will create three RGB color channels. Each channel in ``SC::Store::Color`` is a float value in the inclusive range [0, 1].

.. code-block:: cpp

	float red_color_data[] = { 1.0f, 0.0f, 0.0f, 1.0f };
	SC::Store::Color * red_color = (SC::Store::Color *)red_color_data;
	// (Alternatively a SC::Store::Color could be made directly instead of being cast from a float array.)
	float green_color_data[] = { 0.0f, 1.0f, 0.0f, 1.0f };
	SC::Store::Color * green_color = (SC::Store::Color *)green_color_data;
	float blue_color_data[] = { 0.0f, 0.0f, 1.0f, 1.0f };
	SC::Store::Color * blue_color = (SC::Store::Color *)blue_color_data;
	SC::Store::MaterialKey material_key_red = model.Insert(*red_color);
	SC::Store::MaterialKey material_key_green = model.Insert(*green_color);
	SC::Store::MaterialKey material_key_blue = model.Insert(*blue_color);


Matrices
........

Let's define a scale matrix in our model:
	
.. code-block:: cpp

	float matrix_data[] = {
	  5.0f, 0.0f, 0.0f,
	  0.0f, 5.0f, 0.0f,
	  0.0f, 0.0f, 5.0f,
	  0.0f, 0.0f, 0.0f,
	};
	SC::Store::Matrix3d * matrix = (SC::Store::Matrix3d *)matrix_data;
	// (Alternatively a SC::Store::Matrix3d could be made directly instead of being cast from a float array.)

	SC::Store::MatrixKey matrix_key = model.Insert(*matrix);


Creating geometry instances
...........................

Now that we have mesh, material, and matrix definitions, we can combine these to add instanced geometry into our cache. 

This general pattern of ``Mesh --> MeshElement --> MeshKey --> InstanceKey`` is the way you will create most geometry. Note that these objects are independent of each other and can be used repeatedly to create multiple geometries.

In the code sample below, multiple instances are being created, but some instances have different matrices and materials.

.. code-block:: cpp

	SC::Store::InstanceKey instance_key_1 = model.Instance(mesh_key);
	SC::Store::InstanceKey instance_key_2 = model.Instance(mesh_key, matrix_key);
	SC::Store::InstanceKey instance_key_3 = model.Instance(mesh_key, matrix_key, material_key_blue);
	SC::Store::InstanceKey instance_key_4 = model.Instance(
	  mesh_key,
	  matrix_key,
	  material_key_red,
	  material_key_green,
	  material_key_blue,
	  SC::Store::MaterialMapKey(),
	  SC::Store::MaterialMapKey(),
	  SC::Store::MaterialMapKey(),
	  SC::Store::Visibility(SC::Store::Visibility::Face));
	// Set a component of an instance. Overrides the old component.
	model.Set(instance_key_1, material_key_blue, material_key_green, material_key_red); //blue faces, green edge, red points
	model.Set(instance_key_2, matrix_key);
	model.Set(instance_key_3, mesh_key);
	model.Set(instance_key_4, SC::Store::Visibility(SC::Store::Visibility::Face | SC::Store::Visibility::Line));

	// Delete an instance from our model.
	model.Delete(instance_key_4);


Camera
......

Let's set a default camera for our model.

.. code-block:: cpp

	model.Set(SC::Store::Camera(
	  SC::Store::Camera::Perspective, // Camera projection
	  SC::Store::DPoint(0.0, 0.0, -5.0), // Camera position
	  SC::Store::DPoint(0.0, 0.0, 0.0), // Camera target
	  SC::Store::DVector(0.0, 1.0, 0.0), // Camera up vector
	  2.0, 2.0)); // Camera width and height

The complete code sample is included in the package as *sc_store_sample.cpp*.


Authoring the assembly tree
...........................

This set of functions (available in ``SC::Store::AssemblyTree``) allows you to author the assembly tree node structure:

.. code-block:: cpp

	SC::Store::AssemblyTree assemblyTree(sLogger);  // Creates assembly tree authoring API instance
	uint32_t root_id = 0;
	uint32_t child_id_1 = 0, child_id_2 = 0, child_id_3 = 0, child_id_4 = 0;
	uint32_t root_child_id = 0;
	if (assemblyTree.CreateAssemblyTreeRoot(root_id))    // Creates assembly tree root
	{
	  if (assemblyTree.CreateChild(root_id, root_child_id))  // Creates a child node linked to the root
	  {
		assemblyTree.SetNodeName(root_child_id, "assembly root child");
		assemblyTree.CreateChild(root_child_id, child_id_1);  // Adds child and siblings to the node we just created
		assemblyTree.CreateChild(root_child_id, child_id_2);
		assemblyTree.CreateChild(root_child_id, child_id_3);
		assemblyTree.CreateChild(root_child_id, child_id_4);
		assemblyTree.SetNodeName(child_id_1, "child1");
		assemblyTree.SetNodeName(child_id_2, "child2");
		assemblyTree.SetNodeName(child_id_3, "child3");
		assemblyTree.SetNodeName(child_id_4, "child4");
	  }
	}

The local matrix, material, and visibility of a node can also be specified:
	
.. code-block:: cpp

	SC::Store::Matrix3d local_matrix;
	assemblyTree.SetNodeLocalTransform(child_id_1, local_matrix);

	SC::Store::Material material;
	assemblyTree.SetNodeMaterial(child_id_1, material);

	assemblyTree.SetNodeVisibility(child_id_1, true);
	assemblyTree.SetNodeWasRemoved(child_id_1, false);


Or, some attributes can be added to the node:
	
.. code-block:: cpp

	assemblyTree.AddAttribute(root_child_id, "Author", SC::Store::AssemblyTree::AttributeTypeString, "John Smith");
	assemblyTree.AddAttribute(root_child_id, "Date", SC::Store::AssemblyTree::AttributeTypeTime, "08/15/2012");
	assemblyTree.AddAttribute(root_child_id, "Version", SC::Store::AssemblyTree::AttributeTypeInt, "5");
	assemblyTree.AddAttribute(root_child_id, "Precision", SC::Store::AssemblyTree::AttributeTypeFloat, "0.0001");

You can then link the instance keys returned by instancing bodies with the model:
	
.. code-block:: cpp

	SC::Store::MeshKeys mesh_keys; //Put your mesh keys in here
	for (int i = 0; i < mesh_keys.size(); i++) {
	  SC::Store::InstanceKey instance_key = model.Instance(mesh_keys[i]);
	  uint32_t body_instance_node = 0; // put your body instance nodes here
	  assemblyTree.CreateAndAddBodyInstance(child_id_1, body_instance_node);
	  assemblyTree.SetBodyInstanceMeshInstanceKey(body_instance_node, SC::Store::InstanceInc(include_key, instance_key));
	}

You can then create parts, and link them to assembly tree nodes:
	
.. code-block:: cpp

	uint32_t part_id_1 = assemblyTree.CreatePart();
	assemblyTree.SetPart(child_id_1, part_id_1);
	uint32_t part_id_2 = assemblyTree.CreatePart();
	assemblyTree.SetPart(child_id_2, part_id_2);
	assemblyTree.SetPart(child_id_3, part_id_2);
	assemblyTree.SetPart(child_id_4, part_id_2);   // Note that in this case child 2, 3, and 4 will share the same part data

On the created part, you can add bodies:
	
.. code-block:: cpp

	uint32_t body_id_1, body_id_2;
	assemblyTree.CreateAndAddBody(part_id_2, body_id_1);
	assemblyTree.CreateAndAddBody(part_id_2, body_id_2);

On bodies, you can author measurement data:
	
.. code-block:: cpp

	SC::Store::Point origin(0.0f, 0.0f, 0.0f);
	SC::Store::Vector normal(0.0f, 1.0f, 0.0f);
	assemblyTree.SetLineEdgeMeasurementData(body_id_1, 135, 6.2f);
	assemblyTree.SetCircleEdgeMeasurementData(body_id_1, 98, 8.0f, origin, normal);
	assemblyTree.SetCylinderFaceMeasurementData(body_id_1, 57, 5.0f, origin, normal);
	assemblyTree.SetPlaneFaceMeasurementData(body_id_1, 243, origin, normal);

Then you can save everything to a model:
	
.. code-block:: cpp

	assemblyTree.SerializeToModel(model);

Or you can save it to an XML file:
	
.. code-block:: cpp

	assemblyTree.SerializeToXML(xml_filepath);

Additionally, you can load an assembly tree structure from an already existing XML file:
	
.. code-block:: cpp

	assemblyTree.DeserializeFromXML(xml_filepath);

The XML should look like this:

.. code-block:: html

	<!--HC 4.0-->
	<Root>
		<ModelFile>
			<ProductOccurence Id="0" Name="2+2-Cubes" Behaviour="1" Children="1"/>
			<ProductOccurence Id="1" Name="2+2-Cubes" Behaviour="0" Children="2">
				<Material Color="1 1 1 1"/>
				<Transformation RelativeTransfo="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1"/>
			</ProductOccurence>
			<ProductOccurence Id="2" Name="Default" Behaviour="0" Children="3 4">
				<Transformation RelativeTransfo="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1"/>
				<Attributes>
					<Attr Name="SW-File Name(File Name)" Type="String" Value="2+2-Cubes"/>
					<Attr Name="SW-Folder Name(Folder Name)" Type="String" Value="E:\Tests\SolidWorks\By Issues\New Reader\Too much or to few Solids get\ShowHide\2\"/>
					<Attr Name="SW-Short Date(Short Date)" Type="String" Value="21/10/2014"/>
					<Attr Name="SW-Long Date(Long Date)" Type="String" Value="mardi 21 octobre 2014"/>
					<Attr Name="SW-Configuration Name(Configuration Name)" Type="String" Value="Default"/>
					<Attr Name="SW-Author(Author)" Type="String" Value=""/>
					<Attr Name="SW-Keywords(Keywords)" Type="String" Value=""/>
					<Attr Name="SW-Comments(Comments)" Type="String" Value=""/>
					<Attr Name="SW-Title(Title)" Type="String" Value=""/>
					<Attr Name="SW-Subject(Subject)" Type="String" Value=""/>
					<Attr Name="SW-Created Date(Created Date)" Type="String" Value="lundi 10 décembre 2012 16:32:25"/>
					<Attr Name="SW-Last Saved Date(Last Saved Date)" Type="String" Value="mardi 21 octobre 2014 18:21:12"/>
					<Attr Name="SW-Last Saved By(Last Saved By)" Type="String" Value="erwan"/>
					<Attr Name="Assembly type" Type="Int" Value="0"/>
					<Attr Name="SW-HasDesignTable" Type="Int" Value="0"/>
					<Attr Name="Component Type" Type="Int" Value="0"/>
				</Attributes>
			</ProductOccurence>
			<ProductOccurence Id="3" Name="2-Cubes-1" Behaviour="1" Children="5 6">
				<Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 -130.25111389160156 197.71389770507812 -126.79463195800781 1"/>
			</ProductOccurence>
			<ProductOccurence Id="5" Name="Cube-1" Behaviour="1" InstanceRef="8">
				<Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 57.656867980957031 48.991302490234375 58.701534271240234 1"/>
			</ProductOccurence>
			<ProductOccurence Id="8" Name="" Behaviour="1">
				<PartDefinition Id="7" FilePath="000001E6223BDFE0"/>
			</ProductOccurence>
			<ProductOccurence Id="6" Name="Cube-2" Behaviour="1" InstanceRef="8">
				<Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 239.89179992675781 94.406867980957031 79.417366027832031 1"/>
			</ProductOccurence>
			<ProductOccurence Id="4" Name="2-Cubes-2" Behaviour="0" Children="9 10">
				<Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 -131.93794250488281 90.37158203125 -251.8642578125 1"/>
			</ProductOccurence>
			<ProductOccurence Id="9" Name="Cube-1" Behaviour="1" InstanceRef="8">
				<Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 57.656867980957031 48.991302490234375 58.701534271240234 1"/>
			</ProductOccurence>
			<ProductOccurence Id="10" Name="Cube-2" Behaviour="0" InstanceRef="8">
				<Transformation RelativeTransfo="1 0 -0 0 -0 1 0 0 0 0 1 0 239.89179992675781 94.406867980957031 79.417366027832031 1"/>
			</ProductOccurence>
		</ModelFile>
	</Root>


If you've already built model files for each part and registered the assembly tree data, you can build the master assembly model file using one function call:

.. code-block:: js
	
	assemblyTree.BuildMasterAssemblyModel(models_path_utf8, assembly_model_path_utf8, nullptr, false);

For a more in-depth look at authoring using Stream Cache API, please see the examples in the Communicator package, located at *authoring -> libsc -> examples*.


Exception handling
------------------

**IMPORTANT:** The Stream Cache API will throw exceptions when errors are encountered. Your code should be prepared to catch ``SC::Store::Exception::Exception`` (inherits from ``std::exception``) and handle it as gracefully as possible.
