Refactoring shitcode (stage 2)

This commit is contained in:
Andrew Golovashevich 2024-10-09 15:17:18 +03:00
parent 01ae77c9a9
commit 6d10eb315b
4 changed files with 123 additions and 96 deletions

View File

@ -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;
}
COLOR GetPixel(int x, int y) {
COLOR get_pixel(int x, int y) {
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;
while (x < y) {
// Определяем, какая точка (пиксель): (x, y) или (x, y - 1) ближе к линии окружности
@ -63,20 +63,20 @@ public:
y--;
// Перенос и отражение вычисленных координат на все октанты окружности
SetPixel(x0 + x, y0 + y, color);
SetPixel(x0 + x, y0 - y, color);
SetPixel(x0 + y, y0 + x, color);
SetPixel(x0 + y, y0 - x, color);
SetPixel(x0 - x, y0 + y, color);
SetPixel(x0 - x, y0 - y, color);
SetPixel(x0 - y, y0 + x, color);
SetPixel(x0 - y, y0 - x, color);
set_pixel(x0 + x, y0 + y, outline);
set_pixel(x0 + x, y0 - y, outline);
set_pixel(x0 + y, y0 + x, outline);
set_pixel(x0 + y, y0 - x, outline);
set_pixel(x0 - x, y0 + y, outline);
set_pixel(x0 - x, y0 - y, outline);
set_pixel(x0 - y, y0 + x, outline);
set_pixel(x0 - y, y0 - x, outline);
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;
if (dx == 0 && dy == 0) {
matrix[y1][x1] = color;

View File

@ -27,8 +27,9 @@ int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInst, LPSTR lpszArgs,
wcl.hCursor = LoadCursor(nullptr, IDC_ARROW); // Курсор
wcl.lpszMenuName = nullptr; // Без меню
wcl.cbClsExtra = 0; // Без дополнительной информации
wcl.cbWndExtra = sizeof(Painter *);
static_assert(sizeof(Painter *) == sizeof(LONG_PTR));
wcl.cbWndExtra = sizeof(PainterState *) + sizeof(Painter **);
static_assert(sizeof(PainterState *) == sizeof(LONG_PTR));
static_assert(sizeof(Painter **) == sizeof(LONG_PTR));
wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); //Белый фон
@ -74,22 +75,18 @@ int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInst, LPSTR lpszArgs,
}
static Painter painter;
// Следующая функция вызывается операционной системой Windows и получает в качестве
// параметров сообщения из очереди сообщений данного приложения
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
static int pixelSize = 8; // Размер "большого" пикселя
switch (message) {
case WM_CREATE: {
case WM_CREATE:
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;
// Обработка сообщения на перерисовку окна
case WM_PAINT: {
PAINTSTRUCT ps;
@ -110,8 +107,10 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
int H = (height - 22) / ratio; // Отнимем высоту StatusBar'а
Frame frame(W, H);
auto *painter = reinterpret_cast<Painter *>(GetWindowLongPtr(hWnd, 0));
painter->Draw(frame);
auto *state = reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0));
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 x = 0; x < W * ratio; 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->GREEN = color.green;
pixel->BLUE = color.blue;
@ -190,8 +189,8 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
break;
case WM_LBUTTONDOWN:
reinterpret_cast<Painter *>(GetWindowLongPtr(hWnd, 0))->SetClickedPixel(LOWORD(lParam) / pixelSize, HIWORD(lParam) / pixelSize);
InvalidateRect(hWnd, NULL, false);
reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0))->set_clicked_pixel(LOWORD(lParam) / pixelSize, HIWORD(lParam) / pixelSize);
InvalidateRect(hWnd, nullptr, false);
break;
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 < 64 && wParam == VK_F3) pixelSize++;
InvalidateRect(hWnd, NULL, false);
InvalidateRect(hWnd, nullptr, false);
char str[256];
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) {
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;
// Обработка сообщения на изменение размера окна
@ -217,13 +224,13 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
break;
case WM_TIMER:
reinterpret_cast<Painter *>(GetWindowLongPtr(hWnd, 0))->AngleStep();
reinterpret_cast<PainterState *>(GetWindowLongPtr(hWnd, 0))->angle += 0.05;
InvalidateRect(hWnd, nullptr, false);
break;
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));
PostQuitMessage(0);
break;

View File

@ -1,25 +1,17 @@
#include <tuple>
#include "frame.hpp"
#include "painter.hpp"
void Painter::Draw(Frame &frame) {
// Шахматная текстура
for (int y = 0; y < frame.height; y++)
for (int x = 0; x < frame.width; x++) {
if ((x + y) % 2 == 0)
frame.SetPixel(x, y, {230, 255, 230}); // Золотистый цвет
//frame.SetPixel(x, y, { 217, 168, 14 });
else
frame.SetPixel(x, y, {200, 200, 200}); // Чёрный цвет
//frame.SetPixel(x, y, { 255, 255, 255 }); // Белый цвет
}
class DemoPainter : public Painter {
void draw(PainterState *state, Frame *frame) const override {
int W = frame.width, H = frame.height;
int W = frame->width, H = frame->height;
// Размер рисунка возьмём меньше (7 / 8), чтобы он не касался границ экрана
float a = 7.0f / 8 * ((W < H) ? W - 1 : H - 1) / sqrt(2);
if (a < 1) return; // Если окно очень маленькое, то ничего не рисуем
float angle = this->global_angle; // Угол поворота
float angle = state->angle; // Угол поворота
a = a / 2;
// Инициализируем исходные координаты центра и вершин квадрата
@ -42,7 +34,7 @@ void Painter::Draw(Frame &frame) {
// Рисуем стороны квадрата
for (int i = 0; i < 4; i++) {
int i2 = (i + 1) % 4;
frame.DrawLine( // Добавляем везде 0.5f, чтобы вещественные числа правильно округлялись при преобразовании к целому типу
frame->draw_line( // Добавляем везде 0.5f, чтобы вещественные числа правильно округлялись при преобразовании к целому типу
int(A[i].x + 0.5f),
int(A[i].y + 0.5f),
int(A[i2].x + 0.5f),
@ -50,10 +42,20 @@ void Painter::Draw(Frame &frame) {
}
// Рисуем описанную окружность
frame.Circle((int) C.x, (int) C.y, int(a * sqrt(2) + 0.5f), COLOR(100, 100, 250));
frame->draw_circle((int) C.x, (int) C.y, int(a * sqrt(2) + 0.5f), COLOR(100, 100, 250));
// Рисуем пиксель, на который кликнул пользователь
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}); // Пиксель зелёного цвета
}
if (state->clicked_pixel.x >= 0 && state->clicked_pixel.x < W &&
state->clicked_pixel.y >= 0 && state->clicked_pixel.y < H)
frame->set_pixel(state->clicked_pixel.x, state->clicked_pixel.y, {34, 175, 60}); // Пиксель зелёного цвета
}
};
static auto predefined_painters_ = std::make_tuple(
DemoPainter()
);
Painter const *const predefined_painters[] = {
&std::get<0>(predefined_painters_),
nullptr
};

View File

@ -2,26 +2,44 @@
#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 {
private:
float global_angle = 0;
struct {
int X, Y;
} global_clicked_pixel = {-1, -1};
public:
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);
virtual void draw(PainterState *state, Frame *frame) const = 0;
};
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);
}
}
}
};