Drawing a circle in directx 9 - c++

I'm having a hard time figuring out how to draw a circle in directx. I'm able to draw a triangle, so I imagined that I might be able to draw one by just rotating a triangle in a circle. However, I'm absolutely stumped. I've been scouring the net for hours with no luck. Can anyone help me out? Here's my code:
Main.cpp
#include "Engine.h"
#include "Box2D.h"
#include "Triangle2D.h"
class MyApp : public Engine {
public:
Box2D box2D;
Triangle2D triangle2D;
void OnStartup() override {
box2D.New(10.0f, 10.0f, 100.0f, 100.0f, D3DCOLOR_ARGB(0xff, 0x00, 0x00, 0xff));
triangle2D.New(150.0f, 10.0f, 100.0f, 100.0f, D3DCOLOR_ARGB(0xff, 0xff, 0x00, 0x00));
}
void OnShutdown() override {
box2D.Delete();
triangle2D.Delete();
}
void OnDraw() override {
box2D.Draw();
triangle2D.Draw();
}
void OnMouseDown(int x, int y) {
Debug("%d %d\n", x, y);
}
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MyApp app;
app.Run();
return 0;
}
Engine.cpp
#include "Engine.h"
// Initialize the classes static variables
Engine* Engine::_ENGINE = NULL;
// Returns the current instance of this class
Engine* Engine::GetInstance()
{
return _ENGINE;
}
// Constructor
Engine::Engine()
: _exit(false)
, _window(NULL)
, _directx(NULL)
, _device(NULL)
{
_ENGINE = this;
}
// Deconstructor
Engine::~Engine() {
_ENGINE = NULL;
}
// Run the core main event loop, start to finish
bool Engine::Run() {
// Create the Windows class
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_CLASSDC;
wc.lpfnWndProc = _WND_PROC;
wc.hInstance = GetModuleHandle(NULL);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = _GetModuleName();
RegisterClassEx(&wc);
// Adjust the window rect for the flags
RECT rect;
SetRect(&rect, 0, 0, _WIDTH, _HEIGHT);
const DWORD windowFlags = WS_OVERLAPPED | WS_CAPTION | WS_CLIPCHILDREN | WS_SYSMENU | WS_MINIMIZEBOX;
AdjustWindowRectEx(&rect, windowFlags, FALSE, 0);
// Create the window
_window = CreateWindowEx(0, _GetModuleName(), _GetModuleName(), windowFlags, 0, 0, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandle(NULL), NULL);
if (_window == NULL)
return false;
// Move the window to the center of the screen
RECT system;
SystemParametersInfo(SPI_GETWORKAREA, 0, &system, 0);
MoveWindow(_window, (system.right - system.left) / 2 - (rect.right - rect.left) / 2, (system.bottom - system.top) / 2 - (rect.bottom - rect.top) / 2, rect.right - rect.left, rect.bottom - rect.top, TRUE);
// Startup Direct X
if (_DirectXStartup() == false)
return false;
// Call our startup callback
OnStartup();
// Show the window
ShowWindow(_window, SW_SHOWNORMAL);
// Run the event loop
MSG msg;
ULONGLONG timer = GetTickCount64();
while (!_exit) {
// Handle normal system events
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Run the timer at the framerate
if (timer + 1000 / _FPS < GetTickCount64()) {
timer = GetTickCount64();
// Clear the buffer
_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0x00, 0xff, 0x00), 1.0f, NULL);
// Call our draw callback every frame
OnDraw();
// Render to screen
_device->Present(NULL, NULL, NULL, NULL);
}
}
// Hide the window to avoid flicker
ShowWindow(_window, SW_HIDE);
// Call our shutdown callback
OnShutdown();
// Shutdown Direct X
_DirectXShutdown();
// Cleanup and destroy the window
DestroyWindow(_window);
UnregisterClass(_GetModuleName(), GetModuleHandle(NULL));
return true;
}
// Return the DirectX device, needed by other DirectX objects
LPDIRECT3DDEVICE9 Engine::GetDevice() {
return _device;
}
// Return our width
int Engine::GetWidth() {
return _WIDTH;
}
// Return our height
int Engine::GetHeight() {
return _HEIGHT;
}
// Our own custom debug string
void Engine::Debug(const char* message, ...) {
#if _DEBUG
if (message) {
va_list args;
va_start(args, message);
int size = vsnprintf(NULL, 0, message, args);
if (size > 0) {
char* string = new char[size + 1];
vsnprintf(string, size + 1, message, args);
OutputDebugStringA(string);
delete[] string;
}
va_end(args);
}
#endif
}
// This is the Windows callback
LRESULT CALLBACK Engine::_WND_PROC(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// If we do not have access to an instance of our engine, do nothing
if (Engine::_ENGINE == NULL)
return DefWindowProc(hwnd, uMsg, wParam, lParam);
// Handle system messages
switch (uMsg) {
case WM_LBUTTONDOWN:
Engine::_ENGINE->OnMouseDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if ((lParam & (1 << 30)) == 0)
Engine::_ENGINE->OnKeyDown((int)wParam);
return 0;
case WM_CHAR:
if ((int)wParam <= 127 && isprint((int)wParam) && (lParam & (1 << 30)) == 0)
Engine::_ENGINE->OnASCIIDown((char)wParam);
return 0;
case WM_CLOSE:
Engine::_ENGINE->_exit = true;
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
// Custom function for getting our exe name
WCHAR* Engine::_GetModuleName() {
static WCHAR* TITLE = NULL;
static WCHAR BUFFER[MAX_PATH];
if (TITLE != NULL)
return TITLE;
// Remove the path
GetModuleFileName(NULL, BUFFER, MAX_PATH);
TITLE = wcsrchr(BUFFER, '\\');
if (TITLE == NULL) {
wcscpy(BUFFER, L"Application");
TITLE = BUFFER;
return TITLE;
}
TITLE++;
// Remove the extension
WCHAR* ext = wcsrchr(BUFFER, '.');
if (ext)
*ext = 0;
return TITLE;
}
// Startup DirectX here
bool Engine::_DirectXStartup() {
// Startup Direct X
_directx = Direct3DCreate9(D3D_SDK_VERSION);
if (_directx == NULL)
return false;
// Create a Direct X device
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.hDeviceWindow = _window;
d3dpp.BackBufferWidth = _WIDTH;
d3dpp.BackBufferHeight = _HEIGHT;
d3dpp.BackBufferCount = 1;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
HRESULT result = _directx->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, _window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &_device);
if (FAILED(result))
result = _directx->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, _window, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &_device);
if (FAILED(result))
return false;
return true;
}
// Shutdown DirectX here
bool Engine::_DirectXShutdown() {
if (_device) {
_device->Release();
_device = NULL;
}
if (_directx) {
_directx->Release();
_directx = NULL;
}
return true;
}
Engine.h
#ifndef _ENGINE_H_
#define _ENGINE_H_
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <d3d9.h>
#include <d3dx9.h>
class Engine {
public:
// Return the current singleton of this Engine class
static Engine* GetInstance();
// Constructor and deconstructor
Engine();
virtual ~Engine();
// Run the Engine class
bool Run();
// Return useful information about the class
LPDIRECT3DDEVICE9 GetDevice();
int GetWidth();
int GetHeight();
// Use for debug output
static void Debug(const char* message, ...);
// Virtual callbacks
virtual void OnStartup() {}
virtual void OnShutdown() {}
virtual void OnMouseDown(int x, int y) {}
virtual void OnKeyDown(int key) {}
virtual void OnASCIIDown(char key) {}
virtual void OnDraw() {}
private:
static Engine* _ENGINE;
static const int _WIDTH = 854;
static const int _HEIGHT = 480;
static const int _FPS = 60;
bool _exit;
HWND _window;
LPDIRECT3D9 _directx;
LPDIRECT3DDEVICE9 _device;
static LRESULT CALLBACK _WND_PROC(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
WCHAR* _GetModuleName();
bool _DirectXStartup();
bool _DirectXShutdown();
};
#endif // _ENGINE_H_
Triangle2D.h
#ifndef _TRIANGLE_2D_H_
#define _TRIANGLE_2D_H_
#include "Engine.h"
class Triangle2D {
public:
Triangle2D();
bool New(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color);
void Delete();
void Draw();
void Draw(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color);
private:
struct CustomVertex {
FLOAT x, y, z, w;
DWORD color;
};
static const DWORD _FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE;
LPDIRECT3DVERTEXBUFFER9 _vb;
};
#endif // _BOX_2D_H_
Triangle2D.cpp
#include "Triangle2D.h"
Triangle2D::Triangle2D()
: _vb(NULL)
{
}
bool Triangle2D::New(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color) {
if (FAILED(Engine::GetInstance()->GetDevice()->CreateVertexBuffer(sizeof(CustomVertex)* 4, D3DUSAGE_WRITEONLY, _FVF, D3DPOOL_DEFAULT, &_vb, NULL)))
return false;
CustomVertex* vertices;
_vb->Lock(0, 0, (void**)&vertices, 0);
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[0].w = 1.0f;
vertices[0].color = color;
vertices[1].x = x + width;
vertices[1].y = y;
vertices[1].z = 0.0f;
vertices[1].w = 1.0f;
vertices[1].color = color;
vertices[2].x = x;
vertices[2].y = y + height;
vertices[2].z = 0.0f;
vertices[2].w = 1.0f;
vertices[2].color = color;
_vb->Unlock();
return true;
}
void Triangle2D::Delete(){
if (_vb) {
_vb->Release();
_vb = NULL;
}
}
void Triangle2D::Draw() {
Engine::GetInstance()->GetDevice()->BeginScene();
Engine::GetInstance()->GetDevice()->SetFVF(_FVF);
Engine::GetInstance()->GetDevice()->SetStreamSource(0, _vb, 0, sizeof(CustomVertex));
Engine::GetInstance()->GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
Engine::GetInstance()->GetDevice()->EndScene();
}
void Triangle2D::Draw(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color) {
CustomVertex* vertices;
_vb->Lock(0, 0, (void**)&vertices, 0);
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[0].w = 1.0f;
vertices[0].color = color;
vertices[1].x = x + width;
vertices[1].y = y;
vertices[1].z = 0.0f;
vertices[1].w = 1.0f;
vertices[1].color = color;
vertices[2].x = x;
vertices[2].y = y + height;
vertices[2].z = 0.0f;
vertices[2].w = 1.0f;
vertices[2].color = color;
_vb->Unlock();
Draw();
}

Direct3D does not draw "circles". It only natively draws three fundamental primitives: points, lines, and triangles. There are lots of options for how it draws those things, but that's all it can draw natively. The same is true of OpenGL (which can sometimes draw 'quads' as well, but you can always draw a quad with two triangles).
Typically drawing circles and other smooth objects is best done through "vector graphics" libraries. These can render high-quality approximations of smooth objects like circles at the correct resolution. This is what the legacy GDI library did, and what Direct2D can do. You can code your own approximation for a circle, but you probably won't do as well as Direct2D. These libraries ultimately generate points, lines, and triangles for the actual drawing operations which are performed by Direct3D.
For this reason, if you are doing 'presentation' graphics, you should look at using Direct2D instead of Direct3D. Most games actually never draw true circles. They draw 2D sprites as two textured triangles with Direct3D using an image of a circle drawn on it by an artist in something like Photoshop or Paint.
If you are insistent on using Direct3D, see the DirectX Tool Kit for Direct3D 11 DebugDraw helper that can draw 'rings' (i.e. line-segment circles in 3D space). This should give you an idea for how this is done. This code always uses 32 segments to form the ring, but a 'vector graphics' library would determine how many segments to break it down to based on exactly how many pixels it's going to cover on the screen:
void XM_CALLCONV DX::DrawRing(PrimitiveBatch<VertexPositionColor>* batch,
FXMVECTOR origin,
FXMVECTOR majorAxis,
FXMVECTOR minorAxis,
GXMVECTOR color)
{
static const size_t c_ringSegments = 32;
VertexPositionColor verts[c_ringSegments + 1];
FLOAT fAngleDelta = XM_2PI / float(c_ringSegments);
// Instead of calling cos/sin for each segment we calculate
// the sign of the angle delta and then incrementally calculate sin
// and cosine from then on.
XMVECTOR cosDelta = XMVectorReplicate(cosf(fAngleDelta));
XMVECTOR sinDelta = XMVectorReplicate(sinf(fAngleDelta));
XMVECTOR incrementalSin = XMVectorZero();
static const XMVECTORF32 s_initialCos =
{
1.f, 1.f, 1.f, 1.f
};
XMVECTOR incrementalCos = s_initialCos.v;
for (size_t i = 0; i < c_ringSegments; i++)
{
XMVECTOR pos = XMVectorMultiplyAdd(majorAxis, incrementalCos, origin);
pos = XMVectorMultiplyAdd(minorAxis, incrementalSin, pos);
XMStoreFloat3(&verts[i].position, pos);
XMStoreFloat4(&verts[i].color, color);
// Standard formula to rotate a vector.
XMVECTOR newCos = incrementalCos * cosDelta - incrementalSin * sinDelta;
XMVECTOR newSin = incrementalCos * sinDelta + incrementalSin * cosDelta;
incrementalCos = newCos;
incrementalSin = newSin;
}
verts[c_ringSegments] = verts[0];
batch->Draw(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, verts, c_ringSegments + 1);
}
Direct3D 9 is legacy and unless you are specifically targeting Windows XP, you should be using Direct3D 11 or perhaps Direct2D if you are really doing 2D presentation graphics.

Related

Why is D2D drawing under D3D11?

My intuition is that if X is drawn before Y then X will be under Y. However, my code seems to always draw things drawn by D2D under things drawn by D3D11. This happens regardless of whether I'm using a depth buffer or not. Why is it doing this and how can I make D2D draw over D3D11 so that I can use D2D to create a GUI overlay?
Here is the smallest reproducible sample I could make:
#include <Windows.h>
#include <string>
#include <d3d11.h>
#include <d2d1.h>
#include <wrl.h>
#include <d3dcompiler.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "d3dcompiler.lib")
using namespace std;
using namespace Microsoft::WRL;
// Globals
HWND g_hWnd;
// D3D11
ComPtr<ID3D11Device> g_device;
ComPtr<ID3D11DeviceContext> g_context;
ComPtr<IDXGISwapChain> g_swapChain;
ComPtr<ID3D11RenderTargetView> g_renderTarget;
ComPtr<ID3D11Buffer> g_triangleVertexBuffer;
// D2D
ComPtr<ID2D1RenderTarget> g_renderTarget2D;
ComPtr<ID2D1Factory> g_factory2D;
// Utilities
constexpr const char* VERTEX_SHADER_CODE =
R"(
float4 main(float2 pos : POSITION) : SV_Position
{
return float4(pos, 0.0f, 1.0f);
}
)";
constexpr const char* PIXEL_SHADER_CODE =
R"(
float4 main() : SV_Target
{
return float4(1.0f, 0.0f, 0.0f, 1.0f);
}
)";
struct Vector2f
{
float x, y;
Vector2f() : x(0.0f), y(0.0f) { }
Vector2f(float x, float y) : x(x), y(y) { }
};
void AssertHResult(HRESULT hr, string errorMsg)
{
if (FAILED(hr))
throw std::exception(errorMsg.c_str());
}
void CompileShaderFromString(string code, string shaderType, ID3DBlob** output)
{
AssertHResult(D3DCompile(
code.c_str(),
code.length(),
nullptr,
nullptr,
nullptr,
"main",
shaderType.c_str(),
#ifdef _DEBUG
D3DCOMPILE_DEBUG |
#else
D3DCOMPILE_OPTIMIZATION_LEVEL3 |
#endif
D3DCOMPILE_ENABLE_STRICTNESS,
NULL,
output,
nullptr
), "Failed to compile shader");
}
// Graphics stuff
void InitializeD2D()
{
// Get swap chain surface
ComPtr<IDXGISurface> surface;
AssertHResult(g_swapChain->GetBuffer(
0,
__uuidof(IDXGISurface),
static_cast<void**>(&surface)
), "Failed to get surface of swap chain");
// Create factory
AssertHResult(D2D1CreateFactory<ID2D1Factory>(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&g_factory2D
), "Failed to create factory");
// Create render target
D2D1_RENDER_TARGET_PROPERTIES rtDesc = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_HARDWARE,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)
);
AssertHResult(g_factory2D->CreateDxgiSurfaceRenderTarget(
surface.Get(),
&rtDesc,
&g_renderTarget2D
), "Failed to create D2D render target");
}
void InitializeD3D()
{
// Get window dimensions
RECT rect{};
GetClientRect(g_hWnd, &rect);
float width = static_cast<float>(rect.right - rect.left);
float height = static_cast<float>(rect.bottom - rect.top);
// Create device, context, and swapchain
DXGI_SWAP_CHAIN_DESC scDesc{};
scDesc.BufferCount = 1;
scDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
scDesc.BufferDesc.Width = static_cast<UINT>(width);
scDesc.BufferDesc.Height = static_cast<UINT>(height);
scDesc.BufferDesc.RefreshRate.Numerator = 0;
scDesc.BufferDesc.RefreshRate.Denominator = 0;
scDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
scDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scDesc.Flags = NULL;
scDesc.OutputWindow = g_hWnd;
scDesc.SampleDesc.Count = 1;
scDesc.SampleDesc.Quality = 0;
scDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scDesc.Windowed = true;
AssertHResult(D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
#ifdef _DEBUG
D3D11_CREATE_DEVICE_DEBUG |
#endif
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
nullptr,
NULL,
D3D11_SDK_VERSION,
&scDesc,
&g_swapChain,
&g_device,
nullptr,
&g_context
), "Failed to create device and swapchain");
// Create render target
ComPtr<ID3D11Resource> backBuffer;
AssertHResult(g_swapChain->GetBuffer(
0,
__uuidof(ID3D11Resource),
static_cast<void**>(&backBuffer)
), "Failed to get back buffer of swapchain");
AssertHResult(g_device->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&g_renderTarget
), "Failed to create render target view");
// Bind render target
g_context->OMSetRenderTargets(
1,
g_renderTarget.GetAddressOf(),
nullptr
);
// Bind viewport
D3D11_VIEWPORT viewport{};
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = width;
viewport.Height = height;
g_context->RSSetViewports(
1,
&viewport
);
}
void InitializeD3DTriangle()
{
// Create vertex buffer
Vector2f vertices[3] =
{
Vector2f(-0.5f, -0.5f),
Vector2f(0.0f, 0.5f),
Vector2f(0.5f, -0.5f)
};
D3D11_BUFFER_DESC vbDesc{};
vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbDesc.ByteWidth = static_cast<UINT>(sizeof(Vector2f) * 3);
vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vbDesc.MiscFlags = NULL;
vbDesc.StructureByteStride = sizeof(Vector2f);
vbDesc.Usage = D3D11_USAGE_DYNAMIC;
D3D11_SUBRESOURCE_DATA vbData{};
vbData.pSysMem = vertices;
AssertHResult(g_device->CreateBuffer(
&vbDesc,
&vbData,
&g_triangleVertexBuffer
), "Failed to create vertex buffer");
// Bind vertex buffer
const UINT offset = 0;
const UINT stride = sizeof(Vector2f);
g_context->IASetVertexBuffers(
0,
1,
g_triangleVertexBuffer.GetAddressOf(),
&stride,
&offset
);
// Create and bind vertex shader
ComPtr<ID3DBlob> vsBlob;
ComPtr<ID3D11VertexShader> vertexShader;
CompileShaderFromString(
VERTEX_SHADER_CODE,
"vs_4_0",
&vsBlob
);
AssertHResult(g_device->CreateVertexShader(
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
nullptr,
&vertexShader
), "Failed to create vertex shader");
g_context->VSSetShader(
vertexShader.Get(),
nullptr,
NULL
);
// Create and bind pixel shader
ComPtr<ID3DBlob> pxBlob;
ComPtr<ID3D11PixelShader> pixelShader;
CompileShaderFromString(
PIXEL_SHADER_CODE,
"ps_4_0",
&pxBlob
);
AssertHResult(g_device->CreatePixelShader(
pxBlob->GetBufferPointer(),
pxBlob->GetBufferSize(),
nullptr,
&pixelShader
), "Failed to create pixel shader");
g_context->PSSetShader(
pixelShader.Get(),
nullptr,
NULL
);
// Set topology
g_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Create input layout
ComPtr<ID3D11InputLayout> inputLayout;
D3D11_INPUT_ELEMENT_DESC ilDesc{};
ilDesc.AlignedByteOffset = 0;
ilDesc.Format = DXGI_FORMAT_R32G32_FLOAT;
ilDesc.SemanticName = "POSITION";
ilDesc.SemanticIndex = 0;
ilDesc.InputSlot = 0;
ilDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
ilDesc.InstanceDataStepRate = 0;
AssertHResult(g_device->CreateInputLayout(
&ilDesc,
1,
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
&inputLayout
), "Failed to create input layout");
// Bind input layout
g_context->IASetInputLayout(inputLayout.Get());
}
// Windows
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
return 0;
}
void InitializeWindow(HINSTANCE hInst, int width, int height)
{
// Register window class
WNDCLASSEXW wc{};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"MainWindow";
wc.style = CS_OWNDC;
RegisterClassExW(&wc);
// Adjust width and height to be client area instead of window area
RECT rc{};
rc.left = 0;
rc.top = 0;
rc.right = width;
rc.bottom = height;
constexpr auto ws = WS_OVERLAPPEDWINDOW;
AdjustWindowRectEx(
&rc,
ws,
false,
NULL
);
// Instantiate and show window
g_hWnd = CreateWindowExW(
NULL,
L"MainWindow",
L"Window Title",
ws,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<int>(rc.right - rc.left),
static_cast<int>(rc.bottom - rc.top),
NULL,
NULL,
hInst,
nullptr
);
ShowWindow(g_hWnd, SW_SHOW);
}
// Driver code
void Update()
{
// Begin frame
g_renderTarget2D->BeginDraw();
// Clear screen to black
D2D1_COLOR_F bgColour = { 0.0f, 0.0f, 0.0f, 1.0f };
g_renderTarget2D->Clear(bgColour);
// Draw D3D triangle
g_context->Draw(
3,
0
);
// Draw D2D rectangle
D2D_RECT_F rect{};
rect.bottom = 500;
rect.top = 300;
rect.left = 100;
rect.right = 700;
D2D1_COLOR_F rectColour = { 0.0f, 1.0f, 0.0f, 1.0f };
ComPtr<ID2D1SolidColorBrush> brush;
g_renderTarget2D->CreateSolidColorBrush(
rectColour,
&brush
);
g_renderTarget2D->FillRectangle(
rect,
brush.Get()
);
// End frame
AssertHResult(g_swapChain->Present(
1,
NULL
), "Failed to present swapchain");
g_renderTarget2D->EndDraw();
}
int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE prevInst, LPWSTR cmdArgs, int cmdShow)
{
InitializeWindow(hInst, 800, 600);
InitializeD3D();
InitializeD2D();
InitializeD3DTriangle();
// Run message loop
while (true)
{
// Handle windows messages
MSG msg{};
PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE);
TranslateMessage(&msg);
DispatchMessageW(&msg);
if (msg.message == WM_QUIT)
break;
// Quit is escape is pressed
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
break;
// Do frame
Update();
}
return 0;
}
If you want to control the draw order, then you shouldn't be drawing both at the same time. Call Draw, then BeginDraw / EndDraw. Don't mix them as you have no idea when Direct2D is actually flushing commands to the context in your code, and you have no explicit indication of when Direct3D is done drawing to the render target.
You can of course call Direct3D's Flush which will force all work on the GPU to complete, but it's horribly inefficient to call it every frame.

