<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkStructuredPointsGeometryFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkStructuredPointsGeometryFilter.h"

// Construct with initial extent of all the data
vtkStructuredPointsGeometryFilter::vtkStructuredPointsGeometryFilter()
{
  this->Extent[0] = 0;
  this->Extent[1] = VTK_LARGE_INTEGER;
  this->Extent[2] = 0;
  this->Extent[3] = VTK_LARGE_INTEGER;
  this->Extent[4] = 0;
  this->Extent[5] = VTK_LARGE_INTEGER;
}

void vtkStructuredPointsGeometryFilter::Execute()
{
  int *dims, dimension, dir[3], diff[3];
  int i, j, k, extent[6];
  int ptIds[4], idx, startIdx;
  int cellId;
  vtkPoints *newPts=0;
  vtkCellArray *newVerts=0;
  vtkCellArray *newLines=0;
  vtkCellArray *newPolys=0;
  int totPoints, numPolys;
  int offset[3], pos;
  float *x;
  vtkPointData *pd, *outPD;
  vtkCellData *cd, *outCD;
  vtkStructuredPoints *input=(vtkStructuredPoints *)this->Input;
  vtkPolyData *output=(vtkPolyData *)this->Output;

  vtkDebugMacro(<< "Extracting structured points geometry");

  pd = input->GetPointData();
  outPD = output->GetPointData();
  cd = input->GetCellData();
  outCD = output->GetCellData();
//  this->PointData.CopyNormalsOff();
  dims = input->GetDimensions();
//
// Based on the dimensions of the structured data, and the extent of the geometry,
// compute the combined extent plus the dimensionality of the data
//
  for (dimension=3, i=0; i<3; i++)
    {
    extent[2*i] = this->Extent[2*i] < 0 ? 0 : this->Extent[2*i];
    extent[2*i] = this->Extent[2*i] >= dims[i] ? dims[i]-1 : this->Extent[2*i];
    extent[2*i+1] = this->Extent[2*i+1] >= dims[i] ? dims[i]-1 : this->Extent[2*i+1];
    if ( extent[2*i+1] < extent[2*i] ) extent[2*i+1] = extent[2*i];
    if ( (extent[2*i+1] - extent[2*i]) == 0 ) dimension--;
    }
//
// Now create polygonal data based on dimension of data
//
  startIdx = extent[0] + extent[2]*dims[0] + extent[4]*dims[0]*dims[1];

  switch (dimension)
    {
    default:
      break;

    case 0: // --------------------- build point -----------------------

      newPts = vtkPoints::New();
      newPts->Allocate(1);
      newVerts = vtkCellArray::New();
      newVerts->Allocate(newVerts->EstimateSize(1,1));
      outPD->CopyAllocate(pd,1);
      outCD->CopyAllocate(cd,1);

      ptIds[0] = newPts->InsertNextPoint(input->GetPoint(startIdx));
      outPD->CopyData(pd,startIdx,ptIds[0]);

      cellId = newVerts->InsertNextCell(1,ptIds);
      outCD->CopyData(cd,startIdx,ptIds[0]);
      break;

    case 1: // --------------------- build line -----------------------

      for (dir[0]=dir[1]=dir[2]=totPoints=0, i=0; i<3; i++)
        {
        if ( (diff[i] = extent[2*i+1] - extent[2*i]) > 0 )
          {
          dir[0] = i;
          totPoints = diff[i] + 1;
          break;
          }
        }
      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newLines = vtkCellArray::New();
      newLines->Allocate(newLines->EstimateSize(totPoints-1,2));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,totPoints - 1);
//
//  Load data
//
      if ( dir[0] == 0 )
        offset[0] = 1;
      else if (dir[0] == 1)
        offset[0] = dims[0];
      else
        offset[0] = dims[0]*dims[1];

      for (i=0; i<totPoints; i++)
        {
        idx = startIdx + i*offset[0];
        x = input->GetPoint(idx);
        ptIds[0] = newPts->InsertNextPoint(x);
        outPD->CopyData(pd,idx,ptIds[0]);
        }

      if ( dir[0] == 0 )
        offset[0] = 1;
      else if (dir[0] == 1)
        offset[0] = dims[0] - 1;
      else
        offset[0] = (dims[0] - 1) * (dims[1] - 1);

      for (i=0; i<(totPoints-1); i++)
        {
        idx = startIdx + i*offset[0];
        ptIds[0] = i;
        ptIds[1] = i + 1;
        cellId = newLines->InsertNextCell(2,ptIds);
        outCD->CopyData(cd,idx,cellId);
        }
      break;

    case 2: // --------------------- build plane -----------------------
//
//  Create the data objects
//
      for (dir[0]=dir[1]=dir[2]=idx=0,i=0; i<3; i++)
        {
        if ( (diff[i] = extent[2*i+1] - extent[2*i]) != 0 )
          dir[idx++] = i;
        else
          dir[2] = i;
        }

      totPoints = (diff[dir[0]]+1) * (diff[dir[1]]+1);
      numPolys = diff[dir[0]]  * diff[dir[1]];

      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newPolys = vtkCellArray::New();
      newPolys->Allocate(newLines->EstimateSize(numPolys,4));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,numPolys);
//
//  Create vertices
//
      for (i=0; i<2; i++)
        {
        if ( dir[i] == 0 )
          offset[i] = 1;
        else if ( dir[i] == 1 )
          offset[i] = dims[0];
        else if ( dir[i] == 2 )
          offset[i] = dims[0]*dims[1];
        }

      for (pos=startIdx, j=0; j < (diff[dir[1]]+1); j++)
        {
        for (i=0; i < (diff[dir[0]]+1); i++)
          {
          idx = pos + i*offset[0];
          x = input->GetPoint(idx);
          ptIds[0] = newPts->InsertNextPoint(x);
          outPD->CopyData(pd,idx,ptIds[0]);
          }
        pos += offset[1];
        }

//
//  Create cells
//
      for (i=0; i<2; i++)
        {
        if ( dir[i] == 0 )
          offset[i] = 1;
        else if ( dir[i] == 1 )
          offset[i] = (dims[0] - 1);
        else if ( dir[i] == 2 )
          offset[i] = (dims[0] - 1) * (dims[1] - 1);
        }

      for (pos=startIdx, j=0; j < diff[dir[1]]; j++)
        {
        for (i=0; i < diff[dir[0]]; i++)
          {
          idx = pos + i*offset[0];
          ptIds[0] = i + j*(diff[dir[0]]+1);
          ptIds[1] = ptIds[0] + 1;
          ptIds[2] = ptIds[1] + diff[dir[0]] + 1;
          ptIds[3] = ptIds[2] - 1;
          cellId = newPolys->InsertNextCell(4,ptIds);
          outCD->CopyData(cd,idx,cellId);
          }
        pos += offset[1];
        }
      break;

    case 3: // ------------------- grab points in volume  --------------

//
// Create data objects
//
      for (i=0; i<3; i++) diff[i] = extent[2*i+1] - extent[2*i];

      totPoints = (diff[0]+1) * (diff[1]+1) * (diff[2]+1);

      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newVerts = vtkCellArray::New();
      newVerts->Allocate(newVerts->EstimateSize(totPoints,1));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,totPoints);
//
// Create vertices and cells
//
      offset[0] = dims[0];
      offset[1] = dims[0]*dims[1];

      for (pos=startIdx, k=0; k < (diff[2]+1); k++)
        {
        for (j=0; j < (diff[1]+1); j++)
          {
          pos = startIdx + j*offset[0] + k*offset[1];
          for (i=0; i < (diff[0]+1); i++)
            {
            x = input->GetPoint(pos+i);
            ptIds[0] = newPts->InsertNextPoint(x);
            outPD->CopyData(pd,pos+i,ptIds[0]);
            cellId = newVerts->InsertNextCell(1,ptIds);
            outCD->CopyData(cd,pos+i,cellId);
            }
          }
        }
        break; /* end this case */

    } // switch
//
// Update self and release memory
//
  if (newPts)
    {
    output->SetPoints(newPts);
    newPts->Delete();
    }

  if (newVerts)
    {
    output->SetVerts(newVerts);
    newVerts->Delete();
    }

  if (newLines)
    {
    output->SetLines(newLines);
    newLines->Delete();
    }

  if (newPolys)
    {
    output->SetPolys(newPolys);
    newPolys->Delete();
    }
}

void vtkStructuredPointsGeometryFilter::SetExtent(int iMin, int iMax,
                                                 int jMin, int jMax,
                                                 int kMin, int kMax)
{
  int extent[6];

  extent[0] = iMin;
  extent[1] = iMax;
  extent[2] = jMin;
  extent[3] = jMax;
  extent[4] = kMin;
  extent[5] = kMax;

  this->SetExtent(extent);
}

// Specify (imin,imax, jmin,jmax, kmin,kmax) indices.
void vtkStructuredPointsGeometryFilter::SetExtent(int *extent)
{
  int i;

  if ( extent[0] != this->Extent[0] || extent[1] != this->Extent[1] ||
  extent[2] != this->Extent[2] || extent[3] != this->Extent[3] ||
  extent[4] != this->Extent[4] || extent[5] != this->Extent[5] )
    {
    this->Modified();
    for (i=0; i<3; i++)
      {
      if ( extent[2*i] < 0 ) extent[2*i] = 0;
      if ( extent[2*i+1] < extent[2*i] ) extent[2*i+1] = extent[2*i];
      this->Extent[2*i] = extent[2*i];
      this->Extent[2*i+1] = extent[2*i+1];
      }
    }
}

void vtkStructuredPointsGeometryFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkStructuredPointsToPolyDataFilter::PrintSelf(os,indent);

  os << indent << "Extent: \n";
  os << indent << "  Imin,Imax: (" << this->Extent[0] << ", " << this->Extent[1] << ")\n";
  os << indent << "  Jmin,Jmax: (" << this->Extent[2] << ", " << this->Extent[3] << ")\n";
  os << indent << "  Kmin,Kmax: (" << this->Extent[4] << ", " << this->Extent[5] << ")\n";
}
<commit_msg>ERR: Was not passing cell data.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkStructuredPointsGeometryFilter.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 1993-1998 Ken Martin, Will Schroeder, Bill Lorensen.

This software is copyrighted by Ken Martin, Will Schroeder and Bill Lorensen.
The following terms apply to all files associated with the software unless
explicitly disclaimed in individual files. This copyright specifically does
not apply to the related textbook "The Visualization Toolkit" ISBN
013199837-4 published by Prentice Hall which is covered by its own copyright.

The authors hereby grant permission to use, copy, and distribute this
software and its documentation for any purpose, provided that existing
copyright notices are retained in all copies and that this notice is included
verbatim in any distributions. Additionally, the authors grant permission to
modify this software and its documentation for any purpose, provided that
such modifications are not distributed without the explicit consent of the
authors and that existing copyright notices are retained in all copies. Some
of the algorithms implemented by this software are patented, observe all
applicable patent law.

IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE IS PROVIDED ON AN
"AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

=========================================================================*/
#include "vtkStructuredPointsGeometryFilter.h"

// Construct with initial extent of all the data
vtkStructuredPointsGeometryFilter::vtkStructuredPointsGeometryFilter()
{
  this->Extent[0] = 0;
  this->Extent[1] = VTK_LARGE_INTEGER;
  this->Extent[2] = 0;
  this->Extent[3] = VTK_LARGE_INTEGER;
  this->Extent[4] = 0;
  this->Extent[5] = VTK_LARGE_INTEGER;
}

void vtkStructuredPointsGeometryFilter::Execute()
{
  int *dims, dimension, dir[3], diff[3];
  int i, j, k, extent[6];
  int ptIds[4], idx, startIdx;
  int cellId;
  vtkPoints *newPts=0;
  vtkCellArray *newVerts=0;
  vtkCellArray *newLines=0;
  vtkCellArray *newPolys=0;
  int totPoints, numPolys;
  int offset[3], pos;
  float *x;
  vtkPointData *pd, *outPD;
  vtkCellData *cd, *outCD;
  vtkStructuredPoints *input=(vtkStructuredPoints *)this->Input;
  vtkPolyData *output=(vtkPolyData *)this->Output;

  vtkDebugMacro(<< "Extracting structured points geometry");

  pd = input->GetPointData();
  outPD = output->GetPointData();
  cd = input->GetCellData();
  outCD = output->GetCellData();
//  this->PointData.CopyNormalsOff();
  dims = input->GetDimensions();
//
// Based on the dimensions of the structured data, and the extent of the geometry,
// compute the combined extent plus the dimensionality of the data
//
  for (dimension=3, i=0; i<3; i++)
    {
    extent[2*i] = this->Extent[2*i] < 0 ? 0 : this->Extent[2*i];
    extent[2*i] = this->Extent[2*i] >= dims[i] ? dims[i]-1 : this->Extent[2*i];
    extent[2*i+1] = this->Extent[2*i+1] >= dims[i] ? dims[i]-1 : this->Extent[2*i+1];
    if ( extent[2*i+1] < extent[2*i] ) extent[2*i+1] = extent[2*i];
    if ( (extent[2*i+1] - extent[2*i]) == 0 ) dimension--;
    }
//
// Now create polygonal data based on dimension of data
//
  startIdx = extent[0] + extent[2]*dims[0] + extent[4]*dims[0]*dims[1];

  switch (dimension)
    {
    default:
      break;

    case 0: // --------------------- build point -----------------------

      newPts = vtkPoints::New();
      newPts->Allocate(1);
      newVerts = vtkCellArray::New();
      newVerts->Allocate(newVerts->EstimateSize(1,1));
      outPD->CopyAllocate(pd,1);
      outCD->CopyAllocate(cd,1);

      ptIds[0] = newPts->InsertNextPoint(input->GetPoint(startIdx));
      outPD->CopyData(pd,startIdx,ptIds[0]);

      cellId = newVerts->InsertNextCell(1,ptIds);
      outCD->CopyData(cd,startIdx,cellId);
      break;

    case 1: // --------------------- build line -----------------------

      for (dir[0]=dir[1]=dir[2]=totPoints=0, i=0; i<3; i++)
        {
        if ( (diff[i] = extent[2*i+1] - extent[2*i]) > 0 )
          {
          dir[0] = i;
          totPoints = diff[i] + 1;
          break;
          }
        }
      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newLines = vtkCellArray::New();
      newLines->Allocate(newLines->EstimateSize(totPoints-1,2));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,totPoints - 1);
//
//  Load data
//
      if ( dir[0] == 0 )
        offset[0] = 1;
      else if (dir[0] == 1)
        offset[0] = dims[0];
      else
        offset[0] = dims[0]*dims[1];

      for (i=0; i<totPoints; i++)
        {
        idx = startIdx + i*offset[0];
        x = input->GetPoint(idx);
        ptIds[0] = newPts->InsertNextPoint(x);
        outPD->CopyData(pd,idx,ptIds[0]);
        }

      if ( dir[0] == 0 )
        offset[0] = 1;
      else if (dir[0] == 1)
        offset[0] = dims[0] - 1;
      else
        offset[0] = (dims[0] - 1) * (dims[1] - 1);

      for (i=0; i<(totPoints-1); i++)
        {
        idx = startIdx + i*offset[0];
        ptIds[0] = i;
        ptIds[1] = i + 1;
        cellId = newLines->InsertNextCell(2,ptIds);
        outCD->CopyData(cd,idx,cellId);
        }
      break;

    case 2: // --------------------- build plane -----------------------
//
//  Create the data objects
//
      for (dir[0]=dir[1]=dir[2]=idx=0,i=0; i<3; i++)
        {
        if ( (diff[i] = extent[2*i+1] - extent[2*i]) != 0 )
          dir[idx++] = i;
        else
          dir[2] = i;
        }

      totPoints = (diff[dir[0]]+1) * (diff[dir[1]]+1);
      numPolys = diff[dir[0]]  * diff[dir[1]];

      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newPolys = vtkCellArray::New();
      newPolys->Allocate(newLines->EstimateSize(numPolys,4));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,numPolys);
//
//  Create vertices
//
      for (i=0; i<2; i++)
        {
        if ( dir[i] == 0 )
          offset[i] = 1;
        else if ( dir[i] == 1 )
          offset[i] = dims[0];
        else if ( dir[i] == 2 )
          offset[i] = dims[0]*dims[1];
        }

      for (pos=startIdx, j=0; j < (diff[dir[1]]+1); j++)
        {
        for (i=0; i < (diff[dir[0]]+1); i++)
          {
          idx = pos + i*offset[0];
          x = input->GetPoint(idx);
          ptIds[0] = newPts->InsertNextPoint(x);
          outPD->CopyData(pd,idx,ptIds[0]);
          }
        pos += offset[1];
        }

//
//  Create cells
//
      for (i=0; i<2; i++)
        {
        if ( dir[i] == 0 )
          offset[i] = 1;
        else if ( dir[i] == 1 )
          offset[i] = (dims[0] - 1);
        else if ( dir[i] == 2 )
          offset[i] = (dims[0] - 1) * (dims[1] - 1);
        }

      for (pos=startIdx, j=0; j < diff[dir[1]]; j++)
        {
        for (i=0; i < diff[dir[0]]; i++)
          {
          idx = pos + i*offset[0];
          ptIds[0] = i + j*(diff[dir[0]]+1);
          ptIds[1] = ptIds[0] + 1;
          ptIds[2] = ptIds[1] + diff[dir[0]] + 1;
          ptIds[3] = ptIds[2] - 1;
          cellId = newPolys->InsertNextCell(4,ptIds);
          outCD->CopyData(cd,idx,cellId);
          }
        pos += offset[1];
        }
      break;

    case 3: // ------------------- grab points in volume  --------------

//
// Create data objects
//
      for (i=0; i<3; i++) diff[i] = extent[2*i+1] - extent[2*i];

      totPoints = (diff[0]+1) * (diff[1]+1) * (diff[2]+1);

      newPts = vtkPoints::New();
      newPts->Allocate(totPoints);
      newVerts = vtkCellArray::New();
      newVerts->Allocate(newVerts->EstimateSize(totPoints,1));
      outPD->CopyAllocate(pd,totPoints);
      outCD->CopyAllocate(cd,totPoints);
//
// Create vertices and cells
//
      offset[0] = dims[0];
      offset[1] = dims[0]*dims[1];

      for (pos=startIdx, k=0; k < (diff[2]+1); k++)
        {
        for (j=0; j < (diff[1]+1); j++)
          {
          pos = startIdx + j*offset[0] + k*offset[1];
          for (i=0; i < (diff[0]+1); i++)
            {
            x = input->GetPoint(pos+i);
            ptIds[0] = newPts->InsertNextPoint(x);
            outPD->CopyData(pd,pos+i,ptIds[0]);
            cellId = newVerts->InsertNextCell(1,ptIds);
            outCD->CopyData(cd,pos+i,cellId);
            }
          }
        }
        break; /* end this case */

    } // switch
