//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;
}
popcap sexyframework - Demo3 对图像进行 修改 拉伸 翻转 做动画 以及 按钮 和 鼠标事件
最新推荐文章于 2017-02-27 01:31:16 发布