SlimDX Tutorial 8 - 폰트

가변프레임율과 고정프레임율을 폰트를 사용하여 표시하는 예제입니다.

dx sample의 tiger.x와 tiger.bmp를 소스 폴더에 넣어주어야 제대로 동작합니다.


#include <Windows.h>

using namespace System;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace SlimDX;
using namespace SlimDX::Direct3D9;


struct TextureVertex
{
 Vector3 positon;    
 int color;
 float tu, tv;
};

public ref class WndForm : public Form
{   
 Direct3D^ direct3D;
 PresentParameters^ presentParams;   
 Device^ device; 
 Mesh^ mesh;
 array<Material^>^ meshMaterials;
 array<Texture^>^ meshTextures; 
 SlimDX::Direct3D9::Font^ font;  

public:
 String^ lastError;
 String^ fps1;
 String^ fps2;
 Int32 staticFPS;
 Int32 variableFPS;

 WndForm(void)
 {   
  this->ClientSize = System::Drawing::Size(400, 300);
  this->StartPosition = FormStartPosition::CenterScreen;
  this->Text = "D3D Tutorial 8";
 }

 ~WndForm()
 {
  this->!WndForm();
 }

 !WndForm()
 {
  Release();
 }

 bool InitD3D()
 {
  try {
   // 환경변수 세팅
   direct3D = gcnew Direct3D();
   presentParams = gcnew PresentParameters();
   presentParams->Windowed = true;
   presentParams->SwapEffect = SwapEffect::Discard;
   presentParams->DeviceWindowHandle = this->Handle;
   presentParams->EnableAutoDepthStencil = true;
   presentParams->AutoDepthStencilFormat = Format::D16;

   device = gcnew Device(direct3D, 0, DeviceType::Hardware, this->Handle, CreateFlags::SoftwareVertexProcessing, presentParams);

   // render state
   device->SetRenderState(RenderState::CullMode, Cull::None);
   device->SetRenderState(RenderState::ZEnable, true);
   device->SetRenderState(RenderState::Ambient, 0xffffff);

   // model
   mesh = Mesh::FromFile(device, "tiger.x", MeshFlags::SystemMemory);
   array<ExtendedMaterial>^ materials = mesh->GetMaterials();
   meshMaterials = gcnew array<Material^>(materials->Length);
   meshTextures = gcnew array<Texture^>(materials->Length);           
   for (int i = 0; i < materials->Length; i++) {
    meshMaterials[i] = materials[i].MaterialD3D;
    meshMaterials[i]->Ambient = meshMaterials[i]->Diffuse;
    meshTextures[i] = Texture::FromFile(device, materials[i].TextureFileName);
   }           

   // font
   System::Drawing::Font^ nfont = gcnew System::Drawing::Font("Arial", 15);;
   font = gcnew SlimDX::Direct3D9::Font(device, nfont);

   return true;
  }
  catch (Direct3D9Exception^ ex) {
   lastError = ex->ToString();
   return false;
  }
 }

 void Release()
 {
  if (mesh)
   delete mesh;
  for (int i = 0; i < meshMaterials->Length; i++)
   delete meshMaterials[i];
  for (int i = 0; i < meshTextures->Length; i++)
   delete meshTextures[i];

  if (font)
   delete font;

  if (direct3D)
   delete direct3D;
  if (device)
   delete device;
 }

 void SetupMatrix()
 {       
  device->SetTransform(TransformState::World, Matrix::RotationY(Environment::TickCount / 1000.0f));
  device->SetTransform(TransformState::View, Matrix::LookAtLH(Vector3(0.0f, 3.0f, -5.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, 1.0f, 0.0f)));
  device->SetTransform(TransformState::Projection, Matrix::PerspectiveFovLH((float)Math::PI / 4, 1.0f, 1.0f, 100.0f));        
 }

 void Render()
 {
  if (!device)
   return;

  // 렌더링 시작
  device->Clear(ClearFlags::Target | ClearFlags::ZBuffer, System::Drawing::Color::Black, 1.0f, 0);
  device->BeginScene();
  SetupMatrix();
  
  // 렌더링
  font->DrawString(nullptr, fps1, 20, 20, 0xffff0000);
  font->DrawString(nullptr, fps2, 20, 40, 0xffff0000);
  
  for (int i = 0; i < meshMaterials->Length; i++) {           
   device->Material = *meshMaterials[i];
   device->SetTexture(0, meshTextures[i]);
   mesh->DrawSubset(i);
  }

  // 렌더링 끝
  device->EndScene();
  device->Present();
 } 

 void SetFPS(int sFPS, int vFPS)
 {
  staticFPS = sFPS;
  variableFPS = vFPS;
  fps1 = staticFPS.ToString();
  fps2 = variableFPS.ToString();
 }
};

ref class FrameControl
{
 float timer;
 float frameRate;    
public:
 FrameControl()
 {
  SetFrameRate(60.0f);
 }
 
 ~FrameControl()
 {
 }

 void SetFrameRate(float fps)
 {
  frameRate = 1.0f / fps;
 }

 bool Update(float dt)
 {
  timer += dt;
  if (timer < 0)
   return false;
  timer -= frameRate;

  return true;
 }

 bool FrameMove()
 {
  if (timer >= 0)
   return true;
  
  return false;
 }   
};

INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
{   
 WndForm^ frm = gcnew WndForm();
 FrameControl^ fc = gcnew FrameControl();

 if (!frm->InitD3D()) {
  MessageBox::Show(frm->lastError);
  delete frm;
  return 0;
 }

 frm->Show();
 frm->fps1 = "";
 frm->fps2 = "";
 fc->SetFrameRate(60.0f);    
 int curTick = Environment::TickCount;   
 int lastTick = curTick;
 int tickGap;    

 int staticFrame, variableFrame;
 int lastStaticFrame = 0;
 int lastVariableFrame = 0;

 while (frm->Created) {
  // ms단위의 delta time
  tickGap = Environment::TickCount - curTick;
  curTick = Environment::TickCount;

  // 언제나 고정적으로 해야하는 작업 (intput, network etc..)
  if (fc->Update((float)tickGap / 1000.0f))
   staticFrame++;
  
  // 상황에 따라 많이 할수도 적게 할수도 있는 작업 (rendering etc..)
  if (!fc->FrameMove()) {                               
   variableFrame++;            

   frm->Render();
   Application::DoEvents();
   // 작업의 부하를 테스트하기 위해 밑의 값을 변동해보면 어떻게 동작하는지 볼 수 있습니다. (10~50ms)
   //Sleep(30);
  }

  // 초당 프레임율을 계산해서 문자열로 변환
  if ((Environment::TickCount - lastTick) > 1000) {           
   staticFrame -= lastStaticFrame;         
   variableFrame -= lastVariableFrame;

   frm->SetFPS(staticFrame, variableFrame);

   lastTick = Environment::TickCount;
   lastStaticFrame = staticFrame;
   lastVariableFrame = variableFrame;
  }               
 }

 delete frm;

 return 0;
}

0 개의 댓글:

댓글 쓰기