//
// Update self and release memory
//
  if (newPts)
    {
    output->SetPoints(newPts);
    newPts->Delete();
    }

  if (newVerts)
    {
    output->SetVerts(newVerts);
    newVerts->Delete();
    }

  if (newLines)
    {
    output->SetLines(newLines);
    newLines->Delete();
    }

  if (newPolys)
    {
    output->SetPolys(newPolys);
    newPolys->Delete();
    }
}

void vtkStructuredPointsGeometryFilter::SetExtent(int iMin, int iMax,
                                                 int jMin, int jMax,
                                                 int kMin, int kMax)
{
  int extent[6];

  extent[0] = iMin;
  extent[1] = iMax;
  extent[2] = jMin;
  extent[3] = jMax;
  extent[4] = kMin;
  extent[5] = kMax;

  this->SetExtent(extent);
}

// Specify (imin,imax, jmin,jmax, kmin,kmax) indices.
void vtkStructuredPointsGeometryFilter::SetExtent(int *extent)
{
  int i;

  if ( extent[0] != this->Extent[0] || extent[1] != this->Extent[1] ||
  extent[2] != this->Extent[2] || extent[3] != this->Extent[3] ||
  extent[4] != this->Extent[4] || extent[5] != this->Extent[5] )
    {
    this->Modified();
    for (i=0; i<3; i++)
      {
      if ( extent[2*i] < 0 ) extent[2*i] = 0;
      if ( extent[2*i+1] < extent[2*i] ) extent[2*i+1] = extent[2*i];
      this->Extent[2*i] = extent[2*i];
      this->Extent[2*i+1] = extent[2*i+1];
      }
    }
}

void vtkStructuredPointsGeometryFilter::PrintSelf(ostream& os, vtkIndent indent)
{
  vtkStructuredPointsToPolyDataFilter::PrintSelf(os,indent);

  os << indent << "Extent: \n";
  os << indent << "  Imin,Imax: (" << this->Extent[0] << ", " << this->Extent[1] << ")\n";
  os << indent << "  Jmin,Jmax: (" << this->Extent[2] << ", " << this->Extent[3] << ")\n";
  os << indent << "  Kmin,Kmax: (" << this->Extent[4] << ", " << this->Extent[5] << ")\n";
}
<|endoftext|>


<commit_before>//
//#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <ctime>
#include <algorithm>
#include <cmath>
#include "GPIOClass.h"

using namespace std;

void Pulse(GPIOClass* pin, double cycles);
void Wait(double seconds);
clock_t timer;
double time_to_complete;
double resolution = 10000;

#define PI 4*atan(1)

int main (int argc, char *argv[]) {
	string type = argv[1];
	transform(type.begin(), type.end(), type.begin(), :: tolower);
	// lets assume that the way to run this is
	// pwm.exe [rising/falling/sine/constant]
	if (argc != 2) {
		cout << "Usage: pwm [rising/falling/sine/constant/blink]" << endl;
		return -1;
	}

	while (time_to_complete <= 0) {
		cout << "Input How Long To Run (in seconds)" << endl;
		cin >> time_to_complete;
	}

	GPIOClass* out1 = new GPIOClass("4");
	GPIOClass* in2 = new GPIOClass("17");

	out1->export_gpio();
	in2->export_gpio();

	out1->setdir_gpio("out");
	in2->setdir_gpio("in");

	cout << "Pins are setup." << endl;
	// avoiding flickering will be at 100hz
	// aka turn on and off 100 times a sec
	// a cycle of 0 is off
	// a cycle of 100 is on

	if (type == "rising") {
		clock_t finish = clock() + time_to_complete * CLOCKS_PER_SEC;
		while (clock() < finish) {
			// pulse for however long we need to to achieve brightness.
				cout << sin((PI/2) * (1/time_to_complete)) << endl;
				Pulse(out1, sin((PI/2) * (1/time_to_complete)));
				Wait(sin((PI/2) * (1/time_to_complete)));
		}
	}
	if (type == "falling") {

	}
	if (type == "sine") {

	}
	if (type == "constant") {
		out1->setval_gpio("1"); // turn the pin on
		Wait(time_to_complete); // sleep for number of cycles / 1/100 sec
		//cout << "Waiting during pulse" << endl;
		out1->setval_gpio("0"); // turn the pin off
	}
	if (type == "blink") { // aka. TESTR
		clock_t finish = clock() + time_to_complete * CLOCKS_PER_SEC;
		while (clock() < finish) {
			// pulse for however long we need to to achieve brightness.
			Pulse(out1, 1 * resolution);
			Wait(0.5);
		}
	}
	cout << "Done." << endl;
}

//1 cycle is 1/100th of a second
//100 cycles is 1 sec
void Pulse(GPIOClass* pin, double cycles) {
	bool running = true;
	while (running) {
		pin->setval_gpio("1"); // turn the pin on
		Wait(cycles / resolution); // sleep for number of cycles / 1/100 sec
		//cout << "Waiting during pulse" << endl;
		pin->setval_gpio("0"); // turn the pin off
		running = false; // this is unnessesary but could be useful if modified a bit.
	}
}

void Wait ( double seconds )
{
	clock_t endwait;
	endwait = clock () + seconds * CLOCKS_PER_SEC ;
	while (clock() < endwait) {}
}
<commit_msg>Update pwm.cpp<commit_after>//
//#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <ctime>
#include <algorithm>
#include <cmath>
#include "GPIOClass.h"

using namespace std;

void Pulse(GPIOClass* pin, double cycles);
void Wait(double seconds);
clock_t timer;
double time_to_complete;
double resolution = 10000;

#define PI 4*atan(1)

int main (int argc, char *argv[]) {
	string type = argv[1];
	transform(type.begin(), type.end(), type.begin(), :: tolower);
	// lets assume that the way to run this is
	// pwm.exe [rising/falling/sine/constant]
	if (argc != 2) {
		cout << "Usage: pwm [rising/falling/sine/constant/blink]" << endl;
		return -1;
	}

	while (time_to_complete <= 0) {
		cout << "Input How Long To Run (in seconds)" << endl;
		cin >> time_to_complete;
	}

	GPIOClass* out1 = new GPIOClass("4");
	GPIOClass* in2 = new GPIOClass("17");

	out1->export_gpio();
	in2->export_gpio();

	out1->setdir_gpio("out");
	in2->setdir_gpio("in");

	cout << "Pins are setup." << endl;
	// avoiding flickering will be at 100hz
	// aka turn on and off 100 times a sec
	// a cycle of 0 is off
	// a cycle of 100 is on

	if (type == "rising") {
		clock_t finish = clock() + time_to_complete * CLOCKS_PER_SEC;
		while (clock() < finish) {
			// pulse for however long we need to to achieve brightness.
				cout << sin((PI/2) * (1/clock())) << endl;
				Pulse(out1, sin((PI/2) * (1/time_to_complete)));
				Wait(sin((PI/2) * (1/time_to_complete)));
		}
	}
	if (type == "falling") {

	}
	if (type == "sine") {

	}
	if (type == "constant") {
		out1->setval_gpio("1"); // turn the pin on
		Wait(time_to_complete); // sleep for number of cycles / 1/100 sec
		//cout << "Waiting during pulse" << endl;
		out1->setval_gpio("0"); // turn the pin off
	}
	if (type == "blink") { // aka. TESTR
		clock_t finish = clock() + time_to_complete * CLOCKS_PER_SEC;
		while (clock() < finish) {
			// pulse for however long we need to to achieve brightness.
			Pulse(out1, 1 * resolution);
			Wait(0.5);
		}
	}
	cout << "Done." << endl;
}

//1 cycle is 1/100th of a second
//100 cycles is 1 sec
void Pulse(GPIOClass* pin, double cycles) {
	bool running = true;
	while (running) {
		pin->setval_gpio("1"); // turn the pin on
		Wait(cycles / resolution); // sleep for number of cycles / 1/100 sec
		//cout << "Waiting during pulse" << endl;
		pin->setval_gpio("0"); // turn the pin off
		running = false; // this is unnessesary but could be useful if modified a bit.
	}
}

void Wait ( double seconds )
{
	clock_t endwait;
	endwait = clock () + seconds * CLOCKS_PER_SEC ;
	while (clock() < endwait) {}
}
<|endoftext|>


<commit_before>#include <Sound.h>
#include <Display.h>
#include <SDL.h>
#include <SDL_mixer.h>

#include <hx/Thread.h>

namespace nme
{

bool gSDLIsInit = false;

class SDLSoundChannel;

bool sChannelsInit = false;
enum { sMaxChannels = 8 };

bool sUsedChannel[sMaxChannels];
bool sDoneChannel[sMaxChannels];
void *sUsedMusic = 0;
bool sDoneMusic = false;

unsigned int  sSoundPos = 0;

void onChannelDone(int inChannel)
{
   if (sUsedChannel[inChannel])
      sDoneChannel[inChannel] = true;
}

void onMusicDone()
{
   if (sUsedMusic)
      sDoneMusic = true;
}

void  onPostMix(void *udata, Uint8 *stream, int len)
{
   sSoundPos += len;
}

static bool Init()
{
   if (!gSDLIsInit)
   {
      fprintf(stderr,"Please init Stage before creating sound.\n");
      return false;
   }

   if (!sChannelsInit)
   {
      sChannelsInit = true;
      for(int i=0;i<sMaxChannels;i++)
      {
         sUsedChannel[i] = false;
         sDoneChannel[i] = false;
      }
      Mix_ChannelFinished(onChannelDone);
      Mix_HookMusicFinished(onMusicDone);
      Mix_SetPostMix(onPostMix,0);
   }

   return sChannelsInit;
}

// ---  Using "Mix_Chunk" API ----------------------------------------------------

class SDLSoundChannel : public SoundChannel
{
  enum { BUF_SIZE = 16384 };

public:
   SDLSoundChannel(Object *inSound, Mix_Chunk *inChunk, double inStartTime, int inLoops,
                  const SoundTransform &inTransform)
   {
      mChunk = inChunk;
      mDynamicBuffer = 0;
      mSound = inSound;
      mSound->IncRef();

      mChannel = -1;

      // Allocate myself a channel
      if (mChunk)
      {
         for(int i=0;i<sMaxChannels;i++)
            if (!sUsedChannel[i])
            {
               IncRef();
               sDoneChannel[i] = false;
               sUsedChannel[i] = true;
               mChannel = i;
               break;
            }
      }

      if (mChannel>=0)
      {
         Mix_PlayChannel( mChannel , mChunk, inLoops<0 ? -1 : inLoops==0 ? 0 : inLoops-1 );
         Mix_Volume( mChannel, inTransform.volume*MIX_MAX_VOLUME );
         // Mix_SetPanning
      }
   }

   SDLSoundChannel(const ByteArray &inBytes, const SoundTransform &inTransform)
   {
      mChunk = 0;
      mDynamicBuffer = new short[BUF_SIZE];
      memset(mDynamicBuffer,0,BUF_SIZE*sizeof(short));
      mSound = 0;
      mChannel = -1;
      mDynamicChunk.allocated = 0;
      mDynamicChunk.abuf = (Uint8 *)mDynamicBuffer;
      mDynamicChunk.alen = BUF_SIZE;
      mDynamicChunk.volume = MIX_MAX_VOLUME;
	   mDynamicChunk.length_ticks = 0;
      mDynamicFillPos = 0;
      mDynamicStartPos = 0;
      mDynamicDataDue = 0;

      Mix_QuerySpec(&mFrequency, &mFormat, &mChannels);

      // Allocate myself a channel
      for(int i=0;i<sMaxChannels;i++)
         if (!sUsedChannel[i])
         {
            IncRef();
            sDoneChannel[i] = false;
            sUsedChannel[i] = true;
            mChannel = i;
            break;
         }

      if (mChannel>=0)
      {
         FillBuffer(inBytes);
         // Just once ...
         if (mDynamicFillPos<2048)
         {
            mDynamicDone = true;
            mDynamicChunk.alen = mDynamicFillPos;
            Mix_PlayChannel( mChannel , &mDynamicChunk,  0 );
         }
         else
         {
            mDynamicDone = false;
            Mix_PlayChannel( mChannel , &mDynamicChunk,  -1 );
            // TODO: Lock?
            mDynamicStartPos = sSoundPos;
         }

         Mix_Volume( mChannel, inTransform.volume*MIX_MAX_VOLUME );
      }
   }

   void FillBuffer(const ByteArray &inBytes)
   {
      int floats = inBytes.Size()/sizeof(float);
      const float *buffer = (const float *)inBytes.Bytes();
      int pos = mDynamicFillPos & (BUF_SIZE-1);
      mDynamicFillPos += floats;

      int first = std::min( floats, BUF_SIZE-pos );
      for(int i=0;i<first;i++)
         mDynamicBuffer[pos+i] = *buffer++ * 16385;

      if (first<floats)
      {
         floats -= first;
         for(int i=0;i<floats;i++)
            mDynamicBuffer[i] = *buffer++ * 16385;
      }
   }

   ~SDLSoundChannel()
   {
      delete [] mDynamicBuffer;

      if (mSound)
         mSound->DecRef();
   }

   void CheckDone()
   {
      if (mChannel>=0 && sDoneChannel[mChannel])
      {
         sDoneChannel[mChannel] = false;
         int c = mChannel;
         mChannel = -1;
         DecRef();
         sUsedChannel[c] = 0;
      }
   }

   bool isComplete()
   {
      CheckDone();
      return mChannel < 0;
   }
   double getLeft() { return 1; }
   double getRight() { return 1; }
   double getPosition() { return 1; }
   void stop()
   {
      if (mChannel>=0)
         Mix_HaltChannel(mChannel);
   }
   void setTransform(const SoundTransform &inTransform)
   {
      if (mChannel>=0)
         Mix_Volume( mChannel, inTransform.volume*MIX_MAX_VOLUME );
   }

   double getDataPosition()
   {
      int pos = (sSoundPos-mDynamicStartPos)*1000.0/mFrequency;
   }
   bool needsData()
   {
      if (!mDynamicBuffer || mDynamicDone)
         return false;

      if (mDynamicDataDue<=sSoundPos)
      {
         mDynamicDone = true;
         return true;
      }

      return false;

   }

   void addData(const ByteArray &inBytes)
   {
      mDynamicDone = false;
      mDynamicDataDue = mDynamicFillPos + mDynamicStartPos;
      FillBuffer(inBytes);
   }

   Object    *mSound;
   Mix_Chunk *mChunk;
   int       mChannel;

   Mix_Chunk mDynamicChunk;
   short    *mDynamicBuffer;
   unsigned int  mDynamicFillPos;
   unsigned int  mDynamicStartPos;
   unsigned int  mDynamicDataDue;
   bool      mDynamicDone;
   int       mFrequency;
   Uint16    mFormat;
   int       mChannels;
};

SoundChannel *SoundChannel::Create(const ByteArray &inBytes,const SoundTransform &inTransform)
{
   return new SDLSoundChannel(inBytes,inTransform);
}

class SDLSound : public Sound
{
public:
   SDLSound(const std::string &inFilename)
   {
      IncRef();

      #ifdef HX_MACOS
      char name[1024];
      GetBundleFilename(inFilename.c_str(),name,1024);
      #else
      const char *name = inFilename.c_str();
      #endif

      mChunk = Mix_LoadWAV(name);
      if ( mChunk == NULL )
      {
         mError = SDL_GetError();
         // printf("Error %s (%s)\n", mError.c_str(), name );
      }
   }
   ~SDLSound()
   {
      if (mChunk)
         Mix_FreeChunk( mChunk );
   }
   double getLength()
   {
      if (mChunk==0) return 0;
      #if defined(DYNAMIC_SDL) || defined(WEBOS)
      // ?
      return 0.0;
      #else
	  return 0.0;
      //return mChunk->length_ticks;
      #endif
   }
   // Will return with one ref...
   SoundChannel *openChannel(double startTime, int loops, const SoundTransform &inTransform)
   {
      if (!mChunk)
         return 0;
      return new SDLSoundChannel(this,mChunk,startTime, loops,inTransform);
   }
   int getBytesLoaded() { return mChunk ? mChunk->alen : 0; }
   int getBytesTotal() { return mChunk ? mChunk->alen : 0; }
   bool ok() { return mChunk; }
   std::string getError() { return mError; }

   std::string mError;
   Mix_Chunk *mChunk;
};

// ---  Using "Mix_Music" API ----------------------------------------------------

class SDLMusicChannel : public SoundChannel
{
public:
   SDLMusicChannel(Object *inSound, Mix_Music *inMusic, double inStartTime, int inLoops,
                  const SoundTransform &inTransform)
   {
      mMusic = inMusic;
      mSound = inSound;
      mSound->IncRef();

      mPlaying = false;
      if (mMusic)
      {
         mPlaying = true;
         sUsedMusic = this;
         sDoneMusic = false;
         IncRef();
         Mix_PlayMusic( mMusic, inLoops<0 ? -1 : inLoops==0 ? 0 : inLoops-1 );
         Mix_VolumeMusic( inTransform.volume*MIX_MAX_VOLUME );
         // Mix_SetPanning
      }
   }
   ~SDLMusicChannel()
   {
      mSound->DecRef();
   }

   void CheckDone()
   {
      if (mPlaying && (sDoneMusic || (sUsedMusic!=this)) )
      {
         mPlaying = false;
         if (sUsedMusic == this)
         {
            sUsedMusic = 0;
            sDoneMusic = false;
         }
         DecRef();
      }
   }

   bool isComplete()
   {
      CheckDone();
      return !mPlaying;
   }
   double getLeft() { return 1; }
   double getRight() { return 1; }
   double getPosition() { return 1; }
   void stop()
   {
      if (mMusic)
         Mix_HaltMusic();
   }
   void setTransform(const SoundTransform &inTransform)
   {
      if (mMusic>=0)
         Mix_VolumeMusic( inTransform.volume*MIX_MAX_VOLUME );
   }

