<commit_before>#include <SDL2/SDL.h>
#define GL_GLEXT_PROTOTYPES
#include <SDL2/SDL_opengl.h>
//#include <OpenGL/glu.h>
#include <iostream>
#include <array>
#include <algorithm>
#include <cassert>
#include "glm/gtc/constants.hpp"
#include "renderer.h"
#include "scene.h"
#include "algorithm.h"
#include "resource.h"

static const int SCREEN_WIDTH = 640;
static const int SCREEN_HEIGHT = 480;

template <typename T, unsigned int S>
class DelayQueue
{
    T arr[S];
    unsigned int current;
public:
    DelayQueue(const T& init_v = T())
        : current (0)
    {
        for (auto p = arr; p < arr + S; ++p) *p = init_v;
    }
    T Head() const
    {
        return arr[current];
    }
    T PushPop(const T& v)
    {
        auto r = arr[current];
        arr[current] = v;
        current = (current + 1) % S;
        return r;
    }
};

namespace hardrock
{
    class SpriteModel
    {
        glm::vec2 size;
        glm::vec2 anchor;
        std::uint16_t tex_id;
        std::uint16_t padding;
    public:
        SpriteModel(const glm::vec2& size, const glm::vec2& anchor, std::uint16_t tex_id)
        : size(size)
        , anchor(anchor)
        , tex_id(tex_id)
        , padding(0)
        {
        }
        void SetTileWithPosScaleDir(const glm::vec2& pos, const glm::vec2& scale, const glm::vec2& norm_dir, Tile* p_out_tile)
        {
            const glm::vec2 size = this->size * scale;
            const glm::mat2 transform(norm_dir.x * size.x, norm_dir.y * size.x, -norm_dir.y * size.y, norm_dir.x * size.y);
            p_out_tile->transform = transform;
            p_out_tile->translate = pos - transform * this->anchor;
            p_out_tile->tex_id = this->tex_id;
            p_out_tile->color = { 240, 240, 240, 255 };
        }
        void SetTileWithPos(const glm::vec2& pos, Tile* p_out_tile)
        {
            const glm::mat2 transform(this->size.x, 0, 0, this->size.y);
            p_out_tile->transform = transform;
            p_out_tile->translate = pos - transform * this->anchor;
            p_out_tile->tex_id = this->tex_id;
            p_out_tile->color = { 240, 240, 240, 255 };
        }
    };

    struct IControlTarget
    {
        virtual ~IControlTarget() { }
        virtual void Move(float x, float y) = 0;
    };

    class KeyboardControl
    {
        int left, right, up, down;
    public:
        KeyboardControl() : left(0), right(0), up(0), down(0) { }
        void KeyStatus(int scan_code, bool pressed)
        {
            int v = pressed ? 1 : 0;
            switch (scan_code)
            {
                case SDL_SCANCODE_UP:
                    this->up = v;
                    break;
                case SDL_SCANCODE_DOWN:
                    this->down = v;
                    break;
                case SDL_SCANCODE_LEFT:
                    this->left = v;
                    break;
                case SDL_SCANCODE_RIGHT:
                    this->right = v;
                    break;
                default:
                    return;
            }
        }
        void Control(IControlTarget* p_target)
        {
            int x = this->right - this->left;
            int y = this->down - this->up;
            if (x && y)
                p_target->Move(x * glm::one_over_root_two<float>(), y * glm::one_over_root_two<float>());
            else
                p_target->Move(static_cast<float>(x), static_cast<float>(y));
        }
    };

}

