popcap sexyframework - Demo3 对图像进行 修改 拉伸 翻转 做动画 以及 按钮 和 鼠标事件

//board.h

#ifndef __BOARD_H__
#define __BOARD_H__

#include "SexyAppFramework/Widget.h"
// 这个例子我们学习处理按钮事件
#include "SexyAppFramework/ButtonListener.h"
 
class Graphics; 
class GameApp; 
class DDImage;
class WidgetManager;

// 库中一个封装好的按钮类
class ButtonWidget;  
 
// 在本例子中. 我们让 Board 类做为 按钮 的监听器类. 所以它从ButtonListener派生.
class Board : public Widget, public ButtonListener
{ 
  GameApp*  mApp;
  ButtonWidget* mButton;   // 按钮部件
  int    mAnimFrame;   // 记录闪电动画绘制时. 绘制第几帧. 它在Update()时改变.
  int    mMouseX, mMouseY; // 我们会在处理鼠标移动/拖动消息时更新它的值. 并在Draw()时绘制该信息.
  
  // 记录3个鼠标键的按下状态
  bool   mLeftDown;
  bool   mRightDown;
  bool   mMiddleDown; 
 public: 
  Board(GameApp* theApp) {
   mApp = theApp;

   // Start off drawing the first frame of mLightningImg
   mAnimFrame = 0;

   mButton = NULL;
   
   mMouseX = mMouseY = 0;
   mLeftDown = mRightDown = mMiddleDown = false;
  }

  virtual ~Board(){ delete mButton; } 
  virtual void Draw(Graphics* g); 
  virtual void Update();

  // 
  // 这是定义在基类 ButtonListener 的函数. 我们在此重写它来处理按钮按下事件.
  // 这样. 就会在按钮按下时由 WidgetManager 调用我们实现的ButtonDepress().
  // 参数为被按下的按钮ID.  
  virtual void ButtonDepress(int theId);
  
  virtual void AddedToManager(WidgetManager* theWidgetManager); 
  virtual void RemovedFromManager(WidgetManager* theWidgetManager);

  // 
  // 当鼠标在该部件上(即该部件必须是鼠标指针紧下边的)移动的时候. 
  // 这个函数会被 WidgetManager 自动调用. 
  virtual void MouseMove(int x, int y);

  //
  // 鼠标拖动事件
  // 这个函数和 MouseMove() 类似. 当鼠标在该部件上拖动时. 
  // 该函数被WidgetManager 自动调用.  
  virtual void MouseDrag(int x, int y);
 
  //
  // 处理鼠标按下消息. 
  // 当有鼠标键在该部件上(即该部件必须是鼠标指针紧下边的)按下的时候. 
  // 这个函数会被 WidgetManager 自动调用. 
  // 第3个参数说明哪个鼠标键被按下: 
  //   1.左键  2.左键双击  3.中键   -1.右键   -2.右双击
  virtual void MouseDown(int x, int y, int theClickCount);
 
  //
  // 鼠标键弹起 . 同 MouseDown().
  virtual void MouseUp(int x, int y, int theClickCount);  
};
 
#endif // __BOARD_H__

//gameapp.h

#ifndef __GAMEAPP_H__
#define __GAMEAPP_H__
  
#include "SexyAppFramework/SexyAppBase.h"
  
 class Board; 
 class DDImage; 
 class ImageFont;

class GameApp : public SexyAppBase
{ 
  Board*  mBoard;  
 public: 
  DDImage* mTurbotImg;   
  DDImage* mLightningImg;  //闪电的图像. 
  DDImage* mAlteredImg;  //在本例子中会修改该图像

  ImageFont* mFont; 

  GameApp();
  virtual ~GameApp();
 
  virtual void Init(); 
  virtual void LoadingThreadProc(); 
  virtual void LoadingThreadCompleted();   
};


#endif // __GAMEAPP_H__

//board.cpp

#include "Board.h"
#include "GameApp.h"
#include "SexyAppFramework/Graphics.h"
 
#include "SexyAppFramework/Color.h" 
#include "SexyAppFramework/DDImage.h" 
#include "SexyAppFramework/Rect.h" 
// 按钮部件
#include "SexyAppFramework/ButtonWidget.h"

