<commit_before>#include "depthai/pipeline/node/ColorCamera.hpp"

#include <cmath>

#include "spdlog/fmt/fmt.h"

namespace dai {
namespace node {

ColorCamera::ColorCamera(const std::shared_ptr<PipelineImpl>& par, int64_t nodeId)
    : Node(par, nodeId), rawControl(std::make_shared<RawCameraControl>()), initialControl(rawControl) {
    properties.boardSocket = CameraBoardSocket::AUTO;
    properties.imageOrientation = CameraImageOrientation::AUTO;
    properties.colorOrder = ColorCameraProperties::ColorOrder::BGR;
    properties.interleaved = true;
    properties.previewHeight = 300;
    properties.previewWidth = 300;
    properties.resolution = ColorCameraProperties::SensorResolution::THE_1080_P;
    properties.fps = 30.0;
    properties.previewKeepAspectRatio = true;
}

std::string ColorCamera::getName() const {
    return "ColorCamera";
}

std::vector<Node::Output> ColorCamera::getOutputs() {
    return {raw, isp, video, preview, still};
}

std::vector<Node::Input> ColorCamera::getInputs() {
    return {inputConfig, inputControl};
}

nlohmann::json ColorCamera::getProperties() {
    nlohmann::json j;
    properties.initialControl = *rawControl;
    nlohmann::to_json(j, properties);
    return j;
}

std::shared_ptr<Node> ColorCamera::clone() {
    return std::make_shared<std::decay<decltype(*this)>::type>(*this);
}

// Set board socket to use
void ColorCamera::setBoardSocket(dai::CameraBoardSocket boardSocket) {
    properties.boardSocket = boardSocket;
}

// Get current board socket
CameraBoardSocket ColorCamera::getBoardSocket() const {
    return properties.boardSocket;
}

// Set which color camera to use
void ColorCamera::setCamId(int64_t id) {
    // cast to board socket
    switch(id) {
        case 0:
            properties.boardSocket = CameraBoardSocket::RGB;
            break;
        case 1:
            properties.boardSocket = CameraBoardSocket::LEFT;
            break;
        case 2:
            properties.boardSocket = CameraBoardSocket::RIGHT;
            break;
        default:
            throw std::invalid_argument(fmt::format("CamId value: {} is invalid.", id));
            break;
    }
}

// Get which color camera to use
int64_t ColorCamera::getCamId() const {
    return (int64_t)properties.boardSocket;
}

// Set camera image orientation
void ColorCamera::setImageOrientation(CameraImageOrientation imageOrientation) {
    properties.imageOrientation = imageOrientation;
}

// Get camera image orientation
CameraImageOrientation ColorCamera::getImageOrientation() const {
    // TODO: in case of AUTO, see if possible to return actual value determined by device?
    return properties.imageOrientation;
}

// setColorOrder - RGB or BGR
void ColorCamera::setColorOrder(ColorCameraProperties::ColorOrder colorOrder) {
    properties.colorOrder = colorOrder;
}

// getColorOrder - returns color order
ColorCameraProperties::ColorOrder ColorCamera::getColorOrder() const {
    return properties.colorOrder;
}

// setInterleaved
void ColorCamera::setInterleaved(bool interleaved) {
    properties.interleaved = interleaved;
}

// getInterleaved
bool ColorCamera::getInterleaved() const {
    return properties.interleaved;
}

// setFp16
void ColorCamera::setFp16(bool fp16) {
    properties.fp16 = fp16;
}

// getFp16
bool ColorCamera::getFp16() const {
    return properties.fp16;
}

// set preview output size
void ColorCamera::setPreviewSize(int width, int height) {
    properties.previewWidth = width;
    properties.previewHeight = height;
}

void ColorCamera::setPreviewSize(std::tuple<int, int> size) {
    setPreviewSize(std::get<0>(size), std::get<1>(size));
}

// set video output size
void ColorCamera::setVideoSize(int width, int height) {
    properties.videoWidth = width;
    properties.videoHeight = height;
}

void ColorCamera::setVideoSize(std::tuple<int, int> size) {
    setVideoSize(std::get<0>(size), std::get<1>(size));
}

// set still output size
void ColorCamera::setStillSize(int width, int height) {
    properties.stillWidth = width;
    properties.stillHeight = height;
}

void ColorCamera::setStillSize(std::tuple<int, int> size) {
    setStillSize(std::get<0>(size), std::get<1>(size));
}

void ColorCamera::setIspScale(int horizNum, int horizDenom, int vertNum, int vertDenom) {
    properties.ispScale.horizNumerator = horizNum;
    properties.ispScale.horizDenominator = horizDenom;
    properties.ispScale.vertNumerator = vertNum;
    properties.ispScale.vertDenominator = vertDenom;
}

void ColorCamera::setIspScale(int numerator, int denominator) {
    setIspScale(numerator, denominator, numerator, denominator);
}

void ColorCamera::setIspScale(std::tuple<int, int> scale) {
    setIspScale(std::get<0>(scale), std::get<1>(scale));
}

void ColorCamera::setIspScale(std::tuple<int, int> horizScale, std::tuple<int, int> vertScale) {
    setIspScale(std::get<0>(horizScale), std::get<1>(horizScale), std::get<0>(vertScale), std::get<1>(vertScale));
}

void ColorCamera::setResolution(ColorCameraProperties::SensorResolution resolution) {
    properties.resolution = resolution;
}
ColorCameraProperties::SensorResolution ColorCamera::getResolution() const {
    return properties.resolution;
}

void ColorCamera::setFps(float fps) {
    properties.fps = fps;
}

float ColorCamera::getFps() const {
    // if AUTO
    if(properties.fps == ColorCameraProperties::AUTO || properties.fps == 0) {
        return 30.0f;
    }

    // else return fps
    return properties.fps;
}

// Returns preview size
std::tuple<int, int> ColorCamera::getPreviewSize() const {
    return {properties.previewWidth, properties.previewHeight};
}

int ColorCamera::getPreviewWidth() const {
    return properties.previewWidth;
}

int ColorCamera::getPreviewHeight() const {
    return properties.previewHeight;
}

// Returns video size
std::tuple<int, int> ColorCamera::getVideoSize() const {
    if(properties.videoWidth == ColorCameraProperties::AUTO || properties.videoHeight == ColorCameraProperties::AUTO) {
        // calculate based on auto
        int maxVideoWidth = 1920;
        int maxVideoHeight = 1080;

        if(properties.resolution == ColorCameraProperties::SensorResolution::THE_4_K
           || properties.resolution == ColorCameraProperties::SensorResolution::THE_12_MP) {
            maxVideoWidth = 3840;
            maxVideoHeight = 2160;
        }

        return {maxVideoWidth, maxVideoHeight};
    }

    return {properties.videoWidth, properties.videoHeight};
}

int ColorCamera::getVideoWidth() const {
    return std::get<0>(getVideoSize());
}

int ColorCamera::getVideoHeight() const {
    return std::get<1>(getVideoSize());
}

// Returns still size
std::tuple<int, int> ColorCamera::getStillSize() const {
    // Calculate from AUTO
    if(properties.stillWidth == ColorCameraProperties::AUTO || properties.stillHeight == ColorCameraProperties::AUTO) {
        int maxStillWidth = 1920;
        int maxStillHeight = 1080;
        if(properties.resolution == dai::ColorCameraProperties::SensorResolution::THE_4_K) {
            maxStillWidth = 3840;
            maxStillHeight = 2160;
        }
        if(properties.resolution == dai::ColorCameraProperties::SensorResolution::THE_12_MP) {
            maxStillWidth = 4032;  // Note not 4056 as full sensor resolution
            maxStillHeight = 3040;
        }
        return {maxStillWidth, maxStillHeight};
    }

    // Else return size set
    return {properties.stillWidth, properties.stillHeight};
}

int ColorCamera::getStillWidth() const {
    return std::get<0>(getStillSize());
}

int ColorCamera::getStillHeight() const {
    return std::get<1>(getStillSize());
}

// Returns sensor size
std::tuple<int, int> ColorCamera::getResolutionSize() const {
    switch(properties.resolution) {
        case ColorCameraProperties::SensorResolution::THE_1080_P:
            return {1920, 1080};
            break;

        case ColorCameraProperties::SensorResolution::THE_4_K:
            return {3840, 2160};
            break;

        case ColorCameraProperties::SensorResolution::THE_12_MP:
            return {4056, 3040};
            break;
    }

    return {1920, 1080};
}

int ColorCamera::getResolutionWidth() const {
    return std::get<0>(getResolutionSize());
}

int ColorCamera::getResolutionHeight() const {
    return std::get<1>(getResolutionSize());
}

int ColorCamera::getScaledSize(int input, int num, int denom) const {
    return (input * num - 1) / denom + 1;
}

int ColorCamera::getIspWidth() const {
    int inW = getResolutionWidth();
    int num = properties.ispScale.horizNumerator;
    int den = properties.ispScale.horizDenominator;
    if(num > 0 && den > 0) {
        return getScaledSize(inW, num, den);
    }
    return inW;
}

int ColorCamera::getIspHeight() const {
    int inH = getResolutionHeight();
    int num = properties.ispScale.vertNumerator;
    int den = properties.ispScale.vertDenominator;
    if(num > 0 && den > 0) {
        return getScaledSize(inH, num, den);
    }
    return inH;
}

std::tuple<int, int> ColorCamera::getIspSize() const {
    return {getIspWidth(), getIspHeight()};
}

void ColorCamera::sensorCenterCrop() {
    properties.sensorCropX = ColorCameraProperties::AUTO;
    properties.sensorCropY = ColorCameraProperties::AUTO;
}

void ColorCamera::setSensorCrop(float x, float y) {
    if(x < 0 || x >= 1) {
        throw std::invalid_argument("Sensor crop x must be specified as normalized value [0:1)");
    }
    if(y < 0 || y >= 1) {
        throw std::invalid_argument("Sensor crop y must be specified as normalized value [0:1)");
    }
    properties.sensorCropX = x;
    properties.sensorCropY = y;
}

std::tuple<float, float> ColorCamera::getSensorCrop() const {
    // AUTO - center crop by default
    if(properties.sensorCropX == ColorCameraProperties::AUTO || properties.sensorCropY == ColorCameraProperties::AUTO) {
        float x = std::floor(((getResolutionWidth() - getVideoWidth()) / 2.0f) / getResolutionWidth());
        float y = std::floor(((getResolutionHeight() - getVideoHeight()) / 2.0f) / getResolutionHeight());
        return {x, y};
    }
    return {properties.sensorCropX, properties.sensorCropY};
}

float ColorCamera::getSensorCropX() const {
    return std::get<0>(getSensorCrop());
}

float ColorCamera::getSensorCropY() const {
    return std::get<1>(getSensorCrop());
}

void ColorCamera::setWaitForConfigInput(bool wait) {
    properties.inputConfigSync = wait;
}

bool ColorCamera::getWaitForConfigInput() {
    return properties.inputConfigSync;
}

void ColorCamera::setPreviewKeepAspectRatio(bool keep) {
    properties.previewKeepAspectRatio = keep;
}

bool ColorCamera::getPreviewKeepAspectRatio() {
    return properties.previewKeepAspectRatio;
}

}  // namespace node
}  // namespace dai
<commit_msg>fixed getting size of video/still when setting isp scaling<commit_after>#include "depthai/pipeline/node/ColorCamera.hpp"

#include <cmath>

#include "spdlog/fmt/fmt.h"

namespace dai {
namespace node {

ColorCamera::ColorCamera(const std::shared_ptr<PipelineImpl>& par, int64_t nodeId)
    : Node(par, nodeId), rawControl(std::make_shared<RawCameraControl>()), initialControl(rawControl) {
    properties.boardSocket = CameraBoardSocket::AUTO;
    properties.imageOrientation = CameraImageOrientation::AUTO;
    properties.colorOrder = ColorCameraProperties::ColorOrder::BGR;
    properties.interleaved = true;
    properties.previewHeight = 300;
    properties.previewWidth = 300;
    properties.resolution = ColorCameraProperties::SensorResolution::THE_1080_P;
    properties.fps = 30.0;
    properties.previewKeepAspectRatio = true;
}

std::string ColorCamera::getName() const {
    return "ColorCamera";
}

std::vector<Node::Output> ColorCamera::getOutputs() {
    return {raw, isp, video, preview, still};
}

std::vector<Node::Input> ColorCamera::getInputs() {
    return {inputConfig, inputControl};
}

nlohmann::json ColorCamera::getProperties() {
    nlohmann::json j;
    properties.initialControl = *rawControl;
    nlohmann::to_json(j, properties);
    return j;
}

std::shared_ptr<Node> ColorCamera::clone() {
    return std::make_shared<std::decay<decltype(*this)>::type>(*this);
}

// Set board socket to use
void ColorCamera::setBoardSocket(dai::CameraBoardSocket boardSocket) {
    properties.boardSocket = boardSocket;
}

// Get current board socket
CameraBoardSocket ColorCamera::getBoardSocket() const {
    return properties.boardSocket;
}

// Set which color camera to use
void ColorCamera::setCamId(int64_t id) {
    // cast to board socket
    switch(id) {
        case 0:
            properties.boardSocket = CameraBoardSocket::RGB;
            break;
        case 1:
            properties.boardSocket = CameraBoardSocket::LEFT;
            break;
        case 2:
            properties.boardSocket = CameraBoardSocket::RIGHT;
            break;
        default:
            throw std::invalid_argument(fmt::format("CamId value: {} is invalid.", id));
            break;
    }
}

// Get which color camera to use
int64_t ColorCamera::getCamId() const {
    return (int64_t)properties.boardSocket;
}

// Set camera image orientation
void ColorCamera::setImageOrientation(CameraImageOrientation imageOrientation) {
    properties.imageOrientation = imageOrientation;
}

// Get camera image orientation
CameraImageOrientation ColorCamera::getImageOrientation() const {
    // TODO: in case of AUTO, see if possible to return actual value determined by device?
    return properties.imageOrientation;
}

// setColorOrder - RGB or BGR
void ColorCamera::setColorOrder(ColorCameraProperties::ColorOrder colorOrder) {
    properties.colorOrder = colorOrder;
}

// getColorOrder - returns color order
ColorCameraProperties::ColorOrder ColorCamera::getColorOrder() const {
    return properties.colorOrder;
}

// setInterleaved
void ColorCamera::setInterleaved(bool interleaved) {
    properties.interleaved = interleaved;
}

// getInterleaved
bool ColorCamera::getInterleaved() const {
    return properties.interleaved;
}

// setFp16
void ColorCamera::setFp16(bool fp16) {
    properties.fp16 = fp16;
}

// getFp16
bool ColorCamera::getFp16() const {
    return properties.fp16;
}

// set preview output size
void ColorCamera::setPreviewSize(int width, int height) {
    properties.previewWidth = width;
    properties.previewHeight = height;
}

void ColorCamera::setPreviewSize(std::tuple<int, int> size) {
    setPreviewSize(std::get<0>(size), std::get<1>(size));
}

// set video output size
void ColorCamera::setVideoSize(int width, int height) {
    properties.videoWidth = width;
    properties.videoHeight = height;
}

void ColorCamera::setVideoSize(std::tuple<int, int> size) {
    setVideoSize(std::get<0>(size), std::get<1>(size));
}

// set still output size
void ColorCamera::setStillSize(int width, int height) {
    properties.stillWidth = width;
    properties.stillHeight = height;
}

void ColorCamera::setStillSize(std::tuple<int, int> size) {
    setStillSize(std::get<0>(size), std::get<1>(size));
}

void ColorCamera::setIspScale(int horizNum, int horizDenom, int vertNum, int vertDenom) {
    properties.ispScale.horizNumerator = horizNum;
    properties.ispScale.horizDenominator = horizDenom;
    properties.ispScale.vertNumerator = vertNum;
    properties.ispScale.vertDenominator = vertDenom;
}

void ColorCamera::setIspScale(int numerator, int denominator) {
    setIspScale(numerator, denominator, numerator, denominator);
}

void ColorCamera::setIspScale(std::tuple<int, int> scale) {
    setIspScale(std::get<0>(scale), std::get<1>(scale));
}

void ColorCamera::setIspScale(std::tuple<int, int> horizScale, std::tuple<int, int> vertScale) {
    setIspScale(std::get<0>(horizScale), std::get<1>(horizScale), std::get<0>(vertScale), std::get<1>(vertScale));
}

void ColorCamera::setResolution(ColorCameraProperties::SensorResolution resolution) {
    properties.resolution = resolution;
}
ColorCameraProperties::SensorResolution ColorCamera::getResolution() const {
    return properties.resolution;
}

void ColorCamera::setFps(float fps) {
    properties.fps = fps;
}

float ColorCamera::getFps() const {
    // if AUTO
    if(properties.fps == ColorCameraProperties::AUTO || properties.fps == 0) {
        return 30.0f;
    }

    // else return fps
    return properties.fps;
}

// Returns preview size
std::tuple<int, int> ColorCamera::getPreviewSize() const {
    return {properties.previewWidth, properties.previewHeight};
}

int ColorCamera::getPreviewWidth() const {
    return properties.previewWidth;
}

int ColorCamera::getPreviewHeight() const {
    return properties.previewHeight;
}

// Returns video size
std::tuple<int, int> ColorCamera::getVideoSize() const {
    if(properties.videoWidth == ColorCameraProperties::AUTO || properties.videoHeight == ColorCameraProperties::AUTO) {
        // calculate based on auto
        int maxVideoWidth = 1920;
        int maxVideoHeight = 1080;

        if(properties.resolution == ColorCameraProperties::SensorResolution::THE_4_K
           || properties.resolution == ColorCameraProperties::SensorResolution::THE_12_MP) {
            maxVideoWidth = 3840;
            maxVideoHeight = 2160;
        }

        // Take into the account the ISP scaling
        int numW = properties.ispScale.horizNumerator;
        int denW = properties.ispScale.horizDenominator;
        if(numW > 0 && denW > 0) {
            maxVideoWidth =  getScaledSize(maxVideoWidth, numW, denW);
        }

        int numH = properties.ispScale.vertNumerator;
        int denH = properties.ispScale.vertDenominator;
        if(numH > 0 && denH > 0) {
            maxVideoHeight =  getScaledSize(maxVideoHeight, numH, denH);
        }

        return {maxVideoWidth, maxVideoHeight};
    }

    return {properties.videoWidth, properties.videoHeight};
}

int ColorCamera::getVideoWidth() const {
    return std::get<0>(getVideoSize());
}

int ColorCamera::getVideoHeight() const {
    return std::get<1>(getVideoSize());
}

// Returns still size
std::tuple<int, int> ColorCamera::getStillSize() const {
    // Calculate from AUTO
    if(properties.stillWidth == ColorCameraProperties::AUTO || properties.stillHeight == ColorCameraProperties::AUTO) {
        int maxStillWidth = 1920;
        int maxStillHeight = 1080;
        if(properties.resolution == dai::ColorCameraProperties::SensorResolution::THE_4_K) {
            maxStillWidth = 3840;
            maxStillHeight = 2160;
        }
        if(properties.resolution == dai::ColorCameraProperties::SensorResolution::THE_12_MP) {
            maxStillWidth = 4032;  // Note not 4056 as full sensor resolution
            maxStillHeight = 3040;
        }

        // Take into the account the ISP scaling
        int numW = properties.ispScale.horizNumerator;
        int denW = properties.ispScale.horizDenominator;
        if(numW > 0 && denW > 0) {
            maxStillWidth =  getScaledSize(maxStillWidth, numW, denW);
        }

        int numH = properties.ispScale.vertNumerator;
        int denH = properties.ispScale.vertDenominator;
        if(numH > 0 && denH > 0) {
            maxStillHeight =  getScaledSize(maxStillHeight, numH, denH);
        }

        return {maxStillWidth, maxStillHeight};
    }

    // Else return size set
    return {properties.stillWidth, properties.stillHeight};
}

int ColorCamera::getStillWidth() const {
    return std::get<0>(getStillSize());
}

int ColorCamera::getStillHeight() const {
    return std::get<1>(getStillSize());
}

// Returns sensor size
std::tuple<int, int> ColorCamera::getResolutionSize() const {
    switch(properties.resolution) {
        case ColorCameraProperties::SensorResolution::THE_1080_P:
            return {1920, 1080};
            break;

        case ColorCameraProperties::SensorResolution::THE_4_K:
            return {3840, 2160};
            break;

        case ColorCameraProperties::SensorResolution::THE_12_MP:
            return {4056, 3040};
            break;
    }

    return {1920, 1080};
}

int ColorCamera::getResolutionWidth() const {
    return std::get<0>(getResolutionSize());
}

int ColorCamera::getResolutionHeight() const {
    return std::get<1>(getResolutionSize());
}

int ColorCamera::getScaledSize(int input, int num, int denom) const {
    return (input * num - 1) / denom + 1;
}

int ColorCamera::getIspWidth() const {
    int inW = getResolutionWidth();
    int num = properties.ispScale.horizNumerator;
    int den = properties.ispScale.horizDenominator;
    if(num > 0 && den > 0) {
        return getScaledSize(inW, num, den);
    }
    return inW;
}

int ColorCamera::getIspHeight() const {
    int inH = getResolutionHeight();
    int num = properties.ispScale.vertNumerator;
    int den = properties.ispScale.vertDenominator;
    if(num > 0 && den > 0) {
        return getScaledSize(inH, num, den);
    }
    return inH;
}

std::tuple<int, int> ColorCamera::getIspSize() const {
    return {getIspWidth(), getIspHeight()};
}

void ColorCamera::sensorCenterCrop() {
    properties.sensorCropX = ColorCameraProperties::AUTO;
    properties.sensorCropY = ColorCameraProperties::AUTO;
}

void ColorCamera::setSensorCrop(float x, float y) {
    if(x < 0 || x >= 1) {
        throw std::invalid_argument("Sensor crop x must be specified as normalized value [0:1)");
    }
    if(y < 0 || y >= 1) {
        throw std::invalid_argument("Sensor crop y must be specified as normalized value [0:1)");
    }
    properties.sensorCropX = x;
    properties.sensorCropY = y;
}

std::tuple<float, float> ColorCamera::getSensorCrop() const {
    // AUTO - center crop by default
    if(properties.sensorCropX == ColorCameraProperties::AUTO || properties.sensorCropY == ColorCameraProperties::AUTO) {
        float x = std::floor(((getResolutionWidth() - getVideoWidth()) / 2.0f) / getResolutionWidth());
        float y = std::floor(((getResolutionHeight() - getVideoHeight()) / 2.0f) / getResolutionHeight());
        return {x, y};
    }
    return {properties.sensorCropX, properties.sensorCropY};
}

float ColorCamera::getSensorCropX() const {
    return std::get<0>(getSensorCrop());
}

float ColorCamera::getSensorCropY() const {
    return std::get<1>(getSensorCrop());
}

void ColorCamera::setWaitForConfigInput(bool wait) {
    properties.inputConfigSync = wait;
}

bool ColorCamera::getWaitForConfigInput() {
    return properties.inputConfigSync;
}

void ColorCamera::setPreviewKeepAspectRatio(bool keep) {
    properties.previewKeepAspectRatio = keep;
}

bool ColorCamera::getPreviewKeepAspectRatio() {
    return properties.previewKeepAspectRatio;
}

}  // namespace node
}  // namespace dai
<|endoftext|>


