<commit_before>/*!
 * \file mpi_structure.hpp
 * \brief Headers of the mpi interface for generalized datatypes.
 *        The subroutines and functions are in the mpi_structure.cpp file.
 * \author T. Albring
 * \version 5.0.0 "Raven"
 *
 * SU2 Original Developers: Dr. Francisco D. Palacios.
 *                          Dr. Thomas D. Economon.
 *
 * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University.
 *                 Prof. Piero Colonna's group at Delft University of Technology.
 *                 Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology.
 *                 Prof. Alberto Guardone's group at Polytechnic University of Milan.
 *                 Prof. Rafael Palacios' group at Imperial College London.
 *                 Prof. Edwin van der Weide's group at the University of Twente.
 *                 Prof. Vincent Terrapon's group at the University of Liege.
 *
 * Copyright (C) 2012-2017 SU2, the open-source CFD code.
 *
 * SU2 is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * SU2 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#ifdef HAVE_MPI
#include "mpi.h"
#include <map>
#endif

#include "./datatype_structure.hpp"

#ifdef HAVE_MPI

/*--- Depending on the datatype used, the correct MPI wrapper class is defined.
 * For the default (double type) case this results in using the normal MPI routines. ---*/
#if defined CODI_REVERSE_TYPE || defined CODI_FORWARD_TYPE

#include <medi/medi.hpp>
using namespace medi;

class CMediMPIWrapper;
typedef CMediMPIWrapper SU2_MPI;

#if defined CODI_REVERSE_TYPE
#include <medi/codiMediPackTypes.hpp>
#if CODI_PRIMAL_INDEX_TAPE
typedef CoDiPackToolPrimalRestore<su2double> MediTool;
#else
typedef CoDiPackTool<su2double> MediTool;
#endif // defined CODI_REVERSE_TYPE
#elif defined CODI_FORWARD_TYPE
#include <medi/codiForwardMediPackTypes.hpp>
typedef CoDiPackForwardTool<su2double> MediTool;
#endif // defined CODI_FORWARD_TYPE

typedef medi::MpiTypeDefault<MediTool> AMPI_ADOUBLE_TYPE;
extern AMPI_ADOUBLE_TYPE* AMPI_ADOUBLE;

#else
class CMPIWrapper;
typedef CMPIWrapper SU2_MPI;
#endif // defined CODI_REVERSE_TYPE || defined CODI_FORWARD_TYPE

/*!
 * \class CMPIWrapper
 * \brief Class for defining the MPI wrapper routines; this class features as a base class for
 * MPI interfaces for non-primitive dataypes e.g. used by AD, complex etc.
 * \author T. Albring
 * \version 5.0.0 "Raven"
 */

class CMPIWrapper {

public:

  typedef MPI_Comm Comm;

#if defined CODI_REVERSE_TYPE || defined CODI_FORWARD_TYPE
  typedef AMPI_Request Request;
#else
  typedef MPI_Request Request;
#endif

  static void Init(int *argc, char***argv);

  static inline MPI_Request* convertRequest(Request* request);

  static void Get_count(MPI_Status *status, MPI_Datatype datatype, int *count);

  static void Isend(void *buf, int count, MPI_Datatype datatype, int dest,
                    int tag, MPI_Comm comm, Request* request);

  static void Irecv(void *buf, int count, MPI_Datatype datatype, int source,
                    int tag, MPI_Comm comm, Request* request);

  static void Wait(Request *request, MPI_Status *status);

  static void Waitall(int nrequests, Request *request, MPI_Status *status);

  static void Waitany(int nrequests, Request *request,
                      int *index, MPI_Status *status);

  static void Send(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm);

  static void Recv(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm, MPI_Status *status);

  static void Bcast(void *buf, int count, MPI_Datatype datatype, int root,
                    MPI_Comm comm);

  static void Bsend(void *buf, int count, MPI_Datatype datatype, int dest,
                    int tag, MPI_Comm comm);

  static void Reduce(void *sendbuf, void *recvbuf, int count,
                     MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm);

  static void Allreduce(void *sendbuf, void *recvbuf, int count,
                        MPI_Datatype datatype, MPI_Op op, MPI_Comm comm);

  static void Gather(void *sendbuf, int sendcnt,MPI_Datatype sendtype,
                     void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);

  static void Scatter(void *sendbuf, int sendcnt,MPI_Datatype sendtype,
                      void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);

  static void Allgather(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
                        void *recvbuf, int recvcnt, MPI_Datatype recvtype, MPI_Comm comm);

  static void Sendrecv(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
                       int dest, int sendtag, void *recvbuf, int recvcnt,
                       MPI_Datatype recvtype,int source, int recvtag,
                       MPI_Comm comm, MPI_Status *status);
};

#if defined CODI_REVERSE_TYPE || defined CODI_FORWARD_TYPE

/*!
 * \class CMediMPIWrapper
 * \brief MPI wrapper functions for MediPack tool.
 * \author T. Albring
 * \version 5.0.0 "Raven"
 */

class CMediMPIWrapper: public CMPIWrapper {
public:
  static void Init(int *argc, char***argv);

  static AMPI_Comm convertComm(MPI_Comm comm);

  static AMPI_Status* convertStatus(MPI_Status* status);

  static AMPI_Op convertOp(MPI_Op op);

  static void Get_count(MPI_Status *status, MPI_Datatype datatype, int *count);

  static void Isend(void *buf, int count, MPI_Datatype datatype, int dest,
                    int tag, MPI_Comm comm, Request* request);

  static void Irecv(void *buf, int count, MPI_Datatype datatype, int source,
                    int tag, MPI_Comm comm, Request* request);

  static void Wait(SU2_MPI::Request *request, MPI_Status *status);

  static void Waitall(int nrequests, Request *request, MPI_Status *status);

  static void Waitany(int nrequests, SU2_MPI::Request *request,
                      int *index, MPI_Status *status);

  static void Send(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm);

  static void Recv(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm, MPI_Status *status);

  static void Bcast(void *buf, int count, MPI_Datatype datatype, int root,
                    MPI_Comm comm);

  static void Bsend(void *buf, int count, MPI_Datatype datatype, int dest,
                    int tag, MPI_Comm comm);

  static void Reduce(void *sendbuf, void *recvbuf, int count,
                     MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm);

  static void Allreduce(void *sendbuf, void *recvbuf, int count,
                        MPI_Datatype datatype, MPI_Op op, MPI_Comm comm);

  static void Gather(void *sendbuf, int sendcnt,MPI_Datatype sendtype,
                     void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);

  static void Scatter(void *sendbuf, int sendcnt,MPI_Datatype sendtype,
                      void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);

  static void Allgather(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
                        void *recvbuf, int recvcnt, MPI_Datatype recvtype, MPI_Comm comm);

  static void Sendrecv(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
                       int dest, int sendtag, void *recvbuf, int recvcnt,
                       MPI_Datatype recvtype,int source, int recvtag,
                       MPI_Comm comm, MPI_Status *status);

};
#endif

#else //HAVE_MPI
typedef unsigned short SU2_Comm;
#endif
#include "mpi_structure.inl"
<commit_msg>Added dummy wrapper if no MPI is used<commit_after>/*!
 * \file mpi_structure.hpp
 * \brief Headers of the mpi interface for generalized datatypes.
 *        The subroutines and functions are in the mpi_structure.cpp file.
 * \author T. Albring
 * \version 5.0.0 "Raven"
 *
 * SU2 Original Developers: Dr. Francisco D. Palacios.
 *                          Dr. Thomas D. Economon.
 *
 * SU2 Developers: Prof. Juan J. Alonso's group at Stanford University.
 *                 Prof. Piero Colonna's group at Delft University of Technology.
 *                 Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology.
 *                 Prof. Alberto Guardone's group at Polytechnic University of Milan.
 *                 Prof. Rafael Palacios' group at Imperial College London.
 *                 Prof. Edwin van der Weide's group at the University of Twente.
 *                 Prof. Vincent Terrapon's group at the University of Liege.
 *
 * Copyright (C) 2012-2017 SU2, the open-source CFD code.
 *
 * SU2 is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * SU2 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#ifdef HAVE_MPI
#include "mpi.h"
#include <map>
#endif

#include "./datatype_structure.hpp"

#ifdef HAVE_MPI

/*--- Depending on the datatype used, the correct MPI wrapper class is defined.
 * For the default (double type) case this results in using the normal MPI routines. ---*/
#if defined CODI_REVERSE_TYPE || defined CODI_FORWARD_TYPE

#include <medi/medi.hpp>
using namespace medi;

class CMediMPIWrapper;
typedef CMediMPIWrapper SU2_MPI;

#if defined CODI_REVERSE_TYPE
#include <medi/codiMediPackTypes.hpp>
#if CODI_PRIMAL_INDEX_TAPE
typedef CoDiPackToolPrimalRestore<su2double> MediTool;
#else
typedef CoDiPackTool<su2double> MediTool;
#endif // defined CODI_REVERSE_TYPE
#elif defined CODI_FORWARD_TYPE
#include <medi/codiForwardMediPackTypes.hpp>
typedef CoDiPackForwardTool<su2double> MediTool;
#endif // defined CODI_FORWARD_TYPE

typedef medi::MpiTypeDefault<MediTool> AMPI_ADOUBLE_TYPE;
extern AMPI_ADOUBLE_TYPE* AMPI_ADOUBLE;

#else
class CMPIWrapper;
typedef CMPIWrapper SU2_MPI;
#endif // defined CODI_REVERSE_TYPE || defined CODI_FORWARD_TYPE

/*!
 * \class CMPIWrapper
 * \brief Class for defining the MPI wrapper routines; this class features as a base class for
 * MPI interfaces for non-primitive dataypes e.g. used by AD, complex etc.
 * \author T. Albring
 * \version 5.0.0 "Raven"
 */

class CMPIWrapper {

public:

  typedef MPI_Comm Comm;

#if defined CODI_REVERSE_TYPE || defined CODI_FORWARD_TYPE
  typedef AMPI_Request Request;
#else
  typedef MPI_Request Request;
#endif

  static void Init(int *argc, char***argv);

  static inline MPI_Request* convertRequest(Request* request);

  static void Get_count(MPI_Status *status, MPI_Datatype datatype, int *count);

  static void Isend(void *buf, int count, MPI_Datatype datatype, int dest,
                    int tag, MPI_Comm comm, Request* request);

  static void Irecv(void *buf, int count, MPI_Datatype datatype, int source,
                    int tag, MPI_Comm comm, Request* request);

  static void Wait(Request *request, MPI_Status *status);

  static void Waitall(int nrequests, Request *request, MPI_Status *status);

  static void Waitany(int nrequests, Request *request,
                      int *index, MPI_Status *status);

  static void Send(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm);

  static void Recv(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm, MPI_Status *status);

  static void Bcast(void *buf, int count, MPI_Datatype datatype, int root,
                    MPI_Comm comm);

  static void Bsend(void *buf, int count, MPI_Datatype datatype, int dest,
                    int tag, MPI_Comm comm);

  static void Reduce(void *sendbuf, void *recvbuf, int count,
                     MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm);

  static void Allreduce(void *sendbuf, void *recvbuf, int count,
                        MPI_Datatype datatype, MPI_Op op, MPI_Comm comm);

