<commit_before>//------------------------------------------------------------------------------
//  Emu.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#define CHIPS_IMPL
#include "Emu.h"
#define SOKOL_IMPL
#include "sokol_audio.h"
#include "Input/Input.h"
#include "IO/IO.h"
#include "Assets/Gfx/ShapeBuilder.h"
#include "shaders.h"
#include "emu/kc85-roms.h"
#include <cctype>

namespace Oryol {

//------------------------------------------------------------------------------
//  audio-streaming callback to forward audio samples from the emulator
//  to sokol-audio
//
static void push_audio(const float* samples, int num_samples, void* user_data) {
    saudio_push(samples, num_samples);
}

//------------------------------------------------------------------------------
// a callback to patch some known problems in game snapshot files
//
static void patch_snapshots(const char* snapshot_name, void* user_data) {
    Emu* self = (Emu*) user_data;
    if (strcmp(snapshot_name, "JUNGLE     ") == 0) {
        /* patch start level 1 into memory */
        mem_wr(&self->kc85.mem, 0x36b7, 1);
        mem_wr(&self->kc85.mem, 0x3697, 1);
        for (int i = 0; i < 5; i++) {
            mem_wr(&self->kc85.mem, 0x1770 + i, mem_rd(&self->kc85.mem, 0x36b6 + i));
        }
    }
    else if (strcmp(snapshot_name, "DIGGER  COM\x01") == 0) {
        mem_wr16(&self->kc85.mem, 0x09AA, 0x0160);    /* time for delay-loop 0160 instead of 0260 */
        mem_wr(&self->kc85.mem, 0x3d3a, 0xB5);        /* OR L instead of OR (HL) */
    }
    else if (strcmp(snapshot_name, "DIGGERJ") == 0) {
        mem_wr16(&self->kc85.mem, 0x09AA, 0x0260);
        mem_wr(&self->kc85.mem, 0x3d3a, 0xB5);       /* OR L instead of OR (HL) */
    }
}
//------------------------------------------------------------------------------
void Emu::Setup(const GfxSetup& gfxSetup) {

    // setup the KC85 emulator
    this->TogglePower();

    // setup sokol-audio
    saudio_desc audio_desc = { };
    saudio_setup(&audio_desc);

    // create a mesh, pipeline and texture for rendering the emulator framebuffer
    ShapeBuilder shapeBuilder;
    shapeBuilder.Layout
        .Add(VertexAttr::Position, VertexFormat::Float3)
        .Add(VertexAttr::TexCoord0, VertexFormat::Float2);
    shapeBuilder.Plane(1.0f, 1.0f, 1);
    this->drawState.Mesh[0] = Gfx::CreateResource(shapeBuilder.Build());

    Id shd = Gfx::CreateResource(EmuShader::Setup());
    auto pip = PipelineSetup::FromLayoutAndShader(shapeBuilder.Layout, shd);
    pip.DepthStencilState.DepthWriteEnabled = true;
    pip.DepthStencilState.DepthCmpFunc = CompareFunc::LessEqual;
    pip.RasterizerState.SampleCount = gfxSetup.SampleCount;
    pip.BlendState.ColorFormat = gfxSetup.ColorFormat;
    pip.BlendState.DepthFormat = gfxSetup.DepthFormat;
    this->drawState.Pipeline = Gfx::CreateResource(pip);

    const int w = kc85_std_display_width();
    const int h = kc85_std_display_height();
    auto texSetup = TextureSetup::Empty2D(w, h, 1, PixelFormat::RGBA8, Usage::Stream);
    texSetup.Sampler.MinFilter = TextureFilterMode::Linear;
    texSetup.Sampler.MagFilter = TextureFilterMode::Linear;
    texSetup.Sampler.WrapU = TextureWrapMode::ClampToEdge;
    texSetup.Sampler.WrapV = TextureWrapMode::ClampToEdge;
    this->drawState.FSTexture[EmuShader::irm] = Gfx::CreateResource(texSetup);

    // keyboard input callback
    this->inputCallbackId = Input::SubscribeEvents([this](const InputEvent& e) {
        if (e.Type == InputEvent::WChar) {
            int c = (int) e.WCharCode;
            if ((c > 0x20) && (c < 0x7f)) {
                if (std::islower(c)) {
                    c = std::toupper(c);
                }
                else if (std::isupper(c)) {
                    c = std::tolower(c);
                }
                kc85_key_down(&this->kc85, c);
                kc85_key_up(&this->kc85, c);
            }
        }
        else if ((e.Type == InputEvent::KeyUp) || (e.Type == InputEvent::KeyDown)) {
            int c = 0;
            bool shift = Input::KeyPressed(Key::LeftShift);
            switch (e.KeyCode) {
                case Key::Space:        c = shift ? 0x5B : 0x20; break;
                case Key::Enter:        c = 0x0D; break;
                case Key::Right:        c = 0x09; break;
                case Key::Left:         c = 0x08; break;
                case Key::Down:         c = 0x0A; break;
                case Key::Up:           c = 0x0B; break;
                case Key::Home:         c = 0x10; break;
                case Key::Insert:       c = shift ? 0x0C : 0x1A; break;
                case Key::BackSpace:    c = shift ? 0x0C : 0x01; break;
                case Key::Escape:       c = shift ? 0x13 : 0x03; break;
                case Key::F1:           c = 0xF1; break;
                case Key::F2:           c = 0xF2; break;
                case Key::F3:           c = 0xF3; break;
                case Key::F4:           c = 0xF4; break;
                case Key::F5:           c = 0xF5; break;
                case Key::F6:           c = 0xF6; break;
                case Key::F7:           c = 0xF7; break;
                case Key::F8:           c = 0xF8; break;
                case Key::F9:           c = 0xF9; break;
                case Key::F10:          c = 0xFA; break;
                case Key::F11:          c = 0xFB; break;
                case Key::F12:          c = 0xFC; break;
                default:                c = 0; break;
            }
            if (c) {
                if (e.Type == InputEvent::KeyDown) {
                    kc85_key_down(&this->kc85, c);
                }
                else {
                    kc85_key_up(&this->kc85, c);
                }
            }
        }
    });
}

//------------------------------------------------------------------------------
void Emu::Discard() {
    saudio_shutdown();
    Input::UnsubscribeEvents(this->inputCallbackId);
}

//------------------------------------------------------------------------------
void Emu::Tick(Duration frameTime) {
    this->frameIndex++;
    if (this->switchedOn) {
        kc85_exec(&this->kc85, (uint32_t)frameTime.AsMicroSeconds());
    }
    // start a game?
    if (this->startGamePath && (this->startGameFrameIndex == this->frameIndex)) {
        IO::Load(this->startGamePath, [this](IO::LoadResult ioResult) {
            kc85_quickload(&this->kc85, ioResult.Data.Data(), ioResult.Data.Size());
        });
        this->startGamePath = nullptr;
    }
}

//------------------------------------------------------------------------------
void Emu::Render(const glm::mat4& mvp) {
    if (this->switchedOn) {
        ImageDataAttrs updAttrs;
        updAttrs.NumFaces = 1;
        updAttrs.NumMipMaps = 1;
        updAttrs.Sizes[0][0] = sizeof(this->pixelBuffer);
        Gfx::UpdateTexture(this->drawState.FSTexture[0], this->pixelBuffer, updAttrs);
        EmuShader::vsParams vsParams;
        vsParams.mvp = mvp;
        Gfx::ApplyDrawState(this->drawState);
        Gfx::ApplyUniformBlock(vsParams);
        Gfx::Draw();
    }
}

//------------------------------------------------------------------------------
void Emu::TogglePower() {
    this->switchedOn = !this->switchedOn;
    if (this->switchedOn) {
        kc85_desc_t kc85_desc = { };
        kc85_desc.type = KC85_TYPE_3;
        kc85_desc.pixel_buffer = this->pixelBuffer;
        kc85_desc.pixel_buffer_size = sizeof(this->pixelBuffer);
        kc85_desc.audio_cb = push_audio;
        kc85_desc.audio_sample_rate = saudio_sample_rate();
        kc85_desc.patch_cb = patch_snapshots;
        kc85_desc.rom_caos31 = dump_caos31;
        kc85_desc.rom_caos31_size = sizeof(dump_caos31);
        kc85_desc.rom_kcbasic = dump_basic_c0;
        kc85_desc.rom_kcbasic_size = sizeof(dump_basic_c0);
        kc85_desc.user_data = (void*) this;
        kc85_init(&this->kc85, &kc85_desc);
        kc85_insert_ram_module(&this->kc85, 0x08, KC85_MODULE_M022_16KBYTE);
    }
    else {
        kc85_discard(&this->kc85);
    }
}

//------------------------------------------------------------------------------
bool Emu::SwitchedOn() const {
    return this->switchedOn;
}

//------------------------------------------------------------------------------
void Emu::Reset() {
    if (this->switchedOn) {
        kc85_reset(&this->kc85);
    }
}

//------------------------------------------------------------------------------
void Emu::StartGame(const char* path) {
    if (this->switchedOn) {
        this->TogglePower();
    }
    this->TogglePower();
    this->startGameFrameIndex = this->frameIndex + 3 * 60;
    this->startGamePath = path;
}

} // namespace Oryol

<commit_msg>KC85/3: clamp frametime to 30Hz<commit_after>//------------------------------------------------------------------------------
//  Emu.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#define CHIPS_IMPL
#include "Emu.h"
#define SOKOL_IMPL
#include "sokol_audio.h"
#include "Input/Input.h"
#include "IO/IO.h"
#include "Assets/Gfx/ShapeBuilder.h"
#include "shaders.h"
#include "emu/kc85-roms.h"
#include <cctype>

