blob: e81d129b8a1311783088b239f3b7cb1bdcf64fe6 [file] [log] [blame]
#ifndef RTTL_RT_H
#define RTTL_RT_H
/*! \file rt.h RTTL core api. @ingroup rt_api */
#include "ISG.hxx" // obviously, _that_ should eventually _not_ be visible to the app...
// namespace LRT {
using namespace RTTL;
using namespace ISG;
/** @ingroup rt_api */
/*@{*/
/*! note: this is subject to change: eventually, node_t will be an int
_referencing_ a node, not a pointer to the node itself (thus, we
can use the same ID on both host and device */
typedef ISG::Node *node_t;
/*! a data array. see \ref notes_on_data_arrays */
typedef ISG::DataArray *data_t;
typedef ISG::BaseMesh *mesh_t;
typedef unsigned int uint_t;
// =======================================================
/* PARAMETER TYPES: strongly typed, to make coding easier -- but may
eventually go back to #define'ing them and storing them as RTuint's
like GL does... */
/*! 'default' is always 0 -- make sure that this is the case in all of
the flags defined below ... */
#define RT_DEFAULT 0
/*! the various parameter options for the 'flags' parameter in \ref rtNewRoot */
typedef enum {
RT_HIDDEN=RT_DEFAULT,
RT_VISIBLE
} newroot_flags_t;
/*@}*/
/** @ingroup rt_api */
/*@{*/
/*! probably something like rtInstantiate(root_node) in openrt lingo... -- at least for now */
void rtShow(node_t node);
extern_inline void rtHide(node_t node) { NOTIMPLEMENTED; };
/*! create a new root node (i.e., one that doesn't need a parent -- see \ref node_ownership
as long as we dont konw how (if?) we handle multiple
instantiations (e.g., do we allow instances of instances ??),
thi'll probably just be the same as an "object" in openrt lingo.
\param flags flags for object creation. Currently, can be RT_VISIBLE or RT_HIDDEN (RT_DEFAULT==RT_HIDDEN)
*/
extern_inline node_t rtNewRoot(newroot_flags_t flags)
{
node_t root = new RootNode;
if (flags & RT_VISIBLE)
rtShow(root);
return root;
}
/*! create a new mesh node */
extern_inline mesh_t rtNewMesh(node_t parent, MeshType type)
{
assert(parent);
mesh_t mesh = new BaseMesh(parent,type); // that's all we
GroupNode *group = dynamic_cast<GroupNode*>(parent);
if (!group)
FATAL("can only add meshes to group nodes ... at least right now ... ");
group->addChild(mesh);
// specify -- leave it
// to the core to
// decide what actual
// implementatoin to
// use, depending on
// how the mesh's addtl
// data is specified
return mesh;
}
/*@}*/
extern_inline mesh_t rtTriangleMesh(node_t parent)
{
return rtNewMesh(parent,RT_TRIANGLE_MESH);
}
extern_inline mesh_t rtQuadMesh(node_t parent)
{
return rtNewMesh(parent,RT_QUAD_MESH);
}
/*! the various parameter options for the 'flags' parameter in,
e.g., \ref rtVertexArray3f, \ref TriangleArray3i, etc
different flags can be 'or'ed together. every bit should have a
symbolic name for both its 'true' and its 'false' case (e.g.,
RT_PRIVATE and RT_PERSISTENT, RT_FORCE_OVERWRITE and
RT_NEW_ARRAY, etc)
\note might need better names ....
*/
typedef enum {
RT_PRIVATE=RT_DEFAULT,
/*! if specified, data is _shard_ with the app, i.e., we actually
point into the app's address space instead of copying the data
... */
RT_PERSISTENT=1,
RT_PERSISTENT_BIT=(RT_PERSISTENT),
/*! if specified, _force_ overwriting the specific data array
even though it may be shared. For instance, if two meshes m1 and
m2 share a given vertex array, then rtVertexArray3f(m2, ...,
RT_DEFAULT) would have m1 and m2 end up with two different
vertex arrays (m1 has the old one, m2 the new one), whereas
rtVertexArray(m2, ..., RT_FORCE_OVERWRITE would overwrite the
_shared_ vertex array, thus having a implicit side-effect on m1,
too.
\note: may also be beneficial even if data array is not shared:
e.g., assuming mesh m already has a vertex array of the proper
size, then specifying RT_FORCE_OVERWRITE will actually force a
direct memcopy, whereas not specifying it will first create a
new array
\note opposite of RT_NEW_ARRAY
*/
RT_FORCE_OVERWRITE=RT_DEFAULT,
/*! the opposite of RT_FORCE_OVERWRITE */
RT_NEW_ARRAY=2,
RT_NEW_ARRAY_BIT=(RT_NEW_ARRAY|RT_FORCE_OVERWRITE),
RT_FORCE_OVERWRITE_BIT=(RT_NEW_ARRAY|RT_FORCE_OVERWRITE)
} DataArrayFlags;
/*! mapping modes for rtMap... calls */
typedef enum {
RT_READ = 0x1,
RT_WRITE = 0x2,
RT_RW=RT_READ|RT_WRITE
} MapMode;
// -------------------------------------------------------
/*! initialize the ray tracer -- eventually parse the options etc,
but do nothing as yet */
extern_inline void rtInit(int *acptr, char **avptr)
{
cout << "initializing LRT ray tracer ..." << endl;
};
// -------------------------------------------------------
// -------------------------------------------------------
/*! destroy a node, and all its dependents that do not have other owners -- see \ref node_ownership */
extern_inline void rtDestroy(node_t node)
{
/* not yet implemented ... */
}
extern_inline data_t rtNewDataArray(node_t parent,
SemanticType semanticType=RT_RAW_DATA,
DataFormat dataFormat=RT_BYTE
)
{
DataArray *arr = new DataArray(parent,
semanticType,
dataFormat
);
return arr;
};
/* no type checking/conversion right now ... */
extern_inline void rtWriteToArray(data_t target,
SemanticType semanticType,
DataFormat dataFormat,
unsigned char *const ptr,
int count,
DataArrayFlags flags)
{
assert(target);
DataArray *array = dynamic_cast<DataArray *>(target);
assert(array);
/* actually, would have to do some type checking here, and either
return an error (eg, when app tries to pass persistent array of
wrong format, or convert on the fly */
if ((flags & RT_PERSISTENT_BIT) == RT_PERSISTENT)
{
// have array hard-point into app's memory space, to pointer specified by app
array->set(semanticType,dataFormat,ptr,count,DataArray::APP_IS_OWNER);
}
else
{
array->set(semanticType,dataFormat,ptr,count,DataArray::I_AM_OWNER);
}
}
extern_inline void rtCoords3f(data_t target, const float *const coord, int coords, DataArrayFlags flags)
{
rtWriteToArray(target,RT_COORDS,RT_FLOAT3,(unsigned char *)coord,coords,flags);
// rtWriteToArray(target,RT_COORD,RT_FLOAT3,(unsigned char *)ptr,cnt,flags);
}
extern_inline void rtIndices3i(data_t target, const int *const coord, int coords, DataArrayFlags flags)
{
rtWriteToArray(target,RT_INDICES,RT_INT3,(unsigned char *)coord,coords,flags);
}
extern_inline void rtIndices4i(data_t target, const int *const coord, int coords, DataArrayFlags flags)
{
FATAL("if mesh is triangular mesh then quad tesellation is required");
rtWriteToArray(target,RT_INDICES,RT_INT4,(unsigned char *)coord,coords,flags);
}
/*
void rtMeshCoords(mesh_t meshRef, data_t coord)
{
BaseMesh *mesh = dynamic_cast<BaseMesh *>(meshRef);
assert(mesh);
assert(coord);
mesh->setCoords(coord);
};
void rtMeshIndices(mesh_t meshRef, data_t index)
{
BaseMesh *mesh = dynamic_cast<BaseMesh *>(meshRef);
assert(mesh);
assert(index);
mesh->setIndices(index);
};
*/
/*! returns a _reference_ to the mesh's coord arra. note that you
still have to call rtMapBuffer on that to get the actual pointer
(at least, if you want to stay within the API's memory model
(the data array might live on the DEVICE!), so returning a
reference to it is different from returning a pointer to an
actual buffer that contains the data (which might require an
actual device-to-host memcopy!)
\param node should reference a valid node that contains a vertex
array (such as a mesh). if that is not the case (i.e., node
references a transform node), it will return an invalid
reference (NULL, or whatever reference corresponds to it)
*/
extern_inline data_t rtGetMeshCoords(mesh_t m)
{
BaseMesh *mesh = dynamic_cast<BaseMesh *>(m);
// PRINT(mesh);
assert(mesh);
// PRINT(mesh->coord);
return mesh->coord;
};
extern_inline data_t rtGetMeshIndices(mesh_t m)
{
BaseMesh *mesh = dynamic_cast<BaseMesh *>(m);
assert(mesh);
return mesh->index;
};
extern_inline data_t rtNewCoordArray(node_t parent, DataFormat internalFormat)
{
data_t data = new DataArray(parent, RT_COORDS, internalFormat);
mesh_t mesh = dynamic_cast<BaseMesh*>(parent);
if (mesh)
mesh->setCoords(data);
return data;
}
extern_inline data_t rtNewIndexArray(node_t parent, DataFormat internalFormat)
{
data_t data = new DataArray(parent, RT_INDICES, internalFormat);
mesh_t mesh = dynamic_cast<BaseMesh*>(parent);
if (mesh)
mesh->setIndices(data);
return data;
}
/*! returns whether some data is valid (i.e., non-null). note that
since data_t might be a _reference_ to a pointer on another
device, we can't (shouldn't!) directly compare to 'NULL'.... */
extern_inline bool rtValidData(data_t data)
{
return data != NULL; /* as long as all data is on the host, we can
do that -- but do _NOT_ do that in the
app! */
}
/*! map a data reference. since we're not yet double-buffering,
anyway, right now we'll just return a pointer to the data. will
eventually have to create copies if mapping to buffers that are
still being used internally) */
extern_inline void * rtMapBuffer(data_t data, MapMode mapMode)
{
if (!data) return NULL;
return data->m_ptr;
}
/*! the couterpart to rtMapBuffer. should be _exactly_ the same
pointer as returned by rtMapBuffer. do not fail to unmap any
mapped item, do not unmap more than once. */
extern_inline void rtUnmapBuffer(data_t data)
{};
// #ifdef __cplusplus
// /*! c++ convenience fct */
// vec3f *rtMapCoords_vec3f(mesh_t node, MapMode mapMode)
// {
// data_t data = rtGetMeshCoords(node);
// assert(rtValidData(data));
// return (vec3f*)rtMapBuffer(data,mapMode);
// }
// /*! c++ convenience fct */
// template <class T>
// void rtUnmapBuffer(T *data)
// { rtUnmapBuffer((void*)data); };
// #endif
extern_inline void rtEndGeometry() { /* do nothing right now -- supposed to flag
that we can now start building whatever
data structures we need ... */ };
// }; // end namespace
#endif