Refactoring shitcode (stage 2)
This commit is contained in:
parent
01ae77c9a9
commit
6d10eb315b
@ -42,16 +42,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SetPixel(int x, int y, COLOR color) {
|
void set_pixel(int x, int y, COLOR color) {
|
||||||
matrix[y][x] = color;
|
matrix[y][x] = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
COLOR GetPixel(int x, int y) {
|
COLOR get_pixel(int x, int y) {
|
||||||
return matrix[y][x];
|
return matrix[y][x];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Circle(int x0, int y0, int radius, COLOR color) {
|
void draw_circle(int x0, int y0, int radius, COLOR outline) {
|
||||||
int x = 0, y = radius;
|
int x = 0, y = radius;
|
||||||
while (x < y) {
|
while (x < y) {
|
||||||
// Определяем, какая точка (пиксель): (x, y) или (x, y - 1) ближе к линии окружности
|
// Определяем, какая точка (пиксель): (x, y) или (x, y - 1) ближе к линии окружности
|
||||||
@ -63,20 +63,20 @@ public:
|
|||||||
y--;
|
y--;
|
||||||
|
|
||||||
// Перенос и отражение вычисленных координат на все октанты окружности
|
// Перенос и отражение вычисленных координат на все октанты окружности
|
||||||
SetPixel(x0 + x, y0 + y, color);
|
set_pixel(x0 + x, y0 + y, outline);
|
||||||
SetPixel(x0 + x, y0 - y, color);
|
set_pixel(x0 + x, y0 - y, outline);
|
||||||
SetPixel(x0 + y, y0 + x, color);
|
set_pixel(x0 + y, y0 + x, outline);
|
||||||
SetPixel(x0 + y, y0 - x, color);
|
set_pixel(x0 + y, y0 - x, outline);
|
||||||
SetPixel(x0 - x, y0 + y, color);
|
set_pixel(x0 - x, y0 + y, outline);
|
||||||
SetPixel(x0 - x, y0 - y, color);
|
set_pixel(x0 - x, y0 - y, outline);
|
||||||
SetPixel(x0 - y, y0 + x, color);
|
set_pixel(x0 - y, y0 + x, outline);
|
||||||
SetPixel(x0 - y, y0 - x, color);
|
set_pixel(x0 - y, y0 - x, outline);
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DrawLine(int x1, int y1, int x2, int y2, COLOR color) {
|
void draw_line(int x1, int y1, int x2, int y2, COLOR color) {
|
||||||
int dy = y2 - y1, dx = x2 - x1;
|
int dy = y2 - y1, dx = x2 - x1;
|
||||||
if (dx == 0 && dy == 0) {
|
if (dx == 0 && dy == 0) {
|
||||||
matrix[y1][x1] = color;
|
matrix[y1][x1] = color;
|
||||||
|
41
src/main.cpp
41
src/main.cpp
@ -27,8 +27,9 @@ int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInst, LPSTR lpszArgs,
|
|||||||
wcl.hCursor = LoadCursor(nullptr, IDC_ARROW); // Курсор
|
wcl.hCursor = LoadCursor(nullptr, IDC_ARROW); // Курсор
|
||||||
wcl.lpszMenuName = nullptr; // Без меню
|
wcl.lpszMenuName = nullptr; // Без меню
|
||||||
wcl.cbClsExtra = 0; // Без дополнительной информации
|
wcl.cbClsExtra = 0; // Без дополнительной информации
|
||||||
wcl.cbWndExtra = sizeof(Painter *);
|
wcl.cbWndExtra = sizeof(PainterState *) + sizeof(Painter **);
|
||||||
static_assert(sizeof(Painter *) == sizeof(LONG_PTR));
|
static_assert(sizeof(PainterState *) == sizeof(LONG_PTR));
|
||||||
|
static_assert(sizeof(Painter **) == sizeof(LONG_PTR));
|
||||||
|
|
||||||
|
|
||||||
wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); //Белый фон
|
wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); //Белый фон
|
||||||
@ -74,22 +75,18 @@ int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInst, LPSTR lpszArgs,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Painter painter;
|
|
||||||
|
|
||||||
// Следующая функция вызывается операционной системой Windows и получает в качестве
|
// Следующая функция вызывается операционной системой Windows и получает в качестве
|
||||||
// параметров сообщения из очереди сообщений данного приложения
|
// параметров сообщения из очереди сообщений данного приложения
|
||||||
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
static int pixelSize = 8; // Размер "большого" пикселя
|
static int pixelSize = 8; // Размер "большого" пикселя
|
||||||
|
|
||||||
switch (message) {
|
switch (message) {
|
||||||
case WM_CREATE: {
|
case WM_CREATE:
|
||||||
SetTimer(hWnd, 1, 1000 / 30, nullptr);
|
SetTimer(hWnd, 1, 1000 / 30, nullptr);
|
||||||
SetWindowLongPtr(hWnd, 0, reinterpret_cast<LONG_PTR>(new Painter{}));
|
SetWindowLongPtr(hWnd, 0, (LONG_PTR) new PainterState());
|
||||||
}
|
SetWindowLongPtr(hWnd, sizeof(PainterState *), (LONG_PTR) &predefined_painters[0]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
// Обработка сообщения на перерисовку окна
|
|
||||||
case WM_PAINT: {
|
case WM_PAINT: {
|
||||||
PAINTSTRUCT ps;
|
PAINTSTRUCT ps;
|
||||||
|
|
||||||
@ -110,8 +107,10 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
|
|||||||
int H = (height - 22) / ratio; // Отнимем высоту StatusBar'а
|
int H = (height - 22) / ratio; // Отнимем высоту StatusBar'а
|
||||||
|
|
||||||
Frame frame(W, H);
|
Frame frame(W, H);
|
||||||
auto *painter = reinterpret_cast<Painter *>(GetWindowLongPtr(hWnd, 0));
|
auto *state = reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0));
|
||||||
painter->Draw(frame);
|
auto *painter = *reinterpret_cast<Painter **>(GetWindowLongPtr(hWnd, sizeof(PainterState *)));
|
||||||
|
PixelGridPainter{COLOR{245, 245, 245}, COLOR{240, 240, 240}}.draw(state, &frame);
|
||||||
|
painter->draw(state, &frame);
|
||||||
|
|
||||||
// Системная структура для хранения цвета пикселя
|
// Системная структура для хранения цвета пикселя
|
||||||
// Буфер кадра, который будет передаваться операционной системе, должен состоять из массива этих структур
|
// Буфер кадра, который будет передаваться операционной системе, должен состоять из массива этих структур
|
||||||
@ -132,7 +131,7 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
|
|||||||
for (int y = 0; y < H * ratio; y++)
|
for (int y = 0; y < H * ratio; y++)
|
||||||
for (int x = 0; x < W * ratio; x++) {
|
for (int x = 0; x < W * ratio; x++) {
|
||||||
RGBPIXEL *pixel = bitmap + y * width + x;
|
RGBPIXEL *pixel = bitmap + y * width + x;
|
||||||
COLOR color = frame.GetPixel(x / ratio, y / ratio);
|
COLOR color = frame.get_pixel(x / ratio, y / ratio);
|
||||||
pixel->RED = color.red;
|
pixel->RED = color.red;
|
||||||
pixel->GREEN = color.green;
|
pixel->GREEN = color.green;
|
||||||
pixel->BLUE = color.blue;
|
pixel->BLUE = color.blue;
|
||||||
@ -190,8 +189,8 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_LBUTTONDOWN:
|
case WM_LBUTTONDOWN:
|
||||||
reinterpret_cast<Painter *>(GetWindowLongPtr(hWnd, 0))->SetClickedPixel(LOWORD(lParam) / pixelSize, HIWORD(lParam) / pixelSize);
|
reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0))->set_clicked_pixel(LOWORD(lParam) / pixelSize, HIWORD(lParam) / pixelSize);
|
||||||
InvalidateRect(hWnd, NULL, false);
|
InvalidateRect(hWnd, nullptr, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_KEYDOWN:
|
case WM_KEYDOWN:
|
||||||
@ -199,7 +198,7 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
|
|||||||
if (pixelSize > 1 && wParam == VK_F2) pixelSize--;
|
if (pixelSize > 1 && wParam == VK_F2) pixelSize--;
|
||||||
if (pixelSize < 64 && wParam == VK_F3) pixelSize++;
|
if (pixelSize < 64 && wParam == VK_F3) pixelSize++;
|
||||||
|
|
||||||
InvalidateRect(hWnd, NULL, false);
|
InvalidateRect(hWnd, nullptr, false);
|
||||||
|
|
||||||
char str[256];
|
char str[256];
|
||||||
sprintf_s(str, "Масштаб (F2/F3): %d", pixelSize);
|
sprintf_s(str, "Масштаб (F2/F3): %d", pixelSize);
|
||||||
@ -208,6 +207,14 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
|
|||||||
if (wParam == VK_F1) {
|
if (wParam == VK_F1) {
|
||||||
MessageBoxA(hWnd, "Работу выполнил студент группы ПВ-221 Колесников А.И.", "О программе", MB_ICONINFORMATION);
|
MessageBoxA(hWnd, "Работу выполнил студент группы ПВ-221 Колесников А.И.", "О программе", MB_ICONINFORMATION);
|
||||||
}
|
}
|
||||||
|
if (wParam == VK_F4) {
|
||||||
|
auto newPtr = reinterpret_cast<Painter const *const *>(GetWindowLongPtr(hWnd, sizeof(PainterState *)));
|
||||||
|
newPtr++;
|
||||||
|
if (newPtr == nullptr)
|
||||||
|
newPtr = &predefined_painters[0];
|
||||||
|
|
||||||
|
SetWindowLongPtr(hWnd, sizeof(PainterState *), (LONG_PTR) newPtr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Обработка сообщения на изменение размера окна
|
// Обработка сообщения на изменение размера окна
|
||||||
@ -217,13 +224,13 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
reinterpret_cast<Painter *>(GetWindowLongPtr(hWnd, 0))->AngleStep();
|
reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0))->angle += 0.05;
|
||||||
InvalidateRect(hWnd, nullptr, false);
|
InvalidateRect(hWnd, nullptr, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
delete reinterpret_cast<Painter *>(GetWindowLongPtr(hWnd, 0));
|
delete reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0));
|
||||||
SetWindowLongPtr(hWnd, 0, reinterpret_cast<LONG_PTR>(nullptr));
|
SetWindowLongPtr(hWnd, 0, reinterpret_cast<LONG_PTR>(nullptr));
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
break;
|
break;
|
||||||
|
@ -1,59 +1,61 @@
|
|||||||
|
#include <tuple>
|
||||||
#include "frame.hpp"
|
#include "frame.hpp"
|
||||||
#include "painter.hpp"
|
#include "painter.hpp"
|
||||||
|
|
||||||
|
|
||||||
void Painter::Draw(Frame &frame) {
|
class DemoPainter : public Painter {
|
||||||
// Шахматная текстура
|
|
||||||
for (int y = 0; y < frame.height; y++)
|
void draw(PainterState *state, Frame *frame) const override {
|
||||||
for (int x = 0; x < frame.width; x++) {
|
|
||||||
if ((x + y) % 2 == 0)
|
int W = frame->width, H = frame->height;
|
||||||
frame.SetPixel(x, y, {230, 255, 230}); // Золотистый цвет
|
// Размер рисунка возьмём меньше (7 / 8), чтобы он не касался границ экрана
|
||||||
//frame.SetPixel(x, y, { 217, 168, 14 });
|
float a = 7.0f / 8 * ((W < H) ? W - 1 : H - 1) / sqrt(2);
|
||||||
else
|
if (a < 1) return; // Если окно очень маленькое, то ничего не рисуем
|
||||||
frame.SetPixel(x, y, {200, 200, 200}); // Чёрный цвет
|
float angle = state->angle; // Угол поворота
|
||||||
//frame.SetPixel(x, y, { 255, 255, 255 }); // Белый цвет
|
a = a / 2;
|
||||||
|
|
||||||
|
// Инициализируем исходные координаты центра и вершин квадрата
|
||||||
|
struct {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
} C = {(float) W / 2, (float) H / 2}, A[4] = {{C.x + a, C.y + a},
|
||||||
|
{C.x + a, C.y - a},
|
||||||
|
{C.x - a, C.y - a},
|
||||||
|
{C.x - a, C.y + a}};
|
||||||
|
|
||||||
|
|
||||||
|
// Поворачиваем все вершины квадрата вокруг точки C на угол angle
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
float xi = A[i].x, yi = A[i].y;
|
||||||
|
A[i].x = (xi - C.x) * cos(angle) - (yi - C.y) * sin(angle) + C.x;
|
||||||
|
A[i].y = (xi - C.x) * sin(angle) + (yi - C.y) * cos(angle) + C.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Рисуем стороны квадрата
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
int i2 = (i + 1) % 4;
|
||||||
|
frame->draw_line( // Добавляем везде 0.5f, чтобы вещественные числа правильно округлялись при преобразовании к целому типу
|
||||||
|
int(A[i].x + 0.5f),
|
||||||
|
int(A[i].y + 0.5f),
|
||||||
|
int(A[i2].x + 0.5f),
|
||||||
|
int(A[i2].y + 0.5f), COLOR(200, 30, 45));
|
||||||
|
}
|
||||||
|
|
||||||
int W = frame.width, H = frame.height;
|
// Рисуем описанную окружность
|
||||||
// Размер рисунка возьмём меньше (7 / 8), чтобы он не касался границ экрана
|
frame->draw_circle((int) C.x, (int) C.y, int(a * sqrt(2) + 0.5f), COLOR(100, 100, 250));
|
||||||
float a = 7.0f / 8 * ((W < H) ? W - 1 : H - 1) / sqrt(2);
|
|
||||||
if (a < 1) return; // Если окно очень маленькое, то ничего не рисуем
|
|
||||||
float angle = this->global_angle; // Угол поворота
|
|
||||||
a = a / 2;
|
|
||||||
|
|
||||||
// Инициализируем исходные координаты центра и вершин квадрата
|
// Рисуем пиксель, на который кликнул пользователь
|
||||||
struct {
|
if (state->clicked_pixel.x >= 0 && state->clicked_pixel.x < W &&
|
||||||
float x;
|
state->clicked_pixel.y >= 0 && state->clicked_pixel.y < H)
|
||||||
float y;
|
frame->set_pixel(state->clicked_pixel.x, state->clicked_pixel.y, {34, 175, 60}); // Пиксель зелёного цвета
|
||||||
} C = {(float) W / 2, (float) H / 2}, A[4] = {{C.x + a, C.y + a},
|
|
||||||
{C.x + a, C.y - a},
|
|
||||||
{C.x - a, C.y - a},
|
|
||||||
{C.x - a, C.y + a}};
|
|
||||||
|
|
||||||
|
|
||||||
// Поворачиваем все вершины квадрата вокруг точки C на угол angle
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
float xi = A[i].x, yi = A[i].y;
|
|
||||||
A[i].x = (xi - C.x) * cos(angle) - (yi - C.y) * sin(angle) + C.x;
|
|
||||||
A[i].y = (xi - C.x) * sin(angle) + (yi - C.y) * cos(angle) + C.y;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Рисуем стороны квадрата
|
static auto predefined_painters_ = std::make_tuple(
|
||||||
for (int i = 0; i < 4; i++) {
|
DemoPainter()
|
||||||
int i2 = (i + 1) % 4;
|
);
|
||||||
frame.DrawLine( // Добавляем везде 0.5f, чтобы вещественные числа правильно округлялись при преобразовании к целому типу
|
|
||||||
int(A[i].x + 0.5f),
|
|
||||||
int(A[i].y + 0.5f),
|
|
||||||
int(A[i2].x + 0.5f),
|
|
||||||
int(A[i2].y + 0.5f), COLOR(200, 30, 45));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Рисуем описанную окружность
|
Painter const *const predefined_painters[] = {
|
||||||
frame.Circle((int) C.x, (int) C.y, int(a * sqrt(2) + 0.5f), COLOR(100, 100, 250));
|
&std::get<0>(predefined_painters_),
|
||||||
|
nullptr
|
||||||
// Рисуем пиксель, на который кликнул пользователь
|
};
|
||||||
if (global_clicked_pixel.X >= 0 && global_clicked_pixel.X < W &&
|
|
||||||
global_clicked_pixel.Y >= 0 && global_clicked_pixel.Y < H)
|
|
||||||
frame.SetPixel(global_clicked_pixel.X, global_clicked_pixel.Y, {34, 175, 60}); // Пиксель зелёного цвета
|
|
||||||
}
|
|
@ -2,26 +2,44 @@
|
|||||||
|
|
||||||
#include "frame.hpp"
|
#include "frame.hpp"
|
||||||
|
|
||||||
|
class PainterState {
|
||||||
|
public:
|
||||||
|
float angle = 0;
|
||||||
|
struct {
|
||||||
|
unsigned short x = -1, y = -1;
|
||||||
|
} clicked_pixel;
|
||||||
|
|
||||||
|
PainterState() = default;
|
||||||
|
|
||||||
|
void set_clicked_pixel(unsigned short x, unsigned short y) {
|
||||||
|
this->clicked_pixel.x = x;
|
||||||
|
this->clicked_pixel.y = y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class Painter {
|
class Painter {
|
||||||
private:
|
|
||||||
float global_angle = 0;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
int X, Y;
|
|
||||||
} global_clicked_pixel = {-1, -1};
|
|
||||||
public:
|
public:
|
||||||
|
virtual void draw(PainterState *state, Frame *frame) const = 0;
|
||||||
|
|
||||||
void SetClickedPixel(int x, int y) {
|
|
||||||
this->global_clicked_pixel.X = x;
|
|
||||||
this->global_clicked_pixel.Y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AngleStep() {
|
|
||||||
this->global_angle += 0.05;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Draw(Frame &frame);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern Painter const *const predefined_painters[];
|
||||||
|
|
||||||
|
|
||||||
|
class PixelGridPainter : public Painter {
|
||||||
|
private:
|
||||||
|
const COLOR c1;
|
||||||
|
const COLOR c2;
|
||||||
|
public:
|
||||||
|
inline PixelGridPainter(COLOR c1, COLOR c2) : c1{c1}, c2{c2} {}
|
||||||
|
|
||||||
|
inline void draw(PainterState *state, Frame *frame) const override {
|
||||||
|
for (int y = 0; y < frame->height; y++) {
|
||||||
|
for (int x = 0; x < frame->width; x++) {
|
||||||
|
if ((x + y) % 2 == 0)
|
||||||
|
frame->set_pixel(x, y, this->c1);
|
||||||
|
else
|
||||||
|
frame->set_pixel(x, y, this->c2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user