namespace Oryol {

//------------------------------------------------------------------------------
//  audio-streaming callback to forward audio samples from the emulator
//  to sokol-audio
//
static void push_audio(const float* samples, int num_samples, void* user_data) {
    saudio_push(samples, num_samples);
}

//------------------------------------------------------------------------------
// a callback to patch some known problems in game snapshot files
//
static void patch_snapshots(const char* snapshot_name, void* user_data) {
    Emu* self = (Emu*) user_data;
    if (strcmp(snapshot_name, "JUNGLE     ") == 0) {
        /* patch start level 1 into memory */
        mem_wr(&self->kc85.mem, 0x36b7, 1);
        mem_wr(&self->kc85.mem, 0x3697, 1);
        for (int i = 0; i < 5; i++) {
            mem_wr(&self->kc85.mem, 0x1770 + i, mem_rd(&self->kc85.mem, 0x36b6 + i));
        }
    }
    else if (strcmp(snapshot_name, "DIGGER  COM\x01") == 0) {
        mem_wr16(&self->kc85.mem, 0x09AA, 0x0160);    /* time for delay-loop 0160 instead of 0260 */
        mem_wr(&self->kc85.mem, 0x3d3a, 0xB5);        /* OR L instead of OR (HL) */
    }
    else if (strcmp(snapshot_name, "DIGGERJ") == 0) {
        mem_wr16(&self->kc85.mem, 0x09AA, 0x0260);
        mem_wr(&self->kc85.mem, 0x3d3a, 0xB5);       /* OR L instead of OR (HL) */
    }
}
//------------------------------------------------------------------------------
void Emu::Setup(const GfxSetup& gfxSetup) {

    // setup the KC85 emulator
    this->TogglePower();

    // setup sokol-audio
    saudio_desc audio_desc = { };
    saudio_setup(&audio_desc);

    // create a mesh, pipeline and texture for rendering the emulator framebuffer
    ShapeBuilder shapeBuilder;
    shapeBuilder.Layout
        .Add(VertexAttr::Position, VertexFormat::Float3)
        .Add(VertexAttr::TexCoord0, VertexFormat::Float2);
    shapeBuilder.Plane(1.0f, 1.0f, 1);
    this->drawState.Mesh[0] = Gfx::CreateResource(shapeBuilder.Build());

    Id shd = Gfx::CreateResource(EmuShader::Setup());
    auto pip = PipelineSetup::FromLayoutAndShader(shapeBuilder.Layout, shd);
    pip.DepthStencilState.DepthWriteEnabled = true;
    pip.DepthStencilState.DepthCmpFunc = CompareFunc::LessEqual;
    pip.RasterizerState.SampleCount = gfxSetup.SampleCount;
    pip.BlendState.ColorFormat = gfxSetup.ColorFormat;
    pip.BlendState.DepthFormat = gfxSetup.DepthFormat;
    this->drawState.Pipeline = Gfx::CreateResource(pip);

    const int w = kc85_std_display_width();
    const int h = kc85_std_display_height();
    auto texSetup = TextureSetup::Empty2D(w, h, 1, PixelFormat::RGBA8, Usage::Stream);
    texSetup.Sampler.MinFilter = TextureFilterMode::Linear;
    texSetup.Sampler.MagFilter = TextureFilterMode::Linear;
    texSetup.Sampler.WrapU = TextureWrapMode::ClampToEdge;
    texSetup.Sampler.WrapV = TextureWrapMode::ClampToEdge;
    this->drawState.FSTexture[EmuShader::irm] = Gfx::CreateResource(texSetup);

    // keyboard input callback
    this->inputCallbackId = Input::SubscribeEvents([this](const InputEvent& e) {
        if (e.Type == InputEvent::WChar) {
            int c = (int) e.WCharCode;
            if ((c > 0x20) && (c < 0x7f)) {
                if (std::islower(c)) {
                    c = std::toupper(c);
                }
                else if (std::isupper(c)) {
                    c = std::tolower(c);
                }
                kc85_key_down(&this->kc85, c);
                kc85_key_up(&this->kc85, c);
            }
        }
        else if ((e.Type == InputEvent::KeyUp) || (e.Type == InputEvent::KeyDown)) {
            int c = 0;
            bool shift = Input::KeyPressed(Key::LeftShift);
            switch (e.KeyCode) {
                case Key::Space:        c = shift ? 0x5B : 0x20; break;
                case Key::Enter:        c = 0x0D; break;
                case Key::Right:        c = 0x09; break;
                case Key::Left:         c = 0x08; break;
                case Key::Down:         c = 0x0A; break;
                case Key::Up:           c = 0x0B; break;
                case Key::Home:         c = 0x10; break;
                case Key::Insert:       c = shift ? 0x0C : 0x1A; break;
                case Key::BackSpace:    c = shift ? 0x0C : 0x01; break;
                case Key::Escape:       c = shift ? 0x13 : 0x03; break;
                case Key::F1:           c = 0xF1; break;
                case Key::F2:           c = 0xF2; break;
                case Key::F3:           c = 0xF3; break;
                case Key::F4:           c = 0xF4; break;
                case Key::F5:           c = 0xF5; break;
                case Key::F6:           c = 0xF6; break;
                case Key::F7:           c = 0xF7; break;
                case Key::F8:           c = 0xF8; break;
                case Key::F9:           c = 0xF9; break;
                case Key::F10:          c = 0xFA; break;
                case Key::F11:          c = 0xFB; break;
                case Key::F12:          c = 0xFC; break;
                default:                c = 0; break;
            }
            if (c) {
                if (e.Type == InputEvent::KeyDown) {
                    kc85_key_down(&this->kc85, c);
                }
                else {
                    kc85_key_up(&this->kc85, c);
                }
            }
        }
    });
}

//------------------------------------------------------------------------------
void Emu::Discard() {
    saudio_shutdown();
    Input::UnsubscribeEvents(this->inputCallbackId);
}

//------------------------------------------------------------------------------
void Emu::Tick(Duration frameTime) {
    this->frameIndex++;
    if (this->switchedOn) {
        uint32_t microSecs = (uint32_t)frameTime.AsMicroSeconds();
        // clamp to 30Hz, in case we've been switched to the background
        if (microSecs > 33333) {
            microSecs = 33333;
        }
        kc85_exec(&this->kc85, (uint32_t)frameTime.AsMicroSeconds());
    }
    // start a game?
    if (this->startGamePath && (this->startGameFrameIndex == this->frameIndex)) {
        IO::Load(this->startGamePath, [this](IO::LoadResult ioResult) {
            kc85_quickload(&this->kc85, ioResult.Data.Data(), ioResult.Data.Size());
        });
        this->startGamePath = nullptr;
    }
}

//------------------------------------------------------------------------------
void Emu::Render(const glm::mat4& mvp) {
    if (this->switchedOn) {
        ImageDataAttrs updAttrs;
        updAttrs.NumFaces = 1;
        updAttrs.NumMipMaps = 1;
        updAttrs.Sizes[0][0] = sizeof(this->pixelBuffer);
        Gfx::UpdateTexture(this->drawState.FSTexture[0], this->pixelBuffer, updAttrs);
        EmuShader::vsParams vsParams;
        vsParams.mvp = mvp;
        Gfx::ApplyDrawState(this->drawState);
        Gfx::ApplyUniformBlock(vsParams);
        Gfx::Draw();
    }
}

//------------------------------------------------------------------------------
void Emu::TogglePower() {
    this->switchedOn = !this->switchedOn;
    if (this->switchedOn) {
        kc85_desc_t kc85_desc = { };
        kc85_desc.type = KC85_TYPE_3;
        kc85_desc.pixel_buffer = this->pixelBuffer;
        kc85_desc.pixel_buffer_size = sizeof(this->pixelBuffer);
        kc85_desc.audio_cb = push_audio;
        kc85_desc.audio_sample_rate = saudio_sample_rate();
        kc85_desc.patch_cb = patch_snapshots;
        kc85_desc.rom_caos31 = dump_caos31;
        kc85_desc.rom_caos31_size = sizeof(dump_caos31);
        kc85_desc.rom_kcbasic = dump_basic_c0;
        kc85_desc.rom_kcbasic_size = sizeof(dump_basic_c0);
        kc85_desc.user_data = (void*) this;
        kc85_init(&this->kc85, &kc85_desc);
        kc85_insert_ram_module(&this->kc85, 0x08, KC85_MODULE_M022_16KBYTE);
    }
    else {
        kc85_discard(&this->kc85);
    }
}

//------------------------------------------------------------------------------
bool Emu::SwitchedOn() const {
    return this->switchedOn;
}

//------------------------------------------------------------------------------
void Emu::Reset() {
    if (this->switchedOn) {
        kc85_reset(&this->kc85);
    }
}

//------------------------------------------------------------------------------
void Emu::StartGame(const char* path) {
    if (this->switchedOn) {
        this->TogglePower();
    }
    this->TogglePower();
    this->startGameFrameIndex = this->frameIndex + 3 * 60;
    this->startGamePath = path;
}

} // namespace Oryol

<|endoftext|>


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

#include <string.h>
#include <strings.h>
#include <stdio.h>

#include "MeshGroup.h"
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "utils/string.h"

#include "settings/SettingRegistry.h" // loadExtruderJSONsettings