Double buffering in Direct2D?

I'm very new to Direct2D programming and have been following a tutorial. I've adapted the example given in the tutorial to a slightly more complicated program that bounces a ball off the boundaries of the window.
My main program (main.cpp):
#include "Graphics.h"
Graphics* graphics;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Exit handler
if (uMsg == WM_DESTROY)
{
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE prevInstance, LPWSTR cmd, int nCmdShow)
{
WNDCLASSEX windowClass;
SecureZeroMemory(&windowClass, sizeof(WNDCLASSEX));
// Set up window
windowClass.cbSize = sizeof(WNDCLASSEX);
windowClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
windowClass.hInstance = hInstance;
windowClass.lpfnWndProc = WindowProc;
windowClass.lpszClassName = "MainWindow";
windowClass.style = CS_HREDRAW | CS_VREDRAW;
// Register window class and handle
RegisterClassEx(&windowClass);
RECT rect = { 0, 0, 800, 600 };
AdjustWindowRectEx(&rect, WS_OVERLAPPEDWINDOW, false, WS_EX_OVERLAPPEDWINDOW);
HWND windowHandle = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "MainWindow", "Test Window", WS_OVERLAPPEDWINDOW, 100, 100,
rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, 0);
if (!windowHandle)
return -1;
graphics = new Graphics();
if (!graphics->Init(windowHandle))
{
delete graphics;
return -1;
}
ShowWindow(windowHandle, nCmdShow);
// Message loop
float x = 51.0, xSpeed = 5.0f, y = 0.0, ySpeed = 5.0f;
MSG message;
message.message = WM_NULL;
while (message.message != WM_QUIT)
{
if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
DispatchMessage(&message);
else
{
// Ball physics
//xSpeed += 0.6f;
x += xSpeed;
ySpeed += 0.2f;
y += ySpeed;
if (y > rect.bottom - 50)
{
ySpeed = -ySpeed;
}
if (x > rect.right - 50)
{
xSpeed = -xSpeed;
}
else if (x < 50)
{
xSpeed = -xSpeed;
}
// Redraw ball
graphics->beginDraw();
graphics->clearScreen(0.0f, 0.0f, 0.5f);
graphics->drawCircle(x, y, 50.0f, 1.0f, 1.0f, 1.0f, 1.0f);
graphics->endDraw();
}
}
delete graphics;
return 0;
}
My header file (Graphics.h):
#pragma once
#include <Windows.h>
#include <d2d1.h>
class Graphics
{
ID2D1Factory* factory;
ID2D1HwndRenderTarget* renderTarget;
ID2D1SolidColorBrush* brush;
public:
Graphics();
~Graphics();
bool Init(HWND windowHandle);
void beginDraw() { renderTarget->BeginDraw(); }
void endDraw() { renderTarget->EndDraw(); }
void clearScreen(float r, float g, float b);
void drawCircle(float x, float y, float radius, float r, float g, float b, float a);
};
My graphics functions (Graphics.cpp):
#include "Graphics.h"
#define CHECKRES if (res != S_OK) return false
Graphics::Graphics()
{
factory = NULL;
renderTarget = NULL;
brush = NULL;
}
Graphics::~Graphics()
{
if (factory)
factory->Release();
if (renderTarget)
renderTarget->Release();
if (brush)
brush->Release();
}
bool Graphics::Init(HWND windowHandle)
{
HRESULT res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);
CHECKRES;
RECT rect;
GetClientRect(windowHandle, &rect);
res = factory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(windowHandle, D2D1::SizeU(rect.right, rect.bottom)),
&renderTarget
);
CHECKRES;
res = renderTarget->CreateSolidColorBrush(D2D1::ColorF(0, 0, 0, 0), &brush);
CHECKRES;
return true;
}
void Graphics::clearScreen(float r, float g, float b)
{
renderTarget->Clear(D2D1::ColorF(r, g, b));
}
void Graphics::drawCircle(float x, float y, float radius, float r, float g, float b, float a)
{
brush->SetColor(D2D1::ColorF(r, g, b, a));
renderTarget->DrawEllipse(D2D1::Ellipse(D2D1::Point2F(x, y), radius, radius), brush, 3.0f);
}
While this program does work fine, there is some minor tearing on the ball's bounce. I have seen this question which lead me to this MSDN article. Despite reading the article, I do still not fully understand how to implement double buffering, to hopefully reduce tearing. Can someone provide a concise example and explanation of the ID2D1RenderTarget::CreateCompatibleRenderTarget, as this high level Windows programming is quite different from what I'm used to?
Check article here. ID2D1HwndRenderTarget objects are double buffered by nature and drawing is done to the offscreen buffer first and when drawing ends it will be blitted to the screen.

