Skip to content

Commit bc0c9bb

Browse files
authored
Add files via upload
1 parent 9c3defa commit bc0c9bb

File tree

3 files changed

+295
-17
lines changed

3 files changed

+295
-17
lines changed

HW5/BMP.h

+260
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
#pragma once
2+
#include <fstream>
3+
#include <vector>
4+
#include <stdexcept>
5+
#include <iostream>
6+
7+
#pragma pack(push, 1)
8+
struct BMPFileHeader {
9+
uint16_t file_type{ 0x4D42 }; // File type always BM which is 0x4D42 (stored as hex uint16_t in little endian)
10+
uint32_t file_size{ 0 }; // Size of the file (in bytes)
11+
uint16_t reserved1{ 0 }; // Reserved, always 0
12+
uint16_t reserved2{ 0 }; // Reserved, always 0
13+
uint32_t offset_data{ 0 }; // Start position of pixel data (bytes from the beginning of the file)
14+
};
15+
16+
struct BMPInfoHeader {
17+
uint32_t size{ 0 }; // Size of this header (in bytes)
18+
int32_t width{ 0 }; // width of bitmap in pixels
19+
int32_t height{ 0 }; // width of bitmap in pixels
20+
// (if positive, bottom-up, with origin in lower left corner)
21+
// (if negative, top-down, with origin in upper left corner)
22+
uint16_t planes{ 1 }; // No. of planes for the target device, this is always 1
23+
uint16_t bit_count{ 0 }; // No. of bits per pixel
24+
uint32_t compression{ 0 }; // 0 or 3 - uncompressed. THIS PROGRAM CONSIDERS ONLY UNCOMPRESSED BMP images
25+
uint32_t size_image{ 0 }; // 0 - for uncompressed images
26+
int32_t x_pixels_per_meter{ 0 };
27+
int32_t y_pixels_per_meter{ 0 };
28+
uint32_t colors_used{ 0 }; // No. color indexes in the color table. Use 0 for the max number of colors allowed by bit_count
29+
uint32_t colors_important{ 0 }; // No. of colors used for displaying the bitmap. If 0 all colors are required
30+
};
31+
32+
struct BMPColorHeader {
33+
uint32_t red_mask{ 0x00ff0000 }; // Bit mask for the red channel
34+
uint32_t green_mask{ 0x0000ff00 }; // Bit mask for the green channel
35+
uint32_t blue_mask{ 0x000000ff }; // Bit mask for the blue channel
36+
uint32_t alpha_mask{ 0xff000000 }; // Bit mask for the alpha channel
37+
uint32_t color_space_type{ 0x73524742 }; // Default "sRGB" (0x73524742)
38+
uint32_t unused[16]{ 0 }; // Unused data for sRGB color space
39+
};
40+
#pragma pack(pop)
41+
42+
struct BMP {
43+
BMPFileHeader file_header;
44+
BMPInfoHeader bmp_info_header;
45+
BMPColorHeader bmp_color_header;
46+
std::vector<uint8_t> data;
47+
48+
BMP(const char *fname) {
49+
read(fname);
50+
}
51+
52+
void read(const char *fname) {
53+
std::ifstream inp{ fname, std::ios_base::binary };
54+
if (inp) {
55+
inp.read((char*)&file_header, sizeof(file_header));
56+
if(file_header.file_type != 0x4D42) {
57+
throw std::runtime_error("Error! Unrecognized file format.");
58+
}
59+
inp.read((char*)&bmp_info_header, sizeof(bmp_info_header));
60+
61+
// The BMPColorHeader is used only for transparent images
62+
if(bmp_info_header.bit_count == 32) {
63+
// Check if the file has bit mask color information
64+
if(bmp_info_header.size >= (sizeof(BMPInfoHeader) + sizeof(BMPColorHeader))) {
65+
inp.read((char*)&bmp_color_header, sizeof(bmp_color_header));
66+
// Check if the pixel data is stored as BGRA and if the color space type is sRGB
67+
check_color_header(bmp_color_header);
68+
} else {
69+
std::cerr << "Error! The file \"" << fname << "\" does not seem to contain bit mask information\n";
70+
throw std::runtime_error("Error! Unrecognized file format.");
71+
}
72+
}
73+
74+
// Jump to the pixel data location
75+
inp.seekg(file_header.offset_data, inp.beg);
76+
77+
// Adjust the header fields for output.
78+
// Some editors will put extra info in the image file, we only save the headers and the data.
79+
if(bmp_info_header.bit_count == 32) {
80+
bmp_info_header.size = sizeof(BMPInfoHeader) + sizeof(BMPColorHeader);
81+
file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + sizeof(BMPColorHeader);
82+
} else {
83+
bmp_info_header.size = sizeof(BMPInfoHeader);
84+
file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader);
85+
}
86+
file_header.file_size = file_header.offset_data;
87+
88+
if (bmp_info_header.height < 0) {
89+
throw std::runtime_error("The program can treat only BMP images with the origin in the bottom left corner!");
90+
}
91+
92+
data.resize(bmp_info_header.width * bmp_info_header.height * bmp_info_header.bit_count / 8);
93+
94+
// Here we check if we need to take into account row padding
95+
if (bmp_info_header.width % 4 == 0) {
96+
inp.read((char*)data.data(), data.size());
97+
file_header.file_size += static_cast<uint32_t>(data.size());
98+
}
99+
else {
100+
row_stride = bmp_info_header.width * bmp_info_header.bit_count / 8;
101+
uint32_t new_stride = make_stride_aligned(4);
102+
std::vector<uint8_t> padding_row(new_stride - row_stride);
103+
104+
for (int y = 0; y < bmp_info_header.height; ++y) {
105+
inp.read((char*)(data.data() + row_stride * y), row_stride);
106+
inp.read((char*)padding_row.data(), padding_row.size());
107+
}
108+
file_header.file_size += static_cast<uint32_t>(data.size()) + bmp_info_header.height * static_cast<uint32_t>(padding_row.size());
109+
}
110+
}
111+
else {
112+
throw std::runtime_error("Unable to open the input image file.");
113+
}
114+
}
115+
116+
BMP(int32_t width, int32_t height, bool has_alpha = true) {
117+
if (width <= 0 || height <= 0) {
118+
throw std::runtime_error("The image width and height must be positive numbers.");
119+
}
120+
121+
bmp_info_header.width = width;
122+
bmp_info_header.height = height;
123+
if (has_alpha) {
124+
bmp_info_header.size = sizeof(BMPInfoHeader) + sizeof(BMPColorHeader);
125+
file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader) + sizeof(BMPColorHeader);
126+
127+
bmp_info_header.bit_count = 32;
128+
bmp_info_header.compression = 3;
129+
row_stride = width * 4;
130+
data.resize(row_stride * height);
131+
file_header.file_size = file_header.offset_data + data.size();
132+
}
133+
else {
134+
bmp_info_header.size = sizeof(BMPInfoHeader);
135+
file_header.offset_data = sizeof(BMPFileHeader) + sizeof(BMPInfoHeader);
136+
137+
bmp_info_header.bit_count = 24;
138+
bmp_info_header.compression = 0;
139+
row_stride = width * 3;
140+
data.resize(row_stride * height);
141+
142+
uint32_t new_stride = make_stride_aligned(4);
143+
file_header.file_size = file_header.offset_data + static_cast<uint32_t>(data.size()) + bmp_info_header.height * (new_stride - row_stride);
144+
}
145+
}
146+
147+
void write(const char *fname) {
148+
std::ofstream of{ fname, std::ios_base::binary };
149+
if (of) {
150+
if (bmp_info_header.bit_count == 32) {
151+
write_headers_and_data(of);
152+
}
153+
else if (bmp_info_header.bit_count == 24) {
154+
if (bmp_info_header.width % 4 == 0) {
155+
write_headers_and_data(of);
156+
}
157+
else {
158+
uint32_t new_stride = make_stride_aligned(4);
159+
std::vector<uint8_t> padding_row(new_stride - row_stride);
160+
161+
write_headers(of);
162+
163+
for (int y = 0; y < bmp_info_header.height; ++y) {
164+
of.write((const char*)(data.data() + row_stride * y), row_stride);
165+
of.write((const char*)padding_row.data(), padding_row.size());
166+
}
167+
}
168+
}
169+
else {
170+
throw std::runtime_error("The program can treat only 24 or 32 bits per pixel BMP files");
171+
}
172+
}
173+
else {
174+
throw std::runtime_error("Unable to open the output image file.");
175+
}
176+
}
177+
178+
void fill_region(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h, uint8_t B, uint8_t G, uint8_t R, uint8_t A) {
179+
if (x0 + w > (uint32_t)bmp_info_header.width || y0 + h > (uint32_t)bmp_info_header.height) {
180+
throw std::runtime_error("The region does not fit in the image!");
181+
}
182+
183+
uint32_t channels = bmp_info_header.bit_count / 8;
184+
for (uint32_t y = y0; y < y0 + h; ++y) {
185+
for (uint32_t x = x0; x < x0 + w; ++x) {
186+
data[channels * (y * bmp_info_header.width + x) + 0] = B;
187+
data[channels * (y * bmp_info_header.width + x) + 1] = G;
188+
data[channels * (y * bmp_info_header.width + x) + 2] = R;
189+
if (channels == 4) {
190+
data[channels * (y * bmp_info_header.width + x) + 3] = A;
191+
}
192+
}
193+
}
194+
}
195+
196+
void set_pixel(uint32_t x0, uint32_t y0, uint8_t B, uint8_t G, uint8_t R, uint8_t A) {
197+
if (x0 >= (uint32_t)bmp_info_header.width || y0 >= (uint32_t)bmp_info_header.height || x0 < 0 || y0 < 0) {
198+
throw std::runtime_error("The point is outside the image boundaries!");
199+
}
200+
201+
uint32_t channels = bmp_info_header.bit_count / 8;
202+
data[channels * (y0 * bmp_info_header.width + x0) + 0] = B;
203+
data[channels * (y0 * bmp_info_header.width + x0) + 1] = G;
204+
data[channels * (y0 * bmp_info_header.width + x0) + 2] = R;
205+
if (channels == 4) {
206+
data[channels * (y0 * bmp_info_header.width + x0) + 3] = A;
207+
}
208+
}
209+
210+
void draw_rectangle(uint32_t x0, uint32_t y0, uint32_t w, uint32_t h,
211+
uint8_t B, uint8_t G, uint8_t R, uint8_t A, uint8_t line_w) {
212+
if (x0 + w > (uint32_t)bmp_info_header.width || y0 + h > (uint32_t)bmp_info_header.height) {
213+
throw std::runtime_error("The rectangle does not fit in the image!");
214+
}
215+
216+
fill_region(x0, y0, w, line_w, B, G, R, A); // top line
217+
fill_region(x0, (y0 + h - line_w), w, line_w, B, G, R, A); // bottom line
218+
fill_region((x0 + w - line_w), (y0 + line_w), line_w, (h - (2 * line_w)), B, G, R, A); // right line
219+
fill_region(x0, (y0 + line_w), line_w, (h - (2 * line_w)), B, G, R, A); // left line
220+
}
221+
222+
private:
223+
uint32_t row_stride{ 0 };
224+
225+
void write_headers(std::ofstream &of) {
226+
of.write((const char*)&file_header, sizeof(file_header));
227+
of.write((const char*)&bmp_info_header, sizeof(bmp_info_header));
228+
if(bmp_info_header.bit_count == 32) {
229+
of.write((const char*)&bmp_color_header, sizeof(bmp_color_header));
230+
}
231+
}
232+
233+
void write_headers_and_data(std::ofstream &of) {
234+
write_headers(of);
235+
of.write((const char*)data.data(), data.size());
236+
}
237+
238+
// Add 1 to the row_stride until it is divisible with align_stride
239+
uint32_t make_stride_aligned(uint32_t align_stride) {
240+
uint32_t new_stride = row_stride;
241+
while (new_stride % align_stride != 0) {
242+
new_stride++;
243+
}
244+
return new_stride;
245+
}
246+
247+
// Check if the pixel data is stored as BGRA and if the color space type is sRGB
248+
void check_color_header(BMPColorHeader &bmp_color_header) {
249+
BMPColorHeader expected_color_header;
250+
if(expected_color_header.red_mask != bmp_color_header.red_mask ||
251+
expected_color_header.blue_mask != bmp_color_header.blue_mask ||
252+
expected_color_header.green_mask != bmp_color_header.green_mask ||
253+
expected_color_header.alpha_mask != bmp_color_header.alpha_mask) {
254+
throw std::runtime_error("Unexpected color mask format! The program expects the pixel data to be in the BGRA format");
255+
}
256+
if(expected_color_header.color_space_type != bmp_color_header.color_space_type) {
257+
throw std::runtime_error("Unexpected color space type! The program expects sRGB values");
258+
}
259+
}
260+
};

