From 12b16664f756046e29b3e4114b5b8725f74fdd81 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Mon, 1 Aug 2016 23:41:48 +0200 Subject: ucoo/hal/frame_buffer: add host SDL frame buffer --- ucoo/hal/frame_buffer/Module | 6 + ucoo/hal/frame_buffer/sdl_frame_buffer.host.cc | 433 +++++++++++++++++++++ ucoo/hal/frame_buffer/sdl_frame_buffer.host.hh | 56 +++ ucoo/hal/frame_buffer/test/Makefile | 13 + .../frame_buffer/test/test_frame_buffer.host.cc | 66 ++++ 5 files changed, 574 insertions(+) create mode 100644 ucoo/hal/frame_buffer/Module create mode 100644 ucoo/hal/frame_buffer/sdl_frame_buffer.host.cc create mode 100644 ucoo/hal/frame_buffer/sdl_frame_buffer.host.hh create mode 100644 ucoo/hal/frame_buffer/test/Makefile create mode 100644 ucoo/hal/frame_buffer/test/test_frame_buffer.host.cc diff --git a/ucoo/hal/frame_buffer/Module b/ucoo/hal/frame_buffer/Module new file mode 100644 index 0000000..699de5b --- /dev/null +++ b/ucoo/hal/frame_buffer/Module @@ -0,0 +1,6 @@ +ucoo_hal_frame_buffer_SOURCES := sdl_frame_buffer.host.cc + +SDL_CFLAGS = $(shell sdl2-config --cflags) +SDL_LIBS = $(shell sdl2-config --libs) +host_CFLAGS += $(SDL_CFLAGS) +host_LIBS += $(SDL_LIBS) diff --git a/ucoo/hal/frame_buffer/sdl_frame_buffer.host.cc b/ucoo/hal/frame_buffer/sdl_frame_buffer.host.cc new file mode 100644 index 0000000..cbeebbd --- /dev/null +++ b/ucoo/hal/frame_buffer/sdl_frame_buffer.host.cc @@ -0,0 +1,433 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2016 Nicolas Schodet +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// }}} +#include "ucoo/hal/frame_buffer/sdl_frame_buffer.host.hh" + +#include +#include + +namespace ucoo { + +void +SdlFrameBuffer::enable () +{ + if (SDL_Init (SDL_INIT_VIDEO) != 0) + sdl_error ("Unable to initialise SDL"); + atexit (SDL_Quit); + win_ = SDL_CreateWindow ("GUI test", SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, width, height, 0); + if (!win_) + sdl_error ("Unable to create window"); + rend_ = SDL_CreateRenderer (win_, -1, 0); + if (!rend_) + sdl_error ("Unable to create renderer"); + tex_ = SDL_CreateTexture (rend_, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, width, height); + if (!tex_) + sdl_error ("Unable to create texture"); + pixels_ = new uint32_t[width * height]; +} + +void +SdlFrameBuffer::disable () +{ + SDL_Quit (); +} + +void +SdlFrameBuffer::refresh () +{ + SDL_UpdateTexture (tex_, nullptr, pixels_, width * 4); + SDL_RenderClear (rend_); + SDL_RenderCopy (rend_, tex_, nullptr, nullptr); + SDL_RenderPresent (rend_); +} + +void +SdlFrameBuffer::fill (uint32_t color) +{ + for (int i = 0; i < width * height; i++) + pixels_[i] = color; +} + +void +SdlFrameBuffer::fill (uint32_t color, const Surface::Rect &rect) +{ + // Handle clipping. + int x = rect.x, y = rect.y, w = rect.w, h = rect.h; + if (x < 0) + { + w += x; + x = 0; + } + if (y < 0) + { + h += y; + y = 0; + } + if (x + w > width) + w = width - x; + if (y + h > height) + h = height - y; + if (w < 0 || h < 0) + return; + // Fill. + uint32_t *p = pixels_ + y * width + x; + for (; h; h--) + { + for (int iw = w; iw; iw--) + { + *p++ = color; + } + p += width - w; + } +} + +void +SdlFrameBuffer::blit (const Surface &surface, int x, int y) +{ + int sx = 0, sy = 0, sw = surface.w, sh = surface.h; + // Handle clipping. + if (x < 0) + { + sw += x; + sx = -x; + x = 0; + } + if (y < 0) + { + sh += y; + sy = -y; + y = 0; + } + if (x + sw > width) + sw = width - x; + if (y + sh > height) + sh = height - y; + if (sw < 0 || sh < 0) + return; + uint32_t *p = pixels_ + y * width + x; + int line_skip = width - sw; + // Blit. + switch (surface.format) + { + case Surface::Format::ARGB8888: + { + const uint8_t *s = surface.pixels + (sy * surface.stride + sx) * 4; + for (int j = sh; j; j--) + { + const uint32_t *ls = reinterpret_cast (s); + for (int i = sw; i; i--) + *p++ = *ls++; + p += line_skip; + s = s + surface.stride * 4; + } + } + break; + case Surface::Format::RGB888: + { + const uint8_t *s = surface.pixels + (sy * surface.stride + sx) * 3; + for (int j = sh; j; j--) + { + const uint8_t *ls = s; + for (int i = sw; i; i--) + { + uint32_t w = *ls++; + w |= *ls++ << 8; + w |= *ls++ << 16; + w |= 0xff << 24; + *p++ = w; + } + p += line_skip; + s = s + surface.stride * 3; + } + } + break; + case Surface::Format::RGB565: + { + const uint8_t *s = surface.pixels + (sy * surface.stride + sx) * 2; + for (int j = sh; j; j--) + { + const uint16_t *ls = reinterpret_cast (s); + for (int i = sw; i; i--) + { + uint16_t px = *ls++; + uint32_t r = px >> 11; + uint32_t g = (px >> 5) & 0x3f; + uint32_t b = px & 0x1f; + *p++ = 0xff << 24 + | r << 19 | r >> 2 << 16 + | g << 10 | g >> 4 << 8 + | b << 3 | b >> 2; + } + p += line_skip; + s = s + surface.stride * 2; + } + } + break; + case Surface::Format::ARGB4444: + { + const uint8_t *s = surface.pixels + (sy * surface.stride + sx) * 2; + for (int j = sh; j; j--) + { + const uint16_t *ls = reinterpret_cast (s); + for (int i = sw; i; i--) + { + uint16_t px = *ls++; + uint32_t r = (px >> 8) & 0xf; + uint32_t g = (px >> 4) & 0xf; + uint32_t b = px & 0xf; + *p++ = 0xff << 24 + | r << 20 | r << 16 + | g << 12 | g << 8 + | b << 4 | b; + } + p += line_skip; + s = s + surface.stride * 2; + } + } + break; + case Surface::Format::A8: + case Surface::Format::A4: + assert_unreachable (); + break; + } +} + +void +SdlFrameBuffer::blend (const Surface &surface, int x, int y, + uint32_t const_color) +{ + int sx = 0, sy = 0, sw = surface.w, sh = surface.h; + // Handle clipping. + if (x < 0) + { + sw += x; + sx = -x; + x = 0; + } + if (y < 0) + { + sh += y; + sy = -y; + y = 0; + } + if (x + sw > width) + sw = width - x; + if (y + sh > height) + sh = height - y; + if (sw < 0 || sh < 0) + return; + uint32_t *p = pixels_ + y * width + x; + int line_skip = width - sw; + // Blend. + uint32_t ca = (const_color >> 24) & 0xff; + uint32_t cr = (const_color >> 16) & 0xff; + uint32_t cg = (const_color >> 8) & 0xff; + uint32_t cb = const_color & 0xff; + switch (surface.format) + { + case Surface::Format::ARGB8888: + { + const uint8_t *s = surface.pixels + (sy * surface.stride + sx) * 4; + for (int j = sh; j; j--) + { + const uint32_t *ls = reinterpret_cast (s); + for (int i = sw; i; i--) + { + uint32_t spx = *ls++; + uint32_t a = spx >> 24; + a = a * ca / 255; + uint32_t sr = (spx >> 16) & 0xff; + uint32_t sg = (spx >> 8) & 0xff; + uint32_t sb = spx & 0xff; + uint32_t px = *p; + uint32_t r = (px >> 16) & 0xff; + uint32_t g = (px >> 8) & 0xff; + uint32_t b = px & 0xff; + r = (r * (255 - a) + sr * a) / 255; + g = (g * (255 - a) + sg * a) / 255; + b = (b * (255 - a) + sb * a) / 255; + *p++ = 0xff << 24 | r << 16 | g << 8 | b; + } + p += line_skip; + s = s + surface.stride * 4; + } + } + break; + case Surface::Format::RGB888: + { + const uint8_t *s = surface.pixels + (sy * surface.stride + sx) * 3; + for (int j = sh; j; j--) + { + const uint8_t *ls = s; + for (int i = sw; i; i--) + { + uint32_t sb = *ls++; + uint32_t sg = *ls++; + uint32_t sr = *ls++; + uint32_t px = *p; + uint32_t r = (px >> 16) & 0xff; + uint32_t g = (px >> 8) & 0xff; + uint32_t b = px & 0xff; + r = (r * (255 - ca) + sr * ca) / 255; + g = (g * (255 - ca) + sg * ca) / 255; + b = (b * (255 - ca) + sb * ca) / 255; + *p++ = 0xff << 24 | r << 16 | g << 8 | b; + } + p += line_skip; + s = s + surface.stride * 3; + } + } + break; + case Surface::Format::RGB565: + { + const uint8_t *s = surface.pixels + (sy * surface.stride + sx) * 2; + for (int j = sh; j; j--) + { + const uint16_t *ls = reinterpret_cast (s); + for (int i = sw; i; i--) + { + uint16_t spx = *ls++; + uint32_t sr = spx >> 11; + sr = sr << 3 | sr >> 2; + uint32_t sg = (spx >> 5) & 0x3f; + sg = sg << 2 | sg >> 4; + uint32_t sb = spx & 0x1f; + sb = sb << 3 | sb >> 2; + uint32_t px = *p; + uint32_t r = (px >> 16) & 0xff; + uint32_t g = (px >> 8) & 0xff; + uint32_t b = px & 0xff; + r = (r * (255 - ca) + sr * ca) / 255; + g = (g * (255 - ca) + sg * ca) / 255; + b = (b * (255 - ca) + sb * ca) / 255; + *p++ = 0xff << 24 | r << 16 | g << 8 | b; + } + p += line_skip; + s = s + surface.stride * 2; + } + } + break; + case Surface::Format::ARGB4444: + { + const uint8_t *s = surface.pixels + (sy * surface.stride + sx) * 2; + for (int j = sh; j; j--) + { + const uint16_t *ls = reinterpret_cast (s); + for (int i = sw; i; i--) + { + uint16_t spx = *ls++; + uint32_t a = spx >> 12; + a = a * ca / 255; + uint32_t sr = (spx >> 8) & 0xf; + sr = sr << 4 | sr; + uint32_t sg = (spx >> 4) & 0xf; + sg = sg << 4 | sg; + uint32_t sb = spx & 0xf; + sb = sb << 4 | sb; + uint32_t px = *p; + uint32_t r = (px >> 16) & 0xff; + uint32_t g = (px >> 8) & 0xff; + uint32_t b = px & 0xff; + r = (r * (15 - a) + sr * a) / 15; + g = (g * (15 - a) + sg * a) / 15; + b = (b * (15 - a) + sb * a) / 15; + *p++ = 0xff << 24 | r << 16 | g << 8 | b; + } + p += line_skip; + s = s + surface.stride * 2; + } + } + break; + case Surface::Format::A8: + { + const uint8_t *s = surface.pixels + sy * surface.stride + sx; + for (int j = sh; j; j--) + { + const uint8_t *ls = s; + for (int i = sw; i; i--) + { + uint32_t a = *ls++; + a = a * ca / 255; + uint32_t px = *p; + uint32_t r = (px >> 16) & 0xff; + uint32_t g = (px >> 8) & 0xff; + uint32_t b = px & 0xff; + r = (r * (255 - a) + cr * a) / 255; + g = (g * (255 - a) + cg * a) / 255; + b = (b * (255 - a) + cb * a) / 255; + *p++ = 0xff << 24 | r << 16 | g << 8 | b; + } + p += line_skip; + s = s + surface.stride; + } + } + break; + case Surface::Format::A4: + { + assert (surface.stride % 2 == 0 && sx % 2 == 0 && sw % 2 == 0); + const uint8_t *s = surface.pixels + (sy * surface.stride + sx) / 2; + for (int j = sh; j; j--) + { + const uint8_t *ls = s; + for (int i = sw / 2; i; i--) + { + uint8_t aa = *ls++; + uint32_t a = (aa & 0xf); + a = a * ca / 255; + uint32_t px = *p; + uint32_t r = (px >> 16) & 0xff; + uint32_t g = (px >> 8) & 0xff; + uint32_t b = px & 0xff; + r = (r * (15 - a) + cr * a) / 15; + g = (g * (15 - a) + cg * a) / 15; + b = (b * (15 - a) + cb * a) / 15; + *p++ = 0xff << 24 | r << 16 | g << 8 | b; + a = aa >> 4; + a = a * ca / 255; + px = *p; + r = (px >> 16) & 0xff; + g = (px >> 8) & 0xff; + b = px & 0xff; + r = (r * (15 - a) + cr * a) / 15; + g = (g * (15 - a) + cg * a) / 15; + b = (b * (15 - a) + cb * a) / 15; + *p++ = 0xff << 24 | r << 16 | g << 8 | b; + } + p += line_skip; + s = s + surface.stride / 2; + } + } + break; + } +} + +void +SdlFrameBuffer::sdl_error (const char *error) +{ + std::cerr << error << ": " << SDL_GetError () << std::endl; + exit (1); +} + +} // namespace ucoo diff --git a/ucoo/hal/frame_buffer/sdl_frame_buffer.host.hh b/ucoo/hal/frame_buffer/sdl_frame_buffer.host.hh new file mode 100644 index 0000000..3bf8960 --- /dev/null +++ b/ucoo/hal/frame_buffer/sdl_frame_buffer.host.hh @@ -0,0 +1,56 @@ +#ifndef ucoo_hal_sdl_frame_buffer_host_hh +#define ucoo_hal_sdl_frame_buffer_host_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2016 Nicolas Schodet +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// }}} +#include "ucoo/intf/frame_buffer.hh" +#include + +namespace ucoo { + +/// Simulated frame buffer using SDL. +class SdlFrameBuffer : public FrameBuffer +{ + public: + SdlFrameBuffer (int w, int h) + : FrameBuffer (w, h) { } + void enable () override; + void disable () override; + void refresh () override; + void fill (uint32_t color) override; + void fill (uint32_t color, const Surface::Rect &rect) override; + void blit (const Surface &surface, int x, int y) override; + void blend (const Surface &surface, int x, int y, + uint32_t const_color = 0xff000000) override; + private: + void sdl_error (const char *error); + private: + SDL_Window *win_; + SDL_Renderer *rend_; + SDL_Texture *tex_; + uint32_t *pixels_; +}; + +} // namespace ucoo + +#endif // ucoo_hal_sdl_frame_buffer_host_hh diff --git a/ucoo/hal/frame_buffer/test/Makefile b/ucoo/hal/frame_buffer/test/Makefile new file mode 100644 index 0000000..3aabcb6 --- /dev/null +++ b/ucoo/hal/frame_buffer/test/Makefile @@ -0,0 +1,13 @@ +BASE = ../../../.. + +TARGETS = host +PROGS = test_frame_buffer + +test_frame_buffer_SOURCES = test_frame_buffer.host.cc + +MODULES = ucoo/hal/frame_buffer + +include $(BASE)/build/top.mk + +host_CFLAGS += $(shell sdl2-config --cflags) +host_LIBS += $(shell sdl2-config --libs) diff --git a/ucoo/hal/frame_buffer/test/test_frame_buffer.host.cc b/ucoo/hal/frame_buffer/test/test_frame_buffer.host.cc new file mode 100644 index 0000000..2348917 --- /dev/null +++ b/ucoo/hal/frame_buffer/test/test_frame_buffer.host.cc @@ -0,0 +1,66 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2016 Nicolas Schodet +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// }}} +#include "ucoo/arch/arch.hh" +#include "ucoo/hal/frame_buffer/sdl_frame_buffer.host.hh" + +int +main (int argc, const char **argv) +{ + ucoo::arch_init (argc, argv); + ucoo::SdlFrameBuffer fb (320, 320); + fb.enable (); + uint32_t buf[100][100]; + for (int y = 0; y < 100; y++) + for (int x = 0; x < 100; x++) + buf[x][y] = 0xff << 24 + | (x * 0xff / 99) << 16 + | (y * 0xff / 99) << 0; + ucoo::Surface surf = { ucoo::Surface::Format::ARGB8888, 100, 100, 100, + reinterpret_cast (buf) }; + uint8_t buf2[100][100]; + for (int y = 0; y < 100; y++) + for (int x = 0; x < 100; x++) + buf2[x][y] = (x + y) * 0xff / 198; + ucoo::Surface surf2 = { ucoo::Surface::Format::A8, 100, 100, 100, + reinterpret_cast (buf2) }; + uint16_t buf3[100][100]; + for (int y = 0; y < 100; y++) + for (int x = 0; x < 100; x++) + buf3[x][y] = 0x1f << 11 + | (x * 0x3f / 99) << 5 + | (y * 0x1f / 99) << 0; + ucoo::Surface surf3 = { ucoo::Surface::Format::RGB565, 100, 100, 100, + reinterpret_cast (buf3) }; + for (int i = -120; i < 320 + 120; i += 10) + { + fb.fill (0xffff0000); + fb.fill (0xff00ff00, {i, 110, 100, 100}); + fb.blit (surf, 20, i); + fb.blend (surf2, 120, i, 0xff0000ff); + fb.blend (surf3, 220, i, 0x80000000); + fb.refresh (); + SDL_Delay (100); + } + return 0; +} -- cgit v1.2.3