目录
什么是状态机?
基于状态机模式进行重构
Canvas.h源码
什么是状态机?
回顾之前两部分内容,我们做了:
- 绘制点
- 绘制线(Brensenham)
- 绘制三角形(拆分法)
- 图片操作(stb_image.h)
- 纹理贴图
- 效果处理
我们思考OpenGL是基于什么思想来做的,或者说什么样的设计模式?
答:状态机。那么什么是状态机?
状态机:
- 记录状态参数
- 更改状态参数
- 使用状态参数做事
白话解释:你给我什么参数,我就做什么事。给我true我就去做,false就不去做。
为什么用状态机?
- 图形学的程序结构特殊性,每个阶段关心的事情不一样
- 渲染管线的设置后处理的方便性
- 接口的整洁性
基于状态机模式进行重构
基于以上考虑和分析,我们对现有代码进行小小的重构:
canvas.h:
添加数据元类型,绘图模式,数据元素类:
enum DATA_TYPE {
GT_FLOAT=0,
GT_INT=1
};
enum DRAW_MODE {
GT_LINE=0,
GL_TRIANGLE=1
};
struct DataElement {
int m_size;
DATA_TYPE m_type;
int m_stride;//每次取点的步长
byte* m_data;//数据空间指针
DataElement() {
m_size = -1;
m_type = GT_FLOAT;
m_stride = 0;
m_data = nullptr;
}
};
将之前Canvan类中的一些变量,抽象出来,到一个Statement类中:
随后添加部分状态机接口:
//===========状态机接口===============
void gtVertexPointer(int _size, DATA_TYPE _type, int _stride, byte* _data);
void gtColorPointer(int _size, DATA_TYPE _type, int _stride, byte* _data);
void gtTexCoordPointer(int _size, DATA_TYPE _type, int _stride, byte* _data);
void gtDrawArray(DRAW_MODE _mode,int _first,int _count);//从first的点,画count个点
void Canvas::gtVertexPointer(int _size, DATA_TYPE _type, int _stride, byte* _data)
{
m_state.m_vertexData.m_size = _size;
m_state.m_vertexData.m_type = _type;
m_state.m_vertexData.m_stride = _stride;
m_state.m_vertexData.m_data = _data;
}
void Canvas::gtColorPointer(int _size, DATA_TYPE _type, int _stride, byte* _data)
{
m_state.m_colorData.m_size = _size;
m_state.m_colorData.m_type = _type;
m_state.m_colorData.m_stride = _stride;
m_state.m_colorData.m_data = _data;
}
void Canvas::gtTexCoordPointer(int _size, DATA_TYPE _type, int _stride, byte* _data)
{
m_state.m_texCoordData.m_size = _size;
m_state.m_texCoordData.m_type = _type;
m_state.m_texCoordData.m_stride = _stride;
m_state.m_texCoordData.m_data = _data;
}
void Canvas::gtDrawArray(DRAW_MODE _mode, int _first, int _count)
{
}
Canvas.h源码
为了方便查看,这里贴出Canvas.h的整体源码,也是对之前的一个总结梳理:
#pragma once
#include "GTMATH.hpp"
#include <string.h>
#include <vector>
#include "Image.h"
namespace GT {
//点类
class Point {
public:
int m_x;
int m_y;
RGBA m_color;
floatV2 m_uv;
Point(int _x = 0, int _y = 0, RGBA _color = RGBA(0, 0, 0, 0), floatV2 _uv = floatV2(0.0, 0.0)) {
m_x = _x, m_y = _y, m_color = _color, m_uv = _uv;
}
~Point() {}
};
enum DATA_TYPE {
GT_FLOAT=0,
GT_INT=1
};
enum DRAW_MODE {
GT_LINE=0,
GL_TRIANGLE=1
};
struct DataElement {
int m_size;
DATA_TYPE m_type;
int m_stride;//每次取点的步长
byte* m_data;//数据空间指针
DataElement() {
m_size = -1;
m_type = GT_FLOAT;
m_stride = 0;
m_data = nullptr;
}
};
struct Statement {
bool m_useBlend;//是否启用alpha混合模式
bool m_enableTexture;//是否启用纹理贴图
const Image* m_texture;//纹理贴图素材
Image::TEXTURE_TYPE m_texType;//纹理过滤
byte m_alphaLimit;//大于此像素值才可以进行绘制
DataElement m_vertexData;
DataElement m_colorData;
DataElement m_texCoordData;
Statement() {
m_useBlend = false;
m_enableTexture = false;
m_texture = nullptr;
m_texType = Image::TX_REPEAT;
m_alphaLimit = 0;
}
};
//画布类,封装一些之后的图形API
class Canvas {
private:
int m_width;
int m_height;
RGBA* m_buffer;
Statement m_state;
public:
Canvas(int _width, int _height, void* _buffer) {
if (_width <= 0 || _height <= 0) {
m_width = -1;
m_height = -1;
m_buffer = nullptr;
}
m_width = _width;
m_height = _height;
m_buffer = (RGBA*)_buffer;
m_state.m_useBlend = false;
m_state.m_enableTexture = false;
}
~Canvas()
{
}
//=========画布清洗============
void clear() {
if (m_buffer != nullptr) {
memset(m_buffer, 0, sizeof(RGBA) * m_width * m_height);
}
}
//=========画点操作============
void drawPoint(int x, int y, RGBA _color) {
if (x < 0 || x >= m_width || y < 0 || y >= m_height) {
return;
}
m_buffer[y * m_width + x] = _color;
}
//根据真正的背景值取pixel
RGBA getColor(int x, int y) {
if (x < 0 || x >= m_width || y < 0 || y >= m_height) {
return RGBA(0, 0, 0, 0);
}
return m_buffer[y * m_width + x];
}
//=========画线算法Brensenhem===
void drawLine(Point pt1,Point pt2);
//=========线性插值Lerp=========
inline RGBA colorLerp(RGBA _color1, RGBA _color2, float _scale) {
RGBA _color;
_color.m_r = _color.m_r + (float)(_color2.m_r - _color1.m_r) * _scale;
_color.m_g = _color.m_g + (float)(_color2.m_g - _color1.m_g) * _scale;
_color.m_b = _color.m_b + (float)(_color2.m_b - _color1.m_b) * _scale;
_color.m_a = _color.m_a + (float)(_color2.m_a - _color1.m_a) * _scale;
return _color;
}
//=========画三角形==============
void drawTriange(Point p1, Point p2, Point p3);
void drawTriangeFlat(Point pFlat1, Point pFlat2, Point pt);
//=========判断三角形是否与屏幕相交======
bool judgeInRect(Point p, GT_RECT _rect);
bool judgeInTriangle(Point pt, std::vector<Point> _ptArray);
//==========图片操作=============
void drawImage(int _x, int _y, Image* _image);
void setAlphaLimit(byte _limit) { m_state.m_alphaLimit = _limit; }
void setBlend(bool _useBlend) { m_state.m_useBlend = _useBlend; }
//===========纹理===============
void enableTexture(bool _enable) { m_state.m_enableTexture = _enable; }
void bindTexture(const Image* _image) { m_state.m_texture = _image; }
void setTextureType(Image::TEXTURE_TYPE _type) { m_state.m_texType = _type; }
inline floatV2 uvLerp(floatV2 _uv1, floatV2 _uv2, float _scale) {
floatV2 _uv;
_uv.x = _uv1.x + (_uv2.x - _uv1.x) * _scale;
_uv.y = _uv1.y + (_uv2.y - _uv1.y) * _scale;
return _uv;
}
//===========状态机接口===============
void gtVertexPointer(int _size, DATA_TYPE _type, int _stride, byte* _data);
void gtColorPointer(int _size, DATA_TYPE _type, int _stride, byte* _data);
void gtTexCoordPointer(int _size, DATA_TYPE _type, int _stride, byte* _data);
void gtDrawArray(DRAW_MODE _mode,int _first,int _count);//从first的点,画count个点
};
}