<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Unit test for speech Hotword model using TFLite Ops.

#include <string.h>

#include <memory>
#include <string>

#include "base/logging.h"
#include "testing/base/public/googletest.h"
#include <gtest/gtest.h>
#include "absl/strings/str_cat.h"
#include "tensorflow/contrib/lite/context.h"
#include "tensorflow/contrib/lite/interpreter.h"
#include "tensorflow/contrib/lite/kernels/register.h"
#include "tensorflow/contrib/lite/model.h"
#include "tensorflow/contrib/lite/models/test_utils.h"

namespace tflite {
namespace models {

void RunTest(int model_input_tensor, int svdf_layer_state_tensor,
             int model_output_tensor, const string& model_name,
             const string& golden_in_name, const string& golden_out_name) {
  // Read the model.
  string tflite_file_path = StrCat(TestDataPath(), "/", model_name);
  auto model = FlatBufferModel::BuildFromFile(tflite_file_path.c_str());
  CHECK(model) << "Failed to read model from file " << tflite_file_path;

  // Initialize the interpreter.
  ops::builtin::BuiltinOpResolver builtins;
  std::unique_ptr<Interpreter> interpreter;
  InterpreterBuilder(*model, builtins)(&interpreter);
  CHECK(interpreter != nullptr);
  interpreter->AllocateTensors();

  // Reset the SVDF layer state.
  memset(interpreter->tensor(svdf_layer_state_tensor)->data.raw, 0,
         interpreter->tensor(svdf_layer_state_tensor)->bytes);

  // Load the input frames.
  Frames input_frames;
  const string input_file_path = StrCat(TestDataPath(), "/", golden_in_name);
  ReadFrames(input_file_path, &input_frames);

  // Load the golden output results.
  Frames output_frames;
  const string output_file_path = StrCat(TestDataPath(), "/", golden_out_name);
  ReadFrames(output_file_path, &output_frames);

  const int speech_batch_size =
      interpreter->tensor(model_input_tensor)->dims->data[0];
  const int speech_input_size =
      interpreter->tensor(model_input_tensor)->dims->data[1];
  const int speech_output_size =
      interpreter->tensor(model_output_tensor)->dims->data[1];
  const int input_sequence_size =
      input_frames[0].size() / (speech_input_size * speech_batch_size);
  float* input_ptr = interpreter->tensor(model_input_tensor)->data.f;
  float* output_ptr = interpreter->tensor(model_output_tensor)->data.f;

  // The first layer (SVDF) input size is 40 (speech_input_size). Each speech
  // input frames for this model is 1280 floats, which can be fed to input in a
  // sequence of size 32 (input_sequence_size).
  for (int i = 0; i < TestInputSize(input_frames); i++) {
    int frame_ptr = 0;
    for (int s = 0; s < input_sequence_size; s++) {
      for (int k = 0; k < speech_input_size * speech_batch_size; k++) {
        input_ptr[k] = input_frames[i][frame_ptr++];
      }
      interpreter->Invoke();
    }
    // After the whole frame (1280 floats) is fed, we can check the output frame
    // matches with the golden output frame.
    for (int k = 0; k < speech_output_size; k++) {
      ASSERT_NEAR(output_ptr[k], output_frames[i][k], 1e-5);
    }
  }
}

TEST(SpeechHotword, OkGoogleTestRank1) {
  constexpr int kModelInputTensor = 0;
  constexpr int kSvdfLayerStateTensor = 4;
  constexpr int kModelOutputTensor = 18;

  RunTest(kModelInputTensor, kSvdfLayerStateTensor, kModelOutputTensor,
          "speech_hotword_model_rank1.tflite", "speech_hotword_model_in.csv",
          "speech_hotword_model_out_rank1.csv");
}

TEST(SpeechHotword, OkGoogleTestRank2) {
  constexpr int kModelInputTensor = 17;
  constexpr int kSvdfLayerStateTensor = 1;
  constexpr int kModelOutputTensor = 18;
  RunTest(kModelInputTensor, kSvdfLayerStateTensor, kModelOutputTensor,
          "speech_hotword_model_rank2.tflite", "speech_hotword_model_in.csv",
          "speech_hotword_model_out_rank2.csv");
}

}  // namespace models
}  // namespace tflite
<commit_msg>Update the comment in speech_hotword_model_test.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
// Unit test for speech Hotword model using TFLite Ops.

#include <string.h>

#include <memory>
#include <string>

#include "base/logging.h"
#include "testing/base/public/googletest.h"
#include <gtest/gtest.h>
#include "absl/strings/str_cat.h"
#include "tensorflow/contrib/lite/context.h"
#include "tensorflow/contrib/lite/interpreter.h"
#include "tensorflow/contrib/lite/kernels/register.h"
#include "tensorflow/contrib/lite/model.h"
#include "tensorflow/contrib/lite/models/test_utils.h"

namespace tflite {
namespace models {

void RunTest(int model_input_tensor, int svdf_layer_state_tensor,
             int model_output_tensor, const string& model_name,
             const string& golden_in_name, const string& golden_out_name) {
  // Read the model.
  string tflite_file_path = StrCat(TestDataPath(), "/", model_name);
  auto model = FlatBufferModel::BuildFromFile(tflite_file_path.c_str());
  CHECK(model) << "Failed to read model from file " << tflite_file_path;

  // Initialize the interpreter.
  ops::builtin::BuiltinOpResolver builtins;
  std::unique_ptr<Interpreter> interpreter;
  InterpreterBuilder(*model, builtins)(&interpreter);
  CHECK(interpreter != nullptr);
  interpreter->AllocateTensors();

  // Reset the SVDF layer state.
  memset(interpreter->tensor(svdf_layer_state_tensor)->data.raw, 0,
         interpreter->tensor(svdf_layer_state_tensor)->bytes);

  // Load the input frames.
  Frames input_frames;
  const string input_file_path = StrCat(TestDataPath(), "/", golden_in_name);
  ReadFrames(input_file_path, &input_frames);

  // Load the golden output results.
  Frames output_frames;
  const string output_file_path = StrCat(TestDataPath(), "/", golden_out_name);
  ReadFrames(output_file_path, &output_frames);

  const int speech_batch_size =
      interpreter->tensor(model_input_tensor)->dims->data[0];
  const int speech_input_size =
      interpreter->tensor(model_input_tensor)->dims->data[1];
  const int speech_output_size =
      interpreter->tensor(model_output_tensor)->dims->data[1];
  const int input_sequence_size =
      input_frames[0].size() / (speech_input_size * speech_batch_size);
  float* input_ptr = interpreter->tensor(model_input_tensor)->data.f;
  float* output_ptr = interpreter->tensor(model_output_tensor)->data.f;

  // The first layer (SVDF) input size is 40 (speech_input_size). Each speech
  // input frames for this model is 1600 floats, which can be fed to input in a
  // sequence of size 40 (input_sequence_size).
  for (int i = 0; i < TestInputSize(input_frames); i++) {
    int frame_ptr = 0;
    for (int s = 0; s < input_sequence_size; s++) {
      for (int k = 0; k < speech_input_size * speech_batch_size; k++) {
        input_ptr[k] = input_frames[i][frame_ptr++];
      }
      interpreter->Invoke();
    }
    // After the whole frame (1280 floats) is fed, we can check the output frame
    // matches with the golden output frame.
    for (int k = 0; k < speech_output_size; k++) {
      ASSERT_NEAR(output_ptr[k], output_frames[i][k], 1e-5);
    }
  }
}

TEST(SpeechHotword, OkGoogleTestRank1) {
  constexpr int kModelInputTensor = 0;
  constexpr int kSvdfLayerStateTensor = 4;
  constexpr int kModelOutputTensor = 18;

  RunTest(kModelInputTensor, kSvdfLayerStateTensor, kModelOutputTensor,
          "speech_hotword_model_rank1.tflite", "speech_hotword_model_in.csv",
          "speech_hotword_model_out_rank1.csv");
}

TEST(SpeechHotword, OkGoogleTestRank2) {
  constexpr int kModelInputTensor = 17;
  constexpr int kSvdfLayerStateTensor = 1;
  constexpr int kModelOutputTensor = 18;
  RunTest(kModelInputTensor, kSvdfLayerStateTensor, kModelOutputTensor,
          "speech_hotword_model_rank2.tflite", "speech_hotword_model_in.csv",
          "speech_hotword_model_out_rank2.csv");
}

}  // namespace models
}  // namespace tflite
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2012-2016, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software 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 "ai.h"

#include "IECore/VectorTypedData.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/Primitive.h"
#include "IECore/MessageHandler.h"

