meshInfo - modeler, viper crashes..

Medi8or

incurable dumbass
Ok. I tried writing this before, but Thor was out with his wagon, and lightening and powerfailure hit before I could submit the message.

Anyway. I use meshInfo in some nodes, and Modeler didn't like it so it crashed. I got that fixed by using
Code:
sysid          = (unsigned long)global(LWSYSTEMID_GLOBAL, GFUSE_TRANSIENT);
sysid = sysid & LWSYS_TYPEBITS;
and
Code:
if(sysid != LWSYS_MODELER) {
..
}

Now it seems Viper isn't too thrilled about me using meshInfo either, so the question is, how do I prevent code from running in Viper?
And how do I know what other places I shouldn't use meshInfo?

Thanks in advance. :)
 

Medi8or

incurable dumbass
Yes, I thought this would do it:
Code:
      mesh = objinfo->meshInfo(na->objID, 1);  
      if(mesh) {
           ..
      }
:stumped:
Maybe I have an other bug in there... :bangwall:
 

Sensei

TrueArt Support
It's not meshInfo that crashes Modeler in your example.. LWObjectInfo (objinfo that you use in the above example) is Layout only global not available in Modeler, therefore you must check whether it's not NULL after obtaining it from GlobalFunc and it'll work in Modeler without problem..

The more important question is "why do you need this meshInfo at all?"..

How to you free meshInfo? There's special procedure for this process that I don't see in your example..

Please provide more code because we can't see where exactly you're obtaining LWObjectInfo and MeshInfo.. You cannot do it anywhere, it must be done properly in the right place..
 

Medi8or

incurable dumbass
Sensei said:
It's not meshInfo that crashes Modeler in your example.. LWObjectInfo (objinfo that you use in the above example) is Layout only global not available in Modeler, therefore you must check whether it's not NULL after obtaining it from GlobalFunc and it'll work in Modeler without problem..
Yes. I slapped my forhead and made a check for objinfo right after I wrote the post... :foreheads
.. but Viper still crashes as soon as it hits a surface with the node.

Sensei said:
The more important question is "why do you need this meshInfo at all?"..
One example is the backface-node (see code below) from before polygon side was added to Spot Info. Is there an easier or better way to get vertex and polygon info?

Sensei said:
How to you free meshInfo? There's special procedure for this process that I don't see in your example..
Oops.. :D

Sensei said:
Please provide more code because we can't see where exactly you're obtaining LWObjectInfo and MeshInfo.. You cannot do it anywhere, it must be done properly in the right place..
I'm afraid my coding skills are a bit eh, well, lets say my skills are not compatible with "in the right place"...
Anyway, the code below renders fine, except in Viper.
Code:
#include <lwserver.h>
#include <lwhost.h>
#include <lwxpanel.h>
#include <lwvparm.h>
#include <lwhandler.h>
#include <lwmath.h>
#include <lwnodeeditor.h>
#include <lwnodes.h>
#include <lwmeshes.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include <float.h>

//Establish Global variables 
LWNodeFuncs        *nodeFunc;          // handle to the node functions structure
LWNodeEditorFuncs  *nodeEditorFunc;    // handle to the Node editor structure
LWNodeInputFuncs   *nodeInputFunc;     // handle to the input connection structure
LWNodeOutputFuncs  *nodeOutputFunc;    // handle to the output connection structure
LWInstUpdate       *lwupdate;
LWObjectInfo       *objinfo;
LWMeshInfo         *mesh;


// Our instance data structure
typedef struct st_iBackface 
{
  double           fcolor[3];	       //front-face color
  double           bcolor[3];

  NodeID           nodeID;		       //holds the ID tag for our node

  NodeInputID      fcolorInputID;	   //holds the ID for our input connections
  NodeInputID      bcolorInputID;
} iBackface;

/*
  getnorm()
  
  makes a surface normal for the polygon
*/
int getnorm(LWPolID polygon, LWDVector normal)
{
    LWFVector v0, v1, v2;
    float len;
    int lp;
    LWPntID pnt;
    
    lp = (*mesh->polSize)(mesh,polygon);
    lp -= 1;                      //last vertex for this poly
    pnt = (*mesh->polVertex)(mesh,polygon,0);
    (*mesh->pntOtherPos)(mesh,pnt,v0);
    pnt = (*mesh->polVertex)(mesh,polygon,1);
    (*mesh->pntOtherPos)(mesh,pnt,v1);
    pnt = (*mesh->polVertex)(mesh,polygon,lp);
    (*mesh->pntOtherPos)(mesh,pnt,v2);
               
    VSUB(v1,v0);                  //Vector from first to second vertex
    VSUB(v2,v0);                  //Vector from first to last vertex
    VCROSS(normal,v1,v2);         //Cross product to get normal
    
    len = 1 / VLEN(normal);
    VSCL(normal,len);             //Normalize normal
}