int main(int argc, char* args[])
{
    hardrock::PackResourceManager resource_manager("res.pack");

    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
        return -1;
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

    auto p_window = SDL_CreateWindow(
        "SDL test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    if (p_window == nullptr)
    {
        std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << std::endl;
        return -2;
    }

    auto p_context = SDL_GL_CreateContext(p_window);
    if (p_context == nullptr)
    {
        std::cerr << "SDL_GL_CreateContext failed: " << SDL_GetError() << std::endl;
        return -3;
    }

    {
        auto up_vert_shader_data = std::move(resource_manager.LoadResource(hardrock::FnvHash("test.vert")));
        assert(up_vert_shader_data);
        auto up_frag_shader_data = std::move(resource_manager.LoadResource(hardrock::FnvHash("test.frag")));
        assert(up_frag_shader_data);
        auto up_render_device = hardrock::RenderDevice::Create(SCREEN_WIDTH, SCREEN_HEIGHT, &up_vert_shader_data->at(0), up_vert_shader_data->size(), &up_frag_shader_data->at(0), up_frag_shader_data->size());
        assert(up_render_device);
        std::array<std::uint32_t, 4> tex_res_id_list =
        {
            hardrock::FnvHash("self_l.webp"),
            hardrock::FnvHash("self_m.webp"),
            hardrock::FnvHash("self_r.webp"),
            hardrock::FnvHash("bullet_0.webp"),
        };
        std::sort(tex_res_id_list.begin(), tex_res_id_list.end());
        auto up_tex_res_bundle = resource_manager.LoadResourceBatch(&tex_res_id_list[0], tex_res_id_list.size());
        assert(up_tex_res_bundle);
        int r;
        hardrock::RenderDevice::AtlasIdType atlas_id;
        r = up_render_device->CreateTextureAtlas(*up_tex_res_bundle, 16, 16, 16, atlas_id);
        assert(r == 0);
        hardrock::RenderDevice::BatchIdType batch_id;
        r = up_render_device->CreateBatch(64, atlas_id, batch_id);
        assert(r == 0);
        hardrock::RenderDevice::BatchIdType player_batch_id;
        r = up_render_device->CreateBatch(64, atlas_id, player_batch_id);
        assert(r == 0);
        std::array<hardrock::RenderDevice::RenderQuest, 2> render_quest_list
        {{
            { nullptr, {}, {}, batch_id, {} },
            { nullptr, {}, {}, player_batch_id, {} },
        }};

        assert(r == 0);
        auto tex_self_m_find_iter = std::lower_bound(tex_res_id_list.begin(), tex_res_id_list.end(), hardrock::FnvHash("self_m.webp"));
        assert(*tex_self_m_find_iter == hardrock::FnvHash("self_m.webp"));
        auto const self_m_tex_id = static_cast<hardrock::TileSet::IndexType>(tex_self_m_find_iter - tex_res_id_list.begin());
        hardrock::SpriteModel sprite_model({128, 128}, {0.5, 0.5}, self_m_tex_id);
        hardrock::SpriteModel player_model({64, 64}, {0.5, 0.5}, self_m_tex_id);

        hardrock::TileSet tile_set(64);

        const float pi = glm::pi<float>();
        const float double_pi = pi * 2.0f;
        const float half_pi = glm::half_pi<float>();
        const size_t sprite_count = 16;
        struct SpriteData
        {
            glm::vec2 pos;
            float radius;
            hardrock::TileSet::IndexType tile_idx;
            hardrock::TileSet::IndexType padding;
        } sprite_data[sprite_count];
        for (int i = 0; i < sprite_count; ++i)
        {
            auto const tile_idx = tile_set.TileAdd();
            int x = i % 4;
            int y = i / 4;
            sprite_data[i] = { { x * 128, y * 128 }, (i % 4) * half_pi, tile_idx, 0 };
        }
        struct PlayerData
        {
            glm::vec2 pos;
            hardrock::TileSet::IndexType tile_idx;
            hardrock::TileSet::IndexType padding;
        } player_data;
        hardrock::TileSet player_tile_set(8);
        player_data.tile_idx = player_tile_set.TileAdd();
        player_model.SetTileWithPos({}, &player_tile_set.TileAt(player_data.tile_idx));

        class ControlTranslate : public hardrock::IControlTarget
        {
            glm::vec2* p_translate;
            float x, y;
        public:
            ControlTranslate(glm::vec2* p_translate, float x = 0, float y = 0)
            : p_translate(p_translate)
            , x(x), y(y)
            {
            }
            void Move(float x, float y) override
            {
                this->x += x;
                this->y += y;
                p_translate->x = this->x;
                p_translate->y = this->y;
            }
        };
        ControlTranslate control_translate(&player_data.pos, SCREEN_WIDTH * 0.5, SCREEN_HEIGHT * 0.8);
        hardrock::KeyboardControl keyboard_control;

        typedef decltype(SDL_GetTicks()) tick_t;
        tick_t last_fps_tick = SDL_GetTicks();
        tick_t last_fps_frame = 0;
        DelayQueue<unsigned int, 6> tick_time_queue;
        while (true)
        {
            SDL_Event e;
            bool b_quit = false;
            while (SDL_PollEvent(&e) != 0)
            {
                switch(e.type)
                {
                    case SDL_QUIT:
                        b_quit = true;
                        break;
                    case SDL_KEYDOWN:
                        if (!e.key.repeat)
                        {
                            keyboard_control.KeyStatus(e.key.keysym.scancode, e.key.state);
                        }
                        break;
                    case SDL_KEYUP:
                        keyboard_control.KeyStatus(e.key.keysym.scancode, e.key.state);
                        break;
                }
            }
            if (b_quit)
            {
                break;
            }

            keyboard_control.Control(&control_translate);

            for (int i = 0; i < sprite_count; ++i)
            {
                SpriteData& s = sprite_data[i];
                s.radius += 0.01f;
                if (s.radius > pi)
                    s.radius -= double_pi;
                glm::vec2 norm;
                hardrock::FastSinCos(s.radius, &norm.y, &norm.x);
                sprite_model.SetTileWithPosScaleDir(s.pos, {1, 1}, norm, &tile_set.TileAt(s.tile_idx));
                hardrock::Tile tile0;
                sprite_model.SetTileWithPos(s.pos, &tile0);
                hardrock::Tile tile1;
                sprite_model.SetTileWithPosScaleDir(s.pos, {1, 1}, {1, 0}, &tile1);
                assert(tile0.transform == tile1.transform);
                assert(tile0.translate == tile1.translate);
            }

            glClearColor(0.2f, 0.0f, 0.2f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
            {
                auto tile_seq = tile_set.GetTileSequence();
                render_quest_list[0].p_tile_seq = &tile_seq;
                auto player_tile_seq = player_tile_set.GetTileSequence();
                render_quest_list[1].p_tile_seq = &player_tile_seq;
                render_quest_list[1].translate = player_data.pos;
                up_render_device->Render(render_quest_list.begin(), render_quest_list.end());
            }
            glFlush();

            SDL_GL_SwapWindow(p_window);

            tick_t tick_5 = tick_time_queue.Head();
            tick_t len_5_x = SDL_GetTicks() - tick_5;
            if (len_5_x < 90)
            {
                SDL_Delay(100 - len_5_x);
            }
            tick_t now = SDL_GetTicks();
            tick_time_queue.PushPop(now);
            ++last_fps_frame;
            if (last_fps_frame >= 60)
            {
                std::cout << "fps: " << 60000.0 / (now - last_fps_tick) << std::endl;
                last_fps_tick = now;
                last_fps_frame = 0;
            }
        }
    }

    SDL_GL_DeleteContext(p_context);
    SDL_DestroyWindow(p_window);
    SDL_Quit();

    std::cout << "Quit" << std::endl;

    return 0;
}<commit_msg>Player can shoot bullets.<commit_after>#include <SDL2/SDL.h>
#define GL_GLEXT_PROTOTYPES
#include <SDL2/SDL_opengl.h>
//#include <OpenGL/glu.h>
#include <iostream>
#include <array>
#include <algorithm>
#include <cassert>
#include "glm/gtc/constants.hpp"
#include "renderer.h"
#include "scene.h"
#include "algorithm.h"
#include "resource.h"

static const int SCREEN_WIDTH = 640;
static const int SCREEN_HEIGHT = 480;

template <typename T, unsigned int S>
class DelayQueue
{
    T arr[S];
    unsigned int current;
public:
    DelayQueue(const T& init_v = T())
        : current (0)
    {
        for (auto p = arr; p < arr + S; ++p) *p = init_v;
    }
    T Head() const
    {
        return arr[current];
    }
    T PushPop(const T& v)
    {
        auto r = arr[current];
        arr[current] = v;
        current = (current + 1) % S;
        return r;
    }
};

namespace hardrock
{
    class SpriteModel
    {
        glm::vec2 size;
        glm::vec2 anchor;
        std::uint16_t tex_id;
        std::uint16_t padding;
    public:
        SpriteModel(const glm::vec2& size, const glm::vec2& anchor, std::uint16_t tex_id)
        : size(size)
        , anchor(anchor)
        , tex_id(tex_id)
        , padding(0)
        {
        }
        void SetTileWithPosScaleDir(const glm::vec2& pos, const glm::vec2& scale, const glm::vec2& norm_dir, Tile* p_out_tile)
        {
            const glm::vec2 size = this->size * scale;
            const glm::mat2 transform(norm_dir.x * size.x, norm_dir.y * size.x, -norm_dir.y * size.y, norm_dir.x * size.y);
            p_out_tile->transform = transform;
            p_out_tile->translate = pos - transform * this->anchor;
            p_out_tile->tex_id = this->tex_id;
            p_out_tile->color = { 240, 240, 240, 255 };
        }
        void SetTileWithPos(const glm::vec2& pos, Tile* p_out_tile)
        {
            const glm::mat2 transform(this->size.x, 0, 0, this->size.y);
            p_out_tile->transform = transform;
            p_out_tile->translate = pos - transform * this->anchor;
            p_out_tile->tex_id = this->tex_id;
            p_out_tile->color = { 240, 240, 240, 255 };
        }
    };

    class KeyboardControl
    {
        int left, right, up, down;
        std::uint32_t button_mask;
    public:
        KeyboardControl() : left(0), right(0), up(0), down(0) { }
        void KeyStatus(int scan_code, bool pressed)
        {
            int v = pressed ? 1 : 0;
            switch (scan_code)
            {
                case SDL_SCANCODE_UP:
                    this->up = v;
                    break;
                case SDL_SCANCODE_DOWN:
                    this->down = v;
                    break;
                case SDL_SCANCODE_LEFT:
                    this->left = v;
                    break;
                case SDL_SCANCODE_RIGHT:
                    this->right = v;
                    break;
                case SDL_SCANCODE_SPACE:
                    if (pressed)
                        this->button_mask |= 1;
                    else
                        this->button_mask &= ~ 1;
                    break;
                default:
                    return;
            }
        }
        glm::vec2 GetMoveVector() const
        {
            int x = this->right - this->left;
            int y = this->down - this->up;
            if (x && y)
                return {x * glm::one_over_root_two<float>(), y * glm::one_over_root_two<float>()};
            else
                return {static_cast<float>(x), static_cast<float>(y)};
        }
        std::uint32_t GetButtonMask() const
        {
            return this->button_mask;
        }
    };

}

int main(int argc, char* args[])
{
    hardrock::PackResourceManager resource_manager("res.pack");

    if (SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
        return -1;
    }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);

    auto p_window = SDL_CreateWindow(
        "SDL test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    if (p_window == nullptr)
    {
        std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << std::endl;
        return -2;
    }

    auto p_context = SDL_GL_CreateContext(p_window);
    if (p_context == nullptr)
    {
        std::cerr << "SDL_GL_CreateContext failed: " << SDL_GetError() << std::endl;
        return -3;
    }

    {
        auto up_vert_shader_data = std::move(resource_manager.LoadResource(hardrock::FnvHash("test.vert")));
        assert(up_vert_shader_data);
        auto up_frag_shader_data = std::move(resource_manager.LoadResource(hardrock::FnvHash("test.frag")));
        assert(up_frag_shader_data);
        auto up_render_device = hardrock::RenderDevice::Create(SCREEN_WIDTH, SCREEN_HEIGHT, &up_vert_shader_data->at(0), up_vert_shader_data->size(), &up_frag_shader_data->at(0), up_frag_shader_data->size());
        assert(up_render_device);
        std::array<std::uint32_t, 5> tex_res_id_list =
        {
            hardrock::FnvHash("self_l.webp"),
            hardrock::FnvHash("self_m.webp"),
            hardrock::FnvHash("self_r.webp"),
            hardrock::FnvHash("bullet_0.webp"),
            hardrock::FnvHash("bullet_1.webp"),
        };
        std::sort(tex_res_id_list.begin(), tex_res_id_list.end());
        auto up_tex_res_bundle = resource_manager.LoadResourceBatch(&tex_res_id_list[0], tex_res_id_list.size());
        assert(up_tex_res_bundle);
        int r;
        hardrock::RenderDevice::AtlasIdType atlas_id;
        r = up_render_device->CreateTextureAtlas(*up_tex_res_bundle, 16, 16, 16, atlas_id);
        assert(r == 0);
        hardrock::RenderDevice::BatchIdType batch_id;
        r = up_render_device->CreateBatch(64, atlas_id, batch_id);
        assert(r == 0);
        hardrock::RenderDevice::BatchIdType sprite_batch_id;
        r = up_render_device->CreateBatch(512, atlas_id, sprite_batch_id);
        assert(r == 0);
        std::array<hardrock::RenderDevice::RenderQuest, 2> render_quest_list
        {{
            { nullptr, {}, {}, batch_id, {} },
            { nullptr, {}, {}, sprite_batch_id, {} },
        }};

        auto tex_self_m_find_iter = std::lower_bound(tex_res_id_list.begin(), tex_res_id_list.end(), hardrock::FnvHash("self_m.webp"));
        assert(*tex_self_m_find_iter == hardrock::FnvHash("self_m.webp"));
        auto const self_m_tex_id = static_cast<hardrock::TileSet::IndexType>(tex_self_m_find_iter - tex_res_id_list.begin());
        hardrock::SpriteModel sprite_model({128, 128}, {0.5, 0.5}, self_m_tex_id);
        hardrock::SpriteModel player_model({64, 64}, {0.5, 0.5}, self_m_tex_id);

        auto tex_bullet_1_find_iter = std::lower_bound(tex_res_id_list.begin(), tex_res_id_list.end(), hardrock::FnvHash("bullet_1.webp"));
        assert(*tex_bullet_1_find_iter == hardrock::FnvHash("bullet_1.webp"));
        auto const bullet_1_id = static_cast<hardrock::TileSet::IndexType>(tex_bullet_1_find_iter - tex_res_id_list.begin());
        hardrock::SpriteModel bullet_1_model({32, 32}, {0.5, 0.5}, bullet_1_id);

        hardrock::SpriteModel empty_model({}, {}, 0);

        hardrock::TileSet tile_set(64);

        const float pi = glm::pi<float>();
        const float double_pi = pi * 2.0f;
        const float half_pi = glm::half_pi<float>();
        const size_t sprite_count = 16;
        struct SpriteData
        {
            glm::vec2 pos;
            float radius;
            hardrock::TileSet::IndexType tile_idx;
            hardrock::TileSet::IndexType padding;
        } sprite_data[sprite_count];
        for (int i = 0; i < sprite_count; ++i)
        {
            auto const tile_idx = tile_set.TileAdd();
            int x = i % 4;
            int y = i / 4;
            sprite_data[i] = { { x * 128, y * 128 }, (i % 4) * half_pi, tile_idx, 0 };
        }
        hardrock::TileSet sprite_tile_set(512);

        struct PlayerData
        {
            glm::vec2 pos;
            hardrock::TileSet::IndexType tile_idx;
            hardrock::TileSet::IndexType padding;
        };
        PlayerData player_data =
        {
            { SCREEN_WIDTH * 0.5, SCREEN_HEIGHT * 0.9 },
            sprite_tile_set.TileAdd(),
        };
        player_model.SetTileWithPos(player_data.pos, &sprite_tile_set.TileAt(player_data.tile_idx));

        const auto player_bullet_tile_head_idx = sprite_tile_set.TileAdd();
        empty_model.SetTileWithPos({}, &sprite_tile_set.TileAt(player_bullet_tile_head_idx));

        struct PlayerBulletData
        {
            glm::vec2 pos;
            hardrock::TileSet::IndexType tile_idx;
            hardrock::TileSet::IndexType padding;
        };
        const std::size_t player_bullet_count = 64;
        std::array<PlayerBulletData, player_bullet_count> player_bullet_data;
        std::size_t active_player_bullet_count = 0;

        hardrock::KeyboardControl keyboard_control;

        typedef decltype(SDL_GetTicks()) tick_t;
        tick_t last_fps_tick = SDL_GetTicks();
        tick_t last_fps_frame = 0;
        DelayQueue<unsigned int, 6> tick_time_queue;
        while (true)
        {
            SDL_Event e;
            bool b_quit = false;
            while (SDL_PollEvent(&e) != 0)
            {
                switch(e.type)
                {
                    case SDL_QUIT:
                        b_quit = true;
                        break;
                    case SDL_KEYDOWN:
                        if (!e.key.repeat)
                        {
                            keyboard_control.KeyStatus(e.key.keysym.scancode, e.key.state);
                        }
                        break;
                    case SDL_KEYUP:
                        keyboard_control.KeyStatus(e.key.keysym.scancode, e.key.state);
                        break;
                }
            }
            if (b_quit)
            {
                break;
            }

            for (std::size_t i = 0; i < active_player_bullet_count;)
            {
                auto &bullet_data = player_bullet_data[i];
                const auto bullet_idx = bullet_data.tile_idx;
                auto &pos = bullet_data.pos;
                pos += glm::vec2(0, -16.0f);

                if (pos.y < 0)
                {
                    sprite_tile_set.TileRemove(bullet_idx);
                    player_bullet_data[i] = player_bullet_data[active_player_bullet_count - 1];
                    --active_player_bullet_count;
                }
                else
                {
                    bullet_1_model.SetTileWithPos(pos, &sprite_tile_set.TileAt(bullet_idx));
                    ++i;
                }
            }

            if (keyboard_control.GetButtonMask() & 1 && active_player_bullet_count < player_bullet_count)
            {
                const auto bullet_idx = active_player_bullet_count++;
                auto &bullet_data = player_bullet_data[bullet_idx];
                bullet_data.tile_idx = sprite_tile_set.TileAdd(player_bullet_tile_head_idx);
                const auto bullet_pos = player_data.pos;
                bullet_data.pos = bullet_pos;
                bullet_1_model.SetTileWithPos(bullet_pos, &sprite_tile_set.TileAt(bullet_data.tile_idx));
            }

            player_data.pos += keyboard_control.GetMoveVector() * 2.0f;
            player_model.SetTileWithPos(player_data.pos, &sprite_tile_set.TileAt(player_data.tile_idx));

            for (int i = 0; i < sprite_count; ++i)
            {
                SpriteData& s = sprite_data[i];
                s.radius += 0.01f;
                if (s.radius > pi)
                    s.radius -= double_pi;
                glm::vec2 norm;
                hardrock::FastSinCos(s.radius, &norm.y, &norm.x);
                sprite_model.SetTileWithPosScaleDir(s.pos, {1, 1}, norm, &tile_set.TileAt(s.tile_idx));
            }

            glClearColor(0.2f, 0.0f, 0.2f, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT);
            {
                auto tile_seq = tile_set.GetTileSequence();
                render_quest_list[0].p_tile_seq = &tile_seq;
                auto sprite_tile_seq = sprite_tile_set.GetTileSequence();
                render_quest_list[1].p_tile_seq = &sprite_tile_seq;
                up_render_device->Render(render_quest_list.begin(), render_quest_list.end());
            }
            glFlush();

            SDL_GL_SwapWindow(p_window);

            tick_t tick_5 = tick_time_queue.Head();
            tick_t len_5_x = SDL_GetTicks() - tick_5;
            if (len_5_x < 90)
            {
                SDL_Delay(100 - len_5_x);
            }
            tick_t now = SDL_GetTicks();
            tick_time_queue.PushPop(now);
            ++last_fps_frame;
            if (last_fps_frame >= 60)
            {
                std::cout << "fps: " << 60000.0 / (now - last_fps_tick) << std::endl;
                last_fps_tick = now;
                last_fps_frame = 0;
            }
        }
    }

    SDL_GL_DeleteContext(p_context);
    SDL_DestroyWindow(p_window);
    SDL_Quit();

    std::cout << "Quit" << std::endl;

    return 0;
}<|endoftext|>


<commit_before>#ifndef MJOLNIR_OMP_UNLIMITED_GRID_CELL_LIST_HPP
#define MJOLNIR_OMP_UNLIMITED_GRID_CELL_LIST_HPP
#include <mjolnir/omp/OpenMPSimulatorTraits.hpp>
#include <mjolnir/omp/sort.hpp>
#include <mjolnir/core/UnlimitedGridCellList.hpp>
#include <mjolnir/core/ParallelNeighborList.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
class UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>
{
  public:
    using traits_type         = OpenMPSimulatorTraits<realT, boundaryT>;
    using system_type         = System<traits_type>;
    using real_type           = typename traits_type::real_type;
    using coordinate_type     = typename traits_type::coordinate_type;
    using exclusion_list_type = ExclusionList;
    using parameter_type      = parameterT;
    using neighbor_list_type  = ParallelNeighborList<parameter_type>;
    using neighbor_type       = typename neighbor_list_type::neighbor_type;
    using range_type          = typename neighbor_list_type::range_type;

    constexpr static std::size_t  dim_size  = dimI;
    constexpr static std::int64_t dim       = static_cast<std::int64_t>(dimI);
    constexpr static std::size_t total_size = dim_size * dim_size * dim_size;
    constexpr static real_type mesh_epsilon = 1e-6;

    using particle_cell_idx_pair    = std::pair<std::size_t, std::size_t>;
    using cell_index_container_type = std::vector<particle_cell_idx_pair>;
    using cell_index_const_iterator = typename cell_index_container_type::const_iterator;
    using adjacent_cell_idx         = std::array<std::size_t, 27>;
    using cell_type                 = std::pair<range<cell_index_const_iterator>, adjacent_cell_idx>;
    using cell_list_type            = std::array<cell_type, total_size>;

  public:

    UnlimitedGridCellList()
        : margin_(0.5), current_margin_(-1.0), r_cell_size_(-1.0)
    {}

    ~UnlimitedGridCellList() = default;
    UnlimitedGridCellList(UnlimitedGridCellList const&) = default;
    UnlimitedGridCellList(UnlimitedGridCellList &&)     = default;
    UnlimitedGridCellList& operator=(UnlimitedGridCellList const&) = default;
    UnlimitedGridCellList& operator=(UnlimitedGridCellList &&)     = default;

    explicit UnlimitedGridCellList(const real_type margin)
        : margin_(margin), current_margin_(-1.0), r_cell_size_(-1.0)
    {}

    bool valid() const noexcept
    {
        return current_margin_ >= 0.;
    }

    //XXX do NOT call this from parallel region.
    template<typename PotentialT>
    void initialize(const system_type& sys, const PotentialT& pot)
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        MJOLNIR_LOG_INFO(pot.name(), " cutoff = ", pot.max_cutoff_length());
        MJOLNIR_LOG_INFO("dimension = ", dim, 'x', dim, 'x', dim);
        this->set_cutoff(pot.max_cutoff_length());
        this->exclusion_.make(sys, pot);

        // initialize cell list
#pragma omp parallel for
        for(int x = 0; x < dim; ++x)
        {
            for(int y = 0; y < dim; ++y)
            {
            for(int z = 0; z < dim; ++z)
            {
                auto& cell = this->cell_list_[calc_index(x, y, z)];

                const std::size_t x_prev = (x ==     0) ? dim-1 : x-1;
                const std::size_t x_next = (x == dim-1) ?     0 : x+1;
                const std::size_t y_prev = (y ==     0) ? dim-1 : y-1;
                const std::size_t y_next = (y == dim-1) ?     0 : y+1;
                const std::size_t z_prev = (z ==     0) ? dim-1 : z-1;
                const std::size_t z_next = (z == dim-1) ?     0 : z+1;

                cell.second[ 0] = calc_index(x_prev, y_prev, z_prev);
                cell.second[ 1] = calc_index(x,      y_prev, z_prev);
                cell.second[ 2] = calc_index(x_next, y_prev, z_prev);
                cell.second[ 3] = calc_index(x_prev, y,      z_prev);
                cell.second[ 4] = calc_index(x,      y,      z_prev);
                cell.second[ 5] = calc_index(x_next, y,      z_prev);
                cell.second[ 6] = calc_index(x_prev, y_next, z_prev);
                cell.second[ 7] = calc_index(x,      y_next, z_prev);
                cell.second[ 8] = calc_index(x_next, y_next, z_prev);

                cell.second[ 9] = calc_index(x_prev, y_prev, z);
                cell.second[10] = calc_index(x,      y_prev, z);
                cell.second[11] = calc_index(x_next, y_prev, z);
                cell.second[12] = calc_index(x_prev, y,      z);
                cell.second[13] = calc_index(x,      y,      z);
                cell.second[14] = calc_index(x_next, y,      z);
                cell.second[15] = calc_index(x_prev, y_next, z);
                cell.second[16] = calc_index(x,      y_next, z);
                cell.second[17] = calc_index(x_next, y_next, z);

                cell.second[18] = calc_index(x_prev, y_prev, z_next);
                cell.second[19] = calc_index(x,      y_prev, z_next);
                cell.second[20] = calc_index(x_next, y_prev, z_next);
                cell.second[21] = calc_index(x_prev, y,      z_next);
                cell.second[22] = calc_index(x,      y,      z_next);
                cell.second[23] = calc_index(x_next, y,      z_next);
                cell.second[24] = calc_index(x_prev, y_next, z_next);
                cell.second[25] = calc_index(x,      y_next, z_next);
                cell.second[26] = calc_index(x_next, y_next, z_next);
            } // for z
            } // for y
        } // for x (in parallel)

        this->make(sys, pot);
        return;
    }

    template<typename PotentialT>
    void reconstruct(const system_type& sys, const PotentialT& pot)
    {
        this->initialize(sys, pot); // do the same thing as `initialize`
        return;
    }

    //XXX do NOT call this from parallel region
    template<typename PotentialT>
    void make  (const system_type& sys, const PotentialT& pot)
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        neighbors_.clear();
        if(index_by_cell_.size() != sys.size())
        {
            index_by_cell_    .resize(sys.size());
            index_by_cell_buf_.resize(sys.size());
        }

#pragma omp parallel for
        for(std::size_t i=0; i<sys.size(); ++i)
        {
            // pairof {particle-idx, cell-idx}
            index_by_cell_[i] = std::make_pair(i, calc_index(sys.position(i)));
        }

        omp::sort(this->index_by_cell_, this->index_by_cell_buf_,
                  [](const particle_cell_idx_pair& lhs,
                     const particle_cell_idx_pair& rhs) noexcept -> bool {
                      return lhs.second < rhs.second;
                  });

        // assign first and last iterator for each cells
        // Also, search the max number of particles in a cell
        std::size_t max_neighbors = 0;
#pragma omp parallel for reduction(max:max_neighbors)
        for(std::size_t cell_idx=0; cell_idx<cell_list_.size(); ++cell_idx)
        {
            auto iter = std::find_if(index_by_cell_.cbegin(), index_by_cell_.cend(),
                [cell_idx](const particle_cell_idx_pair& item) noexcept -> bool {
                    return item.second == cell_idx;
                });
            if(iter == index_by_cell_.cend())
            {
                cell_list_[cell_idx].first = make_range(iter, iter);
                continue;
            }
            const auto first = iter; // the first iter of the range
            while(iter != index_by_cell_.cend() && iter->second == cell_idx)
            {
                ++iter;
            }
            cell_list_[cell_idx].first = make_range(first, iter);
            max_neighbors = std::max(max_neighbors,
                                     std::size_t(std::distance(first, iter)));
        }

        MJOLNIR_LOG_INFO("max number of particles per cell is ", max_neighbors);

        // resize neighbor list by the max number of interacting-particles
        this->neighbors_.resize(sys.size(), max_neighbors * 27);

        const real_type r_c  = cutoff_ * (1 + margin_);
        const real_type r_c2 = r_c * r_c;

        std::size_t max_neighbors_actual = 0;
        std::vector<neighbor_type> partner;
#pragma omp parallel for private(partner) reduction(max: max_neighbors_actual)
        for(std::size_t i=0; i<sys.size(); ++i)
        {
            const auto& ri   = sys.position(i);
            const auto& cell = cell_list_[this->calc_index(ri)];

            partner.clear();
            for(std::size_t cidx : cell.second) // for all adjacent cells...
            {
                for(auto pici : cell_list_[cidx].first)
                {
                    const auto j = pici.first;
                    if(j <= i || this->exclusion_.is_excluded(i, j))
                    {
                        continue;
                    }

                    const auto& rj = sys.position(j);
                    if(math::length_sq(sys.adjust_direction(rj - ri)) < r_c2)
                    {
                        partner.emplace_back(j, pot.prepare_params(i, j));
                    }
                }
            }
            // make the result consistent with NaivePairCalculation...
            std::sort(partner.begin(), partner.end());
            this->neighbors_.add_list_for(i, partner.begin(), partner.end());

            max_neighbors_actual = std::max(max_neighbors_actual, partner.size());
        }
        MJOLNIR_LOG_INFO("actual number of partners is ", max_neighbors_actual);

        this->current_margin_ = cutoff_ * margin_;
        return ;
    }

    //XXX do NOT call this from `parallel` region.
    template<typename PotentialT>
    void update(const real_type   dmargin, const system_type& sys,
                const PotentialT& pot)
    {
        this->current_margin_ -= dmargin;

        if(this->current_margin_ < 0.)
        {
            this->make(sys, pot);
        }
        return ;
    }

    real_type cutoff() const noexcept {return this->cutoff_;}
    real_type margin() const noexcept {return this->margin_;}

    range_type partners(std::size_t i) const noexcept {return neighbors_[i];}

  private:

    // calc cell index of the position
    std::size_t calc_index(const coordinate_type& pos) const noexcept
    {
        const auto x = static_cast<std::int64_t>(std::floor(math::X(pos) * r_cell_size_)) % dim;
        const auto y = static_cast<std::int64_t>(std::floor(math::Y(pos) * r_cell_size_)) % dim;
        const auto z = static_cast<std::int64_t>(std::floor(math::Z(pos) * r_cell_size_)) % dim;

        return this->calc_index(
                (x<0) ? x+dim : x, (y<0) ? y+dim : y, (z<0) ? z+dim : z);
    }

    std::size_t calc_index(const std::size_t x, const std::size_t y,
                           const std::size_t z) const noexcept
    {
        return x + dim_size * y + dim_size * dim_size * z;
    }

    void set_cutoff(const real_type c) noexcept
    {
        this->cutoff_ = c;
        this->r_cell_size_ = 1 / (cutoff_ * (1 + margin_) * (1+mesh_epsilon));
    }
    void set_margin(const real_type m) noexcept
    {
        this->margin_ = m;
        this->r_cell_size_ = 1 / (cutoff_ * (1 + margin_) * (1+mesh_epsilon));
    }

  private:

    real_type cutoff_;
    real_type margin_;
    real_type current_margin_;
    real_type r_cell_size_;

    exclusion_list_type       exclusion_;
    neighbor_list_type        neighbors_;
    cell_list_type            cell_list_;
    cell_index_container_type index_by_cell_;
    cell_index_container_type index_by_cell_buf_; // buffer for sort
    // index_by_cell_ has {particle idx, cell idx} and sorted by cell idx
    // first term of cell list contains first and last idx of index_by_cell
};

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
constexpr std::size_t UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>::dim_size;

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
constexpr std::int64_t UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>::dim;

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
constexpr std::size_t UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>::total_size;

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
constexpr typename UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>::real_type
    UnlimitedGridCellList<OpenMPSimulatorTraits<realT, boundaryT>,
                          parameterT, dimI>::mesh_epsilon;

} // mjolnir
#endif/* MJOLNIR_UNLIMITED_GRID_CELL_LIST */
<commit_msg>perf: use normal NeighborList in CellList<commit_after>#ifndef MJOLNIR_OMP_UNLIMITED_GRID_CELL_LIST_HPP
#define MJOLNIR_OMP_UNLIMITED_GRID_CELL_LIST_HPP
#include <mjolnir/omp/OpenMPSimulatorTraits.hpp>
#include <mjolnir/omp/sort.hpp>
#include <mjolnir/core/UnlimitedGridCellList.hpp>

