<commit_before>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "SoundData.h"
#include "core/Engine.h"
#include "utils/Utils.h"

namespace ouzel
{
    namespace audio
    {
        SoundData::SoundData()
        {
        }

        SoundData::~SoundData()
        {
        }

        void SoundData::free()
        {
            data.clear();

            ready = false;
        }

        bool SoundData::initFromFile(const std::string& newFilename)
        {
            filename = newFilename;

            std::vector<uint8_t> newData;
            if (!sharedEngine->getFileSystem()->loadFile(newFilename, newData))
            {
                return false;
            }

            return initFromBuffer(newData);
        }

        bool SoundData::initFromBuffer(const std::vector<uint8_t>& newData)
        {
            ready = false;

            uint32_t offset = 0;

            if (newData.size() < 16) // RIFF + size + WAVE
            {
                log("Failed to load sound file. File too small");
                return false;
            }

            if (newData[offset + 0] != 'R' ||
                newData[offset + 1] != 'I' ||
                newData[offset + 2] != 'F' ||
                newData[offset + 3] != 'F')
            {
                log("Failed to load sound file. Not a RIFF format.");
                return false;
            }

            offset += 4;

            uint32_t length = readUInt32Little(newData.data() + offset);

            offset += 4;

            if (newData.size() != length + 8)
            {
                log("Failed to load sound file. Size mismatch.");
            }

            if (newData[offset + 0] != 'W' ||
                newData[offset + 1] != 'A' ||
                newData[offset + 2] != 'V' ||
                newData[offset + 3] != 'E')
            {
                log("Failed to load sound file. Not a WAVE file.");
                return false;
            }

            offset += 4;

            bool foundChunkFound = false;
            bool dataChunkFound = false;

            for (; offset < newData.size();)
            {
                if (newData.size() < offset + 8)
                {
                    log("Failed to load sound file. Not enough data to read chunk.");
                    return false;
                }

                uint8_t chunkHeader[4];
                chunkHeader[0] = newData[offset + 0];
                chunkHeader[1] = newData[offset + 1];
                chunkHeader[2] = newData[offset + 2];
                chunkHeader[3] = newData[offset + 3];

                offset += 4;

                uint32_t chunkSize = readUInt32Little(newData.data() + offset);
                offset += 4;

                if (newData.size() < offset + chunkSize)
                {
                    log("Failed to load sound file. Not enough data to read chunk.");
                    return false;
                }

                if (chunkHeader[0] == 'f' && chunkHeader[1] == 'm' && chunkHeader[2] == 't' && chunkHeader[3] == ' ')
                {
                    if (chunkSize < 16)
                    {
                        log("Failed to load sound file. Not enough data to read chunk.");
                        return false;
                    }

                    uint32_t i = offset;

                    formatTag = readUInt16Little(newData.data() + i);
                    i += 2;

                    if (formatTag != 1)
                    {
                        log("Failed to load sound file. Bad format tag.");
                        return false;
                    }

                    channels = readUInt16Little(newData.data() + i);
                    i += 2;

                    samplesPerSecond = readUInt32Little(newData.data() + i);
                    i += 4;

                    averageBytesPerSecond = readUInt32Little(newData.data() + i);
                    i += 4;

                    blockAlign = readUInt16Little(newData.data() + i);
                    i += 2;

                    bitsPerSample = readUInt16Little(newData.data() + i);
                    i += 2;

                    foundChunkFound = true;
                }
                else if (chunkHeader[0] == 'd' && chunkHeader[1] == 'a' && chunkHeader[2] == 't' && chunkHeader[3] == 'a')
                {
                    data.assign(newData.begin() + static_cast<int>(offset), newData.begin() + static_cast<int>(offset + chunkSize));

                    dataChunkFound = true;
                }

                offset += ((chunkSize + 1) & 0xFFFFFFFE);
            }

            if (!foundChunkFound)
            {
                log("Failed to load sound file. Failed to find a format chunk.");
                return false;
            }

            if (!dataChunkFound)
            {
                log("Failed to load sound file. Failed to find a data chunk.");
                return false;
            }

            ready = true;

            return true;
        }
    } // namespace audio
} // namespace ouzel
<commit_msg>Fix the typo in formatChunkFound<commit_after>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include "SoundData.h"
#include "core/Engine.h"
#include "utils/Utils.h"

namespace ouzel
{
    namespace audio
    {
        SoundData::SoundData()
        {
        }

        SoundData::~SoundData()
        {
        }

        void SoundData::free()
        {
            data.clear();

            ready = false;
        }

        bool SoundData::initFromFile(const std::string& newFilename)
        {
            filename = newFilename;

            std::vector<uint8_t> newData;
            if (!sharedEngine->getFileSystem()->loadFile(newFilename, newData))
            {
                return false;
            }

            return initFromBuffer(newData);
        }

        bool SoundData::initFromBuffer(const std::vector<uint8_t>& newData)
        {
            ready = false;

            uint32_t offset = 0;

            if (newData.size() < 16) // RIFF + size + WAVE
            {
                log("Failed to load sound file. File too small");
                return false;
            }

            if (newData[offset + 0] != 'R' ||
                newData[offset + 1] != 'I' ||
                newData[offset + 2] != 'F' ||
                newData[offset + 3] != 'F')
            {
                log("Failed to load sound file. Not a RIFF format.");
                return false;
            }

            offset += 4;

            uint32_t length = readUInt32Little(newData.data() + offset);

            offset += 4;

            if (newData.size() != length + 8)
            {
                log("Failed to load sound file. Size mismatch.");
            }

            if (newData[offset + 0] != 'W' ||
                newData[offset + 1] != 'A' ||
                newData[offset + 2] != 'V' ||
                newData[offset + 3] != 'E')
            {
                log("Failed to load sound file. Not a WAVE file.");
                return false;
            }

            offset += 4;

            bool formatChunkFound = false;
            bool dataChunkFound = false;

            for (; offset < newData.size();)
            {
                if (newData.size() < offset + 8)
                {
                    log("Failed to load sound file. Not enough data to read chunk.");
                    return false;
                }

                uint8_t chunkHeader[4];
                chunkHeader[0] = newData[offset + 0];
                chunkHeader[1] = newData[offset + 1];
                chunkHeader[2] = newData[offset + 2];
                chunkHeader[3] = newData[offset + 3];

                offset += 4;

                uint32_t chunkSize = readUInt32Little(newData.data() + offset);
                offset += 4;

                if (newData.size() < offset + chunkSize)
                {
                    log("Failed to load sound file. Not enough data to read chunk.");
                    return false;
                }

                if (chunkHeader[0] == 'f' && chunkHeader[1] == 'm' && chunkHeader[2] == 't' && chunkHeader[3] == ' ')
                {
                    if (chunkSize < 16)
                    {
                        log("Failed to load sound file. Not enough data to read chunk.");
                        return false;
                    }

                    uint32_t i = offset;

                    formatTag = readUInt16Little(newData.data() + i);
                    i += 2;

                    if (formatTag != 1)
                    {
                        log("Failed to load sound file. Bad format tag.");
                        return false;
                    }

                    channels = readUInt16Little(newData.data() + i);
                    i += 2;

                    samplesPerSecond = readUInt32Little(newData.data() + i);
                    i += 4;

                    averageBytesPerSecond = readUInt32Little(newData.data() + i);
                    i += 4;

                    blockAlign = readUInt16Little(newData.data() + i);
                    i += 2;

                    bitsPerSample = readUInt16Little(newData.data() + i);
                    i += 2;

                    formatChunkFound = true;
                }
                else if (chunkHeader[0] == 'd' && chunkHeader[1] == 'a' && chunkHeader[2] == 't' && chunkHeader[3] == 'a')
                {
                    data.assign(newData.begin() + static_cast<int>(offset), newData.begin() + static_cast<int>(offset + chunkSize));

                    dataChunkFound = true;
                }

                offset += ((chunkSize + 1) & 0xFFFFFFFE);
            }

            if (!formatChunkFound)
            {
                log("Failed to load sound file. Failed to find a format chunk.");
                return false;
            }

            if (!dataChunkFound)
            {
                log("Failed to load sound file. Failed to find a data chunk.");
                return false;
            }

            ready = true;

            return true;
        }
    } // namespace audio
} // namespace ouzel
<|endoftext|>


