[ Previous | Next | Contents | Glossary | Home | Search ]
The graPHIGS Programming Interface: Getting Started

Chapter 6. Creating a Very Simple Modeller

This section covers the following topics:

Writing, Compiling, and Running the model Program

The model program allows you to build a 2D model using squares and triangles. Using the menu, you may add squares and triangles, delete all squares or all triangles, or exit the program.

Like the using3d program, this program requires a graPHIGS API PROFILE.

  1. Enter the following program into a file called model.c:
    -----------------------------------------------------------------
    /*
     * COMPONENT_NAME:  graPHIGS API Samples
     *
     * ORIGINS:  27
     *
     * (C) COPYRIGHT International Business Machines Corp. 1990
     * All Rights Reserved
     *
     * Licensed Materials - Property of IBM
     *
     * US Government Users Restricted Rights - Use, duplication or
     * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
     */
    /*--------------------------------------------------------------*/
    /* graPHIGS Start-Up :  a simple modeller                       */
    #include <afmnc.h>
                         /* graPHIGS include file */
     
    main() {
      static float window1[4] = {0.0,70.0,0.0,100.0};
      static float viewpt1[4] = {0.3,1.0,0.0,1.0};
      static float window2[4] = {0.0,9.0,0.0,30.0};
      static float viewpt2[4] = {0.0,0.3,0.0,1.0};
      static float geopts[8] = {0.0,0.0, 5.0,0.0, 5.0,5.0, 
    0.0,5.0};
      static float boxpts[8] = {0.0,0.0, 9.0,0.0, 9.0,1.0, 
    0.0,1.0};
      static float boxoff[2] = {0.0,1.0};
      static float txtpos[2] = {4.5,0.5};
      static char  *menus[9] = {"Exit",
                                "",
                                "Remove squares",
                                "Add squares",
                                "",
                                "Remove triangles",
                                "Add triangles"};
      float lcpos[2],mat[9],dydx;
      int wsid=1, ssid=1, ncid=1, viewid1=1,viewid2=2;
      int mode=1, topstrid=1, tristrid=2, sqstrid=3, menustrid=4;
      int depth,lcview,i,n,major,class,minor;
      struct {int strid, pkid, elnum;} pickpath;
     
      GPOPPH ("        ",0);         /* open graPHIGS               */
      GPCNC  (ncid,1,0,0);           /* connect to graPHIGS nucleus */
      GPCRSS (ssid,ncid,1,0);        /* create structure store      */
      GPSSS  (ssid);      		 /* select structure store      */
      GPCRWS (wsid,ncid,1,"*","X         ",0); /*create workstation */
      GPASSW (wsid,ssid);            /* link structure store to ws  */
      
      n=1;
      GPOPST(topstrid);       /* open geometry structure            */
      GPEF  (2);              /* set edge on                        */
      GPIS  (2);              /* set interior style solid           */
      GPECI (7);              /* set edge color WHITE               */
      GPICI (2);              /* set interior color RED             */
      GPEXST(tristrid);       /* execute triangle structure         */
      GPICI (4);              /* set interior color RED             */
      GPEXST(sqstrid);        /* execute square structure           */
      GPCLST();               /* close geometry structure           */
    
      GPTRL2(boxoff,mat);     /* calculate translation matrix       */
      GPOPST(menustrid);      /* open menu structure                */
      GPEF  (2); GPIS  (2);   GPECI (7); GPICI (4);  /* interior    */
      GPTXCI(7); GPTXAL(3,4); GPTXPR(3); GPCHH (0.6);/* edge attr   */
      n=1;GPADCN(1,&n);       /* add class to set, for picking      */
      n=4;
      for (i=0;i<7;i++) {
        GPPKID(i);            /* insert pick id                     */
        GPPG2 (1,&n,2,boxpts);/* insert menu item, polygon          */
        GPTX2(txtpos,strlen(menus[i]),menus[i]);   /*   text        */
        GPMLX2(mat,2);        /* translate to next menu item        */
      }
      GPCLST();		  /* close menu structure               */
      
      wholescreen(wsid,&dydx);  /* use whole screen, set WSX        */
      window1[3] *= dydx;     /* change window and viewport defs    */
      window2[3] *= dydx;     /*   to match screen aspect ratio     */
      viewpt1[3] *= dydx;                        		        */
      viewpt2[3] *= dydx;
      GPARV (wsid,viewid1,topstrid,1.0;    /* link root to view     */
      GPARV (wsid,viewid2,menustrid,1.0;   /* link root to view     */
      GPVMP2(wsid,viewid1,window1,viewpt1);/* set view mapping      */
      GPVMP2(wsid,viewid2,window2,viewpt2);/* set view mapping      */
      GPVCH (wsid,viewid1,2,2,2,  1,0,  2,1,  2);/* activate view   */
      GPVCH (wsid,viewid2,2,2,2,  1,0,  1,1,  2);/* activate view   */
      GPVIP (wsid,0,viewid1,2);     /* set view input priority 0>1  */
      
      n=1;
      GPPKF (wsid,1,1,&n,0,&n);     /* set pick filter, same class  */
      GPPKMO(wsid,1,3,2);           /* pick: event mode             */
      GPLCMO(wsid,1,3,2);           /* locator: sample mode         */
      GPUPWS(wsid,2);               /* update workstation           */
      
      while (mode != 0) {           /* loop to look for events      */
        GPAWEV(100.0&major,&class,&minor); /*  wait for event       */
        if (class == 5 && minor == 1) {    /*  pick event?          */
          GPGTPK(1,&depth,&pickpath);      /*  get pick information */
          if (pickpath.pkid == 6) mode = 1;/*  square mode          */
          if (pickpath.pkid == 3) mode = 2;/*  triangle mode        */
          if (pickpath.pkid == 0) mode = 0;/*  exit                 */
          if (pickpath.pkid == 5) GPEST(tristrid); /* erase tris    */
          if (pickpath.pkid == 2) GPEST(sqstrid);  /* erase squares */
        }
        if (class == 1 && minor == 1) {
          GPGTLC(&lcview,lcpos);            /* get mouse position   */
          if (lcview == viewid1) {          /* open proper structure*/
            if (mode == 1) { GPOPST(tristrid); n=3;}
            if (mode == 2) { GPOPST(sqstrid);  n=4;}
            GPTRL2(lcpos,mat);      /* calculate translation matrix */
            GPMLX2(mat,3);          /* insert model transform       */
            GPPG2(1,&n,2,geopts);   /* insert square/triangle       */
            GPCLIST();              /* close structure              */
          }
        }
        GPUPWS(wsid,2);             /* update structure             */
      }
      GPCLPH();			/* close graPHIGS               */
    }
    
    wholescreen(WSID,dydx)
      int wsid;
      float *dydx;
    {
      float dcsize[3] ;
      int status, units, rsize[3] ;
      static float window[6] = {0.0,1.0,0.0,1.0,0.0,1.0};
      static float viewpt[6] = {0.0,1.0,0.0,1.0,0.0,1.0};
      
      GPQADS(wsid,&status,&units,dcsize,rsize) ;
      *dydx = window[3] = dcsize[1]/dcsize[0];
      viewpt[1] = dcsize[0];
      viewpt[3] = dcsize[1];
      viewpt[5] = dcsize[2];
      GPWSX3(wsid,window,viewpt) ; 
    }  
    -----------------------------------------------------------------   
  2. Compile the program using the following AIX command:
    cc -o model model.c -lgP
  3. Enter the following into a file called PROFILE:
    * graPHIGS Start-Up - PROFILE for model.c sample
    *
    AFMMDFT DEFNUC=(0,)
  4. Run the program by entering:
    ./model

    A window pops onto the screen. Inside the window is a blue menu on the left, and a blank drawing area on the right. By clicking button 1 on the mouse while the mouse pointer is inside the drawing area, you may add triangles and squares to the model. By selecting a menu item, you may change between square and triangle mode, erase squares and triangles, or exit the program.

Examining the model Program

This section looks at the program in more detail, describing the purpose of various sets of instructions.

Initializing the graPHIGS API

The graPHIGS API has an architecture (high-level design) very similar to that of the X Window System**. With the X Window System, an application (called a client) is linked to XLIB which can send and receive the X protocol (data stream) to and from an X server. Analogous to the X concepts of XLIB and an X server are the graPHIGS API concepts of a shell and nucleus respectively. In the graPHIGS API under AIX, any shell/nucleus combination can communicate in one of the following two ways:

  1. The application is linked with the graPHIGS API shell which then communicates with a graPHIGS API nucleus running as a separate process either on the same node (machine) or on another node but on the same network. When using this communication method, the nucleus is called a remote nucleus and can be shared by multiple graPHIGS API applications.
  2. The application is linked with the graPHIGS API shell which is linked directly to the graPHIGS API nucleus so that the application and the graPHIGS API run as a single process. When using this communication method, the nucleus is called a private nucleus.

In order to take advantage of the architecture of the graPHIGS API, the following graPHIGS API subroutines must be used to initialize the graPHIGS API and create a workstation. (This program uses a private nucleus.)

-----------------------------------------------------------------
GPOPPH ("        ",0);         /* open graPHIGS                */
GPCNC  (ncid,1,0,0);           /* connect to graPHIGS nucleus  */
GPCRSS (ssid,ncid,1,0);        /* create structure store       */
GPSSS  (ssid);                 /* select structure store       */
GPCRWS (wsid, ncid,1,"*","X        ",0); /* create workstation */
GPASSW (wsid,ssid);            /* link structure store to ws   */
-----------------------------------------------------------------

Using Structure Hierarchy

Another new concept is the use of structure hierarchy. The following code is used to create the main geometry structure. Inside this structure, you execute two sub-structures; one to contain the squares, and one to contain the triangles. The capability to arrange structures into a hierarchy is very useful when you wish to:

-----------------------------------------------------------------
GPOPST(topstrid);      /* open geometry structure              */
GPEF  (2);             /* set edge on                          */
GPIS  (2);             /* set interior style solid             */
GPECI (7);             /* set edge color WHITE                 */
GPICI (2);             /* set interior color RED               */
GPEXST(tristrid);      /* execute triangle structure           */
GPICI (4);             /* set interior color RED               */
GPEXST(sqstrid);       /* execute square structure             */
GPCLST();              /* close geometry structure             */
-----------------------------------------------------------------

Creating Menus and Adding Pick Identifiers

The next section of code creates a simple graPHIGS API menu. It defines a list of menu items (text with background 2D polygons) using a separate graPHIGS API stucture. With each menu item, you also add a pick identifier which is returned by the graPHIGS API whenever the corresponding menu item is picked. Prior to defining the menu items, the Add Class Name to Set (GPADCN) subroutine must be used to make the menu items pickable.

-----------------------------------------------------------------
GPTRL2(boxoff,mat);    /* calculate translation matrix         */
GPOPST(menustrid);     /* open menu structure                  */
GPEF  (2); GPIS  (2);   GPECI (7); GPICI (4);  /* interior     */
GPTXCI(7); GPTXAL(3,4); GPTXPR(3); GPCHH (0.6);/* edge attr    */
n=1;GPADCN(1,&n);      /* add class to set, for picking        */
n=4;
for (i=0;i<7;i++) {
  GPPKID(i);           /* insert pick id                       */
  GPPG2 (1,&n,2,boxpts);  /* insert menu item, polygon         */
  GPTX2(txtpos,strlen(menus[i]),menus[i]);   /* text           
*/
  GPMLX2(mat,2);       /* translate to next menu item          */
}
GPCLST();              /* close menu structure                 */
-----------------------------------------------------------------

Picking Menu Items

In order to be able to pick the menu items just created, you must first activate a pick device by using the Set Pick Mode (GPPKMO) subroutine. You must also set a pick filter to match the class name added to the menu structure by using the Set Pick Filter (GPPKF) subroutine.

-----------------------------------------------------------------
n=1;
GPPKF (wsid,1,1,&n,0,;&n);  /* set pick filter, same class     */
GPPKMO(wsid,1,3,2);        /* pick: event mode                 */
GPLCMO(wsid,1,3,2);        /* locator: sample mode             */
GPUPWS(wsid,2);            /* update workstation               */
-----------------------------------------------------------------

Using the Whole Window

In the previous programs (square, flex, using3d and shade), only a single view has been used. This program defines two views; one for the geometry, and one for the menu.

Also, you may have noticed in the previous programs that the X window on the IBM RISC SYSTEM/6000 was not completely used. By default, the graPHIGS API uses a square display surface within a rectangular X window. This program includes a wholescreen utility function to instruct the graPHIGS API to use the entire X window. However, the aspect ratio is now no longer guaranteed to be 1:1. In order for geometry to appear undistorted, you must insure that the aspect ratio for the view's window and viewport values match that of the X window. The wholescreen utility function returns the X window aspect ratio which is then used to modify the view's window and viewport values.

------------------------------------------------------------------
  wholescreen(wsid,&dydx);  /* use whole screen, set WSX        */
  window1[3] *= dydx;    /* change window and viewport defs     */
  window2[3] *= dydx;    /*   to match screen aspect ratio      */
  viewpt1[3] *= dydx;
  viewpt2[3] *= dydx;
  GPARV (wsid,viewid1,topstrid,1.0);    /* link root to view    */
  GPARV (wsid,viewid2,menustrid,1.0);   /* link root to view    */
  GPVMP2(wsid,viewid1,window1,viewpt1); /* set view mapping     */
  GPVMP2(wsid,viewid2,window2,viewpt2); /* set view mapping     */
  GPVCH (wsid,viewid1,2,2,2,  1,0,  2,1,  2); /* activate view  */
  GPVCH (wsid,viewid2,2,2,2,  1,0,  1,1,  2); /* activate view  */
  GPVIP (wsid,0,viewid1,2); /* set view input priority 0>1      */
.
.
.
/* utility to use whole screen */
wholescreen(wsid,dydx)
        int wsid;
        float *dydx;
{
        float dcsize[3] ;
        int status, units, rsize[3] ;
        static float window[6] = {0.0,1.0,0.0,1.0,0.0,1.0};
        static float viewpt[6] = {0.0,1.0,0.0,1.0,0.0,1.0};
 
        GPQADS(wsid,&status,&units,dcsize,rsize) ;
        *dydx = window[3] = dcsize[1]/dcsize[0];
        viewpt[1] = dcsize[0] ;
        viewpt[3] = dcsize[1] ;
        viewpt[5] = dcsize[2] ;
        GPWSX3(wsid,window,viewpt) ;
}
------------------------------------------------------------------

Using the Input Loop

The last section of code contains the input loop. The Await Event (GPAWEV) subroutine instructs the graPHIGS API to wait for an event to occur (PICK or LOCATOR). If a pick event occurs, the pick information is retrieved using the Get Pick (GPGTPK) subroutine. The program uses the returned pick identifier value to determine which menu item was picked and take the appropriate action. If a locator event occurs, the program adds a square or triangle to the appropriate structure depending on the current mode.

------------------------------------------------------------------
  while (mode != 0) {        /* loop to look for events         */
    GPAWEV(100.0,&major,&class,&minor); /* wait for event       */
    if (class == 5 && minor == 1) {     /* pick event?          */
      GPGTPK(1,&depth,&pickpath);       /* get pick information */
      if (pickpath.pkid == 6) mode = 1; /* square mode          */
      if (pickpath.pkid == 3) mode = 2; /* triangle mode        */
      if (pickpath.pkid == 0) mode = 0; /* exit                 */
      if (pickpath.pkid == 5) GPEST(tristrid); /* erase tris    */
      if (pickpath.pkid == 2) GPEST(sqstrid);  /* erase squares */
    }
    if (class == 1 && minor == 1) {
      GPGTLC(&lcview,lcpos);            /* get mouse position   */
      if (lcview == viewid1) {          /* open proper structure*/
        if (mode == 1) { GPOPST(tristrid); n=3;}
        if (mode == 2) { GPOPST(sqstrid);  n=4;}
        GPTRL2(lcpos,mat);      /* calculate translation matrix */
        GPMLX2(mat,3);          /* insert model transform       */
        GPPG2(1,&n,2,geopts);   /* insert square/triangle       */
        GPCLST();               /* close structure              */
      }
    }
    GPUPWS(wsid,2);             /* update structure             */
  }
------------------------------------------------------------------

[ Previous | Next | Contents | Glossary | Home | Search ]