<commit_before>/*
 * Appender.cpp
 *
 * Copyright 2000, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2000, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include <log4cpp/Portability.hh>
#include <log4cpp/Appender.hh>

namespace log4cpp {
#ifdef LOG4CPP_USE_CLEANUP
    Log4cppCleanup& Appender::_fuckinDummy = Log4cppCleanup::_cleanup;
#endif

    Appender::AppenderMap* Appender::_allAppenders;

    /* assume _appenderMapMutex locked */
    Appender::AppenderMap& Appender::_getAllAppenders() {
        if (!_allAppenders)
            _allAppenders = new Appender::AppenderMap();

        return *_allAppenders;
    }

    Appender* Appender::getAppender(const std::string& name) {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = Appender::_getAllAppenders();
        AppenderMap::iterator i = allAppenders.find(name);
        return (allAppenders.end() == i) ? NULL : ((*i).second);
    }

    void Appender::_addAppender(Appender* appender) {
        //REQUIRE(_allAppenders.find(appender->getName()) == _getAllAppenders().end())
        threading::ScopedLock lock(_appenderMapMutex);
        _getAllAppenders()[appender->getName()] = appender;
    }

    void Appender::_removeAppender(Appender* appender) {
        threading::ScopedLock lock(_appenderMapMutex);
        _getAllAppenders().erase(appender->getName());
    }

    bool Appender::reopenAll() {
        threading::ScopedLock lock(_appenderMapMutex);
        bool result = true;
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); i++) {
            result = result && ((*i).second)->reopen();
        }

        return result;
    }

    void Appender::closeAll() {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); i++) {
            ((*i).second)->close();
        }
    }

    void Appender::_deleteAllAppenders() {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); ) {
            Appender *app = (*i).second;
            i++; // increment iterator before delete or iterator will be invalid.
            delete (app);
        }
    }

    Appender::Appender(const std::string& name) :
        _name(name) {
        _addAppender(this);
    }

    Appender::~Appender() {
        _removeAppender(this);
    }
}
<commit_msg>added missing Mutex<commit_after>/*
 * Appender.cpp
 *
 * Copyright 2000, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2000, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include <log4cpp/Portability.hh>
#include <log4cpp/Appender.hh>

namespace log4cpp {
#ifdef LOG4CPP_USE_CLEANUP
    Log4cppCleanup& Appender::_fuckinDummy = Log4cppCleanup::_cleanup;
#endif

    Appender::AppenderMap* Appender::_allAppenders;
    threading::Mutex Appender::_appenderMapMutex;

    /* assume _appenderMapMutex locked */
    Appender::AppenderMap& Appender::_getAllAppenders() {
        if (!_allAppenders)
            _allAppenders = new Appender::AppenderMap();

        return *_allAppenders;
    }

    Appender* Appender::getAppender(const std::string& name) {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = Appender::_getAllAppenders();
        AppenderMap::iterator i = allAppenders.find(name);
        return (allAppenders.end() == i) ? NULL : ((*i).second);
    }

    void Appender::_addAppender(Appender* appender) {
        //REQUIRE(_allAppenders.find(appender->getName()) == _getAllAppenders().end())
        threading::ScopedLock lock(_appenderMapMutex);
        _getAllAppenders()[appender->getName()] = appender;
    }

    void Appender::_removeAppender(Appender* appender) {
        threading::ScopedLock lock(_appenderMapMutex);
        _getAllAppenders().erase(appender->getName());
    }

    bool Appender::reopenAll() {
        threading::ScopedLock lock(_appenderMapMutex);
        bool result = true;
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); i++) {
            result = result && ((*i).second)->reopen();
        }

        return result;
    }

    void Appender::closeAll() {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); i++) {
            ((*i).second)->close();
        }
    }

    void Appender::_deleteAllAppenders() {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); ) {
            Appender *app = (*i).second;
            i++; // increment iterator before delete or iterator will be invalid.
            delete (app);
        }
    }

    Appender::Appender(const std::string& name) :
        _name(name) {
        _addAppender(this);
    }

    Appender::~Appender() {
        _removeAppender(this);
    }
}
<|endoftext|>


<commit_before>#include "init_libc.hpp"

#include <arch/x86/cpu.hpp>
#include <kernel.hpp>
#include <kernel/auxvec.h>
#include <kernel/cpuid.hpp>
#include <kernel/rng.hpp>
#include <kernel/service.hpp>
#include <util/elf_binary.hpp>
#include <version.h>
#include <kprint>

//#define KERN_DEBUG 1
#ifdef KERN_DEBUG
#define PRATTLE(fmt, ...) kprintf(fmt, ##__VA_ARGS__)
#else
#define PRATTLE(fmt, ...) /* fmt */
#endif

extern char _ELF_START_;
extern char _ELF_END_;
extern char _INIT_START_;
extern char _FINI_START_;
extern char _SSP_INIT_;
static uint32_t grub_magic;
static uint32_t grub_addr;

static volatile int global_ctors_ok = 0;
__attribute__((constructor))
static void global_ctor_test(){
  global_ctors_ok = 42;
}