namespace mjolnir
{

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
class UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>
{
  public:
    using traits_type         = OpenMPSimulatorTraits<realT, boundaryT>;
    using system_type         = System<traits_type>;
    using real_type           = typename traits_type::real_type;
    using coordinate_type     = typename traits_type::coordinate_type;
    using exclusion_list_type = ExclusionList;
    using parameter_type      = parameterT;
    using neighbor_list_type  = NeighborList<parameter_type>;
    using neighbor_type       = typename neighbor_list_type::neighbor_type;
    using range_type          = typename neighbor_list_type::range_type;

    constexpr static std::size_t  dim_size  = dimI;
    constexpr static std::int64_t dim       = static_cast<std::int64_t>(dimI);
    constexpr static std::size_t total_size = dim_size * dim_size * dim_size;
    constexpr static real_type mesh_epsilon = 1e-6;

    using particle_cell_idx_pair    = std::pair<std::size_t, std::size_t>;
    using cell_index_container_type = std::vector<particle_cell_idx_pair>;
    using cell_index_const_iterator = typename cell_index_container_type::const_iterator;
    using adjacent_cell_idx         = std::array<std::size_t, 27>;
    using cell_type                 = std::pair<range<cell_index_const_iterator>, adjacent_cell_idx>;
    using cell_list_type            = std::array<cell_type, total_size>;