#include "IECoreArnold/ParameterAlgo.h"
#include "IECoreArnold/ShapeAlgo.h"

using namespace std;
using namespace IECore;
using namespace IECoreArnold;

//////////////////////////////////////////////////////////////////////////
// Internal utilities
//////////////////////////////////////////////////////////////////////////

namespace
{

AtArray *identityIndices( size_t size )
{
	AtArray *result = AiArrayAllocate( size, 1, AI_TYPE_UINT );
	for( size_t i=0; i < size; ++i )
	{
		AiArraySetInt( result, i, i );
	}
	return result;
}

ConstFloatVectorDataPtr radius( const Primitive *primitive )
{
	if( ConstFloatVectorDataPtr radius = primitive->variableData<FloatVectorData>( "radius" ) )
	{
		return radius;
	}

	FloatVectorDataPtr calculatedRadius = new FloatVectorData();
	if( const FloatData *constantRadius = primitive->variableData<FloatData>( "radius", PrimitiveVariable::Constant ) )
	{
		calculatedRadius->writable().push_back( constantRadius->readable() );
	}
	else if( const FloatVectorData *width = primitive->variableData<FloatVectorData>( "width" ) )
	{
		calculatedRadius->writable().resize( width->readable().size() );
		const std::vector<float>::iterator end = calculatedRadius->writable().end();
		std::vector<float>::const_iterator wIt = width->readable().begin();
		for( std::vector<float>::iterator it = calculatedRadius->writable().begin(); it != end; it++, wIt++ )
		{
			*it = *wIt / 2.0f;
		}
	}
	else
	{
		const FloatData *constantWidth = primitive->variableData<FloatData>( "width", PrimitiveVariable::Constant );
		if( !constantWidth )
		{
			constantWidth = primitive->variableData<FloatData>( "constantwidth", PrimitiveVariable::Constant );
		}
		float r = constantWidth ? constantWidth->readable() / 2.0f : 0.5f;
		calculatedRadius->writable().push_back( r );
	}
	return calculatedRadius;
}

} // namespace

//////////////////////////////////////////////////////////////////////////
// Implementation of public API.
//////////////////////////////////////////////////////////////////////////

namespace IECoreArnold
{

namespace ShapeAlgo
{

void convertP( const IECore::Primitive *primitive, AtNode *shape, const char *name )
{
	const V3fVectorData *p = primitive->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
	if( !p )
	{
		throw Exception( "Primitive does not have \"P\" primitive variable of interpolation type Vertex." );
	}

	AiNodeSetArray(
		shape,
		name,
		AiArrayConvert( p->readable().size(), 1, AI_TYPE_POINT, (void *)&( p->readable()[0] ) )
	);
}

void convertP( const std::vector<const IECore::Primitive *> &samples, AtNode *shape, const char *name )
{
	vector<const Data *> dataSamples;
	dataSamples.reserve( samples.size() );

	for( vector<const Primitive *>::const_iterator it = samples.begin(), eIt = samples.end(); it != eIt; ++it )
	{
		const V3fVectorData *p = (*it)->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		if( !p )
		{
			throw Exception( "Primitive does not have \"P\" primitive variable of interpolation type Vertex." );
		}
		dataSamples.push_back( p );
	}

	AtArray *array = ParameterAlgo::dataToArray( dataSamples, AI_TYPE_POINT );
	AiNodeSetArray( shape, name, array );
}

void convertRadius( const IECore::Primitive *primitive, AtNode *shape )
{
	ConstFloatVectorDataPtr r = radius( primitive );

	AiNodeSetArray(
		shape,
		"radius",
		AiArrayConvert( r->readable().size(), 1, AI_TYPE_FLOAT, (void *)&( r->readable()[0] ) )
	);
}

void convertRadius( const std::vector<const IECore::Primitive *> &samples, AtNode *shape )
{
	vector<ConstFloatVectorDataPtr> radiusSamples; // for ownership
	vector<const Data *> dataSamples; // for passing to dataToArray()
	radiusSamples.reserve( samples.size() );
	dataSamples.reserve( samples.size() );

	for( vector<const Primitive *>::const_iterator it = samples.begin(), eIt = samples.end(); it != eIt; ++it )
	{
		ConstFloatVectorDataPtr r = radius( *it );
		radiusSamples.push_back( r );
		dataSamples.push_back( r.get() );
	}

	AtArray *array = ParameterAlgo::dataToArray( dataSamples, AI_TYPE_FLOAT );
	AiNodeSetArray( shape, "radius", array );
}

void convertPrimitiveVariable( const IECore::Primitive *primitive, const PrimitiveVariable &primitiveVariable, AtNode *shape, const char *name )
{
	if( primitiveVariable.interpolation == PrimitiveVariable::Constant )
	{
		ParameterAlgo::setParameter( shape, name, primitiveVariable.data.get() );
	}
	else
	{
		bool isArray = false;
		int type = ParameterAlgo::parameterType( primitiveVariable.data->typeId(), isArray );
		if( type == AI_TYPE_NONE || !isArray )
		{
			msg(
				Msg::Warning,
				"ToArnoldShapeConverter::convertPrimitiveVariable",
				boost::format( "Unable to create user parameter \"%s\" for primitive variable of type \"%s\"" ) % name % primitiveVariable.data->typeName()
			);
			return;
		}

		std::string typeString;
		if( primitiveVariable.interpolation == PrimitiveVariable::Uniform )
		{
			typeString = "uniform ";
		}
		else if( primitiveVariable.interpolation == PrimitiveVariable::Vertex )
		{
			typeString = "varying ";
		}
		else if( primitive->variableSize( primitiveVariable.interpolation ) == primitive->variableSize( PrimitiveVariable::Vertex ) )
		{
			typeString = "varying ";
		}
		else if( primitiveVariable.interpolation == PrimitiveVariable::FaceVarying )
		{
			typeString = "indexed ";
		}

		if( typeString == "" )
		{
			msg(
				Msg::Warning,
				"ToArnoldShapeConverter::convertPrimitiveVariable",
				boost::format( "Unable to create user parameter \"%s\" because primitive variable has unsupported interpolation" ) % name
			);
			return;
		}

		typeString += AiParamGetTypeName( type );
		AiNodeDeclare( shape, name, typeString.c_str() );
		AtArray *array = ParameterAlgo::dataToArray( primitiveVariable.data.get() );
		if( array )
		{
			AiNodeSetArray( shape, name, array );
			if( primitiveVariable.interpolation == PrimitiveVariable::FaceVarying )
			{
				AiNodeSetArray(
					shape,
					(name + string("idxs")).c_str(),
					identityIndices( array->nelements )
				);
			}
		}
		else
		{
			msg(
				Msg::Warning,
				"ToArnoldShapeConverter::convertPrimitiveVariable",
				boost::format( "Failed to create array for parameter \"%s\" from data of type \"%s\"" ) % name % primitiveVariable.data->typeName()
			);
		}
	}
}

void convertPrimitiveVariables( const IECore::Primitive *primitive, AtNode *shape, const char **namesToIgnore )
{
	for( PrimitiveVariableMap::const_iterator it = primitive->variables.begin(), eIt = primitive->variables.end(); it!=eIt; it++ )
	{
		if( namesToIgnore )
		{
			bool skip = false;
			for( const char **n = namesToIgnore; *n; n++ )
			{
				if( it->first == *n )
				{
					skip = true;
					break;
				}
			}
			if( skip )
			{
				continue;
			}
		}

		// we prefix all the names, as otherwise the chance of a conflict between
		// an arbitrary primitive variable name and an existing arnold parameter name
		// seems too great.
		string prefixedName = "user:" + it->first;
		convertPrimitiveVariable( primitive, it->second, shape, prefixedName.c_str() );
	}
}

} // namespace ShapeAlgo

} // namespace IECoreArnold
<commit_msg>IECoreArnold::ShapeAlgo : Refactor for clarity.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2012-2016, Image Engine Design Inc. 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 Image Engine Design nor the names of any
//       other contributors to this software 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 "ai.h"

#include "IECore/VectorTypedData.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/Primitive.h"
#include "IECore/MessageHandler.h"

#include "IECoreArnold/ParameterAlgo.h"
#include "IECoreArnold/ShapeAlgo.h"

using namespace std;
using namespace IECore;
using namespace IECoreArnold;

//////////////////////////////////////////////////////////////////////////
// Internal utilities
//////////////////////////////////////////////////////////////////////////