<commit_before>/*
Copyright (c) 2015-2021 Alternative Games Ltd / Turo Lamminen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifdef RENDERER_NULL

#include "RendererInternal.h"
#include "utils/Utils.h"

namespace renderer {

RendererImpl::RendererImpl(const RendererDesc &desc)
: RendererBase(desc)
{
	SDL_Init(SDL_INIT_EVENTS);

	swapchainFormat = Format::sRGBA8;

	currentRefreshRate = 60;
	maxRefreshRate     = 60;

	recreateRingBuffer(desc.ephemeralRingBufSize);

	frames.resize(desc.swapchain.numFrames);
}

void RendererImpl::recreateRingBuffer(unsigned int newSize) {
	assert(newSize > 0);

	ringBufPtr  = 0;
	ringBufSize = newSize;
	ringBuffer.resize(newSize, 0);
	LOG_TODO("use valgrind to make sure we only write to intended parts of ring buffer");
}

RendererImpl::~RendererImpl() {
	waitForDeviceIdle();

	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		assert(!f.outstanding);
		deleteFrameInternal(f);
	}
	frames.clear();

	SDL_Quit();
}

bool Renderer::isRenderTargetFormatSupported(Format /* format */) const {
	LOG_TODO("actually check it...");
	return true;
}

BufferHandle Renderer::createBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	Buffer buffer;
	buffer.ringBufferAlloc = false;
	buffer.beginOffs       = 0;
	buffer.size            = size;

	LOG_TODO("store contents into buffer");

	return impl->buffers.add(std::move(buffer));
}

BufferHandle Renderer::createEphemeralBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	unsigned int beginPtr = impl->ringBufferAllocate(size, 256);

	LOG_TODO("use valgrind to enforce we only write to intended parts of ring buffer");
	memcpy(&impl->ringBuffer[beginPtr], contents, size);

	auto result    = impl->buffers.add();
	Buffer &buffer = result.first;
	buffer.ringBufferAlloc = true;
	buffer.beginOffs       = beginPtr;
	buffer.size            = size;

	impl->frames.at(impl->currentFrameIdx).ephemeralBuffers.push_back(result.second);

	return result.second;
}

FramebufferHandle Renderer::createFramebuffer(const FramebufferDesc &desc) {
	auto result = impl->framebuffers.add();
	auto &fb = result.first;
	fb.renderPass = desc.renderPass_;

	return result.second;
}

RenderPassHandle Renderer::createRenderPass(const RenderPassDesc &desc) {
	RenderPass rp;
	rp.desc     = desc;

	return impl->renderpasses.add(std::move(rp));
}

PipelineHandle Renderer::createPipeline(const PipelineDesc &desc) {
	auto result = impl->pipelines.add();
	auto &pipeline = result.first;
	pipeline.desc = desc;
	return result.second;
}

RenderTargetHandle Renderer::createRenderTarget(const RenderTargetDesc &desc) {
	assert(desc.width_  > 0);
	assert(desc.height_ > 0);
	assert(desc.format_ != +Format::Invalid);

	RenderTarget rendertarget;
	rendertarget.desc = desc;
	return impl->rendertargets.add(std::move(rendertarget));
}

SamplerHandle Renderer::createSampler(const SamplerDesc &desc) {
	Sampler sampler;
	LOG_TODO("check desc");
	sampler.desc = desc;

	return impl->samplers.add(std::move(sampler));
}

VertexShaderHandle RendererImpl::createVertexShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string vertexShaderName   = name + ".vert";

	auto result_ = vertexShaders.add();
	auto &v = result_.first;
	v.name      = vertexShaderName;

	return result_.second;
}

FragmentShaderHandle RendererImpl::createFragmentShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string fragmentShaderName = name + ".frag";

	auto result_ = fragmentShaders.add();
	auto &f = result_.first;
	f.name      = fragmentShaderName;

	return result_.second;
}

TextureHandle Renderer::createTexture(const TextureDesc &desc) {
	assert(desc.width_   > 0);
	assert(desc.height_  > 0);
	assert(desc.numMips_ > 0);

	LOG_TODO("check data");

	Texture texture;
	LOG_TODO("check desc");
	texture.desc = desc;

	return impl->textures.add(std::move(texture));
}

DSLayoutHandle Renderer::createDescriptorSetLayout(const DescriptorLayout *layout) {
	DescriptorSetLayout dsLayout;

	while (layout->type != +DescriptorType::End) {
		dsLayout.layout.push_back(*layout);
		layout++;
	}
	assert(layout->offset == 0);

	return impl->dsLayouts.add(std::move(dsLayout));
}

TextureHandle Renderer::getRenderTargetView(RenderTargetHandle /* handle */, Format /* f */) {
	TextureHandle handle;

	return handle;
}

void Renderer::deleteBuffer(BufferHandle & /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle & /*  */) {
}

void Renderer::deletePipeline(PipelineHandle & /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle & /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle & /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle & /* handle */) {
}

void Renderer::deleteTexture(TextureHandle & /* handle */) {
}

void Renderer::deleteBuffer(BufferHandle && /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle && /*  */) {
}

void Renderer::deletePipeline(PipelineHandle && /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle && /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle && /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle && /* handle */) {
}

void Renderer::deleteTexture(TextureHandle && /* handle */) {
}

void Renderer::setSwapchainDesc(const SwapchainDesc &desc) {
	impl->swapchainDesc  = desc;
}

glm::uvec2 Renderer::getDrawableSize() const {
	return glm::uvec2(impl->swapchainDesc.width, impl->swapchainDesc.height);
}

MemoryStats Renderer::getMemStats() const {
	MemoryStats stats;
	return stats;
}

void RendererImpl::waitForDeviceIdle() {
	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		if (f.outstanding) {
			// try to wait
			waitForFrame(i);
			assert(!f.outstanding);
		}
	}
}

void Renderer::beginFrame() {
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::beginRenderPassSwapchain(RenderPassHandle rpHandle) {
	assert(rpHandle);
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	assert(!impl->renderingToSwapchain);
	impl->renderingToSwapchain = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::presentFrame() {
	assert(impl->inFrame);
	impl->inFrame = false;

	auto &frame = impl->frames.at(impl->currentFrameIdx);

	frame.usedRingBufPtr = impl->ringBufPtr;
	frame.outstanding    = true;
	frame.lastFrameNum   = impl->frameNum;

	impl->frameNum++;
}

void RendererImpl::waitForFrame(unsigned int frameIdx) {
	assert(frameIdx < frames.size());

	Frame &frame = frames.at(frameIdx);
	assert(frame.outstanding);

	for (auto handle : frame.ephemeralBuffers) {
		Buffer &buffer = buffers.get(handle);
		if (buffer.ringBufferAlloc) {
			buffer.ringBufferAlloc = false;
		}

		assert(buffer.size   >  0);
		buffer.size = 0;
		buffer.beginOffs = 0;

		buffers.remove(handle);
	}
	frame.ephemeralBuffers.clear();
	frame.outstanding    = false;
	lastSyncedFrame      = std::max(lastSyncedFrame, frame.lastFrameNum);
	lastSyncedRingBufPtr = std::max(lastSyncedRingBufPtr, frame.usedRingBufPtr);
}

void RendererImpl::deleteFrameInternal(Frame &f) {
	assert(!f.outstanding);
}

void Renderer::beginRenderPass(RenderPassHandle rpHandle, FramebufferHandle fbHandle) {
	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);

	impl->inRenderPass  = true;
	impl->validPipeline = false;

	assert(fbHandle);
	const auto &fb = impl->framebuffers.get(fbHandle);

	// make sure renderpass and framebuffer match
	assert(fb.renderPass == rpHandle);
}

void Renderer::endRenderPass() {
	assert(impl->inFrame);
	assert(impl->inRenderPass);
	impl->inRenderPass = false;
	impl->renderingToSwapchain = false;
}

void Renderer::layoutTransition(RenderTargetHandle image, Layout src, Layout dest) {
	assert(image);
	assert(dest != +Layout::Undefined);
	assert(src != dest);
}

void Renderer::bindPipeline(PipelineHandle pipeline) {
	assert(impl->inFrame);
	assert(pipeline);
	assert(impl->inRenderPass);
	assert(impl->pipelineDrawn);
	impl->pipelineDrawn = false;
	impl->validPipeline = true;
	impl->scissorSet    = false;

	impl->currentPipeline = impl->pipelines.get(pipeline).desc;
}

void Renderer::bindIndexBuffer(BufferHandle /* buffer */, bool /* bit16 */ ) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindVertexBuffer(unsigned int /* binding */, BufferHandle /* buffer */) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindDescriptorSet(unsigned int /* index */, DSLayoutHandle /* layout */, const void * /* data_ */) {
	assert(impl->validPipeline);
}

void Renderer::setViewport(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->inFrame);
}