#include "SexyAppFramework/WidgetManager.h" 
#include "SexyAppFramework/ImageFont.h"
  
using namespace Sexy;

void Board::Update()
{ 
 Widget::Update();

 // mUpdateCnt 是 Update() 被调用的次数. 
 if (mUpdateCnt % 5 == 0)
 {
  // 绘制闪电使用. 
  if (++mAnimFrame >= mApp->mLightningImg->mNumRows)
   mAnimFrame = 0;
 }
 
 MarkDirty();
}
 
//
void Board::Draw(Graphics* g)
{  
 g->SetColor(Color(0, 0, 0));
 g->FillRect(0, 0, mWidth, mHeight);

 // 绘制图像   拉伸
 // DrawImage() 参数为: Image指针, x, y, 目的宽, 目的高.
 g->DrawImage(mApp->mTurbotImg, 0, 0, mApp->mTurbotImg->GetWidth() * 2, mApp->mTurbotImg->GetHeight() * 2); 
  // 上面拉伸绘制时. 使用的是缺省的拉伸算法. 
 // 即拉伸时平滑了锯齿. 这样绘制较慢. 但效果漂亮一些.

 // 如果拉申时不需要平滑锯齿. 可以:
 //  1. g->SetFastStretch(true) 指示 g 使用快速拉伸算法.
 //  2. 拉伸画图.
 //  3. 一定要 g->SetFastStretch(false) 关闭快速拉伸算法.
 // 可以运行本程序. 对比这两次绘制的图像效果.
 g->SetFastStretch(true);
 g->DrawImage(mApp->mTurbotImg, 275, 0, mApp->mTurbotImg->GetWidth() * 2, mApp->mTurbotImg->GetHeight() * 2);
 g->SetFastStretch(false);

 // 绘制图像. 左右翻转. (镜子中看的效果)
 g->DrawImageMirror(mApp->mTurbotImg, 0, 275);

 // 翻转且拉伸
 // 它的参数包括两个 Rect,  分别表示图像要绘制到的目的区域, 和第一个参数Image中源区域. 
 g->DrawImageMirror(mApp->mTurbotImg, 
      Rect(200, 275, mApp->mTurbotImg->GetWidth() * 2, mApp->mTurbotImg->GetHeight() * 2),
      Rect(0, 0, mApp->mTurbotImg->GetWidth(), mApp->mTurbotImg->GetHeight()));
      

 // 绘制 mAlteredImg. 它拷贝自mTurbotImg, 并且在GameApp::LoadingThreadCompleted()中我们修改了图像的数据. 看看修改的效果.
 g->DrawImage(mApp->mAlteredImg, 500, 0);

 // 下边绘制闪电效果. 
 // 绘制时使用 DrawImageCel(). 只要将最后一个参数指定为要绘制哪一行就可以了. 
 // (可以回到 GameApp::LoadingThreadProc() 看看如何将一个图像分为多个行).
 // 指定行的参数 mAnimFrame 在Update()时修改.
 g->DrawImageCel(mApp->mLightningImg, 0, 540, mAnimFrame);
 // 上边绘制的效果相当于:
 //g->DrawImage(mApp->mLightningImg, 
 //Rect(0, 540, mApp->mLightningImg->GetWidth(), mApp->mLightningImg->GetCelHeight()),
 //Rect(0, mApp->mLightningImg->GetCelHeight() * mAnimFrame, mApp->mLightningImg->GetWidth(), mApp->mLightningImg->GetCelHeight()));
 
 g->SetFont(mApp->mFont);
 g->SetColor(Color(255, 255, 255));
 // 显示当前鼠标的坐标
 g->DrawString(StrFormat(_S("X, Y is %d, %d"), mMouseX, mMouseY), 630, 20); 
 // 当鼠标左/中/右键被按下时. 显示对应的字符串
 SexyString buttonStr;
 if (mLeftDown)
  buttonStr += _S("Left button is down. ");
 if (mRightDown)
  buttonStr += _S("Right button is down. ");
 if (mMiddleDown)
  buttonStr += _S("Middle button is down. ");
 WriteWordWrapped(g, Rect(630, 40, mWidth - 630, 300), buttonStr, -1, -1);
}

 
//
void Board::AddedToManager(WidgetManager* theWidgetManager)
{ 
 Widget::AddedToManager(theWidgetManager);

 // 在将Board窗口添加到 WidgetManager(部件管理器) 时. 我们创建一个按钮部件.
 // 按钮类的构造函数如下: 参数为 按钮的ID  和  按钮的监听器. 
 // 按钮的监听器可以是任何对象. 只要它的类继承自ButtonListener. 就像 Board类那样.
 mButton = new ButtonWidget(1, this);

 // 设置按钮的大小. 文字. 颜色
 mButton->Resize(675, 500, 100, 50); 
 mButton->SetFont(mApp->mFont); 
 mButton->mLabel = _S("Off");
 mButton->SetColor(ButtonWidget::COLOR_LABEL, Color(0, 0, 0));
 mButton->SetColor(ButtonWidget::COLOR_LABEL_HILITE, Color(0, 255, 0));

 // 最后. 把按钮也添加到 部件管理器
 theWidgetManager->AddWidget(mButton);

 // 如果需要. 可以通过 WidgetManager 将一个部件(如这个按钮)设置为 最上层 / 最下层 等.
 // 这些功能需要用 WidgetManager的 PutInFront, PutBehind, BringToFront, BringToBack 函数

 // 另外. 我们还可以为按钮指定一副图片作为皮肤(缺省是没有图像的). 
 // 但那是下一个例子的内容了.. 
}
 
