尝试实现软件渲染器

在了解了 SDL2 如何画点(  http://blog.csdn.net/korekara88730/article/details/70880061 ) 的基础上,尝试实现一个渲染器。

先把基础的绘制封装到一个类里,操作起来方便些。这个 类就叫  MRender. 要实现的基本工程包括:   画点; 画线; 画三角形; 画简单3D 模型


今天先做了个简单的封装,把之前零散的逻辑放到 MRender 里面。这个类将来要根据功能,实现以下几个函数:

drawPoint(), drawLine(), drawTriangle(), drawModel()

由于需要反复操作自定义的 帧缓冲区, 本来打算帧缓冲区作为 MRender 的成员,以二维数组的形式存在。但是感觉不是很方便,于是新增加一个 类 MFrameBufferObject.这样 缓冲区 就可以 以对象的形式,组合进  MRender 里。

MRender 最终暴露出来一些接口,给 main.cpp 这种外围的代码调用。MRender要做成一个黑匣子,对外界透明。今天只简单的封装了一下,所以只有 最最简单的 画点的 功能.

剩下的功能会慢慢补上.


代码先贴在这

main.cpp

#include "MRender.h"

MRender render;

void draw()
{
	for (int x = 0; x < 50;x++)
	{
		for (int y = 0; y < 50;y++)
		{
			render.setColor(0, 255, 0, 255);
			render.drawPoint(x, y);
		}
	}	
}

int main(int argc, char* args[])
{
	if (!render.init())
	{
		return -1;
	}
	render.setClearColor(255, 0, 0, 255);
	render.setDrawFunc(draw);
	render.mainLoop();
	render.cleanup();
	return 0;
}

MRender.h

#ifndef __M_RENDER_H__
#define __M_RENDER_H__

#include "SDL.h"
#include <stdio.h>
#include <stdlib.h>

class MFrameBufferObject;
class MRender{
public:
	MRender();
	virtual ~MRender();

	bool init();
	void mainLoop();
	void cleanup();


	bool genBuffer();

	void setClearColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
	void setColor(Uint8 r,Uint8 g,Uint8 b,Uint8 a);
	void drawPoint(int x,int y);
	void drawLine(int x1, int y1, int x2, int y2);
	void drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3);

private:
	void drawFrameBuffer();
	bool isCurrentBufferAvailable() const;
	int getActiveBufferIndex() const { return _mActiveBufferIndex; }

private:
	SDL_Window* _mWindow;
	SDL_Surface* _mScreenSurface;
	SDL_Renderer* _mRenderer;


private:
	const static int MAX_FRAME_BUFFER_NUM = 3;
	MFrameBufferObject* _mFrameBuffers[MAX_FRAME_BUFFER_NUM];
	int _mActiveBufferIndex;


	Uint8 _drawR, _drawG, _drawB, _drawA;
	Uint8 _clearR, _clearG, _clearB, _clearA;


public:
	void setDrawFunc(void(*drawFunc)());
private:
	void (*_drawFunc)();

};


#endif //__M_RENDER_H__



MRender.cpp

#include "MRender.h"
#include "MFrameBufferObject.h"

const int SCREEN_WIDTH = 400;
const int SCREEN_HEIGHT = 400;

MRender::MRender()
:_mActiveBufferIndex(-1)
{
	for (size_t i = 0; i < MAX_FRAME_BUFFER_NUM; i++)
	{
		_mFrameBuffers[i] = nullptr;
	}
}

MRender::~MRender()
{
	for (size_t i = 0; i < MAX_FRAME_BUFFER_NUM; i++)
	{
		if (_mFrameBuffers[i] != nullptr)
		{
			delete _mFrameBuffers[i];
			_mFrameBuffers[i] = nullptr;
		}
	}
}

bool MRender::init()
{
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("SDL can not initialized!SDL Error:%s\n", SDL_GetError());
		return false;
	}
	_mWindow = SDL_CreateWindow("msdl1", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
	if (_mWindow == nullptr)
	{
		printf("SDL can't create window!SDL Error:%s\n", SDL_GetError());
		return false;
	}
	_mScreenSurface = SDL_GetWindowSurface(_mWindow);
	_mRenderer = SDL_CreateRenderer(_mWindow, -1, SDL_RENDERER_ACCELERATED);
	if (_mRenderer == nullptr)
	{
		return false;
	}
	//SDL_FillRect(gScreenSurface, nullptr, SDL_MapRGBA(gScreenSurface->format, 0xff, 0xff, 0xff, 0xff));
	SDL_FillRect(_mScreenSurface, nullptr, SDL_MapRGBA(_mScreenSurface->format, 0, 0, 0, 0));

	genBuffer();
	return true;
}

void MRender::mainLoop()
{
	bool quit = false;
	SDL_Event evt;
	while (!quit)
	{
		while (SDL_PollEvent(&evt) != 0)
		{
			if (evt.type == SDL_QUIT){
				quit = true;
			}
		}
		SDL_RenderClear(_mRenderer);
		drawFrameBuffer();
		// present
		SDL_RenderPresent(_mRenderer);
	}
}

void MRender::cleanup()
{
	SDL_DestroyRenderer(_mRenderer);
	SDL_DestroyWindow(_mWindow);
	SDL_Quit();
}


bool MRender::genBuffer()
{
	if (getActiveBufferIndex() <= MAX_FRAME_BUFFER_NUM - 1)
	{
		_mActiveBufferIndex++;
		if (_mFrameBuffers[_mActiveBufferIndex] == nullptr)
		{
			_mFrameBuffers[_mActiveBufferIndex] = new MFrameBufferObject(SCREEN_WIDTH, SCREEN_HEIGHT);
		}
	}
	return false;
}


