// Assumes a MacOS Pascal string; the resulting string will have
// a null byte at the end.
void StringSet::Add(size_t Index, unsigned char *String)
{
	if (Index < 0) return;
	
	// Replace string list with longer one if necessary
	size_t NewNumStrings = NumStrings;
	while (Index >= NewNumStrings) {NewNumStrings <<= 1;}
	
	if (NewNumStrings > NumStrings)
	{
		unsigned char **NewStrings = new unsigned char *[NewNumStrings];
		objlist_clear(NewStrings+NumStrings,(NewNumStrings-NumStrings));
		objlist_copy(NewStrings,Strings,NumStrings);
		delete []Strings;
		Strings = NewStrings;
		NumStrings = NewNumStrings;
	}
	
	// Delete the old string if necessary
	if (Strings[Index]) delete []Strings[Index];
	
	unsigned short Length = String[0];
	unsigned char *_String = new unsigned char[Length+2];
	memcpy(_String,String,Length+2);
	_String[Length+1] = 0;	//  for making an in-place C string
	
	Strings[Index] = _String;
}
Beispiel #2
0
void get_recording_header_data(
	short *number_of_players, 
	short *level_number, 
	uint32 *map_checksum,
	short *version, 
	struct player_start_data *starts, 
	struct game_data *game_information)
{
	assert(replay.valid);
	*number_of_players= replay.header.num_players;
	*level_number= replay.header.level_number;
	*map_checksum= replay.header.map_checksum;
	*version= replay.header.version;
	objlist_copy(starts, replay.header.starts, MAXIMUM_NUMBER_OF_PLAYERS);
	obj_copy(*game_information, replay.header.game_information);
}
Beispiel #3
0
void set_recording_header_data(
	short number_of_players, 
	short level_number, 
	uint32 map_checksum,
	short version, 
	struct player_start_data *starts, 
	struct game_data *game_information)
{
	assert(!replay.valid);
	obj_clear(replay.header);
	replay.header.num_players= number_of_players;
	replay.header.level_number= level_number;
	replay.header.map_checksum= map_checksum;
	replay.header.version= version;
	objlist_copy(replay.header.starts, starts, MAXIMUM_NUMBER_OF_PLAYERS);
	obj_copy(replay.header.game_information, *game_information);
	// Use the packed size here!!!
	replay.header.length= SIZEOF_recording_header;
}
Beispiel #4
0
// Neutral case: returns whether vertex-source data was used (present in animated models)
bool Model3D::FindPositions_Neutral(bool UseModelTransform)
{
  // Positions already there
  if (VtxSrcIndices.empty()) {
    return false;
  }

  // Straight copy of the vertices:

  size_t NumVertices = VtxSrcIndices.size();
  Positions.resize(3*NumVertices);

  GLfloat *PP = PosBase();
  GLushort *IP = VtxSIBase();

  size_t NumVtxSources = VtxSources.size();

  if (UseModelTransform) {
    for (size_t k=0; k<NumVertices; k++, IP++, PP+=3)
    {
      size_t VSIndex = *IP;
      if (VSIndex >= 0 && VSIndex < NumVtxSources) {
        Model3D_VertexSource& VS = VtxSources[VSIndex];
        TransformPoint(PP,VS.Position,TransformPos);
      }
      else
      {
        GLfloat VP[3] = {0,0,0};
        TransformPoint(PP,VP,TransformPos);
      }
    }
  }
  else
  {
    for (size_t k=0; k<NumVertices; k++, IP++)
    {
      size_t VSIndex = *IP;
      if (VSIndex >= 0 && VSIndex < NumVtxSources) {
        Model3D_VertexSource& VS = VtxSources[VSIndex];
        GLfloat *VP = VS.Position;
        *(PP++) = *(VP++);
        *(PP++) = *(VP++);
        *(PP++) = *(VP++);
      }
      else
      {
        *(PP++) = 0;
        *(PP++) = 0;
        *(PP++) = 0;
      }
    }
  }

  // Copy in the normals
  Normals.resize(NormSources.size());

  if (UseModelTransform) {
    GLfloat *NormPtr = NormBase();
    GLfloat *NormBasePtr = NormSrcBase();
    size_t NumNorms = NormSources.size()/3;
    for (size_t k=0; k<NumNorms; k++, NormPtr+=3, NormBasePtr+=3)
    {
      TransformVector(NormPtr, NormBasePtr, TransformNorm);
    }
  }
  else
  {
    objlist_copy(NormBase(),NormSrcBase(),NormSources.size());
  }

  return true;
}
Beispiel #5
0
// Normalize the normals
void Model3D::AdjustNormals(int NormalType, float SmoothThreshold)
{
  // Copy in normal sources for processing
  if (!NormSources.empty()) {
    Normals.resize(NormSources.size());
    objlist_copy(NormBase(),NormSrcBase(),NormSources.size());
  }

  // Which kind of special processing?
  switch(NormalType)
  {
  case None:
    Normals.clear();
    break;

  case Original:
  case Reversed:
  default:
    // Normalize
    for (unsigned k=0; k<Normals.size()/3; k++)
      NormalizeNormal(&Normals[3*k]);
    break;

  case ClockwiseSide:
  case CounterclockwiseSide:
    // The really interesting stuff
  {
    // First, create a list of per-polygon normals
    size_t NumPolys = NumVI()/3;
    vector<FlaggedVector> PerPolygonNormalList(NumPolys);

    GLushort *IndxPtr = VIBase();
    for (unsigned k=0; k<NumPolys; k++)
    {
      // The three vertices:
      GLfloat *P0 = &Positions[3*(*(IndxPtr++))];
      GLfloat *P1 = &Positions[3*(*(IndxPtr++))];
      GLfloat *P2 = &Positions[3*(*(IndxPtr++))];
      // The two in-polygon vectors:
      GLfloat P01[3];
      P01[0] = P1[0] - P0[0];
      P01[1] = P1[1] - P0[1];
      P01[2] = P1[2] - P0[2];
      GLfloat P02[3];
      P02[0] = P2[0] - P0[0];
      P02[1] = P2[1] - P0[1];
      P02[2] = P2[2] - P0[2];
      // Those vectors' normal:
      FlaggedVector& PPN = PerPolygonNormalList[k];
      PPN.Vec[0] = P01[1]*P02[2] - P01[2]*P02[1];
      PPN.Vec[1] = P01[2]*P02[0] - P01[0]*P02[2];
      PPN.Vec[2] = P01[0]*P02[1] - P01[1]*P02[0];
      PPN.Flag = NormalizeNormal(PPN.Vec);
    }

    // Create a list of per-vertex normals
    size_t NumVerts = Positions.size()/3;
    vector<FlaggedVector> PerVertexNormalList(NumVerts);
    objlist_clear(&PerVertexNormalList[0],NumVerts);
    IndxPtr = VIBase();
    for (unsigned k=0; k<NumPolys; k++)
    {
      FlaggedVector& PPN = PerPolygonNormalList[k];
      for (unsigned c=0; c<3; c++)
      {
        GLushort VertIndx = *(IndxPtr++);
        GLfloat *V = PerVertexNormalList[VertIndx].Vec;
        *(V++) += PPN.Vec[0];
        *(V++) += PPN.Vec[1];
        *(V++) += PPN.Vec[2];
      }
    }

    // Normalize the per-vertex normals
    for (unsigned k=0; k<NumVerts; k++)
    {
      FlaggedVector& PVN = PerVertexNormalList[k];
      PVN.Flag = NormalizeNormal(PVN.Vec);
    }

    // Find the variance of each of the per-vertex normals;
    // use that to decide whether to keep them unsplit;
    // this also needs counting up the number of polygons per vertex.
    vector<GLfloat> Variances(NumVerts);
    objlist_clear(&Variances[0],NumVerts);
    vector<short> NumPolysPerVert(NumVerts);
    objlist_clear(&NumPolysPerVert[0],NumVerts);
    IndxPtr = VIBase();
    for (unsigned k=0; k<NumPolys; k++)
    {
      FlaggedVector& PPN = PerPolygonNormalList[k];
      for (unsigned c=0; c<3; c++)
      {
        GLushort VertIndx = *(IndxPtr++);
        FlaggedVector& PVN = PerVertexNormalList[VertIndx];
        if (PVN.Flag) {
          GLfloat *V = PVN.Vec;
          GLfloat D0 = *(V++) - PPN.Vec[0];
          GLfloat D1 = *(V++) - PPN.Vec[1];
          GLfloat D2 = *(V++) - PPN.Vec[2];
          Variances[VertIndx] += (D0*D0 + D1*D1 + D2*D2);
          NumPolysPerVert[VertIndx]++;
        }
      }
    }

    // Decide whether to split each vertex;
    // if the flag is "true", a vertex is not to be split
    for (unsigned k=0; k<NumVerts; k++)
    {
      // Vertices without contributions will automatically have
      // their flags be false, as a result of NormalizeNormal()
      unsigned NumVertPolys = NumPolysPerVert[k];
      if (NumVertPolys > 0 && PerVertexNormalList[k].Flag) {
        PerVertexNormalList[k].Flag =
          sqrt(Variances[k]/NumVertPolys) <= SmoothThreshold;
      }
    }

    // The vertex flags are now set for whether to use that vertex's normal;
    // re-count the number of polygons per vertex.
    // Use NONE for unsplit ones
    objlist_clear(&NumPolysPerVert[0],NumVerts);
    IndxPtr = VIBase();
    for (unsigned k=0; k<NumPolys; k++)
    {
      for (unsigned c=0; c<3; c++)
      {
        GLushort VertIndx = *(IndxPtr++);
        FlaggedVector& PVN = PerVertexNormalList[VertIndx];
        if (PVN.Flag) {
          NumPolysPerVert[VertIndx] = NONE;
        }
        else{
          NumPolysPerVert[VertIndx]++;
        }
      }
    }

    // Construct a polygon-association list; this will indicate
    // which polygons are associated with each of the resulting instances
    // of a split vertex (unsplit: NONE).
    // NumPolysPerVert will be recycled as a counter list,
    // after being used to construct a cumulative index-in-list array.
    // Finding that list will be used to find how many new vertices there are.
    vector<short> IndicesInList(NumVerts);
    short IndxInList = 0;
    for (unsigned k=0; k<NumVerts; k++)
    {
      IndicesInList[k] = IndxInList;
      FlaggedVector& PVN = PerVertexNormalList[k];
      IndxInList += PVN.Flag ? 1 : NumPolysPerVert[k];
    }
    GLushort NewNumVerts = IndxInList;
    vector<short> VertexPolygons(NewNumVerts);
    objlist_clear(&NumPolysPerVert[0],NumVerts);

    // In creating that list, also remap the triangles' vertices
    GLushort *VIPtr = VIBase();
    for (unsigned k=0; k<NumPolys; k++)
    {
      for (unsigned c=0; c<3; c++)
      {
        GLushort VertIndx = *VIPtr;
        GLushort NewVertIndx = IndicesInList[VertIndx];
        FlaggedVector& PVN = PerVertexNormalList[VertIndx];
        if (PVN.Flag) {
          NumPolysPerVert[VertIndx] = NONE;
          VertexPolygons[NewVertIndx] = NONE;
        }
        else
        {
          NewVertIndx += (NumPolysPerVert[VertIndx]++);
          VertexPolygons[NewVertIndx] = k;
        }
        *VIPtr = NewVertIndx;
        VIPtr++;
      }
    }

    // Split the vertices
    vector<GLfloat> NewPositions(3*NewNumVerts);
    vector<GLfloat> NewTxtrCoords;
    vector<GLfloat> NewNormals(3*NewNumVerts);
    vector<GLfloat> NewColors;
    vector<GLushort> NewVtxSrcIndices;

    bool TCPresent = !TxtrCoords.empty();
    if (TCPresent) {
      NewTxtrCoords.resize(2*NewNumVerts);
    }

    bool ColPresent = !Colors.empty();
    if (ColPresent) {
      NewColors.resize(3*NewNumVerts);
    }

    bool VSPresent = !VtxSrcIndices.empty();
    if (VSPresent) {
      NewVtxSrcIndices.resize(NewNumVerts);
    }

    // Use marching pointers to speed up the copy-over
    GLfloat *OldP = &Positions[0];
    GLfloat *NewP = &NewPositions[0];
    GLfloat *OldT = &TxtrCoords[0];
    GLfloat *NewT = &NewTxtrCoords[0];
    GLfloat *OldC = &Colors[0];
    GLfloat *NewC = &NewColors[0];
    GLushort *OldS = &VtxSrcIndices[0];
    GLushort *NewS = &NewVtxSrcIndices[0];
    GLfloat *NewN = &NewNormals[0];
    for (unsigned k=0; k<NumVerts; k++)
    {
      FlaggedVector& PVN = PerVertexNormalList[k];
      unsigned NumVertPolys = PVN.Flag ? 1 : NumPolysPerVert[k];
      for (unsigned c=0; c<NumVertPolys; c++)
      {
        GLfloat *OldPP = OldP;
        *(NewP++) = *(OldPP++);
        *(NewP++) = *(OldPP++);
        *(NewP++) = *(OldPP++);
      }
      if (TCPresent) {
        for (unsigned c=0; c<NumVertPolys; c++)
        {
          GLfloat *OldTP = OldT;
          *(NewT++) = *(OldTP++);
          *(NewT++) = *(OldTP++);
        }
      }
      if (ColPresent) {
        for (unsigned c=0; c<NumVertPolys; c++)
        {
          GLfloat *OldCP = OldC;
          *(NewC++) = *(OldCP++);
          *(NewC++) = *(OldCP++);
          *(NewC++) = *(OldCP++);
        }
      }
      if (VSPresent) {
        for (unsigned c=0; c<NumVertPolys; c++)
          *(NewS++) = *OldS;
      }
      if (PVN.Flag) {
        GLfloat *VP = PVN.Vec;
        *(NewN++) = *(VP++);
        *(NewN++) = *(VP++);
        *(NewN++) = *(VP++);
      }
      else
      {
        // A reference so that the incrementing can work on it
        short& IndxInList = IndicesInList[k];
        for (unsigned c=0; c<NumVertPolys; c++)
        {
          GLfloat *VP = PerPolygonNormalList[VertexPolygons[IndxInList++]].Vec;
          *(NewN++) = *(VP++);
          *(NewN++) = *(VP++);
          *(NewN++) = *(VP++);
        }
      }

      // Advance!
      OldP += 3;
      if (TCPresent) {
        OldT += 2;
      }
      if (ColPresent) {
        OldC += 3;
      }
      if (VSPresent) {
        OldS++;
      }
    }
    assert(OldP == &Positions[3*NumVerts]);
    assert(NewP == &NewPositions[3*NewNumVerts]);
    if (TCPresent) {
      assert(OldT == &TxtrCoords[2*NumVerts]);
      assert(NewT == &NewTxtrCoords[2*NewNumVerts]);
    }
    if (ColPresent) {
      assert(OldC == &Colors[3*NumVerts]);
      assert(NewC == &NewColors[3*NewNumVerts]);
    }
    if (VSPresent) {
      assert(OldS == &VtxSrcIndices[NumVerts]);
      assert(NewS == &NewVtxSrcIndices[NewNumVerts]);
    }
    assert(NewN == &NewNormals[3*NewNumVerts]);

    // Accept the new vectors
    Positions.swap(NewPositions);
    TxtrCoords.swap(NewTxtrCoords);
    Normals.swap(NewNormals);
    Colors.swap(NewColors);
    VtxSrcIndices.swap(NewVtxSrcIndices);
  }
  break;
  }

  // Now flip
  switch(NormalType)
  {
  case Reversed:
  case CounterclockwiseSide:
  {
    GLfloat *NormalPtr = NormBase();
    for (unsigned k=0; k<Normals.size(); k++)
      *(NormalPtr++) *= -1;
  }
  }

  // Copy back out to the normal sources;
  // do the copying out if the vertices have sources,
  // which is the case for boned models.
  if (!VtxSources.empty()) {
    size_t NormSize = Normals.size();
    if (NormSize > 0) {
      NormSources.resize(NormSize);
      objlist_copy(NormSrcBase(),NormBase(),NormSize);
    }
    else{
      NormSources.clear();
    }
  }
  else{
    NormSources.clear();
  }
}
Beispiel #6
0
void OGL_ModelData::Load()
{
  // Already loaded?
  if (ModelPresent()) {
    return;
  }

  // Load the model
  Model.Clear();

  if (ModelFile == FileSpecifier()) {
    return;
  }
  if (!ModelFile.Exists()) {
    return;
  }

  bool Success = false;

  char *Type = &ModelType[0];
  if (StringsEqual(Type,"wave",4)) {
    // Alias|Wavefront
    Success = LoadModel_Wavefront(ModelFile, Model);
  }
  else if (StringsEqual(Type,"3ds",3)) {
    // 3D Studio Max
    Success = LoadModel_Studio(ModelFile, Model);
  }
  else if (StringsEqual(Type,"dim3",4)) {
    // Brian Barnes's "Dim3" model format (first pass: model geometry)
    Success = LoadModel_Dim3(ModelFile, Model, LoadModelDim3_First);

    // Second and third passes: frames and sequences
    try
    {
      if (ModelFile1 == FileSpecifier()) {
        throw 0;
      }
      if (!ModelFile1.Exists()) {
        throw 0;
      }
      if (!LoadModel_Dim3(ModelFile1, Model, LoadModelDim3_Rest)) {
        throw 0;
      }
    }
    catch(...)
    {}
    //
    try
    {
      if (ModelFile2 == FileSpecifier()) {
        throw 0;
      }
      if (!ModelFile2.Exists()) {
        throw 0;
      }
      if (!LoadModel_Dim3(ModelFile2, Model, LoadModelDim3_Rest)) {
        throw 0;
      }
    }
    catch(...)
    {}
  }
#if HAVE_QUESA
  else if (StringsEqual(Type,
                        "qd3d") ||
           StringsEqual(Type,"3dmf") || StringsEqual(Type,"quesa")) {
    // QuickDraw 3D / Quesa
    Success = LoadModel_QD3D(ModelFile, Model);
  }
#endif

  if (!Success) {
    Model.Clear();
    return;
  }

  // Calculate transformation matrix
  GLfloat Angle, Cosine, Sine;
  GLfloat RotMatrix[3][3], NewRotMatrix[3][3], IndivRotMatrix[3][3];
  MatIdentity(RotMatrix);

  MatIdentity(IndivRotMatrix);
  Angle = (float)Degree2Radian*XRot;
  Cosine = (float)cos(Angle);
  Sine = (float)sin(Angle);
  IndivRotMatrix[1][1] = Cosine;
  IndivRotMatrix[1][2] = -Sine;
  IndivRotMatrix[2][1] = Sine;
  IndivRotMatrix[2][2] = Cosine;
  MatMult(IndivRotMatrix,RotMatrix,NewRotMatrix);
  MatCopy(NewRotMatrix,RotMatrix);

  MatIdentity(IndivRotMatrix);
  Angle = (float)Degree2Radian*YRot;
  Cosine = (float)cos(Angle);
  Sine = (float)sin(Angle);
  IndivRotMatrix[2][2] = Cosine;
  IndivRotMatrix[2][0] = -Sine;
  IndivRotMatrix[0][2] = Sine;
  IndivRotMatrix[0][0] = Cosine;
  MatMult(IndivRotMatrix,RotMatrix,NewRotMatrix);
  MatCopy(NewRotMatrix,RotMatrix);

  MatIdentity(IndivRotMatrix);
  Angle = (float)Degree2Radian*ZRot;
  Cosine = (float)cos(Angle);
  Sine = (float)sin(Angle);
  IndivRotMatrix[0][0] = Cosine;
  IndivRotMatrix[0][1] = -Sine;
  IndivRotMatrix[1][0] = Sine;
  IndivRotMatrix[1][1] = Cosine;
  MatMult(IndivRotMatrix,RotMatrix,NewRotMatrix);
  MatCopy(NewRotMatrix,RotMatrix);

  MatScalMult(NewRotMatrix,Scale);                              // For the position vertices
  if (Scale < 0) {
    MatScalMult(RotMatrix,-1);                          // For the normals
  }
  // Is model animated or static?
  // Test by trying to find neutral positions (useful for working with the normals later on)
  if (Model.FindPositions_Neutral(false)) {
    // Copy over the vector and normal transformation matrices:
    for (int k=0; k<3; k++)
      for (int l=0; l<3; l++)
      {
        Model.TransformPos.M[k][l] = NewRotMatrix[k][l];
        Model.TransformNorm.M[k][l] = RotMatrix[k][l];
      }

    Model.TransformPos.M[0][3] = XShift;
    Model.TransformPos.M[1][3] = YShift;
    Model.TransformPos.M[2][3] = ZShift;

    // Find the transformed bounding box:
    bool RestOfCorners = false;
    GLfloat NewBoundingBox[2][3];
    // The indices i1, i2, and i3 are for selecting which of the box's two principal corners
    // to get coordinates from
    for (int i1=0; i1<2; i1++)
    {
      GLfloat X = Model.BoundingBox[i1][0];
      for (int i2=0; i2<2; i2++)
      {
        GLfloat Y = Model.BoundingBox[i2][0];
        for (int i3=0; i3<2; i3++)
        {
          GLfloat Z = Model.BoundingBox[i3][0];

          GLfloat Corner[3];
          for (int ic=0; ic<3; ic++)
          {
            GLfloat *Row = Model.TransformPos.M[ic];
            Corner[ic] = Row[0]*X + Row[1]*Y + Row[2]*Z + Row[3];
          }

          if (RestOfCorners) {
            // Find minimum and maximum for each coordinate
            for (int ic=0; ic<3; ic++)
            {
              NewBoundingBox[0][ic] = min(NewBoundingBox[0][ic],Corner[ic]);
              NewBoundingBox[1][ic] = max(NewBoundingBox[1][ic],Corner[ic]);
            }
          }
          else
          {
            // Simply copy it in:
            for (int ic=0; ic<3; ic++)
              NewBoundingBox[0][ic] = NewBoundingBox[1][ic] = Corner[ic];
            RestOfCorners = true;
          }
        }
      }
    }

    for (int ic=0; ic<2; ic++)
      objlist_copy(Model.BoundingBox[ic],NewBoundingBox[ic],3);
  }
  else
  {
    // Static model
    size_t NumVerts = Model.Positions.size()/3;

    for (size_t k=0; k<NumVerts; k++)
    {
      GLfloat *Pos = Model.PosBase() + 3*k;
      GLfloat NewPos[3];
      MatVecMult(NewRotMatrix,Pos,NewPos);                      // Has the scaling
      Pos[0] = NewPos[0] + XShift;
      Pos[1] = NewPos[1] + YShift;
      Pos[2] = NewPos[2] + ZShift;
    }

    size_t NumNorms = Model.Normals.size()/3;
    for (size_t k=0; k<NumNorms; k++)
    {
      GLfloat *Norms = Model.NormBase() + 3*k;
      GLfloat NewNorms[3];
      MatVecMult(RotMatrix,Norms,NewNorms);                     // Not scaled
      objlist_copy(Norms,NewNorms,3);
    }

    // So as to be consistent with the new points
    Model.FindBoundingBox();
  }

  Model.AdjustNormals(NormalType,NormalSplit);
  Model.CalculateTangents();

  // Don't forget the skins
  OGL_SkinManager::Load();
}
Beispiel #7
0
// Src -> Dest
static void MatCopy(const GLfloat SrcMat[3][3], GLfloat DestMat[3][3])
{
  objlist_copy(DestMat[0],SrcMat[0],9);
}