namespace
{

AtArray *identityIndices( size_t size )
{
	AtArray *result = AiArrayAllocate( size, 1, AI_TYPE_UINT );
	for( size_t i=0; i < size; ++i )
	{
		AiArraySetInt( result, i, i );
	}
	return result;
}

ConstFloatVectorDataPtr radius( const Primitive *primitive )
{
	if( ConstFloatVectorDataPtr radius = primitive->variableData<FloatVectorData>( "radius" ) )
	{
		return radius;
	}

	FloatVectorDataPtr calculatedRadius = new FloatVectorData();
	if( const FloatData *constantRadius = primitive->variableData<FloatData>( "radius", PrimitiveVariable::Constant ) )
	{
		calculatedRadius->writable().push_back( constantRadius->readable() );
	}
	else if( const FloatVectorData *width = primitive->variableData<FloatVectorData>( "width" ) )
	{
		calculatedRadius->writable().resize( width->readable().size() );
		const std::vector<float>::iterator end = calculatedRadius->writable().end();
		std::vector<float>::const_iterator wIt = width->readable().begin();
		for( std::vector<float>::iterator it = calculatedRadius->writable().begin(); it != end; it++, wIt++ )
		{
			*it = *wIt / 2.0f;
		}
	}
	else
	{
		const FloatData *constantWidth = primitive->variableData<FloatData>( "width", PrimitiveVariable::Constant );
		if( !constantWidth )
		{
			constantWidth = primitive->variableData<FloatData>( "constantwidth", PrimitiveVariable::Constant );
		}
		float r = constantWidth ? constantWidth->readable() / 2.0f : 0.5f;
		calculatedRadius->writable().push_back( r );
	}
	return calculatedRadius;
}

} // namespace

//////////////////////////////////////////////////////////////////////////
// Implementation of public API.
//////////////////////////////////////////////////////////////////////////

namespace IECoreArnold
{

namespace ShapeAlgo
{

void convertP( const IECore::Primitive *primitive, AtNode *shape, const char *name )
{
	const V3fVectorData *p = primitive->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
	if( !p )
	{
		throw Exception( "Primitive does not have \"P\" primitive variable of interpolation type Vertex." );
	}

	AiNodeSetArray(
		shape,
		name,
		AiArrayConvert( p->readable().size(), 1, AI_TYPE_POINT, (void *)&( p->readable()[0] ) )
	);
}

void convertP( const std::vector<const IECore::Primitive *> &samples, AtNode *shape, const char *name )
{
	vector<const Data *> dataSamples;
	dataSamples.reserve( samples.size() );

	for( vector<const Primitive *>::const_iterator it = samples.begin(), eIt = samples.end(); it != eIt; ++it )
	{
		const V3fVectorData *p = (*it)->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		if( !p )
		{
			throw Exception( "Primitive does not have \"P\" primitive variable of interpolation type Vertex." );
		}
		dataSamples.push_back( p );
	}

	AtArray *array = ParameterAlgo::dataToArray( dataSamples, AI_TYPE_POINT );
	AiNodeSetArray( shape, name, array );
}

void convertRadius( const IECore::Primitive *primitive, AtNode *shape )
{
	ConstFloatVectorDataPtr r = radius( primitive );

	AiNodeSetArray(
		shape,
		"radius",
		AiArrayConvert( r->readable().size(), 1, AI_TYPE_FLOAT, (void *)&( r->readable()[0] ) )
	);
}

void convertRadius( const std::vector<const IECore::Primitive *> &samples, AtNode *shape )
{
	vector<ConstFloatVectorDataPtr> radiusSamples; // for ownership
	vector<const Data *> dataSamples; // for passing to dataToArray()
	radiusSamples.reserve( samples.size() );
	dataSamples.reserve( samples.size() );

	for( vector<const Primitive *>::const_iterator it = samples.begin(), eIt = samples.end(); it != eIt; ++it )
	{
		ConstFloatVectorDataPtr r = radius( *it );
		radiusSamples.push_back( r );
		dataSamples.push_back( r.get() );
	}

	AtArray *array = ParameterAlgo::dataToArray( dataSamples, AI_TYPE_FLOAT );
	AiNodeSetArray( shape, "radius", array );
}

void convertPrimitiveVariable( const IECore::Primitive *primitive, const PrimitiveVariable &primitiveVariable, AtNode *shape, const char *name )
{
	// Deal with the simple case of constant data.

	if( primitiveVariable.interpolation == PrimitiveVariable::Constant )
	{
		ParameterAlgo::setParameter( shape, name, primitiveVariable.data.get() );
		return;
	}

	// Now deal with more complex cases with array data.

	bool isArray = false;
	int type = ParameterAlgo::parameterType( primitiveVariable.data->typeId(), isArray );
	if( type == AI_TYPE_NONE || !isArray )
	{
		msg(
			Msg::Warning,
			"ToArnoldShapeConverter::convertPrimitiveVariable",
			boost::format( "Unable to create user parameter \"%s\" for primitive variable of type \"%s\"" ) % name % primitiveVariable.data->typeName()
		);
		return;
	}

	std::string typeString;
	if( primitiveVariable.interpolation == PrimitiveVariable::Uniform )
	{
		typeString = "uniform ";
	}
	else if( primitiveVariable.interpolation == PrimitiveVariable::Vertex )
	{
		typeString = "varying ";
	}
	else if( primitive->variableSize( primitiveVariable.interpolation ) == primitive->variableSize( PrimitiveVariable::Vertex ) )
	{
		typeString = "varying ";
	}
	else if( primitiveVariable.interpolation == PrimitiveVariable::FaceVarying )
	{
		typeString = "indexed ";
	}

	if( typeString == "" )
	{
		msg(
			Msg::Warning,
			"ToArnoldShapeConverter::convertPrimitiveVariable",
			boost::format( "Unable to create user parameter \"%s\" because primitive variable has unsupported interpolation" ) % name
		);
		return;
	}

	typeString += AiParamGetTypeName( type );
	AiNodeDeclare( shape, name, typeString.c_str() );
	AtArray *array = ParameterAlgo::dataToArray( primitiveVariable.data.get() );
	if( array )
	{
		AiNodeSetArray( shape, name, array );
		if( primitiveVariable.interpolation == PrimitiveVariable::FaceVarying )
		{
			AiNodeSetArray(
				shape,
				(name + string("idxs")).c_str(),
				identityIndices( array->nelements )
			);
		}
	}
	else
	{
		msg(
			Msg::Warning,
			"ToArnoldShapeConverter::convertPrimitiveVariable",
			boost::format( "Failed to create array for parameter \"%s\" from data of type \"%s\"" ) % name % primitiveVariable.data->typeName()
		);
	}
}

void convertPrimitiveVariables( const IECore::Primitive *primitive, AtNode *shape, const char **namesToIgnore )
{
	for( PrimitiveVariableMap::const_iterator it = primitive->variables.begin(), eIt = primitive->variables.end(); it!=eIt; it++ )
	{
		if( namesToIgnore )
		{
			bool skip = false;
			for( const char **n = namesToIgnore; *n; n++ )
			{
				if( it->first == *n )
				{
					skip = true;
					break;
				}
			}
			if( skip )
			{
				continue;
			}
		}

		// we prefix all the names, as otherwise the chance of a conflict between
		// an arbitrary primitive variable name and an existing arnold parameter name
		// seems too great.
		string prefixedName = "user:" + it->first;
		convertPrimitiveVariable( primitive, it->second, shape, prefixedName.c_str() );
	}
}

} // namespace ShapeAlgo

} // namespace IECoreArnold
<|endoftext|>


<commit_before>#ifndef GUARD_signature_hpp
#define GUARD_signature_hpp

#include <boost/noncopyable.hpp>

namespace jewel
{

/**
 * The instantiation of this template for a class T is a
 * non-copyable class the constructor of which is only
 * accessible by
 * class T. This provides a mechanism whereby a
 * function that wants to ensure at compile time
 * that it can only be called by class T, can achieve
 * this simply by having a
 * parameter of type Signature<T>& (or Signature<T> const&).
 * This provides a fine-grained, function-level means of
 * access control, that is not directly provided by
 * the \e friend mechanism.
 */
template <class T>
class Signature:
	private boost::noncopyable
{
public:
	friend T;
private:
	Signature();
};

template <class T>
inline
Signature<T>::Signature()
{
}

}  // namespace jewel

#endif  // GUARD_signature_hpp
<commit_msg>Added note re. jewel::Signature being strictly non-conformant pre-C++11.<commit_after>#ifndef GUARD_signature_hpp
#define GUARD_signature_hpp

#include <boost/noncopyable.hpp>

namespace jewel
{

/**
 * The instantiation of this template for a class T is a
 * non-copyable class the constructor of which is only
 * accessible by
 * class T. This provides a mechanism whereby a
 * function that wants to ensure at compile time
 * that it can only be called by class T, can achieve
 * this simply by having a
 * parameter of type Signature<T>& (or Signature<T> const&).
 * This provides a fine-grained, function-level means of
 * access control, that is not directly provided by
 * the \e friend mechanism.
 */
template <class T>
class Signature:
	private boost::noncopyable
{
public:
	// WARNING this is non-conformant prior to C++11; although
	// some C++98 compilers neverthless allow it.
	friend T;
private:
	Signature();
};

template <class T>
inline
Signature<T>::Signature()
{
}

}  // namespace jewel

#endif  // GUARD_signature_hpp
<|endoftext|>


<commit_before>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <sstream>
#include "app/canvas.hh"
#include "formats/format.hh"
#include "formats/gif/file-gif.hh"
#include "text/formatting.hh"
#include "util/image.hh"
#include "util/image-util.hh"
#include "util/index-iter.hh"
#include "util/frame-iter.hh"
#include "util/make-vector.hh"

namespace faint{

static size_t find_mismatch_index(const std::vector<IntSize>& sizes){
  assert(!sizes.empty());
  size_t i = 1;
  for (; i != sizes.size(); i++){
    if (sizes[i] != sizes[0]){
      break;
    }
  }
  return i;
}

static bool uniform_size(const std::vector<IntSize>& sizes){
  return find_mismatch_index(sizes) == sizes.size();
}

static SaveResult fail_size_mismatch(const std::vector<IntSize>& sizes){
  size_t index = find_mismatch_index(sizes);
  assert(index != sizes.size());
  std::stringstream ss;
  ss << "This image can not be saved as a gif." << std::endl << std::endl <<
    "It contains frames of different sizes." << std::endl <<
    "Frame 1: " << str(sizes[0]) << std::endl <<
    "Frame " << index + 1 << ": " << str(sizes[index]);
  return SaveResult::SaveFailed(utf8_string(ss.str()));
}

static std::vector<IntSize> get_frame_sizes(Canvas& canvas){
  const auto get_size = [](const auto& frame){return frame.GetSize();};
  return make_vector(canvas, get_size);
}

class FormatGIF : public Format {
public:
  FormatGIF()
    : Format(FileExtension("gif"),
      label_t(utf8_string("Graphics Interchange Format (GIF)")),
      can_save(true),
      can_load(true))
  {}

  void Load(const FilePath& filePath, ImageProps& imageProps) override{
    read_gif(filePath, imageProps);
  }

  SaveResult Save(const FilePath& filePath, Canvas& canvas) override{
    // Verify that all frames have the same size
    std::vector<IntSize> sizes = get_frame_sizes(canvas);
    if (!uniform_size(sizes)){
      return fail_size_mismatch(sizes);
    }

    // Flatten and quantize
    std::vector<MappedColors_and_delay> images;

    for (const auto& f : canvas){
      // Fixme: Consider using the same palette for multiple frames
      images.emplace_back(quantized(flatten(f), Dithering::ON), f.GetDelay());
    }

    return write_gif(filePath, images);
  }
};

Format* format_gif(){
  return new FormatGIF();
}

} // namespace
<commit_msg>Using <algorithms> some more.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// Licensed under the Apache License, Version 2.0 (the "License"); you
// may not use this file except in compliance with the License. You
// may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.

#include <algorithm>
#include <sstream>
#include "app/canvas.hh"
#include "formats/format.hh"
#include "formats/gif/file-gif.hh"
#include "text/formatting.hh"
#include "util/image.hh"
#include "util/image-util.hh"
#include "util/index-iter.hh"
#include "util/frame-iter.hh"
#include "util/make-vector.hh"

namespace faint{

static auto find_mismatch(const std::vector<IntSize>& sizes){
  const auto not_equal =
    [first = sizes.front()](const auto& sz){ return sz != first;};
  return std::find_if(sizes.begin(), sizes.end(), not_equal);
}

static bool uniform_size(const std::vector<IntSize>& sizes){
  return find_mismatch(sizes) == sizes.end();
}

static SaveResult fail_size_mismatch(const std::vector<IntSize>& sizes){
  size_t index = std::distance(begin(sizes), find_mismatch(sizes));
  assert(index != sizes.size());
  std::stringstream ss;
  ss << "This image can not be saved as a gif." << std::endl << std::endl <<
    "It contains frames of different sizes." << std::endl <<
    "Frame 1: " << str(sizes[0]) << std::endl <<
    "Frame " << index + 1 << ": " << str(sizes[index]);
  return SaveResult::SaveFailed(utf8_string(ss.str()));
}

static std::vector<IntSize> get_frame_sizes(Canvas& canvas){
  const auto get_size = [](const auto& frame){return frame.GetSize();};
  return make_vector(canvas, get_size);
}

class FormatGIF : public Format {
public:
  FormatGIF()
    : Format(FileExtension("gif"),
      label_t(utf8_string("Graphics Interchange Format (GIF)")),
      can_save(true),
      can_load(true))
  {}

  void Load(const FilePath& filePath, ImageProps& imageProps) override{
    read_gif(filePath, imageProps);
  }

  SaveResult Save(const FilePath& filePath, Canvas& canvas) override{
    // Verify that all frames have the same size
    auto sizes = get_frame_sizes(canvas);
    if (!uniform_size(sizes)){
      return fail_size_mismatch(sizes);
    }

    // Flatten and quantize
    std::vector<MappedColors_and_delay> images;
    for (const auto& f : canvas){
      // Fixme: Consider using the same palette for multiple frames
      images.emplace_back(quantized(flatten(f), Dithering::ON), f.GetDelay());
    }

    return write_gif(filePath, images);
  }
};

Format* format_gif(){
  return new FormatGIF();
}

} // namespace
<|endoftext|>


<commit_before>//
//  video_manager.cpp
//  emptyExample
//
//  Created by Mark van de Korput on 16-05-03.
//
//

#include "video_manager.hpp"
#include "xml_settings.hpp"

using namespace of2030;

SINGLETON_INLINE_IMPLEMENTATION_CODE(VideoManager)

VideoManager::VideoManager(){
#ifdef __APPLE__
    folder_path = "vids/_osx/";
#else
    folder_path = "vids/_raspi/";
#endif // __APPLE__
}

void VideoManager::destroy(){
    // don't iterate like normal, because the iterator gets corrupted and causes
    // BAD ACCESS errors when the map gets modified during its iterations
    // we'll just take the first item every time and remove it, until there's nothing left
    while(!players.empty()){
        unload(players.begin()->first);
    }

    players.clear();
}
//void VideoManager::setup(){
//
//}

void VideoManager::update(){
    for(auto& pair: players){
        pair.second->update();
    }
}

ofVideoPlayer* VideoManager::get(const string &video_name, bool load){
    // assume alias IS the video's path
    return get(video_name, video_name, load);
}

ofVideoPlayer* VideoManager::get(const string &video_name, const string &alias, bool load){
    std::map<string,ofVideoPlayer*>::iterator it = players.find(alias);

    // found it
    if(it != players.end()){
        return it->second;
    }

    // not found, no loading
    if(!load)
        return NULL;

    // (try to) create a player
    ofVideoPlayer* player = createPlayer(video_name);

    // store it
    if(player){
        ofLog() << alias << " loaded.";
        players[alias] = player;
    }

    // return it
    return player;
}

bool VideoManager::unload(const string &alias){
    ofLog() << "VideoManager::unload with " << alias;

    // No specific player specified? destroy all
    if(alias == ""){
        destroy();
        return true;
    }

    // find specified player
    std::map<string,ofVideoPlayer*>::iterator it = players.find(alias);

    // not found, abort
    if(it == players.end()){
        ofLogWarning() << "VideoManager::unload player not found";
        return false;
    }

    ofNotifyEvent(unloadEvent, *it->second, this);

    // remove from our list
    players.erase(it);

    if(it->second){
        // close player/video file
        it->second->close();
        // delete instance from memory
        delete it->second;
    }

    // log and report
    ofLog() << "Video players still loaded: " << players.size();
    return true;
}

void VideoManager::unload(ofVideoPlayer *player){
    if(player == NULL){
        return;
    }

    // find player
    for (auto& pair: players) {
        // this one?
        if(pair.second == player){
            unload(pair.first);
        }
    }
}

