<commit_before>//******************************************************************************
///
/// @file base/image/ppm.cpp
///
/// Implementation of Netpbm Portable Pixmap/Graymap (PPM/PGM) image file
/// handling.
///
/// This module contains the code to read and write the PPM and PGM file formats
/// according to Netpbm specs (http://netpbm.sourceforge.net/doc/):
///
/// For input, both ASCII ("plain") and binary ("raw") formats (magic numbers
/// `P2`/`P3` and `P5`/`P6`, respectively), are supported.
///
/// For outout we write binary ("raw") PPM files (magic number `P6`), unless
/// `Greyscale_Output=on` is specified in which case we write binary PGM files
/// (magic number `P5`). Maxvalue is set to 255 if a bit depth of 8 or lower
/// is chosen, or 65535 otherwise.
///
/// @copyright
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd.
///
/// POV-Ray 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.
///
/// POV-Ray 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/>.
///
/// ----------------------------------------------------------------------------
///
/// POV-Ray is based on the popular DKB raytracer version 2.12.
/// DKBTrace was originally written by David K. Buck.
/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
///
/// @endparblock
///
//******************************************************************************

// Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
#include "base/image/ppm.h"

// C++ variants of standard C header files
#include <cctype>

// Standard C++ header files
#include <vector>

// POV-Ray base header files
#include "base/types.h"
#include "base/image/metadata.h"

// this must be the last file included
#include "base/povdebug.h"

