File indexing completed on 2024-04-28 05:32:20
0001 /* 0002 this file is part of the oxygen gtk engine 0003 SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "oxygentileset.h" 0009 #include "oxygencairocontext.h" 0010 #include "oxygencairoutils.h" 0011 #include "oxygencolorutils.h" 0012 0013 #include <algorithm> 0014 #include <iostream> 0015 0016 namespace Oxygen 0017 { 0018 0019 //______________________________________________________________ 0020 TileSet::TileSet( void ): 0021 _w1(0), 0022 _h1(0), 0023 _w3(0), 0024 _h3(0) 0025 {} 0026 0027 //______________________________________________________________ 0028 TileSet::TileSet( const Cairo::Surface& surface, int w1, int h1, int w2, int h2 ): 0029 _w1(w1), _h1(h1), _w3(0), _h3(0) 0030 { 0031 0032 int sw(0); 0033 int sh(0); 0034 cairo_surface_get_size( surface, sw, sh ); 0035 0036 // set metrics 0037 _w3 = sw - (w1 + w2); 0038 _h3 = sh - (h1 + h2); 0039 0040 int w = w2; while (w < 32 && w2 > 0) w += w2; 0041 int h = h2; while (h < 32 && h2 > 0) h += h2; 0042 0043 // initialise pixmap array 0044 // top 0045 initSurface( _surfaces, surface, _w1, _h1, 0, 0, _w1, _h1 ); 0046 initSurface( _surfaces, surface, w, _h1, _w1, 0, w2, _h1 ); 0047 initSurface( _surfaces, surface, _w3, _h1, _w1+w2, 0, _w3, _h1 ); 0048 0049 // center 0050 initSurface( _surfaces, surface, _w1, h, 0, _h1, _w1, h2 ); 0051 initSurface( _surfaces, surface, w, h, w1, _h1, w2, h2 ); 0052 initSurface( _surfaces, surface, _w3, h, _w1+w2, _h1, _w3, h2 ); 0053 0054 // bottom 0055 initSurface( _surfaces, surface, _w1, _h3, 0, _h1+h2, _w1, _h3 ); 0056 initSurface( _surfaces, surface, w, _h3, _w1, _h1+h2, w2, _h3 ); 0057 initSurface( _surfaces, surface, _w3, _h3, _w1+w2, _h1+h2, _w3, _h3 ); 0058 0059 if(!isValid()) 0060 std::cerr << "oxygen-gtk: BUG: created tileset looks invalid, expect resource leaks ("<<__FILE__<<":"<<__LINE__<<")\n"; 0061 0062 } 0063 0064 //______________________________________________________________ 0065 TileSet::TileSet( const Cairo::Surface& surface, int w1, int h1, int w3, int h3, int x1, int y1, int w2, int h2): 0066 _w1(w1), _h1(h1), _w3(w3), _h3(h3) 0067 { 0068 0069 int sw(0); 0070 int sh(0); 0071 cairo_surface_get_size( surface, sw, sh ); 0072 0073 // set metrics 0074 int x2 = sw - _w3; 0075 int y2 = sh - _h3; 0076 int w = w2; while (w < 32 && w2 > 0) w += w2; 0077 int h = h2; while (h < 32 && h2 > 0) h += h2; 0078 0079 // initialise surface array 0080 // top 0081 initSurface( _surfaces, surface, _w1, _h1, 0, 0, _w1, _h1 ); 0082 initSurface( _surfaces, surface, w, _h1, x1, 0, w2, _h1 ); 0083 initSurface( _surfaces, surface, _w3, h1, x2, 0, _w3, _h1 ); 0084 0085 // center 0086 initSurface( _surfaces, surface, _w1, h, 0, y1, _w1, h2 ); 0087 initSurface( _surfaces, surface, w, h, x1, y1, w2, h2 ); 0088 initSurface( _surfaces, surface, _w3, h, x2, y1, _w3, h2 ); 0089 0090 // bottom 0091 initSurface( _surfaces, surface, _w1, _h3, 0, y2, _w1, _h3 ); 0092 initSurface( _surfaces, surface, w, _h3, x1, y2, w2, _h3 ); 0093 initSurface( _surfaces, surface, _w3, _h3, x2, y2, _w3, _h3 ); 0094 0095 } 0096 0097 //______________________________________________________________ 0098 TileSet::~TileSet( void ) 0099 {} 0100 0101 //___________________________________________________________ 0102 inline bool bits( unsigned int flags, unsigned int testFlags) 0103 { return (flags & testFlags) == testFlags; } 0104 0105 //______________________________________________________________ 0106 void TileSet::render( cairo_t* context, int x0, int y0, int w, int h, unsigned int t ) const 0107 { 0108 0109 // check initialization 0110 if( _surfaces.size() < 9 ) return; 0111 0112 // calculate pixmaps widths 0113 int wLeft(0); 0114 int wRight(0); 0115 if( _w1+_w3 > 0 ) 0116 { 0117 double wRatio( double( _w1 )/double( _w1 + _w3 ) ); 0118 wLeft = (t&Right) ? std::min( _w1, int(w*wRatio) ):_w1; 0119 wRight = (t&Left) ? std::min( _w3, int(w*(1.0-wRatio)) ):_w3; 0120 } 0121 0122 // calculate pixmap heights 0123 int hTop(0); 0124 int hBottom(0); 0125 if( _h1+_h3 > 0 ) 0126 { 0127 double hRatio( double( _h1 )/double( _h1 + _h3 ) ); 0128 hTop = (t&Bottom) ? std::min( _h1, int(h*hRatio) ):_h1; 0129 hBottom = (t&Top) ? std::min( _h3, int(h*(1.0-hRatio)) ):_h3; 0130 } 0131 0132 // calculate corner locations 0133 w -= wLeft + wRight; 0134 h -= hTop + hBottom; 0135 int x1 = x0 + wLeft; 0136 int x2 = x1 + w; 0137 int y1 = y0 + hTop; 0138 int y2 = y1 + h; 0139 0140 // corners 0141 if( bits(t, Top|Left) ) copySurface( context, x0, y0, _surfaces.at(0), 0, 0, wLeft, hTop, CAIRO_EXTEND_NONE ); 0142 if( bits(t, Top|Right) ) copySurface( context, x2, y0, _surfaces.at(2), _w3-wRight, 0, wRight, hTop, CAIRO_EXTEND_NONE); 0143 if( bits(t, Bottom|Left) ) copySurface( context, x0, y2, _surfaces.at(6), 0, _h3-hBottom, wLeft, hBottom, CAIRO_EXTEND_NONE); 0144 if( bits(t, Bottom|Right) ) copySurface( context, x2, y2, _surfaces.at(8), _w3-wRight, _h3-hBottom, wRight, hBottom, CAIRO_EXTEND_NONE ); 0145 0146 // top and bottom 0147 if( w > 0 ) 0148 { 0149 if( t & Top ) copySurface( context, x1, y0, _surfaces.at(1), 0, 0, w, hTop, CAIRO_EXTEND_REPEAT ); 0150 if( t & Bottom ) copySurface( context, x1, y2, _surfaces.at(7), 0, _h3-hBottom, w, hBottom, CAIRO_EXTEND_REPEAT ); 0151 } 0152 0153 // left and right 0154 if( h > 0 ) 0155 { 0156 if( t & Left ) copySurface( context, x0, y1, _surfaces.at(3), 0, 0, wLeft, h, CAIRO_EXTEND_REPEAT ); 0157 if( t & Right ) copySurface( context, x2, y1, _surfaces.at(5), _w3-wRight, 0, wRight, h, CAIRO_EXTEND_REPEAT ); 0158 } 0159 0160 // center 0161 if ( (t & Center) && h > 0 && w > 0 ) copySurface( context, x1, y1, _surfaces.at(4), 0, 0, w, h, CAIRO_EXTEND_REPEAT ); 0162 0163 } 0164 0165 //______________________________________________________________ 0166 void TileSet::initSurface( SurfaceList& surfaces, const Cairo::Surface &source, int w, int h, int sx, int sy, int sw, int sh ) 0167 { 0168 0169 if( sw <= 0 || sh<= 0 || w <=0 || h <= 0 ) surfaces.push_back( 0L ); 0170 else { 0171 0172 // create new surface 0173 Cairo::Surface dest( cairo_surface_create_similar( source, CAIRO_CONTENT_COLOR_ALPHA, w, h ) ); 0174 Cairo::Context context( dest ); 0175 0176 if( sw == w && sh == h ) { 0177 0178 cairo_set_source_surface( context, source, -sx, -sy ); 0179 cairo_rectangle( context, 0, 0, w, h ); 0180 cairo_fill( context ); 0181 0182 } else { 0183 0184 // Bug 316066 0185 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 4) 0186 Cairo::Surface tile( cairo_surface_create_for_rectangle( source, sx, sy, sw, sh ) ); 0187 #else 0188 Cairo::Surface tile( cairo_surface_create_similar( source, CAIRO_CONTENT_COLOR_ALPHA, sw, sh ) ); 0189 { 0190 Cairo::Context local( tile ); 0191 cairo_set_source_surface( local, source, -sx, -sy ); 0192 cairo_rectangle( local, 0, 0, sw, sh ); 0193 cairo_fill( local ); 0194 } 0195 #endif 0196 0197 cairo_set_source_surface( context, tile, 0, 0 ); 0198 cairo_pattern_set_extend( cairo_get_source( context ), CAIRO_EXTEND_REPEAT ); 0199 cairo_rectangle( context, 0, 0, w, h ); 0200 cairo_fill( context ); 0201 0202 } 0203 0204 surfaces.push_back( dest ); 0205 0206 } 0207 } 0208 0209 //______________________________________________________________ 0210 void TileSet::copySurface( cairo_t* context, int x, int y, const Cairo::Surface& source, int sx, int sy, int sw, int sh, cairo_extend_t extend ) const 0211 { 0212 0213 if( !source ) return; 0214 cairo_translate( context, x, y ); 0215 cairo_rectangle( context, 0, 0, sw, sh ); 0216 0217 cairo_set_source_surface( context, source, -sx, -sy ); 0218 cairo_pattern_set_extend( cairo_get_source( context ), extend ); 0219 cairo_fill( context ); 0220 cairo_translate( context, -x, -y ); 0221 } 0222 0223 }