Part 13: Wall ornates - Part 2
Downloads
Loading the databases
//--------------------------------------------------------------------------------------------------------
void CWalls::readOrnatesDB()
{
QDomDocument doc;
QFile f("databases/ornates.xml");
f.open(QIODevice::ReadOnly);
doc.setContent(&f);
f.close();
QDomElement root = doc.documentElement();
QDomElement ornate = root.firstChild().toElement();
while(!ornate.isNull())
{
if (ornate.tagName() == "ornate")
{
COrnateData newOrnate;
newOrnate.name = ornate.attribute("name");
QDomElement ornateInfo = ornate.firstChild().toElement();
while(!ornateInfo.isNull())
{
if (ornateInfo.tagName() == "image_front")
{
newOrnate.imageFront = QString("gfx/3DView/ornates/") + ornateInfo.text();
}
else if (ornateInfo.tagName() == "image_side")
{
newOrnate.imageSide = QString("gfx/3DView/ornates/") + ornateInfo.text();
}
else if (ornateInfo.tagName() == "pos_front")
{
newOrnate.posFront.x = ornateInfo.attribute("x").toInt();
newOrnate.posFront.y = ornateInfo.attribute("y").toInt();
}
else if (ornateInfo.tagName() == "pos_side")
{
newOrnate.posSide.x = ornateInfo.attribute("x").toInt();
newOrnate.posSide.y = ornateInfo.attribute("y").toInt();
}
ornateInfo = ornateInfo.nextSibling().toElement();
}
ornatesDatas.push_back(newOrnate);
}
ornate = ornate.nextSibling().toElement();
}
}
//---------------------------------------------------------------------------------------------
void CWalls::readWallsDB()
{
QDomDocument doc;
QFile f("databases/walls.xml");
f.open(QIODevice::ReadOnly);
doc.setContent(&f);
f.close();
QDomElement root = doc.documentElement();
QDomElement wall = root.firstChild().toElement();
while(!wall.isNull())
{
std::vector<CParamType> paramsTypesList;
if (wall.tagName() == "wall")
{
CWallData newWall;
newWall.name = wall.attribute("name");
QDomElement wallInfo = wall.firstChild().toElement();
while(!wallInfo.isNull())
{
if (wallInfo.tagName() == "param")
{
QString paramType = wallInfo.attribute("type");
if (paramType == "ornate")
{
CParamType newParamType;
newParamType.mType = eParamOrnate;
newParamType.mName = wallInfo.text();
paramsTypesList.push_back(newParamType);
}
}
wallInfo = wallInfo.nextSibling().toElement();
}
wallsDatas.push_back(newWall);
map.mWallsParams.push_back(paramsTypesList);
}
wall = wall.nextSibling().toElement();
}
}
Another walls table
// table with the pos and size of each walls for the ornates
struct SWallInfos
{
CVec2 pos;
CVec2 size;
};
static const SWallInfos gWallsInfos[WALL_TABLE_HEIGHT][WALL_TABLE_WIDTH][3] =
{
// Row 3 (farthest)
{
{{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} }, // 03
{{{0, 0}, {0, 0}}, {{ 8, 58}, {36, 48}}, {{0, 0}, {0, 0}} }, // 13
{{{0, 0}, {0, 0}}, {{78, 59}, {12, 48}}, {{134, 59}, {12, 48}}}, // 23
{{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{180, 58}, {36, 48}}}, // 33
{{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} } // 43
},
// Row 2
{
{{{-77, 58}, {70, 48}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} }, // 02
{{{ 7, 58}, {70, 48}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} }, // 12
{{{ 77, 58}, {70, 48}}, {{60, 52}, {18, 74}}, {{146, 52}, {18, 74}}}, // 22
{{{146, 58}, {70, 48}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} }, // 32
{{{216, 58}, {70, 48}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} } // 42
},
// Row 1
{
{{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} }, // 01
{{{-46, 52}, {105, 74}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} }, // 11
{{{ 59, 52}, {105, 74}}, {{33, 42}, {27, 111}}, {{164, 42}, {27, 111}}}, // 21
{{{164, 52}, {105, 74}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} }, // 31
{{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}} } // 41
},
// Row 0 (nearest)
{
{{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}}, // 00
{{{-127, 42}, {159, 111}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}}, // 10
{{{ 32, 42}, {159, 111}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}}, // 20
{{{ 191, 42}, {159, 111}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}}, // 30
{{{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}, {{0, 0}, {0, 0}}} // 40
}
};
Now you may ask yourself why we need another table, as the one we have in "walls.cpp" already gives us their positions
Setting up the variables
CWalls::COrnateData& ornateData = walls.ornatesDatas[ornate];
const SWallInfos* ornateTabData = &gWallsInfos[tablePos.y][tablePos.x][tableSide];
const SWallInfos* ornate0 = NULL;
QString ornateFileName;
CVec2 ornatePos;
bool ornateFlip = false;
switch(side)
{
case eWallSideUp:
ornate0 = &gWallsInfos[3][2][tableSide];
ornateFileName = ornateData.imageFront;
ornatePos = ornateData.posFront;
break;
case eWallSideLeft:
ornate0 = &gWallsInfos[2][2][1];
ornateFileName = walls.ornatesDatas[ornate].imageSide;
ornatePos = ornateData.posSide;
break;
case eWallSideRight:
ornate0 = &gWallsInfos[2][2][1];
ornateFileName = walls.ornatesDatas[ornate].imageSide;
ornatePos = ornateData.posSide;
ornateFlip = true;
break;
default:
break;
}
Calculating the position and scaling the image
// calculate the position and scale factor and draw the ornate in a temporary image
float scale = (float)ornateTabData->size.y / 111.0f;
QImage ornateImage = fileCache.getImage(ornateFileName.toLocal8Bit().constData());
QSize ornateSize = ornateImage.size() * scale;
ornatePos = (ornatePos - ornate0->pos);
ornatePos.x = ornatePos.x * ornateTabData->size.x / ornate0->size.x;
ornatePos.y = ornatePos.y * ornateTabData->size.y / ornate0->size.y;
if (ornateFlip == true)
ornatePos.x = ornateTabData->size.x - ornatePos.x - ornateSize.width();
ornatePos += ornateTabData->pos;
QImage tempImage(ornateSize, QImage::Format_ARGB32);
tempImage.fill(QColor(0, 0, 0, 0));
graph2D.drawImageScaled(&tempImage, CVec2(), ornateImage, scale, ornateFlip);
In the first 3 lines, we compute the scaling factor of the image, and it's final size.
Darkening the image
// darken the ornate based on it's distance
static const float shadowLevels[] = {0.0f, 0.2f, 0.4f};
float shadow;
if (side == eWallSideUp)
shadow = shadowLevels[WALL_TABLE_HEIGHT - 1 - tablePos.y];
else
shadow = shadowLevels[WALL_TABLE_HEIGHT - 2 - tablePos.y];
QPainter painter(&tempImage);
painter.setOpacity(shadow);
painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
painter.drawImage(QPoint(0, 0), *shadowImage);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.setOpacity(1.0f);
painter.end();
// draw the ornate on screen.
graph2D.drawImage(image, ornatePos, tempImage, 0, false, QRect(0, 33, MAINVIEW_WIDTH, MAINVIEW_HEIGHT));
To achieve that we change the drawing opacity and we draw on top of our temporary image a "shadowImage", that is simply an image
Better graphics