<commit_before>#include <mlopen/activ.hpp>
#include <mlopen/mlo_internal.hpp>
#include <mlopen/kernel_cache.hpp>

namespace mlopen {

mlopenStatus_t ActivationDescriptor::Forward(
		Handle						&handle,
		const void					* /* alpha */,
		const TensorDescriptor		&xDesc,
		const Data_t				x,
		const void					* /* beta */,
		const TensorDescriptor		&yDesc,
		Data_t						y,
		bool                        do_backward,
		Data_t						/* workSpace */) {

	mlopenStatus_t status = mlopenStatusSuccess;
	printf("in activation forward\n");

	mlo_construct_neuron construct_params(1); // forward

	std::string kernel_path = "../src/Kernels/";
	construct_params.setKernelPath(kernel_path);

	construct_params.setStream(handle.GetStream());

	int nOut;
	int cOut;
	int hOut;
	int wOut;
	int nOutStride;
	int cOutStride;
	int hOutStride;
	int wOutStride;

	std::tie(nOut, cOut, hOut, wOut) = tie4(yDesc.GetLengths());
	std::tie(nOutStride, cOutStride, hOutStride, wOutStride) = tie4(yDesc.GetStrides());

	construct_params.setTopDescr(
			"NCHW",
			"FP32",
			nOut,
			cOut,
			hOut,
			wOut,
			nOutStride,
			cOutStride,
			hOutStride,
			wOutStride);
	int nIn;
	int cIn;
	int hIn;
	int wIn;
	int nInStride;
	int cInStride;
	int hInStride;
	int wInStride;

	std::tie(nIn, cIn, hIn, wIn) = tie4(xDesc.GetLengths());
	std::tie(nInStride, cInStride, hInStride, wInStride) = tie4(xDesc.GetStrides());

	construct_params.setBotDescr(
			"NCHW",
			"FP32",
			nIn,
			cIn,
			hIn,
			wIn,
			nInStride,
			cInStride,
			hInStride,
			wInStride);

	double activ_alpha = GetAlpha();
	double activ_beta = GetBeta();
	double activ_power = GetPower();

	construct_params.doBackward(do_backward);
	construct_params.setNeuronDescr(static_cast<int>(mode), activ_power, activ_beta, activ_alpha);

	status = static_cast<mlopenStatus_t>(construct_params.mloConstruct());

	std::string program_name = kernel_path + construct_params.getKernelFile();  // CL kernel filename
	std::string kernel_name = construct_params.getKernelName(); // kernel name
	std::string compiler_options = construct_params.getCompilerOptions(); // kernel parameters

	std::string network_config;
	construct_params.mloBuildConf_Key(network_config);

	const std::vector<size_t> & vld = construct_params.getLocalWkSize();
	const std::vector<size_t> & vgd = construct_params.getGlobalWkSize();

	int imode = mode;
	construct_params.getNeuronDescr(imode, activ_power, activ_beta, activ_alpha);
	float f_activ_alpha = static_cast<float>(activ_alpha);
	float f_activ_beta = static_cast<float>(activ_beta);
	float f_activ_power = static_cast<float>(activ_power);

	handle.GetKernel("mlopenActivationForward",
			network_config,
			program_name,
			kernel_name,
			vld,
			vgd,
			compiler_options)(x, y, f_activ_power, f_activ_beta, f_activ_alpha);

	std::cout << "Activation Forward Finished !!" << std::endl;

	return(status);
}

mlopenStatus_t ActivationDescriptor :: Backward(
		Handle						&handle,
		const void					* /* alpha */,
		const TensorDescriptor		&yDesc,
		const Data_t		  		y,
		const TensorDescriptor		&dyDesc,
		const Data_t		  		dy,
		const TensorDescriptor		&xDesc,
		const Data_t		  		x,
		const void			  		* /* beta */,
		const TensorDescriptor		&dxDesc,
		Data_t						dx,
		const Data_t				/* workSpace */) {

	mlopenStatus_t status = mlopenStatusSuccess;
	printf("in activation backward\n");

	mlo_construct_neuron construct_params(0); // backward

	std::string kernel_path = "../src/Kernels/";

	construct_params.setKernelPath(kernel_path);

	construct_params.setStream(handle.GetStream());
	int ndOut;
	int cdOut;
	int hdOut;
	int wdOut;
	int ndOutStride;
	int cdOutStride;
	int hdOutStride;
	int wdOutStride;

	std::tie(ndOut, cdOut, hdOut, wdOut) = tie4(dyDesc.GetLengths());
	std::tie(ndOutStride, cdOutStride, hdOutStride, wdOutStride) = tie4(dyDesc.GetStrides());

	construct_params.setTopDfDescr(
			"NCHW",
			"FP32",
			ndOut,
			cdOut,
			hdOut,
			wdOut,
			ndOutStride,
			cdOutStride,
			hdOutStride,
			wdOutStride);

	int nOut;
	int cOut;
	int hOut;
	int wOut;
	int nOutStride;
	int cOutStride;
	int hOutStride;
	int wOutStride;

	std::tie(nOut, cOut, hOut, wOut) = tie4(yDesc.GetLengths());
	std::tie(nOutStride, cOutStride, hOutStride, wOutStride) = tie4(yDesc.GetStrides());

	construct_params.setTopDescr(
			"NCHW",
			"FP32",
			nOut,
			cOut,
			hOut,
			wOut,
			nOutStride,
			cOutStride,
			hOutStride,
			wOutStride);

	int ndIn;
	int cdIn;
	int hdIn;
	int wdIn;
	int ndInStride;
	int cdInStride;
	int hdInStride;
	int wdInStride;

	std::tie(ndIn, cdIn, hdIn, wdIn) = tie4(dxDesc.GetLengths());
	std::tie(ndInStride, cdInStride, hdInStride, wdInStride) = tie4(dxDesc.GetStrides());

	construct_params.setBotDfDescr(
			"NCHW",
			"FP32",
			ndIn,
			cdIn,
			hdIn,
			wdIn,
			ndInStride,
			cdInStride,
			hdInStride,
			wdInStride);

	int nIn;
	int cIn;
	int hIn;
	int wIn;
	int nInStride;
	int cInStride;
	int hInStride;
	int wInStride;

	std::tie(nIn, cIn, hIn, wIn) = tie4(xDesc.GetLengths());
	std::tie(nInStride, cInStride, hInStride, wInStride) = tie4(xDesc.GetStrides());

	construct_params.setBotDescr(
			"NCHW",
			"FP32",
			nIn,
			cIn,
			hIn,
			wIn,
			nInStride,
			cInStride,
			hInStride,
			wInStride);

	int activ_mode = GetMode();
	double activ_alpha = GetAlpha();
	double activ_beta = GetBeta();
	double activ_power = GetPower();

	construct_params.setNeuronDescr(activ_mode, activ_power, activ_beta, activ_alpha);

	status = static_cast<mlopenStatus_t>(construct_params.mloConstruct());

	std::string program_name = kernel_path + construct_params.getKernelFile();  // CL kernel filename
	std::string kernel_name = construct_params.getKernelName(); // kernel name
	std::string compiler_options = construct_params.getCompilerOptions(); // kernel parameters

	std::string network_config;
	construct_params.mloBuildConf_Key(network_config);

	const std::vector<size_t> & vld = construct_params.getLocalWkSize();
	const std::vector<size_t> & vgd = construct_params.getGlobalWkSize();

	float f_activ_alpha = static_cast<float>(GetAlpha());
	float f_activ_beta = static_cast<float>(GetBeta());
	float f_activ_power = static_cast<float>(GetPower());
	float f_diff_scale = f_activ_beta * f_activ_power;

	handle.GetKernel("mlopenActivationBackward",
		network_config,
		program_name,
		kernel_name,
		vld,
		vgd,
		compiler_options)(dx, dy, x, y, f_diff_scale, f_activ_power, f_activ_beta, f_activ_alpha);

	std::cout << "Activation Backward Finished !!" << std::endl;

	return(status);
}
}  // namespace mlopen
<commit_msg>removed kernel_path<commit_after>#include <mlopen/activ.hpp>
#include <mlopen/mlo_internal.hpp>
#include <mlopen/kernel_cache.hpp>

