Creating Stream Cache Models
Please be sure to first review the Stream Cache format. The StreamCache API is used to author your own StreamCache models, and support is provided for C++ and Java.
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 Package Description page.
License
Before using any SC functions, you must initialize the SC::Store::Database
with your license key. 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
.
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 materials.
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:
// 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:
// 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.
SC::Store::MeshKey mesh_key = model.Insert(mesh);
After the geometry is created, it must then be instanced 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].
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:
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.
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.
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.