   bool      mPlaying;
   Object    *mSound;
   Mix_Music *mMusic;
};

class SDLMusic : public Sound
{
public:
   SDLMusic(const std::string &inFilename)
   {
      IncRef();

      #ifdef HX_MACOS
      char name[1024];
      GetBundleFilename(inFilename.c_str(),name,1024);
      #else
      const char *name = inFilename.c_str();
      #endif

      mMusic = Mix_LoadMUS(name);
      if ( mMusic == NULL )
      {
         mError = SDL_GetError();
         printf("Error %s (%s)\n", mError.c_str(), name );
      }
   }
   ~SDLMusic()
   {
      if (mMusic)
         Mix_FreeMusic( mMusic );
   }
   double getLength()
   {
      if (mMusic==0) return 0;
      // TODO:
      return 60000;
   }
   // Will return with one ref...
   SoundChannel *openChannel(double startTime, int loops, const SoundTransform &inTransform)
   {
      if (!mMusic)
         return 0;
      return new SDLMusicChannel(this,mMusic,startTime, loops,inTransform);
   }
   int getBytesLoaded() { return mMusic ? 100 : 0; }
   int getBytesTotal() { return mMusic ? 100 : 0; }
   bool ok() { return mMusic; }
   std::string getError() { return mError; }

   std::string mError;
   Mix_Music *mMusic;
};

// --- External Interface -----------------------------------------------------------

Sound *Sound::Create(const std::string &inFilename,bool inForceMusic)
{
   if (!Init())
      return 0;
   Sound *sound = inForceMusic ? 0 :  new SDLSound(inFilename);
   if (!sound || !sound->ok())
   {
      if (sound) sound->DecRef();
      sound = new SDLMusic(inFilename);
   }
   return sound;
}

}
<commit_msg>Fix windows compile<commit_after>#include <Sound.h>
#include <Display.h>
#include <SDL.h>
#include <SDL_mixer.h>

#include <hx/Thread.h>

namespace nme
{

bool gSDLIsInit = false;

class SDLSoundChannel;

bool sChannelsInit = false;
enum { sMaxChannels = 8 };

bool sUsedChannel[sMaxChannels];
bool sDoneChannel[sMaxChannels];
void *sUsedMusic = 0;
bool sDoneMusic = false;

unsigned int  sSoundPos = 0;

void onChannelDone(int inChannel)
{
   if (sUsedChannel[inChannel])
      sDoneChannel[inChannel] = true;
}

void onMusicDone()
{
   if (sUsedMusic)
      sDoneMusic = true;
}

void  onPostMix(void *udata, Uint8 *stream, int len)
{
   sSoundPos += len;
}

static bool Init()
{
   if (!gSDLIsInit)
   {
      fprintf(stderr,"Please init Stage before creating sound.\n");
      return false;
   }

   if (!sChannelsInit)
   {
      sChannelsInit = true;
      for(int i=0;i<sMaxChannels;i++)
      {
         sUsedChannel[i] = false;
         sDoneChannel[i] = false;
      }
      Mix_ChannelFinished(onChannelDone);
      Mix_HookMusicFinished(onMusicDone);
      Mix_SetPostMix(onPostMix,0);
   }

   return sChannelsInit;
}

// ---  Using "Mix_Chunk" API ----------------------------------------------------

class SDLSoundChannel : public SoundChannel
{
  enum { BUF_SIZE = 16384 };

public:
   SDLSoundChannel(Object *inSound, Mix_Chunk *inChunk, double inStartTime, int inLoops,
                  const SoundTransform &inTransform)
   {
      mChunk = inChunk;
      mDynamicBuffer = 0;
      mSound = inSound;
      mSound->IncRef();

      mChannel = -1;

      // Allocate myself a channel
      if (mChunk)
      {
         for(int i=0;i<sMaxChannels;i++)
            if (!sUsedChannel[i])
            {
               IncRef();
               sDoneChannel[i] = false;
               sUsedChannel[i] = true;
               mChannel = i;
               break;
            }
      }

      if (mChannel>=0)
      {
         Mix_PlayChannel( mChannel , mChunk, inLoops<0 ? -1 : inLoops==0 ? 0 : inLoops-1 );
         Mix_Volume( mChannel, inTransform.volume*MIX_MAX_VOLUME );
         // Mix_SetPanning
      }
   }

   SDLSoundChannel(const ByteArray &inBytes, const SoundTransform &inTransform)
   {
      mChunk = 0;
      mDynamicBuffer = new short[BUF_SIZE];
      memset(mDynamicBuffer,0,BUF_SIZE*sizeof(short));
      mSound = 0;
      mChannel = -1;
      mDynamicChunk.allocated = 0;
      mDynamicChunk.abuf = (Uint8 *)mDynamicBuffer;
      mDynamicChunk.alen = BUF_SIZE;
      mDynamicChunk.volume = MIX_MAX_VOLUME;
	   mDynamicChunk.length_ticks = 0;
      mDynamicFillPos = 0;
      mDynamicStartPos = 0;
      mDynamicDataDue = 0;

      Mix_QuerySpec(&mFrequency, &mFormat, &mChannels);

      // Allocate myself a channel
      for(int i=0;i<sMaxChannels;i++)
         if (!sUsedChannel[i])
         {
            IncRef();
            sDoneChannel[i] = false;
            sUsedChannel[i] = true;
            mChannel = i;
            break;
         }

      if (mChannel>=0)
      {
         FillBuffer(inBytes);
         // Just once ...
         if (mDynamicFillPos<2048)
         {
            mDynamicDone = true;
            mDynamicChunk.alen = mDynamicFillPos;
            Mix_PlayChannel( mChannel , &mDynamicChunk,  0 );
         }
         else
         {
            mDynamicDone = false;
            Mix_PlayChannel( mChannel , &mDynamicChunk,  -1 );
            // TODO: Lock?
            mDynamicStartPos = sSoundPos;
         }

         Mix_Volume( mChannel, inTransform.volume*MIX_MAX_VOLUME );
      }
   }

   void FillBuffer(const ByteArray &inBytes)
   {
      int floats = inBytes.Size()/sizeof(float);
      const float *buffer = (const float *)inBytes.Bytes();
      int pos = mDynamicFillPos & (BUF_SIZE-1);
      mDynamicFillPos += floats;

      int first = BUF_SIZE-pos;
      if (floats<first)
         first = floats;
      for(int i=0;i<first;i++)
         mDynamicBuffer[pos+i] = *buffer++ * 16385;

      if (first<floats)
      {
         floats -= first;
         for(int i=0;i<floats;i++)
            mDynamicBuffer[i] = *buffer++ * 16385;
      }
   }

   ~SDLSoundChannel()
   {
      delete [] mDynamicBuffer;

      if (mSound)
         mSound->DecRef();
   }

   void CheckDone()
   {
      if (mChannel>=0 && sDoneChannel[mChannel])
      {
         sDoneChannel[mChannel] = false;
         int c = mChannel;
         mChannel = -1;
         DecRef();
         sUsedChannel[c] = 0;
      }
   }

   bool isComplete()
   {
      CheckDone();
      return mChannel < 0;
   }
   double getLeft() { return 1; }
   double getRight() { return 1; }
   double getPosition() { return 1; }
   void stop()
   {
      if (mChannel>=0)
         Mix_HaltChannel(mChannel);
   }
   void setTransform(const SoundTransform &inTransform)
   {
      if (mChannel>=0)
         Mix_Volume( mChannel, inTransform.volume*MIX_MAX_VOLUME );
   }

   double getDataPosition()
   {
      return (sSoundPos-mDynamicStartPos)*1000.0/mFrequency;
   }
   bool needsData()
   {
      if (!mDynamicBuffer || mDynamicDone)
         return false;

      if (mDynamicDataDue<=sSoundPos)
      {
         mDynamicDone = true;
         return true;
      }

      return false;

   }

   void addData(const ByteArray &inBytes)
   {
      mDynamicDone = false;
      mDynamicDataDue = mDynamicFillPos + mDynamicStartPos;
      FillBuffer(inBytes);
   }

   Object    *mSound;
   Mix_Chunk *mChunk;
   int       mChannel;

   Mix_Chunk mDynamicChunk;
   short    *mDynamicBuffer;
   unsigned int  mDynamicFillPos;
   unsigned int  mDynamicStartPos;
   unsigned int  mDynamicDataDue;
   bool      mDynamicDone;
   int       mFrequency;
   Uint16    mFormat;
   int       mChannels;
};

SoundChannel *SoundChannel::Create(const ByteArray &inBytes,const SoundTransform &inTransform)
{
   return new SDLSoundChannel(inBytes,inTransform);
}

class SDLSound : public Sound
{
public:
   SDLSound(const std::string &inFilename)
   {
      IncRef();

      #ifdef HX_MACOS
      char name[1024];
      GetBundleFilename(inFilename.c_str(),name,1024);
      #else
      const char *name = inFilename.c_str();
      #endif

      mChunk = Mix_LoadWAV(name);
      if ( mChunk == NULL )
      {
         mError = SDL_GetError();
         // printf("Error %s (%s)\n", mError.c_str(), name );
      }
   }
   ~SDLSound()
   {
      if (mChunk)
         Mix_FreeChunk( mChunk );
   }
   double getLength()
   {
      if (mChunk==0) return 0;
      #if defined(DYNAMIC_SDL) || defined(WEBOS)
      // ?
      return 0.0;
      #else
	  return 0.0;
      //return mChunk->length_ticks;
      #endif
   }
   // Will return with one ref...
   SoundChannel *openChannel(double startTime, int loops, const SoundTransform &inTransform)
   {
      if (!mChunk)
         return 0;
      return new SDLSoundChannel(this,mChunk,startTime, loops,inTransform);
   }
   int getBytesLoaded() { return mChunk ? mChunk->alen : 0; }
   int getBytesTotal() { return mChunk ? mChunk->alen : 0; }
   bool ok() { return mChunk; }
   std::string getError() { return mError; }