namespace cura
{

FILE* binaryMeshBlob = nullptr;

/* Custom fgets function to support Mac line-ends in Ascii STL files. OpenSCAD produces this when used on Mac */
void* fgets_(char* ptr, size_t len, FILE* f)
{
    while(len && fread(ptr, 1, 1, f) > 0)
    {
        if (*ptr == '\n' || *ptr == '\r')
        {
            *ptr = '\0';
            return ptr;
        }
        ptr++;
        len--;
    }
    return nullptr;
}

MeshGroup::MeshGroup(SettingsBaseVirtual* settings_base)
: SettingsBase(settings_base)
, extruder_count(-1)
{}

MeshGroup::~MeshGroup()
{
    for (unsigned int extruder = 0; extruder < MAX_EXTRUDERS; extruder++)
    {
        if (extruders[extruder])
        {
            delete extruders[extruder];
        }
    }
}

int MeshGroup::getExtruderCount() const
{
    if (extruder_count == -1)
    {
        extruder_count = getSettingAsCount("machine_extruder_count");
    }
    return extruder_count;
}

ExtruderTrain* MeshGroup::createExtruderTrain(unsigned int extruder_nr)
{
    assert((int)extruder_nr >= 0 && (int)extruder_nr < getSettingAsCount("machine_extruder_count") && "only valid extruder trains may be requested!");
    if (!extruders[extruder_nr])
    {
        extruders[extruder_nr] = new ExtruderTrain(this, extruder_nr);
        int err = SettingRegistry::getInstance()->loadExtruderJSONsettings(extruder_nr, extruders[extruder_nr]);
        if (err)
        {
            logError("Couldn't load extruder.def.json for extruder %i\n", extruder_nr);
            std::exit(1);
        }
    }
    return extruders[extruder_nr];
}

ExtruderTrain* MeshGroup::getExtruderTrain(unsigned int extruder_nr)
{
    assert(extruders[extruder_nr]);
    return extruders[extruder_nr];
}

const ExtruderTrain* MeshGroup::getExtruderTrain(unsigned int extruder_nr) const
{
    assert(extruders[extruder_nr]);
    return extruders[extruder_nr];
}

Point3 MeshGroup::min() const
{
    if (meshes.size() < 1)
    {
        return Point3(0, 0, 0);
    }
    Point3 ret = meshes[0].min();
    for(unsigned int i=1; i<meshes.size(); i++)
    {
        Point3 v = meshes[i].min();
        ret.x = std::min(ret.x, v.x);
        ret.y = std::min(ret.y, v.y);
        ret.z = std::min(ret.z, v.z);
    }
    return ret;
}

Point3 MeshGroup::max() const
{
    if (meshes.size() < 1)
    {
        return Point3(0, 0, 0);
    }
    Point3 ret = meshes[0].max();
    for(unsigned int i=1; i<meshes.size(); i++)
    {
        Point3 v = meshes[i].max();
        ret.x = std::max(ret.x, v.x);
        ret.y = std::max(ret.y, v.y);
        ret.z = std::max(ret.z, v.z);
    }
    return ret;
}

void MeshGroup::clear()
{
    for(Mesh& m : meshes)
    {
        m.clear();
    }
}

void MeshGroup::finalize()
{
    extruder_count = getSettingAsCount("machine_extruder_count");

    //If the machine settings have been supplied, offset the given position vertices to the center of vertices (0,0,0) is at the bed center.
    Point3 meshgroup_offset(0, 0, 0);
    if (!getSettingBoolean("machine_center_is_zero"))
    {
        meshgroup_offset.x = getSettingInMicrons("machine_width") / 2;
        meshgroup_offset.y = getSettingInMicrons("machine_depth") / 2;
    }

    // If a mesh position was given, put the mesh at this position in 3D space.
    for(Mesh& mesh : meshes)
    {
        Point3 mesh_offset(mesh.getSettingInMicrons("mesh_position_x"), mesh.getSettingInMicrons("mesh_position_y"), mesh.getSettingInMicrons("mesh_position_z"));
        if (mesh.getSettingBoolean("center_object"))
        {
            Point3 object_min = mesh.min();
            Point3 object_max = mesh.max();
            Point3 object_size = object_max - object_min;
            mesh_offset += Point3(-object_min.x - object_size.x / 2, -object_min.y - object_size.y / 2, -object_min.z);
        }
        mesh.offset(mesh_offset + meshgroup_offset);
    }
}

bool loadMeshSTL_ascii(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rt");
    char buffer[1024];
    FPoint3 vertex;
    int n = 0;
    Point3 v0(0,0,0), v1(0,0,0), v2(0,0,0);
    while(fgets_(buffer, sizeof(buffer), f))
    {
        if (sscanf(buffer, " vertex %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3)
        {
            n++;
            switch(n)
            {
            case 1:
                v0 = matrix.apply(vertex);
                break;
            case 2:
                v1 = matrix.apply(vertex);
                break;
            case 3:
                v2 = matrix.apply(vertex);
                mesh->addFace(v0, v1, v2);
                n = 0;
                break;
            }
        }
    }
    fclose(f);
    mesh->finish();
    return true;
}

bool loadMeshSTL_binary(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rb");

    fseek(f, 0L, SEEK_END);
    long long file_size = ftell(f); //The file size is the position of the cursor after seeking to the end.
    rewind(f); //Seek back to start.
    size_t face_count = (file_size - 80 - sizeof(uint32_t)) / 50; //Subtract the size of the header. Every face uses exactly 50 bytes.

    char buffer[80];
    //Skip the header
    if (fread(buffer, 80, 1, f) != 1)
    {
        fclose(f);
        return false;
    }

    uint32_t reported_face_count;
    //Read the face count. We'll use it as a sort of redundancy code to check for file corruption.
    if (fread(&reported_face_count, sizeof(uint32_t), 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    if (reported_face_count != face_count)
    {
        logWarning("Face count reported by file (%s) is not equal to actual face count (%s). File could be corrupt!\n", std::to_string(reported_face_count).c_str(), std::to_string(face_count).c_str());
    }

    //For each face read:
    //float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags
    // Every Face is 50 Bytes: Normal(3*float), Vertices(9*float), 2 Bytes Spacer
    mesh->faces.reserve(face_count);
    mesh->vertices.reserve(face_count);
    for (unsigned int i = 0; i < face_count; i++)
    {
        if (fread(buffer, 50, 1, f) != 1)
        {
            fclose(f);
            return false;
        }
        float *v= ((float*)buffer)+3;

        Point3 v0 = matrix.apply(FPoint3(v[0], v[1], v[2]));
        Point3 v1 = matrix.apply(FPoint3(v[3], v[4], v[5]));
        Point3 v2 = matrix.apply(FPoint3(v[6], v[7], v[8]));
        mesh->addFace(v0, v1, v2);
    }
    fclose(f);
    mesh->finish();
    return true;
}

bool loadMeshSTL(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "r");
    if (f == nullptr)
    {
        return false;
    }

    //Skip any whitespace at the beginning of the file.
    unsigned long long num_whitespace = 0; //Number of whitespace characters.
    unsigned char whitespace;
    if (fread(&whitespace, 1, 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    while(isspace(whitespace))
    {
        num_whitespace++;
        if (fread(&whitespace, 1, 1, f) != 1)
        {
            fclose(f);
            return false;
        }
    }
    fseek(f, num_whitespace, SEEK_SET); //Seek to the place after all whitespace (we may have just read too far).

    char buffer[6];
    if (fread(buffer, 5, 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    fclose(f);

    buffer[5] = '\0';
    if (stringcasecompare(buffer, "solid") == 0)
    {
        bool load_success = loadMeshSTL_ascii(mesh, filename, matrix);
        if (!load_success)
            return false;

        // This logic is used to handle the case where the file starts with
        // "solid" but is a binary file.
        if (mesh->faces.size() < 1)
        {
            mesh->clear();
            return loadMeshSTL_binary(mesh, filename, matrix);
        }
        return true;
    }
    return loadMeshSTL_binary(mesh, filename, matrix);
}

bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const FMatrix3x3& transformation, SettingsBaseVirtual* object_parent_settings)
{
    TimeKeeper load_timer;

    const char* ext = strrchr(filename, '.');
    if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
    {
        Mesh mesh = object_parent_settings ? Mesh(object_parent_settings) : Mesh(meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
        if(loadMeshSTL(&mesh,filename,transformation)) //Load it! If successful...
        {
            meshgroup->meshes.push_back(mesh);
            log("loading '%s' took %.3f seconds\n",filename,load_timer.restart());
            return true;
        }
    }
    return false;
}

}//namespace cura
<commit_msg>Simplify max and min functions<commit_after>//Copyright (c) 2018 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include <string.h>
#include <strings.h>
#include <stdio.h>

#include "MeshGroup.h"
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "utils/string.h"

#include "settings/SettingRegistry.h" // loadExtruderJSONsettings

namespace cura
{

FILE* binaryMeshBlob = nullptr;

/* Custom fgets function to support Mac line-ends in Ascii STL files. OpenSCAD produces this when used on Mac */
void* fgets_(char* ptr, size_t len, FILE* f)
{
    while(len && fread(ptr, 1, 1, f) > 0)
    {
        if (*ptr == '\n' || *ptr == '\r')
        {
            *ptr = '\0';
            return ptr;
        }
        ptr++;
        len--;
    }
    return nullptr;
}

MeshGroup::MeshGroup(SettingsBaseVirtual* settings_base)
: SettingsBase(settings_base)
, extruder_count(-1)
{}

MeshGroup::~MeshGroup()
{
    for (unsigned int extruder = 0; extruder < MAX_EXTRUDERS; extruder++)
    {
        if (extruders[extruder])
        {
            delete extruders[extruder];
        }
    }
}

int MeshGroup::getExtruderCount() const
{
    if (extruder_count == -1)
    {
        extruder_count = getSettingAsCount("machine_extruder_count");
    }
    return extruder_count;
}

ExtruderTrain* MeshGroup::createExtruderTrain(unsigned int extruder_nr)
{
    assert((int)extruder_nr >= 0 && (int)extruder_nr < getSettingAsCount("machine_extruder_count") && "only valid extruder trains may be requested!");
    if (!extruders[extruder_nr])
    {
        extruders[extruder_nr] = new ExtruderTrain(this, extruder_nr);
        int err = SettingRegistry::getInstance()->loadExtruderJSONsettings(extruder_nr, extruders[extruder_nr]);
        if (err)
        {
            logError("Couldn't load extruder.def.json for extruder %i\n", extruder_nr);
            std::exit(1);
        }
    }
    return extruders[extruder_nr];
}

ExtruderTrain* MeshGroup::getExtruderTrain(unsigned int extruder_nr)
{
    assert(extruders[extruder_nr]);
    return extruders[extruder_nr];
}

const ExtruderTrain* MeshGroup::getExtruderTrain(unsigned int extruder_nr) const
{
    assert(extruders[extruder_nr]);
    return extruders[extruder_nr];
}

Point3 MeshGroup::min() const
{
    Point3 ret(0, 0, 0);

    for (const Mesh& mesh : meshes)
    {
        Point3 min = mesh.min();
        ret.x = std::min(ret.x, min.x);
        ret.y = std::min(ret.y, min.y);
        ret.z = std::min(ret.z, min.z);
    }
    return ret;
}

Point3 MeshGroup::max() const
{
    Point3 ret(0, 0, 0);

    for (const Mesh& mesh : meshes)
    {
        Point3 max = mesh.max();
        ret.x = std::max(ret.x, max.x);
        ret.y = std::max(ret.y, max.y);
        ret.z = std::max(ret.z, max.z);
    }
    return ret;
}

void MeshGroup::clear()
{
    for(Mesh& m : meshes)
    {
        m.clear();
    }
}

void MeshGroup::finalize()
{
    extruder_count = getSettingAsCount("machine_extruder_count");

    //If the machine settings have been supplied, offset the given position vertices to the center of vertices (0,0,0) is at the bed center.
    Point3 meshgroup_offset(0, 0, 0);
    if (!getSettingBoolean("machine_center_is_zero"))
    {
        meshgroup_offset.x = getSettingInMicrons("machine_width") / 2;
        meshgroup_offset.y = getSettingInMicrons("machine_depth") / 2;
    }

    // If a mesh position was given, put the mesh at this position in 3D space.
    for(Mesh& mesh : meshes)
    {
        Point3 mesh_offset(mesh.getSettingInMicrons("mesh_position_x"), mesh.getSettingInMicrons("mesh_position_y"), mesh.getSettingInMicrons("mesh_position_z"));
        if (mesh.getSettingBoolean("center_object"))
        {
            Point3 object_min = mesh.min();
            Point3 object_max = mesh.max();
            Point3 object_size = object_max - object_min;
            mesh_offset += Point3(-object_min.x - object_size.x / 2, -object_min.y - object_size.y / 2, -object_min.z);
        }
        mesh.offset(mesh_offset + meshgroup_offset);
    }
}

bool loadMeshSTL_ascii(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rt");
    char buffer[1024];
    FPoint3 vertex;
    int n = 0;
    Point3 v0(0,0,0), v1(0,0,0), v2(0,0,0);
    while(fgets_(buffer, sizeof(buffer), f))
    {
        if (sscanf(buffer, " vertex %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3)
        {
            n++;
            switch(n)
            {
            case 1:
                v0 = matrix.apply(vertex);
                break;
            case 2:
                v1 = matrix.apply(vertex);
                break;
            case 3:
                v2 = matrix.apply(vertex);
                mesh->addFace(v0, v1, v2);
                n = 0;
                break;
            }
        }
    }
    fclose(f);
    mesh->finish();
    return true;
}

bool loadMeshSTL_binary(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rb");

    fseek(f, 0L, SEEK_END);
    long long file_size = ftell(f); //The file size is the position of the cursor after seeking to the end.
    rewind(f); //Seek back to start.
    size_t face_count = (file_size - 80 - sizeof(uint32_t)) / 50; //Subtract the size of the header. Every face uses exactly 50 bytes.

    char buffer[80];
    //Skip the header
    if (fread(buffer, 80, 1, f) != 1)
    {
        fclose(f);
        return false;
    }

    uint32_t reported_face_count;
    //Read the face count. We'll use it as a sort of redundancy code to check for file corruption.
    if (fread(&reported_face_count, sizeof(uint32_t), 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    if (reported_face_count != face_count)
    {
        logWarning("Face count reported by file (%s) is not equal to actual face count (%s). File could be corrupt!\n", std::to_string(reported_face_count).c_str(), std::to_string(face_count).c_str());
    }

    //For each face read:
    //float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags
    // Every Face is 50 Bytes: Normal(3*float), Vertices(9*float), 2 Bytes Spacer
    mesh->faces.reserve(face_count);
    mesh->vertices.reserve(face_count);
    for (unsigned int i = 0; i < face_count; i++)
    {
        if (fread(buffer, 50, 1, f) != 1)
        {
            fclose(f);
            return false;
        }
        float *v= ((float*)buffer)+3;

        Point3 v0 = matrix.apply(FPoint3(v[0], v[1], v[2]));
        Point3 v1 = matrix.apply(FPoint3(v[3], v[4], v[5]));
        Point3 v2 = matrix.apply(FPoint3(v[6], v[7], v[8]));
        mesh->addFace(v0, v1, v2);
    }
    fclose(f);
    mesh->finish();
    return true;
}

bool loadMeshSTL(Mesh* mesh, const char* filename, const FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "r");
    if (f == nullptr)
    {
        return false;
    }

    //Skip any whitespace at the beginning of the file.
    unsigned long long num_whitespace = 0; //Number of whitespace characters.
    unsigned char whitespace;
    if (fread(&whitespace, 1, 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    while(isspace(whitespace))
    {
        num_whitespace++;
        if (fread(&whitespace, 1, 1, f) != 1)
        {
            fclose(f);
            return false;
        }
    }
    fseek(f, num_whitespace, SEEK_SET); //Seek to the place after all whitespace (we may have just read too far).

    char buffer[6];
    if (fread(buffer, 5, 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    fclose(f);

    buffer[5] = '\0';
    if (stringcasecompare(buffer, "solid") == 0)
    {
        bool load_success = loadMeshSTL_ascii(mesh, filename, matrix);
        if (!load_success)
            return false;

        // This logic is used to handle the case where the file starts with
        // "solid" but is a binary file.
        if (mesh->faces.size() < 1)
        {
            mesh->clear();
            return loadMeshSTL_binary(mesh, filename, matrix);
        }
        return true;
    }
    return loadMeshSTL_binary(mesh, filename, matrix);
}

bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, const FMatrix3x3& transformation, SettingsBaseVirtual* object_parent_settings)
{
    TimeKeeper load_timer;

    const char* ext = strrchr(filename, '.');
    if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
    {
        Mesh mesh = object_parent_settings ? Mesh(object_parent_settings) : Mesh(meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
        if(loadMeshSTL(&mesh,filename,transformation)) //Load it! If successful...
        {
            meshgroup->meshes.push_back(mesh);
            log("loading '%s' took %.3f seconds\n",filename,load_timer.restart());
            return true;
        }
    }
    return false;
}

}//namespace cura
<|endoftext|>


<commit_before>#include "NodeArray.h"

#include <glm/gtc/packing.hpp>
#include <Color.h>
#include "../../personal/system/StringUtils.h"

#include <algorithm>

#define EPSILON 0.0000000001
#define INITIAL_ALPHA		0.075f

using namespace std;

NodeArray::NodeArray()
  : size_method(SizeMethod::CONSTANT, 1.0f),
    node_color(0.0f, 0.0f, 0.0f, 0.0f),
    edge_color(0.0f, 0.0f, 0.0f, 0.0f),
    face_color(0.0f, 0.0f, 0.0f, 0.0f)
{

}

void
NodeArray::updateAppearance() {
  for (unsigned int i = 0; i < size(); i++) {
    updateAppearanceSlow(i);
  }
}

void
NodeArray::updateAppearanceSlow(int node_id) {
  string label, id, uname, name;

  if (label_method.getValue() == LabelMethod::AUTOMATIC_LABEL) {
    for (auto & cd : getTable().getColumns()) {
      string n = StringUtils::toLower(cd.first);
      if (n == "label") {
	label = cd.second->getText(node_id);
      } else if (n == "uname") {
	uname = cd.second->getText(node_id);
      } else if (n == "name") {
	name = cd.second->getText(node_id);
      } else if (n == "id") {
	id = cd.second->getText(node_id);
      }
    }
  }
  if (label_method.getValue() != LabelMethod::FIXED_LABEL) {
    if (label_method.getValue() == LabelMethod::LABEL_FROM_COLUMN) {
      label = getTable()[label_method.getColumn()].getText(node_id);
    } else if (label_method.getValue() == LabelMethod::AUTOMATIC_LABEL && label.empty()) {
      if (!uname.empty()) {
	label = uname;
      } else if (!name.empty()) {
	label = name;
      } else if (!id.empty()) {
	label = id;
      }
    }
    // cerr << "setting label for node " << node_id << ": " << label << endl;
    setLabel(node_id, label);
  }
}

static table::Column * sort_col = 0;

static bool compareRows(const int & a, const int & b) {
  return sort_col->compare(a, b);
}

#if 0
void
NodeArray::setNodeColorByColumn(int column) {
  sort_col = &(nodes[column]);
  if (size() <= 1) return;
  cerr << "setting colors by column " << sort_col->name() << endl;
  vector<int> v;
  for (int i = 0; i < size(); i++) {
      v.push_back(i);
  }
  sort(v.begin(), v.end(), compareRows);
  glm::vec3 c1(1.0, 0.0, 0.0), c2(1.0, 1.0, 0.0);
  for (int i = 0; i < v.size(); i++) {
    cerr << "node " << i << ": " << sort_col->getDouble(v[i]) << endl;
#if 1
    glm::vec3 c = glm::normalize(glm::mix(c1, c2, (float)(v.size() - 1 - i) / (v.size() - 1)));
#else
    Colorf c;
    c.setHSL(2.0f * (v.size() - 1 - i) / (v.size() - 1) / 3.0f, 0.75, 0.5);
#endif
    graph_color_s tmp = {
	(unsigned char)glm::clamp(int(c.r * 255.0f), 0, 255),
	  (unsigned char)glm::clamp(int(c.g * 255.0f), 0, 255),
	  (unsigned char)glm::clamp(int(c.b * 255.0f), 0, 255),
	  255
    };
    setNodeColor2(v[i], tmp);
  }
  version++;
  // updateFlags(GF_PER_NODE_COLORS, true);
}
#endif

void
NodeArray::setNormal(int i, const glm::vec4 & v) {
  node_geometry[i].normal = glm::packSnorm3x10_1x2(v);
  version++;
}

#if 0
void
NodeArray::setNodeColor2(int i, const canvas::Color & c) {
  int r = int(c.red * 0xff), g = int(c.green * 0xff), b = int(c.blue * 0xff), a = int(c.alpha * 0xff);
  if (r > 255) r = 255;
  else if (r < 0) r = 0;
  if (g > 255) g = 255;
  else if (g < 0) g = 0;
  if (b > 255) b = 255;
  else if (b < 0) b = 0;
  if (a > 255) a = 255;
  else if (a < 0) a = 0;
  graph_color_s tmp = { (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a };
  setNodeColor2(i, tmp);
}
#endif

void
NodeArray::resume2() {
  alpha = INITIAL_ALPHA;
}

void
NodeArray::setLabelTexture(const skey & key, int texture) {
  auto it2 = getNodeCache().find(key);
  if (it2 != getNodeCache().end()) {
    setLabelTexture(it2->second, texture);
  }
}

void
NodeArray::setRandomPosition(int node_id) {
  glm::vec3 v1( 10.0 * rand() / RAND_MAX - 5,
		10.0 * rand() / RAND_MAX - 5,
		10.0 * rand() / RAND_MAX - 5
		);
  setPosition(node_id, v1);
}
<commit_msg>increase random node placement range<commit_after>#include "NodeArray.h"

#include <glm/gtc/packing.hpp>
#include <Color.h>
#include "../../personal/system/StringUtils.h"

#include <algorithm>

#define EPSILON 0.0000000001
#define INITIAL_ALPHA		0.075f

using namespace std;

NodeArray::NodeArray()
  : size_method(SizeMethod::CONSTANT, 1.0f),
    node_color(0.0f, 0.0f, 0.0f, 0.0f),
    edge_color(0.0f, 0.0f, 0.0f, 0.0f),
    face_color(0.0f, 0.0f, 0.0f, 0.0f)
{

}

void
NodeArray::updateAppearance() {
  for (unsigned int i = 0; i < size(); i++) {
    updateAppearanceSlow(i);
  }
}

void
NodeArray::updateAppearanceSlow(int node_id) {
  string label, id, uname, name;

  if (label_method.getValue() == LabelMethod::AUTOMATIC_LABEL) {
    for (auto & cd : getTable().getColumns()) {
      string n = StringUtils::toLower(cd.first);
      if (n == "label") {
	label = cd.second->getText(node_id);
      } else if (n == "uname") {
	uname = cd.second->getText(node_id);
      } else if (n == "name") {
	name = cd.second->getText(node_id);
      } else if (n == "id") {
	id = cd.second->getText(node_id);
      }
    }
  }
  if (label_method.getValue() != LabelMethod::FIXED_LABEL) {
    if (label_method.getValue() == LabelMethod::LABEL_FROM_COLUMN) {
      label = getTable()[label_method.getColumn()].getText(node_id);
    } else if (label_method.getValue() == LabelMethod::AUTOMATIC_LABEL && label.empty()) {
      if (!uname.empty()) {
	label = uname;
      } else if (!name.empty()) {
	label = name;
      } else if (!id.empty()) {
	label = id;
      }
    }
    // cerr << "setting label for node " << node_id << ": " << label << endl;
    setLabel(node_id, label);
  }
}

static table::Column * sort_col = 0;

static bool compareRows(const int & a, const int & b) {
  return sort_col->compare(a, b);
}

#if 0
void
NodeArray::setNodeColorByColumn(int column) {
  sort_col = &(nodes[column]);
  if (size() <= 1) return;
  cerr << "setting colors by column " << sort_col->name() << endl;
  vector<int> v;
  for (int i = 0; i < size(); i++) {
      v.push_back(i);
  }
  sort(v.begin(), v.end(), compareRows);
  glm::vec3 c1(1.0, 0.0, 0.0), c2(1.0, 1.0, 0.0);
  for (int i = 0; i < v.size(); i++) {
    cerr << "node " << i << ": " << sort_col->getDouble(v[i]) << endl;
#if 1
    glm::vec3 c = glm::normalize(glm::mix(c1, c2, (float)(v.size() - 1 - i) / (v.size() - 1)));
#else
    Colorf c;
    c.setHSL(2.0f * (v.size() - 1 - i) / (v.size() - 1) / 3.0f, 0.75, 0.5);
#endif
    graph_color_s tmp = {
	(unsigned char)glm::clamp(int(c.r * 255.0f), 0, 255),
	  (unsigned char)glm::clamp(int(c.g * 255.0f), 0, 255),
	  (unsigned char)glm::clamp(int(c.b * 255.0f), 0, 255),
	  255
    };
    setNodeColor2(v[i], tmp);
  }
  version++;
  // updateFlags(GF_PER_NODE_COLORS, true);
}
#endif

void
NodeArray::setNormal(int i, const glm::vec4 & v) {
  node_geometry[i].normal = glm::packSnorm3x10_1x2(v);
  version++;
}

#if 0
void
NodeArray::setNodeColor2(int i, const canvas::Color & c) {
  int r = int(c.red * 0xff), g = int(c.green * 0xff), b = int(c.blue * 0xff), a = int(c.alpha * 0xff);
  if (r > 255) r = 255;
  else if (r < 0) r = 0;
  if (g > 255) g = 255;
  else if (g < 0) g = 0;
  if (b > 255) b = 255;
  else if (b < 0) b = 0;
  if (a > 255) a = 255;
  else if (a < 0) a = 0;
  graph_color_s tmp = { (unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a };
  setNodeColor2(i, tmp);
}
#endif

void
NodeArray::resume2() {
  alpha = INITIAL_ALPHA;
}

void
NodeArray::setLabelTexture(const skey & key, int texture) {
  auto it2 = getNodeCache().find(key);
  if (it2 != getNodeCache().end()) {
    setLabelTexture(it2->second, texture);
  }
}

void
NodeArray::setRandomPosition(int node_id) {
  glm::vec3 v1( 100.0 * rand() / RAND_MAX - 50,
		100.0 * rand() / RAND_MAX - 50,
		0 // 100.0 * rand() / RAND_MAX - 50
		);
  setPosition(node_id, v1);
}
<|endoftext|>


<commit_before>#include "IR.h"
#include "IROperator.h"
#include "ObjectInstanceRegistry.h"
#include "Parameter.h"
#include "Simplify.h"

namespace Halide {
namespace Internal {

struct ParameterContents {
    mutable RefCount ref_count;
    Type type;
    const bool is_buffer;
    int dimensions;
    const bool is_explicit_name;
    const bool is_registered;
    std::string name;
    Buffer buffer;
    uint64_t data;
    Expr min_constraint[4];
    Expr extent_constraint[4];
    Expr stride_constraint[4];
    Expr min_value, max_value;
    ParameterContents(Type t, bool b, int d, const std::string &n, bool e, bool r)
        : type(t), is_buffer(b), dimensions(d), is_explicit_name(e), is_registered(r), name(n), buffer(Buffer()), data(0) {
        // stride_constraint[0] defaults to 1. This is important for
        // dense vectorization. You can unset it by setting it to a
        // null expression. (param.set_stride(0, Expr());)
        stride_constraint[0] = 1;
    }
};

template<>
EXPORT RefCount &ref_count<Halide::Internal::ParameterContents>(const ParameterContents *p) {return p->ref_count;}

template<>
EXPORT void destroy<Halide::Internal::ParameterContents>(const ParameterContents *p) {delete p;}

void Parameter::check_defined() const {
    user_assert(defined()) << "Parameter is undefined\n";
}

void Parameter::check_is_buffer() const {
    check_defined();
    user_assert(contents.ptr->is_buffer) << "Parameter " << name() << " is not a Buffer\n";
}

void Parameter::check_is_scalar() const {
    check_defined();
    user_assert(!contents.ptr->is_buffer) << "Parameter " << name() << " is a Buffer\n";
}

void Parameter::check_dim_ok(int dim) const {
    user_assert(dim >= 0 && dim < dimensions())
        << "Dimension " << dim << " is not in the range [0, " << dimensions() - 1 << "]\n";
}

Parameter::Parameter() : contents(NULL) {
    // Undefined Parameters are never registered.
}

Parameter::Parameter(Type t, bool is_buffer, int d) :
    contents(new ParameterContents(t, is_buffer, d, unique_name('p'), false, true)) {
    internal_assert(is_buffer || d == 0) << "Scalar parameters should be zero-dimensional";
    // Note that is_registered is always true here; this is just using a parallel code structure for clarity.
    if (contents.defined() && contents.ptr->is_registered) {
        ObjectInstanceRegistry::register_instance(this, 0, ObjectInstanceRegistry::FilterParam, this, NULL);
    }
}

Parameter::Parameter(Type t, bool is_buffer, int d, const std::string &name, bool is_explicit_name, bool register_instance) :
    contents(new ParameterContents(t, is_buffer, d, name, is_explicit_name, register_instance)) {
    internal_assert(is_buffer || d == 0) << "Scalar parameters should be zero-dimensional";
    if (contents.defined() && contents.ptr->is_registered) {
        ObjectInstanceRegistry::register_instance(this, 0, ObjectInstanceRegistry::FilterParam, this, NULL);
    }
}

Parameter::Parameter(const Parameter& that) : contents(that.contents) {
    if (contents.defined() && contents.ptr->is_registered) {
        ObjectInstanceRegistry::register_instance(this, 0, ObjectInstanceRegistry::FilterParam, this, NULL);
    }
}

Parameter& Parameter::operator=(const Parameter& that) {
    bool was_registered = contents.defined() && contents.ptr->is_registered;
    contents = that.contents;
    bool should_be_registered = contents.defined() && contents.ptr->is_registered;
    if (should_be_registered && !was_registered) {
        // This can happen if you do:
        // Parameter p; // undefined
        // p = make_interesting_parameter();
        ObjectInstanceRegistry::register_instance(this, 0, ObjectInstanceRegistry::FilterParam, this, NULL);
    } else if (!should_be_registered && was_registered) {
        // This can happen if you do:
        // Parameter p = make_interesting_parameter();
        // p = Parameter();
        ObjectInstanceRegistry::unregister_instance(this);
    }
    return *this;
}

Parameter::~Parameter() {
    if (contents.defined() && contents.ptr->is_registered) {
        ObjectInstanceRegistry::unregister_instance(this);
    }
}

Type Parameter::type() const {
    check_defined();
    return contents.ptr->type;
}

int Parameter::dimensions() const {
    check_defined();
    return contents.ptr->dimensions;
}

const std::string &Parameter::name() const {
    check_defined();
    return contents.ptr->name;
}

bool Parameter::is_explicit_name() const {
    check_defined();
    return contents.ptr->is_explicit_name;
}

bool Parameter::is_buffer() const {
    check_defined();
    return contents.ptr->is_buffer;
}

Expr Parameter::get_scalar_expr() const {
    check_is_scalar();
    const Type t = type();
    if (t.is_bool()) {
      return scalar_to_constant_expr<bool>(get_scalar<bool>());
    } else if (t.is_float()) {
      switch (t.bits) {
        case 32: return scalar_to_constant_expr<float>(get_scalar<float>());
        case 64: return scalar_to_constant_expr<double>(get_scalar<double>());
      }
    } else if (t.is_int()) {
      switch (t.bits) {
        case 8: return scalar_to_constant_expr<int8_t>(get_scalar<int8_t>());
        case 16: return scalar_to_constant_expr<int16_t>(get_scalar<int16_t>());
        case 64: return scalar_to_constant_expr<int32_t>(get_scalar<int32_t>());
        case 32: return scalar_to_constant_expr<int64_t>(get_scalar<int64_t>());
      }
    } else if (t.is_uint()) {
      switch (t.bits) {
        case 8: return scalar_to_constant_expr<uint8_t>(get_scalar<uint8_t>());
        case 16: return scalar_to_constant_expr<uint16_t>(get_scalar<uint16_t>());
        case 64: return scalar_to_constant_expr<uint32_t>(get_scalar<uint32_t>());
        case 32: return scalar_to_constant_expr<uint64_t>(get_scalar<uint64_t>());
      }
    }
    return Expr();
}

Buffer Parameter::get_buffer() const {
    check_is_buffer();
    return contents.ptr->buffer;
}

void Parameter::set_buffer(Buffer b) {
    check_is_buffer();
    if (b.defined()) {
        user_assert(contents.ptr->type == b.type())
            << "Can't bind Parameter " << name()
            << " of type " << contents.ptr->type
            << " to Buffer " << b.name()
            << " of type " << b.type() << "\n";
    }
    contents.ptr->buffer = b;
}

void *Parameter::get_scalar_address() const {
    check_is_scalar();
    return &contents.ptr->data;
}

/** Tests if this handle is the same as another handle */
bool Parameter::same_as(const Parameter &other) const {
    return contents.ptr == other.contents.ptr;
}

/** Tests if this handle is non-NULL */
bool Parameter::defined() const {
    return contents.defined();
}

void Parameter::set_min_constraint(int dim, Expr e) {
    check_is_buffer();
    check_dim_ok(dim);
    contents.ptr->min_constraint[dim] = e;
}

void Parameter::set_extent_constraint(int dim, Expr e) {
    check_is_buffer();
    check_dim_ok(dim);
    contents.ptr->extent_constraint[dim] = e;
}

void Parameter::set_stride_constraint(int dim, Expr e) {
    check_is_buffer();
    check_dim_ok(dim);
    contents.ptr->stride_constraint[dim] = e;
}

Expr Parameter::min_constraint(int dim) const {
    check_is_buffer();
    check_dim_ok(dim);
    return contents.ptr->min_constraint[dim];
}

Expr Parameter::extent_constraint(int dim) const {
    check_is_buffer();
    check_dim_ok(dim);
    return contents.ptr->extent_constraint[dim];
}

Expr Parameter::stride_constraint(int dim) const {
    check_is_buffer();
    check_dim_ok(dim);
    return contents.ptr->stride_constraint[dim];
}

void Parameter::set_min_value(Expr e) {
    check_is_scalar();
    user_assert(e.type() == contents.ptr->type)
        << "Can't set parameter " << name()
        << " of type " << contents.ptr->type
        << " to have min value " << e
        << " of type " << e.type() << "\n";
    contents.ptr->min_value = e;
}

Expr Parameter::get_min_value() const {
    check_is_scalar();
    return contents.ptr->min_value;
}

void Parameter::set_max_value(Expr e) {
    check_is_scalar();
    user_assert(e.type() == contents.ptr->type)
        << "Can't set parameter " << name()
        << " of type " << contents.ptr->type
        << " to have max value " << e
        << " of type " << e.type() << "\n";
    contents.ptr->max_value = e;
}

Expr Parameter::get_max_value() const {
    check_is_scalar();
    return contents.ptr->max_value;
}

void check_call_arg_types(const std::string &name, std::vector<Expr> *args, int dims) {
    user_assert(args->size() == (size_t)dims)
        << args->size() << "-argument call to \""
        << name << "\", which has " << dims << " dimensions.\n";

    for (size_t i = 0; i < args->size(); i++) {
        user_assert((*args)[i].defined())
            << "Argument " << i << " to call to \"" << name << "\" is an undefined Expr\n";
        Type t = (*args)[i].type();
        if (t.is_float() || (t.is_uint() && t.bits >= 32) || (t.is_int() && t.bits > 32)) {
            user_error << "Implicit cast from " << t << " to int in argument " << (i+1)
                       << " in call to \"" << name << "\" is not allowed. Use an explicit cast.\n";
        }
        // We're allowed to implicitly cast from other varieties of int
        if (t != Int(32)) {
            (*args)[i] = Internal::Cast::make(Int(32), (*args)[i]);
        }
    }
}

}
}

<commit_msg>Fix incorrect switch<commit_after>#include "IR.h"
#include "IROperator.h"
#include "ObjectInstanceRegistry.h"
#include "Parameter.h"
#include "Simplify.h"

namespace Halide {
namespace Internal {

struct ParameterContents {
    mutable RefCount ref_count;
    Type type;
    const bool is_buffer;
    int dimensions;
    const bool is_explicit_name;
    const bool is_registered;
    std::string name;
    Buffer buffer;
    uint64_t data;
    Expr min_constraint[4];
    Expr extent_constraint[4];
    Expr stride_constraint[4];
    Expr min_value, max_value;
    ParameterContents(Type t, bool b, int d, const std::string &n, bool e, bool r)
        : type(t), is_buffer(b), dimensions(d), is_explicit_name(e), is_registered(r), name(n), buffer(Buffer()), data(0) {
        // stride_constraint[0] defaults to 1. This is important for
        // dense vectorization. You can unset it by setting it to a
        // null expression. (param.set_stride(0, Expr());)
        stride_constraint[0] = 1;
    }
};

template<>
EXPORT RefCount &ref_count<Halide::Internal::ParameterContents>(const ParameterContents *p) {return p->ref_count;}

template<>
EXPORT void destroy<Halide::Internal::ParameterContents>(const ParameterContents *p) {delete p;}

void Parameter::check_defined() const {
    user_assert(defined()) << "Parameter is undefined\n";
}

void Parameter::check_is_buffer() const {
    check_defined();
    user_assert(contents.ptr->is_buffer) << "Parameter " << name() << " is not a Buffer\n";
}

void Parameter::check_is_scalar() const {
    check_defined();
    user_assert(!contents.ptr->is_buffer) << "Parameter " << name() << " is a Buffer\n";
}

void Parameter::check_dim_ok(int dim) const {
    user_assert(dim >= 0 && dim < dimensions())
        << "Dimension " << dim << " is not in the range [0, " << dimensions() - 1 << "]\n";
}

Parameter::Parameter() : contents(NULL) {
    // Undefined Parameters are never registered.
}

Parameter::Parameter(Type t, bool is_buffer, int d) :
    contents(new ParameterContents(t, is_buffer, d, unique_name('p'), false, true)) {
    internal_assert(is_buffer || d == 0) << "Scalar parameters should be zero-dimensional";
    // Note that is_registered is always true here; this is just using a parallel code structure for clarity.
    if (contents.defined() && contents.ptr->is_registered) {
        ObjectInstanceRegistry::register_instance(this, 0, ObjectInstanceRegistry::FilterParam, this, NULL);
    }
}

Parameter::Parameter(Type t, bool is_buffer, int d, const std::string &name, bool is_explicit_name, bool register_instance) :
    contents(new ParameterContents(t, is_buffer, d, name, is_explicit_name, register_instance)) {
    internal_assert(is_buffer || d == 0) << "Scalar parameters should be zero-dimensional";
    if (contents.defined() && contents.ptr->is_registered) {
        ObjectInstanceRegistry::register_instance(this, 0, ObjectInstanceRegistry::FilterParam, this, NULL);
    }
}

Parameter::Parameter(const Parameter& that) : contents(that.contents) {
    if (contents.defined() && contents.ptr->is_registered) {
        ObjectInstanceRegistry::register_instance(this, 0, ObjectInstanceRegistry::FilterParam, this, NULL);
    }
}

Parameter& Parameter::operator=(const Parameter& that) {
    bool was_registered = contents.defined() && contents.ptr->is_registered;
    contents = that.contents;
    bool should_be_registered = contents.defined() && contents.ptr->is_registered;
    if (should_be_registered && !was_registered) {
        // This can happen if you do:
        // Parameter p; // undefined
        // p = make_interesting_parameter();
        ObjectInstanceRegistry::register_instance(this, 0, ObjectInstanceRegistry::FilterParam, this, NULL);
    } else if (!should_be_registered && was_registered) {
        // This can happen if you do:
        // Parameter p = make_interesting_parameter();
        // p = Parameter();
        ObjectInstanceRegistry::unregister_instance(this);
    }
    return *this;
}

Parameter::~Parameter() {
    if (contents.defined() && contents.ptr->is_registered) {
        ObjectInstanceRegistry::unregister_instance(this);
    }
}

Type Parameter::type() const {
    check_defined();
    return contents.ptr->type;
}

int Parameter::dimensions() const {
    check_defined();
    return contents.ptr->dimensions;
}

const std::string &Parameter::name() const {
    check_defined();
    return contents.ptr->name;
}

bool Parameter::is_explicit_name() const {
    check_defined();
    return contents.ptr->is_explicit_name;
}

bool Parameter::is_buffer() const {
    check_defined();
    return contents.ptr->is_buffer;
}

Expr Parameter::get_scalar_expr() const {
    check_is_scalar();
    const Type t = type();
    if (t.is_bool()) {
      return scalar_to_constant_expr<bool>(get_scalar<bool>());
    } else if (t.is_float()) {
      switch (t.bits) {
        case 32: return scalar_to_constant_expr<float>(get_scalar<float>());
        case 64: return scalar_to_constant_expr<double>(get_scalar<double>());
      }
    } else if (t.is_int()) {
      switch (t.bits) {
        case 8: return scalar_to_constant_expr<int8_t>(get_scalar<int8_t>());
        case 16: return scalar_to_constant_expr<int16_t>(get_scalar<int16_t>());
        case 32: return scalar_to_constant_expr<int32_t>(get_scalar<int32_t>());
        case 64: return scalar_to_constant_expr<int64_t>(get_scalar<int64_t>());
      }
    } else if (t.is_uint()) {
      switch (t.bits) {
        case 8: return scalar_to_constant_expr<uint8_t>(get_scalar<uint8_t>());
        case 16: return scalar_to_constant_expr<uint16_t>(get_scalar<uint16_t>());
        case 32: return scalar_to_constant_expr<uint32_t>(get_scalar<uint32_t>());
        case 64: return scalar_to_constant_expr<uint64_t>(get_scalar<uint64_t>());
      }
    }
    return Expr();
}

Buffer Parameter::get_buffer() const {
    check_is_buffer();
    return contents.ptr->buffer;
}

void Parameter::set_buffer(Buffer b) {
    check_is_buffer();
    if (b.defined()) {
        user_assert(contents.ptr->type == b.type())
            << "Can't bind Parameter " << name()
            << " of type " << contents.ptr->type
            << " to Buffer " << b.name()
            << " of type " << b.type() << "\n";
    }
    contents.ptr->buffer = b;
}

void *Parameter::get_scalar_address() const {
    check_is_scalar();
    return &contents.ptr->data;
}

/** Tests if this handle is the same as another handle */
bool Parameter::same_as(const Parameter &other) const {
    return contents.ptr == other.contents.ptr;
}

/** Tests if this handle is non-NULL */
bool Parameter::defined() const {
    return contents.defined();
}

void Parameter::set_min_constraint(int dim, Expr e) {
    check_is_buffer();
    check_dim_ok(dim);
    contents.ptr->min_constraint[dim] = e;
}

void Parameter::set_extent_constraint(int dim, Expr e) {
    check_is_buffer();
    check_dim_ok(dim);
    contents.ptr->extent_constraint[dim] = e;
}

void Parameter::set_stride_constraint(int dim, Expr e) {
    check_is_buffer();
    check_dim_ok(dim);
    contents.ptr->stride_constraint[dim] = e;
}

Expr Parameter::min_constraint(int dim) const {
    check_is_buffer();
    check_dim_ok(dim);
    return contents.ptr->min_constraint[dim];
}

Expr Parameter::extent_constraint(int dim) const {
    check_is_buffer();
    check_dim_ok(dim);
    return contents.ptr->extent_constraint[dim];
}

Expr Parameter::stride_constraint(int dim) const {
    check_is_buffer();
    check_dim_ok(dim);
    return contents.ptr->stride_constraint[dim];
}

void Parameter::set_min_value(Expr e) {
    check_is_scalar();
    user_assert(e.type() == contents.ptr->type)
        << "Can't set parameter " << name()
        << " of type " << contents.ptr->type
        << " to have min value " << e
        << " of type " << e.type() << "\n";
    contents.ptr->min_value = e;
}

Expr Parameter::get_min_value() const {
    check_is_scalar();
    return contents.ptr->min_value;
}

void Parameter::set_max_value(Expr e) {
    check_is_scalar();
    user_assert(e.type() == contents.ptr->type)
        << "Can't set parameter " << name()
        << " of type " << contents.ptr->type
        << " to have max value " << e
        << " of type " << e.type() << "\n";
    contents.ptr->max_value = e;
}

Expr Parameter::get_max_value() const {
    check_is_scalar();
    return contents.ptr->max_value;
}

void check_call_arg_types(const std::string &name, std::vector<Expr> *args, int dims) {
    user_assert(args->size() == (size_t)dims)
        << args->size() << "-argument call to \""
        << name << "\", which has " << dims << " dimensions.\n";

    for (size_t i = 0; i < args->size(); i++) {
        user_assert((*args)[i].defined())
            << "Argument " << i << " to call to \"" << name << "\" is an undefined Expr\n";
        Type t = (*args)[i].type();
        if (t.is_float() || (t.is_uint() && t.bits >= 32) || (t.is_int() && t.bits > 32)) {
            user_error << "Implicit cast from " << t << " to int in argument " << (i+1)
                       << " in call to \"" << name << "\" is not allowed. Use an explicit cast.\n";
        }
        // We're allowed to implicitly cast from other varieties of int
        if (t != Int(32)) {
            (*args)[i] = Internal::Cast::make(Int(32), (*args)[i]);
        }
    }
}

}
}

<|endoftext|>


<commit_before><commit_msg>optional: pointer()を定義<commit_after><|endoftext|>


<commit_before>#include "RadixSort.h"

RadixSort::RadixSort (GLuint _numblocks)
	: blocksize (512), numblocks (_numblocks)
{
	// load shaders
	counting.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/counting.glsl", "shaders/simulation/include.glsl");
	counting.Link ();
	blockscan.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/blockscan.glsl", "shaders/simulation/include.glsl");
	blockscan.Link ();
	globalsort.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/globalsort.glsl", "shaders/simulation/include.glsl");
	globalsort.Link ();
	addblocksum.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/addblocksum.glsl", "shaders/simulation/include.glsl");
	addblocksum.Link ();

	// create buffer objects
	glGenBuffers (3, buffers);

	// allocate input buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, buffer);
	glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (glm::vec4) * blocksize * numblocks, NULL, GL_DYNAMIC_DRAW);

	// allocate prefix sum buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, prefixsums);
	glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * blocksize * numblocks, NULL, GL_DYNAMIC_DRAW);

	// create block sum buffers
	uint32_t numblocksums = 4 * numblocks;
	{
		int n = ceil (log (((numblocksums + blocksize - 1) / blocksize) * blocksize) / log (blocksize));
		n++;
		blocksums.resize (n);
		glGenBuffers (n, &blocksums[0]);
	}
	for (int i = 0; i < blocksums.size (); i++)
	{
		GLuint &blocksum = blocksums[i];
		// allocate a single block sum buffer
		glBindBuffer (GL_SHADER_STORAGE_BUFFER, blocksum);
		numblocksums = ((numblocksums + blocksize - 1) / blocksize) * blocksize;
		if (numblocksums < 1)
			numblocksums = 1;
		glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * numblocksums, NULL, GL_STATIC_DRAW);
		numblocksums /= blocksize;
	}

	// allocate output buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, result);
	glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (glm::vec4) * blocksize * numblocks, NULL, GL_STATIC_DRAW);

	// pass block sum offsets to the shader programs
	glm::uvec4 blocksumoffsets (0, numblocks, numblocks * 2, numblocks * 3);
	glProgramUniform4uiv (counting.get (), counting.GetUniformLocation ("blocksumoffsets"), 1,
			glm::value_ptr (blocksumoffsets));
	glProgramUniform4uiv (globalsort.get (), globalsort.GetUniformLocation ("blocksumoffsets"), 1,
			glm::value_ptr (blocksumoffsets));

	// query uniform locations
	counting_bitshift = counting.GetUniformLocation ("bitshift");
	globalsort_bitshift = globalsort.GetUniformLocation ("bitshift");

	// clear block sum buffers
	for (int i = 0; i < blocksums.size (); i++)
	{
		unsigned int &blocksum = blocksums[i];
		glBindBuffer (GL_SHADER_STORAGE_BUFFER, blocksum);
		glClearBufferData (GL_SHADER_STORAGE_BUFFER, GL_RGBA32UI, GL_RGBA, GL_UNSIGNED_INT, NULL);
	}
	glMemoryBarrier (GL_BUFFER_UPDATE_BARRIER_BIT);
}

RadixSort::~RadixSort (void)
{
	// cleanup
	glDeleteBuffers (blocksums.size (), &blocksums[0]);
	glDeleteBuffers (3, buffers);
}

GLuint RadixSort::GetBuffer (void) const
{
	// return the current input buffer
	return buffer;
}

void RadixSort::Run (unsigned int numbits)
{
	// sort bits from least to most significant
	for (int i = 0; i < (numbits + 1) >> 1; i++)
	{
		SortBits (2 * i);
		// swap the buffer objects
		std::swap (result, buffer);
	}
}

/** Integer power.
 * Calculates an integer power.
 * \param x base
 * \param y exponent
 * \returns x to the power of y
 */
uint32_t intpow (uint32_t x, uint32_t y)
{
	uint32_t r = 1;
	while (y)
	{
		if (y & 1)
			r *= x;
		y >>= 1;
		x *= x;
	}
	return r;
}

void RadixSort::SortBits (int bits)
{
	// pass current bit shift to the shader programs
	glProgramUniform1i (counting.get (), counting_bitshift, bits);
	glProgramUniform1i (globalsort.get (), globalsort_bitshift, bits);

	// set buffer bindings
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, buffer);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, prefixsums);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 2, blocksums.front ());
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 3, result);

	// counting
	counting.Use ();
	glDispatchCompute (numblocks, 1, 1);
	glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);

	// create block sums level by level
	blockscan.Use ();
	uint32_t numblocksums = (4 * numblocks) / blocksize;
	for (int i = 0; i < blocksums.size () - 1; i++)
	{
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, blocksums[i]);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, blocksums[i + 1]);
		glDispatchCompute (numblocksums > 0 ? numblocksums : 1, 1, 1);
		numblocksums /= blocksize;
		glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
	}

	// add block sums level by level (in reversed order)
	addblocksum.Use ();
	for (int i = blocksums.size () - 3; i >= 0; i--)
	{
		uint32_t numblocksums = (4 * numblocks) / intpow (blocksize, i + 1);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, blocksums[i]);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, blocksums[i + 1]);
		glDispatchCompute (numblocksums > 0 ? numblocksums : 1, 1, 1);
		glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
	}

	// map values to their global position in the output buffer
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, buffer);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, prefixsums);
	globalsort.Use ();
	glDispatchCompute (numblocks, 1, 1);
	glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
}
<commit_msg>More buffer tweaks.<commit_after>#include "RadixSort.h"

RadixSort::RadixSort (GLuint _numblocks)
	: blocksize (512), numblocks (_numblocks)
{
	// load shaders
	counting.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/counting.glsl", "shaders/simulation/include.glsl");
	counting.Link ();
	blockscan.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/blockscan.glsl", "shaders/simulation/include.glsl");
	blockscan.Link ();
	globalsort.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/globalsort.glsl", "shaders/simulation/include.glsl");
	globalsort.Link ();
	addblocksum.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/addblocksum.glsl", "shaders/simulation/include.glsl");
	addblocksum.Link ();

	// create buffer objects
	glGenBuffers (3, buffers);

    // determine OpenGL extension support
    bool use_buffer_storage = IsExtensionSupported ("GL_ARB_buffer_storage");

	// allocate input buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, buffer);
	if (use_buffer_storage)
		glBufferStorage (GL_SHADER_STORAGE_BUFFER, sizeof (glm::vec4) * blocksize * numblocks, NULL, 0);
	else
		glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (glm::vec4) * blocksize * numblocks, NULL, GL_DYNAMIC_COPY);

	// allocate prefix sum buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, prefixsums);
	if (use_buffer_storage)
		glBufferStorage (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * blocksize * numblocks, NULL, 0);
	else
		glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * blocksize * numblocks, NULL, GL_DYNAMIC_COPY);

	// create block sum buffers
	uint32_t numblocksums = 4 * numblocks;
	{
		int n = ceil (log (((numblocksums + blocksize - 1) / blocksize) * blocksize) / log (blocksize));
		n++;
		blocksums.resize (n);
		glGenBuffers (n, &blocksums[0]);
	}
	for (int i = 0; i < blocksums.size (); i++)
	{
		GLuint &blocksum = blocksums[i];
		// allocate a single block sum buffer
		glBindBuffer (GL_SHADER_STORAGE_BUFFER, blocksum);
		numblocksums = ((numblocksums + blocksize - 1) / blocksize) * blocksize;
		if (numblocksums < 1)
			numblocksums = 1;
		if (use_buffer_storage)
			glBufferStorage (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * numblocksums, NULL, 0);
		else
			glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * numblocksums, NULL, GL_DYNAMIC_COPY);
		numblocksums /= blocksize;
	}

	// allocate output buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, result);
	if (use_buffer_storage)
		glBufferStorage (GL_SHADER_STORAGE_BUFFER, sizeof (glm::vec4) * blocksize * numblocks, NULL, 0);
	else
		glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (glm::vec4) * blocksize * numblocks, NULL, GL_DYNAMIC_COPY);

	// pass block sum offsets to the shader programs
	glm::uvec4 blocksumoffsets (0, numblocks, numblocks * 2, numblocks * 3);
	glProgramUniform4uiv (counting.get (), counting.GetUniformLocation ("blocksumoffsets"), 1,
			glm::value_ptr (blocksumoffsets));
	glProgramUniform4uiv (globalsort.get (), globalsort.GetUniformLocation ("blocksumoffsets"), 1,
			glm::value_ptr (blocksumoffsets));

	// query uniform locations
	counting_bitshift = counting.GetUniformLocation ("bitshift");
	globalsort_bitshift = globalsort.GetUniformLocation ("bitshift");

	// clear block sum buffers
	for (int i = 0; i < blocksums.size (); i++)
	{
		unsigned int &blocksum = blocksums[i];
		glBindBuffer (GL_SHADER_STORAGE_BUFFER, blocksum);
		glClearBufferData (GL_SHADER_STORAGE_BUFFER, GL_RGBA32UI, GL_RGBA, GL_UNSIGNED_INT, NULL);
	}
	glMemoryBarrier (GL_BUFFER_UPDATE_BARRIER_BIT);
}