namespace mlopen {

mlopenStatus_t ActivationDescriptor::Forward(
		Handle						&handle,
		const void					* /* alpha */,
		const TensorDescriptor		&xDesc,
		const Data_t				x,
		const void					* /* beta */,
		const TensorDescriptor		&yDesc,
		Data_t						y,
		bool                        do_backward,
		Data_t						/* workSpace */) {

	mlopenStatus_t status = mlopenStatusSuccess;
	printf("in activation forward\n");

	mlo_construct_neuron construct_params(1); // forward

	construct_params.setStream(handle.GetStream());

	int nOut;
	int cOut;
	int hOut;
	int wOut;
	int nOutStride;
	int cOutStride;
	int hOutStride;
	int wOutStride;

	std::tie(nOut, cOut, hOut, wOut) = tie4(yDesc.GetLengths());
	std::tie(nOutStride, cOutStride, hOutStride, wOutStride) = tie4(yDesc.GetStrides());

	construct_params.setTopDescr(
			"NCHW",
			"FP32",
			nOut,
			cOut,
			hOut,
			wOut,
			nOutStride,
			cOutStride,
			hOutStride,
			wOutStride);
	int nIn;
	int cIn;
	int hIn;
	int wIn;
	int nInStride;
	int cInStride;
	int hInStride;
	int wInStride;

	std::tie(nIn, cIn, hIn, wIn) = tie4(xDesc.GetLengths());
	std::tie(nInStride, cInStride, hInStride, wInStride) = tie4(xDesc.GetStrides());

	construct_params.setBotDescr(
			"NCHW",
			"FP32",
			nIn,
			cIn,
			hIn,
			wIn,
			nInStride,
			cInStride,
			hInStride,
			wInStride);

	double activ_alpha = GetAlpha();
	double activ_beta = GetBeta();
	double activ_power = GetPower();

	construct_params.doBackward(do_backward);
	construct_params.setNeuronDescr(static_cast<int>(mode), activ_power, activ_beta, activ_alpha);

	status = static_cast<mlopenStatus_t>(construct_params.mloConstruct());

	std::string program_name = construct_params.getKernelFile();  // CL kernel filename
	std::string kernel_name = construct_params.getKernelName(); // kernel name
	std::string compiler_options = construct_params.getCompilerOptions(); // kernel parameters

	std::string network_config;
	construct_params.mloBuildConf_Key(network_config);

	const std::vector<size_t> & vld = construct_params.getLocalWkSize();
	const std::vector<size_t> & vgd = construct_params.getGlobalWkSize();

	int imode = mode;
	construct_params.getNeuronDescr(imode, activ_power, activ_beta, activ_alpha);
	float f_activ_alpha = static_cast<float>(activ_alpha);
	float f_activ_beta = static_cast<float>(activ_beta);
	float f_activ_power = static_cast<float>(activ_power);

	handle.GetKernel("mlopenActivationForward",
			network_config,
			program_name,
			kernel_name,
			vld,
			vgd,
			compiler_options)(x, y, f_activ_power, f_activ_beta, f_activ_alpha);

	std::cout << "Activation Forward Finished !!" << std::endl;

	return(status);
}

mlopenStatus_t ActivationDescriptor :: Backward(
		Handle						&handle,
		const void					* /* alpha */,
		const TensorDescriptor		&yDesc,
		const Data_t		  		y,
		const TensorDescriptor		&dyDesc,
		const Data_t		  		dy,
		const TensorDescriptor		&xDesc,
		const Data_t		  		x,
		const void			  		* /* beta */,
		const TensorDescriptor		&dxDesc,
		Data_t						dx,
		const Data_t				/* workSpace */) {

	mlopenStatus_t status = mlopenStatusSuccess;
	printf("in activation backward\n");

	mlo_construct_neuron construct_params(0); // backward

	construct_params.setStream(handle.GetStream());
	int ndOut;
	int cdOut;
	int hdOut;
	int wdOut;
	int ndOutStride;
	int cdOutStride;
	int hdOutStride;
	int wdOutStride;

	std::tie(ndOut, cdOut, hdOut, wdOut) = tie4(dyDesc.GetLengths());
	std::tie(ndOutStride, cdOutStride, hdOutStride, wdOutStride) = tie4(dyDesc.GetStrides());

	construct_params.setTopDfDescr(
			"NCHW",
			"FP32",
			ndOut,
			cdOut,
			hdOut,
			wdOut,
			ndOutStride,
			cdOutStride,
			hdOutStride,
			wdOutStride);

	int nOut;
	int cOut;
	int hOut;
	int wOut;
	int nOutStride;
	int cOutStride;
	int hOutStride;
	int wOutStride;

	std::tie(nOut, cOut, hOut, wOut) = tie4(yDesc.GetLengths());
	std::tie(nOutStride, cOutStride, hOutStride, wOutStride) = tie4(yDesc.GetStrides());

	construct_params.setTopDescr(
			"NCHW",
			"FP32",
			nOut,
			cOut,
			hOut,
			wOut,
			nOutStride,
			cOutStride,
			hOutStride,
			wOutStride);

	int ndIn;
	int cdIn;
	int hdIn;
	int wdIn;
	int ndInStride;
	int cdInStride;
	int hdInStride;
	int wdInStride;

	std::tie(ndIn, cdIn, hdIn, wdIn) = tie4(dxDesc.GetLengths());
	std::tie(ndInStride, cdInStride, hdInStride, wdInStride) = tie4(dxDesc.GetStrides());

	construct_params.setBotDfDescr(
			"NCHW",
			"FP32",
			ndIn,
			cdIn,
			hdIn,
			wdIn,
			ndInStride,
			cdInStride,
			hdInStride,
			wdInStride);

	int nIn;
	int cIn;
	int hIn;
	int wIn;
	int nInStride;
	int cInStride;
	int hInStride;
	int wInStride;

	std::tie(nIn, cIn, hIn, wIn) = tie4(xDesc.GetLengths());
	std::tie(nInStride, cInStride, hInStride, wInStride) = tie4(xDesc.GetStrides());

	construct_params.setBotDescr(
			"NCHW",
			"FP32",
			nIn,
			cIn,
			hIn,
			wIn,
			nInStride,
			cInStride,
			hInStride,
			wInStride);

	int activ_mode = GetMode();
	double activ_alpha = GetAlpha();
	double activ_beta = GetBeta();
	double activ_power = GetPower();

	construct_params.setNeuronDescr(activ_mode, activ_power, activ_beta, activ_alpha);

	status = static_cast<mlopenStatus_t>(construct_params.mloConstruct());

	std::string program_name = construct_params.getKernelFile();  // CL kernel filename
	std::string kernel_name = construct_params.getKernelName(); // kernel name
	std::string compiler_options = construct_params.getCompilerOptions(); // kernel parameters

	std::string network_config;
	construct_params.mloBuildConf_Key(network_config);

	const std::vector<size_t> & vld = construct_params.getLocalWkSize();
	const std::vector<size_t> & vgd = construct_params.getGlobalWkSize();

	float f_activ_alpha = static_cast<float>(GetAlpha());
	float f_activ_beta = static_cast<float>(GetBeta());
	float f_activ_power = static_cast<float>(GetPower());
	float f_diff_scale = f_activ_beta * f_activ_power;

	handle.GetKernel("mlopenActivationBackward",
		network_config,
		program_name,
		kernel_name,
		vld,
		vgd,
		compiler_options)(dx, dy, x, y, f_diff_scale, f_activ_power, f_activ_beta, f_activ_alpha);

	std::cout << "Activation Backward Finished !!" << std::endl;

	return(status);
}
}  // namespace mlopen
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include <osg/GLExtensions>
#include <osg/Texture1D>
#include <osg/State>
#include <osg/GLU>

typedef void (APIENTRY * MyCompressedTexImage1DArbProc) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);

using namespace osg;

Texture1D::Texture1D():
            _textureWidth(0),
            _numMipmapLevels(0)
{
}

Texture1D::Texture1D(const Texture1D& text,const CopyOp& copyop):
            Texture(text,copyop),
            _image(copyop(text._image.get())),
            _textureWidth(text._textureWidth),
            _numMipmapLevels(text._numMipmapLevels),
            _subloadCallback(text._subloadCallback)
{
}

Texture1D::~Texture1D()
{
}

int Texture1D::compare(const StateAttribute& sa) const
{
    // check the types are equal and then create the rhs variable
    // used by the COMPARE_StateAttribute_Paramter macro's below.
    COMPARE_StateAttribute_Types(Texture1D,sa)

    if (_image!=rhs._image) // smart pointer comparison.
    {
        if (_image.valid())
        {
            if (rhs._image.valid())
            {
                int result = _image->compare(*rhs._image);
                if (result!=0) return result;
            }
            else
            {
                return 1; // valid lhs._image is greater than null.
            }
        }
        else if (rhs._image.valid())
        {
            return -1; // valid rhs._image is greater than null.
        }
    }

    int result = compareTexture(rhs);
    if (result!=0) return result;

    // compare each paramter in turn against the rhs.
    COMPARE_StateAttribute_Parameter(_textureWidth)
    COMPARE_StateAttribute_Parameter(_subloadCallback)

    return 0; // passed all the above comparison macro's, must be equal.
}

void Texture1D::setImage(Image* image)
{
    // delete old texture objects.
    dirtyTextureObject();

    _image = image;
    _modifiedTag.setAllElementsTo(0);

}

void Texture1D::apply(State& state) const
{

    // get the contextID (user defined ID of 0 upwards) for the
    // current OpenGL context.
    const unsigned int contextID = state.getContextID();

    // get the texture object for the current contextID.
    TextureObject* textureObject = getTextureObject(contextID);

    if (textureObject != 0)
    {
        textureObject->bind();

        if (getTextureParameterDirty(state.getContextID())) applyTexParameters(GL_TEXTURE_1D,state);

        if (_subloadCallback.valid())
        {
            _subloadCallback->subload(*this,state);
        }
        else if (_image.valid() && getModifiedTag(contextID) != _image->getModifiedTag())
        {
            applyTexImage1D(GL_TEXTURE_1D,_image.get(),state, _textureWidth, _numMipmapLevels);

            // update the modified tag to show that it is upto date.
            getModifiedTag(contextID) = _image->getModifiedTag();
        }

    }
    else if (_subloadCallback.valid())
    {

        // we don't have a applyTexImage1D_subload yet so can't reuse.. so just generate a new texture object.
        _textureObjectBuffer[contextID] = textureObject = getTextureObjectManager()->generateTextureObject(contextID,GL_TEXTURE_2D);

        textureObject->bind();

        applyTexParameters(GL_TEXTURE_1D,state);

        _subloadCallback->load(*this,state);

        textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,1,1,0);

        // in theory the following line is redundent, but in practice
        // have found that the first frame drawn doesn't apply the textures
        // unless a second bind is called?!!
        // perhaps it is the first glBind which is not required...
        //glBindTexture( GL_TEXTURE_1D, handle );

    }
    else if (_image.valid() && _image->data())
    {

        // we don't have a applyTexImage1D_subload yet so can't reuse.. so just generate a new texture object.
        _textureObjectBuffer[contextID] = textureObject = getTextureObjectManager()->generateTextureObject(contextID,GL_TEXTURE_2D);

        textureObject->bind();

        applyTexParameters(GL_TEXTURE_1D,state);

        applyTexImage1D(GL_TEXTURE_1D,_image.get(),state, _textureWidth, _numMipmapLevels);

        textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,1,1,0);

        // update the modified tag to show that it is upto date.
        getModifiedTag(contextID) = _image->getModifiedTag();

        if (_unrefImageDataAfterApply && areAllTextureObjectsLoaded())
        {
            Texture1D* non_const_this = const_cast<Texture1D*>(this);
            non_const_this->_image = 0;
        }

        // in theory the following line is redundent, but in practice
        // have found that the first frame drawn doesn't apply the textures
        // unless a second bind is called?!!
        // perhaps it is the first glBind which is not required...
        //glBindTexture( GL_TEXTURE_1D, handle );

    }
    else
    {
        glBindTexture( GL_TEXTURE_1D, 0 );
    }
}

void Texture1D::computeInternalFormat() const
{
    if (_image.valid()) computeInternalFormatWithImage(*_image);
}

void Texture1D::applyTexImage1D(GLenum target, Image* image, State& state, GLsizei& inwidth, GLsizei& numMipmapLevels) const
{
    // if we don't have a valid image we can't create a texture!
    if (!image || !image->data())
        return;

    // get the contextID (user defined ID of 0 upwards) for the
    // current OpenGL context.
    const unsigned int contextID = state.getContextID();
    const Extensions* extensions = getExtensions(contextID,true);

    // compute the internal texture format, this set the _internalFormat to an appropriate value.
    computeInternalFormat();

    // select the internalFormat required for the texture.
    bool compressed = isCompressedInternalFormat(_internalFormat);

    image->ensureValidSizeForTexturing(extensions->maxTextureSize());

    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());

    static MyCompressedTexImage1DArbProc glCompressedTexImage1D_ptr =
        (MyCompressedTexImage1DArbProc)getGLExtensionFuncPtr("glCompressedTexImage1DARB");

    if( _min_filter == LINEAR || _min_filter == NEAREST )
    {
        if ( !compressed )
        {
            numMipmapLevels = 1;
            glTexImage1D( target, 0, _internalFormat,
                image->s(), _borderWidth,
                (GLenum)image->getPixelFormat(),
                (GLenum)image->getDataType(),
                image->data() );

        }
        else if(glCompressedTexImage1D_ptr)
        {
            numMipmapLevels = 1;
            GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 );
            GLint size = ((image->s()+3)/4)*((image->t()+3)/4)*blockSize;
            glCompressedTexImage1D_ptr(target, 0, _internalFormat,
                  image->s(), _borderWidth,
                  size,
                  image->data());

        }

    }
    else
    {
        if(!image->isMipmap())
        {

            numMipmapLevels = 1;

            gluBuild1DMipmaps( target, _internalFormat,
                image->s(),
                (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
                image->data() );

        }
        else
        {
            numMipmapLevels = image->getNumMipmapLevels();

            int width  = image->s();

            if( !compressed )
            {
                for( GLsizei k = 0 ; k < numMipmapLevels  && width ;k++)
                {

                    glTexImage1D( target, k, _internalFormat,
                         width,_borderWidth,
                        (GLenum)image->getPixelFormat(),
                        (GLenum)image->getDataType(),
                        image->getMipmapData(k));

                    width >>= 1;
                }
            }
            else if(glCompressedTexImage1D_ptr)
            {
                GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 );
                GLint size = 0;
                for( GLsizei k = 0 ; k < numMipmapLevels  && width ;k++)
                {

                    size = ((width+3)/4)*blockSize;
                    glCompressedTexImage1D_ptr(target, k, _internalFormat,
                        width,  _borderWidth, size, image->getMipmapData(k));

                    width >>= 1;
                }
            }
        }

    }

    inwidth = image->s();
}

