0

我正在尝试使用 GDI 制作一个基本的图形框架来制作一些迷你游戏。但是GDI根本没有渲染任何东西,我只是得到一个黑色的客户区,我不知道我做错了什么。

以下代码位于不断运行的游戏循环中:

//render double buffered with GDI
            HDC frontBuffer = GetDC(m_hMainWnd);

            HDC backBuffer;
            HBITMAP bitmap;
            HBITMAP oldBitmap;

            backBuffer = CreateCompatibleDC(frontBuffer);
            bitmap = CreateCompatibleBitmap(frontBuffer, m_ClientWidth, m_ClientHeight);
            oldBitmap = (HBITMAP)SelectObject(backBuffer, bitmap);

            GDI->StartDrawing(backBuffer, m_ClientWidth, m_ClientHeight); //this basically selects pens and brushes etc
            Render(dRenderTime); //here I render some stuff
            GDI->StopDrawing(backBuffer); //selects old pens and brushes back

         //blit backbuffer to frontbuffer
            BitBlt(frontBuffer, 0, 0, m_ClientWidth, m_ClientHeight, backBuffer, 0, 0, SRCCOPY);

            SelectObject(backBuffer, oldBitmap);
            DeleteObject(bitmap);
            DeleteDC(backBuffer);

            ReleaseDC(m_hMainWnd, frontBuffer);
        }

我在这里做错了什么?对不起,如果这是一些愚蠢的错误,我对 Windows 编程一点也不擅长。

编辑:附加代码,根据要求:

gdi.h

    #pragma once

#include <Windows.h>
#include "Macros.h"
#include "Transform.h"
#include "Text.h"

#define GDI gdi::getInstance()

class gdi
{
private:
  HPEN m_OldPen;
  HPEN m_Pen;
  HBRUSH m_OldBrush;
  HBRUSH m_Brush;
  HDC m_hdc;

  int m_DcWidth;
  int m_DcHeight;

  COLORREF m_Color;
  int m_LineWidth;

  DBlib::float3x3 m_Transform;

  gdi();

  void Transform(int& x_out, int& y_out, const DBlib::float2& p) const;
  void Transform_NDC_To_WC(int& x_out, int& y_out, const DBlib::float2& p) const;
  void Transfrom_WC_To_NDC(DBlib::float2& p_out, int x, int y) const;

public:
  ~gdi();

  static gdi* getInstance();

  void StartDrawing(HDC hdc, int dcwidth, int dcheight);
  void StopDrawing(HDC hdc);

  void SetColor(const DBlib::float3& col);
  void SetLineWidth(int width);

  void SetTransform(const DBlib::float3x3& transform);

  void DrawText(const DBlib::float2& p1, const std::tstring& s);
  void DrawLine(const DBlib::float2& p1, const DBlib::float2& p2);
  void DrawPolygon(const DBlib::float2* p, int size);
  void FillPolygon(const DBlib::float2* p, int size);
};

GDI.cpp

#include "gdi.h"

gdi* gdi::getInstance()
{
  static gdi instance;
  return &instance;
}

gdi::gdi()
{
  m_hdc = NULL;
  m_OldPen = NULL;
  m_OldBrush = NULL;
  m_LineWidth = 1;
  m_Color = RGB(0,0,0);
  m_DcWidth = -1;
  m_DcHeight = -1;
  m_Transform.set_identity();

  m_Pen = CreatePen(PS_SOLID,1,RGB(0,0,0));
  m_Brush = CreateSolidBrush(RGB(255,255,255));
}

gdi::~gdi()
{
    if(m_Pen) DeleteObject(m_Pen);
    if(m_Brush) DeleteObject(m_Brush);
}

void gdi::StartDrawing(HDC hdc, int dcwidth, int dcheight)
{
  m_hdc = hdc;
  m_DcWidth = dcwidth;
  m_DcHeight = dcheight;
  m_OldPen = (HPEN)SelectObject(hdc, m_Pen);
  m_OldBrush = (HBRUSH)SelectObject(hdc, m_Brush);
}

void gdi::StopDrawing(HDC hdc)
{
  SelectObject(hdc, m_OldPen);
  SelectObject(hdc, m_OldBrush);

  m_hdc = NULL;
  m_DcWidth = -1;
  m_DcHeight = -1;
  m_OldPen = NULL;
  m_OldBrush = NULL;
}