   std::string mError;
   Mix_Chunk *mChunk;
};

// ---  Using "Mix_Music" API ----------------------------------------------------

class SDLMusicChannel : public SoundChannel
{
public:
   SDLMusicChannel(Object *inSound, Mix_Music *inMusic, double inStartTime, int inLoops,
                  const SoundTransform &inTransform)
   {
      mMusic = inMusic;
      mSound = inSound;
      mSound->IncRef();

      mPlaying = false;
      if (mMusic)
      {
         mPlaying = true;
         sUsedMusic = this;
         sDoneMusic = false;
         IncRef();
         Mix_PlayMusic( mMusic, inLoops<0 ? -1 : inLoops==0 ? 0 : inLoops-1 );
         Mix_VolumeMusic( inTransform.volume*MIX_MAX_VOLUME );
         // Mix_SetPanning
      }
   }
   ~SDLMusicChannel()
   {
      mSound->DecRef();
   }

   void CheckDone()
   {
      if (mPlaying && (sDoneMusic || (sUsedMusic!=this)) )
      {
         mPlaying = false;
         if (sUsedMusic == this)
         {
            sUsedMusic = 0;
            sDoneMusic = false;
         }
         DecRef();
      }
   }

   bool isComplete()
   {
      CheckDone();
      return !mPlaying;
   }
   double getLeft() { return 1; }
   double getRight() { return 1; }
   double getPosition() { return 1; }
   void stop()
   {
      if (mMusic)
         Mix_HaltMusic();
   }
   void setTransform(const SoundTransform &inTransform)
   {
      if (mMusic>=0)
         Mix_VolumeMusic( inTransform.volume*MIX_MAX_VOLUME );
   }

   bool      mPlaying;
   Object    *mSound;
   Mix_Music *mMusic;
};

class SDLMusic : public Sound
{
public:
   SDLMusic(const std::string &inFilename)
   {
      IncRef();

      #ifdef HX_MACOS
      char name[1024];
      GetBundleFilename(inFilename.c_str(),name,1024);
      #else
      const char *name = inFilename.c_str();
      #endif

      mMusic = Mix_LoadMUS(name);
      if ( mMusic == NULL )
      {
         mError = SDL_GetError();
         printf("Error %s (%s)\n", mError.c_str(), name );
      }
   }
   ~SDLMusic()
   {
      if (mMusic)
         Mix_FreeMusic( mMusic );
   }
   double getLength()
   {
      if (mMusic==0) return 0;
      // TODO:
      return 60000;
   }
   // Will return with one ref...
   SoundChannel *openChannel(double startTime, int loops, const SoundTransform &inTransform)
   {
      if (!mMusic)
         return 0;
      return new SDLMusicChannel(this,mMusic,startTime, loops,inTransform);
   }
   int getBytesLoaded() { return mMusic ? 100 : 0; }
   int getBytesTotal() { return mMusic ? 100 : 0; }
   bool ok() { return mMusic; }
   std::string getError() { return mError; }

   std::string mError;
   Mix_Music *mMusic;
};

// --- External Interface -----------------------------------------------------------

Sound *Sound::Create(const std::string &inFilename,bool inForceMusic)
{
   if (!Init())
      return 0;
   Sound *sound = inForceMusic ? 0 :  new SDLSound(inFilename);
   if (!sound || !sound->ok())
   {
      if (sound) sound->DecRef();
      sound = new SDLMusic(inFilename);
   }
   return sound;
}

}
<|endoftext|>


<commit_before>#include <julia.h>
#include "rvalue.h"
#include "Values.h"

using namespace std;

jl_value_t *rPrimitive(const nj::Primitive &prim)
{
   jl_value_t *res = 0;

   switch(prim.type()->getId())
   {
      case nj::null_type: res = (jl_value_t*)jl_null; break;
      case nj::boolean_type:
      {
         const nj::Boolean &v = static_cast<const nj::Boolean&>(prim);

         if(v.val()) res = jl_true;
         else res = jl_false;
      }
      break;
      case nj::char_type:
      {
         const nj::Char &v = static_cast<const nj::Char&>(prim);

         res = jl_box_char(v.val());
      }
      break;
      case nj::int64_type:
      {
         const nj::Int64 &v = static_cast<const nj::Int64&>(prim);

         res = jl_box_int64(v.val());
      }
      break;
      case nj::int32_type:
      {
         const nj::Int32 &v = static_cast<const nj::Int32&>(prim);

         res = jl_box_int32(v.val());
      }
      break;
      case nj::int16_type:
      {
         const nj::Int16 &v = static_cast<const nj::Int16&>(prim);

         res = jl_box_int16(v.val());
      }
      break;
      case nj::uint64_type:
      {
         const nj::UInt64 &v = static_cast<const nj::UInt64&>(prim);

         res = jl_box_uint64(v.val());
      }
      break;
      case nj::uint32_type:
      {
         const nj::UInt32 &v = static_cast<const nj::UInt32&>(prim);

         res = jl_box_uint32(v.val());
      }
      break;
      case nj::uint16_type:
      {
         const nj::UInt16 &v = static_cast<const nj::UInt16&>(prim);

         res = jl_box_uint16(v.val());
      }
      break;
      case nj::uchar_type:
      {
         const nj::UChar &v = static_cast<const nj::UChar&>(prim);

         res = jl_box_uint8(v.val());
      }
      break;
      case nj::float64_type:
      {
         const nj::Float64 &v = static_cast<const nj::Float64&>(prim);

         res = jl_box_float64(v.val());
      }
      break;
      case nj::float32_type:
      {
         const nj::Float32 &v = static_cast<const nj::Float32&>(prim);

         res = jl_box_float32(v.val());
      }
      break;
      case nj::string_type:
      {
         const nj::String &v = static_cast<const nj::String&>(prim);

         res = jl_cstr_to_string(v.val().c_str());
      }
      break;
   }
   return res;
}

template<typename V,typename E> jl_array_t *rArray(const shared_ptr<nj::Value> &array,jl_datatype_t *jl_element_type)
{
   const nj::Array<V,E> &a = static_cast<nj::Array<V,E>&>(*array);
   jl_value_t *jl_atype = jl_apply_array_type(jl_element_type,a.dims().size());
   jl_tuple_t *dims = jl_alloc_tuple(a.dims().size());
   int i = 0;

   for(size_t dim: a.dims()) jl_tupleset(dims,i++,dim);

   return jl_ptr_to_array(jl_atype,a.ptr(),dims,0);
}

jl_array_t *rArray(const shared_ptr<nj::Value> &array)
{
   jl_array_t *res = 0;
   const nj::Array_t *atype = static_cast<const nj::Array_t*>(array->type());

   switch(atype->etype()->getId())
   {
      case nj::boolean_type: res = rArray<bool,nj::Boolean_t>(array,jl_bool_type); break;
      case nj::int64_type: res = rArray<int64_t,nj::Int64_t>(array,jl_int64_type); break;
      case nj::int32_type: res = rArray<int,nj::Int32_t>(array,jl_int32_type); break;
      case nj::int16_type: res = rArray<short,nj::Int16_t>(array,jl_int16_type); break;
      case nj::uint64_type: res = rArray<uint64_t,nj::UInt64_t>(array,jl_uint64_type); break;
      case nj::uint32_type: res = rArray<unsigned int,nj::UInt32_t>(array,jl_uint32_type); break;
      case nj::uint16_type: res = rArray<unsigned short,nj::UInt16_t>(array,jl_uint16_type); break;
      case nj::float64_type: res = rArray<double,nj::Float64_t>(array,jl_float64_type); break;
      case nj::float32_type: res = rArray<float,nj::Float32_t>(array,jl_float32_type); break;
      case nj::char_type: res = rArray<char,nj::Char_t>(array,jl_int8_type); break;
      case nj::uchar_type: res = rArray<unsigned char,nj::UChar_t>(array,jl_uint8_type); break;
   }
   return res;
}

jl_value_t *rvalue(const shared_ptr<nj::Value> &value)
{
   if(value->isPrimitive())
   {
      const nj::Primitive &p = static_cast<const nj::Primitive&>(*value);

      return rPrimitive(p);
   }
   else return (jl_value_t*)rArray(value);
}
<commit_msg>Changed linkage, namespace inclusion of rvalue<commit_after>#include <julia.h>
#include "rvalue.h"
#include "Values.h"

using namespace std;

static jl_value_t *rPrimitive(const nj::Primitive &prim)
{
   jl_value_t *res = 0;

   switch(prim.type()->getId())
   {
      case nj::null_type: res = (jl_value_t*)jl_null; break;
      case nj::boolean_type:
      {
         const nj::Boolean &v = static_cast<const nj::Boolean&>(prim);

         if(v.val()) res = jl_true;
         else res = jl_false;
      }
      break;
      case nj::char_type:
      {
         const nj::Char &v = static_cast<const nj::Char&>(prim);

         res = jl_box_char(v.val());
      }
      break;
      case nj::int64_type:
      {
         const nj::Int64 &v = static_cast<const nj::Int64&>(prim);

         res = jl_box_int64(v.val());
      }
      break;
      case nj::int32_type:
      {
         const nj::Int32 &v = static_cast<const nj::Int32&>(prim);

         res = jl_box_int32(v.val());
      }
      break;
      case nj::int16_type:
      {
         const nj::Int16 &v = static_cast<const nj::Int16&>(prim);

         res = jl_box_int16(v.val());
      }
      break;
      case nj::uint64_type:
      {
         const nj::UInt64 &v = static_cast<const nj::UInt64&>(prim);

         res = jl_box_uint64(v.val());
      }
      break;
      case nj::uint32_type:
      {
         const nj::UInt32 &v = static_cast<const nj::UInt32&>(prim);

         res = jl_box_uint32(v.val());
      }
      break;
      case nj::uint16_type:
      {
         const nj::UInt16 &v = static_cast<const nj::UInt16&>(prim);

         res = jl_box_uint16(v.val());
      }
      break;
      case nj::uchar_type:
      {
         const nj::UChar &v = static_cast<const nj::UChar&>(prim);

         res = jl_box_uint8(v.val());
      }
      break;
      case nj::float64_type:
      {
         const nj::Float64 &v = static_cast<const nj::Float64&>(prim);

         res = jl_box_float64(v.val());
      }
      break;
      case nj::float32_type:
      {
         const nj::Float32 &v = static_cast<const nj::Float32&>(prim);

         res = jl_box_float32(v.val());
      }
      break;
      case nj::string_type:
      {
         const nj::String &v = static_cast<const nj::String&>(prim);

         res = jl_cstr_to_string(v.val().c_str());
      }
      break;
   }
   return res;
}