void Texture1D::copyTexImage1D(State& state, int x, int y, int width)
{
    const unsigned int contextID = state.getContextID();

    // get the texture object for the current contextID.
    TextureObject* textureObject = getTextureObject(contextID);

    if (textureObject != 0)
    {
        if (width==(int)_textureWidth)
        {
            // we have a valid texture object which is the right size
            // so lets play clever and use copyTexSubImage2D instead.
            // this allows use to reuse the texture object and avoid
            // expensive memory allocations.
            copyTexSubImage1D(state,0 ,x, y, width);
            return;
        }
        // the relevent texture object is not of the right size so
        // needs to been deleted
        // remove previously bound textures.
        dirtyTextureObject();
        // note, dirtyTextureObject() dirties all the texture objects for
        // this texture, is this right?  Perhaps we should dirty just the
        // one for this context.  Note sure yet will leave till later.
        // RO July 2001.
    }

    // remove any previously assigned images as these are nolonger valid.
    _image = NULL;

    // switch off mip-mapping.
    _min_filter = LINEAR;
    _mag_filter = LINEAR;

    _textureObjectBuffer[contextID] = textureObject = getTextureObjectManager()->generateTextureObject(contextID,GL_TEXTURE_2D);

    textureObject->bind();

    applyTexParameters(GL_TEXTURE_1D,state);
    glCopyTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, x, y, width, 0 );

    _textureWidth = width;
    _numMipmapLevels = 1;

    textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,1,1,0);

    // inform state that this texture is the current one bound.
    state.haveAppliedAttribute(this);
}

void Texture1D::copyTexSubImage1D(State& state, int xoffset, int x, int y, int width)
{
    const unsigned int contextID = state.getContextID();

    // get the texture object for the current contextID.
    TextureObject* textureObject = getTextureObject(contextID);

    if (textureObject != 0)
    {

        textureObject->bind();

        // we have a valid image
        applyTexParameters(GL_TEXTURE_1D,state);
        glCopyTexSubImage1D( GL_TEXTURE_1D, 0, xoffset, x, y, width);

        /* Redundant, delete later */
        //glBindTexture( GL_TEXTURE_1D, handle );

        // inform state that this texture is the current one bound.
        state.haveAppliedAttribute(this);

    }
    else
    {
        // no texture object already exsits for this context so need to
        // create it upfront - simply call copyTexImage1D.
        copyTexImage1D(state,x,y,width);
    }
}
<commit_msg>From Bob Kuehne, fixed eroneous use of GL_TEXTURE_2D token in texture object manager usage<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include <osg/GLExtensions>
#include <osg/Texture1D>
#include <osg/State>
#include <osg/GLU>

typedef void (APIENTRY * MyCompressedTexImage1DArbProc) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data);

using namespace osg;

Texture1D::Texture1D():
            _textureWidth(0),
            _numMipmapLevels(0)
{
}

Texture1D::Texture1D(const Texture1D& text,const CopyOp& copyop):
            Texture(text,copyop),
            _image(copyop(text._image.get())),
            _textureWidth(text._textureWidth),
            _numMipmapLevels(text._numMipmapLevels),
            _subloadCallback(text._subloadCallback)
{
}

Texture1D::~Texture1D()
{
}

int Texture1D::compare(const StateAttribute& sa) const
{
    // check the types are equal and then create the rhs variable
    // used by the COMPARE_StateAttribute_Paramter macro's below.
    COMPARE_StateAttribute_Types(Texture1D,sa)

    if (_image!=rhs._image) // smart pointer comparison.
    {
        if (_image.valid())
        {
            if (rhs._image.valid())
            {
                int result = _image->compare(*rhs._image);
                if (result!=0) return result;
            }
            else
            {
                return 1; // valid lhs._image is greater than null.
            }
        }
        else if (rhs._image.valid())
        {
            return -1; // valid rhs._image is greater than null.
        }
    }

    int result = compareTexture(rhs);
    if (result!=0) return result;

    // compare each paramter in turn against the rhs.
    COMPARE_StateAttribute_Parameter(_textureWidth)
    COMPARE_StateAttribute_Parameter(_subloadCallback)

    return 0; // passed all the above comparison macro's, must be equal.
}

void Texture1D::setImage(Image* image)
{
    // delete old texture objects.
    dirtyTextureObject();

    _image = image;
    _modifiedTag.setAllElementsTo(0);

}

void Texture1D::apply(State& state) const
{

    // get the contextID (user defined ID of 0 upwards) for the
    // current OpenGL context.
    const unsigned int contextID = state.getContextID();

    // get the texture object for the current contextID.
    TextureObject* textureObject = getTextureObject(contextID);

    if (textureObject != 0)
    {
        textureObject->bind();

        if (getTextureParameterDirty(state.getContextID())) applyTexParameters(GL_TEXTURE_1D,state);

        if (_subloadCallback.valid())
        {
            _subloadCallback->subload(*this,state);
        }
        else if (_image.valid() && getModifiedTag(contextID) != _image->getModifiedTag())
        {
            applyTexImage1D(GL_TEXTURE_1D,_image.get(),state, _textureWidth, _numMipmapLevels);

            // update the modified tag to show that it is upto date.
            getModifiedTag(contextID) = _image->getModifiedTag();
        }

    }
    else if (_subloadCallback.valid())
    {

        // we don't have a applyTexImage1D_subload yet so can't reuse.. so just generate a new texture object.
        _textureObjectBuffer[contextID] = textureObject = getTextureObjectManager()->generateTextureObject(contextID,GL_TEXTURE_1D);

        textureObject->bind();

        applyTexParameters(GL_TEXTURE_1D,state);

        _subloadCallback->load(*this,state);

        textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,1,1,0);

        // in theory the following line is redundent, but in practice
        // have found that the first frame drawn doesn't apply the textures
        // unless a second bind is called?!!
        // perhaps it is the first glBind which is not required...
        //glBindTexture( GL_TEXTURE_1D, handle );

    }
    else if (_image.valid() && _image->data())
    {

        // we don't have a applyTexImage1D_subload yet so can't reuse.. so just generate a new texture object.
        _textureObjectBuffer[contextID] = textureObject = getTextureObjectManager()->generateTextureObject(contextID,GL_TEXTURE_1D);

        textureObject->bind();

        applyTexParameters(GL_TEXTURE_1D,state);

        applyTexImage1D(GL_TEXTURE_1D,_image.get(),state, _textureWidth, _numMipmapLevels);

        textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,1,1,0);

        // update the modified tag to show that it is upto date.
        getModifiedTag(contextID) = _image->getModifiedTag();

        if (_unrefImageDataAfterApply && areAllTextureObjectsLoaded())
        {
            Texture1D* non_const_this = const_cast<Texture1D*>(this);
            non_const_this->_image = 0;
        }

        // in theory the following line is redundent, but in practice
        // have found that the first frame drawn doesn't apply the textures
        // unless a second bind is called?!!
        // perhaps it is the first glBind which is not required...
        //glBindTexture( GL_TEXTURE_1D, handle );

    }
    else
    {
        glBindTexture( GL_TEXTURE_1D, 0 );
    }
}

void Texture1D::computeInternalFormat() const
{
    if (_image.valid()) computeInternalFormatWithImage(*_image);
}

void Texture1D::applyTexImage1D(GLenum target, Image* image, State& state, GLsizei& inwidth, GLsizei& numMipmapLevels) const
{
    // if we don't have a valid image we can't create a texture!
    if (!image || !image->data())
        return;

    // get the contextID (user defined ID of 0 upwards) for the
    // current OpenGL context.
    const unsigned int contextID = state.getContextID();
    const Extensions* extensions = getExtensions(contextID,true);

    // compute the internal texture format, this set the _internalFormat to an appropriate value.
    computeInternalFormat();

    // select the internalFormat required for the texture.
    bool compressed = isCompressedInternalFormat(_internalFormat);

    image->ensureValidSizeForTexturing(extensions->maxTextureSize());

    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());

    static MyCompressedTexImage1DArbProc glCompressedTexImage1D_ptr =
        (MyCompressedTexImage1DArbProc)getGLExtensionFuncPtr("glCompressedTexImage1DARB");

    if( _min_filter == LINEAR || _min_filter == NEAREST )
    {
        if ( !compressed )
        {
            numMipmapLevels = 1;
            glTexImage1D( target, 0, _internalFormat,
                image->s(), _borderWidth,
                (GLenum)image->getPixelFormat(),
                (GLenum)image->getDataType(),
                image->data() );

        }
        else if(glCompressedTexImage1D_ptr)
        {
            numMipmapLevels = 1;
            GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 );
            GLint size = ((image->s()+3)/4)*((image->t()+3)/4)*blockSize;
            glCompressedTexImage1D_ptr(target, 0, _internalFormat,
                  image->s(), _borderWidth,
                  size,
                  image->data());

        }

    }
    else
    {
        if(!image->isMipmap())
        {

            numMipmapLevels = 1;

            gluBuild1DMipmaps( target, _internalFormat,
                image->s(),
                (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
                image->data() );

        }
        else
        {
            numMipmapLevels = image->getNumMipmapLevels();

            int width  = image->s();

            if( !compressed )
            {
                for( GLsizei k = 0 ; k < numMipmapLevels  && width ;k++)
                {

                    glTexImage1D( target, k, _internalFormat,
                         width,_borderWidth,
                        (GLenum)image->getPixelFormat(),
                        (GLenum)image->getDataType(),
                        image->getMipmapData(k));

                    width >>= 1;
                }
            }
            else if(glCompressedTexImage1D_ptr)
            {
                GLint blockSize = ( _internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ? 8 : 16 );
                GLint size = 0;
                for( GLsizei k = 0 ; k < numMipmapLevels  && width ;k++)
                {

                    size = ((width+3)/4)*blockSize;
                    glCompressedTexImage1D_ptr(target, k, _internalFormat,
                        width,  _borderWidth, size, image->getMipmapData(k));

                    width >>= 1;
                }
            }
        }

    }

    inwidth = image->s();
}