ofVideoPlayer* VideoManager::createPlayer(const string &video_name){
    string path = video_name_to_path(video_name);

    ofLog() << "VideoManager::createPlayer loading: " << path; //player->getMoviePath();

    if(!ofFile::doesFileExist(path)){
        ofLogWarning() << "could not find video file.";
        return NULL;
    }

    ofVideoPlayer *player = new ofVideoPlayer;
    if(XmlSettings::instance()->rgbaVidPixels){
        player->setPixelFormat(OF_PIXELS_RGBA);
    }
    player->loadAsync(path);
    player->setVolume(0.0f);
    return player;
}
<commit_msg>video manager minor tweak<commit_after>//
//  video_manager.cpp
//  emptyExample
//
//  Created by Mark van de Korput on 16-05-03.
//
//

#include "video_manager.hpp"
#include "xml_settings.hpp"

using namespace of2030;

SINGLETON_INLINE_IMPLEMENTATION_CODE(VideoManager)

VideoManager::VideoManager(){
#ifdef __APPLE__
    folder_path = "vids/_osx/";
#else
    folder_path = "vids/_raspi/";
#endif // __APPLE__
}

void VideoManager::destroy(){
    // don't iterate like normal, because the iterator gets corrupted and causes
    // BAD ACCESS errors when the map gets modified during its iterations
    // we'll just take the first item every time and remove it, until there's nothing left
    while(!players.empty()){
        unload(players.begin()->first);
    }

    players.clear();
}
//void VideoManager::setup(){
//
//}

void VideoManager::update(){
    for(auto& pair: players){
        pair.second->update();
    }
}

ofVideoPlayer* VideoManager::get(const string &video_name, bool load){
    // assume alias IS the video's path
    return get(video_name, video_name, load);
}

ofVideoPlayer* VideoManager::get(const string &video_name, const string &alias, bool load){
    std::map<string,ofVideoPlayer*>::iterator it = players.find(alias);

    // found it
    if(it != players.end()){
        return it->second;
    }

    // not found, no loading
    if(!load)
        return NULL;

    // (try to) create a player
    ofVideoPlayer* player = createPlayer(video_name);

    // store it
    if(player){
        ofLog() << alias << " loaded.";
        players[alias] = player;
    }

    // return it
    return player;
}

bool VideoManager::unload(const string &alias){
    ofLog() << "VideoManager::unload with " << alias;

    // No specific player specified? destroy all
    if(alias == ""){
        destroy();
        return true;
    }

    // find specified player
    std::map<string,ofVideoPlayer*>::iterator it = players.find(alias);

    // not found, abort
    if(it == players.end()){
        ofLogWarning() << "VideoManager::unload player not found";
        return false;
    }

    ofNotifyEvent(unloadEvent, *it->second, this);

    if(it->second){
        // close player/video file
        it->second->close();
        // delete instance from memory
        delete it->second;
    }

    // remove from our list
    players.erase(it);

    // log and report
    ofLog() << "Video players still loaded: " << players.size();
    return true;
}

void VideoManager::unload(ofVideoPlayer *player){
    if(player == NULL){
        return;
    }

    // find player
    for (auto& pair: players) {
        // this one?
        if(pair.second == player){
            unload(pair.first);
        }
    }
}

ofVideoPlayer* VideoManager::createPlayer(const string &video_name){
    string path = video_name_to_path(video_name);

    ofLog() << "VideoManager::createPlayer loading: " << path; //player->getMoviePath();

    if(!ofFile::doesFileExist(path)){
        ofLogWarning() << "could not find video file.";
        return NULL;
    }

    ofVideoPlayer *player = new ofVideoPlayer;
    if(XmlSettings::instance()->rgbaVidPixels){
        player->setPixelFormat(OF_PIXELS_RGBA);
    }
    player->loadAsync(path);
    player->setVolume(0.0f);
    return player;
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) Jason White
 *
 * MIT License
 *
 * Description:
 * Removes comments and unnecessary whitespace from a Lua file. This is useful
 * for embedding Lua scripts into an executable.
 */
#include <stdio.h>
#include <string.h>
#include <ctype.h>

const char* read_file(FILE* f, size_t* len) {

    // Find the length of the file
    fseek(f, 0, SEEK_END);
    *len = (size_t)ftell(f);
    if (fseek(f, 0, SEEK_SET) != 0) {
        return NULL;
    }

    char* buf = new char[*len];

    if (!buf || fread(buf, 1, *len, f) != *len) {
        return NULL;
    }

    return (const char*)buf;
}

size_t skip_block_comment(const char* buf, size_t len) {
    size_t i = 0;

    if (len >= 4 && strncmp(buf, "--[[", 4) == 0) {
        i += 4;

        while (i < (len - 2)) {
            if (strncmp(buf+i, "]]", 2) == 0) {
                i += 2;
                return i;
            }

            ++i;
        }
    }

    return i;
}

enum StringType {
    STRING_NONE,
    STRING_BLOCK,
    STRING_SINGLE,
    STRING_DOUBLE,
};

size_t skip_string(const char* buf, size_t len) {
    size_t i = 0;

    StringType t = STRING_NONE;

    if (i < len) {
        switch (buf[i]) {
            case '"': t = STRING_DOUBLE; i += 1; break;
            case '\'': t = STRING_SINGLE; i += 1; break;
            case '[':
                if ((len-i) >= 2 && buf[i+1] == '[') {
                    t = STRING_BLOCK;
                    i += 2;
                    break;
                }
                return 0;
            default:
                return 0;
        }
    }

    while (i < len) {
        switch (buf[i]) {
            case '"':
                if (t == STRING_DOUBLE && buf[i-1] != '\\')
                    return i+1;
                break;
            case '\'':
                if (t == STRING_SINGLE && buf[i-1] != '\\')
                    return i+1;
                break;
            case ']':
                if (t == STRING_BLOCK && buf[i-1] != '\\' &&
                    (len-i) > 0 && buf[i+1] == ']')
                    return i+2;
                break;
        }

        ++i;
    }

    if (i > 0)
        fwrite(buf, 1, i, stdout);

    return i;
}

size_t skip_line_comment(const char* buf, size_t len) {
    size_t i = 0;

    if (len >= 2 && strncmp(buf, "--", 2) == 0) {
        i += 2;

        while (i < len && buf[i] != '\n')
            ++i;

        if (buf[i-1] == '\n')
            --i;
    }

    return i;
}

size_t skip_trailing_spaces(const char* buf, size_t len) {
    size_t i = 0;

    // Replace \s*\n with \n
    while (i < len && isblank(buf[i]))
        ++i;

    if (i < len && buf[i] == '\n')
        return i;

    return 0;
}

size_t skip_whitespace(const char* buf, size_t len) {
    size_t i = 0;

    // Replace \n\s* with \n
    if (len > 0 && buf[i] == '\n') {
        ++i;

        while (i < len && isspace(buf[i]))
            ++i;

        putchar('\n');
    }

    return i;
}

void minify(const char* buf, size_t len) {

    size_t delta = 0;

    for (size_t i = 0; i < len; ) {
        while (true) {
            delta = 0;
            delta += skip_block_comment(buf+i+delta, len-i-delta);
            delta += skip_line_comment(buf+i+delta, len-i-delta);
            delta += skip_trailing_spaces(buf+i+delta, len-i-delta);
            delta += skip_whitespace(buf+i+delta, len-i-delta);
            delta += skip_string(buf+i+delta, len-i-delta);

            // As long as we can keep doing work, keep going.
            if (delta > 0) {
                i += delta;
                continue;
            }

            break;
        }

        putchar(buf[i]);
        ++i;
    }
}

int main(int argc, char** argv)
{
    if (argc <= 1) {
        puts("Usage: luamin FILE");
        return 1;
    }

    FILE* f = fopen(argv[1], "rb");
    if (!f) {
        perror("failed to open file");
        return 1;
    }

    size_t len;
    const char* buf = read_file(f, &len);

    fclose(f);

    if (!buf) {
        perror("failed to read file");
        return 1;
    }

    minify(buf, len);

    return 0;
}
<commit_msg>Remove unused luaminify tool<commit_after><|endoftext|>


<commit_before>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include "../../../core/Setup.h"

#if defined(__ANDROID__) && OUZEL_COMPILE_OPENGL

#include "OGLRenderDeviceAndroid.hpp"
#include "../EGLErrorCategory.hpp"
#include "../../../core/Engine.hpp"
#include "../../../core/Window.hpp"
#include "../../../core/android/NativeWindowAndroid.hpp"
#include "../../../utils/Log.hpp"

namespace ouzel::graphics::opengl::android
{
    namespace
    {
        const egl::ErrorCategory eglErrorCategory{};
    }

