我应该使用Direct3D还是只使用Windows GDI来获得高级/高性能的Win32应用程序UI

Should I use Direct3D or just Windows GDI for a fancy/high-perf Win32 app UI?

本文关键字:高性能 高级 应用程序 UI Win32 Direct3D Windows 我应该 GDI      更新时间:2023-10-16

寻找使UI真正快速的正确通用方法。

我正在考虑开发一个UI工具,它可能不仅仅是一些"内部"工具。它将涉及精心制作和自定义的2d元素,并且需要支持快速滚动一个大的虚拟表面,这可能需要非常快速地重新绘制大量的自定义内容。

当XP还是新的时候,我已经做了一些GDI编程,我遇到了一些性能问题,因为我有很多全屏闪电战(无论如何,这是一台速度很慢的计算机)。我知道GDI有一定程度的加速,但我很难确定我期望在这里加速什么。

我只在游戏中使用过Direct3D。让D3D为窗口GUI应用程序供电合理吗?此外,如果我使用D3D,我是否必须从头开始做所有事情,或者我是否可以进行某种GDI/D3D混合,例如,在WM_PAINT内部使用Direct3D调用或其他什么,以便利用一些Win32内容,如菜单栏或列表框,与满是D3D渲染内容的面板并排使用?有人举过把D3D和Win32 gui垃圾混在一起的例子吗?或者这真的不是正确的方法?

像AutoCad、3ds Max或Photoshop这样的程序,或者其他具有类似精细UI的主要Win32应用程序,会做什么?

如果您的GUI涉及3D场景的3D操作,Direct3D或OpenGL可能会胜出。如果你只是想让你的GUI看起来"不无聊",控件是风格化的,并用阿尔法混合位图绘制等等,那么你最好坚持传统的窗口系统(即GDI)作为最底层的渲染层。然而,实现这种"外观和感觉"的最简单方法是使用更高级别的工具包,如wxWidgets或Qt,以实现主题化和自定义,使您的GUI看起来"现代",而不像一个无聊的企业应用程序。

另一种选择是使用本机应用程序中的XAML/WPF,并使用可用于创建基于XAML的GUI(如Microsoft的Expression)的工具。我自己还没有探索过,但使用2013年3月版MSDN杂志上这篇文章中的技术应该是可行的。

简单的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(&parameters,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,
        &parameters,&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

应用程序使用简单的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 <glgl.h>
#include <glglu.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。