Beispiel #1
0
void LabEngine::doMap() {
	static uint16 amigaMapPalette[] = {
		0x0BA8, 0x0C11, 0x0A74, 0x0076,
		0x0A96, 0x0DCB, 0x0CCA, 0x0222,
		0x0444, 0x0555, 0x0777, 0x0999,
		0x0AAA, 0x0ED0, 0x0EEE, 0x0694
	};

	_graphics->_fadePalette = amigaMapPalette;

	updateEvents();
	loadMapData();
	_graphics->blackAllScreen();
	_interface->attachButtonList(&_mapButtonList);
	drawMap(_roomNum, _roomNum, _maps[_roomNum]._pageNumber, true);
	_event->mouseShow();
	_graphics->screenUpdate();
	processMap(_roomNum);
	_event->mouseHide();
	_interface->attachButtonList(nullptr);
	_graphics->fade(false);
	_graphics->blackAllScreen();
	_graphics->rectFill(0, 0, _graphics->_screenWidth - 1, _graphics->_screenHeight - 1, 0);
	freeMapData();
	_event->mouseShow();
	_graphics->screenUpdate();
}
void gameScreen(gameState &game)
{
    vector<vector<char>> processedMap;

    processMap("testing.map", processedMap);

    renderMap(processedMap);

    game = QUIT_MENU;
}
AREXPORT void ArForbiddenRangeDevice::setRobot(ArRobot *robot)
{
  myRobot = robot;
  if (myRobot != NULL)
    myRobot->addSensorInterpTask(myName.c_str(), 20, &myProcessCB);
  ArRangeDevice::setRobot(robot);
  myMap->lock();
  myMap->addMapChangedCB(&myMapChangedCB);
  processMap();
  myMap->unlock();
}
Beispiel #4
0
  DiscreteDepthDistortionModel SlamCalibrator::calibrate() const
  {
    BOOST_ASSERT(!sseqs_.empty());
    DiscreteDepthDistortionModel model(sseqs_[0]->proj_.width_, sseqs_[0]->proj_.height_);

    size_t total_num_training = 0;
    for(size_t i = 0; i < size(); ++i) {
      cout << "Accumulating training data for sequence " << i << flush;
      total_num_training += processMap(*sseqs_[i], trajectories_[i], *maps_[i], &model);
    }

    cout << "Trained new DiscreteDepthDistortionModel using "
         << total_num_training << " training examples." << endl;
  
    return model;
  }
Beispiel #5
0
void LevelXmlParser::processLevel(xmlNodePtr cur, Level* level)
{
    xmlNodePtr child = cur->xmlChildrenNode;
    while (child != NULL)
    {
        if (!xmlStrcmp(child->name, (const xmlChar*)"map"))
        {
            processMap(child, level);
        }
        if (!xmlStrcmp(child->name, (const xmlChar*)"playerstart"))
        {
            processPlayerStart(child, level);
        }
        
        child = child->next;
    }
}
bool
TMXLoader::Private::load(const char *f)
{
	TinyXML::XMLDocument l_tmx;
	XMLElement *l_root;

	is_loaded = false;

	if (l_tmx.LoadFile(f) != XML_NO_ERROR)
	    return(false);

	/* get parent directory */
	base_directory = Core::Platform::PathDirectory(f);

	/* parse general map data */
	if (!(l_root = l_tmx.RootElement())
	 || !processMap(*l_root))
	    return(false);

	/* parse tilesets */
	XMLElement *l_tileset = l_root->FirstChildElement(TMXTILESET_NODE);
	while (l_tileset) {
		if (!processTileset(*l_tileset))
			return(false);
		l_tileset = l_tileset->NextSiblingElement(TMXTILESET_NODE);
	}

	/* parse layers and object groups */
	XMLElement *l_element = l_root->FirstChildElement();
	while (l_element) {
		if (0 == strcmp(l_element->Value(), TMXLAYER_NODE)
		    && !processLayer(*l_element))
			return(false);
		else if (0 == strcmp(l_element->Value(), TMXOBJECTGROUP_NODE)
		    && !processObjectGroup(*l_element))
			return(false);
		l_element = l_element->NextSiblingElement();
	}

	/* attach layers to scene */
	Game::SharedSceneLayerList::iterator l_layer_i;
	for (l_layer_i = layers.begin(); l_layer_i != layers.end(); ++l_layer_i)
		scene.pushLayer(*l_layer_i);

	return(is_loaded = true);
}
Beispiel #7
0
/*
 * Analyze the given object and set up for contour drawing with VBOs
 */
int VertBufManager::analyzeConts(Iobj *obj, int obNum, int thickenCont, int checkStipple,
                                 int checkTime)
{
  RGBTmap colors;
  pair<RGBTmap::iterator,bool> mapret;
  RGBTmap::iterator mapit;
  DrawProps defProps, contProps;
  VertBufData *vbd = obj->vertBufCont;
  RGBTindices rInd;
  b3dUInt32 contRGBT;
  Icont *cont;
  int handleFlags, nonVboFlags, numRemnant, fullState, skip, numVerts, cumInd, co;
  int numInds, ivert, irem, iDefInd, contState, surfState, ind, pt, psize, match;

  rInd.numFanInds = 0;
  handleFlags = CHANGED_COLOR | CHANGED_TRANS;
  nonVboFlags = CHANGED_3DWIDTH;

  // Check if there is a current VBO and it is all still valid 
  // TODO: handle finegrain
  if (vbd && vbd->vbObj && checkStipple == vbd->checkStipple && 
      thickenCont == vbd->thickenCont && checkTime == vbd->checkTime) {
    match = 1;
    if (thickenCont)
      match = checkSelectedAreRemnants(vbd, obNum);
    if (match && checkStipple) {
      for (co = 0; co < obj->contsize; co++) {
        if ((obj->cont[co].flags & ICONT_STIPPLED) && 
            !numberInList(co, vbd->remnantIndList, vbd->numRemnant, 0)) {
          match = 0;
          break;
        }
      }
    }
    if (match && !Imodv->standalone && obNum == Imodv->imod->cindex.object && 
        vbd->checksum != imodObjectChecksum(obj, obNum))
      match = 0;

    if (match)
      return -1;
  }

  istoreDefaultDrawProps(obj, &defProps);
  numRemnant = 0;
  cumInd = 0;
  numVerts = 0;
  for (co = 0; co < obj->contsize; co++) {
    cont = &obj->cont[co];
    if (!imodvCheckContourDraw(cont, co, checkTime))
      continue;
    setOrClearFlags(&cont->flags, ICONT_TEMPUSE, 0);
    fullState = istoreContSurfDrawProps(obj->store, &defProps, &contProps, co, 
                                        cont->surf, &contState, &surfState);

    // Skip a gap without counting it; count ones to be excluded or that can't be handled
    skip = 0;
    if (contProps.gap)
      continue;
    if ((thickenCont && imodvCheckThickerContour(co)) || (fullState & nonVboFlags) || 
        (checkStipple && (cont->flags & ICONT_STIPPLED)))
      skip = 1;

    // Check for point changes that would need to be handled
    if (!skip && cont->store) {
      if (istoreCountItems(cont->store, GEN_STORE_COLOR, 1) || 
          istoreCountItems(cont->store, GEN_STORE_TRANS, 1))
        skip = 1;
      if (!skip && istoreCountItems(cont->store, GEN_STORE_3DWIDTH, 1))
        skip = 1;
      if (!skip && istoreCountItems(cont->store, GEN_STORE_GAP, 1))
        skip = 1;
    }
    if (skip) {
      setOrClearFlags(&cont->flags, ICONT_TEMPUSE, 1);
      numRemnant++;
      continue;
    }

    // Determine the number of indices needed including restart index
    numVerts += cont->psize;
    numInds = cont->psize + 1;
    if (iobjClose(obj->flags) && !(cont->flags & ICONT_OPEN))
      numInds++;

    // For a special contour, add to list of RGBT values with the index count if it
    // is not on the list; if it is already on the list add to its count;
    if (fullState & handleFlags) {
      rInd.firstElement = co;
      rInd.numInds = numInds;
      packRGBT(&contProps, 0, contRGBT);
      mapret = colors.insert(pair<b3dUInt32,RGBTindices>(contRGBT, rInd));
      if (mapret.second == false)
        mapret.first->second.numInds += numInds;
    } else {
      cumInd += numInds;
    }
  }      

  if (!numVerts) {
    vbCleanupContVBD(obj);
    return 2;
  }

  vbd = allocateVBDIfNeeded(&obj->vertBufCont);
  if (!vbd)
    return 1;

  // Add up the special set sizes and re-initialize the counts to be starting indexes
  vbd->numRemnant = numRemnant;
  co = -1;
  if (allocateSpecialSets(vbd, colors.size(), cumInd, 0) || 
      processMap(vbd, &colors, cumInd, 1, co)) {
    vbCleanupContVBD(obj);
    return 1;
  }
      
  imodTrace('b',"dfltInd %d  spec sets %d cumind %d  remnant %d", vbd->numIndDefault,
            vbd->numSpecialSets, cumInd, numRemnant);
  
  if (genAndBindBuffers(vbd, numVerts, cumInd) ||
      allocateTempVerts(numVerts) || allocateTempInds(cumInd)) {
    vbCleanupContVBD(obj);
    return 1;
  }

  // Set properties of this VB
  packRGBT(&defProps, 0, vbd->defaultRGBT);
  vbd->checkTime = checkTime;
  vbd->checkStipple = checkStipple;
  vbd->thickenCont = thickenCont;
  vbd->checksum = imodObjectChecksum(obj, obNum);

  // Load the vertex and index temp arrays
  ivert = 0;
  iDefInd = 0;
  irem = 0;
  for (co = 0; co < obj->contsize; co++) {
    cont = &obj->cont[co];
    if (!imodvCheckContourDraw(cont, co, checkTime))
      continue;
    fullState = istoreContSurfDrawProps(obj->store, &defProps, &contProps, co, 
                                        cont->surf, &contState, &surfState);
    if (contProps.gap)
      continue;

    // Add marked contours to the remnant list
    if (cont->flags & ICONT_TEMPUSE) {
      setOrClearFlags(&cont->flags, ICONT_TEMPUSE, 0);
      vbd->remnantIndList[irem++] = co;
      continue;
    }

    // Copy points onto vertex list
    psize = cont->psize;
    memcpy(&mVerts[3 * ivert], cont->pts, psize * 3 * sizeof(float));
    numInds = psize + 1;
    if (iobjClose(obj->flags) && !(cont->flags & ICONT_OPEN))
      numInds++;

    // Find index where indices start and increment it
    if (fullState & handleFlags) {
      packRGBT(&contProps, 0, contRGBT);
      mapit = colors.find(contRGBT);
      ind = mapit->second.numInds;
      mapit->second.numInds += numInds;
    } else {
      ind = iDefInd;
      iDefInd += numInds;
    }

    // Set up indices to all points, add one if closed, add restart index;
    for (pt = 0; pt < psize; pt++)
      mInds[ind + pt] = ivert + pt;
    if (numInds > psize + 1) {
      mInds[ind + psize] = ivert;
      mInds[ind + psize + 1] = RESTART_INDEX;
    } else
      mInds[ind + psize] = RESTART_INDEX;
    ivert += psize;
  }
  imodTrace('b',"ivert %d  numVerts*3 %d idefind %d cumind %d", ivert, numVerts * 3,
            iDefInd, cumInd);
  /*for (pt = 0; pt < cumInd; pt++) {
    imodPrintStderr(" %d", mInds[pt]);
    if ((pt + 1) % 16 == 0) imodPrintStderr("\n");
  }
  imodPrintStderr("\n"); */

  // Transfer to GL
  b3dBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, cumInd * sizeof(GLuint), mInds);
  b3dBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  b3dBufferSubData(GL_ARRAY_BUFFER, 0, numVerts * 3 * sizeof(GLfloat), mVerts);
  b3dBindBuffer(GL_ARRAY_BUFFER, 0);
  return 0;
}
Beispiel #8
0
/*
 * Analyze spherical points in the given object and convert them to vectors and
 * normals for faster drawing
 */
