/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include "hwDeclarations.h" #include "hwList.h" #include "hwClipped.h" #include "hwScreen.h" #include "hwWindow.h" #include "hwPortLayer.h" #include "hwGather.h" #include "hwView.h" #include "hwMatrix.h" #include "hwXfield.h" #include "hwTmesh.h" #include "hwMaterials.h" #include "hwSort.h" #include "hwDebug.h" static Error _paintRecurse(void* globals, dxObject object, gatherO gather, int buttonUp, screenO parent, screenO grandparent); struct processImageArg { void* win; void* translation; }; /* * Load lighting into the hardware. Provide surface properties to allow * the lights to be biased to represent surface properties. * * Some ports do not have a way to define a material properties that are * independent of the surface color (GL OpenGL). However, we can apply the * coeficients to the lights instead to achieve the same result * * Light at each vertex has three parts, an ambient, a diffuse and a specular * component. The vertex color is: * vert_color = amb_light_color * vert_color * k_amb + * for_each_light( light_color * vert_color * k_diff * misc_stuff + * light_color * k_spec * other_misc_stuff) * * if we wrap the k_amb and k_diff into the light color the equ becomes: * * vert_color = new_amb_light_color * vert_color + * for_each_light( new_light_color * vert_color * misc_stuff + * new_light_color * k_spec/k_diff * other_misc_stuff) * * What is significant here is that we only need to send a single color to GL * for ambient,diffuse and specular, and that this color does not need to be * multiplied before being sent down. This is a big optimization. */ static Error loadLights(void* globals, gatherO gather, materialAttrP newMaterial) { DEFGLOBALDATA(globals); DEFPORT(PORT_HANDLE); int i,j; Light newLight; static materialAttrT identMaterial = {1.0, 1.0, 1.0, 1}; RGBColor color; listO lights; materialO omo, nmo; float gka, gkd, gks, gsp; ENTRY(("loadLights(0x%x, 0x%x, 0x%x)",globals, gather, newMaterial)); /* * if no material coeficients were specified or this port does not * want the coeficients pre-multiplied into the lights, use all * unit valued coeficients. */ if(!newMaterial || !_dxf_isFlagsSet(_dxf_SERVICES_FLAGS(),SF_CONST_COEF_HELP)) newMaterial = &identMaterial; /* * Only re-load the lights if the material coeficients have changed */ if (! _dxf_getHwGatherMaterial(gather, &omo)) goto error; if (omo) if (! _dxf_getHwMaterialInfo(omo, &gka, &gkd, &gks, &gsp)) goto error; if(!omo || gka != newMaterial->ambient || gkd != newMaterial->diffuse) { nmo = _dxf_newHwMaterial( newMaterial->ambient, newMaterial->diffuse, newMaterial->specular, newMaterial->shininess); if (! nmo) goto error; if (! _dxf_setHwGatherMaterial(gather, nmo)) goto error; if (! _dxf_getHwGatherAmbientColor(gather, &color)) goto error; /* Load (or disable) the Ambient light */ if(color.r == 0.0 && color.g == 0.0 && color.b == 0.0) { if (!_dxf_DEFINE_LIGHT (LWIN, 0, NULL)) goto error; } else { float ambient = 1.0; /* * For ports with SF_CONST_COEF_HELP we put the ambient/diffuse coefs * in the ambient light color. This is for GL, this allows us to * use LMC_AD color for surfaces. This reduces the number of calls * we need by 2 per vertex. * * The ambient is divided by the diffuse so that we can multiply the * diffuse into the surface color and use LMC_AD for the color. */ if(newMaterial->diffuse) ambient = newMaterial->ambient / newMaterial->diffuse; else ambient = newMaterial->ambient / (1./10000.); color.r *= ambient; color.g *= ambient; color.b *= ambient; if(!(newLight = DXNewAmbientLight(color))) goto error; if (!_dxf_DEFINE_LIGHT (LWIN, 0, newLight)) goto error; DXDelete((dxObject)newLight); } if (! _dxf_getHwGatherLights(gather, &lights)) goto error; /* Load all directional lights */ for(i=1,j=_dxf_listSize(lights)-1;j>=0 && i<=8;j--,i++) { if (!_dxf_DEFINE_LIGHT (LWIN, i, _dxf_listGetItem(lights,j))) goto error; } /* remove any previously defined lights, that have not been redefined */ for(;i<=8;i++) { if (!_dxf_DEFINE_LIGHT (LWIN, i, NULL)) goto error; } } EXIT(("OK")); return OK; error: EXIT(("ERROR")); return ERROR; } static Field _processImage(Field f, char* args, int size) { struct processImageArg* argI = (struct processImageArg*)args; DEFWINDATA((argI->win)); DEFPORT(PORT_HANDLE); ENTRY(("_processImage(0x%x, \"%s\", %d)",f, args, size)); /* XXX Will this work in parallel ? */ _dxf_DRAW_IMAGE(argI->win, (dxObject)f, argI->translation); EXIT(("f = 0x%x",f)); return f; } Error _dxf_paint(void* globals, viewO view, int buttonUp, screenO camScreen) { DEFGLOBALDATA(globals); DEFPORT(PORT_HANDLE); gatherO gather; translationO translation; int flags; dxObject obj; RGBColor color; RGBColor background; float projectionMat[4][4]; float viewMat[4][4]; SortListP slp; if (! _dxf_getHwViewInfo(view, NULL, &gather, &translation, (float *)&projectionMat, (float *)viewMat, &background)) goto error; ENTRY(("_dxf_paint(0x%x, 0x%x, %d)",globals, view, buttonUp)); /* Turn off trace macros from this level down */ /* Turn it on by exporting this variable */ DEBUG_CALL ( if (!getenv("DXHW_DEBUG_DETAIL")) DEBUG_OFF(); ); if (! _dxf_getHwGatherFlags(gather, &flags)) goto error; if(flags & CONTAINS_IMAGE_ONLY) { dxObject object; static RGBColor black = {0.0,0.0,0.0}; _dxf_SET_BACKGROUND_COLOR(PORT_CTX,black); _dxf_INIT_RENDER_PASS (LWIN,SingleBufferMode,ZBufferDisabled); if (! _dxf_getHwGatherObject(gather, &object)) goto error; _dxf_DRAW_IMAGE(LWIN, object, translation); } else { dxObject object; _dxf_REPLACE_VIEW_MATRIX(PORT_CTX,projectionMat); _dxf_PUSH_REPLACE_MATRIX(PORT_CTX,viewMat); _dxf_SET_BACKGROUND_COLOR(PORT_CTX,background); _dxf_INIT_RENDER_PASS (LWIN,DoubleBufferMode,ZBufferEnabled); /* force a reload of the lights with each new object */ if (! _dxf_setHwGatherMaterial(gather, NULL)) goto error; if (! _dxf_getHwGatherObject(gather, &object)) goto error; if(!_paintRecurse(globals, object, gather, buttonUp, camScreen, NULL)) goto error; slp = (SortListP)SORTLIST; if (slp->itemCount) { if (! _dxf_Sort_Translucent(SORTLIST)) goto error; if (! _dxf_getHwGatherAmbientColor(gather, &color)) goto error; if(!_dxf_DRAW_TRANSPARENT(globals, &color, buttonUp)) goto error; } _dxf_POP_MATRIX(PORT_CTX); } done: DEBUG_ON(); EXIT(("OK")); return OK; error: DEBUG_ON(); EXIT(("ERROR")); return ERROR; } static Error _paintRecurse(void* globals, dxObject object, gatherO gather, int buttonUp, screenO parent, screenO grandparent) { DEFGLOBALDATA(globals); DEFPORT(PORT_HANDLE); xfieldP xf; Class class; int i; dxObject subObject; ENTRY(("_paintRecurse(0x%x, 0x%x, 0x%x, %d)", globals, object, gather, buttonUp)); if(!object) { EXIT(("object = NULL")); return OK; } if(!(class = DXGetObjectClass(object))) goto error; switch (class) { case CLASS_GROUP: PRINT(("CLASS_GROUP")); for (i=0; subObject=DXGetEnumeratedMember((Group)object, i, NULL); i++) { dxObject tmpObject; /* DXDebug("g", "member %d", i); */ if (!_paintRecurse(globals, subObject, gather, buttonUp, parent, grandparent)) goto error; } break; case CLASS_PRIVATE: /* created from CLASS_FIELD in gather */ { switch(_dxf_getHwClass(object)) { case HW_CLASS_XFIELD: { xfieldP xf = _dxf_getXfieldData((xfieldO)object); float fuzz; PRINT(("HW_CLASS_XFIELD")); if(_dxf_isFlagsSet(_dxf_attributeFlags(_dxf_xfieldAttributes(xf)), IN_CLIP_OBJECT)) { /* * The current implementation allows any object to be clip object, * this line allows the beginClip to call back into this function * to get the clip object recursively drawn */ if (!_dxf_DRAW_CLIP(PORT_HANDLE, xf, buttonUp)) goto error; } else { int nClips; Point *clipPts = NULL; Vector *clipVecs = NULL; if (! _dxf_getHwGatherClipPlanes(gather, &nClips, &clipPts, &clipVecs)) goto error; if (nClips) { if (! _dxf_setHwXfieldClipPlanes(object, nClips, clipPts, clipVecs)) goto error; DXFree((Pointer)clipPts); DXFree((Pointer)clipVecs); } if(!loadLights(globals, gather, _dxf_attributeFrontMaterial(_dxf_xfieldAttributes(xf)))) goto error; /* XXXX I hate this. Fuzz forces us to have the camera available when we are drawing each field ! */ if(!_dxf_isFlagsSet(_dxf_attributeFlags(_dxf_xfieldAttributes(xf)), IN_SCREEN_OBJECT) && (fuzz = (float)*_dxf_attributeFuzz(_dxf_xfieldAttributes(xf), NULL))) { float vm[4][4]; RGBColor color; PRINT(("dealing with fuzz...")); _dxfGetViewMatrixWithFuzz(MATRIX_STACK, (double)fuzz, vm); _dxf_PUSH_REPLACE_MATRIX(PORT_CTX,vm); if (! _dxf_getHwGatherAmbientColor(gather, &color)) goto error; if(!_dxf_DRAW_OPAQUE(PORT_HANDLE, xf, color, buttonUp)) goto error; _dxf_POP_MATRIX(PORT_CTX); } else { RGBColor color; PRINT(("! Fuzzy Screen Object")); if (! _dxf_getHwGatherAmbientColor(gather, &color)) goto error; if(!_dxf_DRAW_OPAQUE(PORT_HANDLE, xf, color, buttonUp)) goto error; } } } break; case HW_CLASS_SCREEN: { dxScreen s; float vm[4][4],pm[4][4]; PRINT(("HW_CLASS_SCREEN:")); if(!(_dxf_getHwScreenView((screenO)object, &s, &subObject,vm,NULL, NULL,NULL))) goto error; if (_dxf_getHwClass(parent) != HW_CLASS_SCREEN) { DXSetError(ERROR_INTERNAL, "parent of screen not screen?"); goto error; } if(!(_dxf_getHwScreenView((screenO)parent, NULL, NULL,NULL,pm, NULL,NULL))) goto error; /* * If this is a top level screen object (its parent was created from * the camera and has no parent), then set the projection matix to * identity. Reset the the camera projection matrix on exit. */ if (!grandparent) _dxf_REPLACE_VIEW_MATRIX(PORT_CTX,(float (*)[4])identity); _dxf_PUSH_REPLACE_MATRIX(PORT_CTX,vm); if (!_paintRecurse(globals, subObject, gather, buttonUp, object, parent)) goto error; _dxf_POP_MATRIX(PORT_CTX); if(!grandparent) _dxf_REPLACE_VIEW_MATRIX(PORT_CTX,pm); } break; case HW_CLASS_CLIPPED: { int knt; Point *pts; Vector *nrms; dxObject subObject; int i; PRINT(("HW_CLASS_CLIPPED:")); /* * pt and normal are in world coordinates. _dxf_ADD_CLIP_PLANE * requires view coordinates. * * So we need to apply the inverse of the clipping transform to the * pt and normal to correct for this. */ if (!_dxf_getHwClippedInfo((clippedO)object, &pts, &nrms, &knt, &subObject)) goto error; if (!_dxf_pushHwGatherClipPlanes(gather, knt, pts, nrms)) goto error; if (!_dxf_ADD_CLIP_PLANES(LWIN, pts, nrms, knt)) goto error; if(!_paintRecurse(globals, subObject, gather, buttonUp, parent, grandparent)) goto error; if (!_dxf_popHwGatherClipPlanes(gather)) goto error; if (!_dxf_REMOVE_CLIP_PLANES(LWIN, knt)) goto error; } break; default: DXErrorGoto (ERROR_BAD_PARAMETER, "Unrecognized private Object during paint"); break; } } break; case CLASS_CLIPPED: case CLASS_XFORM: case CLASS_SCREEN: case CLASS_FIELD: case CLASS_LIGHT: default: DXSetError (ERROR_BAD_PARAMETER, "Unrecognized Object (%d) during paint",class); goto error; break; } EXIT(("OK")); return OK; error: EXIT(("ERROR")); return ERROR; }