#include #include #include // #define STB_IMAGE_IMPLEMENTATION #include namespace amy { void image::load(cstr& path) { int c = 0; uc* buf = stbi_load(path.c_str(), &m_w, &m_h, &c, 4); if (c == 3) { // Releoading the Image with tree channels requestet // Still need to find a better way for this :( stbi_image_free(buf); buf = stbi_load(path.c_str(), &m_w, &m_h, &c, 3); m_buffer.assign(buf, buf + (m_w * m_h * 3)); m_fmt = RGB; stbi_image_free(buf); } else if (c == 4) { m_buffer.assign(buf, buf + (m_w * m_h * 4)); m_fmt = RGBA; stbi_image_free(buf); } else { throw std::runtime_error(path + " is using an unsupported image format!"); } } void image::load(const std::vector& data) { int c = 0; uc* buf = stbi_load_from_memory(data.data(), data.size(), &m_w, &m_h, &c, 4); if (c == 3) { // Releoading the Image with tree channels requestet // Still need to find a better way for this :( stbi_image_free(buf); buf = stbi_load_from_memory(data.data(), data.size(), &m_w, &m_h, &c, 3); m_buffer.assign(buf, buf + (m_w * m_h * 3)); m_fmt = RGB; stbi_image_free(buf); } else if (m_fmt == 4) { m_buffer.assign(buf, buf + (m_w * m_h * 4)); m_fmt = RGBA; stbi_image_free(buf); } else { throw std::runtime_error("image mem using an unsupported image format!"); } } void image::copy(const std::vector& pixels, int w, int h, const format& fmt) { int f = getBppOfFmt(fmt); if (pixels.size() != static_cast(w * h * f)) { throw std::runtime_error("Connot copy image due to size error!"); } m_fmt = fmt; m_w = w; m_h = h; m_buffer.clear(); m_buffer.resize(w * h * f); for (size_t i = 0; i < m_buffer.size(); i++) { m_buffer[i] = pixels[i]; } } int image::getBppOfFmt(const image::format& fmt) { switch (fmt) { case RGBA: case ABGR: case BGRA: return 4; break; case RGB: case BGR: return 3; break; case RGB565: return 2; break; default: return 0; // Unknown break; } } void image::convert(image& img, const format& dst) { if (img.m_fmt == dst) { return; } else if (img.m_fmt == RGB && dst == BGR) { utils::image::reverseBuf(img.m_buffer, img.m_w, img.m_h, 3); img.m_fmt = BGR; } else if (img.m_fmt == RGB && dst == RGBA) { utils::image::addAlphaChannel(img.m_buffer, img.m_w, img.m_h); img.m_fmt = RGBA; } else if (img.m_fmt == RGBA && dst == RGB) { utils::image::removeAlphaChannel(img.m_buffer, img.m_w, img.m_h); img.m_fmt = RGB; } else if (img.m_fmt == RGBA && dst == ABGR) { utils::image::reverseBuf(img.m_buffer, img.m_w, img.m_h, 4); img.m_fmt = ABGR; } else if (img.m_fmt == RGB && dst == ABGR) { convert(img, RGBA); convert(img, ABGR); } else if (img.m_fmt == RGBA && dst == RGB565) { convert(img, RGB); convert(img, RGB565); } else if (img.m_fmt == RGB && dst == RGB565) { // Inlined make pixel 565 func auto f = [](uc r, uc g, uc b) -> unsigned short { unsigned short _r = (r >> 3); unsigned short _g = (g >> 2); unsigned short _b = (b >> 3); return (_r << 11) | (_g << 5) | _b; }; std::vector cpy = img.m_buffer; img.m_buffer.resize(img.m_w * img.m_h * 2); for (int y = 0; y < img.m_w; y++) { for (int x = 0; x < img.m_h; x++) { int src = (y * img.m_w + x) * 3; int dst = (y * img.m_w + x) * 2; unsigned short new_px = f(cpy[src + 0], cpy[src + 1], cpy[src + 2]); img.m_buffer[dst + 0] = new_px >> 8; img.m_buffer[dst + 1] = new_px & 0xff; } } img.m_fmt = RGB565; } } void image::retile(image& img, std::function src, std::function dst) { std::vector cpy = img.m_buffer; /** could use fmt here but for 565 that woulnt work as it is not supported by * file loading where fmt is used */ int bpp = img.bpp(); for (int y = 0; y < img.m_h; y++) { for (int x = 0; x < img.m_w; x++) { int src_idx = src(x, y, img.m_w); int dst_idx = dst(x, y, img.m_w); for (int i = 0; i < bpp; i++) { img.m_buffer[dst_idx + i] = cpy[src_idx + i]; } } } } } // namespace amy