zoukankan      html  css  js  c++  java
  • 游戏开发工具之纹理打包器-3.使用GDI+绘图

    上一次我们实现了把我们要的图片添加到CTreeCtrl控件里去,并显示图片的缩略图,现在开始我们要讲比较重要的部分--绘图区。为了实现能编辑图片的功能,绘图区应该具有如下功能。

    1.  添加删除图片。

    2.  放大缩小绘图区。

    3.  选中一张图片,移动一张图片。

    4.  绘制图片

    5.  给图片添加点击事件

    为了更好的实现这些功能,我模仿了cocos2d的内存管理机制以及节点结构,写了一个静态库VALib,它使用GID+渲染图片,以及实现观察者模式来监听鼠标事件。源码可一从这里下载。当然,你也可以使用cocos2d 来实现绘图区的功能。这里我使用我自己写的VALib 库来实现。

    下面开始上码。

    首先我们需要先继承VALib库里的VASprite类,来写一个符合我们自己需求的Image类

    .h文件

    #pragma once
    #pragma comment(lib, "../debug/valib.lib")
    #include "valib.h"
    #include "SelectHandler.h"
    #include "RectPlacement.h"
    
    US_VA_NS
    class VaImage :
    	public VASprite , public SelectHandler ,public CRectPlacement::TRect
    {
    private:
    	bool m_TouchFlag;
    	bool m_selectFlag;
    	VAPoint* m_lastPoing;
    	
    	void init();
    public:
    	VaImage(const char* m_name);
    	~VaImage(void);
    
    	/************************************************************************/
    	/* 使用一个图片创建一个VASprite
    	/* fileName: 图片路径
    	/************************************************************************/
    	static VaImage* FromFile(const WCHAR* filename);
    	bool intersectPoint(VAPoint* pt);
    	/************************************************************************/
    	/* 重写registerTouchDispatcher函数,使图片吞并touch事件,图片下方的图片不响应touch事件                                                                     */
    	/************************************************************************/
    	virtual void registerTouchDispatcher();
    	virtual bool vaTouchBegan(VATouch* m_pTouch, VAEvent* m_pEvent);
    	virtual void vaTouchMoved(VATouch* m_pTouch, VAEvent* m_pEvent);
    	virtual void vaTouchEnded(VATouch* m_pTouch, VAEvent* m_pEvent);
    	virtual void vaTouchCancelled(VATouch* m_pTouch, VAEvent* m_pEvent);
    	virtual bool select(CPoint* pt);
    	virtual void unselect();
    	virtual void draw();
    };
    

    .cpp文件

    #include "StdAfx.h"
    #include "VaImage.h"
    #include <regex>
    
    US_VA_NS
    
    VaImage::VaImage(const char* m_name):VASprite(m_name)
    , m_TouchFlag(false)
    , m_selectFlag(false)
    , m_lastPoing(NULL)
    {
    	init();
    }
    
    VaImage::~VaImage(void)
    {
    }
    
    VaImage* VaImage::FromFile( const WCHAR* filename )
    {
    	Bitmap* bitmap = Bitmap::FromFile( filename );
    	//截取文件名
    	CString tempName = filename;
    	int m_index = tempName.Find(L"\");
    	while ( m_index!=-1 )
    	{
    		tempName = tempName.Right(tempName.GetLength()-(m_index+1));
    		m_index = tempName.Find(L"\");
    	}
    
    	USES_CONVERSION;
    	const char *name = W2A(tempName.GetBuffer(tempName.GetLength()));//LPSTR)(LPCTSTR)tempName;
    	//新建VAImage并贴上图片
    	VaImage* vaImage = new VaImage(name);
    	vaImage->setBitmap(bitmap);
    	return vaImage;
    }
    
    void VaImage::init()
    {
    	registryDispatch();
    }
    
    bool VaImage::intersectPoint( VAPoint* pt )
    {
    	VARect rect  = getRect();
    	VAPoint m_pt = VAPoint(pt->x, pt->y);
    	return rect.containsPoint(m_pt);
    }
    
    void VaImage::registerTouchDispatcher()
    {
    	registerWithTouchDispatcher(NULL, true);
    }
    
    bool VaImage::vaTouchBegan( VATouch* m_pTouch, VAEvent* m_pEvent )
    {
    	VAPoint* pt = new VAPoint(*(m_pTouch->getLocation()));
    	if(intersectPoint(pt)){
    		m_TouchFlag = true;
    		if(m_lastPoing != NULL){
    			//setPosition(new VAPoint( getPosition()->x + (pt->x - m_lastPoing->x), getPosition()->y + (pt->y - m_lastPoing->y) ));
    		}
    		m_lastPoing = pt;
    		pt->release();
    		return true;
    	}
    	pt->release();
    	return false;
    }
    
    void VaImage::vaTouchMoved( VATouch* m_pTouch, VAEvent* m_pEvent )
    {
    	if(m_TouchFlag){
    		VAPoint* pt = new VAPoint(*(m_pTouch->getLocation()));
    		VAPoint tempPT = VAPoint( getPosition().x + (pt->x - m_lastPoing->x), getPosition().y + (pt->y - m_lastPoing->y) );
    		setPosition(tempPT);
    		m_lastPoing = pt;
    		tempPT.release();
    		pt->release();
    	}
    }
    
    void VaImage::vaTouchEnded( VATouch* m_pTouch, VAEvent* m_pEvent )
    {
    	m_TouchFlag = false;
    }
    
    void VaImage::vaTouchCancelled( VATouch* m_pTouch, VAEvent* m_pEvent )
    {
    
    }
    
    bool VaImage::select( CPoint* pt )
    {
    	VAPoint m_pt = VAPoint(pt->x, pt->y);
    	if(intersectPoint(&m_pt)){
    		m_selectFlag = true;
    		m_pt.release();
    		return true;
    	}
    	m_pt.release();
    	unselect();
    	return false;
    }
    
    void VaImage::unselect()
    {
    	m_selectFlag = false;
    }
    
    void VaImage::draw()
    {
    	VASprite::draw();
    	//绘制边框
    	if(m_selectFlag){
    		VADirector* director = VADirector::sharedDirector();
    
    		vertex vertex = cloneVertex();
    		int minX = min(min(min(vertex.leftTop.X, vertex.rightTop.X), vertex.rightBottom.X), vertex.leftBottmo.X);
    		int minY = min(min(min(vertex.leftTop.Y, vertex.rightTop.Y), vertex.rightBottom.Y), vertex.leftBottmo.Y);
    		int maxX = max(max(max(vertex.leftTop.X, vertex.rightTop.X), vertex.rightBottom.X), vertex.leftBottmo.X);
    		int maxY = max(max(max(vertex.leftTop.Y, vertex.rightTop.Y), vertex.rightBottom.Y), vertex.leftBottmo.Y);
    
    		VARect rect  = getRect();
    		Gdiplus::Rect r(rect.getMinX(), rect.getMinY(), rect.getMaxX()-rect.getMinX(), rect.getMaxY()-rect.getMinY());
    		
    		director->DrawBorder(&r);
    	}
    }
    


    完后我们需要继承CWnd来创建一个自定义组件ImageView

    .h文件

    #pragma once
    #include "valib.h"
    #pragma comment(lib, "../debug/valib.lib")
    #include "stdafx.h"
    #include "ImgsTool.h"
    #include "VaImage.h"
    
    // ImageView
    US_VA_NS//使用valib命名空间
    
    typedef std::vector<VaImage*> VaImageArray;
    class ImageView : public CWnd
    {
    	DECLARE_DYNAMIC(ImageView)
    private:
    
    	VADirector* m_vaDirector;
    	VATouchDispatcher* m_vaTouchDispatcher;
    	SelectDispatcher* m_pSelectDispatcher;
    	
    	Bitmap* m_canva;
    	Bitmap* m_bgImg;
    	float m_scale;
    	
    	VaImageArray imgList;
    	float m_tagArrange;
    	bool m_drawTage;
    public:
    	VAScene* m_scene;
    	ImageView();
    	virtual ~ImageView();
    
    	void saveImg(CString filePath, CString type, Bitmap* bitmap = NULL);
    	void savePlis(CString filePath, CString ImageType);
    	void addImage(const WCHAR* filename);
    	void setAutoArrange(float isArrange);
    	void autoArrange();
    protected:
    	DECLARE_MESSAGE_MAP()
    	virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
    	
    	void init();
    	void drawBackground();
    	void update();
    	void draw(CDC* pDC);
    
    	int GetEncoderClsid(const WCHAR* format, CLSID *pClsid);
    };
    
    


    .cpp 文件

    // ImageView.cpp : implementation file
    //
    #include "stdafx.h"
    #include "ImgsTool.h"
    #include "ImageView.h"
    #include <algorithm>
    #include "PublishPlist.h"
    
    // ImageView
    US_VA_NS//使用valib命名空间
    IMPLEMENT_DYNAMIC(ImageView, CWnd)
    enum{
    	viewInterval,
    };
    ImageView::ImageView()
    {
    
    }
    
    ImageView::~ImageView()
    {
    }
    
    BEGIN_MESSAGE_MAP(ImageView, CWnd)
    END_MESSAGE_MAP()
    // ImageView message handlers
    
    LRESULT ImageView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    {
    	// TODO: Add your specialized code here and/or call the base class
    	VATouch* pTouch = new VATouch();
    	CPoint pt = (CPoint)lParam;
    	pTouch->setTouchInfo((float)pt.x, (float)pt.y);
    	switch (message)
    	{
    	case WM_CREATE:
    		init();
    		break;
    	case WM_PAINT:
    		if(m_drawTage){
    			update();
    		}
    		break;
    	case WM_TIMER:
    		Invalidate(FALSE);
    		break;
    	case WM_LBUTTONDOWN:
    		m_pSelectDispatcher->callAllHandler(&pt);
    		m_vaTouchDispatcher->touchesBegan(pTouch, NULL);
    		break;
    	case WM_MOUSEMOVE:
    		m_vaTouchDispatcher->touchesMoved(pTouch, NULL);
    		break;
    	case WM_LBUTTONUP:
    		m_vaTouchDispatcher->touchesEnded(pTouch, NULL);
    		break;
    // 	case WM_COMMAND://接收控件发送来的消息的
    // 		break;
    	}
    	return CWnd::WindowProc(message, wParam, lParam);
    }
    
    void ImageView::init()
    {
    	m_tagArrange = true;
    	CRect rect;
    	this->GetClientRect(rect);
    	m_bgImg = new Bitmap(rect.Width(), rect.Height());
    	drawBackground();//绘制背景
    	m_canva = new Bitmap(rect.Width(), rect. Height());//创建画布
    
    	m_pSelectDispatcher = ToolsCenter::getInstance()->getSelectDispatcher();
    
    	m_vaDirector = VADirector::sharedDirector();
    	m_vaDirector->init(this->m_hWnd);
    	m_vaTouchDispatcher = m_vaDirector->getTouchDispatcher();
    	m_scene = new VAScene();
    
    	SetTimer(viewInterval, 5, NULL);
    	Invalidate(FALSE);
    }
    
    void ImageView::drawBackground()
    {
    	CRect rect;
    	this->GetClientRect(rect);
    	int size = 20;
    	Graphics* bgG = Graphics::FromImage(m_bgImg);
    	
    	Bitmap* m_bgtexture = new Bitmap(size,size);
    	Graphics* txG = Graphics::FromImage(m_bgtexture);
    	txG->FillRectangle(&SolidBrush(Color(255,255,255)), 0, 0, size, size);
    	txG->FillRectangle(&SolidBrush(Color(192,192,192)), size/2, 0, size/2 , size/2);
    	txG->FillRectangle(&SolidBrush(Color(192,192,192)), 0, size/2, size/2 , size/2);
    	
    	bgG->FillRectangle(&TextureBrush(m_bgtexture), rect.left, rect.top, rect.right, rect.bottom);
    	//saveImg(m_bgImg);
    }
    //更新窗口
    void ImageView::update()
    {
    	CDC* dc = this->GetDC();
    	draw(dc);
    }
    //绘制窗口
    void ImageView::draw(CDC* pDC)
    {
    	CDC MemDC;				//首先定义一个显示设备对象
    	CBitmap MemBitmap;	//定义一个位图对象
    	CRect rect;
    	this->GetClientRect(rect);
    
    	MemDC.CreateCompatibleDC(NULL);//随后建立与屏幕显示兼容的内存显示设备
    	MemBitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()); //建立一个与屏幕显示兼容的位图,至于位图的大小嘛,可以用窗口的大小
    
    	//将位图选入到内存显示设备中
    	//只有选入了位图的内存显示设备才有地方绘图,画到指定的位图上
    	CBitmap *pOldBit=MemDC.SelectObject(&MemBitmap);
    
    	Graphics* memG = Graphics::FromHDC(MemDC);
    	Rect destinationRect(0, 0, rect.Width(), rect.Height());
    	memG->DrawImage(m_bgImg, destinationRect, 0, 0, rect.Width(), rect.Height(), Gdiplus::UnitPixel);
    
    	m_canva = new Bitmap(rect.Width(), rect.Height());
    	Graphics* canvaG = Graphics::FromImage(m_canva);
    	//m_scene->update();
    	VADirector::sharedDirector()->initDraw(memG);
     	m_scene->draw();//绘制valib的场景里的各个图片
     	memG->DrawImage(m_canva, destinationRect, 0, 0, rect.Width(), rect.Height(), Gdiplus::UnitPixel);
    
    	delete canvaG;
    	delete m_canva;
    	
    	//绘图后将内存中的图拷贝到屏幕上进行显示
    	pDC->BitBlt(0,0, rect.Width(), rect.Height(), &MemDC,0, 0,SRCCOPY);
    
    	//绘图完成后清理临时对象
    	MemBitmap.DeleteObject();
    	delete memG;
    	MemDC.DeleteDC();
    	ReleaseDC(pDC);
    }
    
    void ImageView::saveImg(CString filePath, CString type,  Bitmap* bitmap /*= NULL*/)
    {
    	//m_drawTage = false;
    	CRect rect;
    	this->GetClientRect(rect);
    	Gdiplus::Bitmap* _canva = new Bitmap(rect.Width(), rect.Height());
    	Gdiplus::Graphics* canvaG = Gdiplus::Graphics::FromImage(_canva);
    	Rect destinationRect(10, 0, rect.Width(), rect.Height());	
    
    	VADirector::sharedDirector()->initDraw(canvaG);
    	m_scene->draw();
    
    	Bitmap* _bitmap;
    	if(!bitmap)
    		_bitmap = _canva;
    	else
    		_bitmap = bitmap;
    	CLSID encoderClsid;
    	this->GetParent();
    	CString t = type.Right(type.GetLength()-1);
    	if(t == "jpg") t = "jpeg";
    	GetEncoderClsid(L"image/" + t, &encoderClsid);
    	_bitmap->Save(filePath+type, &encoderClsid, NULL);
    }
    
    void ImageView::addImage(const WCHAR* filename){
    	VaImage* img = VaImage::FromFile(filename);
    	m_scene->addChild(img);
    	imgList.push_back(img);
    
    	if(m_tagArrange){
    		autoArrange();
    	}
    }
    
    void ImageView::savePlis( CString filePath, CString ImageType)
    {
    	filePath += ".plist";
    	const wchar_t* ffd = filePath.GetBuffer(filePath.GetLength());
    	USES_CONVERSION;
    	const char* file = W2A(ffd);
    	const char* _type = W2A(ImageType.GetBuffer(ImageType.GetLength()));
    	PublishPlist* plist = new PublishPlist(file,_type, "100, 100");
    	for(int i = 0; i< (int)imgList.size(); i++){
    		VaImage* img = imgList.at(i);
    		plist->addItem( img->getName(), int(img->getPosition().x), int(img->getPosition().y), int(img->getSize().width), int(img->getSize().height) );
    	}
    	plist->publish();
    }
    
    void ImageView::setAutoArrange( float isArrange )
    {
    	m_tagArrange = isArrange;
    }
    
    void ImageView::autoArrange(){
    	//排序,由大小
    	std::sort(imgList.begin(), imgList.end(), CRectPlacement::TRect::Greaters);
    	CRectPlacement crp = CRectPlacement(imgList.front()->getSize().width, imgList.front()->getSize().height);
    	for(int i = 0; i< (int)imgList.size(); i++){
    		CRectPlacement::TRect r(0, 0, imgList.at(i)->getSize().width, imgList.at(i)->getSize().height);
    		bool bPlaced = false;
    		bPlaced = crp.AddAtEmptySpotAutoGrow(&r, 100000, 100000);
    		imgList.at(i)->setPosition(VAPoint(r.x, r.y));
    	}
    }
    
    /*获取Image编码
    * format: image/png, image/jpeg, image/gif
    * pClsid: CLSID
    */
    int ImageView::GetEncoderClsid( const WCHAR* format, CLSID *pClsid )
    {
    	UINT num = 0;	//number of image encoder;
    	UINT size = 0;	//size of the image encoder array in bytes;
    	ImageCodecInfo *pImageCodecInfo = NULL;
    	GetImageEncodersSize(&num, &size);
    	if(size ==0)
    		return -1;	//Failure
    	pImageCodecInfo = (ImageCodecInfo *)(malloc(size));
    	if(pImageCodecInfo==NULL)
    		return -1;
    	GetImageEncoders(num, size, pImageCodecInfo);
    	for(UINT j=0; j< num; ++j){
    		if(wcscmp(pImageCodecInfo[j].MimeType, format)==0){
    			*pClsid = pImageCodecInfo[j].Clsid;
    			free(pImageCodecInfo);
    			return j;
    		}
    	}
    	free(pImageCodecInfo);
    	return -1;
    }
    


    这样我们就可以正常显示我们的图片了!

    工具的完整代码可以从这里下载


  • 相关阅读:
    ConcurrentSkipListMap 源码分析
    ConcurrentHashMap 源码分析
    CopyOnWriteArrayList 源码分析
    AtomicBoolean 源码分析
    commons-lang3-3.4.jar
    Effective Java
    FindBugs Bug Descriptions
    EasyMock
    Apache Maven 入门
    Eclipse
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3249251.html
Copyright © 2011-2022 走看看