  static void Gather(void *sendbuf, int sendcnt,MPI_Datatype sendtype,
                     void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);

  static void Scatter(void *sendbuf, int sendcnt,MPI_Datatype sendtype,
                      void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);

  static void Allgather(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
                        void *recvbuf, int recvcnt, MPI_Datatype recvtype, MPI_Comm comm);

  static void Sendrecv(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
                       int dest, int sendtag, void *recvbuf, int recvcnt,
                       MPI_Datatype recvtype,int source, int recvtag,
                       MPI_Comm comm, MPI_Status *status);
};

#if defined CODI_REVERSE_TYPE || defined CODI_FORWARD_TYPE

/*!
 * \class CMediMPIWrapper
 * \brief MPI wrapper functions for MediPack tool.
 * \author T. Albring
 * \version 5.0.0 "Raven"
 */

class CMediMPIWrapper: public CMPIWrapper {
public:
  static void Init(int *argc, char***argv);

  static AMPI_Comm convertComm(MPI_Comm comm);

  static AMPI_Status* convertStatus(MPI_Status* status);

  static AMPI_Op convertOp(MPI_Op op);

  static void Get_count(MPI_Status *status, MPI_Datatype datatype, int *count);

  static void Isend(void *buf, int count, MPI_Datatype datatype, int dest,
                    int tag, MPI_Comm comm, Request* request);

  static void Irecv(void *buf, int count, MPI_Datatype datatype, int source,
                    int tag, MPI_Comm comm, Request* request);

  static void Wait(SU2_MPI::Request *request, MPI_Status *status);

  static void Waitall(int nrequests, Request *request, MPI_Status *status);

  static void Waitany(int nrequests, SU2_MPI::Request *request,
                      int *index, MPI_Status *status);

  static void Send(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm);

  static void Recv(void *buf, int count, MPI_Datatype datatype, int dest,
                   int tag, MPI_Comm comm, MPI_Status *status);

  static void Bcast(void *buf, int count, MPI_Datatype datatype, int root,
                    MPI_Comm comm);

  static void Bsend(void *buf, int count, MPI_Datatype datatype, int dest,
                    int tag, MPI_Comm comm);

  static void Reduce(void *sendbuf, void *recvbuf, int count,
                     MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm);

  static void Allreduce(void *sendbuf, void *recvbuf, int count,
                        MPI_Datatype datatype, MPI_Op op, MPI_Comm comm);

  static void Gather(void *sendbuf, int sendcnt,MPI_Datatype sendtype,
                     void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);

  static void Scatter(void *sendbuf, int sendcnt,MPI_Datatype sendtype,
                      void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root, MPI_Comm comm);

  static void Allgather(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
                        void *recvbuf, int recvcnt, MPI_Datatype recvtype, MPI_Comm comm);

  static void Sendrecv(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
                       int dest, int sendtag, void *recvbuf, int recvcnt,
                       MPI_Datatype recvtype,int source, int recvtag,
                       MPI_Comm comm, MPI_Status *status);

};
#endif

#else //HAVE_MPI
class CMPIWrapper {

public:
  typedef double Comm;

};
typedef CMPIWrapper SU2_MPI;

#endif
#include "mpi_structure.inl"
<|endoftext|>


<commit_before>#include "snapshot.h"
#include "particle.h"
#include <iostream>
#include <cmath>
#include <random>
using namespace std;

int main()
{
  // Number, Mass, and Rs user input
  unsigned number;
  cout << "Please input a positive integer number of bodies.\n";
  cin >> number;
  const double mass_tot=1;
  const double radius_scale=1;
  const double G = 1;
  const double velocity_scale = sqrt(G*mass_tot/radius_scale);
  const double m = mass_tot/number;

  // //Random number generator
  random_device rd;
  mt19937 gen(rd());
  uniform_real_distribution<double> dis(0,1);
  // Position Calculations
  // R^2/3, where R = M(<r)
  const double pi = atan(1)*4; // Pi Defined
   yaNC::Snapshot snap(number);
   for(auto& part:snap) //For each particle calculate Position and Velocity
   {
     part.mass=m;

     // Radius Calculation
     double R = pow(dis(gen), 0.66666666666666666666666666666666666666666667);
     double x = sqrt(R/(1-R));
     double radius = radius_scale * x;

     // Position
     double pphi = 2*pi*dis(gen); // Random Uniform Phi [0,2pi]
     double pcostheta =2*dis(gen)-1; // Random Uniform Cos(theta)[-1,1]
     double psintheta = sqrt(1-pcostheta*pcostheta);
     part.pos={radius*psintheta*cos(pphi),//Spherical to Cartesian X
		  radius*psintheta*sin(pphi),//Spherical to Cartesian Y
		  radius*pcostheta };        //Spherical to Cartesian Z

     // Escape Velocity Calculation
     double psi = 1/sqrt(x*x+1);
     double vescsq = psi+psi;
     double vesc = sqrt(vescsq);

     double f0 = pow(vesc,7);
     double vel, f;
     do{
       vel = cbrt(dis(gen))*vesc;
       f  = pow(vescsq-vel*vel, 3.5);
     } while ( dis(gen)*f0>f );
     // Velocity
     vel *= velocity_scale;
     double vphi = 2*pi*dis(gen);
     double vcostheta = 2*dis(gen)-1;
     double vsintheta = sqrt(1-vcostheta*vcostheta);
     part.vel={vel*vsintheta*cos(vphi),//Spherical to Cartesian X
		  vel*vsintheta*sin(vphi),//Spherical to Cartesian Y
		  vel*vcostheta };        //Spherical to Cartesian Z

   }
   // Name output file
   string filename;
   cout << "Please name the output file \n";
   cin >> filename;
   // Print to file
   std::ofstream out (filename);
   snap.write(out);
   out.close();
}
<commit_msg>Joels changes<commit_after>#include "snapshot.h"
#include "particle.h"
#include <iostream>
#include <cmath>
#include <random>
using namespace std;