Windows freezes after trying to render triangle in directx11

I can initialize win32 window and directx11 fine, but when i try to draw triangle window appears and then it freezes my pc so i have to reboot it.
Here is my WinMain code:
#include "DXApp.h"
#include<DirectXMath.h>
class App : public DXApp {
public:
App(HINSTANCE hInstance);
~App();
bool Init() override;
void Update(float dt) override;
void Render(float dt) override;
};
int WINAPI WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd) {
App app(hInstance);
if (!app.Init()) return 1;
return app.Run();
}
App::App(HINSTANCE hInstance) : DXApp(hInstance)
{
}
App::~App()
{
}
bool App::Init()
{
return DXApp::Init();
}
void App::Update(float dt)
{
}
void App::Render(float dt)
{
immediateContext->ClearRenderTargetView(renderTargetView, DirectX::Colors::CornflowerBlue);
immediateContext->Draw(3, 0);
swapChain->Present(0, 0);
}
And my app header and cpp:
DXApp.h:
#pragma once
#include<Windows.h>
#include<string>
#include"DXUtil.h"
#include<d3dcompiler.h>
#pragma comment(lib, "d3dcompiler.lib")
#define WIN32_LEAN_AND_MEAN
class DXApp
{
public:
DXApp(HINSTANCE hInstance);
void cleanUp();
virtual ~DXApp(void);
//MAIN APPLICATION LOOP
int Run();
//FRAMEWORK METHODS
virtual bool Init();
virtual void Update(float dt) = 0;
virtual void Render(float dt) = 0;
virtual LRESULT MsgProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam);
protected:
HWND hAppWnd;
HINSTANCE hAppInstance;
unsigned int ClientWidth;
unsigned int ClientHeight;
std::string AppTitle;
DWORD WindStyle;
//DIRECTX ATTRIBUTES
ID3D11Device* device;
ID3D11DeviceContext* immediateContext;
IDXGISwapChain* swapChain;
ID3D11RenderTargetView* renderTargetView;
D3D_DRIVER_TYPE driverType;
D3D_FEATURE_LEVEL featureLevel;
D3D11_VIEWPORT viewport;
ID3D11Buffer* triangleVertBuffer;
ID3D11PixelShader* pixelShader;
ID3D11VertexShader* vertexShader;
ID3D10Blob* VSBuffer;
ID3D10Blob* PSBuffer;
ID3D11InputLayout* vertLayout;
protected:
//INITIALZE WIN32 WINDOW
bool windowInit();
//INITIALIZE DIRECTX
bool direct3dInit();
};
DXApp.cpp:
#include "DXApp.h"
namespace {
DXApp * g_pApp = nullptr;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam) {
if (g_pApp) return g_pApp->MsgProc(hwnd, msg, wParam, lParam);
else return DefWindowProc(hwnd, msg, wParam, lParam);
}
//VERTEX
struct Vertex {
Vertex() {}
Vertex(float x, float y, float z) : pos(x, y, z) {}
DirectX::XMFLOAT3 pos;
};
D3D11_INPUT_ELEMENT_DESC layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
unsigned int numLayoutElements = ARRAYSIZE(layout);
DXApp::DXApp(HINSTANCE hInstance)
{
hAppInstance = hInstance;
hAppWnd = NULL;
ClientWidth = 1280;
ClientHeight = 720;
AppTitle = "DirectX11 Engine";
WindStyle = WS_OVERLAPPEDWINDOW;
g_pApp = this;
//DIRECTX
device = nullptr;
swapChain = nullptr;
immediateContext = nullptr;
renderTargetView = nullptr;
vertexShader = nullptr;
pixelShader = nullptr;
triangleVertBuffer = nullptr;
VSBuffer = nullptr;
PSBuffer = nullptr;
vertLayout = nullptr;
}
void DXApp::cleanUp()
{
if (immediateContext) immediateContext->ClearState();
Memory::SafeRelease(renderTargetView);
Memory::SafeRelease(immediateContext);
Memory::SafeRelease(swapChain);
Memory::SafeRelease(device);
Memory::SafeRelease(vertLayout);
Memory::SafeRelease(PSBuffer);
Memory::SafeRelease(VSBuffer);
Memory::SafeRelease(triangleVertBuffer);
Memory::SafeRelease(pixelShader);
Memory::SafeRelease(vertexShader);
}
DXApp::~DXApp()
{
//DIRECTX CLEANUP
if (immediateContext) immediateContext->ClearState();
Memory::SafeRelease(renderTargetView);
Memory::SafeRelease(immediateContext);
Memory::SafeRelease(swapChain);
Memory::SafeRelease(device);
Memory::SafeRelease(vertLayout);
Memory::SafeRelease(PSBuffer);
Memory::SafeRelease(VSBuffer);
Memory::SafeRelease(triangleVertBuffer);
Memory::SafeRelease(pixelShader);
Memory::SafeRelease(vertexShader);
}
int DXApp::Run() {
MSG msg = { 0 };
while (WM_QUIT != msg.message) {
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
Update(0.0f);
Render(0.0f);
}
}
return static_cast<int>(msg.wParam);
}
bool DXApp::Init()
{
if (!windowInit()) {
return false;
}
if (!direct3dInit()) {
return false;
}
return true;
}
bool DXApp::windowInit()
{
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEX));
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.hInstance = hAppInstance;
wcex.lpfnWndProc = MainWndProc;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "DXAPPWNDCLASS";
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wcex)) {
OutputDebugString("\nFAILED TO CREATE WINDOW CLASS!!\n");
return false;
}
RECT r = { 0, 0, ClientWidth, ClientHeight };
AdjustWindowRect(&r, WindStyle, false);
unsigned int width = r.right - r.left;
unsigned int height = r.bottom - r.top;
unsigned int x = GetSystemMetrics(SM_CXSCREEN) / 2 - width / 2;
unsigned int y = GetSystemMetrics(SM_CYSCREEN) / 2 - height / 2;
hAppWnd = CreateWindow("DXAPPWNDCLASS", AppTitle.c_str(), WindStyle, x, y, width, height, NULL, NULL, hAppInstance, NULL);
if (!hAppWnd) {
OutputDebugString("\nFAILED TO CREATE WINDOW!!\n");
return false;
}
ShowWindow(hAppWnd, SW_SHOW);
return true;
}
//DIRECTX INITIALIZATION
bool DXApp::direct3dInit()
{
unsigned int createDeviceFlags = 0;
#ifdef DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif // DEBUG
D3D_DRIVER_TYPE driverTypes[] = {
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE
};
unsigned int numDriverTypes = ARRAYSIZE(driverTypes);
D3D_FEATURE_LEVEL featureLevels[] = {
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3
};
unsigned int numFeatureLevels = ARRAYSIZE(featureLevels);
DXGI_SWAP_CHAIN_DESC swapDesc;
ZeroMemory(&swapDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapDesc.BufferCount = 1;
swapDesc.BufferDesc.Width = ClientWidth;
swapDesc.BufferDesc.Height = ClientHeight;
swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.OutputWindow = hAppWnd;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapDesc.Windowed = true;
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
HRESULT result;
for (int i = 0; i < numDriverTypes; ++i) {
result = D3D11CreateDeviceAndSwapChain(NULL, driverTypes[i], NULL, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &swapDesc, &swapChain, &device, &featureLevel, &immediateContext);
if (SUCCEEDED(result)) {
driverType = driverTypes[i];
break;
}
if (FAILED(result)) {
OutputDebugString("FAILED TO CREATE DX11 DEVICE!!");
return false;
}
}
//RENDER TARGET VIEW
ID3D11Texture2D* backBufferTex = 0;
swapChain->GetBuffer(NULL, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBufferTex));
device->CreateRenderTargetView(backBufferTex, nullptr, &renderTargetView);
//BIND RENDER TARGET VIEW
immediateContext->OMSetRenderTargets(1, &renderTargetView, nullptr);
//COMPILE SHADERS FROM FILE
result = D3DCompileFromFile(L"VertexShader.hlsl", 0, 0, "vertexShader", "vs_4_0", 0, 0, &VSBuffer, &VSBuffer);
result = D3DCompileFromFile(L"PixelShader.hlsl", 0, 0, "pixelShader", "ps_4_0", 0, 0, &PSBuffer, &PSBuffer);
//CREATE SHADER OBJECTS
result = device->CreateVertexShader(VSBuffer->GetBufferPointer(), VSBuffer->GetBufferSize(), 0, &vertexShader);
result = device->CreatePixelShader(PSBuffer->GetBufferPointer(), PSBuffer->GetBufferSize(), 0, &pixelShader);
//SET SHADERS
immediateContext->VSSetShader(vertexShader, 0, 0);
immediateContext->PSSetShader(pixelShader, 0, 0);
//CREATE VERTEX BUFFER
Vertex v[] = {
Vertex(0.0f, 0.5f, 0.5f),
Vertex(0.5f, -0.5f, 0.5f),
Vertex(-0.5f, 0.5f, 0.5f),
};
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory(&vertexBufferDesc, sizeof(D3D11_BUFFER_DESC));
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof(Vertex) * 3;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
vertexBufferData.pSysMem = v;
result = device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &triangleVertBuffer);
//SET VERTEX BUFFER
unsigned int stride = sizeof(Vertex);
unsigned int offset = 0;
immediateContext->IAGetVertexBuffers(0, 1, &triangleVertBuffer, &stride, &offset);
//CREATE INPUT LAYOUT
device->CreateInputLayout(layout, numLayoutElements, VSBuffer->GetBufferPointer(), VSBuffer->GetBufferSize(), &vertLayout);
//SET INPUT LAYOUT
immediateContext->IASetInputLayout(vertLayout);
//SET PRIMITIVE TOPOLOGY
immediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//VIEWPORT CREATION
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.Width = static_cast<float>(ClientWidth);
viewport.Height = static_cast<float>(ClientHeight);
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
//SET VIEWPORT
immediateContext->RSSetViewports(1, &viewport);
return true;
}
//MESSAGES
LRESULT DXApp::MsgProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
The first steps in debugging a Direct3D program are:
Make sure you are properly checking all HRESULT values. There are numerous places in your code where you are failing to check the result. If the Direct3D function returns a void, you can ignore error checking. Otherwise you need to use SUCCEEDED, FAILED, or use something like ThrowIfFailed. This is essentially because continuing beyond a failure is going to make it very hard to debug the true cause of the problem.
Enable the Direct3D debug device and look for output. You appear to have that in your debug builds. Do you see any output in the debug window?
It is highly unusual to have a program 'hang' your system, but it is possible if you have a bad driver or faulty hardware. Without more details, however, it's difficult to diagnose since your program is faulty to begin with.

