diff --git a/inc/hgl/2d/Bitmap.h b/inc/hgl/2d/Bitmap.h index 7161131..d54232e 100644 --- a/inc/hgl/2d/Bitmap.h +++ b/inc/hgl/2d/Bitmap.h @@ -1,13 +1,133 @@ #ifndef HGL_2D_BITMAP_INCLUDE #define HGL_2D_BITMAP_INCLUDE +#include +#include +#include +#include namespace hgl { - /** - * 简单的2D象素处理 - */ - template class Bitmap2D + namespace bitmap { - };// + template + static void FillPixels(T *p,const T &color,const int length) + { + std::fill_n(p,length,color); + } + + /** + * 简单的2D象素处理 + */ + template class Bitmap + { + int width,height; + + T *data; + + public: + + Bitmap() + { + data=nullptr; + width=height=0; + } + + ~Bitmap() + { + delete[] data; + } + + const uint GetChannels ()const{return C;} + const uint GetChannelBits ()const{return (sizeof(T)/C)<<3;} + + const int GetWidth ()const{return width;} + const int GetHeight ()const{return height;} + const uint GetTotalPixels ()const{return width*height;} + const uint GetLineBytes ()const{return width*sizeof(T);} + const uint GetTotalBytes ()const{return width*height*sizeof(T);} + + T *GetData(){return data;} + T *GetData(int x,int y) + { + return (x<0||x>=width||y<0||y>=height)?nullptr:data+(y*width+x); + } + + const T *GetData()const{return data;} + const T *GetData(int x,int y)const + { + return (x<0||x>=width||y<0||y>=height)?nullptr:data+(y*width+x); + } + + bool Create(uint w,uint h) + { + if(!w||!h)return(false); + + if(data) + { + if(width==w&&height==h)return(true); + } + + width=w; + height=h; + + delete[] data; + + data=new T[width*height]; + + return(true); + } + + void Clear() + { + if(data) + { + delete[] data; + data=nullptr; + } + + width=height=0; + } + + void ClearColor(const T &color) + { + if(!data)return; + + FillPixels(data,color,width*height); + } + + void Flip() + { + if(!data||height<=1)return; + + const uint line_bytes=width*sizeof(T); + + T *temp=new T[width]; + + T *top=data; + T *bottom=data+(width*(height-1)); + + while(top class Bitmap + + using BitmapGrey8=Bitmap; + using BitmapRG8=Bitmap; + using BitmapRGB8=Bitmap; + using BitmapRGBA8=Bitmap; + + using BitmapU16=Bitmap; + using BitmapU32=Bitmap; + }//namespace bitmap }//namespace hgl #endif//HGL_2D_BITMAP_INCLUDE + diff --git a/inc/hgl/2d/BitmapLoad.h b/inc/hgl/2d/BitmapLoad.h new file mode 100644 index 0000000..dc8eb31 --- /dev/null +++ b/inc/hgl/2d/BitmapLoad.h @@ -0,0 +1,90 @@ +#pragma once +#include +#include + +namespace hgl +{ + namespace bitmap + { + struct BitmapLoader + { + virtual const uint OnChannels()const=0; + virtual const uint OnChannelBits()const=0; + + const uint OnPixelBits()const + { + return OnChannelBits()*OnChannels(); + } + + virtual void *OnRecvBitmap(uint w,uint h)=0; + + virtual void OnLoadFailed()=0; + virtual void OnFlip()=0; + }; + + template struct BitmapLoaderImpl:public BitmapLoader + { + T *bmp; + + public: + + BitmapLoaderImpl() + { + bmp=nullptr; + } + + const uint OnChannels()const override{return bmp->GetChannels();} + const uint OnChannelBits()const override{return bmp->GetChannelBits();} + + void *OnRecvBitmap(uint w,uint h) override + { + if(!bmp) + bmp=new T; + + bmp->Create(w,h); + return bmp->GetData(); + } + + void OnLoadFailed() override + { + SAFE_CLEAR(bmp); + } + + void OnFlip() override + { + if(bmp) + bmp->Flip(); + } + }; + + bool LoadBitmapFromTGAStream(io::InputStream *,BitmapLoader *); + + template + inline T *LoadBitmapFromTGA(io::InputStream *is) + { + BitmapLoaderImpl bli; + + if(LoadBitmapFromTGAStream(is,&bli)) + return bli.bmp; + + return(nullptr); + } + + inline BitmapRGB8 *LoadBitmapRGB8FromTGA(io::InputStream *is){return LoadBitmapFromTGA(is);} + inline BitmapRGBA8 *LoadBitmapRGBA8FromTGA(io::InputStream *is){return LoadBitmapFromTGA(is);} + + template + inline T *LoadBitmapFromTGA(const OSString &filename) + { + io::OpenFileInputStream fis(filename); + + if(!fis) + return(false); + + return LoadBitmapFromTGA(&fis); + } + + inline BitmapRGB8 *LoadBitmapRGB8FromTGA(const OSString &filename){return LoadBitmapFromTGA(filename);} + inline BitmapRGBA8 *LoadBitmapRGBA8FromTGA(const OSString &filename){return LoadBitmapFromTGA(filename);} + }//namespace bitmap +}//namespace hgl \ No newline at end of file diff --git a/inc/hgl/2d/BitmapSave.h b/inc/hgl/2d/BitmapSave.h new file mode 100644 index 0000000..433e46e --- /dev/null +++ b/inc/hgl/2d/BitmapSave.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include + +namespace hgl +{ + namespace bitmap + { + bool SaveBitmapToTGA(io::OutputStream *os,void *data,uint width,uint height,uint channels,uint single_channel_bits); + + template + inline bool SaveBitmapToTGA(io::OutputStream *os,const T *bmp) + { + if(!os||!bmp)return(false); + + return SaveBitmapToTGA(os,(void *)(bmp->GetData()),bmp->GetWidth(),bmp->GetHeight(),bmp->GetChannels(),bmp->GetChannelBits()); + } + + template + inline bool SaveBitmapToTGA(const OSString &filename,T *bmp) + { + if(filename.IsEmpty()||!bmp) + return(false); + + io::OpenFileOutputStream fos(filename,io::FileOpenMode::CreateTrunc); + + if(!fos) + return(false); + + return SaveBitmapToTGA(fos,bmp); + } + }//namespace bitmap +}//namespace hgl \ No newline at end of file diff --git a/inc/hgl/2d/Blend.h b/inc/hgl/2d/Blend.h new file mode 100644 index 0000000..f805e89 --- /dev/null +++ b/inc/hgl/2d/Blend.h @@ -0,0 +1,106 @@ +#pragma once + +#include +#include + +namespace hgl +{ + namespace bitmap + { + template struct BlendColor + { + virtual const T operator()(const T &src,const T &)const + { + return src; + } + + virtual const T operator()(const T &src,const T &,const float &)const + { + return src; + } + };//template struct BlendColor + + /** + * 位图混合处理模板 + */ + template class BlendBitmap + { + public: + + void operator ()(const ST *src,DT *dst,const float alpha)const; + };//template class BlendBitmap + + struct BlendColorU32Additive:public bitmap::BlendColor + { + const uint32 operator()(const uint32 &src,const uint32 &dst)const + { + uint64 result=src+dst; + + return (result>HGL_U32_MAX)?HGL_U32_MAX:(result&HGL_U32_MAX); + } + + const uint32 operator()(const uint32 &src,const uint32 &dst,const float &alpha)const + { + uint64 result=src*alpha+dst; + + return (result>HGL_U32_MAX)?HGL_U32_MAX:(result&HGL_U32_MAX); + } + }; + + struct BlendColorRGBA8:public bitmap::BlendColor + { + const Vector4u8 operator()(const Vector4u8 &src,const Vector4u8 &dst)const + { + uint8 na=255-src.a; + + return Vector4u8((src.r*src.a+dst.r*na)/255, + (src.g*src.a+dst.g*na)/255, + (src.b*src.a+dst.b*na)/255, + dst.a); + } + + const Vector4u8 operator()(const Vector4u8 &src,const Vector4u8 &dst,const float &alpha)const + { + uint8 a=src.a*alpha; + uint8 na=255-src.a; + + return Vector4u8((src.r*src.a+dst.r*na)/255, + (src.g*src.a+dst.g*na)/255, + (src.b*src.a+dst.b*na)/255, + dst.a); + } + }; + + template<> void bitmap::BlendBitmap::operator()(const BitmapRGBA8 *src_bitmap,BitmapRGB8 *dst_bitmap,const float alpha)const + { + if(!src_bitmap||!dst_bitmap||alpha<=0)return; + + const uint width=src_bitmap->GetWidth(); + const uint height=src_bitmap->GetHeight(); + + if(width!=dst_bitmap->GetWidth()||height!=dst_bitmap->GetHeight()) + return; + + Vector3u8 *dst=dst_bitmap->GetData(); + const Vector4u8 *src=src_bitmap->GetData(); + + float a; + float na; + + for(uint i=0;ia*alpha; + na=255-src->a; + + dst->r=(src->r*a+dst->r*na)/255; + dst->g=(src->g*a+dst->g*na)/255; + dst->b=(src->b*a+dst->b*na)/255; + + ++dst; + ++src; + } + } + + using BlendBitmapRGBA8toRGB8=bitmap::BlendBitmap; + }//namespace bitmap +}//namespace hgl diff --git a/inc/hgl/2d/DrawGeometry.h b/inc/hgl/2d/DrawGeometry.h new file mode 100644 index 0000000..9899593 --- /dev/null +++ b/inc/hgl/2d/DrawGeometry.h @@ -0,0 +1,480 @@ +#pragma once + +#include +#include +#include + +namespace hgl +{ + namespace bitmap + { + template class DrawGeometry + { + protected: + + FormatBitmap *bitmap; + + T draw_color; + float alpha; + + BlendColor no_blend; + BlendColor *blend; + + public: + + DrawGeometry(FormatBitmap *fb) + { + bitmap=fb; + hgl_zero(draw_color); + alpha=1; + blend=&no_blend; + } + + virtual ~DrawGeometry()=default; + + virtual void SetDrawColor(const T &color) + { + draw_color=color; + } + + void SetBlend(BlendColor *bc) + { + blend=bc; + } + + void CloseBlend() + { + blend=&no_blend; + } + + void SetAlpha(const float &a) + { + alpha=a; + } + + bool GetPixel(int x,int y,T &color) + { + if(!data)return(false); + + T *p=GetData(x,y); + + if(!p)return(false); + + color=*p; + + return(true); + } + + bool PutPixel(int x,int y) + { + if(!bitmap)return(false); + + T *p=bitmap->GetData(x,y); + + if(!p)return(false); + + *p=(*blend)(draw_color,*p,alpha); + + return(true); + } + + bool DrawHLine(int x,int y,int length) + { + if(!bitmap)return(false); + + const int width=bitmap->GetWidth(); + const int height=bitmap->GetHeight(); + + if(y<0||y>=height)return(false); + if(x>=width)return(false); + if(x<0){length+=x;x=0;} + if(x+length>width)length=width-x; + + if(length<=0)return(false); + + T *p=bitmap->GetData(x,y); + + for(int i=0;iGetWidth(); + const int height=bitmap->GetHeight(); + + if(l>=width||t>=height)return(false); + + if(l<0){w+=l;l=0;} + if(t<0){h+=t;t=0;} + + if(l+w>width)w=width-l; + if(t+h>height)h=height-t; + + if(w<=0||h<=0)return(false); + + T *p=bitmap->GetData(x,y); + + for(int y=t;yGetWidth(); + const int height=bitmap->GetHeight(); + + if(x<0||x>=width)return(false); + if(y>=height)return(false); + if(y<0){length+=y;y=0;} + if(y+length>height)length=height-y; + + if(length<=0)return(false); + + T *p=bitmap->GetData(x,y); + + for(int i=0;i=0) + { + tn+=(6+((x-y)<<2)); + y--; + } + else + tn+=((x<<2)+2); + + PutPixel(x0+y,y0+x); + PutPixel(x0+x,y0+y); + PutPixel(x0-x,y0+y); + PutPixel(x0-y,y0+x); + PutPixel(x0-y,y0-x); + PutPixel(x0-x,y0-y); + PutPixel(x0+x,y0-y); + PutPixel(x0+y,y0-x); + + x++; + } + + PutPixel(x0+y,y0+x); + PutPixel(x0+x,y0+y); + PutPixel(x0-x,y0+y); + PutPixel(x0-y,y0+x); + PutPixel(x0-y,y0-x); + PutPixel(x0-x,y0-y); + PutPixel(x0+x,y0-y); + PutPixel(x0+y,y0-x); + + return(true); + } + + bool DrawSolidCircle(int x,int y,int radius) + { + if(!bitmap)return(false); + + if(radius<=0)return(false); + + int x0=x-radius; + int y0=y-radius; + int x1=x+radius; + int y1=y+radius; + + const int width=bitmap->GetWidth(); + const int height=bitmap->GetHeight(); + + if(x0<0)x0=0; + if(y0<0)y0=0; + if(x1>=width)x1=width-1; + if(y1>=height)y1=height-1; + + if(x0>x1||y0>y1)return(false); + + int r2=radius*radius; + + for(int cy=y0;cy<=y1;cy++) + { + int dy=cy-y; + int dy2=dy*dy; + + for(int cx=x0;cx<=x1;cx++) + { + int dx=cx-x; + int dx2=dx*dx; + + if(dx2+dy2<=r2) + PutPixel(cx,cy); + } + } + + return(true); + } + + void DrawLine(int x1, int y1, int x2, int y2) + { + int p, n, x, y, tn; + + if(y1==y2) + { + if(x1>x2) + { + x=x2;x2=x1;x1=x; + } + + DrawHLine(x1, y1, x2-x1+1); + return; + } + + if(x1==x2) + { + if(y1>y2) + { + y=y2;y2=y1;y1=y; + } + + DrawVLine(x1, y1, y2-y1+1); + return; + } + + if(abs(y2-y1)<=abs(x2-x1)) + { + if((y2x2)) + { + x=x2;y=y2;x2=x1;y2=y1;x1=x;y1=y; + } + + if(y2>=y1&&x2>=x1) + { + x=x2-x1;y=y2-y1; + p=2*y;n=2*x-2*y;tn=x; + + while(x1<=x2) + { + if(tn>=0)tn-=p; + else { tn+=n;y1++; } + + PutPixel(x1++, y1); + } + } + else + { + x=x2-x1;y=y2-y1; + p=-2*y;n=2*x+2*y;tn=x; + while(x1<=x2) + { + if(tn>=0)tn-=p; + else { tn+=n;y1--; } + + PutPixel(x1++, y1); + } + } + } + else + { + x=x1;x1=y2;y2=x;y=y1;y1=x2;x2=y; + + if((y2x2)) + { + x=x2;y=y2;x2=x1;y2=y1;x1=x;y1=y; + } + + if(y2>=y1&&x2>=x1) + { + x=x2-x1;y=y2-y1;p=2*y;n=2*x-2*y;tn=x; + + while(x1<=x2) + { + if(tn>=0)tn-=p; + else { tn+=n;y1++; } + + PutPixel(y1, x1++); + } + } + else + { + x=x2-x1;y=y2-y1;p=-2*y;n=2*x+2*y;tn=x; + + while(x1<=x2) + { + if(tn>=0)tn-=p; + else { tn+=n;y1--; } + + PutPixel(y1, x1++); + } + } + } + } + + void DrawSector(int x0, int y0, uint r, uint stangle, uint endangle) + { + int i, j; + AutoDeleteArray xy(20); + int bx, ex, bxd, exd, bxf, exf, ben; + int tn, x, y; + int xmax; + + y=r; x=0; + xmax=(int)(r*HGL_SIN_45); + tn=(1-r*2); + + xy[0]=x0+r;xy[1]=y0; + xy[2]=x0; xy[3]=y0-r; + xy[4]=x0; xy[5]=y0-r; + xy[6]=x0-r;xy[7]=y0; + xy[8]=x0-r;xy[9]=y0; + xy[10]=x0; xy[11]=y0+r; + xy[12]=x0; xy[13]=y0+r; + xy[14]=x0+r;xy[15]=y0; + + bx=stangle/45; + ex=endangle/45; + ben=ex-bx-1; + + xy[16]=(int)(r*Lcos(stangle)); + xy[17]=(int)(r*Lsin(stangle)); + xy[18]=(int)(r*Lcos(endangle)); + xy[19]=(int)(r*Lsin(endangle)); + + DrawLine(x0+xy[16], y0-xy[17], x0, y0); + DrawLine(x0+xy[18], y0-xy[19], x0, y0); + + if(bx==1||bx==2||bx==5||bx==6)bxd=abs(xy[16]);else bxd=abs(xy[17]); + if(ex==1||ex==2||ex==5||ex==6)exd=abs(xy[18]);else exd=abs(xy[19]); + if(bx==0||bx==2||bx==4||bx==6)bxf=0; else bxf=1; + if(ex==0||ex==2||ex==4||ex==6)exf=1; else exf=0; + + while(x<=xmax) + { + if(tn>=0) + { + tn+=(6+((x-y)*4)); + y--; + xy[0]--; + xy[3]++; + xy[5]++; + xy[6]++; + xy[8]++; + xy[11]--; + xy[13]--; + xy[14]--; + } + else tn+=((x*4)+2); + + if(stangleendangle) + { + j=(bx+1)*2; + for(i=bx+1;i<8;i++) + { + PutPixel(xy[j], xy[j+1]); + j+=2; + } + j=0; + for(i=0;ibxd)^bxf)PutPixel(xy[i], xy[i+1]);i=ex*2; + if((x>exd)^exf)PutPixel(xy[i], xy[i+1]);x++; + xy[1]--; + xy[2]++; + xy[4]--; + xy[7]--; + xy[9]++; + xy[10]--; + xy[12]++; + xy[15]++; + } + } + + void DrawMonoBitmap(const int left,const int top,const uint8 *data,const int w,const int h) + { + if(!data)return; + + if(left<0||left>=bitmap->GetWidth()-w)return; + if(top<0||top>=bitmap->GetHeight()-h)return; + + const uint8 *sp=data; + uint8 bit; + T *tp=bitmap->GetData(left,top); + + const uint line_wrap=bitmap->GetWidth()-w; + + bit=1<<7; + + for(int row=0;row>=1; + if(bit==0) + { + ++sp; + bit=1<<7; + } + } + + tp+=line_wrap; + } + } + };//template class DrawGeometry + + using DrawGeometryU32=DrawGeometry; + using DrawGeometryRGB8=DrawGeometry; + using DrawGeometryRGBA8=DrawGeometry; + }//namespace bitmap +}//namespace hgl diff --git a/inc/hgl/2d/TGA.h b/inc/hgl/2d/TGA.h new file mode 100644 index 0000000..3a44b88 --- /dev/null +++ b/inc/hgl/2d/TGA.h @@ -0,0 +1,51 @@ +#pragma once + +#include +namespace hgl +{ + namespace imgfmt + { + constexpr const uint TGA_IMAGE_TYPE_COLOR_MAP =1; + constexpr const uint TGA_IMAGE_TYPE_TRUE_COLOR =2; + constexpr const uint TGA_IMAGE_TYPE_GRAYSCALE =3; + + constexpr const uint TGA_DIRECTION_LOWER_LEFT =0; + constexpr const uint TGA_DIRECTION_UPPER_LEFT =1; + +#pragma pack(push,1) + struct TGAHeader + { + uint8 id; + uint8 color_map_type; + uint8 image_type; // 1 colormap image ,2 true-color,3 grayscale + + uint16 color_map_first; + uint16 color_map_length; + uint8 color_map_size; + + uint16 x_origin; + uint16 y_origin; + + uint16 width; + uint16 height; + uint8 bit; + uint8 image_desc; + }; + + union TGAImageDesc + { + uint8 image_desc; + struct + { + uint alpha_depth:4; + uint reserved:1; + uint direction:1; //0 lower-left,1 upper left + }; + }; +#pragma pack(pop) + + constexpr size_t TGAHeaderSize=sizeof(TGAHeader); + + bool FillTGAHeader(TGAHeader *header,const uint16 width,const uint16 height,const uint8 channels,const uint8 single_channel_bits=8); + }//namespace imgfmt +}//namespace hgl diff --git a/src/Bitmap/BitmapTGAStream.cpp b/src/Bitmap/BitmapTGAStream.cpp new file mode 100644 index 0000000..ecdff8c --- /dev/null +++ b/src/Bitmap/BitmapTGAStream.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +namespace hgl +{ + using namespace io; + using namespace imgfmt; + + namespace bitmap + { + bool LoadBitmapFromTGAStream(io::InputStream *is,BitmapLoader *bl) + { + if(!is||!bl)return(false); + + TGAHeader tga_header; + TGAImageDesc tga_desc; + + if(is->Read(&tga_header,TGAHeaderSize)!=TGAHeaderSize) + return(false); + + if(tga_header.image_type!=TGA_IMAGE_TYPE_TRUE_COLOR) + return(false); + + if(tga_header.bit!=bl->OnPixelBits()) + return(false); + + tga_desc.image_desc=tga_header.image_desc; + + void *bmp=bl->OnRecvBitmap(tga_header.width,tga_header.height); + + const uint total_bytes=(tga_header.width*tga_header.height*tga_header.bit)>>3; + + if(is->Read(bmp,total_bytes)!=total_bytes) + { + bl->OnLoadFailed(); + return(false); + } + + if(tga_desc.direction==TGA_DIRECTION_LOWER_LEFT) + bl->OnFlip(); + + return(true); + } + + /** + * TGAʽBitmapݵ + */ + bool SaveBitmapToTGA(io::OutputStream *os,void *data,uint width,uint height,uint channels,uint single_channel_bits) + { + if(!os||!data||width<=0||height<=0||channels<=0||single_channel_bits<=0) + return(false); + + TGAHeader tga_header; + + const uint total_bytes=(width*height*channels*single_channel_bits)>>3; + + FillTGAHeader(&tga_header,width,height,channels,single_channel_bits); + + if(os->Write(&tga_header,TGAHeaderSize)!=TGAHeaderSize) + return(false); + + if(os->Write(data,total_bytes)!=total_bytes) + return(false); + + return(true); + } + }//namespace bitmap +}//namespace hgl diff --git a/src/Bitmap/tga.cpp b/src/Bitmap/tga.cpp new file mode 100644 index 0000000..67c8c9c --- /dev/null +++ b/src/Bitmap/tga.cpp @@ -0,0 +1,45 @@ +#include + +namespace hgl +{ + namespace imgfmt + { + bool FillTGAHeader(TGAHeader *header,const uint16 width,const uint16 height,const uint8 channels,const uint8 single_channel_bits) + { + if(!header)return(false); + if(!width||!height)return(false); + + if(channels!=1 + &&channels!=3 + &&channels!=4)return(false); + + memset(header,0,sizeof(TGAHeader)); + + header->width=width; + header->height=height; + + TGAImageDesc desc; + + desc.image_desc=0; + + if(channels==1) + { + header->image_type=3; + header->bit=single_channel_bits; + } + else + { + header->image_type=2; + header->bit=channels*single_channel_bits; + + if(channels==4) + desc.alpha_depth=single_channel_bits; + } + + desc.direction=TGA_DIRECTION_UPPER_LEFT; + + header->image_desc=desc.image_desc; + return(true); + } + }//namespace imgfmt +}//namespace hgl \ No newline at end of file