aboutsummaryrefslogtreecommitdiff
path: root/source/30-game/Image.cpp
blob: 3673acc11db14691ee19eda66ae65de94278b5ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include "Image.hpp"

#include <stb_image.h>
#include <stb_rect_pack.h>
#include <cstring>

Image::Image()
	: mSize{}
	, mChannels{ 0 } {
}

bool Image::InitFromImageFile(const char* filePath, int desiredChannels) {
	// Dimensions of the image in
	int width, height;
	// Number of channels that the image has, we'll get `desiredChannels` channels in our output (if it's non-0, which is the default argument)
	int channels;

	// NOTE: don't free, the data is passed to std::unique_ptr
	auto result = (uint8_t*)stbi_load(filePath, &width, &height, &channels, desiredChannels);
	if (!result) {
		return false;
	}

	mData.reset(result);
	mSize = { width, height };
	mChannels = desiredChannels == 0 ? channels : desiredChannels;
	return true;
}

bool Image::InitFromImageData(std::span<uint8_t> data, int desiredChannels) {
	int width, height;
	int channels;

	// NOTE: don't free, the data is passed to std::unique_ptr
	auto result = (uint8_t*)stbi_load_from_memory(data.data(), data.size(), &width, &height, &channels, desiredChannels);
	if (!result) {
		return false;
	}

	mData.reset(result);
	mSize = { width, height };
	mChannels = desiredChannels == 0 ? channels : desiredChannels;
	return true;
}

bool Image::InitFromPixels(std::span<uint8_t> pixels, glm::ivec2 dimensions, int channels) {
	mData = std::make_unique<uint8_t[]>(pixels.size());
	std::memcpy(mData.get(), pixels.data(), pixels.size());
	mSize = dimensions;
	mChannels = channels;
	return true;
}

bool Image::InitFromPixels(std::unique_ptr<uint8_t[]> pixels, glm::ivec2 dimensions, int channels) {
	mData = std::move(pixels);
	mSize = dimensions;
	mChannels = channels;
	return true;
}

RgbaColor Image::GetPixel(int x, int y) const {
	size_t offset = (y * mSize.x + x) * mChannels;
	RgbaColor color;
	color.r = mData.get()[offset + 0];
	color.g = mData.get()[offset + 1];
	color.b = mData.get()[offset + 2];
	color.a = mData.get()[offset + 3];
	return color;
}

void Image::SetPixel(int x, int y, RgbaColor color) {
	size_t offset = (y * mSize.x + x) * mChannels;
	mData.get()[offset + 0] = color.r;
	mData.get()[offset + 1] = color.g;
	mData.get()[offset + 2] = color.b;
	mData.get()[offset + 3] = color.a;
}

uint8_t* Image::GetDataPtr() const {
	return mData.get();
}

size_t Image::GetDataLength() const {
	return mSize.x * mSize.y * mChannels * sizeof(uint8_t);
}

std::span<uint8_t> Image::GetData() const {
	return { mData.get(), GetDataLength() };
}

glm::ivec2 Image::GetSize() const {
	return mSize;
}

int Image::GetChannels() const {
	return mChannels;
}

bool Image::IsEmpty() const {
	return mSize.x == 0 || mSize.y == 0;
}