void Texture1D::copyTexImage1D(State& state, int x, int y, int width)
{
    const unsigned int contextID = state.getContextID();

    // get the texture object for the current contextID.
    TextureObject* textureObject = getTextureObject(contextID);

    if (textureObject != 0)
    {
        if (width==(int)_textureWidth)
        {
            // we have a valid texture object which is the right size
            // so lets play clever and use copyTexSubImage1D instead.
            // this allows use to reuse the texture object and avoid
            // expensive memory allocations.
            copyTexSubImage1D(state,0 ,x, y, width);
            return;
        }
        // the relevent texture object is not of the right size so
        // needs to been deleted
        // remove previously bound textures.
        dirtyTextureObject();
        // note, dirtyTextureObject() dirties all the texture objects for
        // this texture, is this right?  Perhaps we should dirty just the
        // one for this context.  Note sure yet will leave till later.
        // RO July 2001.
    }

    // remove any previously assigned images as these are nolonger valid.
    _image = NULL;

    // switch off mip-mapping.
    _min_filter = LINEAR;
    _mag_filter = LINEAR;

    _textureObjectBuffer[contextID] = textureObject = getTextureObjectManager()->generateTextureObject(contextID,GL_TEXTURE_1D);

    textureObject->bind();

    applyTexParameters(GL_TEXTURE_1D,state);
    glCopyTexImage1D( GL_TEXTURE_1D, 0, GL_RGBA, x, y, width, 0 );

    _textureWidth = width;
    _numMipmapLevels = 1;

    textureObject->setAllocated(_numMipmapLevels,_internalFormat,_textureWidth,1,1,0);

    // inform state that this texture is the current one bound.
    state.haveAppliedAttribute(this);
}

void Texture1D::copyTexSubImage1D(State& state, int xoffset, int x, int y, int width)
{
    const unsigned int contextID = state.getContextID();

    // get the texture object for the current contextID.
    TextureObject* textureObject = getTextureObject(contextID);

    if (textureObject != 0)
    {

        textureObject->bind();

        // we have a valid image
        applyTexParameters(GL_TEXTURE_1D,state);
        glCopyTexSubImage1D( GL_TEXTURE_1D, 0, xoffset, x, y, width);

        // inform state that this texture is the current one bound.
        state.haveAppliedAttribute(this);

    }
    else
    {
        // no texture object already exsits for this context so need to
        // create it upfront - simply call copyTexImage1D.
        copyTexImage1D(state,x,y,width);
    }
}
<|endoftext|>


<commit_before>#include <osg/Transform>

using namespace osg;

Transform::Transform()
{
    _type = DYNAMIC;
    _matrix = new osg::Matrix();
    _matrix->makeIdentity();
}

Transform::Transform(const Matrix& mat )
{
    _type = DYNAMIC;
    (*_matrix) = mat;
}

Transform::~Transform()
{
}

const bool Transform::computeBound() const
{
    if (!Group::computeBound()) return false;

    Vec3 xdash = _bsphere._center;
    xdash.x() += _bsphere._radius;
    xdash = xdash*(*_matrix);

    Vec3 ydash = _bsphere._center;
    ydash.y() += _bsphere._radius;
    ydash = ydash*(*_matrix);

    Vec3 zdash = _bsphere._center;
    zdash.y() += _bsphere._radius;
    zdash = zdash*(*_matrix);

    _bsphere._center = _bsphere._center*(*_matrix);

    xdash -= _bsphere._center;
    float len_xdash = xdash.length();

    ydash -= _bsphere._center;
    float len_ydash = ydash.length();

    zdash -= _bsphere._center;
    float len_zdash = zdash.length();

    _bsphere._radius = len_xdash;
    if (_bsphere._radius<len_ydash) _bsphere._radius = len_ydash;
    if (_bsphere._radius<len_zdash) _bsphere._radius = len_zdash;

    return true;
}
<commit_msg>Fixed copy constructor which was copying a matrix to unitialized memory.<commit_after>#include <osg/Transform>

using namespace osg;

Transform::Transform()
{
    _type = DYNAMIC;
    _matrix = new Matrix;
    _matrix->makeIdentity();
}

Transform::Transform(const Matrix& mat )
{
    _type = DYNAMIC;
    _matrix = new Matrix(mat);
}

Transform::~Transform()
{
}

const bool Transform::computeBound() const
{
    if (!Group::computeBound()) return false;

    Vec3 xdash = _bsphere._center;
    xdash.x() += _bsphere._radius;
    xdash = xdash*(*_matrix);

    Vec3 ydash = _bsphere._center;
    ydash.y() += _bsphere._radius;
    ydash = ydash*(*_matrix);

    Vec3 zdash = _bsphere._center;
    zdash.y() += _bsphere._radius;
    zdash = zdash*(*_matrix);

    _bsphere._center = _bsphere._center*(*_matrix);

    xdash -= _bsphere._center;
    float len_xdash = xdash.length();

    ydash -= _bsphere._center;
    float len_ydash = ydash.length();

    zdash -= _bsphere._center;
    float len_zdash = zdash.length();

    _bsphere._radius = len_xdash;
    if (_bsphere._radius<len_ydash) _bsphere._radius = len_ydash;
    if (_bsphere._radius<len_zdash) _bsphere._radius = len_zdash;

    return true;
}
<|endoftext|>


<commit_before>#include <osgFX/Cartoon>
#include <osgFX/Registry>

#include <osg/PolygonOffset>
#include <osg/Texture1D>
#include <osg/VertexProgram>
#include <osg/PolygonMode>
#include <osg/CullFace>
#include <osg/Image>
#include <osg/TexEnv>
#include <osg/LineWidth>
#include <osg/Material>
#include <osg/Program>
#include <osg/Shader>

#include <sstream>

using namespace osgFX;

namespace
{

    osg::Image* create_sharp_lighting_map(int levels = 4, int texture_size = 16)
    {
        osg::ref_ptr<osg::Image> image = new osg::Image;
        image->setImage(texture_size, 1, 1, 4, GL_RGBA, GL_UNSIGNED_BYTE, new unsigned char[4*texture_size], osg::Image::USE_NEW_DELETE);
        for (int i=0; i<texture_size; ++i) {
            float c = i/static_cast<float>(texture_size);
            c = (1+static_cast<int>(sqrtf(c) * (levels))) / static_cast<float>(levels+1);
            *(image->data(i, 0)+0) = static_cast<unsigned char>(c*255);
            *(image->data(i, 0)+1) = static_cast<unsigned char>(c*255);
            *(image->data(i, 0)+2) = static_cast<unsigned char>(c*255);
            *(image->data(i, 0)+3) = 255;
        }
        return image.release();
    }

}

namespace
{

    // register a prototype for this effect
    Registry::Proxy proxy(new Cartoon);

    // default technique class
    class DefaultTechnique: public Technique {
    public:
        DefaultTechnique(osg::Material* wf_mat, osg::LineWidth *wf_lw, int lightnum)
            : Technique(), _wf_mat(wf_mat), _wf_lw(wf_lw), _lightnum(lightnum) {}

        void getRequiredExtensions(std::vector<std::string>& extensions) const
        {
            extensions.push_back("GL_ARB_vertex_program");
        }

    protected:

        void define_passes()
        {
            // implement pass #1 (solid surfaces)
            {
                std::ostringstream vp_oss;
                vp_oss <<
                    "!!ARBvp1.0\n"
                    "OPTION ARB_position_invariant;"
                    "PARAM c0 = { 0, 0, 0, 0 };"
                    "TEMP R0, R1;"
                    "ATTRIB v18 = vertex.normal;"
                    "PARAM s18 = state.light[" << _lightnum << "].position;"
                    "PARAM s16 = state.light[" << _lightnum << "].diffuse;"
                    "PARAM s1 = state.material.diffuse;"
                    "PARAM s631[4] = { state.matrix.modelview.invtrans };"
                    "MOV R0, s1;"
                    "MUL result.color.front.primary, R0, s16;"
                    "DP4 R0.x, s18, s18;"
                    "RSQ R0.x, R0.x;"
                    "MUL R1, R0.x, s18;"
                    "DP4 R0.x, s631[0], v18;"
                    "DP4 R0.y, s631[1], v18;"
                    "DP4 R0.z, s631[2], v18;"
                    "DP4 R0.w, s631[3], v18;"
                    "DP4 R0.x, R1, R0;"
                    "MAX result.texcoord[0].x, c0.x, R0.x;"
                    "END";

                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;

                osg::ref_ptr<osg::PolygonOffset> polyoffset = new osg::PolygonOffset;
                polyoffset->setFactor(1.0f);
                polyoffset->setUnits(1.0f);
                ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
                vp->setVertexProgram(vp_oss.str());
                ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF);

                osg::ref_ptr<osg::Texture1D> texture = new osg::Texture1D;
                texture->setImage(create_sharp_lighting_map());
                texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
                texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
                ss->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv;
                texenv->setMode(osg::TexEnv::MODULATE);
                ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                addPass(ss.get());
            }

            // implement pass #2 (outlines)
            {
                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
                osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode;
                polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
                ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
                cf->setMode(osg::CullFace::FRONT);
                ss->setAttributeAndModes(cf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                ss->setAttributeAndModes(_wf_lw.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                _wf_mat->setColorMode(osg::Material::OFF);
                _wf_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
                _wf_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
                _wf_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));

                // set by outline colour so no need to set here.
                //_wf_mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));

                ss->setAttributeAndModes(_wf_mat.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
                ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
                ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);

                addPass(ss.get());

            }
        }

    private:
        osg::ref_ptr<osg::Material> _wf_mat;
        osg::ref_ptr<osg::LineWidth> _wf_lw;
        int _lightnum;
    };

}

///////////////////////////////////////////////////////////////////////////
// A port of Marco Jez's "cartoon.cg" to the OpenGL Shading Language
// by Mike Weiblen 2003-10-03,
//
// This shader is simplified due to limitations in the OGLSL implementation
// in the current 3Dlabs driver.  As the OGLSL implementation improves,
// need to revisit and enhance this shader.
namespace
{
    class OGLSL_Technique : public Technique {
    public:
        OGLSL_Technique(osg::Material* wf_mat, osg::LineWidth *wf_lw, int lightnum)
            : Technique(), _wf_mat(wf_mat), _wf_lw(wf_lw), _lightnum(lightnum) {}

        void getRequiredExtensions(std::vector<std::string>& extensions) const
        {
            extensions.push_back( "GL_ARB_shader_objects" );
            extensions.push_back( "GL_ARB_vertex_shader" );
            extensions.push_back( "GL_ARB_fragment_shader" );
        }

    protected:

        void define_passes()
        {
            // implement pass #1 (solid surfaces)
            {
                const char * vert_source =
                "const vec3 LightPosition = vec3( 0.0, 2.0, 4.0 );"
                "varying float CartoonTexCoord;"
                "void main( void )"
                "{"
                    "vec3 eye_space_normal = normalize(gl_NormalMatrix * gl_Normal);"
                    "CartoonTexCoord = max(0.0, dot(normalize(LightPosition), eye_space_normal));"
                    "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
                "}";

                const char * frag_source =
                "uniform sampler1D CartoonTexUnit;"
                "varying float CartoonTexCoord;"
                "void main( void )"
                "{"
                    "gl_FragColor = texture1D( CartoonTexUnit, CartoonTexCoord );"
                "}";

                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;

                osg::ref_ptr<osg::PolygonOffset> polyoffset = new osg::PolygonOffset;
                polyoffset->setFactor(1.0f);
                polyoffset->setUnits(1.0f);
                ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                osg::ref_ptr<osg::Program> program = new osg::Program;
                program->addShader( new osg::Shader( osg::Shader::VERTEX, vert_source ) );
                program->addShader( new osg::Shader( osg::Shader::FRAGMENT, frag_source ) );

                ss->addUniform( new osg::Uniform("CartoonTexUnit", 0));
                ss->setAttributeAndModes( program.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF);

                osg::ref_ptr<osg::Texture1D> texture = new osg::Texture1D;
                texture->setImage(create_sharp_lighting_map());
                texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
                texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
                ss->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv;
                texenv->setMode(osg::TexEnv::MODULATE);
                ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                addPass(ss.get());
            }

            // implement pass #2 (outlines)
            {
                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
                osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode;
                polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
                ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
                cf->setMode(osg::CullFace::FRONT);
                ss->setAttributeAndModes(cf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                ss->setAttributeAndModes(_wf_lw.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                _wf_mat->setColorMode(osg::Material::OFF);
                _wf_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
                _wf_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
                _wf_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));

                // set by outline colour so no need to set here.
                //_wf_mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));

                ss->setAttributeAndModes(_wf_mat.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
                ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
                ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);

                addPass(ss.get());

            }
        }

    private:
        osg::ref_ptr<osg::Material> _wf_mat;
        osg::ref_ptr<osg::LineWidth> _wf_lw;
        int _lightnum;
    };

}

///////////////////////////////////////////////////////////////////////////

Cartoon::Cartoon()
:    Effect(),
    _wf_mat(new osg::Material),
    _wf_lw(new osg::LineWidth),
    _lightnum(0)
{
    setOutlineColor(osg::Vec4(0, 0, 0, 1));
}

Cartoon::Cartoon(const Cartoon& copy, const osg::CopyOp& copyop)
:    Effect(copy, copyop),
    _wf_mat(static_cast<osg::Material* >(copyop(copy._wf_mat.get()))),
    _wf_lw(static_cast<osg::LineWidth *>(copyop(copy._wf_lw.get()))),
    _lightnum(copy._lightnum)
{
}

bool Cartoon::define_techniques()
{
    addTechnique(new DefaultTechnique(_wf_mat.get(), _wf_lw.get(), _lightnum));
    addTechnique(new OGLSL_Technique(_wf_mat.get(), _wf_lw.get(), _lightnum));
    return true;
}
<commit_msg>Set the default setting of LineWidth to 2.0 to ensure that old default behavior  is maintained.<commit_after>#include <osgFX/Cartoon>
#include <osgFX/Registry>

#include <osg/PolygonOffset>
#include <osg/Texture1D>
#include <osg/VertexProgram>
#include <osg/PolygonMode>
#include <osg/CullFace>
#include <osg/Image>
#include <osg/TexEnv>
#include <osg/LineWidth>
#include <osg/Material>
#include <osg/Program>
#include <osg/Shader>

#include <sstream>

using namespace osgFX;

namespace
{

    osg::Image* create_sharp_lighting_map(int levels = 4, int texture_size = 16)
    {
        osg::ref_ptr<osg::Image> image = new osg::Image;
        image->setImage(texture_size, 1, 1, 4, GL_RGBA, GL_UNSIGNED_BYTE, new unsigned char[4*texture_size], osg::Image::USE_NEW_DELETE);
        for (int i=0; i<texture_size; ++i) {
            float c = i/static_cast<float>(texture_size);
            c = (1+static_cast<int>(sqrtf(c) * (levels))) / static_cast<float>(levels+1);
            *(image->data(i, 0)+0) = static_cast<unsigned char>(c*255);
            *(image->data(i, 0)+1) = static_cast<unsigned char>(c*255);
            *(image->data(i, 0)+2) = static_cast<unsigned char>(c*255);
            *(image->data(i, 0)+3) = 255;
        }
        return image.release();
    }

}

namespace
{

    // register a prototype for this effect
    Registry::Proxy proxy(new Cartoon);

    // default technique class
    class DefaultTechnique: public Technique {
    public:
        DefaultTechnique(osg::Material* wf_mat, osg::LineWidth *wf_lw, int lightnum)
            : Technique(), _wf_mat(wf_mat), _wf_lw(wf_lw), _lightnum(lightnum) {}

        void getRequiredExtensions(std::vector<std::string>& extensions) const
        {
            extensions.push_back("GL_ARB_vertex_program");
        }

    protected:

        void define_passes()
        {
            // implement pass #1 (solid surfaces)
            {
                std::ostringstream vp_oss;
                vp_oss <<
                    "!!ARBvp1.0\n"
                    "OPTION ARB_position_invariant;"
                    "PARAM c0 = { 0, 0, 0, 0 };"
                    "TEMP R0, R1;"
                    "ATTRIB v18 = vertex.normal;"
                    "PARAM s18 = state.light[" << _lightnum << "].position;"
                    "PARAM s16 = state.light[" << _lightnum << "].diffuse;"
                    "PARAM s1 = state.material.diffuse;"
                    "PARAM s631[4] = { state.matrix.modelview.invtrans };"
                    "MOV R0, s1;"
                    "MUL result.color.front.primary, R0, s16;"
                    "DP4 R0.x, s18, s18;"
                    "RSQ R0.x, R0.x;"
                    "MUL R1, R0.x, s18;"
                    "DP4 R0.x, s631[0], v18;"
                    "DP4 R0.y, s631[1], v18;"
                    "DP4 R0.z, s631[2], v18;"
                    "DP4 R0.w, s631[3], v18;"
                    "DP4 R0.x, R1, R0;"
                    "MAX result.texcoord[0].x, c0.x, R0.x;"
                    "END";

                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;

                osg::ref_ptr<osg::PolygonOffset> polyoffset = new osg::PolygonOffset;
                polyoffset->setFactor(1.0f);
                polyoffset->setUnits(1.0f);
                ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
                vp->setVertexProgram(vp_oss.str());
                ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF);

                osg::ref_ptr<osg::Texture1D> texture = new osg::Texture1D;
                texture->setImage(create_sharp_lighting_map());
                texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
                texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
                ss->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv;
                texenv->setMode(osg::TexEnv::MODULATE);
                ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                addPass(ss.get());
            }

            // implement pass #2 (outlines)
            {
                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
                osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode;
                polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
                ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
                cf->setMode(osg::CullFace::FRONT);
                ss->setAttributeAndModes(cf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                ss->setAttributeAndModes(_wf_lw.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                _wf_mat->setColorMode(osg::Material::OFF);
                _wf_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
                _wf_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
                _wf_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));

                // set by outline colour so no need to set here.
                //_wf_mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));

                ss->setAttributeAndModes(_wf_mat.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
                ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
                ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);

                addPass(ss.get());

            }
        }

    private:
        osg::ref_ptr<osg::Material> _wf_mat;
        osg::ref_ptr<osg::LineWidth> _wf_lw;
        int _lightnum;
    };

}

///////////////////////////////////////////////////////////////////////////
// A port of Marco Jez's "cartoon.cg" to the OpenGL Shading Language
// by Mike Weiblen 2003-10-03,
//
// This shader is simplified due to limitations in the OGLSL implementation
// in the current 3Dlabs driver.  As the OGLSL implementation improves,
// need to revisit and enhance this shader.
namespace
{
    class OGLSL_Technique : public Technique {
    public:
        OGLSL_Technique(osg::Material* wf_mat, osg::LineWidth *wf_lw, int lightnum)
            : Technique(), _wf_mat(wf_mat), _wf_lw(wf_lw), _lightnum(lightnum) {}

        void getRequiredExtensions(std::vector<std::string>& extensions) const
        {
            extensions.push_back( "GL_ARB_shader_objects" );
            extensions.push_back( "GL_ARB_vertex_shader" );
            extensions.push_back( "GL_ARB_fragment_shader" );
        }

    protected:

        void define_passes()
        {
            // implement pass #1 (solid surfaces)
            {
                const char * vert_source =
                "const vec3 LightPosition = vec3( 0.0, 2.0, 4.0 );"
                "varying float CartoonTexCoord;"
                "void main( void )"
                "{"
                    "vec3 eye_space_normal = normalize(gl_NormalMatrix * gl_Normal);"
                    "CartoonTexCoord = max(0.0, dot(normalize(LightPosition), eye_space_normal));"
                    "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
                "}";

                const char * frag_source =
                "uniform sampler1D CartoonTexUnit;"
                "varying float CartoonTexCoord;"
                "void main( void )"
                "{"
                    "gl_FragColor = texture1D( CartoonTexUnit, CartoonTexCoord );"
                "}";

                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;

                osg::ref_ptr<osg::PolygonOffset> polyoffset = new osg::PolygonOffset;
                polyoffset->setFactor(1.0f);
                polyoffset->setUnits(1.0f);
                ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                osg::ref_ptr<osg::Program> program = new osg::Program;
                program->addShader( new osg::Shader( osg::Shader::VERTEX, vert_source ) );
                program->addShader( new osg::Shader( osg::Shader::FRAGMENT, frag_source ) );

                ss->addUniform( new osg::Uniform("CartoonTexUnit", 0));
                ss->setAttributeAndModes( program.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF);

                osg::ref_ptr<osg::Texture1D> texture = new osg::Texture1D;
                texture->setImage(create_sharp_lighting_map());
                texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
                texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
                ss->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv;
                texenv->setMode(osg::TexEnv::MODULATE);
                ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                addPass(ss.get());
            }

            // implement pass #2 (outlines)
            {
                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
                osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode;
                polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
                ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
                cf->setMode(osg::CullFace::FRONT);
                ss->setAttributeAndModes(cf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                ss->setAttributeAndModes(_wf_lw.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);

                _wf_mat->setColorMode(osg::Material::OFF);
                _wf_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
                _wf_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
                _wf_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));

                // set by outline colour so no need to set here.
                //_wf_mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));

                ss->setAttributeAndModes(_wf_mat.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);

                ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
                ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
                ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);

                addPass(ss.get());

            }
        }

    private:
        osg::ref_ptr<osg::Material> _wf_mat;
        osg::ref_ptr<osg::LineWidth> _wf_lw;
        int _lightnum;
    };

}

///////////////////////////////////////////////////////////////////////////

Cartoon::Cartoon()
:    Effect(),
    _wf_mat(new osg::Material),
    _wf_lw(new osg::LineWidth(2.0f)),
    _lightnum(0)
{
    setOutlineColor(osg::Vec4(0, 0, 0, 1));
}

Cartoon::Cartoon(const Cartoon& copy, const osg::CopyOp& copyop)
:    Effect(copy, copyop),
    _wf_mat(static_cast<osg::Material* >(copyop(copy._wf_mat.get()))),
    _wf_lw(static_cast<osg::LineWidth *>(copyop(copy._wf_lw.get()))),
    _lightnum(copy._lightnum)
{
}