void Renderer::setScissorRect(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->validPipeline);
	assert(impl->currentPipeline.scissorTest_);
	impl->scissorSet = true;
}

void Renderer::blit(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAA(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAAToSwapchain(RenderTargetHandle source, Layout finalLayout) {
	assert(source);
	assert(finalLayout != +Layout::Undefined);

	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);
}

void Renderer::draw(unsigned int /* firstVertex */, unsigned int vertexCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedInstanced(unsigned int vertexCount, unsigned int instanceCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(instanceCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedOffset(unsigned int vertexCount, unsigned int /* firstIndex */, unsigned int /* minIndex */, unsigned int /* maxIndex */) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

} // namespace renderer

#endif //  RENDERER_NULL
<commit_msg>Refactor null Renderer::createFramebuffer<commit_after>/*
Copyright (c) 2015-2021 Alternative Games Ltd / Turo Lamminen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifdef RENDERER_NULL

#include "RendererInternal.h"
#include "utils/Utils.h"

namespace renderer {

RendererImpl::RendererImpl(const RendererDesc &desc)
: RendererBase(desc)
{
	SDL_Init(SDL_INIT_EVENTS);

	swapchainFormat = Format::sRGBA8;

	currentRefreshRate = 60;
	maxRefreshRate     = 60;

	recreateRingBuffer(desc.ephemeralRingBufSize);

	frames.resize(desc.swapchain.numFrames);
}

void RendererImpl::recreateRingBuffer(unsigned int newSize) {
	assert(newSize > 0);

	ringBufPtr  = 0;
	ringBufSize = newSize;
	ringBuffer.resize(newSize, 0);
	LOG_TODO("use valgrind to make sure we only write to intended parts of ring buffer");
}

RendererImpl::~RendererImpl() {
	waitForDeviceIdle();

	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		assert(!f.outstanding);
		deleteFrameInternal(f);
	}
	frames.clear();

	SDL_Quit();
}

bool Renderer::isRenderTargetFormatSupported(Format /* format */) const {
	LOG_TODO("actually check it...");
	return true;
}

BufferHandle Renderer::createBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	Buffer buffer;
	buffer.ringBufferAlloc = false;
	buffer.beginOffs       = 0;
	buffer.size            = size;

	LOG_TODO("store contents into buffer");

	return impl->buffers.add(std::move(buffer));
}

BufferHandle Renderer::createEphemeralBuffer(BufferType /* type */, uint32_t size, const void *contents) {
	assert(size != 0);
	assert(contents != nullptr);

	unsigned int beginPtr = impl->ringBufferAllocate(size, 256);

	LOG_TODO("use valgrind to enforce we only write to intended parts of ring buffer");
	memcpy(&impl->ringBuffer[beginPtr], contents, size);

	auto result    = impl->buffers.add();
	Buffer &buffer = result.first;
	buffer.ringBufferAlloc = true;
	buffer.beginOffs       = beginPtr;
	buffer.size            = size;

	impl->frames.at(impl->currentFrameIdx).ephemeralBuffers.push_back(result.second);

	return result.second;
}

FramebufferHandle Renderer::createFramebuffer(const FramebufferDesc &desc) {
	Framebuffer fb;
	fb.renderPass = desc.renderPass_;

	return impl->framebuffers.add(std::move(fb));
}

RenderPassHandle Renderer::createRenderPass(const RenderPassDesc &desc) {
	RenderPass rp;
	rp.desc     = desc;

	return impl->renderpasses.add(std::move(rp));
}

PipelineHandle Renderer::createPipeline(const PipelineDesc &desc) {
	auto result = impl->pipelines.add();
	auto &pipeline = result.first;
	pipeline.desc = desc;
	return result.second;
}

RenderTargetHandle Renderer::createRenderTarget(const RenderTargetDesc &desc) {
	assert(desc.width_  > 0);
	assert(desc.height_ > 0);
	assert(desc.format_ != +Format::Invalid);

	RenderTarget rendertarget;
	rendertarget.desc = desc;
	return impl->rendertargets.add(std::move(rendertarget));
}

SamplerHandle Renderer::createSampler(const SamplerDesc &desc) {
	Sampler sampler;
	LOG_TODO("check desc");
	sampler.desc = desc;

	return impl->samplers.add(std::move(sampler));
}

VertexShaderHandle RendererImpl::createVertexShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string vertexShaderName   = name + ".vert";

	auto result_ = vertexShaders.add();
	auto &v = result_.first;
	v.name      = vertexShaderName;

	return result_.second;
}

FragmentShaderHandle RendererImpl::createFragmentShader(const std::string &name, const ShaderMacros & /* macros */) {
	std::string fragmentShaderName = name + ".frag";

	auto result_ = fragmentShaders.add();
	auto &f = result_.first;
	f.name      = fragmentShaderName;

	return result_.second;
}

TextureHandle Renderer::createTexture(const TextureDesc &desc) {
	assert(desc.width_   > 0);
	assert(desc.height_  > 0);
	assert(desc.numMips_ > 0);

	LOG_TODO("check data");

	Texture texture;
	LOG_TODO("check desc");
	texture.desc = desc;

	return impl->textures.add(std::move(texture));
}

DSLayoutHandle Renderer::createDescriptorSetLayout(const DescriptorLayout *layout) {
	DescriptorSetLayout dsLayout;

	while (layout->type != +DescriptorType::End) {
		dsLayout.layout.push_back(*layout);
		layout++;
	}
	assert(layout->offset == 0);

	return impl->dsLayouts.add(std::move(dsLayout));
}

TextureHandle Renderer::getRenderTargetView(RenderTargetHandle /* handle */, Format /* f */) {
	TextureHandle handle;

	return handle;
}

void Renderer::deleteBuffer(BufferHandle & /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle & /*  */) {
}

void Renderer::deletePipeline(PipelineHandle & /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle & /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle & /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle & /* handle */) {
}

void Renderer::deleteTexture(TextureHandle & /* handle */) {
}

void Renderer::deleteBuffer(BufferHandle && /* handle */) {
}

void Renderer::deleteFramebuffer(FramebufferHandle && /*  */) {
}

void Renderer::deletePipeline(PipelineHandle && /* handle */) {
}

void Renderer::deleteRenderPass(RenderPassHandle && /* handle */) {
}

void Renderer::deleteRenderTarget(RenderTargetHandle && /* handle */) {
}

void Renderer::deleteSampler(SamplerHandle && /* handle */) {
}

void Renderer::deleteTexture(TextureHandle && /* handle */) {
}

void Renderer::setSwapchainDesc(const SwapchainDesc &desc) {
	impl->swapchainDesc  = desc;
}

glm::uvec2 Renderer::getDrawableSize() const {
	return glm::uvec2(impl->swapchainDesc.width, impl->swapchainDesc.height);
}

MemoryStats Renderer::getMemStats() const {
	MemoryStats stats;
	return stats;
}

void RendererImpl::waitForDeviceIdle() {
	for (unsigned int i = 0; i < frames.size(); i++) {
		auto &f = frames.at(i);
		if (f.outstanding) {
			// try to wait
			waitForFrame(i);
			assert(!f.outstanding);
		}
	}
}