extern "C"
int kernel_main(int, char * *, char * *)
{
  PRATTLE("<kernel_main> libc initialization complete \n");
  LL_ASSERT(global_ctors_ok == 42);
  kernel::state().libc_initialized = true;

  Elf_binary<Elf64> elf{{(char*)&_ELF_START_, &_ELF_END_ - &_ELF_START_}};
  LL_ASSERT(elf.is_ELF() && "ELF header intact");

  PRATTLE("<kernel_main> OS start \n");

  // Initialize early OS, platform and devices
#if defined(PLATFORM_x86_pc)
  kernel::start(grub_magic, grub_addr);
#elif defined(PLATFORM_x86_solo5)
  //kernel::start((const char*) (uintptr_t) grub_magic);
  kernel::start("Testing");
#else
  LL_ASSERT(0 && "Implement call to kernel start for this platform");
#endif

  // verify certain read-only sections in memory
  // NOTE: because of page protection we can choose to stop checking here
  kernel_sanity_checks();

  PRATTLE("<kernel_main> post start \n");
  // Initialize common subsystems and call Service::start
  kernel::post_start();

  // Starting event loop from here allows us to profile OS::start
  os::event_loop();
  return 0;
}

namespace x86
{
  // Musl entry
  extern "C"
  int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv);

  void init_libc(uint32_t magic, uint32_t addr)
  {
    grub_magic = magic;
    grub_addr  = addr;

    PRATTLE("* Elf start: %p\n", &_ELF_START_);
    auto* ehdr = (Elf64_Ehdr*)&_ELF_START_;
    auto* phdr = (Elf64_Phdr*)((char*)ehdr + ehdr->e_phoff);
    LL_ASSERT(phdr);
    Elf_binary<Elf64> elf{{(char*)&_ELF_START_, &_ELF_END_ - &_ELF_START_}};
    LL_ASSERT(elf.is_ELF());
    LL_ASSERT(phdr[0].p_type == PT_LOAD);

  #ifdef KERN_DEBUG
    PRATTLE("* Elf ident: %s, program headers: %p\n", ehdr->e_ident, ehdr);
    size_t size =  &_ELF_END_ - &_ELF_START_;
    PRATTLE("\tElf size: %zu \n", size);
    for (int i = 0; i < ehdr->e_phnum; i++)
    {
      PRATTLE("\tPhdr %i @ %p, va_addr: 0x%lx \n", i, &phdr[i], phdr[i].p_vaddr);
    }
  #endif

    // Build AUX-vector for C-runtime
    std::array<char*, 6 + 38> argv;
    // Parameters to main
    argv[0] = (char*) Service::name();
    argv[1] = 0x0;
    int argc = 1;

    // Env vars
    argv[2] = strdup("LC_CTYPE=C");
    argv[3] = strdup("LC_ALL=C");
    argv[4] = strdup("USER=root");
    argv[5] = 0x0;

    // auxiliary vector
    auxv_t* aux = (auxv_t*) &argv[6];
    PRATTLE("* Initializing aux-vector @ %p\n", aux);

    int i = 0;
    aux[i++].set_long(AT_PAGESZ, 4096);
    aux[i++].set_long(AT_CLKTCK, 100);

    // ELF related
    aux[i++].set_long(AT_PHENT, ehdr->e_phentsize);
    aux[i++].set_ptr(AT_PHDR, ((uint8_t*)ehdr) + ehdr->e_phoff);
    aux[i++].set_long(AT_PHNUM, ehdr->e_phnum);

    // Misc
    aux[i++].set_ptr(AT_BASE, nullptr);
    aux[i++].set_long(AT_FLAGS, 0x0);
    aux[i++].set_ptr(AT_ENTRY, (void*) &kernel_main);
    aux[i++].set_long(AT_HWCAP, 0);
    aux[i++].set_long(AT_UID, 0);
    aux[i++].set_long(AT_EUID, 0);
    aux[i++].set_long(AT_GID, 0);
    aux[i++].set_long(AT_EGID, 0);
    aux[i++].set_long(AT_SECURE, 1);

    const char* plat = "x86_64";
    aux[i++].set_ptr(AT_PLATFORM, plat);

    // supplemental randomness
    const long canary = rng_extract_uint64() & 0xFFFFFFFFFFFF00FFul;
    const long canary_idx = i;
    aux[i++].set_long(AT_RANDOM, canary);
    kprintf("* Stack protector value: %#lx\n", canary);
    // entropy slot
    aux[i++].set_ptr(AT_RANDOM, &aux[canary_idx].a_un.a_val);
    aux[i++].set_long(AT_NULL, 0);

#ifdef PLATFORM_x86_pc
    // SYSCALL instruction
  #if defined(__x86_64__)
    PRATTLE("* Initialize syscall MSR (64-bit)\n");
    uint64_t star_kernel_cs = 8ull << 32;
    uint64_t star_user_cs   = 8ull << 48;
    uint64_t star = star_kernel_cs | star_user_cs;
    x86::CPU::write_msr(IA32_STAR, star);
    x86::CPU::write_msr(IA32_LSTAR, (uintptr_t)&__syscall_entry);
  #elif defined(__i386__)
    PRATTLE("Initialize syscall intr (32-bit)\n");
    #warning Classical syscall interface missing for 32-bit
  #endif
#endif

    // GDB_ENTRY;
    PRATTLE("* Starting libc initialization\n");
    __libc_start_main(kernel_main, argc, argv.data());
  }
}
<commit_msg>x86: Don't print stack protector<commit_after>#include "init_libc.hpp"

#include <arch/x86/cpu.hpp>
#include <kernel.hpp>
#include <kernel/auxvec.h>
#include <kernel/cpuid.hpp>
#include <kernel/rng.hpp>
#include <kernel/service.hpp>
#include <util/elf_binary.hpp>
#include <version.h>
#include <kprint>

//#define KERN_DEBUG 1
#ifdef KERN_DEBUG
#define PRATTLE(fmt, ...) kprintf(fmt, ##__VA_ARGS__)
#else
#define PRATTLE(fmt, ...) /* fmt */
#endif

extern char _ELF_START_;
extern char _ELF_END_;
extern char _INIT_START_;
extern char _FINI_START_;
extern char _SSP_INIT_;
static uint32_t grub_magic;
static uint32_t grub_addr;

static volatile int global_ctors_ok = 0;
__attribute__((constructor))
static void global_ctor_test(){
  global_ctors_ok = 42;
}

extern "C"
int kernel_main(int, char * *, char * *)
{
  PRATTLE("<kernel_main> libc initialization complete \n");
  LL_ASSERT(global_ctors_ok == 42);
  kernel::state().libc_initialized = true;

  Elf_binary<Elf64> elf{{(char*)&_ELF_START_, &_ELF_END_ - &_ELF_START_}};
  LL_ASSERT(elf.is_ELF() && "ELF header intact");

  PRATTLE("<kernel_main> OS start \n");

  // Initialize early OS, platform and devices
#if defined(PLATFORM_x86_pc)
  kernel::start(grub_magic, grub_addr);
#elif defined(PLATFORM_x86_solo5)
  //kernel::start((const char*) (uintptr_t) grub_magic);
  kernel::start("Testing");
#else
  LL_ASSERT(0 && "Implement call to kernel start for this platform");
#endif

  // verify certain read-only sections in memory
  // NOTE: because of page protection we can choose to stop checking here
  kernel_sanity_checks();

  PRATTLE("<kernel_main> post start \n");
  // Initialize common subsystems and call Service::start
  kernel::post_start();

  // Starting event loop from here allows us to profile OS::start
  os::event_loop();
  return 0;
}

namespace x86
{
  // Musl entry
  extern "C"
  int __libc_start_main(int (*main)(int,char **,char **), int argc, char **argv);

  void init_libc(uint32_t magic, uint32_t addr)
  {
    grub_magic = magic;
    grub_addr  = addr;

    PRATTLE("* Elf start: %p\n", &_ELF_START_);
    auto* ehdr = (Elf64_Ehdr*)&_ELF_START_;
    auto* phdr = (Elf64_Phdr*)((char*)ehdr + ehdr->e_phoff);
    LL_ASSERT(phdr);
    Elf_binary<Elf64> elf{{(char*)&_ELF_START_, &_ELF_END_ - &_ELF_START_}};
    LL_ASSERT(elf.is_ELF());
    LL_ASSERT(phdr[0].p_type == PT_LOAD);

  #ifdef KERN_DEBUG
    PRATTLE("* Elf ident: %s, program headers: %p\n", ehdr->e_ident, ehdr);
    size_t size =  &_ELF_END_ - &_ELF_START_;
    PRATTLE("\tElf size: %zu \n", size);
    for (int i = 0; i < ehdr->e_phnum; i++)
    {
      PRATTLE("\tPhdr %i @ %p, va_addr: 0x%lx \n", i, &phdr[i], phdr[i].p_vaddr);
    }
  #endif

    // Build AUX-vector for C-runtime
    std::array<char*, 6 + 38> argv;
    // Parameters to main
    argv[0] = (char*) Service::name();
    argv[1] = 0x0;
    int argc = 1;

    // Env vars
    argv[2] = strdup("LC_CTYPE=C");
    argv[3] = strdup("LC_ALL=C");
    argv[4] = strdup("USER=root");
    argv[5] = 0x0;

    // auxiliary vector
    auxv_t* aux = (auxv_t*) &argv[6];
    PRATTLE("* Initializing aux-vector @ %p\n", aux);

    int i = 0;
    aux[i++].set_long(AT_PAGESZ, 4096);
    aux[i++].set_long(AT_CLKTCK, 100);

    // ELF related
    aux[i++].set_long(AT_PHENT, ehdr->e_phentsize);
    aux[i++].set_ptr(AT_PHDR, ((uint8_t*)ehdr) + ehdr->e_phoff);
    aux[i++].set_long(AT_PHNUM, ehdr->e_phnum);

    // Misc
    aux[i++].set_ptr(AT_BASE, nullptr);
    aux[i++].set_long(AT_FLAGS, 0x0);
    aux[i++].set_ptr(AT_ENTRY, (void*) &kernel_main);
    aux[i++].set_long(AT_HWCAP, 0);
    aux[i++].set_long(AT_UID, 0);
    aux[i++].set_long(AT_EUID, 0);
    aux[i++].set_long(AT_GID, 0);
    aux[i++].set_long(AT_EGID, 0);
    aux[i++].set_long(AT_SECURE, 1);

    const char* plat = "x86_64";
    aux[i++].set_ptr(AT_PLATFORM, plat);

    // supplemental randomness
    const long canary = rng_extract_uint64() & 0xFFFFFFFFFFFF00FFul;
    const long canary_idx = i;
    aux[i++].set_long(AT_RANDOM, canary);
    //kprintf("* Stack protector value: %#lx\n", canary);
    // entropy slot
    aux[i++].set_ptr(AT_RANDOM, &aux[canary_idx].a_un.a_val);
    aux[i++].set_long(AT_NULL, 0);

#ifdef PLATFORM_x86_pc
    // SYSCALL instruction
  #if defined(__x86_64__)
    PRATTLE("* Initialize syscall MSR (64-bit)\n");
    uint64_t star_kernel_cs = 8ull << 32;
    uint64_t star_user_cs   = 8ull << 48;
    uint64_t star = star_kernel_cs | star_user_cs;
    x86::CPU::write_msr(IA32_STAR, star);
    x86::CPU::write_msr(IA32_LSTAR, (uintptr_t)&__syscall_entry);
  #elif defined(__i386__)
    PRATTLE("Initialize syscall intr (32-bit)\n");
    #warning Classical syscall interface missing for 32-bit
  #endif
#endif

    // GDB_ENTRY;
    PRATTLE("* Starting libc initialization\n");
    __libc_start_main(kernel_main, argc, argv.data());
  }
}
<|endoftext|>