template<typename V,typename E> static jl_array_t *rArray(const shared_ptr<nj::Value> &array,jl_datatype_t *jl_element_type)
{
   const nj::Array<V,E> &a = static_cast<nj::Array<V,E>&>(*array);
   jl_value_t *jl_atype = jl_apply_array_type(jl_element_type,a.dims().size());
   jl_tuple_t *dims = jl_alloc_tuple(a.dims().size());
   int i = 0;

   for(size_t dim: a.dims()) jl_tupleset(dims,i++,dim);

   return jl_ptr_to_array(jl_atype,a.ptr(),dims,0);
}

static jl_array_t *rArray(const shared_ptr<nj::Value> &array)
{
   jl_array_t *res = 0;
   const nj::Array_t *atype = static_cast<const nj::Array_t*>(array->type());

   switch(atype->etype()->getId())
   {
      case nj::boolean_type: res = rArray<bool,nj::Boolean_t>(array,jl_bool_type); break;
      case nj::int64_type: res = rArray<int64_t,nj::Int64_t>(array,jl_int64_type); break;
      case nj::int32_type: res = rArray<int,nj::Int32_t>(array,jl_int32_type); break;
      case nj::int16_type: res = rArray<short,nj::Int16_t>(array,jl_int16_type); break;
      case nj::uint64_type: res = rArray<uint64_t,nj::UInt64_t>(array,jl_uint64_type); break;
      case nj::uint32_type: res = rArray<unsigned int,nj::UInt32_t>(array,jl_uint32_type); break;
      case nj::uint16_type: res = rArray<unsigned short,nj::UInt16_t>(array,jl_uint16_type); break;
      case nj::float64_type: res = rArray<double,nj::Float64_t>(array,jl_float64_type); break;
      case nj::float32_type: res = rArray<float,nj::Float32_t>(array,jl_float32_type); break;
      case nj::char_type: res = rArray<char,nj::Char_t>(array,jl_int8_type); break;
      case nj::uchar_type: res = rArray<unsigned char,nj::UChar_t>(array,jl_uint8_type); break;
   }
   return res;
}