void Renderer::beginFrame() {
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::beginRenderPassSwapchain(RenderPassHandle rpHandle) {
	assert(rpHandle);
	assert(!impl->inFrame);
	impl->inFrame       = true;
	impl->inRenderPass  = false;
	impl->validPipeline = false;
	impl->pipelineDrawn = true;

	assert(!impl->renderingToSwapchain);
	impl->renderingToSwapchain = true;

	impl->currentFrameIdx        = impl->frameNum % impl->frames.size();
	assert(impl->currentFrameIdx < impl->frames.size());
	auto &frame                  = impl->frames.at(impl->currentFrameIdx);

	// frames are a ringbuffer
	// if the frame we want to reuse is still pending on the GPU, wait for it
	if (frame.outstanding) {
		impl->waitForFrame(impl->currentFrameIdx);
	}
	assert(!frame.outstanding);
}

void Renderer::presentFrame() {
	assert(impl->inFrame);
	impl->inFrame = false;

	auto &frame = impl->frames.at(impl->currentFrameIdx);

	frame.usedRingBufPtr = impl->ringBufPtr;
	frame.outstanding    = true;
	frame.lastFrameNum   = impl->frameNum;

	impl->frameNum++;
}

void RendererImpl::waitForFrame(unsigned int frameIdx) {
	assert(frameIdx < frames.size());

	Frame &frame = frames.at(frameIdx);
	assert(frame.outstanding);

	for (auto handle : frame.ephemeralBuffers) {
		Buffer &buffer = buffers.get(handle);
		if (buffer.ringBufferAlloc) {
			buffer.ringBufferAlloc = false;
		}

		assert(buffer.size   >  0);
		buffer.size = 0;
		buffer.beginOffs = 0;

		buffers.remove(handle);
	}
	frame.ephemeralBuffers.clear();
	frame.outstanding    = false;
	lastSyncedFrame      = std::max(lastSyncedFrame, frame.lastFrameNum);
	lastSyncedRingBufPtr = std::max(lastSyncedRingBufPtr, frame.usedRingBufPtr);
}

void RendererImpl::deleteFrameInternal(Frame &f) {
	assert(!f.outstanding);
}

void Renderer::beginRenderPass(RenderPassHandle rpHandle, FramebufferHandle fbHandle) {
	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);

	impl->inRenderPass  = true;
	impl->validPipeline = false;

	assert(fbHandle);
	const auto &fb = impl->framebuffers.get(fbHandle);

	// make sure renderpass and framebuffer match
	assert(fb.renderPass == rpHandle);
}

void Renderer::endRenderPass() {
	assert(impl->inFrame);
	assert(impl->inRenderPass);
	impl->inRenderPass = false;
	impl->renderingToSwapchain = false;
}

void Renderer::layoutTransition(RenderTargetHandle image, Layout src, Layout dest) {
	assert(image);
	assert(dest != +Layout::Undefined);
	assert(src != dest);
}

void Renderer::bindPipeline(PipelineHandle pipeline) {
	assert(impl->inFrame);
	assert(pipeline);
	assert(impl->inRenderPass);
	assert(impl->pipelineDrawn);
	impl->pipelineDrawn = false;
	impl->validPipeline = true;
	impl->scissorSet    = false;

	impl->currentPipeline = impl->pipelines.get(pipeline).desc;
}

void Renderer::bindIndexBuffer(BufferHandle /* buffer */, bool /* bit16 */ ) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindVertexBuffer(unsigned int /* binding */, BufferHandle /* buffer */) {
	assert(impl->inFrame);
	assert(impl->validPipeline);
}

void Renderer::bindDescriptorSet(unsigned int /* index */, DSLayoutHandle /* layout */, const void * /* data_ */) {
	assert(impl->validPipeline);
}

void Renderer::setViewport(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->inFrame);
}

void Renderer::setScissorRect(unsigned int /* x */, unsigned int /* y */, unsigned int /* width */, unsigned int /* height */) {
	assert(impl->validPipeline);
	assert(impl->currentPipeline.scissorTest_);
	impl->scissorSet = true;
}

