WoW Model Viewer
Your premiere tool for viewing, equipping and animating World of Warcraft models.
Loading...
Searching...
No Matches
CharTexture.cpp
Go to the documentation of this file.
1#include "CharTexture.h"
2
3#include <algorithm>
4#include <map>
5#include <string>
6
7#include "DB2Table.h"
8#include "Game.h"
9#include "GameFile.h"
10#include "Texture.h"
11#include "TextureManager.h"
12#include "WoWDatabase.h"
13
14#include "Logger.h"
15
16std::map<int, std::pair<LayoutSize, std::map<int, CharRegionCoords>>> CharTexture::LAYOUTS;
17constexpr int LAYOUT_BASE_REGION = -1;
18
19void CharTexture::addLayer(GameFile* file, int region, int layer, int blendMode)
20{
21 if (!file)
22 return;
23
24 const CharTextureComponent ct = {file, region, layer, blendMode};
25 m_components.push_back(ct);
26}
27
28void CharTexture::reset(unsigned int _layoutSizeId)
29{
30 m_components.clear();
31 layoutSizeId = _layoutSizeId;
32}
33
34#define DEBUG_TEXTURE 0 // 1 output component names, 2 save intermediate images on disk
35
36void CharTexture::compose(GLuint texID)
37{
38 if (m_components.empty())
39 return;
40
41 std::sort(m_components.begin(), m_components.end());
42
43 SoftwareImage img;
44
45#if DEBUG_TEXTURE > 1
46 static auto baseidx = 0;
47 auto cmpidx = 0;
48#endif
49
50 for (auto it : m_components)
51 {
52 burnComponent(img, it);
53#if DEBUG_TEXTURE > 1
54 img.savePNG("./ComposedTexture" + std::to_string(baseidx) + "_" + std::to_string(cmpidx++) + ".png");
55#endif
56 }
57
58 // good, upload this to video
59 glBindTexture(GL_TEXTURE_2D, texID);
60 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0, GL_BGRA, GL_UNSIGNED_BYTE, img.data());
61 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
62 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
63}
64
66{
67 const DB2Table* layoutsTbl = WOWDB.getTable("CharComponentTextureLayouts");
68 if (!layoutsTbl || layoutsTbl->getRowCount() == 0)
69 {
70 LOG_ERROR << "Fail to retrieve Texture Layout information from game database";
71 return;
72 }
73
74 const DB2Table* sectionsTbl = WOWDB.getTable("CharComponentTextureSections");
75 if (!sectionsTbl || sectionsTbl->getRowCount() == 0)
76 {
77 LOG_ERROR << "Fail to retrieve Section Layout information from game database";
78 return;
79 }
80
81 // Iterate on layout to initialize our members (sections informations)
82 for (const auto& layoutRow : *layoutsTbl)
83 {
84 const int curLayout = static_cast<int>(layoutRow.recordID());
85 LayoutSize texLayout = {static_cast<int>(layoutRow.getUInt("Width")),
86 static_cast<int>(layoutRow.getUInt("Height"))};
87
88 std::map<int, CharRegionCoords> regionCoords;
89 const CharRegionCoords base = {0, 0, texLayout.width, texLayout.height};
90 regionCoords[LAYOUT_BASE_REGION] = base;
91
92 // search all regions for this layout
93 bool found = false;
94 for (const auto& secRow : *sectionsTbl)
95 {
96 if (static_cast<int>(secRow.getUInt("CharComponentTextureLayoutID")) != curLayout)
97 continue;
98
99 found = true;
100 const CharRegionCoords coords = {
101 static_cast<int>(secRow.getUInt("X")),
102 static_cast<int>(secRow.getUInt("Y")),
103 static_cast<int>(secRow.getUInt("Width")),
104 static_cast<int>(secRow.getUInt("Height"))
105 };
106 regionCoords[static_cast<int>(secRow.getUInt("SectionType"))] = coords;
107 }
108
109 if (!found)
110 {
111 LOG_ERROR << "Fail to retrieve Section Layout information from game database for layout" << curLayout;
112 continue;
113 }
114
115 LOG_INFO << "Found" << regionCoords.size() << "regions for layout" << curLayout;
116 CharTexture::LAYOUTS[curLayout] = make_pair(texLayout, regionCoords);
117 }
118}
119
121{
122 auto layoutInfos = CharTexture::LAYOUTS[layoutSizeId];
123
124 const auto& coords = layoutInfos.second[ct.region];
125
126 const auto* tmp = gameFileToQImage(ct.file);
127
128 if (!tmp)
129 return;
130
131 const auto newImage = tmp->scaled(coords.width, coords.height);
132
133
134#if DEBUG_TEXTURE > 0
135 const auto region = ct.region;
136 const auto layer = ct.layer;
137 const auto x = coords.xpos;
138 const auto y = coords.ypos;
139 const auto width = coords.width;
140 const auto height = coords.height;
141 LOG_INFO << __FUNCTION__ << ct.file->fullname() << region << layer << x << y << width << height;
142#endif
143
144#if DEBUG_TEXTURE > 1
145 newImage.savePNG("./tex__" + std::to_string(region) + "_" + std::to_string(x) + "_" + std::to_string(y) + "_" + std::to_string(width) + "_" + std::to_string(height) + ".png");
146#endif
147
148 if ((ct.region == LAYOUT_BASE_REGION
149 || ct.region == 11) // Dracthyr dragon base section
150 && ct.layer == 0)
151 {
152 destImage.assign(newImage);
153 }
154 else
155 {
156 destImage.composite(newImage, coords.xpos, coords.ypos, ct.blendMode);
157 }
158
159 delete tmp;
160}
161
163{
164 SoftwareImage* result = nullptr;
165 const auto temptex = TEXTUREMANAGER.add(file);
166 auto* tex = dynamic_cast<Texture*>(TEXTUREMANAGER.items[temptex]);
167
168 // Alfred 2009.07.03, tex width or height can't be zero
169 if (!tex || tex->w == 0 || tex->h == 0)
170 {
171 TEXTUREMANAGER.del(temptex);
172 return result;
173 }
174
175 auto* tempbuf = static_cast<unsigned char*>(malloc(tex->w * tex->h * 4));
176
177 tex->getPixels(tempbuf, GL_BGRA);
178 result = new SoftwareImage(tempbuf, tex->w, tex->h);
179
180 free(tempbuf);
181 TEXTUREMANAGER.del(temptex);
182
183 return result;
184}
constexpr int LAYOUT_BASE_REGION
#define LOG_ERROR
Definition Logger.h:11
#define LOG_INFO
Definition Logger.h:10
TextureManager TEXTUREMANAGER
#define WOWDB
Definition WoWDatabase.h:65
void reset(unsigned int _layoutSizeId)
std::vector< CharTextureComponent > m_components
Definition CharTexture.h:69
unsigned int layoutSizeId
Definition CharTexture.h:68
void compose(GLuint texID)
void burnComponent(SoftwareImage &destImage, CharTextureComponent &) const
static SoftwareImage * gameFileToQImage(GameFile *file)
static std::map< int, std::pair< LayoutSize, std::map< int, CharRegionCoords > > > LAYOUTS
Definition CharTexture.h:70
static void initRegions()
void addLayer(GameFile *file, int region, int layer, int blendMode=1)
Provides typed, field-name-based access to records in a WDC DB2 file.
Definition DB2Table.h:50
size_t getRowCount() const
Definition DB2Table.cpp:112
Abstract base class representing a file within the game data archive.
Definition GameFile.h:12
const std::string & fullname() const
Definition GameFile.h:56
virtual void del(IDTYPE id)
Definition manager.h:62
std::map< IDTYPE, ManagedItem * > items
Definition manager.h:50
CPU-side image buffer storing BGRA pixel data.
void composite(const SoftwareImage &src, int destX, int destY, int blendMode=1)
Composite a source image onto this image at the given position.
bool savePNG(const std::string &path) const
Save as PNG to the given file path.
void assign(const SoftwareImage &src)
Replace contents entirely with a copy of src.
int height() const
Image height in pixels.
uint8_t * data()
Mutable pointer to the raw BGRA pixel buffer.
int width() const
Image width in pixels.
virtual GLuint add(GameFile *)
Coordinates of a region within the character texture atlas.
Definition CharTexture.h:20
A single texture layer to be composited onto the character skin.
Definition CharTexture.h:32
Dimensions of a character texture layout.
Definition CharTexture.h:26