<commit_before>/*
 * Appender.cpp
 *
 * Copyright 2000, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2000, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include "PortabilityImpl.hh"
#include <log4cpp/Appender.hh>

namespace log4cpp {
    Appender::AppenderMap* Appender::_allAppenders = 0;
    threading::Mutex Appender::_appenderMapMutex;

    /* assume _appenderMapMutex locked */
    Appender::AppenderMap& Appender::_getAllAppenders() {
        if (!_allAppenders)
            _allAppenders = new Appender::AppenderMap();

        return *_allAppenders;
    }

    Appender* Appender::getAppender(const std::string& name) {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = Appender::_getAllAppenders();
        AppenderMap::iterator i = allAppenders.find(name);
        return (allAppenders.end() == i) ? NULL : ((*i).second);
    }

    void Appender::_addAppender(Appender* appender) {
        //REQUIRE(_allAppenders.find(appender->getName()) == _getAllAppenders().end())
        threading::ScopedLock lock(_appenderMapMutex);
        _getAllAppenders()[appender->getName()] = appender;
    }

    void Appender::_removeAppender(Appender* appender) {
        threading::ScopedLock lock(_appenderMapMutex);
        _getAllAppenders().erase(appender->getName());
    }

    bool Appender::reopenAll() {
        threading::ScopedLock lock(_appenderMapMutex);
        bool result = true;
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); i++) {
            result = result && ((*i).second)->reopen();
        }

        return result;
    }

    void Appender::closeAll() {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); i++) {
            ((*i).second)->close();
        }
    }

    void Appender::_deleteAllAppenders() {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); ) {
            Appender *app = (*i).second;
            i++; // increment iterator before delete or iterator will be invalid.
            delete (app);
        }
    }

    Appender::Appender(const std::string& name) :
        _name(name) {
        _addAppender(this);
    }

    Appender::~Appender() {
        _removeAppender(this);
    }
}
<commit_msg>Fix for bug 2940452<commit_after>/*
 * Appender.cpp
 *
 * Copyright 2000, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
 * Copyright 2000, Bastiaan Bakker. All rights reserved.
 *
 * See the COPYING file for the terms of usage and distribution.
 */

#include "PortabilityImpl.hh"
#include <log4cpp/Appender.hh>

namespace log4cpp {
    Appender::AppenderMap* Appender::_allAppenders = 0;
    threading::Mutex Appender::_appenderMapMutex;

    /* assume _appenderMapMutex locked */
    Appender::AppenderMap& Appender::_getAllAppenders() {
        if (!_allAppenders)
            _allAppenders = new Appender::AppenderMap();

        return *_allAppenders;
    }

    Appender* Appender::getAppender(const std::string& name) {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = Appender::_getAllAppenders();
        AppenderMap::iterator i = allAppenders.find(name);
        return (allAppenders.end() == i) ? NULL : ((*i).second);
    }

    void Appender::_addAppender(Appender* appender) {
        //REQUIRE(_allAppenders.find(appender->getName()) == _getAllAppenders().end())
        threading::ScopedLock lock(_appenderMapMutex);
        _getAllAppenders()[appender->getName()] = appender;
    }

    void Appender::_removeAppender(Appender* appender) {
        threading::ScopedLock lock(_appenderMapMutex);
        _getAllAppenders().erase(appender->getName());
        if(_getAllAppenders().size() == 0) {
	    delete _allAppenders; _allAppenders = 0;	// fix for #2940452
        }
    }

    bool Appender::reopenAll() {
        threading::ScopedLock lock(_appenderMapMutex);
        bool result = true;
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); i++) {
            result = result && ((*i).second)->reopen();
        }

        return result;
    }

    void Appender::closeAll() {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); i++) {
            ((*i).second)->close();
        }
    }

    void Appender::_deleteAllAppenders() {
        threading::ScopedLock lock(_appenderMapMutex);
        AppenderMap& allAppenders = _getAllAppenders();
        for(AppenderMap::iterator i = allAppenders.begin(); i != allAppenders.end(); ) {
            Appender *app = (*i).second;
            i++; // increment iterator before delete or iterator will be invalid.
            delete (app);
        }
    }

    Appender::Appender(const std::string& name) :
        _name(name) {
        _addAppender(this);
    }

    Appender::~Appender() {
        _removeAppender(this);
    }
}
<|endoftext|>


<commit_before>#define LUA_LIB

#define PI 3.141592654
#define TAO PI * 2

#include "rikoAudio.h"

#include <LuaJIT/lua.hpp>
#include <LuaJIT/lauxlib.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>

#include <stdlib.h>

#include <math.h>

extern bool audEnabled;

typedef struct {
	double totalTime;
	unsigned long long remainingCycles;
	double frequency;
	double frequencyShift;
	double attack;
	double release;
	float volume;
} Sound;

typedef struct node {
	Sound* data;
	struct node* next;
} node_t;

typedef struct queue {
	node_t* head;
	node_t* tail;
} queue_t;

queue_t* constructQueue() {
	queue_t* newQueue = (queue_t*)malloc(sizeof(queue_t));
	newQueue->head = NULL;
	newQueue->tail = NULL;
	return newQueue;
}

void pushToQueue(queue_t* wqueue, Sound* snd) {
	node_t* nxtNode = (node_t*)malloc(sizeof(node_t));
	nxtNode->data = snd;
	nxtNode->next = NULL;
	if (wqueue->head != NULL)
		  wqueue->head->next = nxtNode;
	else  wqueue->tail = nxtNode;
	wqueue->head = nxtNode;
}

Sound* popFromQueue(queue_t* wqueue) {
	if (wqueue->tail == NULL) {
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Attempt to pop from empty queue (%p)", (void*)wqueue);
		return NULL;
	}
	Sound* data = wqueue->tail->data;
	node_t* old = wqueue->tail;
	if (old == wqueue->head) {
		wqueue->head = NULL;
		wqueue->tail = NULL;
		free(old);
		return data;
	}
	wqueue->tail = wqueue->tail->next;
	free(old);

	return data;
}

void falloutQueue(queue_t* wqueue) {
	if (wqueue->tail == NULL) {
		if (wqueue->head != wqueue->tail) {
			puts("WARN: Queue has dangling head! Some elements may not be freed correctly!\n");
			free(wqueue->head);
		}
		return;
	}

	while (wqueue->tail->next != NULL) {
		Sound* snd = popFromQueue(wqueue);
		free(snd);

		if (wqueue->tail == NULL) {
			if (wqueue->head != wqueue->tail) {
				puts("WARN: Queue has dangling head! Some elements may not be freed correctly!\n");
				free(wqueue->head);
			}
			return;
		}
	}

	if (wqueue->head != wqueue->tail) {
		puts("WARN: Queue has dangling head/tail! Some elements may not be freed correctly!\n");
		free(wqueue->head);
	}

	free(wqueue->tail);
}

SDL_AudioSpec want, have;
SDL_AudioDeviceID dev;

static int sampleRate = 48000;
static int samples = 1024;
static int audDevChanCount = 1;

const int channelCount = 5;
const int queueSize = 512;
static queue* audioQueues[channelCount];
static Sound* playingAudio[channelCount];
static bool channelHasSnd[channelCount];
static double streamPhase[channelCount];
float lstRnd = 0;