void Renderer::blit(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAA(RenderTargetHandle source, RenderTargetHandle target) {
	assert(source);
	assert(target);

	assert(!impl->inRenderPass);
}

void Renderer::resolveMSAAToSwapchain(RenderTargetHandle source, Layout finalLayout) {
	assert(source);
	assert(finalLayout != +Layout::Undefined);

	assert(impl->inFrame);
	assert(!impl->inRenderPass);
	assert(!impl->renderingToSwapchain);
}

void Renderer::draw(unsigned int /* firstVertex */, unsigned int vertexCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedInstanced(unsigned int vertexCount, unsigned int instanceCount) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(instanceCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

void Renderer::drawIndexedOffset(unsigned int vertexCount, unsigned int /* firstIndex */, unsigned int /* minIndex */, unsigned int /* maxIndex */) {
	assert(impl->inRenderPass);
	assert(impl->validPipeline);
	assert(vertexCount > 0);
	assert(!impl->currentPipeline.scissorTest_ || impl->scissorSet);
	impl->pipelineDrawn = true;
}

} // namespace renderer

#endif //  RENDERER_NULL
<|endoftext|>


<commit_before>#include "ompl/extension/samplingbased/kinematic/extension/rrt/RRT.h"

bool ompl::RRT::solve(double solveTime)
{
    SpaceInformationKinematic_t                          si = dynamic_cast<SpaceInformationKinematic_t>(m_si);
    SpaceInformationKinematic::GoalRegionKinematic_t goal_r = dynamic_cast<SpaceInformationKinematic::GoalRegionKinematic_t>(si->getGoal());
    SpaceInformationKinematic::GoalStateKinematic_t  goal_s = dynamic_cast<SpaceInformationKinematic::GoalStateKinematic_t>(si->getGoal());
    unsigned int                                        dim = si->getStateDimension();

    printf("Received motion planning request for %f seconds.\n", solveTime);
    si->printSettings();

    ros::Time endTime = ros::Time::now() +  ros::Duration(solveTime);

    for (unsigned int i = 0 ; i < m_si->getStartStateCount() ; ++i)
    {
	Motion_t motion = new Motion(dim);
	si->copyState(motion->state, dynamic_cast<SpaceInformationKinematic::StateKinematic_t>(si->getStartState(i)));
	if (si->isValid(motion->state))
	    m_nn.add(motion);
	else
	{
	    fprintf(stderr, "Initial state is in collision!\n");
	    delete motion;
	}
    }

    if (m_nn.size() == 0)
    {
	fprintf(stderr, "There are no valid initial states!\n");
	return false;
    }

    std::vector<double> range(dim);
    for (unsigned int i = 0 ; i < dim ; ++i)
	range[i] = m_rho * si->getStateComponent(i).maxValue - si->getStateComponent(i).minValue;

    Motion_t                                    solution = NULL;
    Motion_t                                    rmotion  = new Motion(dim);
    SpaceInformationKinematic::StateKinematic_t rstate   = rmotion->state;
    SpaceInformationKinematic::StateKinematic_t xstate   = new SpaceInformationKinematic::StateKinematic(dim);

    while (ros::Time::now() < endTime)
    {
	/* sample random state (with goal biasing) */
	if (goal_s && random_utils::uniform(&m_rngState, 0.0, 1.0) < m_goalBias)
	    si->copyState(rstate, goal_s->state);
	else
	    si->sample(rstate);

	/* find closest state in the tree */
	Motion_t nmotion = m_nn.nearest(rmotion);

	/* find state to add */
	for (unsigned int i = 0 ; i < dim ; ++i)
	{
	    double diff = rmotion->state->values[i] - nmotion->state->values[i];
	    xstate->values[i] = fabs(diff) < range[i] ? rmotion->state->values[i] : nmotion->state->values[i] + diff * m_rho;
	}

	/* create a motion */
	Motion_t motion = new Motion(dim);
	si->copyState(motion->state, xstate);
	motion->parent = nmotion;

	if (si->checkMotion(nmotion->state, motion->state))
	{
	    m_nn.add(motion);
	    if (goal_r->distanceGoal(motion->state) < goal_r->threshold)
	    {
		solution = motion;
		break;
	    }
	}
    }

    if (solution != NULL)
    {
	/* construct the solution path */
	std::vector<Motion_t> mpath;
	while (solution != NULL)
	{
	    mpath.push_back(solution);
	    solution = solution->parent;
	}

	/* set the solution path */
	SpaceInformationKinematic::PathKinematic_t path = new SpaceInformationKinematic::PathKinematic(m_si);
   	for (int i = mpath.size() - 1 ; i >= 0 ; --i)
	{
	    SpaceInformationKinematic::StateKinematic_t st = new SpaceInformationKinematic::StateKinematic(dim);
	    si->copyState(st, mpath[i]->state);
	    path->states.push_back(st);
	}
	goal_r->setSolutionPath(path);
    }

    delete xstate;
    delete rmotion;

    double tsolve = solveTime - (endTime - ros::Time::now()).to_double();
    printf("Solved in %f seconds\n", tsolve);

    return goal_r->isAchieved();
}
<commit_msg>printing more info<commit_after>#include "ompl/extension/samplingbased/kinematic/extension/rrt/RRT.h"

bool ompl::RRT::solve(double solveTime)
{
    SpaceInformationKinematic_t                          si = dynamic_cast<SpaceInformationKinematic_t>(m_si);
    SpaceInformationKinematic::GoalRegionKinematic_t goal_r = dynamic_cast<SpaceInformationKinematic::GoalRegionKinematic_t>(si->getGoal());
    SpaceInformationKinematic::GoalStateKinematic_t  goal_s = dynamic_cast<SpaceInformationKinematic::GoalStateKinematic_t>(si->getGoal());
    unsigned int                                        dim = si->getStateDimension();

    printf("Received motion planning request for %f seconds.\n", solveTime);
    si->printSettings();

    ros::Time endTime = ros::Time::now() +  ros::Duration(solveTime);

    for (unsigned int i = 0 ; i < m_si->getStartStateCount() ; ++i)
    {
	Motion_t motion = new Motion(dim);
	si->copyState(motion->state, dynamic_cast<SpaceInformationKinematic::StateKinematic_t>(si->getStartState(i)));
	if (si->isValid(motion->state))
	    m_nn.add(motion);
	else
	{
	    fprintf(stderr, "Initial state is in collision!\n");
	    delete motion;
	}
    }

    if (m_nn.size() == 0)
    {
	fprintf(stderr, "There are no valid initial states!\n");
	return false;
    }

    std::vector<double> range(dim);
    for (unsigned int i = 0 ; i < dim ; ++i)
	range[i] = m_rho * si->getStateComponent(i).maxValue - si->getStateComponent(i).minValue;

    Motion_t                                    solution = NULL;
    Motion_t                                    rmotion  = new Motion(dim);
    SpaceInformationKinematic::StateKinematic_t rstate   = rmotion->state;
    SpaceInformationKinematic::StateKinematic_t xstate   = new SpaceInformationKinematic::StateKinematic(dim);

    while (ros::Time::now() < endTime)
    {
	/* sample random state (with goal biasing) */
	if (goal_s && random_utils::uniform(&m_rngState, 0.0, 1.0) < m_goalBias)
	    si->copyState(rstate, goal_s->state);
	else
	    si->sample(rstate);

	/* find closest state in the tree */
	Motion_t nmotion = m_nn.nearest(rmotion);

	/* find state to add */
	for (unsigned int i = 0 ; i < dim ; ++i)
	{
	    double diff = rmotion->state->values[i] - nmotion->state->values[i];
	    xstate->values[i] = fabs(diff) < range[i] ? rmotion->state->values[i] : nmotion->state->values[i] + diff * m_rho;
	}

	/* create a motion */
	Motion_t motion = new Motion(dim);
	si->copyState(motion->state, xstate);
	motion->parent = nmotion;

	if (si->checkMotion(nmotion->state, motion->state))
	{
	    m_nn.add(motion);
	    if (goal_r->distanceGoal(motion->state) < goal_r->threshold)
	    {
		solution = motion;
		break;
	    }
	}
    }

    if (solution != NULL)
    {
	/* construct the solution path */
	std::vector<Motion_t> mpath;
	while (solution != NULL)
	{
	    mpath.push_back(solution);
	    solution = solution->parent;
	}

	/* set the solution path */
	SpaceInformationKinematic::PathKinematic_t path = new SpaceInformationKinematic::PathKinematic(m_si);
   	for (int i = mpath.size() - 1 ; i >= 0 ; --i)
	{
	    SpaceInformationKinematic::StateKinematic_t st = new SpaceInformationKinematic::StateKinematic(dim);
	    si->copyState(st, mpath[i]->state);
	    path->states.push_back(st);
	}
	goal_r->setSolutionPath(path);
    }

    delete xstate;
    delete rmotion;

    return goal_r->isAchieved();
}
<|endoftext|>


<commit_before>#include <vector>
#include <sstream>
#include <iostream>
#include <cstdlib>
#include "test_util.hh"
#include "reader.hh"
#include "printer.hh"
#include "eval.hh"
#include "builtin_util.hh"
#include "vm.hh"

using namespace std;

Lisp_ptr read_from_string(const char* s){
  stringstream ss(s);
  return read(ss);
}

Lisp_ptr eval_text(const char* s){
  auto exp = read_from_string(s);
  if(!exp){
    cerr << "[failed] read error on " << s << "\n";
    return {};
  }

  vm.code.push_back(exp);
  eval();
  auto ret = vm.return_value[0];
  if(!ret){
    cerr << "[failed] eval error on " << s << "\n";
    return {};
  }

  return ret;
}

bool eqv(Lisp_ptr a, Lisp_ptr b){
  auto eqv_ret = zs_call({intern(vm.symtable(), "eqv?"), a, b});
  return eqv_ret.get<bool>();
}

Lisp_ptr zs_call(std::initializer_list<Lisp_ptr> args){
  vm.code.push_back(make_cons_list(args));
  eval();
  return vm.return_value[0];
}

namespace test_util_detail {

with_null_stream::with_null_stream()
  : orig_obuf(std::cerr.rdbuf()){
  cerr.rdbuf(new std::stringbuf());
}

with_null_stream::~with_null_stream(){
  cerr.rdbuf(orig_obuf);
}

} // namespace test_util_detail

int result = true;

struct print_check_error{
  string result;
};

static
void print_check(Lisp_ptr input, const char* expect){
  std::stringstream ss;
  print(ss, input);

  auto evaled = ss.str();

  if(expect != evaled){
    result = false;
    throw print_check_error{evaled};
  }
}

bool check_p(Lisp_ptr input, const char* expect){
  try{
    print_check(input, expect);
    return true;
  }catch(const print_check_error& e){
    cerr << "[failed] expected: " << expect << "\n"
         << "\treturned: " << e.result << "\n";
    result = false;
    return false;
  }
}

bool check_p_success(Lisp_ptr input){
  stringstream ss;
  try{
    print(ss, input);
    return true;
  }catch(...){
    cerr << "[failed] print error: ";
    print(cerr, input);
    cerr << "\n";
    return false;
  }
}

bool check_r(const char* input, const char* expect){
  auto r = read_from_string(input);
  if(!r){
    cerr << "[failed] read error on " << input << "\n";
    result = false;
    return false;
  }

  try{
    print_check(r, expect);
    return true;
  }catch(const print_check_error& e){
    cerr << "[failed] input:" << input << ", expected: " << expect << "\n"
         << "\treturned: " << e.result << "\n";
    result = false;
    return false;
  };
}

bool check_r_undef(const char* input){
  with_expect_error([&]() -> void {
      if(read_from_string(input)){
        result = false;
        cerr << "[failed] read:" << input << ", expected: (undefined)\n";
      }
    });
  return result;
}

bool check_e(const char* input, const char* expect){
  auto e = eval_text(input);
  if(!e){
    result = false;
    return false;
  }

  try{
    print_check(e, expect);
    return true;
  }catch(const print_check_error& err){
    cerr << "[failed] expected " << expect
         << ", but got " << err.result << " (from: " << input << ")\n";
    result = false;
    return false;
  }
}

bool check_e_success(const char* input){
  if(eval_text(input)){
    return true;
  }else{
    cerr << "[failed] eval:" << input << ", expected: (success)\n";
    result = false;
    return false;
  }
}

bool check_e_undef(const char* input){
  with_expect_error([&]() -> void {
      if(eval_text(input)){
        result = false;
        cerr << "[failed] eval:" << input << ", expected: (undefined)\n";
      }
    });
  return result;
}

bool check_er(const char* input, const char* expect){
  auto e = eval_text(input);
  if(!e){
    result = false;
    return false;
  }

  auto r = read_from_string(expect);
  assert(r);

  auto ret = eqv(e, r);
  if(!ret){
    result = false;
    cerr << "[failed] expected " << expect << ", but got ";
    print(cerr, e);
    cerr << " (from: " << input << ")\n";
  }
  return result;
}
<commit_msg>rewrite callback to try/catch (2)<commit_after>#include <vector>
#include <sstream>
#include <iostream>
#include <cstdlib>
#include "test_util.hh"
#include "reader.hh"
#include "printer.hh"
#include "eval.hh"
#include "builtin_util.hh"
#include "vm.hh"

using namespace std;

Lisp_ptr read_from_string(const char* s){
  stringstream ss(s);
  return read(ss);
}

Lisp_ptr eval_text(const char* s){
  auto exp = read_from_string(s);
  if(!exp){
    cerr << "[failed] read error on " << s << "\n";
    return {};
  }

  vm.code.push_back(exp);
  eval();
  auto ret = vm.return_value[0];
  if(!ret){
    cerr << "[failed] eval error on " << s << "\n";
    return {};
  }

  return ret;
}

bool eqv(Lisp_ptr a, Lisp_ptr b){
  auto eqv_ret = zs_call({intern(vm.symtable(), "eqv?"), a, b});
  return eqv_ret.get<bool>();
}

Lisp_ptr zs_call(std::initializer_list<Lisp_ptr> args){
  vm.code.push_back(make_cons_list(args));
  eval();
  return vm.return_value[0];
}

namespace test_util_detail {

with_null_stream::with_null_stream()
  : orig_obuf(std::cerr.rdbuf()){
  cerr.rdbuf(new std::stringbuf());
}

with_null_stream::~with_null_stream(){
  cerr.rdbuf(orig_obuf);
}

} // namespace test_util_detail

int result = true;

struct print_check_error{
  string result;
};

static
void print_check(Lisp_ptr input, const char* expect){
  std::stringstream ss;
  print(ss, input);

  auto evaled = ss.str();

  if(expect != evaled){
    result = false;
    throw print_check_error{evaled};
  }
}

bool check_p(Lisp_ptr input, const char* expect){
  try{
    print_check(input, expect);
    return true;
  }catch(const print_check_error& e){
    cerr << "[failed] expected: " << expect << "\n"
         << "\treturned: " << e.result << "\n";
    result = false;
    return false;
  }
}

bool check_p_success(Lisp_ptr input){
  stringstream ss;
  try{
    print(ss, input);
    return true;
  }catch(...){
    cerr << "[failed] print error: ";
    print(cerr, input);
    cerr << "\n";
    return false;
  }
}

bool check_r(const char* input, const char* expect){
  auto r = read_from_string(input);
  if(!r){
    cerr << "[failed] read error on " << input << "\n";
    result = false;
    return false;
  }

  try{
    print_check(r, expect);
    return true;
  }catch(const print_check_error& e){
    cerr << "[failed] input:" << input << ", expected: " << expect << "\n"
         << "\treturned: " << e.result << "\n";
    result = false;
    return false;
  };
}

bool check_r_undef(const char* input){
  Lisp_ptr ret;
  with_expect_error([&](){ ret = read_from_string(input); });

  if(!ret){
    return true;
  }else{
    cerr << "[failed] read:" << input << ", expected: (undefined)\n";
    result = false;
    return false;
  }
}

bool check_e(const char* input, const char* expect){
  auto e = eval_text(input);
  if(!e){
    result = false;
    return false;
  }

  try{
    print_check(e, expect);
    return true;
  }catch(const print_check_error& err){
    cerr << "[failed] expected " << expect
         << ", but got " << err.result << " (from: " << input << ")\n";
    result = false;
    return false;
  }
}

bool check_e_success(const char* input){
  if(eval_text(input)){
    return true;
  }else{
    cerr << "[failed] eval:" << input << ", expected: (success)\n";
    result = false;
    return false;
  }
}

bool check_e_undef(const char* input){
  Lisp_ptr ret;
  with_expect_error([&](){ ret = eval_text(input); });

  if(!ret){
    return true;
  }else{
    cerr << "[failed] eval:" << input << ", expected: (undefined)\n";
    result = false;
    return false;
  }
}

bool check_er(const char* input, const char* expect){
  auto e = eval_text(input);
  if(!e){
    result = false;
    return false;
  }

  auto r = read_from_string(expect);
  assert(r);

  auto ret = eqv(e, r);
  if(!ret){
    result = false;
    cerr << "[failed] expected " << expect << ", but got ";
    print(cerr, e);
    cerr << " (from: " << input << ")\n";
  }
  return result;
}
<|endoftext|>


<commit_before>#include <boost/algorithm/string/predicate.hpp>
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <cfloat>
#include <time.h>
#include "CurlHelpers.h"
#include "DriverDomoticz.h"

typedef std::pair<const std::string, boost::property_tree::ptree> ptreePair;

HardwareDomoticz::HardwareDomoticz(DBHarware &hw) : MHEHardware(hw.id), _hw(hw)
{
}

HardwareDomoticz::~HardwareDomoticz()
{
}

MHEDevice *HardwareDomoticz::buildObject(DBDevice &dev)
{
    return new DeviceDomoticz(_hw.param1, (dev.param2 == "24havg"), dev);
}

DeviceDomoticz::DeviceDomoticz(std::string &urlDomoticz, bool isDayAverage, DBDevice &dev) : MHEDevice(dev.id, dev.type, dev.cacheLifetime), _urlDomoticz(urlDomoticz), _deviceIdx(dev.param1), _isDayAverage(isDayAverage)
{
    _log = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("DeviceDomoticz"));
}

DeviceDomoticz::~DeviceDomoticz()
{
}

float DeviceDomoticz::getTemperature()
{
    refreshCache();
    return _cache.temperature;
}

float DeviceDomoticz::getHumidity()
{
    refreshCache();
    return _cache.humidity;
}

bool DeviceDomoticz::setTempHum(float temperature, float humidity)
{
    std::stringstream ssUrl;

	ssUrl << _urlDomoticz << "json.htm?type=command&param=udevice&idx=" << _deviceIdx << "&nvalue=0&svalue=" << temperature << ';' << humidity << ";2";
	if (curlExecute(ssUrl.str()))
	{
        time_t now = time(NULL);

        _cache.lastUpdate = now;
		_cache.humidity = humidity;
		_cache.temperature = temperature;
		if (_cloneTo != NULL)
            _cloneTo->setTempHum(temperature, humidity);
		return true;
	}
	return false;
}

bool DeviceDomoticz::isActivated()
{
    refreshCache();
    return _cache.statusIsOn;
}

bool DeviceDomoticz::setStatus(bool activate)
{
    std::stringstream ssUrl;

	ssUrl << _urlDomoticz << "json.htm?type=command&param=switchlight&idx=" << _deviceIdx << "&switchcmd=" << (activate ? "On" : "Off") << "&level=0";
	if (curlExecute(ssUrl.str()))
	{
        time_t now = time(NULL);

        _cache.lastUpdate = now;
        _cache.statusIsOn = activate;
        if (_cloneTo != NULL)
            _cloneTo->setStatus(activate);
        return true;
	}
    return false;
}

void DeviceDomoticz::refreshCache()
{
    time_t now = time(NULL) - _cacheLifetime;

    if (_cache.lastUpdate < now)
    {
        bool isSuccess = false;

        if (_isDayAverage)
            isSuccess = refreshDayAverage();
        else
            isSuccess = refreshNormal();
        if (isSuccess)
        {
            LOG4CPLUS_DEBUG(_log, LOG4CPLUS_TEXT("DeviceDomoticz::refreshCache - Refresh(" << (std::string)*this << ") = " << (std::string)_cache));
            if (_cloneTo != NULL)
                _cloneTo->setTempHum(_cache.temperature, _cache.humidity);
        }
    }
}

bool DeviceDomoticz::refreshNormal()
{
    std::stringstream ssOut, ssUrl;

    ssUrl << _urlDomoticz << "json.htm?type=devices&rid=" << _deviceIdx;
    if (curlExecute(ssUrl.str(), &ssOut))
    {
        boost::property_tree::ptree pTree;

        boost::property_tree::read_json(ssOut, pTree);
        if (pTree.count("result") == 0)
            return false;
        BOOST_FOREACH(ptreePair &it, pTree.get_child("result"))
        {
            if (it.second.size() > 0)
            {
                BOOST_FOREACH(ptreePair &itChild, it.second)
                {
                    if (itChild.first == "Name")
                        _cache.name = itChild.second.get_value<std::string>();
                    else if (itChild.first == "LastUpdate")
                    {
                        std::string date = itChild.second.get_value<std::string>();
                        struct tm tm;

                        memset(&tm, 0, sizeof(tm));
                        tm.tm_zone = *tzname;
                        tm.tm_isdst = daylight;
                        if (strptime(date.c_str(), "%Y-%m-%d %H:%M:%S", &tm) != NULL)
                            _cache.lastUpdate = mktime(&tm);
                    }
                    else if (itChild.first == "Status")
                    {
                        std::string status = itChild.second.get_value<std::string>();

                        _cache.statusIsOn = boost::starts_with(status, "On");
                    }
                    else if (itChild.first == "Temp")
                        _cache.temperature = itChild.second.get_value<float>();
                    else if (itChild.first == "Humidity")
                        _cache.humidity = itChild.second.get_value<float>();
                }
            }
        }
        return true;
    }
    return false;
}

bool DeviceDomoticz::refreshDayAverage()
{
    std::stringstream ssOut, ssUrl;

    ssUrl << _urlDomoticz << "json.htm?type=graph&sensor=temp&idx=" << _deviceIdx << "&range=day";
    if (curlExecute(ssUrl.str(), &ssOut))
    {
        boost::property_tree::ptree pTree;
        double tempTotal = 0.0, tempNumber = 0.0;

        boost::property_tree::read_json(ssOut, pTree);
        if (pTree.count("result") == 0)
            return false;
        BOOST_FOREACH(ptreePair it, pTree.get_child("result"))
        {
            float currentTemp = it.second.get<float>("te", FLT_MIN);

            if (currentTemp > FLT_MIN)
            {
                tempTotal += currentTemp;
                tempNumber++;
            }
        }
        LOG4CPLUS_DEBUG(_log, LOG4CPLUS_TEXT("Domoticz::getLastDayAverageTemperatureOutdoor - tempReturn=" << (tempTotal / tempNumber) << " tempTotal=" << tempTotal << " tempNumber=" << tempNumber << "]"));
        if (tempNumber > 0)
        {
            _cache.temperature = (tempTotal / tempNumber);
            return true;
        }
    }
    return false;
}
<commit_msg>Reindent file.<commit_after>#include <boost/algorithm/string/predicate.hpp>
#include <boost/foreach.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <cfloat>
#include <time.h>
#include "CurlHelpers.h"
#include "DriverDomoticz.h"

typedef std::pair<const std::string, boost::property_tree::ptree> ptreePair;

HardwareDomoticz::HardwareDomoticz(DBHarware &hw) : MHEHardware(hw.id), _hw(hw)
{
}

HardwareDomoticz::~HardwareDomoticz()
{
}

MHEDevice *HardwareDomoticz::buildObject(DBDevice &dev)
{
    return new DeviceDomoticz(_hw.param1, (dev.param2 == "24havg"), dev);
}

DeviceDomoticz::DeviceDomoticz(std::string &urlDomoticz, bool isDayAverage, DBDevice &dev) : MHEDevice(dev.id, dev.type, dev.cacheLifetime), _urlDomoticz(urlDomoticz), _deviceIdx(dev.param1), _isDayAverage(isDayAverage)
{
    _log = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("DeviceDomoticz"));
}

