<commit_before>#include "pen.h"
#include "renderer.h"
#include "timer.h"
#include "file_system.h"
#include "pen_string.h"
#include "loader.h"
#include "dev_ui.h"
#include "camera.h"
#include "debug_render.h"
#include "pmfx.h"
#include "pen_json.h"
#include "hash.h"
#include "str_utilities.h"
#include "input.h"
#include "ces/ces_scene.h"
#include "ces/ces_resources.h"
#include "ces/ces_editor.h"
#include "ces/ces_utilities.h"

using namespace put;
using namespace ces;

pen::window_creation_params pen_window
{
    1280,					    //width
    720,					    //height
    4,						    //MSAA samples
    "rigid_body_primitives"		//window title / process name
};

namespace physics
{
    extern PEN_THREAD_RETURN physics_thread_main( void* params );
}

void create_physics_objects( ces::entity_scene* scene )
{
    clear_scene( scene );

    material_resource* default_material = get_material_resource( PEN_HASH( "default_material" ) );

    geometry_resource* box = get_geometry_resource(PEN_HASH("cube"));
    geometry_resource* cylinder = get_geometry_resource( PEN_HASH( "cylinder" ) );
    geometry_resource* capsule = get_geometry_resource( PEN_HASH( "capsule" ) );
    geometry_resource* sphere = get_geometry_resource( PEN_HASH( "sphere" ) );
    geometry_resource* cone = get_geometry_resource( PEN_HASH( "cone" ) );

    //add light
    u32 light = get_new_node( scene );
    scene->names[light] = "front_light";
    scene->id_name[light] = PEN_HASH( "front_light" );
    scene->lights[light].colour = vec3f::one();
    scene->lights[light].direction = vec3f::one();
    scene->lights[light].type = LIGHT_TYPE_DIR;f
    scene->transforms->translation = vec3f::zero();
    scene->transforms->rotation = quat();
    scene->transforms->scale = vec3f::one();
    scene->entities[light] |= CMP_LIGHT;
    scene->entities[light] |= CMP_TRANSFORM;

    //ground
    u32 ground = get_new_node( scene );
    scene->names[ground] = "ground";
    scene->transforms[ground].translation = vec3f::zero();
    scene->transforms[ground].rotation = quat();
    scene->transforms[ground].scale = vec3f( 50.0f, 1.0f, 50.0f );
    scene->entities[ground] |= CMP_TRANSFORM;
    scene->parents[ground] = ground;
    instantiate_geometry( box, scene, ground );
    instantiate_material( default_material, scene, ground );
    instantiate_model_cbuffer( scene, ground );

    scene->physics_data[ground].rigid_body.shape = physics::BOX;
    scene->physics_data[ground].rigid_body.mass = 0.0f;
    instantiate_rigid_body( scene, ground );

    vec3f start_positions[] =
    {
        vec3f( -20.0f, 10.0f, -20.0f ),
        vec3f( 20.0f, 10.0f,  20.0f ),
        vec3f( -20.0f, 10.0f,  20.0f ),
        vec3f( 20.0f, 10.0f,  -20.0f ),
        vec3f( 0.0f, 10.0f, 0.0f ),
    };

    const c8* primitive_names[] =
    {
        "box",
        "cylinder",
        "capsule",
        "cone",
        "sphere"
    };

    u32 primitive_types[] =
    {
        physics::BOX,
        physics::CYLINDER,
        physics::CAPSULE,
        physics::CONE,
        physics::SPHERE
    };

    geometry_resource* primitive_resources[] =
    {
        box,
        cylinder,
        capsule,
        cone,
        sphere
    };

    s32 num_prims = 5;

    for (s32 p = 0; p < num_prims; ++p)
    {
        //add stack of cubes
        vec3f start_pos = start_positions[p];
        vec3f cur_pos = start_pos;
        for (s32 i = 0; i < 4; ++i)
        {
            cur_pos.y = start_pos.y;

            for (s32 j = 0; j < 4; ++j)
            {
                cur_pos.x = start_pos.x;

                for (s32 k = 0; k < 4; ++k)
                {
                    u32 new_prim = get_new_node( scene );
                    scene->names[new_prim] = primitive_names[p];
                    scene->names[new_prim].appendf( "%i", new_prim );
                    scene->transforms[new_prim].rotation = quat();
                    scene->transforms[new_prim].scale = vec3f::one();
                    scene->transforms[new_prim].translation = cur_pos;
                    scene->entities[new_prim] |= CMP_TRANSFORM;
                    scene->parents[new_prim] = new_prim;
                    instantiate_geometry( primitive_resources[p], scene, new_prim );
                    instantiate_material( default_material, scene, new_prim );
                    instantiate_model_cbuffer( scene, new_prim );

                    scene->physics_data[new_prim].rigid_body.shape = primitive_types[p];
                    scene->physics_data[new_prim].rigid_body.mass = 1.0f;
                    instantiate_rigid_body( scene, new_prim );

                    cur_pos.x += 2.5f;
                }

                cur_pos.y += 2.5f;
            }

            cur_pos.z += 2.5f;
        }
    }
}

PEN_THREAD_RETURN pen::game_entry( void* params )
{
    //unpack the params passed to the thread and signal to the engine it ok to proceed
    pen::job_thread_params* job_params = (pen::job_thread_params*)params;
    pen::job_thread* p_thread_info = job_params->job_thread_info;
    pen::threads_semaphore_signal(p_thread_info->p_sem_continue, 1);

    pen::threads_create_job( physics::physics_thread_main, 1024*10, nullptr, pen::THREAD_START_DETACHED );

	put::dev_ui::init();
	put::dbg::init();

	//create main camera and controller
	put::camera main_camera;
	put::camera_create_perspective( &main_camera, 60.0f, (f32)pen_window.width / (f32)pen_window.height, 0.1f, 1000.0f );

    put::camera_controller cc;
    cc.camera = &main_camera;
    cc.update_function = &ces::update_model_viewer_camera;
    cc.name = "model_viewer_camera";
    cc.id_name = PEN_HASH(cc.name.c_str());

    //create the main scene and controller
    put::ces::entity_scene* main_scene = put::ces::create_scene("main_scene");
    put::ces::editor_init( main_scene );

    put::scene_controller sc;
    sc.scene = main_scene;
    sc.update_function = &ces::update_model_viewer_scene;
    sc.name = "main_scene";
	sc.camera = &main_camera;
    sc.id_name = PEN_HASH(sc.name.c_str());

    //create view renderers
    put::scene_view_renderer svr_main;
    svr_main.name = "ces_render_scene";
    svr_main.id_name = PEN_HASH(svr_main.name.c_str());
    svr_main.render_function = &ces::render_scene_view;

    put::scene_view_renderer svr_editor;
    svr_editor.name = "ces_render_editor";
    svr_editor.id_name = PEN_HASH(svr_editor.name.c_str());
    svr_editor.render_function = &ces::render_scene_editor;

    pmfx::register_scene_view_renderer(svr_main);
    pmfx::register_scene_view_renderer(svr_editor);

    pmfx::register_scene(sc);
    pmfx::register_camera(cc);

    pmfx::init("data/configs/editor_renderer.json");

    create_physics_objects( main_scene );

    bool enable_dev_ui = true;
    f32 frame_time = 0.0f;

    while( 1 )
    {
        static u32 frame_timer = pen::timer_create("frame_timer");
        pen::timer_start(frame_timer);

		put::dev_ui::new_frame();

        pmfx::update();

        pmfx::render();

        pmfx::show_dev_ui();

        if( enable_dev_ui )
        {
            put::dev_ui::console();
            put::dev_ui::render();
        }

        if( pen::input_is_key_held(PENK_MENU) && pen::input_is_key_pressed(PENK_D) )
            enable_dev_ui = !enable_dev_ui;

        frame_time = pen::timer_elapsed_ms(frame_timer);

        pen::renderer_present();
        pen::renderer_consume_cmd_buffer();

		pmfx::poll_for_changes();
		put::poll_hot_loader();

        //msg from the engine we want to terminate
        if( pen::threads_semaphore_try_wait( p_thread_info->p_sem_exit ) )
            break;
    }

	ces::destroy_scene(main_scene);
	ces::editor_shutdown();

    //clean up mem here
	put::pmfx::shutdown();
	put::dbg::shutdown();
	put::dev_ui::shutdown();

    pen::renderer_consume_cmd_buffer();

    //signal to the engine the thread has finished
    pen::threads_semaphore_signal( p_thread_info->p_sem_terminated, 1);

    return PEN_THREAD_OK;
}
<commit_msg>fix texture dependencies on win32, tidy up forward lit shader to handle vertex colours and albedo texture<commit_after>#include "pen.h"
#include "renderer.h"
#include "timer.h"
#include "file_system.h"
#include "pen_string.h"
#include "loader.h"
#include "dev_ui.h"
#include "camera.h"
#include "debug_render.h"
#include "pmfx.h"
#include "pen_json.h"
#include "hash.h"
#include "str_utilities.h"
#include "input.h"
#include "ces/ces_scene.h"
#include "ces/ces_resources.h"
#include "ces/ces_editor.h"
#include "ces/ces_utilities.h"

using namespace put;
using namespace ces;

pen::window_creation_params pen_window
{
    1280,					    //width
    720,					    //height
    4,						    //MSAA samples
    "rigid_body_primitives"		//window title / process name
};

namespace physics
{
    extern PEN_THREAD_RETURN physics_thread_main( void* params );
}

void create_physics_objects( ces::entity_scene* scene )
{
    clear_scene( scene );

    material_resource* default_material = get_material_resource( PEN_HASH( "default_material" ) );

    geometry_resource* box = get_geometry_resource(PEN_HASH("cube"));
    geometry_resource* cylinder = get_geometry_resource( PEN_HASH( "cylinder" ) );
    geometry_resource* capsule = get_geometry_resource( PEN_HASH( "capsule" ) );
    geometry_resource* sphere = get_geometry_resource( PEN_HASH( "sphere" ) );
    geometry_resource* cone = get_geometry_resource( PEN_HASH( "cone" ) );

    //add light
    u32 light = get_new_node( scene );
    scene->names[light] = "front_light";
    scene->id_name[light] = PEN_HASH( "front_light" );
    scene->lights[light].colour = vec3f::one();
    scene->lights[light].direction = vec3f::one();
    scene->lights[light].type = LIGHT_TYPE_DIR;
    scene->transforms->translation = vec3f::zero();
    scene->transforms->rotation = quat();
    scene->transforms->scale = vec3f::one();
    scene->entities[light] |= CMP_LIGHT;
    scene->entities[light] |= CMP_TRANSFORM;

    //ground
    u32 ground = get_new_node( scene );
    scene->names[ground] = "ground";
    scene->transforms[ground].translation = vec3f::zero();
    scene->transforms[ground].rotation = quat();
    scene->transforms[ground].scale = vec3f( 50.0f, 1.0f, 50.0f );
    scene->entities[ground] |= CMP_TRANSFORM;
    scene->parents[ground] = ground;
    instantiate_geometry( box, scene, ground );
    instantiate_material( default_material, scene, ground );
    instantiate_model_cbuffer( scene, ground );

    scene->physics_data[ground].rigid_body.shape = physics::BOX;
    scene->physics_data[ground].rigid_body.mass = 0.0f;
    instantiate_rigid_body( scene, ground );

    vec3f start_positions[] =
    {
        vec3f( -20.0f, 10.0f, -20.0f ),
        vec3f( 20.0f, 10.0f,  20.0f ),
        vec3f( -20.0f, 10.0f,  20.0f ),
        vec3f( 20.0f, 10.0f,  -20.0f ),
        vec3f( 0.0f, 10.0f, 0.0f ),
    };

    const c8* primitive_names[] =
    {
        "box",
        "cylinder",
        "capsule",
        "cone",
        "sphere"
    };

    u32 primitive_types[] =
    {
        physics::BOX,
        physics::CYLINDER,
        physics::CAPSULE,
        physics::CONE,
        physics::SPHERE
    };

    geometry_resource* primitive_resources[] =
    {
        box,
        cylinder,
        capsule,
        cone,
        sphere
    };

    s32 num_prims = 5;

    for (s32 p = 0; p < num_prims; ++p)
    {
        //add stack of cubes
        vec3f start_pos = start_positions[p];
        vec3f cur_pos = start_pos;
        for (s32 i = 0; i < 4; ++i)
        {
            cur_pos.y = start_pos.y;

            for (s32 j = 0; j < 4; ++j)
            {
                cur_pos.x = start_pos.x;

                for (s32 k = 0; k < 4; ++k)
                {
                    u32 new_prim = get_new_node( scene );
                    scene->names[new_prim] = primitive_names[p];
                    scene->names[new_prim].appendf( "%i", new_prim );
                    scene->transforms[new_prim].rotation = quat();
                    scene->transforms[new_prim].scale = vec3f::one();
                    scene->transforms[new_prim].translation = cur_pos;
                    scene->entities[new_prim] |= CMP_TRANSFORM;
                    scene->parents[new_prim] = new_prim;
                    instantiate_geometry( primitive_resources[p], scene, new_prim );
                    instantiate_material( default_material, scene, new_prim );
                    instantiate_model_cbuffer( scene, new_prim );

                    scene->physics_data[new_prim].rigid_body.shape = primitive_types[p];
                    scene->physics_data[new_prim].rigid_body.mass = 1.0f;
                    instantiate_rigid_body( scene, new_prim );

                    cur_pos.x += 2.5f;
                }

                cur_pos.y += 2.5f;
            }

            cur_pos.z += 2.5f;
        }
    }
}