void audioCallback(void *userdata, uint8_t *byteStream, int len) {
	float* floatStream = (float*) byteStream;

	for (int i = 0; i < channelCount; i++) {
		if (!channelHasSnd[i] && audioQueues[i]->tail != NULL) {
			playingAudio[i] = popFromQueue(audioQueues[i]);
			channelHasSnd[i] = true;
		}
	}

	for (int z = 0; z < samples * audDevChanCount; z++) {
		for (int cc = 0; cc < audDevChanCount; cc++) {
			floatStream[z] = 0;

			for (int i = 0; i < channelCount; i++) {
				if (!channelHasSnd[i]) {
					if (audioQueues[i]->tail != NULL) {
						playingAudio[i] = popFromQueue(audioQueues[i]);
						channelHasSnd[i] = true;
					} else {
						continue;
					}
				}

				if (playingAudio[i]->remainingCycles == 0) {
					free(playingAudio[i]);

					if (audioQueues[i]->tail != NULL) {
						// Awesome got another sound queued up, so load it in
						playingAudio[i] = popFromQueue(audioQueues[i]);
					} else {
						channelHasSnd[i] = false;
					}
				}

				if (!channelHasSnd[i]) continue;

				double delta;
				double atC;
				double rlC;

				if (playingAudio[i]->attack == 0) {
					atC = 1;
				} else {
					atC = (playingAudio[i]->totalTime - ((double)playingAudio[i]->remainingCycles / sampleRate)) / playingAudio[i]->attack;
					atC = atC > 1 ? 1 : atC;
				}

				rlC = playingAudio[i]->release - ((double)playingAudio[i]->remainingCycles / sampleRate);
				rlC = rlC > 0 ? 1 - rlC / playingAudio[i]->release : 1;
				double vol = playingAudio[i]->volume * atC * rlC;

				switch (i) {
				case 0:
				case 1:
					// Pulse Wave
				floatStream[z] += (float)((fmod(streamPhase[i], TAO) > PI/4 ? -1 : 1) * vol);
					streamPhase[i] += TAO * playingAudio[i]->frequency / sampleRate;
					break;
				case 2:
					// Triangle Wave
				floatStream[z] += (float)((1 - 4 * fabs(fmod(streamPhase[i], 1) - 0.5)) * vol);
					streamPhase[i] += (double)playingAudio[i]->frequency / sampleRate;
					break;
				case 3:
					// Sawtooth Wave
				floatStream[z] += (float)((2 * fmod(streamPhase[i] - 0.5, 1) - 1) * vol);
					streamPhase[i] += (double)playingAudio[i]->frequency / sampleRate;
					break;
				case 4:
					// Noise (Wave?)
					delta = fmod((streamPhase[i] + 1), playingAudio[i]->frequency);
					if (streamPhase[i] > delta) {
						lstRnd = (float)((((float)rand() / (float)RAND_MAX) * 2 - 1) * vol);
					}
					streamPhase[i] = delta;

				floatStream[z] += lstRnd;

					break;
				}

				playingAudio[i]->remainingCycles--;

				playingAudio[i]->frequency += playingAudio[i]->frequencyShift;
			}
		}
	}
}

static int aud_play(lua_State *L) {
	int off = lua_gettop(L);
	if (off == 0) {
		luaL_error(L, "Expected table as first argument");
		return 0;
	}
	if (lua_type(L, -off) != LUA_TTABLE) {
		luaL_error(L, "Expected table as first argument");
		return 0;
	}

	lua_pushstring(L, "channel");
	lua_gettable(L, -1 - off);
	int chan = (int)luaL_checkinteger(L, -1);

	if (chan <= 0 || chan > channelCount) {
		luaL_error(L, "Channel must be between 1 and %d", channelCount);
	}

	lua_pushstring(L, "volume");
	lua_gettable(L, -2 - off);
	double vol;
	if (lua_isnil(L, -1)) {
		vol = 1;
	} else {
		vol = lua_tonumber(L, -1);
	}

	lua_pushstring(L, "frequency");
	lua_gettable(L, -3 - off);
	int freq = (int)luaL_checkinteger(L, -1);

	lua_pushstring(L, "shift");
	lua_gettable(L, -4 - off);
	int freqShft;
	if (lua_isnil(L, -1)) {
		freqShft = 0;
	} else {
		freqShft = (int)lua_tointeger(L, -1);
	}

	lua_pushstring(L, "time");
	lua_gettable(L, -5 - off);
	double time;
	if (lua_type(L, -1) != LUA_TNUMBER) {
		luaL_error(L, "bad argument 'time' to 'play' (number expected, got %s)", lua_typename(L, lua_type(L, -1)));
		return 0;
	} else {
		time = lua_tonumber(L, -1);
		if (time <= 0) {
			luaL_error(L, "bad argument 'time' to 'play' (number must be greater than 0)");
			return 0;
		}
	}

	lua_pushstring(L, "attack");
	lua_gettable(L, -6 - off);
	double atK = luaL_checknumber(L, -1);
	if (atK < 0) {
		luaL_error(L, "bad argument 'attack' to 'play' (number must be greater than or equal to 0)");
		return 0;
	}

	lua_pushstring(L, "release");
	lua_gettable(L, -7 - off);
	double rls = luaL_checknumber(L, -1);
	if (rls < 0) {
		luaL_error(L, "bad argument 'release' to 'play' (number must be greater than or equal to 0)");
		return 0;
	}

	Sound* puls = (Sound*)malloc(sizeof(Sound));
	if (chan == 5) {
		puls->frequency = (110 - (12 * (log(pow(2, 1 / 12) * freq / 16.35) / log(2))));
		puls->frequencyShift = ((110 - (12 * (log(pow(2, 1 / 12) * (freq + freqShft) / 16.35) / log(2)))) - puls->frequency) / (sampleRate * time);
	} else {
		puls->frequency = freq;
		puls->frequencyShift = (double)freqShft / (sampleRate * time);
	}

	puls->volume = vol < 0 ? 0 : (vol > 1 ? 1 : (float)vol);
	puls->totalTime = time;
	puls->attack = atK;
	puls->release = rls;
	puls->remainingCycles = (unsigned long long)(time * sampleRate);
	pushToQueue(audioQueues[chan - 1], puls);

	return 0;
}

static const luaL_Reg audLib[] = {
	{ "play", aud_play },
	{ NULL, NULL }
};

LUALIB_API int luaopen_aud(lua_State *L) {
	for (int i = 0; i < channelCount; i++) {
		audioQueues[i] = constructQueue();
		streamPhase[i] = 0;
	}

	if (audEnabled) {
		SDL_InitSubSystem(SDL_INIT_AUDIO);

		SDL_zero(want);
		want.freq = sampleRate;
		want.format = AUDIO_F32SYS;
		want.channels = audDevChanCount;
		want.samples = samples;
		want.callback = audioCallback;
		want.userdata = NULL;

		int dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE);
		if (dev == 0) {
			SDL_Log("Failed to open audio: %s", SDL_GetError());
		} else {
			sampleRate = have.freq;
			samples = have.samples;
			audDevChanCount = have.channels;

			if (have.format != want.format) { /* we can't let this one thing change. */
				SDL_Log("We didn't get Float32 audio format.");
			} else {
				SDL_PauseAudioDevice(dev, 0); /* start audio playing. */
			}
		}
	}

	luaL_openlib(L, RIKO_AUD_NAME, audLib, 0);
	return 1;
}

void closeAudio() {
	if (dev != 0) {
		SDL_CloseAudioDevice(dev);
	}

	for (int i = 0; i < channelCount; i++) {
		falloutQueue(audioQueues[i]);
		free(audioQueues[i]);
	}
}
<commit_msg>Fix unintentional shadowing<commit_after>#define LUA_LIB

#define PI 3.141592654
#define TAO PI * 2

#include "rikoAudio.h"

#include <LuaJIT/lua.hpp>
#include <LuaJIT/lauxlib.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>

#include <stdlib.h>

#include <math.h>

extern bool audEnabled;

typedef struct {
	double totalTime;
	unsigned long long remainingCycles;
	double frequency;
	double frequencyShift;
	double attack;
	double release;
	float volume;
} Sound;

typedef struct node {
	Sound* data;
	struct node* next;
} node_t;

typedef struct queue {
	node_t* head;
	node_t* tail;
} queue_t;

queue_t* constructQueue() {
	queue_t* newQueue = (queue_t*)malloc(sizeof(queue_t));
	newQueue->head = NULL;
	newQueue->tail = NULL;
	return newQueue;
}

void pushToQueue(queue_t* wqueue, Sound* snd) {
	node_t* nxtNode = (node_t*)malloc(sizeof(node_t));
	nxtNode->data = snd;
	nxtNode->next = NULL;
	if (wqueue->head != NULL)
		  wqueue->head->next = nxtNode;
	else  wqueue->tail = nxtNode;
	wqueue->head = nxtNode;
}

Sound* popFromQueue(queue_t* wqueue) {
	if (wqueue->tail == NULL) {
		SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Attempt to pop from empty queue (%p)", (void*)wqueue);
		return NULL;
	}
	Sound* data = wqueue->tail->data;
	node_t* old = wqueue->tail;
	if (old == wqueue->head) {
		wqueue->head = NULL;
		wqueue->tail = NULL;
		free(old);
		return data;
	}
	wqueue->tail = wqueue->tail->next;
	free(old);

	return data;
}

void falloutQueue(queue_t* wqueue) {
	if (wqueue->tail == NULL) {
		if (wqueue->head != wqueue->tail) {
			puts("WARN: Queue has dangling head! Some elements may not be freed correctly!\n");
			free(wqueue->head);
		}
		return;
	}

	while (wqueue->tail->next != NULL) {
		Sound* snd = popFromQueue(wqueue);
		free(snd);

		if (wqueue->tail == NULL) {
			if (wqueue->head != wqueue->tail) {
				puts("WARN: Queue has dangling head! Some elements may not be freed correctly!\n");
				free(wqueue->head);
			}
			return;
		}
	}

	if (wqueue->head != wqueue->tail) {
		puts("WARN: Queue has dangling head/tail! Some elements may not be freed correctly!\n");
		free(wqueue->head);
	}

	free(wqueue->tail);
}

SDL_AudioSpec want, have;
SDL_AudioDeviceID dev;

static int sampleRate = 48000;
static int samples = 1024;
static int audDevChanCount = 1;