HW5/durka.bmp

1.98 MB
Binary file not shown.

HW5/main.cpp

+35-17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#ifdef WIN32
1+
#ifdef WIN32
22
#include <SDL.h>
33
#undef main
44
#else
@@ -15,6 +15,8 @@
1515
#include <map>
1616
#include <cmath>
1717
#include <test_image.h>
18+
#include <BMP.h>
19+
1820

1921
std::string to_string(std::string_view str)
2022
{
@@ -53,8 +55,7 @@ in vec2 texpos;
5355
layout (location = 0) out vec4 out_color;
5456
void main()
5557
{
56-
//out_color = (texture(tex, texpos) + texture(texcat, texpos)) / 2;
57-
out_color = texture(texcat, texpos);
58+
out_color = (texture(tex, texpos) + texture(texcat, texpos)) / 2;
5859
}
5960
)";
6061

@@ -97,6 +98,8 @@ GLuint create_program(GLuint vertex_shader, GLuint fragment_shader)
9798
return result;
9899
}
99100

101+
102+
100103
struct vec3
101104
{
102105
float x;
@@ -112,20 +115,20 @@ struct vertex
112115

113116
static vertex plane_vertices[]
114117
{
115-
{{-10.f, 0.f, -10.f}, {1, 1}},
118+
{{-10.f, 0.f, -10.f}, {0, 1}},
116119
{{-10.f, 0.f, 10.f}, {0, 0}},
117-
{{ 10.f, 0.f, -10.f}, {1, 0}},
118-
{{ 10.f, 0.f, 10.f}, {0, 1}},
120+
{{ 10.f, 0.f, -10.f}, {1, 1}},
121+
{{ 10.f, 0.f, 10.f}, {1, 0}},
119122
};
120123

121124
static std::uint32_t plane_indices[]
122125
{
123126
0, 1, 2, 2, 1, 3,
124127
};
125128

126-
static std::uint8_t checker_board[1024][1024][4];
129+
static std::uint8_t checker_board[2048][2048][4];
127130

128-
std::vector<std::uint32_t> red_pixels(512 * 512,
131+
std::vector<std::uint32_t> red_pixels(1024 * 1204,
129132
0xff0000ffu);
130133

131134
std::vector<std::uint32_t> green_pixels(512 * 512,
@@ -200,28 +203,28 @@ int main() try
200203
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)(0));
201204
glEnableVertexAttribArray(1);
202205
glVertexAttribPointer(1, 2, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(vertex), (void*)(sizeof(vec3)));
203-
206+
204207
GLuint texture;
205208
glGenTextures(1, &texture);
206209
glBindTexture(GL_TEXTURE_2D, texture);
207210
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
208211
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
209-
for (int i = 0; i < 1024; i++)
212+
for (int i = 0; i < 2048; i++)
210213
{
211-
for (int j = 0; j < 1024; j++)
214+
for (int j = 0; j < 2048; j++)
212215
{
213216
checker_board[i][j][0] = 255 * ((i + j) % 2);
214217
checker_board[i][j][1] = 255 * ((i + j) % 2);
215218
checker_board[i][j][2] = 255 * ((i + j) % 2);
216219
checker_board[i][j][3] = 255;
217220
}
218221
}
219-
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, &checker_board);
222+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 2048, 2048, 0, GL_RGBA, GL_UNSIGNED_BYTE, &checker_board);
220223
glGenerateMipmap(GL_TEXTURE_2D);
221-
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, red_pixels.data());
222-
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, green_pixels.data());
223-
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, blue_pixels.data());
224-
224+
glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, red_pixels.data());
225+
glTexImage2D(GL_TEXTURE_2D, 2, GL_RGBA8, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, green_pixels.data());
226+
glTexImage2D(GL_TEXTURE_2D, 3, GL_RGBA8, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, blue_pixels.data());
227+
225228
GLuint cat;
226229
glActiveTexture(GL_TEXTURE1);
227230
glGenTextures(1, &cat);
@@ -231,6 +234,19 @@ int main() try
231234
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
232235
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, test_image_width, test_image_height, 0, GL_RGB, GL_UNSIGNED_BYTE, test_image);
233236