    RenderDevice::RenderDevice(const Settings& settings,
                               core::Window& initWindow,
                               const std::function<void(const Event&)>& initCallback):
        opengl::RenderDevice(settings, initWindow, initCallback)
    {
        embedded = true;

        display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

        if (display == EGL_NO_DISPLAY)
            throw std::runtime_error("Failed to get display");

        if (!eglInitialize(display, nullptr, nullptr))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to initialize EGL");

        const EGLint attributeList[] = {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, settings.depth ? 24 : 0,
            EGL_STENCIL_SIZE, settings.stencil ? 8 : 0,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_SAMPLE_BUFFERS, (settings.sampleCount > 1) ? 1 : 0,
            EGL_SAMPLES, static_cast<int>(settings.sampleCount),
            EGL_NONE
        };
        EGLConfig config;
        EGLint numConfig;
        if (!eglChooseConfig(display, attributeList, &config, 1, &numConfig))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to choose EGL config");

        if (!eglBindAPI(EGL_OPENGL_ES_API))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to bind OpenGL ES API");

        EGLint format;
        if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to get config attribute");

        auto windowAndroid = static_cast<core::android::NativeWindow*>(window.getNativeWindow());

        ANativeWindow_setBuffersGeometry(windowAndroid->getNativeWindow(), 0, 0, format);

        surface = eglCreateWindowSurface(display, config, windowAndroid->getNativeWindow(), nullptr);
        if (surface == EGL_NO_SURFACE)
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to create EGL window surface");

        for (EGLint version = 3; version >= 2; --version)
        {
            const EGLint contextAttributes[] = {
                EGL_CONTEXT_CLIENT_VERSION, version,
                EGL_CONTEXT_OPENGL_DEBUG, settings.debugRenderer ? EGL_TRUE : EGL_FALSE,
                EGL_NONE
            };

            context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);

            if (context != EGL_NO_CONTEXT)
            {
                apiVersion = ApiVersion(version, 0);
                logger.log(Log::Level::info) << "EGL OpenGL ES " << version << " context created";
                break;
            }
        }

        if (context == EGL_NO_CONTEXT)
            throw std::runtime_error("Failed to create EGL context");

        if (!eglMakeCurrent(display, surface, surface, context))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set current EGL context");

        if (!eglSwapInterval(display, settings.verticalSync ? 1 : 0))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set EGL frame interval");

        EGLint surfaceWidth;
        EGLint surfaceHeight;

        if (!eglQuerySurface(display, surface, EGL_WIDTH, &surfaceWidth) ||
            !eglQuerySurface(display, surface, EGL_HEIGHT, &surfaceHeight))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to get query window size");

        init(surfaceWidth, surfaceHeight);

        if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to unset EGL context");

        running = true;
        renderThread = Thread(&RenderDevice::renderMain, this);
    }

    RenderDevice::~RenderDevice()
    {
        running = false;
        CommandBuffer commandBuffer;
        commandBuffer.pushCommand(std::make_unique<PresentCommand>());
        submitCommandBuffer(std::move(commandBuffer));

        if (renderThread.isJoinable()) renderThread.join();

        if (context != EGL_NO_CONTEXT)
        {
            eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
            eglDestroyContext(display, context);
        }

        if (surface != EGL_NO_SURFACE)
            eglDestroySurface(display, surface);

        if (display != EGL_NO_DISPLAY)
            eglTerminate(display);
    }

    void RenderDevice::reload()
    {
        running = false;
        CommandBuffer commandBuffer;
        commandBuffer.pushCommand(std::make_unique<PresentCommand>());
        submitCommandBuffer(std::move(commandBuffer));

        if (renderThread.isJoinable()) renderThread.join();

        const EGLint attributeList[] =
        {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, depth ? 24 : 0,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_SAMPLE_BUFFERS, (sampleCount > 1) ? 1 : 0,
            EGL_SAMPLES, static_cast<int>(sampleCount),
            EGL_NONE
        };
        EGLConfig config;
        EGLint numConfig;
        if (!eglChooseConfig(display, attributeList, &config, 1, &numConfig))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to choose EGL config");

        if (!eglBindAPI(EGL_OPENGL_ES_API))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to bind OpenGL ES API");

        EGLint format;
        if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to get config attribute");

        auto windowAndroid = static_cast<core::android::NativeWindow*>(window.getNativeWindow());

        ANativeWindow_setBuffersGeometry(windowAndroid->getNativeWindow(), 0, 0, format);

        surface = eglCreateWindowSurface(display, config, windowAndroid->getNativeWindow(), nullptr);
        if (surface == EGL_NO_SURFACE)
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to create EGL window surface");

        for (EGLint version = 3; version >= 2; --version)
        {
            const EGLint contextAttributes[] = {
                EGL_CONTEXT_CLIENT_VERSION, version,
                EGL_CONTEXT_OPENGL_DEBUG, settings.debugRenderer ? EGL_TRUE : EGL_FALSE,
                EGL_NONE
            };

            context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);

            if (context != EGL_NO_CONTEXT)
            {
                apiVersion = ApiVersion(version, 0);
                logger.log(Log::Level::info) << "EGL OpenGL ES " << version << " context created";
                break;
            }
        }

        if (context == EGL_NO_CONTEXT)
            throw std::runtime_error("Failed to create EGL context");

        if (!eglMakeCurrent(display, surface, surface, context))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set current EGL context");

        if (!eglSwapInterval(display, verticalSync ? 1 : 0))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set EGL frame interval");

        EGLint surfaceWidth;
        EGLint surfaceHeight;

        if (!eglQuerySurface(display, surface, EGL_WIDTH, &surfaceWidth) ||
            !eglQuerySurface(display, surface, EGL_HEIGHT, &surfaceHeight))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to get query window size");

        frameBufferWidth = surfaceWidth;
        frameBufferHeight = surfaceHeight;

        stateCache = StateCache();

        glDisableProc(GL_DITHER);
        glDepthFuncProc(GL_LEQUAL);

        GLenum error;

        if ((error = glGetErrorProc()) != GL_NO_ERROR)
            throw std::system_error(makeErrorCode(error), "Failed to set depth function");

        if (glGenVertexArraysProc) glGenVertexArraysProc(1, &vertexArrayId);

        for (const auto& resource : resources)
            if (resource) resource->invalidate();

        for (const auto& resource : resources)
            if (resource) resource->restore();

        if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to unset EGL context");

        running = true;
        renderThread = Thread(&RenderDevice::renderMain, this);
    }

    void RenderDevice::destroy()
    {
        running = false;
        CommandBuffer commandBuffer;
        commandBuffer.pushCommand(std::make_unique<PresentCommand>());
        submitCommandBuffer(std::move(commandBuffer));

        if (renderThread.isJoinable()) renderThread.join();

        if (context)
        {
            if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
                logger.log(Log::Level::error) << "Failed to unset EGL context";

            if (!eglDestroyContext(display, context))
                logger.log(Log::Level::error) << "Failed to destroy EGL context";

            context = nullptr;
        }

        if (surface)
        {
            if (!eglDestroySurface(display, surface))
                logger.log(Log::Level::error) << "Failed to destroy EGL surface";

            surface = nullptr;
        }
    }

    void RenderDevice::present()
    {
        if (eglSwapBuffers(display, surface) != EGL_TRUE)
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to swap buffers");
    }

    void RenderDevice::renderMain()
    {
        Thread::setCurrentThreadName("Render");

        if (!eglMakeCurrent(display, surface, surface, context))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set current EGL context");

        while (running)
        {
            try
            {
                process();
            }
            catch (const std::exception& e)
            {
                logger.log(Log::Level::error) << e.what();
            }
        }

        if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to unset EGL context");
    }
}

#endif
<commit_msg>Fix the Android build<commit_after>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include "../../../core/Setup.h"

#if defined(__ANDROID__) && OUZEL_COMPILE_OPENGL

#include "OGLRenderDeviceAndroid.hpp"
#include "../EGLErrorCategory.hpp"
#include "../../../core/Engine.hpp"
#include "../../../core/Window.hpp"
#include "../../../core/android/NativeWindowAndroid.hpp"
#include "../../../utils/Log.hpp"

namespace ouzel::graphics::opengl::android
{
    namespace
    {
        const egl::ErrorCategory eglErrorCategory{};
    }

