-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpalette.cpp
126 lines (100 loc) · 3.62 KB
/
palette.cpp
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "palette.h"
#include <QFile>
#include "data-stream.h"
void Palette::reset()
{
for (uint line = 0; line < TOTAL_LINES; ++line)
{
for (uint index = 0; index < COLOURS_PER_LINE; ++index)
{
const uint intensity_1 = index >= 8 ? ~index & 7 : index;
// Fun fact: those three bizarre colours at the bottom of SonMapEd's default
// palette are the result of a bug: one of the colour channels underflow.
// This bug has been recreated here.
const uint intensity_2 = index >= 8 ? (~index - 1) & 7 : index;
uint colour = 0xF000;
switch (line)
{
case 0:
// This is not what SonMapEd does: SonMapEd just includes a copy of the
// primary palette line from the selected Sonic game. But I worry that
// doing that would be a copyright infringement, so instead I use a grey
// version of the other palette lines here.
colour |= (intensity_1 << 9) | (intensity_2 << 5) | (intensity_2 << 1);
break;
case 1:
colour |= (intensity_1 << 9) | (intensity_2 << 1);
break;
case 2:
colour |= (intensity_2 << 5) | (intensity_1 << 1);
break;
case 3:
colour |= (intensity_2 << 9) | (intensity_1 << 5);
break;
}
lines[line].colours[index] = colour;
}
}
}
void Palette::toDataStream(DataStream &stream, const int starting_palette_line, const int ending_palette_line) const
{
for (int line = starting_palette_line; line < ending_palette_line; ++line)
lines[line].toDataStream(stream);
}
void Palette::fromDataStream(DataStream &stream, const int starting_palette_line)
{
for (int line = starting_palette_line; line < TOTAL_LINES; ++line)
lines[line].fromDataStream(stream);
}
void Palette::Line::toDataStream(DataStream &stream) const
{
for (auto &colour : colours)
colour.toDataStream(stream);
}
void Palette::Line::fromDataStream(DataStream &stream)
{
for (auto &colour : colours)
colour.fromDataStream(stream);
}
Palette::Line::Colour& Palette::Line::Colour::operator=(const QColor &colour)
{
const uint red = (static_cast<uint>(colour.red()) >> 5) & 7;
const uint green = (static_cast<uint>(colour.green()) >> 5) & 7;
const uint blue = (static_cast<uint>(colour.blue()) >> 5) & 7;
this->colour = (blue << 9) | (green << 5) | (red << 1);
return *this;
}
QColor Palette::Line::Colour::toQColor(const std::function<uint(uint)> &callback) const
{
// This isn't exactly what SonMapEd does:
// For some reason, SonMapEd treats the colours as 4-bit-per-channel,
// when they're really only 3-bit-per-channel.
const uint red = (colour >> 1) & 7;
const uint green = (colour >> 5) & 7;
const uint blue = (colour >> 9) & 7;
return QColor(callback(red), callback(green), callback(blue));
}
QColor Palette::Line::Colour::toQColor224() const
{
return toQColor([](const uint colour_channel){return colour_channel << 5;});
}
QColor Palette::Line::Colour::toQColor256() const
{
return toQColor([](const uint colour_channel){return colour_channel << 5 | colour_channel << 2 | colour_channel >> 1;});
}
void Palette::Line::Colour::toDataStream(DataStream &stream) const
{
const auto original_byte_order = stream.byteOrder();
stream.setByteOrder(DataStream::BigEndian);
stream.write<quint16>(colour);
stream.setByteOrder(original_byte_order);
}
void Palette::Line::Colour::fromDataStream(DataStream &stream)
{
if (stream.status() != DataStream::Status::Ok)
return;
const auto original_byte_order = stream.byteOrder();
stream.setByteOrder(DataStream::BigEndian);
colour = stream.read<quint16>();
stream.setByteOrder(original_byte_order);
}