游戏开发工具之纹理打包器-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;
}
这样我们就可以正常显示我们的图片了!
工具的完整代码可以从这里下载
游戏开发工具之纹理打包器-3.使用GDI+绘图的更多相关文章
- 5 个最好的3D游戏开发工具(转)
转自:http://www.open-open.com/news/view/33a4f0 5 个最好的3D游戏开发工具 jopen 2012-11-19 22:56:21 • 发布 摘要:UDK(th ...
- Unity 4.2.0 官方最新破解版(Unity3D 最新破解版,3D游戏开发工具和游戏引擎套件)
Unity是一款跨平台的游戏开发工具,从一开始就被设计成易于使用的产品.作为一个完全集成的专业级应用,Unity还包含了价值数百万美元的功能强大的游戏引擎.Unity作为一个游戏开发工具,它的设计主旨 ...
- 优秀工具推荐:两款很棒的 HTML5 游戏开发工具
HTML5 众多强大特性让我们不需要多么高深技术就能创建好玩的网页游戏,同时证明了开放的 Web 技术能与任何其他在游戏开发中使用的技术竞争.正如标题所说,这篇文章推荐的几款很棒 HTML5 游戏开发 ...
- Unity3D ——强大的跨平台3D游戏开发工具(六)
第十一章 制作炮台的旋转 大家知道,炮台需要向四周不同的角度发射炮弹,这就需要我们将炮台设置成为会旋转的物体,接下来我们就一起制作一个会旋转的炮台. 第一步:给炮台的炮筒添加旋转函数. 给炮台的炮筒部 ...
- Unity3D ——强大的跨平台3D游戏开发工具(一)
众所周知,Unity3D是一个能够实现轻松创作的多平台的游戏开发工具,是一个全面整合的专业游戏引擎.在现有的版本中,其强大的游戏制作功能已 经达到让人瞠目结舌的地步.尤其是它在3.0版本里面制作的那款 ...
- 强大的游戏开发工具Unity3D推出2D开发工具,unity将混合3D与2D开发
2013 Unity全球开发者大会(Unite 2013)于2013年8月28日在温哥华隆重开幕,会上Unity全球CEO David Helgason在Keynote上宣布Unity 4.3版本即将 ...
- python+pygame游戏开发之使用Py2exe打包游戏
最近在用python+pygame 开发游戏,写完以后在分享给朋友玩的时候遇到了很大的问题,只有搭建了环境才能运行python脚本. 这会吓退99%以上的人……所以把我们的游戏打包(注意是打包而不是编 ...
- 常用的coco2d-x游戏开发工具(转)
物理编辑工具Physics Editing ToolsMekanimo 网址:http://www.mekanimo.net/PhysicsBench 网址:http://www.cocos2d-ip ...
- Unity3D ——强大的跨平台3D游戏开发工具(四)
第六章 Unity3D中的C#Script编程的注意事项 也许您在学习Unity3D之前,已经是一位C#的编程高手了.但在Unity3D中的C#并不像真正的C#那般强大,在Unity3D的C#中必须全 ...
随机推荐
- javaweb学习总结(八)——HttpServletResponse对象(二)
一.HttpServletResponse常见应用——生成验证码 1.1.生成随机图片用作验证码 生成图片主要用到了一个BufferedImage类,
- 淘宝开放平台TOP测试环境
沙箱测试环境 淘宝沙箱环境是淘宝开放平台(TOP)提供给独立软件开发商(ISV)的测试环境.数据完全独立,大部分API已经部署到该环境中供ISV进行API的功能测试,对与APP的调用量无限制,但获取大 ...
- DotNet中人民币符号的输出
DotNet中人民币符号“¥”的输出<html> <head>DotNet中人民币符号的输出</head> <body> <p>¥100元& ...
- IIS下使用appcmd批量搭建网站
使用 cmd 运行如下命令 > %windir%\system32\inetsrv\appcmd list site /config /xml > d:\sites.xml 修改 d 盘 ...
- (转)【Unity3d】Glow + Outline 轮廓描边
转:http://www.cnblogs.com/dosomething/archive/2012/08/04/2622488.html [Unity3d]Glow + Outline 轮廓描边 轮廓 ...
- iPhone开发视频教程 Objective-C部分 (51课时)
第一.二章 OC基础语法 iPhone开发教程 第一章 OC基础语法 iPhone开发概述-必看(1.1)http://www.apkbus.com/android-102215-1-1.html ...
- openCV_java 图像二值化
较为常用的图像二值化方法有:1)全局固定阈值:2)局部自适应阈值:3)OTSU等. 局部自适应阈值则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值.这样做的好处在于每个像素位置处的二值化 ...
- 每日英语:why can't China produce world-class CEO?
The appointment of India-born Satya Nadella as Microsoft Corp.'s CEO has caused a bit of a stir in C ...
- ASP.NET MVC 入门8、ModelState与数据验证
原帖地址:http://www.cnblogs.com/QLeelulu/archive/2008/10/08/1305962.html ViewData有一个ModelState的属性,这是一个类型 ...
- Asp.net Core 1.0.1升级到Asp.net Core 1.1.0 Preview版本发布到Windows Server2008 R2 IIS中的各种坑
Asp.net Core 1.0.1升级到Asp.net Core 1.1.0后,程序无法运行了 解决方案:在project.json中加入runtime节点 "runtimes" ...