<commit_before>/*
Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
All Rights Reserved.

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

//
// Build a ICC profile for doing soft proofing
//
// N-component LUT-based display profile required tags
// ------------------------------------------------------------------------------
// Tag Name                 General Description
// ------------------------------------------------------------------------------
// profileDescriptionTag    Structure containing invariant and localizable
//                          versions of the profile name for display
// AToB0Tag                 Device to PCS: 8-bit or 16-bit data: intent of 0
// BToA0Tag                 PCS to Device space: 8-bit or 16-bit data: intent of 0
// mediaWhitePointTag       Media XYZ white point
// copyrightTag             Profile copyright information
// chromaticAdaptationTag   Converts XYZ colour from the actual illumination
//                          source to PCS illuminant. Required only if the actual
//                          illumination source is not D50.

#include <cmath>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <vector>

#include "lcms2.h"
#include "lcms2_plugin.h"

#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE;

#include "argparse.h"

void ErrorHandler(cmsContext /*ContextID*/, cmsUInt32Number /*ErrorCode*/, const char *Text)
{
    std::cerr << "OCIO Error: " << Text << "\n";
    return;
}

typedef struct
{
    cmsHTRANSFORM to_PCS16;
    cmsHTRANSFORM from_PCS16;
    //OCIO::ConstProcessorRcPtr shaper_processor;
    OCIO::ConstProcessorRcPtr processor;
} SamplerData;

static void Add3GammaCurves(cmsPipeline* lut, cmsFloat64Number Curve)
{
    cmsToneCurve* id = cmsBuildGamma(NULL, Curve);
    cmsToneCurve* id3[3];
    id3[0] = id;
    id3[1] = id;
    id3[2] = id;
    cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(NULL, 3, id3));
    cmsFreeToneCurve(id);
}

static void AddIdentityMatrix(cmsPipeline* lut)
{
    const cmsFloat64Number Identity[] = {
        1, 0, 0,
        0, 1, 0,
        0, 0, 1,
        0, 0, 0 };
    cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocMatrix(NULL, 3, 3, Identity, NULL));
}

static cmsInt32Number Display2PCS_Sampler16(const cmsUInt16Number in[], cmsUInt16Number out[], void* userdata)
{
    //std::cout << "r" << in[0] << " g" << in[1] << " b" << in[2] << "\n";
    SamplerData* data = (SamplerData*) userdata;
    cmsFloat32Number pix[3] = { static_cast<float>(in[0])/65535.f,
                                static_cast<float>(in[1])/65535.f,
                                static_cast<float>(in[2])/65535.f};
    data->processor->applyRGB(pix);
    out[0] = (cmsUInt16Number)std::max(std::min(pix[0] * 65535.f, 65535.f), 0.f);
    out[1] = (cmsUInt16Number)std::max(std::min(pix[1] * 65535.f, 65535.f), 0.f);
    out[2] = (cmsUInt16Number)std::max(std::min(pix[2] * 65535.f, 65535.f), 0.f);
    cmsDoTransform(data->to_PCS16, out, out, 1);
    return 1;
}

static cmsInt32Number PCS2Display_Sampler16(const cmsUInt16Number in[], cmsUInt16Number out[], void* userdata)
{
    //std::cout << "r" << in[0] << " g" << in[1] << " b" << in[2] << "\n";
    SamplerData* data = (SamplerData*) userdata;
    cmsDoTransform(data->from_PCS16, in, out, 1);
    // we don't have a reverse Lab -> Display transform
    return 1;
}

static std::string outputfile;

static int
parse_end_args(int argc, const char *argv[])
{
    for (int i = 0;  i < argc;  i++)
    {
        outputfile = argv[i];
    }

    return 0;
}

int main (int argc, const char* argv[])
{
    bool help = false;
    std::string inputconfig;
    int cubesize = 32;
    int whitepointtemp = 6505;
    std::string displayicc;
    std::string description;
    std::string copyright = "OpenColorIO, Sony Imageworks";
    std::string inputspace;
    std::string outputspace;

    ArgParse ap;
    ap.options("ocio2icc -- generate an icc profile from an OpenColorIO config\n\n"
               "usage:  ocio2icc [options] output.icc\n\n"
               "example:  ocio2icc --inputspace lg10 --outputspace srgb8 ~/Library/ColorSync/Profiles/test.icc\n\n",
               "%*", parse_end_args, "",
               "--help", &help, "Print help message",
               "--inputspace %s", &inputspace , "the OCIO ColorSpace or Role, for the input (required)",
               "--outputspace %s", &outputspace , "the OCIO ColorSpace or Role, for the output (required)",
               "--cubesize %d", &cubesize, "size of the icc CLUT cube (default: 32)",
               "--whitepoint %d", &whitepointtemp, "whitepoint for the profile (default: 6505)",
               "--displayicc %s", &displayicc , "an icc profile which matches the OCIO profiles target display",
               "--description %s", &description , "a meaningful description, this will show up in UI like photoshop",
               "--copyright %s", &copyright , "a copyright field (default: OpenColorIO, Sony Imageworks)",
               "--iconfig %s", &inputconfig, "Input .ocio configuration file (default: $OCIO)",
               NULL);

    if (ap.parse(argc, argv) < 0)
    {
        std::cout << ap.geterror() << std::endl;
        ap.usage();
        return 1;
    }

    if (help)
    {
        ap.usage();
        return 1;
    }

    if(inputspace.empty())
    {
        std::cout << "need to specify a --inputspace of the source that the icc profile will be applied\n";
        ap.usage();
        return 1;
    }

    if(outputspace.empty())
    {
        std::cout << "need to specify a --outputspace of the display for the icc profile\n";
        ap.usage();
        return 1;
    }

    if(outputfile.empty())
    {
        std::cout << "you need to specify a output icc path\n";
        ap.usage();
        return 1;
    }

    if(description.empty())
    {
        std::ostringstream os;
        os << inputspace << " to " << outputspace;
        description = os.str();
    }

    if(copyright.empty())
    {
        std::cout << "need to specify a --copyright to embed in the icc profile\n";
        ap.usage();
        return 1;
    }

    try
    {
        // Create the OCIO processor for the specified transform.
        OCIO::ConstConfigRcPtr config;

        if(!inputconfig.empty())
        {
            std::cout << "[OpenColorIO INFO]: Loading " << inputconfig << std::endl;
            config = OCIO::Config::CreateFromFile(inputconfig.c_str());
        }
        else if(getenv("OCIO"))
        {
            std::cout << "[OpenColorIO INFO]: Loading $OCIO " << getenv("OCIO") << std::endl;
            config = OCIO::Config::CreateFromEnv();
        }
        else
        {
            std::cout << "ERROR: You must specify an input ocio configuration ";
            std::cout << "(either with --iconfig or $OCIO).\n";
            ap.usage ();
            return 1;
        }

        OCIO::ConstProcessorRcPtr processor =
            config->getProcessor(inputspace.c_str(), outputspace.c_str());

        // Create the ICC Profile

        // Setup the Error Handler
        cmsSetLogErrorHandler(ErrorHandler);

        // D65 white point
        cmsCIExyY whitePoint;
        cmsWhitePointFromTemp(&whitePoint, whitepointtemp);

        // LAB PCS
        cmsHPROFILE labProfile = cmsCreateLab4ProfileTHR(NULL, &whitePoint);

        // Display (OCIO sRGB cube -> LAB)
        cmsHPROFILE DisplayProfile;
        if(displayicc != "") DisplayProfile = cmsOpenProfileFromFile(displayicc.c_str(), "r");
        else DisplayProfile = cmsCreate_sRGBProfileTHR(NULL);

        // Create an empty RGB Profile
        cmsHPROFILE hProfile = cmsCreateRGBProfileTHR(NULL, &whitePoint, NULL, NULL);

        std::cout << "[OpenColorIO INFO]: Setting up Profile: " << outputfile << "\n";

        // Added Header fields
        cmsSetProfileVersion(hProfile, 4.2);
        cmsSetDeviceClass(hProfile, cmsSigDisplayClass);
        cmsSetColorSpace(hProfile, cmsSigRgbData);
        cmsSetPCS(hProfile, cmsSigLabData);
        cmsSetHeaderRenderingIntent(hProfile, INTENT_PERCEPTUAL);

        //
        cmsMLU* DescriptionMLU = cmsMLUalloc(NULL, 1);
        cmsMLU* CopyrightMLU = cmsMLUalloc(NULL, 1);
        cmsMLUsetASCII(DescriptionMLU, "en", "US", description.c_str());
        cmsMLUsetASCII(CopyrightMLU, "en", "US", copyright.c_str());
        cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU);
        cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU);

        //
        SamplerData data;
        data.processor = processor;

        // 16Bit
        data.to_PCS16 = cmsCreateTransform(DisplayProfile, TYPE_RGB_16, labProfile, TYPE_LabV2_16,
                                           INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
        data.from_PCS16 = cmsCreateTransform(labProfile, TYPE_LabV2_16, DisplayProfile, TYPE_RGB_16,
                                             INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);

        //
        // AToB0Tag - Device to PCS (16-bit) intent of 0 (perceptual)
        //
        // cmsSigCurveSetElemType
        // `- cmsSigCLutElemType
        //  `- cmsSigCurveSetElemType
        //   `- cmsSigMatrixElemType
        //    `- cmsSigCurveSetElemType
        //
        std::cout << "[OpenColorIO INFO]: Adding AToB0Tag\n";
        cmsPipeline* AToB0Tag = cmsPipelineAlloc(NULL, 3, 3);

        Add3GammaCurves(AToB0Tag, 1.f); // cmsSigCurveSetElemType

        // cmsSigCLutElemType
        cmsStage* AToB0Clut = cmsStageAllocCLut16bit(NULL, cubesize, 3, 3, NULL);
        std::cout << "[OpenColorIO INFO]: Sampling AToB0 CLUT from Display to Lab\n";
        cmsStageSampleCLut16bit(AToB0Clut, Display2PCS_Sampler16, &data, 0);
        cmsPipelineInsertStage(AToB0Tag, cmsAT_END, AToB0Clut);

        Add3GammaCurves(AToB0Tag, 1.f); // cmsSigCurveSetElemType
        AddIdentityMatrix(AToB0Tag);    // cmsSigMatrixElemType
        Add3GammaCurves(AToB0Tag, 1.f); // cmsSigCurveSetElemType

        // Add AToB0Tag
        cmsWriteTag(hProfile, cmsSigAToB0Tag, AToB0Tag);
        cmsPipelineFree(AToB0Tag);

        //
        // BToA0Tag - PCS to Device space (16-bit) intent of 0 (perceptual)
        //
        // cmsSigCurveSetElemType
        // `- cmsSigMatrixElemType
        //  `- cmsSigCurveSetElemType
        //   `- cmsSigCLutElemType
        //    `- cmsSigCurveSetElemType
        //
        std::cout << "[OpenColorIO INFO]: Adding BToA0Tag\n";
        cmsPipeline* BToA0Tag = cmsPipelineAlloc(NULL, 3, 3);

        Add3GammaCurves(BToA0Tag, 1.f); // cmsSigCurveSetElemType
        AddIdentityMatrix(BToA0Tag);    // cmsSigMatrixElemType
        Add3GammaCurves(BToA0Tag, 1.f); // cmsSigCurveSetElemType

        // cmsSigCLutElemType
        cmsStage* BToA0Clut = cmsStageAllocCLut16bit(NULL, cubesize, 3, 3, NULL);
        std::cout << "[OpenColorIO INFO]: Sampling BToA0 CLUT from Lab to Display\n";
        cmsStageSampleCLut16bit(BToA0Clut, PCS2Display_Sampler16, &data, 0);
        cmsPipelineInsertStage(BToA0Tag, cmsAT_END, BToA0Clut);

        Add3GammaCurves(BToA0Tag, 1.f); // cmsSigCurveSetElemType

        // Add BToA0Tag
        cmsWriteTag(hProfile, cmsSigBToA0Tag, BToA0Tag);
        cmsPipelineFree(BToA0Tag);

        //
        // D2Bx - Device to PCS (float) (Not Yet Impl)
        //

        //
        // B2Dx - PCS to Device (float) (Not Yet Impl)
        //

        //
        // Write
        //
        std::cout << "[OpenColorIO INFO]: Writing " << outputfile << std::endl;
        cmsSaveProfileToFile(hProfile, outputfile.c_str());
        cmsCloseProfile(hProfile);

        std::cout << "[OpenColorIO INFO]: Finished\n";
    }
    catch(OCIO::Exception & exception)
    {
        std::cerr << "OCIO Error: " << exception.what() << std::endl;
        return 1;
    } catch (std::exception& exception)
    {
        std::cerr << "Error: " << exception.what() << "\n";
        return 1;
    }
    catch(...)
    {
        std::cerr << "Unknown OCIO error encountered." << std::endl;
        return 1;
    }

    return 0;
}
<commit_msg>ocio2icc<commit_after>/*
Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
All Rights Reserved.

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

//
// Build a ICC profile for doing soft proofing
//
// N-component LUT-based display profile required tags
// ------------------------------------------------------------------------------
// Tag Name                 General Description
// ------------------------------------------------------------------------------
// profileDescriptionTag    Structure containing invariant and localizable
//                          versions of the profile name for display
// AToB0Tag                 Device to PCS: 8-bit or 16-bit data: intent of 0
// BToA0Tag                 PCS to Device space: 8-bit or 16-bit data: intent of 0
// mediaWhitePointTag       Media XYZ white point
// copyrightTag             Profile copyright information
// chromaticAdaptationTag   Converts XYZ colour from the actual illumination
//                          source to PCS illuminant. Required only if the actual
//                          illumination source is not D50.

#include <cmath>
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <vector>

#include "lcms2.h"
#include "lcms2_plugin.h"

#include <OpenColorIO/OpenColorIO.h>
namespace OCIO = OCIO_NAMESPACE;

#include "argparse.h"

void ErrorHandler(cmsContext /*ContextID*/, cmsUInt32Number /*ErrorCode*/, const char *Text)
{
    std::cerr << "OCIO Error: " << Text << "\n";
    return;
}