DeviceDomoticz::~DeviceDomoticz()
{
}

float DeviceDomoticz::getTemperature()
{
    refreshCache();
    return _cache.temperature;
}

float DeviceDomoticz::getHumidity()
{
    refreshCache();
    return _cache.humidity;
}

bool DeviceDomoticz::setTempHum(float temperature, float humidity)
{
    std::stringstream ssUrl;

    ssUrl << _urlDomoticz << "json.htm?type=command&param=udevice&idx=" << _deviceIdx << "&nvalue=0&svalue=" << temperature << ';' << humidity << ";2";
    if (curlExecute(ssUrl.str()))
    {
        time_t now = time(NULL);

        _cache.lastUpdate = now;
        _cache.humidity = humidity;
        _cache.temperature = temperature;
        if (_cloneTo != NULL)
            _cloneTo->setTempHum(temperature, humidity);
        return true;
    }
    return false;
}

bool DeviceDomoticz::isActivated()
{
    refreshCache();
    return _cache.statusIsOn;
}

bool DeviceDomoticz::setStatus(bool activate)
{
    std::stringstream ssUrl;

	ssUrl << _urlDomoticz << "json.htm?type=command&param=switchlight&idx=" << _deviceIdx << "&switchcmd=" << (activate ? "On" : "Off") << "&level=0";
	if (curlExecute(ssUrl.str()))
	{
        time_t now = time(NULL);

        _cache.lastUpdate = now;
        _cache.statusIsOn = activate;
        if (_cloneTo != NULL)
            _cloneTo->setStatus(activate);
        return true;
	}
    return false;
}