bool MRender::isCurrentBufferAvailable() const
{
	return _mActiveBufferIndex >= 0 && _mActiveBufferIndex < MAX_FRAME_BUFFER_NUM;
}

void MRender::drawFrameBuffer()
{
	if (!isCurrentBufferAvailable()){return;}
	MFrameBufferObject* frameBuffer = _mFrameBuffers[_mActiveBufferIndex];
	frameBuffer->setColor(_clearR, _clearG, _clearB, _clearA);
	frameBuffer->clear();
	if (_drawFunc != nullptr)
	{
		_drawFunc();
	}
	frameBuffer->setColor(_drawR, _drawG, _drawB, _drawA);
	frameBuffer->draw(_mRenderer);
}

void MRender::setClearColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
	_clearR = r; _clearG = g; _clearB = b; _clearA = a;
}

void MRender::setColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
	_drawR = r; _drawG = g; _drawB = b; _drawA = a;
}

void MRender::drawPoint(int x, int y)
{
	_mFrameBuffers[_mActiveBufferIndex]->setColorAt(x, y, _drawR, _drawG, _drawB, _drawA);
}

void MRender::drawLine(int x1, int y1, int x2, int y2)
{

}

void MRender::drawTriangle(int x1, int y1, int x2, int y2, int x3, int y3)
{

}


void MRender::setDrawFunc(void(*drawFunc)())
{
	_drawFunc = drawFunc;
}



MFrameBufferObject.h

#ifndef __M_FRAMEBUIFFER_OBJECT_H__
#define __M_FRAMEBUIFFER_OBJECT_H__

#include "SDL.h"

class MFrameBufferObject{

	
public:
	MFrameBufferObject(int width, int height);
	virtual ~MFrameBufferObject();

	Uint8 getR(size_t x,size_t y);
	Uint8 getG(size_t x, size_t y);
	Uint8 getB(size_t x, size_t y);
	Uint8 getA(size_t x, size_t y);


	void setColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
	void clear();
	void setColorAt(size_t x,size_t y,Uint8 r,Uint8 g,Uint8 b,Uint8 a);

	void draw(SDL_Renderer* pRenderer);

private:
	void resetData();
	int getBaseOffsetAt(size_t x,size_t y);

	// R,G,B,A
	size_t getOffsetR() const { return 0; }
	size_t getOffsetG() const { return 1; }
	size_t getOffsetB() const { return 2; }
	size_t getOffsetA() const { return 3; }

private:
	int _width;
	int _height;
	Uint8* _data;

	Uint8 _colR, _colG, _colB, _colA;
};

#endif //__M_FRAMEBUIFFER_OBJECT_H__

MFrameBufferObject.cpp

#include "MFrameBufferObject.h"
#include <assert.h>
#include <stdio.h>

const int PIXEL_STRID = 4;// 4 means (R,G,B,A) 4 members
MFrameBufferObject::MFrameBufferObject(int width, int height)
	:_width(width),
	_height(height),
	_colR(0x0),
	_colG(0x0),
	_colB(0x0),
	_colA(0x0)
{
	_data = new Uint8[_width * _height * PIXEL_STRID]; 
	resetData();
}

MFrameBufferObject::~MFrameBufferObject()
{
	if (_data){ delete _data; _data = nullptr; }
}

void MFrameBufferObject::resetData()
{
	for (int y = 0; y < _height;y++)
	{
		for (int x = 0; x < _width;x++)
		{
			int offset = getBaseOffsetAt(x,y);
			_data[offset + getOffsetR()] = _colR;
			_data[offset + getOffsetG()] = _colG;
			_data[offset + getOffsetB()] = _colB;
			_data[offset + getOffsetA()] = _colA;
		}
	}
}

int MFrameBufferObject::getBaseOffsetAt(size_t x, size_t y)
{
	assert(x >= 0 && x < _width && y >= 0 && y < _height);
	return y * _width * PIXEL_STRID + x * PIXEL_STRID;
}

Uint8 MFrameBufferObject::getR(size_t x, size_t y)
{
	return _data[getBaseOffsetAt(x,y) + getOffsetR()];
}

Uint8 MFrameBufferObject::getG(size_t x, size_t y)
{
	return _data[getBaseOffsetAt(x, y) + getOffsetG()];
}

Uint8 MFrameBufferObject::getB(size_t x, size_t y)
{
	return _data[getBaseOffsetAt(x, y) + getOffsetB()];
}

Uint8 MFrameBufferObject::getA(size_t x, size_t y)
{
	return _data[getBaseOffsetAt(x, y) + getOffsetA()];
}

void MFrameBufferObject::setColorAt(size_t x, size_t y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
	int baseOffset = getBaseOffsetAt(x, y);
	_data[baseOffset + getOffsetR()] = r;
	_data[baseOffset + getOffsetG()] = g;
	_data[baseOffset + getOffsetB()] = b;
	_data[baseOffset + getOffsetA()] = a;
}

void MFrameBufferObject::setColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
	_colR = r; _colG = g; _colB = b; _colA = a;
}

void MFrameBufferObject::clear()
{
	resetData();
}

void MFrameBufferObject::draw(SDL_Renderer* pRenderer)
{
	for (int y = 0; y < _height; y++)
	{
		for (int x = 0; x < _width; x++)
		{
			SDL_SetRenderDrawColor(pRenderer, getR(x,y),getG(x,y),getB(x,y),getA(x,y));
			SDL_RenderDrawPoint(pRenderer, x, y);
		}
	}

}




展开阅读全文
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值