frameBuffer.h

#pragma once
#include "../global/base.h"

/*
* class FrameBuffer:
* 存储当前画布对应的bmp的内存指针,作为当前绘图画板
*/
class FrameBuffer {
public:
FrameBuffer(uint32_t width, uint32_t height, void* buffer = nullptr);
~FrameBuffer();
FrameBuffer(const FrameBuffer&) = delete;//不准拷贝复制

uint32_t mWidth{ 0 };
uint32_t mHeight{ 0 };
RGBA* mColorBuffer{ nullptr };
bool mExternBuffer{ false };
};

frameBuffer.cpp

#include "frameBuffer.h"

FrameBuffer::FrameBuffer(uint32_t width, uint32_t height, void* buffer) {
mWidth = width;
mHeight = height;

if (!buffer) {
buffer = new RGBA[width * height];
mExternBuffer = false;
}
else {
mExternBuffer = true;
}

mColorBuffer = (RGBA*)buffer;

}

FrameBuffer::~FrameBuffer() {
if (!mExternBuffer && mColorBuffer) {
delete[] mColorBuffer;
}
}

gpu.h

#pragma once
#include "../global/base.h"
#include "frameBuffer.h"
#include "../application/application.h"

#define sgl GPU::getInstance()

/*
* class GPU:
* 模拟GPU的绘图行为以及算法等
*/
class GPU {
public:
static GPU* getInstance();
GPU();

~GPU();

//接受外界传入的bmp对应的内存指针以及窗体的宽/高
void initSurface(const uint32_t& width, const uint32_t& height, void* buffer = nullptr);

//清除画布内容
void clear();

//传入像素位置,绘制成某种颜色
void drawPoint(const uint32_t& x, const uint32_t& y, const RGBA& color);

void drawLine(const Point& p1, const Point& p2);

private:
static GPU* mInstance;

FrameBuffer* mFrameBuffer{ nullptr };
};

raster.h

#pragma once
#include "../global/base.h"

/*
* class Raster
* 对外提供静态函数接口,传入离散的图元点,返回光栅化后的像素数组
*/
class Raster {
public:
Raster();
~Raster();

static void rasterizeLine(
std::vector<Point>& results,
const Point& v0,
const Point& v1
);

static void interpolantLine(const Point& v0, const Point& v1, Point& target);
};

raster.cpp

#include "raster.h"

Raster::Raster() {}

Raster::~Raster() {}

void Raster::rasterizeLine(
std::vector<Point>& results,
const Point& v0,
const Point& v1) {

Point start = v0;
Point end = v1;

//1 保证x方向是从小到大的
if (start.x > end.x) {
auto tmp = start;
start = end;
end = tmp;
}

results.push_back(start);

//2 保证y方向也是从小到大,如果需要翻转,必须记录
bool flipY = false;
if (start.y > end.y) {
start.y *= -1.0f;
end.y *= -1.0f;
flipY = true;
}

//3 保证斜率在0-1之间,如果需要调整,必须记录
int deltaX = static_cast<int>(end.x - start.x);
int deltaY = static_cast<int>(end.y - start.y);

bool swapXY = false;
if (deltaX < deltaY) {
std::swap(start.x, start.y);
std::swap(end.x, end.y);
std::swap(deltaX, deltaY);
swapXY = true;
}

//4 brensenham
int currentX = static_cast<int>(start.x);
int currentY = static_cast<int>(start.y);

int resultX = 0;
int resultY = 0;

Point currentPoint;
int p = 2 * deltaY - deltaX;

for (int i = 0; i < deltaX; ++i) {
if (p >= 0) {
currentY += 1;
p -= 2 * deltaX;
}

currentX += 1;
p += 2 * deltaY;

//处理新xy,flip and swap

resultX = currentX;
resultY = currentY;
if (swapXY) {
std::swap(resultX, resultY);
}

if (flipY) {
resultY *= -1;
}

//产生新顶点
currentPoint.x = resultX;
currentPoint.y = resultY;

interpolantLine(start, end, currentPoint);

results.push_back(currentPoint);
}

}

void Raster::interpolantLine(const Point& v0, const Point& v1, Point& target) {
float weight = 1.0f;
if (v1.x != v0.x) {
//用x做比例
weight = (float)(target.x - v0.x) / (float)(v1.x - v0.x);
}else if (v1.y != v0.y) {
//用y做比例
weight = (float)(target.y - v0.y) / (float)(v1.y - v0.y);
}

RGBA result;
result.mR = static_cast<byte>(static_cast<float>(v1.color.mR) * weight + (1.0f - weight) * static_cast<float>(v0.color.mR));
result.mG = static_cast<byte>(static_cast<float>(v1.color.mG) * weight + (1.0f - weight) * static_cast<float>(v0.color.mG));
result.mB = static_cast<byte>(static_cast<float>(v1.color.mB) * weight + (1.0f - weight) * static_cast<float>(v0.color.mB));
result.mA = static_cast<byte>(static_cast<float>(v1.color.mA) * weight + (1.0f - weight) * static_cast<float>(v0.color.mA));

target.color = result;
}

gpu.cpp

#include "gpu.h"
#include "raster.h"

GPU* GPU::mInstance = nullptr;
GPU* GPU::getInstance() {
if (!mInstance) {
mInstance = new GPU();
}

return mInstance;
}

GPU::GPU() {}

GPU::~GPU() {
if (mFrameBuffer) {
delete mFrameBuffer;
}
}

void GPU::initSurface(const uint32_t& width, const uint32_t& height, void* buffer) {
mFrameBuffer = new FrameBuffer(width, height, buffer);
}

void GPU::clear() {
size_t pixelSize = mFrameBuffer->mWidth * mFrameBuffer->mHeight;
std::fill_n(mFrameBuffer->mColorBuffer, pixelSize, RGBA(0, 0, 0, 0));
}

void GPU::drawPoint(const uint32_t& x, const uint32_t& y, const RGBA& color) {
if (x >= mFrameBuffer->mWidth || y >= mFrameBuffer->mHeight) {
return;
}

//从窗口左下角开始算起
uint32_t pixelPos = y * mFrameBuffer->mWidth + x;
mFrameBuffer->mColorBuffer[pixelPos] = color;
}

void GPU::drawLine(const Point& p1, const Point& p2) {
std::vector<Point> pixels;
Raster::rasterizeLine(pixels, p1, p2);

for (auto p : pixels) {
drawPoint(p.x, p.y, p.color);
}
}