HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
tetprim/GR_PrimTetra.C
/*
* PROPRIETARY INFORMATION. This software is proprietary to
* Side Effects Software Inc., and is not to be reproduced,
* transmitted, or disclosed in any way without written permission.
*
* Produced by:
* Side Effects Software Inc
* 123 Front Street West, Suite 1401
* Toronto, Ontario
* Canada M5J 2M2
* 416-504-9876
*
* NAME: GR_PrimTetra.C (GR Library, C++)
*
* COMMENTS:
*/
#include "GR_PrimTetra.h"
#include "GEO_PrimTetra.h"
#include <GR/GR_Utils.h>
#include <RE/RE_Geometry.h>
using namespace HDK_Sample;
// See GEO_PrimTetra::registerMyself() for installation of the hook.
: GUI_PrimitiveHook("Tetrahedron")
{
}
GR_PrimTetraHook::~GR_PrimTetraHook()
{
}
const GEO_Primitive *geo_prim,
const GR_RenderInfo *info,
const char *cache_name,
GR_PrimAcceptResult &processed)
{
return new GR_PrimTetra(info, cache_name, geo_prim);
}
const char *cache_name,
const GEO_Primitive *prim)
: GR_Primitive(info, cache_name, GA_PrimCompat::TypeMask(0))
{
#ifdef TETRA_GR_PRIM_COLLECTION
myPrimIndices.append( prim->getMapIndex() );
#endif
myID = prim->getTypeId().get();
myGeo = NULL;
}
GR_PrimTetra::~GR_PrimTetra()
{
delete myGeo;
}
void
{
#ifdef TETRA_GR_PRIM_COLLECTION
myPrimIndices.entries(GA_Index(0));
#else
// nothing for single primitives - will not be called.
#endif
}
int geo_type,
const GT_PrimitiveHandle &ph,
const GEO_Primitive *prim)
{
if(geo_type == myID)
{
#ifdef TETRA_GR_PRIM_COLLECTION
myPrimIndices.append( prim->getMapIndex() );
#endif
return GR_PROCESSED;
}
}
void
const GT_PrimitiveHandle &primh,
const GR_UpdateParms &p)
{
// Fetch the GEO primitive from the GT primitive handle
const GEO_PrimTetra *tet = NULL;
// GL3 and above requires named vertex attributes, while GL2 and GL1 use
// the older builtin names.
const char *posname = "P";
const char *nmlname = "N";
RE_VertexArray *pos = NULL;
RE_VertexArray *nml = NULL;
// Initialize the geometry with the proper name for the GL cache
if(!myGeo)
myGeo = new RE_Geometry;
// Enable this codepath in tetra.C to collect multiple GEO_PrimTetras into
// one GR_PrimTetra.
#ifdef TETRA_GR_PRIM_COLLECTION
// Multiple GEO_PrimTetra's collected for this GR_Primitive
const int num_tets = myPrimIndices.entries();
if(num_tets == 0)
{
delete myGeo;
myGeo = NULL;
return;
}
{
const GU_Detail *dtl = georl.getGdp();
for(int i=0; i<myPrimIndices.entries(); i++)
{
GA_Offset off = dtl->primitiveIndex(myPrimIndices(i));
tet = dynamic_cast<const GEO_PrimTetra *>
( dtl->getGEOPrimitive(off) );
if(tet)
{
for(int v=0; v<4; v++)
pt.append(dtl->getPos3(dtl->vertexPoint(
tet->getVertexOffset(v))));
}
}
}
#else
// Single GEO_PrimTetra for this GR_Primitive
getGEOPrimFromGT<GEO_PrimTetra>(primh, tet);
const int num_tets = tet ? 1 : 0;
if(num_tets == 0)
{
delete myGeo;
myGeo = NULL;
return;
}
// Extract tetra point positions.
{
const GU_Detail *dtl = georl.getGdp();
for(int v=0; v<4; v++)
pt.append(dtl->getPos3(dtl->vertexPoint(tet->getVertexOffset(v))));
}
#endif
// Initialize the number of points in the geometry.
myGeo->setNumPoints( 12 * num_tets);
const GR_Decoration pdecs[] = { GR_POINT_MARKER,
dp, pdecs, GR_POINT_ATTRIB);
// Fetch P (point position). If its cache version matches, no upload is
// required.
pos = myGeo->findCachedAttrib(r, posname, RE_GPU_FLOAT32, 3,
if(pos->getCacheVersion() != dp.geo_version)
{
// map() returns a pointer to the GL buffer
UT_Vector3F *pdata = static_cast<UT_Vector3F *>(pos->map(r));
if(pdata)
{
for(int t=0; t<num_tets; t++)
{
pdata[0] = pt(t*4);
pdata[1] = pt(t*4+1);
pdata[2] = pt(t*4+2);
pdata[3] = pt(t*4);
pdata[4] = pt(t*4+2);
pdata[5] = pt(t*4+3);
pdata[6] = pt(t*4+1);
pdata[7] = pt(t*4+2);
pdata[8] = pt(t*4+3);
pdata[9] = pt(t*4);
pdata[10] = pt(t*4+3);
pdata[11] = pt(t*4+1);
pdata += 12;
}
// unmap the buffer so it can be used by GL
pos->unmap(r);
// Always set the cache version after assigning data.
pos->setCacheVersion(dp.geo_version);
}
}
// NOTE: you can add more attributes from a detail, such as Cd, uv, Alpha
// by repeating the process above.
// Fetch N (point normal). This just generates normals for the tetras.
nml = myGeo->findCachedAttrib(r, nmlname, RE_GPU_FLOAT32, 3,
if(nml->getCacheVersion() != dp.geo_version)
{
UT_Vector3F *ndata = static_cast<UT_Vector3F *>(nml->map(r));
if(ndata)
{
UT_Vector3F n0, n1, n2, n3;
// This just creates primitive normals for the tet. It's currently
// not 100% correct (FIXME).
for(int t=0; t<num_tets; t++)
{
n0 = -cross(pt(t*4+2)-pt(t*4), pt(t*4+1)-pt(t*4)).normalize();
n1 = cross(pt(t*4+3)-pt(t*4), pt(t*4+2)-pt(t*4)).normalize();
n2 = -cross(pt(t*4+3)-pt(t*4+1),pt(t*4+2)-pt(t*4+1)).normalize();
n3 = -cross(pt(t*4+1)-pt(t*4), pt(t*4+3)-pt(t*4)).normalize();
ndata[0] = ndata[1] = ndata[2] = n0;
ndata[3] = ndata[4] = ndata[5] = n1;
ndata[6] = ndata[7] = ndata[8] = n2;
ndata[9] = ndata[10] = ndata[11] = n3;
ndata += 12;
}
nml->unmap(r);
// Always set the cache version after assigning data.
nml->setCacheVersion(dp.geo_version);
}
}
// Extra constant inputs for the GL3 default shaders we are using.
// This isn't required unless
fpreal32 col[3] = { 1.0, 1.0, 1.0 };
fpreal32 uv[2] = { 0.0, 0.0 };
fpreal32 alpha = 1.0;
fpreal32 pnt = 0.0;
myGeo->createConstAttribute(r, "Cd", RE_GPU_FLOAT32, 3, col);
myGeo->createConstAttribute(r, "uv", RE_GPU_FLOAT32, 2, uv);
myGeo->createConstAttribute(r, "Alpha", RE_GPU_FLOAT32, 1, &alpha);
myGeo->createConstAttribute(r, "pointSelection", RE_GPU_FLOAT32, 1,&pnt);
myInstancedFlag =
UT_IntArray dummy;
GR_Utils::buildInstanceIndex(r, myGeo, false, dummy, 0);
// Connectivity, for both shaded and wireframe
}
// GL3 shaders. These use some of the builtin Houdini shaders, which are
// described by the .prog file format - a simple container format for various
// shader stages and other information.
static RE_ShaderHandle theNQShader("material/GL32/beauty_lit.prog");
static RE_ShaderHandle theNQFlatShader("material/GL32/beauty_flat_lit.prog");
static RE_ShaderHandle theNQUnlitShader("material/GL32/beauty_unlit.prog");
static RE_ShaderHandle theHQShader("material/GL32/beauty_material.prog");
static RE_ShaderHandle theLineShader("basic/GL32/wire_color.prog");
static RE_ShaderHandle theConstShader("material/GL32/constant.prog");
static RE_ShaderHandle theZCubeShader("basic/GL32/depth_cube.prog");
static RE_ShaderHandle theZLinearShader("basic/GL32/depth_linear.prog");
static RE_ShaderHandle theMatteShader("basic/GL32/matte.prog");
void
GR_RenderMode render_mode,
{
if(!myGeo)
return;
bool need_wire = (render_mode == GR_RENDER_WIREFRAME ||
render_mode == GR_RENDER_HIDDEN_LINE ||
render_mode == GR_RENDER_GHOST_LINE ||
render_mode == GR_RENDER_MATERIAL_WIREFRAME ||
// Shaded mode rendering
if(render_mode == GR_RENDER_BEAUTY ||
render_mode == GR_RENDER_MATERIAL ||
render_mode == GR_RENDER_CONSTANT ||
render_mode == GR_RENDER_HIDDEN_LINE ||
render_mode == GR_RENDER_GHOST_LINE ||
render_mode == GR_RENDER_DEPTH ||
render_mode == GR_RENDER_DEPTH_LINEAR ||
render_mode == GR_RENDER_DEPTH_CUBE ||
render_mode == GR_RENDER_MATTE)
{
// enable polygon offset if doing a wireframe on top of shaded
bool polyoff = r->isPolygonOffset();
if(need_wire)
r->polygonOffset(true);
r->pushShader();
// GL3 requires the use of shaders. The fixed function pipeline
// GL builtins (which are deprecated, like gl_ModelViewMatrix)
// are not initialized in the GL3 renderer.
if(render_mode == GR_RENDER_BEAUTY)
{
r->bindShader(theNQUnlitShader);
else if(flags & GR_RENDER_FLAG_FLAT_SHADED)
r->bindShader(theNQFlatShader);
else
r->bindShader(theNQShader);
}
else if(render_mode == GR_RENDER_MATERIAL)
{
r->bindShader(theHQShader);
}
else if(render_mode == GR_RENDER_CONSTANT ||
render_mode == GR_RENDER_DEPTH ||
render_mode == GR_RENDER_HIDDEN_LINE ||
render_mode == GR_RENDER_GHOST_LINE)
{
// Reuse constant for depth-only since it's so lightweight.
r->bindShader(theConstShader);
}
else if(render_mode == GR_RENDER_DEPTH_LINEAR)
{
// Depth written to world-space Z instead of non-linear depth
// buffer Z ([0..1] near-far depth range)
r->bindShader(theZLinearShader);
}
else if(render_mode == GR_RENDER_DEPTH_CUBE)
{
// Linear depth written to
r->bindShader(theZCubeShader);
}
else if(render_mode == GR_RENDER_MATTE)
{
r->bindShader(theMatteShader);
}
// setup materials and lighting
{
if(!mat)
// Set up lighting for any GL3 lighting blocks
if(shader && dp.opts->getLightList())
dp.opts->getLightList()->bindForShader(r, shader);
// set up the main material block for GL3
mat->updateShaderForMaterial(r, 0, true, true,
}
// Draw call for the geometry
else
myGeo->draw(r, RE_GEO_SHADED_IDX);
if(r->getShader())
r->popShader();
if(need_wire && !polyoff)
r->polygonOffset(polyoff);
}
// Wireframe rendering
if(need_wire)
{
// GL3 requires a shader even for simple wireframe rendering.
r->pushShader(theLineShader);
else
myGeo->draw(r, RE_GEO_WIRE_IDX);
r->popShader();
}
}
void
{
drawDecorationForGeo(r, myGeo, decor, p.opts, p.render_flags,
}
int
const GR_DisplayOption *opt,
unsigned int pick_type,
GR_PickStyle pick_style,
bool has_pick_map)
{
// This example is not pickable.
return 0;
}