PEN_THREAD_RETURN pen::game_entry( void* params )
{
    //unpack the params passed to the thread and signal to the engine it ok to proceed
    pen::job_thread_params* job_params = (pen::job_thread_params*)params;
    pen::job_thread* p_thread_info = job_params->job_thread_info;
    pen::threads_semaphore_signal(p_thread_info->p_sem_continue, 1);

    pen::threads_create_job( physics::physics_thread_main, 1024*10, nullptr, pen::THREAD_START_DETACHED );

	put::dev_ui::init();
	put::dbg::init();

	//create main camera and controller
	put::camera main_camera;
	put::camera_create_perspective( &main_camera, 60.0f, (f32)pen_window.width / (f32)pen_window.height, 0.1f, 1000.0f );

    put::camera_controller cc;
    cc.camera = &main_camera;
    cc.update_function = &ces::update_model_viewer_camera;
    cc.name = "model_viewer_camera";
    cc.id_name = PEN_HASH(cc.name.c_str());

    //create the main scene and controller
    put::ces::entity_scene* main_scene = put::ces::create_scene("main_scene");
    put::ces::editor_init( main_scene );

    put::scene_controller sc;
    sc.scene = main_scene;
    sc.update_function = &ces::update_model_viewer_scene;
    sc.name = "main_scene";
	sc.camera = &main_camera;
    sc.id_name = PEN_HASH(sc.name.c_str());

    //create view renderers
    put::scene_view_renderer svr_main;
    svr_main.name = "ces_render_scene";
    svr_main.id_name = PEN_HASH(svr_main.name.c_str());
    svr_main.render_function = &ces::render_scene_view;

    put::scene_view_renderer svr_editor;
    svr_editor.name = "ces_render_editor";
    svr_editor.id_name = PEN_HASH(svr_editor.name.c_str());
    svr_editor.render_function = &ces::render_scene_editor;

    pmfx::register_scene_view_renderer(svr_main);
    pmfx::register_scene_view_renderer(svr_editor);

    pmfx::register_scene(sc);
    pmfx::register_camera(cc);

    pmfx::init("data/configs/editor_renderer.json");

    create_physics_objects( main_scene );

    bool enable_dev_ui = true;
    f32 frame_time = 0.0f;

    while( 1 )
    {
        static u32 frame_timer = pen::timer_create("frame_timer");
        pen::timer_start(frame_timer);

		put::dev_ui::new_frame();

        pmfx::update();

        pmfx::render();

        pmfx::show_dev_ui();

        if( enable_dev_ui )
        {
            put::dev_ui::console();
            put::dev_ui::render();
        }

        if( pen::input_is_key_held(PENK_MENU) && pen::input_is_key_pressed(PENK_D) )
            enable_dev_ui = !enable_dev_ui;

        frame_time = pen::timer_elapsed_ms(frame_timer);

        pen::renderer_present();
        pen::renderer_consume_cmd_buffer();

		pmfx::poll_for_changes();
		put::poll_hot_loader();

        //msg from the engine we want to terminate
        if( pen::threads_semaphore_try_wait( p_thread_info->p_sem_exit ) )
            break;
    }

	ces::destroy_scene(main_scene);
	ces::editor_shutdown();

    //clean up mem here
	put::pmfx::shutdown();
	put::dbg::shutdown();
	put::dev_ui::shutdown();

    pen::renderer_consume_cmd_buffer();

    //signal to the engine the thread has finished
    pen::threads_semaphore_signal( p_thread_info->p_sem_terminated, 1);

    return PEN_THREAD_OK;
}
<|endoftext|>


<commit_before>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "generatorBase/semanticTree/switchNode.h"

#include <qrutils/stringUtils.h>

using namespace generatorBase::semantics;
using namespace qReal;

SwitchNode::SwitchNode(const Id &idBinded, QObject *parent)
	: NonZoneNode(idBinded, parent)
	, mDefaultBranch(nullptr)
	, mBranchesMerged(false)
	, mGenerateIfs(false)
{
}

void SwitchNode::addBranch(const QString &value, SemanticNode * const node)
{
	ZoneNode * const zone = new ZoneNode(this);
	zone->setParentNode(this);
	bind(value, zone);
	if (node) {
		zone->appendChild(node);
	}
}

void SwitchNode::mergeBranch(const QString &value, NonZoneNode * const node)
{
	Q_ASSERT(node);
	bind(value, node->parentZone());
}

bool SwitchNode::branchesMerged() const
{
	return mBranchesMerged;
}

void SwitchNode::setBranchesMergedFlag()
{
	mBranchesMerged = true;
}

void SwitchNode::setGenerateIfs()
{
	mGenerateIfs = true;
}

QString SwitchNode::toStringImpl(GeneratorCustomizer &customizer, int indent, const QString &indentString) const
{
	QString result;
	bool isHead = true;
	for (ZoneNode * const zone : mBranches.values().toSet()) {
		if (zone == mDefaultBranch) {
			// Branches merged with default on the diagram will be merged with it in code too
			continue;
		}

		result += generatePart(customizer, indent, indentString, zone, isHead
				? customizer.factory()->switchHeadGenerator(mId, customizer, mBranches.keys(zone), mGenerateIfs || !customizer.supportsSwitchUnstableToBreaks())
				: customizer.factory()->switchMiddleGenerator(mId, customizer, mBranches.keys(zone), mGenerateIfs || !customizer.supportsSwitchUnstableToBreaks()));

		isHead = false;
	}

	if (result.isEmpty()) {
		// Then all branches lead to one block, we may ignore switch construction.
		return mDefaultBranch->toString(customizer, indent, indentString);
	}

	result += generatePart(customizer, indent, indentString, mDefaultBranch
			, customizer.factory()->switchDefaultGenerator(mId, customizer, mGenerateIfs || !customizer.supportsSwitchUnstableToBreaks()));

	return result;
}

void SwitchNode::bind(const QString &value, ZoneNode *zone)
{
	if (value.isEmpty()) {
		mDefaultBranch = zone;
	} else {
		mBranches[value] = zone;
	}
}

QString SwitchNode::generatePart(generatorBase::GeneratorCustomizer &customizer
		, int indent
		, const QString &indentString
		, ZoneNode * const zone
		, generatorBase::simple::AbstractSimpleGenerator *generator) const
{
	return utils::StringUtils::addIndent(generator->generate()
			.replace("@@BODY@@", zone->toString(customizer, indent + 1, indentString)), indent, indentString);
}

