问题
I am trying to make a basic framework for graphics with GDI to make some minigames with. But GDI is not rendering anything at all, I just get a black client area, and I have no idea what I'm doing wrong.
The following code is inside a game loop that is running constantly:
//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);
}
What am I doing wrong here? Sorry if it's some stupid mistake, I am not good at all with windows programming.
EDIT: additional code, as requested:
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 - Render method definition
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));
}
回答1:
This is how I used to do GDI rendering (old production code translated from VB6). This is in response to WM_PAINT
that is sent when either you (in your game loop) or Windows invalidates part of your window.
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);
}
You trigger a WM_PAINT
by invalidating your window using InvalidateRect:
InvalidateRect ( hWnd, NULL, FALSE );
Here's an MSDN article about client drawing. Some of this is coming back to me slowly, thanks for the question. :) I haven't done GDI in years.
来源:https://stackoverflow.com/questions/12764312/gdi-is-not-rendering-what-am-i-doing-wrong