RadixSort::~RadixSort (void)
{
	// cleanup
	glDeleteBuffers (blocksums.size (), &blocksums[0]);
	glDeleteBuffers (3, buffers);
}

GLuint RadixSort::GetBuffer (void) const
{
	// return the current input buffer
	return buffer;
}

void RadixSort::Run (unsigned int numbits)
{
	// sort bits from least to most significant
	for (int i = 0; i < (numbits + 1) >> 1; i++)
	{
		SortBits (2 * i);
		// swap the buffer objects
		std::swap (result, buffer);
	}
}

/** Integer power.
 * Calculates an integer power.
 * \param x base
 * \param y exponent
 * \returns x to the power of y
 */
uint32_t intpow (uint32_t x, uint32_t y)
{
	uint32_t r = 1;
	while (y)
	{
		if (y & 1)
			r *= x;
		y >>= 1;
		x *= x;
	}
	return r;
}

void RadixSort::SortBits (int bits)
{
	// pass current bit shift to the shader programs
	glProgramUniform1i (counting.get (), counting_bitshift, bits);
	glProgramUniform1i (globalsort.get (), globalsort_bitshift, bits);

	// set buffer bindings
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, buffer);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, prefixsums);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 2, blocksums.front ());
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 3, result);

	// counting
	counting.Use ();
	glDispatchCompute (numblocks, 1, 1);
	glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);

	// create block sums level by level
	blockscan.Use ();
	uint32_t numblocksums = (4 * numblocks) / blocksize;
	for (int i = 0; i < blocksums.size () - 1; i++)
	{
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, blocksums[i]);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, blocksums[i + 1]);
		glDispatchCompute (numblocksums > 0 ? numblocksums : 1, 1, 1);
		numblocksums /= blocksize;
		glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
	}

	// add block sums level by level (in reversed order)
	addblocksum.Use ();
	for (int i = blocksums.size () - 3; i >= 0; i--)
	{
		uint32_t numblocksums = (4 * numblocks) / intpow (blocksize, i + 1);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, blocksums[i]);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, blocksums[i + 1]);
		glDispatchCompute (numblocksums > 0 ? numblocksums : 1, 1, 1);
		glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
	}

	// map values to their global position in the output buffer
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, buffer);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, prefixsums);
	globalsort.Use ();
	glDispatchCompute (numblocks, 1, 1);
	glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
}
<|endoftext|>