  public:

    UnlimitedGridCellList()
        : margin_(0.5), current_margin_(-1.0), r_cell_size_(-1.0)
    {}

    ~UnlimitedGridCellList() = default;
    UnlimitedGridCellList(UnlimitedGridCellList const&) = default;
    UnlimitedGridCellList(UnlimitedGridCellList &&)     = default;
    UnlimitedGridCellList& operator=(UnlimitedGridCellList const&) = default;
    UnlimitedGridCellList& operator=(UnlimitedGridCellList &&)     = default;

    explicit UnlimitedGridCellList(const real_type margin)
        : margin_(margin), current_margin_(-1.0), r_cell_size_(-1.0)
    {}

    bool valid() const noexcept
    {
        return current_margin_ >= 0.;
    }

    //XXX do NOT call this from parallel region.
    template<typename PotentialT>
    void initialize(const system_type& sys, const PotentialT& pot)
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        MJOLNIR_LOG_INFO(pot.name(), " cutoff = ", pot.max_cutoff_length());
        MJOLNIR_LOG_INFO("dimension = ", dim, 'x', dim, 'x', dim);
        this->set_cutoff(pot.max_cutoff_length());
        this->exclusion_.make(sys, pot);

        // initialize cell list
#pragma omp parallel for
        for(int x = 0; x < dim; ++x)
        {
            for(int y = 0; y < dim; ++y)
            {
            for(int z = 0; z < dim; ++z)
            {
                auto& cell = this->cell_list_[calc_index(x, y, z)];

                const std::size_t x_prev = (x ==     0) ? dim-1 : x-1;
                const std::size_t x_next = (x == dim-1) ?     0 : x+1;
                const std::size_t y_prev = (y ==     0) ? dim-1 : y-1;
                const std::size_t y_next = (y == dim-1) ?     0 : y+1;
                const std::size_t z_prev = (z ==     0) ? dim-1 : z-1;
                const std::size_t z_next = (z == dim-1) ?     0 : z+1;

                cell.second[ 0] = calc_index(x_prev, y_prev, z_prev);
                cell.second[ 1] = calc_index(x,      y_prev, z_prev);
                cell.second[ 2] = calc_index(x_next, y_prev, z_prev);
                cell.second[ 3] = calc_index(x_prev, y,      z_prev);
                cell.second[ 4] = calc_index(x,      y,      z_prev);
                cell.second[ 5] = calc_index(x_next, y,      z_prev);
                cell.second[ 6] = calc_index(x_prev, y_next, z_prev);
                cell.second[ 7] = calc_index(x,      y_next, z_prev);
                cell.second[ 8] = calc_index(x_next, y_next, z_prev);

                cell.second[ 9] = calc_index(x_prev, y_prev, z);
                cell.second[10] = calc_index(x,      y_prev, z);
                cell.second[11] = calc_index(x_next, y_prev, z);
                cell.second[12] = calc_index(x_prev, y,      z);
                cell.second[13] = calc_index(x,      y,      z);
                cell.second[14] = calc_index(x_next, y,      z);
                cell.second[15] = calc_index(x_prev, y_next, z);
                cell.second[16] = calc_index(x,      y_next, z);
                cell.second[17] = calc_index(x_next, y_next, z);

                cell.second[18] = calc_index(x_prev, y_prev, z_next);
                cell.second[19] = calc_index(x,      y_prev, z_next);
                cell.second[20] = calc_index(x_next, y_prev, z_next);
                cell.second[21] = calc_index(x_prev, y,      z_next);
                cell.second[22] = calc_index(x,      y,      z_next);
                cell.second[23] = calc_index(x_next, y,      z_next);
                cell.second[24] = calc_index(x_prev, y_next, z_next);
                cell.second[25] = calc_index(x,      y_next, z_next);
                cell.second[26] = calc_index(x_next, y_next, z_next);
            } // for z
            } // for y
        } // for x (in parallel)

        this->make(sys, pot);
        return;
    }

    template<typename PotentialT>
    void reconstruct(const system_type& sys, const PotentialT& pot)
    {
        this->initialize(sys, pot); // do the same thing as `initialize`
        return;
    }

    //XXX do NOT call this from parallel region
    template<typename PotentialT>
    void make  (const system_type& sys, const PotentialT& pot)
    {
        MJOLNIR_GET_DEFAULT_LOGGER();
        MJOLNIR_LOG_FUNCTION();

        neighbors_.clear();
        if(index_by_cell_.size() != sys.size())
        {
            index_by_cell_    .resize(sys.size());
            index_by_cell_buf_.resize(sys.size());
        }

#pragma omp parallel for
        for(std::size_t i=0; i<sys.size(); ++i)
        {
            // pairof {particle-idx, cell-idx}
            index_by_cell_[i] = std::make_pair(i, calc_index(sys.position(i)));
        }

        MJOLNIR_LOG_INFO("cell indices calculated");

        omp::sort(this->index_by_cell_, this->index_by_cell_buf_,
                  [](const particle_cell_idx_pair& lhs,
                     const particle_cell_idx_pair& rhs) noexcept -> bool {
                      return lhs.second < rhs.second;
                  });

        MJOLNIR_LOG_INFO("particle id & cell indices are sorted");

        // assign first and last iterator for each cells
#pragma omp parallel for
        for(std::size_t cell_idx=0; cell_idx<cell_list_.size(); ++cell_idx)
        {
            auto iter = std::find_if(index_by_cell_.cbegin(), index_by_cell_.cend(),
                [cell_idx](const particle_cell_idx_pair& item) noexcept -> bool {
                    return item.second == cell_idx;
                });
            if(iter == index_by_cell_.cend())
            {
                cell_list_[cell_idx].first = make_range(iter, iter);
                continue;
            }
            const auto first = iter; // the first iter of the range
            while(iter != index_by_cell_.cend() && iter->second == cell_idx)
            {
                ++iter;
            }
            cell_list_[cell_idx].first = make_range(first, iter);
        }

        MJOLNIR_LOG_INFO("ranges are determined");

        const real_type r_c  = cutoff_ * (1 + margin_);
        const real_type r_c2 = r_c * r_c;

        std::vector<neighbor_type> partner;
        for(std::size_t i=0; i<sys.size(); ++i)
        {
            const auto& ri   = sys.position(i);
            const auto& cell = cell_list_[this->calc_index(ri)];

            partner.clear();
            for(std::size_t cidx : cell.second) // for all adjacent cells...
            {
                for(auto pici : cell_list_[cidx].first)
                {
                    const auto j = pici.first;
                    if(j <= i || this->exclusion_.is_excluded(i, j))
                    {
                        continue;
                    }

                    const auto& rj = sys.position(j);
                    if(math::length_sq(sys.adjust_direction(rj - ri)) < r_c2)
                    {
                        partner.emplace_back(j, pot.prepare_params(i, j));
                    }
                }
            }
            // make the result consistent with NaivePairCalculation...
            std::sort(partner.begin(), partner.end());

            this->neighbors_.add_list_for(i, partner.begin(), partner.end());
        }

        MJOLNIR_LOG_INFO("ranges are determined");

        this->current_margin_ = cutoff_ * margin_;
        return ;
    }

    //XXX do NOT call this from `parallel` region.
    template<typename PotentialT>
    void update(const real_type   dmargin, const system_type& sys,
                const PotentialT& pot)
    {
        this->current_margin_ -= dmargin;

        if(this->current_margin_ < 0.)
        {
            this->make(sys, pot);
        }
        return ;
    }

    real_type cutoff() const noexcept {return this->cutoff_;}
    real_type margin() const noexcept {return this->margin_;}

    range_type partners(std::size_t i) const noexcept {return neighbors_[i];}

  private:

    // calc cell index of the position
    std::size_t calc_index(const coordinate_type& pos) const noexcept
    {
        const auto x = static_cast<std::int64_t>(std::floor(math::X(pos) * r_cell_size_)) % dim;
        const auto y = static_cast<std::int64_t>(std::floor(math::Y(pos) * r_cell_size_)) % dim;
        const auto z = static_cast<std::int64_t>(std::floor(math::Z(pos) * r_cell_size_)) % dim;

        return this->calc_index(
                (x<0) ? x+dim : x, (y<0) ? y+dim : y, (z<0) ? z+dim : z);
    }

    std::size_t calc_index(const std::size_t x, const std::size_t y,
                           const std::size_t z) const noexcept
    {
        return x + dim_size * y + dim_size * dim_size * z;
    }

    void set_cutoff(const real_type c) noexcept
    {
        this->cutoff_ = c;
        this->r_cell_size_ = 1 / (cutoff_ * (1 + margin_) * (1+mesh_epsilon));
    }
    void set_margin(const real_type m) noexcept
    {
        this->margin_ = m;
        this->r_cell_size_ = 1 / (cutoff_ * (1 + margin_) * (1+mesh_epsilon));
    }

  private:

    real_type cutoff_;
    real_type margin_;
    real_type current_margin_;
    real_type r_cell_size_;

    exclusion_list_type       exclusion_;
    neighbor_list_type        neighbors_;
    cell_list_type            cell_list_;
    cell_index_container_type index_by_cell_;
    cell_index_container_type index_by_cell_buf_; // buffer for sort
    // index_by_cell_ has {particle idx, cell idx} and sorted by cell idx
    // first term of cell list contains first and last idx of index_by_cell
};

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
constexpr std::size_t UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>::dim_size;

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
constexpr std::int64_t UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>::dim;

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
constexpr std::size_t UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>::total_size;

template<typename realT, template<typename, typename> class boundaryT,
         typename parameterT, std::size_t dimI>
constexpr typename UnlimitedGridCellList<
    OpenMPSimulatorTraits<realT, boundaryT>, parameterT, dimI>::real_type
    UnlimitedGridCellList<OpenMPSimulatorTraits<realT, boundaryT>,
                          parameterT, dimI>::mesh_epsilon;

} // mjolnir
#endif/* MJOLNIR_UNLIMITED_GRID_CELL_LIST */
<|endoftext|>


<commit_before>#include "glresource.hpp"
#include "glx.hpp"
#include "adaptsdl.hpp"
#include "systeminfo.hpp"

namespace rs {
	const std::string& IGLResource::getResourceName() const {
		static std::string str("IGLResource");
		return str;
	}

	namespace {
		template <class Tex_t, class... Ts>
		auto MakeStaticTex(Ts&&... ts) {
			return [&](const spn::URI& uri){
				return UPResource(new Tex_t(uri, std::forward<Ts>(ts)...));
			};
		}
	}