bool Cartoon::define_techniques()
{
    addTechnique(new DefaultTechnique(_wf_mat.get(), _wf_lw.get(), _lightnum));
    addTechnique(new OGLSL_Technique(_wf_mat.get(), _wf_lw.get(), _lightnum));
    return true;
}
<|endoftext|>


<commit_before>#include "number.h"
#include "rtl_platform.h"

namespace rtl {

Number time$now()
{
    return rtl_time_now();
}

} // namespace rtl
<commit_msg>add time.sleep function<commit_after>#include <thread>

#include "number.h"
#include "rtl_platform.h"

namespace rtl {

Number time$now()
{
    return rtl_time_now();
}

void time$sleep(Number seconds)
{
    std::chrono::microseconds us(number_to_uint64(number_multiply(seconds, number_from_uint32(1000000))));
    std::this_thread::sleep_for(us);
}

} // namespace rtl
<|endoftext|>


<commit_before>#include <sstream>

#include <mimosa/init.hh>
#include <mimosa/options/options.hh>
#include <mimosa/http/server.hh>
#include <mimosa/http/dispatch-handler.hh>
#include <mimosa/http/fs-handler.hh>

using namespace mimosa;

uint16_t & PORT = *options::addOption<uint16_t>("", "port", "the port to use", 4242);
std::string & PATH = *options::addOption<std::string>("", "path", "the data dir to expose", "/usr");
std::string & CERT = *options::addOption<std::string>("", "cert", "the certificate (cert.pem)", "");
std::string & KEY = *options::addOption<std::string>("", "key", "the key (key.pem)", "");

class HelloHandler : public mimosa::http::Handler
{
  virtual bool handle(mimosa::http::RequestReader &  /*request*/,
                      mimosa::http::ResponseWriter & response) const
  {
    std::ostringstream os;
    os <<
      "<title>Hello World!</title>"
      "Hello World!
"
      "
"
      "
browse " << PATH << "
"
      "
test query string
"
      "
test post data
"
      "
"
      "";

    std::string data(os.str());
    response.status_ = mimosa::http::kStatusOk;
    response.content_type_ = "text/html";
    response.write(data.data(), data.size());
    return true;
  }
};

class QueryEchoHandler : public mimosa::http::Handler
{
  virtual bool handle(mimosa::http::RequestReader &  request,
                      mimosa::http::ResponseWriter & response) const
  {
    std::ostringstream os;
    os <<
      "<title>Query Echo!</title>"
      "Query Echo!
"
      "
";
    for (auto it = request.query().cbegin(); it != request.query().cend(); ++it)
      os << "
" << it->first << " = " << it->second << "
";
    os <<
      "
"
      "";

    std::string data(os.str());
    response.status_ = mimosa::http::kStatusOk;
    response.content_type_ = "text/html";
    response.write(data.data(), data.size());
    return true;
  }
};

class PostEchoHandler : public mimosa::http::Handler
{
  virtual bool handle(mimosa::http::RequestReader &  request,
                      mimosa::http::ResponseWriter & response) const
  {
    std::ostringstream os;
    os <<
      "<title>Post Echo!</title>"
      "Post Echo!
"
      "Method: " << methodString(request.method()) << "
"
      "Content-Type: " << request.contentType() << "
"
      "
";
    kvs form = request.form();
    for (auto it = form.cbegin(); it != form.cend(); ++it)
      os << "
" << it->first << " = " << it->second << "
";
    os <<
      "
"
      "
"
      "<form method='post' enctype='application/x-www-form-urlencoded' name='test-form'>"
      "firstname <input type='text' name='fname'/>
"
      "lastname <input type='text' name='lname'/>
"
      "<input type='submit' value='submit'/>"
      "</form>"
      "";

    std::string data(os.str());
    response.status_ = mimosa::http::kStatusOk;
    response.content_type_ = "text/html";
    response.write(data.data(), data.size());
    return true;
  }
};

int main(int argc, char ** argv)
{
  mimosa::init(argc, argv);

  {
    auto dispatch(new http::DispatchHandler);
    dispatch->registerHandler("/", new HelloHandler);
    dispatch->registerHandler("/query-echo", new QueryEchoHandler);
    dispatch->registerHandler("/post-echo", new PostEchoHandler);
    dispatch->registerHandler("/data/*", new http::FsHandler(PATH, 1, true));

    http::Server::Ptr server(new http::Server);
    server->setHandler(dispatch);

    if (!CERT.empty() && !KEY.empty())
      server->setSecure(CERT, KEY);

    auto ret = server->listenInet4(PORT);
    if (!ret)
    {
      puts("failed to listen");
      return 1;
    }
    printf("listen on %d succeed\n", PORT);

    while (true)
      server->serveOne();
  }

  mimosa::deinit();
  return 0;
}
<commit_msg>sample web server uses cpuForeach<commit_after>#include <sstream>

#include <mimosa/init.hh>
#include <mimosa/cpu-foreach.hh>
#include <mimosa/options/options.hh>
#include <mimosa/http/server.hh>
#include <mimosa/http/dispatch-handler.hh>
#include <mimosa/http/fs-handler.hh>

using namespace mimosa;

uint16_t & PORT = *options::addOption<uint16_t>("", "port", "the port to use", 4242);
std::string & PATH = *options::addOption<std::string>("", "path", "the data dir to expose", "/usr");
std::string & CERT = *options::addOption<std::string>("", "cert", "the certificate (cert.pem)", "");
std::string & KEY = *options::addOption<std::string>("", "key", "the key (key.pem)", "");

class HelloHandler : public mimosa::http::Handler
{
  virtual bool handle(mimosa::http::RequestReader &  /*request*/,
                      mimosa::http::ResponseWriter & response) const
  {
    std::ostringstream os;
    os <<
      "<title>Hello World!</title>"
      "Hello World!
"
      "
"
      "
browse " << PATH << "
"
      "
test query string
"
      "
test post data
"
      "
"
      "";

    std::string data(os.str());
    response.status_ = mimosa::http::kStatusOk;
    response.content_type_ = "text/html";
    response.write(data.data(), data.size());
    return true;
  }
};

class QueryEchoHandler : public mimosa::http::Handler
{
  virtual bool handle(mimosa::http::RequestReader &  request,
                      mimosa::http::ResponseWriter & response) const
  {
    std::ostringstream os;
    os <<
      "<title>Query Echo!</title>"
      "Query Echo!
"
      "
";
    for (auto it = request.query().cbegin(); it != request.query().cend(); ++it)
      os << "
" << it->first << " = " << it->second << "
";
    os <<
      "
"
      "";

    std::string data(os.str());
    response.status_ = mimosa::http::kStatusOk;
    response.content_type_ = "text/html";
    response.write(data.data(), data.size());
    return true;
  }
};

class PostEchoHandler : public mimosa::http::Handler
{
  virtual bool handle(mimosa::http::RequestReader &  request,
                      mimosa::http::ResponseWriter & response) const
  {
    std::ostringstream os;
    os <<
      "<title>Post Echo!</title>"
      "Post Echo!
"
      "Method: " << methodString(request.method()) << "
"
      "Content-Type: " << request.contentType() << "
"
      "
";
    kvs form = request.form();
    for (auto it = form.cbegin(); it != form.cend(); ++it)
      os << "
" << it->first << " = " << it->second << "
";
    os <<
      "
"
      "
"
      "<form method='post' enctype='application/x-www-form-urlencoded' name='test-form'>"
      "firstname <input type='text' name='fname'/>
"
      "lastname <input type='text' name='lname'/>
"
      "<input type='submit' value='submit'/>"
      "</form>"
      "";

    std::string data(os.str());
    response.status_ = mimosa::http::kStatusOk;
    response.content_type_ = "text/html";
    response.write(data.data(), data.size());
    return true;
  }
};