<commit_before>#include "RayTracer.hpp"
#include "Tree.hpp"
#include <ctime>

//temporary variables
Vec3Df testRayOrigin;
Vec3Df testRayDestination;
string mesh;
extern unsigned int textures[2];
clock_t lastFrameTime;
float fps;
unsigned int framesSinceLastDraw = 30;
string screenFPS;
extern Tree MyTree;

//use this function for any preprocessing of the mesh.
int init(int argc, char **argv){
    // skip program name argv[0] if present
    argc -= (argc > 0);
    argv += (argc > 0);

    option::Stats stats(usage, argc, argv);
    option::Option* options = (option::Option*)calloc(stats.options_max,
            sizeof(option::Option));
    option::Option* buffer = (option::Option*)calloc(stats.buffer_max,
            sizeof(option::Option));

    option::Parser parse(usage, argc, argv, options, buffer);

    if(parse.error())
        return 1;

    if(options[HELP]){
        int columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80;
        option::printUsage(fwrite, stdout, usage, columns);
        return 2;
    }

    lastFrameTime = clock();

    if(options[MESH]){
        const char* arg = options[MESH].last()->arg;
        if(arg != 0){
            mesh = arg;
        }
    }else{
        mesh = "0";
    }

    if(mesh == "0")
        mesh = "cube";
    else if(mesh == "1")
        mesh = "simple_monkey";
    else if(mesh == "2")
        mesh = "monkey";
    else if(mesh == "3")
        mesh = "dodgeColorTest";

    mesh = string("mesh/").append(mesh).append(".obj");
    MyMesh.loadMesh(mesh.c_str(), true);
    MyMesh.computeVertexNormals();
    MyTree.build(MyMesh);

    //one first move: initialize the first light source
    //at least ONE light source has to be in the scene!!!
    //here, we set it to the current location of the camera
    MyLightPositions.push_back(MyCameraPosition);

    if(options[RAYTRACE]){
        startRayTracing(activeTexIndex, true);
        return 255;
    }

    return 0;
}

