Logo Search packages:      
Sourcecode: acm version File versions  Download package

init.c

/*
 *  acm : an aerial combat simulator for X
 *  Copyright (C) 1991-1998  Riley Rainey
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 dated June, 1991.
 *
 *  This program 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 this program;  if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave., Cambridge, MA 02139, USA.
 */

#ifndef WIN32
#include <X11/Xos.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>

#include "pm.h"
#include "alarm.h"

extern craftType *newCraft (void);
extern int compileAircraftInventory (void);
extern void initaim9 (void), initm61a1 (void), initmk82(void), initaim120(void);
extern void buildExplosion (void);
extern void placeObject ();
extern void InitNavaidSystem ();
extern void DMECheckAlarm (char *arg1, char *arg2);
extern void resupplyCheck (char *arg1, char *arg2);
extern void acm_srand PARAMS ((int seed));
extern void addAltitudeEntry (WorldCoordinates * w);
extern int AddNavaid (char *ident, char *type, WorldCoordinates * w,
                  char *magvar, double freq);
extern int AddILS (char *ident, char *type, WorldCoordinates * w,
      WorldCoordinates * gsw, char *magvar, double freq, double loc_width,
               double loc_bearing, double gs_angle);

/*
 *  Defined in doViews.c :
 */

extern VPolygon **poly;
extern long polyCount;

void undersampleObject (VObject * obj, int rate);

static char *errmsg = "Sorry, I cannot find the file %s in ../objects/, %s or %s\n";

extern void
  AddRunway (VMatrix * RWYtoXYZ, double length, double width, int flags,
           VPolygon *** poly, int *poly_count);

/*
 *  acm_fopen :  Open an important acm data file (or die trying).
 */

char _acm_fopen_library_dir[2048];

FILE     *
acm_fopen(char *name, char *access)
{

      FILE     *f;
      char      libname[256];

      if ((f = fopen(name, access)) == (FILE *) NULL) {
            strcpy(libname, "../objects/");
            strcat(libname, name);
            if ((f = fopen(libname, access)) == (FILE *) NULL) {
                  strcpy(libname, _acm_fopen_library_dir);
                  strcat(libname, name);
                  if ((f = fopen(libname, access)) == (FILE *) NULL) {
                        strcpy (libname, SRCDIR);
                        strcat (libname, "/../objects/");
                        strcat (libname, name);
                        if ((f = fopen(libname, access)) == (FILE *) NULL) {
                              fprintf(stderr, errmsg, name, _acm_fopen_library_dir, libname);
                              exit(1);
                        }
                  }
            }
      }

      return f;
}

/*
 *  acm_find_file :  Find an important acm data file (or die trying).
 */

char     *
acm_find_file(char *name)
{
      static char pname[1024];
      struct stat statbuf;

      strcpy(pname, name);
      if (stat(name, &statbuf) != 0) {
            strcpy(pname, "../objects/");
            strcat(pname, name);
            if (stat(pname, &statbuf) != 0) {
                  strcpy(pname, _acm_fopen_library_dir);
                  strcat(pname, name);
                  if (stat(pname, &statbuf) != 0) {
                        fprintf(stderr, errmsg, name, _acm_fopen_library_dir);
                        exit(1);
                  }
            }
      }

      return pname;
}

enum state_t {
    SKIPPING_SPACES,
    ARGUMENT
};

int
split (char *s, int *argc, char *argv[])
{
    int done = 0;
    enum state_t state = SKIPPING_SPACES;

    *argc = 0;

    for (; done == 0; ++s) {

            switch (state) {

            case SKIPPING_SPACES:
                  if (isspace (*s)) {
                  }
                  else if (isascii (*s)) {
                        argv[*argc] = s;
                        (*argc)++;
                        state = ARGUMENT;
                  }
                  else if (*s == '\0') {
                        done = 1;
                  }
                  break;

            case ARGUMENT:
                  if (isspace (*s)) {
                        *s = '\0';
                        state = SKIPPING_SPACES;
                  }
                  else if (*s == '\0') {
                        *s = '\0';
                        done = 1;
                  }
            }
    }
    return 0;
}

/*
 *  readScene :  Process the scene description file, returns zero if successful
 *               or -1 otherwise.
 */