    RenderDevice::RenderDevice(const Settings& settings,
                               core::Window& initWindow,
                               const std::function<void(const Event&)>& initCallback):
        opengl::RenderDevice(settings, initWindow, initCallback)
    {
        embedded = true;

        display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

        if (display == EGL_NO_DISPLAY)
            throw std::runtime_error("Failed to get display");

        if (!eglInitialize(display, nullptr, nullptr))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to initialize EGL");

        const EGLint attributeList[] = {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, settings.depth ? 24 : 0,
            EGL_STENCIL_SIZE, settings.stencil ? 8 : 0,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_SAMPLE_BUFFERS, (settings.sampleCount > 1) ? 1 : 0,
            EGL_SAMPLES, static_cast<int>(settings.sampleCount),
            EGL_NONE
        };
        EGLConfig config;
        EGLint numConfig;
        if (!eglChooseConfig(display, attributeList, &config, 1, &numConfig))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to choose EGL config");

        if (!eglBindAPI(EGL_OPENGL_ES_API))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to bind OpenGL ES API");

        EGLint format;
        if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to get config attribute");

        auto windowAndroid = static_cast<core::android::NativeWindow*>(window.getNativeWindow());

        ANativeWindow_setBuffersGeometry(windowAndroid->getNativeWindow(), 0, 0, format);

        surface = eglCreateWindowSurface(display, config, windowAndroid->getNativeWindow(), nullptr);
        if (surface == EGL_NO_SURFACE)
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to create EGL window surface");

        for (EGLint version = 3; version >= 2; --version)
        {
            const EGLint contextAttributes[] = {
                EGL_CONTEXT_CLIENT_VERSION, version,
                EGL_CONTEXT_OPENGL_DEBUG, settings.debugRenderer ? EGL_TRUE : EGL_FALSE,
                EGL_NONE
            };

            context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);

            if (context != EGL_NO_CONTEXT)
            {
                apiVersion = ApiVersion(version, 0);
                logger.log(Log::Level::info) << "EGL OpenGL ES " << version << " context created";
                break;
            }
        }

        if (context == EGL_NO_CONTEXT)
            throw std::runtime_error("Failed to create EGL context");

        if (!eglMakeCurrent(display, surface, surface, context))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set current EGL context");

        if (!eglSwapInterval(display, settings.verticalSync ? 1 : 0))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set EGL frame interval");

        EGLint surfaceWidth;
        EGLint surfaceHeight;

        if (!eglQuerySurface(display, surface, EGL_WIDTH, &surfaceWidth) ||
            !eglQuerySurface(display, surface, EGL_HEIGHT, &surfaceHeight))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to get query window size");

        init(surfaceWidth, surfaceHeight);

        if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to unset EGL context");

        running = true;
        renderThread = Thread(&RenderDevice::renderMain, this);
    }

    RenderDevice::~RenderDevice()
    {
        running = false;
        CommandBuffer commandBuffer;
        commandBuffer.pushCommand(std::make_unique<PresentCommand>());
        submitCommandBuffer(std::move(commandBuffer));

        if (renderThread.isJoinable()) renderThread.join();

        if (context != EGL_NO_CONTEXT)
        {
            eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
            eglDestroyContext(display, context);
        }

        if (surface != EGL_NO_SURFACE)
            eglDestroySurface(display, surface);

        if (display != EGL_NO_DISPLAY)
            eglTerminate(display);
    }

    void RenderDevice::reload()
    {
        running = false;
        CommandBuffer commandBuffer;
        commandBuffer.pushCommand(std::make_unique<PresentCommand>());
        submitCommandBuffer(std::move(commandBuffer));

        if (renderThread.isJoinable()) renderThread.join();

        const EGLint attributeList[] =
        {
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 8,
            EGL_DEPTH_SIZE, depth ? 24 : 0,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_SAMPLE_BUFFERS, (sampleCount > 1) ? 1 : 0,
            EGL_SAMPLES, static_cast<int>(sampleCount),
            EGL_NONE
        };
        EGLConfig config;
        EGLint numConfig;
        if (!eglChooseConfig(display, attributeList, &config, 1, &numConfig))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to choose EGL config");

        if (!eglBindAPI(EGL_OPENGL_ES_API))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to bind OpenGL ES API");

        EGLint format;
        if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to get config attribute");

        auto windowAndroid = static_cast<core::android::NativeWindow*>(window.getNativeWindow());

        ANativeWindow_setBuffersGeometry(windowAndroid->getNativeWindow(), 0, 0, format);

        surface = eglCreateWindowSurface(display, config, windowAndroid->getNativeWindow(), nullptr);
        if (surface == EGL_NO_SURFACE)
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to create EGL window surface");

        for (EGLint version = 3; version >= 2; --version)
        {
            const EGLint contextAttributes[] = {
                EGL_CONTEXT_CLIENT_VERSION, version,
                EGL_CONTEXT_OPENGL_DEBUG, debugRenderer ? EGL_TRUE : EGL_FALSE,
                EGL_NONE
            };

            context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttributes);

            if (context != EGL_NO_CONTEXT)
            {
                apiVersion = ApiVersion(version, 0);
                logger.log(Log::Level::info) << "EGL OpenGL ES " << version << " context created";
                break;
            }
        }

        if (context == EGL_NO_CONTEXT)
            throw std::runtime_error("Failed to create EGL context");

        if (!eglMakeCurrent(display, surface, surface, context))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set current EGL context");

        if (!eglSwapInterval(display, verticalSync ? 1 : 0))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set EGL frame interval");

        EGLint surfaceWidth;
        EGLint surfaceHeight;

        if (!eglQuerySurface(display, surface, EGL_WIDTH, &surfaceWidth) ||
            !eglQuerySurface(display, surface, EGL_HEIGHT, &surfaceHeight))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to get query window size");

        frameBufferWidth = surfaceWidth;
        frameBufferHeight = surfaceHeight;

        stateCache = StateCache();

        glDisableProc(GL_DITHER);
        glDepthFuncProc(GL_LEQUAL);

        GLenum error;

        if ((error = glGetErrorProc()) != GL_NO_ERROR)
            throw std::system_error(makeErrorCode(error), "Failed to set depth function");

        if (glGenVertexArraysProc) glGenVertexArraysProc(1, &vertexArrayId);

        for (const auto& resource : resources)
            if (resource) resource->invalidate();

        for (const auto& resource : resources)
            if (resource) resource->restore();

        if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to unset EGL context");

        running = true;
        renderThread = Thread(&RenderDevice::renderMain, this);
    }

    void RenderDevice::destroy()
    {
        running = false;
        CommandBuffer commandBuffer;
        commandBuffer.pushCommand(std::make_unique<PresentCommand>());
        submitCommandBuffer(std::move(commandBuffer));

        if (renderThread.isJoinable()) renderThread.join();

        if (context)
        {
            if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
                logger.log(Log::Level::error) << "Failed to unset EGL context";

            if (!eglDestroyContext(display, context))
                logger.log(Log::Level::error) << "Failed to destroy EGL context";

            context = nullptr;
        }

        if (surface)
        {
            if (!eglDestroySurface(display, surface))
                logger.log(Log::Level::error) << "Failed to destroy EGL surface";

            surface = nullptr;
        }
    }

    void RenderDevice::present()
    {
        if (eglSwapBuffers(display, surface) != EGL_TRUE)
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to swap buffers");
    }

    void RenderDevice::renderMain()
    {
        Thread::setCurrentThreadName("Render");

        if (!eglMakeCurrent(display, surface, surface, context))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to set current EGL context");

        while (running)
        {
            try
            {
                process();
            }
            catch (const std::exception& e)
            {
                logger.log(Log::Level::error) << e.what();
            }
        }

        if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT))
            throw std::system_error(eglGetError(), eglErrorCategory, "Failed to unset EGL context");
    }
}

#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library 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.
 *
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_GEOMETRY_SVG_GENERATOR_HPP
#define MAPNIK_GEOMETRY_SVG_GENERATOR_HPP

#define BOOST_SPIRIT_USE_PHOENIX_V3 1

// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp> // for container stuff
#include <mapnik/ctrans.hpp> // for container stuff
#include <mapnik/util/path_iterator.hpp>
#include <mapnik/util/container_adapter.hpp>

// boost
#include <boost/tuple/tuple.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/type_traits/remove_pointer.hpp>

/*!
 * adapted to conform to the concepts
 * required by Karma to be recognized as a container of
 * attributes for output generation.
 */
namespace boost { namespace spirit { namespace traits {

// TODO - this needs to be made generic to any path type
typedef mapnik::coord_transform<mapnik::CoordTransform, mapnik::geometry_type> path_type;

template <>
struct is_container<path_type const> : mpl::true_ {} ;

template <>
struct container_iterator<path_type const>
{
    typedef mapnik::util::path_iterator<path_type> type;
};

template <>
struct begin_container<path_type const>
{
    static mapnik::util::path_iterator<path_type>
    call (path_type const& g)
    {
        return mapnik::util::path_iterator<path_type>(g);
    }
};

template <>
struct end_container<path_type const>
{
    static mapnik::util::path_iterator<path_type>
    call (path_type const& g)
    {
        return mapnik::util::path_iterator<path_type>();
    }
};

}}}

