游戏开发工具之纹理打包器-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#中必须全 ...
随机推荐
- C++11中async中future用法(一)
async意味着异步执行代码,看如下示例: #include <future> #include <thread> #include <chrono> #inclu ...
- IoC实践--用Autofac实现MVC5.0的IoC控制反转方法
Autofac是一个.net平台下发性能还不错的IoC框架,利用它可以实现依赖注入和控制反转,使自己的软件模块之间的耦合性大大降低,让软件扩展.维护更加容易.控制反转(Inversion of Con ...
- NMAP 基础教程
原文地址: http://drops.wooyun.org/tips/2002 0x00 nmap 介绍 Nmap (网络映射器)是由 Gordon Lyon设计,用来探测计算机网络上的主机和服务的 ...
- 解决中64位Win7系统上PLSQL无法连接ORACLE的方法(PLSQL无法识别ORACLE_HOME的配置)
最近新安装了64位的Win7系统,工作中需要用oracle数据库,而数据库是公司IT的DBA进行管理和维护的. 我们只需要连接上去进行使用就可以了,于是我就在自己的机器上安装了oracle clien ...
- 如何在windows7上安装启明星系统。
启明星系统提供多种安装方式.安装包里自带了setup.exe.每个程序的 install下有在线安装(例如请假应用程序为book,则默认为 http://localhost/book/install ...
- C++ 记事本: 从历史说起
C 的简史 在谈论 C++ 的历史那么必须先得了解 C 的历史,那么我们先来看一段来自于 <<C专家编程>> 对 C 语言史前阶段的简单阐述: Ken Thompson(左), ...
- MongoDB副本集配置系列九:MongoDB 常见问题
What is a namespace in MongoDB? If you remove a document, does MongoDB remove it from disk? When doe ...
- [aaronyang]WPF4.5 - AyTabControlBase样式分享,绝对好看
样式代码如下: 对于博客园将文章移除首页的做法:我就迁移了.文章已经迁移:http://www.ayjs.net/post/75.html 由于例子比较简单,你只要指定Style即可,难点,透明区域的 ...
- BZOJ 4726: [POI2017]Sabota? 树形dp
4726: [POI2017]Sabota? 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4726 Description 某个公司有n ...
- Nginx负载均衡深入浅出
nginx不单可以作为强大的web服务器,也可以作为一个反向代理服务器,而且nginx还可以按照调度规则实现动态.静态页面的分离,可以按照轮询.ip哈希.URL哈希.权重等多种方式对后端服务器做负载均 ...