typedef struct
{
    cmsHTRANSFORM to_PCS16;
    cmsHTRANSFORM from_PCS16;
    //OCIO::ConstProcessorRcPtr shaper_processor;
    OCIO::ConstProcessorRcPtr processor;
} SamplerData;

static void Add3GammaCurves(cmsPipeline* lut, cmsFloat64Number Curve)
{
    cmsToneCurve* id = cmsBuildGamma(NULL, Curve);
    cmsToneCurve* id3[3];
    id3[0] = id;
    id3[1] = id;
    id3[2] = id;
    cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocToneCurves(NULL, 3, id3));
    cmsFreeToneCurve(id);
}

static void AddIdentityMatrix(cmsPipeline* lut)
{
    const cmsFloat64Number Identity[] = {
        1, 0, 0,
        0, 1, 0,
        0, 0, 1,
        0, 0, 0 };
    cmsPipelineInsertStage(lut, cmsAT_END, cmsStageAllocMatrix(NULL, 3, 3, Identity, NULL));
}

static cmsInt32Number Display2PCS_Sampler16(const cmsUInt16Number in[], cmsUInt16Number out[], void* userdata)
{
    //std::cout << "r" << in[0] << " g" << in[1] << " b" << in[2] << "\n";
    SamplerData* data = (SamplerData*) userdata;
    cmsFloat32Number pix[3] = { static_cast<float>(in[0])/65535.f,
                                static_cast<float>(in[1])/65535.f,
                                static_cast<float>(in[2])/65535.f};
    data->processor->applyRGB(pix);
    out[0] = (cmsUInt16Number)std::max(std::min(pix[0] * 65535.f, 65535.f), 0.f);
    out[1] = (cmsUInt16Number)std::max(std::min(pix[1] * 65535.f, 65535.f), 0.f);
    out[2] = (cmsUInt16Number)std::max(std::min(pix[2] * 65535.f, 65535.f), 0.f);
    cmsDoTransform(data->to_PCS16, out, out, 1);
    return 1;
}

static cmsInt32Number PCS2Display_Sampler16(const cmsUInt16Number in[], cmsUInt16Number out[], void* userdata)
{
    //std::cout << "r" << in[0] << " g" << in[1] << " b" << in[2] << "\n";
    SamplerData* data = (SamplerData*) userdata;
    cmsDoTransform(data->from_PCS16, in, out, 1);
    // we don't have a reverse Lab -> Display transform
    return 1;
}

static std::string outputfile;

static int
parse_end_args(int argc, const char *argv[])
{
    // The right-most end arg is the output file
    if(argc>0)
    {
        outputfile = argv[argc-1];
    }

    return 0;
}

int main (int argc, const char* argv[])
{
    bool help = false;
    std::string inputconfig;
    int cubesize = 32;
    int whitepointtemp = 6505;
    std::string displayicc;
    std::string description;
    std::string copyright = "OpenColorIO, Sony Imageworks";
    std::string inputspace;
    std::string outputspace;

    std::vector<std::string> luts;

    ArgParse ap;
    ap.options("ocio2icc -- generate an icc profile from either an OpenColorIO config, or from specific lut(s)\n\n"
               "usage:  ocio2icc [options] output.icc\n\n"
               "example:  ocio2icc --inputspace lg10 --outputspace srgb8 ~/Library/ColorSync/Profiles/test.icc\n\n"
               "example:  ocio2icc --lut filmlut.3dl --lut calibration.3dl ~/Library/ColorSync/Profiles/test.icc\n\n",
               "%*", parse_end_args, "",
               "--help", &help, "Print help message",
               "--inputspace %s", &inputspace , "the OCIO ColorSpace or Role, for the input",
               "--outputspace %s", &outputspace , "the OCIO ColorSpace or Role, for the output",
               "--lut %L", &luts, "Specify lut(s) to apply, in the forward direction.",
               "--cubesize %d", &cubesize, "size of the icc CLUT cube (default: 32)",
               "--whitepoint %d", &whitepointtemp, "whitepoint for the profile (default: 6505)",
               "--displayicc %s", &displayicc , "an icc profile which matches the OCIO profiles target display",
               "--description %s", &description , "a meaningful description, this will show up in UI like photoshop",
               "--copyright %s", &copyright , "a copyright field (default: OpenColorIO, Sony Imageworks)",
               "--iconfig %s", &inputconfig, "Input .ocio configuration file (default: $OCIO)",
               NULL);

    if (ap.parse(argc, argv) < 0)
    {
        std::cout << ap.geterror() << std::endl;
        ap.usage();
        return 1;
    }

    if (help)
    {
        ap.usage();
        return 1;
    }

    if(outputfile.empty())
    {
        std::cout << "you need to specify a output icc path\n";
        ap.usage();
        return 1;
    }

    if(copyright.empty())
    {
        std::cout << "need to specify a --copyright to embed in the icc profile\n";
        ap.usage();
        return 1;
    }

    OCIO::ConstProcessorRcPtr processor;

    try
    {
        // Config input / ouput space method
        if(!inputspace.empty() || !outputspace.empty())
        {
            // Create the OCIO processor for the specified transform.
            OCIO::ConstConfigRcPtr config;

            if(!inputconfig.empty())
            {
                std::cout << "[OpenColorIO INFO]: Loading " << inputconfig << std::endl;
                config = OCIO::Config::CreateFromFile(inputconfig.c_str());
            }
            else if(getenv("OCIO"))
            {
                std::cout << "[OpenColorIO INFO]: Loading $OCIO " << getenv("OCIO") << std::endl;
                config = OCIO::Config::CreateFromEnv();
            }
            else
            {
                std::cout << "ERROR: You must specify an input ocio configuration ";
                std::cout << "(either with --iconfig or $OCIO).\n";
                ap.usage ();
                return 1;
            }

            if(inputspace.empty())
            {
                std::cout << "need to specify a --inputspace of the source that the icc profile will be applied\n";
                ap.usage();
                return 1;
            }

            if(outputspace.empty())
            {
                std::cout << "need to specify a --outputspace of the display for the icc profile\n";
                ap.usage();
                return 1;
            }

            if(description.empty())
            {
                std::ostringstream os;
                os << inputspace << " to " << outputspace;
                description = os.str();
            }

            processor =
                config->getProcessor(inputspace.c_str(), outputspace.c_str());
        }
        else if(!luts.empty())
        {
            OCIO::GroupTransformRcPtr groupTransform = OCIO::GroupTransform::Create();

            for(unsigned int i=0; i<luts.size(); ++i)
            {
                OCIO::FileTransformRcPtr fileTransform = OCIO::FileTransform::Create();
                fileTransform->setSrc(luts[i].c_str());
                fileTransform->setInterpolation(OCIO::INTERP_LINEAR);
                groupTransform->push_back(fileTransform);
            }

            OCIO::ConstConfigRcPtr config = OCIO::Config::Create();
            processor = config->getProcessor(groupTransform);
        }
        else
        {
            std::cerr << "Unable to determine OCIO transform to apply." << std::endl;
            std::cerr << "You must either specify --inputspace and --outputspace, or --lut arguments." << std::endl;
            return 1;
        }
    }
    catch(OCIO::Exception & exception)
    {
        std::cerr << "OCIO Error: " << exception.what() << std::endl;
        return 1;
    } catch (std::exception& exception)
    {
        std::cerr << "Error: " << exception.what() << "\n";
        return 1;
    }
    catch(...)
    {
        std::cerr << "Unknown OCIO error encountered." << std::endl;
        return 1;
    }

    if(!processor)
    {
        std::cerr << "Unable to determine OCIO transform to apply." << std::endl;
        return 1;
    }

    // Create the ICC Profile

    // Setup the Error Handler
    cmsSetLogErrorHandler(ErrorHandler);

    // D65 white point
    cmsCIExyY whitePoint;
    cmsWhitePointFromTemp(&whitePoint, whitepointtemp);

    // LAB PCS
    cmsHPROFILE labProfile = cmsCreateLab4ProfileTHR(NULL, &whitePoint);

    // Display (OCIO sRGB cube -> LAB)
    cmsHPROFILE DisplayProfile;
    if(displayicc != "") DisplayProfile = cmsOpenProfileFromFile(displayicc.c_str(), "r");
    else DisplayProfile = cmsCreate_sRGBProfileTHR(NULL);

    // Create an empty RGB Profile
    cmsHPROFILE hProfile = cmsCreateRGBProfileTHR(NULL, &whitePoint, NULL, NULL);

    std::cout << "[OpenColorIO INFO]: Setting up Profile: " << outputfile << "\n";

    // Added Header fields
    cmsSetProfileVersion(hProfile, 4.2);
    cmsSetDeviceClass(hProfile, cmsSigDisplayClass);
    cmsSetColorSpace(hProfile, cmsSigRgbData);
    cmsSetPCS(hProfile, cmsSigLabData);
    cmsSetHeaderRenderingIntent(hProfile, INTENT_PERCEPTUAL);

    //
    cmsMLU* DescriptionMLU = cmsMLUalloc(NULL, 1);
    cmsMLU* CopyrightMLU = cmsMLUalloc(NULL, 1);
    cmsMLUsetASCII(DescriptionMLU, "en", "US", description.c_str());
    cmsMLUsetASCII(CopyrightMLU, "en", "US", copyright.c_str());
    cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU);
    cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU);

    //
    SamplerData data;
    data.processor = processor;

    // 16Bit
    data.to_PCS16 = cmsCreateTransform(DisplayProfile, TYPE_RGB_16, labProfile, TYPE_LabV2_16,
                                       INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);
    data.from_PCS16 = cmsCreateTransform(labProfile, TYPE_LabV2_16, DisplayProfile, TYPE_RGB_16,
                                         INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE);

    //
    // AToB0Tag - Device to PCS (16-bit) intent of 0 (perceptual)
    //
    // cmsSigCurveSetElemType
    // `- cmsSigCLutElemType
    //  `- cmsSigCurveSetElemType
    //   `- cmsSigMatrixElemType
    //    `- cmsSigCurveSetElemType
    //
    std::cout << "[OpenColorIO INFO]: Adding AToB0Tag\n";
    cmsPipeline* AToB0Tag = cmsPipelineAlloc(NULL, 3, 3);

    Add3GammaCurves(AToB0Tag, 1.f); // cmsSigCurveSetElemType

    // cmsSigCLutElemType
    cmsStage* AToB0Clut = cmsStageAllocCLut16bit(NULL, cubesize, 3, 3, NULL);
    std::cout << "[OpenColorIO INFO]: Sampling AToB0 CLUT from Display to Lab\n";
    cmsStageSampleCLut16bit(AToB0Clut, Display2PCS_Sampler16, &data, 0);
    cmsPipelineInsertStage(AToB0Tag, cmsAT_END, AToB0Clut);

    Add3GammaCurves(AToB0Tag, 1.f); // cmsSigCurveSetElemType
    AddIdentityMatrix(AToB0Tag);    // cmsSigMatrixElemType
    Add3GammaCurves(AToB0Tag, 1.f); // cmsSigCurveSetElemType

    // Add AToB0Tag
    cmsWriteTag(hProfile, cmsSigAToB0Tag, AToB0Tag);
    cmsPipelineFree(AToB0Tag);

    //
    // BToA0Tag - PCS to Device space (16-bit) intent of 0 (perceptual)
    //
    // cmsSigCurveSetElemType
    // `- cmsSigMatrixElemType
    //  `- cmsSigCurveSetElemType
    //   `- cmsSigCLutElemType
    //    `- cmsSigCurveSetElemType
    //
    std::cout << "[OpenColorIO INFO]: Adding BToA0Tag\n";
    cmsPipeline* BToA0Tag = cmsPipelineAlloc(NULL, 3, 3);

    Add3GammaCurves(BToA0Tag, 1.f); // cmsSigCurveSetElemType
    AddIdentityMatrix(BToA0Tag);    // cmsSigMatrixElemType
    Add3GammaCurves(BToA0Tag, 1.f); // cmsSigCurveSetElemType

    // cmsSigCLutElemType
    cmsStage* BToA0Clut = cmsStageAllocCLut16bit(NULL, cubesize, 3, 3, NULL);
    std::cout << "[OpenColorIO INFO]: Sampling BToA0 CLUT from Lab to Display\n";
    cmsStageSampleCLut16bit(BToA0Clut, PCS2Display_Sampler16, &data, 0);
    cmsPipelineInsertStage(BToA0Tag, cmsAT_END, BToA0Clut);

    Add3GammaCurves(BToA0Tag, 1.f); // cmsSigCurveSetElemType

    // Add BToA0Tag
    cmsWriteTag(hProfile, cmsSigBToA0Tag, BToA0Tag);
    cmsPipelineFree(BToA0Tag);

    //
    // D2Bx - Device to PCS (float) (Not Yet Impl)
    //

    //
    // B2Dx - PCS to Device (float) (Not Yet Impl)
    //

    //
    // Write
    //
    std::cout << "[OpenColorIO INFO]: Writing " << outputfile << std::endl;
    cmsSaveProfileToFile(hProfile, outputfile.c_str());
    cmsCloseProfile(hProfile);

    std::cout << "[OpenColorIO INFO]: Finished\n";

    return 0;
}
<|endoftext|>