namespace mapnik { namespace util {

    namespace karma = boost::spirit::karma;
    namespace phoenix = boost::phoenix;

    namespace svg_detail {

    template <typename Geometry>
    struct get_type
    {
        template <typename T>
        struct result { typedef int type; };

        int operator() (Geometry const& geom) const
        {
            return static_cast<int>(geom.type());
        }
    };

    template <typename T>
    struct get_first
    {
        typedef T geometry_type;

        template <typename U>
        struct result { typedef typename geometry_type::value_type const type; };

        typename geometry_type::value_type const operator() (geometry_type const& geom) const
        {
            typename geometry_type::value_type coord;
            geom.rewind(0);
            boost::get<0>(coord) = geom.vertex(&boost::get<1>(coord),&boost::get<2>(coord));
            return coord;
        }
    };

    template <typename T>
    struct coordinate_policy : karma::real_policies<T>
    {
        typedef boost::spirit::karma::real_policies<T> base_type;
        static int floatfield(T n) { return base_type::fmtflags::fixed; }
        static unsigned precision(T n) { return 6u ;}
    };
    }

    template <typename OutputIterator, typename Geometry>
    struct svg_generator :
        karma::grammar<OutputIterator, Geometry const& ()>
    {

        typedef Geometry geometry_type;
        typedef typename boost::remove_pointer<typename geometry_type::value_type>::type coord_type;

        svg_generator()
            : svg_generator::base_type(svg)
        {
            using boost::spirit::karma::uint_;
            using boost::spirit::karma::_val;
            using boost::spirit::karma::_1;
            using boost::spirit::karma::lit;
            using boost::spirit::karma::_a;

            svg = point | linestring | polygon
                ;

            point = &uint_(mapnik::Point)[_1 = _type(_val)]
                << svg_point [_1 = _first(_val)]
                ;

            svg_point = &uint_
                << lit("cx=\"") << coordinate
                << lit("\" cy=\"") << coordinate
                << lit('\"')
                ;

            linestring = &uint_(mapnik::LineString)[_1 = _type(_val)]
                << svg_path << lit('\"')
                ;

            polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)]
                << svg_path << lit('\"')
                ;

            svg_path %= ((&uint_(mapnik::SEG_MOVETO) << lit("d=\"") << lit('M')
                          | &uint_(mapnik::SEG_LINETO) [_a +=1] << karma::string [if_(_a == 1) [_1 = "L" ] ])
                         << lit(' ') << coordinate << lit(' ') << coordinate) % lit(' ')
                ;

        }
        // rules
        karma::rule<OutputIterator, geometry_type const& ()> svg;
        karma::rule<OutputIterator, geometry_type const& ()> point;
        karma::rule<OutputIterator, geometry_type const& ()> linestring;
        karma::rule<OutputIterator, geometry_type const& ()> polygon;

        karma::rule<OutputIterator, coord_type ()> svg_point;
        karma::rule<OutputIterator, karma::locals<unsigned>, geometry_type const& ()> svg_path;

        // phoenix functions
        phoenix::function<svg_detail::get_type<geometry_type> > _type;
        phoenix::function<svg_detail::get_first<geometry_type> > _first;
        //
        karma::real_generator<double, svg_detail::coordinate_policy<double> > coordinate;

    };

}}

#endif // MAPNIK_GEOMETRY_SVG_GENERATOR_HPP
<commit_msg>+ fix grammar to work with phoenix v3 and c++11<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library 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.
 *
 * This library 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 this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_GEOMETRY_SVG_GENERATOR_HPP
#define MAPNIK_GEOMETRY_SVG_GENERATOR_HPP

#define BOOST_SPIRIT_USE_PHOENIX_V3 1

// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp> // for container stuff
#include <mapnik/ctrans.hpp> // for container stuff
#include <mapnik/util/path_iterator.hpp>
#include <mapnik/util/container_adapter.hpp>

// boost
#include <boost/tuple/tuple.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/type_traits/remove_pointer.hpp>

/*!
 * adapted to conform to the concepts
 * required by Karma to be recognized as a container of
 * attributes for output generation.
 */
namespace boost { namespace spirit { namespace traits {

// TODO - this needs to be made generic to any path type
typedef mapnik::coord_transform<mapnik::CoordTransform, mapnik::geometry_type> path_type;

template <>
struct is_container<path_type const> : mpl::true_ {} ;

template <>
struct container_iterator<path_type const>
{
    typedef mapnik::util::path_iterator<path_type> type;
};

template <>
struct begin_container<path_type const>
{
    static mapnik::util::path_iterator<path_type>
    call (path_type const& g)
    {
        return mapnik::util::path_iterator<path_type>(g);
    }
};

template <>
struct end_container<path_type const>
{
    static mapnik::util::path_iterator<path_type>
    call (path_type const& g)
    {
        return mapnik::util::path_iterator<path_type>();
    }
};

}}}

namespace mapnik { namespace util {

    namespace karma = boost::spirit::karma;
    namespace phoenix = boost::phoenix;

    namespace svg_detail {

    template <typename Geometry>
    struct get_type
    {
        template <typename T>
        struct result { typedef int type; };

        int operator() (Geometry const& geom) const
        {
            return static_cast<int>(geom.type());
        }
    };

    template <typename T>
    struct get_first
    {
        typedef T geometry_type;

        template <typename U>
        struct result { typedef typename geometry_type::value_type const type; };

        typename geometry_type::value_type const operator() (geometry_type const& geom) const
        {
            typename geometry_type::value_type coord;
            geom.rewind(0);
            boost::get<0>(coord) = geom.vertex(&boost::get<1>(coord),&boost::get<2>(coord));
            return coord;
        }
    };

    template <typename T>
    struct coordinate_policy : karma::real_policies<T>
    {
        typedef boost::spirit::karma::real_policies<T> base_type;
        static int floatfield(T n) { return base_type::fmtflags::fixed; }
        static unsigned precision(T n) { return 6u ;}
    };
    }

    template <typename OutputIterator, typename Geometry>
    struct svg_generator :
        karma::grammar<OutputIterator, Geometry const& ()>
    {

        typedef Geometry geometry_type;
        typedef typename boost::remove_pointer<typename geometry_type::value_type>::type coord_type;

        svg_generator()
            : svg_generator::base_type(svg)
        {
            using boost::spirit::karma::uint_;
            using boost::spirit::karma::_val;
            using boost::spirit::karma::_1;
            using boost::spirit::karma::lit;
            using boost::spirit::karma::_a;

            svg = point | linestring | polygon
                ;

            point = &uint_(mapnik::Point)[_1 = _type(_val)]
                << svg_point [_1 = _first(_val)]
                ;

            svg_point = &uint_
                << lit("cx=\"") << coordinate
                << lit("\" cy=\"") << coordinate
                << lit('\"')
                ;

            linestring = &uint_(mapnik::LineString)[_1 = _type(_val)]
                << svg_path << lit('\"')
                ;

            polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)]
                << svg_path << lit('\"')
                ;

            svg_path %= ((&uint_(mapnik::SEG_MOVETO) << lit("d=\"") << lit('M')
                          | &uint_(mapnik::SEG_LINETO) [_a +=1] << karma::string [if_(_a == 1) [_1 = "L" ].else_[_1 =""]])
                         << lit(' ') << coordinate << lit(' ') << coordinate) % lit(' ')
                ;
        }
        // rules
        karma::rule<OutputIterator, geometry_type const& ()> svg;
        karma::rule<OutputIterator, geometry_type const& ()> point;
        karma::rule<OutputIterator, geometry_type const& ()> linestring;
        karma::rule<OutputIterator, geometry_type const& ()> polygon;

        karma::rule<OutputIterator, coord_type ()> svg_point;
        karma::rule<OutputIterator, karma::locals<unsigned>, geometry_type const& ()> svg_path;

        // phoenix functions
        phoenix::function<svg_detail::get_type<geometry_type> > _type;
        phoenix::function<svg_detail::get_first<geometry_type> > _first;
        //
        karma::real_generator<double, svg_detail::coordinate_policy<double> > coordinate;

    };

}}

#endif // MAPNIK_GEOMETRY_SVG_GENERATOR_HPP
<|endoftext|>