int main(int argc, char ** argv)
{
  mimosa::init(argc, argv);

  {
    auto dispatch(new http::DispatchHandler);
    dispatch->registerHandler("/", new HelloHandler);
    dispatch->registerHandler("/query-echo", new QueryEchoHandler);
    dispatch->registerHandler("/post-echo", new PostEchoHandler);
    dispatch->registerHandler("/data/*", new http::FsHandler(PATH, 1, true));

    http::Server::Ptr server(new http::Server);
    server->setHandler(dispatch);

    if (!CERT.empty() && !KEY.empty())
      server->setSecure(CERT, KEY);

    auto ret = server->listenInet4(PORT);
    if (!ret)
    {
      puts("failed to listen");
      return 1;
    }
    printf("listen on %d succeed\n", PORT);

    cpuForeach([server] {
        while (true)
          server->serveOne();
      });
  }

  mimosa::deinit();
  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/utils/SkRandom.h"
#include "src/core/SkGeometry.h"
#include "src/gpu/GrVx.h"
#include "tests/Test.h"
#include <limits>

using namespace grvx;
using skvx::bit_pun;

DEF_TEST(grvx_cross_dot, r) {
    REPORTER_ASSERT(r, grvx::cross({0,1}, {0,1}) == 0);
    REPORTER_ASSERT(r, grvx::cross({1,0}, {1,0}) == 0);
    REPORTER_ASSERT(r, grvx::cross({1,1}, {1,1}) == 0);
    REPORTER_ASSERT(r, grvx::cross({1,1}, {1,-1}) == -2);
    REPORTER_ASSERT(r, grvx::cross({1,1}, {-1,1}) == 2);

    REPORTER_ASSERT(r, grvx::dot({0,1}, {1,0}) == 0);
    REPORTER_ASSERT(r, grvx::dot({1,0}, {0,1}) == 0);
    REPORTER_ASSERT(r, grvx::dot({1,1}, {1,-1}) == 0);
    REPORTER_ASSERT(r, grvx::dot({1,1}, {1,1}) == 2);
    REPORTER_ASSERT(r, grvx::dot({1,1}, {-1,-1}) == -2);

    SkRandom rand;
    for (int i = 0; i < 100; ++i) {
        float a=rand.nextRangeF(-1,1), b=rand.nextRangeF(-1,1), c=rand.nextRangeF(-1,1),
              d=rand.nextRangeF(-1,1);
        constexpr static float kTolerance = 1.f / (1 << 20);
        REPORTER_ASSERT(r, SkScalarNearlyEqual(
                grvx::cross({a,b}, {c,d}), SkPoint::CrossProduct({a,b}, {c,d}), kTolerance));
        REPORTER_ASSERT(r, SkScalarNearlyEqual(
                grvx::dot({a,b}, {c,d}), SkPoint::DotProduct({a,b}, {c,d}), kTolerance));
    }
}

static bool check_approx_acos(skiatest::Reporter* r, float x, float approx_acos_x) {
    float acosf_x = acosf(x);
    float error = acosf_x - approx_acos_x;
    if (!(fabsf(error) <= GRVX_FAST_ACOS_MAX_ERROR)) {
        ERRORF(r, "Larger-than-expected error from grvx::approx_acos\n"
                  "  x=              %f\n"
                  "  approx_acos_x=  %f  (%f degrees\n"
                  "  acosf_x=        %f  (%f degrees\n"
                  "  error=          %f  (%f degrees)\n"
                  "  tolerance=      %f  (%f degrees)\n\n",
                  x, approx_acos_x, SkRadiansToDegrees(approx_acos_x), acosf_x,
                  SkRadiansToDegrees(acosf_x), error, SkRadiansToDegrees(error),
                  GRVX_FAST_ACOS_MAX_ERROR, SkRadiansToDegrees(GRVX_FAST_ACOS_MAX_ERROR));
        return false;
    }
    return true;
}

DEF_TEST(grvx_approx_acos, r) {
    float4 boundaries = approx_acos(float4{-1, 0, 1, 0});
    check_approx_acos(r, -1, boundaries[0]);
    check_approx_acos(r, 0, boundaries[1]);
    check_approx_acos(r, +1, boundaries[2]);

    // Select a distribution of starting points around which to begin testing approx_acos. These
    // fall roughly around the known minimum and maximum errors. No need to include -1, 0, or 1
    // since those were just tested above. (Those are tricky because 0 is an inflection and the
    // derivative is infinite at 1 and -1.)
    constexpr static int N = 8;
    vec<8> x = {-.99f, -.8f, -.4f, -.2f, .2f, .4f, .8f, .99f};

    // Converge at the various local minima and maxima of "approx_acos(x) - cosf(x)" and verify that
    // approx_acos is always within "kTolerance" degrees of the expected answer.
    vec<N> err_;
    for (int iter = 0; iter < 10; ++iter) {
        // Run our approximate inverse cosine approximation.
        vec<N> approx_acos_x = approx_acos(x);

        // Find d/dx(error)
        //    = d/dx(approx_acos(x) - acos(x))
        //    = (f'g - fg')/gg + 1/sqrt(1 - x^2), [where f = bx^3 + ax, g = dx^4 + cx^2 + 1]
        vec<N> xx = x*x;
        vec<N> a = -0.939115566365855f;
        vec<N> b =  0.9217841528914573f;
        vec<N> c = -1.2845906244690837f;
        vec<N> d =  0.295624144969963174f;
        vec<N> f = (b*xx + a)*x;
        vec<N> f_ = 3*b*xx + a;
        vec<N> g = (d*xx + c)*xx + 1;
        vec<N> g_ = (4*d*xx + 2*c)*x;
        vec<N> gg = g*g;
        vec<N> q = skvx::sqrt(1 - xx);
        err_ = (f_*g - f*g_)/gg + 1/q;

        // Find d^2/dx^2(error)
        //    = ((f''g - fg'')g^2 - (f'g - fg')2gg') / g^4 + x(1 - x^2)^(-3/2)
        //    = ((f''g - fg'')g - (f'g - fg')2g') / g^3 + x(1 - x^2)^(-3/2)
        vec<N> f__ = 6*b*x;
        vec<N> g__ = 12*d*xx + 2*c;
        vec<N> err__ = ((f__*g - f*g__)*g - (f_*g - f*g_)*2*g_) / (gg*g) + x/((1 - xx)*q);

#if 0
        SkDebugf("\n\niter %i\n", iter);
#endif
        // Ensure each lane's approximation is within maximum error.
        for (int j = 0; j < N; ++j) {
#if 0
            SkDebugf("x=%f  err=%f  err'=%f  err''=%f\n",
                     x[j], SkRadiansToDegrees(approx_acos_x[j] - acosf(x[j])),
                     SkRadiansToDegrees(err_[j]), SkRadiansToDegrees(err__[j]));
#endif
            if (!check_approx_acos(r, x[j], approx_acos_x[j])) {
                return;
            }
        }

        // Use Newton's method to update the x values to locations closer to their local minimum or
        // maximum. (This is where d/dx(error) == 0.)
        x -= err_/err__;
        x = skvx::pin(x, vec<N>(-.99f), vec<N>(.99f));
    }

    // Ensure each lane converged to a local minimum or maximum.
    for (int j = 0; j < N; ++j) {
        REPORTER_ASSERT(r, SkScalarNearlyZero(err_[j]));
    }

    // Make sure we found all the actual known locations of local min/max error.
    for (float knownRoot : {-0.983536f, -0.867381f, -0.410923f, 0.410923f, 0.867381f, 0.983536f}) {
        REPORTER_ASSERT(r, skvx::any(skvx::abs(x - knownRoot) < SK_ScalarNearlyZero));
    }
}

static bool check_approx_angle_between_vectors(skiatest::Reporter* r, SkVector a, SkVector b,
                                               float approxTheta) {
    float expectedTheta = SkMeasureAngleBetweenVectors(a, b);
    float error = expectedTheta - approxTheta;
    if (!(fabsf(error) <= GRVX_FAST_ACOS_MAX_ERROR + SK_ScalarNearlyZero)) {
        ERRORF(r, "Larger-than-expected error from grvx::approx_angle_between_vectors\n"
                  "  a=                {%f, %f}\n"
                  "  b=                {%f, %f}\n"
                  "  approxTheta=      %f  (%f degrees\n"
                  "  expectedTheta=     %f  (%f degrees)\n"
                  "  error=             %f  (%f degrees)\n"
                  "  tolerance=         %f  (%f degrees)\n\n",
                  a.fX, a.fY, b.fX, b.fY, approxTheta, SkRadiansToDegrees(approxTheta),
                  expectedTheta, SkRadiansToDegrees(expectedTheta), error,
                  SkRadiansToDegrees(error), GRVX_FAST_ACOS_MAX_ERROR,
                  SkRadiansToDegrees(GRVX_FAST_ACOS_MAX_ERROR));
        return false;
    }
    return true;
}

static bool check_approx_angle_between_vectors(skiatest::Reporter* r, SkVector a, SkVector b) {
    float approxTheta = grvx::approx_angle_between_vectors<1>(a.fX, a.fY, b.fX, b.fY).val;
    return check_approx_angle_between_vectors(r, a, b, approxTheta);
}

DEF_TEST(grvx_approx_angle_between_vectors, r) {
    // Test when a and/or b are zero.
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(0,0,0,0).val));
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(1,1,0,0).val));
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(0,0,1,1).val));
    check_approx_angle_between_vectors(r, {0,0}, {0,0});
    check_approx_angle_between_vectors(r, {1,1}, {0,0});
    check_approx_angle_between_vectors(r, {0,0}, {1,1});

    // Test infinities.
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(
            std::numeric_limits<float>::infinity(),1,2,3).val));
    check_approx_angle_between_vectors(r, {std::numeric_limits<float>::infinity(),1}, {2,3});
    check_approx_angle_between_vectors(r, {0,-std::numeric_limits<float>::infinity()}, {2,3});
    check_approx_angle_between_vectors(r, {0,1}, {std::numeric_limits<float>::infinity(),3});
    check_approx_angle_between_vectors(r, {0,1}, {2,-std::numeric_limits<float>::infinity()});

    // Test NaNs.
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(
            std::numeric_limits<float>::quiet_NaN(),1,2,3).val));
    check_approx_angle_between_vectors(r, {std::numeric_limits<float>::quiet_NaN(),1}, {2,3});
    check_approx_angle_between_vectors(r, {0,std::numeric_limits<float>::quiet_NaN()}, {2,3});
    check_approx_angle_between_vectors(r, {0,1}, {std::numeric_limits<float>::quiet_NaN(),3});
    check_approx_angle_between_vectors(r, {0,1}, {2,std::numeric_limits<float>::quiet_NaN()});

    // Test demorms.
    // NOTE: there isn't a floating point value large enough to multiply a denormalized value to 1,
    // but these should behave the same as SkMeasureAngleBetweenVectors.
    float epsilon = std::numeric_limits<float>::denorm_min();
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(
            epsilon, epsilon, epsilon, epsilon).val));
    check_approx_angle_between_vectors(r, {epsilon, epsilon}, {epsilon, epsilon});
    check_approx_angle_between_vectors(r, {epsilon, epsilon}, {-epsilon, -epsilon});
    check_approx_angle_between_vectors(r, {epsilon, -epsilon*2}, {-epsilon*3, epsilon*4});

    // Test random floats of all types.
    int4 mantissas = {0,0,0,0};
    int4 exp = int4{126, 127, 128, 129};
    for (int i = 0; i < (1 << 12); ++i) {
        int a=exp[0], b=exp[1], c=exp[2], d=exp[3];
        // Run two tests where both components of both vectors have the same exponent, one where
        // both components of a given vector have the same exponent, and one where all components of
        // all vectors have different exponents.
        int4 x0exp = int4{a,b,a,a} << 23;
        int4 y0exp = int4{a,b,a,b} << 23;
        int4 x1exp = int4{a,b,b,c} << 23;
        int4 y1exp = int4{a,b,b,d} << 23;
        int4 signs = int4{i<<31, i<<30, i<<29, i<<28} & (1<<31);
        float4 x0 = bit_pun<float4>(signs | x0exp | mantissas[0]);
        float4 y0 = bit_pun<float4>(signs | y0exp | mantissas[1]);
        float4 x1 = bit_pun<float4>(signs | x1exp | mantissas[2]);
        float4 y1 = bit_pun<float4>(signs | y1exp | mantissas[3]);
        float4 rads = approx_angle_between_vectors(x0, y0, x1, y1);
        for (int j = 0; j < 4; ++j) {
            if (!check_approx_angle_between_vectors(r, {x0[j], y0[j]}, {x1[j], y1[j]}, rads[j])) {
                return;
            }
        }
        // Adding primes makes sure we test every value before we repeat.
        mantissas = (mantissas + int4{123456791, 201345691, 198765433, 156789029}) & ((1<<23) - 1);
        exp = (exp + int4{79, 83, 199, 7}) & 0xff;
    }
}
<commit_msg>Use uint4 instead if int4 in grvx test<commit_after>/*
 * Copyright 2020 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "include/utils/SkRandom.h"
#include "src/core/SkGeometry.h"
#include "src/gpu/GrVx.h"
#include "tests/Test.h"
#include <limits>

using namespace grvx;
using skvx::bit_pun;

DEF_TEST(grvx_cross_dot, r) {
    REPORTER_ASSERT(r, grvx::cross({0,1}, {0,1}) == 0);
    REPORTER_ASSERT(r, grvx::cross({1,0}, {1,0}) == 0);
    REPORTER_ASSERT(r, grvx::cross({1,1}, {1,1}) == 0);
    REPORTER_ASSERT(r, grvx::cross({1,1}, {1,-1}) == -2);
    REPORTER_ASSERT(r, grvx::cross({1,1}, {-1,1}) == 2);

    REPORTER_ASSERT(r, grvx::dot({0,1}, {1,0}) == 0);
    REPORTER_ASSERT(r, grvx::dot({1,0}, {0,1}) == 0);
    REPORTER_ASSERT(r, grvx::dot({1,1}, {1,-1}) == 0);
    REPORTER_ASSERT(r, grvx::dot({1,1}, {1,1}) == 2);
    REPORTER_ASSERT(r, grvx::dot({1,1}, {-1,-1}) == -2);

    SkRandom rand;
    for (int i = 0; i < 100; ++i) {
        float a=rand.nextRangeF(-1,1), b=rand.nextRangeF(-1,1), c=rand.nextRangeF(-1,1),
              d=rand.nextRangeF(-1,1);
        constexpr static float kTolerance = 1.f / (1 << 20);
        REPORTER_ASSERT(r, SkScalarNearlyEqual(
                grvx::cross({a,b}, {c,d}), SkPoint::CrossProduct({a,b}, {c,d}), kTolerance));
        REPORTER_ASSERT(r, SkScalarNearlyEqual(
                grvx::dot({a,b}, {c,d}), SkPoint::DotProduct({a,b}, {c,d}), kTolerance));
    }
}

static bool check_approx_acos(skiatest::Reporter* r, float x, float approx_acos_x) {
    float acosf_x = acosf(x);
    float error = acosf_x - approx_acos_x;
    if (!(fabsf(error) <= GRVX_FAST_ACOS_MAX_ERROR)) {
        ERRORF(r, "Larger-than-expected error from grvx::approx_acos\n"
                  "  x=              %f\n"
                  "  approx_acos_x=  %f  (%f degrees\n"
                  "  acosf_x=        %f  (%f degrees\n"
                  "  error=          %f  (%f degrees)\n"
                  "  tolerance=      %f  (%f degrees)\n\n",
                  x, approx_acos_x, SkRadiansToDegrees(approx_acos_x), acosf_x,
                  SkRadiansToDegrees(acosf_x), error, SkRadiansToDegrees(error),
                  GRVX_FAST_ACOS_MAX_ERROR, SkRadiansToDegrees(GRVX_FAST_ACOS_MAX_ERROR));
        return false;
    }
    return true;
}

DEF_TEST(grvx_approx_acos, r) {
    float4 boundaries = approx_acos(float4{-1, 0, 1, 0});
    check_approx_acos(r, -1, boundaries[0]);
    check_approx_acos(r, 0, boundaries[1]);
    check_approx_acos(r, +1, boundaries[2]);

    // Select a distribution of starting points around which to begin testing approx_acos. These
    // fall roughly around the known minimum and maximum errors. No need to include -1, 0, or 1
    // since those were just tested above. (Those are tricky because 0 is an inflection and the
    // derivative is infinite at 1 and -1.)
    constexpr static int N = 8;
    vec<8> x = {-.99f, -.8f, -.4f, -.2f, .2f, .4f, .8f, .99f};

    // Converge at the various local minima and maxima of "approx_acos(x) - cosf(x)" and verify that
    // approx_acos is always within "kTolerance" degrees of the expected answer.
    vec<N> err_;
    for (int iter = 0; iter < 10; ++iter) {
        // Run our approximate inverse cosine approximation.
        vec<N> approx_acos_x = approx_acos(x);

        // Find d/dx(error)
        //    = d/dx(approx_acos(x) - acos(x))
        //    = (f'g - fg')/gg + 1/sqrt(1 - x^2), [where f = bx^3 + ax, g = dx^4 + cx^2 + 1]
        vec<N> xx = x*x;
        vec<N> a = -0.939115566365855f;
        vec<N> b =  0.9217841528914573f;
        vec<N> c = -1.2845906244690837f;
        vec<N> d =  0.295624144969963174f;
        vec<N> f = (b*xx + a)*x;
        vec<N> f_ = 3*b*xx + a;
        vec<N> g = (d*xx + c)*xx + 1;
        vec<N> g_ = (4*d*xx + 2*c)*x;
        vec<N> gg = g*g;
        vec<N> q = skvx::sqrt(1 - xx);
        err_ = (f_*g - f*g_)/gg + 1/q;

        // Find d^2/dx^2(error)
        //    = ((f''g - fg'')g^2 - (f'g - fg')2gg') / g^4 + x(1 - x^2)^(-3/2)
        //    = ((f''g - fg'')g - (f'g - fg')2g') / g^3 + x(1 - x^2)^(-3/2)
        vec<N> f__ = 6*b*x;
        vec<N> g__ = 12*d*xx + 2*c;
        vec<N> err__ = ((f__*g - f*g__)*g - (f_*g - f*g_)*2*g_) / (gg*g) + x/((1 - xx)*q);

#if 0
        SkDebugf("\n\niter %i\n", iter);
#endif
        // Ensure each lane's approximation is within maximum error.
        for (int j = 0; j < N; ++j) {
#if 0
            SkDebugf("x=%f  err=%f  err'=%f  err''=%f\n",
                     x[j], SkRadiansToDegrees(approx_acos_x[j] - acosf(x[j])),
                     SkRadiansToDegrees(err_[j]), SkRadiansToDegrees(err__[j]));
#endif
            if (!check_approx_acos(r, x[j], approx_acos_x[j])) {
                return;
            }
        }

        // Use Newton's method to update the x values to locations closer to their local minimum or
        // maximum. (This is where d/dx(error) == 0.)
        x -= err_/err__;
        x = skvx::pin(x, vec<N>(-.99f), vec<N>(.99f));
    }

    // Ensure each lane converged to a local minimum or maximum.
    for (int j = 0; j < N; ++j) {
        REPORTER_ASSERT(r, SkScalarNearlyZero(err_[j]));
    }

    // Make sure we found all the actual known locations of local min/max error.
    for (float knownRoot : {-0.983536f, -0.867381f, -0.410923f, 0.410923f, 0.867381f, 0.983536f}) {
        REPORTER_ASSERT(r, skvx::any(skvx::abs(x - knownRoot) < SK_ScalarNearlyZero));
    }
}

static bool check_approx_angle_between_vectors(skiatest::Reporter* r, SkVector a, SkVector b,
                                               float approxTheta) {
    float expectedTheta = SkMeasureAngleBetweenVectors(a, b);
    float error = expectedTheta - approxTheta;
    if (!(fabsf(error) <= GRVX_FAST_ACOS_MAX_ERROR + SK_ScalarNearlyZero)) {
        ERRORF(r, "Larger-than-expected error from grvx::approx_angle_between_vectors\n"
                  "  a=                {%f, %f}\n"
                  "  b=                {%f, %f}\n"
                  "  approxTheta=      %f  (%f degrees\n"
                  "  expectedTheta=     %f  (%f degrees)\n"
                  "  error=             %f  (%f degrees)\n"
                  "  tolerance=         %f  (%f degrees)\n\n",
                  a.fX, a.fY, b.fX, b.fY, approxTheta, SkRadiansToDegrees(approxTheta),
                  expectedTheta, SkRadiansToDegrees(expectedTheta), error,
                  SkRadiansToDegrees(error), GRVX_FAST_ACOS_MAX_ERROR,
                  SkRadiansToDegrees(GRVX_FAST_ACOS_MAX_ERROR));
        return false;
    }
    return true;
}

static bool check_approx_angle_between_vectors(skiatest::Reporter* r, SkVector a, SkVector b) {
    float approxTheta = grvx::approx_angle_between_vectors<1>(a.fX, a.fY, b.fX, b.fY).val;
    return check_approx_angle_between_vectors(r, a, b, approxTheta);
}

DEF_TEST(grvx_approx_angle_between_vectors, r) {
    // Test when a and/or b are zero.
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(0,0,0,0).val));
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(1,1,0,0).val));
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(0,0,1,1).val));
    check_approx_angle_between_vectors(r, {0,0}, {0,0});
    check_approx_angle_between_vectors(r, {1,1}, {0,0});
    check_approx_angle_between_vectors(r, {0,0}, {1,1});

    // Test infinities.
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(
            std::numeric_limits<float>::infinity(),1,2,3).val));
    check_approx_angle_between_vectors(r, {std::numeric_limits<float>::infinity(),1}, {2,3});
    check_approx_angle_between_vectors(r, {0,-std::numeric_limits<float>::infinity()}, {2,3});
    check_approx_angle_between_vectors(r, {0,1}, {std::numeric_limits<float>::infinity(),3});
    check_approx_angle_between_vectors(r, {0,1}, {2,-std::numeric_limits<float>::infinity()});

    // Test NaNs.
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(
            std::numeric_limits<float>::quiet_NaN(),1,2,3).val));
    check_approx_angle_between_vectors(r, {std::numeric_limits<float>::quiet_NaN(),1}, {2,3});
    check_approx_angle_between_vectors(r, {0,std::numeric_limits<float>::quiet_NaN()}, {2,3});
    check_approx_angle_between_vectors(r, {0,1}, {std::numeric_limits<float>::quiet_NaN(),3});
    check_approx_angle_between_vectors(r, {0,1}, {2,std::numeric_limits<float>::quiet_NaN()});

    // Test demorms.
    // NOTE: there isn't a floating point value large enough to multiply a denormalized value to 1,
    // but these should behave the same as SkMeasureAngleBetweenVectors.
    float epsilon = std::numeric_limits<float>::denorm_min();
    REPORTER_ASSERT(r, SkScalarNearlyZero(grvx::approx_angle_between_vectors<1>(
            epsilon, epsilon, epsilon, epsilon).val));
    check_approx_angle_between_vectors(r, {epsilon, epsilon}, {epsilon, epsilon});
    check_approx_angle_between_vectors(r, {epsilon, epsilon}, {-epsilon, -epsilon});
    check_approx_angle_between_vectors(r, {epsilon, -epsilon*2}, {-epsilon*3, epsilon*4});

    // Test random floats of all types.
    uint4 mantissas = {0,0,0,0};
    uint4 exp = uint4{126, 127, 128, 129};
    for (uint32_t i = 0; i < (1 << 12); ++i) {
        uint32_t a=exp[0], b=exp[1], c=exp[2], d=exp[3];
        // Run two tests where both components of both vectors have the same exponent, one where
        // both components of a given vector have the same exponent, and one where all components of
        // all vectors have different exponents.
        uint4 x0exp = uint4{a,b,a,a} << 23;
        uint4 y0exp = uint4{a,b,a,b} << 23;
        uint4 x1exp = uint4{a,b,b,c} << 23;
        uint4 y1exp = uint4{a,b,b,d} << 23;
        uint4 signs = uint4{i<<31, i<<30, i<<29, i<<28} & (1u<<31);
        float4 x0 = bit_pun<float4>(signs | x0exp | mantissas[0]);
        float4 y0 = bit_pun<float4>(signs | y0exp | mantissas[1]);
        float4 x1 = bit_pun<float4>(signs | x1exp | mantissas[2]);
        float4 y1 = bit_pun<float4>(signs | y1exp | mantissas[3]);
        float4 rads = approx_angle_between_vectors(x0, y0, x1, y1);
        for (int j = 0; j < 4; ++j) {
            if (!check_approx_angle_between_vectors(r, {x0[j], y0[j]}, {x1[j], y1[j]}, rads[j])) {
                return;
            }
        }
        // Adding primes makes sure we test every value before we repeat.
        mantissas = (mantissas + uint4{123456791, 201345691, 198765433, 156789029}) & ((1<<23) - 1);
        exp = (exp + uint4{79, 83, 199, 7}) & 0xff;
    }
}
<|endoftext|>