//
void Board::RemovedFromManager(WidgetManager* theWidgetManager)
{ 
 Widget::RemovedFromManager(theWidgetManager);

 // 就像我们在 Board::AddedToManager() 中将一个按钮加入 WidgetManager 
 // 在Board::RemovedFromManager() 也需要将其 remove 
 theWidgetManager->RemoveWidget(mButton); 
}
 
//
//因为 Board 是按钮事件的监听器类(继承自ButtonListener). 
//我们要实现一些监听器的函数来处理按钮事件. 这里处理按钮按下.
void Board::ButtonDepress(int theId)
{
 if (theId == 1)  // 创建按钮时指定的 ID . 
 {
  if (mButton->mLabel == _S("Off"))
   mButton->mLabel = _S("On");
  else
   mButton->mLabel = _S("Off");
 }
}

// 
// 鼠标在该部件上移动时. 会调用该函数. 
// 我们可以在此处理鼠标移动事件.
void Board::MouseMove(int x, int y)
{
 mMouseX = x;
 mMouseY = y;
}

// 
// 处理鼠标在该部件上的拖动事件
void Board::MouseDrag(int x, int y)
{ 
 mMouseX = x;
 mMouseY = y;
}

//
// 鼠标按下 (左/中/右键)
void Board::MouseDown(int x, int y, int theClickCount)
{
 // 先调用基类的MouseDown().
 Widget::MouseDown(x, y, theClickCount);

 // 通过该函数第3个参数, 明确是哪个鼠标键被按下.
 if (theClickCount == 3)
  mMiddleDown = true;
 else if (theClickCount > 0)
  mLeftDown = true;
 else if (theClickCount < 0)
  mRightDown = true;
}
 
//
// 鼠标弹起 (左/中/右键)
void Board::MouseUp(int x, int y, int theClickCount)
{
 // 先调用基类的MouseUp()
 Widget::MouseUp(x, y, theClickCount);
 
 // 通过该函数第3个参数, 明确是哪个鼠标键被按下. 
 // 另外一种确定哪个鼠标键被按下的办法是调用 WidgetManager的 
 //  IsLeftButtonDown() 
 //  IsRightButtonDown() 
 //  IsMiddleButtonDown()
 if (theClickCount == 3)
  mMiddleDown = false;
 else if (theClickCount > 0)
  mLeftDown = false;
 else if (theClickCount < 0)
  mRightDown = false;
}

//gameapp.cpp

#include "GameApp.h"
#include "Board.h"
#include "SexyAppFramework/WidgetManager.h" 
#include "SexyAppFramework/DDImage.h" 
#include "SexyAppFramework/ImageFont.h" 
using namespace Sexy;

 
GameApp::GameApp()
{ 
 mProdName = "Demo 3"; 
 mProductVersion = "1.0"; 
 mTitle = StringToSexyStringFast("SexyAppFramework: " + mProdName + " - " + mProductVersion);
 
 mWidth = 800;
 mHeight = 600;

 // 自动检测3D支持. 
 mAutoEnable3D = true;

 mBoard = NULL;
}
 