<commit_before>#define NO_GLOBALS
#include "harlan.hpp"

#include <stdlib.h>
#include <limits.h>
#include <string>
#include <algorithm>

using namespace std;

#define ALLOC_MAGIC 0xa110ca7e

#define CHECK_MAGIC(hdr) assert((hdr)->magic == ALLOC_MAGIC)

extern cl::program g_prog;

void check_region(region *r) {
    CHECK_MAGIC(r);
    //assert(r->cl_buffer);
}

void print(bool b, std::ostream *f) {
    if(b)
        print("#t", f);
    else
        print("#f", f);
}

void harlan_error(const char *msg) {
    std::cerr << "Harlan Runtime Error: " << msg << std::endl;
    abort();
}

cl_device_type get_device_type()
{
  const char *cfg = getenv("HARLAN_DEVICE");

  if(cfg) {
    string s = cfg;
	transform(s.begin(), s.end(), s.begin(), ::tolower);
    if(s == "gpu") {
      return CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR;
    }
    else if(s == "cpu") {
      return CL_DEVICE_TYPE_CPU;
    }
	else {
		cerr << "HARLAN_DEVICE must be either `cpu` or `gpu`." << endl;
		abort();
	}
  }
  return (CL_DEVICE_TYPE_GPU |
          CL_DEVICE_TYPE_CPU |
          CL_DEVICE_TYPE_ACCELERATOR |
          0);
}

int get_default_region_size()
{
    static bool first_time = true;

    const char *cfg = getenv("HARLAN_MIN_REGION_SIZE");

    if(cfg) {
        int sz = atoi(cfg);
        if(first_time) {
            cerr << "Setting region size from HARLAN_MIN_REGION_SIZE to "
                 << sz << " bytes." << endl;
            first_time = false;
        }
        return sz;
    }
    //else return 8192;
    else return 8 << 20; // 8 megs
}

region *create_region(int size)
{
    if(size == -1) size = get_default_region_size();

    assert(size > sizeof(region));

    // void *ptr = GC_MALLOC(size);
    void *ptr = malloc(size);

    region *header = (region *)ptr;
    header->magic = ALLOC_MAGIC;
    header->size = size;
    header->alloc_ptr = sizeof(region);
    header->cl_buffer = NULL;

    check_region(header);

    // Start out with the region unmapped, to avoid needless copies.
    unmap_region(header);

    return header;
}

void free_region(region *r)
{
    //fprintf(stderr, "freeing region %p. %d bytes allocated\n",
    //        r, r->alloc_ptr);
    if(r->cl_buffer) {
        clReleaseMemObject((cl_mem)r->cl_buffer);
    }
    free(r);
}

void map_region(region *header)
{
    cl_int status = 0;

    assert(header->cl_buffer);

    cl_mem buffer = (cl_mem)header->cl_buffer;

    //printf("map_region: old alloc_ptr = %d\n", header->alloc_ptr);

    // Read just the header
    status = clEnqueueReadBuffer(g_queue,
                                 buffer,
                                 CL_TRUE,
                                 0,
                                 sizeof(region),
                                 header,
                                 0,
                                 NULL,
                                 NULL);
    CL_CHECK(status);

    //printf("map_region: new alloc_ptr = %d\n", header->alloc_ptr);

	if(header->alloc_ptr - sizeof(region) > 0) {
		printf("map_region: read %lu bytes, reading %lu more.\n",
			   sizeof(region), header->alloc_ptr - sizeof(region));

		// Now read the contents
		status = clEnqueueReadBuffer(g_queue,
									 buffer,
									 CL_TRUE,
									 sizeof(region),
									 header->alloc_ptr - sizeof(region),
									 ((char *)header) + sizeof(region),
									 0,
									 NULL,
									 NULL);
		CL_CHECK(status);
	}
	else {
		printf("map_region: no remaining bytes.\n");
	}

    CL_CHECK(clReleaseMemObject(buffer));
    assert(!header->cl_buffer);
    check_region(header);
}

void unmap_region(region *header)
{
    check_region(header);

    // Don't unmap the region twice...
    // TODO: we might want to report a warning in this case.
    if(header->cl_buffer) return;
    //assert(!header->cl_buffer);

    fprintf(stderr, "unmap_region %p, alloc_ptr = %d\n",
            header, header->alloc_ptr);

    cl_int status = 0;
    cl_mem buffer = clCreateBuffer(g_ctx,
                                   CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR,
                                   header->size,
                                   NULL,
                                   &status);
    CL_CHECK(status);

    status = clEnqueueWriteBuffer(g_queue,
                                  buffer,
                                  CL_TRUE,
                                  0,
                                  header->alloc_ptr,
                                  header,
                                  0,
                                  NULL,
                                  NULL);
    CL_CHECK(status);

    header->cl_buffer = buffer;
}

region_ptr alloc_in_region(region **r, unsigned int size)
{
    if((*r)->cl_buffer) {
        map_region(*r);
    }

    // printf("allocating %d bytes from region %p\n", size, *r);
    region_ptr p = (*r)->alloc_ptr;
    (*r)->alloc_ptr += size;

    // If this fails, we allocated too much memory and need to resize
    // the region.
    while((*r)->alloc_ptr > (*r)->size) {
        unsigned int new_size = (*r)->size * 2;
		// As long as we stick with power of two region sizes, this
		// will let us get up to 4GB regions. It's a big of a hacky
		// special case...
		if(new_size == 0) {
		  new_size = UINT_MAX;
		}
		assert(new_size > (*r)->size);
        region *old = *r;
        unsigned int old_size = (*r)->size;
		//printf("realloc(%p, %d)\n", *r, new_size);
        (*r) = (region *)realloc(*r, new_size);

		assert(*r != NULL);

        (*r)->size = new_size;
    }

    return p;
}

region_ptr alloc_vector(region **r, int item_size, int num_items)
{
    if((*r)->cl_buffer) {
        cerr << "Attempting to allocate " << 8 + item_size * num_items <<  " byte vector on GPU." << endl;
        cerr << "region size = " << (*r)->size << endl;
        // This region is on the GPU. Try to do the allocation there.
        cl::buffer<region_ptr> buf
            = g_ctx.createBuffer<region_ptr>(1, CL_MEM_READ_WRITE);

        cl::kernel k = g_prog.createKernel("harlan_rt_alloc_vector");
        k.setArg(0, (*r)->cl_buffer);
        k.setArg(1, item_size);
        k.setArg(2, num_items);
        k.setArg(3, buf);
        g_queue.execute(k, 1);

        cl::buffer_map<region_ptr> map = g_queue.mapBuffer<region_ptr>(buf);
        region_ptr p = map[0];
        if(p) return p;
    }
    cerr << "Not enough space, allocating on CPU instead." << endl;
    // Well, that failed. I guess we'll do here instead.
    region_ptr p = alloc_in_region(r, 8 + item_size * num_items);
    *(int*)get_region_ptr(*r, p) = num_items;

    return p;
}

cl_mem get_cl_buffer(region *r)
{
    assert(r->cl_buffer);
    return (cl_mem)r->cl_buffer;
}

int ARGC = 0;
char **ARGV = NULL;

extern int harlan_main();

int main(int argc, char **argv) {
	ARGC = argc;
	ARGV = argv;

	return harlan_main();
}
<commit_msg>Commenting out verbose runtime logging.<commit_after>#define NO_GLOBALS
#include "harlan.hpp"

#include <stdlib.h>
#include <limits.h>
#include <string>
#include <algorithm>

using namespace std;

#define ALLOC_MAGIC 0xa110ca7e

#define CHECK_MAGIC(hdr) assert((hdr)->magic == ALLOC_MAGIC)

extern cl::program g_prog;

void check_region(region *r) {
    CHECK_MAGIC(r);
    //assert(r->cl_buffer);
}

void print(bool b, std::ostream *f) {
    if(b)
        print("#t", f);
    else
        print("#f", f);
}

void harlan_error(const char *msg) {
    std::cerr << "Harlan Runtime Error: " << msg << std::endl;
    abort();
}

cl_device_type get_device_type()
{
  const char *cfg = getenv("HARLAN_DEVICE");

  if(cfg) {
    string s = cfg;
	transform(s.begin(), s.end(), s.begin(), ::tolower);
    if(s == "gpu") {
      return CL_DEVICE_TYPE_GPU | CL_DEVICE_TYPE_ACCELERATOR;
    }
    else if(s == "cpu") {
      return CL_DEVICE_TYPE_CPU;
    }
	else {
		cerr << "HARLAN_DEVICE must be either `cpu` or `gpu`." << endl;
		abort();
	}
  }
  return (CL_DEVICE_TYPE_GPU |
          CL_DEVICE_TYPE_CPU |
          CL_DEVICE_TYPE_ACCELERATOR |
          0);
}

int get_default_region_size()
{
    static bool first_time = true;

    const char *cfg = getenv("HARLAN_MIN_REGION_SIZE");

    if(cfg) {
        int sz = atoi(cfg);
        if(first_time) {
            cerr << "Setting region size from HARLAN_MIN_REGION_SIZE to "
                 << sz << " bytes." << endl;
            first_time = false;
        }
        return sz;
    }
    //else return 8192;
    else return 8 << 20; // 8 megs
}

region *create_region(int size)
{
    if(size == -1) size = get_default_region_size();

    assert(size > sizeof(region));

    // void *ptr = GC_MALLOC(size);
    void *ptr = malloc(size);

    region *header = (region *)ptr;
    header->magic = ALLOC_MAGIC;
    header->size = size;
    header->alloc_ptr = sizeof(region);
    header->cl_buffer = NULL;

    check_region(header);

    // Start out with the region unmapped, to avoid needless copies.
    unmap_region(header);

    return header;
}

void free_region(region *r)
{
    //fprintf(stderr, "freeing region %p. %d bytes allocated\n",
    //        r, r->alloc_ptr);
    if(r->cl_buffer) {
        clReleaseMemObject((cl_mem)r->cl_buffer);
    }
    free(r);
}

void map_region(region *header)
{
    cl_int status = 0;

    assert(header->cl_buffer);

    cl_mem buffer = (cl_mem)header->cl_buffer;

    //printf("map_region: old alloc_ptr = %d\n", header->alloc_ptr);

    // Read just the header
    status = clEnqueueReadBuffer(g_queue,
                                 buffer,
                                 CL_TRUE,
                                 0,
                                 sizeof(region),
                                 header,
                                 0,
                                 NULL,
                                 NULL);
    CL_CHECK(status);

    //printf("map_region: new alloc_ptr = %d\n", header->alloc_ptr);

	if(header->alloc_ptr - sizeof(region) > 0) {
		//printf("map_region: read %lu bytes, reading %lu more.\n",
		//	   sizeof(region), header->alloc_ptr - sizeof(region));

		// Now read the contents
		status = clEnqueueReadBuffer(g_queue,
									 buffer,
									 CL_TRUE,
									 sizeof(region),
									 header->alloc_ptr - sizeof(region),
									 ((char *)header) + sizeof(region),
									 0,
									 NULL,
									 NULL);
		CL_CHECK(status);
	}
	else {
		//printf("map_region: no remaining bytes.\n");
	}

    CL_CHECK(clReleaseMemObject(buffer));
    assert(!header->cl_buffer);
    check_region(header);
}

void unmap_region(region *header)
{
    check_region(header);

    // Don't unmap the region twice...
    // TODO: we might want to report a warning in this case.
    if(header->cl_buffer) return;
    //assert(!header->cl_buffer);

    //fprintf(stderr, "unmap_region %p, alloc_ptr = %d\n",
    //        header, header->alloc_ptr);

    cl_int status = 0;
    cl_mem buffer = clCreateBuffer(g_ctx,
                                   CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR,
                                   header->size,
                                   NULL,
                                   &status);
    CL_CHECK(status);

    status = clEnqueueWriteBuffer(g_queue,
                                  buffer,
                                  CL_TRUE,
                                  0,
                                  header->alloc_ptr,
                                  header,
                                  0,
                                  NULL,
                                  NULL);
    CL_CHECK(status);

    header->cl_buffer = buffer;
}