//transformer le x, y en position 3D
void produceRay(int x_I, int y_I, Vec3Df * origin, Vec3Df * dest){
    int viewport[4];
    double modelview[16];
    double projection[16];
    //point sur near plane
    //double positionN[3];
    //point sur far plane
    //double positionF[3];
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview); //recuperer matrices
    glGetDoublev(GL_PROJECTION_MATRIX, projection); //recuperer matrices
    glGetIntegerv(GL_VIEWPORT, viewport); //viewport
    int y_new = viewport[3] - y_I;

    double x, y, z;

    gluUnProject(x_I, y_new, 0, modelview, projection, viewport, &x, &y, &z);
    origin->p[0] = float(x);
    origin->p[1] = float(y);
    origin->p[2] = float(z);
    gluUnProject(x_I, y_new, 1, modelview, projection, viewport, &x, &y, &z);
    dest->p[0] = float(x);
    dest->p[1] = float(y);
    dest->p[2] = float(z);
}

void produceRay(int x_I, int y_I, Vec3Df & origin, Vec3Df & dest){
    produceRay(x_I, y_I, &origin, &dest);
}

Vec3Df origin00, dest00;
Vec3Df origin01, dest01;
Vec3Df origin10, dest10;
Vec3Df origin11, dest11;

void raytracePart(Image* result, int w, int h, int xx, int yy, int ww, int hh){
    Vec3Df origin, dest;
    for(float y = yy;y < hh;y++){
        for(float x = xx;x < ww;x++){
            //svp, decidez vous memes quels parametres vous allez passer à la fonction
            //c'est le stront a la plafond, c'est drôle
            //e.g., maillage, triangles, sphères etc.
            Vec3Df total(0, 0, 0);
            for(unsigned int xs = 0;xs < MSAA;xs++){
                for(unsigned int ys = 0;ys < MSAA;ys++){
                    float xscale = 1.0f - (x + float(xs) / MSAA) / (w - 1);
                    float yscale = float(y + float(ys) / MSAA) / (h - 1);
#ifdef LINUX
                    yscale = 1.0f - yscale;
#endif
                    origin = yscale
                            * (xscale * origin00 + (1 - xscale) * origin10)
                            + (1 - yscale)
                                    * (xscale * origin01
                                            + (1 - xscale) * origin11);
                    dest = yscale * (xscale * dest00 + (1 - xscale) * dest10)
                            + (1 - yscale)
                                    * (xscale * dest01 + (1 - xscale) * dest11);

                    total += performRayTracing(origin, dest);
                }
            }

            // calculate average color
            total /= MSAA * MSAA;
            // result->_image
            result->_image[(y * result->_width + x) * 3 + 0] = total[0];
            result->_image[(y * result->_width + x) * 3 + 1] = total[1];
            result->_image[(y * result->_width + x) * 3 + 2] = total[2];
        }
    }
}

void startRayTracing(int texIndex, bool verbose){
    if(verbose)
        cout << "Raytracing" << endl;
    int w = RAYTRACE_RES_X;
    int h = RAYTRACE_RES_Y;
    if(!verbose)
        w = PREVIEW_RES_X;
    if(!verbose)
        h = PREVIEW_RES_Y;
    Image result(w, h);

    produceRay(0, 0, &origin00, &dest00);
    produceRay(0, WINDOW_RES_X - 1, &origin01, &dest01);
    produceRay(WINDOW_RES_X - 1, 0, &origin10, &dest10);
    produceRay(WINDOW_RES_X - 1, WINDOW_RES_Y - 1, &origin11, &dest11);

    // Perform timing
    time_t start, end, ticks;
    start = clock();

    // multithread
#if THREADS != 0
    std::thread** th = (std::thread**)alloca(THREADS * sizeof(std::thread*));
    int subw = w / THREADS;

    for(unsigned int i = 0;i < THREADS;i++)
    th[i] = new std::thread(raytracePart, &result, w, h, i * subw, 0,
            (i + 1) * subw, h);			// i * subw, 0, subw, h);

    // wait for them to finish
    for(unsigned int i = 0;i < THREADS;i++)
    th[i]->join();

    // kill them all
    for(unsigned int i = 0;i < THREADS;i++)
    delete th[i];
#else
    raytracePart(&result, w, h, 0, 0, w, h);
#endif

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    start = end;
    int millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Rendering took %d ms cpu seconds and %d ms wall time\n", millis,
                millis / max(THREADS, 1));

    // write to texture
    glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_FLOAT,
            &result._image[0]);

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Uploading to GPU took %d ms\n", millis);

    if(verbose)
        result.writeImage("result");
}

