/*
FreeWRL support library.
OpenGL initialization and functions. Rendering functions.
*/
/****************************************************************************
This file is part of the FreeWRL/FreeX3D Distribution.
Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FreeWRL/FreeX3D is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FreeWRL/FreeX3D. If not, see .
****************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include "../vrml_parser/Structs.h"
#include "../main/headers.h"
#include "../main/ProdCon.h"
#include "../vrml_parser/CParseGeneral.h"
#include "../scenegraph/Vector.h"
#include "../vrml_parser/CFieldDecls.h"
#include "../vrml_parser/CParseParser.h"
#include "../vrml_parser/CParseLexer.h"
#include "../vrml_parser/CParse.h"
#include "../vrml_parser/CRoutes.h"
#include "../scenegraph/quaternion.h"
#include "../scenegraph/Viewer.h"
#include "../scenegraph/sounds.h"
#include "../scenegraph/LinearAlgebra.h"
#include "../scenegraph/Component_KeyDevice.h" /* resolving implicit declarations */
#include "../input/EAIHeaders.h" /* resolving implicit declarations */
#include "../input/InputFunctions.h"
#include "Frustum.h"
#include "../opengl/Material.h"
#include "../scenegraph/Component_Core.h"
#include "../scenegraph/Component_Networking.h"
#include "LoadTextures.h"
#include "OpenGL_Utils.h"
#include "Textures.h"
#include "../scenegraph/RenderFuncs.h"
#include "../scenegraph/Component_Shape.h"
#include
#include "../x3d_parser/Bindable.h"
#include "../ui/common.h"
void kill_rendering(void);
//static void killNode_hide_obsolete (int index);
static void mesa_Frustum(GLDOUBLE left, GLDOUBLE right, GLDOUBLE bottom, GLDOUBLE top, GLDOUBLE nearZ, GLDOUBLE farZ, GLDOUBLE *m);
#undef DEBUG_FW_LOADMAT
#ifdef DEBUG_FW_LOADMAT
static void fw_glLoadMatrixd(GLDOUBLE *val,char *, int);
#define FW_GL_LOADMATRIX(aaa) fw_glLoadMatrixd(aaa,__FILE__,__LINE__);
#else
static void fw_glLoadMatrixd(GLDOUBLE *val);
#define FW_GL_LOADMATRIX(aaa) fw_glLoadMatrixd(aaa);
#endif
struct shaderTableEntry {
//unsigned int whichOne;
shaderflagsstruct whichOne;
s_shader_capabilities_t *myCapabilities;
};
int unload_broto(struct X3D_Proto* node);
void mesa_Ortho(GLDOUBLE left, GLDOUBLE right, GLDOUBLE bottom, GLDOUBLE top, GLDOUBLE nearZ, GLDOUBLE farZ, GLDOUBLE *m);
static void getShaderCommonInterfaces (s_shader_capabilities_t *me);
static void makeAndCompileShader(struct shaderTableEntry *);
///* is this 24 bit depth? 16? 8?? Assume 24, unless set on opening */
//int displayDepth = 24;
//
////static float cc_red = 0.0f, cc_green = 0.0f, cc_blue = 0.0f, cc_alpha = 1.0f;
//int cc_changed = FALSE;
//static pthread_mutex_t memtablelock = PTHREAD_MUTEX_INITIALIZER;
#define LOCK_MEMORYTABLE pthread_mutex_lock(&p->memtablelock);
#define UNLOCK_MEMORYTABLE pthread_mutex_unlock(&p->memtablelock);
/*
#define LOCK_MEMORYTABLE {printf ("LOCK_MEMORYTABLE at %s:%d\n",__FILE__,__LINE__); pthread_mutex_lock(&memtablelock);}
#define UNLOCK_MEMORYTABLE {printf ("UNLOCK_MEMORYTABLE at %s:%d\n",__FILE__,__LINE__); pthread_mutex_unlock(&memtablelock);}
*/
/* OpenGL perform matrix state here */
#define MAX_LARGE_MATRIX_STACK 256 /* depth of stacks */
#define MAX_SMALL_MATRIX_STACK 9 /* depth of stacks */
#define MATRIX_SIZE 16 /* 4 x 4 matrix */
typedef GLDOUBLE MATRIX4[MATRIX_SIZE];
typedef struct pOpenGL_Utils{
// list of all X3D nodes in this system.
// scene graph is tree-structured. this is a linear list.
struct Vector *linearNodeTable;
// how many holes might we have in this table, due to killing nodes, etc?
int potentialHoleCount;
float cc_red, cc_green, cc_blue, cc_alpha;
pthread_mutex_t memtablelock;// = PTHREAD_MUTEX_INITIALIZER;
MATRIX4 FW_ModelView[MAX_LARGE_MATRIX_STACK];
MATRIX4 FW_ProjectionView[MAX_SMALL_MATRIX_STACK];
MATRIX4 FW_TextureView[MAX_SMALL_MATRIX_STACK];
int modelviewTOS;// = 0;
int projectionviewTOS;// = 0;
int textureviewTOS;// = 0;
//int pickrayviewTOS;// = 0;
int whichMode;// = GL_MODELVIEW;
GLDOUBLE *currentMatrix;// = FW_ModelView[0];
#ifdef GLEW_MX
GLEWContext glewC;
#endif
struct Vector *myShaderTable; /* list of all active shaders requested by input */
int userDefinedShaderCount; /* if the user actually has a Shader node */
char *userDefinedFragmentShader[MAX_USER_DEFINED_SHADERS];
char *userDefinedVertexShader[MAX_USER_DEFINED_SHADERS];
int shadingStyle; //0=flat, 1=gouraud, 2=phong 3=wireframe
int maxStackUsed;
}* ppOpenGL_Utils;
void *OpenGL_Utils_constructor(){
void *v = MALLOCV(sizeof(struct pOpenGL_Utils));
memset(v,0,sizeof(struct pOpenGL_Utils));
return v;
}
void OpenGL_Utils_init(struct tOpenGL_Utils *t)
{
//public
/* is this 24 bit depth? 16? 8?? Assume 24, unless set on opening */
t->displayDepth = 24;
//static float cc_red = 0.0f, cc_green = 0.0f, cc_blue = 0.0f, cc_alpha = 1.0f;
t->cc_changed = FALSE;
//private
t->prv = OpenGL_Utils_constructor();
{
ppOpenGL_Utils p = (ppOpenGL_Utils)t->prv;
p->linearNodeTable = NULL;
p->potentialHoleCount = 0;
p->cc_red = 0.0f;
p->cc_green = 0.0f;
p->cc_blue = 0.0f;
p->cc_alpha = 1.0f;
//p->memtablelock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init(&(p->memtablelock), NULL);
// LoadIdentity will initialize these
p->modelviewTOS = 0;
p->projectionviewTOS = 0;
p->textureviewTOS = 0;
//p->pickrayviewTOS = 0;
p->whichMode = GL_MODELVIEW;
p->currentMatrix = p->FW_ModelView[0];
// load identity matricies in here
loadIdentityMatrix(p->FW_ModelView[0]);
loadIdentityMatrix(p->FW_ProjectionView[0]);
loadIdentityMatrix(p->FW_TextureView[0]);
// create room for some shaders. The order in this table is
// the order in which they are first referenced.
p->myShaderTable = newVector(struct shaderTableEntry *, 8);
// userDefinedShaders - assume 0, unless the user is a geek.
p->userDefinedShaderCount = 0;
p->shadingStyle = 2; //0=flat, 1=gouraud (default), 2=phong, 3=wireframe
//ConsoleMessage ("setting usePhongShaders to true"); p->usePhongShaders=true;
p->maxStackUsed = 0;
}
}
void OpenGL_Utils_clear(struct tOpenGL_Utils *t)
{
//public
//private
{
ppOpenGL_Utils p = (ppOpenGL_Utils)t->prv;
deleteVector(struct X3D_Node*,p->linearNodeTable);
if(p->myShaderTable){
int i;
for(i=0;imyShaderTable);i++){
struct shaderTableEntry *entry = vector_get(struct shaderTableEntry *,p->myShaderTable,i);
FREE_IF_NZ(entry->myCapabilities);
FREE_IF_NZ(entry);
}
deleteVector(struct shaderTableEntry *, p->myShaderTable);
}
}
}
#ifdef GLEW_MX
GLEWContext * glewGetContext()
{
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
return &(p->glewC);
}
#endif
GLDOUBLE *getPickrayMatrix(int index)
{
//feature-AFFINE_GLU_UNPROJECT
bindablestack *bstack;
ttglobal tg = gglobal();
bstack = getActiveBindableStacks(tg);
return bstack->pickraymatrix[index];
}
void setPickrayMatrix(int index, GLDOUBLE *mat)
{
//feature-AFFINE_GLU_UNPROJECT
bindablestack *bstack;
ttglobal tg = gglobal();
bstack = getActiveBindableStacks(tg);
memcpy(bstack->pickraymatrix[index],mat,16*sizeof(GLDOUBLE));
}
// we have a new world, get rid of any old user defined shaders here
void kill_userDefinedShaders() {
int i;
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
//ConsoleMessage ("start kill_userDefinedShaders");
p->userDefinedShaderCount = 0;
// free the strings for the shader source, if they exist
for (i=0; iuserDefinedVertexShader[i], p->userDefinedFragmentShader[i]);
FREE_IF_NZ (p->userDefinedFragmentShader[i]);
FREE_IF_NZ (p->userDefinedVertexShader[i]);
}
for (i=0; i myShaderTable); i++) {
struct shaderTableEntry *me = vector_get(struct shaderTableEntry *,p->myShaderTable, i);
FREE_IF_NZ(me->myCapabilities);
//me->whichOne = 0;
FREE_IF_NZ(me);
}
// set the vector to 0 size. we will keep the Vector around, for the next set
// of shaders for the next world.
p->myShaderTable->n = 0;
}
// we allow a certain number of user-defined shaders to (somehow) fit in here.
int getNextFreeUserDefinedShaderSlot() {
int rv;
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
p->userDefinedShaderCount++;
if (p->userDefinedShaderCount == MAX_USER_DEFINED_SHADERS) return -1;
rv = p->userDefinedShaderCount;
return rv;
}
// from a user defined shader, we capture the shader text here.
void sendShaderTextToEngine(int ste, int parts, char ** vertSource, char ** fragSource) {
char *fs = NULL;
char *vs = NULL;
int i;
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
// find the non-null for each shader text.
for (i=0; iuserDefinedFragmentShader[ste] = fs;
p->userDefinedVertexShader[ste] = vs;
//printf ("so for shaderTableEntry %d, we have %d %d\n",ste,strlen(fs),strlen(vs));
}
#if defined (_ANDROID)
/***************************************************************************************/
/* */
/* UI FrontEnd Scenegraph manipulation nodes. Right now, the FreeX3D UI uses these, */
/* but they are NOT Android specific. Feel free to look and use. JAS. */
/* */
/***************************************************************************************/
/* pass in a X3D_Shape pointer, and from that, we go and return a bunch of fields of
the Shape. If a field is NULL, NULL is returned. If a field is a PROTO, the PROTO
expansion is returned */
void fwl_decomposeShape(struct X3D_Shape * node,
struct X3D_FillProperties **fpptr,
struct X3D_LineProperties **lpptr,
struct X3D_Material **matptr,
struct X3D_ImageTexture **texptr,
struct X3D_TextureTransform **texttptr,
struct X3D_Node **geomptr) {
struct X3D_Appearance *app = X3D_APPEARANCE(node->appearance);
struct X3D_Node * geom = node->geometry;
// initialize every return value to NULL, possibly filed in later
*fpptr = NULL; *lpptr = NULL; *matptr = NULL; *texptr = NULL;
*texttptr = NULL; *geomptr = NULL;
POSSIBLE_PROTO_EXPANSION(struct X3D_Appearance *,X3D_NODE(app),app);
POSSIBLE_PROTO_EXPANSION(struct X3D_Node*,geom,geom);
if (app != NULL) {
struct X3D_FillProperties *fp = X3D_FILLPROPERTIES(app->fillProperties);
struct X3D_LineProperties *lp = X3D_LINEPROPERTIES(app->lineProperties);
struct X3D_Material *mat = X3D_MATERIAL(app->material);
struct X3D_ImageTexture *tex = X3D_IMAGETEXTURE(app->texture);
struct X3D_TextureTransform *tt = X3D_TEXTURE_TRANSFORM(app->textureTransform);
POSSIBLE_PROTO_EXPANSION(struct X3D_FillProperties *,X3D_NODE(fp),*fpptr);
POSSIBLE_PROTO_EXPANSION(struct X3D_LineProperties *,X3D_NODE(lp),*lpptr);
POSSIBLE_PROTO_EXPANSION(struct X3D_Material *,X3D_NODE(mat),*matptr);
POSSIBLE_PROTO_EXPANSION(struct X3D_ImageTexture *,X3D_NODE(tex),*texptr);
POSSIBLE_PROTO_EXPANSION(struct X3D_TextureTransform *,X3D_NODE(tt),*texttptr);
}
if (geom != NULL) {
POSSIBLE_PROTO_EXPANSION(struct X3D_Node *,geom,*geomptr);
}
}
/* returns a Shape node list - Shape nodes must have valid, light (lightable?) geometry.
Expects a pointer to a Vector, will create Vector if required.
Returns an int with the number of valid nodes found;
Returns the filled in Vector pointer, with NODE_Shape pointers. */
int fwl_android_get_valid_shapeNodes(struct Vector **shapeNodes) {
struct Vector *me;
int tc;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
//ConsoleMessage ("fwl_android_get_valid_shapeNodes, passed in vector %p",*shapeNodes);
// create the new vector, if required
if (*shapeNodes == NULL) {
*shapeNodes = newVector (struct X3D_Shape *, 16);
}
// are we running yet?
if (p==NULL) return 0;
if (p->linearNodeTable==NULL) return 0;
// ease of use of this vector -
me = *shapeNodes;
vectorSize(me) = 0;
LOCK_MEMORYTABLE
for (tc=0; tclinearNodeTable); tc++){
struct X3D_Node *node = vector_get(struct X3D_Node *,p->linearNodeTable, tc);
// do we have a valid node?
if (node != NULL) {
POSSIBLE_PROTO_EXPANSION (struct X3D_Node *,node,node);
// do we have a shape, that is actually used?
if ((node->_nodeType == NODE_Shape) && (node->referenceCount>0)) {
struct X3D_Node *geom = X3D_SHAPE(node)->geometry;
// does it actually have a lit geometry underneath it?
if (geom != NULL) {
POSSIBLE_PROTO_EXPANSION (struct X3D_Node *, geom, geom);
if ((geom->_nodeType != NODE_IndexedLineSet) &&
(geom->_nodeType != NODE_LineSet) &&
(geom->_nodeType != NODE_PointSet)) {
// yep! return this one!
vector_pushBack(struct X3D_Node *,me, node);
}
}
}
}
}
UNLOCK_MEMORYTABLE
/*
uncomment to print out the shape nodes found
for (tc=0; tc_nodeType));
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
ConsoleMessage ("EOL, geometry is %s\n",stringNodeType(geom->_nodeType));
if (fp == NULL) ConsoleMessage ("fillProperties NULL"); else ConsoleMessage ("fillProperties %s",stringNodeType(fp->_nodeType));
if (lp == NULL) ConsoleMessage ("lineProperties NULL"); else ConsoleMessage ("lineProperties %s",stringNodeType(lp->_nodeType));
if (mat == NULL) ConsoleMessage ("material NULL"); else ConsoleMessage ("material %s",stringNodeType(mat->_nodeType));
if (tex == NULL) ConsoleMessage ("texture NULL"); else ConsoleMessage ("texture %s",stringNodeType(tex->_nodeType));
if (tt == NULL) ConsoleMessage ("texureTransform NULL"); else ConsoleMessage ("texureTransform %s",stringNodeType(tt->_nodeType));
}
*/
return vectorSize(me);
}
/* Zeroes the Shape Node table, for instance, when loading in a new world,
you want to zero this, otherwise all of the existing node pointers will
be invalid */
void fwl_android_zero_shapeNodeTable(struct Vector **shapeNodes) {
if (*shapeNodes == NULL) {
*shapeNodes = newVector (struct X3D_Shape *, 16);
}
//ConsoleMessage ("fwl_android_zero_shapeNodeTable, was %d, should be 0 after this",vectorSize(*shapeNodes));
vectorSize(*shapeNodes) = 0;
//ConsoleMessage ("fwl_android_zero_shapeNodeTable, is %d, should be 0 after this",vectorSize(*shapeNodes));
}
/* returns TRUE if the shape node actually has a fillProperties node,
and the FillProperties field "_enabled" is TRUE,
returns FALSE if the node does not exist or does not have a FillProperty,
or the FillProperties field "_enabled" is FALSE */
int fwl_get_FillPropStatus(struct Vector **shapeNodes, int whichEntry) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
//ConsoleMessage ("fwl_get_FillPropStatus, pointer is %p");
//ConsoleMessage ("fwl_get_FillPropStatus, vecto size %d",vectorSize(*shapeNodes));
// If we do not have any node entries, maybe this is a new scene, and we have to get
// the valid nodes?
if (vectorSize(*shapeNodes) == 0 ) {
if (fwl_android_get_valid_shapeNodes(shapeNodes) == 0) return FALSE;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
//ConsoleMessage ("node %d is a %s",whichEntry,stringNodeType(node->_nodeType));
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
//ConsoleMessage ("and the fp field is %p",fp);
if (fp != NULL) {
return (fp->_enabled);
}
return (FALSE);
}
void fwl_set_FillPropStatus (struct Vector **shapeNodes, int whichEntry, int yesNo, float fillScale) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
// If we do not have any node entries, maybe this is a new scene, and we have to get
// the valid nodes?
if (vectorSize(*shapeNodes) == 0 ) {
if (fwl_android_get_valid_shapeNodes(shapeNodes) == 0) return;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
//ConsoleMessage ("node %d is a %s",whichEntry,stringNodeType(node->_nodeType));
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (yesNo) {
struct X3D_FillProperties *fp;
// does the shape have an Appearance node yet?
if (X3D_SHAPE(node)->appearance == NULL) {
struct X3D_Material *mat;
ap = createNewX3DNode(NODE_Appearance);
AddRemoveSFNodeFieldChild(node,
offsetPointer_deref(struct X3D_Node **,node,offsetof (struct X3D_Shape, appearance)),
X3D_NODE(ap),0,__FILE__,__LINE__);
mat = createNewX3DNode(NODE_Material);
AddRemoveSFNodeFieldChild(X3D_NODE(ap),
offsetPointer_deref(struct X3D_Node **,ap,offsetof (struct X3D_Appearance, material)),
X3D_NODE(mat),0,__FILE__,__LINE__);
}
ap = X3D_APPEARANCE(X3D_SHAPE(node)->appearance);
// create the node, then "set" it in place. If a node previously existed in the
// fillProperties field, then it gets removed by AddRemoveChild
if (ap->fillProperties == NULL) {
//ConsoleMessage ("fwl_set_FillPropStatus, creating a FillProperties");
fp = X3D_FILLPROPERTIES(createNewX3DNode(NODE_FillProperties));
AddRemoveSFNodeFieldChild(X3D_NODE(ap),
offsetPointer_deref(struct X3D_Node **,X3D_NODE(ap),offsetof (struct X3D_Appearance, fillProperties)),
X3D_NODE(fp),0,__FILE__,__LINE__);
} else {
//ConsoleMessage ("fwl_set_FilPropStatus, just enabling FillProperties _enabled field");
fp = X3D_FILLPROPERTIES(ap->fillProperties);
// ok, we have a node here, if it is a FillProperties, set the enabled flag
if (fp->_nodeType == NODE_FillProperties) fp->_enabled = TRUE;
}
// ensure that the FillProperties scale is ok.
fp->_hatchScale.c[0] = fillScale;
fp->_hatchScale.c[1] = fillScale;
} else {
//ConsoleMessage ("fwl_set_FillPropStatus, removing a FillProperties");
/* do not bother removing it - keep it around in case we re-enable and want original settings
AddRemoveSFNodeFieldChild(X3D_NODE(X3D_SHAPE(node)->appearance),
offsetPointer_deref(struct X3D_Node **,X3D_NODE(X3D_SHAPE(node)->appearance),offsetof (struct X3D_Appearance, fillProperties)),
X3D_NODE(fp),2,__FILE__,__LINE__);
*/
ap = X3D_APPEARANCE(X3D_SHAPE(node)->appearance);
if (ap != NULL) {
if (ap->fillProperties != NULL) {
struct X3D_FillProperties *fp = X3D_FILLPROPERTIES(ap->fillProperties);
// ok, we have a node here, if it is a FillProperties, set the enabled flag
if (fp->_nodeType == NODE_FillProperties) fp->_enabled = FALSE;
}
}
}
// tell the Shape node that we need to check the shaders it uses...
node->_change ++;
}
/* return whether FillProperties hatched is true/false */
int fwl_get_FillPropHatched(struct Vector **shapeNodes, int whichEntry) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return FALSE;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
return (fp->hatched);
}
/* set current FillProperties to hatched */
void fwl_set_FillPropHatched (struct Vector **shapeNodes, int whichEntry, int yesNo) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (fp!=NULL) fp->hatched = yesNo;
}
/* return whether FillProperties filled is true/false */
int fwl_get_FillPropFilled(struct Vector **shapeNodes, int whichEntry) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return FALSE;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
return (fp->filled);
}
/* set current FillProperties to filled */
void fwl_set_FillPropFilled (struct Vector **shapeNodes, int whichEntry, int yesNo) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (fp!=NULL) fp->filled = yesNo;
}
/* return FillProperties style */
int fwl_get_FillPropStyle(struct Vector **shapeNodes, int whichEntry) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return 0;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (fp==NULL) return 0;
return (fp->hatchStyle);
}
/* set current FillProperties hatchStyle */
void fwl_set_FillPropStyle (struct Vector **shapeNodes, int whichEntry, int which) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (fp!=NULL) fp->hatchStyle = which;
}
/* return FillProperties colour */
int fwl_get_FillPropColour(struct Vector **shapeNodes, int whichEntry) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
int integer_colour;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return 0;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
#define CLAMP(value, min, max) (((value) >(max)) ? (max) : (((value) <(min)) ? (min) : (value)))
if (fp==NULL) return 0;
integer_colour = 0xFF000000 + (
((uint8_t)(255.0f *CLAMP(fp->hatchColor.c[0], 0.0, 1.0)) <<16) |
((uint8_t)(255.0f *CLAMP(fp->hatchColor.c[1], 0.0, 1.0)) <<8) |
((uint8_t)(255.0f *CLAMP(fp->hatchColor.c[2], 0.0, 1.0))));
//ConsoleMessage ("fwl_get_fp, is %x",integer_colour);
return (integer_colour);
}
/* set current FillProperties hatchColour */
void fwl_set_FillPropColour (struct Vector **shapeNodes, int whichEntry, int argbColour) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (fp!=NULL) {
fp->hatchColor.c[0] =CLAMP(((float)((argbColour &0xff0000) >>16)) /255.0, 0.0, 1.0);
fp->hatchColor.c[1] =CLAMP(((float)((argbColour &0x00ff00) >>8)) /255.0, 0.0, 1.0);
fp->hatchColor.c[2] =CLAMP(((float)((argbColour &0x0000ff))) /255.0, 0.0, 1.0);
//ConsoleMessage ("converted colour to %f %f %f ", fp->hatchColor.c[0], fp->hatchColor.c[1], fp->hatchColor.c[2]);
}
}
// MAterial - we need to ensure that this is node has a Material; we make it a TwoSidedMaterial
// even if it was a normal Material node.
// returns whether two-sided is true or not.
//JNIEXPORT jboolean JNICALL Java_org_freex3d_FreeX3DLib_setMaterialExisting(JNIEnv *env, jobject obj) {
// return fwl_set_MaterialExisting(&shapeNodes,0);
//}
int fwl_set_MaterialExisting(struct Vector **shapeNodes, int whichEntry) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
struct X3D_TwoSidedMaterial *tsm;
int twoSided = FALSE;
// If we do not have any node entries, maybe this is a new scene, and we have to get
// the valid nodes?
if (vectorSize(*shapeNodes) == 0 ) {
if (fwl_android_get_valid_shapeNodes(shapeNodes) == 0) return FALSE;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
//ConsoleMessage ("node %d is a %s",whichEntry,stringNodeType(node->_nodeType));
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
// does the shape have an Appearance node yet?
if (X3D_SHAPE(node)->appearance == NULL) {
struct X3D_Material *mat;
ap = createNewX3DNode(NODE_Appearance);
AddRemoveSFNodeFieldChild(node,
offsetPointer_deref(struct X3D_Node **,node,offsetof (struct X3D_Shape, appearance)),
X3D_NODE(ap),0,__FILE__,__LINE__);
mat = createNewX3DNode(NODE_TwoSidedMaterial);
AddRemoveSFNodeFieldChild(X3D_NODE(ap),
offsetPointer_deref(struct X3D_Node **,ap,offsetof (struct X3D_Appearance, material)),
X3D_NODE(mat),0,__FILE__,__LINE__);
}
ap = X3D_APPEARANCE(X3D_SHAPE(node)->appearance);
//ConsoleMessage ("so, at this point in time, we have an appearance, type %s",stringNodeType(ap->_nodeType));
// create the node, then "set" it in place. If a node previously existed in the
// fillProperties field, then it gets removed by AddRemoveChild
if (ap->material == NULL) {
//ConsoleMessage ("fwl_set_MaterialPropStatus, creating a MaterialProperties");
tsm = X3D_TWOSIDEDMATERIAL(createNewX3DNode(NODE_TwoSidedMaterial));
AddRemoveSFNodeFieldChild(X3D_NODE(ap),
offsetPointer_deref(struct X3D_Node **,X3D_NODE(ap),offsetof (struct X3D_Appearance, material)),
X3D_NODE(tsm),0,__FILE__,__LINE__);
}
tsm = X3D_TWOSIDEDMATERIAL(ap->material);
// ok, we have a node here, if it is a FillProperties, set the enabled flag
// do we have to change a Material to TwoSidedMaterial??
if (tsm->_nodeType != NODE_TwoSidedMaterial) {
struct X3D_Material *mat = X3D_MATERIAL(tsm);
struct X3D_TwoSidedMaterial *ntsm = createNewX3DNode(NODE_TwoSidedMaterial);
if (mat->_nodeType == NODE_Material) {
//copy over the fields
ntsm->ambientIntensity = mat->ambientIntensity;
ntsm->backAmbientIntensity = mat->ambientIntensity;
ntsm->shininess = mat->shininess;
ntsm->backShininess = mat->shininess;
ntsm->transparency = mat->transparency;
ntsm->backTransparency = mat->transparency;
memcpy((void *)&ntsm->diffuseColor, (void *)&mat->diffuseColor,sizeof(struct SFColor));
memcpy((void *)&ntsm->backDiffuseColor, (void *)&mat->diffuseColor,sizeof(struct SFColor));
memcpy((void *)&ntsm->emissiveColor, (void *)&mat->emissiveColor,sizeof(struct SFColor));
memcpy((void *)&ntsm->backEmissiveColor, (void *)&mat->emissiveColor,sizeof(struct SFColor));
memcpy((void *)&ntsm->specularColor, (void *)&mat->specularColor,sizeof(struct SFColor));
memcpy((void *)&ntsm->backSpecularColor, (void *)&mat->specularColor,sizeof(struct SFColor));
ntsm->separateBackColor=FALSE;
} else {
ConsoleMessage ("somehow the Material is not a node of Material type for this node");
}
// now, make the child our TwoSidedMaterial node
AddRemoveSFNodeFieldChild(X3D_NODE(ap),
offsetPointer_deref(struct X3D_Node **,ap,offsetof (struct X3D_Appearance, material)),
X3D_NODE(ntsm),0,__FILE__,__LINE__);
} else {
// We DO have a TwoSidedMaterial...
twoSided = X3D_TWOSIDEDMATERIAL(tsm)->separateBackColor;
}
// tell the Shape node that we need to check the shaders it uses...
node->_change ++;
return twoSided;
}
/* fwl_get_MaterialColourValue(xx) - example usage:
- Front Diffuse
- Front Emissive
- Front Specular
- Back Diffuse
- Back Emissive
- Back Specular
int frontDiffuse = FreeX3DLib.getMaterialColourValue(0);
int frontEmissive = FreeX3DLib.getMaterialColourValue(1);
int frontSpecular = FreeX3DLib.getMaterialColourValue(2);
int backDiffuse = FreeX3DLib.getMaterialColourValue(3);
int backEmissive = FreeX3DLib.getMaterialColourValue(4);
int backSpecular = FreeX3DLib.getMaterialColourValue(5);
*/
int fwl_get_MaterialColourValue(struct Vector **shapeNodes, int whichEntry, int whichValue) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
struct X3D_TwoSidedMaterial *tsm;
// If we do not have any node entries, maybe this is a new scene, and we have to get
// the valid nodes?
if (vectorSize(*shapeNodes) == 0 ) {
if (fwl_android_get_valid_shapeNodes(shapeNodes) == 0) return 0;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
//ConsoleMessage ("node %d is a %s",whichEntry,stringNodeType(node->_nodeType));
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (mat == NULL) return 0;
if (mat->_nodeType == NODE_TwoSidedMaterial) {
struct SFColor *col = NULL;
struct X3D_TwoSidedMaterial *tmat = X3D_TWOSIDEDMATERIAL(mat);
switch (whichValue) {
case 0: col = &tmat->diffuseColor; break;
case 1: col = &tmat->emissiveColor; break;
case 2: col = &tmat->specularColor; break;
case 3: col = &tmat->backDiffuseColor; break;
case 4: col = &tmat->backEmissiveColor; break;
case 5: col = &tmat->backSpecularColor; break;
default: {}
}
if (col != NULL) {
int integer_colour;
integer_colour = 0xFF000000 + (
((uint8_t)(255.0f *CLAMP(col->c[0], 0.0, 1.0)) <<16) |
((uint8_t)(255.0f *CLAMP(col->c[1], 0.0, 1.0)) <<8) |
((uint8_t)(255.0f *CLAMP(col->c[2], 0.0, 1.0))));
//ConsoleMessage ("getMaterialValue, returning colour %d\n",integer_colour);
return integer_colour;
}
} else {
ConsoleMessage ("getMaterialValue, expected a TwoSidedMaterial, not a %s\n",stringNodeType(mat->_nodeType));
}
return 0;
}
void fwl_set_TwoSidedMaterialStatus( struct Vector **shapeNodes, int whichEntry, int oneTwo) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (mat == NULL) return;
if (mat->_nodeType == NODE_TwoSidedMaterial) {
// ok - we are in the correct place.
X3D_TWOSIDEDMATERIAL(mat)->separateBackColor = oneTwo;
mat->_change++; // signal that this node has changed
}
}
/* set current colour */
void fwl_set_MaterialColourValue (struct Vector **shapeNodes, int whichEntry, int whichValue, int argbColour) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
// Assume that we have a Shape node
if (vectorSize(*shapeNodes) == 0 ) {
return;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (mat == NULL) return;
if (mat->_nodeType == NODE_TwoSidedMaterial) {
struct SFColor *col = NULL;
struct X3D_TwoSidedMaterial *tmat = X3D_TWOSIDEDMATERIAL(mat);
switch (whichValue) {
case 0: col = &tmat->diffuseColor; break;
case 1: col = &tmat->emissiveColor; break;
case 2: col = &tmat->specularColor; break;
case 3: col = &tmat->backDiffuseColor; break;
case 4: col = &tmat->backEmissiveColor; break;
case 5: col = &tmat->backSpecularColor; break;
default: {}
}
if (col != NULL) {
col->c[0] =CLAMP(((float)((argbColour &0xff0000) >>16)) /255.0, 0.0, 1.0);
col->c[1] =CLAMP(((float)((argbColour &0x00ff00) >>8)) /255.0, 0.0, 1.0);
col->c[2] =CLAMP(((float)((argbColour &0x0000ff))) /255.0, 0.0, 1.0);
tmat->_change ++; // signal that this has been updated
}
}
}
/* for a SeekBar, get a field, for a side, and return it as a % 0-100
whichSide - 0->2 front side,
- 3-n, back side,
whichField - 1 - shininess, 2 transparency, 3- Ambient Intensity
*/
int fwl_get_MaterialFloatValue(struct Vector **shapeNodes, int whichEntry, int whichSide, int whichField) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
struct X3D_TwoSidedMaterial *tsm;
//ConsoleMessage ("gwl_get_materialFloatValue, entry %d, side %d, value %d",whichEntry, whichSide, whichField);
// If we do not have any node entries, maybe this is a new scene, and we have to get
// the valid nodes?
if (vectorSize(*shapeNodes) == 0 ) {
if (fwl_android_get_valid_shapeNodes(shapeNodes) == 0) return 0;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
//ConsoleMessage ("node %d is a %s",whichEntry,stringNodeType(node->_nodeType));
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (mat == NULL) return 0;
if (mat->_nodeType == NODE_TwoSidedMaterial) {
float fcol = 0.0;
struct X3D_TwoSidedMaterial *tmat = X3D_TWOSIDEDMATERIAL(mat);
if (whichSide <3) {
switch (whichField) {
case 1: fcol = tmat->shininess; break;
case 2: fcol = tmat->transparency; break;
case 3: fcol = tmat->ambientIntensity; break;
default: {
ConsoleMessage ("hmmm - expect 1-3, got %d",whichField);
return 0;
}
}
} else {
switch (whichField) {
case 1: fcol = tmat->backShininess; break;
case 2: fcol = tmat->backTransparency; break;
case 3: fcol = tmat->backAmbientIntensity; break;
default: {
ConsoleMessage ("hmmm - expect 1-3, got %d",whichField);
return 0;
}
}
}
return (int)(fcol*100.0); // fcol;
} else {
ConsoleMessage ("getMaterialValue, expected a TwoSidedMaterial, not a %s\n",stringNodeType(mat->_nodeType));
}
return 0;
}
void fwl_set_MaterialFloatValue(struct Vector **shapeNodes, int whichEntry, int whichSide, int whichField, int nv) {
struct X3D_FillProperties *fp;
struct X3D_LineProperties *lp;
struct X3D_Material *mat;
struct X3D_ImageTexture *tex;
struct X3D_TextureTransform *tt;
struct X3D_Node *geom;
struct X3D_Appearance *ap;
struct X3D_TwoSidedMaterial *tsm;
//ConsoleMessage ("gwl_set_materialFloatValue, entry %d, side %d, value %d new value %d",whichEntry, whichSide, whichField, nv);
// If we do not have any node entries, maybe this is a new scene, and we have to get
// the valid nodes?
if (vectorSize(*shapeNodes) == 0 ) {
if (fwl_android_get_valid_shapeNodes(shapeNodes) == 0) return;
}
// if we are here, we really do have at least one Shape node.
struct X3D_Node *node = vector_get(struct X3D_Node *,*shapeNodes, whichEntry);
//ConsoleMessage ("node %d is a %s",whichEntry,stringNodeType(node->_nodeType));
fwl_decomposeShape(X3D_SHAPE(node),&fp,&lp,&mat,&tex,&tt,&geom);
if (mat == NULL) return;
if (mat->_nodeType == NODE_TwoSidedMaterial) {
struct X3D_TwoSidedMaterial *tmat = X3D_TWOSIDEDMATERIAL(mat);
float nnv = CLAMP(((float)nv)/100.0,0.0,1.0);
// ConsoleMessage("nv as int %d, as float %f",nv,nnv);
if (whichSide <3) {
switch (whichField) {
case 1: tmat->shininess=nnv; break;
case 2: tmat->transparency=nnv; break;
case 3: tmat->ambientIntensity=nnv; break;
default: {
ConsoleMessage ("hmmm - expect 1-3, got %d",whichField);
}
}
} else {
switch (whichField) {
case 1: tmat->backShininess=nnv; break;
case 2: tmat->backTransparency=nnv; break;
case 3: tmat->backAmbientIntensity=nnv; break;
default: {
ConsoleMessage ("hmmm - expect 1-3, got %d",whichField);
}
}
}
tmat->_change++; // signal that this node has changed
} else {
ConsoleMessage ("getMaterialValue, expected a TwoSidedMaterial, not a %s\n",stringNodeType(mat->_nodeType));
}
}
#endif //ANDROID
#define TURN_OFF_SHOULDSORTCHILDREN node->_renderFlags = node->_renderFlags & (0xFFFF^ VF_shouldSortChildren);
#ifdef OLDCODE
OLDCODE/******************************************************************/
OLDCODE/* textureTransforms of all kinds */
OLDCODE
OLDCODE/* change the clear colour, selected from the GUI, but do the command in the
OLDCODE OpenGL thread */
OLDCODE
OLDCODEvoid fwl_set_glClearColor (float red , float green , float blue , float alpha) {
OLDCODE ppOpenGL_Utils p;
OLDCODE ttglobal tg = gglobal();
OLDCODE p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
OLDCODE p->cc_red = red; p->cc_green = green ; p->cc_blue = blue ; p->cc_alpha = alpha ;
OLDCODE tg->OpenGL_Utils.cc_changed = TRUE;
OLDCODE}
OLDCODE
OLDCODEvoid setglClearColor (float *val) {
OLDCODE ppOpenGL_Utils p;
OLDCODE ttglobal tg = gglobal();
OLDCODE p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
OLDCODE p->cc_red = *val; val++;
OLDCODE p->cc_green = *val; val++;
OLDCODE p->cc_blue = *val;
OLDCODE
OLDCODE// OLD_IPHONE_AQUA #ifdef AQUA
OLDCODE// OLD_IPHONE_AQUA val++;
OLDCODE// OLD_IPHONE_AQUA p->cc_alpha = *val;
OLDCODE// OLD_IPHONE_AQUA #endif
OLDCODE
OLDCODE tg->OpenGL_Utils.cc_changed = TRUE;
OLDCODE}
OLDCODE
#endif //OLDCODE
void fwl_setShadingStyle(int val) {
//0=flat 1=gouraud 2=phong 3=wireframe
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
p->shadingStyle = val;
}
int fwl_getShadingStyle() {
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
return p->shadingStyle;
}
#ifdef OLDCODE
OLDCODE
OLDCODE// use phong shading - better light reflectivity if set to true
OLDCODEvoid fwl_set_phongShading (int val) {
OLDCODE ppOpenGL_Utils p;
OLDCODE ttglobal tg = gglobal();
OLDCODE p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
OLDCODE if(val) fwl_setShadingStyle(2);
OLDCODE else fwl_setShadingStyle(1);
OLDCODE}
OLDCODE
OLDCODEint fwl_get_phongShading () {
OLDCODE ppOpenGL_Utils p;
OLDCODE ttglobal tg = gglobal();
OLDCODE p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
OLDCODE return fwl_getShadingStyle() == 2 ? TRUE : FALSE;
OLDCODE}
#endif //OLDCODE
/**************************************************************************************
Determine near far clip planes.
We have 2 choices; normal geometry, or we have a Geospatial sphere.
If we have normal geometry (normal Viewpoint, or GeoViewpoint with GC coordinates)
then, we take our AABB (axis alligned bounding box), rotate the 8 Vertices, and
find the min/max Z distance, and just use this.
This works very well for examine objects, or when we are within a virtual world.
----
If we are Geospatializing around the earth, so we have GeoSpatial and have UTM or GD
coordinates, lets do some optimizations here.
First optimization, we know our height above the origin, and we most certainly are not
going to see things past the origin, so we assume far plane is height above the origin.
Second, we know our AABB contains the Geospatial sphere, and it ALSO contains the highest
mountain peak, so we just go and find the value representing the highest peak. Our
near plane is thus farPlane - highestPeak.
**************************************************************************************/
#undef MAXREADSIZE
static void shaderErrorLog(GLuint myShader, char *which) {
#if defined (GL_VERSION_2_0) || defined (GL_ES_VERSION_2_0)
#define MAX_INFO_LOG_SIZE 512
GLchar infoLog[MAX_INFO_LOG_SIZE];
char outline[MAX_INFO_LOG_SIZE*2];
glGetShaderInfoLog(myShader, MAX_INFO_LOG_SIZE, NULL, infoLog);
sprintf(outline,"problem with %s shader: %s",which, infoLog);
ConsoleMessage (outline);
#else
ConsoleMessage ("Problem compiling shader");
#endif
}
/****************************************************************************************/
/* find a shader that matches the capabilities requested. If no match, recreate it */
s_shader_capabilities_t *getMyShaders(shaderflagsstruct rq_cap0) { //unsigned int rq_cap0) {
/* GL_ES_VERSION_2_0 has GL_SHADER_COMPILER */
#ifdef GL_SHADER_COMPILER
GLboolean b;
static bool haveDoneThis = false;
#endif
//unsigned int rq_cap;
shaderflagsstruct rq_cap;
int i;
ppOpenGL_Utils p = gglobal()->OpenGL_Utils.prv;
struct Vector *myShaderTable = p->myShaderTable;
struct shaderTableEntry *new = NULL;
rq_cap = rq_cap0;
//rq_cap = NO_APPEARANCE_SHADER; //for thunking to simplest when debugging
for (i=0; iwhichOne.volume == rq_cap0.volume && me->whichOne.effects == rq_cap0.effects){
return me->myCapabilities;
}
}else{
if (me->whichOne.base == rq_cap0.base && me->whichOne.effects == rq_cap0.effects && me->whichOne.usershaders == rq_cap0.usershaders) {
//printf("getMyShaders chosen shader caps base %d effects %d user %d\n",me->whichOne.base,me->whichOne.effects,me->whichOne.usershaders);
return me->myCapabilities;
}
}
}
// if here, we did not find the shader already compiled for us.
//ConsoleMessage ("getMyShader, looking for %x",rq_cap);
//ConsoleMessage ("getMyShader, not found, have to create");
//for (i=0; iwhichOne %x myCap %p\n",i,rq_cap,me->whichOne,me->myCapabilities);
//}
/* GL_ES_VERSION_2_0 has GL_SHADER_COMPILER */
#ifdef GL_SHADER_COMPILER
glGetBooleanv(GL_SHADER_COMPILER,&b);
if (!haveDoneThis) {
haveDoneThis = true;
if (!b) {
//I found desktop openGL version 2.1.2 comes in here, but does still render OK
//ConsoleMessage("NO SHADER COMPILER - have to sometime figure out binary shader distros");
ConsoleMessage("no shader compiler\n");
return NULL;
}
}
#endif
// ConsoleMessage ("getMyShader, here now");
#ifdef VERBOSE
#if defined (GL_SHADER_COMPILER) && defined (GL_HIGH_FLOAT)
/* GL_ES_VERSION_2_0 variables for shaders */
{ /* debugging */
GLint range[2]; GLint precision;
GLboolean b;
ConsoleMessage("starting getMyShader");
glGetBooleanv(GL_SHADER_COMPILER,&b);
if (b) ConsoleMessage("have shader compiler"); else ConsoleMessage("NO SHADER COMPILER");
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_LOW_FLOAT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_LOW_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_MEDIUM_FLOAT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_MEDIUM_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_HIGH_FLOAT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_HIGH_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_LOW_INT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_LOW_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_MEDIUM_INT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_MEDIUM_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_HIGH_INT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_HIGH_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_LOW_FLOAT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_LOW_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_MEDIUM_FLOAT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_HIGH_FLOAT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_HIGH_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_LOW_INT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_LOW_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_MEDIUM_INT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_MEDIUM_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_HIGH_INT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_HIGH_INT range [%d,%d],precision %d",range[0],range[1],precision);
}
#endif // #ifdef GL_ES_VERSION_2_0 specific debugging
#endif //VERBOSE
new = MALLOC(struct shaderTableEntry *, sizeof (struct shaderTableEntry));
new ->whichOne = rq_cap;
new->myCapabilities = MALLOC(s_shader_capabilities_t*, sizeof (s_shader_capabilities_t));
//ConsoleMessage ("going to compile new shader for %x",rq_cap);
makeAndCompileShader(new);
vector_pushBack(struct shaderTableEntry*, myShaderTable, new);
//ConsoleMessage ("going to return new %p",new);
//ConsoleMessage ("... myCapabilities is %p",new->myCapabilities);
return new->myCapabilities;
}
s_shader_capabilities_t *getMyShader(unsigned int rq_cap0) {
shaderflagsstruct rq_cap0s;
memset(&rq_cap0s,0,sizeof(shaderflagsstruct));
rq_cap0s.base = rq_cap0;
return getMyShaders(rq_cap0s);
}
#define DESIRE(whichOne,zzz) ((whichOne & zzz)==zzz)
/* VERTEX inputs */
/*
Update for Projective Texture VertexShader Value, Function by Yoo Kwan Hee, Kim In Kwon
Start
*/
static const GLchar *vertProjValDec = "\
uniform mat4 projTexGenMatCam0; \n \
varying vec4 projTexCoord; \n";
static const GLchar *vertProjCalTexCoord ="\
void vertProjCalTexCoord(void) { \
projTexCoord = projTexGenMatCam0 * fw_Vertex; \
} \n";
static const GLchar *vertProjTexCalculation ="\
vertProjCalTexCoord();\n";
/*
Update for Projective Texture FragmentShader Value, Function by Yoo Kwan Hee, Kim In Kwon
Start
*/
static const GLchar *fragProjValDec = "\
varying vec4 projTexCoord; \n \
vec4 ProjMapColor_forCam1; \n";
static const GLchar *fragProjCalTexCoord ="\
void fragProjCalTexCoord(void) { \
if( projTexCoord.q > 0.0 ){ \n \
ProjMapColor_forCam1 = texture2DProj(fw_Texture_unit0, projTexCoord);\n \
}\n \
} \n";
static const GLchar *fragProjTexCalculation ="\
fragProjCalTexCoord();\n \
finalFrag += ProjMapColor_forCam1;\n \
\n";
/*
Update for multi Projective Texture VertexShader Value, Function by Yoo Kwan Hee, Kim In Kwon
Start
*/
static const GLchar *vertMultiProjValDec = "\
uniform mat4 MultiprojTexGenMatCam1; \n \
uniform mat4 MultiprojTexGenMatCam2; \n \
uniform mat4 MultiprojTexGenMatCam3; \n \
uniform mat4 MultiprojTexGenMatCam4; \n \
varying vec4 MultiprojTexCoord1; \n \
varying vec4 MultiprojTexCoord2; \n \
varying vec4 MultiprojTexCoord3; \n \
varying vec4 MultiprojTexCoord4; \n";
static const GLchar *vertMultiProjCalTexCoord ="\
void vertMultiProjCalTexCoord(void) { \
MultiprojTexCoord1 = MultiprojTexGenMatCam1 * fw_Vertex; \
MultiprojTexCoord2 = MultiprojTexGenMatCam2 * fw_Vertex; \
MultiprojTexCoord3 = MultiprojTexGenMatCam3 * fw_Vertex; \
MultiprojTexCoord4 = MultiprojTexGenMatCam4 * fw_Vertex; \
} \n";
static const GLchar *vertMultiProjTexCalculation ="\
vertMultiProjCalTexCoord();\n";
/*
Update for multi Projective Texture FragmentShader Value, Function by Yoo Kwan Hee, Kim In Kwon
Start
*/
static const GLchar *fragMultiProjValDec = "\
varying vec4 MultiprojTexCoord1; \n \
varying vec4 MultiprojTexCoord2; \n \
varying vec4 MultiprojTexCoord3; \n \
varying vec4 MultiprojTexCoord4; \n \
vec4 final_color = vec4(1.0, 1.0, 1.0, 0.0); \n";
static const GLchar *fragMultiProjCalTexCoord ="\
void fragMultiProjCalTexCoord(void) { \
if( MultiprojTexCoord1.q > 0.0 ){ \n \
vec4 ProjMapColor_forCam1 = texture2DProj(fw_Texture_unit0, MultiprojTexCoord1);\n \
final_color = ProjMapColor_forCam1;\n \
}\n \
if( MultiprojTexCoord2.q > 0.0 ){ \n \
vec4 ProjMapColor_forCam2 = texture2DProj(fw_Texture_unit1, MultiprojTexCoord2);\n \
final_color = final_color+ ProjMapColor_forCam2;\n \
}\n \
if( MultiprojTexCoord3.q > 0.0 ){ \n \
vec4 ProjMapColor_forCam3 = texture2DProj(fw_Texture_unit2, MultiprojTexCoord3);\n \
final_color = final_color+ ProjMapColor_forCam3;\n \
}\n \
} \n";
static const GLchar *fragMultiProjTexCalculation ="\
fragMultiProjCalTexCoord();\n \
finalFrag += final_color;\n \
\n";
/*
Update for Projective Texture FragmentShader Value, Function by Yoo Kwan Hee, Kim In Kwon
End
*/
static const GLchar *vertPosDec = "\
attribute vec4 fw_Vertex; \n \
uniform mat4 fw_ModelViewMatrix; \n \
uniform mat4 fw_ProjectionMatrix; \n ";
static const GLchar *vertNormDec = " \
uniform mat3 fw_NormalMatrix;\n \
attribute vec3 fw_Normal; \n";
static const GLchar *vertSimColDec = "\
attribute vec4 fw_Color;\n ";
static const GLchar *vertTexMatrixDec = "\
uniform mat4 fw_TextureMatrix0;\n";
static const GLchar *vertTexCoordGenDec ="\
uniform int fw_textureCoordGenType;\n";
static const GLchar *vertTexCoordDec = "\
attribute vec2 fw_MultiTexCoord0;\n";
static const GLchar *vertOneMatDec = "\
uniform fw_MaterialParameters\n\
fw_FrontMaterial; \n";
static const GLchar *vertBackMatDec = "\
uniform fw_MaterialParameters fw_BackMaterial; \n";
/* VERTEX outputs */
static const GLchar *vecNormPos = " \
vec3 vertexNorm; \
vec4 vertexPos; \n";
static const GLchar *varyingNormPos = " \
varying vec3 vertexNorm; \
varying vec4 vertexPos; \n";
static const GLchar *varyingTexCoord = "\
varying vec3 fw_TexCoord[4];\n";
static const GLchar *varyingFrontColour = "\
varying vec4 v_front_colour; \n";
static const GLchar *varyingHatchPosition = "\
varying vec2 hatchPosition; \n";
/* VERTEX Calculations */
static const GLchar *vertMainStart = "void main(void) { \n";
static const GLchar *vertEnd = "}";
static const GLchar *vertPos = "gl_Position = fw_ProjectionMatrix * fw_ModelViewMatrix * fw_Vertex;\n ";
static const GLchar *vertNormPosCalc = "\
vertexNorm = normalize(fw_NormalMatrix * fw_Normal);\n \
vertexPos = fw_ModelViewMatrix * fw_Vertex;\n ";
static const GLchar *vertSimColUse = "v_front_colour = fw_Color; \n";
static const GLchar *vertEmissionOnlyColourAss = "v_front_colour = fw_FrontMaterial.emission;\n";
static const GLchar *vertSingTexCalc = "fw_TexCoord[0] = vec3(vec4(fw_TextureMatrix0 *vec4(fw_MultiTexCoord0,0,0))).stp;\n";
static const GLchar *vertSingTexCubeCalc = "\
vec3 u=normalize(vec3(fw_ProjectionMatrix * fw_Vertex)); /* myEyeVertex */ \
/* vec3 n=normalize(vec3(fw_NormalMatrix*fw_Normal)); \
fw_TexCoord[0] = reflect(u,n); myEyeNormal */ \n \
/* v_texC = reflect(normalize(vec3(vertexPos)),vertexNorm);\n */ \
fw_TexCoord[0] = reflect(u,vertexNorm);\n";
/* TextureCoordinateGenerator mapping */
const static GLchar *fragTCGTDefs = TEXTURECOORDINATEGENERATORDefs;
/*
Good hints for code here: http://www.opengl.org/wiki/Mathematics_of_glTexGen
*/
static const GLchar *sphEnvMapCalc = " \n \
/* sphereEnvironMapping Calculation */ \
/* vec3 u=normalize(vec3(fw_ModelViewMatrix * fw_Vertex)); (myEyeVertex) \
vec3 n=normalize(vec3(fw_NormalMatrix*fw_Normal)); \
vec3 r = reflect(u,n); (myEyeNormal) */ \n\
vec3 u=normalize(vec3(vertexPos)); /* u is normalized position, used below more than once */ \n \
vec3 r= reflect(u,vertexNorm); \n\
if (fw_textureCoordGenType==TCGT_SPHERE) { /* TCGT_SPHERE GL_SPHERE_MAP OpenGL Equiv */ \n\
float m=2.0 * sqrt(r.x*r.x + r.y*r.y + (r.z*1.0)*(r.z*1.0)); \n\
fw_TexCoord[0] = vec3(r.x/m+0.5,r.y/m+0.5,0.0); \n \
}else if (fw_textureCoordGenType==TCGT_CAMERASPACENORMAL) /* GL_REFLECTION_MAP used for sampling cubemaps */ {\n \
float dotResult = 2.0 * dot(u,r); \n\
fw_TexCoord[0] = vec3(u-r)*dotResult;\n\
} else { /* default usage - like default CubeMaps */ \n\
vec3 u=normalize(vec3(fw_ProjectionMatrix * fw_Vertex)); /* myEyeVertex */ \
fw_TexCoord[0] = reflect(u,vertexNorm);\n \
}\n\
";
static const GLchar *vertHatchPosCalc = "hatchPosition = fw_Vertex.xy;\n";
static const GLchar *fillPropDefines = "\
uniform vec4 HatchColour; \n\
uniform bool hatched; uniform bool filled;\n\
uniform vec2 HatchScale; uniform vec2 HatchPct; uniform int algorithm; ";
//=============STRUCT METHOD FOR LIGHTS==================
// use for opengl, and angleproject desktop/d3d9
static const GLchar *lightDefines = "\
struct fw_MaterialParameters {\n\
vec4 emission;\n\
vec4 ambient;\n\
vec4 diffuse;\n\
vec4 specular;\n\
float shininess;\n\
};\n\
uniform int lightcount;\n\
//uniform float lightRadius[MAX_LIGHTS];\n\
uniform int lightType[MAX_LIGHTS];//ANGLE like this\n\
struct fw_LightSourceParameters { \n\
vec4 ambient; \n\
vec4 diffuse; \n\
vec4 specular; \n\
vec4 position; \n\
vec4 halfVector; \n\
vec4 spotDirection; \n\
float spotBeamWidth; \n\
float spotCutoff; \n\
vec3 Attenuations; \n\
//float constantAttenuation; \n\
//float linearAttenuation; \n\
//float quadraticAttenuation; \n\
float lightRadius; \n\
//int lightType; ANGLE doesnt like int in struct array \n\
}; \n\
\n\
uniform fw_LightSourceParameters fw_LightSource[MAX_LIGHTS] /* gl_MaxLights */ ;\n\
";
/* replace:
linearAttenuation uniform float light_linAtten[MAX_LIGHTS]; \n\
constantAttenuation uniform float light_constAtten[MAX_LIGHTS]; \n\
quadraticAttenuation uniform float light_quadAtten[MAX_LIGHTS]; \n\
spotCutoff uniform float lightSpotCutoffAngle[MAX_LIGHTS]; \n\
spotExponent uniform float lightSpotBeamWidth[MAX_LIGHTS]; \n\
ambient uniform vec4 lightAmbient[MAX_LIGHTS];\n\
diffuse uniform vec4 lightDiffuse[MAX_LIGHTS];\n\
position uniform vec4 lightPosition[MAX_LIGHTS];\n\
spotDirection uniform vec4 lightSpotDirection[MAX_LIGHTS];\n\
specular uniform vec4 lightSpecular[MAX_LIGHTS];\n\
*/
static const GLchar *ADSLLightModel = "\n\
/* use ADSLightModel here the ADS colour is returned from the function. */\n\
vec4 ADSLightModel(in vec3 myNormal, in vec4 myPosition, in bool useMatDiffuse) {\n\
int i;\n\
vec4 diffuse = vec4(0., 0., 0., 0.);\n\
vec4 ambient = vec4(0., 0., 0., 0.);\n\
vec4 specular = vec4(0., 0., 0., 1.);\n\
vec3 normal = normalize (myNormal);\n\
\n\
vec3 viewv = -normalize(myPosition.xyz); \n \
bool backFacing = (dot(normal,viewv) < 0.0); \n \
vec4 emissive;\n\
vec4 matdiffuse = vec4(1.0,1.0,1.0,1.0);\n\
float myAlph = 0.0;\n\
\n\
fw_MaterialParameters myMat = fw_FrontMaterial;\n\
\n\
/* back Facing materials - flip the normal and grab back materials */ \n \
if (backFacing) { \n \
normal = -normal; \n \
myMat = fw_BackMaterial; \n \
} \n \
\n\
emissive = myMat.emission;\n\
myAlph = myMat.diffuse.a;\n\
if(useMatDiffuse)\n\
matdiffuse = myMat.diffuse;\n\
\n\
/* apply the lights to this material */\n\
for (i=0; i 0.0) {\n\
powerFactor = pow(nDotL,myMat.shininess); \n\
/* tone down the power factor if myMat.shininess borders 0 */\n\
if (myMat.shininess < 1.0) {\n\
powerFactor *= myMat.shininess; \n\
} \n\
} \n\
attenuation = 1.0/(fw_LightSource[i].Attenuations.x + (fw_LightSource[i].Attenuations.y * d) + (fw_LightSource[i].Attenuations.z *d *d));\n\
spotDot = dot (-L,myLightDir);\n\
/* check against spotCosCutoff */\n\
if (spotDot > fw_LightSource[i].spotCutoff) {\n\
spotAttenuation = pow(spotDot,fw_LightSource[i].spotCutoff);\n\
}\n\
attenuation *= spotAttenuation;\n\
/* diffuse light computation */\n\
diffuse += nDotL* matdiffuse*myLightDiffuse * attenuation;\n\
/* ambient light computation */\n\
ambient += myMat.ambient*myLightAmbient;\n\
/* specular light computation */\n\
specular += myLightSpecular * powerFactor * attenuation;\n\
\n\
} else if (myLightType == 2) { \n\
/* DirectionalLight */ \n\
float powerFactor = 0.0; /* for light dropoff */\n\
if (nDotL > 0.0) {\n\
powerFactor = pow(nDotHV, myMat.shininess);\n\
/* tone down the power factor if myMat.shininess borders 0 */\n\
if (myMat.shininess < 1.0) {\n\
powerFactor *= myMat.shininess;\n\
}\n\
}\n\
/* Specular light computation */\n\
specular += myMat.specular *myLightSpecular*powerFactor;\n\
/* diffuse light computation */\n\
diffuse += nDotL*matdiffuse*myLightDiffuse;\n\
/* ambient light computation */\n\
ambient += myMat.ambient*myLightAmbient; \n\
} else {\n\
/* PointLight */\n\
float powerFactor=0.0; /* for light dropoff */\n\
float attenuation = 0.0; /* computed attenuation factor */\n\
float d = length(VP); /* distance to vertex */ \n\
/* are we within range? */\n\
if (d <= fw_LightSource[i].lightRadius) {\n\
if (nDotL > 0.0) {\n\
powerFactor = pow(nDotL, myMat.shininess);\n\
//attenuation = (myMat.shininess-128.0);\n\
}\n\
/* this is actually the SFVec3f attenuation field */\n\
attenuation = 1.0/(fw_LightSource[i].Attenuations.x + (fw_LightSource[i].Attenuations.y * d) + (fw_LightSource[i].Attenuations.z *d *d));\n\
/* diffuse light computation */\n\
diffuse += nDotL* matdiffuse*myLightDiffuse * attenuation;\n\
/* ambient light computation */\n\
ambient += myMat.ambient*myLightAmbient;\n\
/* specular light computation */\n\
attenuation *= (myMat.shininess/128.0);\n\
specular += myLightSpecular * powerFactor * attenuation;\n\
}\n\
}\n\
}\n\
}\n\
return clamp(vec4(vec3(ambient+diffuse+specular+emissive),myAlph), 0.0, 1.0);\n\
}\n\
";
#ifdef USING_SHADER_LIGHT_ARRAY_METHOD
//============= USING_SHADER_LIGHT_ARRAY_METHOD FOR LIGHTS==================
//used for angleproject winRT d3d11 (which can't/doesn't convert GLSL struct[] array to HLSL properly - just affects lights)
//will break custom shader node vertex/pixel shaders that try to use gl_LightSource[] ie teapot-Toon.wrl
static const GLchar *lightDefinesArrayMethod = "\
struct fw_MaterialParameters {\n\
vec4 emission;\n\
vec4 ambient;\n\
vec4 diffuse;\n\
vec4 specular;\n\
float shininess;\n\
};\n\
uniform int lightcount;\n\
uniform int lightType[MAX_LIGHTS];\n\
uniform vec4 lightambient[MAX_LIGHTS]; \n\
uniform vec4 lightdiffuse[MAX_LIGHTS]; \n\
uniform vec4 lightspecular[MAX_LIGHTS]; \n\
uniform vec4 lightposition[MAX_LIGHTS]; \n\
uniform vec4 lighthalfVector[MAX_LIGHTS]; \n\
uniform vec4 lightspotDirection[MAX_LIGHTS]; \n\
uniform float lightspotBeamWidth[MAX_LIGHTS]; \n\
uniform float lightspotCutoff[MAX_LIGHTS]; \n\
uniform float lightRadius[MAX_LIGHTS]; \n\
uniform vec3 lightAttenuations[MAX_LIGHTS]; \n\
";
static const GLchar *ADSLLightModelArrayMethod = "\n\
/* use ADSLightModel here the ADS colour is returned from the function. */\n\
vec4 ADSLightModel(in vec3 myNormal, in vec4 myPosition, in bool useMatDiffuse) {\n\
int i;\n\
vec4 diffuse = vec4(0., 0., 0., 0.);\n\
vec4 ambient = vec4(0., 0., 0., 0.);\n\
vec4 specular = vec4(0., 0., 0., 1.);\n\
vec3 normal = normalize (myNormal);\n\
\n\
vec3 viewv = -normalize(myPosition.xyz); \n \
bool backFacing = (dot(normal,viewv) < 0.0); \n \
vec4 emissive;\n\
vec4 matdiffuse = vec4(1.0,1.0,1.0,1.0);\n\
float myAlph = 0.0;\n\
\n\
fw_MaterialParameters myMat = fw_FrontMaterial;\n\
\n\
/* back Facing materials - flip the normal and grab back materials */ \n \
if (backFacing) { \n \
normal = -normal; \n \
myMat = fw_BackMaterial; \n \
} \n \
\n\
emissive = myMat.emission;\n\
myAlph = myMat.diffuse.a;\n\
if(useMatDiffuse)\n\
matdiffuse = myMat.diffuse;\n\
\n\
/* apply the lights to this material */\n\
for (i=0; i 0.0) {\n\
powerFactor = pow(nDotL,myMat.shininess); \n\
/* tone down the power factor if myMat.shininess borders 0 */\n\
if (myMat.shininess < 1.0) {\n\
powerFactor *= myMat.shininess; \n\
} \n\
} \n\
attenuation = 1.0/(lightAttenuations[i].x + (lightAttenuations[i].y * d) + (lightAttenuations[i].z *d *d));\n\
spotDot = dot (-L,myLightDir);\n\
/* check against spotCosCutoff */\n\
if (spotDot > lightspotCutoff[i]) {\n\
spotAttenuation = pow(spotDot,lightspotBeamWidth[i]);\n\
}\n\
attenuation *= spotAttenuation;\n\
/* diffuse light computation */\n\
diffuse += nDotL* matdiffuse*myLightDiffuse * attenuation;\n\
/* ambient light computation */\n\
ambient += myMat.ambient*myLightAmbient;\n\
/* specular light computation */\n\
specular += myLightSpecular * powerFactor * attenuation;\n\
\n\
} else if (myLightType == 2) { \n\
/* DirectionalLight */ \n\
float powerFactor = 0.0; /* for light dropoff */\n\
if (nDotL > 0.0) {\n\
powerFactor = pow(nDotHV, myMat.shininess);\n\
/* tone down the power factor if myMat.shininess borders 0 */\n\
if (myMat.shininess < 1.0) {\n\
powerFactor *= myMat.shininess;\n\
}\n\
}\n\
/* Specular light computation */\n\
specular += myMat.specular *myLightSpecular*powerFactor;\n\
/* diffuse light computation */\n\
diffuse += nDotL*matdiffuse*myLightDiffuse;\n\
/* ambient light computation */\n\
ambient += myMat.ambient*myLightAmbient; \n\
} else {\n\
/* PointLight */\n\
float powerFactor=0.0; /* for light dropoff */\n\
float attenuation = 0.0; /* computed attenuation factor */\n\
float d = length(VP); /* distance to vertex */ \n\
/* are we within range? */\n\
if (d <= lightRadius[i]) {\n\
if (nDotL > 0.0) {\n\
powerFactor = pow(nDotL, myMat.shininess);\n\
}\n\
/* this is actually the SFVec3f attenuation field */\n\
attenuation = 1.0/(lightAttenuations[i].x + (lightAttenuations[i].y * d) + (lightAttenuations[i].z *d *d));\n\
/* diffuse light computation */\n\
diffuse += nDotL* matdiffuse*myLightDiffuse * attenuation;\n\
/* ambient light computation */\n\
ambient += myMat.ambient*myLightAmbient;\n\
/* specular light computation */\n\
attenuation *= (myMat.shininess/128.0);\n\
specular += myLightSpecular * powerFactor * attenuation;\n\
}\n\
}\n\
}\n\
}\n\
return clamp(vec4(vec3(ambient+diffuse+specular+emissive),myAlph), 0.0, 1.0);\n\
}\n\
";
#endif
/* FRAGMENT bits */
//#if defined (GL_HIGH_FLOAT) && defined(GL_MEDIUM_FLOAT)
/* GL_ES and Desktop GL are different... */
#if defined (GL_ES_VERSION_2_0)
static const GLchar *fragHighPrecision = "precision highp float;\n ";
static const GLchar *fragMediumPrecision = "precision mediump float;\n ";
static const GLchar *maxLights = STR_MAX_LIGHTS; //"\n#define MAX_LIGHTS 2\n ";
#else
static const GLchar *maxLights = STR_MAX_LIGHTS; //"\n#define MAX_LIGHTS 8\n ";
#endif
/* NOTE that we write to the vec4 "finalFrag", and at the end we assign
the gl_FragColor, because we might have textures, fill properties, etc
dug9 Jan 5, 2014 change of strategy to accommodate ONE_MAT + ONE_TEX = 0x2 + 0x8 = 0x10
- in frag main change to 'cascade of v4*v4' so it's easier to combine MAT with TEX
- frag main:
void main() {
vec4 finalFrag = vec4(1.0,1.0,1.0,1.0);
finalFrag = v_front_color * finalFrag; //material
finalFrag = texture2D(fw_Texture_unit0, v_texC.st) * finalFrag; //texture
gl_FragColor = finalFrag;
}
*/
//dug9 Jan 5, 2014 static const GLchar *fragMainStart = "void main() { vec4 finalFrag = vec4(0.,0.,0.,0.);\n";
static const GLchar *fragMainStart = "void main() { vec4 finalFrag = vec4(1.,1.,1.,1.);\n";
static const GLchar *anaglyphGrayFragEnd = "float gray = dot(finalFrag.rgb, vec3(0.299, 0.587, 0.114)); \n \
gl_FragColor = vec4(gray, gray, gray, finalFrag.a);}";
/* discard operations needed for really doing a good job in transparent situations (FillProperties, filled = false,
for instance - drawing operations preclude sorting individual triangles for best rendering, so when the user
requests best shaders, we add in this discard. */
static const GLchar *discardInFragEnd = "if (finalFrag.a==0.0) {discard; } else {gl_FragColor = finalFrag;}}";
static const GLchar *fragEnd = "gl_FragColor = finalFrag;}";
static const GLchar *fragTex0Dec = "uniform sampler2D fw_Texture_unit0; \n";
static const GLchar *fragTex0CubeDec = "uniform samplerCube fw_Texture_unit0; \n";
//dug9 Jan 5,2014 change to 'cascade of v4*v4' in frag main
static const GLchar *fragSimColAss = "finalFrag = v_front_colour * finalFrag;\n ";
static const GLchar *fragNoAppAss = "finalFrag = vec4(1.0, 1.0, 1.0, 1.0);\n";
static const GLchar *fragFrontColAss= " finalFrag = v_front_colour * finalFrag;";
const static GLchar *fragADSLAss = "finalFrag = ADSLightModel(vertexNorm,vertexPos,true) * finalFrag;";
const static GLchar *vertADSLCalc = "v_front_colour = ADSLightModel(vertexNorm,vertexPos,true);";
const static GLchar *vertADSLCalc0 = "v_front_colour = ADSLightModel(vertexNorm,vertexPos,false);";
const static GLchar *fragSingTexAss = "finalFrag = texture2D(fw_Texture_unit0, fw_TexCoord[0].st) * finalFrag;\n";
const static GLchar *fragSingTexCubeAss = "finalFrag = textureCube(fw_Texture_unit0, fw_TexCoord[0]) * finalFrag;\n";
/* MultiTexture stuff */
/* still to do:
#define MTMODE_BLENDCURRENTALPHA 2
#define MTMODE_DOTPRODUCT3 4
#define MTMODE_SELECTARG2 5
#define MTMODE_SELECTARG1 6
#define MTMODE_BLENDDIFFUSEALPHA 7
#define MTMODE_MODULATEINVCOLOR_ADDALPHA 10
#define MTMODE_MODULATEINVALPHA_ADDCOLOR 15
#define MTMODE_MODULATEALPHA_ADDCOLOR 16
*/
const static GLchar *fragMultiTexDef = MULTITEXTUREDefs;
static const GLchar *fragMultiTexUniforms = " \
/* defined for single textures... uniform sampler2D fw_Texture_unit0; */\
uniform sampler2D fw_Texture_unit1; \
uniform sampler2D fw_Texture_unit2; \
/* REMOVE these as shader compile takes long \
uniform sampler2D fw_Texture_unit3; \
uniform sampler2D fw_Texture_unit4; \
uniform sampler2D fw_Texture_unit5; \
uniform sampler2D fw_Texture_unit6; \
uniform sampler2D fw_Texture_unit7; \
*/ \
uniform int fw_Texture_mode0; \
uniform int fw_Texture_mode1; \
uniform int fw_Texture_mode2; \
/* REMOVE these as shader compile takes long \
uniform int fw_Texture_mode3; \
uniform int fw_Texture_mode4; \
uniform int fw_Texture_mode5; \
uniform int fw_Texture_mode6; \
uniform int fw_Texture_mode7; \
*/ \n\
\
uniform int textureCount;\n";
static const GLchar *fragFillPropFunc = "\
vec4 fillPropCalc(in vec4 prevColour, vec2 MCposition, int algorithm) {\
vec4 colour; \
vec2 position, useBrick; \
\
position = MCposition / HatchScale; \
\
if (algorithm == 0) {/* bricking */ \
if (fract(position.y * 0.5) > 0.5) \
position.x += 0.5; \
}\
\
/* algorithm 1, 2 = no futzing required here */ \
if (algorithm == 3) {/* positive diagonals */ \
vec2 curpos = position; \
position.x -= curpos.y; \
} \
\
if (algorithm == 4) {/* negative diagonals */ \
vec2 curpos = position; \
position.x += curpos.y; \
} \
\
if (algorithm == 6) {/* diagonal crosshatch */ \
vec2 curpos = position; \
if (fract(position.y) > 0.5) { \
if (fract(position.x) < 0.5) position.x += curpos.y; \
else position.x -= curpos.y; \
} else { \
if (fract(position.x) > 0.5) position.x += curpos.y; \
else position.x -= curpos.y; \
} \
} \
\
position = fract(position); \
\
useBrick = step(position, HatchPct); \
\
if (filled) {colour = prevColour;} else { colour=vec4(0.,0.,0.,0); }\
if (hatched) { \
colour = mix(HatchColour, colour, useBrick.x * useBrick.y); \
} \
return colour; } ";
static const GLchar *fragFillPropCalc = "\
finalFrag= fillPropCalc(finalFrag, hatchPosition, algorithm);\n";
static const GLchar *fragMulTexFunc ="\
vec4 finalColCalc(in vec4 prevColour, in int mode, in sampler2D tex, in vec2 texcoord) { \
vec4 texel = texture2D(tex,texcoord); \
vec4 rv = vec4(1.,0.,1.,1.); \
\
if (mode==MTMODE_OFF) { rv = vec4(prevColour);} \
else if (mode==MTMODE_REPLACE) {rv = vec4(texture2D(tex, texcoord));}\
else if (mode==MTMODE_MODULATE) { \
\
vec3 ct,cf; \
float at,af; \
\
cf = prevColour.rgb; \
af = prevColour.a; \
\
ct = texel.rgb; \
at = texel.a; \
\
\
rv = vec4(ct*cf, at*af); \
\
} \
else if (mode==MTMODE_MODULATE2X) { \
vec3 ct,cf; \
float at,af; \
\
cf = prevColour.rgb; \
af = prevColour.a; \
\
ct = texel.rgb; \
at = texel.a; \
rv = vec4(vec4(ct*cf, at*af)*vec4(2.,2.,2.,2.)); \
}\
else if (mode==MTMODE_MODULATE4X) { \
vec3 ct,cf; \
float at,af; \
\
cf = prevColour.rgb; \
af = prevColour.a; \
\
ct = texel.rgb; \
at = texel.a; \
rv = vec4(vec4(ct*cf, at*af)*vec4(4.,4.,4.,4.)); \
}\
else if (mode== MTMODE_ADDSIGNED) {\
rv = vec4 (prevColour + texel - vec4 (0.5, 0.5, 0.5, -.5)); \
} \
else if (mode== MTMODE_ADDSIGNED2X) {\
rv = vec4 ((prevColour + texel - vec4 (0.5, 0.5, 0.5, -.5))*vec4(2.,2.,2.,2.)); \
} \
else if (mode== MTMODE_ADD) {\
rv= vec4 (prevColour + texel); \
} \
else if (mode== MTMODE_SUBTRACT) {\
rv = vec4 (prevColour - texel); \
} \
else if (mode==MTMODE_ADDSMOOTH) { \
rv = vec4 (prevColour + (prevColour - vec4 (1.,1.,1.,1.)) * texel); \
} \
return rv; \
\
} \n";
const static GLchar *fragMulTexCalc = "\
if(textureCount>=1) {finalFrag=finalColCalc(finalFrag,fw_Texture_mode0,fw_Texture_unit0,fw_TexCoord[0].st);} \n\
if(textureCount>=2) {finalFrag=finalColCalc(finalFrag,fw_Texture_mode1,fw_Texture_unit1,fw_TexCoord[0].st);} \n\
if(textureCount>=3) {finalFrag=finalColCalc(finalFrag,fw_Texture_mode2,fw_Texture_unit2,fw_TexCoord[0].st);} \n\
/* REMOVE these as shader compile takes long \
if(textureCount>=4) {finalFrag=finalColCalc(finalFrag,fw_Texture_mode3,fw_Texture_unit3,fw_TexCoord[0].st);} \n\
if(textureCount>=5) {finalFrag=finalColCalc(finalFrag,fw_Texture_mode4,fw_Texture_unit4,fw_TexCoord[0].st);} \n\
if(textureCount>=6) {finalFrag=finalColCalc(finalFrag,fw_Texture_mode5,fw_Texture_unit5,fw_TexCoord[0].st);} \n\
if(textureCount>=7) {finalFrag=finalColCalc(finalFrag,fw_Texture_mode6,fw_Texture_unit6,fw_TexCoord[0].st);} \n\
if(textureCount>=8) {finalFrag=finalColCalc(finalFrag,fw_Texture_mode7,fw_Texture_unit7,fw_TexCoord[0].st);} \n\
*/ \n";
const static GLchar *pointSizeDeclare="uniform float pointSize;\n";
const static GLchar *pointSizeAss="gl_PointSize = pointSize; \n";
static int getSpecificShaderSourceOriginal (const GLchar *vertexSource[vertexEndMarker],
const GLchar *fragmentSource[fragmentEndMarker], shaderflagsstruct whichOne) { //unsigned int whichOne) {
bool doThis;
bool didADSLmaterial;
#ifdef USING_SHADER_LIGHT_ARRAY_METHOD
//for angleproject winRT d3d11 - can't do struct[] array for lights
const GLchar *lightDefines0 = lightDefinesArrayMethod;
const GLchar *ADSLLightModel0 = ADSLLightModelArrayMethod;
#else
const GLchar *lightDefines0 = lightDefines;
const GLchar *ADSLLightModel0 = ADSLLightModel;
#endif
/* GL_ES - do we have medium precision, or just low precision?? */
/* Phong shading - use the highest we have */
/* GL_ES_VERSION_2_0 has these definitions */
#if defined (GL_ES_VERSION_2_0)
bool haveHighPrecisionFragmentShaders = false;
#ifdef VARY_VERTEX_PRECISION
bool haveHighPrecisionVertexShaders = false;
#endif
GLint range[2]; GLint precision;
// see where we are doing the lighting. Use highest precision there, if we can.
if (DESIRE(whichOne.base,SHADINGSTYLE_PHONG)) {
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_HIGH_FLOAT, range, &precision);
if (precision!=0) {
haveHighPrecisionFragmentShaders=true;
} else {
haveHighPrecisionFragmentShaders=false;
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_MEDIUM_FLOAT, range, &precision);
if (precision == 0) {
ConsoleMessage("low precision Fragment shaders only available - view may not work so well");
}
}
#ifdef VARY_VERTEX_PRECISION
// if we do lighting on the Vertex shader side, do we have to worry about precision?
} else {
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_HIGH_FLOAT, range, &precision);
if (precision!=0) {
haveHighPrecisionVertexShaders=true;
} else {
haveHighPrecisionVertexShaders=false;
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_MEDIUM_FLOAT, range, &precision);
if (precision == 0) {
ConsoleMessage("low precision Vertex shaders only available - view may not work so well");
}
}
#endif //VARY_VERTEX_PRECISION
}
#else
// ConsoleMessage ("seem to not have GL_MEDIUM_FLOAT or GL_HIGH_FLOAT");
#endif // GL_ES_VERSION_2_0 for GL_HIGH_FLOAT or GL_MEDIUM_FLOAT
#if defined (VERBOSE) && defined (GL_ES_VERSION_2_0)
{ /* debugging - only */
GLboolean b;
glGetBooleanv(GL_SHADER_COMPILER,&b);
if (b) ConsoleMessage("have shader compiler"); else ConsoleMessage("NO SHADER COMPILER");
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_LOW_FLOAT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_LOW_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_MEDIUM_FLOAT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_MEDIUM_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_HIGH_FLOAT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_HIGH_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_LOW_INT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_LOW_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_MEDIUM_INT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_MEDIUM_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_VERTEX_SHADER,GL_HIGH_INT, range, &precision);
ConsoleMessage ("GL_VERTEX_SHADER, GL_HIGH_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_LOW_FLOAT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_LOW_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_MEDIUM_FLOAT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_HIGH_FLOAT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_HIGH_FLOAT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_LOW_INT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_LOW_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_MEDIUM_INT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_MEDIUM_INT range [%d,%d],precision %d",range[0],range[1],precision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER,GL_HIGH_INT, range, &precision);
ConsoleMessage ("GL_FRAGMENT_SHADER, GL_HIGH_INT range [%d,%d],precision %d",range[0],range[1],precision);
}
#endif //VERBOSE for GL_ES_VERSION_2_0
#ifdef VERBOSE
if DESIRE(whichOne.base,NO_APPEARANCE_SHADER) ConsoleMessage ("want NO_APPEARANCE_SHADER");
if DESIRE(whichOne.base,MATERIAL_APPEARANCE_SHADER) ConsoleMessage ("want MATERIAL_APPEARANCE_SHADER");
if DESIRE(whichOne.base,TWO_MATERIAL_APPEARANCE_SHADER) ConsoleMessage ("want TWO_MATERIAL_APPEARANCE_SHADER");
if DESIRE(whichOne.base,ONE_TEX_APPEARANCE_SHADER)ConsoleMessage("want ONE_TEX_APPEARANCE_SHADER");
if DESIRE(whichOne.base,MULTI_TEX_APPEARANCE_SHADER)ConsoleMessage("want MULTI_TEX_APPEARANCE_SHADER");
if DESIRE(whichOne.base,COLOUR_MATERIAL_SHADER)ConsoleMessage("want COLOUR_MATERIAL_SHADER");
if DESIRE(whichOne.base,FILL_PROPERTIES_SHADER)ConsoleMessage("want FILL_PROPERTIES_SHADER");
if DESIRE(whichOne.base,HAVE_LINEPOINTS_COLOR)ConsoleMessage ("want LINE_POINTS_COLOR");
if DESIRE(whichOne.base,HAVE_LINEPOINTS_APPEARANCE)ConsoleMessage ("want LINE_POINTS_APPEARANCE");
if DESIRE(whichOne.base,HAVE_TEXTURECOORDINATEGENERATOR) ConsoleMessage ("want HAVE_TEXTURECOORDINATEGENERATOR");
if DESIRE(whichOne.base,HAVE_CUBEMAP_TEXTURE) ConsoleMessage ("want HAVE_CUBEMAP_TEXTURE");
#endif //VERBOSE
#undef VERBOSE
/* Cross shader Fragment bits - GL_ES_VERSION_2_0 has this */
#if defined(GL_ES_VERSION_2_0)
fragmentSource[fragmentGLSLVersion] = "#version 100\n";
vertexSource[vertexGLSLVersion] = "#version 100\n";
if (haveHighPrecisionFragmentShaders) {
fragmentSource[fragmentPrecisionDeclare] = fragHighPrecision;
//ConsoleMessage("have high precision fragment shaders");
} else {
fragmentSource[fragmentPrecisionDeclare] = fragMediumPrecision;
//ConsoleMessage("have medium precision fragment shaders");
}
#ifdef VARY_VERTEX_PRECISION
// if we do lighting on the Vertex shader side, do we have to worry about precision?
if (haveHighPrecisionVertexShaders) {
vertexSource[vertexPrecisionDeclare] = fragHighPrecision;
ConsoleMessage("have high precision vertex shaders");
} else {
vertexSource[vertexPrecisionDeclare] = fragMediumPrecision;
ConsoleMessage("have medium precision vertex shaders");
}
#endif //VARY_VERTEX_PRECISION
#else
//changed from 120 to 110 Apr2014: main shaders still seem to work the same, openGL 2.0 now compiles them, and 2.1 (by specs) compiles 110
fragmentSource[fragmentGLSLVersion] = "#version 110\n";//"#version 120\n";
vertexSource[vertexGLSLVersion] = "#version 110\n"; //"#version 120\n";
#endif
fragmentSource[fragMaxLightsDeclare] = maxLights;
vertexSource[vertMaxLightsDeclare] = maxLights;
vertexSource[vertexPositionDeclare] = vertPosDec;
/* User defined shaders - only give the defines, let the user do the rest */
if (!whichOne.usershaders) { // & USER_DEFINED_SHADER_MASK) == 0) {
/* initialize */
/* Generic things first */
/* Cross shader Vertex bits */
vertexSource[vertexMainStart] = vertMainStart;
vertexSource[vertexPositionCalculation] = vertPos;
vertexSource[vertexMainEnd] = vertEnd;
fragmentSource[fragmentMainStart] = fragMainStart;
if(Viewer()->anaglyph || Viewer()->anaglyphB)
fragmentSource[fragmentMainEnd] = anaglyphGrayFragEnd;
else {
if (DESIRE(whichOne.base,SHADINGSTYLE_PHONG)) fragmentSource[fragmentMainEnd] = discardInFragEnd;
else fragmentSource[fragmentMainEnd] = fragEnd;
//fragmentSource[fragmentMainEnd] = discardInFragEnd;
}
//ConsoleMessage ("whichOne %x mask %x",whichOne,~whichOne);
/* specific strings for specific shader capabilities */
if DESIRE(whichOne.base,COLOUR_MATERIAL_SHADER) {
vertexSource[vertexSimpleColourDeclare] = vertSimColDec;
vertexSource[vertFrontColourDeclare] = varyingFrontColour;
vertexSource[vertexSimpleColourCalculation] = vertSimColUse;
vertexSource[vertexPointSizeDeclare] = pointSizeDeclare;
vertexSource[vertexPointSizeAssign] = pointSizeAss;
fragmentSource[fragmentSimpleColourDeclare] = varyingFrontColour;
fragmentSource[fragmentSimpleColourAssign] = fragSimColAss;
}
if DESIRE(whichOne.base,NO_APPEARANCE_SHADER) {
fragmentSource[fragmentSimpleColourAssign] = fragNoAppAss;
vertexSource[vertexPointSizeDeclare] = pointSizeDeclare;
vertexSource[vertexPointSizeAssign] = pointSizeAss;
}
/* One or TWO material no texture shaders - one material, choose between
Phong shading (slower) or Gouraud shading (faster). */
if (DESIRE(whichOne.base,SHADINGSTYLE_PHONG)) {
doThis = (DESIRE(whichOne.base,MATERIAL_APPEARANCE_SHADER)) ||
(DESIRE(whichOne.base,TWO_MATERIAL_APPEARANCE_SHADER));
} else {
doThis = DESIRE(whichOne.base,TWO_MATERIAL_APPEARANCE_SHADER);
}
if (doThis) {
vertexSource[vertexNormPosOutput] = varyingNormPos;
vertexSource[vertexNormalDeclare] = vertNormDec;
vertexSource[vertexNormPosCalculation] = vertNormPosCalc;
fragmentSource[fragmentLightDefines] = lightDefines0;
fragmentSource[fragmentOneColourDeclare] = vertOneMatDec;
fragmentSource[fragmentBackColourDeclare] = vertBackMatDec;
fragmentSource[fragmentNormPosDeclare] = varyingNormPos;
fragmentSource[fragmentADSLLightModel] = ADSLLightModel0;
fragmentSource[fragmentADSLAssign] = fragADSLAss;
}
/* TWO_MATERIAL_APPEARANCE_SHADER - this does not crop up
that often, so just use the PHONG shader. */
didADSLmaterial = false;
if((DESIRE(whichOne.base,MATERIAL_APPEARANCE_SHADER)) && (!DESIRE(whichOne.base,SHADINGSTYLE_PHONG))) {
vertexSource[vertexNormalDeclare] = vertNormDec;
vertexSource[vertexLightDefines] = lightDefines0;
vertexSource[vertexOneMaterialDeclare] = vertOneMatDec;
vertexSource[vertFrontColourDeclare] = varyingFrontColour;
vertexSource[vertexNormPosCalculation] = vertNormPosCalc;
vertexSource[vertexNormPosOutput] = vecNormPos;
vertexSource[vertexLightingEquation] = ADSLLightModel0;
vertexSource[vertexBackMaterialDeclare] = vertBackMatDec;
vertexSource[vertexADSLCalculation] = vertADSLCalc;
didADSLmaterial = true;
fragmentSource[fragmentOneColourDeclare] = varyingFrontColour;
fragmentSource[fragmentOneColourAssign] = fragFrontColAss;
vertexSource[vertexProjValDec] = vertProjValDec;
vertexSource[vertexProjCalTexCoord] = vertProjCalTexCoord;
vertexSource[vertexProjTexCalculation] = vertProjTexCalculation;
fragmentSource[fragmentTex0Declare] = fragTex0Dec;
fragmentSource[fragmentProjValDec] = fragProjValDec;
fragmentSource[fragmentProjCalTexCoord] = fragProjCalTexCoord;
fragmentSource[fragmentProjTexAssign] = fragProjTexCalculation;
}
if DESIRE(whichOne.base,HAVE_LINEPOINTS_APPEARANCE) {
vertexSource[vertexLightDefines] = lightDefines0;
vertexSource[vertFrontColourDeclare] = varyingFrontColour;
vertexSource[vertexOneMaterialDeclare] = vertOneMatDec;
#if defined (GL_ES_VERSION_2_0)
vertexSource[vertexPointSizeDeclare] = pointSizeDeclare;
vertexSource[vertexPointSizeAssign] = pointSizeAss;
#endif
vertexSource[vertexOneMaterialCalculation] = vertEmissionOnlyColourAss;
fragmentSource[fragmentSimpleColourDeclare] = varyingFrontColour;
fragmentSource[fragmentSimpleColourAssign] = fragSimColAss;
}
/* texturing - MULTI_TEX builds on ONE_TEX */
if (DESIRE(whichOne.base,ONE_TEX_APPEARANCE_SHADER) ||
DESIRE(whichOne.base,HAVE_TEXTURECOORDINATEGENERATOR) ||
DESIRE(whichOne.base,HAVE_CUBEMAP_TEXTURE) ||
DESIRE(whichOne.base,MULTI_TEX_APPEARANCE_SHADER)) {
ttglobal tg = gglobal();
vertexSource[vertexTexCoordInputDeclare] = vertTexCoordDec;
vertexSource[vertexTexCoordOutputDeclare] = varyingTexCoord;
vertexSource[vertexTextureMatrixDeclare] = vertTexMatrixDec;
vertexSource[vertexSingleTextureCalculation] = vertSingTexCalc;
if(didADSLmaterial)
vertexSource[vertexADSLCalculation] = vertADSLCalc0; //over-ride material diffuseColor with texture
fragmentSource[fragmentTexCoordDeclare] = varyingTexCoord;
fragmentSource[fragmentTex0Declare] = fragTex0Dec;
/*
//À̺κÐÀ» °Çµå¸®¸éµÊ
vertexSource[vertexProjValDec] = vertProjValDec;
vertexSource[vertexProjCalTexCoord] = vertProjCalTexCoord;
vertexSource[vertexProjTexCalculation] = vertProjTexCalculation;
fragmentSource[fragmentProjValDec] = fragProjValDec;
fragmentSource[fragmentProjCalTexCoord] = fragProjCalTexCoord;
//fragmentSource[fragmentProjTexAssign] = fragProjTexCalculation;
if(!tg->Component_PTM.ProjActive)
{
fragmentSource[fragmentTextureAssign] = fragSingTexAss;
}
else
{
fragmentSource[fragmentTextureAssign] = fragProjTexCalculation;
tg->Component_PTM.ProjActive = false;
}
*/
fragmentSource[fragmentTextureAssign] = fragSingTexAss;
}
/* Cubemaps - do not multi-texture these yet */
if (DESIRE(whichOne.base,HAVE_CUBEMAP_TEXTURE)) {
vertexSource[vertexSingleTextureCalculation] = vertSingTexCubeCalc;
fragmentSource[fragmentTex0Declare] = fragTex0CubeDec;
fragmentSource[fragmentTextureAssign] = fragSingTexCubeAss;
}
/* MULTI_TEX builds on ONE_TEX */
if DESIRE(whichOne.base,MULTI_TEX_APPEARANCE_SHADER) {
/* we have to do the material params, in case we need to
modulate/play with this. */
vertexSource[vertexOneMaterialDeclare] = vertOneMatDec;
vertexSource[vertexLightDefines] = lightDefines0;
vertexSource[vertexNormPosCalculation] = vertNormPosCalc;
vertexSource[vertexNormPosOutput] = vecNormPos;
vertexSource[vertexLightingEquation] = ADSLLightModel0;
vertexSource[vertexBackMaterialDeclare] = vertBackMatDec;
fragmentSource[fragmentMultiTexDefines]= fragMultiTexUniforms;
fragmentSource[fragmentMultiTexDeclare] = fragMultiTexDef;
fragmentSource[fragmentTex0Declare] = fragTex0Dec;
fragmentSource[fragmentMultiTexModel] = fragMulTexFunc;
fragmentSource[fragmentTextureAssign] = fragMulTexCalc;
//perspective multi texture
vertexSource[vertexMultiProjValDec] = vertMultiProjValDec;
vertexSource[vertexMultiProjCalTexCoord] = vertMultiProjCalTexCoord;
vertexSource[vertexMultiProjTexCalculation] = vertMultiProjTexCalculation;
fragmentSource[fragmentMultiProjValDec] = fragMultiProjValDec;
fragmentSource[fragmentMultiProjCalTexCoord] = fragMultiProjCalTexCoord;
//fragmentSource[fragmentTextureAssign] = fragMulTexCalc;
fragmentSource[fragmentTextureAssign] = fragMultiProjTexCalculation;
}
/* TextureCoordinateGenerator - do calcs in Vertex, fragment like one texture */
if DESIRE(whichOne.base,HAVE_TEXTURECOORDINATEGENERATOR) {
/* the vertex single texture calculation is different from normal single texture */
/* pass in the type of generator, and do the calculations */
vertexSource[vertexTextureMatrixDeclare] = vertTexCoordGenDec;
vertexSource[vertexSingleTextureCalculation] = sphEnvMapCalc;
vertexSource[vertexTCGTDefines] = fragTCGTDefs;
}
if DESIRE(whichOne.base,FILL_PROPERTIES_SHADER) {
/* just add on top of the other shaders the fill properties "stuff" */
vertexSource[vertexHatchPositionDeclare] = varyingHatchPosition;
vertexSource[vertexHatchPositionCalculation] = vertHatchPosCalc;
fragmentSource[fragmentFillPropDefines] = fillPropDefines;
fragmentSource[fragmentHatchPositionDeclare] = varyingHatchPosition;
fragmentSource[fragmentFillPropModel] = fragFillPropFunc;
fragmentSource[fragmentFillPropAssign] = fragFillPropCalc;
}
} else { // user defined shaders
if (whichOne.usershaders) { // >= USER_DEFINED_SHADER_START) {
int me = 0;
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
//me = (whichOne / USER_DEFINED_SHADER_START) -1;
me = whichOne.usershaders;
//ConsoleMessage ("HAVE USER DEFINED SHADER %x",whichOne);
// add the following:
// this has both Vertex manipulations, and lighting, etc.
// #define HEADLIGHT_LIGHT (MAX_LIGHTS-1)\n
vertexSource[vertexMainStart] = " \n \
#define HEADLIGHT_LIGHT 0\n \
#define ftransform() (fw_ProjectionMatrix*fw_ModelViewMatrix*fw_Vertex)\n \
#define gl_ModelViewProjectionMatrix (fw_ProjectionMatrix*fw_ModelViewMatrix)\n \
#define gl_NormalMatrix fw_NormalMatrix\n \
#define gl_ProjectionMatrix fw_ProjectionMatrix \n\
#define gl_ModelViewMatrix fw_ModelViewMatrix \n\
#define fw_TextureMatrix fw_TextureMatrix0 \n\
#define gl_TextureMatrix fw_TextureMatrix0 \n\
#define gl_Vertex fw_Vertex \n \
#define gl_Normal fw_Normal\n \
#define gl_Texture_unit0 fw_Texture_unit0\n \
#define gl_MultiTexCoord0 fw_MultiTexCoord0\n \
#define gl_Texture_unit1 fw_Texture_unit1\n \
#define gl_MultiTexCoord1 fw_MultiTexCoord1\n \
#define gl_Texture_unit2 fw_Texture_unit2\n \
#define gl_MultiTexCoord2 fw_MultiTexCoord2\n \
#define gl_LightSource fw_LightSource\n ";
// copy over the same defines, but for the fragment shader.
// Some GLSL compilers will complain about the "fttransform()"
// definition if defined in a Fragment shader, so we judiciously
// copy over things that are fragment-only.
// #define HEADLIGHT_LIGHT (MAX_LIGHTS-1)\n
fragmentSource[fragmentMainStart] = " \
#define HEADLIGHT_LIGHT 0\n \
#define gl_NormalMatrix fw_NormalMatrix\n \
#define gl_Normal fw_Normal\n \
#define gl_LightSource fw_LightSource\n ";
vertexSource[vertexLightDefines] = lightDefines0;
vertexSource[vertexSimpleColourDeclare] = vertSimColDec;
vertexSource[vertFrontColourDeclare] = varyingFrontColour;
vertexSource[vertexNormalDeclare] = vertNormDec;
fragmentSource[fragmentLightDefines] = lightDefines0;
//ConsoleMessage ("sources here for %d are %p and %p", me, p->userDefinedVertexShader[me], p->userDefinedFragmentShader[me]);
if ((p->userDefinedVertexShader[me] == NULL) || (p->userDefinedFragmentShader[me]==NULL)) {
ConsoleMessage ("no Shader Source found for user defined shaders...");
return false;
}
fragmentSource[fragmentUserDefinedInput] = p->userDefinedFragmentShader[me];
vertexSource[vertexUserDefinedInput] = p->userDefinedVertexShader[me];
}
}
//#define VERBOSE 1
#ifdef VERBOSE
/* print out the vertex source here */
{
vertexShaderResources_t x1;
fragmentShaderResources_t x2;
int i;
FILE* fp = fopen("C:/tmp/vertex_vc13.src","w+");
ConsoleMessage ("Vertex source:\n");
fprintf(fp,"Vertex source:\n");
for (x1=vertexGLSLVersion; x10){
ConsoleMessage("%s",vertexSource[x1]);
fprintf(fp,"%s",vertexSource[x1]);
}
}
ConsoleMessage("Fragment Source:\n");
fprintf(fp,"Fragment Source:\n");
i=0;
for (x2=fragmentGLSLVersion; x20){
ConsoleMessage("%s",fragmentSource[x2]);
fprintf(fp,"%s",fragmentSource[x2]);
}
}
fclose(fp);
}
#endif //VERBOSE
//#undef VERBOSE
return TRUE;
}
#undef VERBOSE
//see Composite_Shading.c for CastlePlugs details.
int getSpecificShaderSourceCastlePlugs (const GLchar **vertexSource, const GLchar **fragmentSource, shaderflagsstruct whichOne);
int getSpecificShaderSourceVolume (const GLchar **vertexSource, const GLchar **fragmentSource, shaderflagsstruct whichOne);
static int getSpecificShaderSource (const GLchar *vertexSource[vertexEndMarker], const GLchar *fragmentSource[fragmentEndMarker],
shaderflagsstruct whichOne) {
int iret, userDefined, usingCastlePlugs = 1;
userDefined = whichOne.usershaders ? TRUE : FALSE;
if(usingCastlePlugs && !userDefined) { // && !DESIRE(whichOne,SHADINGSTYLE_PHONG)) {
//new Aug 2016 castle plugs
if(whichOne.volume)
iret = getSpecificShaderSourceVolume(vertexSource, fragmentSource, whichOne);
else
iret = getSpecificShaderSourceCastlePlugs(vertexSource, fragmentSource, whichOne);
}else{
iret = getSpecificShaderSourceOriginal(vertexSource, fragmentSource, whichOne);
}
return iret;
}
static void makeAndCompileShader(struct shaderTableEntry *me) {
GLint success;
GLuint myVertexShader = 0;
GLuint myFragmentShader= 0;
GLuint myProg = 0;
s_shader_capabilities_t *myShader = me->myCapabilities;
const GLchar *vertexSource[vertexEndMarker];
const GLchar *fragmentSource[fragmentEndMarker];
vertexShaderResources_t x1;
fragmentShaderResources_t x2;
#ifdef VERBOSE
ConsoleMessage ("makeAndCompileShader called");
#endif //VERBOSE
#undef VERBOSE
/* initialize shader sources to blank strings, later we'll fill it in */
for (x1=vertexGLSLVersion; x1whichOne)) {
return;
}
myVertexShader = CREATE_SHADER (VERTEX_SHADER);
SHADER_SOURCE(myVertexShader, vertexEndMarker, ((const GLchar **)vertexSource), NULL);
COMPILE_SHADER(myVertexShader);
GET_SHADER_INFO(myVertexShader, COMPILE_STATUS, &success);
if (!success) {
shaderErrorLog(myVertexShader,"VERTEX");
} else {
ATTACH_SHADER(myProg, myVertexShader);
}
/* get Fragment shader */
myFragmentShader = CREATE_SHADER (FRAGMENT_SHADER);
SHADER_SOURCE(myFragmentShader, fragmentEndMarker, (const GLchar **) fragmentSource, NULL);
COMPILE_SHADER(myFragmentShader);
GET_SHADER_INFO(myFragmentShader, COMPILE_STATUS, &success);
if (!success) {
shaderErrorLog(myFragmentShader,"FRAGMENT");
} else {
ATTACH_SHADER(myProg, myFragmentShader);
}
LINK_SHADER(myProg);
glGetProgramiv(myProg,GL_LINK_STATUS, &success);
(*myShader).compiledOK = (success == GL_TRUE);
getShaderCommonInterfaces(myShader);
}
static void getShaderCommonInterfaces (s_shader_capabilities_t *me) {
ttglobal tg = gglobal();
GLuint myProg = me->myShaderProgram;
int i;
#ifdef SHADERVERBOSE
{
GLsizei count;
GLuint shaders[10];
GLint xxx[10];
int i;
GLchar sl[3000];
printf ("getShaderCommonInterfaces, I am program %d\n",myProg);
if (glIsProgram(myProg))
printf ("getShaderCommonInterfaces, %d is a program\n",myProg);
else
printf ("hmmm - it is not a program!\n");
glGetAttachedShaders(myProg,10,&count,shaders);
printf ("got %d attached shaders, they are: \n",count);
for (i=0; iprojTexGenMatCam0 = GET_UNIFORM(myProg,"projTexGenMatCam0");
//me->projViewMat = GET_UNIFORM(myProg,"projViewMat");
//me->projMap_forCam1 = GET_UNIFORM(myProg,"projMap_forCam1");
// projector 1:m texture_descriptor m:1 sampler2D
// max 8 1:m 16 m:1 4
for(int i=0;i<16;i++){
//per (projector related) sampler2D and shared with PBR
char line[32];
sprintf(line,"textureUnit[%d]",i);
me->textureUnit[i] = GET_UNIFORM(myProg,line);
}
for(int i=0;i<8;i++){
//per projector
char line[24];
sprintf(line,"projTexGenMatCam[%d]",i);
me->projTexGenMatCam[i] = GET_UNIFORM(myProg,line); //"projTexGenMatCam0"); //vertex shader matrix for projecting rays back to texture
sprintf(line,"pbackCull[%d]",i);
me->pbackCull[i] = GET_UNIFORM(myProg,line);
sprintf(line,"ntdesc[%d]",i);
me->ntdesc[i] = GET_UNIFORM(myProg,line);
}
for(int i=0;i<16;i++){
//per texture descriptor
char line[24];
sprintf(line,"tunits[%d]",i);
me->tunits[i] = GET_UNIFORM(myProg,line);
sprintf(line,"modes[%d]",i);
me->modes[i] = GET_UNIFORM(myProg,line);
sprintf(line,"sources[%d]",i);
me->sources[i] = GET_UNIFORM(myProg,line);
sprintf(line,"funcs[%d]",i);
me->funcs[i] = GET_UNIFORM(myProg,line);
}
me->pCount = GET_UNIFORM(myProg,"pCount");
/*
tg->Component_PTM._projTexGenMatCam0_Location = GET_UNIFORM(myProg,"projTexGenMatCam0"); //vertex shader matrix for projecting rays back to texture
tg->Component_PTM._projViewMat_Location = GET_UNIFORM(myProg,"projViewMat");
tg->Component_PTM._projMap_forCam1_Location = GET_UNIFORM(myProg,"projMap_forCam1");
tg->Component_PTM._MultiprojTexGenMatCam_Location[0] = GET_UNIFORM(myProg,"MultiprojTexGenMatCam1");
tg->Component_PTM._MultiprojTexGenMatCam_Location[1] = GET_UNIFORM(myProg,"MultiprojTexGenMatCam2");
tg->Component_PTM._MultiprojTexGenMatCam_Location[2] = GET_UNIFORM(myProg,"MultiprojTexGenMatCam3");
tg->Component_PTM._MultiprojTexGenMatCam_Location[3] = GET_UNIFORM(myProg,"MultiprojTexGenMatCam4");
*/
me->myMaterialDiffuse = GET_UNIFORM(myProg,"fw_FrontMaterial.diffuse");
me->myMaterialEmissive = GET_UNIFORM(myProg,"fw_FrontMaterial.emissive");
me->myMaterialSpecular = GET_UNIFORM(myProg,"fw_FrontMaterial.specular");
me->myMaterialAmbient = GET_UNIFORM(myProg,"fw_FrontMaterial.ambient");
me->myMaterialShininess = GET_UNIFORM(myProg,"fw_FrontMaterial.shininess");
me->myMaterialTransparency = GET_UNIFORM(myProg,"fw_FrontMaterial.transparency");
me->myMaterialBaseColor = GET_UNIFORM(myProg,"fw_FrontMaterial.baseColor");
me->myMaterialMetallic = GET_UNIFORM(myProg,"fw_FrontMaterial.metallic");
me->myMaterialRoughness = GET_UNIFORM(myProg,"fw_FrontMaterial.roughness");
me->myMaterialType = GET_UNIFORM(myProg,"fw_FrontMaterial.type");
me->myMaterialTransdex = GET_UNIFORM(myProg,"fw_FrontMaterial.transdex");
me->myMaterialNt = GET_UNIFORM(myProg,"fw_FrontMaterial.nt");
for(int i=0;i<10;i++){
char line[200];
sprintf(line,"fw_FrontMaterial.tindex[%d]",i);
me->myMaterialTindex[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_FrontMaterial.mode[%d]",i);
me->myMaterialMode[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_FrontMaterial.source[%d]",i);
me->myMaterialSource[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_FrontMaterial.func[%d]",i);
me->myMaterialFunc[i] = GET_UNIFORM(myProg,line);
}
for(int i=0;i<5;i++){
char line[200];
sprintf(line,"fw_FrontMaterial.cindex[%d]",i);
me->myMaterialCindex[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_FrontMaterial.tstart[%d]",i);
me->myMaterialTstart[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_FrontMaterial.tcount[%d]",i);
me->myMaterialTcount[i] = GET_UNIFORM(myProg,line);
}
me->myMaterialBackDiffuse = GET_UNIFORM(myProg,"fw_BackMaterial.diffuse");
me->myMaterialBackEmissive = GET_UNIFORM(myProg,"fw_BackMaterial.emissive");
me->myMaterialBackSpecular = GET_UNIFORM(myProg,"fw_BackMaterial.specular");
me->myMaterialBackAmbient = GET_UNIFORM(myProg,"fw_BackMaterial.ambient");
me->myMaterialBackShininess = GET_UNIFORM(myProg,"fw_BackMaterial.shininess");
me->myMaterialBackTransparency = GET_UNIFORM(myProg,"fw_BackMaterial.transparency");
me->myMaterialBackBaseColor = GET_UNIFORM(myProg,"fw_BaclMaterial.baseColor");
me->myMaterialBackMetallic = GET_UNIFORM(myProg,"fw_BackMaterial.metallic");
me->myMaterialBackRoughness = GET_UNIFORM(myProg,"fw_BackMaterial.roughness");
me->myMaterialBackType = GET_UNIFORM(myProg,"fw_BackMaterial.type");
me->myMaterialBackTransdex = GET_UNIFORM(myProg,"fw_BackMaterial.transdex");
me->myMaterialBackNt = GET_UNIFORM(myProg,"fw_BackMaterial.nt");
for(int i=0;i<10;i++){
char line[200];
sprintf(line,"fw_BackMaterial.tindex[%d]",i);
me->myMaterialBackTindex[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_BackMaterial.mode[%d]",i);
me->myMaterialBackMode[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_BackMaterial.source[%d]",i);
me->myMaterialBackSource[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_BackMaterial.func[%d]",i);
me->myMaterialBackFunc[i] = GET_UNIFORM(myProg,line);
}
for(int i=0;i<5;i++){
char line[200];
sprintf(line,"fw_BackMaterial.cindex[%d]",i);
me->myMaterialBackCindex[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_BackMaterial.tstart[%d]",i);
me->myMaterialBackTstart[i] = GET_UNIFORM(myProg,line);
sprintf(line,"fw_BackMaterial.tcount[%d]",i);
me->myMaterialBackTcount[i] = GET_UNIFORM(myProg,line);
}
//me->lightState = GET_UNIFORM(myProg,"lightState");
//me->lightType = GET_UNIFORM(myProg,"lightType");
//me->lightRadius = GET_UNIFORM(myProg,"lightRadius");
me->lightcount = GET_UNIFORM(myProg,"lightcount");
/* get lights in a more normal OpenGL GLSL format */
/*
struct gl_LightSourceParameters
{
vec4 ambient; // Aclarri
vec4 diffuse; // Dcli
vec4 specular; // Scli
vec4 position; // Ppli
vec4 halfVector; // Derived: Hi
vec4 spotDirection; // Sdli
float spotExponent; // Srli
float spotCutoff; // Crli
float spotCosCutoff; // Derived: cos(Crli)
vec3 Attenuations (const,lin,quad)
//float constantAttenuation; // K0
//float linearAttenuation; // K1
//float quadraticAttenuation;// K2
float lightRadius;
int lightType;
};
uniform gl_LightSourceParameters gl_LightSource[gl_MaxLights];
*/
{
//using lighsource arrays - see shader
char uniformName[100];
me->haveLightInShader = false;
#ifdef USING_SHADER_LIGHT_ARRAY_METHOD
//char* sndx;
for (i = 0; ilightAmbient[i] = GET_UNIFORM(myProg, uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightAmbient[i]);
strcpy(uniformName, "lightdiffuse[0]");
sndx = strstr(uniformName, "[");
sndx[1] = '0' + i;
me->lightDiffuse[i] = GET_UNIFORM(myProg, uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightDiffuse[i]);
strcpy(uniformName, "lightspecular[0]");
sndx = strstr(uniformName, "[");
sndx[1] = '0' + i;
me->lightSpecular[i] = GET_UNIFORM(myProg, uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightSpecular[i]);
strcpy(uniformName, "lightposition[0]");
sndx = strstr(uniformName, "[");
sndx[1] = '0' + i;
me->lightPosition[i] = GET_UNIFORM(myProg, uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightPosition[i]);
// flag used to determine if we have to send light position info to this shader
if (me->lightPosition[i] != -1) me->haveLightInShader = true;
strcpy(uniformName, "lightspotDirection[0]");
sndx = strstr(uniformName, "[");
sndx[1] = '0' + i;
me->lightSpotDir[i] = GET_UNIFORM(myProg, uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightSpotDir[i]);
strcpy(uniformName, "lightspotExponent[0]");
sndx = strstr(uniformName, "[");
sndx[1] = '0' + i;
me->lightSpotBeamWidth[i] = GET_UNIFORM(myProg, uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightSpotBeamWidth[i]);
strcpy(uniformName, "lightspotCutoff[0]");
sndx = strstr(uniformName, "[");
sndx[1] = '0' + i;
me->lightSpotCutoffAngle[i] = GET_UNIFORM(myProg, uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightSpotCutoffAngle[i]);
strcpy(uniformName, "lightAttenuations[0]");
sndx = strstr(uniformName, "[");
sndx[1] = '0' + i;
me->lightAtten[i] = GET_UNIFORM(myProg, uniformName);
strcpy(uniformName, "lightRadius[0]");
sndx = strstr(uniformName, "[");
sndx[1] = '0' + i;
me->lightRadius[i] = GET_UNIFORM(myProg, uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightQuadAtten[i]);
}
#else //USING_SHADER_LIGHT_ARRAY_METHOD
strcpy(uniformName,"fw_LightSource[0].");
for (i=0; ilightAmbientIntensity[i] = GET_UNIFORM(myProg,uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightAmbient[i]);
strcpy(&uniformName[18],"color");
me->lightColor[i] = GET_UNIFORM(myProg,uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightDiffuse[i]);
strcpy(&uniformName[18],"intensity");
me->lightIntensity[i] = GET_UNIFORM(myProg,uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightSpecular[i]);
strcpy(&uniformName[18],"location");
me->lightLocation[i] = GET_UNIFORM(myProg,uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightPosition[i]);
// flag used to determine if we have to send light position info to this shader
if (me->lightLocation[i] != -1) me->haveLightInShader = true;
strcpy(&uniformName[18],"direction");
me->lightDirection[i] = GET_UNIFORM(myProg,uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightSpotDir[i]);
//strcpy(&uniformName[18],"spotExponent");
strcpy(&uniformName[18],"spotBeamWidth");
me->lightSpotBeamWidth[i] = GET_UNIFORM(myProg,uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightSpotBeamWidth[i]);
strcpy(&uniformName[18],"spotCutoff");
me->lightSpotCutoffAngle[i] = GET_UNIFORM(myProg,uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightSpotCutoffAngle[i]);
strcpy(&uniformName[18],"Attenuations");
me->lightAtten[i] = GET_UNIFORM(myProg,uniformName);
//strcpy(&uniformName[18],"constantAttenuation");
//me->lightConstAtten[i] = GET_UNIFORM(myProg,uniformName);
////ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightConstAtten[i]);
//
//strcpy(&uniformName[18],"linearAttenuation");
//me->lightLinAtten[i] = GET_UNIFORM(myProg,uniformName);
////ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightLinAtten[i]);
//
//strcpy(&uniformName[18],"quadraticAttenuation");
//me->lightQuadAtten[i] = GET_UNIFORM(myProg,uniformName);
////ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightQuadAtten[i]);
strcpy(&uniformName[18],"lightRadius");
me->lightRadius[i] = GET_UNIFORM(myProg,uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightQuadAtten[i]);
//strcpy(&uniformName[18],"lightType");
//me->lightType[i] = GET_UNIFORM(myProg,uniformName);
//ConsoleMessage ("light Uniform test for %d is %s, %d",i,uniformName,me->lightQuadAtten[i]);
}
#endif // USING_SHADER_LIGHT_ARRAY_METHOD
strcpy(uniformName,"lightType[0]");
for (i = 0; i < MAX_LIGHTS; i++) {
/* go through and modify the array for each variable */
uniformName[10] = '0' + i;
me->lightType[i] = GET_UNIFORM(myProg, uniformName);
}
}
//if (me->haveLightInShader) ConsoleMessage ("this shader HAS lightfields");
me->ModelViewMatrix = GET_UNIFORM(myProg,"fw_ModelViewMatrix");
me->ProjectionMatrix = GET_UNIFORM(myProg,"fw_ProjectionMatrix");
me->NormalMatrix = GET_UNIFORM(myProg,"fw_NormalMatrix");
me->ModelViewInverseMatrix = GET_UNIFORM(myProg,"fw_ModelViewInverseMatrix");
//for (i=0; iTextureMatrix[0] = GET_UNIFORM(myProg,"fw_TextureMatrix[0]");
me->TextureMatrix[1] = GET_UNIFORM(myProg,"fw_TextureMatrix[1]");
me->TextureMatrix[2] = GET_UNIFORM(myProg,"fw_TextureMatrix[2]");
me->TextureMatrix[3] = GET_UNIFORM(myProg,"fw_TextureMatrix[3]");
me->nTexMatrix = GET_UNIFORM(myProg,"nTexMatrix");
me->Vertices = GET_ATTRIB(myProg,"fw_Vertex");
me->Normals = GET_ATTRIB(myProg,"fw_Normal");
me->Colours = GET_ATTRIB(myProg,"fw_Color");
me->FogCoords = GET_ATTRIB(myProg,"fw_FogCoords");
//for (i=0; iTexCoords[0] = GET_ATTRIB(myProg,"fw_MultiTexCoord0");
me->TexCoords[1] = GET_ATTRIB(myProg,"fw_MultiTexCoord1");
me->TexCoords[2] = GET_ATTRIB(myProg,"fw_MultiTexCoord2");
me->TexCoords[3] = GET_ATTRIB(myProg,"fw_MultiTexCoord3");
me->nTexCoordChannels = GET_UNIFORM(myProg,"nTexCoordChannels");
for (i=0; iTextureUnit[i]= GET_UNIFORM(myProg,line);
sprintf (line,"fw_Texture_mode%d",i);
me->TextureMode[i] = GET_UNIFORM(myProg,line);
sprintf (line,"fw_Texture_source%d",i);
me->TextureSource[i] = GET_UNIFORM(myProg,line);
sprintf (line,"fw_Texture_function%d",i);
me->TextureFunction[i] = GET_UNIFORM(myProg,line);
//printf (" i %d tu %d mode %d\n",i,me->TextureUnit[i],me->TextureMode[i]);
}
me->textureCount = GET_UNIFORM(myProg,"textureCount");
me->multitextureColor = GET_UNIFORM(myProg,"mt_Color");
//printf ("GETUNIFORM for textureCount is %d\n",me->textureCount);
//texture3D
me->tex3dTiles = GET_UNIFORM(myProg,"tex3dTiles");
me->tex3dUseVertex = GET_UNIFORM(myProg,"tex3dUseVertex");
me->magFilter = GET_UNIFORM(myProg,"magFilter");
me->repeatSTR = GET_UNIFORM(myProg,"repeatSTR");
/* for FillProperties */
me->myPointSize = GET_UNIFORM(myProg, "pointSize");
me->hatchColour = GET_UNIFORM(myProg,"HatchColour");
me->hatchPercent = GET_UNIFORM(myProg,"HatchPct");
me->hatchScale = GET_UNIFORM(myProg,"HatchScale");
me->filledBool = GET_UNIFORM(myProg,"filled");
me->hatchedBool = GET_UNIFORM(myProg,"hatched");
me->algorithm = GET_UNIFORM(myProg,"algorithm");
me->fogColor = GET_UNIFORM(myProg,"fw_fogparams.fogColor");
me->fogvisibilityRange = GET_UNIFORM(myProg,"fw_fogparams.visibilityRange");
me->fogScale = GET_UNIFORM(myProg,"fw_fogparams.fogScale");
me->fogType = GET_UNIFORM(myProg,"fw_fogparams.fogType");
/* clipplane */
me->clipplanes = GET_UNIFORM(myProg,"fw_clipplanes");
me->nclipplanes = GET_UNIFORM(myProg,"fw_nclipplanes");
/* TextureCoordinateGenerator */
me->texCoordGenType = GET_UNIFORM(myProg,"fw_textureCoordGenType");
#ifdef VERBOSE
printf ("shader uniforms: vertex %d normal %d modelview %d projection %d\n",
me->Vertices, me->Normals, me->ModelViewMatrix, me->ProjectionMatrix);
printf ("hatchColour %d, hatchPercent %d",me->hatchColour, me->hatchPercent);
#endif
}
void calculateViewingSpeed(X3D_Viewer *);
static void handle_GeoLODRange(struct X3D_GeoLOD *node) {
int oldInRange;
X3D_Viewer *viewer;
GLDOUBLE cx,cy,cz;
/* find the length of the line between the moved center and our current viewer position */
viewer = Viewer();
getCurrentPosInModelB();
//calculateViewingSpeedB(viewer);
cx = viewer->currentPosInModel.x - node->__movedCoords.c[0];
cy = viewer->currentPosInModel.y - node->__movedCoords.c[1];
cz = viewer->currentPosInModel.z - node->__movedCoords.c[2];
//printf ("geoLOD, distance between me and center is %lf\n", sqrt (cx*cx + cy*cy + cz*cz));
/* try to see if we are closer than the range */
oldInRange = node->__inRange;
/* handle squares, as it is faster than doing square roots */
if((cx*cx+cy*cy+cz*cz) > (node->range * node->range)) {
node->__inRange = FALSE;
} else {
node->__inRange = TRUE;
}
if (oldInRange != node->__inRange) {
#ifdef VERBOSE
if (node->__inRange) printf ("TRUE: "); else printf ("FALSE: ");
printf ("range changed; level %d, comparing %lf:%lf:%lf and range %lf node %u\n",
node->__level, cx,cy,cz, node->range, node);
#endif
/* initialize the "children" field, if required */
if (node->children.p == NULL) node->children.p=MALLOC(struct X3D_Node **,sizeof(struct X3D_Node *) * 4);
if (node->__inRange == TRUE) {
#ifdef VERBOSE
printf ("GeoLOD %u level %d, inRange set to FALSE, range %lf\n",node, node->__level, node->range);
#endif
node->level_changed = 1;
node->children.p[0] = node->__child1Node;
node->children.p[1] = node->__child2Node;
node->children.p[2] = node->__child3Node;
node->children.p[3] = node->__child4Node;
node->children.n = 4;
} else {
#ifdef VERBOSE
printf ("GeoLOD %u level %d, inRange set to TRUE range %lf\n",node, node->__level, node->range);
#endif
node->level_changed = 0;
node->children.n = 0;
if( node->__rootUrl )
{
node->children.p[0] = node->__rootUrl;
node->children.n = 1;
}
else if( node->rootNode.p && node->rootNode.p[0] )
{
node->children.p[0] = node->rootNode.p[0];
node->children.n = 1;
}
}
MARK_EVENT(X3D_NODE(node), offsetof (struct X3D_GeoLOD, level_changed));
MARK_EVENT(X3D_NODE(node), offsetof (struct X3D_GeoLOD, children));
oldInRange = X3D_GEOLOD(node)->__inRange;
/* lets work out extent here */
INITIALIZE_EXTENT;
/* printf ("geolod range changed, initialized extent, czyzsq %4.2f rangesw %4.2f from %4.2f %4.2f %4.2f\n",
cx*cx+cy*cy+cz*cz,node->range*node->range,cx,cy,cz); */
update_node(X3D_NODE(node));
}
}
#ifdef DEBUGGING_CODE
/* draw a simple bounding box around an object */
void drawBBOX(struct X3D_Node *node) {
/* debugging */ FW_GL_COLOR3F((float)1.0,(float)0.6,(float)0.6);
/* debugging */
/* debugging */ /* left group */
/* debugging */ glBegin(GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MIN_Y, node->EXTENT_MIN_Z);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MIN_Y, node->EXTENT_MAX_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MIN_Y, node->EXTENT_MIN_Z);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MAX_Y, node->EXTENT_MIN_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MAX_Y, node->EXTENT_MIN_Z);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MAX_Y, node->EXTENT_MAX_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MIN_Y, node->EXTENT_MAX_Z);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MAX_Y, node->EXTENT_MAX_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ /* right group */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MIN_Y, node->EXTENT_MIN_Z);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MIN_Y, node->EXTENT_MAX_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MIN_Y, node->EXTENT_MIN_Z);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MAX_Y, node->EXTENT_MIN_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MAX_Y, node->EXTENT_MIN_Z);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MAX_Y, node->EXTENT_MAX_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MIN_Y, node->EXTENT_MAX_Z);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MAX_Y, node->EXTENT_MAX_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ /* joiners */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MIN_Y, node->EXTENT_MIN_Z);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MIN_Y, node->EXTENT_MIN_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MIN_Y, node->EXTENT_MAX_Z);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MIN_Y, node->EXTENT_MAX_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MAX_Y, node->EXTENT_MIN_Z);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MAX_Y, node->EXTENT_MIN_Z);
/* debugging */ glEnd();
/* debugging */
/* debugging */ glBegin (GL_LINES);
/* debugging */ glVertex3d(node->EXTENT_MIN_X, node->EXTENT_MAX_Y, node->EXTENT_MAX_Z);
/* debugging */ glVertex3d(node->EXTENT_MAX_X, node->EXTENT_MAX_Y, node->EXTENT_MAX_Z);
/* debugging */ glEnd();
}
#endif //DEBUGGING_CODE
struct depth_slice {
double znear, zfar;
};
static struct depth_slice depth_slices_three [] = {
{1.e-1, 1.01e3},
{1.e3, 1.01e7 },
{1.e7, 1.01e11},
};
static struct depth_slice depth_slices_two [] = {
{1.e-1, 1.05e4},
{1.e4, 1.0e9 },
};
static struct depth_slice depth_slices_one [] = {
{.07, 21000.0},
};
static int n_depth_slices = 1; //should be in gglobal
static int want_depth_slices = 0; //0=auto 1=1 2=2 3=3
int iclamp(int ival, int istart, int iend);
void fwl_set_depth_slices(int nslices){
want_depth_slices = iclamp(nslices,0,3);
//printf("want slices=%d %d\n",nslices,want_depth_slices);
}
int fwl_get_depth_slices(){
return want_depth_slices;
}
static void calculateNearFarplanes(struct X3D_Node *vpnode, int layerid ){
// This Feb 3, 2018 method depth slicing method is great for working on geospatial
// - you can just do 2 or 3 depth slices and benefits:
// * get a great range from .1 to 1B m or 100B m.
// * keep depth range stable (no flutter due to nearplane-changing side-effects when yawing toward planet)
// * reduces z-fighting (same bits, but over shorter ranges)
// * portable - uses normal opengl 2.1, fancy stuff is our code
// * works the same on non-geo and geo scenes / viewpionts
// x Slows frame rate 30%? -like stereo does, an extra loop or 2 on the draw,
//- 1slice .07 - 21000 - our familiar old range, one loop, no performance hit
//- 2slice: .1 - 1B - Mars can disappear while still multiple (~5) pixels wide
//- 3slice: .1 - 100B - Mars still visible as sub-pixel on horizon
// haven't tried other ideas, such as rendering to a float32 fbo, with reversed z:
// https://developer.nvidia.com/content/depth-precision-visualized
// due to it being less portable
float extent6[6];
int previous_n, iwant;
struct X3D_Node* rn;
static int once = 0;
X3D_Viewer *viewer = ViewerByLayerId(layerid);
viewer->nearPlane = DEFAULT_NEARPLANE;
viewer->farPlane = DEFAULT_FARPLANE;
iwant = fwl_get_depth_slices();
previous_n = n_depth_slices;
if(iwant == 0) //auto
{
n_depth_slices = 1;
//regular non-geo scene, or geo scene with non-geo vp
rn = rootNode();
if(rn) {
//include vp current location in scene diameter
// for Mars.x3d, as you navigate away, when its about 4 pixels wide,
// slices change from 2 to 3 so it goes to a point on the horizon
float scene_diameter;
double MM[16];
float vpf[3];
FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, MM);
//Q. is nearPlane farPlane used in setup_viewpoint in root space or vp space?
//H: vp space - its opengl and opengl doesn't know about 'scene root space'
//compute scene diameter in vp space
// seems to work with
// a) regular scene (townsite 1,2,3 as move away, and back)
// b) geo scenes (mars 2-3 on horizon and back) world33 (2-3 on horizon)
// and no flutter when yawing viewpoint toward/away from planet
// only cost: an extra 1 or 2 draw loops on 'big' scenes, slower frame rate
extent6f_copy(extent6,rn->_extent);
extent6f_mattransform4d(extent6,extent6,MM);
//include currently bound viewpoint in scene_diameter
vecset3f(vpf,0.0f,0.0f,0.0f);
extent6f_union_vec3f(extent6,vpf);
scene_diameter = extent6f_get_maxradius(extent6) * 2.0;
if(scene_diameter > 21000.0f ) n_depth_slices = 2;
if(scene_diameter > 1.e9 ) n_depth_slices = 3;
}
}else{
n_depth_slices = want_depth_slices;
}
if(0) if(!once || previous_n != n_depth_slices)
ConsoleMessage("depth slices: %d \n",n_depth_slices);
once = 1;
}
void calculateViewingDistIfJustBound(struct X3D_Node *vpnode, int layerid ){
if(Viewer()->doExamineModeDistanceCalculations){
float extent6[6];
struct X3D_Node* rn;
rn = rootNode();
if(rn) {
float scene_diameter, vpradius;
double MM[16];
float vpf[3], center[3], vpoffset[3];
FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, MM);
//Q. is nearPlane farPlane used in setup_viewpoint in root space or vp space?
//H: vp space - its opengl and opengl doesn't know about 'scene root space'
//compute scene diameter in vp space
// seems to work with
// a) regular scene (townsite 1,2,3 as move away, and back)
// b) geo scenes (mars 2-3 on horizon and back) world33 (2-3 on horizon)
// and no flutter when yawing viewpoint toward/away from planet
// only cost: an extra 1 or 2 draw loops on 'big' scenes, slower frame rate
extent6f_copy(extent6,rn->_extent);
extent6f_mattransform4d(extent6,extent6,MM);
//include currently bound viewpoint in scene_diameter
vecset3f(vpf,0.0f,0.0f,0.0f);
extent6f_get_center3f(extent6,center);
//extent6f_union_vec3f(extent6,vpf);
vecdif3f(vpoffset,center,vpf);
scene_diameter = extent6f_get_maxradius(extent6) * 2.0;
vpradius = veclength3f(vpoffset);
//printf("scene_diameter %f vpradius %f\n",scene_diameter,vpradius);
Viewer()->Dist = vpradius; // + scene_diameter;
//Viewer()->Dist = scene_diameter;
Viewer()->doExamineModeDistanceCalculations = FALSE;
}
}
}
int get_n_depth_slices(){
return n_depth_slices;
}
void get_depth_slice(int islice, double *znear, double *zfar){
switch(n_depth_slices){
default:
case 1:
*znear = depth_slices_one[islice].znear;
*zfar = depth_slices_one[islice].zfar;
break;
case 2:
*znear = depth_slices_two[1-islice].znear;
*zfar = depth_slices_two[1-islice].zfar;
break;
case 3:
*znear = depth_slices_three[2-islice].znear;
*zfar = depth_slices_three[2-islice].zfar;
break;
}
//printf("%d %lf %lf\n",islice,*znear,*zfar);
}
static void calculateNearFarplanes_OLD(struct X3D_Node *vpnode, int layerid ) {
/*
in theory, you get the bounding box of your scene, and transform that into camera space of bound viewpoint
(that's in the camera coordinate system, before projection, with z coming toward the camera, at world scale)
and take the near and far of that box to help decide on a near/far range
to help get the most out of your zbuffer range.
- some or all of bbox might be behind the camera, in that case near should be some +ve default
- the far might be closer than near or behind the bbox - in that case far should be some default
- stabilizing near far so it doesn't flutter frame to frame, if that's a problem
- computing near/far separately for each Layer (each layer has a different binding stack / active viewpoint / scenery)
challenge scenes:
geo: mars http://www.web3d.org/x3d/content/examples/Basic/Geospatial/Mars.x3d
- enormous range, do the faces on the planet z-sort right
- (Oct 1 2017 problem with online mars: mixes x3d v3.3 and degrees with no units specified)
geo: world http://www.web3d.org/x3d/content/examples/Basic/Geospatial/World.x3d
- big range, do the menu boxes show (have been cropping, use Dist menu button)
*/
struct point_XYZ bboxPoints[8];
GLDOUBLE cfp = -DBL_MAX;
GLDOUBLE cnp = DBL_MAX;
GLDOUBLE MM[16];
bool doingGeoSpatial = false;
double bboxMovedCentreZ = 0.0;
double bboxSphereRadius = 0.0;
#ifdef VERBOSE
int smooger = 0;
#endif
int ci;
struct X3D_Node* rn = rootNode();
ttglobal tg = gglobal();
X3D_Viewer *viewer = ViewerByLayerId(layerid);
#ifdef VERBOSE
if (smooger == 0) {
printf ("have a bound viewpoint... lets calculate our near/far planes from it \n");
printf ("we are currently at %4.2f %4.2f %4.2f\n",Viewer()->currentPosInModel.x, Viewer()->currentPosInModel.y, Viewer()->currentPosInModel.z);
}
#endif
/* verify parameters here */
if ((vpnode->_nodeType != NODE_Viewpoint) &&
(vpnode->_nodeType != NODE_OrthoViewpoint) &&
(vpnode->_nodeType != NODE_GeoViewpoint)) {
printf ("can not do this node type yet %s, for cpf\n",stringNodeType(vpnode->_nodeType));
viewer->nearPlane = DEFAULT_NEARPLANE;
viewer->farPlane = DEFAULT_FARPLANE;
viewer->backgroundPlane = DEFAULT_BACKGROUNDPLANE;
return;
}
if (vpnode->_nodeType == NODE_GeoViewpoint) {
doingGeoSpatial = true;
}
if(0){
//stabilizes for ortho, viewpoint and geoviewpoint
viewer->nearPlane = DEFAULT_NEARPLANE;
viewer->farPlane = DEFAULT_FARPLANE;
viewer->backgroundPlane = DEFAULT_BACKGROUNDPLANE;
if(doingGeoSpatial){
viewer->nearPlane = 10000.0;
viewer->farPlane = 2100000000.0;
viewer->backgroundPlane = 2000000000.0;
}
return;
}
if (rn == NULL) {
return; /* nothing to display yet */
}
/* if doing GeoSpatial, use radius to view model, rather than a rotated bounding box */
if (doingGeoSpatial) {
if ((rn->EXTENT_MAX_X - rn->EXTENT_MIN_X) > bboxSphereRadius) {
bboxSphereRadius = rn->EXTENT_MAX_X - rn->EXTENT_MIN_X;
}
if ((rn->EXTENT_MAX_Y - rn->EXTENT_MIN_Y) > bboxSphereRadius) {
bboxSphereRadius = rn->EXTENT_MAX_Y - rn->EXTENT_MIN_Y;
}
if ((rn->EXTENT_MAX_Z - rn->EXTENT_MIN_Z) > bboxSphereRadius) {
bboxSphereRadius = rn->EXTENT_MAX_Z - rn->EXTENT_MIN_Z;
}
bboxSphereRadius /=2.0; // diameter to radius
#ifdef VERBOSE
if (smooger == 0) {
ConsoleMessage ("bboxSphereRadius %lf",bboxSphereRadius);
}
#endif
}
FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, MM);
#ifdef VERBOSE
printf ("rootNode extents x: %4.2f %4.2f y:%4.2f %4.2f z: %4.2f %4.2f\n",rootNode()->EXTENT_MAX_X, rootNode()->EXTENT_MIN_X,rootNode()->EXTENT_MAX_Y, rootNode()->EXTENT_MIN_Y,rootNode()->EXTENT_MAX_Z, rootNode()->EXTENT_MIN_Z);
#endif
/* make up 8 vertices for our bounding box, and place them within our view */
moveAndRotateThisPoint(&bboxPoints[0], rn->EXTENT_MIN_X, rn->EXTENT_MIN_Y, rn->EXTENT_MIN_Z,MM);
moveAndRotateThisPoint(&bboxPoints[1], rn->EXTENT_MIN_X, rn->EXTENT_MIN_Y, rn->EXTENT_MAX_Z,MM);
moveAndRotateThisPoint(&bboxPoints[2], rn->EXTENT_MIN_X, rn->EXTENT_MAX_Y, rn->EXTENT_MIN_Z,MM);
moveAndRotateThisPoint(&bboxPoints[3], rn->EXTENT_MIN_X, rn->EXTENT_MAX_Y, rn->EXTENT_MAX_Z,MM);
moveAndRotateThisPoint(&bboxPoints[4], rn->EXTENT_MAX_X, rn->EXTENT_MIN_Y, rn->EXTENT_MIN_Z,MM);
moveAndRotateThisPoint(&bboxPoints[5], rn->EXTENT_MAX_X, rn->EXTENT_MIN_Y, rn->EXTENT_MAX_Z,MM);
moveAndRotateThisPoint(&bboxPoints[6], rn->EXTENT_MAX_X, rn->EXTENT_MAX_Y, rn->EXTENT_MIN_Z,MM);
moveAndRotateThisPoint(&bboxPoints[7], rn->EXTENT_MAX_X, rn->EXTENT_MAX_Y, rn->EXTENT_MAX_Z,MM);
if(0){
//verifier: alternate cfp,cnp calc, to check, set once
static int done_once = 0;
if(done_once) return;
double bmin, bmax;
bmin = bmax = bboxPoints[0].z;
for (ci=0; ci<8; ci++) {
bmin = min(bmin,bboxPoints[ci].z);
bmax = max(bmax,bboxPoints[ci].z);
}
viewer->nearPlane = max(.1,bmin); //bmax;
viewer->farPlane = bmax; //bmin;
//viewer->backgroundPlane = bmin;
//done_once = 1;
printf("\rnear %lf far %lf",viewer->nearPlane,viewer->farPlane);
return;
}
for (ci=0; ci<8; ci++) {
bboxMovedCentreZ += bboxPoints[ci].z;
#ifdef XXVERBOSE
if (smooger == 0)
printf ("moved bbox node %d is %4.2f %4.2f %4.2f\n",ci,bboxPoints[ci].x, bboxPoints[ci].y, bboxPoints[ci].z);
#endif
if (!doingGeoSpatial) {
if (-(bboxPoints[ci].z) > cfp) cfp = -(bboxPoints[ci].z);
if (-(bboxPoints[ci].z) < cnp) cnp = -(bboxPoints[ci].z);
}
}
bboxMovedCentreZ /= 8.0; // average of 8 z values from bbox
if (doingGeoSpatial) {
cnp = -bboxMovedCentreZ - bboxSphereRadius;
cfp = -bboxMovedCentreZ; // + bboxSphereRadius;
}
#ifdef VERBOSE
if (smooger==0) {
ConsoleMessage ("centre of bbox is %lf Z away",bboxMovedCentreZ);
ConsoleMessage ("bboxMovedCentreZ minus bboxRadius %lf",-bboxMovedCentreZ - bboxSphereRadius);
}
#endif
/* lets bound check here, both must be positive, and farPlane more than DEFAULT_NEARPLANE */
/* because we may be navigating towards the shapes, we give the nearPlane a bit of room, otherwise
we might miss part of the geometry that comes closest to us */
cnp = cnp/2.0;
if (cnp_nodeType == NODE_GeoViewpoint)) {
#ifdef VERBOSE
cnp = Viewer()->currentPosInModel.z/16.0;
if (smooger == 0) {
ConsoleMessage ("vp height %lf moved height %lf posinModel %f",X3D_GEOVIEWPOINT(vpnode)->position.c[2],
X3D_GEOVIEWPOINT(vpnode)->__movedPosition.c[2],Viewer()->currentPosInModel.z);
smooger ++; if (smooger == 100) smooger = 0;
}
#endif
#undef VERBOSE
}
/* lets use these values; leave room for a Background or TextureBackground node here */
if(1){
//code changed March 2015 - started to get zbuffer problems with geoscenes
//viewer->nearPlane = min(cnp,DEFAULT_NEARPLANE);
viewer->nearPlane = cnp; //changed sept 2017 - cnp can be massive like 4.5 million for geo
/* backgroundPlane goes between the farthest geometry, and the farPlane */
if (vectorSize(getActiveBindableStacks(tg)->background)!= 0) {
viewer->farPlane = max(cfp * 10.0,DEFAULT_FARPLANE);
viewer->backgroundPlane = max(cfp*5.0,DEFAULT_BACKGROUNDPLANE);
} else {
viewer->farPlane = max(cfp,DEFAULT_FARPLANE);
viewer->backgroundPlane = max(cfp,DEFAULT_BACKGROUNDPLANE); /* just set it to something */
}
}
if(0) {
//2018 render_background reworked to render before other nodes, and render close to frontplane, with depth off
viewer->nearPlane = cnp; //changed sept 2017 - cnp can be massive like 4.5 million for geo
viewer->farPlane = max(cfp,DEFAULT_FARPLANE);
// NOT USED 2018 viewer->backgroundPlane = max(cfp,DEFAULT_BACKGROUNDPLANE); /* just set it to something */
printf("\rnear %lf far %lf",viewer->nearPlane,viewer->farPlane);
}
if(0) {
//for debugging extents
viewer->nearPlane = .07; //changed sept 2017 - cnp can be massive like 4.5 million for geo
viewer->farPlane = DEFAULT_FARPLANE;
// NOT USED 2018 viewer->backgroundPlane = max(cfp,DEFAULT_BACKGROUNDPLANE); /* just set it to something */
printf("\rnear %lf far %lf",viewer->nearPlane,viewer->farPlane);
}
if(0){
//pre- march 2015 code, with one line changed, worked for most geo scenes
viewer->nearPlane = cnp;
/* backgroundPlane goes between the farthest geometry, and the farPlane */
if (vectorSize(getActiveBindableStacks(tg)->background)!= 0) { //changed sept 2017
viewer->farPlane = cfp * 10.0;
viewer->backgroundPlane = cfp*5.0;
} else {
viewer->farPlane = cfp;
viewer->backgroundPlane = cfp; /* just set it to something */
}
}
}
void doglClearColor() {
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
FW_GL_CLEAR_COLOR(p->cc_red, p->cc_green, p->cc_blue, p->cc_alpha);
tg->OpenGL_Utils.cc_changed = FALSE;
}
void clear_shader_table()
{
/* clearing the shader table forces the shaders to be re-lego-assembled and compiled
- useful for switching anaglyph on/off (a different fragEnd pixel shader is used)
- used in fwl_initialize_GL()
*/
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
if (p->myShaderTable != NULL) {
int i;
for (i=0; imyShaderTable); i++) {
struct shaderTableEntry *me = vector_get(struct shaderTableEntry *,p->myShaderTable, i);
FREE_IF_NZ(me);
}
deleteVector (struct shaderTableEntry *,p->myShaderTable);
p->myShaderTable = newVector(struct shaderTableEntry *, 8);
}
}
/**
* fwl_initializa_GL: initialize GLEW (->rdr caps) and OpenGL initial state
*/
void GLAPIENTRY MessageCallback( GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam )
{
//https://www.khronos.org/opengl/wiki/Debug_Output
if(severity == GL_DEBUG_SEVERITY_HIGH){
fprintf( stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n",
( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ),
type, severity, message );
printf("press enter:");
getchar();
}
}
bool fwl_initialize_GL()
{
char blankTexture[] = {0x40, 0x40, 0x40, 0xFF};
float gl_linewidth;
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start 1");
initialize_rdr_caps();
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start 3");
/* lets make sure everything is sync'd up */
#if KEEP_FV_INLIB
#if defined(TARGET_X11) || defined(TARGET_MOTIF)
XFlush(Xdpy);
#endif
#endif /* KEEP_FV_INLIB */
//#define DEBUG_OPENGL 1
#ifdef DEBUG_OPENGL
{
// https://www.khronos.org/opengl/wiki/OpenGL_Error
// During init, enable debug output
glEnable ( GL_DEBUG_OUTPUT );
glDebugMessageCallback( MessageCallback, 0 );
}
#endif //DEBUG_OPENGL
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start 4");
FW_GL_MATRIX_MODE(GL_PROJECTION);
FW_GL_LOAD_IDENTITY();
FW_GL_MATRIX_MODE(GL_MODELVIEW);
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start 6");
FW_GL_CLEAR_COLOR(p->cc_red, p->cc_green, p->cc_blue, p->cc_alpha);
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start 7");
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start 8");
FW_GL_DEPTHFUNC(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start 9");
gl_linewidth = gglobal()->Mainloop.gl_linewidth;
// dp pointSize in shaders on more modern OpenGL renderings
// keep Windows and Linux doing old way, as we have failures
// circa 2013 in this.
#if defined (GL_ES_VERSION_2_0)
#if defined (GL_PROGRAM_POINT_SIZE)
glEnable(GL_PROGRAM_POINT_SIZE);
#endif
#if defined (GL_PROGRAM_POINT_SIZE_EXT)
glEnable(GL_PROGRAM_POINT_SIZE_EXT);
#endif
#else
glPointSize (gl_linewidth);
#endif
glLineWidth(gl_linewidth);
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start a");
/*
* JAS - ALPHA testing for textures - right now we just use 0/1 alpha
* JAS channel for textures - true alpha blending can come when we sort
* JAS nodes.
*/
glEnable(GL_BLEND);
FW_GL_BLENDFUNC(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
FW_GL_CLEAR(GL_COLOR_BUFFER_BIT);
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start b");
/* for textured appearance add specular highlights as a separate secondary color
redbook p.270, p.455 and http://www.gamedev.net/reference/programming/features/oglch9excerpt/
if we don't have texture we can disable this (less computation)...
but putting this here is already a saving ;)...
*/
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start c0");
/* keep track of light states; initial turn all lights off except for headlight */
initializeLightTables();
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start c1");
/* ensure state of GL_CULL_FACE */
CULL_FACE_INITIALIZE;
FW_GL_PIXELSTOREI(GL_UNPACK_ALIGNMENT,1);
FW_GL_PIXELSTOREI(GL_PACK_ALIGNMENT,1);
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start c");
/* create an empty texture, defaultBlankTexture, to be used when a texture is loading, or if it fails */
FW_GL_GENTEXTURES (1,&tg->Textures.defaultBlankTexture);
glBindTexture (GL_TEXTURE_2D, tg->Textures.defaultBlankTexture);
FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
FW_GL_TEXIMAGE2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, blankTexture);
PRINT_GL_ERROR_IF_ANY("fwl_initialize_GL start d");
/* remove entries in the shader table, if they exist. Android, on "bring to front" will
call this routine, and shaders will be re-created as they are needed to display geometry.
*/
clear_shader_table();
/* moved to clear_shader_table() for anaglyph toggling, dug9 Aug 5, 2012
if (p->myShaderTable != NULL) {
int i;
for (i=0; imyShaderTable); i++) {
struct shaderTableEntry *me = vector_get(struct shaderTableEntry *,p->myShaderTable, i);
FREE_IF_NZ(me);
}
deleteVector (struct shaderTableEntry *,p->myShaderTable);
p->myShaderTable = newVector(struct shaderTableEntry *, 8);
}
*/
return TRUE;
}
ivec4 get_current_viewport();
void BackEndClearBuffer(int which) {
ivec4 vport = get_current_viewport();
FW_GL_SCISSOR(vport.X,vport.Y,vport.W,vport.H);
glEnable(GL_SCISSOR_TEST);
if(which == 2) {
FW_GL_CLEAR(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} else {
if(which==1) {
FW_GL_CLEAR(GL_DEPTH_BUFFER_BIT);
}
}
glDisable(GL_SCISSOR_TEST);
}
/* turn off all non-headlight lights; will turn them on if required. */
void BackEndLightsOff() {
int i;
for (i=0; iOpenGL_Utils.prv;
p->whichMode = mode;
#ifdef VERBOSE
printf ("fw_glMatrixMode, projTOS %d, modTOS %d texvTOS %d\n",p->projectionviewTOS,p->modelviewTOS, p->textureviewTOS);
switch (p->whichMode) {
case GL_PROJECTION: printf ("glMatrixMode(GL_PROJECTION)\n"); break;
case GL_MODELVIEW: printf ("glMatrixMode(GL_MODELVIEW)\n"); break;
case GL_TEXTURE: printf ("glMatrixMode(GL_TEXTURE)\n"); break;
}
#endif
switch (p->whichMode) {
case GL_PROJECTION: p->currentMatrix = (GLDOUBLE *) &p->FW_ProjectionView[p->projectionviewTOS]; break;
case GL_MODELVIEW: p->currentMatrix = (GLDOUBLE *) &p->FW_ModelView[p->modelviewTOS]; break;
case GL_TEXTURE: p->currentMatrix = (GLDOUBLE *) &p->FW_TextureView[p->textureviewTOS]; break;
default: printf ("invalid mode sent in it is %d, expected one of %d %d %d\n",p->whichMode, GL_PROJECTION,GL_MODELVIEW,GL_TEXTURE);
}
}
void fw_glLoadIdentity(void) {
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
//ConsoleMessage ("fw_glLoadIdentity, whichMode %d, tex %d",p->whichMode,GL_TEXTURE);
loadIdentityMatrix(p->currentMatrix);
FW_GL_LOADMATRIX(p->currentMatrix);
}
MATRIX4* PushMat( int a, int *b, int c, MATRIX4 *d){
(*b)++;
if (*b >= c) {
printf("stack overflow, depth %d whichmode %d\n", *b, a);
*b = c - 1;
}
memcpy((void *)d[*b], (void *)d[*b - 1], sizeof(GLDOUBLE)* 16);
return &d[*b];
}
void printMaxStackUsed(){
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
ConsoleMessage("%25s %d\n","max modelview stack used", p->maxStackUsed);
}
void fw_glPushMatrix(void) {
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
switch (p->whichMode) {
case GL_PROJECTION: p->currentMatrix = *PushMat(GL_PROJECTION, &p->projectionviewTOS, MAX_SMALL_MATRIX_STACK, p->FW_ProjectionView); break;
case GL_MODELVIEW: p->currentMatrix = *PushMat(GL_MODELVIEW, &p->modelviewTOS, MAX_LARGE_MATRIX_STACK, p->FW_ModelView); break;
case GL_TEXTURE: p->currentMatrix = *PushMat(GL_TEXTURE, &p->textureviewTOS, MAX_SMALL_MATRIX_STACK, p->FW_TextureView); break;
default:printf("wrong mode in popMatrix\n");
}
p->maxStackUsed = max(p->maxStackUsed, p->modelviewTOS);
FW_GL_LOADMATRIX(p->currentMatrix);
}
//void fw_glPushMatrix(void) {
// ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
//
// switch (p->whichMode) {
// PUSHMAT (GL_PROJECTION,p->projectionviewTOS,MAX_SMALL_MATRIX_STACK,p->FW_ProjectionView)
// PUSHMAT (GL_MODELVIEW,p->modelviewTOS,MAX_LARGE_MATRIX_STACK,p->FW_ModelView)
// PUSHMAT (GL_TEXTURE,p->textureviewTOS,MAX_SMALL_MATRIX_STACK,p->FW_TextureView)
// default :printf ("wrong mode in popMatrix\n");
// }
//
// FW_GL_LOADMATRIX(p->currentMatrix);
//}
//#undef PUSHMAT
//#define POPMAT(a,b,c) case a: b--; if (b<0) {b=0;printf ("popMatrix, stack underflow, whichMode %d\n",p->whichMode);} p->currentMatrix = c[b]; break;
MATRIX4 *PopMat(int a, int *b, MATRIX4 *c){
(*b)--;
if (*b < 0) {
*b = 0;
printf("popMatrix, stack underflow, whichMode %d\n", a);
}
return &c[*b];
}
void fw_glPopMatrix(void) {
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
switch (p->whichMode) {
case GL_PROJECTION: p->currentMatrix = *PopMat(GL_PROJECTION, &p->projectionviewTOS, p->FW_ProjectionView); break;
case GL_MODELVIEW: p->currentMatrix = *PopMat(GL_MODELVIEW, &p->modelviewTOS, p->FW_ModelView); break;
case GL_TEXTURE: p->currentMatrix = *PopMat(GL_TEXTURE, &p->textureviewTOS, p->FW_TextureView); break;
default: printf ("wrong mode in popMatrix\n");
}
FW_GL_LOADMATRIX(p->currentMatrix);
}
//void fw_glPopMatrix(void) {
// ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
//
// switch (p->whichMode) {
// POPMAT(GL_PROJECTION, p->projectionviewTOS, p->FW_ProjectionView)
// POPMAT(GL_MODELVIEW, p->modelviewTOS, p->FW_ModelView)
// POPMAT(GL_TEXTURE, p->textureviewTOS, p->FW_TextureView)
// default:printf("wrong mode in popMatrix\n");
// }
//
// FW_GL_LOADMATRIX(p->currentMatrix);
//}
//#undef POPMAT
void fw_glTransformd(GLDOUBLE *mat) {
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
//printf ("fw_glTranslated %lf %lf %lf\n",x,y,z);
//printf ("translated, currentMatrix %p\n",p->currentMatrix);
matmultiplyAFFINE(p->currentMatrix,mat,p->currentMatrix);
FW_GL_LOADMATRIX(p->currentMatrix);
}
void fw_glTranslated(GLDOUBLE x, GLDOUBLE y, GLDOUBLE z) {
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
//printf ("fw_glTranslated %lf %lf %lf\n",x,y,z);
//printf ("translated, currentMatrix %p\n",p->currentMatrix);
p->currentMatrix[12] = p->currentMatrix[0] * x + p->currentMatrix[4] * y + p->currentMatrix[8] * z + p->currentMatrix[12];
p->currentMatrix[13] = p->currentMatrix[1] * x + p->currentMatrix[5] * y + p->currentMatrix[9] * z + p->currentMatrix[13];
p->currentMatrix[14] = p->currentMatrix[2] * x + p->currentMatrix[6] * y + p->currentMatrix[10] * z + p->currentMatrix[14];
p->currentMatrix[15] = p->currentMatrix[3] * x + p->currentMatrix[7] * y + p->currentMatrix[11] * z + p->currentMatrix[15];
FW_GL_LOADMATRIX(p->currentMatrix);
}
void fw_glTranslatef(float x, float y, float z) {
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
//printf ("fw_glTranslatef %f %f %f\n",x,y,z);
p->currentMatrix[12] = p->currentMatrix[0] * x + p->currentMatrix[4] * y + p->currentMatrix[8] * z + p->currentMatrix[12];
p->currentMatrix[13] = p->currentMatrix[1] * x + p->currentMatrix[5] * y + p->currentMatrix[9] * z + p->currentMatrix[13];
p->currentMatrix[14] = p->currentMatrix[2] * x + p->currentMatrix[6] * y + p->currentMatrix[10] * z + p->currentMatrix[14];
p->currentMatrix[15] = p->currentMatrix[3] * x + p->currentMatrix[7] * y + p->currentMatrix[11] * z + p->currentMatrix[15];
FW_GL_LOADMATRIX(p->currentMatrix);
}
/* perform current = current * mat */
void fw_glMultMatrixd (GLDOUBLE *mat) {
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
matmultiplyFULL(p->currentMatrix,mat,p->currentMatrix);
//FW_GL_LOADMATRIX(p->currentMatrix);
}
/* perform rotation, assuming that the angle is in radians. */
void fw_glRotateRad (GLDOUBLE angle, GLDOUBLE x, GLDOUBLE y, GLDOUBLE z) {
MATRIX4 myMat;
GLDOUBLE mag;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
//printf ("fw_glRotateRad %lf %lf %lf %lf modTOS %d projTOS %d\n",angle,x,y,z,p->modelviewTOS,p->projectionviewTOS);
//printmatrix2(p->currentMatrix,"in rad");
loadIdentityMatrix (myMat);
/* FIXME - any way we can ensure that the angles are normalized? */
mag = x*x + y*y + z*z;
/* bounds check - the axis is invalid. */
if (APPROX(mag,0.00)) {
return;
}
/* bounds check - angle is zero, no rotation happening here */
if (APPROX(angle,0.0)) {
return;
}
if (!APPROX(mag,1.0)) {
struct point_XYZ in; struct point_XYZ out;
in.x = x; in.y = y, in.z = z;
vecnormal(&out,&in);
x = out.x; y = out.y; z = out.z;
}
//printf ("rad, normalized axis %lf %lf %lf\n",x,y,z);
matrotate(myMat,angle,x,y,z);
//printmatrix2 (myMat, "rotation matrix");
matmultiplyAFFINE(p->currentMatrix,myMat,p->currentMatrix);
//printmatrix2 (p->currentMatrix,"currentMatrix after rotate");
FW_GL_LOADMATRIX(p->currentMatrix);
}
/* perform the rotation, assuming that the angle is in degrees */
void fw_glRotated (GLDOUBLE angle, GLDOUBLE x, GLDOUBLE y, GLDOUBLE z) {
MATRIX4 myMat;
GLDOUBLE mag;
GLDOUBLE radAng;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
/* convert angle from degrees to radians */
/* FIXME - must try and make up a rotate-radians call to get rid of these incessant conversions */
radAng = angle * 3.1415926536/ 180.0;
loadIdentityMatrix (myMat);
/* FIXME - any way we can ensure that the angles are normalized? */
mag = x*x + y*y + z*z;
/* bounds check - the axis is invalid. */
if (APPROX(mag,0.00)) {
return;
}
/* bounds check - angle is zero, no rotation happening here */
if (APPROX(angle,0.0)) {
return;
}
if (!APPROX(mag,1.0)) {
struct point_XYZ in; struct point_XYZ out;
in.x = x; in.y = y, in.z = z;
vecnormal(&out,&in);
x = out.x; y = out.y; z = out.z;
}
/* are the axis close to zero? */
if (mag < 0.001) {
return;
}
matrotate(myMat,radAng,x,y,z);
matmultiplyAFFINE(p->currentMatrix,p->currentMatrix,myMat);
FW_GL_LOADMATRIX(p->currentMatrix);
}
void fw_glRotatef (float a, float x, float y, float z) {
fw_glRotated((GLDOUBLE)a, (GLDOUBLE)x, (GLDOUBLE)y, (GLDOUBLE)z);
}
void fw_glScaled (GLDOUBLE x, GLDOUBLE y, GLDOUBLE z) {
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
// printf ("glScaled(%5.4lf %5.4lf %5.4lf)\n",x,y,z);
p->currentMatrix[0] *= x; p->currentMatrix[4] *= y; p->currentMatrix[8] *= z;
p->currentMatrix[1] *= x; p->currentMatrix[5] *= y; p->currentMatrix[9] *= z;
p->currentMatrix[2] *= x; p->currentMatrix[6] *= y; p->currentMatrix[10] *= z;
p->currentMatrix[3] *= x; p->currentMatrix[7] *= y; p->currentMatrix[11] *= z;
FW_GL_LOADMATRIX(p->currentMatrix);
}
void fw_glScalef (float x, float y, float z) {
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
// printf ("glScalef(%5.4f %5.4f %5.4f)\n",x,y,z);
p->currentMatrix[0] *= x; p->currentMatrix[4] *= y; p->currentMatrix[8] *= z;
p->currentMatrix[1] *= x; p->currentMatrix[5] *= y; p->currentMatrix[9] *= z;
p->currentMatrix[2] *= x; p->currentMatrix[6] *= y; p->currentMatrix[10] *= z;
p->currentMatrix[3] *= x; p->currentMatrix[7] *= y; p->currentMatrix[11] *= z;
FW_GL_LOADMATRIX(p->currentMatrix);
}
void fw_glGetDoublev (int ty, GLDOUBLE *mat) {
GLDOUBLE *dp;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
/*
switch (ty) {
case GL_PROJECTION_MATRIX: printf ("getDoublev(GL_PROJECTION_MATRIX)\n"); break;
case GL_MODELVIEW_MATRIX: printf ("getDoublev(GL_MODELVIEW_MATRIX)\n"); break;
case GL_TEXTURE_MATRIX: printf ("getDoublev(GL_TEXTURE_MATRIX)\n"); break;
}
*/
switch (ty) {
case GL_PROJECTION_MATRIX: dp = p->FW_ProjectionView[p->projectionviewTOS]; break;
case GL_MODELVIEW_MATRIX: dp = p->FW_ModelView[p->modelviewTOS]; break;
case GL_TEXTURE_MATRIX: dp = p->FW_TextureView[p->textureviewTOS]; break;
default: {
loadIdentityMatrix(mat);
printf ("invalid mode sent in it is %d, expected one of %d %d %d\n",ty,GL_PROJECTION_MATRIX,GL_MODELVIEW_MATRIX,GL_TEXTURE_MATRIX);
return;}
}
memcpy((void *)mat, (void *) dp, sizeof (GLDOUBLE) * MATRIX_SIZE);
}
void fw_glGetInteger( int ty, int *params){
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
switch(ty){
case GL_TEXTURE_STACK_DEPTH:
params[0] = p->textureviewTOS;
break;
default:
break;
}
}
void fw_glSetDoublev (int ty, GLDOUBLE *mat) {
GLDOUBLE *dp;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
/*
switch (ty) {
case GL_PROJECTION_MATRIX: printf ("getDoublev(GL_PROJECTION_MATRIX)\n"); break;
case GL_MODELVIEW_MATRIX: printf ("getDoublev(GL_MODELVIEW_MATRIX)\n"); break;
case GL_TEXTURE_MATRIX: printf ("getDoublev(GL_TEXTURE_MATRIX)\n"); break;
}
*/
switch (ty) {
case GL_PROJECTION_MATRIX: dp = p->FW_ProjectionView[p->projectionviewTOS]; break;
case GL_MODELVIEW_MATRIX: dp = p->FW_ModelView[p->modelviewTOS]; break;
case GL_TEXTURE_MATRIX: dp = p->FW_TextureView[p->textureviewTOS]; break;
default: {
printf ("invalid mode sent in it is %d, expected one of %d %d %d\n",ty,GL_PROJECTION_MATRIX,GL_MODELVIEW_MATRIX,GL_TEXTURE_MATRIX);
return;}
}
memcpy((void *) dp, (void *)mat, sizeof (GLDOUBLE) * MATRIX_SIZE);
}
/* for Sarah's front end - should be removed sometime... */
void kill_rendering() {
/* printf ("kill_rendering called...\n"); */
}
/* if we have a ReplaceWorld style command, we have to remove the old world. */
/* NOTE: There are 2 kinds of of replaceworld commands - sometimes we have a URL
(eg, from an Anchor) and sometimes we have a list of nodes (from a Javascript
replaceWorld, for instance). The URL ones can really replaceWorld, the node
ones, really, it's just replace the rootNode children, as WE DO NOT KNOW
what the user has programmed, and what nodes are (re) used in the Scene Graph */
void killNodes();
void kill_oldWorld(int kill_EAI, int kill_JavaScript, char *file, int line) {
int i;
struct X3D_Node* rootnode;
struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
char mystring[20];
//printf ("kill_oldWorld called...\n");
#ifdef VERBOSE
printf ("kill 1 myThread %u displayThread %u\n",pthread_self(), gglobal()->threads.DispThrd);
#ifdef _MSC_VER
if (pthread_self().p != gglobal()->threads.DispThrd.p ) {
#else
if (pthread_self() != gglobal()->threads.DispThrd) {
#endif
ConsoleMessage ("kill_oldWorld must run in the displayThread called at %s:%d\n",file,line);
return;
}
#endif
/* get rid of sensor events */
resetSensorEvents();
/* make the root_res equal NULL - this throws away all old resource info */
/*
if (gglobal()->resources.root_res != NULL) {
printf ("root_res %p has the following...\n",gglobal()->resources.root_res);
resource_dump(gglobal()->resources.root_res);
}else {printf ("root_res is null, no need to dump\n");}
*/
resource_tree_destroy(); //dug9 sep2,2013 added this call. just comment out if giving trouble before a release
gglobal()->resources.root_res = NULL;
/* mark all rootNode children for Dispose */
rootnode = rootNode();
if (rootnode != NULL) {
if(rootnode->_nodeType == NODE_Proto){
unload_broto(X3D_PROTO(rootnode));
}else{
struct Multi_Node *children, *sortedChildren;
children = &X3D_PROTO(rootNode())->__children;
sortedChildren = &X3D_PROTO(rootNode())->_sortedChildren;
//children = childrenField(rootNode());
if (children->n != 0) {
for (i=0; in; i++) {
markForDispose(children->p[i], TRUE);
}
}
//if (sortedChildren->n != 0) {
// for (i=0; in; i++) {
// markForDispose(sortedChildren->p[i], TRUE);
// }
//}
/* stop rendering */
sortedChildren->n = 0;
children->n = 0;
}
}
/* close the Console Message system, if required. */
closeConsoleMessage();
/* occlusion testing - zero total count, but keep MALLOC'd memory around */
zeroOcclusion();
/* clock events - stop them from ticking */
kill_clockEvents();
/* kill DEFS, handles */
EAI_killBindables();
kill_bindables();
killKeySensorNodeList();
/* stop routing */
kill_routing();
/* tell the statusbar that it needs to reinitialize */
//kill_status();
setMenuStatus(NULL);
/* any user defined Shader nodes - ComposedShader, PackagedShader, ProgramShader?? */
kill_userDefinedShaders();
/* free textures */
/*
kill_openGLTextures();
*/
/* free scripts */
kill_javascript();
#if !defined(EXCLUDE_EAI)
/* free EAI */
if (kill_EAI) {
/* shutdown_EAI(); */
fwlio_RxTx_control(CHANNEL_EAI, RxTx_STOP) ;
}
#endif
// OLD_IPHONE_AQUA #ifndef AQUA
sprintf (mystring, "QUIT");
Sound_toserver(mystring);
// OLD_IPHONE_AQUA #endif
/* reset any VRML Parser data */
if (globalParser != NULL) {
parser_destroyData(globalParser);
//globalParser = NULL;
//moved to CParse_clear gglobal()->CParse.globalParser = NULL;
}
kill_X3DDefs();
/* tell statusbar that we have none */
//viewer_default();
setMenuStatus("NONE");
}
void unload_globalParser() {
// unload any string tables, and signal to any replacworld scene that it needs a new parser+lexer struct
struct VRMLParser *globalParser = (struct VRMLParser *)gglobal()->CParse.globalParser;
if(globalParser){
parser_destroyData(globalParser); //destroys lexer data too
FREE_IF_NZ(globalParser->lexer);
}
FREE_IF_NZ(globalParser);
gglobal()->CParse.globalParser = NULL; //set to null to trigger a fresh createParser on replaceworld
}
void unload_libraryscenes();
void reset_Browser(){
// erase old world but keep gglobal in good shape, ie everything in _init() functions still good
// -gglobal is erased elsewhere in finalizeRenderSceneUpdateScene()
// also don't erase browser metadata key,value pairs, which could be avatar state to be
// carried over between room-scenes in multi-scene game
struct X3D_Node *rootnode = rootNode();
if (rootnode != NULL) {
if( rootnode->_nodeType == NODE_Proto){
unload_broto(X3D_PROTO(rootnode)); //we still want a rootnode: empty and waiting for parsing (destroy in finalizeRenderSceneUpdateScene only on exit)
unload_globalParser();
resource_tree_destroy();
unload_libraryscenes(); //debate: should proto libraryscenes hang around in case the same protos are used in a different, anchored-to scene?
kill_javascript();
}else{
kill_oldWorld(TRUE,TRUE,__FILE__,__LINE__);
}
}
}
#if defined (_ANDROID)
/* Android wants the OpenGL system to re-create assets like textures on onSurfaceCreated call */
void fwl_Android_reloadAssets(void) {
int tc;
struct X3D_Node *node;
ppOpenGL_Utils p;
p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
/* reset the RenderFuncs cache */
resetGlobalShader();
//ConsoleMessage("fwl_Android_reloadAssets called");
//ConsoleMessage ("fwl_Android_reloadAssets - reloading shader code");
fwl_initialize_GL();
//ConsoleMessage("fwl_Android_reloadAssets - reload the current active shaders");
if (p->linearNodeTable != NULL) {
LOCK_MEMORYTABLE
for (tc=0; tclinearNodeTable); tc++){
node = vector_get(struct X3D_Node *,p->linearNodeTable,tc);
//ConsoleMessage ("rla, node %p\n",node);
if (node!=NULL) {
/* tell each node to update itself */
node->_change ++;
switch (node->_nodeType) {
case NODE_Sphere: {
struct X3D_Sphere *me = (struct X3D_Sphere *)node;
//ConsoleMessage ("Sphere - zeroing VBO");
me->_sideVBO = 0;
me->__SphereIndxVBO = 0;
FREE_IF_NZ(me->__points.p);
me->__points.p = NULL;
me->__points.n = 0;
node->_change ++;
break;
}
case NODE_Cone: {
struct X3D_Cone *me = (struct X3D_Cone *)node;
me->__coneVBO = 0;
node->_change ++;
break;
}
case NODE_Cylinder: {
struct X3D_Cylinder *me = (struct X3D_Cylinder *)node;
me->__cylinderVBO = 0;
node->_change ++;
break;
}
case NODE_Background: {
struct X3D_Background *me = (struct X3D_Background *)node;
//ConsoleMessage ("Background - zeroing VBO");
me->__VBO = 0;
node->_change ++;
break;
}
default: {
struct X3D_PolyRep *pr = node->_intern;
int i;
//ConsoleMessage ("node Type %s, intern %p",stringNodeType(node->_nodeType),pr);
// get rid of the PolyRep VBOs.
if (pr!=NULL) {
for (i=0; iVBO_buffers[i] = 0;
pr->irep_change ++;
node->_change ++;
}
}
}
}
}
UNLOCK_MEMORYTABLE
}
}
#endif
/* for verifying that a memory pointer exists */
int checkNode(struct X3D_Node *node, char *fn, int line) {
int tc;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
if (node == NULL) {
printf ("checkNode, node is NULL at %s %d\n",fn,line);
return FALSE;
}
if (node == X3D_NODE(rootNode())) return FALSE;
LOCK_MEMORYTABLE;
for (tc=0; tclinearNodeTable); tc++){
if (vector_get(struct X3D_Node *,p->linearNodeTable,tc) == node) {
if (node->referenceCount > 0) {
UNLOCK_MEMORYTABLE;
return TRUE;
}
}
}
//printf ("checkNode: did not find %p in memory table at i%s %d\n",node,fn,line);
UNLOCK_MEMORYTABLE;
return FALSE;
}
/*creating node table*/
static void createMemoryTable(){
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
p->linearNodeTable = newVector(struct X3D_Node*, 128);
}
/*keep track of node created*/
void registerX3DNode(struct X3D_Node * tmp){
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
int tc;
bool filledHole = FALSE;
LOCK_MEMORYTABLE
if (p->linearNodeTable == NULL) {
createMemoryTable();
}
// fill in a hole, or just tack it on the end?
if (p->potentialHoleCount > 0) {
for (tc=0; tclinearNodeTable); tc++){
if (!filledHole) {
if (vector_get(struct X3D_Node *,p->linearNodeTable,tc) == NULL) {
vector_set(struct X3D_Node *, p->linearNodeTable, tc, tmp);
p->potentialHoleCount--;
filledHole = TRUE;
//ConsoleMessage ("registerX3DNode, found a hole at %d, now phc %d for type %s",tc,p->potentialHoleCount,stringNodeType(tmp->_nodeType));
}
}
}
}
/*
if (filledHole) ConsoleMessage ("registerX3DNode, filled hole, now phc %d for type %s",p->potentialHoleCount,stringNodeType(tmp->_nodeType));
if (!filledHole) ConsoleMessage ("registerX3DNode, no hole, phc %d for type %s",p->potentialHoleCount,stringNodeType(tmp->_nodeType));
*/
if (!filledHole) vector_pushBack(struct X3D_Node *, p->linearNodeTable, tmp);
UNLOCK_MEMORYTABLE
}
int removeNodeFromVector(int iaction, struct Vector *v, struct X3D_Node *node);
void unRegisterX3DNode(struct X3D_Node * tmp){
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
LOCK_MEMORYTABLE
if (p->linearNodeTable ) {
removeNodeFromVector(1, p->linearNodeTable, tmp);
//int tc;
//for (tc=0; tclinearNodeTable); tc++){
// struct X3D_Node *ns;
// ns = vector_get(struct X3D_Node *,p->linearNodeTable,tc);
// if(ns == tmp) {
// vector_set(struct X3D_Node *, p->linearNodeTable, tc, NULL);
// break;
// }
//}
}
UNLOCK_MEMORYTABLE
}
/*We don't register the first node created for reload reason*/
void doNotRegisterThisNodeForDestroy(struct X3D_Node * nodePtr){
int i;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
LOCK_MEMORYTABLE
/* find this node, and if found, just delete it from the memory table */
for (i=0; ilinearNodeTable); i++) {
if (vector_get(struct X3D_Node *,p->linearNodeTable,i) == nodePtr) {
vector_set(struct X3D_Node *,p->linearNodeTable,i,NULL);
p->potentialHoleCount++;
}
}
UNLOCK_MEMORYTABLE
}
/* sort children - use bubble sort with early exit flag */
/* we use this for z buffer rendering; drawing scene in correct z-buffer order */
/* we ONLY sort if:
1) the node has changed - this is the "needsCompiling" field;
2) the number of children has changed - again, the "needsCompiling" flag should be set,
but we enforce it;
3) the first pass shows that nodes are out of order
*/
static void sortChildren (int line, struct Multi_Node *ch, struct Multi_Node *sortedCh, int sortForDistance) {
int i,j;
int nc;
int noswitch;
struct X3D_Node *a, *b, *c;
/* Thread Race Warning: the (non-broto) parser can still be
adding children in its thread, while we are rendering in this thread.
We don't have mutex locks, so we are relying on 'atomic operations'
if it bombs in here check also REINITIALIZE_SORTED_NODES_FIELD macro which does the same thing
*/
nc = ch->n; //ATOMIC OP - saves the instantaneous size of ch, which may keep growing
#ifdef VERBOSE
printf ("sortChildren line %d nc %d ",line,nc);
if (sortForDistance) printf ("sortForDistance ");
printf ("\n");
#endif //VERBOSE
/* has this changed size? */
if (nc != sortedCh->n) {
FREE_IF_NZ(sortedCh->p); //Mar 11, 2014:
sortedCh->p = MALLOC(void *, sizeof (struct X3DNode *) * nc);
memcpy(sortedCh->p, ch->p, sizeof(struct X3DNode *) * nc); //ATOMIC-OP - ch->p gets realloced frequently, we need a snapshot which may be bigger than nc above
sortedCh->n = nc;
}
#ifdef VERBOSE
printf ("sortChildren start, %d, chptr %u\n",nc,ch);
#endif
/* do we care about rendering order? */
if (!sortForDistance) return;
if (nc < 2) return;
/* simple, inefficient bubble sort */
/* this is a fast sort when nodes are already sorted;
may wish to go and "QuickSort" or so on, when nodes
move around a lot. (Bubblesort is bad when nodes
have to be totally reversed) */
for(i=0; ii; j--) {
/* printf ("comparing %d %d\n",i,j); */
a = X3D_NODE(sortedCh->p[j-1]);
b = X3D_NODE(sortedCh->p[j]);
/* check to see if a child is NULL - if so, skip it */
if (a && b) {
if (a->_dist > b->_dist) {
// printf ("sortChildren at %lf, have to switch %d %d dists %lf %lf\n",TickTime(),i,j,a->_dist, b->_dist);
c = a;
sortedCh->p[j-1] = b;
sortedCh->p[j] = c;
noswitch = FALSE;
}
}
}
/* did we have a clean run? */
if (noswitch) {
break;
}
}
#ifdef VERBOSE
printf ("sortChildren returning.\n");
for(i=0; ip[i];
if (b)
printf ("child %d %u %f %s",i,b,b->_dist,stringNodeType(b->_nodeType));
else
printf ("no child %d", i);
b = ch->p[i];
printf (" unsorted %u\n",b);
}
#endif
}
/* zero the Visibility flag in all nodes */
void zeroVisibilityFlag(void) {
struct X3D_Node* node;
int i;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
/* do not bother doing this if the inputThread is active. */
if (fwl_isinputThreadParsing()) return;
LOCK_MEMORYTABLE
/* do we have GL_ARB_occlusion_query, or are we still parsing Textures? */
if ((gglobal()->Frustum.OccFailed) || fwl_isTextureParsing()) {
/* if we have textures still loading, display all the nodes, so that the textures actually
get put into OpenGL-land. If we are not texture parsing... */
/* no, we do not have GL_ARB_occlusion_query, just tell every node that it has visible children
and hope that, sometime, the user gets a good computer graphics card */
for (i=0; ilinearNodeTable); i++){
node = vector_get(struct X3D_Node *,p->linearNodeTable,i);
if (node != NULL) {
node->_renderFlags = node->_renderFlags | VF_hasVisibleChildren;
}
}
}
else if (p->linearNodeTable)
{
/* we do... lets zero the hasVisibleChildren flag */
for (i=0; ilinearNodeTable); i++){
node = vector_get(struct X3D_Node *,p->linearNodeTable,i);
if (node != NULL) {
#ifdef OCCLUSIONVERBOSE
if (((node->_renderFlags) & VF_hasVisibleChildren) != 0) {
printf ("%lf, zeroVisibility - %d is a %s, flags %x\n",TickTime(), i,stringNodeType(node->_nodeType), (node->_renderFlags) & VF_hasVisibleChildren);
}
#endif
node->_renderFlags = node->_renderFlags & (0xFFFF^VF_hasVisibleChildren);
}
}
}
UNLOCK_MEMORYTABLE
}
/* go through the linear list of nodes, and do "special things" for special nodes, like
Sensitive nodes, Viewpoint nodes, ... */
#define CMD(TTT,YYY) \
/* printf ("nt %s change %d ichange %d\n",stringNodeType(X3D_NODE(YYY)->_nodeType),X3D_NODE(YYY)->_change, X3D_NODE(YYY)->_ichange); */ \
if (NODE_NEEDS_COMPILING) compile_Metadata##TTT((struct X3D_Metadata##TTT *) YYY)
#define BEGIN_NODE(thistype) case NODE_##thistype:
#define END_NODE break;
#define SIBLING_SENSITIVE(thistype) \
/* make Sensitive */ \
if (((struct X3D_##thistype *)node)->enabled) { \
nParents = vectorSize((struct X3D_##thistype *)pnode->_parentVector); \
parentVector = (((struct X3D_##thistype *)pnode)->_parentVector); \
}
#define ANCHOR_SENSITIVE(thistype) \
/* make THIS Sensitive - most nodes make the parents sensitive, Anchors have children...*/ \
anchorPtr = (struct X3D_Anchor *)node;
//#ifdef VIEWPOINT
//#undef VIEWPOINT /* defined for the EAI,SAI, does not concern us uere */
//#endif
#define BINDABLE(thistype) \
setBindPtr = (int *)(((char*)(node))+offsetof (struct X3D_##thistype, set_bind)); \
if ((*setBindPtr) == 100) {setBindPtr = NULL; } //else {printf ("OpenGL, BINDING %d\n",*setBindPtr);}/* already done */
#define CHILDREN_NODE(thistype) \
addChildren = NULL; removeChildren = NULL; \
offsetOfChildrenPtr = offsetof (struct X3D_##thistype, children); \
if (((struct X3D_##thistype *)node)->addChildren.n > 0) { \
addChildren = &((struct X3D_##thistype *)node)->addChildren; \
childrenPtr = &((struct X3D_##thistype *)node)->children; \
} \
if (((struct X3D_##thistype *)node)->removeChildren.n > 0) { \
removeChildren = &((struct X3D_##thistype *)node)->removeChildren; \
childrenPtr = &((struct X3D_##thistype *)node)->children; \
}
#define CHILDREN_SWITCH_NODE(thistype) \
addChildren = NULL; removeChildren = NULL; \
offsetOfChildrenPtr = offsetof (struct X3D_##thistype, choice); \
if (((struct X3D_##thistype *)node)->addChildren.n > 0) { \
addChildren = &((struct X3D_##thistype *)node)->addChildren; \
childrenPtr = &((struct X3D_##thistype *)node)->choice; \
} \
if (((struct X3D_##thistype *)node)->removeChildren.n > 0) { \
removeChildren = &((struct X3D_##thistype *)node)->removeChildren; \
childrenPtr = &((struct X3D_##thistype *)node)->choice; \
}
#define CHILDREN_LOD_NODE \
addChildren = NULL; removeChildren = NULL; \
offsetOfChildrenPtr = offsetof (struct X3D_LOD, children); \
if (X3D_LODNODE(node)->addChildren.n > 0) { \
addChildren = &X3D_LODNODE(node)->addChildren; \
if (X3D_LODNODE(node)->__isX3D == 0) childrenPtr = &X3D_LODNODE(node)->level; \
else childrenPtr = &X3D_LODNODE(node)->children; \
} \
if (X3D_LODNODE(node)->removeChildren.n > 0) { \
removeChildren = &X3D_LODNODE(node)->removeChildren; \
if (X3D_LODNODE(node)->__isX3D == 0) childrenPtr = &X3D_LODNODE(node)->level; \
else childrenPtr = &X3D_LODNODE(node)->children; \
}
#define CHILDREN_ANY_NODE(thistype,thischildren) \
addChildren = NULL; removeChildren = NULL; \
offsetOfChildrenPtr = offsetof (struct X3D_##thistype, thischildren); \
if (((struct X3D_##thistype *)node)->addChildren.n > 0) { \
addChildren = &((struct X3D_##thistype *)node)->addChildren; \
childrenPtr = &((struct X3D_##thistype *)node)->thischildren; \
} \
if (((struct X3D_##thistype *)node)->removeChildren.n > 0) { \
removeChildren = &((struct X3D_##thistype *)node)->removeChildren; \
childrenPtr = &((struct X3D_##thistype *)node)->thischildren; \
}
#define EVIN_AND_FIELD_SAME(thisfield, thistype) \
if ((((struct X3D_##thistype *)node)->set_##thisfield.n) > 0) { \
((struct X3D_##thistype *)node)->thisfield.n = 0; \
FREE_IF_NZ (((struct X3D_##thistype *)node)->thisfield.p); \
((struct X3D_##thistype *)node)->thisfield.p = ((struct X3D_##thistype *)node)->set_##thisfield.p; \
((struct X3D_##thistype *)node)->thisfield.n = ((struct X3D_##thistype *)node)->set_##thisfield.n; \
((struct X3D_##thistype *)node)->set_##thisfield.n = 0; \
((struct X3D_##thistype *)node)->set_##thisfield.p = NULL; \
node->_change++; \
}
//above - polyrep needs to compile after set_coordIndex is copied to coordIndex
#ifdef OLDCODE
OLDCODE/* just tell the parent (a grouping node) that there is a locally scoped light as a child */
OLDCODE/* do NOT send this up the scenegraph! */
OLDCODE#define LOCAL_LIGHT_PARENT_FLAG \
OLDCODE{ int i; \
OLDCODE for (i = 0; i < vectorSize(pnode->_parentVector); i++) { \
OLDCODE struct X3D_Node *n = vector_get(struct X3D_Node*, pnode->_parentVector, i); \
OLDCODE if( n != 0 ) n->_renderFlags = n->_renderFlags | VF_localLight; \
OLDCODE } \
OLDCODE}
#endif //OLDCODE
#define ADD_TO_PARENT_SIBAFFECTORS \
{ int i; \
for (i = 0; i < vectorSize(pnode->_parentVector); i++) { \
struct X3D_Node *n = vector_get(struct X3D_Node*, pnode->_parentVector, i); \
if( n != 0 ) AddToSibAffectors(n,pnode); \
} \
}
#define CHECK_MATERIAL_TRANSPARENCY \
if (((struct X3D_Material *)node)->transparency > 0.0001) { \
/* printf ("node %p MATERIAL HAS TRANSPARENCY of %f \n", node, ((struct X3D_Material *)node)->transparency); */ \
update_renderFlag(X3D_NODE(pnode),VF_Blend | VF_shouldSortChildren);\
gglobal()->RenderFuncs.have_transparency = TRUE; \
}
#define CHECK_FILL_PROPERTY_FILLED \
if ((((struct X3D_FillProperties *)node)->_enabled == TRUE) && (((struct X3D_FillProperties *)node)->filled == FALSE)) { \
/* printf ("node %p FillProperty filled FALSE\n",node); */ \
update_renderFlag(X3D_NODE(pnode),VF_Blend | VF_shouldSortChildren);\
gglobal()->RenderFuncs.have_transparency = TRUE; \
}
#define CHECK_TWOSIDED_MATERIAL_TRANSPARENCY \
if ((((struct X3D_TwoSidedMaterial *)node)->transparency > 0.0001) || (((struct X3D_TwoSidedMaterial *)node)->backTransparency > 0.0001)){ \
/* printf ("node %p TwoSidedMATERIAL HAS TRANSPARENCY of %f %f \n", node, ((struct X3D_TwoSidedMaterial *)node)->transparency,((struct X3D_TwoSidedMaterial *)node)->backTransparency);*/ \
update_renderFlag(X3D_NODE(pnode),VF_Blend | VF_shouldSortChildren);\
gglobal()->RenderFuncs.have_transparency = TRUE; \
}
#define CHECK_IMAGETEXTURE_TRANSPARENCY \
if (isTextureAlpha(((struct X3D_ImageTexture *)node)->__textureTableIndex)) { \
/* printf ("node %d IMAGETEXTURE HAS TRANSPARENCY\n", node); */ \
update_renderFlag(X3D_NODE(pnode),VF_Blend | VF_shouldSortChildren);\
gglobal()->RenderFuncs.have_transparency = TRUE; \
}
#define CHECK_PIXELTEXTURE_TRANSPARENCY \
if (isTextureAlpha(((struct X3D_PixelTexture *)node)->__textureTableIndex)) { \
/* printf ("node %d PIXELTEXTURE HAS TRANSPARENCY\n", node); */ \
update_renderFlag(X3D_NODE(pnode),VF_Blend | VF_shouldSortChildren);\
gglobal()->RenderFuncs.have_transparency = TRUE; \
}
#define CHECK_MOVIETEXTURE_TRANSPARENCY \
if (isTextureAlpha(((struct X3D_MovieTexture *)node)->__textureTableIndex)) { \
/* printf ("node %d MOVIETEXTURE HAS TRANSPARENCY\n", node); */ \
update_renderFlag(X3D_NODE(pnode),VF_Blend | VF_shouldSortChildren);\
gglobal()->RenderFuncs.have_transparency = TRUE; \
}
//dug9 dec 13 >>
//also used in renderfuncs.c setSensitive()
//definition: type node: its the node that represents the type of the node
//which for builtin nodes is the same as the node
// it's only different for protoInstances, where the type node is the first node in the ProtoBody
// or if the first node in the protoBody is a Proto, then its first node ad infinitum
// goal: get the type node, given the node
// then the Proto IS-A typeNode or can be used as one in some places
struct X3D_Node* getTypeNode(struct X3D_Node *node)
{
struct X3D_Node* dnode;
dnode = node; //for builtin types, the type node is just the node
if(node){
if(node->_nodeType == NODE_Proto)
{
struct X3D_Proto *pn = (struct X3D_Proto*)node;
if(1) //some flag to say it's not the scene, but a protoInstance where only the first node is rendered - see isProto
{
//the first node in a protobody determines its type
if(pn->__children.n > 0)
dnode = getTypeNode(pn->__children.p[0]);
else
dnode = NULL;
}
}
}
return dnode;
}
void printStatsNodes(){
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
ConsoleMessage("%25s %d\n","Nodes count", p->linearNodeTable->n);
}
int unRegisterX3DAnyNode(struct X3D_Node *node);
void killNodes()
{
int i;
struct X3D_Node* node;
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
for (i = 0; i < vectorSize(p->linearNodeTable); i++){
node = vector_get(struct X3D_Node *, p->linearNodeTable, i);
if (node != NULL) {
if (node->referenceCount <= 0) {
//ConsoleMessage ("%d ref %d\n",i,node->referenceCount);
//killNode(i);
unRegisterX3DAnyNode(node);
FREE_IF_NZ(node);
vector_set(struct X3D_Node *,p->linearNodeTable,i,NULL);
}
//else{
// printf("%d ", i);
//}
}
}
}
//will have sibprep_ and sibfin_ functions:
int isSiblingAffector(struct X3D_Node *node){
int ret = 0;
switch(node->_nodeType){
case NODE_DirectionalLight: //lights are always added, then global is checked on the local pass and skipped if not local
case NODE_SpotLight:
case NODE_PointLight:
case NODE_LocalFog:
case NODE_ClipPlane:
case NODE_Effect:
case NODE_TextureProjectorPerspective:
case NODE_TextureProjectorParallel:
ret = 1; break;
default:
ret = 0; break;
}
return ret;
}
//has _siblingAffector field:
//(in perl VRMLNodes.pm, __sibAffectors was added after all removeChildren)
// Proto (scene), Inline, Group, Transform, Anchor, Billboard, Collision,
// GeoLocation, GeoTransform, HAnimHumanoid, HAnimSite, EspduTransform, CADAssembly, CADLayer, CADPart,
// Viewport, Layer, LayoutLayer, LayoutGroup, ScreenGroup, PickableGroup
// siblingAffector action, but no add/remove children: staticGroup
//might have _siblingAffector field, but not used: LOD, Switch, HAnimJoint, HAnimSegment, CADLayer
int hasSiblingAffectorField(struct X3D_Node *node, int whereFrom){
//assume everything with AddChildren, RemoveChildren fields qualifies
// and this filter has already been applied ie we are inside AddRemoveChildren
int ret = 0;
// except:
if (node==NULL) {
printf ("hasSiblingAffectorField, node %p from line %d\n",node,whereFrom);
return 0;
}
switch(node->_nodeType){
case NODE_Proto:
case NODE_Inline:
case NODE_Group:
case NODE_Transform:
case NODE_Anchor:
case NODE_Billboard:
case NODE_Collision:
case NODE_GeoLocation:
case NODE_GeoTransform:
case NODE_HAnimSite:
case NODE_HAnimHumanoid:
//case NODE_HAnimSegment:
//case NODE_HAnimJoint:
case NODE_EspduTransform:
case NODE_CADAssembly:
//case NODE_CADLayer:
case NODE_CADPart:
case NODE_Viewport:
case NODE_Layer:
case NODE_LayoutLayer:
case NODE_LayoutGroup:
case NODE_ScreenGroup:
case NODE_PickableGroup:
case NODE_StaticGroup:
ret = 1; break;
default:
ret = 0; break;
}
return ret;
}
void *sibAffectorPtr(struct X3D_Node *node){
//gets the sibAffectors field from the X3DGrouping node (plus staticGroup)
// or returns null if not found
void *fieldPtr;
int *fieldOffsetsPtr;
fieldOffsetsPtr = (int*) NODE_OFFSETS[node->_nodeType];
fieldPtr = NULL;
while(fieldOffsetsPtr[0] > -1){
//printf("foff[0]=%d ft_sas=%d\n",fieldOffsetsPtr[0],FIELDNAMES___sibAffectors);
if(fieldOffsetsPtr[0] == FIELDNAMES___sibAffectors){
fieldPtr = offsetPointer_deref(char *, node,fieldOffsetsPtr[1]);
break;
}
fieldOffsetsPtr += FIELDOFFSET_LENGTH; // &fieldOffsetsPtr[5]; //5 ints per table entry
}
return fieldPtr;
}
void AddToSibAffectors(struct X3D_Node *parent, struct X3D_Node *affector){
//called from 2nd, big loop in startofloopnodeupdates to accumulate
// a list of nodes that affect their siblings, to store in parent
// as alternate to VK_ flagging parent, and doing 3 full loops over children[] in X3DGrouping child_ functions
// - a kind of short list so child_ functions do:
// a short loop (prep_sibAffectors), full loop (normalChildren), short loop (fin_sibAffectors)
//JAS
if (parent==NULL) {
printf ("in AddToSibAffectors, we have node parent NULL, node is a %s\n",stringNodeType(affector->_nodeType));
}
if(hasSiblingAffectorField(parent,__LINE__) && isSiblingAffector(affector)){
struct Multi_Node *safs = sibAffectorPtr(parent);
if(safs){
safs->p = REALLOC(safs->p,(safs->n+1)*sizeof(struct X3D_Node*));
safs->p[safs->n] = affector;
safs->n += 1;
}
}
}
void zeroSibAffectors(struct X3D_Node *node){
//called from first loop in startofloopnodeupdates
//we clear on each frame, then re-populate
struct Multi_Node* saf = sibAffectorPtr(node);
saf->n = 0; //not freeing p, will realloc in AddToSibAffectors
// Q. fragging/memory fragmentation? Multi_Node.nalloc needed?
// alternate to reallocs and MF.nalloc:
// 1. here go through p[] and set each one to NULL, but leave n.
// 2. then in Add, look for first null, realloc only if too short.
// 3. then in prep_sibAffectors and fin_sibAffectors check if entry is null and skip.
}
//dug9 dec 13 <<
int needs_updating_Inline(struct X3D_Node *node);
void update_Inline(struct X3D_Inline *node);
// Dec 14, 2012 new proto IS-A version (see below for older version)
void startOfLoopNodeUpdates(void) {
struct X3D_Node* node;
struct X3D_Node* pnode;
struct X3D_Anchor* anchorPtr;
struct Vector *parentVector;
int nParents;
int i,j,k,foundbound;
int* setBindPtr;
struct Multi_Node *addChildren;
struct Multi_Node *removeChildren;
struct Multi_Node *childrenPtr;
size_t offsetOfChildrenPtr;
/* process one inline per loop; do it outside of the lock/unlock memory table */
//struct Vector *loadInlines;
ppOpenGL_Utils p;
ttglobal tg = gglobal();
p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
if (rootNode() == NULL) return; /* nothing to do, and we have not really started yet */
/* initialization */
addChildren = NULL;
removeChildren = NULL;
childrenPtr = NULL;
parentVector = NULL;
//loadInlines = NULL;
offsetOfChildrenPtr = 0;
/* assume that we do not have any sensitive nodes at all... */
tg->Mainloop.HaveSensitive = FALSE;
tg->RenderFuncs.have_transparency = FALSE;
/* do not bother doing this if the inputparsing thread is active */
if (fwl_isinputThreadParsing()) return;
profile_start("loopnodeupdt");
LOCK_MEMORYTABLE
//printf ("\n******************************************\nstartOfLoopNodeUpdates\n");
/* go through the node table, and zero any bits of interest */
for (i=0; ilinearNodeTable); i++){
node = vector_get(struct X3D_Node *,p->linearNodeTable,i);
if (node != NULL) {
if (node->referenceCount <= 0) {
//unload_brotos -a new way to clean out an old scene of 2014- doesn't rely on reference counting
// when cleaning up a scene - it calls unregisterX3Dnode()
//ConsoleMessage ("%d ref %d\n",i,node->referenceCount);
//killNode(i);
//JAS printf ("node %p has zero reference count...it is a %s\n",
//JAS node,stringNodeType(node->_nodeType));
FREE_IF_NZ(node);
vector_set(struct X3D_Node *,p->linearNodeTable,i,NULL);
} else {
/* turn OFF these flags */
node->_renderFlags = node->_renderFlags & (0xFFFF^VF_Sensitive);
node->_renderFlags = node->_renderFlags & (0xFFFF^VF_Viewpoint);
node->_renderFlags = node->_renderFlags & (0xFFFF^VF_localLight);
node->_renderFlags = node->_renderFlags & (0xFFFF^VF_globalLight);
node->_renderFlags = node->_renderFlags & (0xFFFF^VF_Blend);
//JAS - move this within the ELSE statement as node is free'd by this time.
if(hasSiblingAffectorField(node,__LINE__)){
zeroSibAffectors(node);
}
}
}
}
/* turn OFF these flags */
{
struct X3D_Node* rn = rootNode();
rn->_renderFlags = rn->_renderFlags & (0xFFFF^VF_Sensitive);
rn->_renderFlags = rn->_renderFlags & (0xFFFF^VF_Viewpoint);
rn->_renderFlags = rn->_renderFlags & (0xFFFF^VF_localLight);
rn->_renderFlags = rn->_renderFlags & (0xFFFF^VF_globalLight);
rn->_renderFlags = rn->_renderFlags & (0xFFFF^VF_Blend);
}
/* sort the rootNode, if it is Not NULL */
/* remember, the rootNode is not in the linearNodeTable, so we have to do this outside
of that loop */
if (rootNode() != NULL) {
struct Multi_Node *children, *_sortedChildren;
node = (struct X3D_Node*)rootNode();
children = NULL;
_sortedChildren = NULL;
if(node->_nodeType == NODE_Proto){
children = &X3D_PROTO(node)->__children;
_sortedChildren = &X3D_PROTO(node)->_sortedChildren;
}
if(node->_nodeType == NODE_Group) {
children = &X3D_GROUP(node)->children;
_sortedChildren = &X3D_GROUP(node)->_sortedChildren;
}
sortChildren (__LINE__,children, _sortedChildren,rootNode()->_renderFlags & VF_shouldSortChildren);
rootNode()->_renderFlags=rootNode()->_renderFlags & (0xFFFF^VF_shouldSortChildren);
if(node->_nodeType == NODE_Proto){
//CHILDREN_NODE(Proto)
/* DRracer/t85.wrl has 'children' user fields on protos. This works with other browsers.
But not freewrl. Unless I hide the children field as _children. Then it works.
*/
addChildren = NULL; removeChildren = NULL;
offsetOfChildrenPtr = offsetof (struct X3D_Proto, __children);
if (((struct X3D_Proto *)node)->addChildren.n > 0) {
addChildren = &((struct X3D_Proto *)node)->addChildren;
childrenPtr = &((struct X3D_Proto *)node)->__children;
}
if (((struct X3D_Proto *)node)->removeChildren.n > 0) {
removeChildren = &((struct X3D_Proto *)node)->removeChildren;
childrenPtr = &((struct X3D_Proto *)node)->__children;
}
}else{
CHILDREN_NODE(Group)
}
/* this node possibly has to do add/remove children? */
if (childrenPtr != NULL) {
if (addChildren != NULL) {
AddRemoveChildren(node,childrenPtr,(struct X3D_Node * *) addChildren->p,addChildren->n,1,__FILE__,__LINE__);
addChildren->n=0;
}
if (removeChildren != NULL) {
AddRemoveChildren(node,childrenPtr,(struct X3D_Node * *) removeChildren->p,removeChildren->n,2,__FILE__,__LINE__);
removeChildren->n=0;
}
/* printf ("OpenGL, marking children changed\n"); */
MARK_EVENT(node,offsetOfChildrenPtr);
childrenPtr = NULL;
}
}
/* go through the list of nodes, and "work" on any that need work */
nParents = 0;
setBindPtr = NULL;
anchorPtr = NULL;
for (i=0; ilinearNodeTable); i++){
node = vector_get(struct X3D_Node *,p->linearNodeTable,i);
if (node != NULL)
if (node->referenceCount > 0) {
pnode = node;
node = getTypeNode(node); //+ dug9 dec 13
if(node == NULL && pnode != NULL) //+ dug9 sept 2014
if(pnode->_nodeType == NODE_Proto){
UNLOCK_MEMORYTABLE
/*dug9 sept 2014: I put load_EPI (externProtoInstance) here because I designed it like Inline
where we check and give a time slice to loading when we visit the node instance during render().
But that doesn't work for EPIs which have no concrete NODE type, nor VF_ flag
so render_hier/render() never visits them until they are loaded and we can
see the concrete type of their first node, and perculate VF_ flags up to the EPI
There were other options such as event queue, or following a cascade of protoInstance arrays
down the context heirarchy, or tinkering with the VF_ flag visitation rules in render()
or inventing a VF_Proto flag, or expanding the role of the resource thread to do more work
and keep a list of subscribers with the EPD (externProtoDeclare).
And any of those might work too. This was just convenient/easy/quick
for me, so feel free to move it.
*/
load_externProtoInstance(X3D_PROTO(pnode));
LOCK_MEMORYTABLE
node = getTypeNode(pnode);
}
if (node != NULL)
//switch (node->_nodeType) { //- dug9 dec 13
switch (node->_nodeType) { //+ dug9 dec 13
BEGIN_NODE(Shape)
/* send along a "look at me" flag if we are visible, or we should look again */
if ((X3D_SHAPE(node)->__occludeCheckCount <=0) ||
(X3D_SHAPE(node)->__visible)) {
update_renderFlag (X3D_NODE(pnode),VF_hasVisibleChildren);
/* printf ("shape occludecounter, pushing visiblechildren flags\n"); */
}
X3D_SHAPE(node)->__occludeCheckCount--;
/* printf ("shape occludecounter %d\n",X3D_SHAPE(node)->__occludeCheckCount); */
END_NODE
/* Lights. DirectionalLights are "scope relative", PointLights and
SpotLights are transformed */
BEGIN_NODE(DirectionalLight)
if (X3D_DIRECTIONALLIGHT(node)->on) {
if (X3D_DIRECTIONALLIGHT(node)->global)
update_renderFlag(pnode,VF_globalLight);
else{
//LOCAL_LIGHT_PARENT_FLAG
ADD_TO_PARENT_SIBAFFECTORS
}
}
END_NODE
BEGIN_NODE(SpotLight)
if (X3D_SPOTLIGHT(node)->on) {
if (X3D_SPOTLIGHT(node)->global)
update_renderFlag(pnode,VF_globalLight);
else{
//LOCAL_LIGHT_PARENT_FLAG
ADD_TO_PARENT_SIBAFFECTORS
}
}
END_NODE
BEGIN_NODE(PointLight)
if (X3D_POINTLIGHT(node)->on) {
if (X3D_POINTLIGHT(node)->global)
update_renderFlag(pnode,VF_globalLight);
else{
//LOCAL_LIGHT_PARENT_FLAG
ADD_TO_PARENT_SIBAFFECTORS
}
}
END_NODE
BEGIN_NODE(LocalFog)
ADD_TO_PARENT_SIBAFFECTORS
END_NODE
BEGIN_NODE(ClipPlane)
ADD_TO_PARENT_SIBAFFECTORS
END_NODE
BEGIN_NODE(Effect)
ADD_TO_PARENT_SIBAFFECTORS
END_NODE
BEGIN_NODE(TextureProjectorPerspective)
if (X3D_TEXTUREPROJECTORPERSPECTIVE(node)->on) {
if (X3D_TEXTUREPROJECTORPERSPECTIVE(node)->global)
update_renderFlag(pnode,VF_globalLight);
else{
//LOCAL_LIGHT_PARENT_FLAG
ADD_TO_PARENT_SIBAFFECTORS
}
}
END_NODE
BEGIN_NODE(TextureProjectorParallel)
if (X3D_TEXTUREPROJECTORPARALLEL(node)->on) {
if (X3D_TEXTUREPROJECTORPARALLEL(node)->global)
update_renderFlag(pnode,VF_globalLight);
else{
//LOCAL_LIGHT_PARENT_FLAG
ADD_TO_PARENT_SIBAFFECTORS
}
}
END_NODE
/* some nodes, like Extrusions, have "set_" fields same as normal internal fields,
eg, "set_spine" and "spine". Here we just copy the fields over, and remove the
"set_" fields. This works for MF* fields ONLY */
BEGIN_NODE(IndexedLineSet)
EVIN_AND_FIELD_SAME(colorIndex,IndexedLineSet)
EVIN_AND_FIELD_SAME(coordIndex,IndexedLineSet)
END_NODE
BEGIN_NODE(IndexedTriangleFanSet)
EVIN_AND_FIELD_SAME(index,IndexedTriangleFanSet)
END_NODE
BEGIN_NODE(IndexedTriangleSet)
EVIN_AND_FIELD_SAME(index,IndexedTriangleSet)
END_NODE
BEGIN_NODE(IndexedTriangleStripSet)
EVIN_AND_FIELD_SAME(index,IndexedTriangleStripSet)
END_NODE
BEGIN_NODE(GeoElevationGrid)
EVIN_AND_FIELD_SAME(height,GeoElevationGrid)
END_NODE
BEGIN_NODE(ElevationGrid)
EVIN_AND_FIELD_SAME(height,ElevationGrid)
END_NODE
BEGIN_NODE(Extrusion)
EVIN_AND_FIELD_SAME(crossSection,Extrusion)
EVIN_AND_FIELD_SAME(orientation,Extrusion)
EVIN_AND_FIELD_SAME(scale,Extrusion)
EVIN_AND_FIELD_SAME(spine,Extrusion)
END_NODE
BEGIN_NODE(IndexedFaceSet)
EVIN_AND_FIELD_SAME(colorIndex,IndexedFaceSet)
EVIN_AND_FIELD_SAME(coordIndex,IndexedFaceSet)
EVIN_AND_FIELD_SAME(normalIndex,IndexedFaceSet)
EVIN_AND_FIELD_SAME(texCoordIndex,IndexedFaceSet)
END_NODE
/* GeoViewpoint works differently than other nodes - see compile_GeoViewpoint for manipulation of these fields
BEGIN_NODE(GeoViewpoint)
EVIN_AND_FIELD_SAME(orientation,GeoViewpoint)
EVIN_AND_FIELD_SAME(position,GeoViewpoint)
END_NODE
*/
/* get ready to mark these nodes as Mouse Sensitive */
BEGIN_NODE(LineSensor) SIBLING_SENSITIVE(LineSensor) END_NODE
BEGIN_NODE(PointSensor) SIBLING_SENSITIVE(PointSensor) END_NODE
BEGIN_NODE(PlaneSensor) SIBLING_SENSITIVE(PlaneSensor) END_NODE
BEGIN_NODE(SphereSensor) SIBLING_SENSITIVE(SphereSensor) END_NODE
BEGIN_NODE(CylinderSensor) SIBLING_SENSITIVE(CylinderSensor) END_NODE
BEGIN_NODE(TouchSensor) SIBLING_SENSITIVE(TouchSensor) END_NODE
BEGIN_NODE(GeoTouchSensor) SIBLING_SENSITIVE(GeoTouchSensor) END_NODE
/* Anchor is Mouse Sensitive, AND has Children nodes */
BEGIN_NODE(Anchor)
propagateExtent(X3D_NODE(node));
ANCHOR_SENSITIVE(Anchor)
CHILDREN_NODE(Anchor)
END_NODE
BEGIN_NODE(CADFace)
// the attached Shape node will do the occlusion testing, if enabled.
update_renderFlag (X3D_NODE(pnode),VF_hasVisibleChildren);
END_NODE
BEGIN_NODE(CADLayer)
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(Switch)
END_NODE
BEGIN_NODE(CADPart)
sortChildren (__LINE__,&X3D_CADPART(node)->children,&X3D_CADPART(node)->_sortedChildren,pnode->_renderFlags & VF_shouldSortChildren);
TURN_OFF_SHOULDSORTCHILDREN
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(CADPart)
END_NODE
BEGIN_NODE(CADAssembly)
sortChildren (__LINE__,&X3D_CADASSEMBLY(node)->children,&X3D_CADASSEMBLY(node)->_sortedChildren,pnode->_renderFlags & VF_shouldSortChildren);
TURN_OFF_SHOULDSORTCHILDREN
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(CADAssembly)
END_NODE
/* maybe this is the current Viewpoint? */
BEGIN_NODE(Viewpoint) BINDABLE(Viewpoint) END_NODE
BEGIN_NODE(OrthoViewpoint) BINDABLE(OrthoViewpoint) END_NODE
BEGIN_NODE(GeoViewpoint) BINDABLE(GeoViewpoint) END_NODE
BEGIN_NODE(NavigationInfo)
//render_NavigationInfo ((struct X3D_NavigationInfo *)node);
BINDABLE(NavigationInfo)
END_NODE
BEGIN_NODE(StaticGroup)
/* we should probably not do this, but... */
sortChildren (__LINE__,&X3D_STATICGROUP(node)->children,&X3D_STATICGROUP(node)->_sortedChildren,pnode->_renderFlags & VF_shouldSortChildren);
TURN_OFF_SHOULDSORTCHILDREN
propagateExtent(X3D_NODE(node));
END_NODE
/* does this one possibly have add/removeChildren? */
BEGIN_NODE(Group)
sortChildren (__LINE__,&X3D_GROUP(node)->children,&X3D_GROUP(node)->_sortedChildren,pnode->_renderFlags & VF_shouldSortChildren);
TURN_OFF_SHOULDSORTCHILDREN
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(Group)
END_NODE
BEGIN_NODE(PickableGroup)
//sortChildren (__LINE__,&X3D_PICKABLEGROUP(node)->children,&X3D_PICKABLEGROUP(node)->_sortedChildren,pnode->_renderFlags & VF_shouldSortChildren);
//TURN_OFF_SHOULDSORTCHILDREN
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(PickableGroup)
END_NODE
BEGIN_NODE(Inline)
sortChildren (__LINE__,&X3D_INLINE(node)->__children,&X3D_INLINE(node)->_sortedChildren,node->_renderFlags & VF_shouldSortChildren);
TURN_OFF_SHOULDSORTCHILDREN
propagateExtent(X3D_NODE(node));
CHILDREN_ANY_NODE(Inline,__children)
END_NODE
BEGIN_NODE(Transform)
sortChildren (__LINE__,&X3D_TRANSFORM(node)->children,&X3D_TRANSFORM(node)->_sortedChildren,pnode->_renderFlags & VF_shouldSortChildren);
TURN_OFF_SHOULDSORTCHILDREN
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(Transform)
END_NODE
/* BEGIN_NODE(NurbsGroup)
CHILDREN_NODE(NurbsGroup)
END_NODE
*/
BEGIN_NODE(Contour2D)
CHILDREN_NODE(Contour2D)
END_NODE
BEGIN_NODE(HAnimSite)
CHILDREN_NODE(HAnimSite)
END_NODE
BEGIN_NODE(HAnimSegment)
CHILDREN_NODE(HAnimSegment)
END_NODE
BEGIN_NODE(HAnimJoint)
CHILDREN_NODE(HAnimJoint)
END_NODE
BEGIN_NODE(Billboard)
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(Billboard)
update_renderFlag(pnode,VF_Proximity);
END_NODE
BEGIN_NODE(Collision)
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(Collision)
END_NODE
BEGIN_NODE(Switch)
propagateExtent(X3D_NODE(node));
CHILDREN_SWITCH_NODE(Switch)
END_NODE
BEGIN_NODE(LOD)
propagateExtent(X3D_NODE(node));
CHILDREN_LOD_NODE
update_renderFlag(pnode,VF_Proximity);
END_NODE
/* Material - transparency of materials */
BEGIN_NODE(Material) CHECK_MATERIAL_TRANSPARENCY END_NODE
BEGIN_NODE(TwoSidedMaterial) CHECK_TWOSIDED_MATERIAL_TRANSPARENCY END_NODE
BEGIN_NODE(FillProperties) CHECK_FILL_PROPERTY_FILLED END_NODE
/* Textures - check transparency */
BEGIN_NODE(ImageTexture) CHECK_IMAGETEXTURE_TRANSPARENCY END_NODE
BEGIN_NODE(PixelTexture) CHECK_PIXELTEXTURE_TRANSPARENCY END_NODE
BEGIN_NODE(MovieTexture) CHECK_MOVIETEXTURE_TRANSPARENCY END_NODE
BEGIN_NODE(VolumeData)
tg->RenderFuncs.have_transparency = TRUE;
update_renderFlag(X3D_NODE(pnode),VF_Blend | VF_shouldSortChildren);\
END_NODE
BEGIN_NODE(SegmentedVolumeData)
tg->RenderFuncs.have_transparency = TRUE;
update_renderFlag(X3D_NODE(pnode),VF_Blend | VF_shouldSortChildren);\
END_NODE
BEGIN_NODE(IsoSurfaceVolumeData)
tg->RenderFuncs.have_transparency = TRUE;
update_renderFlag(X3D_NODE(pnode),VF_Blend | VF_shouldSortChildren);\
END_NODE
/* Backgrounds, Fog */
BEGIN_NODE(Background)
BINDABLE(Background)
//if (X3D_BACKGROUND(node)->isBound) update_renderFlag (X3D_NODE(pnode),VF_hasVisibleChildren);
END_NODE
BEGIN_NODE(TextureBackground)
BINDABLE(TextureBackground)
//if (X3D_TEXTUREBACKGROUND(node)->isBound) update_renderFlag (X3D_NODE(pnode),VF_hasVisibleChildren);
END_NODE
BEGIN_NODE(Fog)
BINDABLE(Fog)
//if (X3D_FOG(node)->isBound) update_renderFlag (X3D_NODE(pnode),VF_hasVisibleChildren);
END_NODE
/* VisibilitySensor needs its own flag sent up the chain */
BEGIN_NODE (VisibilitySensor)
#ifdef OCCLUSION_STUFF
/* send along a "look at me" flag if we are visible, or we should look again */
if ((X3D_VISIBILITYSENSOR(node)->__occludeCheckCount <=0) ||
(X3D_VISIBILITYSENSOR(node)->__visible)) {
update_renderFlag (X3D_NODE(pnode),VF_hasVisibleChildren);
/* printf ("vis occludecounter, pushing visiblechildren flags\n"); */
}
X3D_VISIBILITYSENSOR(node)->__occludeCheckCount--;
/* VisibilitySensors have a transparent bounding box we have to render */
update_renderFlag(pnode,VF_Blend & VF_shouldSortChildren);
#else //simple AABB
//pnode->_renderFlags = VF_Other;
//X3D_VISIBILITYSENSOR(node)->__Samples = 0; //cleared at end of do_visibilitysensor
update_renderFlag(pnode,VF_Other);
#endif
END_NODE
/* ProximitySensor needs its own flag sent up the chain */
BEGIN_NODE (ProximitySensor)
if (X3D_PROXIMITYSENSOR(node)->enabled) update_renderFlag(pnode,VF_Proximity);
END_NODE
/* GeoProximitySensor needs its own flag sent up the chain */
BEGIN_NODE (GeoProximitySensor)
if (X3D_GEOPROXIMITYSENSOR(node)->enabled) update_renderFlag(pnode,VF_Proximity);
END_NODE
/* GeoLOD needs its own flag sent up the chain, and it has to push extent up, too */
BEGIN_NODE (GeoLOD)
if (!(NODE_NEEDS_COMPILING)) {
handle_GeoLODRange(X3D_GEOLOD(node));
}
/* update_renderFlag(pnode,VF_Proximity); */
propagateExtent(X3D_NODE(node));
END_NODE
BEGIN_NODE (GeoTransform)
sortChildren (__LINE__,&X3D_GEOTRANSFORM(node)->children,&X3D_GEOTRANSFORM(node)->_sortedChildren,pnode->_renderFlags & VF_shouldSortChildren);
TURN_OFF_SHOULDSORTCHILDREN
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(GeoTransform)
END_NODE
BEGIN_NODE (GeoLocation)
sortChildren (__LINE__,&X3D_GEOLOCATION(node)->children,&X3D_GEOLOCATION(node)->_sortedChildren,pnode->_renderFlags & VF_shouldSortChildren);
TURN_OFF_SHOULDSORTCHILDREN
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(GeoLocation)
END_NODE
BEGIN_NODE (EspduTransform)
propagateExtent(X3D_NODE(node));
CHILDREN_NODE(EspduTransform)
END_NODE
BEGIN_NODE(MetadataSFBool) CMD(SFBool,node); END_NODE
BEGIN_NODE(MetadataSFFloat) CMD(SFFloat,node); END_NODE
BEGIN_NODE(MetadataMFFloat) CMD(MFFloat,node); END_NODE
BEGIN_NODE(MetadataSFRotation) CMD(SFRotation,node); END_NODE
BEGIN_NODE(MetadataMFRotation) CMD(MFRotation,node); END_NODE
BEGIN_NODE(MetadataSFVec3f) CMD(SFVec3f,node); END_NODE
BEGIN_NODE(MetadataMFVec3f) CMD(MFVec3f,node); END_NODE
BEGIN_NODE(MetadataMFBool) CMD(MFBool,node); END_NODE
BEGIN_NODE(MetadataSFInt32) CMD(SFInt32,node); END_NODE
BEGIN_NODE(MetadataMFInt32) CMD(MFInt32,node); END_NODE
BEGIN_NODE(MetadataSFNode) CMD(SFNode,node); END_NODE
BEGIN_NODE(MetadataMFNode) CMD(MFNode,node); END_NODE
BEGIN_NODE(MetadataSFColor) CMD(SFColor,node); END_NODE
BEGIN_NODE(MetadataMFColor) CMD(MFColor,node); END_NODE
BEGIN_NODE(MetadataSFColorRGBA) CMD(SFColorRGBA,node); END_NODE
BEGIN_NODE(MetadataMFColorRGBA) CMD(MFColorRGBA,node); END_NODE
BEGIN_NODE(MetadataSFTime) CMD(SFTime,node); END_NODE
BEGIN_NODE(MetadataMFTime) CMD(MFTime,node); END_NODE
BEGIN_NODE(MetadataSFString) CMD(SFString,node); END_NODE
BEGIN_NODE(MetadataMFString) CMD(MFString,node); END_NODE
BEGIN_NODE(MetadataSFVec2f) CMD(SFVec2f,node); END_NODE
BEGIN_NODE(MetadataMFVec2f) CMD(MFVec2f,node); END_NODE
BEGIN_NODE(MetadataSFImage) CMD(SFImage,node); END_NODE
BEGIN_NODE(MetadataSFVec3d) CMD(SFVec3d,node); END_NODE
BEGIN_NODE(MetadataMFVec3d) CMD(MFVec3d,node); END_NODE
BEGIN_NODE(MetadataSFDouble) CMD(SFDouble,node); END_NODE
BEGIN_NODE(MetadataMFDouble) CMD(MFDouble,node); END_NODE
BEGIN_NODE(MetadataSFMatrix3f) CMD(SFMatrix3f,node); END_NODE
BEGIN_NODE(MetadataMFMatrix3f) CMD(MFMatrix3f,node); END_NODE
BEGIN_NODE(MetadataSFMatrix3d) CMD(SFMatrix3d,node); END_NODE
BEGIN_NODE(MetadataMFMatrix3d) CMD(MFMatrix3d,node); END_NODE
BEGIN_NODE(MetadataSFMatrix4f) CMD(SFMatrix4f,node); END_NODE
BEGIN_NODE(MetadataMFMatrix4f) CMD(MFMatrix4f,node); END_NODE
BEGIN_NODE(MetadataSFMatrix4d) CMD(SFMatrix4d,node); END_NODE
BEGIN_NODE(MetadataMFMatrix4d) CMD(MFMatrix4d,node); END_NODE
BEGIN_NODE(MetadataSFVec2d) CMD(SFVec2d,node); END_NODE
BEGIN_NODE(MetadataMFVec2d) CMD(MFVec2d,node); END_NODE
BEGIN_NODE(MetadataSFVec4f) CMD(SFVec4f,node); END_NODE
BEGIN_NODE(MetadataMFVec4f) CMD(MFVec4f,node); END_NODE
BEGIN_NODE(MetadataSFVec4d) CMD(SFVec4d,node); END_NODE
BEGIN_NODE(MetadataMFVec4d) CMD(MFVec4d,node); END_NODE
}
}
/* now, act on this node for Sensitive nodes. here we tell the PARENTS that they are sensitive */
if (nParents != 0) {
for (j=0; j_renderFlags = n->_renderFlags | VF_Sensitive;
}
/* tell mainloop that we have to do a sensitive pass now */
tg->Mainloop.HaveSensitive = TRUE;
nParents = 0;
}
/* Anchor nodes are slightly different than sibling-sensitive nodes */
if (anchorPtr != NULL) {
anchorPtr->_renderFlags = anchorPtr->_renderFlags | VF_Sensitive;
/* tell mainloop that we have to do a sensitive pass now */
tg->Mainloop.HaveSensitive = TRUE;
anchorPtr = NULL;
}
/* do BINDING of Viewpoint Nodes */
if (setBindPtr != NULL) {
/* check the set_bind eventin to see if it is TRUE or FALSE */
if (*setBindPtr < 100) {
/* up_vector is reset after a bind */
//if (*setBindPtr==1) reset_upvector();
send_bind_to(node,*setBindPtr);
//if(0){
//bind_node (node, getActiveBindableStacks(tg)->viewpoint);
////dug9 added July 24, 2009: when you bind, it should set the
////avatar to the newly bound viewpoint pose and forget any
//// cumulative avatar navigation from the last viewpoint parent
//if (node->_nodeType==NODE_Viewpoint) {
// struct X3D_Viewpoint* vp = (struct X3D_Viewpoint *) node;
// bind_Viewpoint(vp);
// setMenuStatusVP (vp->description->strptr);
//} else if (node->_nodeType==NODE_OrthoViewpoint) {
// struct X3D_OrthoViewpoint *ovp = (struct X3D_OrthoViewpoint *) node;
// bind_OrthoViewpoint(ovp);
// setMenuStatusVP (ovp->description->strptr);
//} else {
// struct X3D_GeoViewpoint *gvp = (struct X3D_GeoViewpoint *) node;
// bind_GeoViewpoint(gvp);
// setMenuStatusVP (gvp->description->strptr);
//}
//}
}
setBindPtr = NULL;
}
/* this node possibly has to do add/remove children? */
if (childrenPtr != NULL) {
//JAS printf ("ok, childrenPtr is NOT NULL in startOfLoopNodeUpdates\n");
if (addChildren != NULL) {
//int i;
//for (i=0; in; i++) {
//struct X3D_Node *ch = X3D_NODE(addChildren->p[i]);
//printf ("SOLNU: adding child indx %d, is %p\n",i,ch);
//}
AddRemoveChildren(node,childrenPtr,(struct X3D_Node * *) addChildren->p,addChildren->n,1,__FILE__,__LINE__);
// now go through and tell the addChildren field that the
// event has been processed.
for (i=0; in; i++) {
struct X3D_Node *ch = X3D_NODE(addChildren->p[i]);
add_parent(ch,node,__FILE__,__LINE__);
}
addChildren->n=0;
}
if (removeChildren != NULL) {
AddRemoveChildren(node,childrenPtr,(struct X3D_Node * *) removeChildren->p,removeChildren->n,2,__FILE__,__LINE__);
// now go through and tell the addChildren field that the
// event has been processed.
for (i=0; in; i++) {
struct X3D_Node *ch = X3D_NODE(removeChildren->p[i]);
remove_parent(ch,node);
}
removeChildren->n=0;
}
/* printf ("OpenGL, marking children changed\n"); */
MARK_EVENT(node,offsetOfChildrenPtr);
childrenPtr = NULL;
}
}
UNLOCK_MEMORYTABLE
/* now, we can go and tell the grouping nodes which ones are the lucky ones that contain the current Viewpoint node */
foundbound = FALSE;
for(k=0;kBindable.bstacks);k++){
bindablestack *bstack = vector_get(bindablestack*,tg->Bindable.bstacks,k);
//if (vectorSize(getActiveBindableStacks(tg)->viewpoint) > 0) {
if( vectorSize(bstack->viewpoint) > 0){
//ConsoleMessage ("going to updateRF on viewpoint, stack is %d in size\n", vectorSize(tg->Bindable.viewpoint_stack));
//struct X3D_Node *boundvp = vector_back(struct X3D_Node*,getActiveBindableStacks(tg)->viewpoint);
struct X3D_Node *boundvp = vector_back(struct X3D_Node*,bstack->viewpoint);
update_renderFlag(boundvp, VF_Viewpoint);
calculateNearFarplanes(boundvp, bstack->layerId);
calculateViewingDistIfJustBound(boundvp,bstack->layerId);
//update_renderFlag(vector_back(struct X3D_Node*,
// tg->Bindable.viewpoint_stack), VF_Viewpoint);
//calculateNearFarplanes(vector_back(struct X3D_Node*, tg->Bindable.viewpoint_stack));
foundbound = TRUE;
}
}
if(!foundbound){
/* keep these at the defaults, if no viewpoint is present. */
X3D_Viewer *viewer = Viewer();
viewer->nearPlane = DEFAULT_NEARPLANE;
viewer->farPlane = DEFAULT_FARPLANE;
viewer->backgroundPlane = DEFAULT_BACKGROUNDPLANE;
}
profile_end("loopnodeupdt");
}
//#define VERBOSE 1
void markForDispose(struct X3D_Node *node, int recursive){
int *fieldOffsetsPtr;
char * fieldPtr;
if (node==NULL) return;
if (node==X3D_NODE(rootNode()) && node->_nodeType != NODE_Proto) {
ConsoleMessage ("not disposing rootNode");
return;
}
#ifdef VERBOSE
ConsoleMessage ("\nmarkingForDispose %p (%s) currently at %d",node,
stringNodeType(node->_nodeType),node->referenceCount);
#endif
if (node->referenceCount > 0)
node->referenceCount--;
else
return; //already marked
if (recursive) {
/* cast a "const int" to an "int" */
fieldOffsetsPtr = (int*) NODE_OFFSETS[node->_nodeType];
/*go thru all field*/
while (*fieldOffsetsPtr != -1) {
fieldPtr = offsetPointer_deref(char *, node,*(fieldOffsetsPtr+1));
#ifdef VERBOSE
ConsoleMessage ("looking at field %s type %s",FIELDNAMES[*fieldOffsetsPtr],FIELDTYPES[*(fieldOffsetsPtr+2)]);
#endif
/* some fields we skip, as the pointers are duplicated, and we CAN NOT free both */
if (*fieldOffsetsPtr == FIELDNAMES_setValue)
break; /* can be a duplicate SF/MFNode pointer */
if (*fieldOffsetsPtr == FIELDNAMES_valueChanged)
break; /* can be a duplicate SF/MFNode pointer */
if (*fieldOffsetsPtr == FIELDNAMES__selected)
break; /* can be a duplicate SFNode pointer - field only in NODE_LOD and NODE_GeoLOD */
if (*fieldOffsetsPtr == FIELDNAMES___oldChildren)
break; /* can be a duplicate SFNode pointer - field only in NODE_LOD and NODE_GeoLOD */
if (*fieldOffsetsPtr == FIELDNAMES___oldKeyPtr)
break; /* used for seeing if interpolator values change */
if (*fieldOffsetsPtr == FIELDNAMES___oldKeyValuePtr)
break; /* used for seeing if interpolator values change */
/* GeoLOD nodes, the children field exports either the rootNode, or the list of child nodes */
if (node->_nodeType == NODE_GeoLOD) {
if (*fieldOffsetsPtr == FIELDNAMES_children) break;
}
if (*fieldOffsetsPtr == FIELDNAMES__shaderUserDefinedFields)
break; /* have to get rid of the fields of a shader here....*/
/* nope, not a special field, lets just get rid of it as best we can */
switch(*(fieldOffsetsPtr+2)){
case FIELDTYPE_MFNode: {
int i;
struct Multi_Node* MNode;
struct X3D_Node *tp;
MNode=(struct Multi_Node *)fieldPtr;
/* printf (" ... field MFNode, %s type %s\n",FIELDNAMES[*fieldOffsetsPtr],FIELDTYPES[*(fieldOffsetsPtr+2)]); */
for (i=0; in; i++) {
tp = MNode->p[i];
if (tp!=NULL) {
#ifdef VERBOSE
ConsoleMessage ("calling markForDispose on node %p as it is an element of an MFNode",tp);
#endif
markForDispose(tp,TRUE);
}
}
// MNode->n=0; unlink_node needs this in order to properly unlink children.
break;
}
case FIELDTYPE_SFNode: {
struct X3D_Node *SNode;
memcpy(&SNode,fieldPtr,sizeof(struct X3D_Node *));
#ifdef VERBOSE
ConsoleMessage ("SFNode, field is %p...",SNode);
if (SNode != NULL) {
ConsoleMessage ("SFNode, .... and it is of type %s",stringNodeType(SNode->_nodeType));
ConsoleMessage (" ... field SFNode, %s type %s\n",FIELDNAMES[*fieldOffsetsPtr],FIELDTYPES[*(fieldOffsetsPtr+2)]);
}
#endif
if(SNode && SNode->referenceCount > 0) {
#ifdef VERBOSE
ConsoleMessage ("calling markForDispose on node %p as it is contents of SFNode field",SNode);
#endif
markForDispose(SNode, TRUE);
}
break;
}
default:; /* do nothing - field not malloc'd */
}
fieldOffsetsPtr += FIELDOFFSET_LENGTH;
}
}
}
#undef VERBOSE
#ifdef OLDCODE
OLDCODE #define DELETE_IF_IN_PRODCON(aaa) \
OLDCODE if (tg->ProdCon.aaa) { \
OLDCODE bool foundIt = FALSE; \
OLDCODE /* ConsoleMessage ("ProdCon stack is %d in size\n",vectorSize(tg->ProdCon.aaa)); */ \
OLDCODE for (i=0; iProdCon.aaa); i++) { \
OLDCODE if (vector_get(struct X3D_Node*,tg->ProdCon.aaa, i) == structptr) { \
OLDCODE foundIt = TRUE; \
OLDCODE /* ConsoleMessage ("found it in the stack!\n"); */ \
OLDCODE } \
OLDCODE } \
OLDCODE if (foundIt) { \
OLDCODE struct Vector *newStack = newVector(struct X3D_Node*, 2); \
OLDCODE for (i=0; iProdCon.aaa); i++) { \
OLDCODE if (vector_get(struct X3D_Node*,tg->ProdCon.aaa, i) != structptr) { \
OLDCODE vector_pushBack(struct X3D_Node*, newStack, \
OLDCODE vector_get(struct X3D_Node*,tg->ProdCon.aaa,i)); \
OLDCODE } \
OLDCODE } \
OLDCODE deleteVector(struct X3D_Node*, tg->ProdCon.aaa); \
OLDCODE tg->ProdCon.aaa = newStack; \
OLDCODE } \
OLDCODE }
OLDCODE
OLDCODE #define DELETE_IF_IN_STACK(aaa) \
OLDCODE if (tg->Bindable.aaa) { \
OLDCODE bool foundIt = FALSE; \
OLDCODE /* ConsoleMessage ("Bindable stack is %d in size\n",vectorSize(tg->Bindable.aaa)); */ \
OLDCODE for (i=0; iBindable.aaa); i++) { \
OLDCODE if (vector_get(struct X3D_Node*,tg->Bindable.aaa, i) == structptr) { \
OLDCODE foundIt = TRUE; \
OLDCODE /* ConsoleMessage ("found it in the stack!\n"); */ \
OLDCODE } \
OLDCODE } \
OLDCODE if (foundIt) { \
OLDCODE struct Vector *newStack = newVector(struct X3D_Node*, 2); \
OLDCODE for (i=0; iBindable.aaa); i++) { \
OLDCODE if (vector_get(struct X3D_Node*,tg->Bindable.aaa, i) != structptr) { \
OLDCODE vector_pushBack(struct X3D_Node*, newStack, \
OLDCODE vector_get(struct X3D_Node*,tg->Bindable.aaa,i)); \
OLDCODE } \
OLDCODE } \
OLDCODE deleteVector(struct X3D_Node*, tg->Bindable.aaa); \
OLDCODE tg->Bindable.aaa = newStack; \
OLDCODE } \
OLDCODE }
#endif //OLDCODE
//#define WRLMODE(val) (((val) % 4)+4) //jan 2013 codegen PROTOKEYWORDS[] was ordered with x3d synonyms first, wrl last
//#define X3DMODE(val) ((val) % 4)
// OLDCODE #ifndef DISABLER
BOOL walk_fields(struct X3D_Node* node, BOOL (*callbackFunc)(), void* callbackData)
// OLDCODE #else
// OLDCODE BOOL walk_fields(struct X3D_Node* node, BOOL (*callbackFunc)(void *callbackData,struct X3D_Node* node,int jfield,union anyVrml *fieldPtr,
// OLDCODE const char *fieldName, indexT mode, indexT type,int isource,BOOL publicfield), void* callbackData)
// OLDCODE #endif
{
//field isource: 0=builtin 1=script user field 2=shader_program user field 3=Proto/Broto user field 4=group __protoDef
int type,mode,source;
BOOL publicfield;
int *fieldOffsetsPtr;
int jfield;
union anyVrml *fieldPtr;
const char* fname;
int foundField = 0;
source = -1;
mode = 0;
type = 0;
fieldPtr = NULL;
jfield = -1;
// field/event exists on the node?
fieldOffsetsPtr = (int *)NODE_OFFSETS[node->_nodeType];
/*go thru all builtin fields (borrowed from OpenGL_Utils killNode() L.3705*/
while (*fieldOffsetsPtr != -1) {
fname = FIELDNAMES[fieldOffsetsPtr[0]];
//skip private fields which scene authors shouldn't be routing or ISing to
publicfield = fname && (fname[0] != '_') ? TRUE : FALSE;
mode = PKW_from_KW(fieldOffsetsPtr[3]);
type = fieldOffsetsPtr[2];
//retrieve nodeinstance values
fieldPtr = (union anyVrml*)offsetPointer_deref(char *, node,*(fieldOffsetsPtr+1));
source = 0;
jfield++;
foundField = callbackFunc(callbackData,node,jfield,fieldPtr,fname,mode,type,source,publicfield);
if( foundField )break;
fieldOffsetsPtr += FIELDOFFSET_LENGTH;
}
if(!foundField)
{
//user-field capable node?
int user;
user = nodeTypeSupportsUserFields(node);
jfield = -1;
publicfield = 1; //assume all user fields are public
if(user)
{
//lexer_stringUser_fieldName(me->lexer, name, mode);
//struct VRMLParser* parser;
//struct VRMLLexer* lexer;
//ttglobal tg = gglobal();
//lexer = NULL;
//parser = tg->CParse.globalParser;
//if (parser)
// lexer = parser->lexer;
//user fields on user-field-capable nodes
switch(node->_nodeType)
{
case NODE_Script:
case NODE_ComposedShader:
case NODE_ShaderProgram :
case NODE_Effect :
case NODE_PackagedShader:
{
int j; //, nameIndex;
struct ScriptFieldDecl* sfield;
struct Shader_Script* shader = NULL;
switch(node->_nodeType)
{
case NODE_Script: shader =(struct Shader_Script *)(X3D_SCRIPT(node)->__scriptObj); break;
case NODE_ComposedShader: shader =(struct Shader_Script *)(X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields); break;
case NODE_ShaderProgram: shader =(struct Shader_Script *)(X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields); break;
case NODE_PackagedShader: shader =(struct Shader_Script *)(X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields); break;
case NODE_Effect: shader =(struct Shader_Script *)(X3D_EFFECT(node)->_shaderUserDefinedFields); break;
}
if (shader)
for(j=0; j!=vectorSize(shader->fields); ++j)
{
sfield= vector_get(struct ScriptFieldDecl*, shader->fields, j);
mode = sfield->fieldDecl->PKWmode;
fname = ScriptFieldDecl_getName(sfield);
type = sfield->fieldDecl->fieldType;
fieldPtr = &sfield->value;
source = node->_nodeType == NODE_Script ? 1 : 2;
jfield = j;
foundField = callbackFunc(callbackData,node,jfield,fieldPtr,fname,mode,type,source,publicfield);
if( foundField)
break;
}
}
break;
case NODE_Proto:
{
int j; //, nameIndex;
struct ProtoFieldDecl* pfield;
struct X3D_Proto* pnode = (struct X3D_Proto*)node;
if(pnode) {
struct ProtoDefinition* pstruct = (struct ProtoDefinition*) pnode->__protoDef;
if(pstruct)
if(pstruct->iface)
for(j=0; j!=vectorSize(pstruct->iface); ++j)
{
pfield= vector_get(struct ProtoFieldDecl*, pstruct->iface, j);
mode = pfield->mode;
fname = pfield->cname;
type = pfield->type;
fieldPtr = &pfield->defaultVal;
source = 3;
jfield = j;
foundField = callbackFunc(callbackData,node,jfield,fieldPtr,fname,mode,type,source,publicfield);
if( foundField)
break;
}
}
}
case NODE_Group:
//not sure how to do it with the metanode interface and mangled names
break;
default:
break;
}
}
}
return foundField;
}
/*
memory management policy, Feb 22, 2013, dug9 after adding unlink_node() call to killNode()
Background: we aren't using any smart pointers / garbage collection library in freewrl. Just old fashioned
malloc and free, with one exception:
We register malloced nodes in linearNodeTable, and when their reference
count goes to zero we call killNode (which calls unlink_node()) and deallocate their memory.
There's one place -startofloopnodeupdates- and one function -killNode- where they get deleted. But there's
two basic scenarios:
a) a node is markForDispose() during the freewrl session. tests/46.wrl
b) you anchor or File > Open another scene. The old scene -in kill_OldWorld() markForDispose() calls
referenceCount-- and then when the new scene comes into startofloopnodeupdates() all the old
nodes trigger a call for killNode().
So to test, I used 46.wrl and File>Open from the statusbar, and that would trigger some killNode activity
(for FileOpen you can open an empty scene with just the vrml header, to simplify debugging)
As I started to do this, freewrl bombed here and there with different data sets. One thing that will
help is to be consistent about what we manage. For that have a policy: what malloced things we are
managing now, so as programmers we are clear on what gets linked, and deleted. We'll call the carefully
linked and unlinked and deallocated nodes 'managed nodes' and the fields we manage 'managed fields'.
Examples,
a) a node hold pointers to other nodes in its SFNode and MFNode fields such as 'children' and
'material'. We'll call all those children.
b) a node holds pointers to other nodes that have it as a child, in its parentVector.
A DEF/USE pair of parent nodes mean the child's parentVector will have 2 entries, one for each
of the DEF and USE.
Here's the rule (I used) for managing nodes:
- Definitions:
public field: a field with no _ prefix on the name, or else its a user field in a Script/shader or Proto
value holding field: initializeOnly/field or inputOutput/exposedField
event field: inputOnly/eventIn or outputOnly/eventOut
node field: SFNode or MFNode type
managed field: value holding public node field, plus prescribed fields, minus exempted fields
prescribed fields: fields we decided to also manage: (none)
exempted fields: fields we decided not to manage: (none)
- if a node is in a managed field of another node -a parent- then it
registers/adds that parent in its own parentVector.
- when the node is taken out/removed from a managed field, it removes the parent
from its parentVector (if it's in just one managed field. If in 2, and removed from one, then parent stays)
- when a node deletes itself, it:
a) goes through all its managed fields and it tells those nodes -called children- to delete it
from their parentVector. Then it clears/zeros that field in itself to zero so its not
pointing at those children. And
b) it goes through its parentVector and tells each parent to remove it from any managed fields.
- if a node is in an event field or private field then it does not register that node in its parent field
- if a node gets routed to an event field of a target node, no parent is registered.
- if a node gets routed from an event field of a source node, the source node is not
registerd in its parentVector (example: script node generates a node in an eventOut field,
and whether or not it's routed anywhere, the script is not put into the nodes' parent list)
HTH
*/
BOOL isManagedField(int mode, int type, BOOL isPublic)
{
BOOL isManaged = (type == FIELDTYPE_SFNode || type == FIELDTYPE_MFNode);
isManaged = isManaged && (mode == PKW_initializeOnly || mode == PKW_inputOutput);
isManaged = isManaged && isPublic;
return isManaged;
}
/* print the parent vector and and SFNode and MFNode subfield entry pointers
for debugging unlink_node (and any linking code)
-needs generalization for FILE*
-maybe a dumpscreen option to get all rootnodes
*/
void indentf(int indent){
int m;
for(m=0;m 80)
// return FALSE;
//if(publicfield && (type == FIELDTYPE_SFNode || type == FIELDTYPE_MFNode))
if(isManagedField(type,mode,publicfield))
{
int n,k,haveSomething;
struct X3D_Node **plist, *sfn;
haveSomething = (type==FIELDTYPE_SFNode && fieldPtr->sfnode) || (type==FIELDTYPE_MFNode && fieldPtr->mfnode.n);
if(haveSomething){
indentf(*level);
printf("%s ",fieldName);
if(type==FIELDTYPE_SFNode){
plist = &fieldPtr->sfnode;
n = 1;
}else{
plist = fieldPtr->mfnode.p;
n = fieldPtr->mfnode.n;
if(n > 1){
printf("[\n");
(*level)++;
//indentf((*level));
}
}
for(k=0;k1) indentf((*level));
print_node_links0(sfn,level);
}
if(type==FIELDTYPE_MFNode && n > 1){
(*level)--;
indentf((*level));
printf("]\n");
}
}
}
(*level)--;
return FALSE; //false to keep walking fields, true to break out
}
void print_node_links0(struct X3D_Node* sfn, int *level)
{
if(sfn)
{
/* unlink children in any SFNode or MFNode field of node */
printf("node %p ",sfn);
if(sfn->_parentVector && vectorSize(sfn->_parentVector)){
int j;
printf(" parents={");
for(j=0;j_parentVector);j++){
struct X3D_Node *parent = vector_get(struct X3D_Node *,sfn->_parentVector, j);
printf("%p, ",parent);
}
printf("}");
}
printf("\n");
walk_fields(sfn,cbPrintLinks,level);
}
}
void print_node_links(struct X3D_Node* sfn)
{
int level = 0;
print_node_links0(sfn,&level);
if(level != 0)
printf("ouch level =%d\n",level);
}
BOOL cbUnlinkChild(void *callbackData,struct X3D_Node* node,int jfield,
union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
{
if(isManagedField(mode,type,publicfield)){
if(type == FIELDTYPE_SFNode){
struct X3D_Node **sfn = &fieldPtr->sfnode;
AddRemoveSFNodeFieldChild(node,sfn,*sfn,2,__FILE__,__LINE__);
if(fieldPtr->sfnode)
printf("didn't delete sfnode child\n");
}else if(type == FIELDTYPE_MFNode){
struct Multi_Node* mfn = &fieldPtr->mfnode;
AddRemoveChildren(node,mfn,mfn->p,mfn->n,2,__FILE__,__LINE__);
}
}
return FALSE; //false to keep walking fields, true to break out
}
BOOL cbUnlinkParent(void *callbackData,struct X3D_Node* parent,int jfield,
union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
{
struct X3D_Node* node = X3D_NODE(callbackData);
if(isManagedField(mode,type,publicfield)){
if(type == FIELDTYPE_SFNode){
struct X3D_Node **sfn = &fieldPtr->sfnode;
AddRemoveSFNodeFieldChild(parent,sfn,node,2,__FILE__,__LINE__);
}else if(type == FIELDTYPE_MFNode){
struct Multi_Node* mfn = &fieldPtr->mfnode;
AddRemoveChildren(parent,mfn,&node,1,2,__FILE__,__LINE__); //Q. is 2 remove?
}
}
return FALSE; //false to keep walking fields, true to break out
}
void unlink_node(struct X3D_Node* node)
{
if(node)
{
/* unlink children in any SFNode or MFNode field of node */
walk_fields(node,cbUnlinkChild,NULL);
/* unlink/remove node from any SFNode or MFNode field of parents */
if(node->_parentVector && vectorSize(node->_parentVector)){
int j;
struct Vector* pp = newVector(struct X3D_Node*,vectorSize(node->_parentVector));
for(j=0;j_parentVector);j++){
struct X3D_Node *parent = vector_get(struct X3D_Node *,node->_parentVector, j);
vector_pushBack(struct X3D_Node*,pp,parent);
}
for(j=0;j_parentVector->n = 0;
deleteVector(struct X3D_Node*, pp);
}
}
}
void deleteMallocedFieldValue(int type,union anyVrml *fieldPtr);
BOOL cbFreeMallocedBuiltinField(void *callbackData,struct X3D_Node* node,int jfield,
union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
{
//for builtins, the field is malloced as part of the node size, so we don't free the field itself
// .. just if its a complex field type holding a malloced pointer
// .. like MF.p or SFString.ptr
// and only if the node owns the pointer, which we determine by if the field is initializeOnly or inputOutput
if(source == 0){
//if(mode == PKW_initializeOnly || mode == PKW_inputOutput){
if(1){
//#define FIELDTYPE_FreeWRLPTR 22
//#define FIELDTYPE_SFImage 23
//if(strcmp(fieldName,"__oldurl") && strcmp(fieldName,"__oldSFString") && strcmp(fieldName,"__oldMFString") && strcmp(fieldName,"_parentVector")) {
//Mar2018 new rule:
// if it has two leading underscores '__' then don't free (see other callbacks for freeing) new mar2018
// else if mentioned on the next line, don't free
// else free
if( strncmp(fieldName,"__",2) && strcmp(fieldName,"__oldurl") && strcmp(fieldName,"_parentVector")) {
//if(1){
//skip double underscore prefixed fields, which we will treat as not-to-be-deleted, because duplicates like GeoViewpoint __oldMFString which is a duplicate of navType
deleteMallocedFieldValue(type,fieldPtr);
if(type == FIELDTYPE_FreeWRLPTR){
if(!strncmp(fieldName,"__x",3) || !strncmp(fieldName,"__v",3)) { //May 2015 special field name prefixes __x and __v signals OK to FREE_IF_NZ
FREE_IF_NZ(fieldPtr->sfnode); //free it as a pointer
}
}
}
}
}
return FALSE; //false to keep walking fields, true to break out
}
BOOL cbFreePublicMallocedBuiltinField(void *callbackData,struct X3D_Node* node,int jfield,
union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
{
//for builtins, the field is malloced as part of the node size, so we don't free the field itself
// .. just if its a complex field type holding a malloced pointer
// .. like MF.p or SFString.ptr
// and only if the node owns the pointer, which we determine by if the field is initializeOnly or inputOutput
if(source == 0){
//if(mode == PKW_initializeOnly || mode == PKW_inputOutput){
if(1){
//#define FIELDTYPE_FreeWRLPTR 22
//#define FIELDTYPE_SFImage 23
if(strncmp(fieldName,"_",1)) { //only public fields, skip _ and __ private fields
//if(1){
//skip double underscore prefixed fields, which we will treat as not-to-be-deleted, because duplicates like GeoViewpoint __oldMFString which is a duplicate of navType
deleteMallocedFieldValue(type,fieldPtr);
}
}
}
return FALSE; //false to keep walking fields, true to break out
}
BOOL cbFreeMallocedUserField(void *callbackData,struct X3D_Node* node,int jfield,
union anyVrml *fieldPtr,char *fieldName, int mode,int type,int source,BOOL publicfield)
{
//for userFields (ie on Script, Proto), the field is malloced as part of a bigger struct
// .. so we free any pointers contained in the field like MF.p or SFString.ptr
// and only if the node owns the pointer, which we determine by if the field is initializeOnly or inputOutput
// .. but we don't free the anyVrml* pointer itself
// .. we rely on something freeing the user fields elsewhere to free the vector of userfields and
// .. a few of their malloced contents
if(source > 0){
//user field in source = {script=1, shaders etc 2, protos = 3}
//if(mode == PKW_initializeOnly || mode == PKW_inputOutput){
if(1){
if(strncmp(fieldName,"__",2)) {
//if(1){
//skip double underscore prefixed fields, which we will treat as not-to-be-deleted, because duplicates like GeoViewpoint __oldMFString which is a duplicate of navType
deleteMallocedFieldValue(type,fieldPtr);
}
}
}
return FALSE; //false to keep walking fields, true to break out
}
struct Shader_Script *getShader(struct X3D_Node *node){
struct Shader_Script *shader = NULL;
switch(node->_nodeType)
{
case NODE_Script: shader =(struct Shader_Script *)(X3D_SCRIPT(node)->__scriptObj); break;
case NODE_ComposedShader: shader =(struct Shader_Script *)(X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields); break;
case NODE_Effect: shader =(struct Shader_Script *)(X3D_EFFECT(node)->_shaderUserDefinedFields); break;
case NODE_ShaderProgram: shader =(struct Shader_Script *)(X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields); break;
case NODE_PackagedShader: shader =(struct Shader_Script *)(X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields); break;
}
return shader;
}
void setShader(struct X3D_Node *node, struct Shader_Script *shader){
switch(node->_nodeType)
{
case NODE_Script: X3D_SCRIPT(node)->__scriptObj = (void *)shader; break;
case NODE_ComposedShader: X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields = (void *)shader;; break;
case NODE_Effect: X3D_EFFECT(node)->_shaderUserDefinedFields = (void *)shader;; break;
case NODE_ShaderProgram: X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields = (void *)shader;; break;
case NODE_PackagedShader: X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields = (void *)shader;; break;
}
}
void deleteShaderDefinition(struct Shader_Script *shader){
if(shader){
if(shader->fields){
int i;
for(i=0;ifields);i++){
struct ScriptFieldDecl *field = vector_get(struct ScriptFieldDecl*,shader->fields,i);
deleteScriptFieldDecl(field);
}
deleteVector(struct ScriptFieldDecl*,shader->fields);
FREE_IF_NZ(shader->fields);
}
FREE_IF_NZ(shader);
}
}
//static struct Vector freed;
//static struct fieldFree ffs[100];
void freeMallocedNodeFields0(struct X3D_Node* node){
//PIMPL Idiom in C is like objects in C++ - each object should know how to delete itself
//we don't have good pimpl habits yet in freewrl
//Here we try and generically free what a node may have allocated
//(a pimpl alternative might be node-type specific freeing)
//assume node->_intern = polyrep, node->_parents vector, and other common private fields are already done
//then this walks over node-specific fields, attempting to free any potentially malloced fields
//except SFNode (and SFNode contents of MFNode) which are garbage collected from
//a per-broto/executioncontext node table
if(node){
int isScriptType, isBrotoType, hasUserFields;
isScriptType = node->_nodeType == NODE_Script || node->_nodeType == NODE_ComposedShader || node->_nodeType == NODE_ShaderProgram || node->_nodeType == NODE_PackagedShader;
isBrotoType = node->_nodeType == NODE_Proto; //inlines have no fields, freed elsewhere || node->_nodeType == NODE_Inline;
hasUserFields = isScriptType || isBrotoType;
//freed.data = ffs;
//freed.allocn = 100;
//freed.n = 0;
if(hasUserFields){
walk_fields(node,cbFreeMallocedUserField,NULL); //&freed);
if(isScriptType){
struct Shader_Script *shader = getShader(node);
if (shader){
deleteShaderDefinition(shader);
setShader(node,NULL);
}
}else if(isBrotoType){
struct X3D_Proto* pnode = (struct X3D_Proto*)node;
deleteProtoDefinition(pnode->__protoDef);
FREE_IF_NZ(pnode->__protoDef);
FREE_IF_NZ(pnode->__typename);
//struct ProtoDefinition* pstruct = (struct ProtoDefinition*) pnode->__protoDef;
//if(pstruct){
// //for vectorget.n field->malloced stuff
// deleteVector(struct ProtoDefinition*,pstruct);
// pnode->__protoDef = NULL;
//}
}
}
/* free malloced public fields */
walk_fields(node,cbFreeMallocedBuiltinField,NULL); //&freed);
}
}
//void freePublicBuiltinNodeFields(struct X3D_Node* node){
// if(node)
// walk_fields(node,cbFreePublicMallocedBuiltinField,NULL); //&freed);
//}
void freeMallocedNodeFields(struct X3D_Node* node){
if(node){
deleteVector(void*,node->_parentVector);
if(node->_gc) free_registered_node_gc(node);
freeMallocedNodeFields0(node);
}
}
#ifdef OLDCODE
OLDCODE/*delete node created
OLDCODEstatic void killNode_hide_obsolete (int index) {
OLDCODE int j=0;
OLDCODE int *fieldOffsetsPtr;
OLDCODE char * fieldPtr;
OLDCODE struct X3D_Node* structptr;
OLDCODE struct Multi_Float* MFloat;
OLDCODE struct Multi_Rotation* MRotation;
OLDCODE struct Multi_Vec3f* MVec3f;
OLDCODE struct Multi_Bool* Mbool;
OLDCODE struct Multi_Int32* MInt32;
OLDCODE struct Multi_Node* MNode;
OLDCODE struct Multi_Color* MColor;
OLDCODE struct Multi_ColorRGBA* MColorRGBA;
OLDCODE struct Multi_Time* MTime;
OLDCODE struct Multi_String* MString;
OLDCODE struct Multi_Vec2f* MVec2f;
OLDCODE intptr_t * VPtr;
OLDCODE struct Uni_String *MyS;
OLDCODE int i;
OLDCODE
OLDCODE ppOpenGL_Utils p;
OLDCODE ttglobal tg = gglobal();
OLDCODE p = (ppOpenGL_Utils)tg->OpenGL_Utils.prv;
OLDCODE
OLDCODE structptr = vector_get(struct X3D_Node *,p->linearNodeTable,index);
OLDCODE //ConsoleMessage("killNode - looking for node %p of type %s in one of the stacks\n", structptr,stringNodeType(structptr->_nodeType));
OLDCODE
OLDCODE if( structptr->referenceCount > -1 ){
OLDCODE // unlinking the node from special arrays, parents and children
OLDCODE // we just need to do this once, and early in the kill process
OLDCODE // - I wish we had a sentinal value for 'unlinked'
OLDCODE DELETE_IF_IN_STACK(viewpoint_stack);
OLDCODE DELETE_IF_IN_STACK(background_stack);
OLDCODE DELETE_IF_IN_STACK(fog_stack);
OLDCODE DELETE_IF_IN_STACK(navigation_stack);
OLDCODE DELETE_IF_IN_PRODCON(viewpointNodes);
OLDCODE delete_first(structptr);
OLDCODE //print_node_links(structptr);
OLDCODE unlink_node(structptr); //unlink before settledown deleting..
OLDCODE //printf("after: \n");
OLDCODE //print_node_links(structptr);
OLDCODE }
OLDCODE
OLDCODE // give this time for things to "settle" in terms of rendering, etc
OLDCODE //JAS: "OpenGL - old code called flush() or finish(), but when the front-end does the actual rendering,
OLDCODE //what happens is that the GL calls get queued up for the GPU, then run when possible. So, there
OLDCODE //is a "hidden" multi-threading going on there. IIRC, I gave it 10 rendering loops for an unused
OLDCODE //node before deleting any of the items in it; really 1 or 2 loops should be fine. (1, but don't
OLDCODE //know about double buffering; 10 is a safe overkill) Without that, having OpenGL issues was a
OLDCODE //random certainty when removing nodes, and data from these nodes."
OLDCODE
OLDCODE structptr->referenceCount --;
OLDCODE if (structptr->referenceCount > -10) {
OLDCODE //ConsoleMessage ("ref count for %p is just %d, waiting\n",structptr,structptr->referenceCount);
OLDCODE return;
OLDCODE }
OLDCODE //ConsoleMessage ("kn %d %s\n",index,stringNodeType(structptr->_nodeType));
OLDCODE
OLDCODE #ifdef VERBOSE
OLDCODE printf("killNode: Node pointer = %p entry %d of %d ",structptr,i,vectorSize(p->linearNodeTable));
OLDCODE if (structptr) {
OLDCODE if (structptr->_parentVector)
OLDCODE printf (" number of parents %d ", vectorSize(structptr->_parentVector));
OLDCODE printf("Node Type = %s",stringNodeType(structptr->_nodeType));
OLDCODE } printf ("\n");
OLDCODE #endif
OLDCODE // node must be already unlinked with unlink_node() when we get here
OLDCODE // delete parent vector.
OLDCODE deleteVector(char*, structptr->_parentVector);
OLDCODE // clear child vector - done below
OLDCODE
OLDCODE fieldOffsetsPtr = (int *)NODE_OFFSETS[structptr->_nodeType];
OLDCODE //go thru all field
OLDCODE while (*fieldOffsetsPtr != -1) {
OLDCODE fieldPtr = offsetPointer_deref(char *, structptr,*(fieldOffsetsPtr+1));
OLDCODE #ifdef VERBOSE
OLDCODE printf ("looking at field %s type %s\n",FIELDNAMES[*fieldOffsetsPtr],FIELDTYPES[*(fieldOffsetsPtr+2)]);
OLDCODE #endif
OLDCODE
OLDCODE // some fields we skip, as the pointers are duplicated, and we CAN NOT free both
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES_setValue)
OLDCODE break; // can be a duplicate SF/MFNode pointer
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES_valueChanged)
OLDCODE break; // can be a duplicate SF/MFNode pointer
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES__parentResource)
OLDCODE break; // can be a duplicate SF/MFNode pointer
OLDCODE
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES___oldmetadata)
OLDCODE break; // can be a duplicate SFNode pointer
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES__selected)
OLDCODE break; // can be a duplicate SFNode pointer - field only in NODE_LOD and NODE_GeoLOD
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES___oldChildren)
OLDCODE break; // can be a duplicate SFNode pointer - field only in NODE_LOD and NODE_GeoLOD
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES___oldMFString)
OLDCODE break;
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES___scriptObj)
OLDCODE break;
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES___oldSFString)
OLDCODE break;
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES___oldKeyPtr)
OLDCODE break; // used for seeing if interpolator values change
OLDCODE
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES___oldKeyValuePtr)
OLDCODE break; // used for seeing if interpolator values change
OLDCODE
OLDCODE
OLDCODE // GeoLOD nodes, the children field exports either the rootNode, or the list of child nodes
OLDCODE if (structptr->_nodeType == NODE_GeoLOD) {
OLDCODE if (*fieldOffsetsPtr == FIELDNAMES_children) break;
OLDCODE }
OLDCODE
OLDCODE // nope, not a special field, lets just get rid of it as best we can
OLDCODE // dug9 sept 2014: GC garbage collection: I wonder if it would be easier/simpler when we malloc something,
OLDCODE // to put it into a flat scene-GC list (and inline-GC list?) - as we do for a few things already, like nodes -
OLDCODE // and don't GC here for fields on occassionally removed nodes, just when we change scenes
OLDCODE // wipe out the whole GC table(s)?
OLDCODE //
OLDCODE switch(*(fieldOffsetsPtr+2)){
OLDCODE case FIELDTYPE_MFFloat:
OLDCODE MFloat=(struct Multi_Float *)fieldPtr;
OLDCODE MFloat->n=0;
OLDCODE FREE_IF_NZ(MFloat->p);
OLDCODE break;
OLDCODE case FIELDTYPE_MFRotation:
OLDCODE MRotation=(struct Multi_Rotation *)fieldPtr;
OLDCODE MRotation->n=0;
OLDCODE FREE_IF_NZ(MRotation->p);
OLDCODE break;
OLDCODE case FIELDTYPE_MFVec3f:
OLDCODE MVec3f=(struct Multi_Vec3f *)fieldPtr;
OLDCODE MVec3f->n=0;
OLDCODE FREE_IF_NZ(MVec3f->p);
OLDCODE break;
OLDCODE case FIELDTYPE_MFBool:
OLDCODE Mbool=(struct Multi_Bool *)fieldPtr;
OLDCODE Mbool->n=0;
OLDCODE FREE_IF_NZ(Mbool->p);
OLDCODE break;
OLDCODE case FIELDTYPE_MFInt32:
OLDCODE MInt32=(struct Multi_Int32 *)fieldPtr;
OLDCODE MInt32->n=0;
OLDCODE FREE_IF_NZ(MInt32->p);
OLDCODE break;
OLDCODE case FIELDTYPE_MFNode:
OLDCODE MNode=(struct Multi_Node *)fieldPtr;
OLDCODE #ifdef VERBOSE
OLDCODE //verify node structure. Each child should point back to me.
OLDCODE {
OLDCODE int i;
OLDCODE struct X3D_Node *tp;
OLDCODE for (i=0; in; i++) {
OLDCODE tp = MNode->p[i];
OLDCODE printf (" MNode field has child %p\n",tp);
OLDCODE if (tp!=NULL)
OLDCODE printf (" ct %s\n",stringNodeType(tp->_nodeType));
OLDCODE }
OLDCODE }
OLDCODE #endif
OLDCODE MNode->n=0;
OLDCODE FREE_IF_NZ(MNode->p);
OLDCODE break;
OLDCODE
OLDCODE case FIELDTYPE_MFColor:
OLDCODE MColor=(struct Multi_Color *)fieldPtr;
OLDCODE MColor->n=0;
OLDCODE FREE_IF_NZ(MColor->p);
OLDCODE break;
OLDCODE case FIELDTYPE_MFColorRGBA:
OLDCODE MColorRGBA=(struct Multi_ColorRGBA *)fieldPtr;
OLDCODE MColorRGBA->n=0;
OLDCODE FREE_IF_NZ(MColorRGBA->p);
OLDCODE break;
OLDCODE case FIELDTYPE_MFTime:
OLDCODE MTime=(struct Multi_Time *)fieldPtr;
OLDCODE MTime->n=0;
OLDCODE FREE_IF_NZ(MTime->p);
OLDCODE break;
OLDCODE case FIELDTYPE_MFString:
OLDCODE MString=(struct Multi_String *)fieldPtr;
OLDCODE {
OLDCODE struct Uni_String* ustr;
OLDCODE for (j=0; jn; j++) {
OLDCODE ustr=MString->p[j];
OLDCODE if (ustr != NULL) {
OLDCODE ustr->len=0;
OLDCODE ustr->touched=0;
OLDCODE FREE_IF_NZ(ustr->strptr);
OLDCODE }
OLDCODE }
OLDCODE MString->n=0;
OLDCODE FREE_IF_NZ(MString->p);
OLDCODE }
OLDCODE break;
OLDCODE case FIELDTYPE_MFVec2f:
OLDCODE MVec2f=(struct Multi_Vec2f *)fieldPtr;
OLDCODE MVec2f->n=0;
OLDCODE FREE_IF_NZ(MVec2f->p);
OLDCODE break;
OLDCODE case FIELDTYPE_FreeWRLPTR:
OLDCODE VPtr = (intptr_t *) fieldPtr;
OLDCODE VPtr = (intptr_t *) (*VPtr);
OLDCODE FREE_IF_NZ(VPtr);
OLDCODE break;
OLDCODE case FIELDTYPE_SFString:
OLDCODE VPtr = (intptr_t *) fieldPtr;
OLDCODE MyS = (struct Uni_String *) *VPtr;
OLDCODE MyS->len = 0;
OLDCODE FREE_IF_NZ(MyS->strptr);
OLDCODE FREE_IF_NZ(MyS);
OLDCODE break;
OLDCODE
OLDCODE default:; // do nothing - field not malloc'd
OLDCODE }
OLDCODE fieldOffsetsPtr += FIELDOFFSET_LENGTH;
OLDCODE }
OLDCODE
OLDCODE FREE_IF_NZ(structptr);
OLDCODE vector_set(struct X3D_Node *, p->linearNodeTable,index,NULL);
OLDCODE p->potentialHoleCount++;
OLDCODE //ConsoleMessage ("kill, index %d, phc %d",index,p->potentialHoleCount);
OLDCODE}
OLDCODE*/
#endif //OLDCODE
#ifdef DEBUG_FW_LOADMAT
static void fw_glLoadMatrixd(GLDOUBLE *val,char *where, int line) {
{int i;
for (i=0; i<16; i++) {
if (val[i] > 2000.0) printf ("FW_GL_LOADMATRIX, val %d %lf at %s:%d\n",i,val[i],where,line);
if (val[i] < -2000.0) printf ("FW_GL_LOADMATRIX, val %d %lf at %s:%d\n",i,val[i],where,line);
}
}
#else
static void fw_glLoadMatrixd(GLDOUBLE *val) {
#endif
//hypothesis this is for old fix-function pipeline and isn't used?
/* printf ("loading matrix...\n"); */
#ifndef GL_ES_VERSION_2_0
glLoadMatrixd(val);
#endif
}
BOOL matrix3x3_inverse_float(float *inn, float *outt);
void sendExplicitMatriciesToShader (GLint ModelViewMatrix, GLint ProjectionMatrix, GLint NormalMatrix, GLint *TextureMatrix, GLint ModelViewInverseMatrix)
{
float spval[16];
int i,j;
float *sp;
GLDOUBLE *dp;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
/* ModelView first */
dp = p->FW_ModelView[p->modelviewTOS];
sp = spval;
/* convert GLDOUBLE to float */
for (i=0; i<16; i++) {
*sp = (float) *dp;
sp ++; dp ++;
}
profile_start("sendmtx");
GLUNIFORMMATRIX4FV(ModelViewMatrix,1,GL_FALSE,spval);
profile_end("sendmtx");
/* ProjectionMatrix */
sp = spval;
dp = p->FW_ProjectionView[p->projectionviewTOS];
matdouble2float4(sp,dp);
///* convert GLDOUBLE to float */
//for (i=0; i<16; i++) {
// *sp = (float) *dp;
// sp ++; dp ++;
//}
profile_start("sendmtx");
GLUNIFORMMATRIX4FV(ProjectionMatrix,1,GL_FALSE,spval);
profile_end("sendmtx");
/* TextureMatrix */
if(TextureMatrix){
for(j=0;jtextureviewTOS) {
sp = spval;
dp = p->FW_TextureView[itexturestackposition]; //[p->textureviewTOS];
//ConsoleMessage ("sendExplicitMatriciesToShader, sizeof GLDOUBLE %d sizeof float %d\n",sizeof(GLDOUBLE), sizeof(float));
//printmatrix2(dp,"dp");
/* convert GLDOUBLE to float */
for (i=0; i<16; i++) {
*sp = (float) *dp;
sp ++; dp ++;
}
profile_start("sendmtx");
GLUNIFORMMATRIX4FV(TextureMatrix[j],1,GL_FALSE,spval);
profile_end("sendmtx");
}
}
}
if( ModelViewInverseMatrix != -1){
//send in the inverse of the modelview matrix
//- handy for cube-map texturing
float spvali[16];
int ii; //,jj;
float *spi;
double *dpi, *dpp;
GLDOUBLE inverseMV[16];
//GLDOUBLE transInverseMV[16];
GLDOUBLE MV[16];
dpp = p->FW_ModelView[p->modelviewTOS];
memcpy(MV,dpp,sizeof(GLDOUBLE)*16);
matinverse (inverseMV,MV);
dpi = inverseMV;
spi = spvali;
for (ii=0; ii<16; ii++) {
*spi = (float) *dpi;
spi ++; dpi ++;
}
GLUNIFORMMATRIX4FV(ModelViewInverseMatrix,1,GL_FALSE,spvali);
}
/* send in the NormalMatrix */
/* Uniform mat3 gl_NormalMatrix; transpose of the inverse of the upper
leftmost 3x3 of gl_ModelViewMatrix */
if (NormalMatrix != -1) {
float normMat[9];
dp = p->FW_ModelView[p->modelviewTOS];
if(1){
//trying to find another .01 FPS
//switch from 4x4 double to 3x3 float inverse
float ftemp[9];
/* convert GLDOUBLE to float */
for (i=0; i<3; i++)
for(j=0;j<3;j++)
spval[i*3 +j] = (float) dp[i*4 + j];
matrix3x3_inverse_float(spval, ftemp);
//transpose
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
normMat[i*3 +j] = ftemp[j*3 + i];
}
if(0){
GLDOUBLE inverseMV[16];
GLDOUBLE transInverseMV[16];
GLDOUBLE MV[16];
memcpy(MV,dp,sizeof(GLDOUBLE)*16);
matinverse (inverseMV,MV);
mattranspose(transInverseMV,inverseMV);
/* get the 3x3 normal matrix from this guy */
normMat[0] = (float) transInverseMV[0];
normMat[1] = (float) transInverseMV[1];
normMat[2] = (float) transInverseMV[2];
normMat[3] = (float) transInverseMV[4];
normMat[4] = (float) transInverseMV[5];
normMat[5] = (float) transInverseMV[6];
normMat[6] = (float) transInverseMV[8];
normMat[7] = (float) transInverseMV[9];
normMat[8] = (float) transInverseMV[10];
}
/*
printf ("NormalMatrix: \n \t%4.3f %4.3f %4.3f\n \t%4.3f %4.3f %4.3f\n \t%4.3f %4.3f %4.3f\n",
normMat[0],normMat[1],normMat[2],
normMat[3],normMat[4],normMat[5],
normMat[6],normMat[7],normMat[8]);
*/
profile_start("sendmtx");
GLUNIFORMMATRIX3FV(NormalMatrix,1,GL_FALSE,normMat);
profile_end("sendmtx");
}
}
/* make this more generic, so that the non-OpenGL-ES 2.0 FillProperties, etc, still work */
void sendMatriciesToShader(s_shader_capabilities_t *me) {
sendExplicitMatriciesToShader (me->ModelViewMatrix, me->ProjectionMatrix, me->NormalMatrix,me->TextureMatrix,me->ModelViewInverseMatrix);
}
#define SEND_VEC2(myMat,myVal) \
if (me->myMat != -1) { GLUNIFORM2FV(me->myMat,1,myVal);}
#define SEND_VEC4(myMat,myVal) \
if (me->myMat != -1) { GLUNIFORM4FV(me->myMat,1,myVal);}
#define SEND_VEC3(myMat,myVal) \
if (me->myMat != -1) { GLUNIFORM3FV(me->myMat,1,myVal);}
#define SEND_FLOAT(myMat,myVal) \
if (me->myMat != -1) { GLUNIFORM1F(me->myMat,myVal);}
#define SEND_INT(myMat,myVal) \
if (me->myMat != -1) { GLUNIFORM1I(me->myMat,myVal);}
struct X3D_Node *getFogParams();
void sendFogToShader(s_shader_capabilities_t *me) {
float color4[4];
struct X3D_Fog *fog = (struct X3D_Fog*) getFogParams(); //gets it from the fog stack, LocalFog and Fog are upcast to Fog: perl first fields in same order
if(!fog) return;
profile_start("sendvec");
memcpy(color4,fog->color.c,sizeof(float)*3);
color4[3] = 1.0;
SEND_VEC4(fogColor,color4);
SEND_FLOAT(fogvisibilityRange,fog->visibilityRange*fog->__fogScale);
SEND_FLOAT(fogScale,1.0f); //fog->__fogScale);
SEND_INT(fogType,fog->__fogType);
//SEND_INT(fogHaveCoords,fogparams->haveCoords);
profile_end("sendvec");
}
float *getTransformedClipPlanes();
int getClipPlaneCount();
void sendClipplanesToShader(s_shader_capabilities_t *me){
int nsend; //i,
float *clipplanes = getTransformedClipPlanes();
nsend = getClipPlaneCount();
GLUNIFORM4FV(me->clipplanes,nsend,clipplanes);
GLUNIFORM1I(me->nclipplanes,nsend);
}
static int nunit = 0;
static int unit[32];
void clear_material_samplers();
int share_or_next_material_sampler_index(GLint texture);
GLint tunit(int index);
int sampler_units_used(){
return nunit;
}
void clear_material_samplers(){
nunit = 0;
}
int share_or_next_material_sampler_index(GLint texture){
int kunit, index;
kunit = bind_or_share_next_textureUnit(GL_TEXTURE_2D, texture);
index = -1;
for(int i=0;iTextureUnit[i],unit[kunit]);
return index;
}
GLint tunit(int index){
return unit[index];
}
void sendMaterialsToShader(s_shader_capabilities_t *me, int sides) {
struct matpropstruct *myap = getAppearanceProperties();
struct fw_MaterialParameters *fw_FrontMaterial, *mp;
struct fw_MaterialParameters *fw_BackMaterial;
int nt;
ttglobal tg = gglobal();
if (!myap) return;
if(sides == 3){
fw_FrontMaterial = &myap->fw_FrontMaterial;
fw_BackMaterial = &myap->fw_BackMaterial;
}else if(sides == 1){
fw_FrontMaterial = &myap->fw_FrontMaterial;
}else if(sides == 2){
fw_FrontMaterial = &myap->fw_BackMaterial;
}
/* go through all of the Uniforms for this shader */
/* ConsoleMessage ("sending in front diffuse %f %f %f %f ambient %f %f %f %f spec %f %f %f %f emission %f %f %f %f, shin %f",
fw_FrontMaterial.diffuse[0],fw_FrontMaterial.diffuse[1],fw_FrontMaterial.diffuse[2],fw_FrontMaterial.diffuse[3],
fw_FrontMaterial.ambient[0],fw_FrontMaterial.ambient[1],fw_FrontMaterial.ambient[2],fw_FrontMaterial.ambient[3],
fw_FrontMaterial.specular[0],fw_FrontMaterial.specular[1],fw_FrontMaterial.specular[2],fw_FrontMaterial.specular[3],
fw_FrontMaterial.emission[0],fw_FrontMaterial.emission[1],fw_FrontMaterial.emission[2],fw_FrontMaterial.emission[3],
fw_FrontMaterial.shininess);
ConsoleMessage ("sending in back diffuse %f %f %f %f ambient %f %f %f %f spec %f %f %f %f emission %f %f %f %f, shin %f",
fw_BackMaterial.diffuse[0],fw_BackMaterial.diffuse[1],fw_BackMaterial.diffuse[2],fw_BackMaterial.diffuse[3],
fw_BackMaterial.ambient[0],fw_BackMaterial.ambient[1],fw_BackMaterial.ambient[2],fw_BackMaterial.ambient[3],
fw_BackMaterial.specular[0],fw_BackMaterial.specular[1],fw_BackMaterial.specular[2],fw_BackMaterial.specular[3],
fw_BackMaterial.emission[0],fw_BackMaterial.emission[1],fw_BackMaterial.emission[2],fw_BackMaterial.emission[3],
fw_BackMaterial.shininess);
*/
PRINT_GL_ERROR_IF_ANY("BEGIN sendMaterialsToShader");
/* eventually do this with code blocks in glsl */
profile_start("sendvec");
GLUNIFORM3FV(me->myMaterialDiffuse,1,fw_FrontMaterial->diffuse);
GLUNIFORM3FV(me->myMaterialEmissive,1,fw_FrontMaterial->emissive);
GLUNIFORM3FV(me->myMaterialSpecular,1,fw_FrontMaterial->specular);
GLUNIFORM3FV(me->myMaterialBaseColor,1,fw_FrontMaterial->baseColor);
GLUNIFORM1F(me->myMaterialAmbient,fw_FrontMaterial->ambient);
GLUNIFORM1F(me->myMaterialShininess,fw_FrontMaterial->shininess);
GLUNIFORM1F(me->myMaterialTransparency,fw_FrontMaterial->transparency);
GLUNIFORM1F(me->myMaterialRoughness,fw_FrontMaterial->roughness);
GLUNIFORM1F(me->myMaterialMetallic,fw_FrontMaterial->metallic);
GLUNIFORM1I(me->myMaterialType,fw_FrontMaterial->type);
GLUNIFORM1I(me->myMaterialTransdex,fw_FrontMaterial->transdex);
mp = fw_FrontMaterial;
nt = 0;
GLint saveTextureStackTop = tg->RenderFuncs.textureStackTop;
for(int i=0;i<5;i++){
mp->tcount[i] = 0;
mp->tstart[i] = nt;
if(mp->textures[i]){
int textures[4], modes[4], sources[4], funcs[4], width[4], height[4];
render_node(mp->textures[i]);
int ntdesc = getTextureDescriptors(mp->textures[i],textures, modes,sources, funcs, width, height);
mp->tcount[i] = ntdesc;
for(int j=0;jtindex[nt] = kunit;
mp->source[nt] = sources[j];
mp->mode[nt] = modes[j];
mp->func[nt] = funcs[j];
int iunit = tunit(kunit);
glUniform1i(me->textureUnit[kunit],iunit); //tunit(kunit));
GLUNIFORM1I(me->myMaterialTindex[nt],mp->tindex[nt]);
nt++;
}
tg->RenderFuncs.textureStackTop = saveTextureStackTop; //keep this frmo building up
}
GLUNIFORM1I(me->myMaterialCindex[i],mp->cindex[i]);
GLUNIFORM1I(me->myMaterialTcount[i],mp->tcount[i]);
GLUNIFORM1I(me->myMaterialTstart[i],mp->tstart[i]);
}
mp->nt = nt;
//SEND_INT(myMaterialNt,mp->nt);
if(sides == 3){
GLUNIFORM3FV(me->myMaterialBackDiffuse,1,fw_BackMaterial->diffuse);
GLUNIFORM3FV(me->myMaterialBackEmissive,1,fw_BackMaterial->emissive);
GLUNIFORM3FV(me->myMaterialBackSpecular,1,fw_BackMaterial->specular);
GLUNIFORM3FV(me->myMaterialBackBaseColor,1,fw_BackMaterial->baseColor);
GLUNIFORM1F(me->myMaterialBackAmbient,fw_BackMaterial->ambient);
GLUNIFORM1F(me->myMaterialBackShininess,fw_BackMaterial->shininess);
GLUNIFORM1F(me->myMaterialBackTransparency,fw_BackMaterial->transparency);
GLUNIFORM1F(me->myMaterialBackRoughness,fw_BackMaterial->roughness);
GLUNIFORM1F(me->myMaterialBackMetallic,fw_BackMaterial->metallic);
GLUNIFORM1I(me->myMaterialBackType,fw_BackMaterial->type);
GLUNIFORM1I(me->myMaterialBackTransdex,fw_BackMaterial->transdex);
mp = fw_BackMaterial;
nt = 0;
for(int i=0;i<5;i++){
mp->tcount[i] = 0;
mp->tstart[i] = nt;
if(mp->textures[i]){
int textures[4], modes[4], sources[4], funcs[4], width[4], height[4];
render_node(mp->textures[i]);
int ntdesc = getTextureDescriptors(mp->textures[i],textures, modes,sources, funcs, width, height);
mp->tcount[i] = ntdesc;
for(int j=0;jtindex[nt] = kunit;
mp->source[nt] = sources[j];
mp->mode[nt] = modes[j];
mp->func[nt] = funcs[j];
glUniform1i(me->textureUnit[kunit],tunit(kunit));
GLUNIFORM1I(me->myMaterialBackTindex[nt],mp->tindex[nt]);
nt++;
}
tg->RenderFuncs.textureStackTop = saveTextureStackTop; //keep this frmo building up
}
GLUNIFORM1I(me->myMaterialBackCindex[i],mp->cindex[i]);
GLUNIFORM1I(me->myMaterialBackTcount[i],mp->tcount[i]);
GLUNIFORM1I(me->myMaterialBackTstart[i],mp->tstart[i]);
}
mp->nt = nt;
}
//SEND_INT(myMaterialBackNt,mp->nt);
//send v4 material textures to shader
// int next_textureUnit2D();
// sharable GLint textures? > fewer units needed
profile_end("sendvec");
if (me->haveLightInShader) sendLightInfo(me);
/* FillProperties, LineProperty lineType */
#if defined (GL_ES_VERSION_2_0)
SEND_FLOAT(myPointSize,myap->pointSize);
#else
glPointSize(myap->pointSize > 0 ? myap->pointSize : 1);
#endif
profile_start("sendmat");
//ConsoleMessage ("rlp %d %d %d %d",me->hatchPercent,me->filledBool,me->hatchedBool,me->algorithm,me->hatchColour);
SEND_INT(filledBool,myap->filledBool);
SEND_INT(hatchedBool,myap->hatchedBool);
SEND_INT(algorithm,myap->algorithm);
SEND_VEC4(hatchColour,myap->hatchColour);
SEND_VEC2(hatchScale,myap->hatchScale);
SEND_VEC2(hatchPercent,myap->hatchPercent);
//TextureCoordinateGenerator
SEND_INT(texCoordGenType,myap->texCoordGeneratorType);
profile_end("sendmat");
PRINT_GL_ERROR_IF_ANY("END sendMaterialsToShader");
}
void __gluMultMatrixVecd(const GLDOUBLE matrix[16], const GLDOUBLE in[4],
GLDOUBLE out[4])
{
int i;
for (i=0; i<4; i++) {
out[i] =
in[0] * matrix[0*4+i] +
in[1] * matrix[1*4+i] +
in[2] * matrix[2*4+i] +
in[3] * matrix[3*4+i];
}
}
void fw_gluProject
(GLDOUBLE objx, GLDOUBLE objy, GLDOUBLE objz,
const GLDOUBLE modelMatrix[16],
const GLDOUBLE projMatrix[16],
const GLint viewport[4],
GLDOUBLE *winx, GLDOUBLE *winy, GLDOUBLE *winz)
{
GLDOUBLE in[4];
GLDOUBLE out[4];
in[0]=objx;
in[1]=objy;
in[2]=objz;
in[3]=1.0;
__gluMultMatrixVecd(modelMatrix, in, out);
__gluMultMatrixVecd(projMatrix, out, in);
if (in[3] == 0.0) return;
in[0] /= in[3];
in[1] /= in[3];
in[2] /= in[3];
/* Map x, y and z to range 0-1 */
in[0] = in[0] * 0.5 + 0.5;
in[1] = in[1] * 0.5 + 0.5;
in[2] = in[2] * 0.5 + 0.5;
/* Map x,y to viewport */
in[0] = in[0] * viewport[2] + viewport[0];
in[1] = in[1] * viewport[3] + viewport[1];
*winx=in[0];
*winy=in[1];
*winz=in[2];
}
void __gluMultMatricesd(const GLDOUBLE a[16], const GLDOUBLE b[16],
GLDOUBLE r[16])
{
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
r[i*4+j] =
a[i*4+0]*b[0*4+j] +
a[i*4+1]*b[1*4+j] +
a[i*4+2]*b[2*4+j] +
a[i*4+3]*b[3*4+j];
}
}
}
/*
** Invert 4x4 matrix.
** Contributed by David Moore (See Mesa bug #6748)
*/
int __gluInvertMatrixd(const GLDOUBLE m[16], GLDOUBLE invOut[16])
{
GLDOUBLE inv[16], det;
int i;
inv[0] = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15]
+ m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
inv[4] = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15]
- m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
inv[8] = m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15]
+ m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14]
- m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
inv[1] = -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15]
- m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
inv[5] = m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15]
+ m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
inv[9] = -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15]
- m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
inv[13] = m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14]
+ m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
inv[2] = m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15]
+ m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
inv[6] = -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15]
- m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
inv[10] = m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15]
+ m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14]
- m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
inv[3] = -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11]
- m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
inv[7] = m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11]
+ m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11]
- m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
inv[15] = m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10]
+ m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
if (det == 0)
return GL_FALSE;
det = 1.0 / det;
for (i = 0; i < 16; i++)
invOut[i] = inv[i] * det;
return GL_TRUE;
}
void fw_gluUnProject(GLDOUBLE winx, GLDOUBLE winy, GLDOUBLE winz,
const GLDOUBLE modelMatrix[16],
const GLDOUBLE projMatrix[16],
const GLint viewport[4],
GLDOUBLE *objx, GLDOUBLE *objy, GLDOUBLE *objz)
{
/* https://www.opengl.org/sdk/docs/man2/xhtml/gluUnProject.xml
FLOPs 196 double: full matmult 64, full mat inverse 102, full transform 16, miscalaneous 8
*/
GLDOUBLE finalMatrix[16];
GLDOUBLE in[4];
GLDOUBLE out[4];
__gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return;
in[0]=winx;
in[1]=winy;
in[2]=winz;
in[3]=1.0;
/* Map x and y from window coordinates */
in[0] = (in[0] - viewport[0]) / viewport[2];
in[1] = (in[1] - viewport[1]) / viewport[3];
/* Map to range -1 to 1 */
in[0] = in[0] * 2 - 1;
in[1] = in[1] * 2 - 1;
in[2] = in[2] * 2 - 1;
__gluMultMatrixVecd(finalMatrix, in, out);
if (out[3] == 0.0) return;
out[0] /= out[3];
out[1] /= out[3];
out[2] /= out[3];
*objx = out[0];
*objy = out[1];
*objz = out[2];
}
void fw_Ortho (GLDOUBLE left, GLDOUBLE right, GLDOUBLE bottom, GLDOUBLE top, GLDOUBLE nearZ, GLDOUBLE farZ) {
GLDOUBLE *dp;
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
/* do the glOrtho on the top of the stack, and send that along */
dp = p->FW_ProjectionView[p->projectionviewTOS];
/* do some bounds checking here */
if (right <= left) right = left+1.0; /* resolve divide by zero possibility */
if (top <= bottom) top= bottom+1.0; /* resolve divide by zero possibility */
if (farZ <= nearZ) farZ= nearZ + 2.0; /* resolve divide by zero possibility */
/* {int i; for (i=0; i<16;i++) { printf ("ModView before %d: %4.3f \n",i,dp[i]); } } */
mesa_Ortho(left,right,bottom,top,nearZ,farZ,dp);
/* {int i; for (i=0; i<16;i++) { printf ("ModView after %d: %4.3f \n",i,dp[i]); } } */
FW_GL_LOADMATRIX(dp);
}
/* gluPerspective replacement */
void fw_gluPerspective(GLDOUBLE fovy, GLDOUBLE aspect, GLDOUBLE zNear, GLDOUBLE zFar) {
GLDOUBLE xmin, xmax, ymin, ymax;
GLDOUBLE *dp;
GLDOUBLE ndp[16];
GLDOUBLE ndp2[16];
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
ymax = zNear * tan(fovy * M_PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
/* do the glFrsutum on the top of the stack, and send that along */
FW_GL_MATRIX_MODE(GL_PROJECTION);
//FW_GL_LOAD_IDENTITY();
dp = p->FW_ProjectionView[p->projectionviewTOS];
mesa_Frustum(xmin, xmax, ymin, ymax, zNear, zFar, ndp);
mattranspose(ndp2,ndp);
//printmatrix2(ndp,"ndp");
//printmatrix2(ndp2,"ndp2 = transpose(ndp)");
//JAS printmatrix2(dp,"dp");
matmultiplyFULL(ndp,ndp2,dp);
//printmatrix2(ndp,"ndp = ndp2*dp");
/* method = 1; */
#define TRY_PERSPECTIVE_METHOD_1
#ifdef TRY_PERSPECTIVE_METHOD_1
FW_GL_LOADMATRIX(ndp);
/* put the matrix back on our matrix stack */
memcpy (p->FW_ProjectionView[p->projectionviewTOS],ndp,16*sizeof (GLDOUBLE));
#endif
#ifdef TRY_PERSPECTIVE_METHOD_2
/* testing... */
{
GLDOUBLE m[16];
GLDOUBLE sine, cotangent, deltaZ;
GLDOUBLE radians = fovy / 2.0 * M_PI / 180.0;
deltaZ = zFar - zNear;
sine = sin(radians);
if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
return;
}
cotangent = cos(radians) / sine;
loadIdentityMatrix(m); //(&m);
//__gluMakeIdentityd(&m[0][0]);
m[0*4+0] = cotangent / aspect;
m[1*4+1] = cotangent;
m[2*4+2] = -(zFar + zNear) / deltaZ;
m[2*4+3] = -1;
m[3*4+2] = -2 * zNear * zFar / deltaZ;
m[3*4+3] = 0;
matmultiplyFULL(m,m,dp);
if(method==2)
FW_GL_LOADMATRIX(m);
//glMultMatrixd(&m[0][0]);
}
#endif
#ifdef TRY_PERSPECTIVE_METHOD_3
{
GLDOUBLE yyy[16];
//printf ("fw_gluPerspective, have...\n");
if(method==3)
gluPerspective(fovy,aspect,zNear,zFar);
FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX,yyy);
//JAS printmatrix2(dp,"dp orig");
//JAS printmatrix2(ndp,"ndp myPup");
//JAS printmatrix2(yyy,"yyy gluP");
//JAS printmatrix2(m,"m mesa");
//for (i=0; i<16;i++) {printf ("%d orig: %5.2lf myPup: %5.2lf gluP: %5.2lf mesa %5.2lf\n",i,dp[i],
// ndp[i],yyy[i],m[i]);
//}
}
#endif
}
void fw_gluPerspective_2(GLDOUBLE xcenter, GLDOUBLE fovy, GLDOUBLE aspect, GLDOUBLE zNear, GLDOUBLE zFar) {
//xcenter is 0.0 if you want the perspective in the center of the viewport.
// -1.0 if you want it on the left edge
// +1.0 if you want it on the right edge
GLDOUBLE xmin, xmax, ymin, ymax;
GLDOUBLE *dp;
GLDOUBLE ndp[16];
GLDOUBLE ndp2[16];
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
ymax = zNear * tan(fovy * M_PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
xmin += xcenter * xmin;
xmax += xcenter * xmin;
/* do the glFrsutum on the top of the stack, and send that along */
FW_GL_MATRIX_MODE(GL_PROJECTION);
//FW_GL_LOAD_IDENTITY();
dp = p->FW_ProjectionView[p->projectionviewTOS];
mesa_Frustum(xmin, xmax, ymin, ymax, zNear, zFar, ndp);
mattranspose(ndp2,ndp);
//printmatrix2(ndp,"ndp");
//printmatrix2(ndp2,"ndp2 = transpose(ndp)");
//JAS printmatrix2(dp,"dp");
matmultiplyFULL(ndp,ndp2,dp);
//printmatrix2(ndp,"ndp = ndp2*dp");
/* method = 1; */
// FW_GL_LOADMATRIX(ndp);
/* put the matrix back on our matrix stack */
memcpy (p->FW_ProjectionView[p->projectionviewTOS],ndp,16*sizeof (GLDOUBLE));
}
void fw_gluPerspectiveTexture(GLDOUBLE fovy, GLDOUBLE aspect, GLDOUBLE zNear, GLDOUBLE zFar) {
GLDOUBLE xmin, xmax, ymin, ymax;
GLDOUBLE *dp;
GLDOUBLE ndp[16];
GLDOUBLE ndp2[16];
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
ymax = zNear * tan(fovy * M_PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
/* do the glFrsutum on the top of the stack, and send that along */
FW_GL_MATRIX_MODE(GL_TEXTURE);
FW_GL_LOAD_IDENTITY();
dp = p->FW_TextureView[p->textureviewTOS];
mesa_Frustum(xmin, xmax, ymin, ymax, zNear, zFar, ndp);
mattranspose(ndp2,ndp);
//printmatrix2(ndp,"ndp");
//printmatrix2(ndp2,"ndp2 = transpose(ndp)");
//JAS printmatrix2(dp,"dp");
matmultiply(ndp,ndp2,dp);
//printmatrix2(ndp,"ndp = ndp2*dp");
FW_GL_LOADMATRIX(ndp);
/* put the matrix back on our matrix stack */
memcpy (p->FW_TextureView[p->textureviewTOS],ndp,16*sizeof (GLDOUBLE));
}
void fw_gluPerspectiveTextureLookAt(GLDOUBLE ex, GLDOUBLE ey, GLDOUBLE ez,
GLDOUBLE cx, GLDOUBLE cy, GLDOUBLE cz,
GLDOUBLE ux,GLDOUBLE uy,GLDOUBLE uz)
{
GLDOUBLE sx, sy, sz;
GLDOUBLE fx, fy, fz;
GLDOUBLE *dp;
GLDOUBLE ndp[16];
GLDOUBLE ndp1[16];
GLDOUBLE ndp2[16];
GLDOUBLE ndp3[16];
ppOpenGL_Utils p = (ppOpenGL_Utils)gglobal()->OpenGL_Utils.prv;
FW_GL_MATRIX_MODE(GL_TEXTURE);
//FW_GL_LOAD_IDENTITY();
dp = p->FW_TextureView[p->textureviewTOS];
sx=cx-ex; sy=cy-ey; sz=cz-ez;
fx=sy*ux-uy*sz; fy=sz*ux-sx*uz; fz=sx*uy-sy*ux;
ndp1[0]=sx;ndp1[4]=sy;ndp1[8]=sz;ndp1[12]=0;
ndp1[1]=ux;ndp1[5]=uy;ndp1[9]=uz;ndp1[13]=0;
ndp1[2]=-fx;ndp1[6]=-fy;ndp1[10]=-fz;ndp1[14]=0;
ndp1[3]=0;ndp1[7]=0;ndp1[11]=0;ndp1[15]=1;
ndp2[0]=1;ndp2[4]=0;ndp2[8]=0;ndp2[12]=-ex;
ndp2[1]=0;ndp2[5]=1;ndp2[9]=0;ndp2[13]=-ey;
ndp2[2]=0;ndp2[6]=0;ndp2[10]=1;ndp2[14]=-ez;
ndp2[3]=0;ndp2[7]=0;ndp2[11]=0;ndp2[15]=1;
matmultiply(ndp3,ndp1,ndp2);
matmultiply(ndp,ndp3,dp);
//printmatrix2(ndp,"ndp = ndp3*dp");
FW_GL_LOADMATRIX(ndp);
/* put the matrix back on our matrix stack */
memcpy (p->FW_TextureView[p->textureviewTOS],ndp,16*sizeof (GLDOUBLE));
}
/* gluPickMatrix replacement */
void fw_gluPickMatrix(GLDOUBLE xx, GLDOUBLE yy, GLDOUBLE width, GLDOUBLE height, GLint *vp) {
#ifdef VERBOSE
printf ("PickMat %lf %lf %lf %lf %d %d %d %d\n",xx,yy,width,height,vp[0], vp[1],vp[2],vp[3]);
#endif
if ((width < 0.0) || (height < 0.0)) return;
/* Translate and scale the picked region to the entire window */
FW_GL_TRANSLATE_D((vp[2] - 2.0 * (xx - vp[0])) / width, (vp[3] - 2.0 * (yy - vp[1])) / height, 0.0);
FW_GL_SCALE_D(vp[2] / width, vp[3] / height, 1.0);
}
/* glFrustum replacement - taken from the MESA source;
* matrix.c
*
* Some useful matrix functions.
*
* Brian Paul
* 10 Feb 2004
*/
/**
* Build a glFrustum matrix.
*/
static void
mesa_Frustum(GLDOUBLE left, GLDOUBLE right, GLDOUBLE bottom, GLDOUBLE top, GLDOUBLE nearZ, GLDOUBLE farZ, GLDOUBLE *m)
{
/* http://www.songho.ca/opengl/gl_projectionmatrix.html shows derivation*/
GLDOUBLE x = (2.0*nearZ) / (right-left);
GLDOUBLE y = (2.0*nearZ) / (top-bottom);
GLDOUBLE a = (right+left) / (right-left);
GLDOUBLE b = (top+bottom) / (top-bottom);
GLDOUBLE c = -(farZ+nearZ) / ( farZ-nearZ);
GLDOUBLE d = -(2.0F*farZ*nearZ) / (farZ-nearZ);
/* printf ("mesa_Frustum (%lf, %lf, %lf, %lf, %lf, %lf)\n",left,right,bottom,top,nearZ, farZ); */
m[0] = x;
m[1] = 0.0;
m[2] = a;
m[3] = 0.0;
m[4] = 0.0;
m[5] = y;
m[6] = b;
m[7] = 0.0;
m[8] = 0.0;
m[9] = 0.0;
m[10] = c;
m[11] = d;
m[12] = 0.0;
m[13] = 0.0;
m[14] = -1.0;
m[15] = 0.0;
/*
#define M(row,col) m[col*4+row]
M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
#undef M
*/
}
/**
* Build a glOrtho marix.
*/
void mesa_Ortho(GLDOUBLE left, GLDOUBLE right, GLDOUBLE bottom, GLDOUBLE top, GLDOUBLE nearZ, GLDOUBLE farZ, GLDOUBLE *m)
{
#define M(row,col) m[col*4+row]
M(0,0) = 2.0F / (right-left);
M(0,1) = 0.0F;
M(0,2) = 0.0F;
M(0,3) = -(right+left) / (right-left);
M(1,0) = 0.0F;
M(1,1) = 2.0F / (top-bottom);
M(1,2) = 0.0F;
M(1,3) = -(top+bottom) / (top-bottom);
M(2,0) = 0.0F;
M(2,1) = 0.0F;
M(2,2) = -2.0F / (farZ-nearZ);
M(2,3) = -(farZ+nearZ) / (farZ-nearZ);
M(3,0) = 0.0F;
M(3,1) = 0.0F;
M(3,2) = 0.0F;
M(3,3) = 1.0F;
#undef M
}
/* Projective Texture gluPerspective */
void projPerspective(GLDOUBLE fovy, GLDOUBLE aspect, GLDOUBLE zNear, GLDOUBLE zFar, GLDOUBLE *matrix) {
GLDOUBLE xmin, xmax, ymin, ymax;
GLDOUBLE ndp[16];
GLDOUBLE ndp2[16];
ymax = zNear * tan(fovy * M_PI / 360.0);
ymin = -ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
mesa_Frustum(xmin, xmax, ymin, ymax, zNear, zFar, ndp);
mattranspose(ndp2,ndp);
//memcpy (p->FW_ProjectionView[p->projectionviewTOS],ndp,16*sizeof (float));
memcpy (matrix,ndp2,16*sizeof (GLDOUBLE));
}
/* Projective Texture gluLookAt */
void projLookAt(GLDOUBLE eyex, GLDOUBLE eyey, GLDOUBLE eyez,
GLDOUBLE centerx, GLDOUBLE centery, GLDOUBLE centerz,
GLDOUBLE upx, GLDOUBLE upy, GLDOUBLE upz, GLDOUBLE *matrix)
{
GLDOUBLE m[16];
GLDOUBLE x[3], y[3], z[3];
GLDOUBLE mag;
z[0] = eyex - centerx;
z[1] = eyey - centery;
z[2] = eyez - centerz;
mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
if (mag) {
z[0] /= mag;
z[1] /= mag;
z[2] /= mag;
}
y[0] = upx;
y[1] = upy;
y[2] = upz;
x[0] = y[1] * z[2] - y[2] * z[1];
x[1] = -y[0] * z[2] + y[2] * z[0];
x[2] = y[0] * z[1] - y[1] * z[0];
y[0] = z[1] * x[2] - z[2] * x[1];
y[1] = -z[0] * x[2] + z[2] * x[0];
y[2] = z[0] * x[1] - z[1] * x[0];
mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
if (mag) {
x[0] /= mag;
x[1] /= mag;
x[2] /= mag;
}
mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
if (mag) {
y[0] /= mag;
y[1] /= mag;
y[2] /= mag;
}
#define M(row,col) m[col*4+row]
M(0, 0) = x[0];
M(0, 1) = x[1];
M(0, 2) = x[2];
M(0, 3) = 0.0;
M(1, 0) = y[0];
M(1, 1) = y[1];
M(1, 2) = y[2];
M(1, 3) = 0.0;
M(2, 0) = z[0];
M(2, 1) = z[1];
M(2, 2) = z[2];
M(2, 3) = 0.0;
M(3, 0) = 0.0;
M(3, 1) = 0.0;
M(3, 2) = 0.0;
M(3, 3) = 1.0;
#undef M
if(0){
//glMultMatrixd(m);
FW_GL_TRANSFORM_D(m);
//glTranslated(-eyex, -eyey, -eyez);
FW_GL_TRANSLATE_D(-eyex, -eyey, -eyez);
}else{
double eye[3];
vecsetd(eye,-eyex,-eyey,-eyez);
mattranslate4d(m,eye);
memcpy (matrix,m,16*sizeof (GLDOUBLE));
}
}
void projOrtho (GLDOUBLE l, GLDOUBLE r, GLDOUBLE b, GLDOUBLE t,
GLDOUBLE n, GLDOUBLE f,GLDOUBLE *matrix)
{
GLDOUBLE m[16];
#define M(row,col) m[col*4+row]
M(0, 0) = 2.0/(r-l);
M(0, 1) = 0.0;
M(0, 2) = 0.0;
M(0, 3) = -((r+l) / r-l);
M(1, 0) = 0.0;
M(1, 1) = 2.0/(t-b);
M(1, 2) = 0.0;
M(1, 3) = -((t+b)/(r-b));
M(2, 0) = 0.0;
M(2, 1) = 0.0;
M(2, 2) = -2.0/(f-n);
M(2, 3) = -((f+n)/(f-n));
M(3, 0) = 0.0;
M(3, 1) = 0.0;
M(3, 2) = 0.0;
M(3, 3) = 1.0;
#undef M
/*
m[0] = 2.0/(r-l);
m[1] = 0.0;
m[2] = 0.0;
m[3] = -((r+l) / r-l);
m[4] = 0.0;
m[5] = 2.0/(t-b);
m[6] = 0.0;
m[7] = -((t+b)/(r-b));
m[8] = 0.0;
m[9] = 0.0;
m[10] = -2.0/(f-n);
m[11] = -((f+n)/(f-n));
m[12] = 0.0;
m[13] = 0.0;
m[14] = 0.0;
m[15] = 1.0;
*/
memcpy (matrix,m,16*sizeof (GLDOUBLE));
}