region_ptr alloc_in_region(region **r, unsigned int size)
{
    if((*r)->cl_buffer) {
        map_region(*r);
    }

    // printf("allocating %d bytes from region %p\n", size, *r);
    region_ptr p = (*r)->alloc_ptr;
    (*r)->alloc_ptr += size;

    // If this fails, we allocated too much memory and need to resize
    // the region.
    while((*r)->alloc_ptr > (*r)->size) {
        unsigned int new_size = (*r)->size * 2;
		// As long as we stick with power of two region sizes, this
		// will let us get up to 4GB regions. It's a big of a hacky
		// special case...
		if(new_size == 0) {
		  new_size = UINT_MAX;
		}
		assert(new_size > (*r)->size);
        region *old = *r;
        unsigned int old_size = (*r)->size;
		//printf("realloc(%p, %d)\n", *r, new_size);
        (*r) = (region *)realloc(*r, new_size);

		assert(*r != NULL);

        (*r)->size = new_size;
    }

    return p;
}

region_ptr alloc_vector(region **r, int item_size, int num_items)
{
    if((*r)->cl_buffer) {
        //cerr << "Attempting to allocate " << 8 + item_size * num_items <<  " byte vector on GPU." << endl;
        //cerr << "region size = " << (*r)->size << endl;
        // This region is on the GPU. Try to do the allocation there.
        cl::buffer<region_ptr> buf
            = g_ctx.createBuffer<region_ptr>(1, CL_MEM_READ_WRITE);

        cl::kernel k = g_prog.createKernel("harlan_rt_alloc_vector");
        k.setArg(0, (*r)->cl_buffer);
        k.setArg(1, item_size);
        k.setArg(2, num_items);
        k.setArg(3, buf);
        g_queue.execute(k, 1);

        cl::buffer_map<region_ptr> map = g_queue.mapBuffer<region_ptr>(buf);
        region_ptr p = map[0];
        if(p) return p;
    }
    //cerr << "Not enough space, allocating on CPU instead." << endl;
    // Well, that failed. I guess we'll do here instead.
    region_ptr p = alloc_in_region(r, 8 + item_size * num_items);
    *(int*)get_region_ptr(*r, p) = num_items;

    return p;
}

cl_mem get_cl_buffer(region *r)
{
    assert(r->cl_buffer);
    return (cl_mem)r->cl_buffer;
}

int ARGC = 0;
char **ARGV = NULL;

extern int harlan_main();

int main(int argc, char **argv) {
	ARGC = argc;
	ARGV = argv;

	return harlan_main();
}
<|endoftext|>


<commit_before>#include "dx11_painter.h"
#include "dx11_video.h"
#include "halley/core/graphics/material/material.h"
#include "halley/core/graphics/material/material_definition.h"
#include "dx11_shader.h"
using namespace Halley;

DX11Painter::DX11Painter(DX11Video& video, Resources& resources)
	: Painter(resources)
	, video(video)
	, vertexBuffer(video)
	, indexBuffer(video)
{
}

void DX11Painter::doStartRender()
{
}

void DX11Painter::doEndRender()
{
}

void DX11Painter::clear(Colour colour)
{
	const float col[] = { colour.r, colour.g, colour.b, colour.a };
	video.getDeviceContext().ClearRenderTargetView(&video.getRenderTarget(), col);
}

void DX11Painter::setMaterialPass(const Material& material, int passN)
{
	auto& pass = material.getDefinition().getPass(passN);
	auto& shader = static_cast<DX11Shader&>(pass.getShader());
	shader.bind(video);
}

void DX11Painter::setMaterialData(const Material& material)
{
	// TODO
}

void DX11Painter::setVertices(const MaterialDefinition& material, size_t numVertices, void* vertexData, size_t numIndices, unsigned short* indices, bool standardQuadsOnly)
{
	const size_t stride = material.getVertexStride();
	const size_t vertexDataSize = stride * numVertices;
	vertexBuffer.setData(gsl::span<const gsl::byte>(reinterpret_cast<const gsl::byte*>(vertexData), vertexDataSize));

	ID3D11Buffer* buffers[] = { vertexBuffer.getBuffer() };
	UINT strides[] = { UINT(stride) };
	UINT offsets[] = { 0 };
	video.getDeviceContext().IASetVertexBuffers(0, 1, buffers, strides, offsets);

	indexBuffer.setData(gsl::as_bytes(gsl::span<unsigned short>(indices, numIndices)));
	video.getDeviceContext().IASetIndexBuffer(indexBuffer.getBuffer(), DXGI_FORMAT_R16_UINT, 0);
}

void DX11Painter::drawTriangles(size_t numIndices)
{
	// TODO
}

void DX11Painter::setViewPort(Rect4i rect)
{
	// TODO
}

void DX11Painter::setClip(Rect4i clip, bool enable)
{
	// TODO
}

void DX11Painter::onUpdateProjection(Material& material)
{
	// TODO
}
<commit_msg>Issue draw call.<commit_after>#include "dx11_painter.h"
#include "dx11_video.h"
#include "halley/core/graphics/material/material.h"
#include "halley/core/graphics/material/material_definition.h"
#include "dx11_shader.h"
using namespace Halley;

DX11Painter::DX11Painter(DX11Video& video, Resources& resources)
	: Painter(resources)
	, video(video)
	, vertexBuffer(video)
	, indexBuffer(video)
{
}

void DX11Painter::doStartRender()
{
}

void DX11Painter::doEndRender()
{
}

void DX11Painter::clear(Colour colour)
{
	const float col[] = { colour.r, colour.g, colour.b, colour.a };
	video.getDeviceContext().ClearRenderTargetView(&video.getRenderTarget(), col);
}

void DX11Painter::setMaterialPass(const Material& material, int passN)
{
	auto& pass = material.getDefinition().getPass(passN);
	auto& shader = static_cast<DX11Shader&>(pass.getShader());
	shader.bind(video);
}

void DX11Painter::setMaterialData(const Material& material)
{
	// TODO
}

void DX11Painter::setVertices(const MaterialDefinition& material, size_t numVertices, void* vertexData, size_t numIndices, unsigned short* indices, bool standardQuadsOnly)
{
	const size_t stride = material.getVertexStride();
	const size_t vertexDataSize = stride * numVertices;
	vertexBuffer.setData(gsl::span<const gsl::byte>(reinterpret_cast<const gsl::byte*>(vertexData), vertexDataSize));

	ID3D11Buffer* buffers[] = { vertexBuffer.getBuffer() };
	UINT strides[] = { UINT(stride) };
	UINT offsets[] = { 0 };
	video.getDeviceContext().IASetVertexBuffers(0, 1, buffers, strides, offsets);

	indexBuffer.setData(gsl::as_bytes(gsl::span<unsigned short>(indices, numIndices)));
	video.getDeviceContext().IASetIndexBuffer(indexBuffer.getBuffer(), DXGI_FORMAT_R16_UINT, 0);
}

void DX11Painter::drawTriangles(size_t numIndices)
{
	video.getDeviceContext().Draw(UINT(numIndices), 0);
}

void DX11Painter::setViewPort(Rect4i rect)
{
	// TODO
}

void DX11Painter::setClip(Rect4i clip, bool enable)
{
	// TODO
}

void DX11Painter::onUpdateProjection(Material& material)
{
	// TODO
}
<|endoftext|>


<commit_before>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2010 Emmanuel Benazera, juban@free.fr
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Portions of the code below appear in the sample code from OpenCV with
 * the following comment:
 * A Demo to OpenCV Implementation of SURF
 * Further Information Refer to "SURF: Speed-Up Robust Feature"
 * Author: Liu Liu
 * liuliu.1987+opencv@gmail.com
 */

#include "ocvsurf.h"
#include "miscutil.h"
#include "errlog.h"

#include <cxflann.h>

#include <iostream>
#include <fstream>

#include <unistd.h>

using sp::miscutil;
using sp::errlog;

namespace seeks_plugins
{
#define EXTENDED_DESCRIPTOR 1

   CvSURFParams ocvsurf::_surf_params = cvSURFParams(600,EXTENDED_DESCRIPTOR);

   void ocvsurf::generate_surf_features(const std::string *img_content,
					CvSeq *&objectKeypoints,
					CvSeq *&objectDescriptors,
					const img_search_snippet *sg)
     {
	// XXX: Ridiculous! OpenCV doesn't support loading an image from memory,
	// all hacks tried where too complicated, and deep into OpenCV. Sad.
	// Now we need to write every image on disk and reload it, which
	// is totally stupid.
	static std::string tmp_rep = "/tmp/"; //TODO: in configuration.

	// write to file.
	std::string tfname = tmp_rep + miscutil::to_string(sg->_id);
	std::ofstream ofile(tfname.c_str(),std::ofstream::binary);
	ofile.write(img_content->c_str(),img_content->length());

	IplImage *img = cvLoadImage(tfname.c_str(),CV_LOAD_IMAGE_GRAYSCALE);
	if (!img) // failed loading image, usually from a broken transfer earlier...
	  {
	     unlink(tfname.c_str());
	     return;
	  }

	// remove file.
	unlink(tfname.c_str());

	// extract SURF features.
	try
	  {
	     cvExtractSURF(img, 0, &objectKeypoints, &objectDescriptors,
			   sg->_surf_storage, ocvsurf::_surf_params);
	  }
	catch (cv::Exception &e)
	  {
	     errlog::log_error(LOG_LEVEL_ERROR,"Error extracting features from image loaded from %s: %s", tfname.c_str(),
			       e.err.c_str());
	     return; // failure.
	  }

	//debug
	/* std::cerr << "extracted features for img " << sg->_cached << std::endl;
	 std::cerr << "keypoints: " << objectKeypoints->total << " -- descriptors: " << objectDescriptors->total << std::endl; */
	//debug
     }

