pixelbuffer.cs

来自「Fireball.CodeEditor is an source code ed」· CS 代码 · 共 1,714 行 · 第 1/4 页

CS
1,714
字号
//  Copyright (C) 2005/2006  Riccardo Marzi <riccardo@dotnetfireball.org>
//	
//	This library is free software; you can redistribute it and/or
//	modify it under the terms of the GNU Lesser General Public
//	License as published by the Free Software Foundation; either
//	version 2.1 of the License, or (at your option) any later version.
//	
//	This library is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//	Lesser General Public License for more details.
//	
//	You should have received a copy of the GNU Lesser General Public
//	License along with this library; if not, write to the Free Software
//	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Fireball.Collections.Generic;



namespace Fireball.Drawing.Drawing2D
{
    public class PixelBuffer : IDisposable
    {
        #region Nested Classes

        public unsafe class PixelIterator
        {
            private int* _pixel;
            private int _startX;
            private int _startY;

            private int _width;
            private int _height;

            private int _startIndex;

            private int _count;

            private int _relativeX;
            private int _relativeY;
            private int _relativeIndex;

            private int _lineOffset;

            internal PixelIterator(int* buffer, int x, int y,int width,int height, int bufferWidth)
            {
                _startIndex = ((bufferWidth * y) + x);

                buffer += _startIndex;

                _pixel = buffer;
                _startX = x;
                _startY = y;
                _width = width;
                _height = height;
                _count = _width * _height;

                _relativeX = 0;
                _relativeY = 0;
                _relativeIndex = 0;

                _lineOffset = bufferWidth - _width;
            }

            public int RelativeX
            {
                get
                {
                    return _relativeX;
                }
            }
            public int RelativeY
            {
                get
                {
                    return _relativeY;
                }
            }
            public int RelativeIndex
            {
                get
                {
                    return _relativeIndex;
                }
            }

            public int CurrentX
            {
                get
                {
                    return _startX + _relativeX;
                }
            }
            public int CurrenY
            {
                get
                {
                    return _startY + _relativeY;
                }
            }
            public int CurrentIndex
            {
                get
                {
                    return _startIndex + _relativeIndex; 
                }
            }

            public int* CurrentPixel
            {
                get
                {
                    return _pixel;
                }
            }

            public bool MoveNext()
            {
                _relativeIndex++;
                if (_relativeIndex < _count)
                {
                    _relativeX++;
                    if (_relativeX == _width)
                    {
                        _relativeX = 0;
                        _relativeY++;
                        _pixel += _lineOffset;
                    }

                    _pixel++;

                    return true;
                }

                return false;
            }
            public void Reset()
            {
                _pixel -= _relativeIndex;

                _relativeX = 0;
                _relativeY = 0;
                _relativeIndex = 0;

            }

            public int GetAlpha()
            {
                return ((*(_pixel)) >> 24) & 0xff;
            }
            public int GetRed()
            {
                return ((*(_pixel)) >> 16) & 0xff;
            }
            public int GetGreen()
            {
                return ((*(_pixel)) >> 8) & 0xff;
            }
            public int GetBlue()
            {
                return (*(_pixel)) & 0xff;
            }
        }

        #endregion

        #region Enums

        public enum FlipMode
        {
            FlipHorizontal = 1,
            FlipVertical = 2,
            FlipBoth = 3
        }
        public enum ResizePivot
        {
            TopLeft=0,
            TopCenter=1,
            TopRight=2,
            MiddleLeft=3,
            MiddleCenter=4,
            MiddleRight=5,
            BottomLeft=6,
            BottomCenter=7,
            BottomRight=8
        }

        #endregion

        #region Fields

        private int[] _buffer;
        private int _width;
        private int _height;
        private int _bytesCount;
        private int _pixelsCount;

        private PixelBufferGraphics _graphics;

        private PixelBufferRenderer _renderer;

        #endregion

        #region Constructors

        private unsafe PixelBuffer(int width, int height, int* buffer)
        {
            Initialize(width, height);
            fixed (int* dest = _buffer)
            {
                CopyBuffer(dest, buffer, _buffer.Length);
            }
        }
        internal unsafe PixelBuffer(int width, int height, int[] buffer)
        {
            Initialize(width, height);

            fixed (int* dest = _buffer)
            {
                fixed (int* src = buffer)
                {
                    CopyBuffer(dest, src, _buffer.Length);
                }
            }
        }
        public PixelBuffer(int width, int height)
        {
            Initialize(width, height);
        }
        public PixelBuffer(Bitmap bmp)
            : this(bmp.Width, bmp.Height)
        {
            CopyBitmapToBuffer(bmp);
        }

        #endregion

        #region Destructors

        ~PixelBuffer()
        {
            this.Dispose();
        }
        public void Dispose()
        {
            _graphics.Dispose();
            _buffer = null;
        }

        #endregion

        #region Initialize