int main()
{
  // Number, Mass, and Rs user input
  unsigned number;
  cout << "Please input a positive integer number of bodies.\n";
  cin >> number;
  unsigned nosys;
  cout << "Please input either 1 or 2 for the number of systems\n";
  cin >> nosys;
  if(nosys >2 && nosys <1)
    {
      cout << "Invalid, please input 1 or 2\n";
      return 2;
    }
  double opx,opy,opz,ovx,ovy,ovz;
  if(nosys==2)
    {
  cout << "Please input the x,y,z offset of the second system\n";
  cin >> opx >> opy >> opz;
  cout << "Please input the x,y,z velocity of the second system\n";
  cin >> ovx >> ovy >> ovz;
    }
  const double mass_tot=1;
  const double radius_scale=1;
  const double G = 1;
  const double velocity_scale = sqrt(G*mass_tot/radius_scale);
  const double m = mass_tot/number;
  // //Random number generator
  random_device rd;
  mt19937 gen(rd());
  uniform_real_distribution<double> dis(0,1);
  // Position Calculations
  // R^2/3, where R = M(<r)
  const double pi = atan(1)*4; // Pi Defined
   yaNC::Snapshot snap(number);
   unsigned count=0;

   for(auto& part:snap) //For each particle calculate Position and Velocity
   {
     part.mass=m;

     // Radius Calculation
     double R = pow(dis(gen), 0.66666666666666666666666666666666666666666667);
     double x = sqrt(R/(1-R));
     double radius = radius_scale * x;

     // Position
     double pphi = 2*pi*dis(gen); // Random Uniform Phi [0,2pi]
     double pcostheta =2*dis(gen)-1; // Random Uniform Cos(theta)[-1,1]
     double psintheta = sqrt(1-pcostheta*pcostheta);
     part.pos={radius*psintheta*cos(pphi),//Spherical to Cartesian X
		  radius*psintheta*sin(pphi),//Spherical to Cartesian Y
		  radius*pcostheta };        //Spherical to Cartesian Z

     // Escape Velocity Calculation
     double psi = 1/sqrt(x*x+1);
     double vescsq = psi+psi;
     double vesc = sqrt(vescsq);

     double f0 = pow(vesc,7);
     double vel, f;
     do{
       vel = cbrt(dis(gen))*vesc;
       f  = pow(vescsq-vel*vel, 3.5);
     } while ( dis(gen)*f0>f );
     // Velocity
     vel *= velocity_scale;
     double vphi = 2*pi*dis(gen);
     double vcostheta = 2*dis(gen)-1;
     double vsintheta = sqrt(1-vcostheta*vcostheta);
     part.vel={vel*vsintheta*cos(vphi),//Spherical to Cartesian X
		  vel*vsintheta*sin(vphi),//Spherical to Cartesian Y
		  vel*vcostheta };        //Spherical to Cartesian Z
     if(nosys==2 && count>((number/2)-1)){

       part.pos[0] += opx;
       part.pos[1] += opy;
       part.pos[2] += opz;
       part.vel[0] += ovx;
       part.vel[1] += ovy;
       part.vel[2] += ovz;
     }
     ++count;

   }
   // Name output file
   string filename;
   cout << "Please name the output file \n";
   cin >> filename;
   // Print to file
   std::ofstream out (filename);
   snap.write(out);
   out.close();
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

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 "OgreStableHeaders.h"
#include "OgreInstanceBatchShader.h"
#include "OgreSubMesh.h"
#include "OgreRenderOperation.h"
#include "OgreHardwareBufferManager.h"
#include "OgreInstancedEntity.h"
#include "OgreMaterial.h"
#include "OgreTechnique.h"

namespace Ogre
{
	InstanceBatchShader::InstanceBatchShader( InstanceManager *creator, MeshPtr &meshReference,
										const MaterialPtr &material, size_t instancesPerBatch,
										const Mesh::IndexMap *indexToBoneMap, const String &batchName ) :
				InstanceBatch( creator, meshReference, material, instancesPerBatch,
								indexToBoneMap, batchName ),
				mNumWorldMatrices( instancesPerBatch )
	{
	}

	InstanceBatchShader::~InstanceBatchShader()
	{
	}

	//-----------------------------------------------------------------------
	size_t InstanceBatchShader::calculateMaxNumInstances( const SubMesh *baseSubMesh, uint16 flags ) const
	{
		const size_t numBones = std::max<size_t>( 1, baseSubMesh->blendIndexToBoneIndexMap.size() );

		mMaterial->load();
		Technique *technique = mMaterial->getBestTechnique();
		if( technique )
		{
			GpuProgramParametersSharedPtr vertexParam = technique->getPass(0)->getVertexProgramParameters();
			GpuConstantDefinitionIterator itor = vertexParam->getConstantDefinitionIterator();
			while( itor.hasMoreElements() )
			{
				const GpuConstantDefinition &constDef = itor.getNext();
				if( constDef.constType == GCT_MATRIX_3X4 ||
					constDef.constType == GCT_MATRIX_4X3 ||		//OGL GLSL bitches without this
					constDef.constType == GCT_MATRIX_2X4 ||
					constDef.constType == GCT_FLOAT4			//OGL GLSL bitches without this
					&& constDef.isFloat() )
				{
					const GpuProgramParameters::AutoConstantEntry *entry =
									vertexParam->_findRawAutoConstantEntryFloat( constDef.physicalIndex );
					if( entry && (entry->paramType == GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY_3x4 || entry->paramType == GpuProgramParameters::ACT_WORLD_DUALQUATERNION_ARRAY_2x4))
					{
						//Material is correctly done!
						size_t arraySize = constDef.arraySize;

						//Deal with GL "hacky" way of doing 4x3 matrices
						if( constDef.constType == GCT_FLOAT4 )
							arraySize /= 3;

						//Check the num of arrays
						size_t retVal = arraySize / numBones;

						if( flags & IM_USE16BIT )
						{
							if( baseSubMesh->vertexData->vertexCount * retVal > 0xFFFF )
								retVal = 0xFFFF / baseSubMesh->vertexData->vertexCount;
						}

						if( retVal < 3 )
						{
							LogManager::getSingleton().logMessage( "InstanceBatchShader: Mesh " +
										mMeshReference->getName() + " using material " +
										mMaterial->getName() + " contains many bones. The amount of "
										"instances per batch is very low. Performance benefits will "
										"be minimal, if any. It might be even slower!",
										LML_NORMAL );
						}

						return retVal;
					}
				}
			}

			//Reaching here means material is supported, but malformed
			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS,
			"Material '" + mMaterial->getName() + "' is malformed for this instancing technique",
			"InstanceBatchShader::calculateMaxNumInstances");
		}

		//Reaching here the material is just unsupported.

		return 0;
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::buildFrom( const SubMesh *baseSubMesh, const RenderOperation &renderOperation )
	{
		if( mMeshReference->hasSkeleton() && !mMeshReference->getSkeleton().isNull() )
			mNumWorldMatrices = mInstancesPerBatch * baseSubMesh->blendIndexToBoneIndexMap.size();
		InstanceBatch::buildFrom( baseSubMesh, renderOperation );
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupVertices( const SubMesh* baseSubMesh )
	{
		mRenderOperation.vertexData = OGRE_NEW VertexData();

		VertexData *thisVertexData = mRenderOperation.vertexData;
		VertexData *baseVertexData = baseSubMesh->vertexData;

		thisVertexData->vertexStart = 0;
		thisVertexData->vertexCount = baseVertexData->vertexCount * mInstancesPerBatch;

		HardwareBufferManager::getSingleton().destroyVertexDeclaration( thisVertexData->vertexDeclaration );
		thisVertexData->vertexDeclaration = baseVertexData->vertexDeclaration->clone();

		if( mMeshReference->hasSkeleton() && !mMeshReference->getSkeleton().isNull() )
		{
			//Building hw skinned batches follow a different path
			setupHardwareSkinned( baseSubMesh, thisVertexData, baseVertexData );
			return;
		}

		//TODO: Can't we, instead of using another source, put the index ID in the same source?
		thisVertexData->vertexDeclaration->addElement(
										thisVertexData->vertexDeclaration->getMaxSource() + 1, 0,
										VET_UBYTE4, VES_BLEND_INDICES );

		for( size_t i=0; i<thisVertexData->vertexDeclaration->getMaxSource(); ++i )
		{
			//Create our own vertex buffer
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize(i),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( i, vertexBuffer );

			//Grab the base submesh data
			HardwareVertexBufferSharedPtr baseVertexBuffer =
													baseVertexData->vertexBufferBinding->getBuffer(i);

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			char* baseBuf = static_cast<char*>(baseVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));

			//Copy and repeat
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				const size_t sizeOfBuffer = baseVertexData->vertexCount *
											baseVertexData->vertexDeclaration->getVertexSize(i);
				memcpy( thisBuf + j * sizeOfBuffer, baseBuf, sizeOfBuffer );
			}

			baseVertexBuffer->unlock();
			vertexBuffer->unlock();
		}

		{
			//Now create the vertices "index ID" to individualize each instance
			const unsigned short lastSource = thisVertexData->vertexDeclaration->getMaxSource();
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize( lastSource ),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( lastSource, vertexBuffer );

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				for( size_t k=0; k<baseVertexData->vertexCount; ++k )
				{
					*thisBuf++ = j;
					*thisBuf++ = j;
					*thisBuf++ = j;
					*thisBuf++ = j;
				}
			}

			vertexBuffer->unlock();
		}
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupIndices( const SubMesh* baseSubMesh )
	{
		mRenderOperation.indexData = OGRE_NEW IndexData();

		IndexData *thisIndexData = mRenderOperation.indexData;
		IndexData *baseIndexData = baseSubMesh->indexData;

		thisIndexData->indexStart = 0;
		thisIndexData->indexCount = baseIndexData->indexCount * mInstancesPerBatch;

		//TODO: Check numVertices is below max supported by GPU
		HardwareIndexBuffer::IndexType indexType = HardwareIndexBuffer::IT_16BIT;
		if( mRenderOperation.vertexData->vertexCount > 65535 )
			indexType = HardwareIndexBuffer::IT_32BIT;
		thisIndexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
													indexType, thisIndexData->indexCount,
													HardwareBuffer::HBU_STATIC_WRITE_ONLY );

		void *buf			= thisIndexData->indexBuffer->lock( HardwareBuffer::HBL_DISCARD );
		void const *baseBuf	= baseIndexData->indexBuffer->lock( HardwareBuffer::HBL_READ_ONLY );

		uint16 *thisBuf16 = static_cast<uint16*>(buf);
		uint32 *thisBuf32 = static_cast<uint32*>(buf);

		for( size_t i=0; i<mInstancesPerBatch; ++i )
		{
			const size_t vertexOffset = i * mRenderOperation.vertexData->vertexCount / mInstancesPerBatch;

			uint16 const *initBuf16 = static_cast<uint16 const *>(baseBuf);
			uint32 const *initBuf32 = static_cast<uint32 const *>(baseBuf);

			for( size_t j=0; j<baseIndexData->indexCount; ++j )
			{
				uint32 originalVal;
				if( baseSubMesh->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT )
					originalVal = *initBuf16++;
				else
					originalVal = *initBuf32++;

				if( indexType == HardwareIndexBuffer::IT_16BIT )
					*thisBuf16++ = static_cast<uint16>(originalVal) + vertexOffset;
				else
					*thisBuf32++ = originalVal + vertexOffset;
			}
		}

		baseIndexData->indexBuffer->unlock();
		thisIndexData->indexBuffer->unlock();
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupHardwareSkinned( const SubMesh* baseSubMesh, VertexData *thisVertexData,
													VertexData *baseVertexData )
	{
		const size_t numBones = baseSubMesh->blendIndexToBoneIndexMap.size();
		mNumWorldMatrices = mInstancesPerBatch * numBones;

		for( size_t i=0; i<=thisVertexData->vertexDeclaration->getMaxSource(); ++i )
		{
			//Create our own vertex buffer
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize(i),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( i, vertexBuffer );

			VertexDeclaration::VertexElementList veList =
											thisVertexData->vertexDeclaration->findElementsBySource(i);

			//Grab the base submesh data
			HardwareVertexBufferSharedPtr baseVertexBuffer =
													baseVertexData->vertexBufferBinding->getBuffer(i);

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			char* baseBuf = static_cast<char*>(baseVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
			char *startBuf = baseBuf;

			//Copy and repeat
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				//Repeat source
				baseBuf = startBuf;

				for( size_t k=0; k<baseVertexData->vertexCount; ++k )
				{
					VertexDeclaration::VertexElementList::const_iterator it = veList.begin();
					VertexDeclaration::VertexElementList::const_iterator en = veList.end();

					while( it != en )
					{
						switch( it->getSemantic() )
						{
						case VES_BLEND_INDICES:
						*(thisBuf + it->getOffset() + 0) = *(baseBuf + it->getOffset() + 0) + j * numBones;
						*(thisBuf + it->getOffset() + 1) = *(baseBuf + it->getOffset() + 1) + j * numBones;
						*(thisBuf + it->getOffset() + 2) = *(baseBuf + it->getOffset() + 2) + j * numBones;
						*(thisBuf + it->getOffset() + 3) = *(baseBuf + it->getOffset() + 3) + j * numBones;
							break;
						default:
							memcpy( thisBuf + it->getOffset(), baseBuf + it->getOffset(), it->getSize() );
							break;
						}
						++it;
					}
					thisBuf += baseVertexData->vertexDeclaration->getVertexSize(i);
					baseBuf += baseVertexData->vertexDeclaration->getVertexSize(i);
				}
			}

			baseVertexBuffer->unlock();
			vertexBuffer->unlock();
		}
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::getWorldTransforms( Matrix4* xform ) const
	{
		InstancedEntityVec::const_iterator itor = mInstancedEntities.begin();
		InstancedEntityVec::const_iterator end  = mInstancedEntities.end();

		while( itor != end )
		{
			xform += (*itor)->getTransforms( xform );
			++itor;
		}
	}
	//-----------------------------------------------------------------------
	unsigned short InstanceBatchShader::getNumWorldTransforms(void) const
	{
		return mNumWorldMatrices;
	}
}
<commit_msg>Improved handling of dual quaternions in InstanceBatchShader (no longer generates in-accurate error messages).<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd

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 "OgreStableHeaders.h"
#include "OgreInstanceBatchShader.h"
#include "OgreSubMesh.h"
#include "OgreRenderOperation.h"
#include "OgreHardwareBufferManager.h"
#include "OgreInstancedEntity.h"
#include "OgreMaterial.h"
#include "OgreTechnique.h"

namespace Ogre
{
	InstanceBatchShader::InstanceBatchShader( InstanceManager *creator, MeshPtr &meshReference,
										const MaterialPtr &material, size_t instancesPerBatch,
										const Mesh::IndexMap *indexToBoneMap, const String &batchName ) :
				InstanceBatch( creator, meshReference, material, instancesPerBatch,
								indexToBoneMap, batchName ),
				mNumWorldMatrices( instancesPerBatch )
	{
	}

	InstanceBatchShader::~InstanceBatchShader()
	{
	}

	//-----------------------------------------------------------------------
	size_t InstanceBatchShader::calculateMaxNumInstances( const SubMesh *baseSubMesh, uint16 flags ) const
	{
		const size_t numBones = std::max<size_t>( 1, baseSubMesh->blendIndexToBoneIndexMap.size() );

		mMaterial->load();
		Technique *technique = mMaterial->getBestTechnique();
		if( technique )
		{
			GpuProgramParametersSharedPtr vertexParam = technique->getPass(0)->getVertexProgramParameters();
			GpuConstantDefinitionIterator itor = vertexParam->getConstantDefinitionIterator();
			while( itor.hasMoreElements() )
			{
				const GpuConstantDefinition &constDef = itor.getNext();
				if( constDef.constType == GCT_MATRIX_3X4 ||
					constDef.constType == GCT_MATRIX_4X3 ||		//OGL GLSL bitches without this
					constDef.constType == GCT_MATRIX_2X4 ||
					constDef.constType == GCT_FLOAT4			//OGL GLSL bitches without this
					&& constDef.isFloat() )
				{
					const GpuProgramParameters::AutoConstantEntry *entry =
									vertexParam->_findRawAutoConstantEntryFloat( constDef.physicalIndex );
					if( entry && (entry->paramType == GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY_3x4 || entry->paramType == GpuProgramParameters::ACT_WORLD_DUALQUATERNION_ARRAY_2x4))
					{
						//Material is correctly done!
						size_t arraySize = constDef.arraySize;

						//Deal with GL "hacky" way of doing 4x3 matrices
						if(entry->paramType == GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY_3x4 && constDef.constType == GCT_FLOAT4)
							arraySize /= 3;
						else if(entry->paramType == GpuProgramParameters::ACT_WORLD_DUALQUATERNION_ARRAY_2x4 && constDef.constType == GCT_FLOAT4)
							arraySize /= 2;

						//Check the num of arrays
						size_t retVal = arraySize / numBones;

						if( flags & IM_USE16BIT )
						{
							if( baseSubMesh->vertexData->vertexCount * retVal > 0xFFFF )
								retVal = 0xFFFF / baseSubMesh->vertexData->vertexCount;
						}

						if((retVal < 3 && entry->paramType == GpuProgramParameters::ACT_WORLD_MATRIX_ARRAY_3x4) ||
							(retVal < 2 && entry->paramType == GpuProgramParameters::ACT_WORLD_DUALQUATERNION_ARRAY_2x4))
						{
							LogManager::getSingleton().logMessage( "InstanceBatchShader: Mesh " +
										mMeshReference->getName() + " using material " +
										mMaterial->getName() + " contains many bones. The amount of "
										"instances per batch is very low. Performance benefits will "
										"be minimal, if any. It might be even slower!",
										LML_NORMAL );
						}

						return retVal;
					}
				}
			}

			//Reaching here means material is supported, but malformed
			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS,
			"Material '" + mMaterial->getName() + "' is malformed for this instancing technique",
			"InstanceBatchShader::calculateMaxNumInstances");
		}

		//Reaching here the material is just unsupported.

		return 0;
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::buildFrom( const SubMesh *baseSubMesh, const RenderOperation &renderOperation )
	{
		if( mMeshReference->hasSkeleton() && !mMeshReference->getSkeleton().isNull() )
			mNumWorldMatrices = mInstancesPerBatch * baseSubMesh->blendIndexToBoneIndexMap.size();
		InstanceBatch::buildFrom( baseSubMesh, renderOperation );
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupVertices( const SubMesh* baseSubMesh )
	{
		mRenderOperation.vertexData = OGRE_NEW VertexData();

		VertexData *thisVertexData = mRenderOperation.vertexData;
		VertexData *baseVertexData = baseSubMesh->vertexData;

		thisVertexData->vertexStart = 0;
		thisVertexData->vertexCount = baseVertexData->vertexCount * mInstancesPerBatch;

		HardwareBufferManager::getSingleton().destroyVertexDeclaration( thisVertexData->vertexDeclaration );
		thisVertexData->vertexDeclaration = baseVertexData->vertexDeclaration->clone();

		if( mMeshReference->hasSkeleton() && !mMeshReference->getSkeleton().isNull() )
		{
			//Building hw skinned batches follow a different path
			setupHardwareSkinned( baseSubMesh, thisVertexData, baseVertexData );
			return;
		}

		//TODO: Can't we, instead of using another source, put the index ID in the same source?
		thisVertexData->vertexDeclaration->addElement(
										thisVertexData->vertexDeclaration->getMaxSource() + 1, 0,
										VET_UBYTE4, VES_BLEND_INDICES );

		for( size_t i=0; i<thisVertexData->vertexDeclaration->getMaxSource(); ++i )
		{
			//Create our own vertex buffer
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize(i),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( i, vertexBuffer );

			//Grab the base submesh data
			HardwareVertexBufferSharedPtr baseVertexBuffer =
													baseVertexData->vertexBufferBinding->getBuffer(i);

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			char* baseBuf = static_cast<char*>(baseVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));

			//Copy and repeat
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				const size_t sizeOfBuffer = baseVertexData->vertexCount *
											baseVertexData->vertexDeclaration->getVertexSize(i);
				memcpy( thisBuf + j * sizeOfBuffer, baseBuf, sizeOfBuffer );
			}

			baseVertexBuffer->unlock();
			vertexBuffer->unlock();
		}

		{
			//Now create the vertices "index ID" to individualize each instance
			const unsigned short lastSource = thisVertexData->vertexDeclaration->getMaxSource();
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize( lastSource ),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( lastSource, vertexBuffer );

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				for( size_t k=0; k<baseVertexData->vertexCount; ++k )
				{
					*thisBuf++ = j;
					*thisBuf++ = j;
					*thisBuf++ = j;
					*thisBuf++ = j;
				}
			}

			vertexBuffer->unlock();
		}
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupIndices( const SubMesh* baseSubMesh )
	{
		mRenderOperation.indexData = OGRE_NEW IndexData();

		IndexData *thisIndexData = mRenderOperation.indexData;
		IndexData *baseIndexData = baseSubMesh->indexData;

		thisIndexData->indexStart = 0;
		thisIndexData->indexCount = baseIndexData->indexCount * mInstancesPerBatch;

		//TODO: Check numVertices is below max supported by GPU
		HardwareIndexBuffer::IndexType indexType = HardwareIndexBuffer::IT_16BIT;
		if( mRenderOperation.vertexData->vertexCount > 65535 )
			indexType = HardwareIndexBuffer::IT_32BIT;
		thisIndexData->indexBuffer = HardwareBufferManager::getSingleton().createIndexBuffer(
													indexType, thisIndexData->indexCount,
													HardwareBuffer::HBU_STATIC_WRITE_ONLY );

		void *buf			= thisIndexData->indexBuffer->lock( HardwareBuffer::HBL_DISCARD );
		void const *baseBuf	= baseIndexData->indexBuffer->lock( HardwareBuffer::HBL_READ_ONLY );

		uint16 *thisBuf16 = static_cast<uint16*>(buf);
		uint32 *thisBuf32 = static_cast<uint32*>(buf);

		for( size_t i=0; i<mInstancesPerBatch; ++i )
		{
			const size_t vertexOffset = i * mRenderOperation.vertexData->vertexCount / mInstancesPerBatch;

			uint16 const *initBuf16 = static_cast<uint16 const *>(baseBuf);
			uint32 const *initBuf32 = static_cast<uint32 const *>(baseBuf);

			for( size_t j=0; j<baseIndexData->indexCount; ++j )
			{
				uint32 originalVal;
				if( baseSubMesh->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_16BIT )
					originalVal = *initBuf16++;
				else
					originalVal = *initBuf32++;

				if( indexType == HardwareIndexBuffer::IT_16BIT )
					*thisBuf16++ = static_cast<uint16>(originalVal) + vertexOffset;
				else
					*thisBuf32++ = originalVal + vertexOffset;
			}
		}

		baseIndexData->indexBuffer->unlock();
		thisIndexData->indexBuffer->unlock();
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::setupHardwareSkinned( const SubMesh* baseSubMesh, VertexData *thisVertexData,
													VertexData *baseVertexData )
	{
		const size_t numBones = baseSubMesh->blendIndexToBoneIndexMap.size();
		mNumWorldMatrices = mInstancesPerBatch * numBones;

		for( size_t i=0; i<=thisVertexData->vertexDeclaration->getMaxSource(); ++i )
		{
			//Create our own vertex buffer
			HardwareVertexBufferSharedPtr vertexBuffer =
											HardwareBufferManager::getSingleton().createVertexBuffer(
											thisVertexData->vertexDeclaration->getVertexSize(i),
											thisVertexData->vertexCount,
											HardwareBuffer::HBU_STATIC_WRITE_ONLY );
			thisVertexData->vertexBufferBinding->setBinding( i, vertexBuffer );

			VertexDeclaration::VertexElementList veList =
											thisVertexData->vertexDeclaration->findElementsBySource(i);

			//Grab the base submesh data
			HardwareVertexBufferSharedPtr baseVertexBuffer =
													baseVertexData->vertexBufferBinding->getBuffer(i);

			char* thisBuf = static_cast<char*>(vertexBuffer->lock(HardwareBuffer::HBL_DISCARD));
			char* baseBuf = static_cast<char*>(baseVertexBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
			char *startBuf = baseBuf;

			//Copy and repeat
			for( size_t j=0; j<mInstancesPerBatch; ++j )
			{
				//Repeat source
				baseBuf = startBuf;

				for( size_t k=0; k<baseVertexData->vertexCount; ++k )
				{
					VertexDeclaration::VertexElementList::const_iterator it = veList.begin();
					VertexDeclaration::VertexElementList::const_iterator en = veList.end();

					while( it != en )
					{
						switch( it->getSemantic() )
						{
						case VES_BLEND_INDICES:
						*(thisBuf + it->getOffset() + 0) = *(baseBuf + it->getOffset() + 0) + j * numBones;
						*(thisBuf + it->getOffset() + 1) = *(baseBuf + it->getOffset() + 1) + j * numBones;
						*(thisBuf + it->getOffset() + 2) = *(baseBuf + it->getOffset() + 2) + j * numBones;
						*(thisBuf + it->getOffset() + 3) = *(baseBuf + it->getOffset() + 3) + j * numBones;
							break;
						default:
							memcpy( thisBuf + it->getOffset(), baseBuf + it->getOffset(), it->getSize() );
							break;
						}
						++it;
					}
					thisBuf += baseVertexData->vertexDeclaration->getVertexSize(i);
					baseBuf += baseVertexData->vertexDeclaration->getVertexSize(i);
				}
			}

			baseVertexBuffer->unlock();
			vertexBuffer->unlock();
		}
	}
	//-----------------------------------------------------------------------
	void InstanceBatchShader::getWorldTransforms( Matrix4* xform ) const
	{
		InstancedEntityVec::const_iterator itor = mInstancedEntities.begin();
		InstancedEntityVec::const_iterator end  = mInstancedEntities.end();

		while( itor != end )
		{
			xform += (*itor)->getTransforms( xform );
			++itor;
		}
	}
	//-----------------------------------------------------------------------
	unsigned short InstanceBatchShader::getNumWorldTransforms(void) const
	{
		return mNumWorldMatrices;
	}
}
<|endoftext|>


<commit_before>// forward.cpp
// Author: Frank C. Anderson
/*
* Copyright (c) 2005, Stanford University. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of the Stanford University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

// INCLUDE
#include <string>
#include <iostream>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Analyses/InvestigationForward.h>

using namespace OpenSim;
using namespace std;

static void PrintUsage(ostream &aOStream);

//_____________________________________________________________________________
/**
 * Main routine for executing a forward integration and running a set of
 * analyses during the forward integration.
 */
int main(int argc,char **argv)
{
	// PARSE COMMAND LINE
	int i;
	string option = "";
	string setupFileName = "";
	if(argc<2) {
		PrintUsage(cout);
		return(-1);
	}
	for(i=1;i<argc;i++) {
		option = argv[i];

		// PRINT THE USAGE OPTIONS
		if((option=="-help")||(option=="-h")||(option=="-Help")||(option=="-H")||
		(option=="-usage")||(option=="-u")||(option=="-Usage")||(option=="-U")) {
			PrintUsage(cout);
			return(0);

		// PRINT A DEFAULT SETUP FILE FOR THIS INVESTIGATION
		} else if((option=="-PrintSetup")||(option=="-PS")) {
			InvestigationForward *investigation = new InvestigationForward();
			investigation->setName("default");
			Object::setSerializeAllDefaults(true);
			investigation->print("default_forward.xml");
			Object::setSerializeAllDefaults(false);
			return(0);

		// IDENTIFY SETUP FILE
		} else if((option=="-Setup")||(option=="-S")) {
			if((i+1)<argc) setupFileName = argv[i+1];
			break;
		}

	}

	// ERROR CHECK
	if(setupFileName=="") {
		cout<<"\n\nforward.exe: ERROR- A setup file must be specified.\n";
		PrintUsage(cout);
		return(-1);
	}

	// CONSTRUCT
	cout<<"Constructing investigation from setup file "<<setupFileName<<".\n\n";
	InvestigationForward forward(setupFileName);
	forward.print("check.xml");

	// PRINT MODEL INFORMATION
	Model *model = forward.getModel();
	if(model==NULL) {
		cout<<"\nperturb:  ERROR- failed to load model.\n";
		exit(-1);
	}
	cout<<"-----------------------------------------------------------------------\n";
	cout<<"Loaded library\n";
	cout<<"-----------------------------------------------------------------------\n";
	model->printDetailedInfo(cout);
	cout<<"-----------------------------------------------------------------------\n\n";

	// ALTER TORSO COM ?
	FILE *fpTorso = fopen("rra_newTorsoBTJ.txt","r");
	if(fpTorso!=NULL) {
		Array<double> btj(0.0,3);
		fscanf(fpTorso,"%lf %lf %lf",&btj[0],&btj[1],&btj[2]);
		int iTorso = model->getBodyIndex("torso");
		cout<<"NOTE- altering torso (index="<<iTorso<<") body-to-joint vector:\n";
		cout<<btj<<endl<<endl;
		model->setBodyToJointBodyLocal(iTorso,&btj[0]);
		fclose(fpTorso);
	}

	// RUN
	forward.run();

	return(0);
}

//_____________________________________________________________________________
/**
 * Print the usage for this application
 */
void PrintUsage(ostream &aOStream)
{
	aOStream<<"\n\nforward.exe:\n\n";
	aOStream<<"Option              Argument       Action / Notes\n";
	aOStream<<"------              --------       --------------\n";
	aOStream<<"-Help, -H                          Print the command-line options for forward.exe.\n";
	aOStream<<"-PrintSetup, -PS                   Print a default setup file for forward.exe (default_forward.xml).\n";
	aOStream<<"-Setup, -S          FileName       Specify the name of the setup file to use for this forward investigation.\n";
}

<commit_msg>Added try/catch block so exception messages are printed to terminal.<commit_after>// forward.cpp
// Author: Frank C. Anderson
/*
* Copyright (c) 2005, Stanford University. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of the Stanford University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

// INCLUDE
#include <string>
#include <iostream>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Analyses/InvestigationForward.h>

using namespace OpenSim;
using namespace std;

static void PrintUsage(ostream &aOStream);

//_____________________________________________________________________________
/**
 * Main routine for executing a forward integration and running a set of
 * analyses during the forward integration.
 */
int main(int argc,char **argv)
{
	//----------------------
	// Surrounding try block
	//----------------------
	try {
	//----------------------

	// PARSE COMMAND LINE
	int i;
	string option = "";
	string setupFileName = "";
	if(argc<2) {
		PrintUsage(cout);
		return(-1);
	}
	for(i=1;i<argc;i++) {
		option = argv[i];

		// PRINT THE USAGE OPTIONS
		if((option=="-help")||(option=="-h")||(option=="-Help")||(option=="-H")||
		(option=="-usage")||(option=="-u")||(option=="-Usage")||(option=="-U")) {
			PrintUsage(cout);
			return(0);

		// PRINT A DEFAULT SETUP FILE FOR THIS INVESTIGATION
		} else if((option=="-PrintSetup")||(option=="-PS")) {
			InvestigationForward *investigation = new InvestigationForward();
			investigation->setName("default");
			Object::setSerializeAllDefaults(true);
			investigation->print("default_forward.xml");
			Object::setSerializeAllDefaults(false);
			return(0);

		// IDENTIFY SETUP FILE
		} else if((option=="-Setup")||(option=="-S")) {
			if((i+1)<argc) setupFileName = argv[i+1];
			break;
		}

	}

	// ERROR CHECK
	if(setupFileName=="") {
		cout<<"\n\nforward.exe: ERROR- A setup file must be specified.\n";
		PrintUsage(cout);
		return(-1);
	}

	// CONSTRUCT
	cout<<"Constructing investigation from setup file "<<setupFileName<<".\n\n";
	InvestigationForward forward(setupFileName);
	forward.print("check.xml");

	// PRINT MODEL INFORMATION
	Model *model = forward.getModel();
	if(model==NULL) {
		cout<<"\nperturb:  ERROR- failed to load model.\n";
		exit(-1);
	}
	cout<<"-----------------------------------------------------------------------\n";
	cout<<"Loaded library\n";
	cout<<"-----------------------------------------------------------------------\n";
	model->printDetailedInfo(cout);
	cout<<"-----------------------------------------------------------------------\n\n";

	// ALTER TORSO COM ?
	FILE *fpTorso = fopen("rra_newTorsoBTJ.txt","r");
	if(fpTorso!=NULL) {
		Array<double> btj(0.0,3);
		fscanf(fpTorso,"%lf %lf %lf",&btj[0],&btj[1],&btj[2]);
		int iTorso = model->getBodyIndex("torso");
		cout<<"NOTE- altering torso (index="<<iTorso<<") body-to-joint vector:\n";
		cout<<btj<<endl<<endl;
		model->setBodyToJointBodyLocal(iTorso,&btj[0]);
		fclose(fpTorso);
	}

	// RUN
	forward.run();

	//----------------------------
	// Catch any thrown exceptions
	//----------------------------
	} catch(Exception x) {
		x.print(cout);
		return(-1);
	}
	//----------------------------

	return(0);
}

//_____________________________________________________________________________
/**
 * Print the usage for this application
 */
void PrintUsage(ostream &aOStream)
{
	aOStream<<"\n\nforward.exe:\n\n";
	aOStream<<"Option              Argument       Action / Notes\n";
	aOStream<<"------              --------       --------------\n";
	aOStream<<"-Help, -H                          Print the command-line options for forward.exe.\n";
	aOStream<<"-PrintSetup, -PS                   Print a default setup file for forward.exe (default_forward.xml).\n";
	aOStream<<"-Setup, -S          FileName       Specify the name of the setup file to use for this forward investigation.\n";
}

<|endoftext|>


<commit_before>/* vim: set tabstop=4 : */
#ifndef __terark_io_var_int_h__
#define __terark_io_var_int_h__

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <limits>

#include <boost/config.hpp>
#include <boost/serialization/strong_typedef.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>

#include <terark/stdtypes.hpp>
#include <terark/pass_by_value.hpp>

#include "byte_swap.hpp"

#undef min
#undef max

namespace terark {

template<class T> struct fixed_to_var;

#if 0

// var int is  var_+IntT, var_int32_t, var_uint32_t, ...
// var_int_org<IntT>::type is original int of the var int
// is_var_int is the typetrait of var int

template<class VarIntT> struct var_int_org;
template<class T> struct is_var_int : boost::mpl::false_ {};

#define TERARK_DEFINE_VAR_INT_IMPL(IntT, VarIntT)\
	BOOST_STRONG_TYPEDEF(IntT, VarIntT)	\
	template<> struct is_var_int<VarIntT> : boost::mpl::true_ {}; \
	template<> struct is_primitive<VarIntT> : boost::mpl::true_ {}; \
	template<> struct fixed_to_var<IntT> : VarIntT { typedef VarIntT type; }; \
	template<> struct fixed_to_var<VarIntT> : VarIntT { typedef VarIntT type; };	 \
	template<> struct var_int_org<VarIntT> { typedef IntT type; };
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#else
#define TERARK_DEFINE_VAR_INT_IMPL(IntT, VarIntT)\
	BOOST_STRONG_TYPEDEF(IntT, VarIntT)	\
	template<> struct fixed_to_var<IntT> : VarIntT { typedef VarIntT type; }; \
	template<> struct fixed_to_var<VarIntT> : VarIntT { typedef VarIntT type; };
#endif

#if defined(BOOST_HAS_LONG_LONG)
	TERARK_DEFINE_VAR_INT_IMPL(         long long, var_int64_t)
	TERARK_DEFINE_VAR_INT_IMPL(unsigned long long, var_uint64_t)
	BOOST_STRONG_TYPEDEF(         long long, var_int61_t)
	BOOST_STRONG_TYPEDEF(unsigned long long, var_uint61_t)
#elif defined(BOOST_HAS_MS_INT64)
	TERARK_DEFINE_VAR_INT_IMPL(         __int64, var_int64_t)
	TERARK_DEFINE_VAR_INT_IMPL(unsigned __int64, var_uint64_t)
	BOOST_STRONG_TYPEDEF(         __int64, var_int61_t)
	BOOST_STRONG_TYPEDEF(unsigned __int64, var_uint61_t)
#endif

#if ULONG_MAX == 0xFFFFFFFF
	TERARK_DEFINE_VAR_INT_IMPL(         long, var_int32_t)
	TERARK_DEFINE_VAR_INT_IMPL(unsigned long, var_uint32_t)
	BOOST_STRONG_TYPEDEF(		  long, var_int30_t)
	BOOST_STRONG_TYPEDEF(unsigned long, var_uint30_t)
  #if UINT_MAX == 0xFFFFFFFF
	template<> struct fixed_to_var<         int> : var_int32_t  { typedef var_int32_t type; };
	template<> struct fixed_to_var<unsigned int> : var_uint32_t { typedef var_uint32_t type; };
  #elif UINT_MAX == 0xFFFF
    #error "don't support 16bit int"
  #endif
#elif UINT_MAX == 0xFFFFFFFF
	TERARK_DEFINE_VAR_INT_IMPL(         int, var_int32_t)
	TERARK_DEFINE_VAR_INT_IMPL(unsigned int, var_uint32_t)
	BOOST_STRONG_TYPEDEF(         int, var_int30_t)
	BOOST_STRONG_TYPEDEF(unsigned int, var_uint30_t)
	template<> struct fixed_to_var<         long> : var_int64_t  { typedef var_int64_t type; };
	template<> struct fixed_to_var<unsigned long> : var_uint64_t { typedef var_uint64_t type; };
#else
#   error no int32
#endif

#if defined(__amd64__) || defined(__amd64) || \
	defined(__x86_64__) || defined(__x86_64) || \
	defined(_M_X64) || \
	defined(__ia64__) || defined(_IA64) || defined(__IA64__) || \
	defined(__ia64) ||\
	defined(_M_IA64)
  typedef var_uint64_t var_size_t_base;
#else
  typedef var_uint32_t var_size_t_base;
#endif
struct var_size_t : public var_size_t_base {
	var_size_t() {}
	template<class T>
	explicit var_size_t(const T y) : var_size_t_base(y) {}
};

inline void byte_swap_in(var_int32_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_int64_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_uint32_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_uint64_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }

inline void byte_swap_in(var_int30_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_int61_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_uint30_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_uint61_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }

template<class IntT>
class as_var_int_ref
{
	IntT& val;

public:
	explicit as_var_int_ref(IntT& x) : val(x) {}

	template<class Input>
	friend void DataIO_loadObject(Input& in, as_var_int_ref x)
	{
		typename fixed_to_var<IntT>::type v;
		in >> v;
		x.val = v.t;
	}
	template<class Output>
	friend void DataIO_saveObject(Output& out, as_var_int_ref x)
	{
		// 必须有这个函数，因为有可能把一个 non-const int& 传递给 as_var_int 来输出
		out << typename fixed_to_var<IntT>::type(x.val);
	}
};

//! for load as var int
template<class IntT>
inline
pass_by_value<as_var_int_ref<IntT> >
as_var_int(IntT& x)
{
	return pass_by_value<as_var_int_ref<IntT> >(as_var_int_ref<IntT>(x));
}

//! for save as var int
template<class IntT>
inline
typename fixed_to_var<IntT>::type
as_var_int(const IntT& x)
{
	return typename fixed_to_var<IntT>::type(x);
}

// lowest bit is sign bit
//
template<class IntType, class UIntType>
inline UIntType var_int_s2u(IntType x)
{
	BOOST_STATIC_ASSERT(boost::is_signed<IntType>::value);
	BOOST_STATIC_ASSERT(boost::is_unsigned<UIntType>::value);
	BOOST_STATIC_ASSERT(sizeof(IntType)==sizeof(UIntType));

	if (x < 0) {
		if (std::numeric_limits<IntType>::min() == x)
			return UIntType(1);
		else
			return UIntType(-x << 1 | 1);
	} else
		return UIntType(x << 1);
}

template<class UIntType, class IntType>
inline IntType var_int_u2s(UIntType u)
{
	BOOST_STATIC_ASSERT(boost::is_signed<IntType>::value);
	BOOST_STATIC_ASSERT(boost::is_unsigned<UIntType>::value);
	BOOST_STATIC_ASSERT(sizeof(IntType)==sizeof(UIntType));

	if (u & 1) {
		if (0 == u >> 1)
			return std::numeric_limits<IntType>::min();
		else
			return -(IntType)(u >> 1);
	} else
		return (IntType)(u >> 1);
}

inline uint32_t var_int32_s2u(int32_t x) { return var_int_s2u<int32_t, uint32_t>(x); }
inline uint32_t var_int30_s2u(int32_t x) { return var_int_s2u<int32_t, uint32_t>(x); } // same as 32

inline int32_t var_int32_u2s(uint32_t u) { return var_int_u2s<uint32_t, int32_t>(u); }
inline int32_t var_int30_u2s(uint32_t u) { return var_int_u2s<uint32_t, int32_t>(u); } // same as 32

#if !defined(BOOST_NO_INT64_T)
inline uint64_t var_int64_s2u(int64_t x) { return var_int_s2u<int64_t, uint64_t>(x); }
inline uint64_t var_int61_s2u(int64_t x) { return var_int_s2u<int64_t, uint64_t>(x); } // same as 64
inline int64_t var_int64_u2s(uint64_t u) { return var_int_u2s<uint64_t, int64_t>(u); }
inline int64_t var_int61_u2s(uint64_t u) { return var_int_u2s<uint64_t, int64_t>(u); } // same as 64
#endif

////////////////////////////////////////////////////////////////////////////////////////
TERARK_DLL_EXPORT uint32_t load_var_uint32(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT uint32_t load_var_uint30(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT uint64_t load_var_uint64(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT uint64_t load_var_uint61(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT  int32_t load_var_int32(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT  int32_t load_var_int30(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT  int64_t load_var_int64(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT  int64_t load_var_int61(const unsigned char* buf, const unsigned char** endp);

//--------------------------------------------------------------------------------------
TERARK_DLL_EXPORT unsigned char* save_var_uint32(unsigned char* buf, uint32_t x);
TERARK_DLL_EXPORT unsigned char* save_var_uint30(unsigned char* buf, uint32_t x);
TERARK_DLL_EXPORT unsigned char* save_var_uint64(unsigned char* buf, uint64_t x);
TERARK_DLL_EXPORT unsigned char* save_var_uint61(unsigned char* buf, uint64_t x);
TERARK_DLL_EXPORT unsigned char* save_var_int32(unsigned char* buf, int32_t x);
TERARK_DLL_EXPORT unsigned char* save_var_int30(unsigned char* buf, int32_t x);
TERARK_DLL_EXPORT unsigned char* save_var_int64(unsigned char* buf, int64_t x);
TERARK_DLL_EXPORT unsigned char* save_var_int61(unsigned char* buf, int64_t x);

////////////////////////////////////////////////////////////////////////////////////////
TERARK_DLL_EXPORT uint32_t reverse_get_var_uint32(const unsigned char* buf, unsigned char const ** cur);
TERARK_DLL_EXPORT int32_t reverse_get_var_int32(const unsigned char* buf, unsigned char const ** cur);

#if !defined(BOOST_NO_INT64_T)
TERARK_DLL_EXPORT uint64_t reverse_get_var_uint64(const unsigned char* buf, unsigned char const ** cur);
TERARK_DLL_EXPORT int64_t reverse_get_var_int64(const unsigned char* buf, unsigned char const ** cur);
#endif

} // namespace terark

#endif // __terark_io_var_int_h__

<commit_msg>terark-base: sync from private repo<commit_after>/* vim: set tabstop=4 : */
#ifndef __terark_io_var_int_h__
#define __terark_io_var_int_h__

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <limits>

#include <boost/config.hpp>
#include <boost/serialization/strong_typedef.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>

#include <terark/stdtypes.hpp>
#include <terark/pass_by_value.hpp>

#include "byte_swap.hpp"

#undef min
#undef max

namespace terark {

template<class T> struct fixed_to_var;

#if 0

// var int is  var_+IntT, var_int32_t, var_uint32_t, ...
// var_int_org<IntT>::type is original int of the var int
// is_var_int is the typetrait of var int

template<class VarIntT> struct var_int_org;
template<class T> struct is_var_int : boost::mpl::false_ {};

#define TERARK_DEFINE_VAR_INT_IMPL(IntT, VarIntT)\
	BOOST_STRONG_TYPEDEF(IntT, VarIntT)	\
	template<> struct is_var_int<VarIntT> : boost::mpl::true_ {}; \
	template<> struct is_primitive<VarIntT> : boost::mpl::true_ {}; \
	template<> struct fixed_to_var<IntT> : VarIntT { typedef VarIntT type; }; \
	template<> struct fixed_to_var<VarIntT> : VarIntT { typedef VarIntT type; };	 \
	template<> struct var_int_org<VarIntT> { typedef IntT type; };
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#else
#define TERARK_DEFINE_VAR_INT_IMPL(IntT, VarIntT)\
	BOOST_STRONG_TYPEDEF(IntT, VarIntT)	\
	template<> struct fixed_to_var<IntT> : VarIntT { typedef VarIntT type; }; \
	template<> struct fixed_to_var<VarIntT> : VarIntT { typedef VarIntT type; };
#endif

#if defined(BOOST_HAS_LONG_LONG)
	TERARK_DEFINE_VAR_INT_IMPL(         long long, var_int64_t)
	TERARK_DEFINE_VAR_INT_IMPL(unsigned long long, var_uint64_t)
	BOOST_STRONG_TYPEDEF(         long long, var_int61_t)
	BOOST_STRONG_TYPEDEF(unsigned long long, var_uint61_t)
#elif defined(BOOST_HAS_MS_INT64)
	TERARK_DEFINE_VAR_INT_IMPL(         __int64, var_int64_t)
	TERARK_DEFINE_VAR_INT_IMPL(unsigned __int64, var_uint64_t)
	BOOST_STRONG_TYPEDEF(         __int64, var_int61_t)
	BOOST_STRONG_TYPEDEF(unsigned __int64, var_uint61_t)
#endif

#if ULONG_MAX == 0xFFFFFFFF
	TERARK_DEFINE_VAR_INT_IMPL(         long, var_int32_t)
	TERARK_DEFINE_VAR_INT_IMPL(unsigned long, var_uint32_t)
	BOOST_STRONG_TYPEDEF(		  long, var_int30_t)
	BOOST_STRONG_TYPEDEF(unsigned long, var_uint30_t)
  #if UINT_MAX == 0xFFFFFFFF
	template<> struct fixed_to_var<         int> : var_int32_t  { typedef var_int32_t type; };
	template<> struct fixed_to_var<unsigned int> : var_uint32_t { typedef var_uint32_t type; };
  #elif UINT_MAX == 0xFFFF
    #error "don't support 16bit int"
  #endif
#elif UINT_MAX == 0xFFFFFFFF
	TERARK_DEFINE_VAR_INT_IMPL(         int, var_int32_t)
	TERARK_DEFINE_VAR_INT_IMPL(unsigned int, var_uint32_t)
	BOOST_STRONG_TYPEDEF(         int, var_int30_t)
	BOOST_STRONG_TYPEDEF(unsigned int, var_uint30_t)
	template<> struct fixed_to_var<         long> : var_int64_t  { typedef var_int64_t type; };
	template<> struct fixed_to_var<unsigned long> : var_uint64_t { typedef var_uint64_t type; };
#else
#   error no int32
#endif

#if defined(__amd64__) || defined(__amd64) || \
	defined(__x86_64__) || defined(__x86_64) || \
	defined(_M_X64) || \
	defined(__ia64__) || defined(_IA64) || defined(__IA64__) || \
	defined(__ia64) ||\
	defined(_M_IA64)
  typedef var_uint64_t var_size_t_base;
#else
  typedef var_uint32_t var_size_t_base;
#endif
struct var_size_t : public var_size_t_base {
	var_size_t() {}
	template<class T>
	explicit var_size_t(const T y) : var_size_t_base(y) {}
};

inline void byte_swap_in(var_int32_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_int64_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_uint32_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_uint64_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }

inline void byte_swap_in(var_int30_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_int61_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_uint30_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }
inline void byte_swap_in(var_uint61_t& x, boost::mpl::true_) { x.t = byte_swap(x.t); }

template<class IntT>
class as_var_int_ref
{
	IntT& val;

public:
	explicit as_var_int_ref(IntT& x) : val(x) {}

	template<class Input>
	friend void DataIO_loadObject(Input& in, as_var_int_ref x)
	{
		typename fixed_to_var<IntT>::type v;
		in >> v;
		x.val = v.t;
	}
	template<class Output>
	friend void DataIO_saveObject(Output& out, as_var_int_ref x)
	{
		// 必须有这个函数，因为有可能把一个 non-const int& 传递给 as_var_int 来输出
		out << typename fixed_to_var<IntT>::type(x.val);
	}
};

//! for load as var int
template<class IntT>
inline
pass_by_value<as_var_int_ref<IntT> >
as_var_int(IntT& x)
{
	return pass_by_value<as_var_int_ref<IntT> >(as_var_int_ref<IntT>(x));
}

//! for save as var int
template<class IntT>
inline
typename fixed_to_var<IntT>::type
as_var_int(const IntT& x)
{
	return typename fixed_to_var<IntT>::type(x);
}

// lowest bit is sign bit
//
template<class IntType, class UIntType>
inline UIntType var_int_s2u(IntType x)
{
	BOOST_STATIC_ASSERT(boost::is_signed<IntType>::value);
	BOOST_STATIC_ASSERT(boost::is_unsigned<UIntType>::value);
	BOOST_STATIC_ASSERT(sizeof(IntType)==sizeof(UIntType));

	if (x < 0) {
		if (std::numeric_limits<IntType>::min() == x)
			return UIntType(1);
		else
			return UIntType(-x << 1 | 1);
	} else
		return UIntType(x << 1);
}

template<class UIntType, class IntType>
inline IntType var_int_u2s(UIntType u)
{
	BOOST_STATIC_ASSERT(boost::is_signed<IntType>::value);
	BOOST_STATIC_ASSERT(boost::is_unsigned<UIntType>::value);
	BOOST_STATIC_ASSERT(sizeof(IntType)==sizeof(UIntType));

	if (u & 1) {
		if (0 == u >> 1)
			return std::numeric_limits<IntType>::min();
		else
			return -(IntType)(u >> 1);
	} else
		return (IntType)(u >> 1);
}

inline uint32_t var_int32_s2u(int32_t x) { return var_int_s2u<int32_t, uint32_t>(x); }
inline uint32_t var_int30_s2u(int32_t x) { return var_int_s2u<int32_t, uint32_t>(x); } // same as 32

inline int32_t var_int32_u2s(uint32_t u) { return var_int_u2s<uint32_t, int32_t>(u); }
inline int32_t var_int30_u2s(uint32_t u) { return var_int_u2s<uint32_t, int32_t>(u); } // same as 32

#if !defined(BOOST_NO_INT64_T)
inline uint64_t var_int64_s2u(int64_t x) { return var_int_s2u<int64_t, uint64_t>(x); }
inline uint64_t var_int61_s2u(int64_t x) { return var_int_s2u<int64_t, uint64_t>(x); } // same as 64
inline int64_t var_int64_u2s(uint64_t u) { return var_int_u2s<uint64_t, int64_t>(u); }
inline int64_t var_int61_u2s(uint64_t u) { return var_int_u2s<uint64_t, int64_t>(u); } // same as 64
#endif

////////////////////////////////////////////////////////////////////////////////////////
TERARK_DLL_EXPORT uint32_t load_var_uint32(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT uint32_t load_var_uint30(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT uint64_t load_var_uint64(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT uint64_t load_var_uint61(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT  int32_t load_var_int32(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT  int32_t load_var_int30(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT  int64_t load_var_int64(const unsigned char* buf, const unsigned char** endp);
TERARK_DLL_EXPORT  int64_t load_var_int61(const unsigned char* buf, const unsigned char** endp);

//--------------------------------------------------------------------------------------
TERARK_DLL_EXPORT unsigned char* save_var_uint32(unsigned char* buf, uint32_t x);
TERARK_DLL_EXPORT unsigned char* save_var_uint30(unsigned char* buf, uint32_t x);
TERARK_DLL_EXPORT unsigned char* save_var_uint64(unsigned char* buf, uint64_t x);
TERARK_DLL_EXPORT unsigned char* save_var_uint61(unsigned char* buf, uint64_t x);
TERARK_DLL_EXPORT unsigned char* save_var_int32(unsigned char* buf, int32_t x);
TERARK_DLL_EXPORT unsigned char* save_var_int30(unsigned char* buf, int32_t x);
TERARK_DLL_EXPORT unsigned char* save_var_int64(unsigned char* buf, int64_t x);
TERARK_DLL_EXPORT unsigned char* save_var_int61(unsigned char* buf, int64_t x);

////////////////////////////////////////////////////////////////////////////////////////
TERARK_DLL_EXPORT uint32_t reverse_get_var_uint32(const unsigned char* buf, unsigned char const ** cur);
TERARK_DLL_EXPORT int32_t reverse_get_var_int32(const unsigned char* buf, unsigned char const ** cur);

#if !defined(BOOST_NO_INT64_T)
TERARK_DLL_EXPORT uint64_t reverse_get_var_uint64(const unsigned char* buf, unsigned char const ** cur);
TERARK_DLL_EXPORT int64_t reverse_get_var_int64(const unsigned char* buf, unsigned char const ** cur);
#endif

/// pos must be const byte_t* or byte_t*
/// result should be size_t
/// use macros is faster than an inline function
#define FAST_READ_VAR_UINT32(pos, result) \
  do { \
		size_t _tmpUint_ = *pos++; \
		result = _tmpUint_ & 0x7F; \
		if ( terark_unlikely((_tmpUint_ & 0x80)) ) { \
			_tmpUint_ = *pos++; \
			result |= (_tmpUint_ & 0x7F) << 7; \
			if ( terark_unlikely((_tmpUint_ & 0x80)) ) { \
				_tmpUint_ = *pos++; \
				result |= (_tmpUint_ & 0x7F) << 14; \
				if ( terark_unlikely((_tmpUint_ & 0x80)) ) { \
					_tmpUint_ = *pos++; \
					result |= (_tmpUint_ & 0x7F) << 21; \
					if ( terark_unlikely((_tmpUint_ & 0x80)) ) { \
						_tmpUint_ = *pos++; \
						result |= (_tmpUint_ & 0x7F) << 28; \
						assert((_tmpUint_ & 0x80) == 0); \
					} \
				} \
			} \
		} \
	} while (0)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

} // namespace terark

#endif // __terark_io_var_int_h__

<|endoftext|>


<commit_before>//
//  Shader.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 07/02/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "Shader.hpp"

#include <stdlib.h>
#include <stdio.h>

using namespace OpenGL;

namespace {
	Shader *bound_shader = nullptr;
}

GLuint Shader::compile_shader(const char *source, GLenum type)
{
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, NULL);
	glCompileShader(shader);

#if defined(DEBUG)
	GLint isCompiled = 0;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
	if(isCompiled == GL_FALSE)
	{
		GLint logLength;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
		if(logLength > 0) {
			GLchar *log = (GLchar *)malloc((size_t)logLength);
			glGetShaderInfoLog(shader, logLength, &logLength, log);
			printf("Compile log:\n%s\n", log);
			free(log);
		}

		throw (type == GL_VERTEX_SHADER) ? VertexShaderCompilationError : FragmentShaderCompilationError;
	}
#endif

	return shader;
}

Shader::Shader(const char *vertex_shader, const char *fragment_shader, const AttributeBinding *attribute_bindings)
{
	shader_program_ = glCreateProgram();
	GLuint vertex = compile_shader(vertex_shader, GL_VERTEX_SHADER);
	GLuint fragment = compile_shader(fragment_shader, GL_FRAGMENT_SHADER);

	glAttachShader(shader_program_, vertex);
	glAttachShader(shader_program_, fragment);

	if(attribute_bindings)
	{
		while(attribute_bindings->name)
		{
			glBindAttribLocation(shader_program_, attribute_bindings->index, attribute_bindings->name);
			attribute_bindings++;
		}
	}

	glLinkProgram(shader_program_);

#if defined(DEBUG)
	GLint didLink = 0;
	glGetProgramiv(shader_program_, GL_LINK_STATUS, &didLink);
	if(didLink == GL_FALSE)
	{
		GLint logLength;
		glGetProgramiv(shader_program_, GL_INFO_LOG_LENGTH, &logLength);
		if(logLength > 0) {
			GLchar *log = (GLchar *)malloc((size_t)logLength);
			glGetProgramInfoLog(shader_program_, logLength, &logLength, log);
			printf("Link log:\n%s\n", log);
			free(log);
		}
		throw ProgramLinkageError;
	}
#endif
}

Shader::~Shader()
{
	if(bound_shader == this) Shader::unbind();
	glDeleteProgram(shader_program_);
}

void Shader::bind()
{
	if(bound_shader != this)
	{
		glUseProgram(shader_program_);
		bound_shader = this;
	}
	flush_functions();
}

void Shader::unbind()
{
	bound_shader = nullptr;
	glUseProgram(0);
}

GLint Shader::get_attrib_location(const GLchar *name)
{
	return glGetAttribLocation(shader_program_, name);
}

GLint Shader::get_uniform_location(const GLchar *name)
{
	return glGetUniformLocation(shader_program_, name);
}

void Shader::enable_vertex_attribute_with_pointer(const char *name, GLint size, GLenum type, GLboolean normalised, GLsizei stride, const GLvoid *pointer, GLuint divisor)
{
	GLint location = get_attrib_location(name);
	glEnableVertexAttribArray((GLuint)location);
	glVertexAttribPointer((GLuint)location, size, type, normalised, stride, pointer);
	glVertexAttribDivisor((GLuint)location, divisor);
}

// The various set_uniforms...
#define location() glGetUniformLocation(shader_program_, name.c_str())
void Shader::set_uniform(const std::string &name, GLint value)
{
	enqueue_function([name, value, this] {
		glUniform1i(location(), value);
	});
}

void Shader::set_uniform(const std::string &name, GLuint value)
{
	enqueue_function([name, value, this] {
		glUniform1ui(location(), value);
	});
}

void Shader::set_uniform(const std::string &name, GLfloat value)
{
	enqueue_function([name, value, this] {
		glUniform1f(location(), value);
	});
}

void Shader::set_uniform(const std::string &name, GLint value1, GLint value2)
{
	enqueue_function([name, value1, value2, this] {
		glUniform2i(location(), value1, value2);
	});
}

void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2)
{
	enqueue_function([name, value1, value2, this] {
		GLint location = location();
		glUniform2f(location, value1, value2);
	});
}

void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2)
{
	enqueue_function([name, value1, value2, this] {
		glUniform2ui(location(), value1, value2);
	});
}

void Shader::set_uniform(const std::string &name, GLint value1, GLint value2, GLint value3)
{
	enqueue_function([name, value1, value2, value3, this] {
		glUniform3i(location(), value1, value2, value3);
	});
}

void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2, GLfloat value3)
{
	enqueue_function([name, value1, value2, value3, this] {
		glUniform3f(location(), value1, value2, value3);
	});
}

void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2, GLuint value3)
{
	enqueue_function([name, value1, value2, value3, this] {
		glUniform3ui(location(), value1, value2, value3);
	});
}

void Shader::set_uniform(const std::string &name, GLint value1, GLint value2, GLint value3, GLint value4)
{
	enqueue_function([name, value1, value2, value3, value4, this] {
		glUniform4i(location(), value1, value2, value3, value4);
	});
}

void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2, GLfloat value3, GLfloat value4)
{
	enqueue_function([name, value1, value2, value3, value4, this] {
		glUniform4f(location(), value1, value2, value3, value4);
	});
}

void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2, GLuint value3, GLuint value4)
{
	enqueue_function([name, value1, value2, value3, value4, this] {
		glUniform4ui(location(), value1, value2, value3, value4);
	});
}

void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLint *values)
{
	size_t number_of_values = (size_t)count * (size_t)size;
	GLint *values_copy = new GLint[number_of_values];
	memcpy(values_copy, values, sizeof(*values) * (size_t)number_of_values);

	enqueue_function([name, size, count, values_copy, this] {
		switch(size)
		{
			case 1: glUniform1iv(location(), count, values_copy);	break;
			case 2: glUniform2iv(location(), count, values_copy);	break;
			case 3: glUniform3iv(location(), count, values_copy);	break;
			case 4: glUniform4iv(location(), count, values_copy);	break;
		}
		delete[] values_copy;
	});
}

void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLfloat *values)
{
	size_t number_of_values = (size_t)count * (size_t)size;
	GLfloat *values_copy = new GLfloat[number_of_values];
	memcpy(values_copy, values, sizeof(*values) * (size_t)number_of_values);

	enqueue_function([name, size, count, values_copy, this] {
		switch(size)
		{
			case 1: glUniform1fv(location(), count, values_copy);	break;
			case 2: glUniform2fv(location(), count, values_copy);	break;
			case 3: glUniform3fv(location(), count, values_copy);	break;
			case 4: glUniform4fv(location(), count, values_copy);	break;
		}
		delete[] values_copy;
	});
}

void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLuint *values)
{
	size_t number_of_values = (size_t)count * (size_t)size;
	GLuint *values_copy = new GLuint[number_of_values];
	memcpy(values_copy, values, sizeof(*values) * (size_t)number_of_values);

	enqueue_function([name, size, count, values_copy, this] {
		switch(size)
		{
			case 1: glUniform1uiv(location(), count, values_copy);	break;
			case 2: glUniform2uiv(location(), count, values_copy);	break;
			case 3: glUniform3uiv(location(), count, values_copy);	break;
			case 4: glUniform4uiv(location(), count, values_copy);	break;
		}
		delete[] values_copy;
	});
}

void Shader::set_uniform_matrix(const std::string &name, GLint size, bool transpose, const GLfloat *values)
{
	set_uniform_matrix(name, size, 1, transpose, values);
}

void Shader::set_uniform_matrix(const std::string &name, GLint size, GLsizei count, bool transpose, const GLfloat *values)
{
	size_t number_of_values = (size_t)count * (size_t)size * (size_t)size;
	GLfloat *values_copy = new GLfloat[number_of_values];
	memcpy(values_copy, values, sizeof(*values) * number_of_values);

	enqueue_function([name, size, count, transpose, values_copy, this] {
		GLboolean glTranspose = transpose ? GL_TRUE : GL_FALSE;
		switch(size)
		{
			case 2: glUniformMatrix2fv(location(), count, glTranspose, values_copy);	break;
			case 3: glUniformMatrix3fv(location(), count, glTranspose, values_copy);	break;
			case 4: glUniformMatrix4fv(location(), count, glTranspose, values_copy);	break;
		}
		delete[] values_copy;
	});
}

void Shader::enqueue_function(std::function<void(void)> function)
{
	function_mutex_.lock();
	enqueued_functions_.push_back(function);
	function_mutex_.unlock();
}

void Shader::flush_functions()
{
	function_mutex_.lock();
	for(std::function<void(void)> function : enqueued_functions_)
	{
		function();
	}
	enqueued_functions_.clear();
	function_mutex_.unlock();
}
<commit_msg>Switched to lock guards.<commit_after>//
//  Shader.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 07/02/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "Shader.hpp"

#include <stdlib.h>
#include <stdio.h>

using namespace OpenGL;

namespace {
	Shader *bound_shader = nullptr;
}

GLuint Shader::compile_shader(const char *source, GLenum type)
{
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &source, NULL);
	glCompileShader(shader);

#if defined(DEBUG)
	GLint isCompiled = 0;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
	if(isCompiled == GL_FALSE)
	{
		GLint logLength;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
		if(logLength > 0) {
			GLchar *log = (GLchar *)malloc((size_t)logLength);
			glGetShaderInfoLog(shader, logLength, &logLength, log);
			printf("Compile log:\n%s\n", log);
			free(log);
		}

		throw (type == GL_VERTEX_SHADER) ? VertexShaderCompilationError : FragmentShaderCompilationError;
	}
#endif

	return shader;
}

Shader::Shader(const char *vertex_shader, const char *fragment_shader, const AttributeBinding *attribute_bindings)
{
	shader_program_ = glCreateProgram();
	GLuint vertex = compile_shader(vertex_shader, GL_VERTEX_SHADER);
	GLuint fragment = compile_shader(fragment_shader, GL_FRAGMENT_SHADER);

	glAttachShader(shader_program_, vertex);
	glAttachShader(shader_program_, fragment);

	if(attribute_bindings)
	{
		while(attribute_bindings->name)
		{
			glBindAttribLocation(shader_program_, attribute_bindings->index, attribute_bindings->name);
			attribute_bindings++;
		}
	}

	glLinkProgram(shader_program_);

#if defined(DEBUG)
	GLint didLink = 0;
	glGetProgramiv(shader_program_, GL_LINK_STATUS, &didLink);
	if(didLink == GL_FALSE)
	{
		GLint logLength;
		glGetProgramiv(shader_program_, GL_INFO_LOG_LENGTH, &logLength);
		if(logLength > 0) {
			GLchar *log = (GLchar *)malloc((size_t)logLength);
			glGetProgramInfoLog(shader_program_, logLength, &logLength, log);
			printf("Link log:\n%s\n", log);
			free(log);
		}
		throw ProgramLinkageError;
	}
#endif
}

Shader::~Shader()
{
	if(bound_shader == this) Shader::unbind();
	glDeleteProgram(shader_program_);
}

void Shader::bind()
{
	if(bound_shader != this)
	{
		glUseProgram(shader_program_);
		bound_shader = this;
	}
	flush_functions();
}

void Shader::unbind()
{
	bound_shader = nullptr;
	glUseProgram(0);
}

GLint Shader::get_attrib_location(const GLchar *name)
{
	return glGetAttribLocation(shader_program_, name);
}

GLint Shader::get_uniform_location(const GLchar *name)
{
	return glGetUniformLocation(shader_program_, name);
}

void Shader::enable_vertex_attribute_with_pointer(const char *name, GLint size, GLenum type, GLboolean normalised, GLsizei stride, const GLvoid *pointer, GLuint divisor)
{
	GLint location = get_attrib_location(name);
	glEnableVertexAttribArray((GLuint)location);
	glVertexAttribPointer((GLuint)location, size, type, normalised, stride, pointer);
	glVertexAttribDivisor((GLuint)location, divisor);
}

// The various set_uniforms...
#define location() glGetUniformLocation(shader_program_, name.c_str())
void Shader::set_uniform(const std::string &name, GLint value)
{
	enqueue_function([name, value, this] {
		glUniform1i(location(), value);
	});
}

void Shader::set_uniform(const std::string &name, GLuint value)
{
	enqueue_function([name, value, this] {
		glUniform1ui(location(), value);
	});
}

void Shader::set_uniform(const std::string &name, GLfloat value)
{
	enqueue_function([name, value, this] {
		glUniform1f(location(), value);
	});
}

void Shader::set_uniform(const std::string &name, GLint value1, GLint value2)
{
	enqueue_function([name, value1, value2, this] {
		glUniform2i(location(), value1, value2);
	});
}

void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2)
{
	enqueue_function([name, value1, value2, this] {
		GLint location = location();
		glUniform2f(location, value1, value2);
	});
}

void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2)
{
	enqueue_function([name, value1, value2, this] {
		glUniform2ui(location(), value1, value2);
	});
}

void Shader::set_uniform(const std::string &name, GLint value1, GLint value2, GLint value3)
{
	enqueue_function([name, value1, value2, value3, this] {
		glUniform3i(location(), value1, value2, value3);
	});
}

void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2, GLfloat value3)
{
	enqueue_function([name, value1, value2, value3, this] {
		glUniform3f(location(), value1, value2, value3);
	});
}

void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2, GLuint value3)
{
	enqueue_function([name, value1, value2, value3, this] {
		glUniform3ui(location(), value1, value2, value3);
	});
}