	std::shared_ptr<FxBlock> InitFxBlock() {
		return std::make_shared<FxBlock>();
	}
	void ReloadFxBlock(const spn::URI& uri) {
		mgr_block.replace(uri, GLEffect::LoadGLXStruct(uri));
	}
	const std::string GLRes::cs_rtname[] = {
		"texture",
		"effect"
	};
	GLRes::GLRes(): ResMgrApp(cs_rtname) {
		_bInit = false;
		_bInDtor = false;
		_upFb.reset(new GLFBuffer());
		// 既にデバイスがアクティブだったらonDeviceResetを呼ぶ
		_cbInit =
			[&](auto h){
				if(_bInit)
					h.ref()->onDeviceReset();
			};

		// EmptyTexture = 1x1の単色テクスチャ
		uint32_t buff1 = 0xffffffff;
		_hlEmptyTex.reset(new HLTex(createTextureInit(spn::Size(1,1), GL_RGBA, false, true, GL_UNSIGNED_BYTE, spn::AB_Byte(&buff1, 1))));
	}
	GLRes::~GLRes() {
		// 破棄フラグを立ててからOnDeviceLost関数を呼ぶ
		_bInDtor = true;
		onDeviceLost();
	}
	const FBInfo_OP& GLRes::getDefaultDepth() const {
		return _defaultDepth;
	}
	const FBInfo_OP& GLRes::getDefaultColor() const {
		return _defaultColor;
	}
	const std::string& GLRes::getResourceName(spn::SHandle sh) const {
		if(sh) {
			IGLResource* gr = HRes::FromHandle(sh)->get();
			return gr->getResourceName();
		}
		const static std::string name("IGLResource");
		return name;
	}
	spn::URI GLRes::_modifyResourceName(spn::URI& key) const {
		spn::URI key_k = base_type::_modifyResourceName(key);
		// Cubeプリフィックスを持っている時は末尾に加える
		if(_chPostfix) {
			auto str = key_k.getLast_utf8();
			str += *_chPostfix;
			key_k.popBack();
			key_k.pushBack(str);
		}
		return key_k;
	}
	HLTex GLRes::loadTexture(const std::string& name, MipState miplevel, OPInCompressedFmt fmt) {
		_setResourceTypeId(ResourceType::Texture);
		return loadTextureUri(_uriFromResourceName(name), miplevel, fmt);
	}
	HLTex GLRes::loadTextureUri(const spn::URI& uri, MipState miplevel, OPInCompressedFmt fmt) {
		_chPostfix = spn::none;
		return Cast<UPTexture>(
			loadResourceApp(uri,
				MakeStaticTex<Texture_StaticURI>(miplevel, fmt),
				_cbInit)
		);
	}
	HLTex GLRes::loadCubeTexture(const std::string& name, MipState miplevel, OPInCompressedFmt fmt) {
		_setResourceTypeId(ResourceType::Texture);
		// 0を付加してリソース検索
		spn::PathBlock pb(name);
		pb.setPathNum([](auto /*num*/) -> spn::Int_OP{ return 0; });

		pb = _uriFromResourceName(pb.plain_utf8()).path();
		// 末尾の0を除く
		pb.setPathNum([](auto) ->spn::Int_OP{ return spn::none; });
		return loadCubeTextureUri(spn::URI("file", pb), miplevel, fmt);
	}
	HLTex GLRes::loadCubeTextureUri(const spn::URI& uri, MipState miplevel, OPInCompressedFmt fmt) {
		// 連番CubeTexutreの場合はキーとなるURIの末尾に"@"を付加する
		_chPostfix = '@';
		// Uriの連番展開
		return Cast<UPTexture>(
					loadResourceApp(uri,
						MakeStaticTex<Texture_StaticCubeURI>(miplevel, fmt),
						_cbInit)
				);
	}
	// 連番キューブ: Key=(Path+@, ext) URI=(Path, ext)
	HLTex GLRes::_loadCubeTexture(MipState miplevel, OPInCompressedFmt fmt, const spn::URI& uri0, const spn::URI& uri1, const spn::URI& uri2,
								  const spn::URI& uri3, const spn::URI& uri4, const spn::URI& uri5)
	{
		_chPostfix = spn::none;
		// 個別指定CubeTextureの場合はリソース名はUriを全部つなげた文字列とする
		std::string tmp(uri0.plainUri_utf8());
		auto fn = [&tmp](const spn::URI& u) { tmp.append(u.plainUri_utf8()); };
		fn(uri1); fn(uri2); fn(uri3); fn(uri4); fn(uri5);

		return Cast<UPTexture>(
			loadResourceApp(spn::URI("file", tmp),
				[&](const spn::URI&){ return UPResource(new Texture_StaticCubeURI(uri0,uri1,uri2,uri3,uri4,uri5,miplevel,fmt)); },
				_cbInit)
		);
	}
	HLTex GLRes::_createTexture(bool bCube, const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore) {
		LHdl lh = base_type::acquire(UPResource(new Texture_Mem(bCube, fmt, size, bStream, bRestore)));
		_cbInit(lh);
		return Cast<UPTexture>(std::move(lh));
	}
	HLTex GLRes::createCubeTexture(const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore) {
		return _createTexture(true, size, fmt, bStream, bRestore);
	}
	HLTex GLRes::createTexture(const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore) {
		return _createTexture(false, size, fmt, bStream, bRestore);
	}
	HLTex GLRes::createTextureInit(const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore, GLTypeFmt srcFmt, spn::AB_Byte data) {
		auto ptr = std::make_unique<Texture_Mem>(false, fmt, size, bStream, bRestore);
		ptr->writeData(data, srcFmt);
		LHdl lh = base_type::acquire(std::move(ptr));
		_cbInit(lh);
		return Cast<UPTexture>(std::move(lh));
	}
	HLSh GLRes::makeShader(ShType type, const std::string& src) {
		LHdl lh = base_type::acquire(UPResource(new GLShader(type, src)));
		_cbInit(lh);
		return Cast<UPShader>(std::move(lh));
	}
	HLFx GLRes::loadEffect(const std::string& name, const CBCreateFx& cb) {
		_chPostfix = spn::none;
		_setResourceTypeId(ResourceType::Effect);
		auto ret = this->base_t::acquire(name, [&](const spn::URI& u){
				return UPResource(cb(u.plain_utf8()));
		});
		if(ret.second)
			_cbInit(ret.first);
		return Cast<UPEffect>(ret.first);
	}
	UPResource GLRes::replaceEffect(HLFx& hlFx, const CBCreateFx& cb) {
		auto& key = this->base_t::getKey(hlFx.get());
		UPResource res(cb(key.plain_utf8()));
		hlFx->get()->onDeviceLost();
		// 前のエンジン変数をとっておく
		UPResource prev = std::move(hlFx.ref());
		// ハンドルの中身(UPResource)を置き換え
		hlFx = Cast<UPEffect>(this->base_t::replace(key, std::move(res)));
		_cbInit(hlFx.get());
		return prev;
	}
	HLVb GLRes::makeVBuffer(GLuint dtype) {
		LHdl lh = base_type::acquire(UPResource(new GLVBuffer(dtype)));
		_cbInit(lh);
		return Cast<UPVBuffer>(std::move(lh));
	}
	HLIb GLRes::makeIBuffer(GLuint dtype) {
		LHdl lh = base_type::acquire(UPResource(new GLIBuffer(dtype)));
		_cbInit(lh);
		return Cast<UPIBuffer>(std::move(lh));
	}

	HLProg GLRes::makeProgram(HSh vsh, HSh psh) {
		LHdl lh = base_type::acquire(UPResource(new GLProgram(vsh,psh)));
		_cbInit(lh);
		return Cast<UPProg>(std::move(lh));
	}
	HLProg GLRes::makeProgram(HSh vsh, HSh gsh, HSh psh) {
		LHdl lh = base_type::acquire(UPResource(new GLProgram(vsh,gsh,psh)));
		_cbInit(lh);
		return Cast<UPProg>(std::move(lh));
	}
	GLFBufferTmp& GLRes::getTmpFramebuffer() const {
		return *_tmpFb;
	}
	HTex GLRes::getEmptyTexture() const {
		return _hlEmptyTex->get();
	}
	bool GLRes::deviceStatus() const {
		return _bInit;
	}
	bool GLRes::isInDtor() const {
		return _bInDtor;
	}
	void GLRes::onDeviceLost() {
		if(_bInit) {
			_bInit = false;
			for(auto& r : *this)
				r->onDeviceLost();
			// 一旦DeviceLostしたらフレームバッファはデフォルトに戻る(in Gameloop)
			_tmpFb->use_begin();
			_tmpFb.reset(nullptr);

			_upFb->onDeviceLost();
			_clearDefaultInfo();
		}
	}
	void GLRes::_initDefaultInfo() {
		GL.glBindFramebuffer(GL_FRAMEBUFFER, 0);
		using Att = GLFBufferCore::Att;
		_defaultColor = GLFBufferCore::GetCurrentInfo(Att::COLOR0);
		_defaultDepth = GLFBufferCore::GetCurrentInfo(Att::DEPTH);
	}
	void GLRes::_clearDefaultInfo() {
		_defaultDepth = spn::none;
		_defaultColor = spn::none;
	}
	void GLRes::onDeviceReset() {
		if(!_bInit) {
			_bInit = true;
			_upFb->onDeviceReset();
			_tmpFb.reset(new GLFBufferTmp(_upFb->getBufferID(), mgr_info.getScreenSize()));
			_initDefaultInfo();
			for(auto& r : *this)
				r->onDeviceReset();
		}
	}
	spn::LHandle GLRes::loadResource(spn::AdaptStream& /*ast*/, const spn::URI& uri) {
		auto ext = uri.getExtension();
		spn::LHandle ret;
		// is it Texture?
		if(ext=="png" || ext=="jpg" || ext=="bmp")
			ret = loadTextureUri(uri);
		// is it Effect(Shader)?
		else if(ext == "glx") {
			HLRW hlRW = mgr_rw.fromURI(uri, RWops::Read);
			ret = loadEffect(uri.plain_utf8(), [](auto& name){
					return new GLEffect(name); });
		}
		return ret;
	}
	HLFb GLRes::makeFBuffer() {
		LHdl lh = base_type::acquire(UPResource(new GLFBuffer()));
		_cbInit(lh);
		return Cast<UPFBuffer>(lh);
	}
	HLRb GLRes::makeRBuffer(int w, int h, GLInRenderFmt fmt) {
		LHdl lh = base_type::acquire(UPResource(new GLRBuffer(w, h, fmt)));
		_cbInit(lh);
		return Cast<UPRBuffer>(lh);
	}

	namespace draw {
		Clear::Clear(const ClearParam& p):
			_param(p)
		{}
		void Clear::exec() {
			GLenum flag = 0;
			if(_param.color) {
				flag |= GL_COLOR_BUFFER_BIT;
				auto& c = *_param.color;
				GL.glClearColor(c.x, c.y, c.z, c.w);
			}
			if(_param.depth) {
				flag |= GL_DEPTH_BUFFER_BIT;
#ifndef USE_OPENGLES2
				GL.glClearDepth
#else
				GL.glClearDepthf
#endif
					(*_param.depth);
			}
			if(_param.stencil) {
				flag |= GL_STENCIL_BUFFER_BIT;
				GL.glClearStencil(*_param.stencil);
			}
			// WindowsではDepthMaskをTrueにしないとクリアされない為、一旦値を退避
			GLboolean b;
			GL.glGetBooleanv(GL_DEPTH_TEST, &b);
			GL.glDepthMask(GL_TRUE);
			GL.glClear(flag);
			// DepthMask値を戻す
			GL.glDepthMask(b);
		}
	}
}
<commit_msg>GLRes: FBufferTmpの初期化パラメータの修正<commit_after>#include "glresource.hpp"
#include "glx.hpp"
#include "adaptsdl.hpp"
#include "systeminfo.hpp"

namespace rs {
	const std::string& IGLResource::getResourceName() const {
		static std::string str("IGLResource");
		return str;
	}

	namespace {
		template <class Tex_t, class... Ts>
		auto MakeStaticTex(Ts&&... ts) {
			return [&](const spn::URI& uri){
				return UPResource(new Tex_t(uri, std::forward<Ts>(ts)...));
			};
		}
	}

