05直线的颜色运算-绘制彩色直线
//CCanvas.h
#pragma once
#include "gameMath.h"
#include <string.h>
namespace GT
{
struct RGBA
{
btye m_b;
btye m_g;
btye m_r;
btye m_a;
RGBA(btye _r = 255,
btye _g = 255,
btye _b = 255,
btye _a = 255)
{
m_r = _r;
m_g = _g;
m_b = _b;
m_a = _a;
}
};
class Point
{
public:
int m_x;
int m_y;
RGBA m_color;
Point(int _x, int _y, RGBA _color)
{
m_x = _x;
m_y = _y;
m_color = _color;
}
~Point()
{
}
};
class CCanvas
{
private:
int m_width;
int m_height;
RGBA* m_buffer;
public:
CCanvas(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;
}
~CCanvas()
{
}
//清屏
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;
}
void drawLine(intV2 pt1, intV2 pt2, RGBA _color);
inline RGBA colorLerp(RGBA _color1, RGBA _color2, float _scale)
{
RGBA _color;
_color.m_r = _color1.m_r + (float)(_color2.m_r - _color1.m_r) * _scale;
_color.m_g = _color1.m_g + (float)(_color2.m_g - _color1.m_g) * _scale;
_color.m_b = _color1.m_b + (float)(_color2.m_b - _color1.m_b) * _scale;
_color.m_a = _color1.m_a + (float)(_color2.m_a - _color1.m_a) * _scale;
return _color;
}
//画线操作 渐变色
void drawLine(Point pt1, Point pt2);
};
}
/CCanvas.cpp
#include "CCanvas.h"
#include <math.h>
namespace GT
{
void CCanvas::drawLine(Point pt1, Point pt2)
{
int disY = abs(pt2.m_y - pt1.m_y);
int disX = abs(pt2.m_x - pt1.m_x);
int xNow = pt1.m_x;
int yNow = pt1.m_y;
int stepX = 0;
int stepY = 0;
if (pt1.m_x < pt2.m_x)
stepX = 1;
else
stepX = -1;
if (pt1.m_y < pt2.m_y)
stepY = 1;
else
stepY = -1;
//对比xy偏移量,决定步进的方向选取x or y
int sumStep = disX;
bool useXstep = true;
if (disX < disY)
{
sumStep = disY;
useXstep = false;
SWAP_INT(disX, disY);
}
//初始化P值
int p = 2 * disY - disX;
for (int i = 0; i < sumStep; ++i)
{
RGBA _color;
float _scale = 0;
if (useXstep)
{
_scale = (float)(xNow - pt1.m_x) / (float)(pt2.m_x - pt1.m_x);
}
else
{
_scale = (float)(yNow - pt1.m_y) / (float)(pt2.m_y - pt1.m_y);
}
_color = colorLerp(pt1.m_color, pt2.m_color, _scale);
drawPoint(xNow, yNow, _color);
if (p >= 0)
{
if (useXstep)
{
yNow += stepY;
}
else
{
xNow += stepX;
}
p = p - 2 * disX;
}
//步进主坐标
if (useXstep)
{
xNow += stepX;
}
else
{
yNow += stepY;
}
p = p + 2 * disY;
}
};
void CCanvas::drawLine(intV2 pt1, intV2 pt2, RGBA _color)
{
//偏移值
int disY = abs(pt2.y - pt1.y);
int disX = abs(pt2.x - pt1.x);
//目前坐标
int xNow = pt1.x;
int yNow = pt1.y;
//步进值
int stepX = 0;
int stepY = 0;
//判断两个方向步进的正负
if (pt1.x < pt2.x)
stepX = 1;
else
stepX = -1;
if (pt1.y < pt2.y)
stepY = 1;
else
stepY = -1;
//对比xy偏移量, 决定步进的方向选取x or y
int sumStep = disX;
bool useXStep = true;
if (disX < disY)
{
sumStep = disY;
useXStep = false;
SWAP_INT(disX, disY);
}
//初始化P值
int p = 2 * disY - disX;
for (int i = 0; i < sumStep; ++i)
{
drawPoint(xNow, yNow, _color);
if (p >= 0)
{
if (useXStep)
{
yNow += stepY;
}
else
{
xNow += stepX;
}
p = p - 2 * disX;
}
//步进主坐标
if (useXStep)
{
xNow += stepX;
}
else
{
yNow += stepY;
}
p = p + 2 * disY;
}
}
}
//gameMath.h
#pragma once
#define PI 3.14151926
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))
#define DEG2RAD(theta) (0.01745329251994329 * (theta))
template<typename T>
void swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
#define SWAP_INT(a, b) swap<int>(a, b);
namespace GT
{
template<typename T>
struct tVec2
{
T x;
T y;
tVec2(T _x, T _y)
{
x = _x;
y = _y;
}
tVec2()
{
x = -1;
y = -1;
}
};
typedef tVec2<int> intV2;
typedef tVec2<float> floatV2;
typedef unsigned int uint;
typedef unsigned char btye;
}
//main.cpp
#include <Windows.h>
#include <tchar.h>
#include "CCanvas.h"
#include <math.h>
//窗口类名
const TCHAR szWindowClass[] = L"class";
//窗口标题
const TCHAR szWindowName[] = L"冒险岛v0.1";
//窗口句柄
HWND hWnd;
//窗口宽度
int wWidth = 800;
//窗口高度
int wHeight = 600;
//DC
HDC hDC;
//内存DC
HDC hMemDC;
GT::CCanvas* _canvas = NULL;
//消息处理回调函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
//渲染函数
void Render(HDC hdc);
int WINAPI wWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nCmdShow)
{
//注册窗口类
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEXW);
//窗口水平或者垂直方向改变重画
wcex.style = CS_HREDRAW | CS_VREDRAW;
//回调函数
wcex.lpfnWndProc = WndProc;
//类和窗口扩展内存 默认写0
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
//实例句柄 从wWinMain参数的hInstance
wcex.hInstance = hInstance;
//窗口图标
wcex.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
//窗口鼠标指针样式
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
//窗口背景
wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
//窗口菜单
wcex.lpszMenuName = nullptr;
//窗口类名
wcex.lpszClassName = szWindowClass;
//窗口小图标
wcex.hIconSm = LoadIcon(nullptr, IDI_APPLICATION);
if (!RegisterClassEx(&wcex)) return -1;
//创建窗口
hWnd = CreateWindowEx(0, szWindowClass, szWindowName,
WS_POPUP, 0, 0, wWidth, wHeight,
nullptr, nullptr, hInstance, nullptr);
if (!hWnd) return -2;
//显示并更新窗口
//缓冲
void* buffer = 0;
hDC = GetDC(hWnd);
hMemDC = CreateCompatibleDC(hDC);
BITMAPINFO bmpInfo;
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = wWidth;
bmpInfo.bmiHeader.biHeight = wHeight;
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 32;
bmpInfo.bmiHeader.biCompression = BI_RGB;
bmpInfo.bmiHeader.biSizeImage = 0;
bmpInfo.bmiHeader.biXPelsPerMeter = 0;
bmpInfo.bmiHeader.biYPelsPerMeter = 0;
bmpInfo.bmiHeader.biClrUsed = 0;
bmpInfo.bmiHeader.biClrImportant = 0;
//创建buffer的内存
HBITMAP hBmp = CreateDIBSection(hDC, &bmpInfo, DIB_RGB_COLORS,
(void**)&buffer, 0, 0);
//选入对象
SelectObject(hMemDC, hBmp);
memset(buffer, 0, wWidth * wHeight * 4);
_canvas = new GT::CCanvas(wWidth, wHeight, buffer);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
MSG msg = { 0 };
//消息循环
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
//Render();
}
ReleaseDC(hWnd, hDC);
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
switch (msg)
{
case WM_PAINT:
{
HDC hdc = BeginPaint(hwnd, &ps);
Render(hdc);
EndPaint(hwnd, &ps);
}
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return ::DefWindowProc(hwnd, msg, wParam, lParam);
}
void Render(HDC hdc)
{
_canvas->clear();
GT::Point pt1(200, 200, GT::RGBA(255,0,0));
GT::intV2 pt1_(100, 100);
//_canvas->drawLine(GT::intV2(100,100),GT::intV2(300,300), GT::RGBA(16,225,200));
float dis = 200;
/*
for (float i = 0; i < 360; i += 10)
{
float radian = DEG2RAD(i);
int x = dis * sin(radian) + pt1_.x;
int y = dis * cos(radian) + pt1_.y;
GT::intV2 pt2(x, y);
_canvas->drawLine(pt1_, pt2, GT::RGBA(120, 120, 90));
}
*/
for (float i = 0; i < 360; i += 20)
{
float radian = DEG2RAD(i);
int x = dis * sin(radian) + pt1.m_x;
int y = dis * cos(radian) + pt1.m_y;
GT::Point pt2(x, y, GT::RGBA(120, 200,0));
_canvas->drawLine(pt1, pt2);
}
BitBlt(hDC, 0, 0, wWidth, wHeight, hMemDC, 0, 0,
SRCCOPY);
}
效果图