   /* void ocvsurf::flannFindPairs(CvSeq *o1desc,
				CvSeq *o2desc,
				std::vector<surf_pair> &ptpairs)
     {
	int length = (int)(o1desc->elem_size/sizeof(float));

	cv::Mat m_object(o1desc->total, length, CV_32F);
	cv::Mat m_image(o2desc->total, length, CV_32F);

	// copy descriptors
	CvSeqReader obj_reader;
	float* obj_ptr = m_object.ptr<float>(0);
	cvStartReadSeq( o1desc, &obj_reader );
	for(int i = 0; i < o1desc->total; i++ )
	  {
	     const float* descriptor = (const float*)obj_reader.ptr;
	     CV_NEXT_SEQ_ELEM( obj_reader.seq->elem_size, obj_reader );
	     memcpy(obj_ptr, descriptor, length*sizeof(float));
	     obj_ptr += length;
	  }

	CvSeqReader img_reader;
	float* img_ptr = m_image.ptr<float>(0);
	cvStartReadSeq( o2desc, &img_reader );
	for(int i = 0; i < o2desc->total; i++ )
	  {
	     const float* descriptor = (const float*)img_reader.ptr;
	     CV_NEXT_SEQ_ELEM( img_reader.seq->elem_size, img_reader );
	     memcpy(img_ptr, descriptor, length*sizeof(float));
	     img_ptr += length;
	  }

	// find nearest neighbors using FLANN
	cv::Mat m_indices(o1desc->total, 2, CV_32S);
	cv::Mat m_dists(o1desc->total, 2, CV_32F);
	cv::flann::Index flann_index(m_image, cv::flann::KDTreeIndexParams(8));  // using 8 randomized kdtrees
	flann_index.knnSearch(m_object, m_indices, m_dists, 2, cv::flann::SearchParams(64) ); // 64 is maximum number of leaves being checked

	int* indices_ptr = m_indices.ptr<int>(0);
	float* dists_ptr = m_dists.ptr<float>(0);
	for (int i=0;i<m_indices.rows;++i)
	  { */
	     /* if (dists_ptr[2*i]<0.6*dists_ptr[2*i+1])
	       {
		  ptpairs.push_back(i);
		  ptpairs.push_back(indices_ptr[2*i]);
	       } */
	    /* ptpairs.push_back(surf_pair(i,indices_ptr[2*i],dists_ptr[2*i]/static_cast<double>(dists_ptr[2*i+1])));
	  }

	//debug
	//std::cout << "ptpairs size: " << ptpairs.size() << std::endl;
	//debug
     } */

#define CORRELATION_THRESHOLD 0.9
   // brute-force attempt at correlating the two sets of features
   int ocvsurf::bruteMatch(CvMat *&points1, CvMat *&points2,
			   CvSeq *kp1, CvSeq *desc1, CvSeq *kp2, CvSeq *desc2,
			   const bool &filter)
     {
      int i,j,k;
	double* avg1 = (double*)malloc(sizeof(double)*kp1->total);
        double* avg2 = (double*)malloc(sizeof(double)*kp2->total);
        double* dev1 = (double*)malloc(sizeof(double)*kp1->total);
        double* dev2 = (double*)malloc(sizeof(double)*kp2->total);
        int* best1 = (int*)malloc(sizeof(int)*kp1->total);
	int* best2 = (int*)malloc(sizeof(int)*kp2->total);
        double* best1corr = (double*)malloc(sizeof(double)*kp1->total);
        double* best2corr = (double*)malloc(sizeof(double)*kp2->total);
        float *seq1, *seq2;
        int descriptor_size = EXTENDED_DESCRIPTOR ? 128 : 64;
        for (i=0; i<kp1->total; i++)
	  {
	   // find average and standard deviation of each descriptor
	   avg1[i] = 0;
	   dev1[i] = 0;
	   seq1 = (float*)cvGetSeqElem(desc1, i);
	   for (k=0; k<descriptor_size; k++) avg1[i] += seq1[k];
	   avg1[i] /= descriptor_size;
	   for (k=0; k<descriptor_size; k++) dev1[i] +=
	     (seq1[k]-avg1[i])*(seq1[k]-avg1[i]);
	   dev1[i] = sqrt(dev1[i]/descriptor_size);

	   // initialize best1 and best1corr
	   best1[i] = -1;
	   best1corr[i] = -1.;
        }
        for (j=0; j<kp2->total; j++)
	  {
	   // find average and standard deviation of each descriptor
	     avg2[j] = 0;
	     dev2[j] = 0;
	     seq2 = (float*)cvGetSeqElem(desc2, j);
	     for (k=0; k<descriptor_size; k++) avg2[j] += seq2[k];
	     avg2[j] /= descriptor_size;
	     for (k=0; k<descriptor_size; k++) dev2[j] +=
	       (seq2[k]-avg2[j])*(seq2[k]-avg2[j]);
	     dev2[j] = sqrt(dev2[j]/descriptor_size);

	     // initialize best2 and best2corr
	     best2[j] = -1;
	     best2corr[j] = -1.;
	  }
        double corr;
        for (i = 0; i < kp1->total; ++i)
	  {
	     seq1 = (float*)cvGetSeqElem(desc1, i);
	     for (j = 0; j < kp2->total; ++j) {
                corr = 0;
                seq2 = (float*)cvGetSeqElem(desc2, j);
                for (k = 0; k < descriptor_size; ++k)
		  corr += (seq1[k]-avg1[i])*(seq2[k]-avg2[j]);
                corr /= (descriptor_size-1)*dev1[i]*dev2[j];
                if (corr > best1corr[i]) {
		   best1corr[i] = corr;
		   best1[i] = j;
                }
                if (corr > best2corr[j])
		  {
		     best2corr[j] = corr;
		     best2[j] = i;
		  }
	     }
	  }
        j = 0;
        for (i = 0; i < kp1->total; i++)
	  if (best2[best1[i]] == i && best1corr[i] > CORRELATION_THRESHOLD)
	    j++;

	if (j>0 && filter)
	  {
	     points1 = cvCreateMat(1,j,CV_32FC2);
	     points2 = cvCreateMat(1,j,CV_32FC2);
	     CvPoint2D32f *p1, *p2;
	     j = 0;
	     for (i = 0; i < kp1->total; i++)
	       {
		  if (best2[best1[i]] == i && best1corr[i] > CORRELATION_THRESHOLD)
		    {
		       p1 = &((CvSURFPoint*)cvGetSeqElem(kp1,i))->pt;
		       p2 = &((CvSURFPoint*)cvGetSeqElem(kp2,best1[i]))->pt;
		       points1->data.fl[j*2] = p1->x;
		       points1->data.fl[j*2+1] = p1->y;
		       points2->data.fl[j*2] = p2->x;
		       points2->data.fl[j*2+1] = p2->y;
		       j++;
		    }
	       }
	  }

        free(best2corr);
        free(best1corr);
        free(best2);
        free(best1);
        free(avg1);
        free(avg2);
        free(dev1);
        free(dev2);
	return j;
     }

   int ocvsurf::removeOutliers(CvMat *&points1, CvMat *&points2)
     {
	CvMat *F = cvCreateMat(3,3,CV_32FC1); //TODO: free F ?
	CvMat *status = cvCreateMat(1,points1->cols,CV_8UC1); //TODO: free status.
	int fm_count = cvFindFundamentalMat(points1,points2,F,
					    CV_FM_RANSAC,1.,0.99,status );

	// iterates the set of putative correspondences and removes correspondences
	// marked as outliers by cvFindFundamentalMat()
	int count = 0;
	int j = 0;
	for (int i = 0; i < status->cols; i++) if (CV_MAT_ELEM(*status,unsigned
							       char,0,i)) count++;
	CvMat *points1_ = points1;
	CvMat *points2_ = points2;
	if (!count)
	  { // no inliers
	     points1 = NULL;
	     points2 = NULL; // beware: leak ?
	     return j;
	  }
	else
	  {
	     points1 = cvCreateMat(1,count,CV_32FC2);
	     points2 = cvCreateMat(1,count,CV_32FC2);
	     int j = 0;
	     for (int i = 0; i < status->cols; i++) {
		if (CV_MAT_ELEM(*status,unsigned char,0,i)) {
		   points1->data.fl[j*2] = points1_->data.fl[i*2];
		   // //p1->x
		   points1->data.fl[j*2+1] = points1_->data.fl[i*2+1];
		   //p1->y
		   points2->data.fl[j*2] = points2_->data.fl[i*2];
		   // //p2->x
		   points2->data.fl[j*2+1] = points2_->data.fl[i*2+1];
		   // //p2->y
		   j++;
		}
	     }
          }
	cvReleaseMat(&points1_);
	cvReleaseMat(&points2_);
	return j;
     }

} /* end of namespace. */

<commit_msg>aknowledgement to function initial author<commit_after>/**
 * The Seeks proxy and plugin framework are part of the SEEKS project.
 * Copyright (C) 2010 Emmanuel Benazera, juban@free.fr
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Portions of the code below appear in the sample code from OpenCV with
 * the following comment:
 * A Demo to OpenCV Implementation of SURF
 * Further Information Refer to "SURF: Speed-Up Robust Feature"
 * Author: Liu Liu
 * liuliu.1987+opencv@gmail.com
 *
 * The bruteMatch function was initially written by Jostein Austvik Jacobsen.
 */

#include "ocvsurf.h"
#include "miscutil.h"
#include "errlog.h"

#include <cxflann.h>

#include <iostream>
#include <fstream>

#include <unistd.h>

using sp::miscutil;
using sp::errlog;

namespace seeks_plugins
{
#define EXTENDED_DESCRIPTOR 1

   CvSURFParams ocvsurf::_surf_params = cvSURFParams(600,EXTENDED_DESCRIPTOR);

   void ocvsurf::generate_surf_features(const std::string *img_content,
					CvSeq *&objectKeypoints,
					CvSeq *&objectDescriptors,
					const img_search_snippet *sg)
     {
	// XXX: Ridiculous! OpenCV doesn't support loading an image from memory,
	// all hacks tried where too complicated, and deep into OpenCV. Sad.
	// Now we need to write every image on disk and reload it, which
	// is totally stupid.
	static std::string tmp_rep = "/tmp/"; //TODO: in configuration.

	// write to file.
	std::string tfname = tmp_rep + miscutil::to_string(sg->_id);
	std::ofstream ofile(tfname.c_str(),std::ofstream::binary);
	ofile.write(img_content->c_str(),img_content->length());

	IplImage *img = cvLoadImage(tfname.c_str(),CV_LOAD_IMAGE_GRAYSCALE);
	if (!img) // failed loading image, usually from a broken transfer earlier...
	  {
	     unlink(tfname.c_str());
	     return;
	  }

	// remove file.
	unlink(tfname.c_str());

	// extract SURF features.
	try
	  {
	     cvExtractSURF(img, 0, &objectKeypoints, &objectDescriptors,
			   sg->_surf_storage, ocvsurf::_surf_params);
	  }
	catch (cv::Exception &e)
	  {
	     errlog::log_error(LOG_LEVEL_ERROR,"Error extracting features from image loaded from %s: %s", tfname.c_str(),
			       e.err.c_str());
	     return; // failure.
	  }

	//debug
	/* std::cerr << "extracted features for img " << sg->_cached << std::endl;
	 std::cerr << "keypoints: " << objectKeypoints->total << " -- descriptors: " << objectDescriptors->total << std::endl; */
	//debug
     }

   /* void ocvsurf::flannFindPairs(CvSeq *o1desc,
				CvSeq *o2desc,
				std::vector<surf_pair> &ptpairs)
     {
	int length = (int)(o1desc->elem_size/sizeof(float));

	cv::Mat m_object(o1desc->total, length, CV_32F);
	cv::Mat m_image(o2desc->total, length, CV_32F);

	// copy descriptors
	CvSeqReader obj_reader;
	float* obj_ptr = m_object.ptr<float>(0);
	cvStartReadSeq( o1desc, &obj_reader );
	for(int i = 0; i < o1desc->total; i++ )
	  {
	     const float* descriptor = (const float*)obj_reader.ptr;
	     CV_NEXT_SEQ_ELEM( obj_reader.seq->elem_size, obj_reader );
	     memcpy(obj_ptr, descriptor, length*sizeof(float));
	     obj_ptr += length;
	  }

	CvSeqReader img_reader;
	float* img_ptr = m_image.ptr<float>(0);
	cvStartReadSeq( o2desc, &img_reader );
	for(int i = 0; i < o2desc->total; i++ )
	  {
	     const float* descriptor = (const float*)img_reader.ptr;
	     CV_NEXT_SEQ_ELEM( img_reader.seq->elem_size, img_reader );
	     memcpy(img_ptr, descriptor, length*sizeof(float));
	     img_ptr += length;
	  }

	// find nearest neighbors using FLANN
	cv::Mat m_indices(o1desc->total, 2, CV_32S);
	cv::Mat m_dists(o1desc->total, 2, CV_32F);
	cv::flann::Index flann_index(m_image, cv::flann::KDTreeIndexParams(8));  // using 8 randomized kdtrees
	flann_index.knnSearch(m_object, m_indices, m_dists, 2, cv::flann::SearchParams(64) ); // 64 is maximum number of leaves being checked

	int* indices_ptr = m_indices.ptr<int>(0);
	float* dists_ptr = m_dists.ptr<float>(0);
	for (int i=0;i<m_indices.rows;++i)
	  { */
	     /* if (dists_ptr[2*i]<0.6*dists_ptr[2*i+1])
	       {
		  ptpairs.push_back(i);
		  ptpairs.push_back(indices_ptr[2*i]);
	       } */
	    /* ptpairs.push_back(surf_pair(i,indices_ptr[2*i],dists_ptr[2*i]/static_cast<double>(dists_ptr[2*i+1])));
	  }

	//debug
	//std::cout << "ptpairs size: " << ptpairs.size() << std::endl;
	//debug
     } */

#define CORRELATION_THRESHOLD 0.9
   // brute-force attempt at correlating the two sets of features
   int ocvsurf::bruteMatch(CvMat *&points1, CvMat *&points2,
			   CvSeq *kp1, CvSeq *desc1, CvSeq *kp2, CvSeq *desc2,
			   const bool &filter)
     {
      int i,j,k;
	double* avg1 = (double*)malloc(sizeof(double)*kp1->total);
        double* avg2 = (double*)malloc(sizeof(double)*kp2->total);
        double* dev1 = (double*)malloc(sizeof(double)*kp1->total);
        double* dev2 = (double*)malloc(sizeof(double)*kp2->total);
        int* best1 = (int*)malloc(sizeof(int)*kp1->total);
	int* best2 = (int*)malloc(sizeof(int)*kp2->total);
        double* best1corr = (double*)malloc(sizeof(double)*kp1->total);
        double* best2corr = (double*)malloc(sizeof(double)*kp2->total);
        float *seq1, *seq2;
        int descriptor_size = EXTENDED_DESCRIPTOR ? 128 : 64;
        for (i=0; i<kp1->total; i++)
	  {
	   // find average and standard deviation of each descriptor
	   avg1[i] = 0;
	   dev1[i] = 0;
	   seq1 = (float*)cvGetSeqElem(desc1, i);
	   for (k=0; k<descriptor_size; k++) avg1[i] += seq1[k];
	   avg1[i] /= descriptor_size;
	   for (k=0; k<descriptor_size; k++) dev1[i] +=
	     (seq1[k]-avg1[i])*(seq1[k]-avg1[i]);
	   dev1[i] = sqrt(dev1[i]/descriptor_size);

	   // initialize best1 and best1corr
	   best1[i] = -1;
	   best1corr[i] = -1.;
        }
        for (j=0; j<kp2->total; j++)
	  {
	   // find average and standard deviation of each descriptor
	     avg2[j] = 0;
	     dev2[j] = 0;
	     seq2 = (float*)cvGetSeqElem(desc2, j);
	     for (k=0; k<descriptor_size; k++) avg2[j] += seq2[k];
	     avg2[j] /= descriptor_size;
	     for (k=0; k<descriptor_size; k++) dev2[j] +=
	       (seq2[k]-avg2[j])*(seq2[k]-avg2[j]);
	     dev2[j] = sqrt(dev2[j]/descriptor_size);

	     // initialize best2 and best2corr
	     best2[j] = -1;
	     best2corr[j] = -1.;
	  }
        double corr;
        for (i = 0; i < kp1->total; ++i)
	  {
	     seq1 = (float*)cvGetSeqElem(desc1, i);
	     for (j = 0; j < kp2->total; ++j) {
                corr = 0;
                seq2 = (float*)cvGetSeqElem(desc2, j);
                for (k = 0; k < descriptor_size; ++k)
		  corr += (seq1[k]-avg1[i])*(seq2[k]-avg2[j]);
                corr /= (descriptor_size-1)*dev1[i]*dev2[j];
                if (corr > best1corr[i]) {
		   best1corr[i] = corr;
		   best1[i] = j;
                }
                if (corr > best2corr[j])
		  {
		     best2corr[j] = corr;
		     best2[j] = i;
		  }
	     }
	  }
        j = 0;
        for (i = 0; i < kp1->total; i++)
	  if (best2[best1[i]] == i && best1corr[i] > CORRELATION_THRESHOLD)
	    j++;

	if (j>0 && filter)
	  {
	     points1 = cvCreateMat(1,j,CV_32FC2);
	     points2 = cvCreateMat(1,j,CV_32FC2);
	     CvPoint2D32f *p1, *p2;
	     j = 0;
	     for (i = 0; i < kp1->total; i++)
	       {
		  if (best2[best1[i]] == i && best1corr[i] > CORRELATION_THRESHOLD)
		    {
		       p1 = &((CvSURFPoint*)cvGetSeqElem(kp1,i))->pt;
		       p2 = &((CvSURFPoint*)cvGetSeqElem(kp2,best1[i]))->pt;
		       points1->data.fl[j*2] = p1->x;
		       points1->data.fl[j*2+1] = p1->y;
		       points2->data.fl[j*2] = p2->x;
		       points2->data.fl[j*2+1] = p2->y;
		       j++;
		    }
	       }
	  }

        free(best2corr);
        free(best1corr);
        free(best2);
        free(best1);
        free(avg1);
        free(avg2);
        free(dev1);
        free(dev2);
	return j;
     }

