/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): */ /* The instruction graph visulizer. IGVisualizer.cpp Peter DeSantis */ #if defined(DEBUG) && (defined(WIN32) || defined(USE_MESA)) && defined(IGVISUALIZE) #include #include #include #include #include "CodeGenerator.h" #include "IGVisualizer.h" #include "Instruction.h" #include "Primitives.h" #include "Vector.h" // To allow glut callbacks to access member data IGVisualizer* IGVisualizer::self = NULL; IGVisualizer:: IGVisualizer() { font = GLUT_STROKE_ROMAN; zoomFactor = 2; cumZoom = 1; objectCenterX = 0; objectCenterY = 0; mouseCenterX = 0; mouseCenterY = 0; nodeLocX = 0; nodeLocY = 0; xWindowDim = 800; // Dimension of window yWindowDim = 600; xDimGL = 10000; yDimGL = 10000; centerX = 0; centerY = 0; INSTRUCTIONWIDTH = 1400; // The size of the instruction itself INSTRUCTIONHEIGHT = 500 ; FRAMEWIDTH = 1450; // Frame is the area around an instruction FRAMEHEIGHT = 750; BORDERWIDTH = 20; // Border around an instruction SPACEBETWEENTREES = 130; ARGUMENTREGISTERS = 4; // VR <= AURGUMENTMENTREGISTERS self = this; roots = new Vector; } IGVisualizer :: ~IGVisualizer() { delete roots; } /* Add all the roots you want to be visualized before calling visualize */ void IGVisualizer :: addRoots(Vector& inRoots) { RootPair* curRoot; VisualInstructionRoot* vRoot = NULL; for(curRoot = inRoots.begin(); curRoot < inRoots.end(); curRoot++) { DataNode* curOutput; Instruction* nextInsn; if(curRoot->root->getOutgoingEdgesEnd() > curRoot->root->getOutgoingEdgesBegin()) { // now walk through all vr's assigned to this producer VirtualRegister* curVR; for (curOutput = curRoot->root->getOutgoingEdgesBegin(); curOutput < curRoot->root->getOutgoingEdgesEnd(); curOutput++) { switch (curOutput->kind) { case vkCond: case vkMemory: nextInsn = curOutput->getInstructionAnnotation(); break; default: curVR = curOutput->getVirtualRegisterAnnotation(); assert (curVR); nextInsn = curVR->getDefineInstruction(); break; } assert (nextInsn); vRoot = new VisualInstructionRoot; vRoot->root = nextInsn; vRoot->exploringAsRoot = false; vRoot->locAsCSE = new Vector; vRoot->currentCSE = NULL; vRoot->locAsRoot = NULL; roots->append(*vRoot); } } if (curRoot->root->getInstructionRoot() != NULL) { nextInsn = curRoot->root->getInstructionRoot(); vRoot = new VisualInstructionRoot; vRoot->root = nextInsn; vRoot->exploringAsRoot = false; vRoot->locAsCSE = new Vector; vRoot->currentCSE = NULL; vRoot->locAsRoot = NULL; roots->append(*vRoot); } } } /* Internal routine which visualizes the set of roots */ void IGVisualizer :: visualizeRoots() { int bottom = 0; int left = 0; VisualInstructionRoot* curRoot; for(curRoot = self->roots->begin(); curRoot < self->roots->end(); curRoot++) { curRoot->exploringAsRoot = true; curRoot->locAsRoot = &DrawTree(*(curRoot->root), bottom, left); bottom = curRoot->locAsRoot->top + self->SPACEBETWEENTREES; curRoot->exploringAsRoot = false; } } VisualInstructionRoot* IGVisualizer :: isInRoots(Instruction* subRoot) { VisualInstructionRoot* curRoot; for(curRoot = self->roots->begin(); curRoot < self->roots->end(); curRoot++) if(curRoot->root == subRoot) return curRoot; return NULL; } /* Internal routine to draw the tree rooted a root so that root's bottom is at yBottom and the tree rooted at root extends to xLeft. */ TreeLocation& IGVisualizer :: DrawTree(Instruction& root, int yBottom, int xLeft) { Instruction* subRoot; InstructionUse* curUse; TreeLocation* loc; TreeLocation* myLocation = new TreeLocation; Vector subTreeLocations; VisualInstructionRoot* vRoot; int left = xLeft; int top = yBottom + self->FRAMEHEIGHT; if(root.next == NULL) { assert(root.prev == NULL); assert(root.getInstructionDefineEnd() == root.getInstructionDefineBegin() +1); assert(root.getInstructionUseEnd() == root.getInstructionUseBegin() +1); // Instruction has been removed from the list curUse = root.getInstructionUseBegin(); subRoot = CodeGenerator::instructionUseToInstruction(*curUse); if(subRoot != NULL) { vRoot = isInRoots(subRoot); if(vRoot != NULL) // CSE { loc = new TreeLocation; loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left; loc->right = self->FRAMEWIDTH + left; loc->top = yBottom + self->FRAMEHEIGHT; loc->bottom = yBottom; DrawSubExpressionNode(subRoot, loc->rootMiddle, loc->bottom); vRoot->locAsCSE->append(*loc); loc = new TreeLocation; loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left; loc->right = self->FRAMEWIDTH + left; loc->top = yBottom + self->FRAMEHEIGHT; loc->bottom = yBottom; return *loc; } else { PrimitiveOperation op = subRoot->getPrimitive()->getOperation(); switch (op) { case(poPhi_M): case(poPhi_I): case(poPhi_L): case(poPhi_F): case(poPhi_D): case(poPhi_A): case(poPhi_C): loc = new TreeLocation; loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left; loc->right = self->FRAMEWIDTH + left; loc->top = yBottom + self->FRAMEHEIGHT; loc->bottom = yBottom; DrawDummyNode(loc->rootMiddle, loc->bottom); return *loc; break; default: return DrawTree(*subRoot, yBottom, left); break; } } } else { // This input is not defined loc = new TreeLocation; loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left; loc->right = self->FRAMEWIDTH + left; loc->top = yBottom + self->FRAMEHEIGHT; loc->bottom = yBottom; if( (curUse->kind == udRegister) && ((*(curUse->name.vr)).index <= self->ARGUMENTREGISTERS) ) { DrawArgumentNode(loc->rootMiddle, loc->bottom); } else DrawDummyNode(loc->rootMiddle, loc->bottom); return *loc; } } assert(root.prev != NULL); // Draw your sub trees for(curUse = root.getInstructionUseBegin(); curUse < root.getInstructionUseEnd(); curUse++) { subRoot = CodeGenerator::instructionUseToInstruction(*curUse); if(subRoot != NULL) { vRoot = isInRoots(subRoot); if(vRoot != NULL) // CSE { loc = new TreeLocation; loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left; loc->right = self->FRAMEWIDTH + left; loc->top = yBottom + (2 * self->FRAMEHEIGHT); loc->bottom = yBottom + self->FRAMEHEIGHT; DrawSubExpressionNode(subRoot, loc->rootMiddle, loc->bottom); vRoot->locAsCSE->append(*loc); loc = new TreeLocation; loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left; loc->right = self->FRAMEWIDTH + left; loc->top = yBottom + (2 * self->FRAMEHEIGHT); loc->bottom = yBottom + self->FRAMEHEIGHT; } else { PrimitiveOperation op = subRoot->getPrimitive()->getOperation(); switch (op) { case(poPhi_M): case(poPhi_I): case(poPhi_L): case(poPhi_F): case(poPhi_D): case(poPhi_A): case(poPhi_C): loc = new TreeLocation; loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left; loc->right = self->FRAMEWIDTH + left; loc->top = yBottom + (2 * self->FRAMEHEIGHT); loc->bottom = yBottom + self->FRAMEHEIGHT; DrawDummyNode(loc->rootMiddle, loc->bottom); break; default: loc = &DrawTree(*subRoot, yBottom + self->FRAMEHEIGHT, left); break; } }//loc = &DrawTree(*subRoot, yBottom + self->FRAMEHEIGHT, left); } else // This input is not defined { loc = new TreeLocation; loc->rootMiddle = (float)self->FRAMEWIDTH/2 + left; loc->right = self->FRAMEWIDTH + left; loc->top = yBottom + (2 * self->FRAMEHEIGHT); loc->bottom = yBottom + self->FRAMEHEIGHT; if( (curUse->kind == udRegister) && ((*(curUse->name.vr)).index <= self->ARGUMENTREGISTERS) ) { DrawArgumentNode(loc->rootMiddle, loc->bottom); } else DrawDummyNode(loc->rootMiddle, loc->bottom); } if(loc->top > top) top = loc->top; left = loc->right; subTreeLocations.append(*loc); } if(subTreeLocations.size() == 0) { myLocation->rootMiddle = (float)self->FRAMEWIDTH/2 + xLeft; myLocation->right = self->FRAMEWIDTH + xLeft; myLocation->top = yBottom + self->FRAMEHEIGHT; myLocation->bottom = yBottom; } else { myLocation->rootMiddle = subTreeLocations.front().rootMiddle + (0.5f)*(subTreeLocations.back().rootMiddle - subTreeLocations.front().rootMiddle); myLocation->right = subTreeLocations.back().right; myLocation->top = top; myLocation->bottom = yBottom; } DrawNode(myLocation->rootMiddle, yBottom, &root, subTreeLocations); return *myLocation; } /* Dum routine reads a file to a stream, returns size printPretty should use strings */ int fileToString(char *fileName, char *string, int len) { FILE* file = fopen(fileName, "r"); assert(file); char c = fgetc(file); int i = 0; while(!feof(file) && i < (len-1)) { if(c == 9) c = ' '; string[i] = c; i++; c = fgetc(file); } string[i] = '\0'; fclose(file); return i; } /* Write instruction Name and label Registers */ void IGVisualizer :: LabelNode(Instruction* inst) { FILE* file; char fileName[] = "shitFile"; file = fopen(fileName, "w" ); char prettyString[50]; // Label instruction ***************************************** glColor3f(0.0, 0.0, 0.0); glPushMatrix(); // 1 glTranslated(3*(float)self->BORDERWIDTH, (float)self->INSTRUCTIONHEIGHT/2.5, 0.0); int len, i; inst->printPretty(file); fclose(file); len = fileToString(fileName, prettyString, 50); for (i = 0; i < len; i++) { glutStrokeCharacter(self->font, prettyString[i]); } glPopMatrix(); // 1 // Label Outputs ********************************************* glColor3f(0.5f, 0.2f, 0.4f); char registerName[50]; float distanceBetween; int vrn, j; InstructionDefine* curDefine; int numberOfOutputs, numberOfInputs; numberOfOutputs= inst->getInstructionDefineEnd() - inst->getInstructionDefineBegin();; assert(numberOfOutputs <= 1); distanceBetween = (float)self->INSTRUCTIONWIDTH/(numberOfOutputs+1); glPushMatrix(); // 2 glTranslatef(0.0, 3*(float)self->BORDERWIDTH, 0.0); j=1; for(curDefine = inst->getInstructionDefineBegin(); curDefine < inst->getInstructionDefineEnd(); curDefine++) { glPushMatrix(); // 3 glTranslatef(j*distanceBetween-100, 0.0, 0.0); if(curDefine->kind == udRegister) { vrn = (*(curDefine->name.vr)).index; sprintf(registerName, "R%d", vrn); } else if (curDefine->kind == udCond) sprintf(registerName, "Cond"); else sprintf(registerName, "Store"); len = strlen(registerName); for (i = 0; i < len; i++) { glutStrokeCharacter(self->font, registerName[i]); } glPopMatrix(); // 3 j++; } glPopMatrix(); // 2 // Label Inputs ********************************************** glColor3f(1.0f, 0.0f, 0.2f); InstructionUse* curUse; numberOfInputs = inst->getInstructionUseEnd() - inst->getInstructionUseBegin(); distanceBetween = (float)self->INSTRUCTIONWIDTH/(numberOfInputs+1); glPushMatrix(); // 4 glTranslatef(0.0, self->INSTRUCTIONHEIGHT - 100 - 3*(float)self->BORDERWIDTH, 0.0); j=1; for(curUse = inst->getInstructionUseBegin(); curUse < inst->getInstructionUseEnd(); curUse++) { glPushMatrix(); // 5 glTranslatef(j*distanceBetween-100, 0.0, 0.0); if(curUse->kind == udRegister) { vrn = (*(curUse->name.vr)).index; sprintf(registerName, "R%d", vrn); } else if (curUse->kind == udCond) sprintf(registerName, "Cond"); else sprintf(registerName, "Store"); len = strlen(registerName); for (i = 0; i < len; i++) { glutStrokeCharacter(self->font, registerName[i]); } glPopMatrix(); // 5 j++; } glPopMatrix(); // 4 } /* Draw a single instruction with its bottom line centered at (xMiddle, yBottom) */ void IGVisualizer :: DrawNode(double xMiddle, int yBottom, Instruction* inst, Vector& subTrees) { glPushMatrix(); // 1 glTranslatef((float)xMiddle - self->INSTRUCTIONWIDTH/2, (float)yBottom, 0); // Draw Instruction body ************************************* glColor3f(0.0, 1.0, 1.0); glRecti(0, 0, self->INSTRUCTIONWIDTH, self->INSTRUCTIONHEIGHT); glColor3f(1.0, 1.0, 1.0); glRecti(self->BORDERWIDTH, self->BORDERWIDTH, self->INSTRUCTIONWIDTH-self->BORDERWIDTH, self->INSTRUCTIONHEIGHT-self->BORDERWIDTH); LabelNode(inst); // Connect Inputs ************************************************* TreeLocation* loc; int numberOfInputs = subTrees.size(); int distToNextLayer = self->FRAMEHEIGHT - self->INSTRUCTIONHEIGHT; float jag = ((float)distToNextLayer/(numberOfInputs + 1)); float diffMid; float distanceBetween = (float)self->INSTRUCTIONWIDTH/(numberOfInputs+1); glPushMatrix(); // 2 glTranslatef(0.0, (float)self->INSTRUCTIONHEIGHT, 0.0); int j=1; for(loc = subTrees.begin(); loc < subTrees.end(); loc++) { glPushMatrix(); // 3 glTranslatef(j*distanceBetween, 0.0, 0.0); diffMid = loc->rootMiddle - (float)xMiddle - (j*distanceBetween - ((0.5f)*self->INSTRUCTIONWIDTH)); glBegin(GL_LINES); glVertex2f(0.0f, 0.0f); glVertex2f(0.0f, j*jag); glVertex2f(0.0f, j*jag); glVertex2f(diffMid, j*jag); glVertex2f(diffMid, j*jag); glVertex2f(diffMid, (numberOfInputs + 1)*jag); glEnd(); glPopMatrix(); // 3 j++; } glPopMatrix(); // 2 glPopMatrix(); // 1 } /* Draw a node as a subexpression */ void IGVisualizer :: DrawSubExpressionNode(Instruction* inst, double xMiddle, double yBottom) { glPushMatrix(); // 1 glTranslatef((float)xMiddle - self->INSTRUCTIONWIDTH/2, (float)yBottom, 0); // Draw Instruction body ************************************* glColor3f(1.0, 1.0, 0.0); glRecti(0, 0, self->INSTRUCTIONWIDTH, self->INSTRUCTIONHEIGHT); glColor3f(1.0, 1.0, 1.0); glRecti(self->BORDERWIDTH, self->BORDERWIDTH, self->INSTRUCTIONWIDTH-self->BORDERWIDTH, self->INSTRUCTIONHEIGHT-self->BORDERWIDTH); // Draw the node LabelNode(inst); glPopMatrix(); // 1 } /* Draw a dummy "unknown" instruction with its bottom line centered at (xMiddle, yBottom) */ void IGVisualizer :: DrawDummyNode(double xMiddle, int yBottom) { char unknownMess[] = " ??? "; glPushMatrix(); // 1 glTranslatef((float)xMiddle - self->INSTRUCTIONWIDTH/2, (float)yBottom, 0); // Draw Instruction body ************************************* glColor3f(1.0, 0.0, 0.0); glRecti(0, 0, self->INSTRUCTIONWIDTH, self->INSTRUCTIONHEIGHT); glColor3f(1.0, 1.0, 1.0); glRecti(5 * self->BORDERWIDTH, 5 * self->BORDERWIDTH, self->INSTRUCTIONWIDTH-(5*self->BORDERWIDTH), self->INSTRUCTIONHEIGHT-(5*self->BORDERWIDTH)); // Write Message ****************************************** glColor3f(1.0, 0.0, 0.0); glPushMatrix(); // 2 glTranslated(3*(float)self->BORDERWIDTH, (float)self->INSTRUCTIONHEIGHT/2.5, 0.0); int len, i; len = (int) strlen(unknownMess); for (i = 0; i < len; i++) { glutStrokeCharacter(self->font, unknownMess[i]); } glPopMatrix(); // 2 glPopMatrix(); //1 } /* Draw an argument node */ void IGVisualizer :: DrawArgumentNode(double xMiddle, int yBottom) { char unknownMess[] = " Argument "; glPushMatrix(); // 1 glTranslatef((float)xMiddle - self->INSTRUCTIONWIDTH/2, (float)yBottom, 0); // Draw Instruction body ************************************* glColor3f(0.0f, 1.0f, 0.3f); glRecti(0, 0, self->INSTRUCTIONWIDTH, self->INSTRUCTIONHEIGHT); glColor3f(1.0f, 1.0f, 1.0f); glRecti(5 * self->BORDERWIDTH, 5 * self->BORDERWIDTH, self->INSTRUCTIONWIDTH-(5*self->BORDERWIDTH), self->INSTRUCTIONHEIGHT-(5*self->BORDERWIDTH)); // Write Message ****************************************** glColor3f(0.0f, 1.0f, 0.3f); glPushMatrix(); // 2 glTranslated(3*(float)self->BORDERWIDTH, (float)self->INSTRUCTIONHEIGHT/2.5, 0.0); int len, i; len = (int) strlen(unknownMess); for (i = 0; i < len; i++) { glutStrokeCharacter(self->font, unknownMess[i]); } glPopMatrix(); // 2 glPopMatrix(); //1 } /* This is the window system specific stuff for setting up the window for gl. Visualize is called only once and it enters a non-returning display loop. */ enum subMenuFields { findAsRoot, findNextRef }; void IGVisualizer :: visualize() { int zoomMenu, rootMenu; char* argv ="myProgram"; int argc = 1; // Initialization glutInit(&argc, &argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(xWindowDim, yWindowDim); glutCreateWindow("Instruction Graph Viewer Dulux"); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-xDimGL, xDimGL, -yDimGL, yDimGL); glMatrixMode(GL_MODELVIEW); glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glLineWidth(1.0); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glColor3f(1.0f, 1.0f, 1.0f); // Add callbacks glutDisplayFunc(display); glutMouseFunc(mouse); glutKeyboardFunc(keyboard); glutReshapeFunc(reshape); // Create the menu zoomMenu = glutCreateMenu(selectZoom); glutAddMenuEntry("X 2", 2); glutAddMenuEntry("X 5", 5); rootMenu = glutCreateMenu(selectRoot); glutAddMenuEntry("Goto Definition", findAsRoot); glutAddMenuEntry("Goto Next Reference", findNextRef); glutCreateMenu(mainMenu); glutAddSubMenu("ZoomFactor", zoomMenu); glutAddSubMenu("Explore Subexpression", rootMenu); glutAddMenuEntry("Exit", 0); glutAttachMenu(GLUT_RIGHT_BUTTON); glutMainLoop(); } /* The callback routines */ void IGVisualizer :: display() { glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); // 1 glScaled(self->cumZoom, self->cumZoom, 1); glTranslated(self->centerX - self->objectCenterX + self->mouseCenterX, self->centerY - self->objectCenterY + self->mouseCenterY, 0); visualizeRoots(); glPopMatrix(); // 1 glutSwapBuffers(); } void IGVisualizer :: selectZoom(int msg) { self->zoomFactor = float(msg); glutPostRedisplay(); } void IGVisualizer :: selectRoot(int msg) { VisualInstructionRoot* vRoot = findRootAtLoc(self->nodeLocX, self->nodeLocY); if(vRoot != NULL) { //printf("FOUND ONE\n"); switch(msg) { case findAsRoot: self->objectCenterX = vRoot->locAsRoot->rootMiddle; self->objectCenterY = vRoot->locAsRoot->bottom; self->mouseCenterX = 0; self->mouseCenterY = 0; break; case findNextRef: if(vRoot->currentCSE == NULL) if(vRoot->locAsCSE->size() != 0) vRoot->currentCSE = vRoot->locAsCSE->begin(); else return; else { vRoot->currentCSE++; if(vRoot->currentCSE == vRoot->locAsCSE->end()) vRoot->currentCSE = vRoot->locAsCSE->begin(); } self->objectCenterX = vRoot->currentCSE->rootMiddle; self->objectCenterY = vRoot->currentCSE->bottom; self->mouseCenterX = 0; self->mouseCenterY = 0; break; } } glutPostRedisplay(); } VisualInstructionRoot* IGVisualizer :: findRootAtLoc(double x, double y) { VisualInstructionRoot* vRoot; TreeLocation* tree; for(vRoot = self->roots->begin(); vRoot < self->roots->end(); vRoot++) { if(isInNode(x, y, vRoot->locAsRoot->rootMiddle, vRoot->locAsRoot->bottom)) return vRoot; for(tree = vRoot->locAsCSE->begin(); tree < vRoot->locAsCSE->end(); tree++) if(isInNode(x, y, tree->rootMiddle, tree->bottom)) return vRoot; } return NULL; } bool IGVisualizer :: isInNode(double x, double y, double middle, int bottom) { if((x < (middle + (.5*self->INSTRUCTIONWIDTH))) && (x > (middle - (.5*self->INSTRUCTIONWIDTH)))) if((y > bottom) && (y < (bottom + self->INSTRUCTIONHEIGHT))) return true; return false; } void IGVisualizer :: mainMenu(int msg) { switch(msg) { case 0: exit(0); break; } glutPostRedisplay(); } void IGVisualizer :: mouse(int button, int state, int x, int y) { if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { double transX = -(x - (.5 * (self->xWindowDim)))*((2*self->xDimGL/self->xWindowDim)/self->cumZoom); double transY = (y - (.5 * (self->yWindowDim)))*((2*self->yDimGL/self->yWindowDim)/self->cumZoom); self->mouseCenterX = self->mouseCenterX + transX; self->mouseCenterY = self->mouseCenterY + transY; } glutPostRedisplay(); } void IGVisualizer :: keyboard(unsigned char key, int x, int y) { switch(key){ case '+': self->cumZoom = self->cumZoom * self->zoomFactor; break; case '-': self->cumZoom = self->cumZoom / self->zoomFactor; break; case 's': double transX = (x - (.5 * (self->xWindowDim)))*((2*self->xDimGL/self->xWindowDim)/self->cumZoom); double transY = -(y - (.5 * (self->yWindowDim)))*((2*self->yDimGL/self->yWindowDim)/self->cumZoom); //printf("mouse center**%f, %f**\n", self->mouseCenterX, self->mouseCenterY); //printf("strans **%f, %f**\n", transX, transY); //printf("obj center **%f, %f**\n", self->objectCenterX, self->objectCenterY); self->nodeLocX = transX - self->mouseCenterX + self->objectCenterX; self->nodeLocY = transY - self->mouseCenterY + self->objectCenterY; //printf("node center **%f, %f**\n", self->nodeLocX, self->nodeLocY); break; } glutPostRedisplay(); } void IGVisualizer :: reshape(int width, int height) { self->xWindowDim = width; self->yWindowDim = height; glViewport(0, 0, width, height); glutPostRedisplay(); } #endif