int VertBufManager::analyzeSpheres(Iobj *obj, int obNum, float zscale, int xybin,
                                   float scrnScale, int quality, int fillType,
                                   int useFillColor, int thickenCont, int checkTime)
{
  RGBTmap colors;
  pair<RGBTmap::iterator,bool> mapret;
  RGBTmap::iterator mapit;
  RGBTindices rInd;
  DrawProps defProps, contProps;
  b3dUInt32 contRGBT;
  VertBufData *vbd = obj->vertBufSphere;
  Icont *cont;
  int handleFlags, nonVboFlags = 0, numRemnant, fullState, skip, numVerts, co, pt;
  int colorType, cumFanInd, cumQuadInd, surfState, contState, stepRes;
  float drawsize;
  int numDefSphVert, numDefSphQuad, numDefSphFan, numTriples,indVert, indQuad, indFan;
  int indQuadDef, indFanDef, irem, match;

  if (fillType > 0)
    handleFlags = (useFillColor ? CHANGED_FCOLOR : CHANGED_COLOR) | CHANGED_TRANS;
  else {
    handleFlags = CHANGED_COLOR | CHANGED_TRANS;
    nonVboFlags = CHANGED_3DWIDTH;
  }
  colorType = useFillColor ? GEN_STORE_FCOLOR : GEN_STORE_COLOR;

  istoreDefaultDrawProps(obj, &defProps);

  // Check if there is a current VBO and it is all still valid 
  // TODO: handle finegrain AND size changes
  //packRGBT(defProps, useFillColor, contRGBT);
  if (vbd && vbd->vbObj && fillType == vbd->fillType && vbd->useFillColor == useFillColor
      && quality == vbd->quality && obj->pdrawsize == vbd->pdrawsize &&
      checkTime == vbd->checkTime && fabs((double)(scrnScale - vbd->scrnScale)) < 1.e-4 &&
      fabs((double)(zscale - vbd->zscale)) < 1.e-4 && 
      (fillType != 0 || thickenCont == vbd->thickenCont)) {
    match = 1;
    if (fillType == 0 && thickenCont)
      match = checkSelectedAreRemnants(vbd, obNum);
    if (match && !Imodv->standalone && obNum == Imodv->imod->cindex.object && 
        vbd->checksum != imodObjectChecksum(obj, obNum))
      match = 0;
    if (match)
      return -1;
  }

  numRemnant = 0;
  cumQuadInd = 0;
  cumFanInd = 0;
  numVerts = 0;
  for (co = 0; co < obj->contsize; co++) {
    cont = &obj->cont[co];
    setOrClearFlags(&cont->flags, ICONT_TEMPUSE, 0);
    if (!imodvCheckContourDraw(cont, co, checkTime))
      continue;
    fullState = istoreContSurfDrawProps(obj->store, &defProps, &contProps, co, 
                                          cont->surf, &contState, &surfState);

    // Skip a gap without counting it; count one to be excluded or that can't be handled
    if (contProps.gap)
      continue;
    skip = 0;
    if ((fullState & nonVboFlags) || (thickenCont && imodvCheckThickerContour(co)))
      skip = 1;

    // Check for point changes that would need to be handled
    if (!skip && cont->store) {
      if (istoreCountItems(cont->store, colorType, 1) || 
          istoreCountItems(cont->store, GEN_STORE_TRANS, 1))
        skip = 1;
      if (!skip && fillType <= 0 && istoreCountItems(cont->store, GEN_STORE_3DWIDTH, 1))
        skip = 1;
    }
    if (skip) {
      setOrClearFlags(&cont->flags, ICONT_TEMPUSE, 1);
      numRemnant++;
      continue;
    }

    // Loop on the points and determine number of vertices and indices needed for each
    // Since we don't skip point drawing, this doesn't need store changes checked
    rInd.numInds = 0;
    rInd.numFanInds = 0;
    for (pt = 0; pt < cont->psize; pt++) {

      // Only draw zero-size points with scattered point objects
      drawsize = imodPointGetSize(obj, cont, pt) / xybin;
      if (!iobjScat(obj->flags) && !drawsize)
        continue;
      stepRes = sphereResForSize(drawsize);
      numVerts += sphereCounts(2 * stepRes, stepRes, fillType, rInd.numInds,
                               rInd.numFanInds);

      // For a special contour, add to list of RGBT values with the counts if it
      // is not on the list; if it is already on the list increment its count;
      if (fullState & handleFlags) {
        rInd.firstElement = co;
        packRGBT(&contProps, useFillColor, contRGBT);
        mapret = colors.insert(pair<b3dUInt32,RGBTindices>(contRGBT, rInd));
        if (mapret.second == false) {
          mapret.first->second.numInds += rInd.numInds;
          mapret.first->second.numFanInds += rInd.numFanInds;
        }
      } else {
        cumQuadInd += rInd.numInds;
        cumFanInd += rInd.numFanInds;
      }
    }
  }      

  if (!numVerts) {
    vbCleanupSphereVBD(obj);
    return 2;
  }

  // Get parameters for default sphere
  drawsize = obj->pdrawsize / xybin;
  stepRes = sphereResForSize(drawsize);
  numDefSphVert = sphereCounts(2 * stepRes, stepRes, fillType, numDefSphQuad, 
                               numDefSphFan);
  imodTrace('b', "numverts %d cumfan %d cumquad %d def vert %d quad %d fan %d rem %d",
            numVerts, cumFanInd, cumQuadInd, numDefSphVert,numDefSphQuad, numDefSphFan,
            numRemnant);

  vbd = allocateVBDIfNeeded(&obj->vertBufSphere); 
  if (!vbd || drawsize < 0) {
    vbCleanupSphereVBD(obj);
    return 1;
  }
  vbd->numFanIndDefault = cumFanInd;
  vbd->numRemnant = numRemnant;

  // Now allocate whatever pieces are needed in VBD
  // Add up the special set sizes and re-initialize the counts to be starting indexes
  if (allocateSpecialSets(vbd, colors.size(), cumQuadInd, 1) ||
      processMap(vbd, &colors, cumQuadInd, 1, cumFanInd)) {
    vbCleanupSphereVBD(obj);
    return 1;
  }
  vbd->fanIndStart = cumQuadInd;

  // Now allocate temps plus default sphere
  numTriples = (1 + (fillType > 0 ? 1 : 0)) * numVerts;
  if (allocateTempVerts(numTriples) || allocateTempInds(cumFanInd) ||
      allocateDefaultSphere(numDefSphVert, numDefSphQuad + numDefSphFan, fillType)) {
    vbCleanupSphereVBD(obj);
    return 1;
  }
    
  if (genAndBindBuffers(vbd, numTriples, cumFanInd)) {
    vbCleanupSphereVBD(obj);
    return 1;
  }

  // Build the default sphere
  indVert = 0;
  indQuad = 0;
  indFan = numDefSphQuad;
  makeSphere(drawsize, 2 * stepRes, stepRes, mDefSphVerts, mDefSphInds, indVert, indQuad, 
           indFan, fillType, 0., 0., 0.);
  imodTrace('b', "numtriples %d cumquad %d cumfan %d after def vert %d quad %d fan %d", 
            numTriples, cumQuadInd, cumFanInd, indVert, indQuad,
            indFan);
  /*for (pt = 0; pt < indFan; pt++) {
    imodPrintStderr(" %d", mDefSphInds[pt]);
    if ((pt + 1) % 16 == 0 || pt == indFan - 1) imodPrintStderr("\n");
    } */

  // Set the identifiers of this vb data
  vbd->zscale = zscale;
  vbd->fillType = fillType;
  vbd->useFillColor = useFillColor;
  packRGBT(&defProps, useFillColor, vbd->defaultRGBT);
  vbd->checkTime = checkTime;
  vbd->scrnScale = scrnScale;
  vbd->quality = quality;
  vbd->pdrawsize = obj->pdrawsize;
  vbd->thickenCont = thickenCont;
  vbd->checksum = imodObjectChecksum(obj, obNum);

  // Process contours and points in them
  indVert = 0;
  indQuadDef = 0;
  indFanDef = cumQuadInd;
  irem = 0;
  for (co = 0; co < obj->contsize; co++) {
    cont = &obj->cont[co];
    if (!imodvCheckContourDraw(cont, co, checkTime))
      continue;
    fullState = istoreContSurfDrawProps(obj->store, &defProps, &contProps, co, 
                                        cont->surf, &contState, &surfState);
    if (contProps.gap)
      continue;

    // Add marked contours to the remnant list
    if (cont->flags & ICONT_TEMPUSE) {
      setOrClearFlags(&cont->flags, ICONT_TEMPUSE, 0);
      vbd->remnantIndList[irem++] = co;
      continue;
    }

    // Set the starting indices for the contour's quads and fans
    if (fullState & handleFlags) {
      packRGBT(&contProps, useFillColor, contRGBT);
      mapit = colors.find(contRGBT);
      indQuad = mapit->second.numInds;
      indFan = mapit->second.numFanInds;
    } else {
      indQuad = indQuadDef;
      indFan = indFanDef;
    }

    // Loop on the points and make sohere or copy the default
    for (pt = 0; pt < cont->psize; pt++) {

      drawsize = imodPointGetSize(obj, cont, pt);
      if (!iobjScat(obj->flags) && !drawsize)
        continue;
      if (drawsize == obj->pdrawsize) {
        copyDefaultSphere(mDefSphVerts, mDefSphInds, numDefSphVert, numDefSphQuad,
                          numDefSphFan, fillType, mVerts, mInds, indVert, indQuad,
                          indFan,  cont->pts[pt].x, cont->pts[pt].y, 
                          cont->pts[pt].z * zscale);
      } else {
        drawsize /= xybin;
        stepRes = sphereResForSize(drawsize);
        makeSphere(drawsize, 2 * stepRes, stepRes, mVerts, mInds, indVert, indQuad,
                 indFan, fillType, cont->pts[pt].x, cont->pts[pt].y, 
                 cont->pts[pt].z * zscale);
      }
    }

    // Save the new indices back where they came from
    if (fullState & handleFlags) {
      mapit->second.numInds = indQuad;
      mapit->second.numFanInds = indFan;
    } else {
      indQuadDef = indQuad;
      indFanDef = indFan;
    }
  }

  imodTrace('b', "cumfan %d after load vert %d quad %d fan %d  irem %d", 
            cumFanInd, indVert, indQuad, indFan, irem);
  /* for (pt = 0; pt < cumFanInd; pt++) {
    imodPrintStderr(" %d", mInds[pt]);
    if ((pt + 1) % 16 == 0 || pt == cumFanInd - 1) imodPrintStderr("\n");
    } */

  // Transfer to GL
  b3dBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, cumFanInd * sizeof(GLuint), mInds);
  b3dBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  b3dBufferSubData(GL_ARRAY_BUFFER, 0, numTriples * 3 * sizeof(GLfloat), mVerts);
  b3dBindBuffer(GL_ARRAY_BUFFER, 0);

  return 0;
}
Beispiel #9
0
/*
 * Analyze a mesh and pack it into VBOs if it qualifies
 */