237+
GLuint durka;
238+
glActiveTexture(GL_TEXTURE2);
239+
glGenTextures(1, &durka);
240+
glBindTexture(GL_TEXTURE_2D, durka);
241+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
242+
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
243+
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
244+
BMP durk = BMP("E:/soft/graphics/practice1/durka.bmp");
245+
int32_t dwidth = durk.bmp_info_header.width, dheight = durk.bmp_info_header.height;
246+
std::vector<uint8_t> durimage = durk.data;
247+
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 928, 558, 0, GL_BGRA, GL_UNSIGNED_BYTE, durimage.data());
248+
249+
234250
auto last_frame_start = std::chrono::high_resolution_clock::now();
235251

236252
float time = 0.f;
@@ -297,7 +313,7 @@ int main() try
297313
};
298314

299315
glUseProgram(program);
300-
glUniform1i(tex_location, 0);
316+
glUniform1i(tex_location, 2);
301317
glUniform1i(texcat_location, 1);
302318
glUniformMatrix4fv(view_location, 1, GL_TRUE, view);
303319
glUniformMatrix4fv(projection_location, 1, GL_TRUE, projection);
@@ -307,6 +323,8 @@ int main() try
307323
glBindTexture(GL_TEXTURE_2D, texture);
308324
glActiveTexture(GL_TEXTURE1);
309325
glBindTexture(GL_TEXTURE_2D, cat);
326+
//glActiveTexture(GL_TEXTURE2);
327+
//glBindTexture(GL_TEXTURE_2D, durka);
310328

311329
glDrawElements(GL_TRIANGLES, std::size(plane_indices), GL_UNSIGNED_INT, nullptr);
312330

0 commit comments

Comments
 (0)