namespace pov_base
{

namespace Netpbm
{

enum NetpbmDataFormat
{
    kNetpbmDataFormat_ASCII,
    kNetpbmDataFormat_8bit,
    kNetpbmDataFormat_16bit,
};

/*****************************************************************************/

void Write (OStream *file, const Image *image, const Image::WriteOptions& options)
{
    int                 file_type = POV_File_Image_PPM;
    int                 width = image->GetWidth() ;
    int                 height = image->GetHeight() ;
    int                 bpcc = options.bpcc;
    bool                grayscale = false;
    unsigned int        rval;
    unsigned int        gval;
    unsigned int        bval;
    unsigned int        gray;
    unsigned int        mask;
    GammaCurvePtr       gamma;
    DitherHandler*      dither = options.dither.get();

    if (bpcc == 0)
        bpcc = image->GetMaxIntValue() == 65535 ? 16 : 8 ;
    else if (bpcc < 5)
        bpcc = 5 ;
    else if (bpcc > 16)
        bpcc = 16 ;

    mask = (1 << bpcc) - 1 ;

    // do we want 16 bit grayscale (PGM) output ?
    // TODO - the check for image container type is here to mimick old code; do we still need it?
    if (image->GetImageDataType () == Image::Gray_Int16 || image->GetImageDataType () == Image::GrayA_Int16 || options.grayscale)
    {
        grayscale   = true;
        bpcc        = 16;
        gamma.reset(); // TODO - this is here to mimick old code, which never did gamma correction for greyscale output; do we want to change that?
        file->printf("P5\n");
    }
    else
    {
        if (options.encodingGamma)
            gamma = TranscodingGammaCurve::Get(options.workingGamma, options.encodingGamma);
        else
            // PPM files may or may not be gamma-encoded; besides the sRGB transfer function, the ITU-R-BT.709 transfer function is said to be common as well.
            // If no encoding gamma is specified, we're defaulting to working gamma space at present, i.e. no gamma correction.
            gamma = NeutralGammaCurve::Get();
#ifndef ASCII_PPM_OUTPUT
        file->printf("P6\n");
#else
        file->printf("P3\n");
#endif
    }

    // Prepare metadata, as comment in the header
    Metadata meta;
    file->printf("# Software: %s\n", meta.getSoftware().c_str());
    file->printf("# Render Date: %s\n" ,meta.getDateTime().c_str());
    if (!meta.getComment1().empty())
        file->printf("# %s\n", meta.getComment1().c_str());
    if (!meta.getComment2().empty())
        file->printf("# %s\n", meta.getComment2().c_str());
    if (!meta.getComment3().empty())
        file->printf("# %s\n", meta.getComment3().c_str());
    if (!meta.getComment4().empty())
        file->printf("# %s\n", meta.getComment4().c_str());
    file->printf("%d %d\n%d\n", width, height, mask);

    for (int y = 0 ; y < height ; y++)
    {
        for (int x = 0; x < width; x++)
        {
            if (grayscale)
            {
                gray = GetEncodedGrayValue (image, x, y, gamma, mask, *dither) ;

                if (bpcc > 8)
                {
                    if (!file->Write_Byte((gray >> 8) & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PGM output data");
                    if (!file->Write_Byte(gray & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PGM output data");
                }
                else
                {
                    if (!file->Write_Byte(gray & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PGM output data");
                }
            }
            else
            {
                GetEncodedRGBValue (image, x, y, gamma, mask, rval, gval, bval, *dither) ;

                if (bpcc > 8)
                {
                    // 16 bit per value
#ifndef ASCII_PPM_OUTPUT
                    file->Write_Byte(rval >> 8) ;
                    file->Write_Byte(rval & 0xFF) ;
                    file->Write_Byte(gval >> 8) ;
                    file->Write_Byte(gval & 0xFF) ;
                    file->Write_Byte(bval >> 8) ;
                    if (!file->Write_Byte(bval & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PPM output data");
#else
                    file->printf("%u ", rval);
                    file->printf("%u ", gval);
                    file->printf("%u\n", bval);
                    if (!file)
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PPM output data");
#endif
                }
                else
                {
                    // 8 bit per value
#ifndef ASCII_PPM_OUTPUT
                    file->Write_Byte(rval & 0xFF) ;
                    file->Write_Byte(gval & 0xFF) ;
                    if (!file->Write_Byte(bval & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PPM output data");
#else
                    file->printf("%u ", rval & 0xff);
                    file->printf("%u ", gval & 0xff);
                    file->printf("%u\n", bval & 0xff);
                    if (!file)
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PPM output data");
#endif
                }
            }
        }
    }
}

/*****************************************************************************/

/// Read an individual character from a Netpbm file, potentially skipping comments.
inline static int ReadNetpbmAsciiChar (IStream *file, bool allowComments)
{
    int c = file->Read_Byte();

    if (allowComments && (c == '#'))
    {
        do
        {
            c = file->Read_Byte();
        }
        while ((c != '\n') && (c != EOF));
    }

    return c;
}

/// Read an plain ASCII numeric value from a Netpbm file, potentially skipping comments.
static POV_UINT32 ReadNetpbmAsciiValue (IStream *file, bool allowComments)
{
    POV_UINT32 value = 0;
    int c;
    int pos = 0;
    char buffer[50] = "";

    do
    {
        c = ReadNetpbmAsciiChar (file, allowComments);
        // TODO - we may want to warn in case we just encountered a CR.
    }
    while (isspace (c));

    if (!isdigit (c))
        throw POV_EXCEPTION(kFileDataErr, "Invalid data in Netpbm (PGM/PPM) file");

    do
    {
        POV_UINT32 oldValue = value;
        value = value * 10 + (c-'0');
        if (value < oldValue)
            // numeric overflow occurred
            throw POV_EXCEPTION(kFileDataErr, "Excessively large value in Netpbm (PGM/PPM) file");
        c = ReadNetpbmAsciiChar (file, allowComments);
    }
    while (isdigit(c));

    if ((c != EOF) && (!isspace (c)))
        throw POV_EXCEPTION(kFileDataErr, "Invalid data in Netpbm (PGM/PPM) file");

    // TODO - we may want to warn in case we just encountered a CR.

    return value;
}

/// Read an individual raster value from a Netpbm file.
inline static POV_UINT16 ReadNetpbmRasterValue (IStream *file, NetpbmDataFormat format)
{
    if (format == kNetpbmDataFormat_ASCII)
        return ReadNetpbmAsciiValue (file, false);

    int hi, lo;

    if (format == kNetpbmDataFormat_16bit)
    {
        hi = file->Read_Byte();
        if (hi == EOF)
            throw POV_EXCEPTION(kFileDataErr, "Unexpected end of file in Netpbm (PGM/PPM) file");
    }
    else
        hi = 0;

    lo = file->Read_Byte();
    if (lo == EOF)
        throw POV_EXCEPTION(kFileDataErr, "Unexpected end of file in Netpbm (PGM/PPM) file");

    return (POV_UINT16(hi) << 8) + POV_UINT16(lo);
}

/*****************************************************************************/

// TODO: make sure we destroy the image if we throw an exception
Image *Read (IStream *file, const Image::ReadOptions& options)
{
    POV_UINT32          width;
    POV_UINT32          height;
    POV_UINT32          maxval;
    Image               *image = NULL;
    unsigned char       magicNumber[2];

    bool                isMonochrome;
    bool                isAsciiData;
    bool                is16BitData;
    NetpbmDataFormat    dataFormat;
    POV_UINT16          maxImageVal;
    POV_UINT16          r,g,b;

    // PGM files may or may not be gamma-encoded.
    GammaCurvePtr gamma;
    if (options.gammacorrect && options.defaultGamma)
        gamma = TranscodingGammaCurve::Get(options.workingGamma, options.defaultGamma);

    // --- Read Header ---
    if (!file->read(magicNumber, 2))
        throw POV_EXCEPTION(kFileDataErr, "Failed to read Netpbm (PGM/PPM) magic number");

    if (magicNumber[0] != 'P')
        throw POV_EXCEPTION(kFileDataErr, "File is not a supported Netpbm (PGM/PPM) file");

    switch (magicNumber[1])
    {
        case '2': // "plain" (ASCII) Portable Gray Map (PGM)
            isMonochrome = true;
            isAsciiData  = true;
            break;

        case '3': // "plain" (ASCII) Portable Pixel Map (PPM)
            isMonochrome = false;
            isAsciiData  = true;
            break;

        case '5': // "raw" (binary) Portable Gray Map (PGM)
            isMonochrome = true;
            isAsciiData  = false;
            break;

        case '6': // "raw" (binary) Portable Pixel Map (PPM)
            isMonochrome = false;
            isAsciiData  = false;
            break;

        case '1': // "plain" (ASCII) Portable Bit Map (PBM)
        case '4': // "raw" (binary) Portable Bit Map (PBM)
        case '7': // Portable Arbitrary Map (PAM)
        default:
            throw POV_EXCEPTION(kFileDataErr, "File is not a supported Netbpm (PGM/PPM) file");
            break;
    }

    width  = ReadNetpbmAsciiValue (file, true);
    height = ReadNetpbmAsciiValue (file, true);
    maxval = ReadNetpbmAsciiValue (file, true);

    if ((maxval > 65535) || (maxval < 1))
        throw POV_EXCEPTION(kFileDataErr, "Unsupported number of brightness levels in Netpbm (PGM/PPM) file");

    is16BitData = (maxval > 255);

    dataFormat  = (isAsciiData ? kNetpbmDataFormat_ASCII : (is16BitData ? kNetpbmDataFormat_16bit : kNetpbmDataFormat_8bit));
    maxImageVal = (is16BitData ? 65535 : 255);

    // We'll be using an image container that provides for automatic decoding if possible - unless there's no such decoding to do.
    gamma = ScaledGammaCurve::GetByDecoding(float(maxImageVal)/float(maxval), gamma); // Note that we'll apply the scaling even if we don't officially gamma-correct
    Image::ImageDataType imagetype = options.itype;
    if (imagetype == Image::Undefined)
        imagetype = Image::GetImageDataType( GammaCurve::IsNeutral(gamma) ? (is16BitData ? Image::kImageChannelDataType_Int16
                                                                                : Image::kImageChannelDataType_Int8)
                                                                          : (is16BitData ? Image::kImageChannelDataType_Gamma16
                                                                                : Image::kImageChannelDataType_Gamma8),
                                             isMonochrome ? Image::kImageChannelLayout_Gray
                                                          : Image::kImageChannelLayout_RGB );
    image = Image::Create (width, height, imagetype) ;
    // NB: PGM files don't use alpha, so premultiplied vs. non-premultiplied is not an issue
    image->TryDeferDecoding(gamma, maxImageVal); // try to have gamma adjustment being deferred until image evaluation.

    for (int i = 0; i < height; i++)
    {
        for (int x = 0; x < width; x++)
        {
            if (isMonochrome)
            {
                g = ReadNetpbmRasterValue (file, dataFormat);
                SetEncodedGrayValue (image, x, i, gamma, maxImageVal, g);
            }
            else
            {
                r = ReadNetpbmRasterValue (file, dataFormat);
                g = ReadNetpbmRasterValue (file, dataFormat);
                b = ReadNetpbmRasterValue (file, dataFormat);
                SetEncodedRGBValue (image, x, i, gamma, maxImageVal, r,g,b);
            }
        }
    }

    // TODO - we may want to warn in case we haven't reached the end of file yet.

    return image;
}

} // end of namespace Netpbm

}

<commit_msg>Hopefully fix Unix build error introduced with commit be34de4.<commit_after>//******************************************************************************
///
/// @file base/image/ppm.cpp
///
/// Implementation of Netpbm Portable Pixmap/Graymap (PPM/PGM) image file
/// handling.
///
/// This module contains the code to read and write the PPM and PGM file formats
/// according to Netpbm specs (http://netpbm.sourceforge.net/doc/):
///
/// For input, both ASCII ("plain") and binary ("raw") formats (magic numbers
/// `P2`/`P3` and `P5`/`P6`, respectively), are supported.
///
/// For outout we write binary ("raw") PPM files (magic number `P6`), unless
/// `Greyscale_Output=on` is specified in which case we write binary PGM files
/// (magic number `P5`). Maxvalue is set to 255 if a bit depth of 8 or lower
/// is chosen, or 65535 otherwise.
///
/// @copyright
/// @parblock
///
/// Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
/// Copyright 1991-2016 Persistence of Vision Raytracer Pty. Ltd.
///
/// POV-Ray 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.
///
/// POV-Ray 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/>.
///
/// ----------------------------------------------------------------------------
///
/// POV-Ray is based on the popular DKB raytracer version 2.12.
/// DKBTrace was originally written by David K. Buck.
/// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
///
/// @endparblock
///
//******************************************************************************

// Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
#include "base/image/ppm.h"

// C++ variants of standard C header files
#include <cctype>

// Standard C++ header files
#include <vector>

// POV-Ray base header files
#include "base/types.h"
#include "base/image/metadata.h"

// this must be the last file included
#include "base/povdebug.h"

namespace pov_base
{

namespace Netpbm
{

enum NetpbmDataFormat
{
    kNetpbmDataFormat_ASCII,
    kNetpbmDataFormat_8bit,
    kNetpbmDataFormat_16bit,
};

/*****************************************************************************/

void Write (OStream *file, const Image *image, const Image::WriteOptions& options)
{
    int                 file_type = POV_File_Image_PPM;
    int                 width = image->GetWidth() ;
    int                 height = image->GetHeight() ;
    int                 bpcc = options.bpcc;
    bool                grayscale = false;
    unsigned int        rval;
    unsigned int        gval;
    unsigned int        bval;
    unsigned int        gray;
    unsigned int        mask;
    GammaCurvePtr       gamma;
    DitherHandler*      dither = options.dither.get();

    if (bpcc == 0)
        bpcc = image->GetMaxIntValue() == 65535 ? 16 : 8 ;
    else if (bpcc < 5)
        bpcc = 5 ;
    else if (bpcc > 16)
        bpcc = 16 ;

    mask = (1 << bpcc) - 1 ;

    // do we want 16 bit grayscale (PGM) output ?
    // TODO - the check for image container type is here to mimick old code; do we still need it?
    if (image->GetImageDataType () == Image::Gray_Int16 || image->GetImageDataType () == Image::GrayA_Int16 || options.grayscale)
    {
        grayscale   = true;
        bpcc        = 16;
        gamma.reset(); // TODO - this is here to mimick old code, which never did gamma correction for greyscale output; do we want to change that?
        file->printf("P5\n");
    }
    else
    {
        if (options.encodingGamma)
            gamma = TranscodingGammaCurve::Get(options.workingGamma, options.encodingGamma);
        else
            // PPM files may or may not be gamma-encoded; besides the sRGB transfer function, the ITU-R-BT.709 transfer function is said to be common as well.
            // If no encoding gamma is specified, we're defaulting to working gamma space at present, i.e. no gamma correction.
            gamma = NeutralGammaCurve::Get();
#ifndef ASCII_PPM_OUTPUT
        file->printf("P6\n");
#else
        file->printf("P3\n");
#endif
    }

    // Prepare metadata, as comment in the header
    Metadata meta;
    file->printf("# Software: %s\n", meta.getSoftware().c_str());
    file->printf("# Render Date: %s\n" ,meta.getDateTime().c_str());
    if (!meta.getComment1().empty())
        file->printf("# %s\n", meta.getComment1().c_str());
    if (!meta.getComment2().empty())
        file->printf("# %s\n", meta.getComment2().c_str());
    if (!meta.getComment3().empty())
        file->printf("# %s\n", meta.getComment3().c_str());
    if (!meta.getComment4().empty())
        file->printf("# %s\n", meta.getComment4().c_str());
    file->printf("%d %d\n%d\n", width, height, mask);

    for (int y = 0 ; y < height ; y++)
    {
        for (int x = 0; x < width; x++)
        {
            if (grayscale)
            {
                gray = GetEncodedGrayValue (image, x, y, gamma, mask, *dither) ;

                if (bpcc > 8)
                {
                    if (!file->Write_Byte((gray >> 8) & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PGM output data");
                    if (!file->Write_Byte(gray & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PGM output data");
                }
                else
                {
                    if (!file->Write_Byte(gray & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PGM output data");
                }
            }
            else
            {
                GetEncodedRGBValue (image, x, y, gamma, mask, rval, gval, bval, *dither) ;

                if (bpcc > 8)
                {
                    // 16 bit per value
#ifndef ASCII_PPM_OUTPUT
                    file->Write_Byte(rval >> 8) ;
                    file->Write_Byte(rval & 0xFF) ;
                    file->Write_Byte(gval >> 8) ;
                    file->Write_Byte(gval & 0xFF) ;
                    file->Write_Byte(bval >> 8) ;
                    if (!file->Write_Byte(bval & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PPM output data");
#else
                    file->printf("%u ", rval);
                    file->printf("%u ", gval);
                    file->printf("%u\n", bval);
                    if (!file)
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PPM output data");
#endif
                }
                else
                {
                    // 8 bit per value
#ifndef ASCII_PPM_OUTPUT
                    file->Write_Byte(rval & 0xFF) ;
                    file->Write_Byte(gval & 0xFF) ;
                    if (!file->Write_Byte(bval & 0xFF))
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PPM output data");
#else
                    file->printf("%u ", rval & 0xff);
                    file->printf("%u ", gval & 0xff);
                    file->printf("%u\n", bval & 0xff);
                    if (!file)
                        throw POV_EXCEPTION(kFileDataErr, "Cannot write PPM output data");
#endif
                }
            }
        }
    }
}

/*****************************************************************************/

/// Read an individual character from a Netpbm file, potentially skipping comments.
inline static int ReadNetpbmAsciiChar (IStream *file, bool allowComments)
{
    int c = file->Read_Byte();

    if (allowComments && (c == '#'))
    {
        do
        {
            c = file->Read_Byte();
        }
        while ((c != '\n') && (c != EOF));
    }

    return c;
}

/// Read an plain ASCII numeric value from a Netpbm file, potentially skipping comments.
static POV_UINT32 ReadNetpbmAsciiValue (IStream *file, bool allowComments)
{
    POV_UINT32 value = 0;
    int c;
    int pos = 0;
    char buffer[50] = "";

    do
    {
        c = ReadNetpbmAsciiChar (file, allowComments);
        // TODO - we may want to warn in case we just encountered a CR.
    }
    while (isspace (c));

    if (!isdigit (c))
        throw POV_EXCEPTION(kFileDataErr, "Invalid data in Netpbm (PGM/PPM) file");

    do
    {
        POV_UINT32 oldValue = value;
        value = value * 10 + (c-'0');
        if (value < oldValue)
            // numeric overflow occurred
            throw POV_EXCEPTION(kFileDataErr, "Excessively large value in Netpbm (PGM/PPM) file");
        c = ReadNetpbmAsciiChar (file, allowComments);
    }
    while (isdigit(c));

    if ((c != EOF) && (!isspace (c)))
        throw POV_EXCEPTION(kFileDataErr, "Invalid data in Netpbm (PGM/PPM) file");

    // TODO - we may want to warn in case we just encountered a CR.

    return value;
}

/// Read an individual raster value from a Netpbm file.
inline static POV_UINT16 ReadNetpbmRasterValue (IStream *file, NetpbmDataFormat format)
{
    if (format == kNetpbmDataFormat_ASCII)
        return ReadNetpbmAsciiValue (file, false);

    int hi, lo;

    if (format == kNetpbmDataFormat_16bit)
    {
        hi = file->Read_Byte();
        if (hi == EOF)
            throw POV_EXCEPTION(kFileDataErr, "Unexpected end of file in Netpbm (PGM/PPM) file");
    }
    else
        hi = 0;

    lo = file->Read_Byte();
    if (lo == EOF)
        throw POV_EXCEPTION(kFileDataErr, "Unexpected end of file in Netpbm (PGM/PPM) file");

    return (static_cast<POV_UINT16>(hi) << 8) + static_cast<POV_UINT16>(lo);
}

/*****************************************************************************/

// TODO: make sure we destroy the image if we throw an exception
Image *Read (IStream *file, const Image::ReadOptions& options)
{
    POV_UINT32          width;
    POV_UINT32          height;
    POV_UINT32          maxval;
    Image               *image = NULL;
    unsigned char       magicNumber[2];

    bool                isMonochrome;
    bool                isAsciiData;
    bool                is16BitData;
    NetpbmDataFormat    dataFormat;
    POV_UINT16          maxImageVal;
    POV_UINT16          r,g,b;

    // PGM files may or may not be gamma-encoded.
    GammaCurvePtr gamma;
    if (options.gammacorrect && options.defaultGamma)
        gamma = TranscodingGammaCurve::Get(options.workingGamma, options.defaultGamma);

    // --- Read Header ---
    if (!file->read(magicNumber, 2))
        throw POV_EXCEPTION(kFileDataErr, "Failed to read Netpbm (PGM/PPM) magic number");

    if (magicNumber[0] != 'P')
        throw POV_EXCEPTION(kFileDataErr, "File is not a supported Netpbm (PGM/PPM) file");

    switch (magicNumber[1])
    {
        case '2': // "plain" (ASCII) Portable Gray Map (PGM)
            isMonochrome = true;
            isAsciiData  = true;
            break;

        case '3': // "plain" (ASCII) Portable Pixel Map (PPM)
            isMonochrome = false;
            isAsciiData  = true;
            break;

        case '5': // "raw" (binary) Portable Gray Map (PGM)
            isMonochrome = true;
            isAsciiData  = false;
            break;

        case '6': // "raw" (binary) Portable Pixel Map (PPM)
            isMonochrome = false;
            isAsciiData  = false;
            break;

        case '1': // "plain" (ASCII) Portable Bit Map (PBM)
        case '4': // "raw" (binary) Portable Bit Map (PBM)
        case '7': // Portable Arbitrary Map (PAM)
        default:
            throw POV_EXCEPTION(kFileDataErr, "File is not a supported Netbpm (PGM/PPM) file");
            break;
    }

    width  = ReadNetpbmAsciiValue (file, true);
    height = ReadNetpbmAsciiValue (file, true);
    maxval = ReadNetpbmAsciiValue (file, true);

    if ((maxval > 65535) || (maxval < 1))
        throw POV_EXCEPTION(kFileDataErr, "Unsupported number of brightness levels in Netpbm (PGM/PPM) file");

    is16BitData = (maxval > 255);

    dataFormat  = (isAsciiData ? kNetpbmDataFormat_ASCII : (is16BitData ? kNetpbmDataFormat_16bit : kNetpbmDataFormat_8bit));
    maxImageVal = (is16BitData ? 65535 : 255);

    // We'll be using an image container that provides for automatic decoding if possible - unless there's no such decoding to do.
    gamma = ScaledGammaCurve::GetByDecoding(float(maxImageVal)/float(maxval), gamma); // Note that we'll apply the scaling even if we don't officially gamma-correct
    Image::ImageDataType imagetype = options.itype;
    if (imagetype == Image::Undefined)
        imagetype = Image::GetImageDataType( GammaCurve::IsNeutral(gamma) ? (is16BitData ? Image::kImageChannelDataType_Int16
                                                                                : Image::kImageChannelDataType_Int8)
                                                                          : (is16BitData ? Image::kImageChannelDataType_Gamma16
                                                                                : Image::kImageChannelDataType_Gamma8),
                                             isMonochrome ? Image::kImageChannelLayout_Gray
                                                          : Image::kImageChannelLayout_RGB );
    image = Image::Create (width, height, imagetype) ;
    // NB: PGM files don't use alpha, so premultiplied vs. non-premultiplied is not an issue
    image->TryDeferDecoding(gamma, maxImageVal); // try to have gamma adjustment being deferred until image evaluation.

    for (int i = 0; i < height; i++)
    {
        for (int x = 0; x < width; x++)
        {
            if (isMonochrome)
            {
                g = ReadNetpbmRasterValue (file, dataFormat);
                SetEncodedGrayValue (image, x, i, gamma, maxImageVal, g);
            }
            else
            {
                r = ReadNetpbmRasterValue (file, dataFormat);
                g = ReadNetpbmRasterValue (file, dataFormat);
                b = ReadNetpbmRasterValue (file, dataFormat);
                SetEncodedRGBValue (image, x, i, gamma, maxImageVal, r,g,b);
            }
        }
    }

    // TODO - we may want to warn in case we haven't reached the end of file yet.

    return image;
}

} // end of namespace Netpbm

}

<|endoftext|>


<commit_before>#include <iostream>
#include <string.h>
#include <Leap.h>

#include "task_runner.h"

#define SWIPE_THRESHOLD .8
#define CIRCLE_THRESHOLD .4

using namespace Leap;

const std::string fingerNames[] = {"Thumb", "Index", "Middle", "Ring", "Pinky"};
const std::string boneNames[] = {"Metacarpal", "Proximal", "Middle", "Distal"};
const std::string stateNames[] = {"STATE_INVALID", "STATE_START", "STATE_UPDATE", "STATE_STOP"};

class GestureListener : public Listener {
  public:
    // virtual void onInit(const Controller&);
    virtual void onConnect(const Controller&);
    // virtual void onDisconnect(const Controller&);
    // virtual void onExit(const Controller&);
    virtual void onFrame(const Controller&);
    // virtual void onFocusGained(const Controller&);
    // virtual void onFocusLost(const Controller&);
    // virtual void onDeviceChange(const Controller&);
    // virtual void onServiceConnect(const Controller&);
    // virtual void onServiceDisconnect(const Controller&);

  private:
};

void GestureListener::onConnect(const Controller& controller) {
  std::cout << "Connected" << std::endl;
  controller.enableGesture(Gesture::TYPE_CIRCLE);
  controller.enableGesture(Gesture::TYPE_KEY_TAP);
  controller.enableGesture(Gesture::TYPE_SCREEN_TAP);
  controller.enableGesture(Gesture::TYPE_SWIPE);
}

float circle_counter = 0; //how much of a circle has been made
bool doing_gesture = false;
bool doing_circle = false;
bool doing_swipe = false;

void GestureListener::onFrame(const Controller& controller) {
  // Get the most recent frame
  const Frame frame = controller.frame();

  // report some basic information
  // std::cout << "Frame id: " << frame.id()
  //           << ", timestamp: " << frame.timestamp()
  //           << ", hands: " << frame.hands().count()
  //           << ", fingers: " << frame.fingers().count()
  //           << ", tools: " << frame.tools().count()
  //           << ", gestures: " << frame.gestures().count() << std::endl;

  // get hand info
  HandList hands = frame.hands();
  for (HandList::const_iterator hl = hands.begin(); hl != hands.end(); ++hl) {
    // Get the first hand
    const Hand hand = *hl;
    std::string handType = hand.isLeft() ? "Left hand" : "Right hand";
    // std::cout << std::string(2, ' ') << handType << ", id: " << hand.id()
    //           << ", palm position: " << hand.palmPosition() << std::endl;
    // Get the hand's normal vector and direction
    const Vector normal = hand.palmNormal();
    const Vector direction = hand.direction();

    // Calculate the hand's pitch, roll, and yaw angles
    // std::cout << std::string(2, ' ') <<  "pitch: " << direction.pitch() * RAD_TO_DEG << " degrees, "
    //           << "roll: " << normal.roll() * RAD_TO_DEG << " degrees, "
    //           << "yaw: " << direction.yaw() * RAD_TO_DEG << " degrees" << std::endl;

    // Get the Arm bone
    Arm arm = hand.arm();
    // std::cout << std::string(2, ' ') <<  "Arm direction: " << arm.direction()
    //           << " wrist position: " << arm.wristPosition()
    //           << " elbow position: " << arm.elbowPosition() << std::endl;

    // Get fingers
    const FingerList fingers = hand.fingers();
    for (FingerList::const_iterator fl = fingers.begin(); fl != fingers.end(); ++fl) {
      const Finger finger = *fl;
      // std::cout << std::string(4, ' ') <<  fingerNames[finger.type()]
      //           << " finger, id: " << finger.id()
      //           << ", length: " << finger.length()
      //           << "mm, width: " << finger.width() << std::endl;

      // Get finger bones
      for (int b = 0; b < 4; ++b) {
        Bone::Type boneType = static_cast<Bone::Type>(b);
        Bone bone = finger.bone(boneType);
        // std::cout << std::string(6, ' ') <<  boneNames[boneType]
        //           << " bone, start: " << bone.prevJoint()
        //           << ", end: " << bone.nextJoint()
        //           << ", direction: " << bone.direction() << std::endl;
      }
    }
  }

  // Get tools
  const ToolList tools = frame.tools();
  for (ToolList::const_iterator tl = tools.begin(); tl != tools.end(); ++tl) {
    const Tool tool = *tl;
    // std::cout << std::string(2, ' ') <<  "Tool, id: " << tool.id()
    //           << ", position: " << tool.tipPosition()
    //           << ", direction: " << tool.direction() << std::endl;
  }

  // Get gestures
  const GestureList gestures = frame.gestures();

  for (int g = 0; g < gestures.count(); ++g) {
    Gesture gesture = gestures[g];

    switch (gesture.type()) {
      case Gesture::TYPE_CIRCLE:
      {
        CircleGesture circle = gesture;
        std::string clockwiseness;
        bool clockwise = false;

        if (circle.pointable().direction().angleTo(circle.normal()) <= PI/2) {
          clockwiseness = "clockwise";
          clockwise = true;
        } else {
          clockwiseness = "counterclockwise";
          clockwise = false;
        }

        if(circle.state() == Gesture::STATE_START && !doing_gesture){
          doing_gesture = true;
          doing_circle = true;
        }
        // Calculate angle swept since last frame
        float sweptAngle = 0;
        if (circle.state() != Gesture::STATE_START && doing_circle) {
          CircleGesture previousUpdate = CircleGesture(controller.frame(1).gesture(circle.id()));
          sweptAngle = (circle.progress() - previousUpdate.progress()) * 2 * PI;
          circle_counter += sweptAngle;

          if(circle_counter >= CIRCLE_THRESHOLD){
            circle_counter = 0;
            circle_action(clockwise);
            std::cout << "scroll" << std::endl;
          }

          std::cout << std::string(2, ' ')
                  << "Circle id: " << gesture.id()
                  << ", state: " << stateNames[gesture.state()]
                  << ", progress: " << circle.progress()
                  << ", radius: " << circle.radius()
                  << ", angle " << sweptAngle * RAD_TO_DEG
                  <<  ", " << clockwiseness
                  << ", timestamp: " << frame.timestamp()
                  << ", counter: " << circle_counter
                  << std::endl;
        }

        if(circle.state() == Gesture::STATE_STOP && doing_gesture && doing_circle){
          doing_gesture = false;
          doing_circle = false;
        }

        break;
      }
      case Gesture::TYPE_SWIPE:
      {
        SwipeGesture swipe = gesture;

        if(swipe.state() == Gesture::STATE_START && !doing_gesture){

          doing_gesture = true;
          doing_swipe = true;

          Vector direction = swipe.direction();
          //swipe(direction);

          std::cout << std::string(2, ' ')
          << "Swipe id: " << gesture.id()
          << ", state: " << stateNames[gesture.state()]
          << ", direction: " << swipe.direction()
          << ", speed: " << swipe.speed()
          << ", timestamp: " << frame.timestamp()
          << std::endl;

        } else if(swipe.state() == Gesture::STATE_STOP && doing_gesture && doing_swipe){
          doing_gesture = false;
          doing_swipe = false;

          std::cout << std::string(2, ' ')
          << "Swipe id: " << gesture.id()
          << ", state: " << stateNames[gesture.state()]
          << ", direction: " << swipe.direction()
          << ", speed: " << swipe.speed()
          << ", timestamp: " << frame.timestamp()
          << std::endl;
        }

        break;
      }
      case Gesture::TYPE_KEY_TAP:
      {
        // KeyTapGesture tap = gesture;
        // std::cout << std::string(2, ' ')
        //   << "Key Tap id: " << gesture.id()
        //   << ", state: " << stateNames[gesture.state()]
        //   << ", position: " << tap.position()
        //   << ", direction: " << tap.direction()
        //   << std::endl;
        break;
      }
      case Gesture::TYPE_SCREEN_TAP:
      {
        // ScreenTapGesture screentap = gesture;
        // std::cout << std::string(2, ' ')
        //   << "Screen Tap id: " << gesture.id()
        //   << ", state: " << stateNames[gesture.state()]
        //   << ", position: " << screentap.position()
        //   << ", direction: " << screentap.direction()
        //   << ", timestamp: " << frame.timestamp()
        //   << std::endl;
        break;
      }
      default:
        std::cout << std::string(2, ' ')  << "Unknown gesture type." << std::endl;
        break;
    }
  }
}

int main(int argc, char** argv) {

    // Create a sample listener and controller
    GestureListener listener;
    Controller controller;
    // Have the sample listener receive events from the controller
    controller.addListener(listener);

    //set the controller to recieve frames even when not in foreground
    controller.setPolicyFlags(Leap::Controller::POLICY_BACKGROUND_FRAMES);

    // if (argc > 1 && strcmp(argv[1], "--bg") == 0)
    //   controller.setPolicyFlags(Leap::Controller::POLICY_BACKGROUND_FRAMES);

    // Keep this process running until Enter is pressed
    std::cout << "Press Enter to quit..." << std::endl;
    std::cin.get();

    // Remove the sample listener when done
    controller.removeListener(listener);

    return 0;
}
<commit_msg>added sleep to swipe to remove interferance<commit_after>#include <iostream>
#include <string.h>
#include <Leap.h>
#include <unistd.h>
#include <cstdlib>

#include "task_runner.h"

#define SWIPE_THRESHOLD .8
#define CIRCLE_THRESHOLD .4

using namespace Leap;

const std::string fingerNames[] = {"Thumb", "Index", "Middle", "Ring", "Pinky"};
const std::string boneNames[] = {"Metacarpal", "Proximal", "Middle", "Distal"};
const std::string stateNames[] = {"STATE_INVALID", "STATE_START", "STATE_UPDATE", "STATE_STOP"};

class GestureListener : public Listener {
  public:
    // virtual void onInit(const Controller&);
    virtual void onConnect(const Controller&);
    // virtual void onDisconnect(const Controller&);
    // virtual void onExit(const Controller&);
    virtual void onFrame(const Controller&);
    // virtual void onFocusGained(const Controller&);
    // virtual void onFocusLost(const Controller&);
    // virtual void onDeviceChange(const Controller&);
    // virtual void onServiceConnect(const Controller&);
    // virtual void onServiceDisconnect(const Controller&);

  private:
};

void GestureListener::onConnect(const Controller& controller) {
  std::cout << "Connected" << std::endl;
  controller.enableGesture(Gesture::TYPE_CIRCLE);
  controller.enableGesture(Gesture::TYPE_KEY_TAP);
  controller.enableGesture(Gesture::TYPE_SCREEN_TAP);
  controller.enableGesture(Gesture::TYPE_SWIPE);
}

float circle_counter = 0; //how much of a circle has been made
bool doing_gesture = false;
bool doing_circle = false;
bool doing_swipe = false;

void GestureListener::onFrame(const Controller& controller) {
  // Get the most recent frame
  const Frame frame = controller.frame();

  // report some basic information
  // std::cout << "Frame id: " << frame.id()
  //           << ", timestamp: " << frame.timestamp()
  //           << ", hands: " << frame.hands().count()
  //           << ", fingers: " << frame.fingers().count()
  //           << ", tools: " << frame.tools().count()
  //           << ", gestures: " << frame.gestures().count() << std::endl;

  // get hand info
  HandList hands = frame.hands();
  for (HandList::const_iterator hl = hands.begin(); hl != hands.end(); ++hl) {
    // Get the first hand
    const Hand hand = *hl;
    std::string handType = hand.isLeft() ? "Left hand" : "Right hand";
    // std::cout << std::string(2, ' ') << handType << ", id: " << hand.id()
    //           << ", palm position: " << hand.palmPosition() << std::endl;
    // Get the hand's normal vector and direction
    const Vector normal = hand.palmNormal();
    const Vector direction = hand.direction();

    // Calculate the hand's pitch, roll, and yaw angles
    // std::cout << std::string(2, ' ') <<  "pitch: " << direction.pitch() * RAD_TO_DEG << " degrees, "
    //           << "roll: " << normal.roll() * RAD_TO_DEG << " degrees, "
    //           << "yaw: " << direction.yaw() * RAD_TO_DEG << " degrees" << std::endl;

    // Get the Arm bone
    Arm arm = hand.arm();
    // std::cout << std::string(2, ' ') <<  "Arm direction: " << arm.direction()
    //           << " wrist position: " << arm.wristPosition()
    //           << " elbow position: " << arm.elbowPosition() << std::endl;

    // Get fingers
    const FingerList fingers = hand.fingers();
    for (FingerList::const_iterator fl = fingers.begin(); fl != fingers.end(); ++fl) {
      const Finger finger = *fl;
      // std::cout << std::string(4, ' ') <<  fingerNames[finger.type()]
      //           << " finger, id: " << finger.id()
      //           << ", length: " << finger.length()
      //           << "mm, width: " << finger.width() << std::endl;

      // Get finger bones
      for (int b = 0; b < 4; ++b) {
        Bone::Type boneType = static_cast<Bone::Type>(b);
        Bone bone = finger.bone(boneType);
        // std::cout << std::string(6, ' ') <<  boneNames[boneType]
        //           << " bone, start: " << bone.prevJoint()
        //           << ", end: " << bone.nextJoint()
        //           << ", direction: " << bone.direction() << std::endl;
      }
    }
  }

  // Get tools
  const ToolList tools = frame.tools();
  for (ToolList::const_iterator tl = tools.begin(); tl != tools.end(); ++tl) {
    const Tool tool = *tl;
    // std::cout << std::string(2, ' ') <<  "Tool, id: " << tool.id()
    //           << ", position: " << tool.tipPosition()
    //           << ", direction: " << tool.direction() << std::endl;
  }

  // Get gestures
  const GestureList gestures = frame.gestures();

  for (int g = 0; g < gestures.count(); ++g) {
    Gesture gesture = gestures[g];

    switch (gesture.type()) {
      case Gesture::TYPE_CIRCLE:
      {
        CircleGesture circle = gesture;
        std::string clockwiseness;
        bool clockwise = false;

        if (circle.pointable().direction().angleTo(circle.normal()) <= PI/2) {
          clockwiseness = "clockwise";
          clockwise = true;
        } else {
          clockwiseness = "counterclockwise";
          clockwise = false;
        }

        if(circle.state() == Gesture::STATE_START && !doing_gesture){
          doing_gesture = true;
          doing_circle = true;
        }
        // Calculate angle swept since last frame
        float sweptAngle = 0;
        if (circle.state() != Gesture::STATE_START && doing_circle) {
          CircleGesture previousUpdate = CircleGesture(controller.frame(1).gesture(circle.id()));
          sweptAngle = (circle.progress() - previousUpdate.progress()) * 2 * PI;
          circle_counter += sweptAngle;

          if(circle_counter >= CIRCLE_THRESHOLD){
            circle_counter = 0;
            circle_action(clockwise);
            std::cout << "scroll" << std::endl;
          }

          std::cout << std::string(2, ' ')
                  << "Circle id: " << gesture.id()
                  << ", state: " << stateNames[gesture.state()]
                  << ", progress: " << circle.progress()
                  << ", radius: " << circle.radius()
                  << ", angle " << sweptAngle * RAD_TO_DEG
                  <<  ", " << clockwiseness
                  << ", timestamp: " << frame.timestamp()
                  << ", counter: " << circle_counter
                  << std::endl;
        }

        if(circle.state() == Gesture::STATE_STOP && doing_gesture && doing_circle){
          doing_gesture = false;
          doing_circle = false;
        }

        break;
      }
      case Gesture::TYPE_SWIPE:
      {
        SwipeGesture swipe = gesture;

        if(swipe.state() == Gesture::STATE_START && !doing_gesture){

          doing_gesture = true;
          doing_swipe = true;

          Vector direction = swipe.direction();
          //swipe(direction);

          std::cout << std::string(2, ' ')
          << "Swipe id: " << gesture.id()
          << ", state: " << stateNames[gesture.state()]
          << ", direction: " << swipe.direction()
          << ", speed: " << swipe.speed()
          << ", timestamp: " << frame.timestamp()
          << std::endl;

        } else if(swipe.state() == Gesture::STATE_STOP && doing_gesture && doing_swipe){
          doing_gesture = false;
          doing_swipe = false;

          std::cout << std::string(2, ' ')
          << "Swipe id: " << gesture.id()
          << ", state: " << stateNames[gesture.state()]
          << ", direction: " << swipe.direction()
          << ", speed: " << swipe.speed()
          << ", timestamp: " << frame.timestamp()
          << std::endl;

          sleep(1);
        }

        break;
      }
      case Gesture::TYPE_KEY_TAP:
      {
        // KeyTapGesture tap = gesture;
        // std::cout << std::string(2, ' ')
        //   << "Key Tap id: " << gesture.id()
        //   << ", state: " << stateNames[gesture.state()]
        //   << ", position: " << tap.position()
        //   << ", direction: " << tap.direction()
        //   << std::endl;
        break;
      }
      case Gesture::TYPE_SCREEN_TAP:
      {
        // ScreenTapGesture screentap = gesture;
        // std::cout << std::string(2, ' ')
        //   << "Screen Tap id: " << gesture.id()
        //   << ", state: " << stateNames[gesture.state()]
        //   << ", position: " << screentap.position()
        //   << ", direction: " << screentap.direction()
        //   << ", timestamp: " << frame.timestamp()
        //   << std::endl;
        break;
      }
      default:
        std::cout << std::string(2, ' ')  << "Unknown gesture type." << std::endl;
        break;
    }
  }
}

int main(int argc, char** argv) {

    // Create a sample listener and controller
    GestureListener listener;
    Controller controller;
    // Have the sample listener receive events from the controller
    controller.addListener(listener);

    //set the controller to recieve frames even when not in foreground
    controller.setPolicyFlags(Leap::Controller::POLICY_BACKGROUND_FRAMES);

    // if (argc > 1 && strcmp(argv[1], "--bg") == 0)
    //   controller.setPolicyFlags(Leap::Controller::POLICY_BACKGROUND_FRAMES);

    // Keep this process running until Enter is pressed
    std::cout << "Press Enter to quit..." << std::endl;
    std::cin.get();

    // Remove the sample listener when done
    controller.removeListener(listener);

    return 0;
}
<|endoftext|>


<commit_before>// Compiler.cpp : Defines the entry point for the console application.
//
#include "../core/basic.h"
#include "../core/slang-io.h"
#include "compiler.h"
#include "lexer.h"
#include "parameter-binding.h"
#include "parser.h"
#include "preprocessor.h"
#include "syntax-visitors.h"
#include "slang-stdlib.h"

#include "reflection.h"
#include "emit.h"

// Utilities for pass-through modes
#include "../../tools/glslang/glslang.h"

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#undef WIN32_LEAN_AND_MEAN
#undef NOMINMAX
#include <d3dcompiler.h>
#endif

#ifdef CreateDirectory
#undef CreateDirectory
#endif

namespace Slang
{

    // CompileResult

    void CompileResult::append(CompileResult const& result)
    {
        // Find which to append to
        ResultFormat appendTo = ResultFormat::None;

        if (format == ResultFormat::None)
        {
            format = result.format;
            appendTo = result.format;
        }
        else if (format == result.format)
        {
            appendTo = format;
        }

        if (appendTo == ResultFormat::Text)
        {
            outputString.append(result.outputString.Buffer());
        }
        else if (appendTo == ResultFormat::Binary)
        {
            outputBinary.AddRange(result.outputBinary.Buffer(), result.outputBinary.Count());
        }
    }

    // EntryPointRequest

    TranslationUnitRequest* EntryPointRequest::getTranslationUnit()
    {
        return compileRequest->translationUnits[translationUnitIndex].Ptr();
    }

    //

    Profile Profile::LookUp(char const* name)
    {
        #define PROFILE(TAG, NAME, STAGE, VERSION)	if(strcmp(name, #NAME) == 0) return Profile::TAG;
        #define PROFILE_ALIAS(TAG, NAME)			if(strcmp(name, #NAME) == 0) return Profile::TAG;
        #include "profile-defs.h"

        return Profile::Unknown;
    }

    //

    String emitHLSLForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        auto compileRequest = entryPoint->compileRequest;
        auto translationUnit = entryPoint->getTranslationUnit();
        if (compileRequest->passThrough != PassThroughMode::None)
        {
            // Generate a string that includes the content of
            // the source file(s), along with a line directive
            // to ensure that we get reasonable messages
            // from the downstream compiler when in pass-through
            // mode.

            StringBuilder codeBuilder;
            for(auto sourceFile : translationUnit->sourceFiles)
            {
                codeBuilder << "#line 1 \"";
                for(auto c : sourceFile->path)
                {
                    char buffer[] = { c, 0 };
                    switch(c)
                    {
                    default:
                        codeBuilder << buffer;
                        break;

                    case '\\':
                        codeBuilder << "\\\\";
                    }
                }
                codeBuilder << "\"\n";
                codeBuilder << sourceFile->content << "\n";
            }

            return codeBuilder.ProduceString();
        }
        else
        {
            return emitEntryPoint(
                entryPoint,
                compileRequest->layout.Ptr(),
                CodeGenTarget::HLSL);
        }
    }

    String emitGLSLForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        auto compileRequest = entryPoint->compileRequest;
        auto translationUnit = entryPoint->getTranslationUnit();

        if (compileRequest->passThrough != PassThroughMode::None)
        {
            // Generate a string that includes the content of
            // the source file(s), along with a line directive
            // to ensure that we get reasonable messages
            // from the downstream compiler when in pass-through
            // mode.

            StringBuilder codeBuilder;
            int translationUnitCounter = 0;
            for(auto sourceFile : translationUnit->sourceFiles)
            {
                int translationUnitIndex = translationUnitCounter++;

                // We want to output `#line` directives, but we need
                // to skip this for the first file, since otherwise
                // some GLSL implementations will get tripped up by
                // not having the `#version` directive be the first
                // thing in the file.
                if(translationUnitIndex != 0)
                {
                    codeBuilder << "#line 1 " << translationUnitIndex << "\n";
                }
                codeBuilder << sourceFile->content << "\n";
            }

            return codeBuilder.ProduceString();
        }
        else
        {
            // TODO(tfoley): need to pass along the entry point
            // so that we properly emit it as the `main` function.
            return emitEntryPoint(
                entryPoint,
                compileRequest->layout.Ptr(),
                CodeGenTarget::GLSL);
        }
    }

    char const* GetHLSLProfileName(Profile profile)
    {
        switch(profile.raw)
        {
        #define PROFILE(TAG, NAME, STAGE, VERSION) case Profile::TAG: return #NAME;
        #include "profile-defs.h"

        default:
            // TODO: emit an error here!
            return "unknown";
        }
    }

#ifdef _WIN32
    void* GetD3DCompilerDLL()
    {
        // TODO(tfoley): let user specify version of d3dcompiler DLL to use.
        static HMODULE d3dCompiler =  LoadLibraryA("d3dcompiler_47");
        // TODO(tfoley): handle case where we can't find it gracefully
        assert(d3dCompiler);
        return d3dCompiler;
    }

    List<uint8_t> EmitDXBytecodeForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        static pD3DCompile D3DCompile_ = nullptr;
        if (!D3DCompile_)
        {
            HMODULE d3dCompiler = (HMODULE)GetD3DCompilerDLL();
            assert(d3dCompiler);

            D3DCompile_ = (pD3DCompile)GetProcAddress(d3dCompiler, "D3DCompile");
            assert(D3DCompile_);
        }

        auto hlslCode = emitHLSLForEntryPoint(entryPoint);

        ID3DBlob* codeBlob;
        ID3DBlob* diagnosticsBlob;
        HRESULT hr = D3DCompile_(
            hlslCode.begin(),
            hlslCode.Length(),
            "slang",
            nullptr,
            nullptr,
            entryPoint->name.begin(),
            GetHLSLProfileName(entryPoint->profile),
            0,
            0,
            &codeBlob,
            &diagnosticsBlob);

        List<uint8_t> data;
        if (codeBlob)
        {
            data.AddRange((uint8_t const*)codeBlob->GetBufferPointer(), (int)codeBlob->GetBufferSize());
            codeBlob->Release();
        }
        if (diagnosticsBlob)
        {
            // TODO(tfoley): need a better policy for how we translate diagnostics
            // back into the Slang world (although we should always try to generate
            // HLSL that doesn't produce any diagnostics...)
            String diagnostics = (char const*) diagnosticsBlob->GetBufferPointer();
            fprintf(stderr, "%s", diagnostics.begin());
            OutputDebugStringA(diagnostics.begin());
            diagnosticsBlob->Release();
        }
        if (FAILED(hr))
        {
            // TODO(tfoley): What to do on failure?
            exit(1);
        }
        return data;
    }

#if 0
    List<uint8_t> EmitDXBytecode(
        ExtraContext&				context)
    {
        if(context.getTranslationUnitOptions().entryPoints.Count() != 1)
        {
            if(context.getTranslationUnitOptions().entryPoints.Count() == 0)
            {
                // TODO(tfoley): need to write diagnostics into this whole thing...
                fprintf(stderr, "no entry point specified\n");
            }
            else
            {
                fprintf(stderr, "multiple entry points specified\n");
            }
            return List<uint8_t>();
        }

        return EmitDXBytecodeForEntryPoint(context, context.getTranslationUnitOptions().entryPoints[0]);
    }
#endif

    List<uint8_t> EmitDXBytecodeAssemblyForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        static pD3DDisassemble D3DDisassemble_ = nullptr;
        if (!D3DDisassemble_)
        {
            HMODULE d3dCompiler = (HMODULE)GetD3DCompilerDLL();
            assert(d3dCompiler);

            D3DDisassemble_ = (pD3DDisassemble)GetProcAddress(d3dCompiler, "D3DDisassemble");
            assert(D3DDisassemble_);
        }

        List<uint8_t> dxbc = EmitDXBytecodeForEntryPoint(entryPoint);
        if (!dxbc.Count())
        {
            return List<uint8_t>();
        }

        ID3DBlob* codeBlob;
        HRESULT hr = D3DDisassemble_(
            &dxbc[0],
            dxbc.Count(),
            0,
            nullptr,
            &codeBlob);

        List<uint8_t> result;
        if (codeBlob)
        {
            result.AddRange((uint8_t*)codeBlob->GetBufferPointer(), codeBlob->GetBufferSize());
            codeBlob->Release();
        }
        if (FAILED(hr))
        {
            // TODO(tfoley): need to figure out what to diagnose here...
        }
        return result;
    }

#if 0
    String EmitDXBytecodeAssembly(
        ExtraContext&				context)
    {
        if(context.getTranslationUnitOptions().entryPoints.Count() == 0)
        {
            // TODO(tfoley): need to write diagnostics into this whole thing...
            fprintf(stderr, "no entry point specified\n");
            return "";
        }

        StringBuilder sb;
        for (auto entryPoint : context.getTranslationUnitOptions().entryPoints)
        {
            sb << EmitDXBytecodeAssemblyForEntryPoint(context, entryPoint);
        }
        return sb.ProduceString();
    }
#endif

    HMODULE getGLSLCompilerDLL()
    {
        // TODO(tfoley): let user specify version of glslang DLL to use.
        static HMODULE glslCompiler =  LoadLibraryA("glslang");
        // TODO(tfoley): handle case where we can't find it gracefully
        assert(glslCompiler);
        return glslCompiler;
    }

    List<uint8_t> emitSPIRVForEntryPoint(
        EntryPointRequest*  entryPoint,
        bool spirvAssembly)
    {
        String rawGLSL = emitGLSLForEntryPoint(entryPoint);

        static glslang_CompileFunc glslang_compile = nullptr;
        if (!glslang_compile)
        {
            HMODULE glslCompiler = getGLSLCompilerDLL();
            assert(glslCompiler);

            glslang_compile = (glslang_CompileFunc)GetProcAddress(glslCompiler, "glslang_compile");
            assert(glslang_compile);
        }

        List<uint8_t> diagnosticOutput;
        List<uint8_t> output;

        auto outputFunc = [](void const* data, size_t size, void* userData)
        {
            ((List<uint8_t>*)userData)->AddRange((uint8_t*)data, size);
        };

        glslang_CompileRequest request;
        request.sourcePath = "slang";
        request.sourceText = rawGLSL.begin();
        request.slangStage = (SlangStage)entryPoint->profile.GetStage();
        request.disassembleResult = spirvAssembly;

        request.diagnosticFunc = outputFunc;
        request.diagnosticUserData = &diagnosticOutput;

        request.outputFunc = outputFunc;
        request.outputUserData = &output;

        int err = glslang_compile(&request);

        if (err)
        {
            char const* diagnosticString = (char const*)diagnosticOutput.Buffer();
            String debugStr(diagnosticString, diagnosticString + diagnosticOutput.Count());

            OutputDebugStringA(debugStr.Buffer());
            fprintf(stderr, "%s", debugStr.Buffer());
            exit(1);
        }

        return output;
    }
#endif

#if 0
    String emitSPIRVAssembly(
        ExtraContext&				context)
    {
        if(context.getTranslationUnitOptions().entryPoints.Count() == 0)
        {
            // TODO(tfoley): need to write diagnostics into this whole thing...
            fprintf(stderr, "no entry point specified\n");
            return "";
        }

        StringBuilder sb;
        for (auto entryPoint : context.getTranslationUnitOptions().entryPoints)
        {
            sb << emitSPIRVAssemblyForEntryPoint(context, entryPoint);
        }
        return sb.ProduceString();
    }
#endif

    // Do emit logic for a single entry point
    CompileResult emitEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        CompileResult result;

        auto compileRequest = entryPoint->compileRequest;

        switch (compileRequest->Target)
        {
        case CodeGenTarget::HLSL:
            {
                String code = emitHLSLForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::GLSL:
            {
                String code = emitGLSLForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::DXBytecode:
            {
                List<uint8_t> code = EmitDXBytecodeForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::DXBytecodeAssembly:
            {
                List<uint8_t> code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::SPIRV:
            {
                List<uint8_t> code = emitSPIRVForEntryPoint(entryPoint, false);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::SPIRVAssembly:
            {
                List<uint8_t> code = emitSPIRVForEntryPoint(entryPoint, true);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::None:
            // The user requested no output
            break;

        // Note(tfoley): We currently hit this case when compiling the stdlib
        case CodeGenTarget::Unknown:
            break;

        default:
            throw "unimplemented";
        }

        return result;
    }

    CompileResult emitTranslationUnitEntryPoints(
        TranslationUnitRequest* translationUnit)
    {
        CompileResult result;

        for (auto& entryPoint : translationUnit->entryPoints)
        {
            CompileResult entryPointResult = emitEntryPoint(entryPoint.Ptr());

            entryPoint->result = entryPointResult;
        }

        // The result for the translation unit will just be the concatenation
        // of the results for each entry point. This doesn't actually make
        // much sense, but it is good enough for now.
        //
        // TODO: Replace this with a packaged JSON and/or binary format.
        for (auto& entryPoint : translationUnit->entryPoints)
        {
            result.append(entryPoint->result);
        }

        return result;
    }

    // Do emit logic for an entire translation unit, which might
    // have zero or more entry points
    CompileResult emitTranslationUnit(
        TranslationUnitRequest* translationUnit)
    {
        return emitTranslationUnitEntryPoints(translationUnit);
    }

#if 0
    TranslationUnitResult generateOutput(ExtraContext& context)
    {
        TranslationUnitResult result = emitTranslationUnit(context);
        return result;
    }
#endif

    void generateOutput(
        CompileRequest* compileRequest)
    {
        // Allow for an "extra" target to verride things first.
        switch (compileRequest->extraTarget)
        {
        case CodeGenTarget::ReflectionJSON:
            {
                String reflectionJSON = emitReflectionJSON(compileRequest->layout.Ptr());

                // HACK(tfoley): just print it out since that is what people probably expect.
                // TODO: need a way to control where output gets routed across all possible targets.
                fprintf(stdout, "%s", reflectionJSON.begin());

                return;
            }
            break;

        default:
            break;
        }

        // For most targets, we will do things per-translation-unit
        for( auto translationUnit : compileRequest->translationUnits )
        {
            CompileResult translationUnitResult = emitTranslationUnit(translationUnit.Ptr());
            translationUnit->result = translationUnitResult;
        }
    }

}
<commit_msg>Fixup for binary/string output.<commit_after>// Compiler.cpp : Defines the entry point for the console application.
//
#include "../core/basic.h"
#include "../core/slang-io.h"
#include "compiler.h"
#include "lexer.h"
#include "parameter-binding.h"
#include "parser.h"
#include "preprocessor.h"
#include "syntax-visitors.h"
#include "slang-stdlib.h"

#include "reflection.h"
#include "emit.h"

// Utilities for pass-through modes
#include "../../tools/glslang/glslang.h"

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#undef WIN32_LEAN_AND_MEAN
#undef NOMINMAX
#include <d3dcompiler.h>
#endif

#ifdef CreateDirectory
#undef CreateDirectory
#endif

namespace Slang
{

    // CompileResult

    void CompileResult::append(CompileResult const& result)
    {
        // Find which to append to
        ResultFormat appendTo = ResultFormat::None;

        if (format == ResultFormat::None)
        {
            format = result.format;
            appendTo = result.format;
        }
        else if (format == result.format)
        {
            appendTo = format;
        }

        if (appendTo == ResultFormat::Text)
        {
            outputString.append(result.outputString.Buffer());
        }
        else if (appendTo == ResultFormat::Binary)
        {
            outputBinary.AddRange(result.outputBinary.Buffer(), result.outputBinary.Count());
        }
    }

    // EntryPointRequest

    TranslationUnitRequest* EntryPointRequest::getTranslationUnit()
    {
        return compileRequest->translationUnits[translationUnitIndex].Ptr();
    }

    //

    Profile Profile::LookUp(char const* name)
    {
        #define PROFILE(TAG, NAME, STAGE, VERSION)	if(strcmp(name, #NAME) == 0) return Profile::TAG;
        #define PROFILE_ALIAS(TAG, NAME)			if(strcmp(name, #NAME) == 0) return Profile::TAG;
        #include "profile-defs.h"

        return Profile::Unknown;
    }

    //

    String emitHLSLForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        auto compileRequest = entryPoint->compileRequest;
        auto translationUnit = entryPoint->getTranslationUnit();
        if (compileRequest->passThrough != PassThroughMode::None)
        {
            // Generate a string that includes the content of
            // the source file(s), along with a line directive
            // to ensure that we get reasonable messages
            // from the downstream compiler when in pass-through
            // mode.

            StringBuilder codeBuilder;
            for(auto sourceFile : translationUnit->sourceFiles)
            {
                codeBuilder << "#line 1 \"";
                for(auto c : sourceFile->path)
                {
                    char buffer[] = { c, 0 };
                    switch(c)
                    {
                    default:
                        codeBuilder << buffer;
                        break;

                    case '\\':
                        codeBuilder << "\\\\";
                    }
                }
                codeBuilder << "\"\n";
                codeBuilder << sourceFile->content << "\n";
            }

            return codeBuilder.ProduceString();
        }
        else
        {
            return emitEntryPoint(
                entryPoint,
                compileRequest->layout.Ptr(),
                CodeGenTarget::HLSL);
        }
    }

    String emitGLSLForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        auto compileRequest = entryPoint->compileRequest;
        auto translationUnit = entryPoint->getTranslationUnit();

        if (compileRequest->passThrough != PassThroughMode::None)
        {
            // Generate a string that includes the content of
            // the source file(s), along with a line directive
            // to ensure that we get reasonable messages
            // from the downstream compiler when in pass-through
            // mode.

            StringBuilder codeBuilder;
            int translationUnitCounter = 0;
            for(auto sourceFile : translationUnit->sourceFiles)
            {
                int translationUnitIndex = translationUnitCounter++;

                // We want to output `#line` directives, but we need
                // to skip this for the first file, since otherwise
                // some GLSL implementations will get tripped up by
                // not having the `#version` directive be the first
                // thing in the file.
                if(translationUnitIndex != 0)
                {
                    codeBuilder << "#line 1 " << translationUnitIndex << "\n";
                }
                codeBuilder << sourceFile->content << "\n";
            }

            return codeBuilder.ProduceString();
        }
        else
        {
            // TODO(tfoley): need to pass along the entry point
            // so that we properly emit it as the `main` function.
            return emitEntryPoint(
                entryPoint,
                compileRequest->layout.Ptr(),
                CodeGenTarget::GLSL);
        }
    }

    char const* GetHLSLProfileName(Profile profile)
    {
        switch(profile.raw)
        {
        #define PROFILE(TAG, NAME, STAGE, VERSION) case Profile::TAG: return #NAME;
        #include "profile-defs.h"

        default:
            // TODO: emit an error here!
            return "unknown";
        }
    }

#ifdef _WIN32
    void* GetD3DCompilerDLL()
    {
        // TODO(tfoley): let user specify version of d3dcompiler DLL to use.
        static HMODULE d3dCompiler =  LoadLibraryA("d3dcompiler_47");
        // TODO(tfoley): handle case where we can't find it gracefully
        assert(d3dCompiler);
        return d3dCompiler;
    }

    List<uint8_t> EmitDXBytecodeForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        static pD3DCompile D3DCompile_ = nullptr;
        if (!D3DCompile_)
        {
            HMODULE d3dCompiler = (HMODULE)GetD3DCompilerDLL();
            assert(d3dCompiler);

            D3DCompile_ = (pD3DCompile)GetProcAddress(d3dCompiler, "D3DCompile");
            assert(D3DCompile_);
        }

        auto hlslCode = emitHLSLForEntryPoint(entryPoint);

        ID3DBlob* codeBlob;
        ID3DBlob* diagnosticsBlob;
        HRESULT hr = D3DCompile_(
            hlslCode.begin(),
            hlslCode.Length(),
            "slang",
            nullptr,
            nullptr,
            entryPoint->name.begin(),
            GetHLSLProfileName(entryPoint->profile),
            0,
            0,
            &codeBlob,
            &diagnosticsBlob);

        List<uint8_t> data;
        if (codeBlob)
        {
            data.AddRange((uint8_t const*)codeBlob->GetBufferPointer(), (int)codeBlob->GetBufferSize());
            codeBlob->Release();
        }
        if (diagnosticsBlob)
        {
            // TODO(tfoley): need a better policy for how we translate diagnostics
            // back into the Slang world (although we should always try to generate
            // HLSL that doesn't produce any diagnostics...)
            String diagnostics = (char const*) diagnosticsBlob->GetBufferPointer();
            fprintf(stderr, "%s", diagnostics.begin());
            OutputDebugStringA(diagnostics.begin());
            diagnosticsBlob->Release();
        }
        if (FAILED(hr))
        {
            // TODO(tfoley): What to do on failure?
            exit(1);
        }
        return data;
    }

#if 0
    List<uint8_t> EmitDXBytecode(
        ExtraContext&				context)
    {
        if(context.getTranslationUnitOptions().entryPoints.Count() != 1)
        {
            if(context.getTranslationUnitOptions().entryPoints.Count() == 0)
            {
                // TODO(tfoley): need to write diagnostics into this whole thing...
                fprintf(stderr, "no entry point specified\n");
            }
            else
            {
                fprintf(stderr, "multiple entry points specified\n");
            }
            return List<uint8_t>();
        }

        return EmitDXBytecodeForEntryPoint(context, context.getTranslationUnitOptions().entryPoints[0]);
    }
#endif

    String EmitDXBytecodeAssemblyForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        static pD3DDisassemble D3DDisassemble_ = nullptr;
        if (!D3DDisassemble_)
        {
            HMODULE d3dCompiler = (HMODULE)GetD3DCompilerDLL();
            assert(d3dCompiler);

            D3DDisassemble_ = (pD3DDisassemble)GetProcAddress(d3dCompiler, "D3DDisassemble");
            assert(D3DDisassemble_);
        }

        List<uint8_t> dxbc = EmitDXBytecodeForEntryPoint(entryPoint);
        if (!dxbc.Count())
        {
            return String();
        }

        ID3DBlob* codeBlob;
        HRESULT hr = D3DDisassemble_(
            &dxbc[0],
            dxbc.Count(),
            0,
            nullptr,
            &codeBlob);

        String result;
        if (codeBlob)
        {
            char const* codeBegin = (char const*)codeBlob->GetBufferPointer();
            char const* codeEnd = codeBegin + codeBlob->GetBufferSize();
            result.append(codeBegin, codeEnd);
            codeBlob->Release();
        }
        if (FAILED(hr))
        {
            // TODO(tfoley): need to figure out what to diagnose here...
        }
        return result;
    }

#if 0
    String EmitDXBytecodeAssembly(
        ExtraContext&				context)
    {
        if(context.getTranslationUnitOptions().entryPoints.Count() == 0)
        {
            // TODO(tfoley): need to write diagnostics into this whole thing...
            fprintf(stderr, "no entry point specified\n");
            return "";
        }

        StringBuilder sb;
        for (auto entryPoint : context.getTranslationUnitOptions().entryPoints)
        {
            sb << EmitDXBytecodeAssemblyForEntryPoint(context, entryPoint);
        }
        return sb.ProduceString();
    }
#endif

    HMODULE getGLSLCompilerDLL()
    {
        // TODO(tfoley): let user specify version of glslang DLL to use.
        static HMODULE glslCompiler =  LoadLibraryA("glslang");
        // TODO(tfoley): handle case where we can't find it gracefully
        assert(glslCompiler);
        return glslCompiler;
    }

    int invokeGLSLCompilerForEntryPoint(
        EntryPointRequest*          entryPoint,
        glslang_CompileRequest&     request)
    {
        String rawGLSL = emitGLSLForEntryPoint(entryPoint);

        static glslang_CompileFunc glslang_compile = nullptr;
        if (!glslang_compile)
        {
            HMODULE glslCompiler = getGLSLCompilerDLL();
            assert(glslCompiler);

            glslang_compile = (glslang_CompileFunc)GetProcAddress(glslCompiler, "glslang_compile");
            assert(glslang_compile);
        }

        String diagnosticOutput;
        auto diagnosticOutputFunc = [](void const* data, size_t size, void* userData)
        {
            (*(String*)userData).append((char const*)data, (char const*)data + size);
        };

        request.sourcePath = "slang";
        request.sourceText = rawGLSL.begin();
        request.slangStage = (SlangStage)entryPoint->profile.GetStage();

        request.diagnosticFunc = diagnosticOutputFunc;
        request.diagnosticUserData = &diagnosticOutput;

        int err = glslang_compile(&request);

        if (err)
        {
            OutputDebugStringA(diagnosticOutput.Buffer());
            fprintf(stderr, "%s", diagnosticOutput.Buffer());
            exit(1);
        }

        return 0;
    }

    List<uint8_t> emitSPIRVForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        List<uint8_t> output;
        auto outputFunc = [](void const* data, size_t size, void* userData)
        {
            ((List<uint8_t>*)userData)->AddRange((uint8_t*)data, size);
        };

        glslang_CompileRequest request;
        request.outputFunc = outputFunc;
        request.outputUserData = &output;
        request.disassembleResult = false;

        int err = invokeGLSLCompilerForEntryPoint(entryPoint, request);

        if (err)
        {
            return List<uint8_t>();
        }

        return output;
    }

    String emitSPIRVAssemblyForEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        String output;
        auto outputFunc = [](void const* data, size_t size, void* userData)
        {
            (*(String*)userData).append((char const*)data, (char const*)data + size);
        };

        glslang_CompileRequest request;
        request.outputFunc = outputFunc;
        request.outputUserData = &output;
        request.disassembleResult = true;

        int err = invokeGLSLCompilerForEntryPoint(entryPoint, request);

        if (err)
        {
            String();
        }

        return output;
    }
#endif

#if 0
    String emitSPIRVAssembly(
        ExtraContext&				context)
    {
        if(context.getTranslationUnitOptions().entryPoints.Count() == 0)
        {
            // TODO(tfoley): need to write diagnostics into this whole thing...
            fprintf(stderr, "no entry point specified\n");
            return "";
        }

        StringBuilder sb;
        for (auto entryPoint : context.getTranslationUnitOptions().entryPoints)
        {
            sb << emitSPIRVAssemblyForEntryPoint(context, entryPoint);
        }
        return sb.ProduceString();
    }
#endif

    // Do emit logic for a single entry point
    CompileResult emitEntryPoint(
        EntryPointRequest*  entryPoint)
    {
        CompileResult result;

        auto compileRequest = entryPoint->compileRequest;

        switch (compileRequest->Target)
        {
        case CodeGenTarget::HLSL:
            {
                String code = emitHLSLForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::GLSL:
            {
                String code = emitGLSLForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::DXBytecode:
            {
                List<uint8_t> code = EmitDXBytecodeForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::DXBytecodeAssembly:
            {
                String code = EmitDXBytecodeAssemblyForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::SPIRV:
            {
                List<uint8_t> code = emitSPIRVForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::SPIRVAssembly:
            {
                String code = emitSPIRVAssemblyForEntryPoint(entryPoint);
                result = CompileResult(code);
            }
            break;

        case CodeGenTarget::None:
            // The user requested no output
            break;

        // Note(tfoley): We currently hit this case when compiling the stdlib
        case CodeGenTarget::Unknown:
            break;

        default:
            throw "unimplemented";
        }

        return result;
    }

    CompileResult emitTranslationUnitEntryPoints(
        TranslationUnitRequest* translationUnit)
    {
        CompileResult result;

        for (auto& entryPoint : translationUnit->entryPoints)
        {
            CompileResult entryPointResult = emitEntryPoint(entryPoint.Ptr());

            entryPoint->result = entryPointResult;
        }

        // The result for the translation unit will just be the concatenation
        // of the results for each entry point. This doesn't actually make
        // much sense, but it is good enough for now.
        //
        // TODO: Replace this with a packaged JSON and/or binary format.
        for (auto& entryPoint : translationUnit->entryPoints)
        {
            result.append(entryPoint->result);
        }

        return result;
    }

    // Do emit logic for an entire translation unit, which might
    // have zero or more entry points
    CompileResult emitTranslationUnit(
        TranslationUnitRequest* translationUnit)
    {
        return emitTranslationUnitEntryPoints(translationUnit);
    }

#if 0
    TranslationUnitResult generateOutput(ExtraContext& context)
    {
        TranslationUnitResult result = emitTranslationUnit(context);
        return result;
    }
#endif

    void generateOutput(
        CompileRequest* compileRequest)
    {
        // Allow for an "extra" target to verride things first.
        switch (compileRequest->extraTarget)
        {
        case CodeGenTarget::ReflectionJSON:
            {
                String reflectionJSON = emitReflectionJSON(compileRequest->layout.Ptr());

                // HACK(tfoley): just print it out since that is what people probably expect.
                // TODO: need a way to control where output gets routed across all possible targets.
                fprintf(stdout, "%s", reflectionJSON.begin());

                return;
            }
            break;

        default:
            break;
        }

        // For most targets, we will do things per-translation-unit
        for( auto translationUnit : compileRequest->translationUnits )
        {
            CompileResult translationUnitResult = emitTranslationUnit(translationUnit.Ptr());
            translationUnit->result = translationUnitResult;
        }
    }

}
<|endoftext|>


<commit_before>// Code for basic file search
//
#include <cstdio>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
	// get input file
	if(argc != 2){
		cout << "No input file specified" << endl;
		return 1;
	}

	// print/search file contents
	FILE * pfile;
	int current_bit = 0;
	int pattern_aa  = 0xaa;
	int pattern_55  = 0x55;
	int count_aa = 0;
	int count_55 = 0;
	int count_error = 0;
	bool was_aa  = 0;

	pfile = fopen(argv[1], "r");

	if(pfile != NULL){
		while(current_bit != EOF){
			current_bit = fgetc(pfile);
			if(current_bit == EOF) break;
			if(current_bit == pattern_aa){
				count_aa++;
				was_aa = 1;
			}else if(current_bit == pattern_55){
				count_55++;
				was_aa = 0;
			}else{
				int error_bit   = 0;

				if(was_aa)				// therefore should be 0x55
					error_bit = 0x55 ^ current_bit;
				else					// should be 0xaa
					error_bit = 0xaa ^ current_bit;

				count_error += __builtin_popcount(error_bit);
			}
		}
		fclose(pfile);
	}else{
		cout << "File cannot be opened" << endl;
		return 1;
	}

	cout << "count 0x55: "  << count_55    << endl;
	cout << "count 0xaa: "  << count_aa    << endl;
	cout << "error count: " << count_error << endl;

	return 0;
}

<commit_msg>added TODOs<commit_after>// Code for basic file search
//
#include <cstdio>
#include <iostream>
using namespace std;

int main(int argc, char* argv[])
{
	// get input file
	if(argc != 2){
		cout << "No input file specified" << endl;
		return 1;
	}

	// print/search file contents
	FILE * pfile;
	int current_bit = 0;
	int pattern_aa  = 0xaa;
	int pattern_55  = 0x55;
	int count_aa = 0;
	int count_55 = 0;
	int count_error = 0;
	bool was_aa  = 0;

	pfile = fopen(argv[1], "r");

	if(pfile != NULL){
		while(current_bit != EOF){
			current_bit = fgetc(pfile);
			if(current_bit == EOF) break;
			if(current_bit == pattern_aa){
				count_aa++;
				was_aa = 1;
			}else if(current_bit == pattern_55){
				count_55++;
				was_aa = 0;
			}else{
				int error_bit   = 0;

				if(was_aa)				// therefore should be 0x55
					error_bit = 0x55 ^ current_bit;
				else					// should be 0xaa
					error_bit = 0xaa ^ current_bit;

				count_error += __builtin_popcount(error_bit);
			}
		}
		fclose(pfile);
	}else{
		cout << "File cannot be opened" << endl;
		return 1;
	}

	//TODO add overall percentage count

	cout << "count 0x55: "  << count_55    << endl;
	cout << "count 0xaa: "  << count_aa    << endl;
	cout << "error count: " << count_error << endl;

	return 0;
}

<|endoftext|>