	std::shared_ptr<FxBlock> InitFxBlock() {
		return std::make_shared<FxBlock>();
	}
	void ReloadFxBlock(const spn::URI& uri) {
		mgr_block.replace(uri, GLEffect::LoadGLXStruct(uri));
	}
	const std::string GLRes::cs_rtname[] = {
		"texture",
		"effect"
	};
	GLRes::GLRes(): ResMgrApp(cs_rtname) {
		_bInit = false;
		_bInDtor = false;
		_upFb.reset(new GLFBuffer());
		// 既にデバイスがアクティブだったらonDeviceResetを呼ぶ
		_cbInit =
			[&](auto h){
				if(_bInit)
					h.ref()->onDeviceReset();
			};

		// EmptyTexture = 1x1の単色テクスチャ
		uint32_t buff1 = 0xffffffff;
		_hlEmptyTex.reset(new HLTex(createTextureInit(spn::Size(1,1), GL_RGBA, false, true, GL_UNSIGNED_BYTE, spn::AB_Byte(&buff1, sizeof(buff1)))));
	}
	GLRes::~GLRes() {
		// 破棄フラグを立ててからOnDeviceLost関数を呼ぶ
		_bInDtor = true;
		onDeviceLost();
	}
	const FBInfo_OP& GLRes::getDefaultDepth() const {
		return _defaultDepth;
	}
	const FBInfo_OP& GLRes::getDefaultColor() const {
		return _defaultColor;
	}
	const std::string& GLRes::getResourceName(spn::SHandle sh) const {
		if(sh) {
			IGLResource* gr = HRes::FromHandle(sh)->get();
			return gr->getResourceName();
		}
		const static std::string name("IGLResource");
		return name;
	}
	spn::URI GLRes::_modifyResourceName(spn::URI& key) const {
		spn::URI key_k = base_type::_modifyResourceName(key);
		// Cubeプリフィックスを持っている時は末尾に加える
		if(_chPostfix) {
			auto str = key_k.getLast_utf8();
			str += *_chPostfix;
			key_k.popBack();
			key_k.pushBack(str);
		}
		return key_k;
	}
	HLTex GLRes::loadTexture(const std::string& name, MipState miplevel, OPInCompressedFmt fmt) {
		_setResourceTypeId(ResourceType::Texture);
		return loadTextureUri(_uriFromResourceName(name), miplevel, fmt);
	}
	HLTex GLRes::loadTextureUri(const spn::URI& uri, MipState miplevel, OPInCompressedFmt fmt) {
		_chPostfix = spn::none;
		return Cast<UPTexture>(
			loadResourceApp(uri,
				MakeStaticTex<Texture_StaticURI>(miplevel, fmt),
				_cbInit)
		);
	}
	HLTex GLRes::loadCubeTexture(const std::string& name, MipState miplevel, OPInCompressedFmt fmt) {
		_setResourceTypeId(ResourceType::Texture);
		// 0を付加してリソース検索
		spn::PathBlock pb(name);
		pb.setPathNum([](auto /*num*/) -> spn::Int_OP{ return 0; });

		pb = _uriFromResourceName(pb.plain_utf8()).path();
		// 末尾の0を除く
		pb.setPathNum([](auto) ->spn::Int_OP{ return spn::none; });
		return loadCubeTextureUri(spn::URI("file", pb), miplevel, fmt);
	}
	HLTex GLRes::loadCubeTextureUri(const spn::URI& uri, MipState miplevel, OPInCompressedFmt fmt) {
		// 連番CubeTexutreの場合はキーとなるURIの末尾に"@"を付加する
		_chPostfix = '@';
		// Uriの連番展開
		return Cast<UPTexture>(
					loadResourceApp(uri,
						MakeStaticTex<Texture_StaticCubeURI>(miplevel, fmt),
						_cbInit)
				);
	}
	// 連番キューブ: Key=(Path+@, ext) URI=(Path, ext)
	HLTex GLRes::_loadCubeTexture(MipState miplevel, OPInCompressedFmt fmt, const spn::URI& uri0, const spn::URI& uri1, const spn::URI& uri2,
								  const spn::URI& uri3, const spn::URI& uri4, const spn::URI& uri5)
	{
		_chPostfix = spn::none;
		// 個別指定CubeTextureの場合はリソース名はUriを全部つなげた文字列とする
		std::string tmp(uri0.plainUri_utf8());
		auto fn = [&tmp](const spn::URI& u) { tmp.append(u.plainUri_utf8()); };
		fn(uri1); fn(uri2); fn(uri3); fn(uri4); fn(uri5);

		return Cast<UPTexture>(
			loadResourceApp(spn::URI("file", tmp),
				[&](const spn::URI&){ return UPResource(new Texture_StaticCubeURI(uri0,uri1,uri2,uri3,uri4,uri5,miplevel,fmt)); },
				_cbInit)
		);
	}
	HLTex GLRes::_createTexture(bool bCube, const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore) {
		LHdl lh = base_type::acquire(UPResource(new Texture_Mem(bCube, fmt, size, bStream, bRestore)));
		_cbInit(lh);
		return Cast<UPTexture>(std::move(lh));
	}
	HLTex GLRes::createCubeTexture(const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore) {
		return _createTexture(true, size, fmt, bStream, bRestore);
	}
	HLTex GLRes::createTexture(const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore) {
		return _createTexture(false, size, fmt, bStream, bRestore);
	}
	HLTex GLRes::createTextureInit(const spn::Size& size, GLInSizedFmt fmt, bool bStream, bool bRestore, GLTypeFmt srcFmt, spn::AB_Byte data) {
		auto ptr = std::make_unique<Texture_Mem>(false, fmt, size, bStream, bRestore);
		ptr->writeData(data, srcFmt);
		LHdl lh = base_type::acquire(std::move(ptr));
		_cbInit(lh);
		return Cast<UPTexture>(std::move(lh));
	}
	HLSh GLRes::makeShader(ShType type, const std::string& src) {
		LHdl lh = base_type::acquire(UPResource(new GLShader(type, src)));
		_cbInit(lh);
		return Cast<UPShader>(std::move(lh));
	}
	HLFx GLRes::loadEffect(const std::string& name, const CBCreateFx& cb) {
		_chPostfix = spn::none;
		_setResourceTypeId(ResourceType::Effect);
		auto ret = this->base_t::acquire(name, [&](const spn::URI& u){
				return UPResource(cb(u.plain_utf8()));
		});
		if(ret.second)
			_cbInit(ret.first);
		return Cast<UPEffect>(ret.first);
	}
	UPResource GLRes::replaceEffect(HLFx& hlFx, const CBCreateFx& cb) {
		auto& key = this->base_t::getKey(hlFx.get());
		UPResource res(cb(key.plain_utf8()));
		hlFx->get()->onDeviceLost();
		// 前のエンジン変数をとっておく
		UPResource prev = std::move(hlFx.ref());
		// ハンドルの中身(UPResource)を置き換え
		hlFx = Cast<UPEffect>(this->base_t::replace(key, std::move(res)));
		_cbInit(hlFx.get());
		return prev;
	}
	HLVb GLRes::makeVBuffer(GLuint dtype) {
		LHdl lh = base_type::acquire(UPResource(new GLVBuffer(dtype)));
		_cbInit(lh);
		return Cast<UPVBuffer>(std::move(lh));
	}
	HLIb GLRes::makeIBuffer(GLuint dtype) {
		LHdl lh = base_type::acquire(UPResource(new GLIBuffer(dtype)));
		_cbInit(lh);
		return Cast<UPIBuffer>(std::move(lh));
	}

	HLProg GLRes::makeProgram(HSh vsh, HSh psh) {
		LHdl lh = base_type::acquire(UPResource(new GLProgram(vsh,psh)));
		_cbInit(lh);
		return Cast<UPProg>(std::move(lh));
	}
	HLProg GLRes::makeProgram(HSh vsh, HSh gsh, HSh psh) {
		LHdl lh = base_type::acquire(UPResource(new GLProgram(vsh,gsh,psh)));
		_cbInit(lh);
		return Cast<UPProg>(std::move(lh));
	}
	GLFBufferTmp& GLRes::getTmpFramebuffer() const {
		return *_tmpFb;
	}
	HTex GLRes::getEmptyTexture() const {
		return _hlEmptyTex->get();
	}
	bool GLRes::deviceStatus() const {
		return _bInit;
	}
	bool GLRes::isInDtor() const {
		return _bInDtor;
	}
	void GLRes::onDeviceLost() {
		if(_bInit) {
			_bInit = false;
			for(auto& r : *this)
				r->onDeviceLost();
			// 一旦DeviceLostしたらフレームバッファはデフォルトに戻る(in Gameloop)
			_tmpFb->use_begin();
			_tmpFb.reset(nullptr);

			_upFb->onDeviceLost();
			_clearDefaultInfo();
		}
	}
	void GLRes::_initDefaultInfo() {
		GL.glBindFramebuffer(GL_FRAMEBUFFER, 0);
		using Att = GLFBufferCore::Att;
		_defaultColor = GLFBufferCore::GetCurrentInfo(Att::COLOR0);
		_defaultDepth = GLFBufferCore::GetCurrentInfo(Att::DEPTH);
	}
	void GLRes::_clearDefaultInfo() {
		_defaultDepth = spn::none;
		_defaultColor = spn::none;
	}
	void GLRes::onDeviceReset() {
		if(!_bInit) {
			_bInit = true;
			_upFb->onDeviceReset();
			_tmpFb.reset(new GLFBufferTmp(_upFb->getBufferID(), mgr_info.getScreenSize()));
			_initDefaultInfo();
			for(auto& r : *this)
				r->onDeviceReset();
		}
	}
	spn::LHandle GLRes::loadResource(spn::AdaptStream& /*ast*/, const spn::URI& uri) {
		auto ext = uri.getExtension();
		spn::LHandle ret;
		// is it Texture?
		if(ext=="png" || ext=="jpg" || ext=="bmp")
			ret = loadTextureUri(uri);
		// is it Effect(Shader)?
		else if(ext == "glx") {
			HLRW hlRW = mgr_rw.fromURI(uri, RWops::Read);
			ret = loadEffect(uri.plain_utf8(), [](auto& name){
					return new GLEffect(name); });
		}
		return ret;
	}
	HLFb GLRes::makeFBuffer() {
		LHdl lh = base_type::acquire(UPResource(new GLFBuffer()));
		_cbInit(lh);
		return Cast<UPFBuffer>(lh);
	}
	HLRb GLRes::makeRBuffer(int w, int h, GLInRenderFmt fmt) {
		LHdl lh = base_type::acquire(UPResource(new GLRBuffer(w, h, fmt)));
		_cbInit(lh);
		return Cast<UPRBuffer>(lh);
	}

	namespace draw {
		Clear::Clear(const ClearParam& p):
			_param(p)
		{}
		void Clear::exec() {
			GLenum flag = 0;
			if(_param.color) {
				flag |= GL_COLOR_BUFFER_BIT;
				auto& c = *_param.color;
				GL.glClearColor(c.x, c.y, c.z, c.w);
			}
			if(_param.depth) {
				flag |= GL_DEPTH_BUFFER_BIT;
#ifndef USE_OPENGLES2
				GL.glClearDepth
#else
				GL.glClearDepthf
#endif
					(*_param.depth);
			}
			if(_param.stencil) {
				flag |= GL_STENCIL_BUFFER_BIT;
				GL.glClearStencil(*_param.stencil);
			}
			// WindowsではDepthMaskをTrueにしないとクリアされない為、一旦値を退避
			GLboolean b;
			GL.glGetBooleanv(GL_DEPTH_TEST, &b);
			GL.glDepthMask(GL_TRUE);
			GL.glClear(flag);
			// DepthMask値を戻す
			GL.glDepthMask(b);
		}
	}
}
<|endoftext|>


<commit_before>// This file is part of gltfpack; see gltfpack.h for version/license details
#include "gltfpack.h"

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

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

struct BasisSettings
{
	int etc1s_l;
	int etc1s_q;
	int uastc_l;
	float uastc_q;
};

static const char* kMimeTypes[][2] = {
    {"image/jpeg", ".jpg"},
    {"image/jpeg", ".jpeg"},
    {"image/png", ".png"},
};

static const BasisSettings kBasisSettings[10] = {
    {1, 1, 0, 1.5f},
    {1, 6, 0, 1.f},
    {1, 20, 1, 1.0f},
    {1, 50, 1, 0.75f},
    {1, 90, 1, 0.5f},
    {1, 128, 1, 0.4f},
    {1, 160, 1, 0.34f},
    {1, 192, 1, 0.29f}, // default
    {1, 224, 2, 0.26f},
    {1, 255, 2, 0.f},
};

void analyzeImages(cgltf_data* data, std::vector<ImageInfo>& images)
{
	for (size_t i = 0; i < data->materials_count; ++i)
	{
		const cgltf_material& material = data->materials[i];

		if (material.has_pbr_metallic_roughness)
		{
			const cgltf_pbr_metallic_roughness& pbr = material.pbr_metallic_roughness;

			if (pbr.base_color_texture.texture && pbr.base_color_texture.texture->image)
				images[pbr.base_color_texture.texture->image - data->images].srgb = true;
		}

		if (material.has_pbr_specular_glossiness)
		{
			const cgltf_pbr_specular_glossiness& pbr = material.pbr_specular_glossiness;

			if (pbr.diffuse_texture.texture && pbr.diffuse_texture.texture->image)
				images[pbr.diffuse_texture.texture->image - data->images].srgb = true;
		}

		if (material.emissive_texture.texture && material.emissive_texture.texture->image)
			images[material.emissive_texture.texture->image - data->images].srgb = true;

		if (material.normal_texture.texture && material.normal_texture.texture->image)
			images[material.normal_texture.texture->image - data->images].normal_map = true;
	}
}

const char* inferMimeType(const char* path)
{
	const char* ext = strrchr(path, '.');
	if (!ext)
		return "";

	std::string extl = ext;
	for (size_t i = 0; i < extl.length(); ++i)
		extl[i] = char(tolower(extl[i]));

	for (size_t i = 0; i < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++i)
		if (extl == kMimeTypes[i][1])
			return kMimeTypes[i][0];

	return "";
}

static const char* mimeExtension(const char* mime_type)
{
	for (size_t i = 0; i < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++i)
		if (strcmp(kMimeTypes[i][0], mime_type) == 0)
			return kMimeTypes[i][1];

	return ".raw";
}

