<commit_before>#include "TransToETC2.h"

#include <ee/math_common.h>
#include <ee/ImagePack.h>
#include <ee/Exception.h>

#include <etcpack_lib.h>

#include <fstream>

#include <assert.h>

namespace eimage
{

TransToETC2::TransToETC2(const uint8_t* pixels, int width, int height, int channels,
						 Type type, bool align_bottom, bool fastest)
	: m_type(type)
	, m_fastest(fastest)
	, m_perceptual(false)
{
	Prepare(pixels, width, height, channels, align_bottom);
	Encode();
}

TransToETC2::~TransToETC2()
{
	delete m_rgb_data;
	delete m_alpha_data;
	delete m_compressed;
}

void TransToETC2::OutputFile(const std::string& filepath) const
{
	std::ofstream fout(filepath.c_str(), std::ios::binary);
	OutputHeader(fout);
	fout.write(reinterpret_cast<const char*>(m_compressed), m_size);
	fout.close();
}

uint8_t* TransToETC2::GetPixelsData(int& width, int& height) const
{
	width = m_width;
	height = m_height;

	int sz = m_width * m_height;
	uint8_t* pixels = new uint8_t[m_size];
	memcpy(pixels, m_compressed, sz);
	return pixels;
}

void TransToETC2::Prepare(const uint8_t* pixels)
{
	int rgb_sz = m_width * m_height * 3,
		alpha_sz = m_width * m_height;
	m_rgb_data = new uint8_t[rgb_sz];
	m_alpha_data = new uint8_t[alpha_sz];

	const uint8_t* in = pixels;
	uint8_t *out_rgb = m_rgb_data,
		    *out_alpha = m_alpha_data;
	const uint8_t* end = in + m_width * m_height * 4;
	while (in < end)
	{
		memcpy(out_rgb, in, 3);
		out_rgb += 3;
		in += 3;

		if (m_type == RGBA1) {
			*out_alpha++ = (*in++) > 180 ? 255 : 0;
		} else {
			*out_alpha++ = *in++;
		}
	}
}

void TransToETC2::Prepare(const uint8_t* pixels, int width, int height, int channels, bool align_bottom)
{
	assert(channels == 4);
	if (ee::is_power_of_two(width) &&
		ee::is_power_of_two(height) &&
		width == height)
	{
		m_width = width;
		m_height = height;
		Prepare(pixels);
	}
	else
	{
		int nw = ee::next_p2(width),
			nh = ee::next_p2(height);
		ee::ImagePack pack(nw, nh);
		int h = align_bottom ? nh - height : 0;
		pack.AddImage(pixels, width, height, 0, h, ee::ImagePack::PT_NORMAL);

		m_width = nw;
		m_height = nh;
		Prepare(pack.GetPixels());
	}

	if (m_type == RGBA) {
		m_size = m_width * m_height;
	} else {
		m_size = m_width * m_height / 2;
	}

	m_compressed = new uint8_t[m_size];
}

static void WriteRGB(uint8_t*& output, unsigned int block1, unsigned int block2)
{
	output[0] = (block1 >> 24) & 0xFF;
	output[1] = (block1 >> 16) & 0xFF;
	output[2] = (block1 >> 8) & 0xFF;
	output[3] =  block1 & 0xFF;
	output[4] = (block2 >> 24) & 0xFF;
	output[5] = (block2 >> 16) & 0xFF;
	output[6] = (block2 >> 8) & 0xFF;
	output[7] =  block2 & 0xFF;
	output += 8;
}

static void WriteAlpha(uint8_t*& output, uint8_t* alphadata)
{
	memcpy(output, alphadata, 8);
	output += 8;
}

void TransToETC2::Encode()
{
	uint8_t* decoded = new uint8_t[m_width * m_height * 3];

	uint8_t* output = m_compressed;

	int bw = m_width / 4;
	int bh = m_height / 4;
	for (int y = 0; y < bh; ++y) {
		for (int x = 0; x < bw; ++x) {
			switch (m_type)
			{
			case RGB:
				{
					unsigned int block1, block2;
					ComputeRGB(decoded, x, y, block1, block2);
					WriteRGB(output, block1, block2);
				}
				break;
			case RGBA:
				{
					uint8_t alphadata[8];
					ComputeAlpha(x, y, alphadata);
					WriteAlpha(output, alphadata);

					unsigned int block1, block2;
					ComputeRGB(decoded, x, y, block1, block2);
					WriteRGB(output, block1, block2);
				}
				break;
			case RGBA1:
				{
					unsigned int block1, block2;
					compressBlockETC2RGBA1(m_rgb_data, m_alpha_data, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
					WriteRGB(output, block1, block2);
				}
				break;
			default:
				throw ee::Exception("TransToETC2::Encode: Unknown type");
			}
		}
	}
}

void TransToETC2::OutputHeader(std::ofstream& fout) const
{
	unsigned char magic[4] = {'P', 'K', 'M', ' '};
	fout.write(reinterpret_cast<const char*>(&magic[0]), 1);
	fout.write(reinterpret_cast<const char*>(&magic[1]), 1);
	fout.write(reinterpret_cast<const char*>(&magic[2]), 1);
	fout.write(reinterpret_cast<const char*>(&magic[3]), 1);

	unsigned char version[2] = { '2', '0' };
	fout.write(reinterpret_cast<const char*>(&version[0]), 1);
	fout.write(reinterpret_cast<const char*>(&version[1]), 1);

	// In a PKM-file, the codecs are stored using the following identifiers
	//
	// identifier                         value               codec
	// --------------------------------------------------------------------
	// ETC1_RGB_NO_MIPMAPS                  0                 GL_ETC1_RGB8_OES
	// ETC2PACKAGE_RGB_NO_MIPMAPS           1                 GL_COMPRESSED_RGB8_ETC2
	// ETC2PACKAGE_RGBA_NO_MIPMAPS_OLD      2, not used       -
	// ETC2PACKAGE_RGBA_NO_MIPMAPS          3                 GL_COMPRESSED_RGBA8_ETC2_EAC
	// ETC2PACKAGE_RGBA1_NO_MIPMAPS         4                 GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
	// ETC2PACKAGE_R_NO_MIPMAPS             5                 GL_COMPRESSED_R11_EAC
	// ETC2PACKAGE_RG_NO_MIPMAPS            6                 GL_COMPRESSED_RG11_EAC
	// ETC2PACKAGE_R_SIGNED_NO_MIPMAPS      7                 GL_COMPRESSED_SIGNED_R11_EAC
	// ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS     8                 GL_COMPRESSED_SIGNED_RG11_EAC

	enum ETC_TYPE
	{
		ETC1_RGB_NO_MIPMAPS = 0,
		ETC2PACKAGE_RGB_NO_MIPMAPS,
		ETC2PACKAGE_RGBA_NO_MIPMAPS_OLD,
		ETC2PACKAGE_RGBA_NO_MIPMAPS,
		ETC2PACKAGE_RGBA1_NO_MIPMAPS,
		ETC2PACKAGE_R_NO_MIPMAPS,
		ETC2PACKAGE_RG_NO_MIPMAPS,
		ETC2PACKAGE_R_SIGNED_NO_MIPMAPS,
		ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS
	};

	unsigned short type;
	switch (m_type)
	{
	case RGB:
		type = ETC2PACKAGE_RGB_NO_MIPMAPS;
		break;
	case RGBA:
		type = ETC2PACKAGE_RGBA_NO_MIPMAPS;
		break;
	case RGBA1:
		type = ETC2PACKAGE_RGBA1_NO_MIPMAPS;
		break;
	default:
		throw ee::Exception("TransToETC2::OutputHeader: Unknown type");
	}
	WriteBigEndian2byteWord(&type, fout);

	unsigned short w = m_width, h = m_height;
	WriteBigEndian2byteWord(&w, fout);
	WriteBigEndian2byteWord(&h, fout);

	WriteBigEndian2byteWord(&w, fout);
	WriteBigEndian2byteWord(&h, fout);
}

void TransToETC2::ComputeRGB(uint8_t* decoded, int x, int y, unsigned int& block1, unsigned int& block2)
{
	if (m_perceptual) {
		if (m_fastest) {
			compressBlockETC2FastPerceptual(m_rgb_data, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
		} else {
			compressBlockETC2ExhaustivePerceptual(m_rgb_data, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
		}
	} else {
		if (m_fastest) {
			compressBlockETC2Fast(m_rgb_data, NULL, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
		} else {
			compressBlockETC2Exhaustive(m_rgb_data, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
		}
	}
}

void TransToETC2::ComputeAlpha(int x, int y, uint8_t* alphadata)
{
	if (m_fastest) {
		compressBlockAlphaFast(m_alpha_data, x * 4, y * 4, m_width, m_height, alphadata);
	} else {
		compressBlockAlphaSlow(m_alpha_data, x * 4, y * 4, m_width, m_height, alphadata);
	}
}

void TransToETC2::WriteBigEndian2byteWord(unsigned short* blockadr, std::ofstream& fout)
{
	uint8 bytes[2];
	unsigned short block;

	block = blockadr[0];

	bytes[0] = (block >> 8) & 0xff;
	bytes[1] = (block >> 0) & 0xff;

	fout.write(reinterpret_cast<const char*>(&bytes[0]), 1);
	fout.write(reinterpret_cast<const char*>(&bytes[1]), 1);
}

void TransToETC2::WriteBigEndian4byteWord(unsigned short* blockadr, std::ofstream& fout)
{
	uint8 bytes[4];
	unsigned int block;

	block = blockadr[0];

	bytes[0] = (block >> 24) & 0xff;
	bytes[1] = (block >> 16) & 0xff;
	bytes[2] = (block >> 8) & 0xff;
	bytes[3] = (block >> 0) & 0xff;

	fout.write(reinterpret_cast<const char*>(&bytes[0]), 1);
	fout.write(reinterpret_cast<const char*>(&bytes[1]), 1);
	fout.write(reinterpret_cast<const char*>(&bytes[2]), 1);
	fout.write(reinterpret_cast<const char*>(&bytes[3]), 1);
}

}<commit_msg>[FIXED] ect2 init<commit_after>#include "TransToETC2.h"

#include <ee/math_common.h>
#include <ee/ImagePack.h>
#include <ee/Exception.h>

#include <etcpack_lib.h>

#include <fstream>

#include <assert.h>

namespace eimage
{

TransToETC2::TransToETC2(const uint8_t* pixels, int width, int height, int channels,
						 Type type, bool align_bottom, bool fastest)
	: m_type(type)
	, m_fastest(fastest)
	, m_perceptual(false)
{
	readCompressParams();
	setupAlphaTableAndValtab();

	Prepare(pixels, width, height, channels, align_bottom);
	Encode();
}

TransToETC2::~TransToETC2()
{
	delete m_rgb_data;
	delete m_alpha_data;
	delete m_compressed;
}

void TransToETC2::OutputFile(const std::string& filepath) const
{
	std::ofstream fout(filepath.c_str(), std::ios::binary);
	OutputHeader(fout);
	fout.write(reinterpret_cast<const char*>(m_compressed), m_size);
	fout.close();
}

uint8_t* TransToETC2::GetPixelsData(int& width, int& height) const
{
	width = m_width;
	height = m_height;

	int sz = m_width * m_height;
	uint8_t* pixels = new uint8_t[m_size];
	memcpy(pixels, m_compressed, sz);
	return pixels;
}

void TransToETC2::Prepare(const uint8_t* pixels)
{
	int rgb_sz = m_width * m_height * 3,
		alpha_sz = m_width * m_height;
	m_rgb_data = new uint8_t[rgb_sz];
	m_alpha_data = new uint8_t[alpha_sz];

	const uint8_t* in = pixels;
	uint8_t *out_rgb = m_rgb_data,
		    *out_alpha = m_alpha_data;
	const uint8_t* end = in + m_width * m_height * 4;
	while (in < end)
	{
		memcpy(out_rgb, in, 3);
		out_rgb += 3;
		in += 3;

		if (m_type == RGBA1) {
			*out_alpha++ = (*in++) > 180 ? 255 : 0;
		} else {
			*out_alpha++ = *in++;
		}
	}
}

void TransToETC2::Prepare(const uint8_t* pixels, int width, int height, int channels, bool align_bottom)
{
	assert(channels == 4);
	if (ee::is_power_of_two(width) &&
		ee::is_power_of_two(height) &&
		width == height)
	{
		m_width = width;
		m_height = height;
		Prepare(pixels);
	}
	else
	{
		int nw = ee::next_p2(width),
			nh = ee::next_p2(height);
		ee::ImagePack pack(nw, nh);
		int h = align_bottom ? nh - height : 0;
		pack.AddImage(pixels, width, height, 0, h, ee::ImagePack::PT_NORMAL);

		m_width = nw;
		m_height = nh;
		Prepare(pack.GetPixels());
	}

	if (m_type == RGBA) {
		m_size = m_width * m_height;
	} else {
		m_size = m_width * m_height / 2;
	}

	m_compressed = new uint8_t[m_size];
}

static void WriteRGB(uint8_t*& output, unsigned int block1, unsigned int block2)
{
	output[0] = (block1 >> 24) & 0xFF;
	output[1] = (block1 >> 16) & 0xFF;
	output[2] = (block1 >> 8) & 0xFF;
	output[3] =  block1 & 0xFF;
	output[4] = (block2 >> 24) & 0xFF;
	output[5] = (block2 >> 16) & 0xFF;
	output[6] = (block2 >> 8) & 0xFF;
	output[7] =  block2 & 0xFF;
	output += 8;
}

static void WriteAlpha(uint8_t*& output, uint8_t* alphadata)
{
	memcpy(output, alphadata, 8);
	output += 8;
}

void TransToETC2::Encode()
{
	uint8_t* decoded = new uint8_t[m_width * m_height * 3];

	uint8_t* output = m_compressed;

	int bw = m_width / 4;
	int bh = m_height / 4;
	for (int y = 0; y < bh; ++y) {
		for (int x = 0; x < bw; ++x) {
			switch (m_type)
			{
			case RGB:
				{
					unsigned int block1, block2;
					ComputeRGB(decoded, x, y, block1, block2);
					WriteRGB(output, block1, block2);
				}
				break;
			case RGBA:
				{
					uint8_t alphadata[8];
					ComputeAlpha(x, y, alphadata);
					WriteAlpha(output, alphadata);

					unsigned int block1, block2;
					ComputeRGB(decoded, x, y, block1, block2);
					WriteRGB(output, block1, block2);
				}
				break;
			case RGBA1:
				{
					unsigned int block1, block2;
					compressBlockETC2RGBA1(m_rgb_data, m_alpha_data, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
					WriteRGB(output, block1, block2);
				}
				break;
			default:
				throw ee::Exception("TransToETC2::Encode: Unknown type");
			}
		}
	}
}

void TransToETC2::OutputHeader(std::ofstream& fout) const
{
	unsigned char magic[4] = {'P', 'K', 'M', ' '};
	fout.write(reinterpret_cast<const char*>(&magic[0]), 1);
	fout.write(reinterpret_cast<const char*>(&magic[1]), 1);
	fout.write(reinterpret_cast<const char*>(&magic[2]), 1);
	fout.write(reinterpret_cast<const char*>(&magic[3]), 1);

	unsigned char version[2] = { '2', '0' };
	fout.write(reinterpret_cast<const char*>(&version[0]), 1);
	fout.write(reinterpret_cast<const char*>(&version[1]), 1);

	// In a PKM-file, the codecs are stored using the following identifiers
	//
	// identifier                         value               codec
	// --------------------------------------------------------------------
	// ETC1_RGB_NO_MIPMAPS                  0                 GL_ETC1_RGB8_OES
	// ETC2PACKAGE_RGB_NO_MIPMAPS           1                 GL_COMPRESSED_RGB8_ETC2
	// ETC2PACKAGE_RGBA_NO_MIPMAPS_OLD      2, not used       -
	// ETC2PACKAGE_RGBA_NO_MIPMAPS          3                 GL_COMPRESSED_RGBA8_ETC2_EAC
	// ETC2PACKAGE_RGBA1_NO_MIPMAPS         4                 GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
	// ETC2PACKAGE_R_NO_MIPMAPS             5                 GL_COMPRESSED_R11_EAC
	// ETC2PACKAGE_RG_NO_MIPMAPS            6                 GL_COMPRESSED_RG11_EAC
	// ETC2PACKAGE_R_SIGNED_NO_MIPMAPS      7                 GL_COMPRESSED_SIGNED_R11_EAC
	// ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS     8                 GL_COMPRESSED_SIGNED_RG11_EAC

	enum ETC_TYPE
	{
		ETC1_RGB_NO_MIPMAPS = 0,
		ETC2PACKAGE_RGB_NO_MIPMAPS,
		ETC2PACKAGE_RGBA_NO_MIPMAPS_OLD,
		ETC2PACKAGE_RGBA_NO_MIPMAPS,
		ETC2PACKAGE_RGBA1_NO_MIPMAPS,
		ETC2PACKAGE_R_NO_MIPMAPS,
		ETC2PACKAGE_RG_NO_MIPMAPS,
		ETC2PACKAGE_R_SIGNED_NO_MIPMAPS,
		ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS
	};

	unsigned short type;
	switch (m_type)
	{
	case RGB:
		type = ETC2PACKAGE_RGB_NO_MIPMAPS;
		break;
	case RGBA:
		type = ETC2PACKAGE_RGBA_NO_MIPMAPS;
		break;
	case RGBA1:
		type = ETC2PACKAGE_RGBA1_NO_MIPMAPS;
		break;
	default:
		throw ee::Exception("TransToETC2::OutputHeader: Unknown type");
	}
	WriteBigEndian2byteWord(&type, fout);

	unsigned short w = m_width, h = m_height;
	WriteBigEndian2byteWord(&w, fout);
	WriteBigEndian2byteWord(&h, fout);

	WriteBigEndian2byteWord(&w, fout);
	WriteBigEndian2byteWord(&h, fout);
}

void TransToETC2::ComputeRGB(uint8_t* decoded, int x, int y, unsigned int& block1, unsigned int& block2)
{
	if (m_perceptual) {
		if (m_fastest) {
			compressBlockETC2FastPerceptual(m_rgb_data, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
		} else {
			compressBlockETC2ExhaustivePerceptual(m_rgb_data, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
		}
	} else {
		if (m_fastest) {
			compressBlockETC2Fast(m_rgb_data, NULL, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
		} else {
			compressBlockETC2Exhaustive(m_rgb_data, decoded, m_width, m_height, x * 4, y * 4, block1, block2);
		}
	}
}

void TransToETC2::ComputeAlpha(int x, int y, uint8_t* alphadata)
{
	if (m_fastest) {
		compressBlockAlphaFast(m_alpha_data, x * 4, y * 4, m_width, m_height, alphadata);
	} else {
		compressBlockAlphaSlow(m_alpha_data, x * 4, y * 4, m_width, m_height, alphadata);
	}
}

void TransToETC2::WriteBigEndian2byteWord(unsigned short* blockadr, std::ofstream& fout)
{
	uint8 bytes[2];
	unsigned short block;

	block = blockadr[0];

	bytes[0] = (block >> 8) & 0xff;
	bytes[1] = (block >> 0) & 0xff;

	fout.write(reinterpret_cast<const char*>(&bytes[0]), 1);
	fout.write(reinterpret_cast<const char*>(&bytes[1]), 1);
}

void TransToETC2::WriteBigEndian4byteWord(unsigned short* blockadr, std::ofstream& fout)
{
	uint8 bytes[4];
	unsigned int block;

	block = blockadr[0];

	bytes[0] = (block >> 24) & 0xff;
	bytes[1] = (block >> 16) & 0xff;
	bytes[2] = (block >> 8) & 0xff;
	bytes[3] = (block >> 0) & 0xff;

	fout.write(reinterpret_cast<const char*>(&bytes[0]), 1);
	fout.write(reinterpret_cast<const char*>(&bytes[1]), 1);
	fout.write(reinterpret_cast<const char*>(&bytes[2]), 1);
	fout.write(reinterpret_cast<const char*>(&bytes[3]), 1);
}

}<|endoftext|>


<commit_before>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include "../../core/Setup.h"

#if OUZEL_COMPILE_OPENSL

#include <array>
#include <system_error>
#include "OSLAudioDevice.hpp"
#include "OSLErrorCategory.hpp"
#include "../../core/Engine.hpp"
#include "../../utils/Log.hpp"

namespace ouzel::audio::opensl
{
    namespace
    {
        const ErrorCategory errorCategory{};

        std::error_code makeErrorCode(SLresult e)
        {
            return std::error_code(static_cast<int>(e), errorCategory);
        }

        void playerCallback(SLAndroidSimpleBufferQueueItf bufferQueue, void* context)
        {
            try
            {
                auto audioDevice = static_cast<AudioDevice*>(context);

                audioDevice->enqueue(bufferQueue);
            }
            catch (const std::exception& e)
            {
                logger.log(Log::Level::error) << e.what();
            }
        }

        constexpr SLuint32 getChannelMask(std::uint32_t channels)
        {
            switch (channels)
            {
                case 1: return SL_SPEAKER_FRONT_CENTER;
                case 2: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
                case 4: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
                case 6: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
                case 7: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
                case 8: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
                default:
                    throw std::runtime_error("Invalid channel count");
            }
        }
    }

    AudioDevice::AudioDevice(const Settings& settings,
                             const std::function<void(std::uint32_t frames,
                                                      std::uint32_t channels,
                                                      std::uint32_t sampleRate,
                                                      std::vector<float>& samples)>& initDataGetter):
        audio::AudioDevice(Driver::openSL, settings, initDataGetter)
    {
        const std::array engineInterfaces = { SL_IID_ENGINE, SL_IID_ENGINECAPABILITIES };
        constexpr std::array engineRequirements = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE };

        SLObjectItf engineObjectPointer;
        if (const auto result = slCreateEngine(&engineObjectPointer, 0, nullptr,
                                               static_cast<SLuint32>(engineInterfaces.size()),
                                               engineInterfaces.data(),
                                               engineRequirements.data()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL engine object");

        engineObject = engineObjectPointer;

        if (const auto result = engineObject->Realize(engineObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL engine object");

        SLEngineCapabilitiesItf engineCapabilities;
        if (const auto result = engineObject->GetInterface(engineObject.get(), SL_IID_ENGINECAPABILITIES, &engineCapabilities); result == SL_RESULT_SUCCESS)
        {
            SLint16 major;
            SLint16 minor;
            SLint16 step;
            if (const auto result = (*engineCapabilities)->QueryAPIVersion(engineCapabilities, &major, &minor, &step); result != SL_RESULT_SUCCESS)
                throw std::system_error(makeErrorCode(result), "Failed to get OpenSL version");

            apiMajorVersion = static_cast<std::uint16_t>(major);
            apiMinorVersion = static_cast<std::uint16_t>(minor);
        }
        else
        {
            // engine capabilities interface is not supported in OpenSL ES 1.0
            apiMajorVersion = 1;
            apiMinorVersion = 0;
        }

        if (const auto result = engineObject->GetInterface(engineObject.get(), SL_IID_ENGINE, &engine); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL engine");

        SLObjectItf outputMixObjectPointer;
        if (const auto result = (*engine)->CreateOutputMix(engine, &outputMixObjectPointer, 0, nullptr, nullptr); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL output mix");

        outputMixObject = outputMixObjectPointer;

        if (const auto result = outputMixObject->Realize(outputMixObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL output mix");

        SLDataLocator_AndroidSimpleBufferQueue location = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};

        SLDataFormat_PCM dataFormat;
        dataFormat.formatType = SL_DATAFORMAT_PCM;
        // TODO: get speaker count
        dataFormat.numChannels = channels;
        dataFormat.samplesPerSec = sampleRate * 1000; // mHz
        dataFormat.bitsPerSample = sizeof(std::int16_t) * 8;
        dataFormat.containerSize = dataFormat.bitsPerSample;
        dataFormat.channelMask = getChannelMask(channels);
        dataFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;

        SLDataSource dataSource{&location, &dataFormat};
        SLDataLocator_OutputMix dataLocatorOut{SL_DATALOCATOR_OUTPUTMIX, outputMixObject.get()};
        SLDataSink dataSink{&dataLocatorOut, nullptr};
        constexpr SLuint32 playerIIDCount = 3;
        const SLInterfaceID playerIIDs[] = {SL_IID_BUFFERQUEUE, SL_IID_PLAY, SL_IID_VOLUME};
        constexpr SLboolean playerReqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};

        SLObjectItf playerObjectPointer;
        if (const auto result = (*engine)->CreateAudioPlayer(engine, &playerObjectPointer, &dataSource, &dataSink, playerIIDCount, playerIIDs, playerReqs); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL player object");

        playerObject = playerObjectPointer;

        sampleFormat = SampleFormat::signedInt16;

        if (const auto result = playerObject->Realize(playerObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL player object");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_PLAY, &player); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL player interface");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_BUFFERQUEUE, &bufferQueue); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL buffer queue interface");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_VOLUME, &playerVolume); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL volume interface");

        if (const auto result = (*bufferQueue)->Clear(bufferQueue); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to clear OpenSL buffer");

        if (const auto result = (*bufferQueue)->RegisterCallback(bufferQueue, playerCallback, this); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to register OpenSL buffer queue callback");
    }

    void AudioDevice::start()
    {
        getData(bufferSize / (channels * sizeof(std::int16_t)), data);

        if (const auto result = (*bufferQueue)->Enqueue(bufferQueue, data.data(), data.size()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to enqueue OpenSL data");

        if (const auto result = (*player)->SetPlayState(player, SL_PLAYSTATE_PLAYING); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to play sound");
    }

    void AudioDevice::stop()
    {
        if (const auto result = (*player)->SetPlayState(player, SL_PLAYSTATE_STOPPED); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to stop sound");
    }

    void AudioDevice::enqueue(SLAndroidSimpleBufferQueueItf bufferQueue)
    {
        getData(bufferSize / (channels * sizeof(std::int16_t)), data);

        if (const auto result = (*bufferQueue)->Enqueue(bufferQueue, data.data(), data.size()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to enqueue OpenSL data");
    }
}
#endif
<commit_msg>Throw exception if got a result different than SL_RESULT_FEATURE_UNSUPPORTED<commit_after>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include "../../core/Setup.h"

#if OUZEL_COMPILE_OPENSL

#include <array>
#include <system_error>
#include "OSLAudioDevice.hpp"
#include "OSLErrorCategory.hpp"
#include "../../core/Engine.hpp"
#include "../../utils/Log.hpp"

namespace ouzel::audio::opensl
{
    namespace
    {
        const ErrorCategory errorCategory{};

        std::error_code makeErrorCode(SLresult e)
        {
            return std::error_code(static_cast<int>(e), errorCategory);
        }

        void playerCallback(SLAndroidSimpleBufferQueueItf bufferQueue, void* context)
        {
            try
            {
                auto audioDevice = static_cast<AudioDevice*>(context);

                audioDevice->enqueue(bufferQueue);
            }
            catch (const std::exception& e)
            {
                logger.log(Log::Level::error) << e.what();
            }
        }

        constexpr SLuint32 getChannelMask(std::uint32_t channels)
        {
            switch (channels)
            {
                case 1: return SL_SPEAKER_FRONT_CENTER;
                case 2: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
                case 4: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
                case 6: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT;
                case 7: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
                case 8: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT;
                default:
                    throw std::runtime_error("Invalid channel count");
            }
        }
    }

    AudioDevice::AudioDevice(const Settings& settings,
                             const std::function<void(std::uint32_t frames,
                                                      std::uint32_t channels,
                                                      std::uint32_t sampleRate,
                                                      std::vector<float>& samples)>& initDataGetter):
        audio::AudioDevice(Driver::openSL, settings, initDataGetter)
    {
        const std::array engineInterfaces = { SL_IID_ENGINE, SL_IID_ENGINECAPABILITIES };
        constexpr std::array engineRequirements = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE };

        SLObjectItf engineObjectPointer;
        if (const auto result = slCreateEngine(&engineObjectPointer, 0, nullptr,
                                               static_cast<SLuint32>(engineInterfaces.size()),
                                               engineInterfaces.data(),
                                               engineRequirements.data()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL engine object");

        engineObject = engineObjectPointer;

        if (const auto result = engineObject->Realize(engineObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL engine object");

        SLEngineCapabilitiesItf engineCapabilities;
        if (const auto result = engineObject->GetInterface(engineObject.get(), SL_IID_ENGINECAPABILITIES, &engineCapabilities); result == SL_RESULT_SUCCESS)
        {
            SLint16 major;
            SLint16 minor;
            SLint16 step;
            if (const auto result = (*engineCapabilities)->QueryAPIVersion(engineCapabilities, &major, &minor, &step); result != SL_RESULT_SUCCESS)
                throw std::system_error(makeErrorCode(result), "Failed to get OpenSL version");

            apiMajorVersion = static_cast<std::uint16_t>(major);
            apiMinorVersion = static_cast<std::uint16_t>(minor);
        }
        else if (result == SL_RESULT_FEATURE_UNSUPPORTED)
        {
            // engine capabilities interface is not supported in OpenSL ES 1.0
            apiMajorVersion = 1;
            apiMinorVersion = 0;
        }
        else
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL engine capabilities");

        if (const auto result = engineObject->GetInterface(engineObject.get(), SL_IID_ENGINE, &engine); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL engine");

        SLObjectItf outputMixObjectPointer;
        if (const auto result = (*engine)->CreateOutputMix(engine, &outputMixObjectPointer, 0, nullptr, nullptr); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL output mix");

        outputMixObject = outputMixObjectPointer;

        if (const auto result = outputMixObject->Realize(outputMixObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL output mix");

        SLDataLocator_AndroidSimpleBufferQueue location = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};

        SLDataFormat_PCM dataFormat;
        dataFormat.formatType = SL_DATAFORMAT_PCM;
        // TODO: get speaker count
        dataFormat.numChannels = channels;
        dataFormat.samplesPerSec = sampleRate * 1000; // mHz
        dataFormat.bitsPerSample = sizeof(std::int16_t) * 8;
        dataFormat.containerSize = dataFormat.bitsPerSample;
        dataFormat.channelMask = getChannelMask(channels);
        dataFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;

        SLDataSource dataSource{&location, &dataFormat};
        SLDataLocator_OutputMix dataLocatorOut{SL_DATALOCATOR_OUTPUTMIX, outputMixObject.get()};
        SLDataSink dataSink{&dataLocatorOut, nullptr};
        constexpr SLuint32 playerIIDCount = 3;
        const SLInterfaceID playerIIDs[] = {SL_IID_BUFFERQUEUE, SL_IID_PLAY, SL_IID_VOLUME};
        constexpr SLboolean playerReqs[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};

        SLObjectItf playerObjectPointer;
        if (const auto result = (*engine)->CreateAudioPlayer(engine, &playerObjectPointer, &dataSource, &dataSink, playerIIDCount, playerIIDs, playerReqs); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL player object");

        playerObject = playerObjectPointer;

        sampleFormat = SampleFormat::signedInt16;

        if (const auto result = playerObject->Realize(playerObject.get(), SL_BOOLEAN_FALSE); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to create OpenSL player object");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_PLAY, &player); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL player interface");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_BUFFERQUEUE, &bufferQueue); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL buffer queue interface");

        if (const auto result = playerObject->GetInterface(playerObject.get(), SL_IID_VOLUME, &playerVolume); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to get OpenSL volume interface");

        if (const auto result = (*bufferQueue)->Clear(bufferQueue); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to clear OpenSL buffer");

        if (const auto result = (*bufferQueue)->RegisterCallback(bufferQueue, playerCallback, this); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to register OpenSL buffer queue callback");
    }

    void AudioDevice::start()
    {
        getData(bufferSize / (channels * sizeof(std::int16_t)), data);

        if (const auto result = (*bufferQueue)->Enqueue(bufferQueue, data.data(), data.size()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to enqueue OpenSL data");

        if (const auto result = (*player)->SetPlayState(player, SL_PLAYSTATE_PLAYING); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to play sound");
    }

    void AudioDevice::stop()
    {
        if (const auto result = (*player)->SetPlayState(player, SL_PLAYSTATE_STOPPED); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to stop sound");
    }

    void AudioDevice::enqueue(SLAndroidSimpleBufferQueueItf bufferQueue)
    {
        getData(bufferSize / (channels * sizeof(std::int16_t)), data);

        if (const auto result = (*bufferQueue)->Enqueue(bufferQueue, data.data(), data.size()); result != SL_RESULT_SUCCESS)
            throw std::system_error(makeErrorCode(result), "Failed to enqueue OpenSL data");
    }
}
#endif
<|endoftext|>


<commit_before>//******************************************************************************
// Board.cpp
// Revision History:
//
// Date           Author               Description
// 11/28/2017     Jason Chen           Added class
//******************************************************************************

#include <iostream>
#include <sstream>
#include "Deck.h"
#include "Hand.h"
#include "Card.h"
#include "Board.h"
#include "Player.h"
#include "ConsoleUI.h"
#include "helper.h"
using namespace std;

//constructor
//initialize the board for a new game
Board::Board(Player* hum, Player* AI, int smallBlindPlayer)
{
	human = hum;
	this->AI=AI;
	setCommunity();
	help=new helper();
	this->smallBlindPlayer=smallBlindPlayer;
}

void Board::setBlind(int bld)
{
	smallBlind = bld;
}

void Board::setCommunity()
{
	for(int i = 0; i < 5; i++)
	{
		community[i] = dek.draw();
	}
	//set player cards
	human->addOne(dek.draw());
	human->addTwo(dek.draw());
	AI->addOne(dek.draw());
	AI->addTwo(dek.draw());
}

void Board::printBoard()
{
	cout << "The pot is: " << pot << endl;
	cout << "Your stack size is: " << human->getTotalChips() << endl;
	cout << "AI's stack size is: " << AI->getTotalChips() << endl << endl;
}

bool Board::run()
{
	string inputTemp;
	ConsoleUI* ui = new ConsoleUI();
	if(human ->getTotalChips() < AI->getPrevBet())
	{
		inputTemp = ui->input("Fold (1) or All in (4)");
		while (!help->isInt(inputTemp)||(stoi(inputTemp)!=1 && stoi(inputTemp)!=4))
		{
			ui->output("Input must a choice number provided");
			inputTemp=ui->input("Fold (1) or All in (4)");
		}
	}
	else if(human->getTotalChips() < 2*AI->getPrevBet())
	{
		inputTemp=ui->input("Fold (1), Call (2), or All in (4)\n");
		while (!help->isInt(inputTemp)||(stoi(inputTemp)!=1 && stoi(inputTemp)!=3 &&stoi(inputTemp)!=4))
		{
			ui->output("Input must a choice number provided");
			inputTemp=ui->input("Fold (1), Call (2), or All in (4)");
		}
	}
	else if(human->getTempPool() < AI->getTempPool())
	{
		inputTemp=ui->input("Fold (1), Call (2), or Raise (3)\n");
		while (!help->isInt(inputTemp)||stoi(inputTemp)<1||stoi(inputTemp)>3)
		{
			ui->output("Input must a choice number provided");
			inputTemp=ui->input("Fold (1), Call (2), or Raise (3)");
		}
	}
	else
	{
		inputTemp=ui->input("Fold (1), Check (2), or Raise (3)\n");
		while (!help->isInt(inputTemp)||stoi(inputTemp)<1||stoi(inputTemp)>3)
		{
			ui->output("Input must be a choice number provided.");
			inputTemp=ui->input("Fold (1), Check (2), or Raise (3)");
		}
	}
	if(inputTemp == "1")
	{
		return true;
	}
	else if(inputTemp == "2")
	{
		human->call(AI);
		pot=human->getTempPool()+AI->getTempPool();
		printBoard();
		return false;
	}
	else if(inputTemp == "3")
	{
		int prev = AI->getPrevBet();
		string r = ui->input("How much do you want to raise by?");
		while (!help->isInt(r)|| stoi(r) < prev*2 || stoi(r) > min(human->getTotalChips(), AI->getTotalChips()) || stoi(r) % smallBlind != 0)
		{
			ui->output("Input must be (1) an integer multiple of the small blind (2) at least double the previous bet (3) less than your total chip count.");
			r=ui->input("How much do you want to raise by?");
		}
		human->raise(stoi(r));
		pot=human->getTempPool()+AI->getTempPool();
		human->setPrevBet(stoi(r));
		printBoard();
		return false;
	}
	else
	{
		human->raise(human->getTotalChips());
		pot=human->getTempPool()+AI->getTempPool();
		printBoard();
		return false;
	}

}

bool Board::runAI(){
	ConsoleUI* ui = new ConsoleUI();
	ui->output("AI's turn: ");
	AI->call(human); //for now
	pot=AI->getTempPool()+human->getTempPool();
	printBoard();
	return false;
}
bool Board::preflop()
{
	printBoard();
	ConsoleUI* ui=new ConsoleUI();
	string inputTemp;
	//print user's hand
	ui->output("Your hand: ");
	(human->getHandOne()).printCard();
	(human->getHandTwo()).printCard();
	ui->output("");
	//force user to put in blind
	pot=smallBlind*3;
	if (smallBlindPlayer==1){
		AI->raise(smallBlind);
		human->raise(smallBlind*2);
	}
	else{
		human->raise(smallBlind);
		AI->raise(smallBlind*2);
	}
	cout<<"AI total chips: "<<AI->getTotalChips()<<endl; //980
	cout<<"Human total chips: "<<human->getTotalChips()<<endl;  //990
	cout<<"small blind player : "<<smallBlindPlayer<<endl;
	while(human->getTempPool()!=AI->getTempPool()) //player facing a bet
	{
		if (smallBlindPlayer==1){
			//AI goes first
			this->runAI();
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
		}
		else if (smallBlindPlayer==0){
			//player goes first
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
			this->runAI();
		}
	}
	return false;
}

bool Board::flop()
{
	ConsoleUI* ui=new ConsoleUI();
	cout << "The flop is " << endl;
	community[0].printCard();
	community[1].printCard();
	community[2].printCard();
	cout << endl;
	//print user's hand
	ui->output("Your hand: ");
	(human->getHandOne()).printCard();
	(human->getHandTwo()).printCard();
	ui->output("");

	cout<<"AI total chips: "<<AI->getTotalChips()<<endl; //980
	cout<<"Human total chips: "<<human->getTotalChips()<<endl;  //990
	cout<<"small blind player : "<<smallBlindPlayer<<endl;
	do
	{
		if (smallBlindPlayer==1){
			//AI goes first
			this->runAI();
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
		}
		else if (smallBlindPlayer==0){
			//player goes first
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
			this->runAI();
		}
	}
	while(human->getTempPool()!=AI->getTempPool()); //player facing a bet

	return false;
}

bool Board::turn()
{
	cout << "The turn is " << endl;
	community[0].printCard();
	community[1].printCard();
	community[2].printCard();
	community[3].printCard();
	cout << endl;
	ConsoleUI* ui=new ConsoleUI();
	//print user's hand
	ui->output("Your hand: ");
	(human->getHandOne()).printCard();
	(human->getHandTwo()).printCard();
	ui->output("");
	cout<<"AI total chips: "<<AI->getTotalChips()<<endl; //980
	cout<<"Human total chips: "<<human->getTotalChips()<<endl;  //990
	cout<<"small blind player : "<<smallBlindPlayer<<endl;
	do
	{
		if (smallBlindPlayer==1){
			//AI goes first
			this->runAI();
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
		}
		else if (smallBlindPlayer==0){
			//player goes first
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
			this->runAI();
		}
	}
	while(human->getTempPool()!=AI->getTempPool()); //player facing a bet
	return false;
}

bool Board::river()
{
	cout << "The river is " << endl;
	community[0].printCard();
	community[1].printCard();
	community[2].printCard();
	community[3].printCard();
	community[4].printCard();
	cout << endl;
	ConsoleUI* ui=new ConsoleUI();
	//print user's hand
	ui->output("Your hand: ");
	(human->getHandOne()).printCard();
	(human->getHandTwo()).printCard();
	ui->output("");
	cout<<"AI total chips: "<<AI->getTotalChips()<<endl; //980
	cout<<"Human total chips: "<<human->getTotalChips()<<endl;  //990
	cout<<"small blind player : "<<smallBlindPlayer<<endl;
	do
	{
		if (smallBlindPlayer==1){
			//AI goes first
			this->runAI();
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
		}
		else if (smallBlindPlayer==0){
			//player goes first
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
			this->runAI();
		}
	}
	while(human->getTempPool()!=AI->getTempPool()); //player facing a bet

	//after everything is done
	Hand* humanBest=help->bestHand((human->getHandOne()),(human->getHandTwo()),
					community[0],community[1],community[2],community[3],community[4]);
	Hand* AIBest=help->bestHand((AI->getHandOne()),(AI->getHandTwo()),
			community[0],community[1],community[2],community[3],community[4]);
	int result=help->compareHands(humanBest,AIBest);
	ui->output("Community Cards: ");
	for (int i=0;i<5;i++){
		community[i].printCard();
	}
	ui->output("");
	ui->output("AI's cards: ");
	AI->getHandOne().printCard();
	AI->getHandTwo().printCard();
	ui->output("");
	ui->output("Your cards: ");
	human->getHandOne().printCard();
	human->getHandTwo().printCard();
	ui->output("");
	ui->output("Your best hand: ");
	humanBest->printHand();
	ui->output("");
	ui->output("AI's best hand: ");
	AIBest->printHand();
	ui->output("");
	if (result==1){
		ui->output("You won.");
		human->setTotalChips(human->getTotalChips()+pot);
	}
	else if (result==0){
		ui->output("AI won");
		AI->setTotalChips(AI->getTotalChips()+pot);
	}
	else{
		ui->output("Tie");
		human->setTotalChips(human->getTotalChips()+pot/2);
		AI->setTotalChips(AI->getTotalChips()+pot/2);
	}
	//cout<<"Result: "<<result<<endl;
	return false;
}

void Board::clearBoard()
{
	human->resetTempPool();
	AI->resetTempPool();
	pot=0;
	dek.shuffle();
	setCommunity();
	if (smallBlindPlayer==0){
		smallBlindPlayer=1;
	}
	else{
		smallBlindPlayer=0;
	}
}
<commit_msg>minor changes to previous bets<commit_after>//******************************************************************************
// Board.cpp
// Revision History:
//
// Date           Author               Description
// 11/28/2017     Jason Chen           Added class
//******************************************************************************

#include <iostream>
#include <sstream>
#include "Deck.h"
#include "Hand.h"
#include "Card.h"
#include "Board.h"
#include "Player.h"
#include "ConsoleUI.h"
#include "helper.h"
using namespace std;

//constructor
//initialize the board for a new game
Board::Board(Player* hum, Player* AI, int smallBlindPlayer)
{
	human = hum;
	this->AI=AI;
	setCommunity();
	help=new helper();
	this->smallBlindPlayer=smallBlindPlayer;
}

void Board::setBlind(int bld)
{
	smallBlind = bld;
}

void Board::setCommunity()
{
	for(int i = 0; i < 5; i++)
	{
		community[i] = dek.draw();
	}
	//set player cards
	human->addOne(dek.draw());
	human->addTwo(dek.draw());
	AI->addOne(dek.draw());
	AI->addTwo(dek.draw());
}

void Board::printBoard()
{
	cout << "The pot is: " << pot << endl;
	cout << "Your stack size is: " << human->getTotalChips() << endl;
	cout << "AI's stack size is: " << AI->getTotalChips() << endl << endl;
}

bool Board::run()
{
	string inputTemp;
	ConsoleUI* ui = new ConsoleUI();
	if(human ->getTotalChips() < AI->getPrevBet())
	{
		inputTemp = ui->input("Fold (1) or All in (4)");
		while (!help->isInt(inputTemp)||(stoi(inputTemp)!=1 && stoi(inputTemp)!=4))
		{
			ui->output("Input must a choice number provided");
			inputTemp=ui->input("Fold (1) or All in (4)");
		}
	}
	else if(human->getTotalChips() < 2*AI->getPrevBet())
	{
		inputTemp=ui->input("Fold (1), Call (2), or All in (4)\n");
		while (!help->isInt(inputTemp)||(stoi(inputTemp)!=1 && stoi(inputTemp)!=3 &&stoi(inputTemp)!=4))
		{
			ui->output("Input must a choice number provided");
			inputTemp=ui->input("Fold (1), Call (2), or All in (4)");
		}
	}
	else if(human->getTempPool() < AI->getTempPool())
	{
		inputTemp=ui->input("Fold (1), Call (2), or Raise (3)\n");
		while (!help->isInt(inputTemp)||stoi(inputTemp)<1||stoi(inputTemp)>3)
		{
			ui->output("Input must a choice number provided");
			inputTemp=ui->input("Fold (1), Call (2), or Raise (3)");
		}
	}
	else
	{
		inputTemp=ui->input("Fold (1), Check (2), or Raise (3)\n");
		while (!help->isInt(inputTemp)||stoi(inputTemp)<1||stoi(inputTemp)>3)
		{
			ui->output("Input must be a choice number provided.");
			inputTemp=ui->input("Fold (1), Check (2), or Raise (3)");
		}
	}
	if(inputTemp == "1")
	{
		return true;
	}
	else if(inputTemp == "2")
	{
		human->call(AI);
		pot=human->getTempPool()+AI->getTempPool();
		printBoard();
		return false;
	}
	else if(inputTemp == "3")
	{
		int prev = AI->getPrevBet();
		string r = ui->input("How much do you want to raise by?");
		while (!help->isInt(r)|| stoi(r) < prev*2 || stoi(r) > min(human->getTotalChips(), AI->getTotalChips()) || stoi(r) % smallBlind != 0)
		{
			ui->output("Input must be (1) an integer multiple of the small blind (2) at least double the previous bet (3) less than your total chip count.");
			r=ui->input("How much do you want to raise by?");
		}
		human->raise(stoi(r));
		pot=human->getTempPool()+AI->getTempPool();
		human->setPrevBet(stoi(r));
		printBoard();
		return false;
	}
	else
	{
		human->raise(human->getTotalChips());
		pot=human->getTempPool()+AI->getTempPool();
		printBoard();
		return false;
	}

}

bool Board::runAI(){
	ConsoleUI* ui = new ConsoleUI();
	ui->output("AI's turn: ");
	AI->call(human); //for now
	pot=AI->getTempPool()+human->getTempPool();
	printBoard();
	return false;
}
bool Board::preflop()
{
	human->setPrevBet(0);
	AI->setPrevBet(0);
	printBoard();
	ConsoleUI* ui=new ConsoleUI();
	string inputTemp;
	//print user's hand
	ui->output("Your hand: ");
	(human->getHandOne()).printCard();
	(human->getHandTwo()).printCard();
	ui->output("");
	//force user to put in blind
	pot=smallBlind*3;
	if (smallBlindPlayer==1){
		AI->raise(smallBlind);
		human->raise(smallBlind*2);
	}
	else{
		human->raise(smallBlind);
		AI->raise(smallBlind*2);
	}
	cout<<"AI total chips: "<<AI->getTotalChips()<<endl; //980
	cout<<"Human total chips: "<<human->getTotalChips()<<endl;  //990
	cout<<"small blind player : "<<smallBlindPlayer<<endl;
	while(human->getTempPool()!=AI->getTempPool()) //player facing a bet
	{
		if (smallBlindPlayer==1){
			//AI goes first
			this->runAI();
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
		}
		else if (smallBlindPlayer==0){
			//player goes first
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
			this->runAI();
		}
	}
	return false;
}

bool Board::flop()
{
	human->setPrevBet(0);
	AI->setPrevBet(0);
	ConsoleUI* ui=new ConsoleUI();
	cout << "The flop is " << endl;
	community[0].printCard();
	community[1].printCard();
	community[2].printCard();
	cout << endl;
	//print user's hand
	ui->output("Your hand: ");
	(human->getHandOne()).printCard();
	(human->getHandTwo()).printCard();
	ui->output("");

	cout<<"AI total chips: "<<AI->getTotalChips()<<endl; //980
	cout<<"Human total chips: "<<human->getTotalChips()<<endl;  //990
	cout<<"small blind player : "<<smallBlindPlayer<<endl;
	do
	{
		if (smallBlindPlayer==1){
			//AI goes first
			this->runAI();
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
		}
		else if (smallBlindPlayer==0){
			//player goes first
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
			this->runAI();
		}
	}
	while(human->getTempPool()!=AI->getTempPool()); //player facing a bet

	return false;
}

bool Board::turn()
{
	human->setPrevBet(0);
	AI->setPrevBet(0);
	cout << "The turn is " << endl;
	community[0].printCard();
	community[1].printCard();
	community[2].printCard();
	community[3].printCard();
	cout << endl;
	ConsoleUI* ui=new ConsoleUI();
	//print user's hand
	ui->output("Your hand: ");
	(human->getHandOne()).printCard();
	(human->getHandTwo()).printCard();
	ui->output("");
	cout<<"AI total chips: "<<AI->getTotalChips()<<endl; //980
	cout<<"Human total chips: "<<human->getTotalChips()<<endl;  //990
	cout<<"small blind player : "<<smallBlindPlayer<<endl;
	do
	{
		if (smallBlindPlayer==1){
			//AI goes first
			this->runAI();
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
		}
		else if (smallBlindPlayer==0){
			//player goes first
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
			this->runAI();
		}
	}
	while(human->getTempPool()!=AI->getTempPool()); //player facing a bet
	return false;
}

bool Board::river()
{
	human->setPrevBet(0);
	AI->setPrevBet(0);
	cout << "The river is " << endl;
	community[0].printCard();
	community[1].printCard();
	community[2].printCard();
	community[3].printCard();
	community[4].printCard();
	cout << endl;
	ConsoleUI* ui=new ConsoleUI();
	//print user's hand
	ui->output("Your hand: ");
	(human->getHandOne()).printCard();
	(human->getHandTwo()).printCard();
	ui->output("");
	cout<<"AI total chips: "<<AI->getTotalChips()<<endl; //980
	cout<<"Human total chips: "<<human->getTotalChips()<<endl;  //990
	cout<<"small blind player : "<<smallBlindPlayer<<endl;
	do
	{
		if (smallBlindPlayer==1){
			//AI goes first
			this->runAI();
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
		}
		else if (smallBlindPlayer==0){
			//player goes first
			bool flag=this->run();
			if (flag==true){
				AI->setTotalChips(AI->getTotalChips()+pot);
				return true;
			}
			this->runAI();
		}
	}
	while(human->getTempPool()!=AI->getTempPool()); //player facing a bet

	//after everything is done
	Hand* humanBest=help->bestHand((human->getHandOne()),(human->getHandTwo()),
					community[0],community[1],community[2],community[3],community[4]);
	Hand* AIBest=help->bestHand((AI->getHandOne()),(AI->getHandTwo()),
			community[0],community[1],community[2],community[3],community[4]);
	int result=help->compareHands(humanBest,AIBest);
	ui->output("Community Cards: ");
	for (int i=0;i<5;i++){
		community[i].printCard();
	}
	ui->output("");
	ui->output("AI's cards: ");
	AI->getHandOne().printCard();
	AI->getHandTwo().printCard();
	ui->output("");
	ui->output("Your cards: ");
	human->getHandOne().printCard();
	human->getHandTwo().printCard();
	ui->output("");
	ui->output("Your best hand: ");
	humanBest->printHand();
	ui->output("");
	ui->output("AI's best hand: ");
	AIBest->printHand();
	ui->output("");
	if (result==1){
		ui->output("You won.");
		human->setTotalChips(human->getTotalChips()+pot);
	}
	else if (result==0){
		ui->output("AI won");
		AI->setTotalChips(AI->getTotalChips()+pot);
	}
	else{
		ui->output("Tie");
		human->setTotalChips(human->getTotalChips()+pot/2);
		AI->setTotalChips(AI->getTotalChips()+pot/2);
	}
	//cout<<"Result: "<<result<<endl;
	return false;
}

void Board::clearBoard()
{
	human->resetTempPool();
	AI->resetTempPool();
	human->setPrevBet(0);
	AI->setPrevBet(0);
	pot=0;
	dek.shuffle();
	setCommunity();
	if (smallBlindPlayer==0){
		smallBlindPlayer=1;
	}
	else{
		smallBlindPlayer=0;
	}
}
<|endoftext|>


<commit_before>//Copyright (c) 2020 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "InwardDistributedBeadingStrategy.h"

namespace cura
{

    InwardDistributedBeadingStrategy::Beading InwardDistributedBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
    {
        Beading ret;

        ret.total_thickness = thickness;
        if (bead_count > 0)
        {
            const coord_t to_be_divided = thickness - bead_count * optimal_width;
            float total_weight = 0;
            const float middle = static_cast<float>(bead_count - 1) / 2;

            const auto getWeight = [middle, this](coord_t bead_idx)
            {
                const float dev_from_middle = bead_idx - middle;
                return std::max(0.0f, 1.0f - one_over_distribution_radius_squared * dev_from_middle * dev_from_middle);
            };

            for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
            {
                total_weight += getWeight(bead_idx);
            }

            for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
            {
                const coord_t width = optimal_width + to_be_divided * getWeight(bead_idx) / total_weight;
                if (bead_idx == 0)
                {
                    ret.toolpath_locations.emplace_back(width / 2);
                }
                else
                {
                    ret.toolpath_locations.emplace_back(ret.toolpath_locations.back() + (ret.bead_widths.back() + width) / 2);
                }
                ret.bead_widths.emplace_back(width);
            }
            ret.left_over = 0;
        }
        else
        {
            ret.left_over = thickness;
        }

        return ret;
    }

} // namespace cura
<commit_msg>Calculate weights only once<commit_after>//Copyright (c) 2020 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <numeric>

#include "InwardDistributedBeadingStrategy.h"

namespace cura
{

    InwardDistributedBeadingStrategy::Beading InwardDistributedBeadingStrategy::compute(coord_t thickness, coord_t bead_count) const
    {
        Beading ret;

        ret.total_thickness = thickness;
        if (bead_count > 0)
        {
            const coord_t to_be_divided = thickness - bead_count * optimal_width;
            const float middle = static_cast<float>(bead_count - 1) / 2;

            const auto getWeight = [middle, this](coord_t bead_idx)
            {
                const float dev_from_middle = bead_idx - middle;
                return std::max(0.0f, 1.0f - one_over_distribution_radius_squared * dev_from_middle * dev_from_middle);
            };

            std::vector<float> weights;
            weights.resize(bead_count);
            for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
            {
                weights[bead_idx] = getWeight(bead_idx);
            }

            const float total_weight = std::accumulate(weights.cbegin(), weights.cend(), 0.f);
            for (coord_t bead_idx = 0; bead_idx < bead_count; bead_idx++)
            {
                const float weight_fraction = weights[bead_idx] / total_weight;
                const coord_t splitup_left_over_weight = to_be_divided * weight_fraction;
                const coord_t width = optimal_width + splitup_left_over_weight;
                if (bead_idx == 0)
                {
                    ret.toolpath_locations.emplace_back(width / 2);
                }
                else
                {
                    ret.toolpath_locations.emplace_back(ret.toolpath_locations.back() + (ret.bead_widths.back() + width) / 2);
                }
                ret.bead_widths.emplace_back(width);
            }
            ret.left_over = 0;
        }
        else
        {
            ret.left_over = thickness;
        }

        return ret;
    }

} // namespace cura
<|endoftext|>


<commit_before>//
// base.hpp
// ~~~~~~~~
//
// Copyright (c) 2014 Rick Yang (rick68 at gmail dot com)
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

#ifndef EIGENJS_BASIC_HPP
#define EIGENJS_BASIC_HPP

#include <v8.h>
#include <node.h>
#include <nan.h>

#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>

#include <eigen3/Eigen/Dense>

#include <complex>
#include <memory>
#include <type_traits>

#include "Complex_fwd.hpp"
#include "Matrix_fwd.hpp"
#include "CMatrix_fwd.hpp"
#include "Vector_fwd.hpp"
#include "CVector_fwd.hpp"
#include "RowVector_fwd.hpp"
#include "CRowVector_fwd.hpp"
#include "MatrixBlock_fwd.hpp"
#include "CMatrixBlock_fwd.hpp"

#include "detail/unwrap_eigen_block.hpp"
#include "detail/is_eigen_block.hpp"
#include "detail/is_eigen_matrix.hpp"

namespace EigenJS {

namespace detail {
  template <typename ScalarType>
  struct std_complex_dummy_ptr {
    typedef ScalarType scalar_type;
    typedef std::complex<scalar_type> value_type;

    NAN_INLINE value_type& operator*() { return value_; }
    NAN_INLINE const value_type& operator*() const { return value_; }
    NAN_INLINE value_type* operator->() { return &value_; }
    NAN_INLINE const value_type* operator->() const { return &value_; }

   private:
    value_type value_;
  };

}  // namespace detail

template <
  template <typename, typename, const char*> class Derived
, typename ScalarType
, typename ValueType
, const char* ClassName
>
struct base : node::ObjectWrap {
  typedef Derived<ScalarType, ValueType, ClassName> derived_type;

  typedef ScalarType scalar_type;
  typedef typename detail::unwrap_eigen_block<ValueType>::type value_type;

  typedef typename std::conditional<
      std::is_same<
        value_type
      , typename detail::std_complex_dummy_ptr<scalar_type>::value_type
      >::value
    , detail::std_complex_dummy_ptr<scalar_type>
    , std::shared_ptr<value_type>
    >::type pointer_type;

  static NAN_INLINE bool is_scalar(const v8::Handle<v8::Value>& arg) {
    return arg->IsNumber() ? true : false;
  }

  static NAN_INLINE bool is_complex(const v8::Handle<v8::Value>& arg) {
    return Complex<scalar_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool
  is_complex_or_saclar(const v8::Handle<v8::Value>& arg) {
    return
      Complex<scalar_type>::base_type::has_instance(arg) || arg->IsNumber()
      ? true : false;
  }

  static NAN_INLINE bool is_matrix(const v8::Handle<v8::Value>& arg) {
    return Matrix<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_cmatrix(const v8::Handle<v8::Value>& arg) {
    return CMatrix<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_vector(const v8::Handle<v8::Value>& arg) {
    return Vector<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_cvector(const v8::Handle<v8::Value>& arg) {
    return CVector<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_rowvector(const v8::Handle<v8::Value>& arg) {
    return RowVector<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_crowvector(const v8::Handle<v8::Value>& arg) {
    return CRowVector<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool has_instance(const v8::Handle<v8::Value>& value) {
    NanScope();
    v8::Local<v8::FunctionTemplate> tpl = NanNew(function_template);
    return tpl->HasInstance(value);
  }

  template <typename T>
  static NAN_INLINE v8::Local<v8::Object>
  new_instance(const T& args, int argc, v8::Handle<v8::Value> argv[]) {
    v8::Local<v8::Function> ctor = NanNew(constructor);
    v8::Local<v8::Object> instance = ctor->NewInstance(argc, argv);
    return instance;
  }

  template <typename T, int Rows, int Cols>
  static NAN_INLINE bool is_out_of_range(
      const Eigen::Matrix<T, Rows, Cols>& eigen_matrix
    , const typename Eigen::Matrix<T, Rows, Cols>::Index& row
    , const typename Eigen::Matrix<T, Rows, Cols>::Index& col) {
    return row < 0 || row >= eigen_matrix.rows() ||
           col < 0 || col >= eigen_matrix.cols()
      ? NanThrowError("Row or column numbers are out of range"), true
      : false;
  }

  template <
    typename XprType
  , int BlockRows
  , int BlockCols
  , bool InnerPanel
  >
  static NAN_INLINE bool is_out_of_range(
      const Eigen::Block<
        XprType
      , BlockRows
      , BlockCols
      , InnerPanel
      >& eigen_block
    , const typename XprType::Index& row
    , const typename XprType::Index& col) {
    return row < 0 || row >= eigen_block.rows() ||
           col < 0 || col >= eigen_block.cols()
      ? NanThrowError("Row or column numbers are out of range"), true
      : false;
  }

  template <typename T, typename U>
  static NAN_INLINE
  typename std::enable_if<
    boost::mpl::and_<
      boost::mpl::or_<
        detail::is_eigen_block<typename T::value_type>
      , detail::is_eigen_matrix<typename T::value_type>
      >
    , boost::mpl::or_<
        detail::is_eigen_block<typename T::value_type>
      , detail::is_eigen_matrix<typename T::value_type>
      >
    >::value
  , bool
  >::type
  is_nonconformate_arguments(
      const T* const& op1
    , const U* const& op2) {
    return (*op1)->rows() != (*op2)->rows() ||
           (*op1)->cols() != (*op2)->cols()
      ? NanThrowError("Nonconformant arguments"), true
      : false;
  }

  template <typename T, typename U>
  static NAN_INLINE
  typename std::enable_if<
    boost::mpl::and_<
      boost::mpl::or_<
        detail::is_eigen_block<typename T::value_type>
      , detail::is_eigen_matrix<typename T::value_type>
      >
    , boost::mpl::or_<
        detail::is_eigen_block<typename T::value_type>
      , detail::is_eigen_matrix<typename T::value_type>
      >
    >::value
  , bool
  >::type
  is_invalid_matrix_product(
      const T* const& op1
    , const U* const& op2) {
    return (*op1)->cols() != (*op2)->rows()
      ? NanThrowError("Invalid matrix product"), true
      : false;
  }

 public:
  NAN_INLINE value_type& operator*() { return *value_ptr_; }
  NAN_INLINE const value_type& operator*() const { return *value_ptr_; }
  NAN_INLINE value_type* operator->() { return value_ptr_.get(); }
  NAN_INLINE const value_type* operator->() const { return value_ptr_.get(); }

  NAN_INLINE operator const pointer_type&() const {
    return value_ptr_;
  }

 protected:
  base() : value_ptr_(new value_type()) {}

  explicit base(const Complex<scalar_type>&) : value_ptr_() {}

  explicit base(const pointer_type& value_ptr)
    : value_ptr_(value_ptr)
  {}

  ~base() {}

  static v8::Persistent<v8::FunctionTemplate> function_template;
  static v8::Persistent<v8::Function> constructor;

 private:
  friend derived_type;
  pointer_type value_ptr_;
};

template<
  template <typename, typename, const char*> class Derived
, typename ScalarType
, typename ValueType
, const char* ClassName
>
v8::Persistent<v8::FunctionTemplate>
    base<Derived, ScalarType, ValueType, ClassName>::function_template;

template<
  template <typename, typename, const char*> class Derived
, typename ScalarType
, typename ValueType
, const char* ClassName
>
v8::Persistent<v8::Function>
    base<Derived, ScalarType, ValueType, ClassName>::constructor;

}  // namespace EigenJS

#endif  // EIGENJS_BASIC_HPP
<commit_msg>src: fixed a mistake<commit_after>//
// base.hpp
// ~~~~~~~~
//
// Copyright (c) 2014 Rick Yang (rick68 at gmail dot com)
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

#ifndef EIGENJS_BASIC_HPP
#define EIGENJS_BASIC_HPP

#include <v8.h>
#include <node.h>
#include <nan.h>

#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>

#include <eigen3/Eigen/Dense>

#include <complex>
#include <memory>
#include <type_traits>

#include "Complex_fwd.hpp"
#include "Matrix_fwd.hpp"
#include "CMatrix_fwd.hpp"
#include "Vector_fwd.hpp"
#include "CVector_fwd.hpp"
#include "RowVector_fwd.hpp"
#include "CRowVector_fwd.hpp"
#include "MatrixBlock_fwd.hpp"
#include "CMatrixBlock_fwd.hpp"

#include "detail/unwrap_eigen_block.hpp"
#include "detail/is_eigen_block.hpp"
#include "detail/is_eigen_matrix.hpp"

namespace EigenJS {

namespace detail {
  template <typename ScalarType>
  struct std_complex_dummy_ptr {
    typedef ScalarType scalar_type;
    typedef std::complex<scalar_type> value_type;

    NAN_INLINE value_type& operator*() { return value_; }
    NAN_INLINE const value_type& operator*() const { return value_; }
    NAN_INLINE value_type* operator->() { return &value_; }
    NAN_INLINE const value_type* operator->() const { return &value_; }

   private:
    value_type value_;
  };

}  // namespace detail

template <
  template <typename, typename, const char*> class Derived
, typename ScalarType
, typename ValueType
, const char* ClassName
>
struct base : node::ObjectWrap {
  typedef Derived<ScalarType, ValueType, ClassName> derived_type;

  typedef ScalarType scalar_type;
  typedef typename detail::unwrap_eigen_block<ValueType>::type value_type;

  typedef typename std::conditional<
      std::is_same<
        value_type
      , typename detail::std_complex_dummy_ptr<scalar_type>::value_type
      >::value
    , detail::std_complex_dummy_ptr<scalar_type>
    , std::shared_ptr<value_type>
    >::type pointer_type;

  static NAN_INLINE bool is_scalar(const v8::Handle<v8::Value>& arg) {
    return arg->IsNumber() ? true : false;
  }

  static NAN_INLINE bool is_complex(const v8::Handle<v8::Value>& arg) {
    return Complex<scalar_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool
  is_complex_or_saclar(const v8::Handle<v8::Value>& arg) {
    return
      Complex<scalar_type>::base_type::has_instance(arg) || arg->IsNumber()
      ? true : false;
  }

  static NAN_INLINE bool is_matrix(const v8::Handle<v8::Value>& arg) {
    return Matrix<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_cmatrix(const v8::Handle<v8::Value>& arg) {
    return CMatrix<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_vector(const v8::Handle<v8::Value>& arg) {
    return Vector<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_cvector(const v8::Handle<v8::Value>& arg) {
    return CVector<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_rowvector(const v8::Handle<v8::Value>& arg) {
    return RowVector<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool is_crowvector(const v8::Handle<v8::Value>& arg) {
    return CRowVector<scalar_type, value_type>::base_type::has_instance(arg);
  }

  static NAN_INLINE bool has_instance(const v8::Handle<v8::Value>& value) {
    NanScope();
    v8::Local<v8::FunctionTemplate> tpl = NanNew(function_template);
    return tpl->HasInstance(value);
  }

  template <typename T>
  static NAN_INLINE v8::Local<v8::Object>
  new_instance(const T& args, int argc, v8::Handle<v8::Value> argv[]) {
    v8::Local<v8::Function> ctor = NanNew(constructor);
    v8::Local<v8::Object> instance = ctor->NewInstance(argc, argv);
    return instance;
  }

  template <typename T, int Rows, int Cols>
  static NAN_INLINE bool is_out_of_range(
      const Eigen::Matrix<T, Rows, Cols>& eigen_matrix
    , const typename Eigen::Matrix<T, Rows, Cols>::Index& row
    , const typename Eigen::Matrix<T, Rows, Cols>::Index& col) {
    return row < 0 || row >= eigen_matrix.rows() ||
           col < 0 || col >= eigen_matrix.cols()
      ? NanThrowError("Row or column numbers are out of range"), true
      : false;
  }

  template <
    typename XprType
  , int BlockRows
  , int BlockCols
  , bool InnerPanel
  >
  static NAN_INLINE bool is_out_of_range(
      const Eigen::Block<
        XprType
      , BlockRows
      , BlockCols
      , InnerPanel
      >& eigen_block
    , const typename XprType::Index& row
    , const typename XprType::Index& col) {
    return row < 0 || row >= eigen_block.rows() ||
           col < 0 || col >= eigen_block.cols()
      ? NanThrowError("Row or column numbers are out of range"), true
      : false;
  }

  template <typename T, typename U>
  static NAN_INLINE
  typename std::enable_if<
    boost::mpl::and_<
      boost::mpl::or_<
        detail::is_eigen_block<typename T::value_type>
      , detail::is_eigen_matrix<typename T::value_type>
      >
    , boost::mpl::or_<
        detail::is_eigen_block<typename U::value_type>
      , detail::is_eigen_matrix<typename U::value_type>
      >
    >::value
  , bool
  >::type
  is_nonconformate_arguments(
      const T* const& op1
    , const U* const& op2) {
    return (*op1)->rows() != (*op2)->rows() ||
           (*op1)->cols() != (*op2)->cols()
      ? NanThrowError("Nonconformant arguments"), true
      : false;
  }

  template <typename T, typename U>
  static NAN_INLINE
  typename std::enable_if<
    boost::mpl::and_<
      boost::mpl::or_<
        detail::is_eigen_block<typename T::value_type>
      , detail::is_eigen_matrix<typename T::value_type>
      >
    , boost::mpl::or_<
        detail::is_eigen_block<typename U::value_type>
      , detail::is_eigen_matrix<typename U::value_type>
      >
    >::value
  , bool
  >::type
  is_invalid_matrix_product(
      const T* const& op1
    , const U* const& op2) {
    return (*op1)->cols() != (*op2)->rows()
      ? NanThrowError("Invalid matrix product"), true
      : false;
  }

 public:
  NAN_INLINE value_type& operator*() { return *value_ptr_; }
  NAN_INLINE const value_type& operator*() const { return *value_ptr_; }
  NAN_INLINE value_type* operator->() { return value_ptr_.get(); }
  NAN_INLINE const value_type* operator->() const { return value_ptr_.get(); }

  NAN_INLINE operator const pointer_type&() const {
    return value_ptr_;
  }

 protected:
  base() : value_ptr_(new value_type()) {}

  explicit base(const Complex<scalar_type>&) : value_ptr_() {}

  explicit base(const pointer_type& value_ptr)
    : value_ptr_(value_ptr)
  {}

  ~base() {}

  static v8::Persistent<v8::FunctionTemplate> function_template;
  static v8::Persistent<v8::Function> constructor;

 private:
  friend derived_type;
  pointer_type value_ptr_;
};

template<
  template <typename, typename, const char*> class Derived
, typename ScalarType
, typename ValueType
, const char* ClassName
>
v8::Persistent<v8::FunctionTemplate>
    base<Derived, ScalarType, ValueType, ClassName>::function_template;

template<
  template <typename, typename, const char*> class Derived
, typename ScalarType
, typename ValueType
, const char* ClassName
>
v8::Persistent<v8::Function>
    base<Derived, ScalarType, ValueType, ClassName>::constructor;

}  // namespace EigenJS

#endif  // EIGENJS_BASIC_HPP
<|endoftext|>


<commit_before>#include "Chip8.hpp"

Chip8::Chip8()
{

   // Set up the SFML stuff
   window.create(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Chip8 Emulator");
   window.setFramerateLimit(CLOCK_SPEED);
   pixel.setSize(sf::Vector2f(PIXEL_WIDTH, PIXEL_HEIGHT));
   pixel.setFillColor(sf::Color::White);

   // Initialize
   clearScreen();
   opcode = 0;
   for(int i = 0; i < MEMORY_SIZE; i++)
      memory[i] = 0;
   for(int i = 0; i < NUM_REGISTERS; i++)
      V[i] = 0;
   I = 0;
   pc = PROGRAM_START;
   delayTimer = 0;
   soundTimer = 0;
   for(int i = 0; i < STACK_SIZE; i++)
      stack[i] = 0;
   sp = 0;
   for(int i = 0; i < NUM_KEYS; i++)
      key[i] = 0;
   drawFlag = false;

   // Load fontset
   loadFontSet();

}

void Chip8::loadFontSet()
{

   unsigned char chip8_fontset[FONTSET_SIZE] =
   {
      0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
      0x20, 0x60, 0x20, 0x20, 0x70, // 1
      0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
      0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
      0x90, 0x90, 0xF0, 0x10, 0x10, // 4
      0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
      0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
      0xF0, 0x10, 0x20, 0x40, 0x40, // 7
      0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
      0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
      0xF0, 0x90, 0xF0, 0x90, 0x90, // A
      0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
      0xF0, 0x80, 0x80, 0x80, 0xF0, // C
      0xE0, 0x90, 0x90, 0x90, 0xE0, // D
      0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
      0xF0, 0x80, 0xF0, 0x80, 0x80  // F
   };

   for(int i = 0; i < FONTSET_SIZE; i++)
      memory[i] = chip8_fontset[i];

}

void Chip8::drawGraphics()
{

   window.clear();

   for(int i = 0; i < PIXELS_X; i++)
   {
      for(int j = 0; j < PIXELS_Y; j++)
      {
         if(graphics[i + (j * PIXELS_X)])
         {
            pixel.setPosition(sf::Vector2f(i * PIXEL_WIDTH, j * PIXEL_HEIGHT));
            window.draw(pixel);
         }
      }
   }

   window.display();

   drawFlag = false;

}

void Chip8::tick()
{

   // Fetch opcode
   opcode = memory[pc] << 8 | memory[pc + 1];

   // Decode opcode
   switch(opcode & 0xF000)
   {
   case 0x0000:
      {
         switch(opcode & 0x000F)
         {
         case 0x0000:   // 0x00E0: Clear screen
            clearScreen();
            break;
         case 0x000E:   // 0x00EE: Returns from subroutine
            pc = stack[--sp];
            break;
         default:
            {
               std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
            }
         }
         break;
      }
   case 0x2000:   // 0x2NNN: Call subroutine at NNN
      {
         stack[sp++] = pc;
         pc = opcode & 0x0FFF;
         break;
      }
   case 0x6000:   // 0x6XNN: Sets VX to NN
      {
         V[(opcode & 0x0F00) >> 8] = (opcode & 0x00FF);
         pc += 2;
         break;
      }
   case 0x8000:
      {
         switch(opcode & 0x000F)
         {
         case 0x0004:   // 0x8XY4: Add VX to VY and set VF if needed
            {
               if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8]))   // Value at VY is larger than (max - value at VX)
                  V[0xF] = 1;
               else
                  V[0xF] = 0;
               V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
               pc += 2;
               break;
            }
         default:
            {
               std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
            }
         }
         break;
      }
   case 0xA000:   // 0xANNN: Sets I to the address NNN
      {
         I = opcode & 0x0FFF;
         pc += 2;
         break;
      }
   case 0xD000:   // 0xDXYN: Draw sprite at coordinates VX, VY with a width of 8 pixels and height of N.  Sprite starts at I
      {
         unsigned short x = V[(opcode & 0x0F00) >> 8];
         unsigned short y = V[(opcode & 0x00F0) >> 4];
         unsigned short height = opcode & 0x000F;
         unsigned short pix;

         V[0xF] = 0;
         for(int yline = 0; yline <  height; yline++)
         {
            pix = memory[I + yline];
            for(int xline = 0; xline < 8; xline++)
            {
               if((pix & (0x80 >> xline)) != 0)
               {
                  if(graphics[(x + xline + ((y + yline) * PIXELS_X))] == 1)
                     V[0xF] = 1;
                  graphics[x + xline + ((y + yline) * PIXELS_X)] ^= 1;
               }
            }
         }

         drawFlag = true;
         pc += 2;
         break;
      }
   case 0xE000:
      {
         switch(opcode & 0x00FF)
         {
         case 0x009E:   // 0xEX9E skips the next instruction if the key stored in VX is pressed
            {
               if(key[V[(opcode & 0x0F00) >> 8]] != 0)
                  pc += 4;
               else
                  pc += 2;
               break;
            }
         default:
            {
               std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
            }
         }
         break;
      }
   case 0xF000:
      {
         switch(opcode & 0x00FF)
         {
         case 0x0029:   // 0xFX29: Sets I to the location of the sprite for the character in VX
            {
               unsigned char ch = V[(opcode & 0x0F00) >> 8];
               I = ch * 10;      // 10 bytes per character
               pc += 2;
               break;
            }
         case 0x0033:   // 0xFX33: Stores the binary-coded decimal representation of VX at I, I + 1, and I + 2
            {
               memory[I] = V[(opcode & 0x0F00) >> 8] / 100;
               memory[I + 1] = (V[(opcode & 0x0F00) >> 8] / 10) % 10;
               memory[I + 2] = (V[(opcode & 0x0F00) >> 8] % 100) % 10;
               pc += 2;
               break;
            }
         case 0x0065:   // 0xFX65: Fills V0 to VX with values from memory starting at address I
            {
               unsigned char numRegs = (opcode & 0x0F00) >> 8;
               for(int i = 0; i < numRegs; i++)
                  V[i] = memory[I + (i * 2)];
               pc += 2;
               break;
            }
         default:
            {
               std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
            }
         }
         break;
      }
   default:
      {
         std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
      }
   }

   // Update timers
   if(delayTimer > 0)
      delayTimer--;

   if(soundTimer > 0)
   {
      std::cout<<"\a";
      soundTimer--;
   }

}

void Chip8::setKeys(sf::Event evt)
{

   switch(evt.key.code)
   {
   case sf::Keyboard::Num1:
      {
         key[1] = 1;
         break;
      }
   case sf::Keyboard::Num2:
      {
         key[2] = 1;
         break;
      }
   case sf::Keyboard::Num3:
      {
         key[3] = 1;
         break;
      }
   case sf::Keyboard::Num4:
      {
         key[0xC] = 1;
         break;
      }
   case sf::Keyboard::Q:
      {
         key[4] = 1;
         break;
      }
   case sf::Keyboard::W:
      {
         key[5] = 1;
         break;
      }
   case sf::Keyboard::E:
      {
         key[6] = 1;
         break;
      }
   case sf::Keyboard::R:
      {
         key[0xD] = 1;
         break;
      }
   case sf::Keyboard::A:
      {
         key[7] = 1;
         break;
      }
   case sf::Keyboard::S:
      {
         key[8] = 1;
         break;
      }
   case sf::Keyboard::D:
      {
         key[9] = 1;
         break;
      }
   case sf::Keyboard::F:
      {
         key[0xE] = 1;
         break;
      }
   case sf::Keyboard::Z:
      {
         key[0xA] = 1;
         break;
      }
   case sf::Keyboard::X:
      {
         key[0] = 1;
         break;
      }
   case sf::Keyboard::C:
      {
         key[0xB] = 1;
         break;
      }
   case sf::Keyboard::V:
      {
         key[0xF] = 1;
         break;
      }
   }

}

void Chip8::clearScreen()
{

   for(int i = 0; i < PIXELS_X * PIXELS_Y; i++)
      graphics[i] = 0;

}

void Chip8::dumpMemory()
{

   for(int i = 0; i < MEMORY_SIZE; i++)
      std::cout<<std::hex<<(int)memory[i];

   std::cout<<"\n";

}

void Chip8::dumpRegisters()
{

   for(int i = 0; i < NUM_REGISTERS; i++)
      std::cout<<std::hex<<(int)V[i];

   std::cout<<"\n";

}

void Chip8::dumpKeys()
{

   for(int i = 0; i < NUM_KEYS; i++)
      std::cout<<(int)key[i];

   std::cout<<"\n";

}

void Chip8::loadProgram(std::string fileName)
{

   std::ifstream input(fileName, std::ifstream::binary);

   if(input)
   {
      // Get the length of the file
      input.seekg(0, input.end);
      int length = input.tellg();
      input.seekg(0, input.beg);

      // Make our buffer
      unsigned char *buffer = new unsigned char[length];

      // Read from the file
      input.read((char*)buffer, length);

      if(!input)
         std::cout<<"Error reading file: only "<<input.gcount()<<" could be read\n";

      // Move the program into memory
      for(int i = 0; i < length; i++)
         memory[i + PROGRAM_START] = buffer[i];

      input.close();
      delete[] buffer;
   }
   else
      std::cout<<"Error reading file: "<<fileName<<"\n";

}

void Chip8::run()
{

   sf::Clock clock;
   clock.restart();

   const sf::Time FRAMETIME = sf::microseconds(1000000.f / CLOCK_SPEED);      // No in-class initialization allowed?

   while(window.isOpen())
   {
      sf::Event event;
      while(window.pollEvent(event))
      {
         // Request for closing the window
         if(event.type == sf::Event::Closed)
            window.close();
         if(event.type == sf::Event::KeyPressed)
            setKeys(event);
      }

      // The clock cycle for the CPU needs to be 60Hz
      sf::Time timeElapsed = clock.restart();
      if(timeElapsed > FRAMETIME)
         sf::sleep(FRAMETIME - timeElapsed);

      // Emulate
      tick();

      // Draw the graphics
      if(drawFlag)
         drawGraphics();
   }

}

Chip8::~Chip8()
{
}
<commit_msg>Added Opcode 0x7XNN<commit_after>#include "Chip8.hpp"

Chip8::Chip8()
{

   // Set up the SFML stuff
   window.create(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), "Chip8 Emulator");
   window.setFramerateLimit(CLOCK_SPEED);
   pixel.setSize(sf::Vector2f(PIXEL_WIDTH, PIXEL_HEIGHT));
   pixel.setFillColor(sf::Color::White);

   // Initialize
   clearScreen();
   opcode = 0;
   for(int i = 0; i < MEMORY_SIZE; i++)
      memory[i] = 0;
   for(int i = 0; i < NUM_REGISTERS; i++)
      V[i] = 0;
   I = 0;
   pc = PROGRAM_START;
   delayTimer = 0;
   soundTimer = 0;
   for(int i = 0; i < STACK_SIZE; i++)
      stack[i] = 0;
   sp = 0;
   for(int i = 0; i < NUM_KEYS; i++)
      key[i] = 0;
   drawFlag = false;

   // Load fontset
   loadFontSet();

}

void Chip8::loadFontSet()
{

   unsigned char chip8_fontset[FONTSET_SIZE] =
   {
      0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
      0x20, 0x60, 0x20, 0x20, 0x70, // 1
      0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
      0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
      0x90, 0x90, 0xF0, 0x10, 0x10, // 4
      0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
      0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
      0xF0, 0x10, 0x20, 0x40, 0x40, // 7
      0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
      0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
      0xF0, 0x90, 0xF0, 0x90, 0x90, // A
      0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
      0xF0, 0x80, 0x80, 0x80, 0xF0, // C
      0xE0, 0x90, 0x90, 0x90, 0xE0, // D
      0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
      0xF0, 0x80, 0xF0, 0x80, 0x80  // F
   };

   for(int i = 0; i < FONTSET_SIZE; i++)
      memory[i] = chip8_fontset[i];

}

void Chip8::drawGraphics()
{

   window.clear();

   for(int i = 0; i < PIXELS_X; i++)
   {
      for(int j = 0; j < PIXELS_Y; j++)
      {
         if(graphics[i + (j * PIXELS_X)])
         {
            pixel.setPosition(sf::Vector2f(i * PIXEL_WIDTH, j * PIXEL_HEIGHT));
            window.draw(pixel);
         }
      }
   }

   window.display();

   drawFlag = false;

}

void Chip8::tick()
{

   // Fetch opcode
   opcode = memory[pc] << 8 | memory[pc + 1];

   // Decode opcode
   switch(opcode & 0xF000)
   {
   case 0x0000:
      {
         switch(opcode & 0x000F)
         {
         case 0x0000:   // 0x00E0: Clear screen
            clearScreen();
            break;
         case 0x000E:   // 0x00EE: Returns from subroutine
            pc = stack[--sp];
            break;
         default:
            {
               std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
            }
         }
         break;
      }
   case 0x2000:   // 0x2NNN: Call subroutine at NNN
      {
         stack[sp++] = pc;
         pc = opcode & 0x0FFF;
         break;
      }
   case 0x6000:   // 0x6XNN: Sets VX to NN
      {
         V[(opcode & 0x0F00) >> 8] = (opcode & 0x00FF);
         pc += 2;
         break;
      }
   case 0x7000:   // 0x7XNN: Adds NN to VX
      {
         unsigned char add = opcode & 0x00FF;
         V[(opcode & 0x0F00) >> 8] += add;
         pc += 2;
         break;
      }
   case 0x8000:
      {
         switch(opcode & 0x000F)
         {
         case 0x0004:   // 0x8XY4: Add VX to VY and set VF if needed
            {
               if(V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode & 0x0F00) >> 8]))   // Value at VY is larger than (max - value at VX)
                  V[0xF] = 1;
               else
                  V[0xF] = 0;
               V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
               pc += 2;
               break;
            }
         default:
            {
               std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
            }
         }
         break;
      }
   case 0xA000:   // 0xANNN: Sets I to the address NNN
      {
         I = opcode & 0x0FFF;
         pc += 2;
         break;
      }
   case 0xD000:   // 0xDXYN: Draw sprite at coordinates VX, VY with a width of 8 pixels and height of N.  Sprite starts at I
      {
         unsigned short x = V[(opcode & 0x0F00) >> 8];
         unsigned short y = V[(opcode & 0x00F0) >> 4];
         unsigned short height = opcode & 0x000F;
         unsigned short pix;

         V[0xF] = 0;
         for(int yline = 0; yline <  height; yline++)
         {
            pix = memory[I + yline];
            for(int xline = 0; xline < 8; xline++)
            {
               if((pix & (0x80 >> xline)) != 0)
               {
                  if(graphics[(x + xline + ((y + yline) * PIXELS_X))] == 1)
                     V[0xF] = 1;
                  graphics[x + xline + ((y + yline) * PIXELS_X)] ^= 1;
               }
            }
         }

         drawFlag = true;
         pc += 2;
         break;
      }
   case 0xE000:
      {
         switch(opcode & 0x00FF)
         {
         case 0x009E:   // 0xEX9E skips the next instruction if the key stored in VX is pressed
            {
               if(key[V[(opcode & 0x0F00) >> 8]] != 0)
                  pc += 4;
               else
                  pc += 2;
               break;
            }
         default:
            {
               std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
            }
         }
         break;
      }
   case 0xF000:
      {
         switch(opcode & 0x00FF)
         {
         case 0x0029:   // 0xFX29: Sets I to the location of the sprite for the character in VX
            {
               unsigned char ch = V[(opcode & 0x0F00) >> 8];
               I = ch * 10;      // 10 bytes per character
               pc += 2;
               break;
            }
         case 0x0033:   // 0xFX33: Stores the binary-coded decimal representation of VX at I, I + 1, and I + 2
            {
               memory[I] = V[(opcode & 0x0F00) >> 8] / 100;
               memory[I + 1] = (V[(opcode & 0x0F00) >> 8] / 10) % 10;
               memory[I + 2] = (V[(opcode & 0x0F00) >> 8] % 100) % 10;
               pc += 2;
               break;
            }
         case 0x0065:   // 0xFX65: Fills V0 to VX with values from memory starting at address I
            {
               unsigned char numRegs = (opcode & 0x0F00) >> 8;
               for(int i = 0; i < numRegs; i++)
                  V[i] = memory[I + (i * 2)];
               pc += 2;
               break;
            }
         default:
            {
               std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
            }
         }
         break;
      }
   default:
      {
         std::cout<<"Unknown opcode: 0x"<<std::hex<<opcode<<"\n";
      }
   }

   // Update timers
   if(delayTimer > 0)
      delayTimer--;

   if(soundTimer > 0)
   {
      std::cout<<"\a";
      soundTimer--;
   }

}

void Chip8::setKeys(sf::Event evt)
{

   switch(evt.key.code)
   {
   case sf::Keyboard::Num1:
      {
         key[1] = 1;
         break;
      }
   case sf::Keyboard::Num2:
      {
         key[2] = 1;
         break;
      }
   case sf::Keyboard::Num3:
      {
         key[3] = 1;
         break;
      }
   case sf::Keyboard::Num4:
      {
         key[0xC] = 1;
         break;
      }
   case sf::Keyboard::Q:
      {
         key[4] = 1;
         break;
      }
   case sf::Keyboard::W:
      {
         key[5] = 1;
         break;
      }
   case sf::Keyboard::E:
      {
         key[6] = 1;
         break;
      }
   case sf::Keyboard::R:
      {
         key[0xD] = 1;
         break;
      }
   case sf::Keyboard::A:
      {
         key[7] = 1;
         break;
      }
   case sf::Keyboard::S:
      {
         key[8] = 1;
         break;
      }
   case sf::Keyboard::D:
      {
         key[9] = 1;
         break;
      }
   case sf::Keyboard::F:
      {
         key[0xE] = 1;
         break;
      }
   case sf::Keyboard::Z:
      {
         key[0xA] = 1;
         break;
      }
   case sf::Keyboard::X:
      {
         key[0] = 1;
         break;
      }
   case sf::Keyboard::C:
      {
         key[0xB] = 1;
         break;
      }
   case sf::Keyboard::V:
      {
         key[0xF] = 1;
         break;
      }
   }

}

void Chip8::clearScreen()
{

   for(int i = 0; i < PIXELS_X * PIXELS_Y; i++)
      graphics[i] = 0;

}

void Chip8::dumpMemory()
{

   for(int i = 0; i < MEMORY_SIZE; i++)
      std::cout<<std::hex<<(int)memory[i];

   std::cout<<"\n";

}

void Chip8::dumpRegisters()
{

   for(int i = 0; i < NUM_REGISTERS; i++)
      std::cout<<std::hex<<(int)V[i];

   std::cout<<"\n";

}

void Chip8::dumpKeys()
{

   for(int i = 0; i < NUM_KEYS; i++)
      std::cout<<(int)key[i];

   std::cout<<"\n";

}

void Chip8::loadProgram(std::string fileName)
{

   std::ifstream input(fileName, std::ifstream::binary);

   if(input)
   {
      // Get the length of the file
      input.seekg(0, input.end);
      int length = input.tellg();
      input.seekg(0, input.beg);

      // Make our buffer
      unsigned char *buffer = new unsigned char[length];

      // Read from the file
      input.read((char*)buffer, length);

      if(!input)
         std::cout<<"Error reading file: only "<<input.gcount()<<" could be read\n";

      // Move the program into memory
      for(int i = 0; i < length; i++)
         memory[i + PROGRAM_START] = buffer[i];

      input.close();
      delete[] buffer;
   }
   else
      std::cout<<"Error reading file: "<<fileName<<"\n";

}

void Chip8::run()
{

   sf::Clock clock;
   clock.restart();

   const sf::Time FRAMETIME = sf::microseconds(1000000.f / CLOCK_SPEED);      // No in-class initialization allowed?

   while(window.isOpen())
   {
      sf::Event event;
      while(window.pollEvent(event))
      {
         // Request for closing the window
         if(event.type == sf::Event::Closed)
            window.close();
         if(event.type == sf::Event::KeyPressed)
            setKeys(event);
      }

      // The clock cycle for the CPU needs to be 60Hz
      sf::Time timeElapsed = clock.restart();
      if(timeElapsed > FRAMETIME)
         sf::sleep(FRAMETIME - timeElapsed);

      // Emulate
      tick();

      // Draw the graphics
      if(drawFlag)
         drawGraphics();
   }

}

Chip8::~Chip8()
{
}
<|endoftext|>