   int ocvsurf::removeOutliers(CvMat *&points1, CvMat *&points2)
     {
	CvMat *F = cvCreateMat(3,3,CV_32FC1); //TODO: free F ?
	CvMat *status = cvCreateMat(1,points1->cols,CV_8UC1); //TODO: free status.
	int fm_count = cvFindFundamentalMat(points1,points2,F,
					    CV_FM_RANSAC,1.,0.99,status );

	// iterates the set of putative correspondences and removes correspondences
	// marked as outliers by cvFindFundamentalMat()
	int count = 0;
	int j = 0;
	for (int i = 0; i < status->cols; i++) if (CV_MAT_ELEM(*status,unsigned
							       char,0,i)) count++;
	CvMat *points1_ = points1;
	CvMat *points2_ = points2;
	if (!count)
	  { // no inliers
	     points1 = NULL;
	     points2 = NULL; // beware: leak ?
	     return j;
	  }
	else
	  {
	     points1 = cvCreateMat(1,count,CV_32FC2);
	     points2 = cvCreateMat(1,count,CV_32FC2);
	     int j = 0;
	     for (int i = 0; i < status->cols; i++) {
		if (CV_MAT_ELEM(*status,unsigned char,0,i)) {
		   points1->data.fl[j*2] = points1_->data.fl[i*2];
		   // //p1->x
		   points1->data.fl[j*2+1] = points1_->data.fl[i*2+1];
		   //p1->y
		   points2->data.fl[j*2] = points2_->data.fl[i*2];
		   // //p2->x
		   points2->data.fl[j*2+1] = points2_->data.fl[i*2+1];
		   // //p2->y
		   j++;
		}
	     }
          }
	cvReleaseMat(&points1_);
	cvReleaseMat(&points2_);
	return j;
     }

} /* end of namespace. */

<|endoftext|>


<commit_before>#include "pixelboost/debug/log.h"
#include "pixelboost/file/fileSystem.cpp"

#if defined(PIXELBOOST_PLATFORM_ANDROID)
    #include <android/log.h>
#elif defined(PIXELBOOST_PLATFORM_NACL)
    #include "ppapi/cpp/instance.h"
    #include "ppapi/cpp/var.h"
    #include "pixelboost/framework/engine.h"
#endif

using namespace pb;

LogSubscriber::LogSubscriber()
{
    _Level = kLogLevelDebug;
    _Filter = "";
}

LogSubscriber::~LogSubscriber()
{

}

void LogSubscriber::SetFilter(LogLevel logLevel, const std::string& systemFilter)
{
    _Level = logLevel;
    _Filter = systemFilter;
}

LogLevel LogSubscriber::GetLogLevel()
{
    return _Level;
}

std::string LogSubscriber::GetSystemFilter()
{
    return _Filter;
}

void LogSubscriberConsole::OnLogMessage(LogLevel logLevel, const std::string& system, const std::string& message)
{
#if defined(PIXELBOOST_PLATFORM_ANDROID)
    switch (logLevel)
    {
        case kLogLevelDebug:
            __android_log_print(ANDROID_LOG_DEBUG, system, "%s", message.c_str());
            break;
        case kLogLevelError:
            __android_log_print(ANDROID_LOG_ERROR, system, "%s", message.c_str());
            break;
        case kLogLevelInfo:
            __android_log_print(ANDROID_LOG_INFO, system, "%s", message.c_str());
            break;
        case kLogLevelWarn:
            __android_log_print(ANDROID_LOG_WARN, system, "%s", message.c_str());
            break;
        case kLogLevelNone:
            break;
    }
#elif defined(PIXELBOOST_PLATFORM_NACL)
    static_cast<pp::Instance*>(pb::Engine::Instance()->GetViewController())->PostMessage(pp::Var(status));
#else
    std::string levelString;
    switch (logLevel) {
        case kLogLevelDebug:
            levelString = "[Debug]";
            break;
        case kLogLevelError:
            levelString = "[Error]";
            break;
        case kLogLevelInfo:
            levelString = " [Info]";
            break;
        case kLogLevelWarn:
            levelString = " [Warn]";
            break;
        case kLogLevelNone:
            break;
    }
    printf("%s (%s) %s\n", levelString.c_str(), system.c_str(), message.c_str());
#endif
}

LogSubscriberFile::LogSubscriberFile(const std::string& filename)
{
    _File = pb::FileSystem::Instance()->OpenFile(filename, kFileModeWrite);
}

LogSubscriberFile::~LogSubscriberFile()
{
    delete _File;
}

void LogSubscriberFile::OnLogMessage(LogLevel logLevel, const std::string& system, const std::string& message)
{
    std::string levelString;
    switch (logLevel) {
        case kLogLevelDebug:
            levelString = "[Debug]";
            break;
        case kLogLevelError:
            levelString = "[Error]";
            break;
        case kLogLevelInfo:
            levelString = " [Info]";
            break;
        case kLogLevelWarn:
            levelString = " [Warn]";
            break;
        case kLogLevelNone:
            break;
    }
    char log[2048];
    snprintf(log, 2048, "%s (%s) %s\n", levelString.c_str(), system.c_str(), message.c_str());
    _File->Write(std::string(log));
}

LogSystem::LogSystem()
{

}

LogSystem::~LogSystem()
{
    for (auto it = _Subscribers.begin(); it != _Subscribers.end(); ++it)
    {
        delete *it;
    }
}

LogSystem* LogSystem::Instance()
{
    static LogSystem* instance = new LogSystem();
    return instance;
}

void LogSystem::AddSubscriber(LogSubscriber* subscriber)
{
    _Subscribers.push_back(subscriber);
}

void LogSystem::Log(LogLevel logLevel, const std::string& system, const std::string& message)
{
    _Mutex.lock();
    for (auto it = _Subscribers.begin(); it != _Subscribers.end(); ++it)
    {
        if (logLevel >= (*it)->GetLogLevel())
        {
            (*it)->OnLogMessage(logLevel, system, message);
        }
    }
    _Mutex.unlock();
}
<commit_msg>Fix console log compile issues on Android<commit_after>#include "pixelboost/debug/log.h"
#include "pixelboost/file/fileSystem.cpp"

#if defined(PIXELBOOST_PLATFORM_ANDROID)
    #include <android/log.h>
#elif defined(PIXELBOOST_PLATFORM_NACL)
    #include "ppapi/cpp/instance.h"
    #include "ppapi/cpp/var.h"
    #include "pixelboost/framework/engine.h"
#endif

using namespace pb;

LogSubscriber::LogSubscriber()
{
    _Level = kLogLevelDebug;
    _Filter = "";
}

LogSubscriber::~LogSubscriber()
{

}

void LogSubscriber::SetFilter(LogLevel logLevel, const std::string& systemFilter)
{
    _Level = logLevel;
    _Filter = systemFilter;
}

LogLevel LogSubscriber::GetLogLevel()
{
    return _Level;
}

std::string LogSubscriber::GetSystemFilter()
{
    return _Filter;
}

void LogSubscriberConsole::OnLogMessage(LogLevel logLevel, const std::string& system, const std::string& message)
{
#if defined(PIXELBOOST_PLATFORM_ANDROID)
    switch (logLevel)
    {
        case kLogLevelDebug:
            __android_log_print(ANDROID_LOG_DEBUG, system.c_str(), "%s", message.c_str());
            break;
        case kLogLevelError:
            __android_log_print(ANDROID_LOG_ERROR, system.c_str(), "%s", message.c_str());
            break;
        case kLogLevelInfo:
            __android_log_print(ANDROID_LOG_INFO, system.c_str(), "%s", message.c_str());
            break;
        case kLogLevelWarn:
            __android_log_print(ANDROID_LOG_WARN, system.c_str(), "%s", message.c_str());
            break;
        case kLogLevelNone:
            break;
    }
#elif defined(PIXELBOOST_PLATFORM_NACL)
    static_cast<pp::Instance*>(pb::Engine::Instance()->GetViewController())->PostMessage(pp::Var(status));
#else
    std::string levelString;
    switch (logLevel) {
        case kLogLevelDebug:
            levelString = "[Debug]";
            break;
        case kLogLevelError:
            levelString = "[Error]";
            break;
        case kLogLevelInfo:
            levelString = " [Info]";
            break;
        case kLogLevelWarn:
            levelString = " [Warn]";
            break;
        case kLogLevelNone:
            break;
    }
    printf("%s (%s) %s\n", levelString.c_str(), system.c_str(), message.c_str());
#endif
}

LogSubscriberFile::LogSubscriberFile(const std::string& filename)
{
    _File = pb::FileSystem::Instance()->OpenFile(filename, kFileModeWrite);
}

LogSubscriberFile::~LogSubscriberFile()
{
    delete _File;
}

void LogSubscriberFile::OnLogMessage(LogLevel logLevel, const std::string& system, const std::string& message)
{
    std::string levelString;
    switch (logLevel) {
        case kLogLevelDebug:
            levelString = "[Debug]";
            break;
        case kLogLevelError:
            levelString = "[Error]";
            break;
        case kLogLevelInfo:
            levelString = " [Info]";
            break;
        case kLogLevelWarn:
            levelString = " [Warn]";
            break;
        case kLogLevelNone:
            break;
    }
    char log[2048];
    snprintf(log, 2048, "%s (%s) %s\n", levelString.c_str(), system.c_str(), message.c_str());
    _File->Write(std::string(log));
}

LogSystem::LogSystem()
{

}

LogSystem::~LogSystem()
{
    for (auto it = _Subscribers.begin(); it != _Subscribers.end(); ++it)
    {
        delete *it;
    }
}

LogSystem* LogSystem::Instance()
{
    static LogSystem* instance = new LogSystem();
    return instance;
}

void LogSystem::AddSubscriber(LogSubscriber* subscriber)
{
    _Subscribers.push_back(subscriber);
}

void LogSystem::Log(LogLevel logLevel, const std::string& system, const std::string& message)
{
    _Mutex.lock();
    for (auto it = _Subscribers.begin(); it != _Subscribers.end(); ++it)
    {
        if (logLevel >= (*it)->GetLogLevel())
        {
            (*it)->OnLogMessage(logLevel, system, message);
        }
    }
    _Mutex.unlock();
}
<|endoftext|>


<commit_before>#include "sensors.h"
#include "sensorsbank.h"

#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string>
#include <sstream>
#include <string.h>
#include <unistd.h>
#include "log.h"

Sensors * Sensors::me=NULL;
#define ADDRESS 0x04

// The I2C bus: This is for V2 and V3 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-1";

void Sensors::start(unsigned int readinterval, unsigned int postinterval) throw (ThreadCreateException){
	if (Sensors::me==NULL) {
		Sensors::me=new Sensors(readinterval,postinterval);
		Sensors::me->running=true;
		if(pthread_create(Sensors::me->thread, NULL, Sensors::run, Sensors::me)) {
			Log::logger->log("SENSORS",ERROR) << "Can't create sensors thread " << strerror (errno) << endl;
			throw ThreadCreateException();
		}
	}
}

void Sensors::stop() {
	Sensors::me->running=false;
	pthread_join(*(Sensors::me->thread), NULL);
	delete Sensors::me;
	Sensors::me=NULL;
}

void * Sensors::run(void * sensors) {
	Sensors * me=(Sensors *) sensors;
	unsigned int postloop=me->postinterval/me->readinterval;
	unsigned int loop=0;
	while (me->running) {
		sleep(me->readinterval);
		if (me->readSensors()) {
			loop++;
			if (loop>postloop) {
				for (std::map<string, double>::iterator it=me->value.begin();it!=me->value.end(); it++) {
					me->lastavg[it->first]=it->second/loop;
					me->value[it->first]=0;
				}
				try {
					SensorsBank::sendData(me->lastavg);
				} catch(CurlInitException &e) {
				} catch(PostException &e) {
				}
				loop=0;
			}
		}
	}
	return NULL;
}

Sensors::Sensors(unsigned int readinterval, unsigned int postinterval) {
	this->readinterval=readinterval;
	this->postinterval=postinterval;
	this->thread= (pthread_t *) malloc(sizeof(pthread_t));
	this->value["Temperature"]=0;
	this->value["Humidity"]=0;
	this->value["MQ-2"]=0;
	this->value["MQ-4"]=0;
	this->value["MQ-5"]=0;
	this->value["MQ-6"]=0;
	this->value["MQ-7"]=0;
	this->value["MQ-135"]=0;
	this->lastavg["Temperature"]=0;
	this->lastavg["Humidity"]=0;
	this->lastavg["MQ-2"]=0;
	this->lastavg["MQ-4"]=0;
	this->lastavg["MQ-5"]=0;
	this->lastavg["MQ-6"]=0;
	this->lastavg["MQ-7"]=0;
	this->lastavg["MQ-135"]=0;

}

Sensors::~Sensors() {
	free(this->thread);
}

bool Sensors::readSensors() {
	int file;
	if ((file = open(devName, O_RDWR)) < 0) {
    	Log::logger->log("SENSORS",ERROR) << "Failed to access I2C device " << devName << endl;
    	return false;
	}

	Log::logger->log("SENSORS",DEBUG) << "I2C: acquiring buss to 0x" << ADDRESS << endl;
 	if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    	Log::logger->log("SENSORS",ERROR) << "I2C: Failed to acquire bus access/talk to slave 0x" << ADDRESS << endl;
    	close(file);
		return false;
	}
 	unsigned char cmd[1];
 	bool result=true;
    cmd[0] = 0;
    if (write(file, cmd, 1) == 1) {
		usleep(10000);
		char buf[16];
		if (read(file, buf, 16) == 16) {
			double data[8];
			data[0] = ((double) (buf[0]+ (255*buf[1])))/10;
	    	data[1] = ((double) (buf[2]+ (255*buf[3])))/10;
	        data[2] = ((double) (buf[4]+ (255*buf[5])))/10;
	        data[3] = ((double) (buf[6]+ (255*buf[7])))/10;
	        data[4] = ((double) (buf[8]+ (255*buf[9])))/10;
	        data[5] = ((double) (buf[10]+ (255*buf[11])))/10;
	        data[6] = ((double) (buf[12]+ (255*buf[13])))/10;
	        data[7] = ((double) (buf[14] + (255*buf[15])))/10;
	        this->value["Humidity"]		+= data[0];
	    	this->value["Temperature"]	+= data[1];
	        this->value["MQ-2"] 		+= data[2];
	        this->value["MQ-4"]		 	+= data[3];
	        this->value["MQ-5"]			+= data[4];
	        this->value["MQ-6"]			+= data[5];
	        this->value["MQ-7"]			+= data[6];
	        this->value["MQ-135"]		+= data[7];

	        if (data[1] >60) {
	        	Log::logger->log("SENSORS",DEBUG) << "Temperature too high : ";
	        	for (int i=0;i<8;i++) Log::logger->log("SENSORS",DEBUG) << data[i] <<" \t";
	        	Log::logger->log("SENSORS",DEBUG) << endl;
	        }
		} else {
			result=false;
		}
	} else {
		result=false;
	}
	close(file);
	return result;
}
<commit_msg>debug sensor data<commit_after>#include "sensors.h"
#include "sensorsbank.h"

#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string>
#include <sstream>
#include <string.h>
#include <unistd.h>
#include "log.h"

Sensors * Sensors::me=NULL;
#define ADDRESS 0x04

// The I2C bus: This is for V2 and V3 pi's. For V1 Model B you need i2c-0
static const char *devName = "/dev/i2c-1";

void Sensors::start(unsigned int readinterval, unsigned int postinterval) throw (ThreadCreateException){
	if (Sensors::me==NULL) {
		Sensors::me=new Sensors(readinterval,postinterval);
		Sensors::me->running=true;
		if(pthread_create(Sensors::me->thread, NULL, Sensors::run, Sensors::me)) {
			Log::logger->log("SENSORS",ERROR) << "Can't create sensors thread " << strerror (errno) << endl;
			throw ThreadCreateException();
		}
	}
}

void Sensors::stop() {
	Sensors::me->running=false;
	pthread_join(*(Sensors::me->thread), NULL);
	delete Sensors::me;
	Sensors::me=NULL;
}

void * Sensors::run(void * sensors) {
	Sensors * me=(Sensors *) sensors;
	unsigned int postloop=me->postinterval/me->readinterval;
	unsigned int loop=0;
	while (me->running) {
		sleep(me->readinterval);
		if (me->readSensors()) {
			loop++;
			if (loop>postloop) {
				for (std::map<string, double>::iterator it=me->value.begin();it!=me->value.end(); it++) {
					me->lastavg[it->first]=it->second/loop;
					me->value[it->first]=0;
				}
				try {
					SensorsBank::sendData(me->lastavg);
				} catch(CurlInitException &e) {
				} catch(PostException &e) {
				}
				loop=0;
			}
		}
	}
	return NULL;
}

Sensors::Sensors(unsigned int readinterval, unsigned int postinterval) {
	this->readinterval=readinterval;
	this->postinterval=postinterval;
	this->thread= (pthread_t *) malloc(sizeof(pthread_t));
	this->value["Temperature"]=0;
	this->value["Humidity"]=0;
	this->value["MQ-2"]=0;
	this->value["MQ-4"]=0;
	this->value["MQ-5"]=0;
	this->value["MQ-6"]=0;
	this->value["MQ-7"]=0;
	this->value["MQ-135"]=0;
	this->lastavg["Temperature"]=0;
	this->lastavg["Humidity"]=0;
	this->lastavg["MQ-2"]=0;
	this->lastavg["MQ-4"]=0;
	this->lastavg["MQ-5"]=0;
	this->lastavg["MQ-6"]=0;
	this->lastavg["MQ-7"]=0;
	this->lastavg["MQ-135"]=0;

}

Sensors::~Sensors() {
	free(this->thread);
}

bool Sensors::readSensors() {
	int file;
	if ((file = open(devName, O_RDWR)) < 0) {
    	Log::logger->log("SENSORS",ERROR) << "Failed to access I2C device " << devName << endl;
    	return false;
	}

	Log::logger->log("SENSORS",DEBUG) << "I2C: acquiring buss to 0x" << ADDRESS << endl;
 	if (ioctl(file, I2C_SLAVE, ADDRESS) < 0) {
    	Log::logger->log("SENSORS",ERROR) << "I2C: Failed to acquire bus access/talk to slave 0x" << ADDRESS << endl;
    	close(file);
		return false;
	}
 	unsigned char cmd[1];
 	bool result=true;
    cmd[0] = 0;
    if (write(file, cmd, 1) == 1) {
		usleep(10000);
		char buf[16];
		if (read(file, buf, 16) == 16) {
			double data[8];
			data[0] = ((double) (buf[0]+ (255*buf[1])))/10;
	    	data[1] = ((double) (buf[2]+ (255*buf[3])))/10;
	        data[2] = ((double) (buf[4]+ (255*buf[5])))/10;
	        data[3] = ((double) (buf[6]+ (255*buf[7])))/10;
	        data[4] = ((double) (buf[8]+ (255*buf[9])))/10;
	        data[5] = ((double) (buf[10]+ (255*buf[11])))/10;
	        data[6] = ((double) (buf[12]+ (255*buf[13])))/10;
	        data[7] = ((double) (buf[14] + (255*buf[15])))/10;
	        this->value["Humidity"]		+= data[0];
	    	this->value["Temperature"]	+= data[1];
	        this->value["MQ-2"] 		+= data[2];
	        this->value["MQ-4"]		 	+= data[3];
	        this->value["MQ-5"]			+= data[4];
	        this->value["MQ-6"]			+= data[5];
	        this->value["MQ-7"]			+= data[6];
	        this->value["MQ-135"]		+= data[7];

	        if (data[1] >60) {
	        	Log::logger->log("SENSORS",DEBUG) << "Sensors Error Raw Data : ";
	        	for (int i=0;i<16;i++) Log::logger->log("SENSORS",DEBUG) << buf[i] <<" \t";
	        	Log::logger->log("SENSORS",DEBUG) << endl;
	        	Log::logger->log("SENSORS",DEBUG) << "Sensors Error Data : ";
	        	for (int i=0;i<8;i++) Log::logger->log("SENSORS",DEBUG) << data[i] <<" \t";
	        	Log::logger->log("SENSORS",DEBUG) << endl;
	        }
		} else {
			result=false;
		}
	} else {
		result=false;
	}
	close(file);
	return result;
}
<|endoftext|>


<commit_before>// main window and event handling for X11

#include <stdio.h>
#include <stdarg.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <GL/glx.h>

#include "drawstuff/drawstuff.h"
#include "drawstuff/version.h"
#include "internal.h"

//***************************************************************************
// error handling for unix

static void printMessage (char *msg1, char *msg2, va_list ap)
{
  fflush (stderr);
  fflush (stdout);
  fprintf (stderr,"\n%s: ",msg1);
  vfprintf (stderr,msg2,ap);
  fprintf (stderr,"\n");
  fflush (stderr);
}

extern "C" void dsError (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  printMessage ("Error",msg,ap);
  exit (1);
}

extern "C" void dsDebug (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  printMessage ("INTERNAL ERROR",msg,ap);
  // *((char *)0) = 0;	 ... commit SEGVicide ?
  abort();
}

extern "C" void dsPrint (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  vprintf (msg,ap);
}

//***************************************************************************
// openGL window

// X11 display info
static Display *display=0;
static int screen=0;
static XVisualInfo *visual=0;		// best visual for openGL
static Colormap colormap=0;		// window's colormap
static Atom wm_protocols_atom = 0;
static Atom wm_delete_window_atom = 0;

// window and openGL
static Window win=0;			// X11 window, 0 if not initialized
static int width=0,height=0;		// window size
static GLXContext glx_context=0;	// openGL rendering context
static int last_key_pressed=0;		// last key pressed in the window
static int run=1;			// 1 if simulation running
static int pause=0;			// 1 if in `pause' mode
static int singlestep=0;		// 1 if single step key pressed

static void createMainWindow (int _width, int _height)
{
  // create X11 display connection
  display = XOpenDisplay (0);
  if (!display) dsError (0,"can not open X11 display");
  screen = DefaultScreen(display);

  // get GL visual
  static int attribList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE,16,
			     GLX_RED_SIZE,4, GLX_GREEN_SIZE,4,
			     GLX_BLUE_SIZE,4, None};
  visual = glXChooseVisual (display,screen,attribList);
  if (!visual) dsError ("no good X11 visual found for OpenGL");

  // create colormap
  colormap = XCreateColormap (display,RootWindow(display,screen),
			      visual->visual,AllocNone);

  // initialize variables
  win = 0;
  width = _width;
  height = _height;
  glx_context = 0;
  last_key_pressed = 0;

  if (width < 1 || height < 1) dsDebug (0,"bad window width or height");

  // create the window
  XSetWindowAttributes attributes;
  attributes.background_pixel = BlackPixel(display,screen);
  attributes.colormap = colormap;
  attributes.event_mask = ButtonPressMask | ButtonReleaseMask |
    KeyPressMask | KeyReleaseMask | ButtonMotionMask | PointerMotionHintMask |
    StructureNotifyMask;
  win = XCreateWindow (display,RootWindow(display,screen),50,50,width,height,
		       0,visual->depth, InputOutput,visual->visual,
		       CWBackPixel | CWColormap | CWEventMask,&attributes);

  // associate a GLX context with the window
  glx_context = glXCreateContext (display,visual,0,GL_TRUE);
  if (!glx_context) dsError ("can't make an OpenGL context");

  // set the window title
  XTextProperty window_name;
  window_name.value = (unsigned char *) "Simulation";
  window_name.encoding = XA_STRING;
  window_name.format = 8;
  window_name.nitems = strlen((char *) window_name.value);
  XSetWMName (display,win,&window_name);

  // participate in the window manager 'delete yourself' protocol
  wm_protocols_atom = XInternAtom (display,"WM_PROTOCOLS",False);
  wm_delete_window_atom = XInternAtom (display,"WM_DELETE_WINDOW",False);
  if (XSetWMProtocols (display,win,&wm_delete_window_atom,1)==0)
    dsError ("XSetWMProtocols() call failed");

  // pop up the window
  XMapWindow (display,win);
  XSync (display,win);
}