jl_value_t *nj::rvalue(const shared_ptr<nj::Value> &value)
{
   if(value->isPrimitive())
   {
      const nj::Primitive &p = static_cast<const nj::Primitive&>(*value);

      return rPrimitive(p);
   }
   else return (jl_value_t*)rArray(value);
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2008-2018 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include <Urho3D/IO/File.h>
#include <Urho3D/IO/Log.h>
#include "GenerateClassWrappers.h"
#include "GeneratorContext.h"

namespace Urho3D
{

void GenerateClassWrappers::Start()
{
    printer_ << "#pragma once";
    printer_ << "#include <Urho3D/Urho3DAll.h>";
    printer_ << "";
    printer_ << "namespace Wrappers";
    printer_ << "{";
}

bool GenerateClassWrappers::Visit(MetaEntity* entity, cppast::visitor_info info)
{
    if (entity->ast_ == nullptr)
        return true;

    if (entity->ast_->kind() != cppast::cpp_entity_kind::class_t)
        return true;

    // Visit only once
    if (info.event == info.container_entity_exit)
        return true;

    // Class is not supposed to be inherited
    if (generator->final_.Contains(entity->uniqueName_))
        return true;

    const auto& cls = entity->Ast<cppast::cpp_class>();
    if (!HasVirtual(cls) && !HasProtected(cls))
    {
        // Skip children for classes that do not have virtual or protected members
        return info.event != info.container_entity_enter;
    }

    printer_ << fmt("class URHO3D_EXPORT_API {{name}} : public {{symbol}}", {
        {"name", entity->name_},
        {"symbol", entity->uniqueName_},
    });
    printer_.Indent();

    // Urho3D-specific
    if (IsSubclassOf(cls, "Urho3D::Object"))
    {
        printer_ << fmt("URHO3D_OBJECT({{name}}, {{symbol_name}});", {{"name",        entity->name_},
                                                                      {"symbol_name", entity->uniqueName_}});
    }

    printer_.WriteLine("public:", false);
    // Wrap constructors
    for (const auto& e : entity->children_)
    {
        if (e->kind_ == cppast::cpp_entity_kind::constructor_t)
        {
            const auto& ctor = e->Ast<cppast::cpp_constructor>();
            printer_ << fmt("{{name}}({{parameter_list}}) : {{symbol_name}}({{parameter_name_list}}) { }",
                {{"name",                entity->name_},
                 {"symbol_name",         entity->uniqueName_},
                 {"parameter_list",      ParameterList(ctor.parameters())},
                 {"parameter_name_list", ParameterNameList(ctor.parameters())},});
        }
    }
    printer_ << fmt("virtual ~{{name}}() = default;", {{"name", entity->name_}});

    std::vector<std::string> wrappedList;
    auto implementWrapperClassMembers = [&](const MetaEntity* cls)
    {
        for (const auto& child : cls->children_)
        {
            if (child->kind_ == cppast::cpp_entity_kind::member_variable_t && child->access_ == cppast::cpp_protected)
            {
                // Getters and setters for protected class variables.
                const auto& var = child->Ast<cppast::cpp_member_variable>();
                const auto& type = var.type();

                // Avoid returning non-builtin complex types as by copy
                bool wouldReturnByCopy =
                    type.kind() != cppast::cpp_type_kind::pointer_t &&
                    type.kind() != cppast::cpp_type_kind::reference_t &&
                    type.kind() != cppast::cpp_type_kind::builtin_t;

                auto vars = fmt({
                    {"name", child->name_},
                    {"type", cppast::to_string(type)},
                    {"ref", wouldReturnByCopy ? "&" : ""}
                });

                printer_ << fmt("{{type}}{{ref}} __get_{{name}}() { return {{name}}; }", vars);
                printer_ << fmt("void __set_{{name}}({{type}} value) { {{name}} = value; }", vars);
            }
            else if (child->kind_ == cppast::cpp_entity_kind::member_function_t)
            {
                const auto& func = child->Ast<cppast::cpp_member_function>();

                auto methodId = func.name() + func.signature();
                if (std::find(wrappedList.begin(), wrappedList.end(), methodId) == wrappedList.end())
                {
                    wrappedList.emplace_back(methodId);
                    // Function pointer that virtual method will call
                    const auto& cls = child->parent_;
                    auto vars = fmt({
                        {"type",                cppast::to_string(func.return_type())},
                        {"name",                child->name_},
                        {"class_name",          entity->name_},
                        {"full_class_name",     entity->uniqueName_},
                        {"parameter_list",      ParameterList(func.parameters())},
                        {"parameter_name_list", ParameterNameList(func.parameters())},
                        {"return",              IsVoid(func.return_type()) ? "" : "return"},
                        {"const",               cppast::is_const(func.cv_qualifier()) ? "const " : ""},
                        {"has_params",          Count(func.parameters()) > 0},
                        {"symbol_name",         Sanitize(child->uniqueName_)}
                    });
                    if (func.is_virtual())
                    {
                        printer_ << fmt("{{type}}(*fn{{symbol_name}})({{class_name}} {{const}}*{{#has_params}}, {{/has_params}}{{parameter_list}}) = nullptr;", vars);
                        // Virtual method that calls said pointer
                        printer_ << fmt("{{type}} {{name}}({{parameter_list}}) {{const}}override", vars);
                        printer_.Indent();
                        {
                            printer_ << fmt("if (fn{{symbol_name}} == nullptr)", vars);
                            printer_.Indent();
                            {
                                printer_ << fmt("{{full_class_name}}::{{name}}({{parameter_name_list}});", vars);
                            }
                            printer_.Dedent();
                            printer_ << "else";
                            printer_.Indent();
                            {
                                printer_ << fmt("{{return}}(fn{{symbol_name}})(this{{#has_params}}, {{/has_params}}{{parameter_name_list}});", vars);
                            }
                            printer_.Dedent();

                        }
                        printer_.Dedent();
                    }
                    else if (child->access_ == cppast::cpp_protected) // Protected virtuals are not exposed, no point
                    {
                        printer_ << fmt("{{type}} __public_{{name}}({{parameter_list}})", vars);
                        printer_.Indent();
                        printer_ << fmt("{{name}}({{parameter_name_list}});", vars);
                        printer_.Dedent();
                    }
                }
            }
        }
    };

    std::function<void(MetaEntity*)> implementBaseWrapperClassMembers = [&](MetaEntity* cls)
    {
        const auto& astCls = cls->Ast<cppast::cpp_class>();
        for (const auto& base : astCls.bases())
        {
            if (base.access_specifier() == cppast::cpp_private)
                continue;

            auto* parentCls = GetEntity(base.type());
            if (parentCls != nullptr)
            {
                auto* baseOverlay = static_cast<MetaEntity*>(parentCls->user_data());
                implementWrapperClassMembers(baseOverlay);
                implementBaseWrapperClassMembers(baseOverlay);
            }
            else
                URHO3D_LOGWARNINGF("Base class %s not found!", base.name().c_str());
        }
    };

    implementWrapperClassMembers(entity);
    implementBaseWrapperClassMembers(entity);

    printer_.Dedent("};");
    printer_ << "";
    entity->sourceName_ = "Wrappers::" + entity->name_;    // Wrap a wrapper class
    return true;
}

void GenerateClassWrappers::Stop()
{
    printer_ << "}";    // namespace Wrappers

    File file(context_, GetSubsystem<GeneratorContext>()->outputDirCpp_ + "ClassWrappers.hpp", FILE_WRITE);
    if (!file.IsOpen())
    {
        URHO3D_LOGERROR("Failed saving ClassWrappers.hpp");
        return;
    }
    file.WriteLine(printer_.Get());
    file.Close();
}

}
<commit_msg>Convert GenerateClassWrappersPass to use fmt lib.<commit_after>//
// Copyright (c) 2008-2018 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include <fmt/format.h>
#include <Urho3D/IO/File.h>
#include <Urho3D/IO/Log.h>
#include "GenerateClassWrappers.h"
#include "GeneratorContext.h"

namespace Urho3D
{

void GenerateClassWrappers::Start()
{
    printer_ << "#pragma once";
    printer_ << "#include <Urho3D/Urho3DAll.h>";
    printer_ << "";
    printer_ << "namespace Wrappers";
    printer_ << "{";
}

bool GenerateClassWrappers::Visit(MetaEntity* entity, cppast::visitor_info info)
{
    if (entity->ast_ == nullptr)
        return true;

    if (entity->ast_->kind() != cppast::cpp_entity_kind::class_t)
        return true;

    // Visit only once
    if (info.event == info.container_entity_exit)
        return true;

    // Class is not supposed to be inherited
    if (generator->final_.Contains(entity->uniqueName_))
        return true;

    const auto& cls = entity->Ast<cppast::cpp_class>();
    if (!HasVirtual(cls) && !HasProtected(cls))
    {
        // Skip children for classes that do not have virtual or protected members
        return info.event != info.container_entity_enter;
    }

    printer_ << fmt::format("class URHO3D_EXPORT_API {} : public {}", entity->name_, entity->uniqueName_);
    printer_.Indent();

    // Urho3D-specific
    if (IsSubclassOf(cls, "Urho3D::Object"))
        printer_ << fmt::format("URHO3D_OBJECT({}, {});", entity->name_, entity->uniqueName_);

    printer_.WriteLine("public:", false);
    // Wrap constructors
    for (const auto& e : entity->children_)
    {
        if (e->kind_ == cppast::cpp_entity_kind::constructor_t)
        {
            const auto& ctor = e->Ast<cppast::cpp_constructor>();
            printer_ << fmt::format("{}({}) : {}({}) {{ }}", entity->name_, ParameterList(ctor.parameters()),
                entity->uniqueName_, ParameterNameList(ctor.parameters()));
        }
    }
    printer_ << fmt::format("virtual ~{}() = default;", entity->name_);

    std::vector<std::string> wrappedList;
    auto implementWrapperClassMembers = [&](const MetaEntity* cls)
    {
        for (const auto& child : cls->children_)
        {
            if (child->kind_ == cppast::cpp_entity_kind::member_variable_t && child->access_ == cppast::cpp_protected)
            {
                // Getters and setters for protected class variables.
                const auto& var = child->Ast<cppast::cpp_member_variable>();
                const auto& type = var.type();

                // Avoid returning non-builtin complex types as by copy
                bool wouldReturnByCopy =
                    type.kind() != cppast::cpp_type_kind::pointer_t &&
                    type.kind() != cppast::cpp_type_kind::reference_t &&
                    type.kind() != cppast::cpp_type_kind::builtin_t;

                auto name = child->name_;
                auto typeName = cppast::to_string(type);
                auto ref = wouldReturnByCopy ? "&" : "";

                printer_ << fmt::format("{typeName}{ref} __get_{name}() {{ return {name}; }}",
                    FMT_CAPTURE(name), FMT_CAPTURE(typeName), FMT_CAPTURE(ref));
                printer_ << fmt::format("void __set_{name}({typeName} value) {{ {name} = value; }}",
                    FMT_CAPTURE(name), FMT_CAPTURE(typeName), FMT_CAPTURE(ref));
            }
            else if (child->kind_ == cppast::cpp_entity_kind::member_function_t)
            {
                const auto& func = child->Ast<cppast::cpp_member_function>();

                auto methodId = func.name() + func.signature();
                if (std::find(wrappedList.begin(), wrappedList.end(), methodId) == wrappedList.end())
                {
                    wrappedList.emplace_back(methodId);
                    // Function pointer that virtual method will call
                    const auto& cls = child->parent_;
                    auto typeName = cppast::to_string(func.return_type());
                    auto name = child->name_;
                    auto parameterList = ParameterList(func.parameters());
                    auto parameterNameList = ParameterNameList(func.parameters());
                    auto constModifier = cppast::is_const(func.cv_qualifier()) ? "const " : "";
                    auto pc = Count(func.parameters()) > 0 ? ", " : "";
                    auto symbolName = Sanitize(child->uniqueName_);
                    auto fullClassName = entity->uniqueName_;
                    auto className = entity->name_;

                    if (func.is_virtual())
                    {
                        printer_ << fmt::format("{typeName}(*fn{symbolName})({className} {constModifier}*{pc}{parameterList}) = nullptr;",
                            FMT_CAPTURE(typeName), FMT_CAPTURE(symbolName), FMT_CAPTURE(className),
                            FMT_CAPTURE(constModifier), FMT_CAPTURE(pc), FMT_CAPTURE(parameterList));
                        // Virtual method that calls said pointer
                        printer_ << fmt::format("{typeName} {name}({parameterList}) {constModifier}override",
                            FMT_CAPTURE(typeName), FMT_CAPTURE(name), FMT_CAPTURE(parameterList),
                            FMT_CAPTURE(constModifier));
                        printer_.Indent();
                        {
                            printer_ << fmt::format("if (fn{symbolName} == nullptr)", FMT_CAPTURE(symbolName));
                            printer_.Indent();
                            {
                                printer_ << fmt::format("{fullClassName}::{name}({parameterNameList});",
                                    FMT_CAPTURE(fullClassName), FMT_CAPTURE(name), FMT_CAPTURE(parameterNameList));
                            }
                            printer_.Dedent();
                            printer_ << "else";
                            printer_.Indent();
                            {
                                printer_ << (IsVoid(func.return_type()) ? "" : "return ") +
                                    fmt::format("(fn{symbolName})(this{pc}{parameterNameList});",
                                        FMT_CAPTURE(symbolName), FMT_CAPTURE(pc), FMT_CAPTURE(parameterNameList));
                            }
                            printer_.Dedent();

                        }
                        printer_.Dedent();
                    }
                    else if (child->access_ == cppast::cpp_protected) // Protected virtuals are not exposed, no point
                    {
                        printer_ << fmt::format("{typeName} __public_{name}({parameterList})",
                            FMT_CAPTURE(typeName), FMT_CAPTURE(name), FMT_CAPTURE(parameterList));
                        printer_.Indent();
                        printer_ << fmt::format("{name}({parameterNameList});", FMT_CAPTURE(name),
                            FMT_CAPTURE(parameterNameList));
                        printer_.Dedent();
                    }
                }
            }
        }
    };

    std::function<void(MetaEntity*)> implementBaseWrapperClassMembers = [&](MetaEntity* cls)
    {
        const auto& astCls = cls->Ast<cppast::cpp_class>();
        for (const auto& base : astCls.bases())
        {
            if (base.access_specifier() == cppast::cpp_private)
                continue;

            auto* parentCls = GetEntity(base.type());
            if (parentCls != nullptr)
            {
                auto* baseOverlay = static_cast<MetaEntity*>(parentCls->user_data());
                implementWrapperClassMembers(baseOverlay);
                implementBaseWrapperClassMembers(baseOverlay);
            }
            else
                URHO3D_LOGWARNINGF("Base class %s not found!", base.name().c_str());
        }
    };

    implementWrapperClassMembers(entity);
    implementBaseWrapperClassMembers(entity);

    printer_.Dedent("};");
    printer_ << "";
    entity->sourceName_ = "Wrappers::" + entity->name_;    // Wrap a wrapper class
    return true;
}

void GenerateClassWrappers::Stop()
{
    printer_ << "}";    // namespace Wrappers

    File file(context_, GetSubsystem<GeneratorContext>()->outputDirCpp_ + "ClassWrappers.hpp", FILE_WRITE);
    if (!file.IsOpen())
    {
        URHO3D_LOGERROR("Failed saving ClassWrappers.hpp");
        return;
    }
    file.WriteLine(printer_.Get());
    file.Close();
}

}
<|endoftext|>