void DeviceDomoticz::refreshCache()
{
    time_t now = time(NULL) - _cacheLifetime;

    if (_cache.lastUpdate < now)
    {
        bool isSuccess = false;

        if (_isDayAverage)
            isSuccess = refreshDayAverage();
        else
            isSuccess = refreshNormal();
        if (isSuccess)
        {
            LOG4CPLUS_DEBUG(_log, LOG4CPLUS_TEXT("DeviceDomoticz::refreshCache - Refresh(" << (std::string)*this << ") = " << (std::string)_cache));
            if (_cloneTo != NULL)
                _cloneTo->setTempHum(_cache.temperature, _cache.humidity);
        }
    }
}

bool DeviceDomoticz::refreshNormal()
{
    std::stringstream ssOut, ssUrl;

    ssUrl << _urlDomoticz << "json.htm?type=devices&rid=" << _deviceIdx;
    if (curlExecute(ssUrl.str(), &ssOut))
    {
        boost::property_tree::ptree pTree;

        boost::property_tree::read_json(ssOut, pTree);
        if (pTree.count("result") == 0)
            return false;
        BOOST_FOREACH(ptreePair &it, pTree.get_child("result"))
        {
            if (it.second.size() > 0)
            {
                BOOST_FOREACH(ptreePair &itChild, it.second)
                {
                    if (itChild.first == "Name")
                        _cache.name = itChild.second.get_value<std::string>();
                    else if (itChild.first == "LastUpdate")
                    {
                        std::string date = itChild.second.get_value<std::string>();
                        struct tm tm;

                        memset(&tm, 0, sizeof(tm));
                        tm.tm_zone = *tzname;
                        tm.tm_isdst = daylight;
                        if (strptime(date.c_str(), "%Y-%m-%d %H:%M:%S", &tm) != NULL)
                            _cache.lastUpdate = mktime(&tm);
                    }
                    else if (itChild.first == "Status")
                    {
                        std::string status = itChild.second.get_value<std::string>();

                        _cache.statusIsOn = boost::starts_with(status, "On");
                    }
                    else if (itChild.first == "Temp")
                        _cache.temperature = itChild.second.get_value<float>();
                    else if (itChild.first == "Humidity")
                        _cache.humidity = itChild.second.get_value<float>();
                }
            }
        }
        return true;
    }
    return false;
}

bool DeviceDomoticz::refreshDayAverage()
{
    std::stringstream ssOut, ssUrl;

    ssUrl << _urlDomoticz << "json.htm?type=graph&sensor=temp&idx=" << _deviceIdx << "&range=day";
    if (curlExecute(ssUrl.str(), &ssOut))
    {
        boost::property_tree::ptree pTree;
        double tempTotal = 0.0, tempNumber = 0.0;

        boost::property_tree::read_json(ssOut, pTree);
        if (pTree.count("result") == 0)
            return false;
        BOOST_FOREACH(ptreePair it, pTree.get_child("result"))
        {
            float currentTemp = it.second.get<float>("te", FLT_MIN);

            if (currentTemp > FLT_MIN)
            {
                tempTotal += currentTemp;
                tempNumber++;
            }
        }
        LOG4CPLUS_DEBUG(_log, LOG4CPLUS_TEXT("Domoticz::getLastDayAverageTemperatureOutdoor - tempReturn=" << (tempTotal / tempNumber) << " tempTotal=" << tempTotal << " tempNumber=" << tempNumber << "]"));
        if (tempNumber > 0)
        {
            _cache.temperature = (tempTotal / tempNumber);
            return true;
        }
    }
    return false;
}
<|endoftext|>


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

