Mercurial > malikania
changeset 7:45b3c770803c
Misc: switch to lower case (part 2)
line wrap: on
line diff
--- a/docs/doxygen/CMakeLists.txt Wed Mar 23 09:49:51 2016 +0100 +++ b/docs/doxygen/CMakeLists.txt Wed Mar 23 17:11:39 2016 +0100 @@ -25,7 +25,7 @@ set(DOXYGEN_HAVE_DOT YES) set(DOXYGEN_DOT_PATH \"${DOXYGEN_DOT_EXECUTABLE}\") else () - set(DOXYGEN_HAVE_DOT NOsc) + set(DOXYGEN_HAVE_DOT NO) set(DOXYGEN_DOT_PATH) endif ()
--- a/docs/doxygen/Doxyfile.in Wed Mar 23 09:49:51 2016 +0100 +++ b/docs/doxygen/Doxyfile.in Wed Mar 23 17:11:39 2016 +0100 @@ -163,7 +163,9 @@ # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = libclient/malikania \ + libcommon/malikania \ + libserver/malikania # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -172,7 +174,7 @@ # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = @CMAKE_SOURCE_DIR@/libclient # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -806,7 +808,8 @@ # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = libclient/malikania/backend \ + libcommon/malikania/backend # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded
--- a/libclient/CMakeLists.txt Wed Mar 23 09:49:51 2016 +0100 +++ b/libclient/CMakeLists.txt Wed Mar 23 17:11:39 2016 +0100 @@ -18,37 +18,37 @@ set( HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Animation.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Animator.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/ClientResourcesLoader.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Color.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Font.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Image.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Label.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Line.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Point.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Rectangle.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Size.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Sprite.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Window.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/FontBackend.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/ImageBackend.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/WindowBackend.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/animation.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/animator.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client-resources-loader.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/color.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/font.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/image.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/label.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/line.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/point.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/rectangle.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/size.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/sprite.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/window.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/font-backend.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/image-backend.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/window-backend.h ) set( SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Animator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/ClientResourcesLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Color.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Font.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Image.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Label.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Sprite.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Window.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/FontBackend.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/ImageBackend.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/WindowBackend.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/animator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client-resources-loader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/color.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/font.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/image.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/label.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/sprite.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/window.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/font-backend.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/image-backend.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/${WITH_BACKEND_DIRECTORY}/window-backend.cpp ) find_package(SDL2 REQUIRED)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/animation.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,154 @@ +/* + * animation.h -- animation description + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_ANIMATION_H +#define MALIKANIA_ANIMATION_H + +/** + * @file animation.h + * @brief Describe an animation. + */ + +#include <cassert> +#include <cstdint> +#include <memory> +#include <vector> + +#include "sprite.h" + +namespace malikania { + +class Window; + +/** + * @class AnimationFrame + * @brief Animation frame description. + * + * A frame is a duration before switching to the next sprite cell. It is currently implemented as a class for future + * usage. + */ +class AnimationFrame { +private: + std::uint16_t m_delay; + +public: + /** + * Construct a frame. + * + * @param delay the optional delay + */ + inline AnimationFrame(std::uint16_t delay = 100) noexcept + : m_delay(delay) + { + } + + /** + * Get the the delay. + * + * @return the delay + */ + inline std::uint16_t delay() const noexcept + { + return m_delay; + } +}; + +/** + * @brief List of frames. + */ +using AnimationFrames = std::vector<AnimationFrame>; + +/** + * @class Animation + * @brief Animation description. + * + * An animation is a sprite with a set of frames containing a delay for showing all sprites in a specific amount of + * time. + * + * Because an animation contains an image, a state (time, current cell) it must be constructed with an Animator object + * so the user is able to use the same animation on different parts of the screen without having to duplicate + * resources. + * + * @see Animator + */ +class Animation { +private: + Sprite m_sprite; + AnimationFrames m_frames; + +public: + /** + * Create an animation. + * + * @param sprite the sprite image + * @param frames the frames to show + */ + inline Animation(Sprite sprite, AnimationFrames frames) noexcept + : m_sprite(std::move(sprite)) + , m_frames(std::move(frames)) + { + } + + /** + * Get the underlying sprite. + * + * @return the sprite + */ + inline const Sprite &sprite() const noexcept + { + return m_sprite; + } + + /** + * Overloaded function. + * + * @return the sprite + */ + inline Sprite &sprite() noexcept + { + return m_sprite; + } + + /** + * Get the frames. + * + * @return the frames + */ + inline const AnimationFrames &frames() const noexcept + { + return m_frames; + } + + /** + * Access a frame. + * + * @pre index < number of frames + * @param index the index + * @return the frame + */ + inline const AnimationFrame &operator[](unsigned index) const noexcept + { + assert(index < m_frames.size()); + + return m_frames[index]; + } +}; + +} // !malikania + +#endif // !MALIKANIA_ANIMATION_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/animator.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,53 @@ +/* + * animator.cpp -- animation drawing object + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "animation.h" +#include "animator.h" + +namespace malikania { + +Animator::Animator(Animation &animation) noexcept + : m_animation(animation) +{ +} + +void Animator::update() noexcept +{ + unsigned total = m_animation.sprite().rows() * m_animation.sprite().columns(); + + if (m_current >= total) { + return; + } + + if (m_timer.elapsed() >= m_animation[m_current].delay()) { + m_current ++; + m_timer.reset(); + } +} + +void Animator::draw(Window &window, const Point &point) +{ + // TODO: assert ? + if (m_current >= m_animation.sprite().rows() * m_animation.sprite().columns()) { + return; + } + + m_animation.sprite().draw(window, m_current, point); +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/animator.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,74 @@ +/* + * animator.h -- animation drawing object + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_ANIMATOR_H +#define MALIKANIA_ANIMATOR_H + +/** + * @file animator.h + * @brief Draw animations. + */ + +#include <malikania/elapsed-timer.h> + +namespace malikania { + +class Animation; +class Position; +class Window; + +/** + * @class Animator + * @brief Object for drawing animations. + * + * The animator contains an animation and a state. + */ +class Animator { +private: + Animation &m_animation; + ElapsedTimer m_timer; + unsigned m_current{0}; + +public: + /** + * Construct an animator. + * + * @pre animation must not be null + * @param animation the animation + */ + Animator(Animation &animation) noexcept; + + /** + * Update the animator state. + * + * This function should be called in the main loop to update the cell to draw before calling draw(). + */ + void update() noexcept; + + /** + * Draw the animation. + * + * @param window the window + * @param position the position in the window + */ + void draw(Window &window, const Point &position); +}; + +} // !malikania + +#endif // !MALIKANIA_ANIMATOR_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/backend/sdl/font-backend.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,57 @@ +/* + * font-backend.cpp -- font object (SDL2 implementation) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <malikania/Size.h> +#include <malikania/Font.h> + +#include <malikania/backend/sdl/common-sdl.h> + +#include "font-backend.h" + +using namespace std::string_literals; + +namespace malikania { + +Font::Backend::Backend(std::string data, unsigned size) + : m_font(nullptr, nullptr) +{ + auto rw = sdl::RWFromBinary(std::move(data)); + + if (rw == nullptr) { + throw std::runtime_error(SDL_GetError()); + } + + m_font = Handle(TTF_OpenFontRW(rw, true, size), TTF_CloseFont); + + if (m_font == NULL) { + throw std::runtime_error(TTF_GetError()); + } +} + +Size Font::Backend::clip(const Font &, const std::string &text) const +{ + int width, height; + + if (TTF_SizeUTF8(m_font.get(), text.c_str(), &width, &height) != 0) { + throw std::runtime_error(SDL_GetError()); + } + + return Size((unsigned)width, (unsigned)height); +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/backend/sdl/font-backend.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,53 @@ +/* + * font-backend.h -- font object (SDL2 implementation) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_FONT_BACKEND_H +#define MALIKANIA_FONT_BACKEND_H + +#include <memory> + +#include <SDL.h> +#include <SDL_ttf.h> + +#include <malikania/font.h> + +namespace malikania { + +class Font; +class Size; + +class Font::Backend { +private: + using Handle = std::unique_ptr<TTF_Font, void (*)(TTF_Font*)>; + + Handle m_font; + +public: + Backend(std::string data, unsigned size); + + inline TTF_Font *font() noexcept + { + return m_font.get(); + } + + Size clip(const Font &self, const std::string &text) const; +}; + +} // !malikania + +#endif // !MALIKANIA_FONT_BACKEND_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/backend/sdl/image-backend.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,99 @@ +/* + * image-backend.cpp -- image object (SDL2 implementation) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <SDL_image.h> + +#include <malikania/backend/sdl/common-sdl.h> + +#include "image-backend.h" +#include "window-backend.h" + +using namespace std::string_literals; + +namespace malikania { + +Image::Backend::Backend(Image &, Window &window, std::string data) + : m_texture(nullptr, nullptr) +{ + /* Initialize the texture */ + auto rw = sdl::RWFromBinary(std::move(data)); + + if (rw == nullptr) { + throw std::runtime_error(SDL_GetError()); + } + + m_texture = Handle(IMG_LoadTexture_RW(window.backend().renderer(), rw, true), SDL_DestroyTexture); + + if (m_texture == nullptr) { + throw std::runtime_error(SDL_GetError()); + } + + /* Store the size */ + int width, height; + + if (SDL_QueryTexture(m_texture.get(), nullptr, nullptr, &width, &height) < 0) { + throw std::runtime_error(SDL_GetError()); + } + + m_size = Size((unsigned)width, (unsigned)height); +} + +void Image::Backend::draw(Window &window, const Point &point) +{ + SDL_Rect target; + + target.x = (int)point.x(); + target.y = (int)point.y(); + target.w = (int)m_size.width(); + target.h = (int)m_size.height(); + + if (SDL_RenderCopy(window.backend().renderer(), m_texture.get(), nullptr, &target) < 0) { + throw std::runtime_error(SDL_GetError()); + } +} + +void Image::Backend::draw(Window &window, const Rectangle &source, const Rectangle &target) +{ + SDL_Rect sr, st; + + sr.x = source.x(); + sr.y = source.y(); + sr.w = (int)source.width(); + sr.h = (int)source.height(); + + st.x = target.x(); + st.y = target.y(); + st.w = (int)target.width(); + st.h = (int)target.height(); + + /* Readjust .w, .h if null */ + if (source.isNull()) { + sr.w = (int)m_size.width(); + sr.h = (int)m_size.height(); + } + if (target.isNull()) { + st.w = (int)m_size.width(); + st.h = (int)m_size.height(); + } + + if (SDL_RenderCopy(window.backend().renderer(), m_texture.get(), &sr, &st) < 0) { + throw std::runtime_error(SDL_GetError()); + } +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/backend/sdl/image-backend.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,63 @@ +/* + * image-backend.h -- image object (SDL2 implementation) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_IMAGE_BACKEND_H +#define MALIKANIA_IMAGE_BACKEND_H + +#include <memory> + +#include <SDL.h> + +#include <malikania/size.h> +#include <malikania/image.h> + +namespace malikania { + +class Image; +class Point; +class Rectangle; +class Window; + +class Image::Backend { +private: + using Handle = std::unique_ptr<SDL_Texture, void (*)(SDL_Texture *)>; + + Handle m_texture; + Size m_size; + +public: + Backend(Image &self, Window &window, std::string data); + + inline SDL_Texture *texture() noexcept + { + return m_texture.get(); + } + + inline const Size &size() const noexcept + { + return m_size; + } + + void draw(Window &window, const Point &position); + + void draw(Window &window, const Rectangle &source, const Rectangle &target); +}; + +} // !malikania + +#endif // !MALIKANIA_IMAGE_BACKEND_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/backend/sdl/window-backend.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,244 @@ +/* + * window-backend.cpp -- window object (SDL2 implementation) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <SDL.h> +#include <SDL_ttf.h> + +#include <stdexcept> + +#include "font-backend.h" +#include "window-backend.h" + +namespace malikania { + +Window::Backend::Backend(Window &, unsigned width, unsigned height) + : m_window(nullptr, nullptr) + , m_renderer(nullptr, nullptr) +{ + SDL_SetMainReady(); + SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO); + + m_window = WindowHandle( + SDL_CreateWindow("Malikania", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_OPENGL), + SDL_DestroyWindow + ); + + if (m_window == nullptr) { + throw std::runtime_error(SDL_GetError()); + } + + // Create renderer + m_renderer = RendererHandle( + SDL_CreateRenderer(m_window.get(), -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC), + SDL_DestroyRenderer + ); + + if (m_renderer == nullptr) { + throw std::runtime_error(SDL_GetError()); + } + + if (TTF_Init() == -1) { + throw std::runtime_error(TTF_GetError()); + } +} + +void Window::Backend::processEvents(Window &window) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_KEYUP: + window.onKeyUp(event.key.keysym.sym); + break; + // TODO continue implemanting all event possible + case SDL_KEYDOWN: + window.onKeyDown(event.key.keysym.sym); + break; + case SDL_QUIT: + window.close(); + break; + default: + break; + } + } +} + +void Window::Backend::clear() +{ + SDL_RenderClear(m_renderer.get()); +} + +void Window::Backend::update() +{ + // TO AUDIT +#if 0 + for (Refresh function : m_refreshList) { + function(); + } +#endif +} + +void Window::Backend::present() +{ + SDL_RenderPresent(m_renderer.get()); +} + +Size Window::Backend::resolution() +{ + SDL_DisplayMode current; + int width = 0; + int height = 0; + for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) { + int error = SDL_GetCurrentDisplayMode(i, ¤t); + if (error == 0) { + // Get the last one + // TODO test with only one display mode, but we have to test with more than that + width = current.w; + height = current.h; + } else { + throw std::runtime_error("Could not get display mode for video display" + std::string(SDL_GetError())); + } + } + + return Size((unsigned)width, (unsigned)height); +} + +void Window::Backend::setDrawingColor(const Color &color) +{ + int error = SDL_SetRenderDrawColor(m_renderer.get(), color.red(), color.green(), color.blue(), color.alpha()); + if (error != 0) { + throw std::runtime_error("Couldn't set drawing color" + std::string(SDL_GetError())); + } +} + +void Window::Backend::drawLine(const Line &line) +{ + if (SDL_RenderDrawLine(m_renderer.get(), line.x1(), line.y1(), line.x2(), line.y2()) != 0) { + throw std::runtime_error(SDL_GetError()); + } +} + +void Window::Backend::drawLines(const std::vector<Point> &points) +{ + std::vector<SDL_Point> sdlPoints(points.size()); + + for (unsigned i = 0; i < points.size(); ++i) { + sdlPoints[i] = SDL_Point{points[i].x(), points[i].y()}; + } + + if (SDL_RenderDrawLines(m_renderer.get(), sdlPoints.data(), sdlPoints.size()) != 0) { + throw std::runtime_error(SDL_GetError()); + } +} + +void Window::Backend::drawPoint(const Point &point) +{ + if (SDL_RenderDrawPoint(m_renderer.get(), point.x(), point.y()) != 0) { + throw std::runtime_error(SDL_GetError()); + } +} + +void Window::Backend::drawPoints(const std::vector<Point> &points) +{ + std::vector<SDL_Point> sdlPoints(points.size()); + + for (unsigned i = 0; i < points.size(); ++i) { + sdlPoints[i] = SDL_Point{points[i].x(), points[i].y()}; + } + + if (SDL_RenderDrawPoints(m_renderer.get(), sdlPoints.data(), sdlPoints.size()) != 0) { + throw std::runtime_error(SDL_GetError()); + } +} + +// TODO: not sure to keep this signature (add fillRect probably) +void Window::Backend::drawRectangle(const Rectangle &rectangle, bool filled, const malikania::Color &fillColor) +{ + SDL_Rect rect{rectangle.x(), rectangle.y(), (int)rectangle.width(), (int)rectangle.height()}; + int error = SDL_RenderDrawRect(m_renderer.get(), &rect); + if (error != 0) { + throw std::runtime_error(SDL_GetError()); + } + if (filled) { + this->setDrawingColor(fillColor); + error = SDL_RenderFillRect(m_renderer.get(), &rect); + if (error != 0) { + throw std::runtime_error(SDL_GetError()); + } + } +} + +// TODO: same as above +void Window::Backend::drawRectangles(const std::vector<Rectangle> &rectangles, bool filled, std::vector<Color> fillColors) +{ + std::vector<SDL_Rect> sdlRects(rectangles.size()); + + for (unsigned i = 0; i < rectangles.size(); ++i) { + sdlRects[i] = SDL_Rect{rectangles[i].x(), rectangles[i].y(), (int)rectangles[i].width(), (int)rectangles[i].height()}; + } + + if (SDL_RenderDrawRects(m_renderer.get(), sdlRects.data(), sdlRects.size()) != 0) { + throw std::runtime_error(SDL_GetError()); + } + + if (filled) { + if (rectangles.size() != fillColors.size()) { + throw std::runtime_error("Couldn't fill rectangles, rectangles size and fillColors size are not the same"); + } + + int j = 0; + for (Color fillColor : fillColors) { + this->setDrawingColor(fillColor); + + if (SDL_RenderFillRect(m_renderer.get(), &sdlRects[j++]) != 0) { + throw std::runtime_error("Couldn't fill rectangle" + std::string(SDL_GetError())); + } + } + } +} + +// TODO: merge this into only one function and test results. +void Window::Backend::drawText(const std::string &text, Font &font, const Rectangle &rectangle) +{ + SDL_Color color = {0, 0, 0, 255}; + SDL_Surface* message = TTF_RenderUTF8_Blended(font.backend().font(), text.c_str(), color); + SDL_Texture* texture = SDL_CreateTextureFromSurface(m_renderer.get(), message); + SDL_Rect rect{rectangle.x(), rectangle.y(), (int)rectangle.width(), (int)rectangle.height()}; + + SDL_RenderCopy(m_renderer.get(), texture, nullptr, &rect); + SDL_FreeSurface(message); +} + +void Window::Backend::drawText(const std::string &text, Font &font, const Point &point) +{ + SDL_Color color = {0, 0, 0, 0}; + SDL_GetRenderDrawColor(m_renderer.get(), &color.r, &color.g, &color.b, &color.a); + SDL_Surface* message = TTF_RenderUTF8_Blended(font.backend().font(), text.c_str(), color); + SDL_Texture* textTexture = SDL_CreateTextureFromSurface(m_renderer.get(), message); + SDL_Rect rect{point.x(), point.y(), message->w, message->h}; + + SDL_RenderCopy(m_renderer.get(), textTexture, nullptr, &rect); + SDL_FreeSurface(message); +} + +void Window::Backend::close() +{ +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/backend/sdl/window-backend.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,76 @@ +/* + * window-backend.h -- window object (SDL2 implementation) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_WINDOW_BACKEND_H +#define MALIKANIA_WINDOW_BACKEND_H + +#include <memory> +#include <vector> + +#include <SDL.h> + +#include <malikania/color.h> +#include <malikania/font.h> +#include <malikania/line.h> +#include <malikania/point.h> +#include <malikania/rectangle.h> +#include <malikania/size.h> +#include <malikania/window.h> + +namespace malikania { + +class Window; + +class Window::Backend { +private: + using WindowHandle = std::unique_ptr<SDL_Window, void (*)(SDL_Window *)>; + using RendererHandle = std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer *)>; + + WindowHandle m_window; + RendererHandle m_renderer; + +public: + Backend(Window &self, unsigned width, unsigned height); + + void close(); + void processEvents(Window &window); + void clear(); + void update(); + void present(); + Size resolution(); + + // Drawing functions + void setDrawingColor(const Color &color); + void drawLine(const Line &line); + void drawLines(const std::vector<Point> &points); + void drawPoint(const Point &point); + void drawPoints(const std::vector<Point> &points); + void drawRectangle(const Rectangle &rectangle, bool filled, const Color &fillColor); + void drawRectangles(const std::vector<Rectangle> &rectangles, bool filled, std::vector<Color> fillColors); + void drawText(const std::string &text, Font &font, const Rectangle &rectangle); + void drawText(const std::string &text, Font &font, const Point &point); + + inline SDL_Renderer *renderer() noexcept + { + return m_renderer.get(); + } +}; + +} // !malikania + +#endif // !MALIKANIA_WINDOW_BACKEND_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/client-resources-loader.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,119 @@ +/* + * client-resources-loader.cpp -- load shared resources files for the client + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include "animation.h" +#include "client-resources-loader.h" +#include "size.h" +#include "sprite.h" + +namespace malikania { + +Size ClientResourcesLoader::requireSize(const std::string &id, const json::Value &object, const std::string &property) const +{ + assert(object.isObject()); + + auto it = object.find(property); + + if (it == object.end() || !it->isArray()) { + throw std::runtime_error(id + ": missing '" + property + "' property (array expected)"); + } + if (it->size() != 2) { + throw std::runtime_error(id + ": property '" + property + "' must have two values"); + } + if (!(*it)[0].isInt() || !(*it)[1].isInt()) { + throw std::runtime_error(id + ": property '" + property + "' must have to integer values"); + } + + return Size((*it)[0].toInt(), (*it)[1].toInt()); +} + +Size ClientResourcesLoader::getSize(const std::string &, const json::Value &object, const std::string &key) const noexcept +{ + assert(object.isObject()); + + auto it = object.find(key); + + if (it == object.end() || !it->isArray() || it->size() != 2 || !(*it)[0].isInt() || !(*it)[1].isInt()) { + return Size(); + } + + return Size((*it)[0].toInt(), (*it)[1].toInt()); +} + +Image ClientResourcesLoader::loadImage(const std::string &id) +{ + return Image(m_window, locator().read(id)); +} + +Sprite ClientResourcesLoader::loadSprite(const std::string &id) +{ + json::Value value = json::fromString(locator().read(id)); + + if (!value.isObject()) { + throw std::runtime_error(id + ": not a JSON object"); + } + + return Sprite( + loadImage(requireString(id, value, "image")), + requireSize(id, value, "cell"), + getSize(id, value, "size"), + getSize(id, value, "space"), + getSize(id, value, "margin") + ); +} + +Animation ClientResourcesLoader::loadAnimation(const std::string &id) +{ + json::Value value = json::fromString(locator().read(id)); + + if (!value.isObject()) { + throw std::runtime_error(id + ": not a JSON object"); + } + + Sprite sprite = loadSprite(requireString(id, value, "sprite")); + + /* Load all frames */ + json::Value property = value["frames"]; + + if (!property.isArray()) { + throw std::runtime_error(id + ": missing 'frames' property (array expected)"); + } + + AnimationFrames frames; + + for (auto it = property.begin(); it != property.end(); ++it) { + if (!it->isObject()) { + throw std::runtime_error(id + ": frame " + std::to_string(it.index()) + ": not a JSON object"); + } + + auto delay = it->find("delay"); + + if (delay == it->end() || !delay->isInt()) { + throw std::runtime_error(id + ": frame " + std::to_string(it.index()) + + ": missing 'delay' property (int expected)"); + } + + frames.emplace_back(delay->toInt()); + } + + return Animation(std::move(sprite), std::move(frames)); +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/client-resources-loader.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,112 @@ +/* + * client-resources-loader.h -- load shared resources files for the client + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_CLIENT_RESOURCES_LOADER_H +#define MALIKANIA_CLIENT_RESOURCES_LOADER_H + +#include <malikania/resources-loader.h> + +#include "animation.h" +#include "image.h" +#include "size.h" +#include "sprite.h" + +namespace malikania { + +class Window; + +/** + * @class ClientResourcesLoader + * @brief Load client resources. + */ +class ClientResourcesLoader : public ResourcesLoader { +private: + Window &m_window; + +protected: + /** + * Require a size object from an object property. + * + * The size is an array of two integers (e.g. [ 1, 2 ]). + * + * @pre object.isObject() + * @param id the resource id + * @param object the object + * @param property the property + * @return the size + * @throw std::runtime_error if the property is not a size + */ + Size requireSize(const std::string &id, const json::Value &object, const std::string &property) const; + + /** + * Get a size object or a default one if not present or invalid. + * + * @pre object.isObject() + * @param id the resource id + * @param object the object + * @param property the property + * @return the size or default one + */ + Size getSize(const std::string &id, const json::Value &object, const std::string &property) const noexcept; + +public: + /** + * Client resources loader constructor. + * + * The window is required because some of the resources require it. + * + * @param window the window + * @param locator the resources locator + */ + inline ClientResourcesLoader(Window &window, ResourcesLocator &locator) + : ResourcesLoader(locator) + , m_window(window) + { + } + + /** + * Load an image. + * + * @param id the resource id + * @return the image + * @throw std::runtime_error on errors + */ + virtual Image loadImage(const std::string &id); + + /** + * Load a sprite. + * + * @param id the resource id + * @return the sprite + * @throw std::runtime_error on errors + */ + virtual Sprite loadSprite(const std::string &id); + + /** + * Load an animation. + * + * @param id the resource id + * @return the animation + * @throw std::runtime_error on errors + */ + virtual Animation loadAnimation(const std::string &id); +}; + +} // !malikania + +#endif // !MALIKANIA_CLIENT_RESOURCES_LOADER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/color.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,236 @@ +/* + * color.cpp -- color description + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <unordered_map> +#include <cctype> + +#include "color.h" + +namespace malikania { + +namespace { + +constexpr unsigned rgb(std::uint8_t r, std::uint8_t g, std::uint8_t b) noexcept +{ + return (0xff000000 | (r << 16) | (g << 8) | b); +} + +/* + * Convert hexadecimal value to the correct number. + */ +std::uint8_t value(char digit) +{ + if (std::isdigit(digit)) { + return digit - '0'; + } + if ((digit = std::toupper(digit)) < 'A' || digit > 'F') { + throw std::invalid_argument("invalid hexadecimal value: " + std::to_string(digit)); + } + + return digit - 55; +} + +inline std::uint8_t value(char digit1, char digit2) +{ + return ((value(digit1) << 4) & 0xf0) | value(digit2); +} + +const std::unordered_map<std::string, std::uint32_t> colors{ + { "aliceblue", rgb(240, 248, 255) }, + { "antiquewhite", rgb(250, 235, 215) }, + { "aqua", rgb( 0, 255, 255) }, + { "aquamarine", rgb(127, 255, 212) }, + { "azure", rgb(240, 255, 255) }, + { "beige", rgb(245, 245, 220) }, + { "bisque", rgb(255, 228, 196) }, + { "black", rgb( 0, 0, 0) }, + { "blanchedalmond", rgb(255, 235, 205) }, + { "blue", rgb( 0, 0, 255) }, + { "blueviolet", rgb(138, 43, 226) }, + { "brown", rgb(165, 42, 42) }, + { "burlywood", rgb(222, 184, 135) }, + { "cadetblue", rgb( 95, 158, 160) }, + { "chartreuse", rgb(127, 255, 0) }, + { "chocolate", rgb(210, 105, 30) }, + { "coral", rgb(255, 127, 80) }, + { "cornflowerblue", rgb(100, 149, 237) }, + { "cornsilk", rgb(255, 248, 220) }, + { "crimson", rgb(220, 20, 60) }, + { "cyan", rgb( 0, 255, 255) }, + { "darkblue", rgb( 0, 0, 139) }, + { "darkcyan", rgb( 0, 139, 139) }, + { "darkgoldenrod", rgb(184, 134, 11) }, + { "darkgray", rgb(169, 169, 169) }, + { "darkgreen", rgb( 0, 100, 0) }, + { "darkgrey", rgb(169, 169, 169) }, + { "darkkhaki", rgb(189, 183, 107) }, + { "darkmagenta", rgb(139, 0, 139) }, + { "darkolivegreen", rgb( 85, 107, 47) }, + { "darkorange", rgb(255, 140, 0) }, + { "darkorchid", rgb(153, 50, 204) }, + { "darkred", rgb(139, 0, 0) }, + { "darksalmon", rgb(233, 150, 122) }, + { "darkseagreen", rgb(143, 188, 143) }, + { "darkslateblue", rgb( 72, 61, 139) }, + { "darkslategray", rgb( 47, 79, 79) }, + { "darkslategrey", rgb( 47, 79, 79) }, + { "darkturquoise", rgb( 0, 206, 209) }, + { "darkviolet", rgb(148, 0, 211) }, + { "deeppink", rgb(255, 20, 147) }, + { "deepskyblue", rgb( 0, 191, 255) }, + { "dimgray", rgb(105, 105, 105) }, + { "dimgrey", rgb(105, 105, 105) }, + { "dodgerblue", rgb( 30, 144, 255) }, + { "firebrick", rgb(178, 34, 34) }, + { "floralwhite", rgb(255, 250, 240) }, + { "forestgreen", rgb( 34, 139, 34) }, + { "fuchsia", rgb(255, 0, 255) }, + { "gainsboro", rgb(220, 220, 220) }, + { "ghostwhite", rgb(248, 248, 255) }, + { "gold", rgb(255, 215, 0) }, + { "goldenrod", rgb(218, 165, 32) }, + { "gray", rgb(128, 128, 128) }, + { "green", rgb( 0, 128, 0) }, + { "greenyellow", rgb(173, 255, 47) }, + { "grey", rgb(128, 128, 128) }, + { "honeydew", rgb(240, 255, 240) }, + { "hotpink", rgb(255, 105, 180) }, + { "indianred", rgb(205, 92, 92) }, + { "indigo", rgb( 75, 0, 130) }, + { "ivory", rgb(255, 255, 240) }, + { "khaki", rgb(240, 230, 140) }, + { "lavender", rgb(230, 230, 250) }, + { "lavenderblush", rgb(255, 240, 245) }, + { "lawngreen", rgb(124, 252, 0) }, + { "lemonchiffon", rgb(255, 250, 205) }, + { "lightblue", rgb(173, 216, 230) }, + { "lightcoral", rgb(240, 128, 128) }, + { "lightcyan", rgb(224, 255, 255) }, + { "lightgoldenrodyellow", rgb(250, 250, 210) }, + { "lightgray", rgb(211, 211, 211) }, + { "lightgreen", rgb(144, 238, 144) }, + { "lightgrey", rgb(211, 211, 211) }, + { "lightpink", rgb(255, 182, 193) }, + { "lightsalmon", rgb(255, 160, 122) }, + { "lightseagreen", rgb( 32, 178, 170) }, + { "lightskyblue", rgb(135, 206, 250) }, + { "lightslategray", rgb(119, 136, 153) }, + { "lightslategrey", rgb(119, 136, 153) }, + { "lightsteelblue", rgb(176, 196, 222) }, + { "lightyellow", rgb(255, 255, 224) }, + { "lime", rgb( 0, 255, 0) }, + { "limegreen", rgb( 50, 205, 50) }, + { "linen", rgb(250, 240, 230) }, + { "magenta", rgb(255, 0, 255) }, + { "maroon", rgb(128, 0, 0) }, + { "mediumaquamarine", rgb(102, 205, 170) }, + { "mediumblue", rgb( 0, 0, 205) }, + { "mediumorchid", rgb(186, 85, 211) }, + { "mediumpurple", rgb(147, 112, 219) }, + { "mediumseagreen", rgb( 60, 179, 113) }, + { "mediumslateblue", rgb(123, 104, 238) }, + { "mediumspringgreen", rgb( 0, 250, 154) }, + { "mediumturquoise", rgb( 72, 209, 204) }, + { "mediumvioletred", rgb(199, 21, 133) }, + { "midnightblue", rgb( 25, 25, 112) }, + { "mintcream", rgb(245, 255, 250) }, + { "mistyrose", rgb(255, 228, 225) }, + { "moccasin", rgb(255, 228, 181) }, + { "navajowhite", rgb(255, 222, 173) }, + { "navy", rgb( 0, 0, 128) }, + { "oldlace", rgb(253, 245, 230) }, + { "olive", rgb(128, 128, 0) }, + { "olivedrab", rgb(107, 142, 35) }, + { "orange", rgb(255, 165, 0) }, + { "orangered", rgb(255, 69, 0) }, + { "orchid", rgb(218, 112, 214) }, + { "palegoldenrod", rgb(238, 232, 170) }, + { "palegreen", rgb(152, 251, 152) }, + { "paleturquoise", rgb(175, 238, 238) }, + { "palevioletred", rgb(219, 112, 147) }, + { "papayawhip", rgb(255, 239, 213) }, + { "peachpuff", rgb(255, 218, 185) }, + { "peru", rgb(205, 133, 63) }, + { "pink", rgb(255, 192, 203) }, + { "plum", rgb(221, 160, 221) }, + { "powderblue", rgb(176, 224, 230) }, + { "purple", rgb(128, 0, 128) }, + { "red", rgb(255, 0, 0) }, + { "rosybrown", rgb(188, 143, 143) }, + { "royalblue", rgb( 65, 105, 225) }, + { "saddlebrown", rgb(139, 69, 19) }, + { "salmon", rgb(250, 128, 114) }, + { "sandybrown", rgb(244, 164, 96) }, + { "seagreen", rgb( 46, 139, 87) }, + { "seashell", rgb(255, 245, 238) }, + { "sienna", rgb(160, 82, 45) }, + { "silver", rgb(192, 192, 192) }, + { "skyblue", rgb(135, 206, 235) }, + { "slateblue", rgb(106, 90, 205) }, + { "slategray", rgb(112, 128, 144) }, + { "slategrey", rgb(112, 128, 144) }, + { "snow", rgb(255, 250, 250) }, + { "springgreen", rgb( 0, 255, 127) }, + { "steelblue", rgb( 70, 130, 180) }, + { "tan", rgb(210, 180, 140) }, + { "teal", rgb( 0, 128, 128) }, + { "thistle", rgb(216, 191, 216) }, + { "tomato", rgb(255, 99, 71) }, + { "transparent", 0 }, + { "turquoise", rgb( 64, 224, 208) }, + { "violet", rgb(238, 130, 238) }, + { "wheat", rgb(245, 222, 179) }, + { "white", rgb(255, 255, 255) }, + { "whitesmoke", rgb(245, 245, 245) }, + { "yellow", rgb(255, 255, 0) }, + { "yellowgreen", rgb(154, 205, 50) } +}; + +} // !namespace + +Color::Color(const std::string &name) +{ + if (!name.empty()) { + /* Parse #rrggbb or #rgb */ + if (name[0] == '#') { + if (name.length() == 7) { + m_red = value(name[1], name[2]); + m_green = value(name[3], name[4]); + m_blue = value(name[5], name[6]); + } else if (name.length() == 4) { + m_red = value(name[1], name[1]); + m_green = value(name[2], name[2]); + m_blue = value(name[3], name[3]); + } else { + throw std::invalid_argument{"invalid format"}; + } + } else { + /* Name lookup */ + auto it = colors.find(name); + + if (it == colors.end()) { + throw std::invalid_argument{name + " is not a valid color"}; + } + + /* Assign the color to *this */ + *this = it->second; + } + } +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/color.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,126 @@ +/* + * color.h -- color description + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_COLOR_H +#define MALIKANIA_COLOR_H + +#include <cstdint> +#include <string> + +namespace malikania { + +/** + * @class Color + * @brief Color description + */ +class Color { +private: + std::uint8_t m_red{0}; + std::uint8_t m_green{0}; + std::uint8_t m_blue{0}; + std::uint8_t m_alpha{255}; + +public: + /** + * Default color to black. + */ + inline Color() noexcept = default; + + /** + * Constructor with all fields. + * + * @param red the red value + * @param green the green value + * @param blue the blue value + * @param alpha the alpha value + */ + inline Color(std::uint8_t red, std::uint8_t green, std::uint8_t blue, std::uint8_t alpha) noexcept + : m_red(red) + , m_green(green) + , m_blue(blue) + , m_alpha(alpha) + { + } + + /** + * Constructor with an hexadecimal value. + * + * @param hex the color + */ + inline Color(std::uint32_t hex) noexcept + : m_red((hex >> 16) & 0xff) + , m_green((hex >> 8) & 0xff) + , m_blue(hex & 0xff) + , m_alpha((hex >> 24) & 0xff) + { + } + + /** + * Construct a color from #rrggbb or name. + * + * See the SVG this [list](http://www.december.com/html/spec/colorsvg.html) for supported names. + * + * @param name the color name + * @throw std::invalid_argument if the color does not exist or is invalid + */ + Color(const std::string &name); + + /** + * Get the red value. + * + * @return the value + */ + inline std::uint8_t red() const noexcept + { + return m_red; + } + + /** + * Get the green value. + * + * @return the value + */ + inline std::uint8_t green() const noexcept + { + return m_green; + } + + /** + * Get the blue value. + * + * @return the value + */ + inline std::uint8_t blue() const noexcept + { + return m_blue; + } + + /** + * Get the alpha value. + * + * @return the value + */ + inline std::uint8_t alpha() const noexcept + { + return m_alpha; + } +}; + +} // !malikania + +#endif // !MALIKANIA_COLOR_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/font.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,40 @@ +/* + * font.cpp -- font object + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "font-backend.h" + +namespace malikania { + +Font::Font(std::string data, unsigned size) + : m_backend(std::make_unique<Backend>(std::move(data), size)) + , m_size(size) +{ +} + +Font::Font(Font &&other) noexcept = default; + +Font::~Font() noexcept = default; + +Size Font::clip(const std::string &text) const +{ + return m_backend->clip(*this, text); +} + +Font &Font::operator=(Font &&other) noexcept = default; + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/font.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,115 @@ +/* + * font.h -- font object + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_FONT_H +#define MALIKANIA_FONT_H + +/** + * @file Font.h + * @brief Fonts. + */ + +#include <memory> +#include <string> + +#include "size.h" + +namespace malikania { + +/** + * @class Font + * @brief Font object. + */ +class Font { +private: + class Backend; + + std::unique_ptr<Backend> m_backend; + unsigned m_size; + +public: + /** + * Construct a font from binary data. + * + * @param data the raw data + * @param size the size + */ + Font(std::string data, unsigned size); + + /** + * Default move constructor. + * + * @param other the other font + */ + Font(Font &&other) noexcept; + + /** + * Default destructor. + */ + virtual ~Font() noexcept; + + /** + * Get the font size. + * + * @return the font size + */ + inline unsigned size() const noexcept + { + return m_size; + } + + /** + * Get the underlying backend. + * + * @return the backend + */ + inline const Backend &backend() const noexcept + { + return *m_backend; + } + + /** + * Overloaded function. + * + * @return the backend + */ + inline Backend &backend() noexcept + { + return *m_backend; + } + + /** + * Get the clipping size required to draw the given text. + * + * @param text the text to clip + * @return the required size + */ + Size clip(const std::string &text) const; + + /** + * Default move assignment operator. + * + * @param other the other font + * @return this + */ + Font &operator=(Font &&other) noexcept; +}; + +} // !malikania + +#endif // MALIKANIA_FONT_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/image.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,49 @@ +/* + * image.cpp -- image object + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "image-backend.h" + +namespace malikania { + +Image::Image(Window &window, std::string data) + : m_backend(std::make_unique<Backend>(*this, window, std::move(data))) +{ +} + +Image::Image(Image &&) noexcept = default; + +Image::~Image() noexcept = default; + +const Size &Image::size() const noexcept +{ + return m_backend->size(); +} + +void Image::draw(Window &window, const Point &position) +{ + m_backend->draw(window, position); +} + +void Image::draw(Window &window, const Rectangle &source, const Rectangle &target) +{ + m_backend->draw(window, source, target); +} + +Image &Image::operator=(Image &&) noexcept = default; + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/image.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,124 @@ +/* + * image.h -- image object + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_IMAGE_H +#define MALIKANIA_IMAGE_H + +/** + * @file image.h + * @brief Images. + */ + +#include <memory> +#include <string> + +#include "point.h" +#include "rectangle.h" +#include "size.h" + +namespace malikania { + +class Window; + +/** + * @class Image + * @brief Image object. + */ +class Image { +private: + class Backend; + + std::unique_ptr<Backend> m_backend; + +public: + /** + * Construct an image from the binary data. + * + * @param window the window + * @param data the data + */ + Image(Window &window, std::string data); + + /** + * Default move constructor. + * + * @param other the other image + */ + Image(Image &&other) noexcept; + + /** + * Default destructor. + */ + ~Image() noexcept; + + /** + * Overloaded function. + * + * @return the backend + */ + inline Backend &backend() noexcept + { + return *m_backend; + } + + /** + * Get the underlying backend. + * + * @return the backend + */ + inline const Backend &backend() const noexcept + { + return *m_backend; + } + + /** + * Get the image size. + * + * @return the size + */ + const Size &size() const noexcept; + + /** + * Draw the image to the window. + * + * @param window the window + * @param position the position + */ + void draw(Window &window, const Point &position = {0, 0}); + + /** + * Overloaded function. + * + * @param window the window + * @param source the source to clip + * @param target the target destination + */ + void draw(Window &window, const Rectangle &source, const Rectangle &target); + + /** + * Default move assignment operator. + * + * @param other the other image + * @return this + */ + Image &operator=(Image &&image) noexcept; +}; + +} // !malikania + +#endif // !MALIKANIA_IMAGE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/label.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,42 @@ +/* + * label.cpp -- GUI label + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "label.h" + +namespace malikania { + +Label::Label(std::string text, std::shared_ptr<Font> font, Rectangle frame, Color textColor, Color backgroundColor) + : m_text(std::move(text)) + , m_font(std::move(font)) + , m_frame(std::move(frame)) + , m_textColor(std::move(textColor)) + , m_backgroundColor(std::move(backgroundColor)) +{ +} + +int Label::fontSize() const noexcept +{ + // TODO + return 12; +} + +void Label::draw(Window &, const Rectangle &) +{ +} + +}// !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/label.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,69 @@ +/* + * label.h -- GUI label + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_LABEL_H +#define MALIKANIA_LABEL_H + +#include "color.h" +#include "font.h" +#include "image.h" +#include "rectangle.h" + +namespace malikania { + +class Window; + +class Label { +private: + std::string m_text; + std::shared_ptr<Font> m_font; + Rectangle m_frame; + Color m_textColor; + Color m_backgroundColor; + +public: + Label(std::string text, std::shared_ptr<Font> font, Rectangle frame, Color textColor = {0, 0, 0, 255}, Color backgroundColor = {255, 255, 255, 0}); + + inline const std::string text() const noexcept + { + return m_text; + } + + inline std::string text() noexcept + { + return m_text; + } + + inline const std::shared_ptr<Font> &font() const noexcept + { + return m_font; + } + + inline std::shared_ptr<Font> &font() noexcept + { + return m_font; + } + + int fontSize() const noexcept; + + void draw(Window &window, const Rectangle &rectangle); +}; + +}// !malikania + +#endif // !MALIKANIA_LABEL_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/line.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,126 @@ +/* + * line.h -- line description + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_LINE_H +#define MALIKANIA_LINE_H + +/** + * @file line.h + * @brief Line description. + */ + +namespace malikania { + +/** + * @class Line + * @brief Line description. + * + * A line has an origin (x, y) and a destination (x, y). + */ +class Line { +private: + int m_x1; + int m_y1; + int m_x2; + int m_y2; + +public: + /** + * Construct a line. + * + * @param x1 the first x + * @param y1 the first y + * @param x2 the second x + * @param y2 the second y + */ + inline Line(int x1 = 0, int y1 = 0, int x2 = 0, int y2 = 0) noexcept + : m_x1(x1) + , m_y1(y1) + , m_x2(x2) + , m_y2(y2) + { + } + + /** + * Get the first x. + * + * @return the x1 + */ + inline int x1() const noexcept + { + return m_x1; + } + + /** + * Get the first y. + * + * @return the y1 + */ + inline int y1() const noexcept + { + return m_y1; + } + + /** + * Get the second x. + * + * @return the x2 + */ + inline int x2() const noexcept + { + return m_x2; + } + + /** + * Get the second y. + * + * @return the y2 + */ + inline int y2() const noexcept + { + return m_y2; + } +}; + +/** + * Compare equality. + * + * @param l1 the first line + * @param l2 the second line + * @return true if they equal + */ +inline bool operator==(const Line &l1, const Line &l2) noexcept +{ + return l1.x1() == l2.x1() && l1.x2() == l2.x2() && l1.y1() == l2.y1() && l1.y2() == l2.y2(); +} + +/** + * Compare equality. + * + * @param l1 the first line + * @param l2 the second line + * @return false if they equal + */ +inline bool operator!=(const Line &l1, const Line &l2) noexcept +{ + return !(l1 == l2); +} + +} // !malikania + +#endif // !MALIKANIA_LINE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/point.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,98 @@ +/* + * point.h -- point description + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_POINT_H +#define MALIKANIA_POINT_H + +/** + * @file point.h + * @brief Point description. + */ + +namespace malikania { + +/** + * @class Point + * @brief Point coordinate. + */ +class Point { +private: + int m_x; + int m_y; + +public: + /** + * Construct a point. + * + * @param x the x + * @param y the y + */ + inline Point(int x = 0, int y = 0) noexcept + : m_x(x) + , m_y(y) + { + } + + /** + * Get the x position. + * + * @return the x + */ + inline int x() const noexcept + { + return m_x; + } + + /** + * Get the y position. + * + * @return the y + */ + inline int y() const noexcept + { + return m_y; + } +}; + +/** + * Compare equality. + * + * @param p1 the first point + * @param p2 the second point + * @return true if they equal + */ +inline bool operator==(const Point &p1, const Point &p2) noexcept +{ + return p1.x() == p2.x() && p1.y() == p2.y(); +} + +/** + * Compare equality. + * + * @param p1 the first point + * @param p2 the second point + * @return false if they equal + */ +inline bool operator!=(const Point &p1, const Point &p2) noexcept +{ + return !(p1 == p2); +} + +} // !malikania + +#endif // !MALIKANIA_POINT_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/rectangle.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,138 @@ +/* + * rectangle.h -- rectangle description + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_RECTANGLE_H +#define MALIKANIA_RECTANGLE_H + +/** + * @file rectangle.h + * @brief Rectangle description. + */ + +namespace malikania { + +/** + * @class Rectangle + * @brief Rectangle description. + * + * A rectangle has coordinates (x, y) and dimensions (width, height). + * + * They are commonly used for clipping images into the window. + */ +class Rectangle { +private: + int m_x; + int m_y; + unsigned m_width; + unsigned m_height; + +public: + /** + * Construct a rectangle. + * + * @param x the x position + * @param y the y position + * @param width the width + * @param height the height + */ + inline Rectangle(int x = 0, int y = 0, unsigned width = 0, unsigned height = 0) noexcept + : m_x(x) + , m_y(y) + , m_width(width) + , m_height(height) + { + } + + /** + * Get the x position. + * + * @return the x position + */ + inline int x() const noexcept + { + return m_x; + } + + /** + * Get the y position. + * + * @return the y position + */ + inline int y() const noexcept + { + return m_y; + } + + /** + * Get the rectangle width. + * + * @return the width + */ + inline unsigned width() const noexcept + { + return m_width; + } + + /** + * Get the rectangle height. + * + * @return the height + */ + inline unsigned height() const noexcept + { + return m_height; + } + + /** + * Check if the rectangle has null dimensions. + * + * @return true if weight and height are 0 + */ + inline bool isNull() const noexcept + { + return m_width == 0 && m_height == 0; + } +}; + +/** + * Compare equality. + * + * @param r1 the first rectangle + * @param r2 the second rectangle + * @return true if they equal + */ +inline bool operator==(const Rectangle &r1, const Rectangle &r2) noexcept +{ + return r1.x() == r2.x() && r1.y() == r2.y() && r1.width() == r2.width() && r1.height() == r2.height(); +} + +/** + * Compare equality. + * + * @param r1 the first rectangle + * @param r2 the second rectangle + * @return false if they equal + */ +inline bool operator!=(const Rectangle &r1, const Rectangle &r2) noexcept +{ + return !(r1 == r2); +} + +} // !malikania + +#endif // !MALIKANIA_RECTANGLE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/size.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,103 @@ +/* + * size.h -- size description + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_SIZE_H +#define MALIKANIA_SIZE_H + +namespace malikania { + +/** + * @class Size + * @brief Size description. + */ +class Size { +private: + unsigned m_width; + unsigned m_height; + +public: + /** + * Constructor. + * + * @param width the size width + * @param height the size height + */ + inline Size(unsigned width = 0, unsigned height = 0) noexcept + : m_width(width) + , m_height(height) + { + } + + /** + * Get the width. + * + * @return the width + */ + inline unsigned width() const noexcept + { + return m_width; + } + + /** + * Get the height. + * + * @return the height + */ + inline unsigned height() const noexcept + { + return m_height; + } + + /** + * Check if the size is 0, 0. + * + * @return true if height and width are 0 + */ + inline bool isNull() const noexcept + { + return m_height == 0 && m_width == 0; + } +}; + +/** + * Compare equality. + * + * @param s1 the first size + * @param s2 the second size + * @return true if they equal + */ +inline bool operator==(const Size &s1, const Size &s2) noexcept +{ + return s1.width() == s2.width() && s1.height() == s2.height(); +} + +/** + * Compare equality. + * + * @param s1 the first size + * @param s2 the second size + * @return false if they equal + */ +inline bool operator!=(const Size &s1, const Size &s2) noexcept +{ + return !(s1 == s2); +} + +} // !malikania + +#endif // !MALIKANIA_SIZE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/sprite.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,61 @@ +/* + * sprite.cpp -- image sprite + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "sprite.h" + +namespace malikania { + +Sprite::Sprite(Image image, Size cell, Size size, Size space, Size margin) noexcept + : m_image(std::move(image)) + , m_cell(std::move(cell)) + , m_margin(std::move(margin)) + , m_space(std::move(space)) + , m_size(std::move(size)) +{ + assert(m_cell.width() > 0); + assert(m_cell.height() > 0); + + /* If size is not specified, take from image */ + if (m_size.isNull()) { + m_size = m_image.size(); + } + + /* Compute number of cells */ + m_rows = (m_size.height() - (margin.height() * 2) + m_space.height()) / (m_cell.height() + m_space.height()); + m_columns = (m_size.width() - (m_margin.width() * 2) + m_space.width()) / (m_cell.width() + m_space.width()); +} + +void Sprite::draw(Window &window, unsigned cell, const Point &point) +{ + assert(cell < m_rows * m_columns); + + /* Compute index in the grid */ + unsigned hindex = (cell % m_columns); + unsigned vindex = (cell / m_columns); + + /* Compute the pixel boundaries */ + int x = m_margin.width() + (hindex * m_space.width()) + (hindex * m_cell.width()); + int y = m_margin.height() + (vindex * m_space.height()) + (vindex * m_cell.height()); + + Rectangle source(x, y, m_cell.width(), m_cell.height()); + Rectangle target(point.x(), point.y(), m_cell.width(), m_cell.height()); + + m_image.draw(window, source, target); +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/sprite.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,146 @@ +/* + * sprite.h -- image sprite + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_SPRITE_H +#define MALIKANIA_SPRITE_H + +/** + * @file sprite.h + * @brief Sprite description. + */ + +#include <malikania/json.h> + +#include "image.h" + +namespace malikania { + +class Point; +class Window; + +/** + * @class Sprite + * @brief A Sprite is an image divided into cells. + */ +class Sprite { +private: + Image m_image; + Size m_cell; + Size m_margin; + Size m_space; + Size m_size; + unsigned m_rows; + unsigned m_columns; + +public: + /** + * Construct a sprite. + * + * @pre cell must not have height or width null + * @param image the image to use + * @param cell size of cell in the image + * @param margin the optional space from borders + * @param space the optional space between cells + * @param size the sprite size (if 0, taken from the image) + */ + Sprite(Image image, Size cell, Size margin = { 0, 0 }, Size space = { 0, 0 }, Size size = { 0, 0 }) noexcept; + + /** + * Get the underlying image. + * + * @return the image + */ + inline const Image &image() const noexcept + { + return m_image; + } + + /** + * Overloaded function. + * + * @return the image + */ + inline Image &image() noexcept + { + return m_image; + } + + /** + * Get the cell size. + * + * @return the cell size + */ + inline const Size &cell() const noexcept + { + return m_cell; + } + + /** + * Get the margin size. + * + * @return the margin size + */ + inline const Size &margin() noexcept + { + return m_margin; + } + + /** + * Get the space size. + * + * @return the space size + */ + inline const Size &space() const noexcept + { + return m_space; + } + + /** + * Get the number of rows in the grid. + * + * @return the number of rows + */ + inline unsigned rows() const noexcept + { + return m_rows; + } + + /** + * Get the number of columns in the grid. + * + * @return the number of columns + */ + inline unsigned columns() const noexcept + { + return m_columns; + } + + /** + * Draw the sprite into the window at the specified position. + * + * @pre cell < rows() * columns() + * @param window the window + * @param cell the cell index + * @param position the position in the window + */ + void draw(Window &window, unsigned cell, const Point &position); +}; + +} // !malikania + +#endif // !MALIKANIA_SPRITE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/window.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,115 @@ +#include <stdexcept> + +#include "window-backend.h" + +namespace malikania { + +Window::Window(unsigned width, unsigned height) + : m_backend(std::make_unique<Backend>(*this, width, height)) +{ +} + +Window::Window(Window &&) noexcept = default; + +Window::~Window() noexcept = default; + +Size Window::getWindowResolution() +{ + return m_backend->resolution(); +} + +void Window::processEvent() +{ + m_backend->processEvents(*this); +} + +void Window::clear() +{ + m_backend->clear(); +} + +void Window::update() +{ + m_backend->update(); +} + +void Window::present() +{ + m_backend->present(); +} + +void Window::close() noexcept +{ + m_isOpen = false; + m_backend->close(); +} + +void Window::setOnKeyUp(KeyUp function) +{ + m_keyUpList.push_back(std::move(function)); +} + +void Window::setOnKeyDown(KeyDown function) +{ + m_keyDownList.push_back(std::move(function)); +} + +void Window::setOnMouseMove(MouseMove function) +{ + m_mouseMoveList.push_back(std::move(function)); +} + +void Window::setOnRefresh(Refresh function) +{ + m_refreshList.push_back(std::move(function)); +} + +void Window::setDrawingColor(Color color) +{ + m_drawingColor = std::move(color); + m_backend->setDrawingColor(color); +} + +void Window::drawLine(const Line &line) +{ + m_backend->drawLine(line); +} + +void Window::drawLines(const std::vector<Point> &points) +{ + m_backend->drawLines(points); +} + +void Window::drawPoint(const Point &point) +{ + m_backend->drawPoint(point); +} + +void Window::drawPoints(const std::vector<Point> &points) +{ + m_backend->drawPoints(points); +} + +void Window::drawRectangle(const Rectangle &rectangle, bool filled, Color fillColor) +{ + m_backend->drawRectangle(rectangle, filled, fillColor); +} + +void Window::drawRectangles(const std::vector<Rectangle> &rectangles, bool filled, std::vector<Color> fillColors) +{ + m_backend->drawRectangles(rectangles, filled, fillColors); +} + +void Window::drawText(const std::string &text, Font &font, const Rectangle &rectangle) +{ + m_backend->drawText(text, font, rectangle); +} + +void Window::drawText(const std::string &text, Font &font, const Point &point) +{ + m_backend->drawText(text, font, point); +} + +Window &Window::operator=(Window &&) noexcept = default; + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/window.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,133 @@ +#ifndef MALIKANIA_WINDOW_H +#define MALIKANIA_WINDOW_H + +#include <functional> +#include <vector> +#include <string> +#include <map> +#include <memory> + +#include "line.h" +#include "color.h" +#include "font.h" +#include "point.h" +#include "rectangle.h" +#include "size.h" + +namespace malikania { + +class Window { +public: + using KeyUp = std::function<void (int)>; + using KeyDown = std::function<void (int)>; + using MouseMove = std::function<void (int, int)>; + using Refresh = std::function<void (void)>; + using KeyUpList = std::vector<KeyUp>; + using KeyDownList = std::vector<KeyDown>; + using MouseMoveList = std::vector<MouseMove>; + using RefreshList = std::vector<Refresh>; + +private: + class Backend; + + std::unique_ptr<Backend> m_backend; + + bool m_isOpen{true}; + KeyUpList m_keyUpList; + KeyDownList m_keyDownList; + MouseMoveList m_mouseMoveList; + RefreshList m_refreshList; + Color m_drawingColor; + + template <typename FuncList, typename... Args> + inline void notify(FuncList list, Args&&... args) + { + for (auto &f : list) { + f(std::forward<Args>(args)...); + } + } + +public: + Window(unsigned width = 640, unsigned height = 480); + + Window(Window &&) noexcept; + + virtual ~Window() noexcept; + + inline const Backend &backend() const noexcept + { + return *m_backend; + } + + inline Backend &backend() noexcept + { + return *m_backend; + } + + Size getWindowResolution(); + + void processEvent(); + + void clear(); + + void update(); + + void present(); + + inline bool isOpen() noexcept + { + return m_isOpen; + } + + void close() noexcept; + + void setOnKeyUp(KeyUp function); + void setOnKeyDown(KeyDown function); + void setOnMouseMove(MouseMove function); + void setOnRefresh(Refresh function); + + inline void onKeyUp(int key) + { + notify(m_keyUpList, key); + } + + inline void onKeyDown(int key) + { + notify(m_keyDownList, key); + } + + inline void onMouseMove(int x, int y) + { + notify(m_mouseMoveList, x, y); + } + + inline Color drawingColor() + { + return m_drawingColor; + } + + void setDrawingColor(Color color); + + void drawLine(const Line &line); + + void drawLines(const std::vector<Point> &points); + + void drawPoint(const Point &point); + + void drawPoints(const std::vector<Point> &points); + + void drawRectangle(const Rectangle &rectangle, bool filled = false, Color fillColor = {255, 255, 255, 255}); + + void drawRectangles(const std::vector<Rectangle> &rectangles, bool filled = false + , std::vector<Color> fillColors = {{255, 255, 255, 255}}); + + void drawText(const std::string &text, Font &font, const Rectangle &rectangle); + + void drawText(const std::string &text, Font &font, const Point &point); + + Window &operator=(Window &&other) noexcept; +}; + +}// !malikania + +#endif // !_MALIKANIA_WINDOW_H_
--- a/libcommon/CMakeLists.txt Wed Mar 23 09:49:51 2016 +0100 +++ b/libcommon/CMakeLists.txt Wed Mar 23 17:11:39 2016 +0100 @@ -18,34 +18,32 @@ set( HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Application.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Game.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/ElapsedTimer.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Game.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Id.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Js.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Json.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/ResourcesLoader.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/ResourcesLocator.h - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Util.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/application.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/game.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/elapsed-timer.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/game.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/id.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/json.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/resources-loader.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/resources-locator.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/util.h ) set( SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Application.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/ElapsedTimer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Js.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Json.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/ResourcesLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/ResourcesLocator.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/Util.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/application.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/elapsed-timer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/json.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/resources-loader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/resources-locator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/util.cpp ) if (WITH_BACKEND_SDL) find_package(SDL2 REQUIRED) - list(APPEND HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/malikania/backend/sdl/CommonSdl.h) - list(APPEND SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/malikania/backend/sdl/CommonSdl.cpp) + list(APPEND HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/malikania/backend/sdl/common-sdl.h) + list(APPEND SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/malikania/backend/sdl/common-sdl.cpp) list(APPEND INCLUDES ${SDL2_INCLUDE_DIRS}) list(APPEND LIBRARIES ${SDL2_LIBRARIES}) endif () @@ -59,18 +57,8 @@ TARGET libcommon SOURCES ${HEADERS} ${SOURCES} FLAGS "MALIKANIA_COMMON_BUILD" - PUBLIC_INCLUDES - ${CMAKE_CURRENT_SOURCE_DIR} - ${Jansson_INCLUDE_DIRS} - ${ZIP_INCLUDE_DIRS} - ${OPENSSL_INCLUDE_DIR} - ${INCLUDES} - LIBRARIES - extern-jansson - ${LIBRARIES} - ${Jansson_LIBRARIES} - ${ZIP_LIBRARIES} - ${OPENSSL_LIBRARIES} + PUBLIC_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} ${INCLUDES} + LIBRARIES extern-jansson ${LIBRARIES} ) set_target_properties(libcommon PROPERTIES PREFIX "")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/application.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,28 @@ +/* + * application.cpp -- main application class + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "application.h" + +namespace malikania { + +Application::Application(int, char **) +{ + // TODO: find the executable path +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/application.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,51 @@ +/* + * application.h -- main application class + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_APPLICATION_H +#define MALIKANIA_APPLICATION_H + +/** + * @file application.h + * @brief Main class for the client or server + */ + +namespace malikania { + +/** + * @class Application + * @brief Main class for argument parsing and executable path retrievement + */ +class Application { +public: + /** + * Construct the application. + * + * @param argc the argument count + * @param argv the arguments + */ + Application(int argc, char **argv); + + /** + * Virtual destructor defaulted. + */ + virtual ~Application() = default; +}; + +} // !malikania + +#endif // !MALIKANIA_APPLICATION_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/backend/sdl/common-sdl.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,153 @@ +/* + * CommonSdl.cpp -- common SDL2 related code + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cerrno> +#include <cstdint> +#include <cstring> +#include <new> + +#include "common-sdl.h" + +namespace malikania { + +namespace sdl { + +namespace { + +/* + * RWFromBinary implementation + * ------------------------------------------------------------------ + * + * A little bit inspired by official SDL_RWFromMem implementation, largely modified to match our conventions and the + * C++ code. + */ + +class Buffer { +public: + std::string m_data; + std::uint64_t m_position; + std::uint64_t m_length; + + inline Buffer(std::string data) noexcept + : m_data(std::move(data)) + , m_position(0U) + , m_length(m_data.length()) + { + } +}; + +Sint64 size(SDL_RWops *ops) +{ + return reinterpret_cast<Buffer *>(ops->hidden.unknown.data1)->m_length; +} + +Sint64 seek(SDL_RWops *ops, Sint64 offset, int whence) +{ + Buffer *data = reinterpret_cast<Buffer *>(ops->hidden.unknown.data1); + Sint64 position = data->m_position; + + switch (whence) { + case RW_SEEK_SET: + position = offset; + break; + case RW_SEEK_CUR: + position = data->m_position + offset; + break; + case RW_SEEK_END: + position = data->m_length + offset; + break; + default: + break; + } + + if (position < 0) + position = 0; + else if ((std::uint64_t)position > data->m_length) + position = data->m_length; + + return (data->m_position = position); +} + +size_t read(SDL_RWops *ops, void *dst, size_t size, size_t number) +{ + Buffer *data = reinterpret_cast<Buffer *>(ops->hidden.unknown.data1); + size_t total = number * size; + size_t avail = data->m_length - data->m_position; + + if (number <= 0 || size <= 0 || ((total / number) != (size_t)size)) { + return 0; + } + if (total > avail) { + total = avail; + } + + SDL_memcpy(dst, &data->m_data[data->m_position], total); + + data->m_position += total; + + return (total / size); +} + +size_t write(SDL_RWops *, const void *, size_t, size_t) +{ + SDL_SetError("write not supported"); + + return -1; +} + +int close(SDL_RWops *ops) +{ + if (ops != nullptr) { + delete reinterpret_cast<Buffer *>(ops->hidden.unknown.data1); + SDL_FreeRW(ops); + } + + return 0; +} + +} // !namespace + +SDL_RWops *RWFromBinary(std::string data) noexcept +{ + SDL_RWops *ops = SDL_AllocRW(); + + if (ops == nullptr) { + return nullptr; + } + + ops->hidden.unknown.data1 = new (std::nothrow) Buffer(std::move(data)); + + if (ops->hidden.unknown.data1 == nullptr) { + SDL_SetError("%s", std::strerror(errno)); + SDL_FreeRW(ops); + return nullptr; + } + + ops->type = SDL_RWOPS_UNKNOWN; + ops->seek = seek; + ops->size = size; + ops->read = read; + ops->write = write; + ops->close = close; + + return ops; +} + +} // !sdl + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/backend/sdl/common-sdl.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,49 @@ +/* + * CommonSdl.h -- common SDL2 related code + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_COMMON_SDL_H +#define MALIKANIA_COMMON_SDL_H + +#include <SDL.h> + +#include <string> + +namespace malikania { + +namespace sdl { + +/** + * Create a SDL_RWops that owns the binary data. + * + * This is a safe alternative to SDL_RWFromMem because it owns the memory pointed by data until it is closed. The + * data is moved so there are no copies. + * + * The stream has read-only support and can not write. + * + * Seeking past-the-end or past-the-begin readjust the position to the end or begin respectively. + * + * @param data the data + * @return the object or nullptr on errors + */ +SDL_RWops *RWFromBinary(std::string data) noexcept; + +} // !sdl + +} // !malikania + +#endif // !MALIKANIA_COMMON_SDL_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/common-config.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,14 @@ +#ifndef COMMON_CONFIG_H +#define COMMON_CONFIG_H + +#if defined(_WIN32) +# if defined(MALIKANIA_COMMON_BUILD) +# define MALIKANIA_COMMON_EXPORT __declspec(dllexport) +# else +# define MALIKANIA_COMMON_EXPORT __declspec(dllimport) +# endif +#else +# define MALIKANIA_COMMON_EXPORT +#endif + +#endif // !COMMON_CONFIG_H \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/elapsed-timer.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,64 @@ +/* + * elapsed-timer.cpp -- measure elapsed time + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "elapsed-timer.h" + +using std::chrono::duration_cast; +using std::chrono::high_resolution_clock; +using std::chrono::milliseconds; + +namespace malikania { + +ElapsedTimer::ElapsedTimer() noexcept +{ + m_last = high_resolution_clock::now(); +} + +void ElapsedTimer::pause() noexcept +{ + /* + * When we put the timer on pause, do not forget to set the already + * elapsed time. + */ + (void)elapsed(); + m_paused = true; +} + +void ElapsedTimer::restart() noexcept +{ + m_paused = false; + m_last = high_resolution_clock::now(); +} + +void ElapsedTimer::reset() noexcept +{ + m_elapsed = 0; + m_last = high_resolution_clock::now(); +} + +unsigned ElapsedTimer::elapsed() noexcept +{ + if (!m_paused) { + m_elapsed += duration_cast<milliseconds>(high_resolution_clock::now() - m_last).count(); + m_last = high_resolution_clock::now(); + } + + return m_elapsed; +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/elapsed-timer.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,81 @@ +/* + * elapsed-timer.h -- measure elapsed time + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_ELAPSED_TIMER_H +#define MALIKANIA_ELAPSED_TIMER_H + +/** + * @file elapsed-timer.h + * @brief Measure elapsed time + */ + +#include <chrono> + +namespace malikania { + +/** + * @class ElapsedTimer + * @brief Measure elapsed time + * + * This class provides an abstraction to measure elapsed time since the + * construction of the object. + * + * It uses std::chrono::high_resolution_clock for more precision and uses + * milliseconds only. + */ +class ElapsedTimer { +public: + using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>; + +private: + TimePoint m_last; + bool m_paused{false}; + unsigned m_elapsed{0}; + +public: + /** + * Construct the elapsed timer, start counting. + */ + ElapsedTimer() noexcept; + + /** + * Put the timer on pause, the already elapsed time is stored. + */ + void pause() noexcept; + + /** + * Restart the timer, does not reset it. + */ + void restart() noexcept; + + /** + * Reset the timer to 0. + */ + void reset() noexcept; + + /** + * Get the number of elapsed milliseconds. + * + * @return the milliseconds + */ + unsigned elapsed() noexcept; +}; + +} // !malikania + +#endif // !MALIKANIA_ELAPSED_TIMER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/game.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,124 @@ +/* + * game.h -- basic game class + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_GAME_H +#define MALIKANIA_GAME_H + +#include <cassert> +#include <string> +#include <vector> + +namespace malikania { + +namespace json { + +class Document; + +} // !json + +/** + * @class Game + * @brief Basic game class. + */ +class Game { +private: + std::string m_name; + std::string m_version; + std::string m_requires; + std::string m_license; + std::string m_author; + +public: + /** + * Construct a game. + * + * @pre name must not be empty + * @pre version must not be empty + * @pre requires must not be empty + * @param name the game name + * @param version the version + * @param requires the engine version required + * @param license the license (Optional) + * @param authors the authors (Optional) + */ + inline Game(std::string name, std::string version, std::string requires, std::string license, std::string author) + : m_name(std::move(name)) + , m_version(std::move(version)) + , m_requires(std::move(requires)) + , m_license(std::move(license)) + , m_author(std::move(author)) + { + assert(!m_name.empty()); + assert(!m_version.empty()); + assert(!m_requires.empty()); + } + + /** + * Get the game name. + * + * @return the name + */ + inline const std::string &name() const noexcept + { + return m_name; + } + + /** + * Get the author. + * + * @return the author + */ + inline const std::string &author() const noexcept + { + return m_author; + } + + /** + * Get the license. + * + * @return the license + */ + inline const std::string &license() const noexcept + { + return m_license; + } + + /** + * Get the license. + * + * @return the license + */ + inline const std::string &version() const noexcept + { + return m_version; + } + + /** + * Get the engine version required to run the game. + * + * @return the version required + */ + inline const std::string &requires() const noexcept + { + return m_requires; + } +}; + +} // !malikania + +#endif // !MALIKANIA_GAME_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/id.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,176 @@ +/* + * id.h -- integer id generator + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_COMMON_ID_H +#define MALIKANIA_COMMON_ID_H + +/** + * @file id.h + * @brief Integer id generator + */ + +#include <limits> +#include <queue> +#include <stdexcept> + +namespace malikania { + +/** + * @class IdGen + * @brief Integer id generator + * + * This class helps generating and release unique integer id that can be used anywhere. The ids are generated in a + * sequence and when an id is released it is reused instead of incrementing the next number. + * + * The template can use any integral integer but unsigned are preferred. + * + * The maximum number of id is equal to std::numeric_limits<T>::max - 1. + */ +template <typename T> +class IdGen { +private: + static_assert(std::numeric_limits<T>::is_integer, "IdGen requires integral types"); + + T m_current{0}; + std::priority_queue<T> m_reusable; + +public: + /** + * Get the next id for that player. + * + * @return the id + * @throw std::out_of_range if no number is available + */ + T next(); + + /** + * Release the player id. + * + * @param id the id not needed anymore + */ + inline void release(T id) noexcept + { + m_reusable.push(id); + } + + /** + * Reset the ids to 0 and remove the queue. + */ + void reset() noexcept; +}; + +template <typename T> +T IdGen<T>::next() +{ + T id; + + if (m_reusable.size() > 0) { + id = m_reusable.top(); + m_reusable.pop(); + } else { + if (m_current == std::numeric_limits<T>::max()) { + throw std::out_of_range("no id available"); + } + + id = m_current++; + } + + return id; +} + +template <typename T> +void IdGen<T>::reset() noexcept +{ + m_current = 0; + + while (!m_reusable.empty()) { + m_reusable.pop(); + } +} + +/** + * @class Id + * @brief RAII based id owner + * + * This class is similar to a std::lock_guard or std::unique_lock in a way that the id is acquired + * when the object is instanciated and released when destroyed. + * + * This class does not take ownership of the IdGen so it must still exists when the Id is destroyed. + */ +template <typename T> +class Id { +private: + IdGen<T> &m_gen; + T m_id; + +public: + /** + * Construct a new Id and take the next number. + * + * @param gen the generator + * @throw any exception if IdGen fails to give an id. + */ + inline Id(IdGen<T> &gen) + : m_gen(gen) + , m_id(m_gen.next()) + { + } + + /** + * Construct an Id with an already taken number. + * + * @param gen the generator + * @param id the id + * @warning be sure that the id was taken from this generator + */ + Id(IdGen<T> &gen, T id) + : m_gen(gen) + , m_id(id) + { + } + + /** + * Destroy the id and release the number. + */ + ~Id() noexcept + { + m_gen.release(m_id); + } + + /** + * Get the number id. + * + * @return the id + */ + inline T value() const noexcept + { + return m_id; + } + + /** + * Convert the id to the number. + */ + inline operator T() const noexcept + { + return m_id; + } +}; + +} // !malikania + +#endif // !MALIKANIA_COMMON_ID_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/json.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,345 @@ +/* + * json.cpp -- C++14 JSON manipulation using jansson parser + * + * Copyright (c) 2015-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <jansson.h> + +#include <sstream> + +#include "json.h" + +namespace malikania { + +namespace json { + +namespace { + +void readObject(Value &parent, json_t *object); +void readArray(Value &parent, json_t *array); + +Value readValue(json_t *v) +{ + if (json_is_null(v)) + return Value(nullptr); + if (json_is_string(v)) + return Value(json_string_value(v)); + if (json_is_real(v)) + return Value(json_number_value(v)); + if (json_is_integer(v)) + return Value(static_cast<int>(json_integer_value(v))); + if (json_is_boolean(v)) + return Value(json_boolean_value(v)); + if (json_is_object(v)) { + Value object(Type::Object); + + readObject(object, v); + + return object; + } + if (json_is_array(v)) { + Value array(Type::Array); + + readArray(array, v); + + return array; + } + + return Value(); +} + +void readObject(Value &parent, json_t *object) +{ + const char *key; + json_t *value; + + json_object_foreach(object, key, value) + parent.insert(key, readValue(value)); +} + +void readArray(Value &parent, json_t *array) +{ + size_t index; + json_t *value; + + json_array_foreach(array, index, value) + parent.append(readValue(value)); +} + +template <typename Func, typename... Args> +Value convert(Func fn, Args&&... args) +{ + json_error_t error; + json_t *json = fn(std::forward<Args>(args)..., &error); + + if (json == nullptr) + throw Error(error.text, error.source, error.line, error.column, error.position); + + Value value; + + if (json_is_object(json)) { + value = Value(Type::Object); + readObject(value, json); + } else { + value = Value(Type::Array); + readArray(value, json); + } + + json_decref(json); + + return value; +} + +std::string indent(int param, int level) +{ + std::string str; + + if (param < 0) + str = std::string(level, '\t'); + else if (param > 0) + str = std::string(param * level, ' '); + + return str; +} + +} // !namespace + +void Value::copy(const Value &other) +{ + switch (other.m_type) { + case Type::Array: + new (&m_array) std::vector<Value>(other.m_array); + break; + case Type::Boolean: + m_boolean = other.m_boolean; + break; + case Type::Int: + m_integer = other.m_integer; + break; + case Type::Object: + new (&m_object) std::map<std::string, Value>(other.m_object); + break; + case Type::Real: + m_number = other.m_number; + break; + case Type::String: + new (&m_string) std::string(other.m_string); + break; + default: + break; + } + + m_type = other.m_type; +} + +void Value::move(Value &&other) +{ + switch (other.m_type) { + case Type::Array: + new (&m_array) std::vector<Value>(std::move(other.m_array)); + break; + case Type::Boolean: + m_boolean = other.m_boolean; + break; + case Type::Int: + m_integer = other.m_integer; + break; + case Type::Object: + new (&m_object) std::map<std::string, Value>(std::move(other.m_object)); + break; + case Type::Real: + m_number = other.m_number; + break; + case Type::String: + new (&m_string) std::string(std::move(other.m_string)); + break; + default: + break; + } + + m_type = other.m_type; +} + +Value::Value(Type type) + : m_type(type) +{ + switch (m_type) { + case Type::Array: + new (&m_array) std::vector<Value>(); + break; + case Type::Boolean: + m_boolean = false; + break; + case Type::Int: + m_integer = 0; + break; + case Type::Object: + new (&m_object) std::map<std::string, Value>(); + break; + case Type::Real: + m_number = 0; + break; + case Type::String: + new (&m_string) std::string(); + break; + default: + break; + } +} + +Value::~Value() +{ + switch (m_type) { + case Type::Array: + m_array.~vector<Value>(); + break; + case Type::Object: + m_object.~map<std::string, Value>(); + break; + case Type::String: + m_string.~basic_string(); + break; + default: + break; + } +} + +std::string Value::toString(bool coerce) const +{ + std::string result; + + if (m_type == Type::String) + result = m_string; + else if (coerce) + result = toJson(); + + return result; +} + +std::string Value::toJson(int level, int current) const +{ + std::ostringstream oss; + + switch (m_type) { + case Type::Array: { + oss << '[' << (level != 0 ? "\n" : ""); + + unsigned total = m_array.size(); + unsigned i = 0; + for (const auto &v : m_array) { + oss << indent(level, current + 1) << v.toJson(level, current + 1); + oss << (++i < total ? "," : ""); + oss << (level != 0 ? "\n" : ""); + } + + oss << (level != 0 ? indent(level, current) : "") << ']'; + break; + } + case Type::Boolean: + oss << (m_boolean ? "true" : "false"); + break; + case Type::Int: + oss << m_integer; + break; + case Type::Null: + oss << "null"; + break; + case Type::Object: { + oss << '{' << (level != 0 ? "\n" : ""); + + unsigned total = m_object.size(); + unsigned i = 0; + for (const auto &pair : m_object) { + oss << indent(level, current + 1); + + /* Key and : */ + oss << "\"" << pair.first << "\":" << (level != 0 ? " " : ""); + + /* Value */ + oss << pair.second.toJson(level, current + 1); + + /* Comma, new line if needed */ + oss << (++i < total ? "," : "") << (level != 0 ? "\n" : ""); + } + + oss << (level != 0 ? indent(level, current) : "") << '}'; + break; + } + case Type::Real: + oss << m_number; + break; + case Type::String: + oss << "\"" << escape(m_string) << "\""; + break; + default: + break; + } + + return oss.str(); +} + +std::string escape(const std::string &value) +{ + std::string result; + + for (auto it = value.begin(); it != value.end(); ++it) { + switch (*it) { + case '\\': + result += "\\\\"; + break; + case '/': + result += "\\/"; + break; + case '"': + result += "\\\""; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + default: + result += *it; + break; + } + } + + return result; +} + +Value fromString(const std::string &buffer) +{ + return convert(json_loads, buffer.c_str(), 0); +} + +Value fromFile(const std::string &path) +{ + return convert(json_load_file, path.c_str(), 0); +} + +} // !json + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/json.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,1200 @@ +/* + * json.h -- C++14 JSON manipulation using jansson parser + * + * Copyright (c) 2015-2016 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_JSON_H +#define MALIKANIA_JSON_H + +/** + * @file json.h + * @brief Jansson C++14 wrapper + */ + +#include <cassert> +#include <exception> +#include <initializer_list> +#include <map> +#include <string> +#include <utility> +#include <vector> + +namespace malikania { + +/** + * Json namespace. + */ +namespace json { + +/** + * @enum Type + * @brief Type of Value. + */ +enum class Type { + Array, //!< Value is an array [] + Boolean, //!< Value is boolean + Int, //!< Value is integer + Null, //!< Value is defined to null + Object, //!< Value is object {} + Real, //!< Value is float + String //!< Value is unicode string +}; + +/** + * @class Error + * @brief Error description. + */ +class Error : public std::exception { +private: + std::string m_text; + std::string m_source; + int m_line; + int m_column; + int m_position; + +public: + /** + * Create the error. + * + * @param text the text message + * @param source the source (e.g. file name) + * @param line the line number + * @param column the column number + * @param position the position + */ + inline Error(std::string text, std::string source, int line, int column, int position) noexcept + : m_text(std::move(text)) + , m_source(std::move(source)) + , m_line(line) + , m_column(column) + , m_position(position) + { + } + + /** + * Get the error message. + * + * @return the text + */ + inline const std::string &text() const noexcept + { + return m_text; + } + + /** + * Get the source (e.g. a file name). + * + * @return the source + */ + inline const std::string &source() const noexcept + { + return m_source; + } + + /** + * Get the line. + * + * @return the line + */ + inline int line() const noexcept + { + return m_line; + } + + /** + * Get the column. + * + * @return the column + */ + inline int column() const noexcept + { + return m_column; + } + + /** + * Get the position. + * + * @return the position + */ + inline int position() const noexcept + { + return m_position; + } + + /** + * Get the error message. + * + * @return the message + */ + const char *what() const noexcept override + { + return m_text.c_str(); + } +}; + +/** + * @class Iterator + * @brief This is the base class for iterator and const_iterator + * + * This iterator works for both arrays and objects. Because of that purpose, it is only available + * as forward iterator. + * + * When iterator comes from an object, you can use key() otherwise you can use index(). + */ +template <typename ValueType, typename ArrayIteratorType, typename ObjectIteratorType> +class Iterator : public std::iterator<std::forward_iterator_tag, ValueType> { +private: + friend class Value; + + ValueType *m_parent{nullptr}; + ArrayIteratorType m_ita; + ObjectIteratorType m_itm; + + inline void increment() + { + if (m_parent->isObject()) + m_itm++; + else + m_ita++; + } + + inline Iterator(ValueType *parent, ObjectIteratorType it) + : m_parent(parent) + , m_itm(it) + { + assert(parent); + } + + inline Iterator(ValueType *parent, ArrayIteratorType it) + : m_parent(parent) + , m_ita(it) + { + assert(parent); + } + +public: + /** + * Default constructor. + */ + Iterator() = default; + + /** + * Get the iterator key (for objects). + * + * @pre iterator must be dereferenceable + * @pre iterator must come from object + * @return the key + */ + inline const std::string &key() const noexcept + { + assert(m_parent && m_parent->isObject()); + assert(m_itm != m_parent->m_object.end()); + + return m_itm->first; + } + + /** + * Get the iterator position (for arrays). + * + * @pre iterator must be dereferenceable + * @pre iterator must come from arrays + * @return the index + */ + inline unsigned index() const noexcept + { + assert(m_parent && m_parent->isArray()); + assert(m_ita != m_parent->m_array.end()); + + return std::distance(m_parent->m_array.begin(), m_ita); + } + + /** + * Dereference the iterator. + * + * @pre iterator be dereferenceable + * @return the value + */ + inline ValueType &operator*() noexcept + { + assert(m_parent); + assert((m_parent->isArray() && m_ita != m_parent->m_array.end()) || + (m_parent->isObject() && m_itm != m_parent->m_object.end())); + + return (m_parent->m_type == Type::Object) ? m_itm->second : *m_ita; + } + + /** + * Dereference the iterator as a pointer. + * + * @pre iterator must be dereferenceable + * @return the value + */ + inline ValueType *operator->() noexcept + { + assert(m_parent); + assert((m_parent->isArray() && m_ita != m_parent->m_array.end()) || + (m_parent->isObject() && m_itm != m_parent->m_object.end())); + + return (m_parent->m_type == Type::Object) ? &m_itm->second : &(*m_ita); + } + + /** + * Increment the iterator. (Prefix version). + * + * @pre iterator must be dereferenceable + * @return *this; + */ + inline Iterator &operator++() noexcept + { + assert(m_parent); + assert((m_parent->isArray() && m_ita != m_parent->m_array.end()) || + (m_parent->isObject() && m_itm != m_parent->m_object.end())); + + increment(); + + return *this; + } + + /** + * Increment the iterator. (Postfix version). + * + * @pre iterator must be dereferenceable + * @return *this; + */ + inline Iterator &operator++(int) noexcept + { + assert(m_parent); + assert((m_parent->isArray() && m_ita != m_parent->m_array.end()) || + (m_parent->isObject() && m_itm != m_parent->m_object.end())); + + increment(); + + return *this; + } + + /** + * Compare two iterators. + * + * @param it1 the first iterator + * @param it2 the second iterator + * @return true if they are same + */ + bool operator==(const Iterator &it) const noexcept + { + return m_parent == it.m_parent && m_itm == it.m_itm && m_ita == it.m_ita; + } + + /** + * Test if the iterator is different. + * + * @param it the iterator + * @return true if they are different + */ + inline bool operator!=(const Iterator &it) const noexcept + { + return !(*this == it); + } +}; + +/** + * @class Value + * @brief Generic JSON value wrapper. + */ +class Value { +private: + Type m_type{Type::Null}; + + union { + double m_number; + bool m_boolean; + int m_integer; + std::string m_string; + std::vector<Value> m_array; + std::map<std::string, Value> m_object; + }; + + void copy(const Value &); + void move(Value &&); + std::string toJson(int indent, int current) const; + + friend class Iterator<Value, typename std::vector<Value>::iterator, typename std::map<std::string, Value>::iterator>; + friend class Iterator<const Value, typename std::vector<Value>::const_iterator, typename std::map<std::string, Value>::const_iterator>; + +public: + /** + * Forward iterator. + */ + using iterator = Iterator<Value, typename std::vector<Value>::iterator, typename std::map<std::string, Value>::iterator>; + + /** + * Const forward iterator. + */ + using const_iterator = Iterator<const Value, typename std::vector<Value>::const_iterator, typename std::map<std::string, Value>::const_iterator>; + + /** + * Construct a null value. + */ + inline Value() noexcept + { + } + + /** + * Create a value with a specified type, this is usually only needed when you want to create an object or + * an array. + * + * For any other types, initialize with sane default value. + * + * @param type the type + */ + Value(Type type); + + /** + * Construct a null value. + */ + inline Value(std::nullptr_t) noexcept + : m_type(Type::Null) + { + } + + /** + * Construct a boolean value. + * + * @param value the boolean value + */ + inline Value(bool value) noexcept + : m_type(Type::Boolean) + , m_boolean(value) + { + } + + /** + * Create value from integer. + * + * @param value the value + */ + inline Value(int value) noexcept + : m_type(Type::Int) + , m_integer(value) + { + } + + /** + * Construct a value from a C-string. + * + * @param value the C-string + */ + inline Value(const char *value) + : m_type(Type::String) + { + new (&m_string) std::string{value ? value : ""}; + } + + /** + * Construct a number value. + * + * @param value the real value + */ + inline Value(double value) noexcept + : m_type(Type::Real) + , m_number(value) + { + } + + /** + * Construct a string value. + * + * @param value the string + */ + inline Value(std::string value) noexcept + : m_type(Type::String) + { + new (&m_string) std::string(std::move(value)); + } + + /** + * Create an object from a map. + * + * @param values the values + * @see fromObject + */ + inline Value(std::map<std::string, Value> values) + : Value(Type::Object) + { + for (const auto &pair : values) + insert(pair.first, pair.second); + } + + /** + * Create an array from a vector. + * + * @param values the values + * @see fromArray + */ + inline Value(std::vector<Value> values) + : Value(Type::Array) + { + for (Value value : values) + append(std::move(value)); + } + + /** + * Move constructor. + * + * @param other the value to move from + */ + inline Value(Value &&other) + { + move(std::move(other)); + } + + /** + * Copy constructor. + * + * @param other the value to copy from + */ + inline Value(const Value &other) + { + copy(other); + } + + /** + * Copy operator. + * + * @param other the value to copy from + * @return *this + */ + inline Value &operator=(const Value &other) + { + copy(other); + + return *this; + } + + /** + * Move operator. + * + * @param other the value to move from + */ + inline Value &operator=(Value &&other) + { + move(std::move(other)); + + return *this; + } + + /** + * Destructor. + */ + ~Value(); + + /** + * Get an iterator to the beginning. + * + * @pre must be an array or object + * @return the iterator + */ + inline iterator begin() noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? iterator(this, m_object.begin()) : iterator(this, m_array.begin()); + } + + /** + * Overloaded function. + * + * @pre must be an array or object + * @return the iterator + */ + inline const_iterator begin() const noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? const_iterator(this, m_object.begin()) : const_iterator(this, m_array.begin()); + } + + /** + * Overloaded function. + * + * @pre must be an array or object + * @return the iterator + */ + inline const_iterator cbegin() const noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? const_iterator(this, m_object.cbegin()) : const_iterator(this, m_array.cbegin()); + } + + /** + * Get an iterator to the end. + * + * @pre must be an array or object + * @return the iterator + */ + inline iterator end() noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? iterator(this, m_object.end()) : iterator(this, m_array.end()); + } + + /** + * Get an iterator to the end. + * + * @pre must be an array or object + * @return the iterator + */ + inline const_iterator end() const noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? const_iterator(this, m_object.end()) : const_iterator(this, m_array.end()); + } + + /** + * Get an iterator to the end. + * + * @pre must be an array or object + * @return the iterator + */ + inline const_iterator cend() const noexcept + { + assert(isArray() || isObject()); + + return m_type == Type::Object ? const_iterator(this, m_object.cend()) : const_iterator(this, m_array.cend()); + } + + /** + * Get the value type. + * + * @return the type + */ + inline Type typeOf() const noexcept + { + return m_type; + } + + /** + * Get the value as boolean. + * + * @return the value or false if not a boolean + */ + inline bool toBool() const noexcept + { + return m_type != Type::Boolean ? false : m_boolean; + } + + /** + * Get the value as integer. + * + * @return the value or 0 if not a integer + */ + inline int toInt() const noexcept + { + return m_type != Type::Int ? 0 : m_integer; + } + + /** + * Get the value as real. + * + * @return the value or 0 if not a real + */ + inline double toReal() const noexcept + { + return m_type != Type::Real ? 0 : m_number; + } + + /** + * Get the value as string. + * + * @param coerce set to true to coerce the value if not a string + * @return the value or empty string if not a string + */ + std::string toString(bool coerce = false) const; + + /** + * Check if the value is boolean type. + * + * @return true if boolean + */ + inline bool isBool() const noexcept + { + return m_type == Type::Boolean; + } + + /** + * Check if the value is integer type. + * + * @return true if integer + */ + inline bool isInt() const noexcept + { + return m_type == Type::Int; + } + + /** + * Check if the value is object type. + * + * @return true if object + */ + inline bool isObject() const noexcept + { + return m_type == Type::Object; + } + + /** + * Check if the value is array type. + * + * @return true if array + */ + inline bool isArray() const noexcept + { + return m_type == Type::Array; + } + + /** + * Check if the value is integer or real type. + * + * @return true if integer or real + * @see toInt + * @see toReal + */ + inline bool isNumber() const noexcept + { + return m_type == Type::Real || m_type == Type::Int; + } + + /** + * Check if the value is real type. + * + * @return true if real + */ + inline bool isReal() const noexcept + { + return m_type == Type::Real; + } + + /** + * Check if the value is null type. + * + * @return true if null + */ + inline bool isNull() const noexcept + { + return m_type == Type::Null; + } + + /** + * Check if the value is string type. + * + * @return true if string + */ + inline bool isString() const noexcept + { + return m_type == Type::String; + } + + /** + * Get the array or object size. + * + * @pre must be an array or object + * @return the size + */ + inline unsigned size() const noexcept + { + assert(isArray() || isObject()); + + if (m_type == Type::Object) + return m_object.size(); + + return m_array.size(); + } + + /** + * Remove all the values. + * + * @pre must be an array or an object + */ + inline void clear() noexcept + { + assert(isArray() || isObject()); + + if (m_type == Type::Array) + m_array.clear(); + else + m_object.clear(); + } + + /* + * Array functions + * ---------------------------------------------------------- + */ + + /** + * Get the value at the specified position or the defaultValue if position is out of bounds. + * + * @param position the position + * @param defaultValue the value replacement + * @return the value or defaultValue + */ + template <typename DefaultValue> + inline Value valueOr(unsigned position, DefaultValue &&defaultValue) const + { + if (m_type != Type::Array || position >= m_array.size()) + return defaultValue; + + return m_array[position]; + } + + /** + * Overloaded function with type check. + * + * @param position the position + * @param type the requested type + * @param defaultValue the value replacement + * @return the value or defaultValue + */ + template <typename DefaultValue> + inline Value valueOr(unsigned position, Type type, DefaultValue &&defaultValue) const + { + if (m_type != Type::Array || position >= m_array.size() || m_array[position].typeOf() != type) + return defaultValue; + + return m_array[position]; + } + + /** + * Get a value at the specified index. + * + * @pre must be an array + * @param position the position + * @return the value + * @throw std::out_of_range if out of bounds + */ + inline const Value &at(unsigned position) const + { + assert(isArray()); + + return m_array.at(position); + } + + /** + * Overloaded function. + * + * @pre must be an array + * @param position the position + * @return the value + * @throw std::out_of_range if out of bounds + */ + inline Value &at(unsigned position) + { + assert(isArray()); + + return m_array.at(position); + } + + /** + * Get a value at the specified index. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + * @return the value + */ + inline const Value &operator[](unsigned position) const + { + assert(isArray()); + assert(position < m_array.size()); + + return m_array[position]; + } + + /** + * Overloaded function. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + * @return the value + */ + inline Value &operator[](unsigned position) + { + assert(isArray()); + assert(position < m_array.size()); + + return m_array[position]; + } + + /** + * Push a value to the beginning of the array. + * + * @pre must be an array + * @param value the value to push + */ + inline void push(const Value &value) + { + assert(isArray()); + + m_array.insert(m_array.begin(), value); + } + + /** + * Overloaded function. + * + * @pre must be an array + * @param value the value to push + */ + inline void push(Value &&value) + { + assert(isArray()); + + m_array.insert(m_array.begin(), std::move(value)); + } + + /** + * Insert a value at the specified position. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + * @param value the value to push + */ + inline void insert(unsigned position, const Value &value) + { + assert(isArray()); + assert(position <= m_array.size()); + + m_array.insert(m_array.begin() + position, value); + } + + /** + * Overloaded function. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + * @param value the value to push + */ + inline void insert(unsigned position, Value &&value) + { + assert(isArray()); + assert(position <= m_array.size()); + + m_array.insert(m_array.begin() + position, std::move(value)); + } + + /** + * Add a new value to the end. + * + * @pre must be an array + * @param value the value to append + */ + inline void append(const Value &value) + { + assert(isArray()); + + m_array.push_back(value); + } + + /** + * Overloaded function. + * + * @pre must be an array + * @param value the value to append + */ + inline void append(Value &&value) + { + assert(isArray()); + + m_array.push_back(std::move(value)); + } + + /** + * Remove a value at the specified position. + * + * @pre must be an array + * @pre position must be valid + * @param position the position + */ + inline void erase(unsigned position) + { + assert(isArray()); + assert(position < m_array.size()); + + m_array.erase(m_array.begin() + position); + } + + /* + * Object functions + * ---------------------------------------------------------- + */ + + /** + * Get the value at the specified key or the defaultValue if key is absent. + * + * @param name the name + * @param defaultValue the value replacement + * @return the value or defaultValue + */ + template <typename DefaultValue> + Value valueOr(const std::string &name, DefaultValue &&defaultValue) const + { + if (m_type != Type::Object) + return defaultValue; + + auto it = m_object.find(name); + + if (it == m_object.end()) + return defaultValue; + + return it->second; + } + + /** + * Overloaded function with type check. + * + * @param name the name + * @param type the requested type + * @param defaultValue the value replacement + * @return the value or defaultValue + */ + template <typename DefaultValue> + Value valueOr(const std::string &name, Type type, DefaultValue &&defaultValue) const + { + if (m_type != Type::Object) + return defaultValue; + + auto it = m_object.find(name); + + if (it == m_object.end() || it->second.typeOf() != type) + return defaultValue; + + return it->second; + } + + /** + * Get a value from the object. + * + * @pre must be an object + * @param name the value key + * @return the value + * @throw std::out_of_range if not found + */ + inline const Value &at(const std::string &name) const + { + assert(isObject()); + + return m_object.at(name); + } + + /** + * Overloaded function. + * + * @pre must be an object + * @param name the value key + * @return the value + * @throw std::out_of_range if not found + */ + inline Value &at(const std::string &name) + { + assert(isObject()); + + return m_object.at(name); + } + + /** + * Get a value from the object. + * + * @pre must be an object + * @param name the value key + * @return the value + */ + inline Value &operator[](const std::string &name) + { + assert(isObject()); + + return m_object[name]; + } + + /** + * Find a value by key. + * + * @pre must be an object + * @param key the property key + * @return the iterator or past the end if not found + */ + inline iterator find(const std::string &key) + { + assert(isObject()); + + return iterator(this, m_object.find(key)); + } + + /** + * Overloaded function. + * + * @pre must be an object + * @param key the property key + * @return the iterator or past the end if not found + */ + inline const_iterator find(const std::string &key) const + { + assert(isObject()); + + return const_iterator(this, m_object.find(key)); + } + + /** + * Insert a new value. + * + * @pre must be an object + * @param name the key + * @param value the value + */ + inline void insert(std::string name, const Value &value) + { + assert(isObject()); + + m_object.insert({std::move(name), value}); + } + + /** + * Overloaded function. + * + * @pre must be an object + * @param name the key + * @param value the value + */ + inline void insert(std::string name, Value &&value) + { + assert(isObject()); + + m_object.insert({std::move(name), std::move(value)}); + } + + /** + * Check if a value exists. + * + * @pre must be an object + * @param key the key value + * @return true if exists + */ + inline bool contains(const std::string &key) const noexcept + { + assert(isObject()); + + return m_object.find(key) != m_object.end(); + } + + /** + * Remove a value of the specified key. + * + * @pre must be an object + * @param key the value key + */ + inline void erase(const std::string &key) + { + assert(isObject()); + + m_object.erase(key); + } + + /** + * Return this value as JSon representation. + * + * @param indent the indentation to use (0 == compact, < 0 == tabs, > 0 == number of spaces) + * @return the string + */ + inline std::string toJson(int indent = 2) const + { + return toJson(indent, 0); + } +}; + +/** + * Escape the input. + * + * @param input the input + * @return the escaped string + */ +std::string escape(const std::string &input); + +/** + * Convenient function to create an empty array. + * + * @return an empty array + */ +inline Value array() +{ + return Value(Type::Array); +} + +/** + * Convenient function for creating array from initializer list. + * + * @param values the values + * @return the array + */ +inline Value array(std::initializer_list<Value> values) +{ + return Value(std::vector<Value>(values.begin(), values.end())); +} + +/** + * Convenient function to create an empty object. + * + * @return an empty object + */ +inline Value object() +{ + return Value(Type::Object); +} + +/** + * Convenient function for creating object from initializer list. + * + * @param values the values + * @return the object + */ +inline Value object(std::initializer_list<std::pair<std::string, Value>> values) +{ + return Value(std::map<std::string, Value>(values.begin(), values.end())); +} + +/** + * Construct a value from a buffer. + * + * @param data the JSON data + * @return the parsed value + * @throw Error on errors + */ +Value fromString(const std::string &data); + +/** + * Construct a value from a file. + * + * @param path the path to the file + * @return the parsed value + * @throw Error on errors + */ +Value fromFile(const std::string &path); + +} // !json + +} // !malikania + +#endif // !MALIKANIA_JSON_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/resources-loader.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,109 @@ +/* + * resources-loader.cpp -- load shared resources files + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cassert> + +#include "game.h" +#include "resources-loader.h" +#include "resources-locator.h" + +namespace malikania { + +void ResourcesLoader::requires(const std::string &id, + const json::Value &object, + const std::unordered_map<std::string, json::Type> props) const +{ + assert(object.isObject()); + + for (const auto &pair : props) { + auto it = object.find(pair.first); + + if (it == object.end() || it->typeOf() != pair.second) { + std::string msg = id + ": missing '" + pair.first + "' property ("; + + switch (pair.second) { + case json::Type::Array: + msg += "array"; + break; + case json::Type::Boolean: + msg += "boolean"; + break; + case json::Type::Int: + msg += "int"; + break; + case json::Type::Object: + msg += "object"; + break; + case json::Type::Real: + msg += "real"; + break; + case json::Type::String: + msg += "string"; + break; + default: + break; + } + + msg += " expected)"; + + throw std::runtime_error(std::move(msg)); + } + } +} + +std::string ResourcesLoader::requireString(const std::string &id, + const json::Value &object, + const std::string &property) const +{ + assert(object.isObject()); + + auto it = object.find(property); + + if (it == object.end() || !it->isString()) { + throw std::runtime_error(id + ": missing '" + property + "' property (string expected)"); + } + + return it->toString(); +} + +ResourcesLoader::ResourcesLoader(ResourcesLocator &locator) + : m_locator(locator) +{ +} + +Game ResourcesLoader::loadGame() const +{ + json::Value value = json::fromString(m_locator.read("game.json")); + + if (!value.isObject()) + throw std::runtime_error("game.json: not a JSON object"); + + requires("game.json", value, { + { "name", json::Type::String }, + { "version", json::Type::String }, + { "requires", json::Type::String } + }); + + return Game(value["name"].toString(), + value["version"].toString(), + value["requires"].toString(), + value.valueOr("license", json::Type::String, "").toString(), + value.valueOr("author", json::Type::String, "").toString()); +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/resources-loader.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,110 @@ +/* + * resources-loader.h -- load shared resources files + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_RESOURCES_LOADER_H +#define MALIKANIA_RESOURCES_LOADER_H + +#include <string> +#include <unordered_map> + +#include "json.h" +#include "resources-locator.h" + +namespace malikania { + +class Game; + +/** + * @class ResourcesLoader + * @brief Open resources files using a ResourcesLocator. + * + * This class is used to load resources files that are common to the server and the client. + * + * @see ResourcesLoaderClient + * @see ResourcesLoaderServer + */ +class ResourcesLoader { +private: + ResourcesLocator &m_locator; + +protected: + /** + * Check that an object has the specified properties of the given type. + * + * Throws an error when any of the property is missing or not the correct type. + * + * You can use this function when you have lot of properties to extract, otherwise, you can use one of the + * require* or get* functions to avoid performances overhead. + * + * @pre object.isObject() + * @param id the resource id + * @param object the object + * @param props the properties + * @throw std::runtime_error when a property is missing / invalid + */ + void requires(const std::string &id, + const json::Value &object, + const std::unordered_map<std::string, json::Type> props) const; + + /** + * Require a string. + * + * @pre object.isObject() + * @param id the resource id + * @param object the object + * @param property the property + * @return the string + * @throw std::runtime_error if the property is not a string or missing + */ + std::string requireString(const std::string &id, const json::Value &object, const std::string &property) const; + +public: + /** + * Construct the ResourcesLoader. + * + * @param locator the locator + */ + ResourcesLoader(ResourcesLocator &locator); + + /** + * Virtual destructor defaulted. + */ + virtual ~ResourcesLoader() = default; + + /** + * Get the underlying locator. + * + * @return the locator + */ + inline ResourcesLocator &locator() noexcept + { + return m_locator; + } + + /** + * Load a game. + * + * @return the game + * @throw std::runtime_error on errors + */ + virtual Game loadGame() const; +}; + +} // !malikania + +#endif // !MALIKANIA_RESOURCES_LOADER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/resources-locator.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,56 @@ +/* + * resources-locator.cpp -- file and stream loader + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <cerrno> +#include <cstring> +#include <fstream> +#include <iterator> +#include <stdexcept> + +#include "resources-locator.h" + +namespace malikania { + +ResourcesLocatorDirectory::ResourcesLocatorDirectory(std::string path) noexcept + : m_path(std::move(path)) +{ +} + +std::string ResourcesLocatorDirectory::read(const std::string &id) +{ + std::ifstream in(m_path + "/" + id, std::ifstream::in | std::ifstream::binary); + + if (!in) { + throw std::runtime_error(std::strerror(errno)); + } + + return std::string(std::istreambuf_iterator<char>(in.rdbuf()), std::istreambuf_iterator<char>()); +} + +std::unique_ptr<std::istream> ResourcesLocatorDirectory::open(const std::string &id) +{ + std::unique_ptr<std::istream> ptr = std::make_unique<std::ifstream>(m_path + "/" + id); + + if (!(*ptr)) { + throw std::runtime_error(std::strerror(errno)); + } + + return ptr; +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/resources-locator.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,82 @@ +/* + * resources-locator.h -- file and stream loader + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_RESOURCES_LOCATOR_H +#define MALIKANIA_RESOURCES_LOCATOR_H + +#include <string> +#include <memory> +#include <istream> + +namespace malikania { + +/** + * @class ResourcesLocator + * @brief Load files from directories and zip. + */ +class ResourcesLocator { +public: + /** + * Read a whole resource as a string. + * + * @param id the resource id + * @return the string + * @throw std::runtime_error on any errors + */ + virtual std::string read(const std::string &id) = 0; + + /** + * Open a resource as a stream. + * + * @param id the resource id + * @return the stream + * @throw std::runtime_error on any errors + */ + virtual std::unique_ptr<std::istream> open(const std::string &id) = 0; +}; + +/** + * @class ResourcesLocatorDirectory + * @brief Load a game from a directory. + */ +class ResourcesLocatorDirectory : public ResourcesLocator { +private: + std::string m_path; + +public: + /** + * Load the game from the directory. + * + * @param path the base directory + */ + ResourcesLocatorDirectory(std::string path) noexcept; + + /** + * @copydoc ResourcesLocator::read + */ + std::string read(const std::string &id) override; + + /** + * @copydoc ResourcesLocator::open + */ + std::unique_ptr<std::istream> open(const std::string &id) override; +}; + +} // !malikania + +#endif // !MALIKANIA_RESOURCES_LOCATOR_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/util.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,40 @@ +/* + * util.cpp -- malikania utilities + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "util.h" + +namespace malikania { + +namespace util { + +std::vector<std::string> netsplit(std::string &input) +{ + std::vector<std::string> ret; + std::string::size_type pos; + + while ((pos = input.find("\r\n\r\n")) != std::string::npos) { + ret.push_back(input.substr(0U, pos)); + input.erase(0U, pos + 4); + } + + return ret; +} + +} // !util + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/util.h Wed Mar 23 17:11:39 2016 +0100 @@ -0,0 +1,47 @@ +/* + * util.h -- malikania utilities + * + * Copyright (c) 2013-2016 Malikania Authors + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MALIKANIA_UTIL_H +#define MALIKANIA_UTIL_H + +/** + * @file util.h + * @brief Some utilities + */ + +#include <string> +#include <vector> + +namespace malikania { + +namespace util { + +/** + * Split the network message buffer by \r\n\r\n and update the + * buffer in-place. + * + * @param input the buffer to split and update + * @return the list of received message or empty if not ready + */ +std::vector<std::string> netsplit(std::string &input); + +} // !util + +} // !malikania + +#endif // !MALIKANIA_UTIL_H
--- a/tests/libclient/animation/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libclient/animation/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -22,11 +22,11 @@ #include <gtest/gtest.h> -#include <malikania/Animation.h> -#include <malikania/Animator.h> -#include <malikania/ClientResourcesLoader.h> -#include <malikania/ResourcesLocator.h> -#include <malikania/Window.h> +#include <malikania/animation.h> +#include <malikania/animator.h> +#include <malikania/client-resources-loader.h> +#include <malikania/resources-locator.h> +#include <malikania/window.h> using namespace malikania;
--- a/tests/libclient/color/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libclient/color/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -18,7 +18,7 @@ #include <gtest/gtest.h> -#include <malikania/Color.h> +#include <malikania/color.h> using namespace malikania; @@ -348,4 +348,4 @@ testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +}
--- a/tests/libclient/font/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libclient/font/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -21,10 +21,10 @@ #include <gtest/gtest.h> -#include <malikania/Color.h> -#include <malikania/Font.h> -#include <malikania/ResourcesLocator.h> -#include <malikania/Window.h> +#include <malikania/color.h> +#include <malikania/font.h> +#include <malikania/resources-locator.h> +#include <malikania/window.h> using namespace malikania;
--- a/tests/libclient/image/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libclient/image/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -21,10 +21,10 @@ #include <gtest/gtest.h> -#include <malikania/ClientResourcesLoader.h> -#include <malikania/Image.h> -#include <malikania/ResourcesLocator.h> -#include <malikania/Window.h> +#include <malikania/client-resources-loader.h> +#include <malikania/image.h> +#include <malikania/resources-locator.h> +#include <malikania/window.h> using namespace malikania;
--- a/tests/libclient/line/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libclient/line/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -18,7 +18,7 @@ #include <gtest/gtest.h> -#include <malikania/Line.h> +#include <malikania/line.h> using namespace malikania;
--- a/tests/libclient/point/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libclient/point/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -18,7 +18,7 @@ #include <gtest/gtest.h> -#include <malikania/Point.h> +#include <malikania/point.h> using namespace malikania;
--- a/tests/libclient/rectangle/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libclient/rectangle/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -18,7 +18,7 @@ #include <gtest/gtest.h> -#include <malikania/Rectangle.h> +#include <malikania/rectangle.h> using namespace malikania;
--- a/tests/libclient/size/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libclient/size/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -18,7 +18,7 @@ #include <gtest/gtest.h> -#include <malikania/Size.h> +#include <malikania/size.h> using namespace malikania;
--- a/tests/libclient/sprite/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libclient/sprite/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -22,10 +22,10 @@ #include <gtest/gtest.h> -#include <malikania/ClientResourcesLoader.h> -#include <malikania/ResourcesLocator.h> -#include <malikania/Sprite.h> -#include <malikania/Window.h> +#include <malikania/client-resources-loader.h> +#include <malikania/resources-locator.h> +#include <malikania/sprite.h> +#include <malikania/window.h> using namespace malikania;
--- a/tests/libcommon/elapsed-timer/main.cpp Wed Mar 23 09:49:51 2016 +0100 +++ b/tests/libcommon/elapsed-timer/main.cpp Wed Mar 23 17:11:39 2016 +0100 @@ -20,7 +20,7 @@ #include <gtest/gtest.h> -#include <malikania/ElapsedTimer.h> +#include <malikania/elapsed-timer.h> using namespace malikania; using namespace std::chrono_literals;