/*
  vtransform()

  transforms a vector with the provided transformation matrix
*/
void vtransform(double xfrm[9], LWDVector normal)
{
     LWDVector temp;
     
     VCPY(temp,normal);
     
     normal[0] = temp[0] * xfrm[0]
               + temp[1] * xfrm[1]
               + temp[2] * xfrm[2];
     normal[1] = temp[0] * xfrm[3]
               + temp[1] * xfrm[4]
               + temp[2] * xfrm[5];
     normal[2] = temp[0] * xfrm[6]
               + temp[1] * xfrm[7]
               + temp[2] * xfrm[8];
}


/*****************************************************************************\
  Create()

  Initialize the node along with creating the input and output node connections
\*****************************************************************************/
XCALL_(static LWInstance)
Create(void *priv, NodeID nodeID, LWError *err)
{
  iBackface *inst;

  //Reserve enough memeory for our instance structure
  inst = calloc(1, sizeof(iBackface));
  
  //If for some reason we could not properly create an instance if our 
  //instance structure exit
  if(!inst) 
   {
    *err = "Couldn't allocate memory for instance.";
    return NULL;
  }
  
  //Store the ID of the new node
  inst->nodeID = nodeID;

  //Default colors
  inst->fcolor[0] = 0.4;
  inst->fcolor[1] = 0.1;
  inst->fcolor[2] = 0.1;
  
  inst->bcolor[0] = 0.0;
  inst->bcolor[1] = 0.3;
  inst->bcolor[2] = 0.3;

  //Create the actual node input connectors
  inst->fcolorInputID = nodeInputFunc->create(inst->nodeID, NOT_VECTOR, "Front", NULL);
  inst->bcolorInputID = nodeInputFunc->create(inst->nodeID, NOT_VECTOR, "Back", NULL);
  
  //Create the actual node output connector
  nodeOutputFunc->create(inst->nodeID, NOT_VECTOR,"Output");

  //Return our filled in instance structure.
  return inst;
}


/*****************************************************************************\
  Destroy()

  Handler callback.  Free resources allocated by Create().
\*****************************************************************************/
XCALL_(static void)
Destroy(iBackface *inst)
{
  //If we still have a valid instance of our structure then delete the VParm we
  //created for the controls, then free the memory.
  if(inst) 
  {
    free(inst);
  }
}


/*****************************************************************************\
  Init()

  Handler callback, called at the start of rendering. We don't have
  anything to do, but it's here in case we want to add something later.
\*****************************************************************************/
XCALL_(static LWError)
Init(iBackface *inst, int mode)
{
  return NULL;
}


/*****************************************************************************\
  Copy()

  Handler callback.  Copy instance data.

  Create() has already been called for the to instance, so most of the instance 
  has been initialized, or will be later.  We just need to copy the values of 
  our vparms.
\*****************************************************************************/
XCALL_(static LWError)
Copy(iBackface *to, iBackface *from)
{
  return NULL;
}


/*****************************************************************************\
  Load()

  Handler callback.  Read instance data. Used for both objects and presets.
\*****************************************************************************/
XCALL_(static LWError)
Load(iBackface *inst, const LWLoadState *ls)
{
  return NULL;
}


/*****************************************************************************\
  Save()

  Handler callback.  Write instance data. Used for both objects and presets.
\*****************************************************************************/
XCALL_(static LWError)
Save(iBackface *inst, const LWSaveState *ss)
{
  return NULL;
}


/*****************************************************************************\
  Cleanup()

  Handler callback, called at the end of rendering.  We don't have
  anything to do, but it's here in case we want to add something later.
\*****************************************************************************/
XCALL_(static void)
Cleanup(iBackface *inst)
{
  return;
}


/*****************************************************************************\
  NewTime()

  Handler callback, called at the start of each sampling pass.  We grab
  the parameter values for the current time and precompute a couple of
  values that are constant for all evaluations at a given time.
\*****************************************************************************/
XCALL_(static LWError)
NewTime(iBackface *inst, LWFrame f, LWTime t)
{
  return NULL;
}


