2016-08-21 19:25:26 chip
Page 1826
📢 PUBLIC
Image.cpp performs all the actual draw operations.
Image.cpp:
/*************************************************************************/
/** Image.cpp: Manages the offscreen image, SwapChain method. **/
/** (C)2016 nlited systems, Chip Doran **/
/*************************************************************************/
#include <Windows.h>
#include "Util.h"
#include "MyD2D.h"
#include "Sprite.h"
#include "Globals.h"
using namespace D2D1; //Direct2D version 1
#define SPRITE_MAX 8000 //Limit the number of sprites to create
struct Bitmap_s BitmapList[]= {
{ BITMAP_ROCKET_PNG, L"PNG", L"PNG_ROCKET",2 },
{ BITMAP_NONE }
};
class Image {
public:
static Image *Ptr(HIMAGE hImg);
static int Create(HIMAGE *phImg, HWND hWnd);
int Destroy(void);
int Resize(const RECT *pR);
int SetAttract(HATTRACT hAttract);
int Redraw(void);
int Paint(void);
int Begin(void);
ID2D1RenderTarget *GetRender(void);
int End(void);
int AddSprite(struct Sprite_s *pSprite);
//Data
UINT32 Signature;
private:
Image(void);
~Image(void);
int Create2(HWND hWnd);
int DrawCreate(ID2D1HwndRenderTarget **pRender);
int DrawCreateBitmaps(void);
void ReleaseEverything(void);
int DrawBackground(void);
int DrawStatus(void);
int DrawSprites(void);
void DrawText(const D2D_RECT_F &rText, const WCHAR *Fmt, ...);
//Data
HWND hWnd;
HATTRACT hAttract;
bool IsBuilding;
bool DoRedraw;
bool DoReset;
bool IsBitmapLoaded;
RECT rImg;
ID2D1BitmapRenderTarget *pImgRender;
UINT RedrawCt;
UINT SpriteCt;
struct Sprite_s *Sprites[SPRITE_MAX];
D2D_COLOR_F TextClr;
INT64 uSecTicks; //QueryPerformanceCounter() ticks per microsecond
INT64 DrawTime; //Elapsed microseconds for previous Redraw()
INT64 PaintTime; //Elapsed microseconds for previous Paint()
UINT DrawAvg; //Rolling average of DrawTime
UINT PaintAvg; //Rolling average of PaintTime
UINT FramesPerSec;
UINT FrameCt;
UINT64 FrameCtEnd;
WCHAR Text[200];
};
/*************************************************************************/
/** Public interface **/
/*************************************************************************/
int ImgCreate(HIMAGE *phImg, HWND hWnd) {
if(IsBadPtr(phImg,sizeof(*phImg),BADPTR_WRITE))
return(ERR_BADPTR);
if(!IsWindow(hWnd))
return(ERR_BADARG1);
return(Image::Create(phImg,hWnd));
}
int ImgDestroy(HIMAGE hImg) {
Image *pImg= Image::Ptr(hImg);
if(!pImg)
return(ERR_BADHANDLE);
return(pImg->Destroy());
}
int ImgResize(HIMAGE hImg, const RECT *pR) {
Image *pImg= Image::Ptr(hImg);
if(!pImg)
return(ERR_BADHANDLE);
if(IsBadPtr(pR,sizeof(*pR),BADPTR_READ))
return(ERR_BADPTR);
return(pImg->Resize(pR));
}
int ImgSetAttract(HIMAGE hImg, HATTRACT hAttract) {
Image *pImg= Image::Ptr(hImg);
if(!pImg)
return(ERR_BADHANDLE);
return(pImg->SetAttract(hAttract));
}
int ImgPaint(HIMAGE hImg) {
Image *pImg= Image::Ptr(hImg);
if(!pImg)
return(ERR_BADHANDLE);
return(pImg->Paint());
}
int ImgBegin(HIMAGE hImg) {
Image *pImg= Image::Ptr(hImg);
if(!pImg)
return(ERR_BADHANDLE);
return(pImg->Begin());
}
ID2D1RenderTarget *ImgGetRender(HIMAGE hImg) {
Image *pImg= Image::Ptr(hImg);
if(!pImg)
return(0);
return(pImg->GetRender());
}
int ImgEnd(HIMAGE hImg) {
Image *pImg= Image::Ptr(hImg);
if(!pImg)
return(ERR_BADHANDLE);
return(pImg->End());
}
int ImgAddSprite(HIMAGE hImg, struct Sprite_s *pSprite) {
Image *pImg= Image::Ptr(hImg);
if(!pImg)
return(ERR_BADHANDLE);
if(IsBadPtr(pSprite,sizeof(*pSprite),BADPTR_RW))
return(ERR_BADPTR);
return(pImg->AddSprite(pSprite));
}
/*************************************************************************/
/** Public internals **/
/*************************************************************************/
Image *Image::Ptr(HIMAGE hImg) {
Image *pImg= (Image*)hImg;
if(!hImg || IsBadPtr(pImg,sizeof(*pImg),BADPTR_RW) || pImg->Signature!=SIGNATURE_IMAGE)
pImg= 0;
return(pImg);
}
int Image::Create(HIMAGE *phImg, HWND hWnd) {
int Err= ERR_OK;
Image *pImg= new Image;
if(!pImg) {
Err= Error(ERR_NOMEM,__FUNCTION__": NoMem(%d)",sizeof(*pImg));
} else if(IsErr(Err= pImg->Create2(hWnd))) {
delete pImg;
} else {
*phImg= (HIMAGE)pImg;
}
return(Err);
}
int Image::Destroy(void) {
int Err= ERR_OK;
delete this;
return(Err);
}
int Image::Resize(const RECT *pR) {
int Err= ERR_OK;
rImg= *pR;
ID2D1HwndRenderTarget *pRender= MyD2DRenderWnd(ghD2D,hWnd);
if(pRender)
pRender->Resize(SizeU(RWID(rImg),RHGT(rImg)));
if(pImgRender)
SafeRelease(pImgRender);
DoRedraw= 1;
return(Err);
}
int Image::SetAttract(HATTRACT hAttract) {
this->hAttract= hAttract;
return(ERR_OK);
}
int Image::Redraw(void) {
int Err= ERR_OK;
HRESULT WinErr;
LARGE_INTEGER Start,End;
D2D1_TAG Tag1,Tag2;
ID2D1HwndRenderTarget *pRender= MyD2DRenderWnd(ghD2D,hWnd);
if(IsBuilding)
return(ERR_BUSY);
if(!(pRender && pImgRender /*&& pImgBitmap*/))
return(ERR_NOINIT);
RedrawCt++;
FrameCt++;
QueryPerformanceCounter(&Start);
pImgRender->BeginDraw();
DrawBackground();
DrawSprites();
DrawStatus();
if(hAttract)
AttractDraw(hAttract,(HIMAGE)this);
WinErr= pImgRender->EndDraw(&Tag1,&Tag2);
QueryPerformanceCounter(&End);
DrawTime= (End.QuadPart-Start.QuadPart)/uSecTicks;
if(!SUCCEEDED(WinErr)) {
Warn(ERR_SYSCREATE,__FUNCTION__": Draw failed. [%d/%X:%d:%d]",WinErr,WinErr,Tag1,Tag2);
if(WinErr==D2DERR_RECREATE_TARGET)
DoReset= 1;
}
DoRedraw= 0;
return(Err);
}
int Image::Paint(void) {
int Err= ERR_OK;
HRESULT WinErr;
D2D1_TAG Tag1,Tag2;
ID2D1HwndRenderTarget *pRender= MyD2DRenderWnd(ghD2D,hWnd);
ID2D1Bitmap *pImage;
LARGE_INTEGER Start,End;
if(!FrameCtEnd) {
FrameCtEnd= GetTickCount64()+10000;
FrameCt= 0;
}
if(!(pRender && pImgRender) && IsErr(Err= DrawCreate(&pRender)))
return(Err);
if(DoRedraw)
Redraw();
QueryPerformanceCounter(&Start);
pRender->BeginDraw();
pImgRender->GetBitmap(&pImage);
pRender->DrawBitmap(pImage);
WinErr= pRender->EndDraw(&Tag1,&Tag2);
QueryPerformanceCounter(&End);
PaintTime= (End.QuadPart-Start.QuadPart)/uSecTicks;
if(!SUCCEEDED(WinErr)) {
Warn(ERR_SYSCREATE,__FUNCTION__": Draw failed. [%d/%X:%d:%d]",WinErr,WinErr,Tag1,Tag2);
if(WinErr==D2DERR_RECREATE_TARGET)
DoReset= 1;
}
if(GetTickCount64()>=FrameCtEnd) {
FramesPerSec= FrameCt;
FrameCt= 0;
FrameCtEnd= GetTickCount64()+10000;
}
if(DoReset) {
//EVERYTHING needs to be released and recreated.
Warn(ERR_OK,__FUNCTION__": Resetting...");
ReleaseEverything();
DoReset= 0;
}
return(Err);
}
int Image::Begin(void) {
int Err= ERR_OK;
SpriteCt= 0;
IsBuilding= 1;
DoRedraw= 1;
return(Err);
}
ID2D1RenderTarget *Image::GetRender(void) {
return(pImgRender);
}
int Image::End(void) {
int Err= ERR_OK;
IsBuilding= 0;
return(Err);
}
int Image::AddSprite(struct Sprite_s *pSprite) {
int Err= ERR_OK;
UINT n1;
if(SpriteCt>=SPRITE_MAX) {
Err= Warn(ERR_TOO_MANY,__FUNCTION__": Too many sprites! [%d]",SpriteCt);
} else {
if(pSprite->SpriteID==SPRITE_BITMAP) {
for(n1=0;BitmapList[n1].BitmapID && BitmapList[n1].BitmapID!=pSprite->BitmapID;n1++);
pSprite->pBitmap= &BitmapList[n1];
}
//TODO: Sort by Z-Order
Sprites[SpriteCt++]= pSprite;
}
return(Err);
}
/*************************************************************************/
/** Private internals **/
/*************************************************************************/
Image::Image(void) {
LARGE_INTEGER Freq;
memset(this,0,sizeof(*this));
Signature= SIGNATURE_IMAGE;
TextClr= D2D1::ColorF(RGB(200,249,40),(FLOAT)0.85);
QueryPerformanceFrequency(&Freq);
uSecTicks= Freq.QuadPart/1000000; //Ticks per microsecond.
srand(GetTickCount());
}
Image::~Image(void) {
Signature|= SIGNATURE_INVALID;
ReleaseEverything();
}
int Image::Create2(HWND hWnd) {
int Err= ERR_OK;
this->hWnd= hWnd;
DoRedraw= 1;
return(Err);
}
int Image::DrawCreate(ID2D1HwndRenderTarget **ppRender) {
int Err= ERR_OK;
HRESULT WinErr;
ID2D1RenderTarget *pRender= 0;
if(IsErr(Err= MyD2DCreateResourcesWnd(ghD2D,hWnd))) {
Err= Error(Err,__FUNCTION__": Unable to create Direct2D resources.");
} else if(!(pRender= MyD2DRenderWnd(ghD2D,hWnd))) {
Err= Error(Err,__FUNCTION__": Unable to retrieve Renderer.");
} else if(!pImgRender && !SUCCEEDED(WinErr= pRender->CreateCompatibleRenderTarget(0,0,0,D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE,&pImgRender))) {
Err= Error(ERR_SYSCREATE,__FUNCTION__": Unable to create ImgRender. [%X]",WinErr);
} else if(!IsBitmapLoaded && IsErr(Err= DrawCreateBitmaps())) {
Err= Error(Err,__FUNCTION__": Unable to load bitmaps.");
} else {
IsBitmapLoaded= 1;
DoReset= 0;
}
*ppRender= (ID2D1HwndRenderTarget*)pRender;
return(Err);
}
int Image::DrawCreateBitmaps(void) {
int Err= ERR_OK;
UINT n1;
for(n1=0;BitmapList[n1].BitmapID;n1++) {
Err= MyD2DBitmapCreate(ghD2D,&BitmapList[n1]);
}
return(Err);
}
void Image::ReleaseEverything(void) {
UINT n1;
IsBitmapLoaded= 0;
for(n1=0;BitmapList[n1].BitmapID;n1++)
SafeRelease(BitmapList[n1].pBitmap);
SafeRelease(pImgRender);
MyD2DReleaseResources(ghD2D,hWnd);
}
/*************************************************************************/
/** Draw frame components **/
/*************************************************************************/
int Image::DrawBackground(void) {
int Err= ERR_OK;
D2D_COLOR_F FillClr(ColorF(RGB(40,10,20)));
if(pImgRender) {
pImgRender->Clear(FillClr);
}
return(Err);
}
int Image::DrawStatus(void) {
int Err= ERR_OK;
UINT ChrCt= 0;
WCHAR Text[80];
D2D_RECT_F rText(RectF(20.0f,(FLOAT)(rImg.bottom-20),(FLOAT)(rImg.right-20),(FLOAT)rImg.bottom));
if(pImgRender) {
DrawAvg+= (int)(DrawTime-DrawAvg)/100;
PaintAvg+= (int)(PaintTime-PaintAvg)/100;
pImgRender->SetTransform(Matrix3x2F::Identity());
ChrCt+= StrFormatW(Text+ChrCt,STRSIZE(Text)-ChrCt,L"%u.%01u FPS, ",FramesPerSec/10,FramesPerSec%10);
ChrCt+= StrFormatW(Text+ChrCt,STRSIZE(Text)-ChrCt,L"%04u sprites, ",SpriteCt);
ChrCt+= StrFormatW(Text+ChrCt,STRSIZE(Text)-ChrCt,L"Draw %2u.%03ums, ",DrawAvg/1000,DrawAvg%1000);
ChrCt+= StrFormatW(Text+ChrCt,STRSIZE(Text)-ChrCt,L"Paint %2u.%03ums",PaintAvg/1000,PaintAvg%1000);
DrawText(rText,L"Redraw %6d: %s",RedrawCt,Text);
}
return(Err);
}
/*************************************************************************/
/** Sprites **/
/*************************************************************************/
int Image::DrawSprites(void) {
int Err= ERR_OK;
UINT n1;
if(pImgRender) {
for(n1=0;n1<SpriteCt;n1++) {
SpriteDrawImg(pImgRender,Sprites[n1]);
}
}
return(Err);
}
/*************************************************************************/
/** Format and draw text. **/
/*************************************************************************/
void Image::DrawText(const D2D_RECT_F &rText, const WCHAR *Fmt, ...) {
UINT ChrCt= 0;
va_list ArgList;
ID2D1SolidColorBrush *pBrush= 0;
IDWriteTextFormat *pFormat= MyD2DTextFormat(ghD2D);
if(pImgRender && pFormat) {
va_start(ArgList,Fmt);
ChrCt+= StrFormatVW(Text+ChrCt,STRSIZE(Text)-ChrCt,Fmt,ArgList);
pImgRender->CreateSolidColorBrush(TextClr,&pBrush);
pImgRender->DrawTextW(Text,ChrCt,pFormat,rText,pBrush);
pBrush->Release();
va_end(ArgList);
}
}
WebV7 (C)2018 nlited | Rendered by tikope in 55.904ms | 18.223.170.253