static void destroyMainWindow()
{
  glXDestroyContext (display,glx_context);
  XDestroyWindow (display,win);
  XSync (display,0);
  display = 0;
  win = 0;
  glx_context = 0;
}

static void handleEvent (XEvent &event, dsFunctions *fn)
{
  static int mx=0,my=0; 	// mouse position
  static int mode = 0;		// mouse button bits

  switch (event.type) {

  case ButtonPress: {
    if (event.xbutton.button == Button1) mode |= 1;
    if (event.xbutton.button == Button2) mode |= 2;
    if (event.xbutton.button == Button3) mode |= 4;
    mx = event.xbutton.x;
    my = event.xbutton.y;
  }
  return;

  case ButtonRelease: {
    if (event.xbutton.button == Button1) mode &= (~1);
    if (event.xbutton.button == Button2) mode &= (~2);
    if (event.xbutton.button == Button3) mode &= (~4);
    mx = event.xbutton.x;
    my = event.xbutton.x;
  }
  return;

  case MotionNotify: {
    if (event.xmotion.is_hint) {
      Window root,child;
      unsigned int mask;
      XQueryPointer (display,win,&root,&child,&event.xbutton.x_root,
		     &event.xbutton.y_root,&event.xbutton.x,&event.xbutton.y,
		     &mask);
    }
    dsMotion (mode, event.xmotion.x - mx, event.xmotion.y - my);
    mx = event.xmotion.x;
    my = event.xmotion.y;
  }
  return;

  case KeyPress: {
    KeySym key;
    XLookupString (&event.xkey,NULL,0,&key,0);
    if ( (event.xkey.state & (ShiftMask | ControlMask)) == 0) {
      if (key >= ' ' && key <= 126) fn->command (key);
    }
    else if (event.xkey.state & ControlMask) {
      switch (key) {
      case 't': case 'T':
	dsSetTextures (dsGetTextures() ^ 1);
	break;
      case 's': case 'S':
	dsSetShadows (dsGetShadows() ^ 1);
	break;
      case 'x': case 'X':
	run = 0;
	break;
      case 'p': case 'P':
	pause ^= 1;
	singlestep = 0;
	break;
      case 'o': case 'O':
	if (pause) singlestep = 1;
	break;
      }
    }
    last_key_pressed = key;		// a kludgy place to put this...
  }
  return;

  case KeyRelease: {
    // hmmmm...
  }
  return;

  case ClientMessage:
    if (event.xclient.message_type == wm_protocols_atom &&
	event.xclient.format == 32 &&
	Atom(event.xclient.data.l[0]) == wm_delete_window_atom) {
      run = 0;
      return;
    }
    return;

  case ConfigureNotify:
    width = event.xconfigure.width;
    height = event.xconfigure.height;
    return;
  }
}

void dsPlatformSimLoop (int window_width, int window_height, dsFunctions *fn)
{
  createMainWindow (window_width, window_height);
  glXMakeCurrent (display,win,glx_context);

  dsStartGraphics (window_width,window_height,fn);
  if (fn->start) fn->start();

  fprintf (stderr,
	   "\n"
	   "Simulation test environment v%d.%02d\n"
	   "   Ctrl-P : pause / unpause.\n"
	   "   Ctrl-O : single step when paused.\n"
	   "   Ctrl-T : toggle textures (or say `-notex' on command line).\n"
	   "   Ctrl-S : toggle shadows (or say `-noshadow' on command line).\n"
	   "   Ctrl-X : exit.\n"
	   "\n",DS_VERSION >> 8,DS_VERSION & 0xff);

  run = 1;
  while (run) {
    // read in and process all pending events for the main window
    XEvent event;
    while (run && XPending (display)) {
      XNextEvent (display,&event);
      handleEvent (event,fn);
    }

    dsDrawFrame (width,height,fn,pause && !singlestep);
    singlestep = 0;

    glFlush();
    glXSwapBuffers (display,win);
    XSync (display,0);
  };

  if (fn->stop) fn->stop();
  dsStopGraphics();

  destroyMainWindow();
}
<commit_msg>viewport printing.<commit_after>// main window and event handling for X11

#include <stdio.h>
#include <stdarg.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <GL/glx.h>

#include "drawstuff/drawstuff.h"
#include "drawstuff/version.h"
#include "internal.h"

//***************************************************************************
// error handling for unix

static void printMessage (char *msg1, char *msg2, va_list ap)
{
  fflush (stderr);
  fflush (stdout);
  fprintf (stderr,"\n%s: ",msg1);
  vfprintf (stderr,msg2,ap);
  fprintf (stderr,"\n");
  fflush (stderr);
}

extern "C" void dsError (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  printMessage ("Error",msg,ap);
  exit (1);
}

extern "C" void dsDebug (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  printMessage ("INTERNAL ERROR",msg,ap);
  // *((char *)0) = 0;	 ... commit SEGVicide ?
  abort();
}

extern "C" void dsPrint (char *msg, ...)
{
  va_list ap;
  va_start (ap,msg);
  vprintf (msg,ap);
}

//***************************************************************************
// openGL window

// X11 display info
static Display *display=0;
static int screen=0;
static XVisualInfo *visual=0;		// best visual for openGL
static Colormap colormap=0;		// window's colormap
static Atom wm_protocols_atom = 0;
static Atom wm_delete_window_atom = 0;

// window and openGL
static Window win=0;			// X11 window, 0 if not initialized
static int width=0,height=0;		// window size
static GLXContext glx_context=0;	// openGL rendering context
static int last_key_pressed=0;		// last key pressed in the window
static int run=1;			// 1 if simulation running
static int pause=0;			// 1 if in `pause' mode
static int singlestep=0;		// 1 if single step key pressed

static void createMainWindow (int _width, int _height)
{
  // create X11 display connection
  display = XOpenDisplay (0);
  if (!display) dsError (0,"can not open X11 display");
  screen = DefaultScreen(display);

  // get GL visual
  static int attribList[] = {GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE,16,
			     GLX_RED_SIZE,4, GLX_GREEN_SIZE,4,
			     GLX_BLUE_SIZE,4, None};
  visual = glXChooseVisual (display,screen,attribList);
  if (!visual) dsError ("no good X11 visual found for OpenGL");

  // create colormap
  colormap = XCreateColormap (display,RootWindow(display,screen),
			      visual->visual,AllocNone);

  // initialize variables
  win = 0;
  width = _width;
  height = _height;
  glx_context = 0;
  last_key_pressed = 0;

  if (width < 1 || height < 1) dsDebug (0,"bad window width or height");

  // create the window
  XSetWindowAttributes attributes;
  attributes.background_pixel = BlackPixel(display,screen);
  attributes.colormap = colormap;
  attributes.event_mask = ButtonPressMask | ButtonReleaseMask |
    KeyPressMask | KeyReleaseMask | ButtonMotionMask | PointerMotionHintMask |
    StructureNotifyMask;
  win = XCreateWindow (display,RootWindow(display,screen),50,50,width,height,
		       0,visual->depth, InputOutput,visual->visual,
		       CWBackPixel | CWColormap | CWEventMask,&attributes);

  // associate a GLX context with the window
  glx_context = glXCreateContext (display,visual,0,GL_TRUE);
  if (!glx_context) dsError ("can't make an OpenGL context");

  // set the window title
  XTextProperty window_name;
  window_name.value = (unsigned char *) "Simulation";
  window_name.encoding = XA_STRING;
  window_name.format = 8;
  window_name.nitems = strlen((char *) window_name.value);
  XSetWMName (display,win,&window_name);

  // participate in the window manager 'delete yourself' protocol
  wm_protocols_atom = XInternAtom (display,"WM_PROTOCOLS",False);
  wm_delete_window_atom = XInternAtom (display,"WM_DELETE_WINDOW",False);
  if (XSetWMProtocols (display,win,&wm_delete_window_atom,1)==0)
    dsError ("XSetWMProtocols() call failed");

  // pop up the window
  XMapWindow (display,win);
  XSync (display,win);
}

static void destroyMainWindow()
{
  glXDestroyContext (display,glx_context);
  XDestroyWindow (display,win);
  XSync (display,0);
  display = 0;
  win = 0;
  glx_context = 0;
}

static void handleEvent (XEvent &event, dsFunctions *fn)
{
  static int mx=0,my=0; 	// mouse position
  static int mode = 0;		// mouse button bits

  switch (event.type) {

  case ButtonPress: {
    if (event.xbutton.button == Button1) mode |= 1;
    if (event.xbutton.button == Button2) mode |= 2;
    if (event.xbutton.button == Button3) mode |= 4;
    mx = event.xbutton.x;
    my = event.xbutton.y;
  }
  return;

  case ButtonRelease: {
    if (event.xbutton.button == Button1) mode &= (~1);
    if (event.xbutton.button == Button2) mode &= (~2);
    if (event.xbutton.button == Button3) mode &= (~4);
    mx = event.xbutton.x;
    my = event.xbutton.x;
  }
  return;

  case MotionNotify: {
    if (event.xmotion.is_hint) {
      Window root,child;
      unsigned int mask;
      XQueryPointer (display,win,&root,&child,&event.xbutton.x_root,
		     &event.xbutton.y_root,&event.xbutton.x,&event.xbutton.y,
		     &mask);
    }
    dsMotion (mode, event.xmotion.x - mx, event.xmotion.y - my);
    mx = event.xmotion.x;
    my = event.xmotion.y;
  }
  return;

  case KeyPress: {
    KeySym key;
    XLookupString (&event.xkey,NULL,0,&key,0);
    if ( (event.xkey.state & (ShiftMask | ControlMask)) == 0) {
      if (key >= ' ' && key <= 126) fn->command (key);
    }
    else if (event.xkey.state & ControlMask) {
      switch (key) {
      case 't': case 'T':
	dsSetTextures (dsGetTextures() ^ 1);
	break;
      case 's': case 'S':
	dsSetShadows (dsGetShadows() ^ 1);
	break;
      case 'x': case 'X':
	run = 0;
	break;
      case 'p': case 'P':
	pause ^= 1;
	singlestep = 0;
	break;
      case 'o': case 'O':
	if (pause) singlestep = 1;
	break;
      case 'v': case 'V': {
	float xyz[3],hpr[3];
	dsGetViewpoint (xyz,hpr);
	printf ("Viewpoint = (%.4f,%.4f,%.4f,%.4f,%.4f,%.4f)\n",
		xyz[0],xyz[1],xyz[2],hpr[0],hpr[1],hpr[2]);
	break;
      }
      }
    }
    last_key_pressed = key;		// a kludgy place to put this...
  }
  return;

  case KeyRelease: {
    // hmmmm...
  }
  return;

  case ClientMessage:
    if (event.xclient.message_type == wm_protocols_atom &&
	event.xclient.format == 32 &&
	Atom(event.xclient.data.l[0]) == wm_delete_window_atom) {
      run = 0;
      return;
    }
    return;

  case ConfigureNotify:
    width = event.xconfigure.width;
    height = event.xconfigure.height;
    return;
  }
}

void dsPlatformSimLoop (int window_width, int window_height, dsFunctions *fn)
{
  createMainWindow (window_width, window_height);
  glXMakeCurrent (display,win,glx_context);

  dsStartGraphics (window_width,window_height,fn);
  if (fn->start) fn->start();

  fprintf (stderr,
	   "\n"
	   "Simulation test environment v%d.%02d\n"
	   "   Ctrl-P : pause / unpause.\n"
	   "   Ctrl-O : single step when paused.\n"
	   "   Ctrl-T : toggle textures (or say `-notex' on command line).\n"
	   "   Ctrl-S : toggle shadows (or say `-noshadow' on command line).\n"
	   "   Ctrl-V : print current viewpoint coordinates (x,y,z,h,p,r).\n"
	   "   Ctrl-X : exit.\n"
	   "\n",DS_VERSION >> 8,DS_VERSION & 0xff);

  run = 1;
  while (run) {
    // read in and process all pending events for the main window
    XEvent event;
    while (run && XPending (display)) {
      XNextEvent (display,&event);
      handleEvent (event,fn);
    }

    dsDrawFrame (width,height,fn,pause && !singlestep);
    singlestep = 0;

    glFlush();
    glXSwapBuffers (display,win);
    XSync (display,0);
  };

  if (fn->stop) fn->stop();
  dsStopGraphics();

  destroyMainWindow();
}
<|endoftext|>