QLinkedList<SemanticNode *> SwitchNode::children() const
{
	QLinkedList<SemanticNode *> result;
	for (ZoneNode * const zone : mBranches.values().toSet()) {
		result << zone;
	}

	if (mDefaultBranch) {
		result << mDefaultBranch;
	}

	return result;
}
<commit_msg>Style guide fixes<commit_after>/* Copyright 2007-2015 QReal Research Group
 *
 * 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 "generatorBase/semanticTree/switchNode.h"

#include <qrutils/stringUtils.h>

using namespace generatorBase::semantics;
using namespace qReal;

SwitchNode::SwitchNode(const Id &idBinded, QObject *parent)
	: NonZoneNode(idBinded, parent)
	, mDefaultBranch(nullptr)
	, mBranchesMerged(false)
	, mGenerateIfs(false)
{
}

void SwitchNode::addBranch(const QString &value, SemanticNode * const node)
{
	ZoneNode * const zone = new ZoneNode(this);
	zone->setParentNode(this);
	bind(value, zone);
	if (node) {
		zone->appendChild(node);
	}
}

void SwitchNode::mergeBranch(const QString &value, NonZoneNode * const node)
{
	Q_ASSERT(node);
	bind(value, node->parentZone());
}

bool SwitchNode::branchesMerged() const
{
	return mBranchesMerged;
}

void SwitchNode::setBranchesMergedFlag()
{
	mBranchesMerged = true;
}

void SwitchNode::setGenerateIfs()
{
	mGenerateIfs = true;
}

QString SwitchNode::toStringImpl(GeneratorCustomizer &customizer, int indent, const QString &indentString) const
{
	QString result;
	bool isHead = true;
	for (ZoneNode * const zone : mBranches.values().toSet()) {
		if (zone == mDefaultBranch) {
			// Branches merged with default on the diagram will be merged with it in code too
			continue;
		}

		result += generatePart(customizer, indent, indentString, zone, isHead
				? customizer.factory()->switchHeadGenerator(mId, customizer, mBranches.keys(zone)
						, mGenerateIfs || !customizer.supportsSwitchUnstableToBreaks())
				: customizer.factory()->switchMiddleGenerator(mId, customizer, mBranches.keys(zone)
						, mGenerateIfs || !customizer.supportsSwitchUnstableToBreaks()));

		isHead = false;
	}

	if (result.isEmpty()) {
		// Then all branches lead to one block, we may ignore switch construction.
		return mDefaultBranch->toString(customizer, indent, indentString);
	}

	result += generatePart(customizer, indent, indentString, mDefaultBranch
			, customizer.factory()->switchDefaultGenerator(mId, customizer
			, mGenerateIfs || !customizer.supportsSwitchUnstableToBreaks()));

	return result;
}

void SwitchNode::bind(const QString &value, ZoneNode *zone)
{
	if (value.isEmpty()) {
		mDefaultBranch = zone;
	} else {
		mBranches[value] = zone;
	}
}

QString SwitchNode::generatePart(generatorBase::GeneratorCustomizer &customizer
		, int indent
		, const QString &indentString
		, ZoneNode * const zone
		, generatorBase::simple::AbstractSimpleGenerator *generator) const
{
	return utils::StringUtils::addIndent(generator->generate()
			.replace("@@BODY@@", zone->toString(customizer, indent + 1, indentString)), indent, indentString);
}

QLinkedList<SemanticNode *> SwitchNode::children() const
{
	QLinkedList<SemanticNode *> result;
	for (ZoneNode * const zone : mBranches.values().toSet()) {
		result << zone;
	}

	if (mDefaultBranch) {
		result << mDefaultBranch;
	}

	return result;
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2005 by Andrew Mann
    Based in part on work by Matt Reda

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csutil/event.h"
#include "csutil/sysfunc.h"
#include "iutil/cfgfile.h"
#include "iutil/cmdline.h"
#include "iutil/comp.h"
#include "iutil/event.h"
#include "iutil/eventh.h"
#include "iutil/eventh.h"
#include "iutil/eventq.h"
#include "iutil/objreg.h"
#include "iutil/plugin.h"
#include "iutil/virtclk.h"
#include "ivaria/reporter.h"

#include "../../renderer.h"
#include "isndsys/ss_driver.h"
#include "isndsys/ss_renderer.h"
#include "driver_coreaudio.h"

CS_IMPLEMENT_PLUGIN

CS_PLUGIN_NAMESPACE_BEGIN(SndSysCOREAUDIO)
{

SCF_IMPLEMENT_FACTORY (csSndSysDriverCoreAudio)

SCF_IMPLEMENT_IBASE(csSndSysDriverCoreAudio)
SCF_IMPLEMENTS_INTERFACE(iSndSysSoftwareDriver)
SCF_IMPLEMENTS_EMBEDDED_INTERFACE(iComponent)
SCF_IMPLEMENT_IBASE_END;

SCF_IMPLEMENT_EMBEDDED_IBASE (csSndSysDriverCoreAudio::eiComponent)
SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

// CoreAudio static IO procedure wrapper
static OSStatus StaticAudioProc(AudioDeviceID inDevice,
				const AudioTimeStamp *inNow,
				const AudioBufferList *inInputData,
				const AudioTimeStamp *inInputTime,
				AudioBufferList *outOutputData,
				const AudioTimeStamp *inOutputTime,
				void *inClientData)
{
  csSndSysDriverCoreAudio *p_audio=(csSndSysDriverCoreAudio *)inClientData;

  return p_audio->AudioProc(inDevice, inNow, inInputData, inInputTime,
			    outOutputData, inOutputTime);

}

csSndSysDriverCoreAudio::csSndSysDriverCoreAudio(iBase* piBase) :
  object_reg(0), attached_renderer(0), running(false)
{
  SCF_CONSTRUCT_IBASE(piBase);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
  convert_buffer = 0;
}

csSndSysDriverCoreAudio::~csSndSysDriverCoreAudio()
{
  SCF_DESTRUCT_EMBEDDED_IBASE(scfiComponent);
  SCF_DESTRUCT_IBASE();
  free(convert_buffer);
}

void csSndSysDriverCoreAudio::Report(int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);

  csRef<iReporter> reporter = CS_QUERY_REGISTRY(object_reg, iReporter);

  if (reporter)
  {
    reporter->ReportV (severity,
      "crystalspace.sndsys.driver.software.coreaudio", msg, arg);
  }
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

bool csSndSysDriverCoreAudio::Initialize (iObjectRegistry* r)
{
  object_reg = r;
  Report (CS_REPORTER_SEVERITY_DEBUG,
    "Sound System: CoreAudio driver for software sound renderer initialized.");
  return true;
}

bool csSndSysDriverCoreAudio::Open (csSndSysRendererSoftware *renderer,
				   csSndSysSoundFormat *requested_format)
{
  uint32 propertysize, buffersize;
  AudioStreamBasicDescription outStreamDesc;
  //description of the data that CS will be providing
  AudioStreamBasicDescription inStreamDesc;

  OSStatus status;

  Report(CS_REPORTER_SEVERITY_DEBUG, "Sound System: CoreAudio Driver: Open()");

  attached_renderer = renderer;

  // Retrieve the output device ID - this is almost verbatim from the available
  // sample code
  propertysize = sizeof(outputDeviceID);
  status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
				    (UInt32*)&propertysize, &outputDeviceID);
  if (status)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to obtain default CoreAudio output device.  Return of %d.",
	   (int)status);
    return false;
  }
  if (outputDeviceID == kAudioDeviceUnknown)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to obtain default CoreAudio output device.  "
	   "Resulting ID is kAudioDeviceUnknown.");
    return false;
  }

  // Set buffer size - 1/10th of a second buffer of floats
  propertysize = sizeof(buffersize);
  buffersize = requested_format->Freq * sizeof(float) *
    requested_format->Channels / 10;

  convert_size = requested_format->Freq / 10;

  convert_buffer = malloc(convert_size * requested_format->Channels * requested_format->Bits/8);

  status = AudioDeviceSetProperty(outputDeviceID, 0, 0, false,
    kAudioDevicePropertyBufferSize, propertysize, &buffersize);
  if (status)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to set buffersize to %d bytes for CoreAudio output device. "
	   "Return of %d.", buffersize, (int)status);
	free(convert_buffer);
    return false;
  }

  // Get stream information
  propertysize = sizeof(outStreamDesc);
  status = AudioDeviceGetProperty(outputDeviceID, 0, false,
    kAudioDevicePropertyStreamFormat, (UInt32*)&propertysize, &outStreamDesc);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to retrieve output stream description from CoreAudio "
	   "output device.  Return of %d.", (int)status);
    return false;
  }
  //get another copy to create the input format spec
  status = AudioDeviceGetProperty(outputDeviceID, 0, false,
    kAudioDevicePropertyStreamFormat, (UInt32*)&propertysize, &inStreamDesc);

  // Set up source stream description for an AudioConverter to do its thang

  inStreamDesc.mSampleRate = requested_format->Freq;
  inStreamDesc.mFormatID = kAudioFormatLinearPCM;
  inStreamDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked ;
  if ((requested_format->Flags & CSSNDSYS_SAMPLE_ENDIAN_MASK) == CSSNDSYS_SAMPLE_BIG_ENDIAN)
    inStreamDesc.mFormatFlags |= kAudioFormatFlagIsBigEndian;
  inStreamDesc.mChannelsPerFrame = requested_format->Channels;
  inStreamDesc.mBitsPerChannel = requested_format->Bits;
  inStreamDesc.mFramesPerPacket = 1;
  inStreamDesc.mBytesPerFrame = requested_format->Channels * requested_format->Bits / 8;
  // The bytes per packet is purely a product of bytes per frame and frames per
  // packet since we don't have any padding in a packet here
  inStreamDesc.mBytesPerPacket =
    inStreamDesc.mFramesPerPacket * inStreamDesc.mBytesPerFrame;
/*
   inStreamDesc.mSampleRate = 44100.00;
  inStreamDesc.mFormatID = kAudioFormatLinearPCM;
  inStreamDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked ;
  inStreamDesc.mChannelsPerFrame = 2;
  inStreamDesc.mBitsPerChannel = 16;
  inStreamDesc.mFramesPerPacket = 1;
  inStreamDesc.mBytesPerFrame = 4;
  // The bytes per packet is purely a product of bytes per frame and frames per
  // packet since we don't have any padding in a packet here
  inStreamDesc.mBytesPerPacket = 4;
*/
	Report(CS_REPORTER_SEVERITY_WARNING,"Read in hardware properties of to Freq=%f Channels=%d Bits=%d FormatID=%s Flags=%x", outStreamDesc.mSampleRate,
	   outStreamDesc.mChannelsPerFrame, outStreamDesc.mBitsPerChannel, &outStreamDesc.mFormatID, outStreamDesc.mFormatFlags );
  // Set up destination stream parameters
  outStreamDesc.mSampleRate = 44100.00;
  outStreamDesc.mFormatID=kAudioFormatLinearPCM;
  outStreamDesc.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagIsBigEndian;
  outStreamDesc.mChannelsPerFrame= 2;
  outStreamDesc.mBitsPerChannel= 32;
//  outStreamDesc.mFramesPerPacket= 1;
  // At this level, Core Audio demands 32 bit floats
  outStreamDesc.mBytesPerFrame = requested_format->Channels * sizeof(float);
  // The bytes per packet is purely a product of bytes per frame and frames per
  // packet since we don't have any padding in a packet here
  outStreamDesc.mBytesPerPacket =
    outStreamDesc.mFramesPerPacket * outStreamDesc.mBytesPerFrame;

  //Make sure our HAL likes the output format?
  propertysize = sizeof(outStreamDesc);
  status = AudioDeviceSetProperty(outputDeviceID, 0, 0, false,
    kAudioDevicePropertyStreamFormat, propertysize, &outStreamDesc);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to set output stream properties to  Freq=%f Channels=%d Bits=%d FormatID=%s Flags=%x. Return of %s", outStreamDesc.mSampleRate,
	   outStreamDesc.mChannelsPerFrame, outStreamDesc.mBitsPerChannel, &outStreamDesc.mFormatID, outStreamDesc.mFormatFlags, &status);
    //return false;
  }

  //Create a converter to do the translation for us
  status = AudioConverterNew(&inStreamDesc, &outStreamDesc, &converter);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to create converter with error %s", &status);
    //return false;
  }

  // Copy the final format into local storage
  memcpy(&playback_format, requested_format, sizeof(csSndSysSoundFormat));

  // Add a callback and begin playback
  status = AudioDeviceAddIOProc(outputDeviceID, StaticAudioProc, this);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to add audio device IO proc.  Return of %d.", (int)status);
    return false;
  }

  return true;
}

void csSndSysDriverCoreAudio::Close ()
{
  StopThread();
  AudioDeviceRemoveIOProc(outputDeviceID, StaticAudioProc);
  free(convert_buffer);
  convert_buffer = 0;
}

bool csSndSysDriverCoreAudio::StartThread()
{
  OSStatus status;
  // Since the Core Audio API is callback driven, we don't actually start a
  // thread here ourselves.  Instead we start the audio device pulling from the
  // audio procedure.  This runs in its own thread that we don't see.
  Report(CS_REPORTER_SEVERITY_ERROR, "Getting our thread on!");
  status = AudioDeviceStart(outputDeviceID, StaticAudioProc);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR, "Failed to start audio device IO proc. "
	   "Return of %d.", (int)status);
    return false;
  }
  running = true;
  return true;
}

void csSndSysDriverCoreAudio::StopThread()
{
  running = false;
  AudioDeviceStop(outputDeviceID, StaticAudioProc);
  csSleep(100);
}

OSStatus csSndSysDriverCoreAudio::AudioProc(AudioDeviceID inDevice,
					  const AudioTimeStamp *inNow,
					  const AudioBufferList *inInputData,
					  const AudioTimeStamp *inInputTime,
					  AudioBufferList *outOutputData,
					  const AudioTimeStamp *inOutputTime)
{
  if (!running)
  {
    outOutputData->mBuffers[0].mDataByteSize=0;
    return 0;
  }

  // Fill the provided buffer with as many samples as possible and return the
  // number of frames provided
    int q = 0;
    OSStatus stat = 0;
	int x = 0; //lame attempt to null-terminate OSStatus for string interpretation
    size_t framesFilled = attached_renderer->FillDriverBuffer( convert_buffer, convert_size, 0, 0);
	size_t bytesWritten = outOutputData->mBuffers[0].mDataByteSize;
    stat = AudioConverterConvertBuffer(converter, framesFilled * playback_format.Bits/8 * playback_format.Channels, convert_buffer, &bytesWritten, outOutputData->mBuffers[0].mData);
    if(stat){
	  //attached_renderer->RecordEvent(SSEC_DRIVER,SSEL_DEBUG, "Audio convert error %s",&stat);
	}
	//attached_renderer->RecordEvent(SSEC_DRIVER,SSEL_DEBUG, "CA requested %d bytes, we wrote %d.",outOutputData->mBuffers[0].mDataByteSize,bytesWritten);
  return stat;
}

}
CS_PLUGIN_NAMESPACE_END(SndSysCOREAUDIO)