void Shader::set_uniform(const std::string &name, GLint value1, GLint value2, GLint value3, GLint value4)
{
	enqueue_function([name, value1, value2, value3, value4, this] {
		glUniform4i(location(), value1, value2, value3, value4);
	});
}

void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2, GLfloat value3, GLfloat value4)
{
	enqueue_function([name, value1, value2, value3, value4, this] {
		glUniform4f(location(), value1, value2, value3, value4);
	});
}

void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2, GLuint value3, GLuint value4)
{
	enqueue_function([name, value1, value2, value3, value4, this] {
		glUniform4ui(location(), value1, value2, value3, value4);
	});
}

void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLint *values)
{
	size_t number_of_values = (size_t)count * (size_t)size;
	GLint *values_copy = new GLint[number_of_values];
	memcpy(values_copy, values, sizeof(*values) * (size_t)number_of_values);

	enqueue_function([name, size, count, values_copy, this] {
		switch(size)
		{
			case 1: glUniform1iv(location(), count, values_copy);	break;
			case 2: glUniform2iv(location(), count, values_copy);	break;
			case 3: glUniform3iv(location(), count, values_copy);	break;
			case 4: glUniform4iv(location(), count, values_copy);	break;
		}
		delete[] values_copy;
	});
}

void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLfloat *values)
{
	size_t number_of_values = (size_t)count * (size_t)size;
	GLfloat *values_copy = new GLfloat[number_of_values];
	memcpy(values_copy, values, sizeof(*values) * (size_t)number_of_values);

	enqueue_function([name, size, count, values_copy, this] {
		switch(size)
		{
			case 1: glUniform1fv(location(), count, values_copy);	break;
			case 2: glUniform2fv(location(), count, values_copy);	break;
			case 3: glUniform3fv(location(), count, values_copy);	break;
			case 4: glUniform4fv(location(), count, values_copy);	break;
		}
		delete[] values_copy;
	});
}