/*****************************************************************************\
  Evaluate()

  Get the input values from the input nodes if connected else
  use the colors from the interface.
\*****************************************************************************/
XCALL_(static void)
Evaluate(iBackface *inst, LWNodalAccess *na, NodeOutputID nid, NodeValue nv)
{
    LWDVector fcolor, bcolor, color, norm;

    LWPolID poly;
  
    double test;
  
    //Get colors from the envelopes
    VCPY(fcolor,inst->fcolor);
    VCPY(bcolor, inst->bcolor);

    //Get colors from inputs, if connected
    nodeInputFunc->evaluate(inst->fcolorInputID, na, fcolor);
    nodeInputFunc->evaluate(inst->bcolorInputID, na, bcolor);
    VCPY(color,fcolor);                        //Default color is the front color,

  
    if(objinfo) {
        mesh = objinfo->meshInfo(na->objID, 0);
    }
  
    if(mesh) {
        poly = na->polygon;
               
        getnorm(poly, norm);
               
        //From object to world space
        vtransform(na->wXfrm, norm);
                       
        test = VDOT(na->wNorm0,norm);
        if(test<0) {                  //If negative, it's a Back-face
            VCPY(color,bcolor);
        }
    }
  
    //Set the value of the output connector
    nodeOutputFunc->setValue(nv, color);
}


/*****************************************************************************\
  Interface()

  The Interface activation function. Check the version and fill in the callback 
  fields of the interface structure as needed.
\*****************************************************************************/
XCALL_(int)
Interface(long version, GlobalFunc *global, LWInterface *local, void *serverData)
{
  iBackface *inst = (iBackface *)local->inst;
	
  //Verify that we are linking to the correct version of the LWNode class
  if(version != LWINTERFACE_VERSION)
    return AFUNC_BADVERSION;

  //Initialize our global xPanel structures
  lwupdate = global(LWINSTUPDATE_GLOBAL, GFUSE_TRANSIENT);

  //If for some reason anyone of these are not properly declared and/or initialize exit
  if(!lwupdate) 
    return AFUNC_BADGLOBAL;

  //Set up the handler callback functions we will use.
  local->options = NULL;
  local->command = NULL;

  return AFUNC_OK;
}


/*****************************************************************************\
  Handler()

  The Handler activation function. Check the version and fill in the callback 
  fields of the handler structure as needed.
\*****************************************************************************/
XCALL_(static int) 
Handler(long version, GlobalFunc *global, LWNodeHandler *local, void *serverData)
{
  //Verify that we are linking to the correct version of the LWNode class
  if(version != LWNODECLASS_VERSION) 
    return AFUNC_BADVERSION;

  //Initialize our global structures
  nodeFunc       = global(LWNODEFUNCS_GLOBAL, GFUSE_TRANSIENT);
  nodeEditorFunc = global(LWNODEEDITORFUNCS_GLOBAL, GFUSE_TRANSIENT);
  nodeInputFunc  = global(LWNODEINPUTFUNCS_GLOBAL, GFUSE_TRANSIENT);
  nodeOutputFunc = global(LWNODEOUTPUTFUNCS_GLOBAL, GFUSE_TRANSIENT);
  objinfo        = global(LWOBJECTINFO_GLOBAL, GFUSE_TRANSIENT);

  //If for some reason anyone of these are not properly declared and/or initialize exit
  if(!nodeFunc || !nodeEditorFunc || !nodeInputFunc || !nodeOutputFunc)
    return AFUNC_BADGLOBAL;

  //Set up the handler callback functions we will use.
  local->inst->priv     = global;
  local->inst->create   = Create;
  local->inst->destroy  = Destroy;
  local->rend->init     = Init;
  local->inst->copy     = Copy;
  local->inst->load     = Load;
  local->inst->save     = Save;
  local->rend->cleanup  = Cleanup;
  local->rend->newTime  = NewTime;
  local->evaluate       = Evaluate;

  return AFUNC_OK;
}

// Put node in Item Info menu
static ServerTagInfo ServerTag[] = {
   { "Item Info", SRVTAG_NODEGROUP },
   { "", 0 }
};

/*****************************************************************************\
  ServerRecord
  Creates the server description for the Handler and the Interface plugins
\*****************************************************************************/
ServerRecord ServerDesc[] = 
{
  {LWNODE_HCLASS, "Backface2ni", Handler, ServerTag},
  {LWNODE_ICLASS, "Backface2ni", NULL},
  {NULL}
};
 
Last edited:

Sensei

TrueArt Support
You don't fill global variables with NULL, don't check whether some resources have been created in Create(), don't check whether polygon has more than 3 vertices before tring to get polygon normal (that's should crash each time when tried on object with less than 3 vertices), don't delete resources in Destroy() call-back, don't free mesh info properly, and trying to get it for EACH evaluation call, that's what I called "getting meshinfo in the right place".. I meant freeing it in Cleanup() and in the begining of NewTime() (if it has been allocated, that's why setting global variables to NULL is so important!) and taking it again...

That was brief look at your source code.. ;)

First of all make sure that meshinfo is not taken so often and FREE it properly (described on mesh info page in LW SDK), otherwise LW can reach out of memory limit very quickly...

Second, make sure that normal is not taken when polygon is no good..
 
Top Bottom