int VertBufManager::analyzeMesh(Imesh *mesh, float zscale, int fillType, int useFillColor,
                  DrawProps *defProps)
{
  bool valid = true;
  RGBTmap colors;
  pair<RGBTmap::iterator,bool> mapret;
  RGBTmap::iterator mapit;
  VertBufData *vbd = mesh->vertBuf;
  RGBTindices rInd;
  Istore *stp;
  Istore store;
  int *mlist = mesh->list;
  DrawProps curProps;
  int i, j, cumInd, defInd, nextItemIndex, stateFlags, vertDflt, changeFlags, firstDflt;
  b3dUInt32 vertRGBT, firstRGBT;
  int remInd, curSave, curNext;
  int numDefaultTri = 0, numMixedTri = 0;
  int handleFlags, nonVboFlags = 0;
  
  if (fillType)
    handleFlags = (useFillColor ? CHANGED_FCOLOR : CHANGED_COLOR) | CHANGED_TRANS;
  else {
    handleFlags = CHANGED_COLOR | CHANGED_TRANS;
    nonVboFlags = CHANGED_3DWIDTH;
  }
  rInd.numFanInds = 0;

  // Check if there is a current VBO and it is all still valid 
  packRGBT(defProps, useFillColor, firstRGBT);
  if (vbd && vbd->vbObj && fillType == vbd->fillType && 
      (!ilistSize(mesh->store) || 
       (vbd->useFillColor == useFillColor && vbd->defaultRGBT == firstRGBT)) &&
      vbd->checksum == istoreChecksum(mesh->store)) {

    // If Z-scale still valid, return a -1; if have to fix the Z-scale, do it, return -2
    if (fabs((double)(zscale - vbd->zscale)) < 1.e-4)
      return -1;
    b3dBindBuffer(GL_ARRAY_BUFFER, vbd->vbObj);
    if (loadVertexNormalArray(mesh, zscale, fillType)) {
      vbCleanupVBD(mesh);
      return 1;
    }
    vbd->zscale = zscale;
    return -2;
  }

  // Now proceed to full analysis
  nextItemIndex = istoreFirstChangeIndex(mesh->store);
  
  for (i = 0; i < mesh->lsize && valid; i++) {
    switch (mlist[i]) {

    case IMOD_MESH_BGNTRI:
    case IMOD_MESH_ENDTRI:
    case IMOD_MESH_BGNPOLY:
    case IMOD_MESH_NORMAL:
    case IMOD_MESH_BGNBIGPOLY:
    case IMOD_MESH_SWAP:
      valid = false;
      break;

    case IMOD_MESH_BGNPOLYNORM:
      i++;
      while (mlist[i] != IMOD_MESH_ENDPOLY && valid) {
        valid = (mlist[i] == mlist[i+1] + 1) && (mlist[i+2] == mlist[i+3] + 1) && 
          (mlist[i+4] == mlist[i+5] + 1);
        i += 6;
        numDefaultTri++;
      }
      break;

    case IMOD_MESH_BGNPOLYNORM2:
      i++;
      while (mlist[i] != IMOD_MESH_ENDPOLY) {
        if (nextItemIndex < i || nextItemIndex > i + 2) {
          
          // Count a default triangle if no changes in this range
          numDefaultTri++;
          i += 3;
        } else {

          // Otherwise look at each vertex and get its properties if it is changed
          for (j = 0; j < 3; j++) {
            vertDflt = 1;
            if (i == nextItemIndex) {
              curProps = *defProps;
              stateFlags = 0;
              nextItemIndex = istoreNextChange(mesh->store, defProps, &curProps,
                                               &stateFlags, &changeFlags);
              if (stateFlags & handleFlags) {
                vertDflt = 0;
                packRGBT(&curProps, useFillColor, vertRGBT);
              }

              // Take triangle as mixed if it has unhandleable flags
              if (stateFlags & nonVboFlags) {
                firstDflt = -1;
                i++;
                continue;
              }
            }

            // For first vertex record the triangle properties, for later one record if 
            // there is a mismatch from the first
            if (!j) {
              firstDflt = vertDflt;
              firstRGBT = vertRGBT;
            } else if (vertDflt != firstDflt || (!vertDflt && vertRGBT != firstRGBT)) {
              firstDflt = -1;
            }
            i++;
          }
          
          // Count whether it is a default or mixed triangle
          if (firstDflt < 0) {
            numMixedTri++;
          } else if (firstDflt > 0) {
            numDefaultTri++;
          } else {
            
            // For a special triangle, add to list of RGBT values with a count of 1 if it
            // is not on the list; if it is already on the list increment its count;
            rInd.firstElement = i;
            rInd.numInds = 1;
            mapret = colors.insert(pair<b3dUInt32,RGBTindices>(firstRGBT, rInd));
            if (mapret.second == false)
              mapret.first->second.numInds++;
          }
        }
      }
      break;

    case IMOD_MESH_END:
      break;
    }
  }

  if (!valid) {
    vbCleanupVBD(mesh);
    return 3;
  }
  if (!colors.size() && !numDefaultTri) {
    vbCleanupVBD(mesh);
    return 2;
  }

  vbd = allocateVBDIfNeeded(&mesh->vertBuf); 
  if (!vbd)
    return 1;

  // Now allocate whatever pieces are needed in there.  Set remnant value in vbd first
  // Add up the special set sizes and re-initialize the counts to be starting indexes
  cumInd = numDefaultTri * 3;
  vbd->numRemnant = 0;
  if (numMixedTri)
    vbd->numRemnant = numMixedTri * 3 + 3;
  i = -1;
  if (allocateSpecialSets(vbd, colors.size(), cumInd, 0) ||
      processMap(vbd, &colors, cumInd, 3, i)) {
    vbCleanupVBD(mesh);
    return 1;
  }
      
  imodTrace('b',"dfltInd %d  spec sets %d cumind %d  remnant %d", vbd->numIndDefault,
            vbd->numSpecialSets, cumInd, numMixedTri);

  // Create the store for remnants
  if (numMixedTri) {
    ilistDelete(vbd->remnantStore);
    vbd->remnantStore = ilistNew(sizeof(Istore), vbd->numRemnant / 8);
    if (!vbd->remnantStore) {
      vbCleanupVBD(mesh);
      return 1;
    }
    vbd->remnantStore->quantum = B3DMAX(vbd->remnantStore->quantum, vbd->numRemnant / 8);
    vbd->remnantIndList[0] = IMOD_MESH_BGNPOLYNORM2;
  }

  // Now get the vertex buffers themselves
  if (genAndBindBuffers(vbd,  mesh->vsize, cumInd)) {
    vbCleanupVBD(mesh);
    return 1;
  }
        
  imodTrace('b',"vbObj %d  ebObj %d", vbd->vbObj, vbd->ebObj);

  // Load the vertices and finish with buffer for now
  if (loadVertexNormalArray(mesh, zscale, fillType)) {
    vbCleanupVBD(mesh);
    return 1;
  }
  b3dBindBuffer(GL_ARRAY_BUFFER, 0);

  // Set the identifiers of this vb data
  vbd->zscale = zscale;
  vbd->fillType = fillType;
  vbd->useFillColor = useFillColor;
  packRGBT(defProps, useFillColor, vbd->defaultRGBT);
  vbd->checksum = istoreChecksum(mesh->store);

  // Get or use temporary array for indexes
  if (allocateTempInds(cumInd)) {
    vbCleanupVBD(mesh);
    return 1;
  }

  // No fine grain: copy all the indices into index array
  defInd = 0;
  if (!mesh->store) {
    i = 0;
    while (mlist[i] != IMOD_MESH_END) {
      if (mlist[i] ==  IMOD_MESH_BGNPOLYNORM) {
        i++;
        while (mlist[i] != IMOD_MESH_ENDPOLY) {
          i++;
          mInds[defInd++] = mlist[i++] / 2;
        }
      }
      else if (mlist[i] ==  IMOD_MESH_BGNPOLYNORM2) {
        i++;
        while (mlist[i] != IMOD_MESH_ENDPOLY) {
          mInds[defInd++] = mlist[i++] / 2;
        }
      }
      i++;
    }
  } else {

    // Otherwise process all triangles into index array or remnant arrays
    nextItemIndex = istoreFirstChangeIndex(mesh->store);
    remInd = 1;
    for (i = 0; i < mesh->lsize; i++) {
      switch (mlist[i]) {
      case IMOD_MESH_BGNPOLYNORM2:
        i++;
        while (mlist[i] != IMOD_MESH_ENDPOLY) {
          
          // Repeat the analysis to determine default, special, or mixed triangle
          curSave = mesh->store->current;
          if (nextItemIndex < i || nextItemIndex > i + 2) {
            firstDflt = 1;
          } else {

            // Otherwise look at each vertex and get its properties if it is changed
            for (j = 0; j < 3; j++) {
              vertDflt = 1;
              if (i + j == nextItemIndex) {
                curProps = *defProps;
                stateFlags = 0;
                nextItemIndex = istoreNextChange(mesh->store, defProps, &curProps,
                                                 &stateFlags, &changeFlags);
                if (stateFlags & handleFlags) {
                  vertDflt = 0;
                  packRGBT(&curProps, useFillColor, vertRGBT);
                }
                if (stateFlags & nonVboFlags) {
                  firstDflt = -1;
                  continue;
                }
              }
              
              // For first vertex record the triangle properties, for later one stop if 
              // there is a mismatch from the first
              if (!j) {
                firstDflt = vertDflt;
                firstRGBT = vertRGBT;
              } else if (vertDflt != firstDflt || (!vertDflt && vertRGBT != firstRGBT)) {
                firstDflt = -1;
              }
            }
          }
          
          // Save indexes for default or special triangles
          if (firstDflt > 0) {
            mInds[defInd++] = mlist[i++] / 2;
            mInds[defInd++] = mlist[i++] / 2;
            mInds[defInd++] = mlist[i++] / 2;
          } else if (firstDflt == 0) {
            mapit = colors.find(firstRGBT);
            mInds[mapit->second.numInds++] = mlist[i++] / 2;
            mInds[mapit->second.numInds++] = mlist[i++] / 2;
            mInds[mapit->second.numInds++] = mlist[i++] / 2;
          } else {

            // For mixed triangle, save the current pointer, copy the index for each 
            // vertex to the remnant index array, and copy all stores for that vertex
            // to the remnant store, changing the index to the new value
            curNext = mesh->store->current;
            for (j = 0; j < 3; j++) {
              vbd->remnantIndList[remInd] = mlist[i];
              while (curSave < curNext) {
                stp = istoreItem(mesh->store, curSave);
                if (stp->index.i == i) {
                  store = *stp;
                  store.index.i = remInd;
                  if (istoreInsert(&vbd->remnantStore, &store)) {
                    vbCleanupVBD(mesh);
                    return 1;
                  }
                  curSave++;
                } else
                  break;
              }
              i++;
              remInd++;
            }
            mesh->store->current = curNext;
          }
        }
        break;

      case IMOD_MESH_END:
        break;
      }
    }
  }
  if (vbd->numRemnant) {
    vbd->remnantIndList[remInd++] = IMOD_MESH_ENDPOLY;
    vbd->remnantIndList[remInd++] = IMOD_MESH_END;
  }
  b3dBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, cumInd * sizeof(GLuint), mInds);
  b3dBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
  return 0;
}