void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLuint *values)
{
	size_t number_of_values = (size_t)count * (size_t)size;
	GLuint *values_copy = new GLuint[number_of_values];
	memcpy(values_copy, values, sizeof(*values) * (size_t)number_of_values);

	enqueue_function([name, size, count, values_copy, this] {
		switch(size)
		{
			case 1: glUniform1uiv(location(), count, values_copy);	break;
			case 2: glUniform2uiv(location(), count, values_copy);	break;
			case 3: glUniform3uiv(location(), count, values_copy);	break;
			case 4: glUniform4uiv(location(), count, values_copy);	break;
		}
		delete[] values_copy;
	});
}

void Shader::set_uniform_matrix(const std::string &name, GLint size, bool transpose, const GLfloat *values)
{
	set_uniform_matrix(name, size, 1, transpose, values);
}

void Shader::set_uniform_matrix(const std::string &name, GLint size, GLsizei count, bool transpose, const GLfloat *values)
{
	size_t number_of_values = (size_t)count * (size_t)size * (size_t)size;
	GLfloat *values_copy = new GLfloat[number_of_values];
	memcpy(values_copy, values, sizeof(*values) * number_of_values);

	enqueue_function([name, size, count, transpose, values_copy, this] {
		GLboolean glTranspose = transpose ? GL_TRUE : GL_FALSE;
		switch(size)
		{
			case 2: glUniformMatrix2fv(location(), count, glTranspose, values_copy);	break;
			case 3: glUniformMatrix3fv(location(), count, glTranspose, values_copy);	break;
			case 4: glUniformMatrix4fv(location(), count, glTranspose, values_copy);	break;
		}
		delete[] values_copy;
	});
}

void Shader::enqueue_function(std::function<void(void)> function)
{
	std::lock_guard<std::mutex> function_guard(function_mutex_);
	enqueued_functions_.push_back(function);
}

void Shader::flush_functions()
{
	std::lock_guard<std::mutex> function_guard(function_mutex_);
	for(std::function<void(void)> function : enqueued_functions_)
	{
		function();
	}
	enqueued_functions_.clear();
}
<|endoftext|>