<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX64M グループ・PHY 定義 @n
			Copyright 2017 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include "common/io_utils.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  PHY 定義クラス
		@param[in]	ETHC	インサーネット・コントローラー
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class ETHC>
	class phy_t {

	public:
		enum class LinkStat : uint8_t {
			NO_LINK = 0,
			LINK_10H,
			LINK_10F,
			LINK_100H,
			LINK_100F,
		};

	private:
		// Media Independent Interface
		static const int PHY_MII_ST    = 1;
		static const int PHY_MII_READ  = 2;
		static const int PHY_MII_WRITE = 1;

		/*
 		 * PHY address selection.
		 * Please select one of them.
		 */
		static const int PHY_MII_ADDR = 0;  /* for GR-SAKURA (RX63N). */

		static const int PHY_MII_WAIT = 2;

		/* Standard PHY Registers */
		static const int PHY_REG_CONTROL          = 0;
		static const int PHY_REG_STATUS           = 1;
		static const int PHY_REG_IDENTIFIER1      = 2;
		static const int PHY_REG_IDENTIFIER2      = 3;
		static const int PHY_REG_AN_ADVERTISEMENT = 4;
		static const int PHY_REG_AN_LINK_PARTNER  = 5;
		static const int PHY_REG_AN_EXPANSION     = 6;

		/* Vendor Specific PHY Registers */
		#ifdef MICREL_KSZ8041NL
		static const uint16_t PHY_REG_PHY_CONTROL_1 = (0x1E);
		#endif /* MICREL_KSZ8041NL */

		/* Basic Mode Control Register Bit Definitions */
		static const uint16_t PHY_CONTROL_RESET        = (1 << 15);
		static const uint16_t PHY_CONTROL_LOOPBACK     = (1 << 14);
		static const uint16_t PHY_CONTROL_100_MBPS     = (1 << 13);
		static const uint16_t PHY_CONTROL_AN_ENABLE    = (1 << 12);
		static const uint16_t PHY_CONTROL_POWER_DOWN   = (1 << 11);
		static const uint16_t PHY_CONTROL_ISOLATE      = (1 << 10);
		static const uint16_t PHY_CONTROL_AN_RESTART   = (1 << 9);
		static const uint16_t PHY_CONTROL_FULL_DUPLEX  = (1 << 8);
		static const uint16_t PHY_CONTROL_COLLISION    = (1 << 7);

		/* Basic Mode Status Register Bit Definitions */
		static const uint16_t PHY_STATUS_100_T4        = (1 << 15);
		static const uint16_t PHY_STATUS_100F          = (1 << 14);
		static const uint16_t PHY_STATUS_100H          = (1 << 13);
		static const uint16_t PHY_STATUS_10F           = (1 << 12);
		static const uint16_t PHY_STATUS_10H           = (1 << 11);
		static const uint16_t PHY_STATUS_AN_COMPLETE   = (1 << 5);
		static const uint16_t PHY_STATUS_RM_FAULT      = (1 << 4);
		static const uint16_t PHY_STATUS_AN_ABILITY    = (1 << 3);
		static const uint16_t PHY_STATUS_LINK_UP       = (1 << 2);
		static const uint16_t PHY_STATUS_JABBER        = (1 << 1);
		static const uint16_t PHY_STATUS_EX_CAPABILITY = (1 << 0);

		/* Auto Negotiation Advertisement Bit Definitions */
		static const uint16_t PHY_AN_ADVERTISEMENT_NEXT_PAGE = (1 << 15);
		static const uint16_t PHY_AN_ADVERTISEMENT_RM_FAULT  = (1 << 13);
		static const uint16_t PHY_AN_ADVERTISEMENT_ASM_DIR   = (1 << 11);
		static const uint16_t PHY_AN_ADVERTISEMENT_PAUSE     = (1 << 10);
		static const uint16_t PHY_AN_ADVERTISEMENT_100_T4    = (1 << 9);
		static const uint16_t PHY_AN_ADVERTISEMENT_100F      = (1 << 8);
		static const uint16_t PHY_AN_ADVERTISEMENT_100H      = (1 << 7);
		static const uint16_t PHY_AN_ADVERTISEMENT_10F       = (1 << 6);
		static const uint16_t PHY_AN_ADVERTISEMENT_10H       = (1 << 5);
		static const uint16_t PHY_AN_ADVERTISEMENT_SELECTOR  = (1 << 0);

		/* Auto Negostiate Link Partner Ability Bit Definitions */
		static const uint16_t PHY_AN_LINK_PARTNER_NEXT_PAGE = (1 << 15);
		static const uint16_t PHY_AN_LINK_PARTNER_ACK       = (1 << 14);
		static const uint16_t PHY_AN_LINK_PARTNER_RM_FAULT  = (1 << 13);
		static const uint16_t PHY_AN_LINK_PARTNER_ASM_DIR   = (1 << 11);
		static const uint16_t PHY_AN_LINK_PARTNER_PAUSE     = (1 << 10);
		static const uint16_t PHY_AN_LINK_PARTNER_100_T4    = (1 << 9);
		static const uint16_t PHY_AN_LINK_PARTNER_100F      = (1 << 8);
		static const uint16_t PHY_AN_LINK_PARTNER_100H      = (1 << 7);
		static const uint16_t PHY_AN_LINK_PARTNER_10F       = (1 << 6);
		static const uint16_t PHY_AN_LINK_PARTNER_10H       = (1 << 5);
		static const uint16_t PHY_AN_LINK_PARTNER_SELECTOR  = (1 << 0);

		/* Delay constants */
		static const uint32_t PHY_DELAY_RESET               = 0x00020000L;
		static const uint32_t PHY_DELAY_AN                  = 0x00800000L;

		uint16_t	local_advertise_;

		/*
		 * The value is read from the PHY register by the frame format of MII Management Interface provided
		 * for by Table 22-12 of 22.2.4.5 of IEEE 802.3-2008_section2.
		 */
		uint16_t read_(uint16_t reg_addr)
		{
			preamble_();
			reg_set_(reg_addr, PHY_MII_READ);
			trans_Zto0_();
			uint16_t data = reg_read_();
			trans_Zto0_();
			return data;
		}

		/*
		 * The value is read from the PHY register by the frame format of MII Management Interface provided
		 * for by Table 22-12 of 22.2.4.5 of IEEE 802.3-2008_section2.
		 */
		void write_(uint16_t reg_addr, uint16_t data)
		{
			preamble_();
			reg_set_(reg_addr, PHY_MII_WRITE);
			trans_1to0_();
			reg_write_(data);
			trans_Zto0_();
		}

		/*
		 * The processing of PRE (preamble) about the frame format of MII Management Interface which is
		 * provided by "Table 22-12" of "22.2.4.5" of "IEEE 802.3-2008_section2".
		 */
		void preamble_()
		{
			int i = 32;
			while( i > 0 )
			{
				mii_write1_();
				i--;
			}
		}

		/*
		 * The processing of ST (start of frame),OP (operation code), PHYAD (PHY Address), and
		 * REGAD (Register Address)  about the frame format of MII Management Interface which is
		 * provided by "Table 22-12" of "22.2.4.5" of "IEEE 802.3-2008_section2".
		 */
		void reg_set_(uint16_t reg_addr, int32_t option)
		{
			uint16_t data = 0;
			data = (PHY_MII_ST << 14);          /* ST code    */

			if( option == PHY_MII_READ ) {
				data |= (PHY_MII_READ << 12);   /* OP code(RD)  */
			} else {
				data |= (PHY_MII_WRITE << 12);  /* OP code(WT)  */
			}

			data |= (PHY_MII_ADDR << 7);        /* PHY Address  */
			data |= (reg_addr << 2);            /* Reg Address  */

			int i = 14;
			while( i > 0 ) {
				if( (data & 0x8000) == 0 ) {
					mii_write0_();
				} else {
					mii_write1_();
				}
				data <<= 1;
				i--;
			}
		}

		/*
		 * The processing of DATA (data) about reading of the frame format of MII Management Interface which is
		 * provided by "Table 22-12" of "22.2.4.5" of "IEEE 802.3-2008_section2".
		 */
		uint16_t reg_read_()
		{
			uint16_t reg_data = 0;
			int i = 16;
			while( i > 0 ) {
				for(int j = PHY_MII_WAIT; j > 0; j--) {
					ETHC::PIR = 0x00000000;
				}
				for(int j = PHY_MII_WAIT; j > 0; j--) {
					ETHC::PIR = 0x00000001;
				}

				reg_data <<= 1;
				reg_data |= (ETHC::PIR() & 0x00000008) >> 3;  /* MDI read  */

				for(int j = PHY_MII_WAIT; j > 0; j--) {
					ETHC::PIR = 0x00000001;
				}
				for(int j = PHY_MII_WAIT; j > 0; j--) {
					ETHC::PIR = 0x00000000;
				}
				i--;
			}
			return reg_data;
		}

		/*
		 * The processing of DATA (data) about writing of the frame format of MII Management Interface which is
		 * provided by "Table 22-12" of "22.2.4.5" of "IEEE 802.3-2008_section2".
		 */
		void reg_write_(uint16_t data)
		{
    		int i = 16;
			while( i > 0 ) {
				if( (data & 0x8000) == 0 ) {
					mii_write0_();
				} else {
					mii_write1_();
				}
				i--;
				data <<= 1;
			}
		}

		/*
		 * The processing of TA (turnaround) about reading of the frame format of MII Management Interface
		 * which is provided by "Table 22-12" of "22.2.4.5" of "IEEE 802.3-2008_section2".
		 */
		void trans_Zto0_()
		{
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR = 0x00000000;
			}
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR = 0x00000001;
			}
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR = 0x00000001;
			}
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR = 0x00000000;
			}
		}

		/*
		 * The processing of TA (turnaround) about writing of the frame format of MII Management Interface
		 * which is provided by "Table 22-12" of "22.2.4.5" of "IEEE 802.3-2008_section2".
		 */
		void trans_1to0_() {
			mii_write1_();
			mii_write0_();
		}

		/*
		 * The processing of one bit about frame format of MII Management Interface which is
		 * provided by "Table 22-12" of "22.2.4.5" of "IEEE 802.3-2008_section2".
		 * The data that 1 is output.
		 */
		void mii_write1_()
		{
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR = 0x00000006;
			}
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR = 0x00000007;
			}
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR = 0x00000007;
			}
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR = 0x00000006;
			}
		}

		/*
		 * The processing of one bit about frame format of MII Management Interface which is
		 * provided by "Table 22-12" of "22.2.4.5" of "IEEE 802.3-2008_section2".
		 * The data that 0 is output.
		 */
		void mii_write0_()
		{
			for(int j = PHY_MII_WAIT; j > 0; j--) {
		        ETHC::PIR = 0x00000002;
    		}
			for(int j = PHY_MII_WAIT; j > 0; j--) {
		        ETHC::PIR = 0x00000003;
    		}
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR = 0x00000003;
			}
			for(int j = PHY_MII_WAIT; j > 0; j--) {
				ETHC::PIR.LONG = 0x00000002;
			}
		}

		void nop_() const {
			asm("nop");
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		phy_t() : local_advertise_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  Resets Ethernet PHY device
			@return OK: true, ERROR: false
		*/
		//-----------------------------------------------------------------//
		bool init()
		{
			/* Reset PHY */
			write_(PHY_REG_CONTROL, PHY_CONTROL_RESET);

			uint16_t count = 0;
			uint16_t reg;
			/* Reset completion waiting */
			do {
				reg = read_(PHY_REG_CONTROL);
				count++;
			} while ( (reg & PHY_CONTROL_RESET) && (count < PHY_DELAY_RESET) );

			if( count < PHY_DELAY_RESET ) {
				/*
				 * When KSZ8041NL of the Micrel, Inc. is used,
				 * the pin that outputs the state of LINK is used combinedly with ACTIVITY in default.
				 * The setting of the pin is changed so that only the state of LINK is output.
				 */
#ifdef MICREL_KSZ8041NL
				reg = read_(PHY_REG_PHY_CONTROL_1);
				reg &= ~0x8000;
				reg |= 0x4000;
				write_(PHY_REG_PHY_CONTROL_1, reg);
#endif
				return true;
			}
			return false;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  Starts autonegotiate
			@param[in]	PauseFrameEnableFlag
		*/
		//-----------------------------------------------------------------//
		void start_autonegotiate(bool PauseFrameEnableFlag)
		{
			/* Set local ability */
			/* When pause frame is not used */
			if (PauseFrameEnableFlag) {
				local_advertise_ = (PHY_AN_ADVERTISEMENT_100F    |
									PHY_AN_ADVERTISEMENT_100H    |
									PHY_AN_ADVERTISEMENT_10F     |
									PHY_AN_ADVERTISEMENT_10H     |
									PHY_AN_ADVERTISEMENT_SELECTOR);
			} else {
				local_advertise_ = (PHY_AN_ADVERTISEMENT_ASM_DIR |
									PHY_AN_ADVERTISEMENT_PAUSE   |
									PHY_AN_ADVERTISEMENT_100F    |
									PHY_AN_ADVERTISEMENT_100H    |
									PHY_AN_ADVERTISEMENT_10F     |
									PHY_AN_ADVERTISEMENT_10H     |
									PHY_AN_ADVERTISEMENT_SELECTOR);
			}

			/* Configure what the PHY and the Ethernet controller on this board supports */
			write_(PHY_REG_AN_ADVERTISEMENT, local_advertise_);
			write_(PHY_REG_CONTROL, (PHY_CONTROL_AN_ENABLE | PHY_CONTROL_AN_RESTART) );
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  reports the other side's physical capability
			@param[in]	line_speed_duplex	both the line speed and the duplex
			@param[in]	local_pause			store the local pause bits.
			@param[in]	partner_pause		store the partner pause bits.
			@return OK: true, ERROR: false
		*/
		//-----------------------------------------------------------------//
		bool set_autonegotiate(LinkStat& line_speed_duplex, uint16_t& local_pause, uint16_t& partner_pause)
		{
			line_speed_duplex = LinkStat::NO_LINK;

			/* Because reading the first time shows the previous state, the Link status bit is read twice. */
			uint16_t reg = read_(PHY_REG_STATUS);
			reg = read_(PHY_REG_STATUS);

			/* When the link isn't up, return error */
			if (!(reg & PHY_STATUS_LINK_UP)) {
				nop_();
				return false;
			}

			/* Establish local pause capability */
			if (local_advertise_ & PHY_AN_ADVERTISEMENT_PAUSE) {
				local_pause |= (1 << 1);
    		}

			if (local_advertise_ & PHY_AN_ADVERTISEMENT_ASM_DIR) {
				local_pause |= 1;
			}

			/* When the auto-negotiation isn't completed, return error */
			if (!(reg & PHY_STATUS_AN_COMPLETE)) {
				return false;
			} else {
				/* Get the link partner response */
				reg = read_(PHY_REG_AN_LINK_PARTNER);

				/* Establish partner pause capability */
				if ( (reg & PHY_AN_LINK_PARTNER_PAUSE) == PHY_AN_LINK_PARTNER_PAUSE ) {
					partner_pause = ( 1 << 1 );
				}

				if ( (reg & PHY_AN_LINK_PARTNER_ASM_DIR) == PHY_AN_LINK_PARTNER_ASM_DIR ) {
					partner_pause |= 1;
				}

				/* Establish the line speed and the duplex */
				if ( reg & PHY_AN_LINK_PARTNER_10H ) {
					line_speed_duplex = LinkStat::LINK_10H;
				}

				if ( reg & PHY_AN_LINK_PARTNER_10F ) {
					line_speed_duplex = LinkStat::LINK_10F;
				}

				if ( reg & PHY_AN_LINK_PARTNER_100H ) {
					line_speed_duplex = LinkStat::LINK_100H;
				}

				if ( reg & PHY_AN_LINK_PARTNER_100F ) {
					line_speed_duplex = LinkStat::LINK_100F;
				}

			return true;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  Returns the status of the physical link
			@return false: links is down, true: otherwise
		*/
		//-----------------------------------------------------------------//
		bool get_link_status()
		{
			/* Because reading the first time shows the previous state, the Link status bit is read twice. */
			uint16_t reg = read_(PHY_REG_STATUS);
			reg = read_(PHY_REG_STATUS);

			/* When the link isn't up, return error */
			if (!(reg & PHY_STATUS_LINK_UP)) {
				nop_();
				/* Link is down */
				return false;
			} else {
				/* Link is up */
				return true;
			}
		}

	};
}
<commit_msg>remove file<commit_after><|endoftext|>


<commit_before>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "strigiconfig.h"
#include "oleinputstream.h"
#include "oleendanalyzer.h"
#include "subinputstream.h"
#include "analysisresult.h"
#include "fieldtypes.h"
#include "textutils.h"
#include <sstream>
using namespace Strigi;
using namespace std;

void
OleEndAnalyzerFactory::registerFields(FieldRegister& reg) {
    static const char summaryKey[] = {0xE0,0x85,0x9F,0xF2,0xF9,0x4F,0x68,0x10,
        0xAB,0x91,0x08,0x00,0x2B,0x27,0xB3,0xD9};
    static const char docSummaryKey[]= {0x02,0xD5,0xCD,0xD5,0x9C,0x2E,0x1B,0x10,
        0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE};
    const RegisteredField* r;
    string key;
    map<int,const RegisteredField*>* m;

    // register the fields for the Summary Information Stream
    key.assign(summaryKey, 16);
    m = &fieldsMaps[key];
    r = reg.registerField("title", FieldRegister::stringType, 1, 0);
    if (r) (*m)[2] = r;
    r = reg.registerField("subject", FieldRegister::stringType, -1, 0);
    if (r) (*m)[3] = r;
    r = reg.registerField("author", FieldRegister::stringType, -1, 0);
    if (r) (*m)[4] = r;
    r = reg.registerField("keywords", FieldRegister::stringType, -1, 0);
    if (r) (*m)[5] = r;
    r = reg.registerField("comments", FieldRegister::stringType, -1, 0);
    if (r) (*m)[6] = r;

    // register the fields for the Document Summary Information Stream
    key.assign(docSummaryKey, 16);
    m = &fieldsMaps[key];
    r = reg.registerField("category", FieldRegister::stringType, 1, 0);
    if (r) (*m)[2] = r;
    r = reg.registerField("presentationtarget",FieldRegister::stringType, 1, 0);
    if (r) (*m)[3] = r;
    r = reg.registerField("manager", FieldRegister::stringType, 1, 0);
    if (r) (*m)[14] = r;
    r = reg.registerField("company", FieldRegister::stringType, 1, 0);
    if (r) (*m)[15] = r;
}
const map<int, const RegisteredField*>*
OleEndAnalyzerFactory::getFieldMap(const string& key) const {
    map<string, map<int,const RegisteredField*> >::const_iterator i
        = fieldsMaps.find(key);
    return (i == fieldsMaps.end()) ?0 :&i->second;
}
bool
OleEndAnalyzer::checkHeader(const char* header, int32_t headersize) const {
    return OleInputStream::checkHeader(header, headersize);
}
bool
tryThumbsdbEntry(const string& name, AnalysisResult& ar, InputStream* in) {
    static const char magic[] = {0x0c, 0, 0, 0, 0x01, 0, 0, 0};
    const char* d;
    uint32_t nread = in->read(d, 12, 12);
    if (nread != 12 || memcmp(magic, d, 8)) {
        in->reset(0);
        return false;
    }
    SubInputStream thumb(in, in->size()-12);
    ar.indexChild(name, 0, &thumb);
    return true;
}
void
tryPictures(AnalysisResult& ar, InputStream* in) {
    const char* d;
    int32_t nread = in->read(d, 25, 25);
    ostringstream s;
    int pos = 1;
    while (nread == 25) {
        uint32_t size = readLittleEndianInt32(d+4)-17;
        SubInputStream sub(in, size);
        s << "Pictures/" << pos++;
        ar.indexChild(s.str(), 0, &sub);
        s.str("");
        nread = in->read(d, 25, 25);
    }
}
// format description: http://jakarta.apache.org/poi/hpsf/internals.html
bool
OleEndAnalyzer::tryPropertyStream(AnalysisResult& idx,
        InputStream* in) {
    static const char magic[] = {0xfe, 0xff, 0, 0};
    const char* d;
    uint32_t nread = in->read(d, 28, 28);
    in->reset(0);
    if (nread != 28 || memcmp(magic, d, 4)) {
        return false;
    }
    // read all the data
    nread = in->read(d, in->size(), in->size());
    if (nread != in->size()) {
        return false;
    }
    int32_t n = readLittleEndianUInt32(d+24);
    if (in->size() < 28+n*20) {
        return false;
    }
    for (int32_t i=0; i<n; ++i) {
        const char* key = d + 28 + i*20;
        int32_t offset = readLittleEndianInt32(key+16);
        if (offset >= in->size()) {
            return false;
        }
        handlePropertyStream(key, d+offset, d+in->size());
    }
    return true;
}
void
OleEndAnalyzer::handleProperty(const RegisteredField* field, const char* data) {
    int32_t datatype = readLittleEndianInt32(data);
    // currently we only support null-terminated strings
    if (datatype == 30) {
        result->addValue(field, data+4);
    }
}
void
OleEndAnalyzer::handlePropertyStream(const char* key, const char* data,
        const char* end) {
    // get the fieldtable
    string k(key, 16);
    const map<int, const RegisteredField*>* table = factory->getFieldMap(k);
    if (table == 0) {
        return;
    }

    int32_t len = readLittleEndianInt32(data);
    const char* p = data + 8;
    const char* n = data + readLittleEndianInt32(data+4)*4 + 8;
    if (len < 0 || len > end-data || n > end) {
        return;
    }
    map<int, const RegisteredField*>::const_iterator field;
    while (p < n) {
        int32_t id = readLittleEndianInt32(p);
        field = table->find(id);
        if (field != table->end()) {
            int32_t offset = readLittleEndianInt32(p+4);
            handleProperty(field->second, data+offset);
        }
        p += 8;
    }
}
char
OleEndAnalyzer::analyze(AnalysisResult& ar, InputStream* in) {
    if(!in)
        return -1;

    result = &ar;
    OleInputStream ole(in);
    InputStream *s = ole.nextEntry();
    if (ole.status()) {
        fprintf(stderr, "error: %s\n", ole.error());
//        exit(1);
    }
    while (s) {
        const string& name = ole.entryInfo().filename;
        if (name.size()) {
            if (tryThumbsdbEntry(name, ar, s)) {
            } else if (name[0] == 5) {
                // todo: handle property stream
                tryPropertyStream(ar, s);
            } else if (name == "Pictures") {
                tryPictures(ar, s);
            } else {
                ar.indexChild(name, ole.entryInfo().mtime,
                    s);
            }
        }
        s = ole.nextEntry();
    }
    if (ole.status() == Error) {
        m_error = ole.error();
        return -1;
    } else {
        m_error.resize(0);
    }
    return 0;
}
<commit_msg>bit of docu<commit_after>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "strigiconfig.h"
#include "oleinputstream.h"
#include "oleendanalyzer.h"
#include "subinputstream.h"
#include "analysisresult.h"
#include "fieldtypes.h"
#include "textutils.h"
#include <sstream>
using namespace Strigi;
using namespace std;

void
OleEndAnalyzerFactory::registerFields(FieldRegister& reg) {
    static const char summaryKey[] = {0xE0,0x85,0x9F,0xF2,0xF9,0x4F,0x68,0x10,
        0xAB,0x91,0x08,0x00,0x2B,0x27,0xB3,0xD9};
    static const char docSummaryKey[]= {0x02,0xD5,0xCD,0xD5,0x9C,0x2E,0x1B,0x10,
        0x93,0x97,0x08,0x00,0x2B,0x2C,0xF9,0xAE};
    const RegisteredField* r;
    string key;
    map<int,const RegisteredField*>* m;

    // register the fields for the Summary Information Stream
    key.assign(summaryKey, 16);
    m = &fieldsMaps[key];
    r = reg.registerField("title", FieldRegister::stringType, 1, 0);
    if (r) (*m)[2] = r;
    r = reg.registerField("subject", FieldRegister::stringType, -1, 0);
    if (r) (*m)[3] = r;
    r = reg.registerField("author", FieldRegister::stringType, -1, 0);
    if (r) (*m)[4] = r;
    r = reg.registerField("keywords", FieldRegister::stringType, -1, 0);
    if (r) (*m)[5] = r;
    r = reg.registerField("comments", FieldRegister::stringType, -1, 0);
    if (r) (*m)[6] = r;

    // register the fields for the Document Summary Information Stream
    key.assign(docSummaryKey, 16);
    m = &fieldsMaps[key];
    r = reg.registerField("category", FieldRegister::stringType, 1, 0);
    if (r) (*m)[2] = r;
    r = reg.registerField("presentationtarget",FieldRegister::stringType, 1, 0);
    if (r) (*m)[3] = r;
    r = reg.registerField("manager", FieldRegister::stringType, 1, 0);
    if (r) (*m)[14] = r;
    r = reg.registerField("company", FieldRegister::stringType, 1, 0);
    if (r) (*m)[15] = r;
}
const map<int, const RegisteredField*>*
OleEndAnalyzerFactory::getFieldMap(const string& key) const {
    map<string, map<int,const RegisteredField*> >::const_iterator i
        = fieldsMaps.find(key);
    return (i == fieldsMaps.end()) ?0 :&i->second;
}
bool
OleEndAnalyzer::checkHeader(const char* header, int32_t headersize) const {
    return OleInputStream::checkHeader(header, headersize);
}
bool
tryThumbsdbEntry(const string& name, AnalysisResult& ar, InputStream* in) {
    static const char magic[] = {0x0c, 0, 0, 0, 0x01, 0, 0, 0};
    const char* d;
    uint32_t nread = in->read(d, 12, 12);
    if (nread != 12 || memcmp(magic, d, 8)) {
        in->reset(0);
        return false;
    }
    SubInputStream thumb(in, in->size()-12);
    ar.indexChild(name, 0, &thumb);
    return true;
}
/**
 * Exctract images from a 'Pictures' field from a ppt file.
 * http://jakarta.apache.org/poi/apidocs/org/apache/poi/hslf/model/Picture.html
 **/
void
tryPictures(AnalysisResult& ar, InputStream* in) {
    const char* d;
    int32_t nread = in->read(d, 25, 25);
    ostringstream s;
    int pos = 1;
    while (nread == 25) {
        uint32_t size = readLittleEndianInt32(d+4)-17;
        SubInputStream sub(in, size);
        s << "Pictures/" << pos++;
        ar.indexChild(s.str(), 0, &sub);
        s.str("");
        nread = in->read(d, 25, 25);
    }
}
// format description: http://jakarta.apache.org/poi/hpsf/internals.html
bool
OleEndAnalyzer::tryPropertyStream(AnalysisResult& idx,
        InputStream* in) {
    static const char magic[] = {0xfe, 0xff, 0, 0};
    const char* d;
    uint32_t nread = in->read(d, 28, 28);
    in->reset(0);
    if (nread != 28 || memcmp(magic, d, 4)) {
        return false;
    }
    // read all the data
    nread = in->read(d, in->size(), in->size());
    if (nread != in->size()) {
        return false;
    }
    int32_t n = readLittleEndianUInt32(d+24);
    if (in->size() < 28+n*20) {
        return false;
    }
    for (int32_t i=0; i<n; ++i) {
        const char* key = d + 28 + i*20;
        int32_t offset = readLittleEndianInt32(key+16);
        if (offset >= in->size()) {
            return false;
        }
        handlePropertyStream(key, d+offset, d+in->size());
    }
    return true;
}
void
OleEndAnalyzer::handleProperty(const RegisteredField* field, const char* data) {
    int32_t datatype = readLittleEndianInt32(data);
    // currently we only support null-terminated strings
    if (datatype == 30) {
        result->addValue(field, data+4);
    }
}
void
OleEndAnalyzer::handlePropertyStream(const char* key, const char* data,
        const char* end) {
    // get the fieldtable
    string k(key, 16);
    const map<int, const RegisteredField*>* table = factory->getFieldMap(k);
    if (table == 0) {
        return;
    }

    int32_t len = readLittleEndianInt32(data);
    const char* p = data + 8;
    const char* n = data + readLittleEndianInt32(data+4)*4 + 8;
    if (len < 0 || len > end-data || n > end) {
        return;
    }
    map<int, const RegisteredField*>::const_iterator field;
    while (p < n) {
        int32_t id = readLittleEndianInt32(p);
        field = table->find(id);
        if (field != table->end()) {
            int32_t offset = readLittleEndianInt32(p+4);
            handleProperty(field->second, data+offset);
        }
        p += 8;
    }
}
char
OleEndAnalyzer::analyze(AnalysisResult& ar, InputStream* in) {
    if(!in)
        return -1;

    result = &ar;
    OleInputStream ole(in);
    InputStream *s = ole.nextEntry();
    if (ole.status()) {
        fprintf(stderr, "error: %s\n", ole.error());
//        exit(1);
    }
    while (s) {
        const string& name = ole.entryInfo().filename;
        if (name.size()) {
            if (tryThumbsdbEntry(name, ar, s)) {
            } else if (name[0] == 5) {
                // todo: handle property stream
                tryPropertyStream(ar, s);
            } else if (name == "Pictures") {
                tryPictures(ar, s);
            } else {
                ar.indexChild(name, ole.entryInfo().mtime,
                    s);
            }
        }
        s = ole.nextEntry();
    }
    if (ole.status() == Error) {
        m_error = ole.error();
        return -1;
    } else {
        m_error.resize(0);
    }
    return 0;
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <fstream>
#include <iostream>
#include <ostream>
#include <string>
#include "Getopt.hpp"
#include "snarkfront.hpp"

using namespace snarkfront;
using namespace snarklib;
using namespace std;

void printUsage(const char* exeName) {
    const string
        PAIR = " -p BN128|Edwards",
        KEY = " -k",
        OUT = " [-o output_file]";

    cout << "key pair entropy: " << exeName << PAIR << KEY << OUT << endl
         << "proof entropy:    " << exeName << PAIR << OUT << endl;

    exit(EXIT_FAILURE);
}

template <typename PAIRING>
void writeEntropy(ostream& os, const bool is_keypair) {
    if (is_keypair) {
        PPZK_KeypairRandomness<typename PAIRING::Fr, typename PAIRING::Fr> entropy(1);
        os << entropy;

    } else {
        PPZK_ProofRandomness<typename PAIRING::Fr> entropy(0);
        os << entropy;
    }
}

int main(int argc, char *argv[])
{
    Getopt cmdLine(argc, argv, "po", "", "k");
    if (!cmdLine || cmdLine.empty()) printUsage(argv[0]);

    const auto pairing = cmdLine.getString('p');
    const auto outfile = cmdLine.getString('o');
    const auto is_keypair = cmdLine.getFlag('k');

    if (!validPairingName(pairing)) {
        cerr << "error: elliptic curve pairing " << pairing << endl;
        exit(EXIT_FAILURE);
    }

    ofstream ofs(outfile);
    if (!outfile.empty() && !ofs) {
        cerr << "error: output file " << outfile << endl;
        exit(EXIT_FAILURE);
    }

    ostream& os = outfile.empty() ? cout : ofs;

    if (pairingBN128(pairing)) {
        // Barreto-Naehrig 128 bits
        init_BN128();
        writeEntropy<BN128_PAIRING>(os, is_keypair);

    } else if (pairingEdwards(pairing)) {
        // Edwards 80 bits
        init_Edwards();
        writeEntropy<EDWARDS_PAIRING>(os, is_keypair);
    }

    exit(EXIT_SUCCESS);
}
<commit_msg>Lagrange point and blind greeks randomness<commit_after>#include <cstdlib>
#include <fstream>
#include <iostream>
#include <ostream>
#include <string>
#include "Getopt.hpp"
#include "snarkfront.hpp"

using namespace snarkfront;
using namespace snarklib;
using namespace std;

void printUsage(const char* exeName) {
    const string
        PAIR = " -p BN128|Edwards",
        KEY = " -k",
        OUT = " [-o output_file]";

    cout << "key pair entropy: " << exeName << PAIR << KEY << OUT << endl
         << "proof entropy:    " << exeName << PAIR << OUT << endl;

    exit(EXIT_FAILURE);
}

template <typename PAIRING>
void writeEntropy(ostream& os, const bool is_keypair) {
    if (is_keypair) {
        PPZK_LagrangePoint<typename PAIRING::Fr> lagrangeRand(0);
        PPZK_BlindGreeks<typename PAIRING::Fr, typename PAIRING::Fr> blindRand(0);
        os << lagrangeRand << blindRand;

    } else {
        PPZK_ProofRandomness<typename PAIRING::Fr> entropy(0);
        os << entropy;
    }
}

int main(int argc, char *argv[])
{
    Getopt cmdLine(argc, argv, "po", "", "k");
    if (!cmdLine || cmdLine.empty()) printUsage(argv[0]);

    const auto pairing = cmdLine.getString('p');
    const auto outfile = cmdLine.getString('o');
    const auto is_keypair = cmdLine.getFlag('k');

    if (!validPairingName(pairing)) {
        cerr << "error: elliptic curve pairing " << pairing << endl;
        exit(EXIT_FAILURE);
    }

    ofstream ofs(outfile);
    if (!outfile.empty() && !ofs) {
        cerr << "error: output file " << outfile << endl;
        exit(EXIT_FAILURE);
    }

    ostream& os = outfile.empty() ? cout : ofs;

    if (pairingBN128(pairing)) {
        // Barreto-Naehrig 128 bits
        init_BN128();
        writeEntropy<BN128_PAIRING>(os, is_keypair);

    } else if (pairingEdwards(pairing)) {
        // Edwards 80 bits
        init_Edwards();
        writeEntropy<EDWARDS_PAIRING>(os, is_keypair);
    }

    exit(EXIT_SUCCESS);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2018 Markus Lindelöw
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files(the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"

#include <tinycsocket.h>

TEST_CASE("init test")
{
    CHECK(tcs_lib_init() == TINYCSOCKET_SUCCESS);
    CHECK(tcs_lib_free() == TINYCSOCKET_SUCCESS);
}
<commit_msg>Add UDP test<commit_after>/*
 * Copyright 2018 Markus Lindelöw
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files(the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest.h"

#include <tinycsocket.h>
#include <thread>

TEST_CASE("init test")
{
    CHECK(tcs_lib_init() == TINYCSOCKET_SUCCESS);
    CHECK(tcs_lib_free() == TINYCSOCKET_SUCCESS);
}

TEST_CASE("UDP test")
{
  CHECK(tcs_lib_init() == TINYCSOCKET_SUCCESS);

  struct tcs_addrinfo* address_info = NULL;

  struct tcs_addrinfo hints = { 0 };
  hints.ai_family = TINYCSOCKET_AF_INET;
  hints.ai_socktype = TINYCSOCKET_SOCK_DGRAM;

  tcs_getaddrinfo("localhost", "1212", &hints, &address_info);

  // Setup UDP reciever
  CHECK(tcs_lib_init() == TINYCSOCKET_SUCCESS);
  tcs_socket recv_soc = TINYCSOCKET_NULLSOCKET;

  bool didBind = false;
  for (struct tcs_addrinfo* address_iterator = address_info; address_iterator != NULL; address_iterator = address_iterator->ai_next)
  {
    if (tcs_create(&recv_soc, address_iterator->ai_family, address_iterator->ai_socktype, address_iterator->ai_protocol) != TINYCSOCKET_SUCCESS)
      continue;

    if (tcs_bind(recv_soc, address_iterator->ai_addr, address_iterator->ai_addrlen) != TINYCSOCKET_SUCCESS)
      continue;

    didBind = true;
    break;
  }

  CHECK(didBind);

  struct tcs_sockaddr remote_address = { 0 };
  size_t remote_address_size = sizeof(remote_address);
  uint8_t recv_buffer[1024] = { 0 };
  size_t bytes_recieved = 0;

  std::thread recv_thread([&]() {
    CHECK(tcs_recvfrom(recv_soc, recv_buffer, sizeof(recv_buffer) - sizeof('\0'), 0, &remote_address, &remote_address_size, &bytes_recieved) == TINYCSOCKET_SUCCESS);
    recv_buffer[bytes_recieved] = '\0';
  });

  // Setup UDP sender
  tcs_socket socket = TINYCSOCKET_NULLSOCKET;

  bool didConnect = false;
  for (struct tcs_addrinfo* address_iterator = address_info; address_iterator != NULL; address_iterator = address_iterator->ai_next)
  {
    if (tcs_create(&socket, address_iterator->ai_family, address_iterator->ai_socktype, address_iterator->ai_protocol) != TINYCSOCKET_SUCCESS)
      continue;

    if (tcs_connect(socket, address_iterator->ai_addr, address_iterator->ai_addrlen) != TINYCSOCKET_SUCCESS)
      continue;

    didConnect = true;
    break;
  }

  CHECK(didConnect);

  // Send message
  uint8_t msg[] = "hello world\n";
  CHECK(tcs_send(socket, msg, sizeof(msg), 0, NULL) == TINYCSOCKET_SUCCESS);

  // Join threads and check if we did send the message correctly
  recv_thread.join();
  CHECK(strcmp(reinterpret_cast<const char*>(recv_buffer), reinterpret_cast<const char*>(msg)) == 0);
  CHECK(tcs_freeaddrinfo(&address_info) == TINYCSOCKET_SUCCESS);
  CHECK(tcs_close(&recv_soc) == TINYCSOCKET_SUCCESS);
  CHECK(tcs_lib_free() == TINYCSOCKET_SUCCESS);
}
<|endoftext|>


<commit_before>#define CATCH_CONFIG_RUNNER
#include <iostream>
#include "./Catch/catch.hpp"
#include "../include/Elson.hpp"

using namespace JSON;

TEST_CASE( "base/types", "Basic JSON Data types" ) {
    Value val = 5;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("5") == 0);

    val = 3.0;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("3") == 0);

    val = 1L;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("1") == 0);

    val = 7u;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("7") == 0);

    val = -7.5;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("-7.5") == 0);

    val = -.05;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("-0.05") == 0);

    val = 1E3;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("1000") == 0);

    val = -7.5;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<unsigned int>() == 7);

    val = "5";
    REQUIRE(val.is(JSON_STRING));
    REQUIRE(val.as<int>() == 5);

    val = "5L";
    REQUIRE(val.is(JSON_STRING));
    REQUIRE(val.as<long>() == 5L);

    val = "\\";
    REQUIRE(val.is(JSON_STRING));
    REQUIRE(val.as<std::string>().compare("\\") == 0);

    val = true;
    REQUIRE(val.is(JSON_BOOL));
    REQUIRE(val.as<bool>());
    REQUIRE(val.as<int>() == 1);
    REQUIRE(val.as<std::string>() == "true");

    val = false;
    REQUIRE(val.is(JSON_BOOL));
    REQUIRE(!val.as<bool>());
    REQUIRE(val.as<int>() == 0);
    REQUIRE(val.as<std::string>() == "false");

    val = { true, false };
    REQUIRE(val[0].is(JSON_BOOL));
    REQUIRE(val[1].is(JSON_BOOL));
    REQUIRE(val.is(JSON_ARRAY));
    REQUIRE(val[0].as<bool>());
    REQUIRE(!val[1].as<bool>());

    val = { 1, .5, "hello world", true, false, null };
    REQUIRE(val[0].is(JSON_NUMBER));
    REQUIRE(val[1].is(JSON_NUMBER));
    REQUIRE(val[2].is(JSON_STRING));
    REQUIRE(val[3].is(JSON_BOOL));
    REQUIRE(val[4].is(JSON_BOOL));
    REQUIRE(val[5].is(JSON_NULL));

    val = { {1,0,0}, {0,1,0},{0,0,1} };
    REQUIRE(val.is(JSON_ARRAY));
    REQUIRE(val.as<Array>().size() == 3);
    REQUIRE(val[0].is(JSON_ARRAY));
    REQUIRE(val[1].is(JSON_ARRAY));
    REQUIRE(val[2].is(JSON_ARRAY));
    REQUIRE(val[0].as<Array>().size() == 3);
    REQUIRE(val[1].as<Array>().size() == 3);
    REQUIRE(val[2].as<Array>().size() == 3);
    REQUIRE(val[0][0].is(JSON_NUMBER));
    REQUIRE(val[0][1].is(JSON_NUMBER));
    REQUIRE(val[0][2].is(JSON_NUMBER));
    REQUIRE(val[1][0].is(JSON_NUMBER));
    REQUIRE(val[1][1].is(JSON_NUMBER));
    REQUIRE(val[1][2].is(JSON_NUMBER));
    REQUIRE(val[2][0].is(JSON_NUMBER));
    REQUIRE(val[2][1].is(JSON_NUMBER));
    REQUIRE(val[2][2].is(JSON_NUMBER));

    std::string key = "property";
    val = Object { { "property", "value" } };
    REQUIRE(val.is(JSON_OBJECT));
    REQUIRE(val["property"].is(JSON_STRING));
    REQUIRE(val[key].is(JSON_STRING));
    REQUIRE(val[std::string("property")].is(JSON_STRING));

    REQUIRE(val["property"].as<std::string>().compare("value") == 0);

    val["property"] = 42;
    REQUIRE(val["property"].is(JSON_NUMBER));
    REQUIRE(val[key].as<unsigned int>() == 42);
}

TEST_CASE( "base/parse", "Basic parsing") {
    Parser p;
    Printer printer;
    Value val;

    REQUIRE_THROWS(p.parse(val, "[]a"));
    REQUIRE_THROWS(p.parse(val, "a[]"));

    REQUIRE_NOTHROW(p.parse(val, ""));
    REQUIRE(val.is(JSON_NULL));

    auto numbers = {"0", "1", "1E3", "1e-3", "0.5", "-.05e-07"};

    for (auto number: numbers) {
        REQUIRE_NOTHROW(p.parse(val, number));
        REQUIRE(val.is(JSON_NUMBER));
    }

    REQUIRE_THROWS(p.parse(val, "-0.5w4"));

    std::vector<std::string> strings = {
        "\"\"",
        "\"0\"",
        "\"hello world\"",
        "\"äöüȩéáã\""
    };

    for (int i = 0; i < strings.size(); i++) {
        REQUIRE_NOTHROW(p.parse(val, strings[i]));
        REQUIRE(printer.print(val).compare(strings[i]) == 0);
    }

    std::map<std::string, std::string> escapes = {
        { "\"\\\\\"", "\"\\\"" },
        { "\"\\/\"", "\"/\"" },
        { "\"\\u5022\"", "\"倢\"" }
    };

    for (auto pair: escapes) {
        REQUIRE_NOTHROW(p.parse(val, pair.first));
        REQUIRE(printer.print(val).compare(pair.second) == 0);
    }

    REQUIRE_NOTHROW(p.parse(val, "true"));
    REQUIRE(val.is(JSON_BOOL));
    REQUIRE(val.as<bool>());
    REQUIRE(printer.print(val).compare("true") == 0);

    REQUIRE_NOTHROW(p.parse(val, "false"));
    REQUIRE(val.is(JSON_BOOL));
    REQUIRE(!val.as<bool>());
    REQUIRE(printer.print(val).compare("false") == 0);

    REQUIRE_NOTHROW(p.parse(val, "null"));
    REQUIRE(val.is(JSON_NULL));
    REQUIRE(printer.print(val).compare("null") == 0);

    REQUIRE_NOTHROW(p.parse(val, "[]"));
    REQUIRE(val.is(JSON_ARRAY));
    REQUIRE(printer.print(val).compare("[]") == 0);
    REQUIRE(val.as<Array>().size() == 0);

    REQUIRE_NOTHROW(p.parse(val, "[ 1, 2,   4   ]"));
    REQUIRE(val.is(JSON_ARRAY));
    REQUIRE(printer.print(val).compare("[1,2,4]") == 0);
    REQUIRE(val.as<Array>().size() == 3);

    REQUIRE_THROWS(p.parse(val, "["));
    REQUIRE_THROWS(p.parse(val, "]"));
    REQUIRE_THROWS(p.parse(val, "[["));
    REQUIRE_THROWS(p.parse(val, "]]"));
    REQUIRE_THROWS(p.parse(val, "[,]"));
    REQUIRE_THROWS(p.parse(val, "[][]"));
    REQUIRE_THROWS(p.parse(val, "[1,]"));
    REQUIRE_THROWS(p.parse(val, "[,1]"));
    REQUIRE_THROWS(p.parse(val, "[1,2"));
    REQUIRE_THROWS(p.parse(val, "1,2]"));
    REQUIRE_THROWS(p.parse(val, "[[],[]"));
    REQUIRE_THROWS(p.parse(val, "[[],]]"));
    REQUIRE_THROWS(p.parse(val, "[[1,2,],[]]"));
    REQUIRE_THROWS(p.parse(val, "[[1,2,] []]"));

    REQUIRE_NOTHROW(p.parse(val, "[[]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[]]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[],[]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[]],[[]]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[1]],[[2]]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[1,null,true,false,\"\"]],[[]]]"));
    REQUIRE(val[0][0][0].is(JSON_NUMBER));
    REQUIRE(val[0][0][1].is(JSON_NULL));
    REQUIRE(val[0][0][2].is(JSON_BOOL));
    REQUIRE(val[0][0][3].is(JSON_BOOL));
    REQUIRE(val[0][0][4].is(JSON_STRING));
    REQUIRE(val[0][0].as<Array>().size() == 5);
    REQUIRE(printer.print(val).compare("[[[1,null,true,false,\"\"]],[[]]]") == 0);

    val[0][0].as<Array>().push_back(null);
    REQUIRE(val[0][0].as<Array>().size() == 5);

    val[0][0].asMutable<Array>().push_back(null);
    REQUIRE(val[0][0].as<Array>().size() == 6);

    REQUIRE_NOTHROW(p.parse(val, "{}"));
    REQUIRE_THROWS(p.parse(val, "{1}"));
    REQUIRE_THROWS(p.parse(val, "{{}}"));
    REQUIRE_NOTHROW(p.parse(val, "{\"a\": \"b\"}"));
    REQUIRE(val["a"].as<std::string>().compare("b") == 0);
    REQUIRE_THROWS(val.as<double>());

    REQUIRE_NOTHROW(p.parse(val, "[{}]"));
    REQUIRE_NOTHROW(p.parse(val, "[{},{}]"));
    REQUIRE_NOTHROW(p.parse(val, "[{},[]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[{}]]]"));
    REQUIRE_THROWS(p.parse(val, "[[[{}]]"));
    REQUIRE_THROWS(p.parse(val, "[{}]]"));
    REQUIRE_THROWS(p.parse(val, "{[]}"));
}

TEST_CASE( "base/unicode", "Unicode escape handling") {
    Parser p;
    Printer printer;
    Value val;

    std::map<std::string, std::string> escapes = {
        { "\"\\u0041\"", "\"A\"" },
        { "\"\\u0042\"", "\"B\"" },
        { "\"\\u0043\"", "\"C\"" },
        { "\"\\u0044\"", "\"D\"" },
        { "\"\\u0045\"", "\"E\"" },
        { "\"\\u0046\"", "\"F\"" },
        { "\"\\u0047\"", "\"G\"" },
        { "\"\\u0048\"", "\"H\"" },
        { "\"\\u0049\"", "\"I\"" },
        { "\"\\u0041\\u0042\\u0043\"", "\"ABC\"" },
        { "\"\\u0041B\\u0043\"", "\"ABC\"" },
        { "\"A\\u0042\\u0043\"", "\"ABC\"" },
        { "\"\\u0041\\u0042C\"", "\"ABC\"" },
        { "[\"\\u0041\\u0042C\"]", "[\"ABC\"]" },
        { "\"\\u0041\\u004212\"", "\"AB12\"" },
    };

    for (auto pair: escapes) {
        REQUIRE_NOTHROW(p.parse(val, pair.first));
        REQUIRE(printer.print(val).compare(pair.second) == 0);
    }

    REQUIRE_THROWS(p.parse(val, "\"\\u0fg\""));
    REQUIRE_THROWS(p.parse(val, "\"\\u00\""));
    REQUIRE_THROWS(p.parse(val, "\"\\u\""));
}

TEST_CASE( "utils/bas", "Unicode escape handling") {
    Value val = Object {
        { "a", 1 },
        { "b", 2 },
        { "c", 3}
    };

    PropertyList properties = traverse(val);
    REQUIRE(properties.size() == 3);

    PropertyList list = filter(traverse(val),
        [] (std::string name, Value& value) -> bool {
            return name.compare("b") == 0;
        });

    REQUIRE(list.size() == 2);
}

int main (int argc, char* const argv[]) {
    return Catch::Main( argc, argv );
}
<commit_msg>travis integration<commit_after>#define CATCH_CONFIG_RUNNER
#include <iostream>
#include "./Catch/catch.hpp"
#include "../include/Elson.hpp"

using namespace JSON;

TEST_CASE( "base/types", "Basic JSON Data types" ) {
    Value val = 5;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("5") == 0);

    val = 3.0;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("3") == 0);

    val = 1L;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("1") == 0);

    val = 7u;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("7") == 0);

    val = -7.5;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("-7.5") == 0);

    val = -.05;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("-0.05") == 0);

    val = 1E3;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<std::string>().compare("1000") == 0);

    val = -7.5;
    REQUIRE(val.is(JSON_NUMBER));
    REQUIRE(val.as<unsigned int>() == 7);

    val = "5";
    REQUIRE(val.is(JSON_STRING));
    REQUIRE(val.as<int>() == 5);

    val = "5L";
    REQUIRE(val.is(JSON_STRING));
    REQUIRE(val.as<long>() == 5L);

    val = "\\";
    REQUIRE(val.is(JSON_STRING));
    REQUIRE(val.as<std::string>().compare("\\") == 0);

    val = true;
    REQUIRE(val.is(JSON_BOOL));
    REQUIRE(val.as<bool>());
    REQUIRE(val.as<int>() == 1);
    REQUIRE(val.as<std::string>() == "true");

    val = false;
    REQUIRE(val.is(JSON_BOOL));
    REQUIRE(!val.as<bool>());
    REQUIRE(val.as<int>() == 0);
    REQUIRE(val.as<std::string>() == "false");

    val = { true, false };
    REQUIRE(val[0].is(JSON_BOOL));
    REQUIRE(val[1].is(JSON_BOOL));
    REQUIRE(val.is(JSON_ARRAY));
    REQUIRE(val[0].as<bool>());
    REQUIRE(!val[1].as<bool>());

    val = { 1, .5, "hello world", true, false, null };
    REQUIRE(val[0].is(JSON_NUMBER));
    REQUIRE(val[1].is(JSON_NUMBER));
    REQUIRE(val[2].is(JSON_STRING));
    REQUIRE(val[3].is(JSON_BOOL));
    REQUIRE(val[4].is(JSON_BOOL));
    REQUIRE(val[5].is(JSON_NULL));

    val = { {1,0,0}, {0,1,0},{0,0,1} };
    REQUIRE(val.is(JSON_ARRAY));
    REQUIRE(val.as<Array>().size() == 3);
    REQUIRE(val[0].is(JSON_ARRAY));
    REQUIRE(val[1].is(JSON_ARRAY));
    REQUIRE(val[2].is(JSON_ARRAY));
    REQUIRE(val[0].as<Array>().size() == 3);
    REQUIRE(val[1].as<Array>().size() == 3);
    REQUIRE(val[2].as<Array>().size() == 3);
    REQUIRE(val[0][0].is(JSON_NUMBER));
    REQUIRE(val[0][1].is(JSON_NUMBER));
    REQUIRE(val[0][2].is(JSON_NUMBER));
    REQUIRE(val[1][0].is(JSON_NUMBER));
    REQUIRE(val[1][1].is(JSON_NUMBER));
    REQUIRE(val[1][2].is(JSON_NUMBER));
    REQUIRE(val[2][0].is(JSON_NUMBER));
    REQUIRE(val[2][1].is(JSON_NUMBER));
    REQUIRE(val[2][2].is(JSON_NUMBER));

    std::string key = "property";
    val = Object { { "property", "value" } };
    REQUIRE(val.is(JSON_OBJECT));
    REQUIRE(val["property"].is(JSON_STRING));
    REQUIRE(val[key].is(JSON_STRING));
    REQUIRE(val[std::string("property")].is(JSON_STRING));

    REQUIRE(val["property"].as<std::string>().compare("value") == 0);

    val["property"] = 42;
    REQUIRE(val["property"].is(JSON_NUMBER));
    REQUIRE(val[key].as<unsigned int>() == 42);
}

TEST_CASE( "base/parse", "Basic parsing") {
    Parser p;
    Printer printer;
    Value val;

    REQUIRE_THROWS(p.parse(val, "[]a"));
    REQUIRE_THROWS(p.parse(val, "a[]"));

    REQUIRE_NOTHROW(p.parse(val, ""));
    REQUIRE(val.is(JSON_NULL));

    auto numbers = {"0", "1", "1E3", "1e-3", "0.5", "-.05e-07"};

    for (auto number: numbers) {
        REQUIRE_NOTHROW(p.parse(val, number));
        REQUIRE(val.is(JSON_NUMBER));
    }

    REQUIRE_THROWS(p.parse(val, "-0.5w4"));

    std::vector<std::string> strings = {
        "\"\"",
        "\"0\"",
        "\"hello world\"",
        "\"äöüȩéáã\""
    };

    for (int i = 0; i < strings.size(); i++) {
        REQUIRE_NOTHROW(p.parse(val, strings[i]));
        REQUIRE(printer.print(val).compare(strings[i]) == 0);
    }

    std::map<std::string, std::string> escapes = {
        { "\"\\\\\"", "\"\\\"" },
        { "\"\\/\"", "\"/\"" },
        { "\"\\u5022\"", "\"倢\"" }
    };

    for (auto pair: escapes) {
        REQUIRE_NOTHROW(p.parse(val, pair.first));
        REQUIRE(printer.print(val).compare(pair.second) == 0);
    }

    REQUIRE_NOTHROW(p.parse(val, "true"));
    REQUIRE(val.is(JSON_BOOL));
    REQUIRE(val.as<bool>());
    REQUIRE(printer.print(val).compare("true") == 0);

    REQUIRE_NOTHROW(p.parse(val, "false"));
    REQUIRE(val.is(JSON_BOOL));
    REQUIRE(!val.as<bool>());
    REQUIRE(printer.print(val).compare("false") == 0);

    REQUIRE_NOTHROW(p.parse(val, "null"));
    REQUIRE(val.is(JSON_NULL));
    REQUIRE(printer.print(val).compare("null") == 0);

    REQUIRE_NOTHROW(p.parse(val, "[]"));
    REQUIRE(val.is(JSON_ARRAY));
    REQUIRE(printer.print(val).compare("[]") == 0);
    REQUIRE(val.as<Array>().size() == 0);

    REQUIRE_NOTHROW(p.parse(val, "[ 1, 2,   4   ]"));
    REQUIRE(val.is(JSON_ARRAY));
    REQUIRE(printer.print(val).compare("[1,2,4]") == 0);
    REQUIRE(val.as<Array>().size() == 3);

    REQUIRE_THROWS(p.parse(val, "["));
    REQUIRE_THROWS(p.parse(val, "]"));
    REQUIRE_THROWS(p.parse(val, "[["));
    REQUIRE_THROWS(p.parse(val, "]]"));
    REQUIRE_THROWS(p.parse(val, "[,]"));
    REQUIRE_THROWS(p.parse(val, "[][]"));
    REQUIRE_THROWS(p.parse(val, "[1,]"));
    REQUIRE_THROWS(p.parse(val, "[,1]"));
    REQUIRE_THROWS(p.parse(val, "[1,2"));
    REQUIRE_THROWS(p.parse(val, "1,2]"));
    REQUIRE_THROWS(p.parse(val, "[[],[]"));
    REQUIRE_THROWS(p.parse(val, "[[],]]"));
    REQUIRE_THROWS(p.parse(val, "[[1,2,],[]]"));
    REQUIRE_THROWS(p.parse(val, "[[1,2,] []]"));

    REQUIRE_NOTHROW(p.parse(val, "[[]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[]]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[],[]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[]],[[]]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[1]],[[2]]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[1,null,true,false,\"\"]],[[]]]"));
    REQUIRE(val[0][0][0].is(JSON_NUMBER));
    REQUIRE(val[0][0][1].is(JSON_NULL));
    REQUIRE(val[0][0][2].is(JSON_BOOL));
    REQUIRE(val[0][0][3].is(JSON_BOOL));
    REQUIRE(val[0][0][4].is(JSON_STRING));
    REQUIRE(val[0][0].as<Array>().size() == 5);
    REQUIRE(printer.print(val).compare("[[[1,null,true,false,\"\"]],[[]]]") == 0);

    val[0][0].as<Array>().push_back(null);
    REQUIRE(val[0][0].as<Array>().size() == 5);

    val[0][0].asMutable<Array>().push_back(null);
    REQUIRE(val[0][0].as<Array>().size() == 6);

    REQUIRE_NOTHROW(p.parse(val, "{}"));
    REQUIRE_THROWS(p.parse(val, "{1}"));
    REQUIRE_THROWS(p.parse(val, "{{}}"));
    REQUIRE_NOTHROW(p.parse(val, "{\"a\": \"b\"}"));
    REQUIRE(val["a"].as<std::string>().compare("b") == 0);
    REQUIRE_THROWS(val.as<double>());

    REQUIRE_NOTHROW(p.parse(val, "[{}]"));
    REQUIRE_NOTHROW(p.parse(val, "[{},{}]"));
    REQUIRE_NOTHROW(p.parse(val, "[{},[]]"));
    REQUIRE_NOTHROW(p.parse(val, "[[[{}]]]"));
    REQUIRE_THROWS(p.parse(val, "[[[{}]]"));
    REQUIRE_THROWS(p.parse(val, "[{}]]"));
    REQUIRE_THROWS(p.parse(val, "{[]}"));
}

TEST_CASE( "base/unicode", "Unicode escape handling") {
    Parser p;
    Printer printer;
    Value val;

    std::map<std::string, std::string> escapes = {
        { "\"\\u0041\"", "\"A\"" },
        { "\"\\u0042\"", "\"B\"" },
        { "\"\\u0043\"", "\"C\"" },
        { "\"\\u0044\"", "\"D\"" },
        { "\"\\u0045\"", "\"E\"" },
        { "\"\\u0046\"", "\"F\"" },
        { "\"\\u0047\"", "\"G\"" },
        { "\"\\u0048\"", "\"H\"" },
        { "\"\\u0049\"", "\"I\"" },
        { "\"\\u0041\\u0042\\u0043\"", "\"ABC\"" },
        { "\"\\u0041B\\u0043\"", "\"ABC\"" },
        { "\"A\\u0042\\u0043\"", "\"ABC\"" },
        { "\"\\u0041\\u0042C\"", "\"ABC\"" },
        { "[\"\\u0041\\u0042C\"]", "[\"ABC\"]" },
        { "\"\\u0041\\u004212\"", "\"AB12\"" },
    };

    for (auto pair: escapes) {
        REQUIRE_NOTHROW(p.parse(val, pair.first));
        REQUIRE(printer.print(val).compare(pair.second) == 0);
    }

    REQUIRE_THROWS(p.parse(val, "\"\\u0fg\""));
    REQUIRE_THROWS(p.parse(val, "\"\\u00\""));
    REQUIRE_THROWS(p.parse(val, "\"\\u\""));
}

TEST_CASE( "utils/bas", "Unicode escape handling") {
    Value val = Object {
        { "a", 1 },
        { "b", 2 },
        { "c", 3}
    };

    PropertyList properties = traverse(val);
    REQUIRE(properties.size() == 3);

    PropertyList list = filter(traverse(val),
        [] (std::string name, Value& value) -> bool {
            return name.compare("b") == 0;
        });

    REQUIRE(list.size() == 2);
}

int main (int argc, char* const argv[]) {
    exit(Catch::Main( argc, argv ));
    return 0;
}
<|endoftext|>


<commit_before>#include "rasterizer.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>

// Currently sized according to the Larrabee rasterizer's description
#define FRAMEBUFFER_TILE_WIDTH_IN_PIXELS 128
#define FRAMEBUFFER_COARSE_BLOCK_WIDTH_IN_PIXELS 16
#define FRAMEBUFFER_FINE_BLOCK_WIDTH_IN_PIXELS 4

// Convenience
#define FRAMEBUFFER_PIXELS_PER_TILE (FRAMEBUFFER_TILE_WIDTH_IN_PIXELS * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS)

// The swizzle masks, using alternating yxyxyx bit pattern for morton-code swizzling pixels in a tile.
// This makes the pixels morton code swizzled within every rasterization level (fine/coarse/tile)
// The tiles themselves are stored row major.
// For examples of this concept, see:
// https://software.intel.com/en-us/node/514045
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn770442%28v=vs.85%29.aspx
#define FRAMEBUFFER_TILE_X_SWIZZLE_MASK (0x55555555 & (FRAMEBUFFER_TILE_WIDTH_IN_PIXELS - 1))
#define FRAMEBUFFER_TILE_Y_SWIZZLE_MASK (~FRAMEBUFFER_TILE_X_SWIZZLE_MASK & (FRAMEBUFFER_TILE_WIDTH_IN_PIXELS - 1))

// If there are too many commands and this buffer gets filled up,
// then the command buffer for that tile must be flushed.
#define TILE_COMMAND_BUFFER_SIZE_IN_DWORDS 128

typedef struct tile_cmdbuf_t
{
    // start and past-the-end of the allocation for the buffer
    uint32_t* cmdbuf_start;
    uint32_t* cmdbuf_end;
    // the next location where to read and write commands
    uint32_t* cmdbuf_read;
    uint32_t* cmdbuf_write;
} tile_cmdbuf_t;

typedef struct framebuffer_t
{
    pixel_t* backbuffer;

    uint32_t* tile_cmdpool;
    tile_cmdbuf_t* tile_cmdbufs;

    uint32_t width_in_pixels;
    uint32_t height_in_pixels;

    // num_tiles_per_row * num_pixels_per_tile
    uint32_t pixels_per_row_of_tiles;

    // pixels_per_row_of_tiles * num_tile_rows
    uint32_t pixels_per_slice;
} framebuffer_t;

framebuffer_t* new_framebuffer(uint32_t width, uint32_t height)
{
    // limits of the rasterizer's precision
    // this is based on an analysis of the range of results of the 2D cross product between two fixed16.8 numbers.
    assert(width < 16384);
    assert(height < 16384);

    framebuffer_t* fb = (framebuffer_t*)malloc(sizeof(framebuffer_t));
    assert(fb);

    fb->width_in_pixels = width;
    fb->height_in_pixels = height;

    // pad framebuffer up to size of next tile
    // that way the rasterization code doesn't have to handlep otential out of bounds access after tile binning
    uint32_t padded_width_in_pixels = (width + (FRAMEBUFFER_TILE_WIDTH_IN_PIXELS - 1)) & -FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t padded_height_in_pixels = (height + (FRAMEBUFFER_TILE_WIDTH_IN_PIXELS - 1)) & -FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;

    uint32_t width_in_tiles = padded_width_in_pixels / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t height_in_tiles = padded_height_in_pixels / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t total_num_tiles = width_in_tiles * height_in_tiles;

    fb->pixels_per_row_of_tiles = padded_width_in_pixels * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    fb->pixels_per_slice = padded_height_in_pixels / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS * fb->pixels_per_row_of_tiles;

    fb->backbuffer = (pixel_t*)malloc(fb->pixels_per_slice * sizeof(pixel_t));
    assert(fb->backbuffer);

    // clear to black/transparent initially
    memset(fb->backbuffer, 0, fb->pixels_per_slice * sizeof(pixel_t));

    fb->tile_cmdpool = (uint32_t*)malloc(total_num_tiles * TILE_COMMAND_BUFFER_SIZE_IN_DWORDS * sizeof(uint32_t));
    assert(fb->tile_cmdpool);

    fb->tile_cmdbufs = (tile_cmdbuf_t*)malloc(total_num_tiles * sizeof(tile_cmdbuf_t));
    assert(fb->tile_cmdbufs);

    for (uint32_t i = 0; i < total_num_tiles; i++)
    {
        fb->tile_cmdbufs[i].cmdbuf_start = &fb->tile_cmdpool[i * TILE_COMMAND_BUFFER_SIZE_IN_DWORDS];
        fb->tile_cmdbufs[i].cmdbuf_end = fb->tile_cmdbufs[i].cmdbuf_start + TILE_COMMAND_BUFFER_SIZE_IN_DWORDS;
        fb->tile_cmdbufs[i].cmdbuf_read = fb->tile_cmdbufs[i].cmdbuf_start;
        fb->tile_cmdbufs[i].cmdbuf_write = fb->tile_cmdbufs[i].cmdbuf_start;
    }

    return fb;
}

void delete_framebuffer(framebuffer_t* fb)
{
    if (!fb)
        return;

    free(fb->tile_cmdbufs);
    free(fb->tile_cmdpool);
    free(fb->backbuffer);
    free(fb);
}

void framebuffer_resolve(framebuffer_t* fb)
{

}

void framebuffer_pack_row_major(framebuffer_t* fb, uint32_t x, uint32_t y, uint32_t width, uint32_t height, pixelformat_t format, void* data)
{
    assert(fb);
    assert(x < fb->width_in_pixels);
    assert(y < fb->height_in_pixels);
    assert(width <= fb->width_in_pixels);
    assert(height <= fb->height_in_pixels);
    assert(x + width <= fb->width_in_pixels);
    assert(y + height <= fb->height_in_pixels);
    assert(data);

    uint32_t topleft_tile_y = y / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t topleft_tile_x = x / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t bottomright_tile_y = (y + (height - 1)) / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t bottomright_tile_x = (x + (width - 1)) / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;

    uint32_t dst_i = 0;

    uint32_t curr_tile_row_start = topleft_tile_y * fb->pixels_per_row_of_tiles + topleft_tile_x * FRAMEBUFFER_PIXELS_PER_TILE;
    for (uint32_t tile_y = topleft_tile_y; tile_y <= bottomright_tile_y; tile_y++)
    {
        uint32_t curr_tile_start = curr_tile_row_start;

        for (uint32_t tile_x = topleft_tile_x; tile_x <= bottomright_tile_x; tile_x++)
        {
            for (uint32_t pixel_y = 0, pixel_y_bits = 0;
                pixel_y < FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
                pixel_y++, pixel_y_bits = (pixel_y_bits - FRAMEBUFFER_TILE_Y_SWIZZLE_MASK) & FRAMEBUFFER_TILE_Y_SWIZZLE_MASK)
            {
                for (uint32_t pixel_x = 0, pixel_x_bits = 0;
                    pixel_x < FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
                    pixel_x++, pixel_x_bits = (pixel_x_bits - FRAMEBUFFER_TILE_X_SWIZZLE_MASK) & FRAMEBUFFER_TILE_X_SWIZZLE_MASK)
                {
                    uint32_t src_y = tile_y * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS + pixel_y;
                    uint32_t src_x = tile_x * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS + pixel_x;

                    // don't copy pixels outside src rectangle region
                    if (src_y < y || src_y >= y + height)
                        continue;
                    if (src_x < x || src_x >= x + width)
                        continue;

                    uint32_t src_i = curr_tile_start + (pixel_y_bits | pixel_x_bits);
                    pixel_t src = fb->backbuffer[src_i];
                    if (format == pixelformat_r8g8b8a8_unorm)
                    {
                        uint8_t* dst = (uint8_t*)data + dst_i * 4;
                        dst[0] = (uint8_t)((src & 0x00FF0000) >> 16);
                        dst[1] = (uint8_t)((src & 0x0000FF00) >> 8);
                        dst[2] = (uint8_t)((src & 0x000000FF) >> 0);
                        dst[3] = (uint8_t)((src & 0xFF000000) >> 24);
                    }
                    else if (format == pixelformat_b8g8r8a8_unorm)
                    {
                        uint8_t* dst = (uint8_t*)data + dst_i * 4;
                        dst[0] = (uint8_t)((src & 0x000000FF) >> 0);
                        dst[1] = (uint8_t)((src & 0x0000FF00) >> 8);
                        dst[2] = (uint8_t)((src & 0x00FF0000) >> 16);
                        dst[3] = (uint8_t)((src & 0xFF000000) >> 24);
                    }
                    else
                    {
                        assert(!"Unknown pixel format");
                    }

                    dst_i++;
                }
            }

            curr_tile_start += FRAMEBUFFER_PIXELS_PER_TILE;
        }

        curr_tile_row_start += fb->pixels_per_row_of_tiles;
    }
}

// hack
uint32_t g_Color;

void rasterize_triangle_fixed16_8(
    framebuffer_t* fb,
    uint32_t window_x0, uint32_t window_y0, uint32_t window_z0,
    uint32_t window_x1, uint32_t window_y1, uint32_t window_z1,
    uint32_t window_x2, uint32_t window_y2, uint32_t window_z2)
{
}<commit_msg>unit tests, bug fixes, pack_row_major perf improvement<commit_after>#include "rasterizer.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>

#include <intrin.h>

// runs unit tests automatically when the library is used
#define RASTERIZER_UNIT_TESTS

#ifdef RASTERIZER_UNIT_TESTS
void run_rasterizer_unit_tests();
#endif

// Sized according to the Larrabee rasterizer's description
#define FRAMEBUFFER_TILE_WIDTH_IN_PIXELS 128
#define FRAMEBUFFER_COARSE_BLOCK_WIDTH_IN_PIXELS 16
#define FRAMEBUFFER_FINE_BLOCK_WIDTH_IN_PIXELS 4

// small sizes (for testing)
// #define FRAMEBUFFER_TILE_WIDTH_IN_PIXELS 4
// #define FRAMEBUFFER_COARSE_BLOCK_WIDTH_IN_PIXELS 2
// #define FRAMEBUFFER_FINE_BLOCK_WIDTH_IN_PIXELS 1

// Convenience
#define FRAMEBUFFER_PIXELS_PER_TILE (FRAMEBUFFER_TILE_WIDTH_IN_PIXELS * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS)

// The swizzle masks, using alternating yxyxyx bit pattern for morton-code swizzling pixels in a tile.
// This makes the pixels morton code swizzled within every rasterization level (fine/coarse/tile)
// The tiles themselves are stored row major.
// For examples of this concept, see:
// https://software.intel.com/en-us/node/514045
// https://msdn.microsoft.com/en-us/library/windows/desktop/dn770442%28v=vs.85%29.aspx
#define FRAMEBUFFER_TILE_X_SWIZZLE_MASK (0x55555555 & (FRAMEBUFFER_PIXELS_PER_TILE - 1))
#define FRAMEBUFFER_TILE_Y_SWIZZLE_MASK (0xAAAAAAAA & (FRAMEBUFFER_PIXELS_PER_TILE - 1))

// If there are too many commands and this buffer gets filled up,
// then the command buffer for that tile must be flushed.
#define TILE_COMMAND_BUFFER_SIZE_IN_DWORDS 128

// parallel bit deposit low-order source bits according to mask bits
#ifdef __AVX2__
__forceinline uint32_t pdep_u32(uint32_t source, uint32_t mask)
{
    return _pdep_u32(source, mask);
}
#else
__forceinline uint32_t pdep_u32(uint32_t source, uint32_t mask)
{
    // horribly inefficient, but that's life without AVX2.
    // however, typically not a problem since you only need to swizzle once up front.
    uint32_t dst = 0;
    for (uint32_t mask_i = 0, dst_i = 0; mask_i < 32; mask_i++)
    {
        if (mask & (1 << mask_i))
        {
            uint32_t src_bit = (source & (1 << dst_i)) >> dst_i;
            dst |= src_bit << mask_i;

            dst_i++;
        }
    }
    return dst;
}
#endif

typedef struct tile_cmdbuf_t
{
    // start and past-the-end of the allocation for the buffer
    uint32_t* cmdbuf_start;
    uint32_t* cmdbuf_end;
    // the next location where to read and write commands
    uint32_t* cmdbuf_read;
    uint32_t* cmdbuf_write;
} tile_cmdbuf_t;

typedef struct framebuffer_t
{
    pixel_t* backbuffer;

    uint32_t* tile_cmdpool;
    tile_cmdbuf_t* tile_cmdbufs;

    uint32_t width_in_pixels;
    uint32_t height_in_pixels;

    // num_tiles_per_row * num_pixels_per_tile
    uint32_t pixels_per_row_of_tiles;

    // pixels_per_row_of_tiles * num_tile_rows
    uint32_t pixels_per_slice;
} framebuffer_t;

framebuffer_t* new_framebuffer(uint32_t width, uint32_t height)
{
#ifdef RASTERIZER_UNIT_TESTS
    static int ran_rasterizer_unit_tests_once = 0;
    if (!ran_rasterizer_unit_tests_once)
    {
        // set this before running the tests, so that unit tests can create framebuffers without causing infinite recursion
        ran_rasterizer_unit_tests_once = 1;
        run_rasterizer_unit_tests();
    }
#endif

    // limits of the rasterizer's precision
    // this is based on an analysis of the range of results of the 2D cross product between two fixed16.8 numbers.
    assert(width < 16384);
    assert(height < 16384);

    framebuffer_t* fb = (framebuffer_t*)malloc(sizeof(framebuffer_t));
    assert(fb);

    fb->width_in_pixels = width;
    fb->height_in_pixels = height;

    // pad framebuffer up to size of next tile
    // that way the rasterization code doesn't have to handlep otential out of bounds access after tile binning
    uint32_t padded_width_in_pixels = (width + (FRAMEBUFFER_TILE_WIDTH_IN_PIXELS - 1)) & -FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t padded_height_in_pixels = (height + (FRAMEBUFFER_TILE_WIDTH_IN_PIXELS - 1)) & -FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;

    uint32_t width_in_tiles = padded_width_in_pixels / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t height_in_tiles = padded_height_in_pixels / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t total_num_tiles = width_in_tiles * height_in_tiles;

    fb->pixels_per_row_of_tiles = padded_width_in_pixels * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    fb->pixels_per_slice = padded_height_in_pixels / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS * fb->pixels_per_row_of_tiles;

    fb->backbuffer = (pixel_t*)malloc(fb->pixels_per_slice * sizeof(pixel_t));
    assert(fb->backbuffer);

    // clear to black/transparent initially
    memset(fb->backbuffer, 0, fb->pixels_per_slice * sizeof(pixel_t));

    // allocate command lists for each tile
    fb->tile_cmdpool = (uint32_t*)malloc(total_num_tiles * TILE_COMMAND_BUFFER_SIZE_IN_DWORDS * sizeof(uint32_t));
    assert(fb->tile_cmdpool);

    fb->tile_cmdbufs = (tile_cmdbuf_t*)malloc(total_num_tiles * sizeof(tile_cmdbuf_t));
    assert(fb->tile_cmdbufs);

    // command lists are circular queues that are initially empty
    for (uint32_t i = 0; i < total_num_tiles; i++)
    {
        fb->tile_cmdbufs[i].cmdbuf_start = &fb->tile_cmdpool[i * TILE_COMMAND_BUFFER_SIZE_IN_DWORDS];
        fb->tile_cmdbufs[i].cmdbuf_end = fb->tile_cmdbufs[i].cmdbuf_start + TILE_COMMAND_BUFFER_SIZE_IN_DWORDS;
        fb->tile_cmdbufs[i].cmdbuf_read = fb->tile_cmdbufs[i].cmdbuf_start;
        fb->tile_cmdbufs[i].cmdbuf_write = fb->tile_cmdbufs[i].cmdbuf_start;
    }

    return fb;
}

void delete_framebuffer(framebuffer_t* fb)
{
    if (!fb)
        return;

    free(fb->tile_cmdbufs);
    free(fb->tile_cmdpool);
    free(fb->backbuffer);
    free(fb);
}

void framebuffer_resolve(framebuffer_t* fb)
{
    assert(fb);
}

void framebuffer_pack_row_major(framebuffer_t* fb, uint32_t x, uint32_t y, uint32_t width, uint32_t height, pixelformat_t format, void* data)
{
    assert(fb);
    assert(x < fb->width_in_pixels);
    assert(y < fb->height_in_pixels);
    assert(width <= fb->width_in_pixels);
    assert(height <= fb->height_in_pixels);
    assert(x + width <= fb->width_in_pixels);
    assert(y + height <= fb->height_in_pixels);
    assert(data);

    uint32_t topleft_tile_y = y / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t topleft_tile_x = x / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t bottomright_tile_y = (y + (height - 1)) / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
    uint32_t bottomright_tile_x = (x + (width - 1)) / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;

    uint32_t dst_i = 0;

    uint32_t curr_tile_row_start = topleft_tile_y * fb->pixels_per_row_of_tiles + topleft_tile_x * FRAMEBUFFER_PIXELS_PER_TILE;
    for (uint32_t tile_y = topleft_tile_y; tile_y <= bottomright_tile_y; tile_y++)
    {
        uint32_t curr_tile_start = curr_tile_row_start;

        for (uint32_t tile_x = topleft_tile_x; tile_x <= bottomright_tile_x; tile_x++)
        {
            uint32_t topleft_y = tile_y * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
            uint32_t topleft_x = tile_x * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
            uint32_t bottomright_y = topleft_y + FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
            uint32_t bottomright_x = topleft_x + FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
            uint32_t pixel_y_min = topleft_y < y ? y : topleft_y;
            uint32_t pixel_x_min = topleft_x < x ? x : topleft_x;
            uint32_t pixel_y_max = bottomright_y > y + height ? y + height : bottomright_y;
            uint32_t pixel_x_max = bottomright_x > x + width ? x + width : bottomright_x;

            for (uint32_t pixel_y = pixel_y_min, pixel_y_bits = pdep_u32(topleft_y, FRAMEBUFFER_TILE_Y_SWIZZLE_MASK);
                pixel_y < pixel_y_max;
                pixel_y++, pixel_y_bits = (pixel_y_bits - FRAMEBUFFER_TILE_Y_SWIZZLE_MASK) & FRAMEBUFFER_TILE_Y_SWIZZLE_MASK)
            {
                for (uint32_t pixel_x = pixel_x_min, pixel_x_bits = pdep_u32(topleft_x, FRAMEBUFFER_TILE_X_SWIZZLE_MASK);
                    pixel_x < pixel_x_max;
                    pixel_x++, pixel_x_bits = (pixel_x_bits - FRAMEBUFFER_TILE_X_SWIZZLE_MASK) & FRAMEBUFFER_TILE_X_SWIZZLE_MASK)
                {
                    uint32_t src_i = curr_tile_start + (pixel_y_bits | pixel_x_bits);
                    pixel_t src = fb->backbuffer[src_i];
                    if (format == pixelformat_r8g8b8a8_unorm)
                    {
                        uint8_t* dst = (uint8_t*)data + dst_i * 4;
                        dst[0] = (uint8_t)((src & 0x00FF0000) >> 16);
                        dst[1] = (uint8_t)((src & 0x0000FF00) >> 8);
                        dst[2] = (uint8_t)((src & 0x000000FF) >> 0);
                        dst[3] = (uint8_t)((src & 0xFF000000) >> 24);
                    }
                    else if (format == pixelformat_b8g8r8a8_unorm)
                    {
                        uint8_t* dst = (uint8_t*)data + dst_i * 4;
                        dst[0] = (uint8_t)((src & 0x000000FF) >> 0);
                        dst[1] = (uint8_t)((src & 0x0000FF00) >> 8);
                        dst[2] = (uint8_t)((src & 0x00FF0000) >> 16);
                        dst[3] = (uint8_t)((src & 0xFF000000) >> 24);
                    }
                    else
                    {
                        assert(!"Unknown pixel format");
                    }

                    dst_i++;
                }
            }

            curr_tile_start += FRAMEBUFFER_PIXELS_PER_TILE;
        }

        curr_tile_row_start += fb->pixels_per_row_of_tiles;
    }
}

// hack
uint32_t g_Color;

void rasterize_triangle_fixed16_8(
    framebuffer_t* fb,
    uint32_t window_x0, uint32_t window_y0, uint32_t window_z0,
    uint32_t window_x1, uint32_t window_y1, uint32_t window_z1,
    uint32_t window_x2, uint32_t window_y2, uint32_t window_z2)
{
}

#ifdef RASTERIZER_UNIT_TESTS
void run_rasterizer_unit_tests()
{
    // pdep tests
    //             source  mask
    assert(pdep_u32(0b000, 0b000000) == 0b000000);
    assert(pdep_u32(0b001, 0b000001) == 0b000001);
    assert(pdep_u32(0b001, 0b000010) == 0b000010);
    assert(pdep_u32(0b011, 0b001100) == 0b001100);
    assert(pdep_u32(0b101, 0b101010) == 0b100010);
    assert(pdep_u32(0b010, 0b010101) == 0b000100);

    // swizzle test
    {
        uint32_t w = FRAMEBUFFER_TILE_WIDTH_IN_PIXELS * 2;
        uint32_t h = FRAMEBUFFER_TILE_WIDTH_IN_PIXELS * 2;

        framebuffer_t* fb = new_framebuffer(w, h);
        uint8_t* rowmajor_data = new uint8_t[w * h * 4];

        // write indices of pixels linearly in memory (ignoring swizzling)
        // this will be read back and checked to verify the layout
        // For tiles of 4x4 pixels, a 8x8 row major image should look something like:
        //  0  1  4  5 | 16 17 20 21
        //  2  3  6  7 | 18 19 22 23
        //  8  9 12 13 | 24 25 28 29
        // 10 11 14 15 | 26 27 30 31
        // -------------------------
        // 32 33 36 37 | 48 49 52 53
        // 34 35 38 39 | 50 51 54 55
        // 40 41 44 45 | 56 57 60 61
        // 42 43 46 47 | 58 59 62 63
        // see: https://en.wikipedia.org/wiki/Z-order_curve
        for (uint32_t i = 0; i < fb->pixels_per_slice; i++)
        {
            fb->backbuffer[i] = i;
        }

        framebuffer_pack_row_major(fb, 0, 0, w, h, pixelformat_r8g8b8a8_unorm, rowmajor_data);

        for (uint32_t y = 0; y < h; y++)
        {
            uint32_t tile_y = y / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;

            for (uint32_t x = 0; x < w; x++)
            {
                uint32_t tile_x = x / FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
                uint32_t tile_i = tile_y * (fb->pixels_per_row_of_tiles / FRAMEBUFFER_PIXELS_PER_TILE) + tile_x;
                uint32_t topleft_pixel_i = tile_i * FRAMEBUFFER_PIXELS_PER_TILE;

                uint32_t tile_relative_x = x - tile_x * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
                uint32_t tile_relative_y = y - tile_y * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS;
                uint32_t rowmajor_i = topleft_pixel_i + (tile_relative_y * FRAMEBUFFER_TILE_WIDTH_IN_PIXELS + tile_relative_x);

                uint32_t xmask = FRAMEBUFFER_TILE_X_SWIZZLE_MASK;
                uint32_t ymask = FRAMEBUFFER_TILE_Y_SWIZZLE_MASK;
                uint32_t xbits = pdep_u32(x, xmask);
                uint32_t ybits = pdep_u32(y, ymask);
                uint32_t swizzled_i = topleft_pixel_i + xbits + ybits;

                assert(rowmajor_data[rowmajor_i * 4 + 0] == ((fb->backbuffer[swizzled_i] & 0x00FF0000) >> 16));
                assert(rowmajor_data[rowmajor_i * 4 + 1] == ((fb->backbuffer[swizzled_i] & 0x0000FF00) >> 8));
                assert(rowmajor_data[rowmajor_i * 4 + 2] == ((fb->backbuffer[swizzled_i] & 0x000000FF) >> 0));
                assert(rowmajor_data[rowmajor_i * 4 + 3] == ((fb->backbuffer[swizzled_i] & 0xFF000000) >> 24));
            }
        }

        delete[] rowmajor_data;
        delete_framebuffer(fb);
    }
}
#endif<|endoftext|>


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

// a ray tracer in C++

// libraries, namespace
#include <thread>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
#include <random>
#include "library/loadXML.cpp"
#include "library/scene.cpp"
using namespace std;

// scene to load (project #) + all ray tracing options & settings
string xml = "scenes/prj11-1.xml";
bool printXML = false;
bool zBuffer = false;
bool sampleCount = false;
int bounceCount = 5;
int sampleMin = 4;
int sampleMax = 32;
float sampleThreshold = 0.001;
int shadowMin = 8;
int shadowMax = 32;
bool gammaCorr = true;
bool globalIllum = true;
bool irradCache = true;
int samplesGI = 16;

// variables for ray tracing
int w;
int h;
int size;
Color24* img;
float* zImg;
float* sampleImg;
IrradianceMap im;

// variables for anti-aliasing brightness calculations (XYZ, Lab)
float perR = 0.2126;
float perG = 0.7152;
float perB = 0.0722;
float Ycutoff = pow(6.0 / 29.0, 3.0);
float Yprecalc = (1.0 / 3.0) * pow(29.0 / 6.0, 2.0);

// setup threading
static const int numThreads = 8;
void rayTracing(int i);

// for camera ray generation
void cameraRayVars();
float imageDistance = 1.0;
Point *imageTopLeftV;
Point *dXV;
Point *dYV;
Point *dVx;
Point *dVy;
Point firstPixel;
Transformation* c;
Point cameraRay(float pX, float pY, Point offset);

// ray tracer
int main(){

  // load scene: root node, camera, image (and set shadow casting variables)
  loadScene(xml, printXML, shadowMin, shadowMax, globalIllum, irradCache, samplesGI);

  // set the scene as the root node
  setScene(rootNode);

  // set variables for ray tracing
  w = render.getWidth();
  h = render.getHeight();
  size = render.getSize();
  img = render.getRender();
  zImg = render.getZBuffer();
  sampleImg = render.getSample();
  if(globalIllum && irradCache)
    im.Initialize(w, h);

  // set variables for generating camera rays
  cameraRayVars();

  // compute an irradiance cache for global illumination
  if(globalIllum && irradCache){

    // subdivide our image to compute indirect illumination
    bool subdivide = true;
    while(subdivide){

      // check if we are on final subdivide
      if(im.GetSubdivLevel() == 0)
        subdivide = false;

      // calculate indirect illumination

      // subdivide (if necessary)
      if(subdivide)
        im.Subdivide();
    }
  }

  // sample test output (know irrad map done)
  cout << "onto ray tracing!" << endl;

  // start ray tracing loop (in parallel with threads)
  thread t[numThreads];
  for(int i = 0; i < numThreads; i++)
    t[i] = thread(rayTracing, i);

  // when finished, join all threads back to main
  for(int i = 0; i < numThreads; i++)
    t[i].join();

  // output ray-traced image & z-buffer & sample count image (if set)
  render.save("images/image.ppm");
  if(zBuffer){
    render.computeZImage();
    render.saveZImage("images/imageZ.ppm");
  }
  if(sampleCount){
    render.computeSampleImage();
    render.saveSampleImage("images/imageSample.ppm");
  }
}

// ray tracing loop (for an individual pixel)
void rayTracing(int i){

  // initial starting pixel
  int pixel = i;

  // setup random generator for anti-aliasing & depth-of-field
  mt19937 rnd;
  uniform_real_distribution<float> dist{0.0, 1.0};

  // thread continuation condition
  while(pixel < size){

    // number of samples
    int s = 0;

    // establish pixel location (center)
    float pX = pixel % w;
    float pY = pixel / w;

    // color values to store across samples
    Color col;
    Color colAvg;
    float zAvg = 0.0;
    float rVar = 0.0;
    float gVar = 0.0;
    float bVar = 0.0;
    float var = sampleThreshold;
    float brightness = 0.0;

    // random rotation of Halton sequence on circle of confusion
    float dcR = dist(rnd) * 2.0 * M_PI;

    // compute multi-adaptive sampling for each pixel (anti-aliasing)
    while(s < sampleMin || (s != sampleMax && (rVar * perR > var + brightness * var || gVar * perG > var + brightness * var || bVar * perB > var + brightness * var))){

      // grab Halton sequence to shift point by on image plane
      float dpX = centerHalton(Halton(s, 3));
      float dpY = centerHalton(Halton(s, 2));

      // grab Halton sequence to shift point along circle of confusion
      float dcS = sqrt(Halton(s, 2)) * camera.dof;

      // grab Halton sequence to shift point around circle of confusion
      float dcT = Halton(s, 3) * 2.0 * M_PI;

      // compute the offset for depth of field sampling
      Point posOffset = (*dVx * cos(dcR + dcT) + *dVy * sin(dcR + dcT)) * dcS;

      // transform ray into world space (offset by Halton seqeunce for sampling)
      Point rayDir = cameraRay(pX + dpX, pY + dpY, posOffset);
      Cone *ray = new Cone();
      ray->pos = camera.pos + c->transformFrom(posOffset);
      ray->dir = c->transformFrom(rayDir);
      ray->radius = 0.0;
      ray->tan = dXV->x / (2.0 * imageDistance);

      // traverse through scene DOM
      // transform rays into model space
      // detect ray intersections and get back HitInfo
      HitInfo hi = HitInfo();
      bool hit = traceRay(*ray, hi);

      // update z-buffer, if necessary
      if(zBuffer)
        zAvg = (zAvg * s + hi.z) / (float) (s + 1);

      // if hit, get the node's material
      if(hit){
        Node *n = hi.node;
        Material *m;
        if(n)
          m = n->getMaterial();

        // if there is a material, shade the pixel
        // 5-passes for reflections and refractions
        if(m)
          col = m->shade(*ray, hi, lights, bounceCount);

        // otherwise color it white (as a hit)
        else
          col.Set(0.929, 0.929, 0.929);

      // if we hit nothing, draw the background
      }else{
        Point p = Point((float) pX / w, (float) pY / h, 0.0);
        Color b = background.sample(p);
        col = b;
      }

      // compute average color
      float rAvg = (colAvg.r * s + col.r) / (float) (s + 1);
      float gAvg = (colAvg.g * s + col.g) / (float) (s + 1);
      float bAvg = (colAvg.b * s + col.b) / (float) (s + 1);
      colAvg.Set(rAvg, gAvg, bAvg);

      // compute color variances
      rVar = (rVar * s + (col.r - rAvg) * (col.r - rAvg)) / (float) (s + 1);
      gVar = (gVar * s + (col.g - gAvg) * (col.g - gAvg)) / (float) (s + 1);
      bVar = (bVar * s + (col.b - bAvg) * (col.b - bAvg)) / (float) (s + 1);

      // calculate and update brightness average using XYZ and Lab space
      float Y = perR * rAvg + perG * gAvg + perB * bAvg;
      float Y13 = Y;
      if(Y13 > Ycutoff)
        Y13 = pow(Y13, 1.0 / 3.0);
      else
        Y13 = Yprecalc * Y13 + (4.0 / 29.0);
      brightness = (116.0 * Y13 - 16.0) / 100.0;

      // increment sample count
      s++;

      // watch for errors at any individual sample, terminate thread if so
      if(colAvg[0] != colAvg[0] || colAvg[1] != colAvg[1] || colAvg[2] != colAvg[2]){
        cout << "ERROR - pixel " << pixel << " & sample " << s << endl;
        s = sampleMax;
        pixel = size;
      }
    }

    // gamma correction
    if(gammaCorr){
      colAvg.r = pow(colAvg.r, 1.0 / 2.2);
      colAvg.g = pow(colAvg.g, 1.0 / 2.2);
      colAvg.b = pow(colAvg.b, 1.0 / 2.2);
    }

    // color the pixel image
    img[pixel] = Color24(colAvg);

    // update the z-buffer image, if necessary
    if(zBuffer)
      zImg[pixel] = zAvg;

    // update the sample count image, if necessary
    if(sampleCount)
      sampleImg[pixel] = s;

    // re-assign next pixel (naive, but works)
    pixel += numThreads;
  }
}

// create variables for camera ray generation
void cameraRayVars(){
  float fov = camera.fov * M_PI / 180.0;
  float aspectRatio = (float) w / (float) h;
  imageDistance = camera.focalDist;
  float imageTipY = imageDistance * tan(fov / 2.0);
  float imageTipX = imageTipY * aspectRatio;
  float dX = (2.0 * imageTipX) / (float) w;
  float dY = (2.0 * imageTipY) / (float) h;
  imageTopLeftV = new Point(-imageTipX, imageTipY, -imageDistance);
  dXV = new Point(dX, 0.0, 0.0);
  dYV = new Point(0.0, -dY, 0.0);
  firstPixel = *imageTopLeftV + (*dXV * 0.5) + (*dYV * 0.5);

  // set up camera transformation (only need to rotate coordinates)
  c = new Transformation();
  Matrix *rotate = new cyMatrix3f();
  rotate->Set(camera.cross, camera.up, -camera.dir);
  c->transform(*rotate);

  // get normalized rays on the focal plane
  dVx = new Point(1.0, 0.0, 0.0);
  dVy = new Point(0.0, 1.0, 0.0);
}

// compute camera ray direction
Point cameraRay(float pX, float pY, Point offset){
  Point ray = firstPixel + (*dXV * pX) + (*dYV * pY) - offset;
  ray.Normalize();
  return ray;
}
<commit_msg>add test of the irradiance map variables and prepping the indirect light for ray caching<commit_after>// Copyright 2013 Sean McKenna
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//

// a ray tracer in C++

// libraries, namespace
#include <thread>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <cmath>
#include <random>
#include "library/loadXML.cpp"
#include "library/scene.cpp"
using namespace std;

// scene to load (project #) + all ray tracing options & settings
string xml = "scenes/prj11-1.xml";
bool printXML = false;
bool zBuffer = false;
bool sampleCount = false;
int bounceCount = 5;
int sampleMin = 4;
int sampleMax = 32;
float sampleThreshold = 0.001;
int shadowMin = 8;
int shadowMax = 32;
bool gammaCorr = true;
bool globalIllum = true;
bool irradCache = true;
int samplesGI = 16;

// variables for ray tracing
int w;
int h;
int size;
Color24* img;
float* zImg;
float* sampleImg;
IrradianceMap im;

// variables for anti-aliasing brightness calculations (XYZ, Lab)
float perR = 0.2126;
float perG = 0.7152;
float perB = 0.0722;
float Ycutoff = pow(6.0 / 29.0, 3.0);
float Yprecalc = (1.0 / 3.0) * pow(29.0 / 6.0, 2.0);

// setup threading
static const int numThreads = 8;
void rayTracing(int i);
void rayTracingCache(int i);

// for camera ray generation
void cameraRayVars();
float imageDistance = 1.0;
Point *imageTopLeftV;
Point *dXV;
Point *dYV;
Point *dVx;
Point *dVy;
Point firstPixel;
Transformation* c;
Point cameraRay(float pX, float pY, Point offset);

// ray tracer
int main(){

  // load scene: root node, camera, image (and set shadow casting variables)
  loadScene(xml, printXML, shadowMin, shadowMax, globalIllum, irradCache, samplesGI);

  // set the scene as the root node
  setScene(rootNode);

  // set variables for ray tracing
  w = render.getWidth();
  h = render.getHeight();
  size = render.getSize();
  img = render.getRender();
  zImg = render.getZBuffer();
  sampleImg = render.getSample();
  if(globalIllum && irradCache)
    im.Initialize(w, h);

  // set variables for generating camera rays
  cameraRayVars();

  // compute an irradiance cache for global illumination
  if(globalIllum && irradCache){

    // caching light list
    LightList lightCache;
    lightCache.deleteAll();
    string name = "indirect";
    IndirectLight *l = new IndirectLight();
    Light *light = NULL;
    l->setLightList(&lights);
    l->setEnvironment(environment);
    l->setSamples(samplesGI);
    light = l;
    light->setName(name);
    lightCache.push_back(light);

    // subdivide our image to compute indirect illumination
    bool subdivide = true;
    while(subdivide){

      // check if we are on final subdivide
      if(im.GetSubdivLevel() == 0)
        subdivide = false;

      // calculate indirect illumination
      int cnt = 0;
      for(int i = 0; i < im.GetDataCount(); i++){
        if(im.IsValid(i))
          cnt++;
      }
      cout << "size: " << im.GetDataCount() << endl;
      cout << "valid: " << cnt << endl;
      float x;
      float y;
      im.GetPosition(32, x, y);
      cout << "(x, y): " << x << ", " << y << endl;
      int pix = x + y * w;
      cout << "pixel #" << pix << endl << endl;

      // subdivide (if necessary)
      if(subdivide)
        im.Subdivide();
    }
  }

  // sample test output (know irrad map done)
  cout << "onto ray tracing!" << endl;

  // start ray tracing loop (in parallel with threads)
  thread t[numThreads];
  for(int i = 0; i < numThreads; i++)
    t[i] = thread(rayTracing, i);

  // when finished, join all threads back to main
  for(int i = 0; i < numThreads; i++)
    t[i].join();

  // output ray-traced image & z-buffer & sample count image (if set)
  render.save("images/image.ppm");
  if(zBuffer){
    render.computeZImage();
    render.saveZImage("images/imageZ.ppm");
  }
  if(sampleCount){
    render.computeSampleImage();
    render.saveSampleImage("images/imageSample.ppm");
  }
}

// ray tracing loop (for an individual pixel)
void rayTracing(int i){

  // initial starting pixel
  int pixel = i;

  // setup random generator for anti-aliasing & depth-of-field
  mt19937 rnd;
  uniform_real_distribution<float> dist{0.0, 1.0};

  // thread continuation condition
  while(pixel < size){

    // number of samples
    int s = 0;

    // establish pixel location (center)
    float pX = pixel % w;
    float pY = pixel / w;

    // color values to store across samples
    Color col;
    Color colAvg;
    float zAvg = 0.0;
    float rVar = 0.0;
    float gVar = 0.0;
    float bVar = 0.0;
    float var = sampleThreshold;
    float brightness = 0.0;

    // random rotation of Halton sequence on circle of confusion
    float dcR = dist(rnd) * 2.0 * M_PI;

    // compute multi-adaptive sampling for each pixel (anti-aliasing)
    while(s < sampleMin || (s != sampleMax && (rVar * perR > var + brightness * var || gVar * perG > var + brightness * var || bVar * perB > var + brightness * var))){

      // grab Halton sequence to shift point by on image plane
      float dpX = centerHalton(Halton(s, 3));
      float dpY = centerHalton(Halton(s, 2));

      // grab Halton sequence to shift point along circle of confusion
      float dcS = sqrt(Halton(s, 2)) * camera.dof;

      // grab Halton sequence to shift point around circle of confusion
      float dcT = Halton(s, 3) * 2.0 * M_PI;

      // compute the offset for depth of field sampling
      Point posOffset = (*dVx * cos(dcR + dcT) + *dVy * sin(dcR + dcT)) * dcS;

      // transform ray into world space (offset by Halton seqeunce for sampling)
      Point rayDir = cameraRay(pX + dpX, pY + dpY, posOffset);
      Cone *ray = new Cone();
      ray->pos = camera.pos + c->transformFrom(posOffset);
      ray->dir = c->transformFrom(rayDir);
      ray->radius = 0.0;
      ray->tan = dXV->x / (2.0 * imageDistance);

      // traverse through scene DOM
      // transform rays into model space
      // detect ray intersections and get back HitInfo
      HitInfo hi = HitInfo();
      bool hit = traceRay(*ray, hi);

      // update z-buffer, if necessary
      if(zBuffer)
        zAvg = (zAvg * s + hi.z) / (float) (s + 1);

      // if hit, get the node's material
      if(hit){
        Node *n = hi.node;
        Material *m;
        if(n)
          m = n->getMaterial();

        // if there is a material, shade the pixel
        // 5-passes for reflections and refractions
        if(m)
          col = m->shade(*ray, hi, lights, bounceCount);

        // otherwise color it white (as a hit)
        else
          col.Set(0.929, 0.929, 0.929);

      // if we hit nothing, draw the background
      }else{
        Point p = Point((float) pX / w, (float) pY / h, 0.0);
        Color b = background.sample(p);
        col = b;
      }

      // compute average color
      float rAvg = (colAvg.r * s + col.r) / (float) (s + 1);
      float gAvg = (colAvg.g * s + col.g) / (float) (s + 1);
      float bAvg = (colAvg.b * s + col.b) / (float) (s + 1);
      colAvg.Set(rAvg, gAvg, bAvg);

      // compute color variances
      rVar = (rVar * s + (col.r - rAvg) * (col.r - rAvg)) / (float) (s + 1);
      gVar = (gVar * s + (col.g - gAvg) * (col.g - gAvg)) / (float) (s + 1);
      bVar = (bVar * s + (col.b - bAvg) * (col.b - bAvg)) / (float) (s + 1);

      // calculate and update brightness average using XYZ and Lab space
      float Y = perR * rAvg + perG * gAvg + perB * bAvg;
      float Y13 = Y;
      if(Y13 > Ycutoff)
        Y13 = pow(Y13, 1.0 / 3.0);
      else
        Y13 = Yprecalc * Y13 + (4.0 / 29.0);
      brightness = (116.0 * Y13 - 16.0) / 100.0;

      // increment sample count
      s++;

      // watch for errors at any individual sample, terminate thread if so
      if(colAvg[0] != colAvg[0] || colAvg[1] != colAvg[1] || colAvg[2] != colAvg[2]){
        cout << "ERROR - pixel " << pixel << " & sample " << s << endl;
        s = sampleMax;
        pixel = size;
      }
    }

    // gamma correction
    if(gammaCorr){
      colAvg.r = pow(colAvg.r, 1.0 / 2.2);
      colAvg.g = pow(colAvg.g, 1.0 / 2.2);
      colAvg.b = pow(colAvg.b, 1.0 / 2.2);
    }

    // color the pixel image
    img[pixel] = Color24(colAvg);

    // update the z-buffer image, if necessary
    if(zBuffer)
      zImg[pixel] = zAvg;

    // update the sample count image, if necessary
    if(sampleCount)
      sampleImg[pixel] = s;

    // re-assign next pixel (naive, but works)
    pixel += numThreads;
  }
}

// create variables for camera ray generation
void cameraRayVars(){
  float fov = camera.fov * M_PI / 180.0;
  float aspectRatio = (float) w / (float) h;
  imageDistance = camera.focalDist;
  float imageTipY = imageDistance * tan(fov / 2.0);
  float imageTipX = imageTipY * aspectRatio;
  float dX = (2.0 * imageTipX) / (float) w;
  float dY = (2.0 * imageTipY) / (float) h;
  imageTopLeftV = new Point(-imageTipX, imageTipY, -imageDistance);
  dXV = new Point(dX, 0.0, 0.0);
  dYV = new Point(0.0, -dY, 0.0);
  firstPixel = *imageTopLeftV + (*dXV * 0.5) + (*dYV * 0.5);

  // set up camera transformation (only need to rotate coordinates)
  c = new Transformation();
  Matrix *rotate = new cyMatrix3f();
  rotate->Set(camera.cross, camera.up, -camera.dir);
  c->transform(*rotate);

  // get normalized rays on the focal plane
  dVx = new Point(1.0, 0.0, 0.0);
  dVy = new Point(0.0, 1.0, 0.0);
}

// compute camera ray direction
Point cameraRay(float pX, float pY, Point offset){
  Point ray = firstPixel + (*dXV * pX) + (*dYV * pY) - offset;
  ray.Normalize();
  return ray;
}
<|endoftext|>