GameApp::~GameApp()
{ 
 mWidgetManager->RemoveWidget(mBoard);
 delete mBoard; 
 delete mTurbotImg;
 delete mLightningImg;
 delete mAlteredImg;
 delete mFont;
}
 
void GameApp::Init()
{ 
 SexyAppBase::Init(); 
}
 
void GameApp::LoadingThreadProc()
{  
 mTurbotImg = (DDImage*) GetImage("images/turbot_worry"); 
 if (mTurbotImg == NULL)
 {
  mLoadingFailed = true; 
  Popup("There was an error loading the file: images/turbot_worry"); 
  return;
 }

 mLightningImg = (DDImage*) GetImage("images/lightning");
 if (mLightningImg == NULL)
 {
  mLoadingFailed = true;
  Popup("There was an error loading the file: images/lightning");
  return;
 }
 
 // 对上一步加载的闪电图像. 我们把它分为 8行1列. (去文件夹下看看该资源文件先).
 // 之后我们可以用 DrawImageCel() 选择绘制某一行(列). 将该图像做为动画显示时很方便.
 mLightningImg->mNumRows = 8;
 mLightningImg->mNumCols = 1; 
 
 mLightningImg->Palletize();
 mTurbotImg->Palletize();
 
 mFont = new ImageFont(this, "fonts/Kiloton9.txt"); 
 if (!mFont->mFontData->mInitialized) 
 {
  delete mFont;
  mLoadingFailed = true;
  Popup("There was an error loading fonts/Kiloton9.txt");
  return;
 }
 
}
 
void GameApp::LoadingThreadCompleted()
{ 
 SexyAppBase::LoadingThreadCompleted();

 if (mLoadingFailed)
  return;
 
 mBoard = new Board(this); 
 mBoard->Resize(0, 0, mWidth, mHeight); 
 mWidgetManager->AddWidget(mBoard);

 /
 // 下边演示如何修改图像 mTurbotImg.
 //  1.为了不破坏源图像 mTurbotImg, 我们先对它做一个拷贝.
 //  这只要要调用 CopyImage() 即可. 它返回拷贝图像的指针. 
 //  要注意的是当不使用该拷贝图像以后. 这个指针要 delete.
 mAlteredImg = (DDImage*) CopyImage(mTurbotImg);

 //  2.取得图像的每个象素的值. 这通过调用 GetBits().
 //  它返回的 unsigned long 数组保存了该图像的每个象素的argb值. 
 unsigned long* bits = mAlteredImg->GetBits();

 //  3.遍历该数组(数组长度就是mAlteredImg的 宽*高). 修改每个象素. 
 for (int i = 0; i < mAlteredImg->GetWidth() * mAlteredImg->GetHeight(); i++)
 { 
  unsigned long c = bits[i];
  unsigned char alpha  = (unsigned char) (c >> 24);
  unsigned char red  = (unsigned char) ((c >> 16) & 0xFF);
  unsigned char green  = (unsigned char) ((c >> 8) & 0xFF);
  unsigned char blue  = (unsigned char) (c & 0xFF);
  // 修改
  unsigned long gray = (unsigned long) ((float)red * 0.30f + (float)green * 0.59f + (float)blue * 0.11f);
  // 写回
  bits[i] = (alpha << 24) | (gray << 16) | (gray << 8) | gray;
 }

 //  4.修改图像的数据后. 必须调用下边的 BitsChanged() 来通知该图像已经被修改. 否则它是不知道的.
 mAlteredImg->BitsChanged();
}

//main.cpp

//
// 通过这个例子我们学习:
//  自动检测并支持3D模式
//  修改图像的数据
//  拉伸图像
//  左右翻转图像(镜子中看到的图像).
//  使用图像的动画带(把图像分成若干条,每次显示一条, 形成动画)
//  按钮组件, 监听器, 事件,  鼠标的移动.点击.拖动.
//

#include "GameApp.h" 
using namespace Sexy;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{  
 gHInstance = hInstance; 
 GameApp* anApp = new GameApp();
 anApp->Init(); 
 anApp->Start();
 
 delete anApp; 
 return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值