Essentially, I'm trying to go oldschool and make a lil 2D engine, but instead of just importing bmp's or other image files, i'm looking to print each pixel to the screen myself.
Firstly, Ive got it so I can display a single image I made, however, for colors such as dark red, they show up fine on a black background, but change the background colour and the darkred becomes pink or whatever, like the background is bleeding through.
Secondly, I doubt my method is the best method for what i'm trying to do, so aswell as a fix to the above problem, and suggestions would be welcome.
And finally, yes, my code is so unoptimised as to probably give you a migraine. I seriously need to go through it and clean it up. :)
main.cpp
#include <Windows.h>
#include <windowsx.h>
#include "system.h"
LRESULT CALLBACK wndProc(HWND hwnd, UINT uint, WPARAM wparam, LPARAM lparam);
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hinstancePrev, LPSTR cmdLine, int cmdShow)
{
gameSystem* sys;
bool result;
sys = new gameSystem;
if (!sys)
return false;
result = sys->systemInit();
if (result)
{
sys->systemRun();
}
sys->systemShutdown();
delete sys;
sys = 0;
return 0;
}
----
system.h
#pragma once
#ifndef _GAMESYSTEM_
#define _GAMESYSTEM_
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include "game2D.h"
class gameSystem
{
public:
gameSystem();
gameSystem(const gameSystem&);
~gameSystem();
bool systemInit();
void systemShutdown();
void systemRun();
LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);
private:
bool systemFrame();
bool initWindows(int&, int&);
void shutdownWindows();
LPSTR appName;
HINSTANCE hInstance;
HWND hwnd;
bool fullscreen;
game2D* lD2D;
};
static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
static gameSystem* appHandle = 0;
#endif
----
system.cpp
#include "system.h"
#include "game2D.h"
gameSystem::gameSystem()
{
}
gameSystem::gameSystem(const gameSystem& other)
{
}
gameSystem::~gameSystem()
{
}
bool gameSystem::systemInit()
{
// HRESULT hr;
int scrW, scrH;
//bool result;
scrW = 0;
scrH = 0;
fullscreen = 0;
lD2D = new game2D();
lD2D->game2DInit();
if (!initWindows(scrW, scrH))
{
return false;
}
return true;
}
void gameSystem::systemShutdown()
{
lD2D->game2DShutdown();
shutdownWindows();
return;
}
void gameSystem::systemRun()
{
MSG msg;
bool done, result;
ZeroMemory(&msg, sizeof(MSG));
done = false;
while (!done)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (msg.message == WM_QUIT)
{
done = true;
}
else
{
result = systemFrame();
if (!result)
{
done = true;
}
}
}
return;
}
bool gameSystem::systemFrame()
{
lD2D->game2DRender();
return true;
}
LRESULT CALLBACK gameSystem::MessageHandler(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_KEYDOWN:
{
return 0;
}
case WM_KEYUP:
{
return 0;
}
default:
{
return DefWindowProc(hwnd, msg, wparam, lparam);
}
}
}
bool gameSystem::initWindows(int& screenWidth, int& screenHeight)
{
WNDCLASSEX wc;
DEVMODE dmScreenSettings;
int posX, posY;
appHandle = this;
hInstance = GetModuleHandle(NULL);
appName = "Engine";
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 3);
wc.lpszMenuName = NULL;
wc.lpszClassName = appName;
wc.cbSize = sizeof(WNDCLASSEX);
RegisterClassEx(&wc);
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN);
if (fullscreen)
{
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth;
dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
posX = posY = 0;
}
else
{
screenWidth = 320;
screenHeight = 240;
posX = (GetSystemMetrics(SM_CXSCREEN) - screenWidth) / 2;
posY = (GetSystemMetrics(SM_CYSCREEN) - screenHeight) / 2;
}
hwnd = CreateWindowEx(NULL, appName, appName, WS_OVERLAPPEDWINDOW, posX, posY, screenWidth, screenHeight, NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, SW_SHOW);
SetForegroundWindow(hwnd);
SetFocus(hwnd);
/*ShowCursor(false);*/
//if (!dxEng->initDX(hInstance, screenWidth, screenHeight, hwnd))
//{
// return false;
//}
lD2D->game2DCreateDevice(hwnd);
lD2D->game2DResize(screenWidth, screenHeight);
return true;
}
void gameSystem::shutdownWindows()
{
ShowCursor(true);
delete lD2D;
lD2D = 0;
if (fullscreen)
{
ChangeDisplaySettings(NULL, 0);
}
DestroyWindow(hwnd);
hwnd = NULL;
UnregisterClass(appName, hInstance);
hInstance = NULL;
appHandle = NULL;
return;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
default:
{
return appHandle->MessageHandler(hwnd, msg, wparam, lparam);
}
}
}
----
game2d.h
#pragma once
#include <d2d1.h>
#include <d2d1helper.h>
#include <string>
#include <vector>
struct pixelImage
{
int rows;
int cols;
std::vector <float> dataStore;
};
class game2D
{
public:
game2D();
~game2D();
HRESULT game2DInit();
void game2DRender();
void game2DResize(UINT width, UINT height);
D2D1_RECT_F setPixel(UINT xCoord, UINT yCoord, float red, float blue, float green, float alpha);
void loadAsset();
void convertTo();
HRESULT game2DCreateDevice(HWND localHWND);
void game2DShutdown();
private:
bool CDevComplete;
std::vector <char> tempStore;
pixelImage pxImage;
std::string fileContents;
long filesize;
int storeSize;
ID2D1Factory* D2DFactory;
ID2D1HwndRenderTarget* D2DRenderTarget;
ID2D1SolidColorBrush* D2DColorBrush;
ID2D1LinearGradientBrush* D2DGradientBrush;
};
----
game2d.cpp
#include "game2D.h"
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#pragma comment( lib, "d2d1.lib" )
game2D::game2D()
{
D2DFactory = NULL;
D2DRenderTarget = NULL;
D2DColorBrush = NULL;
D2DGradientBrush = NULL;
CDevComplete = false;
}
/*game2D::game2D(const game2D&)
{
}*/
game2D::~game2D()
{
}
HRESULT game2D::game2DInit()
{
HRESULT hr;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &D2DFactory);
return hr;
}
void game2D::game2DResize(UINT width, UINT height)
{
if (D2DRenderTarget)
{
D2DRenderTarget->Resize(D2D1::SizeU(width, height));
}
}
D2D1_RECT_F game2D::setPixel(UINT xCoord, UINT yCoord, float red, float blue, float green, float alpha)
{
D2D1_RECT_F local;
local = D2D1::RectF(
xCoord - 0.0f,
yCoord - 0.0f,
xCoord + 1.0f,
yCoord + 1.0f
);
D2DRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF(red, blue, green, alpha)), &D2DColorBrush);
return local;
}
void game2D::convertTo()
{
bool endLine = false;
bool deci = false;
int dataCount = 0;
int startCount = 0;
int trueCount = 0;
pxImage.dataStore.resize(filesize);
for (int i = 0; i < filesize; i++)
{
switch (tempStore[i])
{
if (endLine == true) endLine = false;
case 44: // ,
endLine = true;
dataCount++;
break;
case 46: // .
deci = true;
break;
case 48: // 0
if (startCount == 0) {
pxImage.cols = 0;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 0;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.0;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 0;
trueCount++;
}
}
break;
case 49: // 1
if (startCount == 0) {
pxImage.cols = 1;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 1;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.1;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 1;
trueCount++;
}
}
break;
case 50: // 2
if (startCount == 0) {
pxImage.cols = 2;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 2;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.2;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 2;
trueCount++;
}
}
break;
case 51: // 3
if (startCount == 0) {
pxImage.cols = 3;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 3;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.3;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 3;
trueCount++;
}
}
break;
case 52: // 4
if (startCount == 0) {
pxImage.cols = 4;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 4;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.4;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 4;
trueCount++;
}
}
break;
case 53: // 5
if (startCount == 0) {
pxImage.cols = 5;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 5;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.5;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 5;
trueCount++;
}
}
break;
case 54: // 6
if (startCount == 0) {
pxImage.cols = 6;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 6;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.6;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 6;
trueCount++;
}
}
break;
case 55: // 7
if (startCount == 0) {
pxImage.cols = 7;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 7;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.7;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 7;
trueCount++;
}
}
break;
case 56: // 8
if (startCount == 0) {
pxImage.cols = 8;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 8;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.8;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 8;
trueCount++;
}
}
break;
case 57: // 9
if (startCount == 0) {
pxImage.cols = 9;
startCount++;
}
else if (startCount == 1) {
pxImage.rows = 9;
startCount++;
}
else {
if (deci == true) {
pxImage.dataStore[dataCount] = (float)0.9;
trueCount--;
deci = false;
}
else {
pxImage.dataStore[dataCount] = 9;
trueCount++;
}
}
break;
}
}
//pxImage.dataStore.resize(trueCount);
}
void game2D::loadAsset()
{
std::ifstream infile("c:\\heart.pxl", std::ios::hex || std::ios::in);
if (infile.is_open())
{
infile.seekg(0, std::ios::end);
filesize = (long)infile.tellg();
infile.seekg(0, std::ios::beg);
fileContents.resize(filesize);
tempStore.resize(filesize);
infile.read((char*)&tempStore[0], filesize);
infile.close();
}
storeSize = 0;
convertTo();
}
void game2D::game2DRender()
{
std::vector <float> test;
if (CDevComplete)
{
D2DRenderTarget->BeginDraw();
D2DRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
D2DRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::HotPink));
D2D1_SIZE_F rtSize = D2DRenderTarget->GetSize();
int width = static_cast<int>(rtSize.width);
int height = static_cast<int>(rtSize.height);
loadAsset();
float locLeft = 100.0f;
float locTop = 100.0f;
int pxCount = 2;
int check4Black = 0;
float sizeOfPixel = 10.0f;
float tempLeft = 0.0f;
float tempTop = 0.0f;
float f1 = 0.0f;
float f2 = 0.0f;
float f3 = 0.0f;
for (int i = 0; i < pxImage.rows; i++)
{
for (int j = 0; j < pxImage.cols; j++)
{
D2D1_RECT_F rect1 = D2D1::RectF(
locLeft + ((float)j * sizeOfPixel),
locTop + ((float)i * sizeOfPixel),
locLeft + ((float)j * sizeOfPixel) + sizeOfPixel,
locTop + ((float)i * sizeOfPixel) + sizeOfPixel
);
check4Black = pxCount;
f1 = pxImage.dataStore[check4Black++];
f2 = pxImage.dataStore[check4Black++];
f3 = pxImage.dataStore[check4Black++];
if (f1 == 0.0f && f2 == 0.0f && f3 == 0.0f)
{
D2DRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&D2DColorBrush
);
pxCount += 4;
}
else
{
D2DRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF(pxImage.dataStore[pxCount++], pxImage.dataStore[pxCount++], pxImage.dataStore[pxCount++], pxImage.dataStore[pxCount++])),
&D2DColorBrush
);
}
D2DRenderTarget->FillRectangle(&rect1, D2DColorBrush);
}
}
D2DRenderTarget->EndDraw();
}
else
{
game2DShutdown();
}
}
HRESULT game2D::game2DCreateDevice(HWND localHWND)
{
HRESULT hr;
if (!D2DRenderTarget)
{
RECT rc;
GetClientRect(localHWND, &rc);
D2D1_SIZE_U size = D2D1::SizeU(
rc.right - rc.left,
rc.bottom - rc.top);
hr = D2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(localHWND, size),
&D2DRenderTarget);
if (SUCCEEDED(hr))
{
CDevComplete = true;
}
}
return hr;
}
void game2D::game2DShutdown()
{
/*
ID2D1Factory* D2DFactory;
ID2D1HwndRenderTarget* D2DRenderTarget;
ID2D1SolidColorBrush* D2DColorBrush;
ID2D1LinearGradientBrush* D2DGradientBrush;
*/
CDevComplete = false;
if (D2DColorBrush != NULL)
{
D2DColorBrush->Release();
D2DColorBrush = NULL;
}
if (D2DRenderTarget != NULL)
{
D2DRenderTarget->Release();
D2DRenderTarget = NULL;
}
if (D2DFactory != NULL)
{
D2DFactory->Release();
D2DFactory = NULL;
}
}
----
These two images show the result:
With a black background: Click Here
With a hot pink background: Click Here
Also, can I just take this moment to complain about the lack of web based guides/tutorials for direct2D? It's damned infuriating.
Anyway, any help I might recieve would be wonderful.