I have just begun my directx c++ tutorial and I finally drew triangle, but whenever I try to transform it, by any matrix, that never works although I followed the tutorial step by step and I also looked for it in the MSDN tutorial, but I didn't figure out the problem, here's the full code:
main.cpp:
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "define.h"
LRESULT WINAPI WndProc( HWND, UINT, WPARAM, LPARAM );
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow )
{
HICON icon;
icon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_APP_ICON));
WNDCLASS wc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)NULL;
wc.hCursor = LoadCursor(hInst, IDC_ARROW);
wc.hIcon = icon;
wc.hInstance = hInst;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = "Window Class";
wc.lpszMenuName = NULL;
wc.style = CS_VREDRAW | CS_HREDRAW;
RegisterClass( &wc );
HWND hWnd = CreateWindow("Window Class", "D3D Tutorial 01: CreateDevice",
WS_OVERLAPPEDWINDOW, 0, 0, 1440, 900,
NULL, NULL, hInst, NULL );
ShowWindow( hWnd, SW_NORMAL);
initD3D(hWnd);
initGraphics();
Render();
MSG msg;
// Check to see if any messages are waiting in the queue
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT WINAPI WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
{
if(wParam == 0x51)
PostQuitMessage(1);
return 0;
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
clearD3D();
return 1;
break;
}
default:
{
return DefWindowProc( hWnd, msg, wParam, lParam );
}
}
}
void initD3D(HWND hwnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dparams;
ZeroMemory(&d3dparams, sizeof(D3DPRESENT_PARAMETERS));
d3dparams.hDeviceWindow = hwnd;
d3dparams.Windowed = FALSE;
d3dparams.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dparams.BackBufferHeight = 900;
d3dparams.BackBufferWidth = 1440;
d3dparams.SwapEffect = D3DSWAPEFFECT_FLIP;
d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_NOWINDOWCHANGES, &d3dparams, &d3ddevice);
d3ddevice->SetRenderState(D3DRS_LIGHTING, FALSE);
}
void Render()
{
// clear the window to a deep blue
d3ddevice->Clear(NULL, 0, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 20, 40, 100), 1.0f, 0);
d3ddevice->BeginScene(); // begins the 3D scene
// do 3D rendering on the back buffer here
d3ddevice->SetFVF(FVFcode);
D3DXMatrixIdentity(&matrix);
D3DXMatrixTranslation(&matrix, 900, 0, 0);
d3ddevice->SetTransform(D3DTS_WORLD, &matrix);
D3DXMATRIX out;
D3DXVECTOR3 eye(2,3,3);
D3DXVECTOR3 Lat(0,0,0);
D3DXVECTOR3 up(0,1,0);
D3DXMatrixLookAtLH(&out, &eye, &Lat, &up);
d3ddevice->SetTransform(D3DTS_VIEW, &out);
D3DXMATRIX pro;
D3DXMatrixPerspectiveFovLH(&pro,
D3DXToRadian(45), // the horizontal field of view
(FLOAT)1440 / (FLOAT)900, // aspect ratio
1.0f, // the near view-plane
100.0f); // the far view-plane
d3ddevice->SetTransform(D3DTS_PROJECTION, &pro);
d3ddevice->SetStreamSource(0, v_buffer, 0, sizeof(vertex));
d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddevice->EndScene(); // ends the 3D scene
d3ddevice->Present(NULL, NULL, NULL, NULL); // displays the created frame on the screen
}
void initGraphics()
{
vertex v [] =
{{320.0f, 50.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255)},
{520.0f, 400.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0)},
{120.0f, 400.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0)},
};
d3ddevice->CreateVertexBuffer( 3*sizeof(vertex), 0, FVFcode, D3DPOOL_DEFAULT, &v_buffer, NULL );
VOID* pVoid;
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
CopyMemory(pVoid, v, sizeof(v));
v_buffer->Unlock();
}
define.h:
#ifndef DEFINE_H_INCLUDED
#define DEFINE_H_INCLUDED
#define IDI_APP_ICON 1
#define FVFcode (D3DFVF_DIFFUSE | D3DFVF_XYZRHW)
//all the declarations and prototypes:
//Dx functions:
void initD3D (HWND);
void clearD3D (void);
void Render(void);
void initGraphics(void);
//constants:
LPDIRECT3D9 d3d;
D3DXMATRIX matrix;
LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL;
LPDIRECT3DDEVICE9 d3ddevice;
//Vertices Structure:
struct vertex
{
float x, y,z, rhw;
DWORD color;
};
void clearD3D ()
{
d3d->Release();
d3ddevice->Release();
v_buffer->Release();
}
#endif // DEFINE_H_INCLUDED
and I just have another resource file where I just imported the app icon, I know the code is so long and will take time to read, but I am so sorry I can't find any other solution for this. I also have another question, do I have to set the three matrices, world view and projection, to be able to make an effect like changing the triangles place using world matrix, do I have to set the other two matrices, to change it or only world?? Lastly, thanks for any replier so much, thanks fr his effort and time.
EDIT
The relevant parts/ parts related to transforms from the whole code -coz it is too long- are:
d3ddevice->BeginScene(); // begins the 3D scene
// do 3D rendering on the back buffer here
d3ddevice->SetFVF(FVFcode);
D3DXMATRIX matrix;
D3DXMatrixIdentity(&matrix);
D3DXMatrixTranslation(&matrix, 900, 0, 0);
d3ddevice->SetTransform(D3DTS_WORLD, &matrix);
D3DXMATRIX out;
D3DXVECTOR3 eye(2,3,3);
D3DXVECTOR3 Lat(0,0,0);
D3DXVECTOR3 up(0,1,0);
D3DXMatrixLookAtLH(&out, &eye, &Lat, &up);
d3ddevice->SetTransform(D3DTS_VIEW, &out);
D3DXMATRIX pro;
D3DXMatrixPerspectiveFovLH(&pro,
D3DXToRadian(45), // the horizontal field of view
(FLOAT)1440 / (FLOAT)900, // aspect ratio
1.0f, // the near view-plane
100.0f); // the far view-plane
d3ddevice->SetTransform(D3DTS_PROJECTION, &pro);
d3ddevice->SetStreamSource(0, v_buffer, 0, sizeof(vertex));
d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);
d3ddevice->EndScene(); // ends the 3D scene
So lets start with the basics:
The world matrix
Defined here
D3DXMATRIX matrix;
D3DXMatrixIdentity(&matrix);
D3DXMatrixTranslation(&matrix, 900, 0, 0);
d3ddevice->SetTransform(D3DTS_WORLD, &matrix);
This matrix defines the transformation from the origin that the vertices will have. In this case, you are translating the vertices 900 units to the positive X axis. I.e, if you render its position as (0,0,0), it will be actually at (900,0,0).
This matrix is used when you need to efficiently transform a static mesh, so you don't have to mess with the vertex buffer, only with a single matrix, which is much more efficent. This is the matrix that you should be look at in order to translate, rotate and skew.
The view matrix
Defined here:
D3DXMATRIX out;
D3DXVECTOR3 eye(2,3,3);
D3DXVECTOR3 Lat(0,0,0);
D3DXVECTOR3 up(0,1,0);
D3DXMatrixLookAtLH(&out, &eye, &Lat, &up);
d3ddevice->SetTransform(D3DTS_VIEW, &out);
This matrix defines the transformation that will take place in order to transform the vertex from world space into view space. That is, the relative position of the vertex to the camera. If all you want is rotate or translate the camera, this is where you should change.
The projection matrix
D3DXMATRIX pro;
D3DXMatrixPerspectiveFovLH(&pro,
D3DXToRadian(45), // the horizontal field of view
(FLOAT)1440 / (FLOAT)900, // aspect ratio
1.0f, // the near view-plane
100.0f); // the far view-plane
d3ddevice->SetTransform(D3DTS_PROJECTION, &pro);
This matrix defines how the vertices will be projected to screen space. Look at this image:
Objects closer to the camera than the near view plane or farther than the far view plane will not be shown. In the image, the green sphere will not be shown, since it is out of bounds.
The FOV angle in practice, means a "zoom" (not quite, but you can think like that).
This matrix is changed when you need some artifacts, like zooming, PIP and such.
In your case, it seems that you want to change just the world matrix. A good start would be using the D3DXMatrixTransformation function.
The basic problem is here:
#define FVFcode (D3DFVF_DIFFUSE | D3DFVF_XYZRHW)
D3DFVF_XYZRHW indicates the vertex has transformed positions and therefore the world, view and projection transforms should not be applied.
To fix, you'll need to change that D3DFVF_XYZRHW to D3DFVF_XYZ. Then the vertex structure needs the rhw dropped:
struct vertex
{
float x, y, z;
DWORD color;
};
and the initialization of v must be altered:
vertex v [] =
{{320.0f, 50.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255)},
{520.0f, 400.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0)},
{120.0f, 400.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0)},
};
That should get DirectX to apply the transformations. I haven't checked to see if there are additional problems with the math of the transformations.
Related
I'm using the SpriteFont/SpriteBatch classes to render text onto my game because quite frankly, i am tired of using Direct2D and DirectWrite... But everytime I draw text using SpriteFont, I get the text written on the screen, but it is written on a black background... The black background blocks the entire scene of my game.. is there any way to remove the black background and only keep the text?
Down below is my implementation of SpriteFont..
void RenderText(int FPS)
{
std::unique_ptr<DirectX::SpriteFont> Sprite_Font(new DirectX::SpriteFont(device, L"myfile.spritefont"));
std::unique_ptr<DirectX::SpriteBatch> Sprite_Batch(new DirectX::SpriteBatch(DevContext));
Sprite_Batch->Begin();
Sprite_Font->DrawString(Sprite_Batch.get(), L"FPS: ", DirectX::XMFLOAT2(200,200));
Sprite_Batch->End();
}
It seems to me that the black background is drawn because of the values that I specified in the function ClearRenderTargetView().
float BackgroundColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
DevContext->ClearRenderTargetView(RenderTarget, BackgroundColor); //This is where the black background gets drawn over my entire scene
Everytime i change BackgroundColor[4] to different values, the background color changes as well, respectably. How can I remove the black background from my game and only include the text?
Here is my entire code.
#include <Windows.h>
#include <SpriteFont.h>
#include <SpriteBatch.h>
#include <d3dcompiler.h>
#include <SimpleMath.h>
#pragma comment (lib, "dinput8.lib")
#pragma comment (lib, "D3D11.lib")
#pragma comment (lib, "d3dcompiler.lib")
LRESULT CALLBACK WindowProcedure(HWND, unsigned int, WPARAM, LPARAM);
void Create_Window(HINSTANCE&);
void Initialize_Direct3D11(HINSTANCE);
void Initialize_Rendering_Pipeline();
void Initialize_Sprites();
void Render_Frame();
void Render_Text();
void Create_Vertex_Buffer_for_triangle();
HWND MainWindow;
IDXGISwapChain * SwapChain;
ID3D11Device * device;
ID3D11DeviceContext * DevContext;
ID3D11RenderTargetView * RenderTarget;
ID3D11Buffer * VertexBuffer;
ID3D10Blob * VertexShader;
ID3D10Blob * PixelShader;
ID3D11VertexShader * VS;
ID3D11PixelShader * PS;
ID3D11InputLayout * inputLayout;
std::unique_ptr<DirectX::SpriteFont> Sprite_Font;
std::unique_ptr<DirectX::SpriteBatch> Sprite_Batch;
DirectX::SimpleMath::Vector2 m_fontPos;
const wchar_t* output = L"Hello World";
struct Vertex_Buffer
{
float Positions[3];
Vertex_Buffer(float x, float y, float z)
{
Positions[0] = x;
Positions[1] = y;
Positions[2] = z;
};
};
int WINAPI WinMain(HINSTANCE CurrentInstance, HINSTANCE PrevInstance, LPSTR ignore, int WindowShow)
{
MSG message;
HRESULT status;
Create_Window(CurrentInstance);
Initialize_Direct3D11(CurrentInstance);
Initialize_Sprites();
Initialize_Rendering_Pipeline();
Create_Vertex_Buffer_for_triangle();
while (true)
{
if (PeekMessage(&message, MainWindow, 0, 0, PM_REMOVE))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
else
{
Render_Frame();
Render_Text();
SwapChain->Present(0, 0);
}
}
}
void Initialize_Sprites()
{
Sprite_Font.reset(new DirectX::SpriteFont(device, L"myfile.spritefont"));
Sprite_Batch.reset(new DirectX::SpriteBatch(DevContext));
m_fontPos.x = 200;
m_fontPos.y = 200;
}
void Create_Window(HINSTANCE &CurrentInstance)
{
WNDCLASSEX windowclass;
ZeroMemory(&windowclass, sizeof(WNDCLASSEX));
windowclass.cbSize = sizeof(WNDCLASSEX);
windowclass.lpszClassName = L"Window Class";
windowclass.hInstance = CurrentInstance;
windowclass.lpfnWndProc = WindowProcedure;
windowclass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
windowclass.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClassEx(&windowclass);
MainWindow = CreateWindowEx(
0,
L"Window Class",
L"The Empire of Anatoria",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
NULL,
CurrentInstance,
NULL
);
ShowWindow(MainWindow, SW_SHOW);
}
void Render_Text()
{
DirectX::SimpleMath::Vector2 origin = Sprite_Font->MeasureString(output);
Sprite_Batch->Begin();
Sprite_Font->DrawString(Sprite_Batch.get(), output,
m_fontPos, DirectX::Colors::White, 0.f, origin);
Sprite_Batch->End();
}
void Initialize_Direct3D11(HINSTANCE instance)
{
DXGI_MODE_DESC BackBufferDesc;
DXGI_SWAP_CHAIN_DESC SwapChainDesc;
ZeroMemory(&BackBufferDesc, sizeof(DXGI_MODE_DESC));
BackBufferDesc.Width = 400;
BackBufferDesc.Height = 400;
BackBufferDesc.RefreshRate.Numerator = 60;
BackBufferDesc.RefreshRate.Denominator = 1;
BackBufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
ZeroMemory(&SwapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
SwapChainDesc.BufferDesc = BackBufferDesc;
SwapChainDesc.BufferCount = 1;
SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDesc.SampleDesc.Count = 1;
SwapChainDesc.SampleDesc.Quality = 0;
SwapChainDesc.OutputWindow = MainWindow;
SwapChainDesc.Windowed = TRUE;
SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&SwapChainDesc,
&SwapChain,
&device,
NULL,
&DevContext
);
ID3D11Texture2D * BackBuffer;
SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&BackBuffer);
device->CreateRenderTargetView(BackBuffer, NULL, &RenderTarget);
DevContext->OMSetRenderTargets(
1,
&RenderTarget,
NULL
);
BackBuffer->Release();
DevContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
void Initialize_Rendering_Pipeline()
{
D3DCompileFromFile(L"VertexShader.hlsl", 0, 0, "main", "vs_5_0", 0, 0, &VertexShader, 0);
D3DCompileFromFile(L"VertexShader.hlsl", 0, 0, "Pixel_Shader", "ps_5_0", 0, 0, &PixelShader, 0);
device->CreateVertexShader(VertexShader->GetBufferPointer(), VertexShader->GetBufferSize(), NULL, &VS);
device->CreatePixelShader(PixelShader->GetBufferPointer(), PixelShader->GetBufferSize(), NULL, &PS);
DevContext->VSSetShader(VS, 0, 0);
DevContext->PSSetShader(PS, 0, 0);
D3D11_VIEWPORT Raster;
ZeroMemory(&Raster, sizeof(D3D11_VIEWPORT));
Raster.MinDepth = 0.0f;
Raster.MaxDepth = 1.0f;
Raster.Width = 400;
Raster.Height = 400;
DevContext->RSSetViewports(1, &Raster);
D3D11_INPUT_ELEMENT_DESC InputLayout[1];
ZeroMemory(&InputLayout[0], sizeof(D3D11_INPUT_ELEMENT_DESC));
InputLayout[0].SemanticName = "POSITION";
InputLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
InputLayout[0].InputSlot = 0;
InputLayout[0].AlignedByteOffset = 0;
InputLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
device->CreateInputLayout(
InputLayout,
1,
VertexShader->GetBufferPointer(),
VertexShader->GetBufferSize(),
&inputLayout
);
DevContext->IASetInputLayout(inputLayout);
}
void Render_Frame()
{
float BackgroundColor[4] = {0.0f, 0.0f, 0.0f, 1.0f};
DevContext->ClearRenderTargetView(RenderTarget, BackgroundColor);
DevContext->Draw(3, 0);
}
void Create_Vertex_Buffer_for_triangle()
{
D3D11_BUFFER_DESC VertexBufferDesc;
D3D11_SUBRESOURCE_DATA VertexData;
UINT stride = sizeof(Vertex_Buffer);
UINT offset = 0;
ZeroMemory(&VertexBufferDesc, sizeof(D3D11_BUFFER_DESC));
VertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
VertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
VertexBufferDesc.CPUAccessFlags = 0;
VertexBufferDesc.ByteWidth = sizeof(Vertex_Buffer) * 3;
Vertex_Buffer VerticesData[] =
{
Vertex_Buffer(0.0f, 0.5f, 0.5f),
Vertex_Buffer(0.5f, -0.5f, 0.5f),
Vertex_Buffer(-0.5f, -0.5f, 0.5f)
};
ZeroMemory(&VertexData, sizeof(D3D11_SUBRESOURCE_DATA));
VertexData.pSysMem = VerticesData;
device->CreateBuffer(
&VertexBufferDesc,
&VertexData,
&VertexBuffer);
DevContext->IASetVertexBuffers(
0,
1,
&VertexBuffer,
&stride,
&offset
);
}
LRESULT CALLBACK WindowProcedure(HWND handle, unsigned int message, WPARAM ignore1, LPARAM ignore2)
{
switch (message)
{
case WM_CREATE:
return 0;
case WM_CLOSE:
DestroyWindow(handle);
return 0;
default:
return DefWindowProc(handle, message, ignore1, ignore2);
}
}
Here is the VertexShader.hlsl file
float4 main( float4 pos : POSITION ) : SV_POSITION
{
return pos;
}
float4 Pixel_Shader() : SV_TARGET
{
return float4(1.0f, 0.0f, 0.0f, 1.0f);
}
First, if your code snippet is accurate, you should not be creating the SpriteFont and SpriteBatch instance every frame. You only have to create them when the device changes.
By default, SpriteFont is drawing using pre-multiplied alpha blending modes, so if you are getting a fully "background color" image then something else is amiss in your pipeline state. It is likely that you are leaving some state in effect in the rendering between the clear and RenderText that is affecting the SpriteBatch renderer that you should reset.
It might also be the color you are using for the background clear which has the alpha set to 0 rather than 1. Try using:
float BackgroundColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
Try working through a few of the DirectX Tool Kit tutorials to make sure things are working in isolation and so you understand how the classes work, specifically Drawing text.
You and me have the same problem with SpriteFont. We forgot to reset the VertexBuffers and all other rendering states after the call to SpriteFont. See my post and the solution from Chuck Walbourn: DirectX::SpriteFont/SpriteBatch prevents 3D scene from drawing.
To quote Chuck:
You set the render state up for your scene in InitScene, but drawing anything else changes the state which is exactly what SpriteBatch does. I document which render states each object in DirectX Toolkit manipulates on the wiki. You need to set all the state your Draw requires each frame, not assume it is set forever, if you do more than a single draw.
See my question for additional links providing more information.
I have a simple red rectangle rendered in a window, and I created an arcball in order to rotate it in any direction. I was following the code from NeHe's Arcball Rotation tutorial.
The problem is that once the rectangle is rendered and the left mouse button is clicked, it spins like a top in the window. The mouse click-drag-stop update happens every time the mouse is moved, which is the reason why it spins that way. I am not able to figure out a way to restrict the rotation only for the duration of the click-drag-stop. How do I restrict the rotation? I have been trying to debug this for about 4-5 days now with no luck.
I added the original Arcball.h and Arcball.cpp files to my project, with one change to to the header file; I simply created a default constructor for the Arcball_t class with this line -
ArcBall_t() {};
The only other changes from the original project are that I threw the Update() function call into my code:
// ==========================================================================================
// function declarations
#define GET_PROC_ADDRESS( str ) wglGetProcAddress( str )
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DrawOpenGLScene(HDC hDC);
void Update();
HGLRC SetUpOpenGLContext(HWND hWnd);
// ==========================================================================================
// Trackball declarations
const float PI2 = 2.0*3.1415926535f; // PI Squared
GLUquadricObj *quadratic;
Point2fT MousePt; // NEW: Current Mouse Point
bool isClicked = false; // NEW: Clicking The Mouse?
bool isRClicked = false; // NEW: Clicking The Right Mouse Button?
bool isDragging = false; // NEW: Dragging The Mouse?
Matrix4fT Transform = { 1.0f, 0.0f, 0.0f, 0.0f, // NEW: Final Transform
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f };
Matrix3fT LastRot = { 1.0f, 0.0f, 0.0f, // NEW: Last Rotation
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f };
Matrix3fT ThisRot = { 1.0f, 0.0f, 0.0f, // NEW: This Rotation
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f };
// ==========================================================================================
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
static char szClassName[] = "Myclass";
static char szTitle[]="A Simple Win32 API OpenGL Program";
WNDCLASS wc;
MSG msg;
HWND hWnd;
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject (BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szClassName;
if (!RegisterClass (&wc))
return 0;
hWnd = CreateWindow(szClassName, szTitle,
WS_OVERLAPPEDWINDOW |
// NEED THESE for OpenGL calls to work!
WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
0, 0, 1024, 256,
NULL, NULL, hInstance, NULL);
ArcBall_t ArcBall(1024.0f, 256.0f); // NEW: ArcBall Instance
ShowWindow(hWnd, nCmdShow);
UpdateWindow( hWnd );
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return(msg.wParam);
}
// ==========================================================================================
//*******************************************************
// This is the brain of the loop
// Checks for a new key press or mouse movement
// renders when something is detected
//*******************************************************
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg,
WPARAM wParam, LPARAM lParam )
{
HDC hDC;
static HGLRC hRC; // Note this is STATIC!
PAINTSTRUCT ps;
switch (msg)
{
case WM_CREATE:
// Select a pixel format and create a rendering context
hRC = SetUpOpenGLContext(hWnd);
break;
case WM_PAINT:
// Draw the scene
// Get a DC, make RC current & associate it with this DC
hDC = BeginPaint(hWnd, &ps);
wglMakeCurrent(hDC, hRC);
DrawOpenGLScene(hDC); // Draw
// We're done with the RC, so deselect it
wglMakeCurrent(NULL, NULL);
EndPaint(hWnd, &ps);
break;
//*NEW* Mouse based messages for arcball
case WM_LBUTTONUP:
isClicked = false;
break;
case WM_RBUTTONUP:
isRClicked = false;
break;
case WM_LBUTTONDOWN:
isClicked = true;
break;
case WM_RBUTTONDOWN:
isRClicked = true;
break;
case WM_MOUSEMOVE:
MousePt.s.X = (GLfloat)LOWORD(lParam);
MousePt.s.Y = (GLfloat)HIWORD(lParam);
isClicked = (LOWORD(wParam) & MK_LBUTTON) ? true : false;
isRClicked = (LOWORD(wParam) & MK_RBUTTON) ? true : false;
Update();
RedrawWindow(hWnd, NULL, NULL, RDW_INTERNALPAINT);
break;
case WM_DESTROY:
// Clean up and terminate
wglDeleteContext(hRC);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return (0);
}
// ==========================================================================================
//*******************************************************
// SetUpOpenGL sets the pixel format and a rendering
// context then returns the RC
//*******************************************************
HGLRC SetUpOpenGLContext(HWND hWnd)
{
static PIXELFORMATDESCRIPTOR pfd = {
sizeof (PIXELFORMATDESCRIPTOR), // strcut size
1, // Version number
PFD_DRAW_TO_WINDOW | // Flags, draw to a window,
PFD_SUPPORT_OPENGL | // use OpenGL
PFD_DOUBLEBUFFER, // Use a double buffer
PFD_TYPE_RGBA, // RGBA pixel values
32, // 24-bit color
0, 0, 0, // RGB bits & shift sizes.
0, 0, 0, // Don't care about them
0, 0, // No alpha buffer info
0, 0, 0, 0, 0, // No accumulation buffer
32, // 32-bit depth buffer
8, // No stencil buffer
0, // No auxiliary buffers
PFD_MAIN_PLANE, // Layer type
0, // Reserved (must be 0)
0, // No layer mask
0, // No visible mask
0 // No damage mask
};
int nMyPixelFormatID;
HDC hDC;
HGLRC hRC;
hDC = GetDC(hWnd);
nMyPixelFormatID = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, nMyPixelFormatID, &pfd);
hRC = wglCreateContext(hDC);
ReleaseDC(hWnd, hDC);
quadratic=gluNewQuadric(); // Create A Pointer To The Quadric Object
gluQuadricNormals(quadratic, GLU_SMOOTH); // Create Smooth Normals
gluQuadricTexture(quadratic, GL_TRUE); // Create Texture Coords
return hRC;
}
// ==========================================================================================
// simple test code - rectangle/triangle
void DrawOpenGLScene(HDC hDC)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode( GL_MODELVIEW );
glTranslatef(0.0f, 0.0f, 0.0f);
glColor3f(1.0, 0.0, 0.0); // drawing color
glBegin(GL_POLYGON); // define the rectangle
glVertex2f(-0.5,-0.5);
glVertex2f(-0.5,0.5);
glVertex2f(0.5,0.5);
glVertex2f(0.5,-0.5);
glEnd();
glMultMatrixf(Transform.M);
glFlush(); // force execution
SwapBuffers(hDC);
}
// ==========================================================================================
void Update () // Perform Motion Updates Here
{
ArcBall_t ArcBall;
if (isRClicked) // If Right Mouse Clicked, Reset All Rotations
{
Matrix3fSetIdentity(&LastRot); // Reset Rotation
Matrix3fSetIdentity(&ThisRot); // Reset Rotation
Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot); // Reset Rotation
}
if (!isDragging) // Not Dragging
{
if (isClicked) // First Click
{
isDragging = true; // Prepare For Dragging
LastRot = ThisRot; // Set Last Static Rotation To Last Dynamic One
ArcBall.click(&MousePt); // Update Start Vector And Prepare For Dragging
}
}
else
{
if (isClicked) // Still Clicked, So Still Dragging
{
Quat4fT ThisQuat;
ArcBall.drag(&MousePt, &ThisQuat); // Update End Vector And Get Rotation As Quaternion
Matrix3fSetRotationFromQuat4f(&ThisRot, &ThisQuat); // Convert Quaternion Into Matrix3fT
Matrix3fMulMatrix3f(&ThisRot, &LastRot); // Accumulate Last Rotation Into This One
Matrix4fSetRotationFromMatrix3f(&Transform, &ThisRot); // Set Our Final Transform's Rotation From This One
}
else // No Longer Dragging
isDragging = false;
}
}
EDIT: I fixed the issue with the uncontrollable scene rotation by inserting a check within the case WM_MOUSEMOVE: handler of the WndProc() routine. The check was: if(isClicked == true) { //code }, and that seemed to do the trick. It no longer spins like a top. However, I still do not have fine control over the rotation; it still spins like a top within the click-drag-release duration.
Assuming your arcball.drag and arcball.click functions are correct, the only problem with your code is that you are applying the rotation after you draw and your need to do it before.
Your Code:
glTranslatef(0.0f, 0.0f, 0.0f);
glColor3f(1.0, 0.0, 0.0); // drawing color
glBegin(GL_POLYGON); // define the rectangle
glVertex2f(-0.5,-0.5);
glVertex2f(-0.5,0.5);
glVertex2f(0.5,0.5);
glVertex2f(0.5,-0.5);
glEnd();
glMultMatrixf(Transform.M);
Try changing it to:
glTranslatef(0.0f, 0.0f, 0.0f);
glMultMatrixf(Transform.M);
glColor3f(1.0, 0.0, 0.0); // drawing color
glBegin(GL_POLYGON); // define the rectangle
glVertex2f(-0.5,-0.5);
glVertex2f(-0.5,0.5);
glVertex2f(0.5,0.5);
glVertex2f(0.5,-0.5);
glEnd();
Although, based on the code you have provided, I dont think your image should rotate at all BECAUSE you are applying the rotation after. I think more code might be needed to find your issue.
I'm trying to create a window that uses directx to draw opaque content on top of a transparent view (i.e. the desktop shows through). With DirectX11 I'm trying to do the following, but it's not making the background transparent. In fact, any opacity value I put in gives me the exact same results.
What I'm doing:
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
deviceContext->ClearRenderTargetView(backBuffer, color);
Working repro code (main.cpp):
#include <Windows.h>
#include <windowsx.h>
#pragma comment (lib, "Winmm.lib")
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#include <d3dcompiler.h>
#pragma comment(lib, "D3DCompiler.lib")
#include <dwmapi.h>
#pragma comment (lib, "Dwmapi.lib")
// Globals
IDXGISwapChain *swapChain;
ID3D11Device *device;
ID3D11DeviceContext *deviceContext;
ID3D11RenderTargetView *backBuffer;
ID3D11InputLayout *inputLayout; // the pointer to the input layout
ID3D11VertexShader *vertexShader; // the pointer to the vertex shader
ID3D11PixelShader *pixelShader; // the pointer to the pixel shader
ID3D11Buffer *vertexBuffer; // the pointer to the vertex buffer
void InitializeDirectX(HWND hWnd);
void LoadTriangle();
struct Vertex {
float x, y, z;
float color[4];
};
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
// Globals
const LPCWSTR ClassName = L"className";
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// the handle for the window, filled by a function
HWND hWnd;
// this struct holds information for the window class
WNDCLASSEX wc;
// Pick out window size
int windowHeight = 400;
int windowWidth = 400;
// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = ClassName;
// register the window class
RegisterClassEx(&wc);
// Window style
DWORD exStyle = WS_EX_LAYERED | WS_EX_TOPMOST;
DWORD style = WS_POPUP;
// create the window and use the result as the handle
hWnd = CreateWindowEx(
exStyle, // extended styles
ClassName, // name of the window class
L"TestOverlay", // title of the window
style, // window style
0, // x-position of the window
0, // y-position of the window
400, // width of the window
400, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
SetWindowPos(hWnd,
HWND_TOPMOST,
0, 0,
windowWidth, windowHeight,
SWP_SHOWWINDOW);
// Show the window
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
// Make the window transparent
SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 255, LWA_ALPHA | LWA_COLORKEY);
// NOTE: If I uncomment DwmExtendFrameIntoClientArea then it becomes transparent, otherwise its a black screen
MARGINS dwmMargin = { -1 };
//DwmExtendFrameIntoClientArea(hWnd, &dwmMargin);
// DirectX
InitializeDirectX(hWnd);
LoadTriangle();
// enter the main loop:
MSG msg;
BOOL gotMessage;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
// DirectX stuff
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
deviceContext->ClearRenderTargetView(backBuffer, color);
// Draw triangle
UINT stride = sizeof(Vertex);
UINT offset = 0;
deviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
deviceContext->Draw(3, 0);
swapChain->Present(0, 0);
}
}
return msg.wParam;
}
void InitializeDirectX(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapChain,
&device,
NULL,
&deviceContext);
// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// use the back buffer address to create the render target
device->CreateRenderTargetView(pBackBuffer, NULL, &backBuffer);
pBackBuffer->Release();
// set the render target as the back buffer
deviceContext->OMSetRenderTargets(1, &backBuffer, NULL);
// Set the viewport size
RECT cRect;
GetClientRect(hWnd, &cRect);
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = cRect.right - cRect.left;
viewport.Height = cRect.bottom - cRect.top;
deviceContext->RSSetViewports(1, &viewport);
// Initialize pipeline stuff
ID3D10Blob *VS, *PS;
// compile shader
D3DCompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, &VS, 0);
D3DCompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, &PS, 0);
// encapsulate both shaders into shader objects
device->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &vertexShader);
device->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pixelShader);
deviceContext->VSSetShader(vertexShader, 0, 0);
deviceContext->PSSetShader(pixelShader, 0, 0);
// create input layout object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
device->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &inputLayout);
deviceContext->IASetInputLayout(inputLayout);
}
void LoadTriangle()
{
// create a triangle using the VERTEX struct
Vertex OurVertices[] =
{
{ 0.0f, 0.5f, 0.0f, { 1.0f, 0.0f, 0.0f, 1.0f } },
{ 0.45f, -0.5, 0.0f, { 0.0f, 1.0f, 0.0f, 1.0f } },
{ -0.45f, -0.5f, 0.0f, { 0.0f, 0.0f, 1.0f, 1.0f } }
};
// create the vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC; // write access access by CPU and GPU
bd.ByteWidth = sizeof(Vertex)* 3; // size is the VERTEX struct * 3
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; // use as a vertex buffer
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // allow CPU to write in buffer
device->CreateBuffer(&bd, NULL, &vertexBuffer); // create the buffer
// copy the vertices into the buffer
D3D11_MAPPED_SUBRESOURCE ms;
deviceContext->Map(vertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
memcpy(ms.pData, OurVertices, sizeof(OurVertices)); // copy the data
deviceContext->Unmap(vertexBuffer, NULL); // unmap the buffer
}
Shader file (shaders.shader):
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
VOut output;
output.position = position;
output.color = color;
return output;
}
float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
return color;
}
If you uncomment the DwmExtendFrameIntoClientArea call on line 119ish, then it gets the effect I'm looking for. I'm wondering if there's a way to get the same effect without the use of dwm (for reasons I won't go into).
Any ideas?
Edit: Added full source code of working example. Found out that if I make a call to DwmExtendFrameIntoClientArea, then I get the effect I want. But I'd still like to know if its possible to do it without using dwm apis.
You can't make a Window transparent with DirectX only, The following code only clear the background color to black.
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
To achieve transparent effect of your window, you need to involve some win32 stuff, SetLayeredWindowAttributes is your choice.
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED) ;
SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 100, LWA_ALPHA);
UPDATE:
Workable code draw nothing but make the window transparent in green color.
#include <Windows.h>
#include <windowsx.h>
#pragma comment (lib, "Winmm.lib")
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#include <d3dcompiler.h>
#pragma comment(lib, "D3DCompiler.lib")
#include <dwmapi.h>
#pragma comment (lib, "Dwmapi.lib")
// Globals
IDXGISwapChain *swapChain;
ID3D11Device *device;
ID3D11DeviceContext *deviceContext;
ID3D11RenderTargetView *backBuffer;
void InitializeDirectX(HWND hWnd);
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
// Globals
const LPCWSTR ClassName = L"className";
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = ClassName;
// register the window class
RegisterClassEx(&wc);
// create the window and use the result as the handle
HWND hWnd = CreateWindowEx(
NULL, // extended styles
ClassName, // name of the window class
L"TestOverlay", // title of the window
WS_OVERLAPPEDWINDOW, // window style
0, // x-position of the window
0, // y-position of the window
400, // width of the window
400, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Make the window transparent
SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED) ;
SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 128, LWA_ALPHA);
// DirectX
InitializeDirectX(hWnd);
// enter the main loop:
MSG msg;
BOOL gotMessage;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
// DirectX stuff
float color[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
deviceContext->ClearRenderTargetView(backBuffer, color);
swapChain->Present(0, 0);
}
}
return msg.wParam;
}
void InitializeDirectX(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapChain,
&device,
NULL,
&deviceContext);
// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// use the back buffer address to create the render target
device->CreateRenderTargetView(pBackBuffer, NULL, &backBuffer);
pBackBuffer->Release();
// set the render target as the back buffer
deviceContext->OMSetRenderTargets(1, &backBuffer, NULL);
// Set the viewport size
RECT cRect;
GetClientRect(hWnd, &cRect);
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = cRect.right - cRect.left;
viewport.Height = cRect.bottom - cRect.top;
deviceContext->RSSetViewports(1, &viewport);
}
I am trying to texture a quad, with a character, that is within the glyph texture (obtained with D3DXFont::GetGlyphData).
Most of the characters are drawn correctly.
However characters such as: 'F', and 'A' are being drawn upside down.
None of the glyphs when saved to file seem to be upside down.
#include <Windows.h>
#include <d3d9.h>
#include <d3dx9.h>
// global declarations
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
ID3DXSprite* pSprite;
ID3DXFont* pFont;
void drawCharacter(const char c, int screenX, int screenY, D3DCOLOR color)
{
struct CUSTOMVERTEX
{
float x, y, z, rhw, tu, tv;
};
WORD glyphIndex;
IDirect3DTexture9* texture;
RECT rect;
POINT point;
D3DSURFACE_DESC desc;
if(GetGlyphIndices(pFont->GetDC(), &c, 1, &glyphIndex, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR)
return;
if(pFont->GetGlyphData(glyphIndex, &texture, &rect, &point) != S_OK)
return;
if(texture->GetLevelDesc(0, &desc) != D3D_OK)
return;
const float glyphWidth = static_cast<float>(desc.Width);
const float glyphHeight = static_cast<float>(desc.Height);
const float charWidth = static_cast<float>(rect.right - rect.left);
const float charHeight = static_cast<float>(rect.bottom - rect.top);
const float startX = static_cast<float>(screenY);
const float startY = static_cast<float>(screenY);
float u = (static_cast<float>(rect.left) + 0.5f) / glyphWidth;
float v = (static_cast<float>(rect.top) + 0.5f) / glyphHeight;
float u2 = u + (charWidth / glyphWidth);
float v2 = v + (charHeight / glyphHeight);
const CUSTOMVERTEX char_quad[4] =
{
// Bottom left vertex
{
startX, startY, 0.0f, 1.0f,
u, v2
},
// Bottom right vertex
{
startX + charWidth, startY, 0.0f, 1.0f,
u2, v2
},
// Top right vertex
{
startX + charWidth, startY + charHeight, 0.0f, 1.0f,
u2, v
},
// Top left vertex
{
startX, startY + charHeight, 0.0f, 1.0f,
u, v
}
};
// D3DXSaveTextureToFileA("glyph.dds", D3DXIFF_DDS, texture, 0);
d3ddev->SetTexture(0, texture);
d3ddev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, char_quad, sizeof(CUSTOMVERTEX));
}
// this is the function used to render a single frame
void render_frame()
{
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
pSprite->Begin(D3DXSPRITE_ALPHABLEND);
// select which vertex format we are using
d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1);
drawCharacter('F', 100, 100, D3DCOLOR_XRGB(0, 255, 0));
pSprite->End();
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc = {};
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = "WindowClass";
if(!RegisterClassEx(&wc))
{
return 0;
}
hWnd = CreateWindowEx(NULL,
"WindowClass",
"Our Direct3D Program",
WS_OVERLAPPEDWINDOW,
0, 0,
800, 600,
NULL,
NULL,
hInstance,
NULL);
if(!hWnd)
{
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
d3d = Direct3DCreate9(D3D_SDK_VERSION);
if(!d3d)
{
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
D3DPRESENT_PARAMETERS d3dpp = {};
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = 800;
d3dpp.BackBufferHeight = 600;
// create a device class using this information and the info from the d3dpp stuct
if(d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev) != D3D_OK)
{
d3d->Release();
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
if(D3DXCreateSprite(d3ddev, &pSprite) != D3D_OK)
{
d3d->Release();
d3ddev->Release();
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
if(D3D_OK != D3DXCreateFont(d3ddev,
14,
0,
FW_BOLD,
1,
FALSE,
DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,
ANTIALIASED_QUALITY,
DEFAULT_PITCH | FF_DONTCARE,
"Georgia",
&pFont))
{
d3d->Release();
d3ddev->Release();
pSprite->Release();
UnregisterClass(wc.lpszClassName, hInstance);
return 0;
}
MSG msg;
while(TRUE)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(msg.message == WM_QUIT)
break;
render_frame();
}
d3d->Release();
d3ddev->Release();
pSprite->Release();
pFont->Release();
UnregisterClass(wc.lpszClassName, hInstance);
return msg.wParam;
}
Edit: Updated to include a full example of my problem.
It's been a while since I did any DirextX stuff, but I think it may be to do with the quad texture coordinate ordering. I ran your code and tried this:
const CUSTOMVERTEX char_quad[4] =
{
// Top left vertex
{
startX, startY + charHeight, 0.0f, 1.0f,
u, v2
},
// Top right vertex
{
startX + charWidth, startY + charHeight, 0.0f, 1.0f,
u2, v2
},
// Bottom right vertex
{
startX + charWidth, startY, 0.0f, 1.0f,
u2, v
},
// Bottom left vertex
{
startX, startY, 0.0f, 1.0f,
u, v
}
};
which output the characters ABCDEF all Ok.
I can't exactly remember how to specify the custom vertex, so I guess I was probably lucky with the above hack :)
Had another look at this and I think the coords should be ordered to render the TRIANGLEFAN in Clockwise Winding Order (so it doesn't get backface culled). Reordering the coords makes more sense I think:
// TRIANGLEFAN coords:
// v1-----v2 clockwise winding order
// | / |
// | / |
// v0-----v3
//
const CUSTOMVERTEX char_quad[4] =
{
// Bottom left vertex
{
startX, startY, 0.0f, 1.0f,
u, v
},
// Top left vertex
{
startX, startY + charHeight, 0.0f, 1.0f,
u, v2
},
// Top right vertex
{
startX + charWidth, startY + charHeight, 0.0f, 1.0f,
u2, v2
},
// Bottom right vertex
{
startX + charWidth, startY, 0.0f, 1.0f,
u2, v
},
};
Below is the code I am using and the error happens when I attempt to check for the available tenique within the FX file. I'm not sure if the FX file is bad or what. I am using the default simple.fx that comes with DirectX.
// Include the basic Windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>
#include <d3d9.h>
#include <d3dx9.h>
// Define the screen resolution and keyboard macros
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
// Include the Direct3D library files
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")
// Global declarations
LPDIRECT3D9 d3d; // The pointer to our Direct3D interface
LPDIRECT3DDEVICE9 d3ddev; // The pointer to the device class
// Mesh declarations
LPD3DXMESH meshTeapot; // Define the mesh pointer
// effect declarations
LPD3DXEFFECT effect; // Define the effect pointer
D3DXHANDLE technique; // Define the handle for the best technique
// Function prototypes
void initD3D(HWND hWnd); // Sets up and initializes Direct3D
void render_frame(void); // Renders a single frame
void cleanD3D(void); // Closes Direct3D and releases memory
void init_graphics(void); // 3D declarations
// The WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// The entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, L"WindowClass", L"Our Direct3D Program",
WS_EX_TOPMOST | WS_POPUP, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
// Set up and initialize Direct3D
initD3D(hWnd);
// Enter the main loop:
MSG msg;
while(TRUE)
{
DWORD starting_point = GetTickCount();
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
render_frame();
// Check the 'escape' key
if(KEY_DOWN(VK_ESCAPE))
PostMessage(hWnd, WM_DESTROY, 0, 0);
while ((GetTickCount() - starting_point) < 25);
}
// Clean up DirectX and COM
cleanD3D();
return msg.wParam;
}
// This is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// This function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
// Create a device class using this information and the information from the d3dpp stuct
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
init_graphics(); // Call the function to initialize the triangle
LPD3DXBUFFER errorlog; // For storing errors
// Load the effect file
D3DXCreateEffectFromFile(d3ddev, L"simple.fx", 0, 0, 0, 0, &effect, &errorlog);
// Find the best technique
effect->FindNextValidTechnique(NULL, &technique);
return;
}
// This is the function used to render a single frame
void render_frame(void)
{
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
// Set the view transform
D3DXMATRIX matView; // The view transform matrix
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (0.0f, 3.0f, 6.0f), // The camera position
&D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // The look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // The up direction
effect->SetMatrix("View", &matView);
// Set the projection transform
D3DXMATRIX matProjection; // The projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(45), // The horizontal field of view
(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // Aspect ratio
1.0f, // The near view-plane
100.0f); // The far view-plane
effect->SetMatrix("Projection", &matProjection);
// Set the world transform
static float index = 0.0f; // An ever-increasing float value
index+=0.03f;
D3DXMATRIX matRotateY; // A matrix to store the rotation for each triangle
D3DXMatrixRotationY(&matRotateY, index); // The rotation matrix
effect->SetMatrix("World", &matRotateY);
effect->Begin(NULL, NULL); // Begin using the effect
effect->BeginPass(0); // Begin the pass
// Render whatever
meshTeapot->DrawSubset(0);
effect->EndPass(); // End the pass
effect->End(); // End the effect
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
return;
}
// This is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
meshTeapot->Release(); // Close and release the teapot mesh
effect->Release(); // Close and release the effect
d3ddev->Release(); // Close and release the 3D device
d3d->Release(); // Close and release Direct3D
return;
}
// This is the function that puts the 3D models into video RAM
void init_graphics(void)
{
D3DXCreateTeapot(d3ddev, &meshTeapot, NULL); // Create the teapot
return;
}
I presume you have copied the code from www.directxtutorial.com. I had the same problem.
You should keep track of the errors the Effect compiler throws at you. Convert the errorlog variable to a string in order to read the errors properly:
char * Error = (char *)errorlog->GetBufferPointer();
The first error you get is:
error X3539: ps_1_x is no longer supported; use /Gec in fxc to automatically upgrade to ps_2_0
It seems that ps_1_x is not supported. So if you open the simple.fx file, you should find something like this:
PixelShader = compile ps_1_1 PS();
Change ps_1_1 to ps_2_0 and everything should run like a charm.
I forgot to mention that you should only try to get a buffer pointer from the errorlog if it's not NULL, so:
if(errorlog)
{
char * Error = (char *)errorlog->GetBufferPointer();
// And do the output somewhere
}
I had the same problem.This is my code and solution:
//create pixel shader
ID3DXBuffer* codeBuffer = 0;
ID3DXBuffer* errorBuffer = 0;
HRESULT hr = D3DXCompileShaderFromFile("ps.txt",
0,
0,
"PS_Main", // entry point function name
"ps_2_0", //ps_1_1 is error X3539
D3DXSHADER_DEBUG,
&codeBuffer,
&errorBuffer,
&pixelConstTable);