Faster way to draw huge amount of triangle / height map (Direct 3D, C++)

I'm currently writting a 3D visualization tool for a scientific application and I am facing a performance problem.
I have a relatively large grid (~ 1000 rows x 1000 columns) and for each point of this grid I have a physical value that I want to represent as height (for instance: temperature).
Here is an example of what I am trying to draw with white gaussian noise:
http://i.stack.imgur.com/KM23m.jpg
I am using DirectX 9 to draw my scene. I basiclaly draw a bunch of triangles with the (X,Y) coordinate being a point on the grid, and the Z coordinate being the physical measurement at that point.
Here are the operations that I do on each frame:
I create a vertex buffer (CreateVertexBuffer()) and an index buffer (CreateIndexBuffer()) (the data changes on each frame, but the size of the data does not)
I lock them
I fill the two buffers properly, including assigning a color depending on the value (high value are red, low value are blue)
I unlock them
I set the stream source (SetStreamSource()), set the indices (SetIndices()) and draw the triangles (as a triangle strip)
I release the two buffers
My problem is that the frame rate is not as high as expected.
I achieve ~30fps for ~2 millions triangles drawn on a Nvidia GTX 770 (& Intel Core i7 4770k if that matters) when I want to have at least 60fps.
Is there a better way to do what I am doing or my problem is that the number of triangle is too large ?
Will I get better performance if I use DirectX 11 ?
Thank you for your help.
Edit here is a stand-alone simplified code:
#include <windows.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <windowsx.h>
#include <d3d9.h>
#include <vector>
#include <random>
#include <fcntl.h>
#include <io.h>
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define COLORMAPSIZE 256
#pragma comment (lib, "d3d9.lib")
#define DEG2RAD(x) (x* (float)M_PI/180.0f)
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
std::default_random_engine randGenerator;
// global declarations
LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 d3ddev;
const int Nrows = 1000, Ncols = 2000;
float indexAz=DEG2RAD(90), indexEl = DEG2RAD(60), distance=80;
const float dataAmplitude = 5.f;
std::vector<float> dataBuffer;
typedef struct D3DXVECTOR3 : public D3DVECTOR
{
public:
FLOAT x,y,z;
D3DXVECTOR3() {};
D3DXVECTOR3( FLOAT xx, FLOAT yy, FLOAT zz ) : x(xx), y(yy), z(zz) {};
} D3DXVECTOR3, *LPD3DXVECTOR3;
typedef struct {
float x, y, z;
D3DCOLOR color;
} Vertex;
void initD3D(HWND hWnd);
void resetD3D(HWND hWnd);
void render_frame(void);
void cleanD3D(void);
void draw_graphics(void);
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void CreateConsole() {
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
int consoleHandleR, consoleHandleW ;
long stdioHandle;
FILE *fptr;
AllocConsole();
std::wstring strW = L"Dev Console";
SetConsoleTitleW( strW.c_str() );
EnableMenuItem(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE , MF_GRAYED);
DrawMenuBar(GetConsoleWindow());
GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo );
stdioHandle = (long)GetStdHandle( STD_INPUT_HANDLE );
consoleHandleR = _open_osfhandle( stdioHandle, _O_TEXT );
fptr = _fdopen( consoleHandleR, "r" );
*stdin = *fptr;
setvbuf( stdin, NULL, _IONBF, 0 );
stdioHandle = (long) GetStdHandle( STD_OUTPUT_HANDLE );
consoleHandleW = _open_osfhandle( stdioHandle, _O_TEXT );
fptr = _fdopen( consoleHandleW, "w" );
*stdout = *fptr;
setvbuf( stdout, NULL, _IONBF, 0 );
stdioHandle = (long)GetStdHandle( STD_ERROR_HANDLE );
*stderr = *fptr;
setvbuf( stderr, NULL, _IONBF, 0 );
}
// Generate a random number following a uniform distribution
double rand(const double inf=0, const double sup=1) {
std::uniform_real_distribution<double> distribution(inf,sup);
return distribution(randGenerator);
}
// Update the buffer with new data
void UpdateDataBuffer()
{
static bool firstCall = true;
if (firstCall) //fill the whole buffer
{
for(unsigned k = 0 ; k < Nrows*Ncols ; k++)
dataBuffer[k] = (float)rand(0,dataAmplitude);
firstCall = false;
} else { // remove the first column, shift the whole buffer and update the last column
memmove(&dataBuffer[0], &dataBuffer[Nrows], (Ncols-1)*Nrows*sizeof(float));
for(unsigned k= Nrows*(Ncols-1) ; k < Nrows*Ncols ; k++)
dataBuffer[k] = (float)rand(0,dataAmplitude);
}
}
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
CreateConsole();
randGenerator.seed( GetTickCount() );
dataBuffer.resize(Nrows * Ncols);
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = "WindowClass";
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, "WindowClass", "Our Direct3D Program",
WS_OVERLAPPEDWINDOW, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
initD3D(hWnd);
MSG msg;
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2;
float fps = 0.f;
float NFramAvg = 1.0f/10.0f, totalElapsedTime = 0.0f;
QueryPerformanceFrequency(&frequency);
while(TRUE)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(msg.message == WM_QUIT)
break;
UpdateDataBuffer();
QueryPerformanceCounter(&t1);
render_frame();
QueryPerformanceCounter(&t2);
fps = fps - NFramAvg*fps + NFramAvg* frequency.QuadPart / (t2.QuadPart - t1.QuadPart);
totalElapsedTime += (t2.QuadPart - t1.QuadPart)*1000.0f / frequency.QuadPart;;
if (totalElapsedTime > 1000) {
printf("FPS = %g\n", fps);
totalElapsedTime = 0.0;
}
}
cleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int clickX, clickY;
static bool down = false;
switch(message)
{
case WM_LBUTTONDOWN:
if (!down)
{
clickX = GET_X_LPARAM(lParam);
clickY = GET_Y_LPARAM(lParam);
}
down = true;
break;
case WM_LBUTTONUP:
down = false;
break;
case WM_MOUSEMOVE:
if (down)
{
int dx = GET_X_LPARAM(lParam) - clickX;
int dy = GET_Y_LPARAM(lParam) - clickY;
indexAz += dx*DEG2RAD(0.5f);
if (indexEl + dy*DEG2RAD(0.5f) < M_PI_2 && indexEl + dy*DEG2RAD(0.5f) > -M_PI_2)
indexEl += dy*DEG2RAD(0.5f);
clickX += dx;
clickY += dy;
}
break;
case WM_MOUSEWHEEL:
{
int zDelta = GET_WHEEL_DELTA_WPARAM(wParam); //scroll power
distance -= 2*zDelta/120.f;
distance = max(1.0f, distance);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
case WM_SIZE:
if (d3ddev)
resetD3D(hWnd);
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;
RECT rect;
GetClientRect(hWnd, &rect);
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = rect.right - rect.left;
d3dpp.BackBufferHeight = rect.bottom -rect.top;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // turn off culling
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
}
void resetD3D(HWND hWnd)
{
D3DPRESENT_PARAMETERS d3dpp;
RECT rect;
GetClientRect(hWnd, &rect);
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = rect.right - rect.left;
d3dpp.BackBufferHeight = rect.bottom -rect.top;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
if (d3dpp.BackBufferWidth && d3dpp.BackBufferHeight)
{
d3ddev->Reset(&d3dpp);
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
InvalidateRect(hWnd, NULL, FALSE);
}
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // turn off culling
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
}
D3DXVECTOR3 *D3DVec3Subtract(D3DXVECTOR3 *pOut, const D3DXVECTOR3 *pV1,const D3DXVECTOR3 *pV2)
{
pOut->x = pV1->x - pV2->x;
pOut->y = pV1->y - pV2->y;
pOut->z = pV1->z - pV2->z;
return pOut;
}
D3DXVECTOR3* D3DVec3Normalize(D3DXVECTOR3 *pOut,const D3DXVECTOR3 *pV)
{
FLOAT norm = sqrt( pV->x * pV->x + pV->y * pV->y + pV->z * pV->z );
pOut->x = pV->x / norm;
pOut->y = pV->y / norm;
pOut->z = pV->z / norm;
return pOut;
}
D3DXVECTOR3* D3DVec3Cross(D3DXVECTOR3 *pOut,const D3DXVECTOR3 *pV1,const D3DXVECTOR3 *pV2)
{
pOut->x = pV1->y*pV2->z - pV1->z*pV2->y;
pOut->y = pV1->z*pV2->x - pV1->x*pV2->z;
pOut->z = pV1->x*pV2->y - pV1->y*pV2->x;
return pOut;
}
FLOAT D3DVec3Dot(const D3DXVECTOR3 *pV1,const D3DXVECTOR3 *pV2)
{
return pV1->x * pV2->x + pV1->y * pV2->y + pV1->z * pV2->z;
}
D3DMATRIX* D3DMatrixLookAtLH(D3DMATRIX *pOut,const D3DXVECTOR3 *pEye,const D3DXVECTOR3 *pAt,const D3DXVECTOR3 *pUp)
{
D3DXVECTOR3 right, rightn, up, upn, vec, vec2;
D3DVec3Subtract(&vec2, pAt, pEye);
D3DVec3Normalize(&vec, &vec2);
D3DVec3Cross(&right, pUp, &vec);
D3DVec3Cross(&up, &vec, &right);
D3DVec3Normalize(&rightn, &right);
D3DVec3Normalize(&upn, &up);
pOut->m[0][0] = rightn.x;
pOut->m[1][0] = rightn.y;
pOut->m[2][0] = rightn.z;
pOut->m[3][0] = -D3DVec3Dot(&rightn,pEye);
pOut->m[0][1] = upn.x;
pOut->m[1][1] = upn.y;
pOut->m[2][1] = upn.z;
pOut->m[3][1] = -D3DVec3Dot(&upn, pEye);
pOut->m[0][2] = vec.x;
pOut->m[1][2] = vec.y;
pOut->m[2][2] = vec.z;
pOut->m[3][2] = -D3DVec3Dot(&vec, pEye);
pOut->m[0][3] = 0.0f;
pOut->m[1][3] = 0.0f;
pOut->m[2][3] = 0.0f;
pOut->m[3][3] = 1.0f;
return pOut;
}
D3DMATRIX* D3DXMatrixPerspectiveFovLH(D3DMATRIX *pOut, const FLOAT fovy, const FLOAT Aspect, const FLOAT zn, const FLOAT zf)
{
FLOAT yScale = tanf((float)M_PI_2 - fovy/2);
FLOAT xScale = yScale /Aspect;
memset(pOut,0, sizeof(*pOut));
pOut->_11 = xScale;
pOut->_22 = yScale;
pOut->_33 = zf/(zf-zn);
pOut->_34 = 1;
pOut->_43 = -zn*zf/(zf-zn);
return pOut;
}
long GetColor(const float x, const float inf, const float sup)
{
BYTE c =(BYTE)( 255 * (x-inf)/(sup-inf) );
return D3DCOLOR_XRGB(c,c,c);
}
// this is the function that puts the 3D models into video RAM
void draw_graphics(void)
{
static long colorTab[COLORMAPSIZE] = {0,};
static std::vector<Vertex> tmp;
static LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL;
static LPDIRECT3DINDEXBUFFER9 i_buffer = NULL;
static unsigned NVertex = 0;
// Create empty IDirect3DTexture9
const unsigned MN = Nrows*Ncols;
unsigned k=0;
if (MN > tmp.size())
tmp.resize( MN );
if (colorTab[0] == 0) // if colortab empty, fill it
{
for(int i=0 ; i < COLORMAPSIZE ;i++)
colorTab[i] = GetColor((float)i, (float)0, (float)(COLORMAPSIZE-1));
}
if (!v_buffer)
d3ddev->CreateVertexBuffer(MN*sizeof(Vertex), 0,D3DFVF_XYZ | D3DFVF_DIFFUSE,D3DPOOL_MANAGED,&v_buffer,NULL);
float factor = (COLORMAPSIZE-1.0f)/dataAmplitude;
for (k=0 ; k < MN ; k++)
{
if (dataBuffer[k] >= dataAmplitude)
tmp[k].color = colorTab[COLORMAPSIZE-1];
else if (dataBuffer[k] <= 0)
tmp[k].color = colorTab[0];
else
tmp[k].color = colorTab[(int)( ( dataBuffer[k])*factor )];
}
float M_2 = Nrows/2.0f, N_2 = Ncols/2.0f;
k=0;
for (unsigned n=0 ; n < Ncols ; n++)
{
for (unsigned m=0 ; m < Nrows ; m++, k++)
{
tmp[k].x = M_2 - m;
tmp[k].z = n - N_2;
tmp[k].y = dataBuffer[k];
}
}
Vertex* pVoid;
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, &tmp[0], MN*sizeof(Vertex));
v_buffer->Unlock();
if (!i_buffer)
d3ddev->CreateIndexBuffer(3*2*(Nrows-1)*(Ncols-1)*sizeof(DWORD), 0, D3DFMT_INDEX32, D3DPOOL_MANAGED,&i_buffer,NULL);
DWORD *indices;
i_buffer->Lock(0, 0, (void**)&indices, 0);
k=0;
for (unsigned n=0 ; n < Ncols-1 ; n++)
{
if (n!=0)
indices[k++] = n*Nrows;
for (unsigned m=0 ; m < Nrows-1 ; m++)
{
indices[k++] = m + n*Nrows;
indices[k++] = m + (n+1)*Nrows;
}
indices[k++] = Nrows-2 + (n+1)*Nrows;
}
NVertex = k;
i_buffer->Unlock();
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(Vertex));
d3ddev->SetIndices(i_buffer);
d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, MN, 0, NVertex-2);
//printf("%d triangle drawn\n", NVertex-2);
//i_buffer->Release();
//v_buffer->Release();
}
// 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();
d3ddev->SetFVF(CUSTOMFVF);
// set the view transform
D3DMATRIX matView; // the view transform matrix
float R = distance*25;
D3DMatrixLookAtLH(&matView,
&D3DXVECTOR3 (R*sin(indexAz)*cos(indexEl), R*sin(indexEl),R*cos(indexAz)*cos(indexEl)), // the camera position
&D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView); // set the view transform to matView
// set the projection transform
D3DMATRIX matProjection; // the projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
DEG2RAD(45), // the horizontal field of view
(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
0.001f, // the near view-plane
100000.f); // the far view-plane
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection
indexAz += DEG2RAD(0.1f);
draw_graphics();
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
d3ddev->Release();
d3d->Release();
}
Well, because you say you're IO bound, the best thing would be to reduce the amount of data you send to the GPU every update.
If you're targeting SM 3.0 or higher you can use vertex texture fetching to sample the height from a texture that you update every frame. This is a lot easier on the input assembler and on BW.
To do this most easily, you might want to change your vertex data, instead of supplying a float3 with xyz, you might want to supply a uint2 with just xz, this way you can directly fetch from the texture without doing a float to int conversion in your shader.
as a side note, there is very little reason for you to write a vertex's color to your VB if it can be trivially derived from its position, it would be less bw to calculate it in the shader with a lerp or some other blending operation.
I've done this very thing for a project of mine, and the speedup is massive on my GTX 480. Brought me from spending 50ms on rendering heightmaps to around 1ms.
Unless I am missing something you don't need to lock your index buffer and update it, you are setting it to the same values anyways. That will get rid of that 1000x2000 loop.
Also I wouldn't update the vertex buffer everyframe if the data isn't changing everyframe. Just update it whenever the data is actually updated.