int
readScene (char *ground, int len)
{
    FILE *f, *f1;
    char file[256], *name, *filep;
    char *argv[32], line[1024];
    char lat[64], lon[64], lat_lon[64];
    double z, heading, freq, mag, length, width;
    int s, i = 0, j, undersample, depthcue, argc;
    craftType *c;
    extern char *sceneFile;   /* from server.c */
    VPoint scale, down, local_fwd, local_right, local_down;
    int done = 0;
    WorldCoordinates w, w1, w2, gsw;
    dis_world_coordinates xyz, xyz1;
    double loc_width, loc_bearing, gs_angle;
    VObject *object = NULL;
    VPolygon **rpoly;
    int rpoly_count;
    VMatrix RWYtoXYZ, XYZtoNED;

      /* initialize list of active viewers -- null list */

      vl_head = vl_tail = NULL;
      vl_count = 0;

      rpoly = NULL;
      rpoly_count = 0;

    name = (sceneFile) ? sceneFile : "default-scene";

    /*
     *  The units used in the objects we've created ate expressed in FEET.
     *  Internally, graphics objects should be METERS.
     */

    scale.x = scale.y = scale.z = FEETtoMETERS (1.0);
    VSetReadObjectScale (&scale);

    f = acm_fopen (name, "r");

    fscanf (f, "%s %s %lf %lf", lat, lon, &z, &heading);
#ifdef FLAT_WORLD
    teamLoc[1].x = x * NM;
    teamLoc[1].y = y * NM;
    teamLoc[1].z = z;
#else
    strcat (lat, lon);
    DISStringToLatLong (lat, &teamLatLon[1]);
    teamLatLon[1].z = FEETtoMETERS (z);
#endif
    teamHeading[1] = DEGtoRAD (heading);

    fscanf (f, "%s %s %lf %lf", lat, lon, &z, &heading);
#ifdef FLAT_WORLD
    teamLoc[2].x = x * NM;
    teamLoc[2].y = y * NM;
    teamLoc[2].z = z;
#else
    strcat (lat, lon);
    DISStringToLatLong (lat, &teamLatLon[2]);
    teamLatLon[2].z = FEETtoMETERS (z);
#endif
    teamHeading[2] = DEGtoRAD (heading);

    /*
     *  Get the ground color (the first call to fgets() gets us to a new line).
     */

    ground[0] = '\0';
    if (fgets (ground, len, f) == (char *) NULL) {
            return -1;
    }
    if (fgets (ground, len, f) == (char *) NULL) {
            return -1;
    }
    len = strlen (ground);
    if (len > 0 && ground[len - 1] == '\n') {
            ground[len - 1] = '\0';
            if (len > 0 && ground[len - 2] == '\r') {
                  ground[len - 2] = '\0';
            }
    }

    /*
     *  Now get the NAVAID and runway records
     */

    fgets (line, sizeof (line), f);
    done = 0;
    while (done == 0) {
      len = strlen (line);
      if (len > 0 && line[len - 1] == '\n') {
          line[len - 1] = '\0';
      }
      split (line, &argc, argv);

    /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
     *
     *  RWY : Runway record
     *
     *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/

      if (strcmp (argv[0], "RWY") == 0) {

          /*
           *  Parse Latitude/Longitude of both runway ends
           */
          length = FEETtoMETERS (atoi (argv[4]));
          width = FEETtoMETERS (atoi (argv[5]));

          strcpy (lat_lon, argv[6]);
          strcat (lat_lon, argv[7]);
          DISStringToLatLong (lat_lon, &w);
          w.z = FEETtoMETERS (atoi (argv[3]));

          addAltitudeEntry (&w);

          strcpy (lat_lon, argv[8]);
          strcat (lat_lon, argv[9]);
          DISStringToLatLong (lat_lon, &w1);
          w1.z = w.z;

          DISWorldCoordinatesToGeocentric (&w,
                                 (dis_world_coordinates *) & xyz);
          mag = sqrt (xyz.x * xyz.x + xyz.y * xyz.y + xyz.z * xyz.z);

          DISWorldCoordinatesToGeocentric (&w1,
                                (dis_world_coordinates *) & xyz1);

          /*
           *  Average those two points to generate a midpoint that will be the
           *  origin of a runway coordinate system.
           */

          local_fwd.x = xyz1.x - xyz.x;
          local_fwd.y = xyz1.y - xyz.y;
          local_fwd.z = xyz1.z - xyz.z;

          xyz.x = (xyz.x + xyz1.x) / 2.0;
          xyz.y = (xyz.y + xyz1.y) / 2.0;
          xyz.z = (xyz.z + xyz1.z) / 2.0;

          DISGeocentricToWorldCoordinates (&xyz, &w2);
          GenerateWorldToLocalMatrix (&w2, &XYZtoNED);
          down.z = 1.0;
          down.x = down.y = 0.0;
          VReverseTransform_ (&down, &XYZtoNED, &local_down);

          mag = sqrt (
                     local_fwd.x * local_fwd.x +
                     local_fwd.y * local_fwd.y +
                     local_fwd.z * local_fwd.z
            );
          local_fwd.x /= mag;
          local_fwd.y /= mag;
          local_fwd.z /= mag;

          /*
           *  A basic property of Cross Products: k x i = j
           */

          VCrossProd (&local_down, &local_fwd, &local_right);

          /*
           *  Generate a transformation matrix to get from "runway" coordinates to
           *  Geocentric.
           */
          VIdentMatrix (&RWYtoXYZ);

          RWYtoXYZ.m[0][0] = local_fwd.x;
          RWYtoXYZ.m[1][0] = local_fwd.y;
          RWYtoXYZ.m[2][0] = local_fwd.z;

          RWYtoXYZ.m[0][1] = local_right.x;
          RWYtoXYZ.m[1][1] = local_right.y;
          RWYtoXYZ.m[2][1] = local_right.z;

          RWYtoXYZ.m[0][2] = local_down.x;
          RWYtoXYZ.m[1][2] = local_down.y;
          RWYtoXYZ.m[2][2] = local_down.z;

          RWYtoXYZ.m[0][3] = xyz.x;
          RWYtoXYZ.m[1][3] = xyz.y;
          RWYtoXYZ.m[2][3] = xyz.z;

          /*
           *  AddRunway will return rpoly_count indicating the number of polygons
           *  that were generated. rpoly is a malloc'ed vector of pointers to 
             *  the polygons.
           */

          AddRunway (&RWYtoXYZ, length, width, 0,
                   &rpoly, &rpoly_count);

          /*
           *  optimize a bit here and put all the
           *  runways for a given airport in the same object ...
           *  object->name is the identifier of the current airport.
           */

          if ((object != NULL) && (strcmp (object->name, argv[1]) == 0)) {

            /*
             *  New runway at same airport as last .. add a polygon to the last object.
             */

            object->polygon = (VPolygon **) realloc (
                                              object->polygon,
                sizeof (VPolygon *) * (object->numPolys + rpoly_count));
            if (!object->polygon) {
                printf ("memory allocation error\n");
                exit (1);
            }
            for (j = 0; j < rpoly_count; ++j) {
                object->polygon[object->numPolys + j] = rpoly[j];
            }
            object->numPolys += rpoly_count;
            free (rpoly);
            rpoly_count = 0;
            VComputeObjectExtent (object);
          }
          else {

            /*
             *    New airport.  New object and craftInfo.
             */
            object = (VObject *) Vmalloc (sizeof (VObject));
            memset (object, 0, sizeof (VObject));
            object->name = strdup (argv[1]);
            object->numPolys = rpoly_count;
            object->polygon = rpoly;
            object->order = (unsigned short *) NULL;

            VComputeObjectExtent (object);

            stbl[i].type = CT_SURFACE;
            stbl[i].flags = FL_FIXED_OBJECT;
            stbl[i].cinfo = newCraft ();
            if (! stbl[i].cinfo) {
                  fprintf (stderr, "Out of craft types while loading scene.\n");
                  exit(1);
            }
            stbl[i].cinfo->name = strdup (argv[1]);
            stbl[i].cinfo->object = object;
            stbl[i].cinfo->placeProc = NULL;
            stbl[i].curHeading = stbl[i].curPitch = stbl[i].curRoll = 0.0;
            stbl[i].Sg.x = stbl[i].Sg.y = stbl[i].Sg.z = 0.0;
            if (++i == MAXSURFACE) {
                fprintf (stderr,
                "Only the first %d surface objects will be displayed.\n",
                       MAXSURFACE);
                i = MAXSURFACE - 1;
            }
          }
      }

    /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
     *
     *  NAV: NAVAID record
     *
     *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/

      else if (strcmp (argv[0], "NAV") == 0) {

          /*
           *  Parse Latitude/Longitude
           */

          strcpy (lat_lon, argv[3]);
          strcat (lat_lon, argv[4]);
          DISStringToLatLong (lat_lon, &w);
          w.z = FEETtoMETERS (atoi (argv[5]));
          freq = strtod (argv[7], (char **) NULL);

          AddNavaid (argv[1], argv[2], &w, argv[6], freq);
      }

    /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
     *
     *  ILS :  Instrument Landing System record
     *
     *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/

      else if (strcmp (argv[0], "ILS") == 0) {

          /*
           *  Parse Latitude/Longitude of localizer transmitter
           */

          strcpy (lat_lon, argv[5]);
          strcat (lat_lon, argv[6]);
          DISStringToLatLong (lat_lon, &w);
          w.z = FEETtoMETERS (atoi (argv[9]));

          /*
           *  Is Glide Slope transmitter information present?
           */

          if (strcmp (argv[7], "-") != 0) {
            strcpy (lat_lon, argv[7]);
            strcat (lat_lon, argv[8]);
            DISStringToLatLong (lat_lon, &gsw);
            gsw.z = w.z;
          }
          freq = strtod (argv[4], (char **) NULL);
          loc_width = strtod (argv[11], (char **) NULL);
          loc_bearing = strtod (argv[12], (char **) NULL);
          gs_angle = strtod (argv[13], (char **) NULL);

          AddILS (argv[3], argv[2], &w, &gsw, argv[10], freq,
                loc_width, loc_bearing, gs_angle);
      }
      else if (strcmp (argv[0], "FEATURES") == 0) {
          done = 1;
      }
      if (done == 0) {
          fgets (line, sizeof (line), f);
      }
    }

  /*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
   *
   *  Now the simple terrain/man-made features
   *
   *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/

    while (s = fscanf (f, "%s %s %s %lf %lf",
                   file, lat, lon, &z, &heading) == 5) {

      depthcue = 1;

      if (file[0] == '@') {
          filep = &file[1];
          undersample = 1;
      }
      else if (file[0] == '+') {
          filep = &file[1];
          depthcue = 0;
      }
      else {
          filep = file;
          undersample = 0;
      }
      stbl[i].type = CT_SURFACE;
      if ((c = lookupCraft (filep))) {
          stbl[i].cinfo = c;
      }
      else {
            char *p = strrchr (filep, '.');

          f1 = acm_fopen (filep, "r");
          stbl[i].cinfo = newCraft ();
          stbl[i].cinfo->name = strdup (filep);
            stbl[i].cinfo->object = NULL;
            if (p != NULL && (strcmp (p, ".dxf") == 0 ||
                                      strcmp (p, ".DXF") == 0)) {
                  stbl[i].cinfo->object = VReadDepthCueuedDXFObject (f1,
                                                                                             depthcue);
            }
            else {
                  stbl[i].cinfo->object = VReadDepthCueuedObject (f1,
                                                                                          depthcue);
            }

          if (!stbl[i].cinfo->object) {
                  fprintf (stderr,
                               "Error reading object %s\n", filep);
                  exit (1);
          }
          if (undersample) {
                  undersampleObject (stbl[i].cinfo->object, 3);
          }
          fclose (f1);
      }
#ifdef FLAT_WORLD
      stbl[i].Sg.x = x * NM;
      stbl[i].Sg.y = y * NM;
      stbl[i].Sg.z = z;
#else
      strcat (lat, lon);
      DISStringToLatLong (lat, &stbl[i].w);
      stbl[i].w.z = FEETtoMETERS (z);
      DISWorldCoordinatesToGeocentric (&stbl[i].w,
                            (dis_world_coordinates *) & stbl[i].Sg);
#endif
      stbl[i].curHeading = DEGtoRAD (heading);
      stbl[i].curPitch = stbl[i].curRoll = 0.0;
      if (++i == MAXSURFACE) {
          fprintf (stderr,
               "Only the first %d surface objects will be displayed.\n",
                 MAXSURFACE);
          fclose (f);
          return 0;
      }
    }
    fclose (f);
    return (s == EOF || s == 0) ? 0 : -1;
}

/*
 *  undersampleObject
 *
 *  Remove some of the detail in an object to reduce the CPU overhead
 *  of transforming and clipping it.
 */

void
undersampleObject (VObject * obj, int rate)
{
    int i, j, k;

    k = 0;

    for (i = 1; i < obj->numPolys; ++i) {
      for (j = 0; j < obj->polygon[i]->numVtces; j += rate) {
          obj->polygon[i]->vertex[k++] =
            obj->polygon[i]->vertex[j];
      }
      obj->polygon[i]->numVtces = k;
    }
}

/*
 *  init :  Set up the acm server
 */

int
init (const char *runtime_directory)
{
    int i;
    craft *p;
    alarm_id_t id;
    char ground[256];

      if (runtime_directory != NULL) {
            strcpy (_acm_fopen_library_dir, runtime_directory);
      }

    polyCount = 32768;
    poly = (VPolygon **) Vmalloc (sizeof (VPolygon *) * polyCount);

    cbase = -CLOUD_BASE;
    ctop = -CLOUD_TOP;

    /*
     *  VSetDepthCue() must be called before calling VSetVisibility().
     */

    VSetDepthCue (VAllocColor ("#A6BBCD"), depth_cue_steps);
    VSetVisibility (visibility);

    for ((i = 0, p = stbl); i < MAXSURFACE; (++i, ++p))
            p->type = CT_FREE;

    for ((i = 0, p = ptbl); i < MAXPLAYERS; (++i, ++p)) {
            p->pIndex = i;
            p->type = CT_FREE;
    }

    for ((i = 0, p = mtbl); i < MAXPROJECTILES; (++i, ++p)) {
            p->pIndex = i;
            p->type = CT_FREE;
    }

    acm_srand ((int) time (0));

    HUDColor = VAllocColor ("white");
    whiteColor = VAllocColor ("white");
    blackColor = VAllocColor ("black");
    radarColor = VAllocColor ("#0c0");
    HSIMagentaColor = VAllocColor ("magenta");
    radarBackgroundColor = VAllocColor ("#094200");
    cloudColor = VAllocDepthCueuedColor ("#ccc", 1);

    buildExplosion ();

    /*
     *  Set up the scene
     */

    if (readScene (ground, sizeof (ground)) != 0) {
            fprintf (stderr, "Fatal error\n");
            exit (1);
    }

    groundColor = VAllocDepthCueuedColor (ground, 1);

    /*
     *  Compile the aircraft inventory, DIS entity/munition maps
     */

    if (compileAircraftInventory () != 0) {
            fprintf (stderr, "Fatal error\n");
            exit (1);
    }

    if (compileEntityMap("object-map.txt", &eo_map_count, &eo_map) != 0) {
            fprintf (stderr, "Fatal error\n");
            exit(1);
    }

    if (compileMunitionMap("munition-map.txt",
                                       &mun_map_count, &mun_map) != 0) {
            fprintf (stderr, "Fatal error\n");
            exit(1);
    }

    /*
     *  Initialize weapons
     */

    initaim9 ();
    initm61a1 ();
      initmk82 ();
      initaim120 ();

    /*
     *  Set up the radio/navaid check.
     */

    id = addAlarm (5.0, DMECheckAlarm, NULL, NULL);

    /*
     *  Add the periodic resupply check procedure
     */

    id = addAlarm (RESUPPLY_INTERVAL, resupplyCheck, NULL, NULL);

    return 0;
}

void
closeScene()
{
      int i;

      for (i=0; i<MAXSURFACE; ++i) {
            if (stbl[i].type != CT_FREE) {
            }
      }
}

void
freeAll(void)
{
      freeRendering();
      freeCraftTypes();
      freeAllNavaids();
      freeEffects();
      dis_close();
      releaseVResources ();
}

Generated by  Doxygen 1.6.0   Back to index