From ce480b07335d8f7d380ac302a1a6422c4fa3742b Mon Sep 17 00:00:00 2001 From: Yaniv Kamay Date: Mon, 28 Dec 2009 00:31:35 +0200 Subject: client: add soft renderer and cegui --- client/gui/softrenderer.cpp | 372 ++++++++++++++++++++++++++++++++++++++++++++ client/gui/softrenderer.h | 131 ++++++++++++++++ client/gui/softtexture.cpp | 124 +++++++++++++++ client/gui/softtexture.h | 40 +++++ client/windows/redc.vcproj | 28 +++- client/x11/Makefile.am | 10 +- 6 files changed, 697 insertions(+), 8 deletions(-) create mode 100644 client/gui/softrenderer.cpp create mode 100644 client/gui/softrenderer.h create mode 100644 client/gui/softtexture.cpp create mode 100644 client/gui/softtexture.h (limited to 'client') diff --git a/client/gui/softrenderer.cpp b/client/gui/softrenderer.cpp new file mode 100644 index 00000000..9e08f7a5 --- /dev/null +++ b/client/gui/softrenderer.cpp @@ -0,0 +1,372 @@ +#include "common.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "utils.h" +#include "debug.h" + +#include "softrenderer.h" +#include "softtexture.h" + +#include "CEGUIExceptions.h" +#include "CEGUIImageCodec.h" +#include "CEGUIDynamicModule.h" +#include "CEGUIEventArgs.h" + +#define S_(X) #X +#define STRINGIZE(X) S_(X) + +namespace CEGUI { + +SoftRenderer::SoftRenderer(uint8_t* surface, uint width, uint height, uint stride, + ImageCodec* codec) + : _surface (surface) + , _width (width) + , _height (height) + , _image_codec (codec) + , _image_codec_module (NULL) + , _queueing(true) +{ + assert(stride == _width * 4); //for now + if (!_image_codec) { + setupImageCodec(); + } +} + +SoftRenderer::~SoftRenderer() +{ + destroyAllTextures(); + cleanupImageCodec(); +} + + +void SoftRenderer::reset_surface(uint8_t* surface, uint width, uint height, uint stride) +{ + assert(stride == width * 4); //for now + _surface = surface; + _width = width; + _height = height; + + EventArgs args; + fireEvent(EventDisplaySizeChanged, args, EventNamespace); +} + +#if defined(CEGUI_STATIC) +extern "C" CEGUI::ImageCodec* createImageCodec(void); +extern "C" void destroyImageCodec(CEGUI::ImageCodec*); +#endif + +void SoftRenderer::setupImageCodec() +{ +#if defined(CEGUI_STATIC) + _destroy_image_codec = destroyImageCodec; + _image_codec = createImageCodec(); +#else + String _default_codec_name(STRINGIZE(TGAImageCodec/*CEGUI_DEFAULT_IMAGE_CODEC*/)); + DynamicModule* module = NULL; + try { + DynamicModule* module = new DynamicModule(String("CEGUI") + _default_codec_name); + + _destroy_image_codec = (void(*)(ImageCodec*))module->getSymbolAddress("destroyImageCodec"); + if (!_destroy_image_codec) { + throw GenericException("Missing destroyImageCodec symbol"); + } + + ImageCodec* (*create_f)(void); + create_f = (ImageCodec* (*)(void))module->getSymbolAddress("createImageCodec"); + if (!create_f) { + throw GenericException("Missing createImageCodec symbol"); + } + _image_codec = create_f(); + } catch (...) { + delete module; + throw; + } + _image_codec_module = module; +#endif +} + + +void SoftRenderer::cleanupImageCodec() +{ + _destroy_image_codec(_image_codec); + delete _image_codec_module; +} + + +static inline uint8_t calac_pixel(uint64_t c1, uint64_t c2, uint64_t c3, uint64_t a_mul) +{ + //(c' * c" * a' * a" + c"' * 255 ^ 3 - c"' * a' * a" * 255) / 255^4 + + return uint8_t((c1 * c2 * a_mul + c3 * 255 * 255 * 255 - c3 * a_mul * 255) / (255 * 255 * 255)); +} + +inline void SoftRenderer::componnentAtPoint(int x_pos, int y_pos, + int top_left, int top_right, + int bottom_left, int bottom_right, + uint64_t& comp) +{ + int a = top_left + (((x_pos * (top_right - top_left)) + (1 << 15)) >> 16); + int b = bottom_left + (((x_pos * (bottom_right - bottom_left)) + (1 << 15)) >> 16); + comp = a + (((b - a) * y_pos + (1 << 15)) >> 16); +} + +void SoftRenderer::colourAtPoint(int x, int x_max, int y, int y_max, + const ColourIRect& colours, + uint64_t& r, uint64_t& g, + uint64_t& b, uint64_t& a) +{ + int x_pos = (x << 16) / x_max; + int y_pos = (y << 16) / y_max; + + + componnentAtPoint(x_pos, y_pos, colours.top_left.r, colours.top_right.r, + colours.bottom_left.r, colours.bottom_right.r, r); + componnentAtPoint(x_pos, y_pos, colours.top_left.g, colours.top_right.g, + colours.bottom_left.g, colours.bottom_right.g, g); + componnentAtPoint(x_pos, y_pos, colours.top_left.b, colours.top_right.b, + colours.bottom_left.b, colours.bottom_right.b, b); + componnentAtPoint(x_pos, y_pos, colours.top_left.a, colours.top_right.a, + colours.bottom_left.a, colours.bottom_right.a, a); +} + +void SoftRenderer::renderQuadWithColourRect(const QuadInfo& quad) +{ + uint32_t* src = quad.tex->_surf + quad.tex_src.top * (int)quad.tex->getWidth(); + src += quad.tex_src.left; + + + int src_width = quad.tex_src.right - quad.tex_src.left; + int src_height = quad.tex_src.bottom - quad.tex_src.top; + + int dest_width = quad.dest.right - quad.dest.left; + int dest_height = quad.dest.bottom - quad.dest.top; + + + uint32_t x_scale = (src_width << 16) / dest_width; + uint32_t y_scale = (src_height << 16) / dest_height; + + uint32_t* line = (uint32_t*)_surface + quad.dest.top * _width; + line += quad.dest.left; + + for (int i = 0; i < dest_height; line += _width, i++) { + uint32_t* pix = line; + uint32_t* src_line = src + (((i * y_scale) + (1 << 15)) >> 16) * (int)quad.tex->getWidth(); + + for (int j = 0; j < dest_width; pix++, j++) { + uint64_t r; + uint64_t g; + uint64_t b; + uint64_t a; + + colourAtPoint(j, dest_width, i, dest_height, quad.colors, r, g, b, a); + + uint8_t* tex_pix = (uint8_t*)&src_line[(((j * x_scale)+ (1 << 15)) >> 16)]; + uint64_t a_mul = a * tex_pix[3]; + + ((uint8_t *)pix)[0] = calac_pixel(tex_pix[0], b, ((uint8_t *)pix)[0], a_mul); + ((uint8_t *)pix)[1] = calac_pixel(tex_pix[1], g, ((uint8_t *)pix)[1], a_mul); + ((uint8_t *)pix)[2] = calac_pixel(tex_pix[2], r, ((uint8_t *)pix)[2], a_mul); + } + } +} + +void SoftRenderer::renderQuad(const QuadInfo& quad) +{ + if (!quad.colors.top_left.isSameColour(quad.colors.top_right) || + !quad.colors.top_left.isSameColour(quad.colors.bottom_left) || + !quad.colors.top_left.isSameColour(quad.colors.bottom_right)) { + renderQuadWithColourRect(quad); + return; + } + + + uint32_t* src = quad.tex->_surf + quad.tex_src.top * (int)quad.tex->getWidth(); + src += quad.tex_src.left; + + + int src_width = quad.tex_src.right - quad.tex_src.left; + int src_height = quad.tex_src.bottom - quad.tex_src.top; + + int dest_width = quad.dest.right - quad.dest.left; + int dest_height = quad.dest.bottom - quad.dest.top; + + + uint32_t x_scale = (src_width << 16) / dest_width; + uint32_t y_scale = (src_height << 16) / dest_height; + + uint32_t* line = (uint32_t*)_surface + quad.dest.top * _width; + line += quad.dest.left; + + uint64_t r = quad.colors.top_left.r; + uint64_t g = quad.colors.top_left.g; + uint64_t b = quad.colors.top_left.b; + uint64_t a = quad.colors.top_left.a; + + for (int i = 0; i < dest_height; line += _width, i++) { + uint32_t* pix = line; + uint32_t* src_line = src + (((i * y_scale) + (1 << 15)) >> 16) * (int)quad.tex->getWidth(); + + for (int j = 0; j < dest_width; pix++, j++) { + uint8_t* tex_pix = (uint8_t*)&src_line[(((j * x_scale)+ (1 << 15)) >> 16)]; + uint64_t a_mul = a * tex_pix[3]; + + ((uint8_t *)pix)[0] = calac_pixel(tex_pix[0], b, ((uint8_t *)pix)[0], a_mul); + ((uint8_t *)pix)[1] = calac_pixel(tex_pix[1], g, ((uint8_t *)pix)[1], a_mul); + ((uint8_t *)pix)[2] = calac_pixel(tex_pix[2], r, ((uint8_t *)pix)[2], a_mul); + } + } +} + +inline void SoftRenderer::setRGB(ColourI& dest, const colour& src) +{ + dest.r = uint8_t(src.getRed()* 255); + dest.g = uint8_t(src.getGreen() * 255); + dest.b = uint8_t(src.getBlue() * 255); + dest.a = uint8_t(src.getAlpha() * 255); +} + +void SoftRenderer::addQuad(const Rect& dest_rect, float z, const Texture* texture, + const Rect& texture_rect, const ColourRect& colours, + QuadSplitMode quad_split_mode) +{ + if (dest_rect.d_right <= dest_rect.d_left || dest_rect.d_bottom <= dest_rect.d_top) { + return; + } + + if (texture_rect.d_right <= texture_rect.d_left || + texture_rect.d_bottom <= texture_rect.d_top) { + return; + } + + QuadInfo quad; + quad.dest.top = (int)dest_rect.d_top; + quad.dest.left = (int)dest_rect.d_left; + quad.dest.bottom = (int)dest_rect.d_bottom; + quad.dest.right = (int)dest_rect.d_right; + + quad.tex = (const SoftTexture*)texture; + + quad.tex_src.top = int(texture_rect.d_top * texture->getHeight()); + quad.tex_src.bottom = int(texture_rect.d_bottom * texture->getHeight()); + quad.tex_src.left = int(texture_rect.d_left * texture->getWidth()); + quad.tex_src.right = int(texture_rect.d_right * texture->getWidth()); + + setRGB(quad.colors.top_left, colours.d_top_left); + setRGB(quad.colors.top_right, colours.d_top_right); + setRGB(quad.colors.bottom_left, colours.d_bottom_left); + setRGB(quad.colors.bottom_right, colours.d_bottom_right); + + quad.z = z; + + if (!_queueing) { + renderQuad(quad); + return; + } + + _queue.insert(quad); +} + +void SoftRenderer::doRender() +{ + QuadQueue::iterator iter = _queue.begin(); + + for (; iter != _queue.end(); ++iter) { + renderQuad(*iter); + } +} + +void SoftRenderer::clearRenderList() +{ + _queue.clear(); +} + +void SoftRenderer::setQueueingEnabled(bool val) +{ + _queueing = val; +} + +bool SoftRenderer::isQueueingEnabled() const +{ + return _queueing; +} + +Texture* SoftRenderer::createTexture() +{ + SoftTexture* texture = new SoftTexture(this); + _textures.push_back(texture); + return texture; +} + +Texture* SoftRenderer::createTexture(const String& filename, + const String& resourceGroup) +{ + SoftTexture* texture = new SoftTexture(this, filename, resourceGroup); + _textures.push_back(texture); + return texture; +} + +Texture* SoftRenderer::createTexture(float size) +{ + SoftTexture* texture = new SoftTexture(this, (uint)size); + _textures.push_back(texture); + return texture; +} + +void SoftRenderer::destroyTexture(Texture* texture) +{ + if (!texture) { + return; + } + SoftTexture* soft_texture = (SoftTexture*)texture; + _textures.remove(soft_texture); + delete soft_texture; +} + +void SoftRenderer::destroyAllTextures() +{ + while (!_textures.empty()) { + SoftTexture* texture = *_textures.begin(); + _textures.pop_front(); + delete texture; + } +} + +uint SoftRenderer::getMaxTextureSize() const +{ + return 1 << 16; +} + +float SoftRenderer::getWidth() const +{ + return (float)_width; +} + +float SoftRenderer::getHeight() const +{ + return (float)_height; +} + +Size SoftRenderer::getSize() const +{ + return Size((float)_width, (float)_height); +} + +Rect SoftRenderer::getRect() const +{ + return Rect(0, 0, (float)_width, (float)_height); +} + +uint SoftRenderer::getHorzScreenDPI() const +{ + return 96; +} + +uint SoftRenderer::getVertScreenDPI() const +{ + return 96; +} + +} + + diff --git a/client/gui/softrenderer.h b/client/gui/softrenderer.h new file mode 100644 index 00000000..939eb38b --- /dev/null +++ b/client/gui/softrenderer.h @@ -0,0 +1,131 @@ +#ifndef _directfbrenderer_h_ +#define _directfbrenderer_h_ + +#include +#include +#include + +#include "CEGUIRenderer.h" +#include "CEGUIColourRect.h" +#include "CEGUIRect.h" + + +namespace CEGUI +{ + class SoftTexture; + class ImageCodec; + + class SoftRenderer : public Renderer + { + public: + SoftRenderer(uint8_t* surface, uint width, uint height, uint stride, + ImageCodec* codec = NULL); + virtual ~SoftRenderer(); + + void reset_surface(uint8_t* surface, uint width, uint height, uint stride); + + virtual void addQuad(const Rect& dest_rect, float z, const Texture* tex, + const Rect& texture_rect, const ColourRect& colours, + QuadSplitMode quad_split_mode); + virtual void doRender(); + virtual void clearRenderList(); + virtual void setQueueingEnabled(bool setting); + virtual bool isQueueingEnabled() const; + + virtual Texture* createTexture(); + virtual Texture* createTexture(const String& filename, + const String& resourceGroup); + virtual Texture* createTexture(float size); + virtual void destroyTexture(Texture* texture); + virtual void destroyAllTextures(); + virtual uint getMaxTextureSize() const; + + virtual float getWidth() const; + virtual float getHeight() const; + virtual Size getSize() const; + virtual Rect getRect() const; + + virtual uint getHorzScreenDPI() const; + virtual uint getVertScreenDPI() const; + + ImageCodec* getImageCodec() { return _image_codec;} + + private: + void setupImageCodec(); + void cleanupImageCodec(); + struct QuadInfo; + void renderQuad(const QuadInfo& quad); + void renderQuadWithColourRect(const QuadInfo& quad); + + class ColourI { + public: + + bool isSameColour(const ColourI& other) const + { + return other.r == r && other.g == g && other.b == b && other.a == a; + } + + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + }; + + static inline void setRGB(ColourI& dest, const colour& src); + static inline void componnentAtPoint(int x_pos, int y_pos, + int top_left, int top_right, + int bottom_left, int bottom_right, + uint64_t& comp); + + struct ColourIRect { + ColourI top_left; + ColourI top_right; + ColourI bottom_left; + ColourI bottom_right; + }; + + static void colourAtPoint(int x, int x_max, int y, int y_max, + const ColourIRect& colours, + uint64_t& r, uint64_t& g, + uint64_t& b, uint64_t& a); + + private: + uint8_t* _surface; + int _width; + int _height; + ImageCodec* _image_codec; + DynamicModule* _image_codec_module; + void (*_destroy_image_codec)(ImageCodec*); + bool _queueing; + + struct RectI { + int left; + int top; + int right; + int bottom; + }; + + struct QuadInfo { + RectI dest; + const SoftTexture* tex; + RectI tex_src; + ColourIRect colors; + float z; + + bool operator < (const QuadInfo& other) const + { + return z > other.z; + } + }; + + typedef std::multiset QuadQueue; + QuadQueue _queue; + + typedef std::list TexturesList; + TexturesList _textures; + }; +} + +#endif + + diff --git a/client/gui/softtexture.cpp b/client/gui/softtexture.cpp new file mode 100644 index 00000000..562edeab --- /dev/null +++ b/client/gui/softtexture.cpp @@ -0,0 +1,124 @@ +#include "common.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#include "softtexture.h" +#include "softrenderer.h" + +#include "CEGUIImageCodec.h" +#include "CEGUISystem.h" +#include "CEGUIExceptions.h" + +namespace CEGUI +{ + + +SoftTexture::SoftTexture(Renderer* owner) + : Texture (owner) + , _surf (NULL) + , _width (0) + , _height (0) +{ + +} + +SoftTexture::SoftTexture(Renderer* owner, uint size) + : Texture (owner) + , _surf (new uint32[size * size]) + , _width (size) + , _height (size) +{ + +} + +SoftTexture::SoftTexture(Renderer* owner, const String& filename, + const String& resourceGroup) + : Texture (owner) + , _surf (NULL) + , _width (0) + , _height (0) +{ + loadFromFile(filename, resourceGroup); +} + + +SoftTexture::~SoftTexture() +{ + freeSurf(); +} + +void SoftTexture::freeSurf() +{ + _width = _height = 0; + delete[] _surf; + _surf = NULL; +} + +void SoftTexture::loadFromFile(const String& filename, const String& resourceGroup) +{ + freeSurf(); + SoftRenderer* renderer = static_cast(getRenderer()); + RawDataContainer texture_file; + ResourceProvider* resource_provider = System::getSingleton().getResourceProvider(); + resource_provider->loadRawDataContainer(filename, texture_file, resourceGroup); + ImageCodec *codec = renderer->getImageCodec(); + Texture* res = codec->load(texture_file, this); + resource_provider->unloadRawDataContainer(texture_file); + if (!res) { + throw RendererException("load from file failed"); + } +} + +void SoftTexture::loadFromMemory(const void* buffPtr, uint buffWidth, + uint buffHeight, + PixelFormat pixelFormat) +{ + freeSurf(); + _surf = new uint32[buffWidth * buffHeight]; + _width = buffWidth; + _height = buffHeight; + + switch (pixelFormat) { + case PF_RGBA: { + const uint32_t *src = static_cast(buffPtr); + uint32* line = _surf; + uint32* end_line = _surf + _width * _height; + for (int i = 0; line != end_line; line += _width, i++) { + uint32* pixel = line; + uint32* end_pixel = pixel + _width; + for (; pixel != end_pixel; pixel++, src++) { + ((uint8_t*)pixel)[0] = ((uint8_t*)src)[2]; + ((uint8_t*)pixel)[1] = ((uint8_t*)src)[1]; + ((uint8_t*)pixel)[2] = ((uint8_t*)src)[0]; + ((uint8_t*)pixel)[3] = ((uint8_t*)src)[3]; + } + } + break; + } + case PF_RGB: { + const uint8_t *src = static_cast(buffPtr); + uint32* line = _surf; + uint32* end_line = _surf + _width * _height; + for (int i = 0; line != end_line; line += _width, i++) { + uint8* pixel = (uint8*)line; + uint8* end_pixel = (uint8*)(line + _width); + for (; pixel != end_pixel; pixel += 4, src += 3) { + pixel[2] = src[0]; + pixel[1] = src[1]; + pixel[0] = src[2]; + pixel[3] = 0xff; + } + } + break; + } + default: + throw RendererException("invalid pixel format"); + } +} + + +} + diff --git a/client/gui/softtexture.h b/client/gui/softtexture.h new file mode 100644 index 00000000..37617f29 --- /dev/null +++ b/client/gui/softtexture.h @@ -0,0 +1,40 @@ + +#ifndef _softtexture_h_ +#define _softtexture_h_ + +#include +#include "CEGUIBase.h" +#include "CEGUITexture.h" + +namespace CEGUI +{ + class SoftTexture : public Texture + { + public: + SoftTexture(Renderer* owner); + SoftTexture(Renderer* owner, uint size); + SoftTexture(Renderer* owner, const String& filename, + const String& resourceGroup); + virtual ~SoftTexture(); + + virtual ushort getWidth(void) const { return _width;} + virtual ushort getHeight(void) const { return _height;} + + virtual void loadFromFile(const String& filename, const String& resourceGroup); + virtual void loadFromMemory(const void* buffPtr, uint buffWidth, uint buffHeight, + PixelFormat pixelFormat); + + private: + void freeSurf(); + + private: + uint32_t* _surf; + ushort _width; + ushort _height; + + friend class SoftRenderer; + }; +} + +#endif + diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj index 302d3912..2741ae57 100644 --- a/client/windows/redc.vcproj +++ b/client/windows/redc.vcproj @@ -41,8 +41,8 @@ + + + + @@ -572,6 +580,14 @@ RelativePath="..\shared_cache.hpp" > + + + + diff --git a/client/x11/Makefile.am b/client/x11/Makefile.am index 99f0c26a..072548db 100644 --- a/client/x11/Makefile.am +++ b/client/x11/Makefile.am @@ -22,6 +22,7 @@ INCLUDES = \ $(CELT051_CFLAGS) \ $(SSL_CFLAGS) \ $(XRANDR_CFLAGS) \ + $(CEGUI_CFLAGS) \ $(WARN_CFLAGS) \ $(NULL) @@ -101,7 +102,11 @@ RED_COMMON_SRCS = \ $(top_srcdir)/client/tunnel_channel.h \ $(top_srcdir)/client/utils.cpp \ $(top_srcdir)/client/utils.h \ - $(top_srcdir)/client/icon.h \ + $(top_srcdir)/client/icon.h \ + $(top_srcdir)/client/gui/softrenderer.h \ + $(top_srcdir)/client/gui/softrenderer.cpp \ + $(top_srcdir)/client/gui/softtexture.h \ + $(top_srcdir)/client/gui/softtexture.cpp \ $(NULL) bin_PROGRAMS = spicec @@ -141,7 +146,7 @@ spicec_LDFLAGS = \ $(LOG4CPP_LIBS) \ $(CELT051_LIBS) \ $(SSL_LIBS) \ - $(SPICEC_STATIC_LINKAGE_BDYNAMIC) + $(CEGUI_LIBS) spicec_LDADD = \ $(QCAIRO_LIBS) \ @@ -149,5 +154,6 @@ spicec_LDADD = \ $(ALSA_LIBS) \ $(GL_LIBS) \ $(XRANDR_LIBS) \ + $(CEGUI_LIBS) \ -lrt -- cgit