glutKeyboardFunc error [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have an opengl c++ code for reading .ply file. I want to read keyboard arrow keys(up,down,right,left) for move a point on the screen. I used glutKeyboardFunc function but i have an error:
Unhandled exception at 0x1000bb1e in opengl3.exe: 0xC0000005: Access violation reading location 0x00000070.
On this line:
glutKeyboardFunc(keyPressed);
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <cmath>
#include <string>
#include <conio.h>
HWND hWnd;
HDC hDC;
HGLRC hRC;
// Set up pixel format for graphics initialization
void SetupPixelFormat()
{
PIXELFORMATDESCRIPTOR pfd, *ppfd;
int pixelformat;
ppfd = &pfd;
ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
ppfd->nVersion = 1;
ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
ppfd->dwLayerMask = PFD_MAIN_PLANE;
ppfd->iPixelType = PFD_TYPE_COLORINDEX;
ppfd->cColorBits = 16;
ppfd->cDepthBits = 16;
ppfd->cAccumBits = 0;
ppfd->cStencilBits = 0;
pixelformat = ChoosePixelFormat(hDC, ppfd);
SetPixelFormat(hDC, pixelformat, ppfd);
}
void InitGraphics()
{
hDC = GetDC(hWnd);
SetupPixelFormat();
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
glClearColor(0, 0, 0, 0.5);
glClearDepth(1.0);
glEnable(GL_DEPTH_TEST);
}
// Resize graphics to fit window
void ResizeGraphics()
{
// Get new window size
RECT rect;
int width, height;
GLfloat aspect;
GetClientRect(hWnd, &rect);
width = rect.right;
height = rect.bottom;
aspect = (GLfloat)width / height;
// Adjust graphics to window size
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, aspect, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
}
// Draw frame
void DrawGraphics()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set location in front of camera
glLoadIdentity();
glTranslated(0, 0, -10);
// Draw a square
glBegin(GL_QUADS);
glColor3d(100, 200, 30);
/*
glVertex3d(-2, 2, 0);
glVertex3d(2, 2, 0);
glVertex3d(2, -2, 0);
glVertex3d(-2, -2, 0);
*/
//FILE * file = fopen("D:\\dart.ply","r");
FILE * file = fopen("mosalas.ply","r");
if (file!=NULL)
{
fseek(file,0,SEEK_END);
long fileSize = ftell(file);
float* Vertex_Buffer;
try
{
Vertex_Buffer = (float*) malloc (ftell(file));
}
catch (char* )
{
//return -1;
}
//if (Vertex_Buffer == NULL) return -1;
fseek(file,0,SEEK_SET);
//Faces_Triangles = (float*) malloc(fileSize*sizeof(float));
//Normals = (float*) malloc(fileSize*sizeof(float));
if (file)
{
int i = 0;
int temp = 0;
int quads_index = 0;
int triangle_index = 0;
int normal_index = 0;
char buffer[1000];
fgets(buffer,300,file); // ply
// READ HEADER
// -----------------
int TotalConnectedPoints;
// Find number of vertexes
while ( strncmp( "element vertex", buffer,strlen("element vertex")) != 0 )
{
fgets(buffer,300,file); // format
}
strcpy(buffer, buffer+strlen("element vertex"));
sscanf(buffer,"%i", &TotalConnectedPoints);
int TotalFaces;
// Find number of face
fseek(file,0,SEEK_SET);
while ( strncmp( "element face", buffer,strlen("element face")) != 0 )
{
fgets(buffer,300,file); // format
}
strcpy(buffer, buffer+strlen("element face"));
sscanf(buffer,"%i", &TotalFaces);
// go to end_header
while ( strncmp( "end_header", buffer,strlen("end_header")) != 0 )
{
fgets(buffer,300,file); // format
}
i =0;
float* ver0,ver1,ver2,ver3;
//char* key[100];
for (int iterator = 0; iterator < TotalConnectedPoints; iterator++)
{
fgets(buffer,300,file);
//sscanf(buffer,"%f %f %f", &Vertex_Buffer[i], &Vertex_Buffer[i+1], &Vertex_Buffer[i+2]);
sscanf(buffer,"%f %f %f", &ver1, &ver2, &ver3);
glNormal3f(ver1, ver2, ver3);
glVertex3d(ver1, ver2, ver3);
//glVertex3f(ver1, ver2, ver3);
i += 3;
}
}
}
glPushMatrix();
glBegin;
glTranslatef(-10,5,0);
glColor3f(1,1,1);
glRotatef(90,0,1,0);
glutSolidCone(0.25, 15, 20, 20);
glEnd();
glPopMatrix();
//glutMouseFunc(0,0,0);
/*
glVertex3d(1.000000, 1.000000, 6);
glVertex3d(3.000000, 0.000000, 4);
glVertex3d(0.000000, 0.000000, 4);
glVertex3d(0.000000, 3.000000, 4);
glVertex3d(1.500000, 0.500000, 0);*/
glEnd();
// Show the new scene
SwapBuffers(hDC);/**/
}
void keyPressed (unsigned char key, int x, int y) {
}
// Handle window events and messages
LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
ResizeGraphics();
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
// Default event handler
default:
return DefWindowProc (hWnd, uMsg, wParam, lParam);
break;
}
return 1;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
const LPCWSTR appname = TEXT("OpenGL Sample");
WNDCLASS wndclass;
MSG msg;
// Define the window class
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)MainWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, appname);
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wndclass.lpszMenuName = appname;
wndclass.lpszClassName = appname;
// Register the window class
if (!RegisterClass(&wndclass)) return FALSE;
// Create the window
hWnd = CreateWindow(
appname,
appname,
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd) return FALSE;
// Initialize OpenGL
InitGraphics();
// Display the window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
DrawGraphics();
// Event loop
int key;
int asgh = 0;
POINT pt;
/**/while (1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE)
{
if (!GetMessage(&msg, NULL, 0, 0))
return TRUE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
glutKeyboardFunc(keyPressed);
DrawGraphics();
}
wglDeleteContext(hRC);
ReleaseDC(hWnd, hDC);
}
The program you posted lacks a call to glutInit().
Furthermore you're doing all of the platform-specific window management and context creation that GLUT is supposed abstract away.
Bottom line: If you want to use GLUT, use GLUT. If you want to use Win32, use Win32. Don't try to mix-and-match.