<commit_msg>AndyDude changed the non-error CoreAudio messages to be not so 'loud'. The two CoreAudio messages that I changed were Report()'d at very high severity levels, when it wasn't really that severe.<commit_after>/*
    Copyright (C) 2005 by Andrew Mann
    Based in part on work by Matt Reda

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csutil/event.h"
#include "csutil/sysfunc.h"
#include "iutil/cfgfile.h"
#include "iutil/cmdline.h"
#include "iutil/comp.h"
#include "iutil/event.h"
#include "iutil/eventh.h"
#include "iutil/eventh.h"
#include "iutil/eventq.h"
#include "iutil/objreg.h"
#include "iutil/plugin.h"
#include "iutil/virtclk.h"
#include "ivaria/reporter.h"

#include "../../renderer.h"
#include "isndsys/ss_driver.h"
#include "isndsys/ss_renderer.h"
#include "driver_coreaudio.h"

CS_IMPLEMENT_PLUGIN

CS_PLUGIN_NAMESPACE_BEGIN(SndSysCOREAUDIO)
{

SCF_IMPLEMENT_FACTORY (csSndSysDriverCoreAudio)

SCF_IMPLEMENT_IBASE(csSndSysDriverCoreAudio)
SCF_IMPLEMENTS_INTERFACE(iSndSysSoftwareDriver)
SCF_IMPLEMENTS_EMBEDDED_INTERFACE(iComponent)
SCF_IMPLEMENT_IBASE_END;

SCF_IMPLEMENT_EMBEDDED_IBASE (csSndSysDriverCoreAudio::eiComponent)
SCF_IMPLEMENTS_INTERFACE (iComponent)
SCF_IMPLEMENT_EMBEDDED_IBASE_END

// CoreAudio static IO procedure wrapper
static OSStatus StaticAudioProc(AudioDeviceID inDevice,
				const AudioTimeStamp *inNow,
				const AudioBufferList *inInputData,
				const AudioTimeStamp *inInputTime,
				AudioBufferList *outOutputData,
				const AudioTimeStamp *inOutputTime,
				void *inClientData)
{
  csSndSysDriverCoreAudio *p_audio=(csSndSysDriverCoreAudio *)inClientData;

  return p_audio->AudioProc(inDevice, inNow, inInputData, inInputTime,
			    outOutputData, inOutputTime);

}

csSndSysDriverCoreAudio::csSndSysDriverCoreAudio(iBase* piBase) :
  object_reg(0), attached_renderer(0), running(false)
{
  SCF_CONSTRUCT_IBASE(piBase);
  SCF_CONSTRUCT_EMBEDDED_IBASE(scfiComponent);
  convert_buffer = 0;
}

csSndSysDriverCoreAudio::~csSndSysDriverCoreAudio()
{
  SCF_DESTRUCT_EMBEDDED_IBASE(scfiComponent);
  SCF_DESTRUCT_IBASE();
  free(convert_buffer);
}

void csSndSysDriverCoreAudio::Report(int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);

  csRef<iReporter> reporter = CS_QUERY_REGISTRY(object_reg, iReporter);

  if (reporter)
  {
    reporter->ReportV (severity,
      "crystalspace.sndsys.driver.software.coreaudio", msg, arg);
  }
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

bool csSndSysDriverCoreAudio::Initialize (iObjectRegistry* r)
{
  object_reg = r;
  Report (CS_REPORTER_SEVERITY_DEBUG,
    "Sound System: CoreAudio driver for software sound renderer initialized.");
  return true;
}

bool csSndSysDriverCoreAudio::Open (csSndSysRendererSoftware *renderer,
				   csSndSysSoundFormat *requested_format)
{
  uint32 propertysize, buffersize;
  AudioStreamBasicDescription outStreamDesc;
  //description of the data that CS will be providing
  AudioStreamBasicDescription inStreamDesc;

  OSStatus status;

  Report(CS_REPORTER_SEVERITY_DEBUG, "Sound System: CoreAudio Driver: Open()");

  attached_renderer = renderer;

  // Retrieve the output device ID - this is almost verbatim from the available
  // sample code
  propertysize = sizeof(outputDeviceID);
  status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
				    (UInt32*)&propertysize, &outputDeviceID);
  if (status)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to obtain default CoreAudio output device.  Return of %d.",
	   (int)status);
    return false;
  }
  if (outputDeviceID == kAudioDeviceUnknown)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to obtain default CoreAudio output device.  "
	   "Resulting ID is kAudioDeviceUnknown.");
    return false;
  }

  // Set buffer size - 1/10th of a second buffer of floats
  propertysize = sizeof(buffersize);
  buffersize = requested_format->Freq * sizeof(float) *
    requested_format->Channels / 10;

  convert_size = requested_format->Freq / 10;

  convert_buffer = malloc(convert_size * requested_format->Channels * requested_format->Bits/8);

  status = AudioDeviceSetProperty(outputDeviceID, 0, 0, false,
    kAudioDevicePropertyBufferSize, propertysize, &buffersize);
  if (status)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to set buffersize to %d bytes for CoreAudio output device. "
	   "Return of %d.", buffersize, (int)status);
	free(convert_buffer);
    return false;
  }

  // Get stream information
  propertysize = sizeof(outStreamDesc);
  status = AudioDeviceGetProperty(outputDeviceID, 0, false,
    kAudioDevicePropertyStreamFormat, (UInt32*)&propertysize, &outStreamDesc);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to retrieve output stream description from CoreAudio "
	   "output device.  Return of %d.", (int)status);
    return false;
  }
  //get another copy to create the input format spec
  status = AudioDeviceGetProperty(outputDeviceID, 0, false,
    kAudioDevicePropertyStreamFormat, (UInt32*)&propertysize, &inStreamDesc);

  // Set up source stream description for an AudioConverter to do its thang

  inStreamDesc.mSampleRate = requested_format->Freq;
  inStreamDesc.mFormatID = kAudioFormatLinearPCM;
  inStreamDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked ;
  if ((requested_format->Flags & CSSNDSYS_SAMPLE_ENDIAN_MASK) == CSSNDSYS_SAMPLE_BIG_ENDIAN)
    inStreamDesc.mFormatFlags |= kAudioFormatFlagIsBigEndian;
  inStreamDesc.mChannelsPerFrame = requested_format->Channels;
  inStreamDesc.mBitsPerChannel = requested_format->Bits;
  inStreamDesc.mFramesPerPacket = 1;
  inStreamDesc.mBytesPerFrame = requested_format->Channels * requested_format->Bits / 8;
  // The bytes per packet is purely a product of bytes per frame and frames per
  // packet since we don't have any padding in a packet here
  inStreamDesc.mBytesPerPacket =
    inStreamDesc.mFramesPerPacket * inStreamDesc.mBytesPerFrame;
/*
   inStreamDesc.mSampleRate = 44100.00;
  inStreamDesc.mFormatID = kAudioFormatLinearPCM;
  inStreamDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked ;
  inStreamDesc.mChannelsPerFrame = 2;
  inStreamDesc.mBitsPerChannel = 16;
  inStreamDesc.mFramesPerPacket = 1;
  inStreamDesc.mBytesPerFrame = 4;
  // The bytes per packet is purely a product of bytes per frame and frames per
  // packet since we don't have any padding in a packet here
  inStreamDesc.mBytesPerPacket = 4;
*/
	Report(CS_REPORTER_SEVERITY_DEBUG,"Read in hardware properties of to Freq=%f Channels=%d Bits=%d FormatID=%s Flags=%x", outStreamDesc.mSampleRate,
	   outStreamDesc.mChannelsPerFrame, outStreamDesc.mBitsPerChannel, &outStreamDesc.mFormatID, outStreamDesc.mFormatFlags );
  // Set up destination stream parameters
  outStreamDesc.mSampleRate = 44100.00;
  outStreamDesc.mFormatID=kAudioFormatLinearPCM;
  outStreamDesc.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagIsBigEndian;
  outStreamDesc.mChannelsPerFrame= 2;
  outStreamDesc.mBitsPerChannel= 32;
//  outStreamDesc.mFramesPerPacket= 1;
  // At this level, Core Audio demands 32 bit floats
  outStreamDesc.mBytesPerFrame = requested_format->Channels * sizeof(float);
  // The bytes per packet is purely a product of bytes per frame and frames per
  // packet since we don't have any padding in a packet here
  outStreamDesc.mBytesPerPacket =
    outStreamDesc.mFramesPerPacket * outStreamDesc.mBytesPerFrame;

  //Make sure our HAL likes the output format?
  propertysize = sizeof(outStreamDesc);
  status = AudioDeviceSetProperty(outputDeviceID, 0, 0, false,
    kAudioDevicePropertyStreamFormat, propertysize, &outStreamDesc);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to set output stream properties to  Freq=%f Channels=%d Bits=%d FormatID=%s Flags=%x. Return of %s", outStreamDesc.mSampleRate,
	   outStreamDesc.mChannelsPerFrame, outStreamDesc.mBitsPerChannel, &outStreamDesc.mFormatID, outStreamDesc.mFormatFlags, &status);
    //return false;
  }

  //Create a converter to do the translation for us
  status = AudioConverterNew(&inStreamDesc, &outStreamDesc, &converter);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to create converter with error %s", &status);
    //return false;
  }

  // Copy the final format into local storage
  memcpy(&playback_format, requested_format, sizeof(csSndSysSoundFormat));

  // Add a callback and begin playback
  status = AudioDeviceAddIOProc(outputDeviceID, StaticAudioProc, this);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR,
	   "Failed to add audio device IO proc.  Return of %d.", (int)status);
    return false;
  }

  return true;
}

void csSndSysDriverCoreAudio::Close ()
{
  StopThread();
  AudioDeviceRemoveIOProc(outputDeviceID, StaticAudioProc);
  free(convert_buffer);
  convert_buffer = 0;
}

bool csSndSysDriverCoreAudio::StartThread()
{
  OSStatus status;
  // Since the Core Audio API is callback driven, we don't actually start a
  // thread here ourselves.  Instead we start the audio device pulling from the
  // audio procedure.  This runs in its own thread that we don't see.
  Report(CS_REPORTER_SEVERITY_DEBUG, "Getting our thread on!");
  status = AudioDeviceStart(outputDeviceID, StaticAudioProc);
  if (status != 0)
  {
    Report(CS_REPORTER_SEVERITY_ERROR, "Failed to start audio device IO proc. "
	   "Return of %d.", (int)status);
    return false;
  }
  running = true;
  return true;
}

void csSndSysDriverCoreAudio::StopThread()
{
  running = false;
  AudioDeviceStop(outputDeviceID, StaticAudioProc);
  csSleep(100);
}

OSStatus csSndSysDriverCoreAudio::AudioProc(AudioDeviceID inDevice,
					  const AudioTimeStamp *inNow,
					  const AudioBufferList *inInputData,
					  const AudioTimeStamp *inInputTime,
					  AudioBufferList *outOutputData,
					  const AudioTimeStamp *inOutputTime)
{
  if (!running)
  {
    outOutputData->mBuffers[0].mDataByteSize=0;
    return 0;
  }

  // Fill the provided buffer with as many samples as possible and return the
  // number of frames provided
    int q = 0;
    OSStatus stat = 0;
	int x = 0; //lame attempt to null-terminate OSStatus for string interpretation
    size_t framesFilled = attached_renderer->FillDriverBuffer( convert_buffer, convert_size, 0, 0);
	size_t bytesWritten = outOutputData->mBuffers[0].mDataByteSize;
    stat = AudioConverterConvertBuffer(converter, framesFilled * playback_format.Bits/8 * playback_format.Channels, convert_buffer, &bytesWritten, outOutputData->mBuffers[0].mData);
    if(stat){
	  //attached_renderer->RecordEvent(SSEC_DRIVER,SSEL_DEBUG, "Audio convert error %s",&stat);
	}
	//attached_renderer->RecordEvent(SSEC_DRIVER,SSEL_DEBUG, "CA requested %d bytes, we wrote %d.",outOutputData->mBuffers[0].mDataByteSize,bytesWritten);
  return stat;
}

}
CS_PLUGIN_NAMESPACE_END(SndSysCOREAUDIO)

<|endoftext|>


<commit_before>//
//  Landscape.cpp
//
//  Created by Soso Limited on 5/26/15.
//
//

#include "Landscape.h"

#include "cinder/Log.h"
#include "Constants.h"
#include "LandscapeGeometry.h"
#include "cinder/Json.h"
#include "cinder/Xml.h"

#include "cinder/gl/GlslProg.h"
#include "cinder/app/App.h"
#include "cinder/Easing.h"

using namespace soso;
using namespace cinder;