const int channelCount = 5;
const int queueSize = 512;
static queue* audioQueues[channelCount];
static Sound* playingAudio[channelCount];
static bool channelHasSnd[channelCount];
static double streamPhase[channelCount];
float lstRnd = 0;

void audioCallback(void *userdata, uint8_t *byteStream, int len) {
	float* floatStream = (float*) byteStream;

	for (int i = 0; i < channelCount; i++) {
		if (!channelHasSnd[i] && audioQueues[i]->tail != NULL) {
			playingAudio[i] = popFromQueue(audioQueues[i]);
			channelHasSnd[i] = true;
		}
	}

	for (int z = 0; z < samples * audDevChanCount; z++) {
		for (int cc = 0; cc < audDevChanCount; cc++) {
			floatStream[z] = 0;

			for (int i = 0; i < channelCount; i++) {
				if (!channelHasSnd[i]) {
					if (audioQueues[i]->tail != NULL) {
						playingAudio[i] = popFromQueue(audioQueues[i]);
						channelHasSnd[i] = true;
					} else {
						continue;
					}
				}

				if (playingAudio[i]->remainingCycles == 0) {
					free(playingAudio[i]);

					if (audioQueues[i]->tail != NULL) {
						// Awesome got another sound queued up, so load it in
						playingAudio[i] = popFromQueue(audioQueues[i]);
					} else {
						channelHasSnd[i] = false;
					}
				}

				if (!channelHasSnd[i]) continue;

				double delta;
				double atC;
				double rlC;

				if (playingAudio[i]->attack == 0) {
					atC = 1;
				} else {
					atC = (playingAudio[i]->totalTime - ((double)playingAudio[i]->remainingCycles / sampleRate)) / playingAudio[i]->attack;
					atC = atC > 1 ? 1 : atC;
				}

				rlC = playingAudio[i]->release - ((double)playingAudio[i]->remainingCycles / sampleRate);
				rlC = rlC > 0 ? 1 - rlC / playingAudio[i]->release : 1;
				double vol = playingAudio[i]->volume * atC * rlC;

				switch (i) {
				case 0:
				case 1:
					// Pulse Wave
				floatStream[z] += (float)((fmod(streamPhase[i], TAO) > PI/4 ? -1 : 1) * vol);
					streamPhase[i] += TAO * playingAudio[i]->frequency / sampleRate;
					break;
				case 2:
					// Triangle Wave
				floatStream[z] += (float)((1 - 4 * fabs(fmod(streamPhase[i], 1) - 0.5)) * vol);
					streamPhase[i] += (double)playingAudio[i]->frequency / sampleRate;
					break;
				case 3:
					// Sawtooth Wave
				floatStream[z] += (float)((2 * fmod(streamPhase[i] - 0.5, 1) - 1) * vol);
					streamPhase[i] += (double)playingAudio[i]->frequency / sampleRate;
					break;
				case 4:
					// Noise (Wave?)
					delta = fmod((streamPhase[i] + 1), playingAudio[i]->frequency);
					if (streamPhase[i] > delta) {
						lstRnd = (float)((((float)rand() / (float)RAND_MAX) * 2 - 1) * vol);
					}
					streamPhase[i] = delta;

				floatStream[z] += lstRnd;

					break;
				}

				playingAudio[i]->remainingCycles--;

				playingAudio[i]->frequency += playingAudio[i]->frequencyShift;
			}
		}
	}
}

static int aud_play(lua_State *L) {
	int off = lua_gettop(L);
	if (off == 0) {
		luaL_error(L, "Expected table as first argument");
		return 0;
	}
	if (lua_type(L, -off) != LUA_TTABLE) {
		luaL_error(L, "Expected table as first argument");
		return 0;
	}

	lua_pushstring(L, "channel");
	lua_gettable(L, -1 - off);
	int chan = (int)luaL_checkinteger(L, -1);

	if (chan <= 0 || chan > channelCount) {
		luaL_error(L, "Channel must be between 1 and %d", channelCount);
	}

	lua_pushstring(L, "volume");
	lua_gettable(L, -2 - off);
	double vol;
	if (lua_isnil(L, -1)) {
		vol = 1;
	} else {
		vol = lua_tonumber(L, -1);
	}

	lua_pushstring(L, "frequency");
	lua_gettable(L, -3 - off);
	int freq = (int)luaL_checkinteger(L, -1);

	lua_pushstring(L, "shift");
	lua_gettable(L, -4 - off);
	int freqShft;
	if (lua_isnil(L, -1)) {
		freqShft = 0;
	} else {
		freqShft = (int)lua_tointeger(L, -1);
	}

	lua_pushstring(L, "time");
	lua_gettable(L, -5 - off);
	double time;
	if (lua_type(L, -1) != LUA_TNUMBER) {
		luaL_error(L, "bad argument 'time' to 'play' (number expected, got %s)", lua_typename(L, lua_type(L, -1)));
		return 0;
	} else {
		time = lua_tonumber(L, -1);
		if (time <= 0) {
			luaL_error(L, "bad argument 'time' to 'play' (number must be greater than 0)");
			return 0;
		}
	}

	lua_pushstring(L, "attack");
	lua_gettable(L, -6 - off);
	double atK = luaL_checknumber(L, -1);
	if (atK < 0) {
		luaL_error(L, "bad argument 'attack' to 'play' (number must be greater than or equal to 0)");
		return 0;
	}

	lua_pushstring(L, "release");
	lua_gettable(L, -7 - off);
	double rls = luaL_checknumber(L, -1);
	if (rls < 0) {
		luaL_error(L, "bad argument 'release' to 'play' (number must be greater than or equal to 0)");
		return 0;
	}

	Sound* puls = (Sound*)malloc(sizeof(Sound));
	if (chan == 5) {
		puls->frequency = (110 - (12 * (log(pow(2, 1 / 12) * freq / 16.35) / log(2))));
		puls->frequencyShift = ((110 - (12 * (log(pow(2, 1 / 12) * (freq + freqShft) / 16.35) / log(2)))) - puls->frequency) / (sampleRate * time);
	} else {
		puls->frequency = freq;
		puls->frequencyShift = (double)freqShft / (sampleRate * time);
	}

	puls->volume = vol < 0 ? 0 : (vol > 1 ? 1 : (float)vol);
	puls->totalTime = time;
	puls->attack = atK;
	puls->release = rls;
	puls->remainingCycles = (unsigned long long)(time * sampleRate);
	pushToQueue(audioQueues[chan - 1], puls);

	return 0;
}

static const luaL_Reg audLib[] = {
	{ "play", aud_play },
	{ NULL, NULL }
};

LUALIB_API int luaopen_aud(lua_State *L) {
	for (int i = 0; i < channelCount; i++) {
		audioQueues[i] = constructQueue();
		streamPhase[i] = 0;
	}

	if (audEnabled) {
		SDL_InitSubSystem(SDL_INIT_AUDIO);

		SDL_zero(want);
		want.freq = sampleRate;
		want.format = AUDIO_F32SYS;
		want.channels = audDevChanCount;
		want.samples = samples;
		want.callback = audioCallback;
		want.userdata = NULL;

		dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_ANY_CHANGE);
		if (dev == 0) {
			SDL_Log("Failed to open audio: %s", SDL_GetError());
		} else {
			sampleRate = have.freq;
			samples = have.samples;
			audDevChanCount = have.channels;

			if (have.format != want.format) { /* we can't let this one thing change. */
				SDL_Log("We didn't get Float32 audio format.");
			} else {
				SDL_PauseAudioDevice(dev, 0); /* start audio playing. */
			}
		}
	}

	luaL_openlib(L, RIKO_AUD_NAME, audLib, 0);
	return 1;
}

void closeAudio() {
	if (dev != 0) {
		SDL_CloseAudioDevice(dev);
	}

	for (int i = 0; i < channelCount; i++) {
		falloutQueue(audioQueues[i]);
		free(audioQueues[i]);
	}
}
<|endoftext|>


<commit_before>#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>

#include <zombye/ecs/typed_value.hpp>
#include <zombye/utils/assign.hpp>
#include <zombye/utils/logger.hpp>

namespace zombye {
    std::unique_ptr<zombye::value_pack> assign_values(const std::string& name, const Json::Value& object,
    const rtti::property_list& properties) {
        auto value_pack = new zombye::value_pack(name);
        for (auto& p : properties) {
            auto wrapped_value = object[p->name()];
            auto value = assign_value(p.get(), wrapped_value);
            if (!value) {
                log(LOG_FATAL, "type of property " + p->name() + " at " + name + " is unknown");
            }
            value_pack->emplace_back(std::move(value));
        }
        return std::unique_ptr<zombye::value_pack>{value_pack};
    }

    std::unique_ptr<abstract_value> assign_value(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = property->type();
        switch (type) {
            case property_types::BOOL:
                return assign_bool(property, wrapped_value);
            case property_types::INT:
                return assign_int(property, wrapped_value);
            case property_types::IVEC2:
                return assign_ivec2(property, wrapped_value);
            case property_types::IVEC3:
                return assign_ivec3(property, wrapped_value);
            case property_types::IVEC4:
                return assign_ivec4(property, wrapped_value);
            case property_types::FLOAT:
                return assign_float(property, wrapped_value);
            case property_types::VEC2:
                return assign_vec2(property, wrapped_value);
            case property_types::VEC3:
                return assign_vec3(property, wrapped_value);
            case property_types::VEC4:
                return assign_vec4(property, wrapped_value);
            case property_types::QUAT:
                return assign_quat(property, wrapped_value);
            case property_types::STRING:
                return assign_string(property, wrapped_value);
            default:
                return nullptr;
        }
    }