        private unsafe void Initialize(int width, int height)
        {
            _width = width;
            _height = height;

            _pixelsCount = _width * _height;
            _bytesCount = _pixelsCount * 4;

            _buffer = new int[_pixelsCount];

            _renderer = new PixelBufferManagedRenderer(this);

            //_graphics = new PixelBufferGraphics(this);
            _graphics = new PixelBufferManagedGraphics(this);
            
        }

        #endregion

        #region Private Members

        private int BlendColorByAlpha(int backColor, int foreColor)
        {
            int foreBlue = foreColor & 0xff;
            int foreGreen = (foreColor >> 8) & 0xff;
            int foreRed = (foreColor >> 16) & 0xff;
            int foreAlpha = (foreColor >> 24) & 0xff;

            int backBlue = backColor & 0xff;
            int backGreen = (backColor >> 8) & 0xff;
            int backRed = (backColor >> 16) & 0xff;
            int backAlpha = (backColor >> 24) & 0xff;

            int displayAlpha = foreAlpha * foreAlpha / 255 + backAlpha * (255 - foreAlpha) / 255;
            int displayRed = foreRed * foreAlpha / 255 + backRed * (255 - foreAlpha) / 255;
            int displayGreen = foreGreen * foreAlpha / 255 + backGreen * (255 - foreAlpha) / 255;
            int displayBlue = foreBlue * foreAlpha / 255 + backBlue * (255 - foreAlpha) / 255;

            int color = ((displayAlpha << 24) | (displayRed << 16) | (displayGreen << 8) | displayBlue);

            return color;

        }
        private unsafe void BlendBufferColor(int* dest, int color)
        {
            for (int i = 0; i < _pixelsCount; i++)
            {
                int cDest = *((int*)dest);
                *((int*)dest) = BlendColorByAlpha(cDest, color);
                dest++;
            }
        }
        private unsafe void BlendBufferRectBuffer(int* dest, int* src, int x, int y, int width, int height)
        {
            int lineOffset = (_width - width);
            int start = GetPixelBytesIndex(x, y,_width);
            dest += start;

            for (int iy = 0; iy < height; iy++)
            {
                for (int ix = 0; ix < width; ix++)
                {
                    int cDest = *((int*)dest);
                    int cSrc = *((int*)src);
                    *((int*)dest) = BlendColorByAlpha(cDest, cSrc);
                    dest++;
                    src++;
                }
                dest += lineOffset;
            }
        }
        private unsafe void BlendBufferRectBufferOutside(int[] srcBuffer, int x, int y, int width, int height)
        {
            int sx = 0;
            int sy = 0;
            int sw = width;
            int sh = height;

            if (x < 0)
            {
                sx = -x;
                sw += x;
            }
            else if ((x + width) > _width)
            {
                sx = 0;
                sw = _width - x;
            }

            if (y < 0)
            {
                sy = -y;
                sh += y;
            }
            else if ((y + height) > _height)
            {
                sy = 0;
                sh = _height - y;
            }

            if (sw <= 0 || sh <= 0)
            {
                return;
            }

            //TODO: problema con l'indice del pixel di un buffer senza istanza
            //
            //int[] blitBufferArray = new int[sw * sh];
            //fixed (int* src = srcBuffer)
            //{
            //    fixed (int* dest = blitBufferArray)
            //    {
            //        CopyBufferRect(dest, src, sx, sy, sw, sh);
            //    }
            //}
            PixelBuffer srcBufferHelper = new PixelBuffer(width, height, srcBuffer);
            PixelBuffer blitBufferArray = srcBufferHelper.GetSubBuffer(sx, sy, sw, sh);

            int fx = x;
            int fy = y;
            if (x < 0) fx = 0;
            if (y < 0) fy = 0;

            fixed (int* src = blitBufferArray.InternalBuffer)
            {
                fixed (int* dest = _buffer)
                {
                    BlendBufferRectBuffer(dest, src, fx, fy, sw, sh);
                }
            }

            srcBufferHelper.Dispose();
            blitBufferArray.Dispose();
        }
        private unsafe void BlendBufferRectColor(int* dest, int color, int x, int y, int width, int height)
        {
            int lineOffset = (_width - width);
            int start = GetPixelBytesIndex(x, y,_width);
            dest += start;

            for (int iy = 0; iy < height; iy++)
            {
                for (int ix = 0; ix < width; ix++)
                {
                    int cDest = *((int*)dest);
                    *((int*)dest) = BlendColorByAlpha(cDest, color);
                    dest++;
                }
                dest += lineOffset;
            }
        }
        private unsafe void BlendBufferRectColorOutside(int color, int x, int y, int width, int height)
        {
            int sx = x;
            int sy = y;
            int sw = width;
            int sh = height;

            if (x < 0)
            {
                sx = 0;
                sw += x;
            }
            else if ((x + width) > _width)
            {
                sw = _width - x;
            }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?