namespace {

struct alignas(16) Vertex {
  /// Position
	vec3	position;
  float frame_offset;
  /// Color
	vec2	color_tex_coord;		 // smooth across sections (bars in a section have shared edge values)
	vec2	flat_tex_coord;      // shared within bands
  float color_weight;
  /// Deformation
  vec3	normal;
  float deform_frame_offset; // shared across seams
  float deform_weight;
};

const auto kVertexLayout = ([] {
		auto layout = geom::BufferLayout();
		layout.append( geom::Attrib::POSITION, 3, sizeof(Vertex), offsetof(Vertex, position) );
		layout.append( geom::Attrib::NORMAL, 3, sizeof(Vertex), offsetof(Vertex, normal) );
		layout.append( geom::Attrib::TEX_COORD_0, 2, sizeof(Vertex), offsetof(Vertex, color_tex_coord) );
		layout.append( geom::Attrib::TEX_COORD_1, 2, sizeof(Vertex), offsetof(Vertex, flat_tex_coord) );
		layout.append( geom::Attrib::CUSTOM_0, 1, sizeof(Vertex), offsetof(Vertex, deform_weight) );
		layout.append( geom::Attrib::CUSTOM_1, 1, sizeof(Vertex), offsetof(Vertex, frame_offset) );
		layout.append( geom::Attrib::CUSTOM_2, 1, sizeof(Vertex), offsetof(Vertex, color_weight) );
    layout.append( geom::Attrib::CUSTOM_3, 1, sizeof(Vertex), offsetof(Vertex, deform_frame_offset) );
		return layout;
	} ());

const auto kVertexMapping = ([] {
		return gl::Batch::AttributeMapping{ { geom::Attrib::CUSTOM_0, "DeformScaling" },
                                        { geom::Attrib::CUSTOM_1, "FrameOffset" },
                                        { geom::Attrib::CUSTOM_2, "ColorWeight" },
                                        { geom::Attrib::CUSTOM_3, "DeformFrameOffset" } };
	} ());

// Load a shader and handle exceptions. Return nullptr on failure.
gl::GlslProgRef loadShader( const fs::path &iVertex, const fs::path &iFragment )
{
	try {
		auto shader_format = gl::GlslProg::Format()
			.vertex( app::loadAsset( iVertex ) )
			.fragment( app::loadAsset( iFragment ) );

		return gl::GlslProg::create( shader_format );
	}
	catch( ci::Exception &exc ) {
		CI_LOG_E( "Error loading shader: " << exc.what() );
	}

	return nullptr;
}

/// Add a ring of geometry containing a given number of time bands (slitscanning effect) and repeats around the donut.
void addRing( std::vector<Vertex> &vertices, const Bar &bar, int next_bar_time, float deform_start_time, const ci::vec2 &center_offset )
{
	const auto segments = 64;
	const auto texture_insets = vec2( 0.05f, 0.0875f );

	// Generate cartesian position.
	const auto calc_pos = [=] (int r, int s) {
		auto pos = mix( bar.begin, bar.end, (float)r ) + center_offset;
		auto t = (float) s / segments;

		auto rotation = glm::rotate<float>( t * Tau, vec3(0, 1, 0) );

		return vec3( rotation * vec4( pos, 0.0f, 1.0f ) );
	};

	const auto calc_normal = [=] (int r, int s) {
		auto normal = normalize( vec3(mix(bar.normal_begin, bar.normal_end, (float)r), 0.0f) );
		auto t = (float) s / segments;
		auto rotation = glm::rotate<float>( t * Tau, vec3(0, 1, 0) );
		return vec3( rotation * vec4(normal, 0.0f) );
	};

	// Generate texture coordinate mirrored at halfway point.
	const auto calc_tc = [=] (int r, int s) {
		auto t = (float) s / segments;
		if( t < 1 ) {
			t = glm::fract( t * bar.repeats );
		}
		// mirror copies
		t = std::abs( t - 0.5f ) * 2.0f;
		auto tc = vec2(0);
		// Repeat t with mirroring
		// insetting the texture coordinates minimizes edge color flashing.
		tc.y = mix( texture_insets.y, 1.0f - texture_insets.y, t );
		auto x = mix( bar.texture_begin, bar.texture_end, (float) r );
		tc.x = mix( 1.0f - texture_insets.x, texture_insets.x, x );
		return tc;
	};

	// Add a vertex to texture (color_tc parameter allows us to do flat shading in ES2)
	const auto add_vert = [=,&vertices] (int r, int s, const ivec2 &provoking) {
		auto pos = calc_pos(r, s);
		auto color_tc = calc_tc(r, s);
    auto flat_tc = calc_tc( provoking.x, provoking.y );
		auto normal = calc_normal(r, s);

		auto deform_t = lmap( glm::clamp<float>( bar.time, deform_start_time, 144.0f ), deform_start_time, 144.0f, 0.0f, 1.0f );
    auto deform_scaling = easeInOutQuad( deform_t );
		auto color_weight = easeInOutCubic( deform_t );
		auto deform_frame = (float)mix( bar.time, next_bar_time, (float)r );
		if (deform_scaling > 1.0f) {
			CI_LOG_W("Deform scaling out of bounds: " << deform_scaling );
		}

    vertices.emplace_back( Vertex { pos, (float)bar.time,
                                    color_tc, flat_tc, color_weight,
                                    normal, deform_frame, deform_scaling } );
	};

	// Create triangles for flat shading
	const auto r = 0;
	for( auto s = 0; s < segments; s += 1 )
	{
		auto provoking = ivec2(r, s);
		add_vert( r, s, provoking );
		add_vert( r, s + 1, provoking );
		add_vert( r + 1, s + 1, provoking );

		add_vert( r, s, provoking );
		add_vert( r + 1, s, provoking );
		add_vert( r + 1, s + 1, provoking );
	}
}

} // namespace

void Landscape::setup()
{
  CI_LOG_I("Loading landscape shader");
	auto shader = loadShader( "landscape.vs", "landscape.fs" );

	std::vector<Vertex> vertices;

	auto offset = vec2( 0.05f, 0.0f );

  CI_LOG_I("Loading shape profile.");
	auto xml = XmlTree( app::loadAsset("profile.xml") );
	auto deform_start_time = xml.getChild("shape").getChild("deform_start").getValue<float>();
	auto &bars = xml.getChild("shape").getChild("bars").getChildren();
	auto iter = bars.begin();
	Bar bar(**iter);
	while( iter != bars.end() ) {
		++iter;
		if( iter != bars.end() ) {
			Bar next(**iter);
			addRing( vertices, bar, next.time, deform_start_time, offset );
			bar = next;
		}
		else {
			addRing( vertices, bar, bar.time, deform_start_time, offset );
		}
	}

	auto center = vec3( 0, -4.0f, 0 );

	// Flip up
	auto xf = glm::rotate<float>( Tau * 0.25f, vec3( 0, 0, 1 ) ) * glm::translate( center ) * glm::scale( vec3( 4.0f ) );
	for( auto &v : vertices ) {
		v.position = vec3( xf * vec4(v.position, 1.0f) );
		v.normal = vec3( xf * vec4(v.normal, 0.0f) );
	}

  /*
	// Mirror (maybe just draw twice)
	auto copy = vertices;
	auto mirror = glm::mat4( glm::angleAxis<float>( Tau * 0.5f, vec3( 0, 1, 0 ) ) );

	for( auto &v : copy ) {
		v.position = vec3( mirror * vec4(v.position, 1.0f) );
		v.normal = vec3( mirror * vec4(v.normal, 0.0f) );
	}

	vertices.insert( vertices.end(), copy.begin(), copy.end() );
//  */

  CI_LOG_I("Uploading shape to GPU.");
	auto vbo = gl::Vbo::create( GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW );
	auto mesh = gl::VboMesh::create( vertices.size(), GL_TRIANGLES, {{ kVertexLayout, vbo }} );
	batch = gl::Batch::create( mesh, shader, kVertexMapping );
}

void Landscape::setTextureUnits( uint8_t iClearUnit, uint8_t iBlurredUnit )
{
	auto &shader = batch->getGlslProg();
	shader->uniform( "uClearTexture", iClearUnit );
	shader->uniform( "uBlurredTexture", iBlurredUnit );
}

void Landscape::setGridSize( const ci::vec2 &iSize )
{
  auto &shader = batch->getGlslProg();
  shader->uniform( "uGridSize", iSize );
}

void Landscape::draw( float iFrameOffset )
{
	auto &shader = batch->getGlslProg();
	shader->uniform( "uCurrentFrame", iFrameOffset );

	batch->draw();
}
<commit_msg>Mirrored, but overlapping.<commit_after>//
//  Landscape.cpp
//
//  Created by Soso Limited on 5/26/15.
//
//

#include "Landscape.h"

#include "cinder/Log.h"
#include "Constants.h"
#include "LandscapeGeometry.h"
#include "cinder/Json.h"
#include "cinder/Xml.h"

#include "cinder/gl/GlslProg.h"
#include "cinder/app/App.h"
#include "cinder/Easing.h"

using namespace soso;
using namespace cinder;

namespace {

struct alignas(16) Vertex {
  /// Position
	vec3	position;
  float frame_offset;
  /// Color
	vec2	color_tex_coord;		 // smooth across sections (bars in a section have shared edge values)
	vec2	flat_tex_coord;      // shared within bands
  float color_weight;
  /// Deformation
  vec3	normal;
  float deform_frame_offset; // shared across seams
  float deform_weight;
};

const auto kVertexLayout = ([] {
		auto layout = geom::BufferLayout();
		layout.append( geom::Attrib::POSITION, 3, sizeof(Vertex), offsetof(Vertex, position) );
		layout.append( geom::Attrib::NORMAL, 3, sizeof(Vertex), offsetof(Vertex, normal) );
		layout.append( geom::Attrib::TEX_COORD_0, 2, sizeof(Vertex), offsetof(Vertex, color_tex_coord) );
		layout.append( geom::Attrib::TEX_COORD_1, 2, sizeof(Vertex), offsetof(Vertex, flat_tex_coord) );
		layout.append( geom::Attrib::CUSTOM_0, 1, sizeof(Vertex), offsetof(Vertex, deform_weight) );
		layout.append( geom::Attrib::CUSTOM_1, 1, sizeof(Vertex), offsetof(Vertex, frame_offset) );
		layout.append( geom::Attrib::CUSTOM_2, 1, sizeof(Vertex), offsetof(Vertex, color_weight) );
    layout.append( geom::Attrib::CUSTOM_3, 1, sizeof(Vertex), offsetof(Vertex, deform_frame_offset) );
		return layout;
	} ());

const auto kVertexMapping = ([] {
		return gl::Batch::AttributeMapping{ { geom::Attrib::CUSTOM_0, "DeformScaling" },
                                        { geom::Attrib::CUSTOM_1, "FrameOffset" },
                                        { geom::Attrib::CUSTOM_2, "ColorWeight" },
                                        { geom::Attrib::CUSTOM_3, "DeformFrameOffset" } };
	} ());

// Load a shader and handle exceptions. Return nullptr on failure.
gl::GlslProgRef loadShader( const fs::path &iVertex, const fs::path &iFragment )
{
	try {
		auto shader_format = gl::GlslProg::Format()
			.vertex( app::loadAsset( iVertex ) )
			.fragment( app::loadAsset( iFragment ) );

		return gl::GlslProg::create( shader_format );
	}
	catch( ci::Exception &exc ) {
		CI_LOG_E( "Error loading shader: " << exc.what() );
	}

	return nullptr;
}

/// Add a ring of geometry containing a given number of time bands (slitscanning effect) and repeats around the donut.
void addRing( std::vector<Vertex> &vertices, const Bar &bar, int next_bar_time, float deform_start_time, const ci::vec2 &center_offset )
{
	const auto segments = 64;
	const auto texture_insets = vec2( 0.05f, 0.0875f );

	// Generate cartesian position.
	const auto calc_pos = [=] (int r, int s) {
		auto pos = mix( bar.begin, bar.end, (float)r ) + center_offset;
		auto t = (float) s / segments;

		auto rotation = glm::rotate<float>( t * Tau, vec3(0, 1, 0) );

		return vec3( rotation * vec4( pos, 0.0f, 1.0f ) );
	};

	const auto calc_normal = [=] (int r, int s) {
		auto normal = normalize( vec3(mix(bar.normal_begin, bar.normal_end, (float)r), 0.0f) );
		auto t = (float) s / segments;
		auto rotation = glm::rotate<float>( t * Tau, vec3(0, 1, 0) );
		return vec3( rotation * vec4(normal, 0.0f) );
	};

	// Generate texture coordinate mirrored at halfway point.
	const auto calc_tc = [=] (int r, int s) {
		auto t = (float) s / segments;
		if( t < 1 ) {
			t = glm::fract( t * bar.repeats );
		}
		// mirror copies
		t = std::abs( t - 0.5f ) * 2.0f;
		auto tc = vec2(0);
		// Repeat t with mirroring
		// insetting the texture coordinates minimizes edge color flashing.
		tc.y = mix( texture_insets.y, 1.0f - texture_insets.y, t );
		auto x = mix( bar.texture_begin, bar.texture_end, (float) r );
		tc.x = mix( 1.0f - texture_insets.x, texture_insets.x, x );
		return tc;
	};

	// Add a vertex to texture (color_tc parameter allows us to do flat shading in ES2)
	const auto add_vert = [=,&vertices] (int r, int s, const ivec2 &provoking) {
		auto pos = calc_pos(r, s);
		auto color_tc = calc_tc(r, s);
    auto flat_tc = calc_tc( provoking.x, provoking.y );
		auto normal = calc_normal(r, s);

		auto deform_t = lmap( glm::clamp<float>( bar.time, deform_start_time, 144.0f ), deform_start_time, 144.0f, 0.0f, 1.0f );
    auto deform_scaling = easeInOutQuad( deform_t );
		auto color_weight = easeInOutCubic( deform_t );
		auto deform_frame = (float)mix( bar.time, next_bar_time, (float)r );
		if (deform_scaling > 1.0f) {
			CI_LOG_W("Deform scaling out of bounds: " << deform_scaling );
		}

    vertices.emplace_back( Vertex { pos, (float)bar.time,
                                    color_tc, flat_tc, color_weight,
                                    normal, deform_frame, deform_scaling } );
	};

	// Create triangles for flat shading
	const auto r = 0;
	for( auto s = 0; s < segments; s += 1 )
	{
		auto provoking = ivec2(r, s);
		add_vert( r, s, provoking );
		add_vert( r, s + 1, provoking );
		add_vert( r + 1, s + 1, provoking );

		add_vert( r, s, provoking );
		add_vert( r + 1, s, provoking );
		add_vert( r + 1, s + 1, provoking );
	}
}

} // namespace

