Skip to content

Instantly share code, notes, and snippets.

@gszauer
Last active December 18, 2015 03:29
Show Gist options
  • Save gszauer/5718473 to your computer and use it in GitHub Desktop.
Save gszauer/5718473 to your computer and use it in GitHub Desktop.
#include "BackBuffer.h"
#pragma comment (lib,"Gdiplus.lib")
using namespace Gdiplus;
GDIBackBuffer* g_pBackBuffer = 0;
void InitGDIBitmap(GDIBitmap& b) {
b.path.clear();
b.refCount = 0;
b.width = 0;
b.height = 0;
b.bitmap = 0;
b.brush = 0;
}
GDIBackBuffer::GDIBackBuffer() {
m_nScreenWidth = 0;
m_nScreenHeight = 0;
m_nWidthReciprical = 0.0f;
m_nHeightReciprical = 0.0f;
m_hWnd = (HWND)0;
m_hInstance = (HINSTANCE)0;
m_hDc = (HDC)0;
m_hBitmap = (HBITMAP)0;
m_hOldBitmap = (HBITMAP)0;
}
GDIBackBuffer::~GDIBackBuffer() { }
GDIBackBuffer* GDIBackBuffer::GetInstance() {
static GDIBackBuffer staticBuffer;
return &staticBuffer;
}
void GDIBackBuffer::Initialize(HWND hWnd, HINSTANCE hInstance, HDC hDc) {
m_hWnd = hWnd;
m_hInstance = hInstance;
m_hWndDc = hDc;
g_pBackBuffer = GDIBackBuffer::GetInstance();
RECT clientRect;
GetClientRect(hWnd, &clientRect);
m_nScreenWidth = clientRect.right - clientRect.left;
m_nScreenHeight = clientRect.bottom - clientRect.top;
m_nWidthReciprical = 1.0f / float(m_nScreenWidth);
m_nHeightReciprical = 1.0f / float(m_nScreenHeight);
m_hDc = CreateCompatibleDC(NULL);
m_hBitmap = CreateCompatibleBitmap(m_hWndDc, m_nScreenWidth, m_nScreenHeight);
m_hOldBitmap = (HBITMAP)SelectObject(m_hDc, m_hBitmap);
m_vLoadedBitmaps.clear();
GdiplusStartup(&m_gdiToken, &m_gdiStartupInput, NULL);
m_gdiGraphics = new Graphics(m_hDc);
m_gdiSolidBrush = new SolidBrush(Color::Black);
m_gdiPen = new Pen(Color::Black);
m_gdiFont = new Font(Gdiplus::FontFamily::GenericSansSerif(), 12);
}
void GDIBackBuffer::Shutdown() {
for (int i = int(m_vLoadedBitmaps.size()) - 1; i >= 0; --i)
UnloadImage(i);
m_vLoadedBitmaps.clear();
delete m_gdiFont;
delete m_gdiPen;
delete m_gdiSolidBrush;
delete m_gdiGraphics;
GdiplusShutdown(m_gdiToken);
SelectObject(m_hDc, m_hOldBitmap);
DeleteObject(m_hBitmap);
DeleteDC(m_hDc);
}
int GDIBackBuffer::LoadImage(std::string path) {
unsigned int size = m_vLoadedBitmaps.size();
int itemIndex = -1;
for (unsigned int i = 0; i < size; ++i) {
if (m_vLoadedBitmaps[i].path == path) {
m_vLoadedBitmaps[i].refCount += 1;
return i;
}
if (m_vLoadedBitmaps[i].refCount == 0) {
if (itemIndex == -1) {
itemIndex = i;
}
}
}
if (itemIndex == -1) {
GDIBitmap newBitmap;
InitGDIBitmap(newBitmap);
m_vLoadedBitmaps.push_back(newBitmap);
itemIndex = int(size);
}
m_vLoadedBitmaps[itemIndex].path = path;
m_vLoadedBitmaps[itemIndex].refCount = 1;
std::wstring unicodeFilename(path.length(), L' ');
std::copy(path.begin(), path.end(), unicodeFilename.begin());
m_vLoadedBitmaps[itemIndex].bitmap = Bitmap::FromFile(unicodeFilename.c_str(), false);
//m_vLoadedBitmaps[itemIndex].bitmap.RotateFlip(Gdiplus::RotateNoneFlipY);
m_vLoadedBitmaps[itemIndex].width = int(m_vLoadedBitmaps[itemIndex].bitmap->GetWidth());
m_vLoadedBitmaps[itemIndex].height = int(m_vLoadedBitmaps[itemIndex].bitmap->GetHeight());
m_vLoadedBitmaps[itemIndex].brush = new TextureBrush(m_vLoadedBitmaps[itemIndex].bitmap);
return itemIndex;
}
void GDIBackBuffer::UnloadImage(int imageId) {
m_vLoadedBitmaps[imageId].refCount -= 1;
if (m_vLoadedBitmaps[imageId].refCount > 0)
return;
m_vLoadedBitmaps[imageId].refCount = 0;
m_vLoadedBitmaps[imageId].path.clear();
m_vLoadedBitmaps[imageId].width = 0;
m_vLoadedBitmaps[imageId].height = 0;
delete m_vLoadedBitmaps[imageId].brush;
m_vLoadedBitmaps[imageId].brush = 0;
delete m_vLoadedBitmaps[imageId].bitmap;
m_vLoadedBitmaps[imageId].bitmap = 0;
}
void GDIBackBuffer::BlitImage(int imageId, int x_dest, int y_dest, int width, int height, int x_source, int y_source, int source_w, int source_h) {
if (width == -1 && height == -1) {
width = m_vLoadedBitmaps[imageId].width;
height = m_vLoadedBitmaps[imageId].height;
}
if (source_w == -1 && source_h == -1) {
source_w = width;
source_h = height;
}
Point dest[2];
dest[0].X = x_dest;
dest[0].Y = y_dest;
dest[1].X = x_dest + width;
dest[1].Y = y_dest + width;
m_gdiGraphics->DrawImage(m_vLoadedBitmaps[imageId].bitmap, dest, 2, x_source, y_source, source_w, source_h, UnitPixel, NULL, NULL, NULL);
}
void GDIBackBuffer::PutPixel(int x, int y, COLORREF color) {
m_gdiSolidBrush->SetColor(Color(GetRValue(color), GetGValue(color), GetBValue(color)));
m_gdiGraphics->FillRectangle(m_gdiSolidBrush, x, y, 1, 1);
}
void GDIBackBuffer::PutPixel(int x, int y, int r, int g, int b) {
PutPixel(x, y, RGB(BYTE(r), BYTE(g), BYTE(b)));
}
void GDIBackBuffer::DrawLine(int x1, int y1, int x2, int y2, int r, int g, int b) {
DrawLine(x1, y1, x2, y2, RGB(BYTE(r), BYTE(g), BYTE(b)));
}
void GDIBackBuffer::DrawLine(int x1, int y1, int x2, int y2, COLORREF color) {
m_gdiPen->SetColor(Color(GetRValue(color), GetGValue(color), GetBValue(color)));
m_gdiGraphics->DrawLine(m_gdiPen, x1, y1, x2, y2);
}
void GDIBackBuffer::DrawTriangle(int* points, int r, int g, int b) {
DrawTriangle(points, RGB(BYTE(r), BYTE(g), BYTE(b)));
}
void GDIBackBuffer::DrawTriangle(int* points, COLORREF color) {
m_gdiPen->SetColor(Color(GetRValue(color), GetGValue(color), GetBValue(color)));
Point triangle[3];
triangle[0].X = points[0];
triangle[0].Y = points[1];
triangle[1].X = points[2];
triangle[1].Y = points[3];
triangle[2].X = points[4];
triangle[2].Y = points[5];
m_gdiGraphics->DrawPolygon(m_gdiPen, triangle, 3);
}
void GDIBackBuffer::FillTriangle(int* points, int r, int g, int b) {
m_gdiSolidBrush->SetColor(Color(BYTE(r), BYTE(g), BYTE(b)));
Point triangle[3];
triangle[0].X = points[0];
triangle[0].Y = points[1];
triangle[1].X = points[2];
triangle[1].Y = points[3];
triangle[2].X = points[4];
triangle[2].Y = points[5];
m_gdiGraphics->FillPolygon(m_gdiSolidBrush, triangle, 3);
}
void GDIBackBuffer::FillTriangle(int* points, int imageId) {
Point triangle[3];
triangle[0].X = points[0];
triangle[0].Y = points[1];
triangle[1].X = points[2];
triangle[1].Y = points[3];
triangle[2].X = points[4];
triangle[2].Y = points[5];
m_gdiGraphics->FillPolygon(m_vLoadedBitmaps[imageId].brush, triangle, 3);
}
void GDIBackBuffer::DrawSquare(int x, int y, int w, int h, int r, int g, int b) {
DrawSquare(x, y, w, h, RGB(BYTE(r), BYTE(g), BYTE(b)));
}
void GDIBackBuffer::DrawSquare(int x, int y, int w, int h, COLORREF color) {
m_gdiPen->SetColor(Color(GetRValue(color), GetGValue(color), GetBValue(color)));
m_gdiGraphics->DrawRectangle(m_gdiPen, x, y, w, h);
}
void GDIBackBuffer::FillSquare(int x, int y, int w, int h, int r, int g, int b) {
m_gdiSolidBrush->SetColor(Color(BYTE(r), BYTE(g), BYTE(b)));
m_gdiGraphics->FillRectangle(m_gdiSolidBrush, x, y, w, h);
}
void GDIBackBuffer::FillSquare(int x, int y, int w, int h, int imageId) {
m_gdiGraphics->FillRectangle(m_vLoadedBitmaps[imageId].brush, x, y, w, h);
}
void GDIBackBuffer::DrawSphere(int x, int y, int rad, int r, int g, int b) {
DrawSphere(x, y, rad, RGB(BYTE(r), BYTE(g), BYTE(b)));
}
void GDIBackBuffer::DrawSphere(int x, int y, int rad, COLORREF color) {
m_gdiPen->SetColor(Color(GetRValue(color), GetGValue(color), GetBValue(color)));
m_gdiGraphics->DrawEllipse(m_gdiPen, x - (rad / 2), y - (rad / 2), rad, rad);
}
void GDIBackBuffer::FillSphere(int x, int y, int rad, int r, int g, int b) {
m_gdiSolidBrush->SetColor(Color(BYTE(r), BYTE(g), BYTE(b)));
m_gdiGraphics->FillEllipse(m_gdiSolidBrush, x - (rad / 2), y - (rad / 2), rad, rad);
}
void GDIBackBuffer::FillSphere(int x, int y, int rad, int imageId) {
m_gdiGraphics->FillEllipse(m_vLoadedBitmaps[imageId].brush, x - (rad / 2), y - (rad / 2), rad, rad);
}
void GDIBackBuffer::Text(int x, int y, int r, int g, int b, std::string text) {
std::wstring wideString(text.length(), L' ');
std::copy(text.begin(), text.end(), wideString.begin());
m_gdiSolidBrush->SetColor(Color(BYTE(r), BYTE(g), BYTE(b)));
m_gdiGraphics->DrawString(wideString.c_str(), wideString.size(), m_gdiFont, PointF(x, y), m_gdiSolidBrush);
}
void GDIBackBuffer::Text(int x, int y, COLORREF color, std::string text) {
std::wstring wideString(text.length(), L' ');
std::copy(text.begin(), text.end(), wideString.begin());
m_gdiSolidBrush->SetColor(Color(GetRValue(color), GetGValue(color), GetBValue(color)));
m_gdiGraphics->DrawString(wideString.c_str(), wideString.size(), m_gdiFont, PointF(x, y), m_gdiSolidBrush);
}
void GDIBackBuffer::Clear() {
m_gdiSolidBrush->SetColor(Color::White);
m_gdiGraphics->FillRectangle(m_gdiSolidBrush, 0, 0, m_nScreenWidth, m_nScreenHeight);
}
void GDIBackBuffer::Clear(int r, int g, int b) {
m_gdiSolidBrush->SetColor(Color(BYTE(r), BYTE(g), BYTE(b)));
m_gdiGraphics->FillRectangle(m_gdiSolidBrush, 0, 0, m_nScreenWidth, m_nScreenHeight);
}
void GDIBackBuffer::Clear(COLORREF color) {
m_gdiSolidBrush->SetColor(Color(GetRValue(color), GetGValue(color), GetBValue(color)));
m_gdiGraphics->FillRectangle(m_gdiSolidBrush, 0, 0, m_nScreenWidth, m_nScreenHeight);
}
void GDIBackBuffer::Present() {
BitBlt(m_hWndDc, 0, 0, m_nScreenWidth, m_nScreenHeight, m_hDc, 0, 0, SRCCOPY);
/*POINT dest[3];
dest[0].x = 0;
dest[0].y = m_nScreenHeight;
dest[1].x = m_nScreenWidth;
dest[1].y = m_nScreenHeight;
dest[2].x = 0;
dest[2].y = 0;
PlgBlt(m_hWndDc, dest, m_hDc, 0, 0, m_nScreenWidth, m_nScreenHeight, 0, 0, 0);*/
}
void GDIBackBuffer::Resize(int width, int height) {
RECT clientRect;
GetClientRect(m_hWnd, &clientRect);
m_nScreenWidth = clientRect.right - clientRect.left;
m_nScreenHeight = clientRect.bottom - clientRect.top;
m_nWidthReciprical = 1.0f / float(m_nScreenWidth);
m_nHeightReciprical = 1.0f / float(m_nScreenHeight);
SelectObject(m_hDc, m_hOldBitmap);
DeleteObject(m_hBitmap);
DeleteDC(m_hDc);
m_hDc = CreateCompatibleDC(NULL);
m_hBitmap = CreateCompatibleBitmap(m_hWndDc, m_nScreenWidth, m_nScreenHeight);
m_hOldBitmap = (HBITMAP)SelectObject(m_hDc, m_hBitmap);
delete m_gdiGraphics;
m_gdiGraphics = new Graphics(m_hDc);
}
#ifndef _H_BACKBUFFER_
#define _H_BACKBUFFER_
#include <windows.h>
#include <string>
#include <vector>
#include <gdiplus.h>
typedef struct t_bitmap {
std::string path;
int refCount;
int width;
int height;
//HDC hdc;
//HBITMAP bitmap;
//HBITMAP oldBitmap;
Gdiplus::Bitmap* bitmap;
Gdiplus::TextureBrush* brush;
} GDIBitmap;
void InitGDIBitmap(GDIBitmap& b);
class GDIBackBuffer {
protected:
int m_nScreenWidth;
int m_nScreenHeight;
float m_nWidthReciprical;
float m_nHeightReciprical;
HWND m_hWnd;
HDC m_hWndDc;
HINSTANCE m_hInstance;
HDC m_hDc;
HBITMAP m_hBitmap;
HBITMAP m_hOldBitmap;
std::vector<GDIBitmap> m_vLoadedBitmaps;
Gdiplus::Graphics* m_gdiGraphics;
Gdiplus::GdiplusStartupInput m_gdiStartupInput;
ULONG_PTR m_gdiToken;
Gdiplus::SolidBrush* m_gdiSolidBrush;
Gdiplus::Pen* m_gdiPen;
Gdiplus::Font* m_gdiFont;
protected:
GDIBackBuffer();
GDIBackBuffer(const GDIBackBuffer&);
GDIBackBuffer& operator=(const GDIBackBuffer&);
public:
static GDIBackBuffer* GetInstance();
~GDIBackBuffer();
void Initialize(HWND hWnd, HINSTANCE hInstance, HDC hDc);
void Shutdown();
int LoadImage(std::string path);
void UnloadImage(int imageId);
void BlitImage(int imageId, int x_dest, int y_dest, int width = -1, int height = -1,
int x_source = 0, int y_source = 0, int source_w = -1, int source_h = -1);
void PutPixel(int x, int y, int r, int g, int b);
void PutPixel(int x, int y, COLORREF color);
void DrawLine(int x1, int y1, int x2, int y2, int r, int g, int b);
void DrawLine(int x1, int y1, int x2, int y2, COLORREF color);
void DrawTriangle(int* points, int r, int g, int b);
void DrawTriangle(int* points, COLORREF color);
void FillTriangle(int* points, int r, int g, int b);
void FillTriangle(int* points, int imageId);
void DrawSquare(int x, int y, int w, int h, int r, int g, int b);
void DrawSquare(int x, int y, int w, int h, COLORREF color);
void FillSquare(int x, int y, int w, int h, int r, int g, int b);
void FillSquare(int x, int y, int w, int h, int imageId);
void DrawSphere(int x, int y, int rad, int r, int g, int b);
void DrawSphere(int x, int y, int rad, COLORREF color);
void FillSphere(int x, int y, int rad, int r, int g, int b);
void FillSphere(int x, int y, int rad, int imageId);
void Text(int x, int y, int r, int g, int b, std::string text);
void Text(int x, int y, COLORREF color, std::string text);
void Clear();
void Clear(int r, int g, int b);
void Clear(COLORREF color);
void Present();
void Resize(int width, int height);
};
#endif
#include <windows.h>
#include <stdlib.h>
#include "BackBuffer.h"
#include "BackBufferLua.h"
// Include win main
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define TARGET_FPS 60
#define WND_CLASSNAME "WIN32IMGUI"
#define WND_TITLE "Win32 IMGUI: Base"
HWND g_hWnd;
HINSTANCE g_hInstance;
GDIBackBuffer* g_pGdiBackBuffer;
////////////////////////////////////////////////////////////////////
// Hook
void Initialize() { }
void Update() {
g_pGdiBackBuffer->Clear(RGB(0, 255, 0));
g_pGdiBackBuffer->Text(20, 20, RGB(255, 0, 0), "Hello World");
g_pGdiBackBuffer->Present();
}
void Shutdown() { }
void Resize(int width, int height) {
//g_pGdiBackBuffer->Resize(width, height);
}
////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
const int SKIP_TICKS = 1000 / TARGET_FPS;
DWORD next_game_tick = GetTickCount();
int sleep_time = 0;
MSG msg; HDC hdc;
g_hInstance = hInstance;
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wndclass.lpszMenuName = 0;
wndclass.lpszClassName = WND_CLASSNAME;
RegisterClassEx(&wndclass);
RECT windowRect;
SetRect(&windowRect, (GetSystemMetrics(SM_CXSCREEN) / 2) - (WINDOW_WIDTH / 2), (GetSystemMetrics(SM_CYSCREEN) / 2) - (WINDOW_HEIGHT / 2), (GetSystemMetrics(SM_CXSCREEN) / 2) + (WINDOW_WIDTH / 2), (GetSystemMetrics(SM_CYSCREEN) / 2) + (WINDOW_HEIGHT / 2));
AdjustWindowRectEx(&windowRect, WS_VISIBLE | WS_OVERLAPPEDWINDOW, FALSE, 0);
g_hWnd = CreateWindowEx(0, WND_CLASSNAME, WND_TITLE, WS_VISIBLE | WS_OVERLAPPEDWINDOW, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, NULL, NULL, hInstance, szCmdLine);
hdc = GetDC(g_hWnd);
g_pGdiBackBuffer = GDIBackBuffer::GetInstance();
ExposeToLua::GDIBBLuaPointer = g_pGdiBackBuffer;
g_pGdiBackBuffer->Initialize(g_hWnd, g_hInstance, hdc);
Initialize();
ShowWindow(g_hWnd, SW_SHOW);
UpdateWindow(g_hWnd);
while (true) {
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
next_game_tick += SKIP_TICKS;
sleep_time = next_game_tick - GetTickCount();
if(sleep_time >= 0)
Sleep(sleep_time);
Update();
}
Shutdown();
g_pGdiBackBuffer->Shutdown();
ReleaseDC(g_hWnd, hdc);
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
RECT window = { 0 };
switch (iMsg) {
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE:
GetClientRect(hwnd, &window);
Resize(int(window.right - window.left), int(window.bottom - window.top));
break;
case WM_PAINT:
case WM_ERASEBKGND:
return 0;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment