-
Notifications
You must be signed in to change notification settings - Fork 1
/
Texture.h
185 lines (158 loc) · 5.81 KB
/
Texture.h
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
#pragma once
#define MIN_TEXTURE_SIZE 8
struct FIBITMAP;
// texture stored in main memory in 32bit ARGB uchar format or 96bit RGB float
class BaseTexture
{
public:
enum Format
{
RGBA,
RGB_FP
};
BaseTexture()
: m_width(0), m_height(0), m_realWidth(0), m_realHeight(0), m_format(RGBA)
{ }
BaseTexture(const int w, const int h, const Format format = RGBA)
: m_width(w), m_height(h), m_data((format == RGBA ? 4 : 3*4) * (w*h)), m_realWidth(w), m_realHeight(h), m_format(format)
{ }
int width() const { return m_width; }
int height() const { return m_height; }
int pitch() const { return (m_format == RGBA ? 4 : 3*4) * m_width; } // pitch in bytes
BYTE* data() { return m_data.data(); }
private:
int m_width;
int m_height;
public:
std::vector<BYTE> m_data;
int m_realWidth, m_realHeight;
Format m_format;
void SetOpaque();
void CopyFrom_Raw(const void* bits) // copy bits which are already in the right format
{
memcpy(data(), bits, m_data.size());
}
void CopyTo_ConvertAlpha(BYTE* const __restrict bits) // premultiplies alpha (as Win32 AlphaBlend() wants it like that) OR converts rgb_fp format to 32bits
{
if(m_format == RGB_FP) // Tonemap for 8bpc-Display
{
const float * const __restrict src = (float*)m_data.data();
unsigned int o = 0;
for (int j = 0; j < m_height; ++j)
for (int i = 0; i < m_width; ++i, ++o)
{
const float r = src[o * 3];
const float g = src[o * 3 + 1];
const float b = src[o * 3 + 2];
const float l = r*0.176204f + g*0.812985f + b*0.0108109f;
const float n = (l*0.25f + 1.0f) / (l + 1.0f); // overflow is handled by clamp
bits[o * 4 ] = (BYTE)(clamp(b*n, 0.f, 1.f) * 255.f);
bits[o * 4 + 1] = (BYTE)(clamp(g*n, 0.f, 1.f) * 255.f);
bits[o * 4 + 2] = (BYTE)(clamp(r*n, 0.f, 1.f) * 255.f);
bits[o * 4 + 3] = 255;
}
}
else
{
if (GetWinVersion() >= 2600) // For everything newer than Windows XP: use the alpha in the bitmap, thus RGB needs to be premultiplied with alpha, due to how AlphaBlend() works
{
unsigned int o = 0;
for (int j = 0; j < m_height; ++j)
for (int i = 0; i < m_width; ++i, ++o)
{
const unsigned int alpha = m_data[o * 4 + 3];
if (alpha == 0) // adds a checkerboard where completely transparent (for the image manager display)
{
const BYTE c = ((((i >> 4) ^ (j >> 4)) & 1) << 7) + 127;
bits[o * 4 ] = c;
bits[o * 4 + 1] = c;
bits[o * 4 + 2] = c;
bits[o * 4 + 3] = 0;
}
else if (alpha != 255) // premultiply alpha for win32 AlphaBlend()
{
bits[o * 4 ] = ((unsigned int)m_data[o * 4 ] * alpha) >> 8;
bits[o * 4 + 1] = ((unsigned int)m_data[o * 4 + 1] * alpha) >> 8;
bits[o * 4 + 2] = ((unsigned int)m_data[o * 4 + 2] * alpha) >> 8;
bits[o * 4 + 3] = alpha;
}
else
((DWORD*)bits)[o] = ((DWORD*)m_data.data())[o];
}
}
else // adds a checkerboard pattern where alpha is set to output bits
{
unsigned int o = 0;
for (int j = 0; j < m_height; ++j)
for (int i = 0; i < m_width; ++i, ++o)
{
const unsigned int alpha = m_data[o * 4 + 3];
if (alpha != 255)
{
const unsigned int c = (((((i >> 4) ^ (j >> 4)) & 1) << 7) + 127) * (255 - alpha);
bits[o * 4 ] = ((unsigned int)m_data[o * 4 ] * alpha + c) >> 8;
bits[o * 4 + 1] = ((unsigned int)m_data[o * 4 + 1] * alpha + c) >> 8;
bits[o * 4 + 2] = ((unsigned int)m_data[o * 4 + 2] * alpha + c) >> 8;
bits[o * 4 + 3] = alpha;
}
else
((DWORD*)bits)[o] = ((DWORD*)m_data.data())[o];
}
}
}
}
static BaseTexture *CreateFromHBitmap(const HBITMAP hbm);
static BaseTexture *CreateFromFile(const char *filename);
static BaseTexture *CreateFromFreeImage(FIBITMAP* dib);
static BaseTexture *CreateFromData(const void *data, const size_t size);
};
class Texture : public ILoadable
{
public:
Texture();
Texture(BaseTexture * const base);
virtual ~Texture();
// ILoadable callback
virtual bool LoadToken(const int id, BiffReader * const pbr);
HRESULT SaveToStream(IStream *pstream, PinTable *pt);
HRESULT LoadFromStream(IStream *pstream, int version, PinTable *pt);
void FreeStuff();
void EnsureHBitmap();
void CreateGDIVersion();
void CreateTextureOffscreen(const int width, const int height);
BaseTexture *CreateFromHBitmap(const HBITMAP hbm);
void CreateFromResource(const int id);
bool IsHDR() const
{
if (m_pdsBuffer == NULL)
return false;
else
return (m_pdsBuffer->m_format == BaseTexture::RGB_FP);
}
void SetSizeFrom(const BaseTexture* const tex)
{
m_width = tex->width();
m_height = tex->height();
m_realWidth = tex->m_realWidth;
m_realHeight = tex->m_realHeight;
}
// create/release a DC which contains a (read-only) copy of the texture; for editor use
void GetTextureDC(HDC *pdc);
void ReleaseTextureDC(HDC dc);
private:
bool LoadFromMemory(BYTE * const data, const DWORD size);
public:
// width and height of texture can be different than width and height
// of m_pdsBuffer, since the surface can be limited to smaller sizes by the user
int m_width, m_height;
int m_realWidth, m_realHeight;
float m_alphaTestValue;
BaseTexture* m_pdsBuffer;
HBITMAP m_hbmGDIVersion; // HBitmap at screen depth and converted/visualized alpha so GDI draws it fast
PinBinary *m_ppb; // if this image should be saved as a binary stream, otherwise just LZW compressed from the live bitmap
char m_szName[MAXTOKEN];
char m_szInternalName[MAXTOKEN];
char m_szPath[MAX_PATH];
private:
HBITMAP m_oldHBM; // this is to cache the result of SelectObject()
};