Importing stub for lab2
This commit is contained in:
parent
4da7d43344
commit
69d3a747fe
15
CMakeLists.txt
Normal file
15
CMakeLists.txt
Normal file
@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.29)
|
||||
project(cg1)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
|
||||
add_executable(
|
||||
cg1
|
||||
|
||||
WIN32
|
||||
|
||||
src/Frame.h
|
||||
src/main.cpp
|
||||
src/Painter.h
|
||||
)
|
164
src/Frame.h
Normal file
164
src/Frame.h
Normal file
@ -0,0 +1,164 @@
|
||||
#ifndef FRAME_H
|
||||
#define FRAME_H
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// Cтруктура для задания цвета
|
||||
typedef struct tagCOLOR
|
||||
{
|
||||
unsigned char RED; // Компонента красного цвета
|
||||
unsigned char GREEN; // Компонента зелёного цвета
|
||||
unsigned char BLUE; // Компонента синего цвета
|
||||
unsigned char ALPHA; // Прозрачность (альфа канал)
|
||||
|
||||
tagCOLOR() : RED(0), GREEN(0), BLUE(0), ALPHA(255) { }
|
||||
tagCOLOR(unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha = 255) : RED(red), GREEN(green), BLUE(blue), ALPHA(alpha) { }
|
||||
|
||||
} COLOR;
|
||||
|
||||
|
||||
template<typename TYPE> void swap(TYPE& a, TYPE& b)
|
||||
{
|
||||
TYPE t = a;
|
||||
a = b;
|
||||
b = t;
|
||||
}
|
||||
|
||||
|
||||
// Буфер кадра
|
||||
class Frame
|
||||
{
|
||||
// Указатель на массив пикселей
|
||||
// Буфер кадра будет представлять собой матрицу, которая располагается в памяти в виде непрерывного блока
|
||||
COLOR* pixels;
|
||||
|
||||
// Указатели на строки пикселей буфера кадра
|
||||
COLOR** matrix;
|
||||
|
||||
public:
|
||||
|
||||
// Размеры буфера кадра
|
||||
int width, height;
|
||||
|
||||
Frame(int _width, int _height) : width(_width), height(_height)
|
||||
{
|
||||
int size = width * height;
|
||||
|
||||
// Создание буфера кадра в виде непрерывной матрицы пикселей
|
||||
pixels = new COLOR[size];
|
||||
|
||||
// Указатели на строки пикселей запишем в отдельный массив
|
||||
matrix = new COLOR* [height];
|
||||
|
||||
// Инициализация массива указателей
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
matrix[i] = pixels + i * width;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Задаёт цвет color пикселю с координатами (x, y)
|
||||
void SetPixel(int x, int y, COLOR color)
|
||||
{
|
||||
matrix[y][x] = color;
|
||||
}
|
||||
|
||||
// Возвращает цвет пикселя с координатами (x, y)
|
||||
COLOR GetPixel(int x, int y)
|
||||
{
|
||||
return matrix[y][x];
|
||||
}
|
||||
|
||||
|
||||
// Рисование окружности
|
||||
void Circle(int x0, int y0, int radius, COLOR color)
|
||||
{
|
||||
int x = 0, y = radius;
|
||||
while(x < y)
|
||||
{
|
||||
// Определяем, какая точка (пиксель): (x, y) или (x, y - 1) ближе к линии окружности
|
||||
int D1 = x * x + y * y - radius * radius;
|
||||
int D2 = x * x + (y - 1) * (y - 1) - radius * radius;
|
||||
|
||||
// Если ближе точка (x, y - 1), то смещаемся к ней
|
||||
if (D1 > -D2)
|
||||
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);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Рисование отрезка
|
||||
void DrawLine(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;
|
||||
return;
|
||||
}
|
||||
|
||||
if (abs(dx) > abs(dy))
|
||||
{
|
||||
if (x2 < x1)
|
||||
{
|
||||
// Обмен местами точек (x1, y1) и (x2, y2)
|
||||
swap(x1, x2);
|
||||
swap(y1, y2);
|
||||
dx = -dx; dy = -dy;
|
||||
}
|
||||
|
||||
int y, dx2 = dx / 2, p = 0;
|
||||
if (dy < 0) dx2 = -dx2;
|
||||
for (int x = x1; x <= x2; x++)
|
||||
{
|
||||
// y = (dy * (x - x1) + dx2) / dx + y1;
|
||||
y = (p + dx2) / dx + y1;
|
||||
p += dy;
|
||||
matrix[y][x] = color;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (y2 < y1)
|
||||
{
|
||||
// Обмен местами точек (x1, y1) и (x2, y2)
|
||||
swap(x1, x2);
|
||||
swap(y1, y2);
|
||||
dx = -dx; dy = -dy;
|
||||
}
|
||||
|
||||
int x, dy2 = dy / 2, p = 0;
|
||||
if (dx < 0) dy2 = -dy2;
|
||||
for (int y = y1; y <= y2; y++)
|
||||
{
|
||||
// x = (dx * (y - y1) + dy2) / dy + x1;
|
||||
x = (p + dy2) / dy + x1;
|
||||
p += dx;
|
||||
matrix[y][x] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
~Frame(void)
|
||||
{
|
||||
delete []pixels;
|
||||
delete []matrix;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // FRAME_H
|
80
src/Painter.h
Normal file
80
src/Painter.h
Normal file
@ -0,0 +1,80 @@
|
||||
#ifndef PAINTER_H
|
||||
#define PAINTER_H
|
||||
|
||||
#include "Frame.h"
|
||||
|
||||
|
||||
// Угол поворота фигуры
|
||||
float global_angle = 0;
|
||||
|
||||
// Координаты последнего пикселя, который выбрал пользователь
|
||||
struct
|
||||
{
|
||||
int X, Y;
|
||||
} global_clicked_pixel = {-1, -1};
|
||||
|
||||
|
||||
class Painter
|
||||
{
|
||||
public:
|
||||
|
||||
void 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 }); // Белый цвет
|
||||
}
|
||||
|
||||
|
||||
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 = global_angle; // Угол поворота
|
||||
a = a / 2;
|
||||
|
||||
// Инициализируем исходные координаты центра и вершин квадрата
|
||||
struct
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} C = {W / 2, 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.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));
|
||||
}
|
||||
|
||||
// Рисуем описанную окружность
|
||||
frame.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 }); // Пиксель зелёного цвета
|
||||
}
|
||||
};
|
||||
|
||||
#endif // PAINTER_H
|
254
src/main.cpp
Normal file
254
src/main.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
// lab_1_basics.cpp : Определяет точку входа для приложения.
|
||||
|
||||
|
||||
#include <Windows.h>
|
||||
#include <commctrl.h>
|
||||
#include "stdio.h"
|
||||
#include "Frame.h"
|
||||
#include "Painter.h"
|
||||
|
||||
// Windows-приложение для создания буфера кадра
|
||||
|
||||
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
HWND hWndStatusBar; // Дескриптор компонента StatusBar
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInst, LPSTR lpszArgs, int nWinMode)
|
||||
{
|
||||
char szWinName[] = "Graphics Window Class"; // Имя класса окна
|
||||
|
||||
HWND hWnd; // Дескриптор главного окна
|
||||
MSG msg;
|
||||
WNDCLASSA wcl; // Определитель класса окна
|
||||
wcl.hInstance = hThisInstance; // Дескриптор приложения
|
||||
wcl.lpszClassName = szWinName;// Имя класса окна
|
||||
wcl.lpfnWndProc = WindowProc; // Функция обработки сообщений
|
||||
wcl.style = 0; // Стиль по умолчанию
|
||||
wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION);// Иконка
|
||||
wcl.hCursor = LoadCursor(NULL, IDC_ARROW); // Курсор
|
||||
wcl.lpszMenuName = NULL; // Без меню
|
||||
wcl.cbClsExtra = 0; // Без дополнительной информации
|
||||
wcl.cbWndExtra = 0;
|
||||
|
||||
wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //Белый фон
|
||||
|
||||
if (!RegisterClassA(&wcl)) // Регистрируем класс окна
|
||||
return 0;
|
||||
|
||||
hWnd = CreateWindowA(szWinName, // Создать окно
|
||||
"Лабораторная работа №1. Буфер кадра. Алгоритмы Брезенхейма",
|
||||
WS_OVERLAPPEDWINDOW, // Стиль окна
|
||||
CW_USEDEFAULT, // x-координата
|
||||
CW_USEDEFAULT, // y-координата
|
||||
CW_USEDEFAULT, // Ширина
|
||||
CW_USEDEFAULT, // Высота
|
||||
HWND_DESKTOP, // Без родительского окна
|
||||
NULL, // Без меню
|
||||
hThisInstance, // Дескриптор приложения
|
||||
NULL); // Без дополнительных аргументов
|
||||
|
||||
// Создаём компонент типа StatusBar
|
||||
hWndStatusBar = CreateWindowExA(
|
||||
0, STATUSCLASSNAMEA, NULL,
|
||||
WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
|
||||
0, 0, 0, 0,
|
||||
hWnd, (HMENU) 10001,
|
||||
hThisInstance, NULL
|
||||
);
|
||||
|
||||
// Настройка частей StatusBar'а
|
||||
int statwidths[] = { 150, 300, -1 };
|
||||
SendMessageA(hWndStatusBar, SB_SETPARTS, sizeof(statwidths) / sizeof(int), (LPARAM)statwidths);
|
||||
|
||||
ShowWindow(hWnd, nWinMode); // Показать окно
|
||||
UpdateWindow(hWnd); // Перерисовать окно
|
||||
|
||||
while (GetMessage(&msg, NULL, 0, 0)) // Запустить цикл обработки сообщений
|
||||
{
|
||||
TranslateMessage(&msg); // Разрешить использование клавиатуры
|
||||
DispatchMessage(&msg); // Вернуть управление операционной системе Windows
|
||||
}
|
||||
|
||||
return msg.wParam;
|
||||
|
||||
}
|
||||
|
||||
// Следующая функция вызывается операционной системой Windows и получает в качестве
|
||||
// параметров сообщения из очереди сообщений данного приложения
|
||||
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static int pixelSize = 8; // Размер "большого" пикселя
|
||||
|
||||
switch (message)
|
||||
{
|
||||
// Обработка сообщения на создание окна
|
||||
case WM_CREATE:
|
||||
{
|
||||
// Создаем таймер, посылающий сообщения
|
||||
// функции окна примерно 30 раз в секунду
|
||||
SetTimer(hWnd, 1, 1000/30, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
// Обработка сообщения на перерисовку окна
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
|
||||
HDC hdc = BeginPaint(hWnd, &ps);
|
||||
|
||||
// Определяем ширину и высоту окна
|
||||
RECT rect = ps.rcPaint;
|
||||
GetClientRect(hWnd, &rect);
|
||||
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
|
||||
// Рисование в буфер кадра
|
||||
|
||||
int ratio = pixelSize; // Размер "большого" пикселя
|
||||
|
||||
int W = width / ratio;
|
||||
int H = (height - 22) / ratio; // Отнимем высоту StatusBar'а
|
||||
|
||||
Frame frame(W, H);
|
||||
Painter painter;
|
||||
painter.Draw(frame);
|
||||
|
||||
// Системная структура для хранения цвета пикселя
|
||||
// Буфер кадра, который будет передаваться операционной системе, должен состоять из массива этих структур
|
||||
// Она не совпадает с порядком следования цветов в формате RBG
|
||||
typedef struct tagRGBPIXEL
|
||||
{
|
||||
unsigned char BLUE; // Компонента синего цвета
|
||||
unsigned char GREEN; // Компонента зелёного цвета
|
||||
unsigned char RED; // Компонента красного цвета
|
||||
unsigned char ALPHA; // Прозрачность
|
||||
} RGBPIXEL;
|
||||
|
||||
// Выделение памяти для второго буфера, который будет передаваться функции CreateBitmap для создания картинки
|
||||
RGBPIXEL* bitmap = (RGBPIXEL*) HeapAlloc(GetProcessHeap(), 0, width * height * sizeof(RGBPIXEL));
|
||||
|
||||
// Копирование массива пикселей в соответствии с системным форматом пикселя и масштабирование картинки
|
||||
// W и H - ширина и высота изображения в буфере кадра
|
||||
// ratio - коэффициент масштабирования пикселей
|
||||
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);
|
||||
pixel->RED = color.RED;
|
||||
pixel->GREEN = color.GREEN;
|
||||
pixel->BLUE = color.BLUE;
|
||||
pixel->ALPHA = color.ALPHA;
|
||||
}
|
||||
|
||||
|
||||
// Получить дескриптор на новое растровое изображение
|
||||
HBITMAP hBitMap = CreateBitmap(width, height, 1, sizeof(RGBPIXEL) * 8, bitmap);
|
||||
|
||||
// Освободить память, которую занимает буфер цвета
|
||||
HeapFree(GetProcessHeap(), 0, bitmap);
|
||||
|
||||
// Создать в оперативной памяти контекст, совместимый с экранным контекстом, который мы используем, чтобы рисовать
|
||||
HDC srcHdc = CreateCompatibleDC(hdc);
|
||||
|
||||
// Связать картинку с новым контекстом
|
||||
SelectObject(srcHdc, hBitMap);
|
||||
|
||||
// Копировать содержимое из временного контекста srcHdc в основной контекст окна hdc
|
||||
BitBlt(
|
||||
hdc, // Основной контекст
|
||||
0, 0, // Координаты левого верхнего угла, от которого будет выполняться вставка
|
||||
width, // Ширина вставляемого изображения
|
||||
height, // Высота вставляемого изображения
|
||||
srcHdc, // Дескриптор временного контекста
|
||||
0, 0, // Координаты считываемого изображения
|
||||
SRCCOPY); // Параметры операции - копирование
|
||||
|
||||
EndPaint(hWnd, &ps);
|
||||
|
||||
// Удаление картинки из памяти
|
||||
DeleteObject(hBitMap);
|
||||
|
||||
// Удаление временного контекста
|
||||
DeleteDC(srcHdc);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
{
|
||||
char str[256];
|
||||
|
||||
// Устанавливаем текст в разных частях StatusBar'а
|
||||
// Экранные координаты курсора мыши
|
||||
sprintf_s(str, "X = %d, Y = %d", LOWORD(lParam), HIWORD(lParam));
|
||||
SendMessageA(hWndStatusBar, SB_SETTEXTA, 2, (LPARAM)str);
|
||||
|
||||
// Координаты пикселя в буфере кадра
|
||||
sprintf_s(str, "BX = %d, BY = %d", LOWORD(lParam) / pixelSize, HIWORD(lParam) / pixelSize);
|
||||
SendMessageA(hWndStatusBar, SB_SETTEXTA, 1, (LPARAM)str);
|
||||
|
||||
sprintf_s(str, "Масштаб (F2/F3): %d", pixelSize);
|
||||
SendMessageA(hWndStatusBar, SB_SETTEXTA, 0, (LPARAM)str);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
// Запоминаем координаты пикселя, по которому щёлкнул пользователь
|
||||
global_clicked_pixel.X = LOWORD(lParam) / pixelSize;
|
||||
global_clicked_pixel.Y = HIWORD(lParam) / pixelSize;
|
||||
// Перерисовать окно
|
||||
InvalidateRect(hWnd, NULL, false);
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
if (wParam == VK_F2 || wParam == VK_F3)
|
||||
{
|
||||
if (pixelSize > 1 && wParam == VK_F2) pixelSize--;
|
||||
if (pixelSize < 64 && wParam == VK_F3) pixelSize++;
|
||||
|
||||
// Перерисовать окно
|
||||
InvalidateRect(hWnd, NULL, false);
|
||||
|
||||
char str[256];
|
||||
sprintf_s(str, "Масштаб (F2/F3): %d", pixelSize);
|
||||
SendMessageA(hWndStatusBar, SB_SETTEXTA, 0, (LPARAM)str);
|
||||
}
|
||||
if (wParam == VK_F1)
|
||||
{
|
||||
MessageBoxA(hWnd, "Работу выполнил студент группы ПВ-221 Колесников А.И.", "О программе", MB_ICONINFORMATION);
|
||||
}
|
||||
break;
|
||||
|
||||
// Обработка сообщения на изменение размера окна
|
||||
case WM_SIZE:
|
||||
|
||||
// Подгоняем размеры StatusBar под размер окна
|
||||
SendMessageA(hWndStatusBar, WM_SIZE, 0, 0);
|
||||
|
||||
// Перерисовать окно
|
||||
InvalidateRect(hWnd, NULL, false);
|
||||
break;
|
||||
|
||||
case WM_TIMER:
|
||||
|
||||
// При срабатывании таймера увеличим угол поворота
|
||||
global_angle += 0.05;
|
||||
// Перерисовать окно
|
||||
InvalidateRect(hWnd, NULL, false);
|
||||
break;
|
||||
|
||||
case WM_DESTROY: // Завершение программы
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Все сообщения, не обрабатываемые в данной функции, направляются на обработку по умолчанию
|
||||
return DefWindowProcA(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user