    std::unique_ptr<abstract_value> assign_bool(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::booleanValue) {
            log(LOG_FATAL, "expected type bool at property " + property->name() + " : " + wrapped_value.asString());
        }
        return std::unique_ptr<abstract_value>(new typed_value<bool>{*static_cast<typed_property<bool>*>(property),
            wrapped_value.asBool()});
    }

    std::unique_ptr<abstract_value> assign_int(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::intValue) {
            log(LOG_FATAL, "expected type int at property " + property->name() + " : " + wrapped_value.asString());
        }
        return std::unique_ptr<abstract_value>(new typed_value<int>{*static_cast<typed_property<int>*>(property),
            wrapped_value.asInt()});
    }

    std::unique_ptr<abstract_value> assign_ivec2(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type ivec2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 3) {
            log(LOG_FATAL, "expected size 2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "i") {
            log(LOG_FATAL, "expected type ivec2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::ivec2 vec;
        for (auto i = 1; i < 3; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type int at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asInt();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::ivec2>
            {*static_cast<typed_property<glm::ivec2>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_ivec3(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type ivec3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 4) {
            log(LOG_FATAL, "expected size 3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "i") {
            log(LOG_FATAL, "expected type ivec3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::ivec3 vec;
        for (auto i = 1; i < 4; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type int at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asInt();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::ivec3>
            {*static_cast<typed_property<glm::ivec3>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_ivec4(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type ivec4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 5) {
            log(LOG_FATAL, "expected size 4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "i") {
            log(LOG_FATAL, "expected type ivec4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::ivec4 vec;
        for (auto i = 1; i < 5; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type int at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asInt();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::ivec4>
            {*static_cast<typed_property<glm::ivec4>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_float(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::realValue) {
            log(LOG_FATAL, "expected type float at property " + property->name() + " : " + wrapped_value.asString());
        }
        return std::unique_ptr<abstract_value>(new typed_value<float>{*static_cast<typed_property<float>*>(property),
            wrapped_value.asFloat()});
    }

    std::unique_ptr<abstract_value> assign_vec2(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type vec2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 3) {
            log(LOG_FATAL, "expected size 2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "f") {
            log(LOG_FATAL, "expected type vec2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::vec2 vec;
        for (auto i = 1; i < 3; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type float at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asInt();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::vec2>
            {*static_cast<typed_property<glm::vec2>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_vec3(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type vec3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 4) {
            log(LOG_FATAL, "expected size 3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "f") {
            log(LOG_FATAL, "expected type vec3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::vec3 vec;
        for (auto i = 1; i < 4; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type float at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asInt();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::vec3>
            {*static_cast<typed_property<glm::vec3>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_vec4(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type vec4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 5) {
            log(LOG_FATAL, "expected size 4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "f") {
            log(LOG_FATAL, "expected type vec4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::vec4 vec;
        for (auto i = 1; i < 5; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type float at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asInt();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::vec4>
            {*static_cast<typed_property<glm::vec4>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_quat(abstract_property* property, const Json::Value& wrapped_value) {
        return nullptr;
    }

    std::unique_ptr<abstract_value> assign_string(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::stringValue) {
            log(LOG_ERROR, "expected type string at property " + property->name() + " : " + wrapped_value.asString());
            return nullptr;
        }
        return std::unique_ptr<abstract_value>(new typed_value<std::string>
            {*static_cast<typed_property<std::string>*>(property), wrapped_value.asString()});
    }
}<commit_msg>add missing quaternion conversion to assign<commit_after>#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>

#include <zombye/ecs/typed_value.hpp>
#include <zombye/utils/assign.hpp>
#include <zombye/utils/logger.hpp>

namespace zombye {
    std::unique_ptr<zombye::value_pack> assign_values(const std::string& name, const Json::Value& object,
    const rtti::property_list& properties) {
        auto value_pack = new zombye::value_pack(name);
        for (auto& p : properties) {
            auto wrapped_value = object[p->name()];
            auto value = assign_value(p.get(), wrapped_value);
            if (!value) {
                log(LOG_FATAL, "type of property " + p->name() + " at " + name + " is unknown");
            }
            value_pack->emplace_back(std::move(value));
        }
        return std::unique_ptr<zombye::value_pack>{value_pack};
    }

    std::unique_ptr<abstract_value> assign_value(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = property->type();
        switch (type) {
            case property_types::BOOL:
                return assign_bool(property, wrapped_value);
            case property_types::INT:
                return assign_int(property, wrapped_value);
            case property_types::IVEC2:
                return assign_ivec2(property, wrapped_value);
            case property_types::IVEC3:
                return assign_ivec3(property, wrapped_value);
            case property_types::IVEC4:
                return assign_ivec4(property, wrapped_value);
            case property_types::FLOAT:
                return assign_float(property, wrapped_value);
            case property_types::VEC2:
                return assign_vec2(property, wrapped_value);
            case property_types::VEC3:
                return assign_vec3(property, wrapped_value);
            case property_types::VEC4:
                return assign_vec4(property, wrapped_value);
            case property_types::QUAT:
                return assign_quat(property, wrapped_value);
            case property_types::STRING:
                return assign_string(property, wrapped_value);
            default:
                return nullptr;
        }
    }

    std::unique_ptr<abstract_value> assign_bool(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::booleanValue) {
            log(LOG_FATAL, "expected type bool at property " + property->name() + " : " + wrapped_value.asString());
        }
        return std::unique_ptr<abstract_value>(new typed_value<bool>{*static_cast<typed_property<bool>*>(property),
            wrapped_value.asBool()});
    }

    std::unique_ptr<abstract_value> assign_int(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::intValue) {
            log(LOG_FATAL, "expected type int at property " + property->name() + " : " + wrapped_value.asString());
        }
        return std::unique_ptr<abstract_value>(new typed_value<int>{*static_cast<typed_property<int>*>(property),
            wrapped_value.asInt()});
    }

    std::unique_ptr<abstract_value> assign_ivec2(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type ivec2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 3) {
            log(LOG_FATAL, "expected size 2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "i") {
            log(LOG_FATAL, "expected type ivec2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::ivec2 vec;
        for (auto i = 1; i < 3; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type int at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asInt();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::ivec2>
            {*static_cast<typed_property<glm::ivec2>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_ivec3(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type ivec3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 4) {
            log(LOG_FATAL, "expected size 3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "i") {
            log(LOG_FATAL, "expected type ivec3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::ivec3 vec;
        for (auto i = 1; i < 4; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type int at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asInt();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::ivec3>
            {*static_cast<typed_property<glm::ivec3>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_ivec4(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type ivec4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 5) {
            log(LOG_FATAL, "expected size 4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "i") {
            log(LOG_FATAL, "expected type ivec4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::ivec4 vec;
        for (auto i = 1; i < 5; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type int at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asInt();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::ivec4>
            {*static_cast<typed_property<glm::ivec4>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_float(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::realValue) {
            log(LOG_FATAL, "expected type float at property " + property->name() + " : " + wrapped_value.asString());
        }
        return std::unique_ptr<abstract_value>(new typed_value<float>{*static_cast<typed_property<float>*>(property),
            wrapped_value.asFloat()});
    }

    std::unique_ptr<abstract_value> assign_vec2(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type vec2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 3) {
            log(LOG_FATAL, "expected size 2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "f") {
            log(LOG_FATAL, "expected type vec2 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::vec2 vec;
        for (auto i = 1; i < 3; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type float at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asFloat();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::vec2>
            {*static_cast<typed_property<glm::vec2>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_vec3(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type vec3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 4) {
            log(LOG_FATAL, "expected size 3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "f") {
            log(LOG_FATAL, "expected type vec3 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::vec3 vec;
        for (auto i = 1; i < 4; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type float at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asFloat();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::vec3>
            {*static_cast<typed_property<glm::vec3>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_vec4(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type vec4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 5) {
            log(LOG_FATAL, "expected size 4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "f") {
            log(LOG_FATAL, "expected type vec4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::vec4 vec;
        for (auto i = 1; i < 5; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type float at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asFloat();
        }
        return std::unique_ptr<abstract_value>(new typed_value<glm::vec4>
            {*static_cast<typed_property<glm::vec4>*>(property), vec});
    }

    std::unique_ptr<abstract_value> assign_quat(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::arrayValue) {
            log(LOG_FATAL, "expected type quat at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value.size() != 5) {
            log(LOG_FATAL, "expected size 4 at property " + property->name() + " : " + wrapped_value.asString());
        }
        if (wrapped_value[0].asString() != "q") {
            log(LOG_FATAL, "expected type quat at property " + property->name() + " : " + wrapped_value.asString());
        }
        glm::vec4 vec;
        for (auto i = 1; i < 5; ++i) {
            auto& elem = wrapped_value[i];
            if (elem.type() != Json::ValueType::intValue) {
                log(LOG_FATAL, "expected element type float at property " + property->name() + " : "
                    + wrapped_value.asString());
            }
            vec[i - 1] = elem.asFloat();
        }
        glm::quat quat(vec[0], glm::vec3{vec[1], vec[2], vec[3]});
        return std::unique_ptr<abstract_value>(new typed_value<glm::quat>
            {*static_cast<typed_property<glm::quat>*>(property), quat});
    }

    std::unique_ptr<abstract_value> assign_string(abstract_property* property, const Json::Value& wrapped_value) {
        auto type = wrapped_value.type();
        if (type != Json::ValueType::stringValue) {
            log(LOG_ERROR, "expected type string at property " + property->name() + " : " + wrapped_value.asString());
            return nullptr;
        }
        return std::unique_ptr<abstract_value>(new typed_value<std::string>
            {*static_cast<typed_property<std::string>*>(property), wrapped_value.asString()});
    }
}<|endoftext|>