// Interface header.
#include "appleseedmaya/exporters/lightexporter.h"

// Standard headers.
#include <sstream>

// Maya headers.
#include <maya/MFnDagNode.h>

// appleseed.foundation headers.
#include "foundation/math/scalar.h"

// appleseed.renderer headers.
#include "renderer/api/scene.h"

// appleseed.maya headers.
#include "appleseedmaya/attributeutils.h"
#include "appleseedmaya/exporters/exporterfactory.h"

namespace asf = foundation;
namespace asr = renderer;

void LightExporter::registerExporter()
{
    NodeExporterFactory::registerDagNodeExporter("directionalLight", &LightExporter::create);
    NodeExporterFactory::registerDagNodeExporter("pointLight", &LightExporter::create);
    NodeExporterFactory::registerDagNodeExporter("spotLight", &LightExporter::create);
}

DagNodeExporter *LightExporter::create(
    const MDagPath&                 path,
    asr::Project&                   project,
    AppleseedSession::SessionMode   sessionMode)
{
    return new LightExporter(path, project, sessionMode);
}

LightExporter::LightExporter(
    const MDagPath&                 path,
    asr::Project&                   project,
    AppleseedSession::SessionMode   sessionMode)
  : DagNodeExporter(path, project, sessionMode)
{
}

bool LightExporter::supportsMotionBlur() const
{
    return false;
}

void LightExporter::createEntity(const AppleseedSession::Options& options)
{
    asr::LightFactoryRegistrar lightFactories;
    const asr::ILightFactory *lightFactory = 0;
    asr::ParamArray lightParams;

    MFnDependencyNode depNodeFn(node());

    MStatus status;
    MPlug plug = depNodeFn.findPlug("intensity", &status);
    if(plug.isConnected())
    {
        // todo: add warning here...
    }

    float intensity = 1.0;
    AttributeUtils::get(plug, intensity);

    plug = depNodeFn.findPlug("color", &status);
    if(plug.isConnected())
    {
        // todo: add warning here...
    }

    // Create a color entity.
    MString colorName = appleseedName() + MString("_intensity_color");
    {
        MColor color(1.0f, 1.0f, 1.0f);
        AttributeUtils::get(plug, color);
        asr::ColorValueArray values(3, &color.r);

        asr::ParamArray params;
        params.insert("color_space", "linear_rgb");
        m_lightColor.reset(
            asr::ColorEntityFactory::create(colorName.asChar(), params, values));
    }

    if(depNodeFn.typeName() == "directionalLight")
    {
        lightFactory = lightFactories.lookup("directional_light");
        lightParams.insert("irradiance", colorName.asChar());
        lightParams.insert("irradiance_multiplier", intensity);
    }
    if(depNodeFn.typeName() == "pointLight")
    {
        lightFactory = lightFactories.lookup("point_light");
        lightParams.insert("intensity", colorName.asChar());
        lightParams.insert("intensity_multiplier", intensity);
    }
    else // spotLight
    {
        lightFactory = lightFactories.lookup("spot_light");
        lightParams.insert("intensity", colorName.asChar());
        lightParams.insert("intensity_multiplier", intensity);

        // TODO: use MAngle to do the right thing and remove
        // deg / rad conversions...
        float coneAngle = asf::deg_to_rad(20.0f);
        AttributeUtils::get(node(), "coneAngle", coneAngle);
        lightParams.insert("inner_angle", asf::rad_to_deg(coneAngle));

        float penumbraAngle = asf::deg_to_rad(5.0f);
        AttributeUtils::get(node(), "penumbraAngle", penumbraAngle);
        lightParams.insert("outer_angle", asf::rad_to_deg(coneAngle + 2.0 * penumbraAngle));
    }

    m_light = lightFactory->create(appleseedName().asChar(), lightParams);

    asf::Matrix4d m = convert(dagPath().inclusiveMatrix());
    asf::Matrix4d invM = convert(dagPath().inclusiveMatrixInverse());
    asf::Transformd xform(m, invM);
    m_light->set_transform(xform);
}

void LightExporter::flushEntity()
{
    mainAssembly().colors().insert(m_lightColor.release());
    mainAssembly().lights().insert(m_light.release());
}
<commit_msg>Use MAngle for spotlights.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2016 Esteban Tovagliari, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "appleseedmaya/exporters/lightexporter.h"

// Standard headers.
#include <sstream>

// Maya headers.
#include <maya/MFnDagNode.h>

// appleseed.foundation headers.
#include "foundation/math/scalar.h"

// appleseed.renderer headers.
#include "renderer/api/scene.h"

// appleseed.maya headers.
#include "appleseedmaya/attributeutils.h"
#include "appleseedmaya/exporters/exporterfactory.h"

namespace asf = foundation;
namespace asr = renderer;

void LightExporter::registerExporter()
{
    NodeExporterFactory::registerDagNodeExporter("directionalLight", &LightExporter::create);
    NodeExporterFactory::registerDagNodeExporter("pointLight", &LightExporter::create);
    NodeExporterFactory::registerDagNodeExporter("spotLight", &LightExporter::create);
}

DagNodeExporter *LightExporter::create(
    const MDagPath&                 path,
    asr::Project&                   project,
    AppleseedSession::SessionMode   sessionMode)
{
    return new LightExporter(path, project, sessionMode);
}

LightExporter::LightExporter(
    const MDagPath&                 path,
    asr::Project&                   project,
    AppleseedSession::SessionMode   sessionMode)
  : DagNodeExporter(path, project, sessionMode)
{
}

bool LightExporter::supportsMotionBlur() const
{
    return false;
}

void LightExporter::createEntity(const AppleseedSession::Options& options)
{
    asr::LightFactoryRegistrar lightFactories;
    const asr::ILightFactory *lightFactory = 0;
    asr::ParamArray lightParams;

    MFnDependencyNode depNodeFn(node());

    MStatus status;
    MPlug plug = depNodeFn.findPlug("intensity", &status);
    if(plug.isConnected())
    {
        // todo: add warning here...
    }

    float intensity = 1.0;
    AttributeUtils::get(plug, intensity);

    plug = depNodeFn.findPlug("color", &status);
    if(plug.isConnected())
    {
        // todo: add warning here...
    }

    // Create a color entity.
    MString colorName = appleseedName() + MString("_intensity_color");
    {
        MColor color(1.0f, 1.0f, 1.0f);
        AttributeUtils::get(plug, color);
        asr::ColorValueArray values(3, &color.r);

        asr::ParamArray params;
        params.insert("color_space", "linear_rgb");
        m_lightColor.reset(
            asr::ColorEntityFactory::create(colorName.asChar(), params, values));
    }

    if(depNodeFn.typeName() == "directionalLight")
    {
        lightFactory = lightFactories.lookup("directional_light");
        lightParams.insert("irradiance", colorName.asChar());
        lightParams.insert("irradiance_multiplier", intensity);
    }
    if(depNodeFn.typeName() == "pointLight")
    {
        lightFactory = lightFactories.lookup("point_light");
        lightParams.insert("intensity", colorName.asChar());
        lightParams.insert("intensity_multiplier", intensity);
    }
    else // spotLight
    {
        lightFactory = lightFactories.lookup("spot_light");
        lightParams.insert("intensity", colorName.asChar());
        lightParams.insert("intensity_multiplier", intensity);

        MAngle coneAngle(20.0f, MAngle::kDegrees);
        AttributeUtils::get(node(), "coneAngle", coneAngle);
        lightParams.insert("inner_angle", coneAngle.asDegrees());

        MAngle penumbraAngle(5.0f, MAngle::kDegrees);
        AttributeUtils::get(node(), "penumbraAngle", penumbraAngle);
        const float outerAngle = coneAngle.asDegrees() + 2.0 * penumbraAngle.asDegrees();
        lightParams.insert("outer_angle", outerAngle);
    }

    m_light = lightFactory->create(appleseedName().asChar(), lightParams);

    asf::Matrix4d m = convert(dagPath().inclusiveMatrix());
    asf::Matrix4d invM = convert(dagPath().inclusiveMatrixInverse());
    asf::Transformd xform(m, invM);
    m_light->set_transform(xform);
}

void LightExporter::flushEntity()
{
    mainAssembly().colors().insert(m_lightColor.release());
    mainAssembly().lights().insert(m_light.release());
}
<|endoftext|>