void Landscape::setup()
{
  CI_LOG_I("Loading landscape shader");
	auto shader = loadShader( "landscape.vs", "landscape.fs" );

	std::vector<Vertex> vertices;

	auto offset = vec2( 0.05f, 0.0f );

  CI_LOG_I("Loading shape profile.");
	auto xml = XmlTree( app::loadAsset("profile.xml") );
	auto deform_start_time = xml.getChild("shape").getChild("deform_start").getValue<float>();
	auto &bars = xml.getChild("shape").getChild("bars").getChildren();
	auto iter = bars.begin();
	Bar bar(**iter);
	while( iter != bars.end() ) {
		++iter;
		if( iter != bars.end() ) {
			Bar next(**iter);
			addRing( vertices, bar, next.time, deform_start_time, offset );
			bar = next;
		}
		else {
			addRing( vertices, bar, bar.time, deform_start_time, offset );
		}
	}

	auto center = vec3( 0, -4.0f, 0 );

	// Flip up
	auto xf = glm::rotate<float>( Tau * 0.25f, vec3( 0, 0, 1 ) ) * glm::translate( center ) * glm::scale( vec3( 4.0f ) );
	for( auto &v : vertices ) {
		v.position = vec3( xf * vec4(v.position, 1.0f) );
		v.normal = vec3( xf * vec4(v.normal, 0.0f) );
	}

//  /*
	// Mirror (maybe just draw twice)
	auto copy = vertices;
	auto mirror = glm::translate( vec3( -8.0f, 0.0f, 0.0f ) ) * glm::mat4( glm::angleAxis<float>( Tau * 0.5f, vec3( 0, 1, 0 ) ) );

	for( auto &v : copy ) {
		v.position = vec3( mirror * vec4(v.position, 1.0f) );
		v.normal = vec3( mirror * vec4(v.normal, 0.0f) );
	}

	vertices.insert( vertices.end(), copy.begin(), copy.end() );
//  */

  CI_LOG_I("Uploading shape to GPU.");
	auto vbo = gl::Vbo::create( GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW );
	auto mesh = gl::VboMesh::create( vertices.size(), GL_TRIANGLES, {{ kVertexLayout, vbo }} );
	batch = gl::Batch::create( mesh, shader, kVertexMapping );
}

void Landscape::setTextureUnits( uint8_t iClearUnit, uint8_t iBlurredUnit )
{
	auto &shader = batch->getGlslProg();
	shader->uniform( "uClearTexture", iClearUnit );
	shader->uniform( "uBlurredTexture", iBlurredUnit );
}

void Landscape::setGridSize( const ci::vec2 &iSize )
{
  auto &shader = batch->getGlslProg();
  shader->uniform( "uGridSize", iSize );
}

void Landscape::draw( float iFrameOffset )
{
	auto &shader = batch->getGlslProg();
	shader->uniform( "uCurrentFrame", iFrameOffset );

	batch->draw();
}
<|endoftext|>


<commit_before>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_FUNCTIONS_H_
#define LUWRA_FUNCTIONS_H_

#include "common.hpp"
#include "types.hpp"
#include "stack.hpp"

LUWRA_NS_BEGIN

namespace internal {
	template <typename T>
	struct FunctionWrapper {
		static_assert(
			sizeof(T) == -1,
			"Parameter to FunctionWrapper is not a function signature"
		);
	};

	template <>
	struct FunctionWrapper<void()> {
		template <void(*function_pointer)()> static inline
		int invoke(State*) {
			function_pointer();
			return 0;
		}
	};

	template <typename R>
	struct FunctionWrapper<R()> {
		template <R(*function_pointer)()> static inline
		int invoke(State* state) {
			return push(state, function_pointer());
		}
	};

	template <typename... A>
	struct FunctionWrapper<void(A...)> {
		template <void (*function_pointer)(A...)> static inline
		int invoke(State* state) {
			apply(state, function_pointer);
			return 0;
		}
	};

	template <typename R, typename... A>
	struct FunctionWrapper<R(A...)> {
		template <R (*function_pointer)(A...)> static inline
		int invoke(State* state) {
			return push(
				state,
				apply(state, function_pointer)
			);
		}
	};

	template <typename T>
	struct FunctionWrapperHelper {
		static_assert(
			sizeof(T) == -1,
			"Parameter to FunctionWrapperHelper is not a function pointer"
		);
	};

	template <typename R, typename... A>
	struct FunctionWrapperHelper<R(*)(A...)> {
		using Signature = R(A...);

		template <R(*function_pointer)(A...)> static
		constexpr CFunction wrapped =
			&internal::FunctionWrapper<Signature>::template invoke<function_pointer>;
	};
}

/**
 * Assuming its parameters can be retrieved from the Lua stack, ordinary functions can be wrapped
 * using the `wrap_function` instance in order to produce a C function which can be used by the
 * Lua VM.
 *
 * Assuming your function has the following signature:
 *
 *   R my_fun(A0, A1 ... An);
 *
 * Generate a Lua-compatible like so:
 *
 *   CFunction wrapped_fun = wrap_function<R(A0, A1 ... An), my_fun>;
 */
template <
	typename S,
	S* function_pointer
>
constexpr CFunction wrap_function =
	&internal::FunctionWrapper<S>::template invoke<function_pointer>;

/**
 * This macros allows you to wrap functions without providing a type signature.
 */
#define LUWRA_WRAP_FUNCTION(fun) \
	(luwra::internal::FunctionWrapperHelper<decltype(&fun)>::wrapped<&fun>)

LUWRA_NS_END

#endif
<commit_msg>Fix bug with Clang where wrapped function pointers are optimized out<commit_after>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_FUNCTIONS_H_
#define LUWRA_FUNCTIONS_H_

#include "common.hpp"
#include "types.hpp"
#include "stack.hpp"

LUWRA_NS_BEGIN

namespace internal {
	template <typename T>
	struct FunctionWrapper {
		static_assert(
			sizeof(T) == -1,
			"Parameter to FunctionWrapper is not a function signature"
		);
	};

	template <>
	struct FunctionWrapper<void()> {
		template <void(*function_pointer)()> static inline
		int invoke(State*) {
			function_pointer();
			return 0;
		}
	};

	template <typename R>
	struct FunctionWrapper<R()> {
		template <R(*function_pointer)()> static inline
		int invoke(State* state) {
			return push(state, function_pointer());
		}
	};

	template <typename... A>
	struct FunctionWrapper<void(A...)> {
		template <void (*function_pointer)(A...)> static inline
		int invoke(State* state) {
			apply(state, function_pointer);
			return 0;
		}
	};

	template <typename R, typename... A>
	struct FunctionWrapper<R(A...)> {
		template <R (*function_pointer)(A...)> static inline
		int invoke(State* state) {
			return push(
				state,
				apply(state, function_pointer)
			);
		}
	};

	template <typename T>
	struct FunctionWrapperHelper {
		static_assert(
			sizeof(T) == -1,
			"Parameter to FunctionWrapperHelper is not a function pointer"
		);
	};

	template <typename R, typename... A>
	struct FunctionWrapperHelper<R(*)(A...)> {
		using Signature = R(A...);
	};
}

/**
 * Assuming its parameters can be retrieved from the Lua stack, ordinary functions can be wrapped
 * using the `wrap_function` instance in order to produce a C function which can be used by the
 * Lua VM.
 *
 * Assuming your function has the following signature:
 *
 *   R my_fun(A0, A1 ... An);
 *
 * Generate a Lua-compatible like so:
 *
 *   CFunction wrapped_fun = wrap_function<R(A0, A1 ... An), my_fun>;
 */
template <
	typename S,
	S* function_pointer
>
constexpr CFunction wrap_function =
	&internal::FunctionWrapper<S>::template invoke<function_pointer>;

/**
 * This macros allows you to wrap functions without providing a type signature.
 */
#define LUWRA_WRAP_FUNCTION(fun) \
	(luwra::wrap_function< \
	     typename luwra::internal::FunctionWrapperHelper<decltype(&fun)>::Signature, \
	     &fun \
	 >)

LUWRA_NS_END

#endif
<|endoftext|>


<commit_before>//===-- GameModel.cpp - Model for Game State ----------------------- c++ --===//
//
//                               UWH Timer
//
//           This file is distributed under the BSD 3-Clause License.
//                      See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "uwhd/model/GameModel.h"

#include <ctime>
#include <iomanip>
#include <string>
#include <sstream>

using namespace uwhtimer;

bool GameModel::operator==(const GameModel &Other) {
  return BlackScore == Other.BlackScore &&
         WhiteScore == Other.WhiteScore &&
         GameClockSecs == Other.GameClockSecs;
}

GameModel *GameModelManager::getModel() {
  return &Model;
}

std::string GameModel::dump() {
  std::stringstream SS;

  SS << "Black: " << BlackScore << "\n"
     << "White: " << WhiteScore << "\n"
     << "GameClockSecs: " << GameClockSecs << "\n";

  return SS.str();
}

std::string GameModel::serialize() {
  std::stringstream SS;

  SS << "S"
     << "B" << std::setfill('0') << std::setw(2) << BlackScore
     << "W" << std::setfill('0') << std::setw(2) << WhiteScore
     << "T" << std::setfill('0') << std::setw(5) << GameClockSecs
     << "E";

  return SS.str();
}

static bool check(std::stringstream &SS, char V) {
  char C;
  SS.get(C);
  return C != V;
}

bool GameModel::deSerialize(std::string S, GameModel &M) {
  GameModel NewM;
  std::stringstream SS;
  SS << S;

  if (check(SS, 'S'))
    return true;

  if (check(SS, 'B'))
    return true;

  SS >> NewM.BlackScore;

  if (check(SS, 'W'))
    return true;

  SS >> NewM.WhiteScore;

  if (check(SS, 'T'))
    return true;

  SS >> NewM.GameClockSecs;

  if (check(SS, 'E'))
    return true;

  M = NewM;
  return false;
}
<commit_msg>Always dump GameModel values as int values<commit_after>//===-- GameModel.cpp - Model for Game State ----------------------- c++ --===//
//
//                               UWH Timer
//
//           This file is distributed under the BSD 3-Clause License.
//                      See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "uwhd/model/GameModel.h"

#include <ctime>
#include <iomanip>
#include <string>
#include <sstream>

using namespace uwhtimer;

bool GameModel::operator==(const GameModel &Other) {
  return BlackScore == Other.BlackScore &&
         WhiteScore == Other.WhiteScore &&
         GameClockSecs == Other.GameClockSecs;
}

GameModel *GameModelManager::getModel() {
  return &Model;
}

std::string GameModel::dump() {
  std::stringstream SS;

  SS << "Black: " << int(BlackScore) << "\n"
     << "White: " << int(WhiteScore) << "\n"
     << "GameClockSecs: " << int(GameClockSecs) << "\n";

  return SS.str();
}

std::string GameModel::serialize() {
  std::stringstream SS;

  SS << "S"
     << "B" << std::setfill('0') << std::setw(2) << BlackScore
     << "W" << std::setfill('0') << std::setw(2) << WhiteScore
     << "T" << std::setfill('0') << std::setw(5) << GameClockSecs
     << "E";

  return SS.str();
}

static bool check(std::stringstream &SS, char V) {
  char C;
  SS.get(C);
  return C != V;
}

bool GameModel::deSerialize(std::string S, GameModel &M) {
  GameModel NewM;
  std::stringstream SS;
  SS << S;

  if (check(SS, 'S'))
    return true;

  if (check(SS, 'B'))
    return true;

  SS >> NewM.BlackScore;

  if (check(SS, 'W'))
    return true;

  SS >> NewM.WhiteScore;

  if (check(SS, 'T'))
    return true;

  SS >> NewM.GameClockSecs;

  if (check(SS, 'E'))
    return true;

  M = NewM;
  return false;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2019, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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 "UBLOX_N2XX.h"

using namespace mbed;
using namespace events;

static const intptr_t cellular_properties[AT_CellularBase::PROPERTY_MAX] = {
    AT_CellularNetwork::RegistrationModeLAC,        // C_EREG
    AT_CellularNetwork::RegistrationModeDisable,    // C_GREG
    AT_CellularNetwork::RegistrationModeDisable,    // C_REG
    1,  // AT_CGSN_WITH_TYPE
    0,  // AT_CGDATA
    0,  // AT_CGAUTH
    0,  // AT_CNMI
    0,  // AT_CSMP
    0,  // AT_CMGF
    0,  // AT_CSDH
    1,  // PROPERTY_IPV4_STACK
    0,  // PROPERTY_IPV6_STACK
    0,  // PROPERTY_IPV4V6_STACK
};

UBLOX_N2XX::UBLOX_N2XX(FileHandle *fh): AT_CellularDevice(fh)
{
    AT_CellularBase::set_cellular_properties(cellular_properties);
    _at->set_urc_handler("+NPIN:", mbed::Callback<void()>(this, &UBLOX_N2XX::NPIN_URC));
    memset(simstr, 0, sizeof(simstr));
}

UBLOX_N2XX::~UBLOX_N2XX()
{
    _at->set_urc_handler("+NPIN:", NULL);
}

// Callback for Sim Pin.
void UBLOX_N2XX::NPIN_URC()
{
    _at->read_string(simstr, sizeof(simstr));
}

AT_CellularContext *UBLOX_N2XX::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
{
    return new UBLOX_N2XX_CellularContext(at, this, apn, cp_req, nonip_req);
}

AT_CellularSMS *UBLOX_N2XX::open_sms_impl(ATHandler &at)
{
    return new UBLOX_N2XX_CellularSMS(at);
}

nsapi_error_t UBLOX_N2XX::init()
{
    _at->lock();
    _at->flush();
    _at->cmd_start("AT"); // echo off
    _at->cmd_stop_read_resp();

    _at->cmd_start("AT+CMEE=1"); // verbose responses
    _at->cmd_stop_read_resp();

#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN
    set_pin(MBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN);
#endif
    return _at->unlock_return_error();
}

nsapi_error_t UBLOX_N2XX::get_sim_state(SimState &state)
{
    nsapi_error_t error = NSAPI_ERROR_DEVICE_ERROR;

    _at->lock();
    _at->flush();
    _at->cmd_start("AT+CFUN=1");
    _at->cmd_stop();

    _at->resp_start();
    _at->read_string(simstr, sizeof(simstr));
    _at->resp_stop();
    error = _at->unlock_return_error();

    int len = strlen(simstr);
    if (len > 0 || error == NSAPI_ERROR_OK) {
        if (error == NSAPI_ERROR_OK) {
            state = SimStateReady;
        } else if (len >= 6 && memcmp(simstr, "ENTER PIN", 9) == 0) {
            state = SimStatePinNeeded;
        } else {
            simstr[len] = '\0';
            tr_error("Unknown SIM state %s", simstr);
            state = SimStateUnknown;
        }
        error = NSAPI_ERROR_OK;
    } else {
        tr_warn("SIM not readable.");
        state = SimStateUnknown; // SIM may not be ready yet or pin command may not be supported
    }

#if MBED_CONF_MBED_TRACE_ENABLE
    switch (state) {
        case SimStatePinNeeded:
            tr_info("SIM PIN required");
            break;
        case SimStatePukNeeded:
            tr_error("SIM PUK required");
            break;
        case SimStateUnknown:
            tr_warn("SIM state unknown");
            break;
        default:
            tr_info("SIM is ready");
            break;
    }
#endif
    return error;
}

nsapi_error_t UBLOX_N2XX::set_pin(const char *sim_pin)
{
    // if SIM is already in ready state then settings the PIN
    // will return error so let's check the state before settings the pin.
    SimState state;
    if (get_sim_state(state) == NSAPI_ERROR_OK && state == SimStateReady) {
        return NSAPI_ERROR_OK;
    }

    if (sim_pin == NULL) {
        return NSAPI_ERROR_PARAMETER;
    }

    _at->lock();
    _at->cmd_start("AT+NPIN=0,");
    _at->write_string(sim_pin);
    _at->cmd_stop_read_resp();
    return _at->unlock_return_error();
}
<commit_msg>C030_N2XX default interface<commit_after>/*
 * Copyright (c) 2019, Arm Limited and affiliates.
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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 "UBLOX_N2XX.h"

using namespace mbed;
using namespace events;

static const intptr_t cellular_properties[AT_CellularBase::PROPERTY_MAX] = {
    AT_CellularNetwork::RegistrationModeLAC,        // C_EREG
    AT_CellularNetwork::RegistrationModeDisable,    // C_GREG
    AT_CellularNetwork::RegistrationModeDisable,    // C_REG
    1,  // AT_CGSN_WITH_TYPE
    0,  // AT_CGDATA
    0,  // AT_CGAUTH
    0,  // AT_CNMI
    0,  // AT_CSMP
    0,  // AT_CMGF
    0,  // AT_CSDH
    1,  // PROPERTY_IPV4_STACK
    0,  // PROPERTY_IPV6_STACK
    0,  // PROPERTY_IPV4V6_STACK
};

UBLOX_N2XX::UBLOX_N2XX(FileHandle *fh): AT_CellularDevice(fh)
{
    AT_CellularBase::set_cellular_properties(cellular_properties);
    _at->set_urc_handler("+NPIN:", mbed::Callback<void()>(this, &UBLOX_N2XX::NPIN_URC));
    memset(simstr, 0, sizeof(simstr));
}

UBLOX_N2XX::~UBLOX_N2XX()
{
    _at->set_urc_handler("+NPIN:", NULL);
}

// Callback for Sim Pin.
void UBLOX_N2XX::NPIN_URC()
{
    _at->read_string(simstr, sizeof(simstr));
}

AT_CellularContext *UBLOX_N2XX::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
{
    return new UBLOX_N2XX_CellularContext(at, this, apn, cp_req, nonip_req);
}

AT_CellularSMS *UBLOX_N2XX::open_sms_impl(ATHandler &at)
{
    return new UBLOX_N2XX_CellularSMS(at);
}

nsapi_error_t UBLOX_N2XX::init()
{
    _at->lock();
    _at->flush();
    _at->cmd_start("AT"); // echo off
    _at->cmd_stop_read_resp();

    _at->cmd_start("AT+CMEE=1"); // verbose responses
    _at->cmd_stop_read_resp();

#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN
    set_pin(MBED_CONF_NSAPI_DEFAULT_CELLULAR_SIM_PIN);
#endif
    return _at->unlock_return_error();
}

nsapi_error_t UBLOX_N2XX::get_sim_state(SimState &state)
{
    nsapi_error_t error = NSAPI_ERROR_DEVICE_ERROR;

    _at->lock();
    _at->flush();
    _at->cmd_start("AT+CFUN=1");
    _at->cmd_stop();

    _at->resp_start();
    _at->read_string(simstr, sizeof(simstr));
    _at->resp_stop();
    error = _at->unlock_return_error();

    int len = strlen(simstr);
    if (len > 0 || error == NSAPI_ERROR_OK) {
        if (error == NSAPI_ERROR_OK) {
            state = SimStateReady;
        } else if (len >= 6 && memcmp(simstr, "ENTER PIN", 9) == 0) {
            state = SimStatePinNeeded;
        } else {
            simstr[len] = '\0';
            tr_error("Unknown SIM state %s", simstr);
            state = SimStateUnknown;
        }
        error = NSAPI_ERROR_OK;
    } else {
        tr_warn("SIM not readable.");
        state = SimStateUnknown; // SIM may not be ready yet or pin command may not be supported
    }

#if MBED_CONF_MBED_TRACE_ENABLE
    switch (state) {
        case SimStatePinNeeded:
            tr_info("SIM PIN required");
            break;
        case SimStatePukNeeded:
            tr_error("SIM PUK required");
            break;
        case SimStateUnknown:
            tr_warn("SIM state unknown");
            break;
        default:
            tr_info("SIM is ready");
            break;
    }
#endif
    return error;
}

nsapi_error_t UBLOX_N2XX::set_pin(const char *sim_pin)
{
    // if SIM is already in ready state then settings the PIN
    // will return error so let's check the state before settings the pin.
    SimState state;
    if (get_sim_state(state) == NSAPI_ERROR_OK && state == SimStateReady) {
        return NSAPI_ERROR_OK;
    }

    if (sim_pin == NULL) {
        return NSAPI_ERROR_PARAMETER;
    }

    _at->lock();
    _at->cmd_start("AT+NPIN=0,");
    _at->write_string(sim_pin);
    _at->cmd_stop_read_resp();
    return _at->unlock_return_error();
}

#if MBED_CONF_UBLOX_N2XX_PROVIDE_DEFAULT
#include "UARTSerial.h"
CellularDevice *CellularDevice::get_default_instance()
{
    static UARTSerial serial(MBED_CONF_UBLOX_N2XX_TX, MBED_CONF_UBLOX_N2XX_RX, MBED_CONF_UBLOX_N2XX_BAUDRATE);
#if defined (MBED_CONF_UBLOX_N2XX_RTS) && defined(MBED_CONF_UBLOX_N2XX_CTS)
    tr_debug("UBLOX_N2XX flow control: RTS %d CTS %d", MBED_CONF_UBLOX_N2XX_RTS, MBED_CONF_UBLOX_N2XX_CTS);
    serial.set_flow_control(SerialBase::RTSCTS, MBED_CONF_UBLOX_N2XX_RTS, MBED_CONF_UBLOX_N2XX_CTS);
#endif
    static UBLOX_N2XX device(&serial);
    return &device;
}
#endif
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Alexandru-Eugen Ichim
 *                      Willow Garage, 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 Willow Garage, Inc. 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.
 *
 *  $Id$
 */

#ifndef PCL_FEATURES_IMPL_NORMAL_BASED_SIGNATURE_H_
#define PCL_FEATURES_IMPL_NORMAL_BASED_SIGNATURE_H_

#include "pcl/features/normal_based_signature.h"

template <typename PointT, typename PointNT, typename PointFeature> void
pcl::NormalBasedSignatureEstimation<PointT, PointNT, PointFeature>::computeFeature (FeatureCloud &output)
{
  // do a few checks before starting the computations
  if (!normals_)
  {
    PCL_ERROR ("NormalBasedSignatureEstimation: input normals not set\n");
    return;
  }

  PointFeature test_feature;
  if (N_prime * M_prime != sizeof (test_feature.values) / sizeof (float))
  {
    PCL_ERROR ("NormalBasedSignatureEstimation: not using the proper signature size: %u vs %u\n", N_prime * M_prime, sizeof (test_feature.values) / sizeof (float));
    return;
  }

  tree_->setInputCloud (input_);
  output.points.clear ();
  //for (size_t point_i = 0; point_i < input_->points.size (); ++point_i)
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t point_i = indices_->at (index_i);
    Eigen::MatrixXf s_matrix (N, M);
    Eigen::Vector3f center_point = input_->points[point_i].getVector3fMap ();
    for (size_t k = 0; k < N; ++k)
    {
      Eigen::VectorXf s_row (M);
      for (size_t l = 0; l < M; ++l)
      {
        Eigen::Vector3f normal = normals_->points[point_i].getNormalVector3fMap ();
        Eigen::Vector3f normal_u, normal_v;

        if (fabs (normal.x ()) > 0.0001f)
        {
          normal_u.x () = - normal.y () / normal.x ();
          normal_u.y () = 1.0f;
          normal_u.z () = 0.0f;
          normal_u.normalize ();

        }
        else if (fabs (normal.y ()) > 0.0001f)
        {
          normal_u.x () = 1.0f;
          normal_u.y () = - normal.x () / normal.y ();
          normal_u.z () = 0.0f;
          normal_u.normalize ();
        }
        else
        {
          normal_u.x () = 0.0f;
          normal_u.y () = 1.0f;
          normal_u.z () = - normal.y () / normal.z ();
        }
        normal_v = normal.cross (normal_u);

        Eigen::Vector3f zeta_point = 2.0f*(l+1)*scale_h / M * (cos (2.0f*M_PI*(k+1) / N) * normal_u + sin (2.0f*M_PI*(k+1) / N) * normal_v);

        // compute normal by using the neighbors
        Eigen::Vector3f zeta_point_plus_center = zeta_point + center_point;
        PointT zeta_point_pcl;
        zeta_point_pcl.x = zeta_point_plus_center.x (); zeta_point_pcl.y = zeta_point_plus_center.y (); zeta_point_pcl.z = zeta_point_plus_center.z ();
        std::vector<int> k_indices;
        std::vector<float> k_sqr_distances;
        tree_->radiusSearch (zeta_point_pcl,
                             normal_search_radius,
                             k_indices,
                             k_sqr_distances);
        // do k nearest search if there are no neighbors nearby
        if (k_indices.size () == 0)
        {
          k_indices.resize (5);
          k_sqr_distances.resize (5);
          tree_->nearestKSearch (zeta_point_pcl,
                                 5,
                                 k_indices,
                                 k_sqr_distances);
        }
        Eigen::Vector3f average_normal (0.0f, 0.0f, 0.0f);
        float average_normalization_factor = 0.0f;
        // normals weighted by 1/squared_distances
        for (size_t nn_i = 0; nn_i < k_indices.size (); ++nn_i)
        {
          if (k_sqr_distances[nn_i] < 0.0000001f)
          {
            average_normal = normals_->points[k_indices[nn_i]].getNormalVector3fMap ();
            average_normalization_factor = 1.0f;
            break;
          }
          average_normal += normals_->points[k_indices[nn_i]].getNormalVector3fMap () / k_sqr_distances[nn_i];
          average_normalization_factor += 1.0f / k_sqr_distances[nn_i];
        }
        average_normal /= average_normalization_factor;
        float s = zeta_point.dot (average_normal) / zeta_point.norm ();
        s_row[l] = s;
      }

      // do DCT on the s_matrix row-wise
      Eigen::VectorXf dct_row (M);
      for (int m = 0; m < s_row.size (); ++m)
      {
        float Xk = 0.0f;
        for (int n = 0; n < s_row.size (); ++n)
          Xk += s_row[n] * cos (M_PI / M * (n + 0.5f) * k);
        dct_row[m] = Xk;
      }
      s_row = dct_row;
      s_matrix.row (k) = dct_row;
    }

    // do DFT on the s_matrix column-wise
    Eigen::MatrixXf dft_matrix (N, M);
    for (size_t column_i = 0; column_i < M; ++column_i)
    {
      Eigen::VectorXf dft_col (N);
      for (size_t k = 0; k < N; ++k)
      {
        float Xk_real = 0.0f, Xk_imag = 0.0f;
        for (size_t n = 0; n < N; ++n)
        {
          Xk_real += s_matrix(n, column_i) * cos (2.0f * M_PI / N * k * n);
          Xk_imag += s_matrix(n, column_i) * sin (2.0f * M_PI / N * k * n);
        }
        dft_col[k] = sqrt (Xk_real*Xk_real + Xk_imag*Xk_imag);
      }
      dft_matrix.col (column_i) = dft_col;
    }

    Eigen::MatrixXf final_matrix = dft_matrix.block (0, 0, N_prime, M_prime);

    PointFeature feature_point;
    for (size_t i = 0; i < N_prime; ++i)
      for (size_t j = 0; j < M_prime; ++j)
        feature_point.values[i*M_prime + j] = final_matrix (i, j);
    output.points.push_back (feature_point);
  }
}