#define VEWY_HIGH 10e6f

Vec3Df black(0, 0, 0);

//return the color of your pixel.
Vec3Df performRayTracing(const Vec3Df & origin, const Vec3Df & dest){
    Ray ray = Ray(black, origin, dest);

	// calculate nearest triangle
	Triangle* triangle;
	float dist = MyTree.collide(ray, &triangle);

	Vec3Df light(17, 8, 20);
	Vec3Df lightColor(0.2, 0.3, 1.0);

	Vec3Df impact = origin + ray.dir * dist;
	Vec3Df tolight = light - impact;
	Vec3Df tocam = origin - impact;
	tolight.normalize();

	if (!triangle)
		return black;

	// start with black
	Vec3Df color = black;

	// ambient lighting
	color += Vec3Df(0.2, 0.2, 0.2);

	// diffuse
	float angle = dot(triangle->normal, tolight) * 2;
	if (angle > 0)
	color += angle * lightColor;

	// specular
	float angle2 = dot(tocam, tolight) * 0.5f;
	if (angle2 > 0)
	color += angle2 * lightColor;

	// reflection

	// return color
	return color;
}

void yourDebugDraw(){
    //draw open gl debug stuff
    //this function is called every frame

    drawFPS();

    //as an example:
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glDisable(GL_LIGHTING);
    glColor3f(1, 0, 1);
    glBegin(GL_LINES);
    glVertex3f(testRayOrigin[0], testRayOrigin[1], testRayOrigin[2]);
    glVertex3f(testRayDestination[0], testRayDestination[1],
            testRayDestination[2]);
    glEnd();
    glPointSize(10);
    glBegin(GL_POINTS);
    glVertex3fv(MyLightPositions[0].pointer());
    glEnd();
    glPopAttrib();

}

void yourKeyboardFunc(char t, int x, int y){
    // do what you want with the keyboard input t.
    // x, y are the screen position

    //here I use it to get the coordinates of a ray, which I then draw in the debug function.
    produceRay(x, y, testRayOrigin, testRayDestination);

    std::cout << t << " pressed! The mouse was in location " << x << "," << y
            << "!" << std::endl;
}

void drawFPS(){
    clock_t diff = clock() - lastFrameTime;
    lastFrameTime = clock();
    fps = 1 / ((float)diff / (float)CLOCKS_PER_SEC / (float)THREADS);

    if(framesSinceLastDraw++ > 29){
        framesSinceLastDraw = 0;
        screenFPS = to_string((int)fps);
    }

    glLoadIdentity();
    //glRasterPos2f(1.0f, 1.0f); // FPS draws on the lefthand bottom side of the screen now, if anyone knows how to get it to the lefthand top of the screen please fix it ;)
    for(unsigned int i = 0;i < screenFPS.length();i++){
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, screenFPS[i]);
    }
}
<commit_msg>cleaned up fps function<commit_after>#include "RayTracer.hpp"
#include "Tree.hpp"
#include <ctime>

//temporary variables
Vec3Df testRayOrigin;
Vec3Df testRayDestination;
string mesh;
extern unsigned int textures[2];
clock_t lastFrameTime;
float fps;
extern Tree MyTree;

//use this function for any preprocessing of the mesh.
int init(int argc, char **argv){
    // skip program name argv[0] if present
    argc -= (argc > 0);
    argv += (argc > 0);

    option::Stats stats(usage, argc, argv);
    option::Option* options = (option::Option*)calloc(stats.options_max,
            sizeof(option::Option));
    option::Option* buffer = (option::Option*)calloc(stats.buffer_max,
            sizeof(option::Option));

    option::Parser parse(usage, argc, argv, options, buffer);

    if(parse.error())
        return 1;

    if(options[HELP]){
        int columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80;
        option::printUsage(fwrite, stdout, usage, columns);
        return 2;
    }

    lastFrameTime = clock();

    if(options[MESH]){
        const char* arg = options[MESH].last()->arg;
        if(arg != 0){
            mesh = arg;
        }
    }else{
        mesh = "0";
    }

    if(mesh == "0")
        mesh = "cube";
    else if(mesh == "1")
        mesh = "simple_monkey";
    else if(mesh == "2")
        mesh = "monkey";
    else if(mesh == "3")
        mesh = "dodgeColorTest";

    mesh = string("mesh/").append(mesh).append(".obj");
    MyMesh.loadMesh(mesh.c_str(), true);
    MyMesh.computeVertexNormals();
    MyTree.build(MyMesh);

    //one first move: initialize the first light source
    //at least ONE light source has to be in the scene!!!
    //here, we set it to the current location of the camera
    MyLightPositions.push_back(MyCameraPosition);

    if(options[RAYTRACE]){
        startRayTracing(activeTexIndex, true);
        return 255;
    }

    return 0;
}

//transformer le x, y en position 3D
void produceRay(int x_I, int y_I, Vec3Df * origin, Vec3Df * dest){
    int viewport[4];
    double modelview[16];
    double projection[16];
    //point sur near plane
    //double positionN[3];
    //point sur far plane
    //double positionF[3];
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview); //recuperer matrices
    glGetDoublev(GL_PROJECTION_MATRIX, projection); //recuperer matrices
    glGetIntegerv(GL_VIEWPORT, viewport); //viewport
    int y_new = viewport[3] - y_I;

    double x, y, z;

    gluUnProject(x_I, y_new, 0, modelview, projection, viewport, &x, &y, &z);
    origin->p[0] = float(x);
    origin->p[1] = float(y);
    origin->p[2] = float(z);
    gluUnProject(x_I, y_new, 1, modelview, projection, viewport, &x, &y, &z);
    dest->p[0] = float(x);
    dest->p[1] = float(y);
    dest->p[2] = float(z);
}

void produceRay(int x_I, int y_I, Vec3Df & origin, Vec3Df & dest){
    produceRay(x_I, y_I, &origin, &dest);
}

Vec3Df origin00, dest00;
Vec3Df origin01, dest01;
Vec3Df origin10, dest10;
Vec3Df origin11, dest11;

void raytracePart(Image* result, int w, int h, int xx, int yy, int ww, int hh){
    Vec3Df origin, dest;
    for(float y = yy;y < hh;y++){
        for(float x = xx;x < ww;x++){
            //svp, decidez vous memes quels parametres vous allez passer à la fonction
            //c'est le stront a la plafond, c'est drôle
            //e.g., maillage, triangles, sphères etc.
            Vec3Df total(0, 0, 0);
            for(unsigned int xs = 0;xs < MSAA;xs++){
                for(unsigned int ys = 0;ys < MSAA;ys++){
                    float xscale = 1.0f - (x + float(xs) / MSAA) / (w - 1);
                    float yscale = float(y + float(ys) / MSAA) / (h - 1);
#ifdef LINUX
                    yscale = 1.0f - yscale;
#endif
                    origin = yscale
                            * (xscale * origin00 + (1 - xscale) * origin10)
                            + (1 - yscale)
                                    * (xscale * origin01
                                            + (1 - xscale) * origin11);
                    dest = yscale * (xscale * dest00 + (1 - xscale) * dest10)
                            + (1 - yscale)
                                    * (xscale * dest01 + (1 - xscale) * dest11);

                    total += performRayTracing(origin, dest);
                }
            }

            // calculate average color
            total /= MSAA * MSAA;
            // result->_image
            result->_image[(y * result->_width + x) * 3 + 0] = total[0];
            result->_image[(y * result->_width + x) * 3 + 1] = total[1];
            result->_image[(y * result->_width + x) * 3 + 2] = total[2];
        }
    }
}

void startRayTracing(int texIndex, bool verbose){
    if(verbose)
        cout << "Raytracing" << endl;
    int w = RAYTRACE_RES_X;
    int h = RAYTRACE_RES_Y;
    if(!verbose)
        w = PREVIEW_RES_X;
    if(!verbose)
        h = PREVIEW_RES_Y;
    Image result(w, h);

    produceRay(0, 0, &origin00, &dest00);
    produceRay(0, WINDOW_RES_X - 1, &origin01, &dest01);
    produceRay(WINDOW_RES_X - 1, 0, &origin10, &dest10);
    produceRay(WINDOW_RES_X - 1, WINDOW_RES_Y - 1, &origin11, &dest11);

    // Perform timing
    time_t start, end, ticks;
    start = clock();

    // multithread
#if THREADS != 0
    std::thread** th = (std::thread**)alloca(THREADS * sizeof(std::thread*));
    int subw = w / THREADS;

    for(unsigned int i = 0;i < THREADS;i++)
    th[i] = new std::thread(raytracePart, &result, w, h, i * subw, 0,
            (i + 1) * subw, h);			// i * subw, 0, subw, h);

    // wait for them to finish
    for(unsigned int i = 0;i < THREADS;i++)
    th[i]->join();

    // kill them all
    for(unsigned int i = 0;i < THREADS;i++)
    delete th[i];
#else
    raytracePart(&result, w, h, 0, 0, w, h);
#endif

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    start = end;
    int millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Rendering took %d ms cpu seconds and %d ms wall time\n", millis,
                millis / max(THREADS, 1));

    // write to texture
    glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_FLOAT,
            &result._image[0]);

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Uploading to GPU took %d ms\n", millis);

    if(verbose)
        result.writeImage("result");
}

#define VEWY_HIGH 10e6f

Vec3Df black(0, 0, 0);

//return the color of your pixel.
Vec3Df performRayTracing(const Vec3Df & origin, const Vec3Df & dest){
    Ray ray = Ray(black, origin, dest);

    // calculate nearest triangle
    Triangle* triangle;
    float dist = MyTree.collide(ray, &triangle);

    Vec3Df light(17, 8, 20);
    Vec3Df lightColor(0.2, 0.3, 1.0);

    Vec3Df impact = origin + ray.dir * dist;
    Vec3Df tolight = light - impact;
    Vec3Df tocam = origin - impact;
    tolight.normalize();

    if(!triangle)
        return black;

    // start with black
    Vec3Df color = black;

    // ambient lighting
    color += Vec3Df(0.2, 0.2, 0.2);

    // diffuse
    float angle = dot(triangle->normal, tolight) * 2;
    if(angle > 0)
        color += angle * lightColor;

    // specular
    float angle2 = dot(tocam, tolight) * 0.5f;
    if(angle2 > 0)
        color += angle2 * lightColor;

    // reflection

    // return color
    return color;
}

void yourDebugDraw(){
    drawFPS();
}

void yourKeyboardFunc(char t, int x, int y){
    // do what you want with the keyboard input t.
    // x, y are the screen position

    //here I use it to get the coordinates of a ray, which I then draw in the debug function.
    produceRay(x, y, testRayOrigin, testRayDestination);

    std::cout << t << " pressed! The mouse was in location " << x << "," << y
            << "!" << std::endl;
}

void drawFPS(){
    clock_t diff = clock() - lastFrameTime;
    lastFrameTime = clock();
    fps = 1 / ((float)diff / (float)CLOCKS_PER_SEC / (float)THREADS);

    char *screenFPS = (char*)malloc(sizeof(char) * 10);
    sprintf(screenFPS, "%.1f fps", fps);

    glLoadIdentity();
    //glRasterPos2f(1.0f, 1.0f); // FPS draws on the lefthand bottom side of the screen now, if anyone knows how to get it to the lefthand top of the screen please fix it ;)
    int i = -1;
    while(screenFPS[++i] != '\0'){
        glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, screenFPS[i]);
    }
}
<|endoftext|>