#ifdef __EMSCRIPTEN__
EM_JS(int, execute, (const char* cmd, bool ignore_stdout, bool ignore_stderr), {
	var cp = require('child_process');
	var stdio = [ 'ignore', ignore_stdout ? 'ignore' : 'inherit', ignore_stderr ? 'ignore' : 'inherit' ];
	var ret = cp.spawnSync(UTF8ToString(cmd), [], {shell:true, stdio:stdio });
	return ret.status == null ? 256 : ret.status;
});

EM_JS(const char*, readenv, (const char* name), {
	var val = process.env[UTF8ToString(name)];
	if (!val)
		return 0;
	var ret = _malloc(lengthBytesUTF8(val) + 1);
	stringToUTF8(val, ret, lengthBytesUTF8(val) + 1);
	return ret;
});
#else
static int execute(const char* cmd_, bool ignore_stdout, bool ignore_stderr)
{
#ifdef _WIN32
	std::string ignore = "nul";
#else
	std::string ignore = "/dev/null";
#endif

	std::string cmd = cmd_;

	if (ignore_stdout)
		(cmd += " >") += ignore;
	if (ignore_stderr)
		(cmd += " 2>") += ignore;

	return system(cmd.c_str());
}

static const char* readenv(const char* name)
{
	return getenv(name);
}
#endif

bool checkBasis(bool verbose)
{
	const char* basisu_path = readenv("BASISU_PATH");
	std::string cmd = basisu_path ? basisu_path : "basisu";

	cmd += " -version";

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ true);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0;
}

bool encodeBasis(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool pow2, bool uastc, bool verbose)
{
	(void)scale;
	(void)pow2;

	TempFile temp_input(mimeExtension(mime_type));
	TempFile temp_output(".basis");

	if (!writeFile(temp_input.path.c_str(), data))
		return false;

	const char* basisu_path = readenv("BASISU_PATH");
	std::string cmd = basisu_path ? basisu_path : "basisu";

	const BasisSettings& bs = kBasisSettings[quality <= 0 ? 0 : quality > 9 ? 9 : quality - 1];

	cmd += " -mipmap";

	if (normal_map)
	{
		cmd += " -normal_map";
		// for optimal quality we should specify seperate_rg_to_color_alpha but this requires renderer awareness
	}
	else if (!srgb)
	{
		cmd += " -linear";
	}

	if (uastc)
	{
		char settings[128];
		sprintf(settings, " -uastc_level %d -uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

		cmd += " -uastc";
		cmd += settings;
		cmd += " -uastc_rdo_d 1024";
	}
	else
	{
		char settings[128];
		sprintf(settings, " -comp_level %d -q %d", bs.etc1s_l, bs.etc1s_q);

		cmd += settings;
	}

	cmd += " -file ";
	cmd += temp_input.path;
	cmd += " -output_file ";
	cmd += temp_output.path;

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ false);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0 && readFile(temp_output.path.c_str(), result);
}

bool checkKtx(bool verbose)
{
	const char* toktx_path = readenv("TOKTX_PATH");
	std::string cmd = toktx_path ? toktx_path : "toktx";

	cmd += " --version";

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ true);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0;
}

static int readInt16(const std::string& data, size_t offset)
{
	return (unsigned char)data[offset] * 256 + (unsigned char)data[offset + 1];
}

static bool getDimensionsPng(const std::string& data, int& width, int& height)
{
	if (data.size() < 8 + 8 + 13 + 4)
		return false;

	const char* signature = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a";
	if (data.compare(0, 8, signature) != 0)
		return false;

	if (data.compare(12, 4, "IHDR") != 0)
		return false;

	width = readInt16(data, 18);
	height = readInt16(data, 22);

	return true;
}

static bool getDimensionsJpeg(const std::string& data, int& width, int& height)
{
	size_t offset = 0;

	// note, this can stop parsing before reaching the end but we stop at SOF anyway
	while (offset + 4 <= data.size())
	{
		if (data[offset] != '\xff')
			return false;

		char marker = data[offset];

		if (marker == '\xff')
		{
			offset++;
			continue; // padding
		}

		// d0..d9 correspond to SOI, RSTn, EOI
		if (marker == 0 || unsigned(marker - '\xd0') <= 9)
		{
			offset += 2;
			continue; // no payload
		}

		// c0..c1 correspond to SOF0, SOF1
		if (marker == '\xc0' || marker == '\xc2')
		{
			if (offset + 10 > data.size())
				return false;

			width = readInt16(data, offset + 7);
			height = readInt16(data, offset + 5);

			return true;
		}

		offset += 2 + readInt16(data, offset + 2);
	}

	return false;
}

static bool getDimensions(const std::string& data, const char* mime_type, int& width, int& height)
{
	if (strcmp(mime_type, "image/png") == 0)
		return getDimensionsPng(data, width, height);
	if (strcmp(mime_type, "image/jpeg") == 0)
		return getDimensionsJpeg(data, width, height);

	return false;
}

static int roundPow2(int value)
{
	int result = 1;

	while (result < value)
		result <<= 1;

	// to prevent odd texture sizes from increasing the size too much, we round to nearest power of 2 above a certain size
	if (value > 128 && result * 3 / 4 > value)
		result >>= 1;

	return result;
}

static int roundBlock(int value)
{
	return (value == 1 || value == 2) ? value : (value + 3) & ~3;
}

bool encodeKtx(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool pow2, bool uastc, bool verbose)
{
	int width = 0, height = 0;
	if (!getDimensions(data, mime_type, width, height))
		return false;

	TempFile temp_input(mimeExtension(mime_type));
	TempFile temp_output(".ktx2");

	if (!writeFile(temp_input.path.c_str(), data))
		return false;

	const char* toktx_path = readenv("TOKTX_PATH");
	std::string cmd = toktx_path ? toktx_path : "toktx";

	const BasisSettings& bs = kBasisSettings[quality <= 0 ? 0 : quality > 9 ? 9 : quality - 1];

	cmd += " --t2";
	cmd += " --2d";
	cmd += " --genmipmap";
	cmd += " --nowarn";

	int (*round)(int value) = pow2 ? roundPow2 : roundBlock;
	int newWidth = round(int(width * scale)), newHeight = round(int(height * scale));

	if (newWidth != width || newHeight != height)
	{
		char wh[128];
		sprintf(wh, " --resize %dx%d", newWidth, newHeight);
		cmd += wh;
	}

	if (uastc)
	{
		char settings[128];
		sprintf(settings, " %d --uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

		cmd += " --uastc";
		cmd += settings;
		cmd += " --uastc_rdo_d 1024";
		cmd += " --zcmp 9";
	}
	else
	{
		char settings[128];
		sprintf(settings, " --clevel %d --qlevel %d", bs.etc1s_l, bs.etc1s_q);

		cmd += " --bcmp";
		cmd += settings;

		// for optimal quality we should specify separate_rg_to_color_alpha but this requires renderer awareness
		if (normal_map)
			cmd += " --normal_map";
	}

	if (srgb)
		cmd += " --srgb";
	else
		cmd += " --linear";

	cmd += " -- ";
	cmd += temp_output.path;
	cmd += " ";
	cmd += temp_input.path;

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ false, /* ignore_stderr= */ false);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0 && readFile(temp_output.path.c_str(), result);
}
<commit_msg>gltfpack: Fix rounding logic for small textures<commit_after>// This file is part of gltfpack; see gltfpack.h for version/license details
#include "gltfpack.h"

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

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

struct BasisSettings
{
	int etc1s_l;
	int etc1s_q;
	int uastc_l;
	float uastc_q;
};

static const char* kMimeTypes[][2] = {
    {"image/jpeg", ".jpg"},
    {"image/jpeg", ".jpeg"},
    {"image/png", ".png"},
};

static const BasisSettings kBasisSettings[10] = {
    {1, 1, 0, 1.5f},
    {1, 6, 0, 1.f},
    {1, 20, 1, 1.0f},
    {1, 50, 1, 0.75f},
    {1, 90, 1, 0.5f},
    {1, 128, 1, 0.4f},
    {1, 160, 1, 0.34f},
    {1, 192, 1, 0.29f}, // default
    {1, 224, 2, 0.26f},
    {1, 255, 2, 0.f},
};

void analyzeImages(cgltf_data* data, std::vector<ImageInfo>& images)
{
	for (size_t i = 0; i < data->materials_count; ++i)
	{
		const cgltf_material& material = data->materials[i];

		if (material.has_pbr_metallic_roughness)
		{
			const cgltf_pbr_metallic_roughness& pbr = material.pbr_metallic_roughness;

			if (pbr.base_color_texture.texture && pbr.base_color_texture.texture->image)
				images[pbr.base_color_texture.texture->image - data->images].srgb = true;
		}

		if (material.has_pbr_specular_glossiness)
		{
			const cgltf_pbr_specular_glossiness& pbr = material.pbr_specular_glossiness;

			if (pbr.diffuse_texture.texture && pbr.diffuse_texture.texture->image)
				images[pbr.diffuse_texture.texture->image - data->images].srgb = true;
		}

		if (material.emissive_texture.texture && material.emissive_texture.texture->image)
			images[material.emissive_texture.texture->image - data->images].srgb = true;

		if (material.normal_texture.texture && material.normal_texture.texture->image)
			images[material.normal_texture.texture->image - data->images].normal_map = true;
	}
}

const char* inferMimeType(const char* path)
{
	const char* ext = strrchr(path, '.');
	if (!ext)
		return "";

	std::string extl = ext;
	for (size_t i = 0; i < extl.length(); ++i)
		extl[i] = char(tolower(extl[i]));

	for (size_t i = 0; i < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++i)
		if (extl == kMimeTypes[i][1])
			return kMimeTypes[i][0];

	return "";
}

static const char* mimeExtension(const char* mime_type)
{
	for (size_t i = 0; i < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); ++i)
		if (strcmp(kMimeTypes[i][0], mime_type) == 0)
			return kMimeTypes[i][1];

	return ".raw";
}

#ifdef __EMSCRIPTEN__
EM_JS(int, execute, (const char* cmd, bool ignore_stdout, bool ignore_stderr), {
	var cp = require('child_process');
	var stdio = [ 'ignore', ignore_stdout ? 'ignore' : 'inherit', ignore_stderr ? 'ignore' : 'inherit' ];
	var ret = cp.spawnSync(UTF8ToString(cmd), [], {shell:true, stdio:stdio });
	return ret.status == null ? 256 : ret.status;
});

EM_JS(const char*, readenv, (const char* name), {
	var val = process.env[UTF8ToString(name)];
	if (!val)
		return 0;
	var ret = _malloc(lengthBytesUTF8(val) + 1);
	stringToUTF8(val, ret, lengthBytesUTF8(val) + 1);
	return ret;
});
#else
static int execute(const char* cmd_, bool ignore_stdout, bool ignore_stderr)
{
#ifdef _WIN32
	std::string ignore = "nul";
#else
	std::string ignore = "/dev/null";
#endif

	std::string cmd = cmd_;

	if (ignore_stdout)
		(cmd += " >") += ignore;
	if (ignore_stderr)
		(cmd += " 2>") += ignore;

	return system(cmd.c_str());
}

static const char* readenv(const char* name)
{
	return getenv(name);
}
#endif

bool checkBasis(bool verbose)
{
	const char* basisu_path = readenv("BASISU_PATH");
	std::string cmd = basisu_path ? basisu_path : "basisu";

	cmd += " -version";

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ true);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0;
}

bool encodeBasis(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool pow2, bool uastc, bool verbose)
{
	(void)scale;
	(void)pow2;

	TempFile temp_input(mimeExtension(mime_type));
	TempFile temp_output(".basis");

	if (!writeFile(temp_input.path.c_str(), data))
		return false;

	const char* basisu_path = readenv("BASISU_PATH");
	std::string cmd = basisu_path ? basisu_path : "basisu";

	const BasisSettings& bs = kBasisSettings[quality <= 0 ? 0 : quality > 9 ? 9 : quality - 1];

	cmd += " -mipmap";

	if (normal_map)
	{
		cmd += " -normal_map";
		// for optimal quality we should specify seperate_rg_to_color_alpha but this requires renderer awareness
	}
	else if (!srgb)
	{
		cmd += " -linear";
	}

	if (uastc)
	{
		char settings[128];
		sprintf(settings, " -uastc_level %d -uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

		cmd += " -uastc";
		cmd += settings;
		cmd += " -uastc_rdo_d 1024";
	}
	else
	{
		char settings[128];
		sprintf(settings, " -comp_level %d -q %d", bs.etc1s_l, bs.etc1s_q);

		cmd += settings;
	}

	cmd += " -file ";
	cmd += temp_input.path;
	cmd += " -output_file ";
	cmd += temp_output.path;

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ false);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0 && readFile(temp_output.path.c_str(), result);
}

