我应该使用 Direct3D 还是只使用 Windows GDI 来获得花哨/高性能的 Win32 应用程序 UI? [关闭]
Posted
技术标签:
【中文标题】我应该使用 Direct3D 还是只使用 Windows GDI 来获得花哨/高性能的 Win32 应用程序 UI? [关闭]【英文标题】:Should I use Direct3D or just Windows GDI for a fancy/high-perf Win32 app UI? [closed] 【发布时间】:2015-11-02 21:07:29 【问题描述】:寻找正确的通用方法来使 UI 变得非常活泼。
我正在考虑开发一种 UI 工具,它可能会超越一些“内部”工具。它将涉及精细和自定义的 2d 元素,并且需要支持大型虚拟表面的快速滚动,这可能需要非常快速地重新绘制大量自定义内容。
早在 XP 刚推出时,我就做过一些 GDI 编程,但我遇到了一些性能问题,有很多全屏 blitting(无论如何,它是一台速度很慢的计算机)。我知道 GDI 有一定程度的加速,但我很难确定我可以在这里加速什么。
我只在游戏中使用过 Direct3D。让 D3D 为窗口 GUI 应用程序提供动力是否合理?另外,如果我使用 D3D,我是否必须从头开始做所有事情,或者我可以制作某种 GDI/D3D 混合,例如,在 WM_PAINT 中使用 Direct3D 调用或其他东西,以利用一些 Win32 的东西,如菜单栏或列表框与一个充满 D3D 渲染内容的面板并排?有没有人有将 D3D 与 Win32 gui junk 混合的例子?或者这真的不是正确的方法吗?
AutoCad 或 3ds Max 或 Photoshop 等程序,或其他具有类似复杂 UI 的主要 Win32 应用程序有什么作用?
【问题讨论】:
简短回答:坚持使用 GDI。 Blitting 是硬件加速的,所以不用担心那里的性能问题。 Direct3D 意味着巨大的开销。即使在渲染大量小部件(可能有数百个)时,GPU 加速最终分摊的开销(数十万个多边形)也相去甚远。 Direct3D 也意味着进入一个痛苦的世界。现在您受驱动程序供应商的摆布,他们似乎无法就光栅化规则达成一致:您将看到一个像素的偏移量。对于游戏来说问题不大,但忘记在您的 GUI 中进行像素完美渲染。 【参考方案1】:如果您的 GUI 涉及 3D 场景的 3D 操作,那么 Direct3D 或 OpenGL 可能会更胜一筹。如果你只是想给你的 GUI 一个“不乏味”的外观,其中控件被风格化并使用 alpha 混合位图等进行绘制,那么你最好坚持使用传统的窗口系统(即 GDI)作为底部- 大多数渲染层。然而,实现这种“外观”的最简单方法是使用更高级别的工具包,如 wxWidgets 或 Qt,以实现主题和自定义,使您的 GUI 看起来“现代”,而不是像无聊的公司应用程序.
另一种选择是使用来自本机应用程序的 XAML/WPF,并使用可用于创建基于 XAML 的 GUI 的工具,例如 Microsoft 的 Expression。我自己还没有探索过,但是使用 2013 年 3 月 MSDN 杂志上的 this article 中的技术应该是可行的。
【讨论】:
谢谢。我关心的不是菜单和按钮等等,也不是试图看起来“现代”。这是正在编辑的主要主题,主要是数千个带有标签和自定义交互和绘画的二维彩色矩形。我正在考虑使用混合,使用 GDI 或 WPF 来处理典型的 UI 内容(例如菜单、工具栏、帮助窗口),然后为图形加速内容使用不可见的无边框窗口。 Direct2D/DirectWrite 旨在成为 GDI 的 GPU 加速替代品。 Direct2D 是一种类似于 GDI 的“矢量绘图”技术,因此它比直接使用 Direct3D 更好。 根据您非常笼统的描述,很难准确地说出哪个是最佳的整体选择。当然,长期以来人们一直在编写处理数千个矩形的 GDI 应用程序——用于电子设备设计或电路板设计的 CAD 应用程序就是一个很好的例子。当然,将数以千计的文本标签塞进一个窗口会非常忙碌,即使该窗口是全屏的。 Direct2D/DirectWrite 无疑是一种可以为您提供 GPU 加速的选项,并且可以对 2D 基元进行高质量的抗锯齿处理。 XAML/WPF 过去对本机应用程序的支持有限。使用 Windows 10 和 Universal Windows Platform 应用程序,情况发生了变化。您现在可以使用 XAML/WPF 编写本机应用程序,使用纯 C++、带有Windows Runtime C++ Template Library (WRL) 或 C++/CX 的 C++。【参考方案2】:简单的 C 风格 D3D9 应用程序代码(显示网格)。
////////////////////////////////////////////////////////////////
// Defines main Direct3D rendering funcions
#include <windows.h>
#include <mmsystem.h>
#include <d3d9.h>
#include "d3dx9.h"
#include "cube_prim.h"
#ifndef __D3D_RENDERER_H__
#define __D3D_RENDERER_H__
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
LPDIRECT3D9 pDirect3D = NULL;
LPDIRECT3DDEVICE9 pDirect3DDevice = NULL;
LPDIRECT3DVERTEXBUFFER9 pDirect3DVertexBuffer = NULL;
LPDIRECT3DINDEXBUFFER9 pDirect3DIndexBuffer = NULL;
LPDIRECT3DTEXTURE9 pDirect3DTexture01 = NULL;
LPDIRECT3DTEXTURE9 pDirect3DTexture02 = NULL;
LPD3DXMESH pD3DXMesh = NULL;
D3DMATERIAL9* pDirect3DMaterial = NULL;
LPDIRECT3DTEXTURE9* pDirect3DTexture = NULL;
DWORD Subsets = 0;
FLOAT XRot = 0.0f;
FLOAT YRot = 0.0f;
HRESULT InitializeD3D(HWND hWnd)
D3DDISPLAYMODE dispMode;
D3DPRESENT_PARAMETERS parameters;
pDirect3D = Direct3DCreate9(D3D_SDK_VERSION);
if (pDirect3D == NULL)
return E_FAIL;
if (FAILED(pDirect3D->GetAdapterDisplayMode(
D3DADAPTER_DEFAULT,&dispMode)))
return E_FAIL;
ZeroMemory(¶meters,sizeof(D3DPRESENT_PARAMETERS));
parameters.Windowed = FALSE;
parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
parameters.BackBufferFormat = dispMode.Format;
parameters.BackBufferWidth = dispMode.Width;
parameters.BackBufferHeight = dispMode.Height;
parameters.BackBufferCount = 2;
parameters.EnableAutoDepthStencil = TRUE;
parameters.AutoDepthStencilFormat = D3DFMT_D24S8;
if (FAILED(pDirect3D->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,hWnd,D3DCREATE_HARDWARE_VERTEXPROCESSING,
¶meters,&pDirect3DDevice)))
return E_FAIL;
pDirect3DDevice->SetRenderState(D3DRS_LIGHTING,TRUE);
pDirect3DDevice->SetRenderState(D3DRS_AMBIENT,RGB(180,180,180));
pDirect3DDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
pDirect3DDevice->SetRenderState(D3DRS_ZENABLE,TRUE);
//pDirect3DDevice->SetRenderState(D3DRS_AMBIENTMATERIALSOURCE,D3DMCS_COLOR2);
//pDirect3DDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE,D3DMCS_COLOR2);
pDirect3DDevice->SetRenderState(D3DRS_SPECULARENABLE,TRUE);
return S_OK;
HRESULT InitializeD3DBufferObject(void)
VOID* pVertices = NULL;
VOID* pIndicies = NULL;
if (pDirect3DDevice != NULL)
if (FAILED(pDirect3DDevice->CreateVertexBuffer(
sizeof(vertices),0,D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT,&pDirect3DVertexBuffer,NULL)))
return E_FAIL;
if (FAILED(pDirect3DVertexBuffer->Lock(0,
sizeof(vertices),(void**)&pVertices,NULL)))
return E_FAIL;
memcpy(pVertices,vertices,sizeof(vertices));
pDirect3DVertexBuffer->Unlock();
if (FAILED(pDirect3DDevice->CreateIndexBuffer(
sizeof(indices),0,D3DFMT_INDEX32,D3DPOOL_DEFAULT,
&pDirect3DIndexBuffer,NULL)))
return E_FAIL;
if (FAILED(pDirect3DIndexBuffer->Lock(0,
sizeof(indices),(void**)&pIndicies,NULL)))
return E_FAIL;
memcpy(pIndicies,indices,sizeof(indices));
pDirect3DIndexBuffer->Unlock();
if (FAILED(D3DXCreateTextureFromFile(pDirect3DDevice,
_T("wood.tga"),&pDirect3DTexture01)))
return E_FAIL;
if (FAILED(D3DXCreateTextureFromFile(pDirect3DDevice,
_T("stripes.tga"),&pDirect3DTexture02)))
return E_FAIL;
return S_OK;
else
return E_FAIL;
HRESULT InitialMesh(void)
LPD3DXBUFFER pMeshObj = NULL;
LPD3DXMATERIAL pMaterial = NULL;
char buffer[255];
if (pDirect3DDevice != NULL)
if (FAILED(D3DXLoadMeshFromX(_T("Dwarf\\Dwarf.x"),
D3DXMESH_SYSTEMMEM,
pDirect3DDevice,
NULL,
&pMeshObj,
NULL,
&Subsets,
&pD3DXMesh)))
return E_FAIL;
pMaterial = (D3DXMATERIAL*)pMeshObj->GetBufferPointer();
pDirect3DMaterial = new D3DMATERIAL9[Subsets];
pDirect3DTexture = new LPDIRECT3DTEXTURE9[Subsets];
for (INT i = 0; i < Subsets; i++)
pDirect3DMaterial[i] = pMaterial[i].MatD3D;
sprintf(buffer,"Dwarf\\");
strcat(buffer,pMaterial[i].pTextureFilename);
if (FAILED(D3DXCreateTextureFromFileA(
pDirect3DDevice,buffer,&pDirect3DTexture[i])))
return E_FAIL;
pMeshObj->Release();
return S_OK;
else
return E_FAIL;
VOID ChangeSize(INT cx,INT cy)
D3DXMATRIX projMatrix;
if (pDirect3DDevice != NULL)
if (cy == 0)
cy = 1;
FLOAT aspectRatio = static_cast<FLOAT>(cx) /
static_cast<FLOAT>(cy);
D3DXMatrixPerspectiveFovLH(&projMatrix,45.0f,
aspectRatio,1.0f,150.0f);
pDirect3DDevice->SetTransform(D3DTS_PROJECTION,&projMatrix);
VOID RotateScene(void)
if (GetAsyncKeyState(VK_ESCAPE))
exit(0);
if (GetAsyncKeyState(VK_UP))
XRot -= 0.1f;
if (GetAsyncKeyState(VK_DOWN))
XRot += 0.1f;
if (GetAsyncKeyState(VK_LEFT))
YRot -= 0.1f;
if (GetAsyncKeyState(VK_RIGHT))
YRot += 0.1f;
VOID RenderScene(void)
D3DXMATRIX worldMatrix;
D3DMATERIAL9 material;
D3DLIGHT9 light;
D3DCAPS9 caps;
D3DCOLORVALUE ambientLight = 0.0f, 0.0f, 0.0f, 1.0f ;
D3DCOLORVALUE diffuseLight = 0.7f, 0.7f, 0.7f, 1.0f ;
D3DCOLORVALUE specularLight = 1.0f, 1.0f, 1.0f, 1.0f ;
D3DCOLORVALUE materialColor = 1.0f, 1.0f, 1.0f, 1.0f ;
ZeroMemory(&material,sizeof(D3DMATERIAL9));
material.Ambient = materialColor;
material.Diffuse = materialColor;
material.Specular = specularLight;
material.Power = 20.0f;
ZeroMemory(&light,sizeof(D3DLIGHT9));
light.Ambient = ambientLight;
light.Diffuse = diffuseLight;
light.Specular = specularLight;
light.Range = 300.0f;
light.Position = D3DXVECTOR3(-30,150,-10);
light.Type = D3DLIGHT_POINT;
light.Attenuation0 = 1.0f;
if (pDirect3DDevice != NULL)
D3DXMatrixIdentity(&worldMatrix);
pDirect3DDevice->SetTransform(D3DTS_WORLD,&worldMatrix);
D3DXMatrixTranslation(&worldMatrix,0.0f,0.0f,4.0f);
pDirect3DDevice->MultiplyTransform(D3DTS_WORLD,&worldMatrix);
D3DXMatrixRotationX(&worldMatrix,XRot);
pDirect3DDevice->MultiplyTransform(D3DTS_WORLD,&worldMatrix);
D3DXMatrixRotationY(&worldMatrix,YRot);
pDirect3DDevice->MultiplyTransform(D3DTS_WORLD,&worldMatrix);
pDirect3DDevice->Clear(0,0,D3DCLEAR_TARGET |
D3DCLEAR_ZBUFFER,D3DCOLOR_ARGB(255,0,0,0),1.0f,0);
pDirect3DDevice->SetMaterial(&material);
pDirect3DDevice->SetLight(0,&light);
pDirect3DDevice->LightEnable(0,TRUE);
pDirect3DDevice->SetTexture(0,pDirect3DTexture01);
//pDirect3DDevice->SetTexture(1,pDirect3DTexture02);
pDirect3DDevice->SetTextureStageState(0,
D3DTSS_COLORARG1,D3DTA_TEXTURE);
pDirect3DDevice->SetTextureStageState(0,
D3DTSS_COLORARG2,D3DTA_DIFFUSE);
pDirect3DDevice->SetTextureStageState(0,
D3DTSS_COLOROP,D3DTOP_MODULATE);
pDirect3DDevice->SetTextureStageState(1,
D3DTSS_TEXCOORDINDEX,0);
pDirect3DDevice->SetTextureStageState(1,
D3DTSS_COLORARG1,D3DTA_TEXTURE);
pDirect3DDevice->SetTextureStageState(1,
D3DTSS_COLORARG1,D3DTA_TEXTURE);
pDirect3DDevice->SetTextureStageState(1,
D3DTSS_COLOROP,D3DTOP_MODULATE);
pDirect3DDevice->GetDeviceCaps(&caps);
pDirect3DDevice->SetSamplerState(0,D3DSAMP_MAXANISOTROPY,caps.MaxAnisotropy);
pDirect3DDevice->SetSamplerState(0,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
pDirect3DDevice->SetSamplerState(0,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC);
pDirect3DDevice->SetSamplerState(0,D3DSAMP_MIPFILTER,D3DTEXF_ANISOTROPIC);
pDirect3DDevice->SetSamplerState(1,D3DSAMP_MAXANISOTROPY,caps.MaxAnisotropy);
pDirect3DDevice->SetSamplerState(1,D3DSAMP_MINFILTER,D3DTEXF_ANISOTROPIC);
pDirect3DDevice->SetSamplerState(1,D3DSAMP_MAGFILTER,D3DTEXF_ANISOTROPIC);
pDirect3DDevice->SetSamplerState(1,D3DSAMP_MIPFILTER,D3DTEXF_ANISOTROPIC);
pDirect3DDevice->BeginScene();
pDirect3DDevice->SetStreamSource(0,pDirect3DVertexBuffer,0,
sizeof(CUSTOMVERTEX));
pDirect3DDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
pDirect3DDevice->SetIndices(pDirect3DIndexBuffer);
/*pDirect3DDevice->DrawIndexedPrimitive(
D3DPT_TRIANGLELIST,0,0,36,0,12);*/
for (int i = 0; i < Subsets; i++)
pDirect3DDevice->SetMaterial(&pDirect3DMaterial[i]);
pDirect3DDevice->SetTexture(0,pDirect3DTexture[i]);
pD3DXMesh->DrawSubset(i);
pDirect3DDevice->EndScene();
pDirect3DDevice->Present(NULL,NULL,NULL,NULL);
VOID ReleaseD3D(void)
if (pDirect3DTexture)
for (int i = 0; i < 0; i++)
pDirect3DTexture[i]->Release();
if (pDirect3DMaterial)
delete [] pDirect3DMaterial;
if (pD3DXMesh)
pD3DXMesh->Release();
if (pDirect3DTexture02)
pDirect3DTexture02->Release();
if (pDirect3DTexture01)
pDirect3DTexture01->Release();
if (pDirect3DIndexBuffer)
pDirect3DIndexBuffer->Release();
if (pDirect3DVertexBuffer)
pDirect3DVertexBuffer->Release();
if (pDirect3DDevice)
pDirect3DDevice->Release();
if (pDirect3D)
pDirect3D->Release();
#endif
App 使用简单的 Win32 框架和 WinMain 等...
MFC 类中的示例代码
#include "MainWnd.h"
#include "d3d_renderer.h"
CMainWnd::CMainWnd(void)
CMainWnd::~CMainWnd(void)
BEGIN_MESSAGE_MAP(CMainWnd, CWnd)
ON_WM_CREATE()
ON_WM_DESTROY()
ON_WM_SIZE()
ON_WM_TIMER()
ON_WM_PAINT()
END_MESSAGE_MAP()
// WM_CREATE
int CMainWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (FAILED(InitializeD3D(m_hWnd)))
exit(0);
if (FAILED(InitializeD3DBufferObject()))
exit(0);
if (FAILED(InitialMesh()))
exit(0);
SetTimer(33,1,NULL);
return 0;
// WM_DESTROY
void CMainWnd::OnDestroy()
CWnd::OnDestroy();
KillTimer(101);
ReleaseD3D();
// WM_SIZE
void CMainWnd::OnSize(UINT nType, int cx, int cy)
CWnd::OnSize(nType, cx, cy);
ChangeSize(cx,cy);
// WM_TIMER
void CMainWnd::OnTimer(UINT_PTR nIDEvent)
InvalidateRect(NULL,FALSE);
CWnd::OnTimer(nIDEvent);
// WM_PAINT
void CMainWnd::OnPaint()
RotateScene();
RenderScene();
ValidateRect(NULL);
所以决定你想使用什么(D3D 比 GDI 快得多)
您还可以使用 OpenGL 以更少的代码量绘制加速图形(比 D3D 慢一点)。
使用 OpenGL 和纯 Win32 UI 显示 3D 文本
#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
// Palette Handle
HPALETTE hPalette = NULL;
static LPCTSTR lpszAppName = "Text3D";
GLint nFontList;
// Light values and coordinates
GLfloat whiteLight[] = 0.4f, 0.4f, 0.4f, 1.0f ;
GLfloat diffuseLight[] = 0.8f, 0.8f, 0.8f, 1.0f ;
GLfloat specular[] = 0.9f, 0.9f, 0.9f, 1.0f;
GLfloat lightPos[] = -100.0f, 200.0f, 50.0f, 1.0f ;
// Declaration for Window procedure
LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);
// Set Pixel Format function - forward declaration
void SetDCPixelFormat(HDC hDC);
void ChangeSize(GLsizei w, GLsizei h)
GLfloat nRange = 100.0f;
GLfloat fAspect;
// Prevent a divide by zero
if(h == 0)
h = 1;
fAspect = (GLfloat)w/(GLfloat)h;
// Set Viewport to window dimensions
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
// Reset coordinate system
glLoadIdentity();
// Setup perspective for viewing
gluPerspective(17.5f,fAspect,1,300);
// Viewing transformation
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-1.8f, 0.0f, -15.0f);
glRotatef(-20.0f, 0.0f, 1.0f,0.0f);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
void RenderScene(void)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Blue 3D Text
glColor3ub(0, 0, 255);
glPushMatrix();
glListBase(nFontList);
glCallLists (6, GL_UNSIGNED_BYTE, "OpenGL");
glPopMatrix();
void SetupRC(HDC hDC)
// Setup the Font characteristics
HFONT hFont;
GLYPHMETRICSFLOAT agmf[128]; // Throw away
LOGFONT logfont;
logfont.lfHeight = -10;
logfont.lfWidth = 0;
logfont.lfEscapement = 0;
logfont.lfOrientation = 0;
logfont.lfWeight = FW_BOLD;
logfont.lfItalic = FALSE;
logfont.lfUnderline = FALSE;
logfont.lfStrikeOut = FALSE;
logfont.lfCharSet = ANSI_CHARSET;
logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logfont.lfQuality = DEFAULT_QUALITY;
logfont.lfPitchAndFamily = DEFAULT_PITCH;
strcpy(logfont.lfFaceName,"Arial");
// Create the font and display list
hFont = CreateFontIndirect(&logfont);
SelectObject (hDC, hFont);
//create display lists for glyphs 0 through 128 with 0.1 extrusion
// and default deviation.
nFontList = glGenLists(128);
wglUseFontOutlines(hDC, 0, 128, nFontList, 0.0f, 0.5f,
WGL_FONT_POLYGONS, agmf);
DeleteObject(hFont);
glEnable(GL_DEPTH_TEST); // Hidden surface removal
glEnable(GL_COLOR_MATERIAL);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0,GL_AMBIENT,whiteLight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glEnable(GL_LIGHT0);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glMaterialfv(GL_FRONT, GL_SPECULAR,specular);
glMateriali(GL_FRONT,GL_SHININESS,128);
// If necessary, creates a 3-3-2 palette for the device context listed.
HPALETTE GetOpenGLPalette(HDC hDC)
HPALETTE hRetPal = NULL; // Handle to palette to be created
PIXELFORMATDESCRIPTOR pfd; // Pixel Format Descriptor
LOGPALETTE *pPal; // Pointer to memory for logical palette
int nPixelFormat; // Pixel format index
int nColors; // Number of entries in palette
int i; // Counting variable
BYTE RedRange,GreenRange,BlueRange;
// Range for each color entry (7,7,and 3)
// Get the pixel format index and retrieve the pixel format description
nPixelFormat = GetPixelFormat(hDC);
DescribePixelFormat(hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
// Does this pixel format require a palette? If not, do not create a
// palette and just return NULL
if(!(pfd.dwFlags & PFD_NEED_PALETTE))
return NULL;
// Number of entries in palette. 8 bits yeilds 256 entries
nColors = 1 << pfd.cColorBits;
// Allocate space for a logical palette structure plus all the palette entries
pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));
// Fill in palette header
pPal->palVersion = 0x300; // Windows 3.0
pPal->palNumEntries = nColors; // table size
// Build mask of all 1's. This creates a number represented by having
// the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and
// pfd.cBlueBits.
RedRange = (1 << pfd.cRedBits) -1;
GreenRange = (1 << pfd.cGreenBits) - 1;
BlueRange = (1 << pfd.cBlueBits) -1;
// Loop through all the palette entries
for(i = 0; i < nColors; i++)
// Fill in the 8-bit equivalents for each component
pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange;
pPal->palPalEntry[i].peRed = (unsigned char)(
(double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);
pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange;
pPal->palPalEntry[i].peGreen = (unsigned char)(
(double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange);
pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange;
pPal->palPalEntry[i].peBlue = (unsigned char)(
(double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);
pPal->palPalEntry[i].peFlags = (unsigned char) NULL;
// Create the palette
hRetPal = CreatePalette(pPal);
// Go ahead and select and realize the palette for this device context
SelectPalette(hDC,hRetPal,FALSE);
RealizePalette(hDC);
// Free the memory used for the logical palette structure
free(pPal);
// Return the handle to the new palette
return hRetPal;
// Select the pixel format for a given device context
void SetDCPixelFormat(HDC hDC)
int nPixelFormat;
static PIXELFORMATDESCRIPTOR pfd =
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
1, // Version of this structure
PFD_DRAW_TO_WINDOW | // Draw to Window (not to bitmap)
PFD_SUPPORT_OPENGL | // Support OpenGL calls in window
PFD_DOUBLEBUFFER, // Double buffered mode
PFD_TYPE_RGBA, // RGBA Color mode
32, // Want 32 bit color
0,0,0,0,0,0, // Not used to select mode
0,0, // Not used to select mode
0,0,0,0,0, // Not used to select mode
16, // Size of depth buffer
0, // Not used to select mode
0, // Not used to select mode
0, // Draw in main plane
0, // Not used to select mode
0,0,0 ; // Not used to select mode
// Choose a pixel format that best matches that described in pfd
nPixelFormat = ChoosePixelFormat(hDC, &pfd);
// Set the pixel format for the device context
SetPixelFormat(hDC, nPixelFormat, &pfd);
// Entry point of all Windows programs
int APIENTRY WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
MSG msg; // Windows message structure
WNDCLASS wc; // Windows class structure
HWND hWnd; // Storeage for window handle
// Register Window style
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// No need for background brush for OpenGL window
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = lpszAppName;
// Register the window class
if(RegisterClass(&wc) == 0)
return FALSE;
// Create the main application window
hWnd = CreateWindow(
lpszAppName,
lpszAppName,
// OpenGL requires WS_CLIPCHILDREN and WS_CLIPSIBLINGS
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
// Window position and size
100, 100,
250, 250,
NULL,
NULL,
hInstance,
NULL);
// If window was not created, quit
if(hWnd == NULL)
return FALSE;
// Display the window
ShowWindow(hWnd,SW_SHOW);
UpdateWindow(hWnd);
// Process application messages until the application closes
while( GetMessage(&msg, NULL, 0, 0))
TranslateMessage(&msg);
DispatchMessage(&msg);
return msg.wParam;
// Window procedure, handles all messages for this program
LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
static HGLRC hRC; // Permenant Rendering context
static HDC hDC; // Private GDI Device context
switch (message)
// Window creation, setup for OpenGL
case WM_CREATE:
// Store the device context
hDC = GetDC(hWnd);
// Select the pixel format
SetDCPixelFormat(hDC);
// Create the rendering context and make it current
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
// Create the palette
hPalette = GetOpenGLPalette(hDC);
SetupRC(hDC);
break;
// Window is being destroyed, cleanup
case WM_DESTROY:
// Kill the timer that we created
KillTimer(hWnd,101);
glDeleteLists(nFontList, 128);
// Deselect the current rendering context and delete it
wglMakeCurrent(hDC,NULL);
wglDeleteContext(hRC);
// Delete the palette
if(hPalette != NULL)
DeleteObject(hPalette);
// Tell the application to terminate after the window
// is gone.
PostQuitMessage(0);
break;
// Window is resized.
case WM_SIZE:
// Call our function which modifies the clipping
// volume and viewport
ChangeSize(LOWORD(lParam), HIWORD(lParam));
break;
// The painting function. This message sent by Windows
// whenever the screen needs updating.
case WM_PAINT:
// Call OpenGL drawing code
RenderScene();
// Call function to swap the buffers
SwapBuffers(hDC);
ValidateRect(hWnd,NULL);
break;
// Windows is telling the application that it may modify
// the system palette. This message in essance asks the
// application for a new palette.
case WM_QUERYNEWPALETTE:
// If the palette was created.
if(hPalette)
int nRet;
// Selects the palette into the current device context
SelectPalette(hDC, hPalette, FALSE);
// Map entries from the currently selected palette to
// the system palette. The return value is the number
// of palette entries modified.
nRet = RealizePalette(hDC);
// Repaint, forces remap of palette in current window
InvalidateRect(hWnd,NULL,FALSE);
return nRet;
break;
// This window may set the palette, even though it is not the
// currently active window.
case WM_PALETTECHANGED:
// Don't do anything if the palette does not exist, or if
// this is the window that changed the palette.
if((hPalette != NULL) && ((HWND)wParam != hWnd))
// Select the palette into the device context
SelectPalette(hDC,hPalette,FALSE);
// Map entries to system palette
RealizePalette(hDC);
// Remap the current colors to the newly realized palette
UpdateColors(hDC);
return 0;
break;
default: // Passes it on if unproccessed
return (DefWindowProc(hWnd, message, wParam, lParam));
return (0L);
无需重置调色板即可工作
作为窗口句柄,您可以使用所有合法的窗口句柄(面板、列表框、按钮等...),因此您几乎可以在任何地方显示 3d 内容
Photoshop 使用 OpenGL,3DS Max 可选(OpenGL,Direct3D),AutoCad 很难说:GDI 旧版本,最新也使用 .NET。
【讨论】:
你们为什么这么消极? @VoidStar 询问了 GDI 和(在这种情况下为 D3D(OpenGL)的加速图形)之间的性能差异,以及 Direct3D(OpenGL)的可能用法。所以我展示了所有这些。 exept GDI(我想我们都熟悉这个 API)。标签显示用户对 C++ 和 WinAPI 感兴趣。 “VoidStar 询问了 GDI 和加速图形之间的性能差异 [...] 所以我展示了所有这些。除了 GDI”。你不认为你当时没有回答这个问题吗?以上是关于我应该使用 Direct3D 还是只使用 Windows GDI 来获得花哨/高性能的 Win32 应用程序 UI? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
我应该针对哪种版本的OpenGL / Direct3D实现最佳兼容性? [关闭]