forked from hitmen047/Source-PlusPlus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimagepacker.cpp
141 lines (118 loc) · 3.39 KB
/
imagepacker.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose:
//
// $Workfile: $
// $Date: $
// $NoKeywords: $
//=============================================================================
#include "vrad.h"
#include "imagepacker.h"
bool CImagePacker::Reset( int maxLightmapWidth, int maxLightmapHeight )
{
int i;
Assert( maxLightmapWidth <= MAX_MAX_LIGHTMAP_WIDTH );
m_MaxLightmapWidth = maxLightmapWidth;
m_MaxLightmapHeight = maxLightmapHeight;
m_MaxBlockWidth = maxLightmapWidth + 1;
m_MaxBlockHeight = maxLightmapHeight + 1;
m_AreaUsed = 0;
m_MinimumHeight = -1;
for( i = 0; i < m_MaxLightmapWidth; i++ )
{
m_pLightmapWavefront[i] = -1;
}
return true;
}
inline int CImagePacker::GetMaxYIndex( int firstX, int width )
{
int maxY = -1;
int maxYIndex = 0;
for( int x = firstX; x < firstX + width; ++x )
{
// NOTE: Want the equals here since we'll never be able to fit
// in between the multiple instances of maxY
if( m_pLightmapWavefront[x] >= maxY )
{
maxY = m_pLightmapWavefront[x];
maxYIndex = x;
}
}
return maxYIndex;
}
bool CImagePacker::AddBlock( int width, int height, int *returnX, int *returnY )
{
// If we've already determined that a block this big couldn't fit
// then blow off checking again...
if ( ( width >= m_MaxBlockWidth ) && ( height >= m_MaxBlockHeight ) )
return false;
int bestX = -1;
int maxYIdx;
int outerX = 0;
int outerMinY = m_MaxLightmapHeight;
int lastX = m_MaxLightmapWidth - width;
int lastMaxYVal = -2;
while (outerX <= lastX)
{
// Skip all tiles that have the last Y value, these
// aren't going to change our min Y value
if (m_pLightmapWavefront[outerX] == lastMaxYVal)
{
++outerX;
continue;
}
maxYIdx = GetMaxYIndex( outerX, width );
lastMaxYVal = m_pLightmapWavefront[maxYIdx];
if (outerMinY > lastMaxYVal)
{
outerMinY = lastMaxYVal;
bestX = outerX;
}
outerX = maxYIdx + 1;
}
if( bestX == -1 )
{
// If we failed to add it, remember the block size that failed
// *only if both dimensions are smaller*!!
// Just because a 1x10 block failed, doesn't mean a 10x1 block will fail
if ( ( width <= m_MaxBlockWidth ) && ( height <= m_MaxBlockHeight ) )
{
m_MaxBlockWidth = width;
m_MaxBlockHeight = height;
}
return false;
}
// Set the return positions for the block.
*returnX = bestX;
*returnY = outerMinY + 1;
// Check if it actually fit height-wise.
// hack
// if( *returnY + height > maxLightmapHeight )
if( *returnY + height >= m_MaxLightmapHeight - 1 )
{
if ( ( width <= m_MaxBlockWidth ) && ( height <= m_MaxBlockHeight ) )
{
m_MaxBlockWidth = width;
m_MaxBlockHeight = height;
}
return false;
}
// It fit!
// Keep up with the smallest possible size for the image so far.
if( *returnY + height > m_MinimumHeight )
m_MinimumHeight = *returnY + height;
// Update the wavefront info.
int x;
for( x = bestX; x < bestX + width; x++ )
{
m_pLightmapWavefront[x] = outerMinY + height;
}
// AddBlockToLightmapImage( *returnX, *returnY, width, height );
m_AreaUsed += width * height;
return true;
}