Fish - FiberLib for VISH 0.3
Fish - The Fiber Bundle API for the Vish Visualization Shell
ColoredLines.cpp

Display a set of lines as specified by the Edge skeleton of a grid.

Display a set of lines as specified by the Edge skeleton of a grid.Refinement levels and fragmented fields not implemented.

#include <ocean/plankton/VPipeline.hpp>
#include <ocean/GLvish/VGLRenderObject.hpp>
#include <ocean/GLvish/BoundingBox.hpp>
#include <ocean/GLvish/VGLColormap.hpp>
#include <ocean/GLvish/GlossyTexture.hpp>
#include <ocean/GLvish/ArrayTypes.hpp>
#include <eagle/PhysicalSpace.hpp>
#include <ocean/shrimp/VEnum.hpp>
#include <ocean/shrimp/TimeDependent.hpp>
#include <ocean/shrimp/VObjectStatus.hpp>
#include <ocean/shrimp/EaglePhysicalSpaceTVector.hpp>
#include <ocean/Anemonia/FloatOrigin.hpp>
#include <GL/FieldBuffer.hpp>
#include <GL/LineSetRenderer.hpp>
#include <bone/GridActor.hpp>
#include <bone/GridObject.hpp>
#include <bone/FishField.hpp>
#include <bundle/BundleProperty.hpp>
#include <grid/types/LineSet.hpp>
#include <baseop/ExpandBBox.hpp>
#include <baseop/GridField.hpp>
#include <fiberop/Range.hpp>
#include <field/ArrayRef.hpp>
#include <memcore/Chunk.hpp>
//#define VERBOSE
using namespace Wizt;
using namespace Fiber;
using namespace Eagle;
namespace
{
class RampTexture : public GLTexture1D
{
typedef FixedArray<float,3> rgb;
rgba_float_t color1;
rgba_float_t color2;
public:
RampTexture(const int tex_unit, const rgba_float_t&c1, const rgba_float_t&c2)
: GLTexture1D(tex_unit)
, color1(c1)
, color2(c2)
{}
void enlighten()
{
rgb texture[512];
rgb col;
double p;
for(int i = 0; i < 512 ; i++)
{
p = double(i)/512.0;
col[0] = (1-p)*color1[0] + p*color2[0];
col[1] = (1-p)*color1[1] + p*color2[1];
col[2] = (1-p)*color1[2] + p*color2[2];
texture[i] = col;
}
create_and_bind();
GL::TexImage1D( texture, 512, GL_RGB);
glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri( GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
void prerender()
{
enable();
//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); //not really nesseccasy ?
bind(); // should do corresponding glActiveTexture(GL_TEXTURE1); ?? automatically ??
}
};
/**@example ColoredLines.cpp Display a set of lines as specified by the Edge skeleton of a grid.
Refinement levels and fragmented fields not implemented.
*/
/**@ingroup LineViz
Render Lines with a color-mapped scalar field.
@see GlossyLines
@todo Should probably derive all line render VObject's from a common base class.
*/
class GlossColorMapLines : public virtual VGLRenderObject
, public TimeDependent
, public FloatOrigin
{
struct FieldState : State
{
WeakPtr<Grid> theGridOfInterest;
};
RefPtr<State> newState() const override
{
return new FieldState();
}
struct FragIt : FieldFragmentIterator
{
RefPtr<FieldState> S;
FragIt( RefPtr<FieldState> & SP )
: S( SP )
{
S->fragments.clear();
}
bool apply(const RefPtr<FragmentID>&f,
{
if(!f)
return false;
S->fragments.push_back( f );
return true;
}
} ;
public:
GlossyTexture::Parameters GlossyParameters;
TypedSlot<Grid> MyLinesGrid;
TypedSlot<Field> InputField;
TypedSlot<double> LineWidth;
TypedSlot<rgba_float_t> ColStart, ColEnd;
TypedSlot<Enum> GhostyLines;
TypedSlot<Range> InputRange;
enum { NumberOfInputFields = 1 };
typedef META::LIST<double> InputTypes;
// wrong, should check for line sets
// typedef Fiber::GridInspector<BundleProperty::Anything> GridInspector;
struct GridInspector
{
static SkeletonExistence InspectionProperty()
{
return SkeletonExistence( LineSet::ID() );
}
};
GlossColorMapLines(const string&name, int p, const RefPtr<VCreationPreferences>&VP)
, GlossyParameters(this)
, MyLinesGrid(this, "grid", GridSelector(), 2)
, InputField(this, "field" )
, LineWidth(this, "linewidth", 2.0, 1)
, ColStart(this, "col_start", {0.0, 1.0, 0.0, 1.0},2)
, ColEnd (this, "col_end" , {1.0, 0.0, 0.0, 1.0},2)
// , AutoLenScale(this, "autoscale", Enum(1,"on", "off"), 0)
, GhostyLines(this, "ghostylines", Enum("off", "on"),3 )
, InputRange(this, "range", Range(0,1), 0)
, Colormap(this, "colormap", NullPtr() )
// , LengthRange( self(), "fieldrange", Range(0.0, 1.0) )
{
LineWidth.setProperty( "max", 20.0);
}
void setup(const CreationSlots_t&CreationSlots) override
{
setupTime(CreationSlots);
}
bool update(VRequest&R, double precision) override;
bool renderGL(VGLRenderContext&Context) const override;
static string createChildname(const string&parent_name)
{
return "ColoredLinesOf" + parent_name;
}
};
//
// Update function, is called whenever some input is changed
// It extracts the fields required for rendering and deposits them
// in the context-relative state object. This state object is
// available then during rendering.
//
bool GlossColorMapLines::update(VRequest&Context, double precision)
{
// exit(0);
/*
{
VEnum als;
AutoLenScale << Context >> als;
if (als()==0) setExpertLevel(InputRange, 10);
else setExpertLevel(InputRange, 0);
}
*/
InputField << Context >> FS;
MyLinesGrid << Context >> GS;
GridField GF(GS, FS, getTime(Context) );
if (!GF.getGrid() )
{
return setStatusError(Context, "No grid object found at T=" + String( getTime(Context) ) );
}
/*
Info<Skeleton> SI;
{
SI = GS.getRefinementLevel( getTime(Context), 0, 0 );
}
double time = SI.getTime();
if (!SI.getGrid() )
{
SI = FS.getRefinementLevel( getTime(Context), 0, 0 );
time = SI.getTime();
if (!SI.getGrid() )
return setStatusError(Context,"No grid object found at T=" + String(time) );
}
*/
setBoundingBall( Context, getBoundingBox( *GF.getGrid() ) );
RefPtr<FieldState> S = myState(Context);
LineSet LS = GF.getGrid();
if (!LS)
{
return setStatusError(Context,"No line grid found at T=" + String( GF.getTime() ) );
}
if (!LS.CartesianVertices)
{
return setStatusError(Context,"No grid without cartesian vertices at T=" + String( GF.getTime() ) );
}
S->theGridOfInterest = GF.getGrid();
LS.setupStandardFields( GF.getGrid() );
// collect fragment IDs in state
FragIt myIt(S);
if( LS.LineIndices )
LS.LineIndices->iterate(myIt);
else
setStatusError(Context,"No LineIndices Field fount at T=" + String( GF.getTime() ) );
#ifdef VERBOSE
for(size_t i = 0; i < S->fragments.size(); i++ )
cout << "Found LineSet-Fragment: " << S->fragments[i]->Name() << endl;
#endif
// if no fragments push one NullPtr on the vector, so the for loop in the rendering
// can be used for unfragmented linesets as well
if( S->fragments.empty() )
S->fragments.push_back( NullPtr() );
//RefPtr<Field> F = (*LS.CartesianVertices)( FS.getFieldName() );
// if (!F) F = (*LS.CartesianVertices)( LineSet::ArcLengthFieldName );
// if (F)
{
/*
if (RefPtr<DataRange<double> > DR = getRange(*F) )
{
Range FieldRange(DR->Min(), DR->Max() );
LengthRange << Context << FieldRange;
}
*/
// S->TextureField = F;
// S->Fieldname = FS.getFieldName();
return setStatusInfo(Context, "Lines ready, inspecting " + FS.getFieldName() );
}
// else
{
// S->TextureField = NullPtr();
// return setStatusInfo(Context, "Lines ready, no field available.");
}
}
static
RefPtr<MemBase> ApplyRange(const Range&R, const RefPtr<MemArray<1, double> >&Data)
{
const MultiArray<1, double>&Input = *Data;
ArrayRef<double> Output(Input.Size() );
for(index_t i=0; i<Output.size(); i++)
{
Output[i] = R(Input[ i ]);
}
return Output;
}
/*
The renderer object for the VBO. It uses the information
about line segments to issue glDrawElements() commands.
It is implemented as a callback iterator object for
LineSet's.
@todo Investigate this construction whether it not creates a
circular reference keeping the involved Grid object
alive by itself. Probably it does not, but that has
to be verified by investing some more brain power.
Update: yes it did. Must not derive from LineSet here.
This is an absolute NO.
Previous code die
@code
struct MyRenderer : DrawArrays, LineSet
{
};
@endcode
which was a very bad idea...
*/
/*
The render routine. Takes care of vertex buffer objects
and calls its render routines.
*/
bool GlossColorMapLines::renderGL(VGLRenderContext&Context) const
{
Eagle::tvector3 TranslationVector;
auto V = getCoordinateTranslation(Context, TranslationVector);
// cout << "Transvec: " << TranslationVector << endl;
// puts("GlossColorMapLines::render()");fflush(stdout);
RefPtr<FieldState> S = getState(Context);
if (!S)
return false;
if (!S->theGridOfInterest)
return false;
LineSet LS(S->theGridOfInterest);
if (!LS.LineIndices)
return false;
FieldSelector FS, FS_off;
InputField << Context >> FS;
string Fieldname = FS.getFieldName();
//
// Setup glossy texture on unit 0
//
glActiveTexture(GL_TEXTURE0);
RefPtr<GlossyTexture> LineTexture;
{
RefPtr<ValueSet> GlossyValues = new ValueSet();
try
{
LineTexture = Context( *S )( this ) ( GlossyValues ) ( TEXTURE() );
}
catch( const GLError&)
{}
if (!LineTexture)
{
LineTexture = new GlossyTexture(0);
LineTexture->enlighten();
LineTexture->enlighten(GlossyParameters, Context);
GLCHECK( LineTexture->enlighten );
Context[ *S ][ this ][ GlossyValues ] ( TEXTURE() ) = LineTexture;
}
}
//
// Setup coloration texture on unit 1
//
{
RefPtr<ValueSet> CmapValues = new ValueSet(Colormap(Context) );
TextureCreator&TC = Context[ *LS.LineIndices ][ this ][ CmapValues ]( TEXTURE() );
RefPtr<RampTexture> LineTexture2;
VColormap Cmap;
Colormap << Context >> Cmap;
if (!GLColormap::Enable(Cmap, TC, 1, true) )
{
rgba_float_t c1, c2;
ColStart << Context >> c1;
ColEnd << Context >> c2;
LineTexture2 = new RampTexture(1, c1, c2);
LineTexture2->enlighten();
LineTexture2->prerender();
}
}
//
//
// OpenGL prefix
//
//
double width = 1.0;
LineWidth << Context >> width;
if( width < 1e-4)
width = 0.01;
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glDisable(GL_LIGHTING);
glEnable( GL_DEPTH_TEST );
glLineWidth(width);
// blending, experiment here
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_ONE, GL_ONE);
Enum GhostL;
GhostyLines << Context >> GhostL;
if (GhostL("on") )
glEnable( GL_BLEND );
else
glDisable( GL_BLEND );
glEnable ( GL_COLOR_MATERIAL );
//Enum Auto;
// AutoLenScale << Context >> Auto;
{
glActiveTexture(GL_TEXTURE0);
assert(LineTexture);
GlossyTexture::Render LINERENDER( *LineTexture, Context.getCameraSettings() );
Range ValueRange(0.0, 1.0);
/*
switch( Auto() )
{
case 1:
*/
InputRange << Context >> ValueRange;
/*
break;
default:
case 0:
LengthRange << Context >> ValueRange;
}
*/
const int ColormapTextureUnit = 1;
#if 0
//
// Do scaling of colormap values via texture matrix on unit 1
// which is much faster than rescaling the input values of the
// provided scalar field.
//
glActiveTexture(GL_TEXTURE1);
glMatrixMode(GL_TEXTURE);
glTexCoord4d(0.0, 0.0, 0.0, 1.0);
/*
m * (t,0,0,0) = t( m[0] + m[1] + m[2] + m[3] )
*/
/*
double m[16] = { ValueRange.inv_scale(), 0,0, ValueRange.inv_bias(),
0,1,0,0,
0,0,1,0,
0,0,0,1 };
*/
// double m[16] = { ValueRange.inv_scale(), 0,0, ValueRange.bias(),
// double m[16] = { 1.0, 0,0, ValueRange.bias(),
double m[16] = { 1.0, 0,0, 0,
0,1,0,0,
0,0,1,0,
0,0,0,1 };
/* printf("TEXTURE MAPPING: inv[scale=%lg, bias=%lg] [scale=%lg, bias=%lg], f(0)=%lg f(1)=%lg\n",
ValueRange.inv_scale(), ValueRange.inv_bias(),
ValueRange.scale(), ValueRange.bias(),
m[3], m[0] + m[3]
);
*/
glLoadMatrixd( m );
glMatrixMode(GL_MODELVIEW);
#endif
RefPtr<ValueSet> myCacheableValues = new ValueSet();
// for each field make a new VBO
*myCacheableValues <<= InputField(Context);
// printf("CACHE VALUE: [%s]\n", myCacheableValues->ValueState().c_str() );
// WeakPtr<VValueBase> VB = InputField(Context);
// printf("INPUT FIELD: [%s]\n", VB->Text().c_str() );
// TODO sort by kdtree
for( size_t frag_i = 0; frag_i < S->fragments.size(); frag_i++ )
{
string VBOKey ="";
if( S->fragments[frag_i] )
VBOKey = S->fragments[frag_i]->Name();
#ifdef VERBOSE
cout << "VBKey: " << VBOKey << endl;
#endif
RefPtr<VBO> myVBO;
Intercube&CacheObject = *S->theGridOfInterest;
try
{
myVBO = Context( CacheObject )( typeid(*this) )( myCacheableValues )( VERTEXBUFFER(), VBOKey );
}
catch(...){} // could investigate reasons here why cache is not available.
RefPtr<Field> TextureField = (*LS.CartesianVertices)( Fieldname );
#if 1
if (!myVBO || !myVBO->getRenderer() ||
myVBO->isOlderThan( ConnectionAge() ) ||
(LS.Coords && myVBO->isOlderThan( *LS.Coords) ) ||
(LS.LineIndices && myVBO->isOlderThan( *LS.LineIndices) ) ||
(TextureField && myVBO->isOlderThan( *TextureField) ) ||
// InputRange.age( Context ).isNewerThan( *S ) ||
InputRange.age( Context ).isNewerThan( *myVBO ) )
#else
if (true)
#endif
{
#ifdef VERBOSE
if (!myVBO) puts("No VBO found");
else
{
if (!myVBO->getRenderer() ) puts("No rendered in VBO");
if (LS.Coords && myVBO->isOlderThan( *LS.Coords) ) puts("Coordinates are newer");
if (LS.LineIndices && myVBO->isOlderThan( *LS.LineIndices) ) puts("Line indices are newer");
if (myVBO->isOlderThan( ConnectionAge() ) ) puts("network connections have changed");
if (TextureField && myVBO->isOlderThan( *TextureField) ) puts("color field has changed");
if (InputRange.age( Context ).isNewerThan( *S ) ) puts("input range is newer than status");
if (InputRange.age( Context ).isNewerThan( *myVBO ) ) puts("input range is newer than vbo");
}
#endif
RefPtr<MemBase> Pts = LS.Coords->getData( S->fragments[frag_i] );
//std::vector<point> vertices = Pts;
RefPtr<MemArray<1, point> > TA = Pts;
if(!TA)
{
puts("No coords array retrieved");
return false;
}
std::vector<point> VertexVector = TA->myChunk()->get_vector();
// here float origin?
for(index_t v = 0; v < VertexVector.size(); v++ )
VertexVector[v] -= TranslationVector;
myVBO = Context[ CacheObject ][ typeid(*this) ][ myCacheableValues ] ( VERTEXBUFFER(), VBOKey );
myVBO->clear();
if (RefPtr<LineSet::TangentialVector_t> Tangents = LS.getTangentialVectors( S->fragments[frag_i] ) )
{
#ifdef VERBOSE
for(mi[0] = 0; mi[0] < 3; mi[0]++)
std::cout << (*Tangents)[mi] << std::endl;
#endif
const int TextureUnit = 0;
RefPtr<BufferArray> TCA =
GL::FieldBuffer<TypedTexCoordArray<Eagle::tvector3> >::createParam( TextureUnit, Tangents, false, NullPtr() );
myVBO->append( TCA );
#ifdef VERBOSE
cout << "ColoredLines::render() appended tangents: # " << TCA->BufferArray::NumberOfElements() << endl;
#endif
}
else
{
LS.getLineset().Speak("********************LineSet EDGE Sets - WRONG EDGE SET DATA TYPE?");
return false;
}
#ifdef VERBOSE
puts("Load a texture coordinate field, maybe?");
#endif
if (TextureField)
{
if (RefPtr<MemArray<1, double> > TextureData = TextureField->getData( S->fragments[frag_i] ) )
{
#ifdef VERBOSE
puts("Load a texture coordinate field");
#endif
RefPtr<MemArray<1, double> > LoadData = ApplyRange(~ValueRange, TextureData);
RefPtr<BufferArray> TCA =
GL::FieldBuffer<TypedTexCoordArray<double> >::createParam( ColormapTextureUnit,
LoadData, false, NullPtr() );
myVBO->append( TCA );
#ifdef VERBOSE
cout << "ColoredLines::render() appended texture: # " << TCA->BufferArray::NumberOfElements() << endl;
#endif
}
else
{
puts("NOTE: CANNOT get texture field data?!");
}
}
else
{
puts("NOTE: NO texture field!");
}
RefPtr<TypedVertexArray<point> > VA = new TypedVertexArray<point>();
VA->load(VertexVector);
myVBO->append( VA );
#ifdef VERBOSE
cout << "ColoredLines::render() appended vertices: # " << VA->BufferArray::NumberOfElements() << endl;
#endif
myVBO->setRenderer( new GL::LineSetRenderer( S->theGridOfInterest, GL::LineSetRenderer::AsLineStrip, S->fragments[frag_i] ) );
myVBO->update( ConnectionAge() );
//#define VERBOSE
#ifdef VERBOSE
puts("CREATING NEW LINE RENDER VBO");
if (TextureField && myVBO->isOlderThan( *TextureField) )
{
puts(" BECAUSE this VBO is older than the associated texture field");
TextureField.speak("ASSOC TEXTURE FIELD");
{
InputField << Context >> FS;
printf(" FIELDNAME: %s\n", FS.getFieldName().c_str() );
}
}
else
{
puts(" BUT texture field has not changed");
}
#endif
}
#ifdef VERBOSE
else
puts("USING CACHED LINE RENDER VBO");
#endif
#ifdef VERBOSE
puts("call1");fflush(stdout);
#endif
myVBO->call();
glActiveTexture(GL_TEXTURE1);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
}
}
return true;
}
//
// Object Creation
//
struct GridInspector
{
static SkeletonExistence InspectionProperty()
{
return SkeletonExistence( LineSet::ID() );
}
};
MyGlossyLinesCreator( "Display/ColoredLines", ObjectQuality::OUTDATED);
MyTransparentColoredSurfaceCreator("Display/OnColoredLines", ObjectQuality::OUTDATED);
} // anon namespace
_Expr< _ValFunClos< _ValArray, _Tp >, _Tp > apply(_Tp __func(_Tp)) const
constexpr _Bind_helper< __is_socketlike< _Func >::value, _Func, _BoundArgs... >::type bind(_Func &&__f, _BoundArgs &&... __args)
basic_ostream< _CharT, _Traits > & endl(basic_ostream< _CharT, _Traits > &__os)
ostream cout
constexpr size_type size() const noexcept
An array reference class, which is a convenience class for reference pointers to multidimensional mem...
Definition ArrayRef.hpp:28
An internal class that stores a couple of textual names.
Definition FieldSelector.hpp:18
Context information to select a grid from within a bundle.
Definition GridSelector.hpp:26
A set of lines stored on a Grid.
Definition LineSet.hpp:55
RefPtr< LinesetArray_t > getLineset(const RefPtr< FragmentID > &f=NullPtr()) const
Return edges information.
Definition LineSet.hpp:326
bool setupStandardFields(const RefPtr< Grid > &theGrid)
Setup some standard fields suitable for lines on this Grid.
Definition LineSet.cpp:663
RefPtr< TangentialVector_t > getTangentialVectors(const RefPtr< FragmentID > &f=NullPtr(), const string &FieldName=TangentialVectorFieldName)
Compute tangential vectors in a grid object, which has a set of lines defined.
Definition LineSet.cpp:262
Class for N-dimensional MultiArrays with MemCore memory management.
Definition MemArray.hpp:34
Definition MultiArray.hpp:371
A multidimensional index that is automatically a lower-dimensional index via recursion.
Definition MultiIndex.hpp:449
A concrete Grid Property which looks for the existence of a Skeleton of the specified dimension and i...
Definition BundleProperty.hpp:76
void speak(const char *s, const char *prefix="") const noexcept
bool isNewerThan(const Ageable &a) const noexcept
bool setProperty(const string &theName, const Type &theValue) const
const Ageable & age(const RefPtr< ValuePool > &Context) const
string String(const T &Val)
std::nullptr_t NullPtr
Given a fragmented field of curvilinear coordinates, (3D array of coordinates), build a uniform Grid ...
Definition FAQ.dox:2
note: cannot derive from FloatingSkeletonRenderer as long as independent base class TriangleRenderer ...
virtual string createChildname(const string &parent_name) const
DEFAULT_OBJECT
Definition Lytica.hpp:7
Definition fs/init.hpp:20
A helper class to retrieve fields given on a Grid.
Definition GridField.hpp:19
double getTime() const
Return the time when the Grid was found.
Definition GridField.hpp:37
Definition 200-SpatialSorting.cpp:36
Templated static member function to load data from MemArrays into vertex arrays.
Definition FieldBuffer.hpp:38
static bool Enable(const RefPtr< Colormap > &Cmap, const RefPtr< GLTexture1D > &CmapTexture, const bool clampP, bool Discrete)
Common base class for objects that render information given on line sets, merely for grouping purpose...
Definition eye/retina/LineSetRenderer.hpp:39