void gdi::SetColor(const DBlib::float3& col)
{
    int r = static_cast<int>(DBlib::clamp(col.x*255.0f, 0.0f, 255.0f));
    int g = static_cast<int>(DBlib::clamp(col.y*255.0f, 0.0f, 255.0f));
    int b = static_cast<int>(DBlib::clamp(col.z*255.0f, 0.0f, 255.0f));
    m_Color = RGB(r,g,b);

    SetTextColor(m_hdc, m_Color);

    if(m_Pen) DeleteObject(m_Pen);
    if(m_Brush) DeleteObject(m_Brush);
    m_Pen= CreatePen(PS_SOLID, m_LineWidth, m_Color);
    m_Brush= CreateSolidBrush(m_Color);
}

void gdi::SetLineWidth(int width)
{
    m_LineWidth = width;

    if(m_Pen) DeleteObject(m_Pen);
    m_Pen= CreatePen(PS_SOLID, m_LineWidth, m_Color);
}

void gdi::SetTransform(const DBlib::float3x3& transform)
{
    m_Transform = transform;
}

void gdi::Transform_NDC_To_WC(int& x_out, int& y_out, const DBlib::float2& p) const
{
    x_out = static_cast<int>((p.x+1.0f)*(static_cast<float>(m_DcWidth)/2.0f));
    y_out = m_DcHeight - static_cast<int>((p.y+1.0f)*(static_cast<float>(m_DcHeight)/2.0f));
}

void gdi::Transfrom_WC_To_NDC(DBlib::float2& p_out, int x, int y) const
{
    p_out.x = static_cast<float>(x)*2.0f/static_cast<float>(m_DcWidth) - 1.0f;
    p_out.y = -(static_cast<float>(y)*2.0f/static_cast<float>(m_DcHeight) - 1.0f);
}

void gdi::Transform(int& x_out, int& y_out, const DBlib::float2& p) const
{
    Transform_NDC_To_WC(x_out, y_out, p*m_Transform);
}

void gdi::DrawText(const DBlib::float2& pos, const std::tstring& s)
{
    int x,y;
    Transform(x,y,pos);
    TextOut(m_hdc, x, y, s.c_str(), (int)s.size());
}

void gdi::DrawLine(const DBlib::float2& p1, const DBlib::float2& p2)
{
    int x1,y1,x2,y2;
    Transform(x1,y1,p1);
    Transform(x2,y2,p2);

    MoveToEx(m_hdc, x1, y1, NULL);
    LineTo(m_hdc, x2, y2);
}

void gdi::DrawPolygon(const DBlib::float2* p, int size)
{
    int* x = new int[size];
    int* y = new int[size];

    for(int i=0; i<size; ++i) {
        Transform(x[i],y[i],*(p+i));
    }
    for(int i=0; i<size; ++i) {
        MoveToEx(m_hdc, x[i], y[i], NULL);
        LineTo(m_hdc, x[(i+1)%size], y[(i+1)%size]);
    }

    delete[] x;
    delete[] y;
}

void gdi::FillPolygon(const DBlib::float2* p, int size)
{
    int* x = new int[size];
    int* y = new int[size];
    POINT* pts = new POINT[size];

    for(int i=0; i<size; ++i) {
        Transform(x[i],y[i],*(p+i));
        pts[i].x = static_cast<LONG>(x[i]);
        pts[i].y = static_cast<LONG>(y[i]);
    }

    Polygon(m_hdc, pts, size);

    delete[] x;
    delete[] y;
    delete[] pts;
}

App.cpp - 渲染方法定义

void App::Render(float dTime)
{
    GDI->SetColor(DBlib::float3(1.0f,1.0f,1.0f));
    GDI->SetLineWidth(50);
    GDI->DrawLine(DBlib::float2(-1.0f,-1.0f), DBlib::float2(1.0f,1.0f));
}
4

1 回答 1

1

这就是我以前进行 GDI 渲染的方式(从 VB6 翻译的旧生产代码)。WM_PAINT这是在您(在您的游戏循环中)或 Windows 使您的部分窗口无效时发送的响应。

PAINTSTRUCT stPaintStruct;
HDC hPaintDC = BeginPaint(hWnd, &stPaintStruct);

if (hPaintDC != HANDLE_NULL)
{
    // establish clipping rect using stPaintStruct.rcPaint

    if (!m_bRendering)
    {
        m_bRendering = TRUE;

        // Render() knows the output bitmap and all the content to render
        // and makes sure resources are allocated / discarded during
        // rendering.
        Render ();

        m_bRendering = FALSE;
    }

    EndPaint (hWnd, &stPaintStruct);
    return (TRUE);
}

WM_PAINT您通过使用InvalidateRect使窗口无效来触发 a :

InvalidateRect ( hWnd, NULL, FALSE );

这是一篇关于客户端绘图的MSDN 文章。其中一些慢慢地回到我身边,谢谢你的提问。:) 我已经很多年没有做过 GDI 了。

于 2012-10-06T22:57:33.340 回答