#define PCL_INSTANTIATE_NormalBasedSignatureEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::NormalBasedSignatureEstimation<T,NT,OutT>;

#endif /* PCL_FEATURES_IMPL_NORMAL_BASED_SIGNATURE_H_ */
<commit_msg>tiny optimizations<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Alexandru-Eugen Ichim
 *                      Willow Garage, 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 Willow Garage, Inc. 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.
 *
 *  $Id$
 */

#ifndef PCL_FEATURES_IMPL_NORMAL_BASED_SIGNATURE_H_
#define PCL_FEATURES_IMPL_NORMAL_BASED_SIGNATURE_H_

#include "pcl/features/normal_based_signature.h"

template <typename PointT, typename PointNT, typename PointFeature> void
pcl::NormalBasedSignatureEstimation<PointT, PointNT, PointFeature>::computeFeature (FeatureCloud &output)
{
  // do a few checks before starting the computations
  if (!normals_)
  {
    PCL_ERROR ("NormalBasedSignatureEstimation: input normals not set\n");
    return;
  }

  PointFeature test_feature;
  if (N_prime * M_prime != sizeof (test_feature.values) / sizeof (float))
  {
    PCL_ERROR ("NormalBasedSignatureEstimation: not using the proper signature size: %u vs %u\n", N_prime * M_prime, sizeof (test_feature.values) / sizeof (float));
    return;
  }

  std::vector<int> k_indices;
  std::vector<float> k_sqr_distances;

  tree_->setInputCloud (input_);
  output.points.resize (indices_->size ());

  //for (size_t point_i = 0; point_i < input_->points.size (); ++point_i)
  for (size_t index_i = 0; index_i < indices_->size (); ++index_i)
  {
    size_t point_i = (*indices_)[index_i];
    Eigen::MatrixXf s_matrix (N, M);

    Eigen::Vector4f center_point = input_->points[point_i].getVector4fMap ();

    for (size_t k = 0; k < N; ++k)
    {
      Eigen::VectorXf s_row (M);

      for (size_t l = 0; l < M; ++l)
      {
        Eigen::Vector4f normal = normals_->points[point_i].getNormalVector4fMap ();
        Eigen::Vector4f normal_u = Eigen::Vector4f::Zero ();
        Eigen::Vector4f normal_v = Eigen::Vector4f::Zero ();

        if (fabs (normal.x ()) > 0.0001f)
        {
          normal_u.x () = - normal.y () / normal.x ();
          normal_u.y () = 1.0f;
          normal_u.z () = 0.0f;
          normal_u.normalize ();

        }
        else if (fabs (normal.y ()) > 0.0001f)
        {
          normal_u.x () = 1.0f;
          normal_u.y () = - normal.x () / normal.y ();
          normal_u.z () = 0.0f;
          normal_u.normalize ();
        }
        else
        {
          normal_u.x () = 0.0f;
          normal_u.y () = 1.0f;
          normal_u.z () = - normal.y () / normal.z ();
        }
        normal_v = normal.cross3 (normal_u);

        Eigen::Vector4f zeta_point = 2.0f * (l+1) * scale_h / M * (cos (2.0f * M_PI * (k+1) / N) * normal_u + sin (2.0f * M_PI * (k+1) / N) * normal_v);

        // Compute normal by using the neighbors
        Eigen::Vector4f zeta_point_plus_center = zeta_point + center_point;
        PointT zeta_point_pcl;
        zeta_point_pcl.x = zeta_point_plus_center.x (); zeta_point_pcl.y = zeta_point_plus_center.y (); zeta_point_pcl.z = zeta_point_plus_center.z ();

        tree_->radiusSearch (zeta_point_pcl, normal_search_radius, k_indices, k_sqr_distances);

        // Do k nearest search if there are no neighbors nearby
        if (k_indices.size () == 0)
        {
          k_indices.resize (5);
          k_sqr_distances.resize (5);
          tree_->nearestKSearch (zeta_point_pcl, 5, k_indices, k_sqr_distances);
        }

        Eigen::Vector4f average_normal = Eigen::Vector4f::Zero ();

        float average_normalization_factor = 0.0f;

        // Normals weighted by 1/squared_distances
        for (size_t nn_i = 0; nn_i < k_indices.size (); ++nn_i)
        {
          if (k_sqr_distances[nn_i] < 0.0000001f)
          {
            average_normal = normals_->points[k_indices[nn_i]].getNormalVector4fMap ();
            average_normalization_factor = 1.0f;
            break;
          }
          average_normal += normals_->points[k_indices[nn_i]].getNormalVector4fMap () / k_sqr_distances[nn_i];
          average_normalization_factor += 1.0f / k_sqr_distances[nn_i];
        }
        average_normal /= average_normalization_factor;
        float s = zeta_point.dot (average_normal) / zeta_point.norm ();
        s_row[l] = s;
      }

      // do DCT on the s_matrix row-wise
      Eigen::VectorXf dct_row (M);
      for (int m = 0; m < s_row.size (); ++m)
      {
        float Xk = 0.0f;
        for (int n = 0; n < s_row.size (); ++n)
          Xk += s_row[n] * cos (M_PI / M * (n + 0.5f) * k);
        dct_row[m] = Xk;
      }
      s_row = dct_row;
      s_matrix.row (k) = dct_row;
    }

    // do DFT on the s_matrix column-wise
    Eigen::MatrixXf dft_matrix (N, M);
    for (size_t column_i = 0; column_i < M; ++column_i)
    {
      Eigen::VectorXf dft_col (N);
      for (size_t k = 0; k < N; ++k)
      {
        float Xk_real = 0.0f, Xk_imag = 0.0f;
        for (size_t n = 0; n < N; ++n)
        {
          Xk_real += s_matrix(n, column_i) * cos (2.0f * M_PI / N * k * n);
          Xk_imag += s_matrix(n, column_i) * sin (2.0f * M_PI / N * k * n);
        }
        dft_col[k] = sqrt (Xk_real*Xk_real + Xk_imag*Xk_imag);
      }
      dft_matrix.col (column_i) = dft_col;
    }

    Eigen::MatrixXf final_matrix = dft_matrix.block (0, 0, N_prime, M_prime);

    PointFeature feature_point;
    for (size_t i = 0; i < N_prime; ++i)
      for (size_t j = 0; j < M_prime; ++j)
        feature_point.values[i*M_prime + j] = final_matrix (i, j);

    output.points[index_i] = feature_point;
  }
}

#define PCL_INSTANTIATE_NormalBasedSignatureEstimation(T,NT,OutT) template class PCL_EXPORTS pcl::NormalBasedSignatureEstimation<T,NT,OutT>;

#endif /* PCL_FEATURES_IMPL_NORMAL_BASED_SIGNATURE_H_ */
<|endoftext|>