bool checkKtx(bool verbose)
{
	const char* toktx_path = readenv("TOKTX_PATH");
	std::string cmd = toktx_path ? toktx_path : "toktx";

	cmd += " --version";

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ true, /* ignore_stderr= */ true);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0;
}

static int readInt16(const std::string& data, size_t offset)
{
	return (unsigned char)data[offset] * 256 + (unsigned char)data[offset + 1];
}

static bool getDimensionsPng(const std::string& data, int& width, int& height)
{
	if (data.size() < 8 + 8 + 13 + 4)
		return false;

	const char* signature = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a";
	if (data.compare(0, 8, signature) != 0)
		return false;

	if (data.compare(12, 4, "IHDR") != 0)
		return false;

	width = readInt16(data, 18);
	height = readInt16(data, 22);

	return true;
}

static bool getDimensionsJpeg(const std::string& data, int& width, int& height)
{
	size_t offset = 0;

	// note, this can stop parsing before reaching the end but we stop at SOF anyway
	while (offset + 4 <= data.size())
	{
		if (data[offset] != '\xff')
			return false;

		char marker = data[offset];

		if (marker == '\xff')
		{
			offset++;
			continue; // padding
		}

		// d0..d9 correspond to SOI, RSTn, EOI
		if (marker == 0 || unsigned(marker - '\xd0') <= 9)
		{
			offset += 2;
			continue; // no payload
		}

		// c0..c1 correspond to SOF0, SOF1
		if (marker == '\xc0' || marker == '\xc2')
		{
			if (offset + 10 > data.size())
				return false;

			width = readInt16(data, offset + 7);
			height = readInt16(data, offset + 5);

			return true;
		}

		offset += 2 + readInt16(data, offset + 2);
	}

	return false;
}

static bool getDimensions(const std::string& data, const char* mime_type, int& width, int& height)
{
	if (strcmp(mime_type, "image/png") == 0)
		return getDimensionsPng(data, width, height);
	if (strcmp(mime_type, "image/jpeg") == 0)
		return getDimensionsJpeg(data, width, height);

	return false;
}

static int roundPow2(int value)
{
	int result = 1;

	while (result < value)
		result <<= 1;

	// to prevent odd texture sizes from increasing the size too much, we round to nearest power of 2 above a certain size
	if (value > 128 && result * 3 / 4 > value)
		result >>= 1;

	return result;
}

static int roundBlock(int value)
{
	return (value + 3) & ~3;
}

bool encodeKtx(const std::string& data, const char* mime_type, std::string& result, bool normal_map, bool srgb, int quality, float scale, bool pow2, bool uastc, bool verbose)
{
	int width = 0, height = 0;
	if (!getDimensions(data, mime_type, width, height))
		return false;

	TempFile temp_input(mimeExtension(mime_type));
	TempFile temp_output(".ktx2");

	if (!writeFile(temp_input.path.c_str(), data))
		return false;

	const char* toktx_path = readenv("TOKTX_PATH");
	std::string cmd = toktx_path ? toktx_path : "toktx";

	const BasisSettings& bs = kBasisSettings[quality <= 0 ? 0 : quality > 9 ? 9 : quality - 1];

	cmd += " --t2";
	cmd += " --2d";
	cmd += " --genmipmap";
	cmd += " --nowarn";

	int newWidth = roundBlock(int(width * scale)), newHeight = roundBlock(int(height * scale));

	if (pow2)
	{
		newWidth = roundPow2(newWidth);
		newHeight = roundPow2(newHeight);
	}

	if (newWidth != width || newHeight != height)
	{
		char wh[128];
		sprintf(wh, " --resize %dx%d", newWidth, newHeight);
		cmd += wh;
	}

	if (uastc)
	{
		char settings[128];
		sprintf(settings, " %d --uastc_rdo_q %.2f", bs.uastc_l, bs.uastc_q);

		cmd += " --uastc";
		cmd += settings;
		cmd += " --uastc_rdo_d 1024";
		cmd += " --zcmp 9";
	}
	else
	{
		char settings[128];
		sprintf(settings, " --clevel %d --qlevel %d", bs.etc1s_l, bs.etc1s_q);

		cmd += " --bcmp";
		cmd += settings;

		// for optimal quality we should specify separate_rg_to_color_alpha but this requires renderer awareness
		if (normal_map)
			cmd += " --normal_map";
	}

	if (srgb)
		cmd += " --srgb";
	else
		cmd += " --linear";

	cmd += " -- ";
	cmd += temp_output.path;
	cmd += " ";
	cmd += temp_input.path;

	int rc = execute(cmd.c_str(), /* ignore_stdout= */ false, /* ignore_stderr= */ false);
	if (verbose)
		printf("%s => %d\n", cmd.c_str(), rc);

	return rc == 0 && readFile(temp_output.path.c_str(), result);
}
<|endoftext|>


<commit_before>//
// Created by Miguel Rentes on 30/01/2017.
//

#include "STL.h"

void printKMax(int arr[], int n, int k) {
    deque<int> mydeque;
    for (int i = 0; i < n; i++) {
        // clean the deque at the back if the array element is greater
        // than the ones currently on the deque
        for (; !mydeque.empty() && arr[i] > mydeque.back();)
            mydeque.pop_back();
        mydeque.push_back(arr[i]);
        if (i >= k && mydeque.front() == arr[i-k])
            mydeque.pop_front();
        // at the end of the k-elements
        if (i >= k-1)
            printf (i < n-1 ? "%d " : "%d\n", mydeque.front());
    }
}

int main(void) {
    int t;
    cin >> t;
    while (t > 0) {
        int n, k;
        cin >> n >> k;
        int i;
        int arr[n];
        for (i = 0; i < n; i++)
            cin >> arr[i];
        printKMax(arr, n, k);
        t--;
    }
    return EXIT_SUCCESS;
}<commit_msg>Refactors solution for the Deque-STL challenge.<commit_after>//
// Created by Miguel Rentes on 30/01/2017.
//

#include "STL.h"

void printKMax(int arr[], int n, int k) {
    deque<int> mydeque;
    for (int i = 0; i < n; i++) {
        // clean the deque at the back if the array element is greater
        // than the ones currently on the deque
        for (; !mydeque.empty() && arr[i] > mydeque.back();)
            mydeque.pop_back();
        mydeque.push_back(arr[i]);
        // at another set of k-elements
        // pop out the elements if they are the same as the ones
        // previously read
        if (i >= k && mydeque.front() == arr[i-k])
            mydeque.pop_front();
        // at the end of the k-elements
        if (i >= k-1)
            printf (i < n-1 ? "%d " : "%d\n", mydeque.front());
    }
}

int main(void) {
    int t;
    cin >> t;
    while (t > 0) {
        int n, k;
        cin >> n >> k;
        int i;
        int arr[n];
        for (i = 0; i < n; i++)
            cin >> arr[i];
        printKMax(arr, n, k);
        t--;
    }
    return EXIT_SUCCESS;
}<|endoftext|>


<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkPath.h"
#include "SkRandom.h"

#define W   400
#define H   400
#define N   10

constexpr SkScalar SH = SkIntToScalar(H);

static void rnd_quad(SkPath* p, SkPaint* paint, SkRandom& rand) {
    p->moveTo(rand.nextRangeScalar(0,  W), rand.nextRangeScalar(0,  H));
    for (int x = 0; x < 2; ++x) {
        auto a = rand.nextRangeScalar(W/4, W),
             b = rand.nextRangeScalar(  0, H),
             c = rand.nextRangeScalar(  0, W),
             d = rand.nextRangeScalar(H/4, H);
        p->quadTo(a,b,c,d);
    }
    paint->setColor(rand.nextU());
    SkScalar width = rand.nextRangeScalar(1, 5);
    width *= width;
    paint->setStrokeWidth(width);
    paint->setAlpha(0xFF);
}

static void rnd_cubic(SkPath* p, SkPaint* paint, SkRandom& rand) {
    auto a = rand.nextRangeScalar(0,W),
         b = rand.nextRangeScalar(0,H);
    p->moveTo(a,b);
    for (int x = 0; x < 2; ++x) {
        auto c = rand.nextRangeScalar(W/4, W),
             d = rand.nextRangeScalar(  0, H),
             e = rand.nextRangeScalar(  0, W),
             f = rand.nextRangeScalar(H/4, H),
             g = rand.nextRangeScalar(W/4, W),
             h = rand.nextRangeScalar(H/4, H);
        p->cubicTo(c,d,e,f,g,h);
    }
    paint->setColor(rand.nextU());
    SkScalar width = rand.nextRangeScalar(1, 5);
    width *= width;
    paint->setStrokeWidth(width);
    paint->setAlpha(0xFF);
}

class BeziersGM : public skiagm::GM {
public:
    BeziersGM() {}

protected:

    SkString onShortName() override {
        return SkString("beziers");
    }

    SkISize onISize() override {
        return SkISize::Make(W, H*2);
    }

    void onDraw(SkCanvas* canvas) override {
        SkPaint paint;
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(SkIntToScalar(9)/2);
        paint.setAntiAlias(true);

        SkRandom rand;
        for (int i = 0; i < N; i++) {
            SkPath p;
            rnd_quad(&p, &paint, rand);
            canvas->drawPath(p, paint);
        }
        canvas->translate(0, SH);
        for (int i = 0; i < N; i++) {
            SkPath p;
            rnd_cubic(&p, &paint, rand);
            canvas->drawPath(p, paint);
        }
    }

private:
    typedef skiagm::GM INHERITED;
};

DEF_GM( return new BeziersGM; )
<commit_msg>beziers: I missed an unsequenced moveTo() pair.<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"
#include "SkPath.h"
#include "SkRandom.h"

#define W   400
#define H   400
#define N   10

constexpr SkScalar SH = SkIntToScalar(H);

static void rnd_quad(SkPath* p, SkPaint* paint, SkRandom& rand) {
    auto a = rand.nextRangeScalar(0,W),
         b = rand.nextRangeScalar(0,H);
    p->moveTo(a,b);
    for (int x = 0; x < 2; ++x) {
        auto c = rand.nextRangeScalar(W/4, W),
             d = rand.nextRangeScalar(  0, H),
             e = rand.nextRangeScalar(  0, W),
             f = rand.nextRangeScalar(H/4, H);
        p->quadTo(c,d,e,f);
    }
    paint->setColor(rand.nextU());
    SkScalar width = rand.nextRangeScalar(1, 5);
    width *= width;
    paint->setStrokeWidth(width);
    paint->setAlpha(0xFF);
}

static void rnd_cubic(SkPath* p, SkPaint* paint, SkRandom& rand) {
    auto a = rand.nextRangeScalar(0,W),
         b = rand.nextRangeScalar(0,H);
    p->moveTo(a,b);
    for (int x = 0; x < 2; ++x) {
        auto c = rand.nextRangeScalar(W/4, W),
             d = rand.nextRangeScalar(  0, H),
             e = rand.nextRangeScalar(  0, W),
             f = rand.nextRangeScalar(H/4, H),
             g = rand.nextRangeScalar(W/4, W),
             h = rand.nextRangeScalar(H/4, H);
        p->cubicTo(c,d,e,f,g,h);
    }
    paint->setColor(rand.nextU());
    SkScalar width = rand.nextRangeScalar(1, 5);
    width *= width;
    paint->setStrokeWidth(width);
    paint->setAlpha(0xFF);
}

class BeziersGM : public skiagm::GM {
public:
    BeziersGM() {}

protected:

    SkString onShortName() override {
        return SkString("beziers");
    }

    SkISize onISize() override {
        return SkISize::Make(W, H*2);
    }

    void onDraw(SkCanvas* canvas) override {
        SkPaint paint;
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(SkIntToScalar(9)/2);
        paint.setAntiAlias(true);

        SkRandom rand;
        for (int i = 0; i < N; i++) {
            SkPath p;
            rnd_quad(&p, &paint, rand);
            canvas->drawPath(p, paint);
        }
        canvas->translate(0, SH);
        for (int i = 0; i < N; i++) {
            SkPath p;
            rnd_cubic(&p, &paint, rand);
            canvas->drawPath(p, paint);
        }
    }

private:
    typedef skiagm::GM INHERITED;
};

DEF_GM( return new BeziersGM; )
<|endoftext|>