1
0
forked from 0ad/0ad
0ad/source/graphics/TextureEntry.cpp

217 lines
5.7 KiB
C++
Raw Normal View History

#include "precompiled.h"
#include <string>
#include "ogl.h"
#include "res/ogl_tex.h"
#include "CLogger.h"
#include "TextureEntry.h"
#include "TextureManager.h"
#include "Texture.h"
#include "Renderer.h"
#include "Overlay.h"
#include "Parser.h"
#include "XeroXMB.h"
#include "Xeromyces.h"
using namespace std;
#define LOG_CATEGORY "graphics"
/////////////////////////////////////////////////////////////////////////////////////
// CTextureEntry constructor
CTextureEntry::CTextureEntry():
m_pParent(NULL),
m_Bitmap(NULL),
m_Handle(-1),
m_BaseColor(0),
m_BaseColorValid(false)
{}
/////////////////////////////////////////////////////////////////////////////////////
// CTextureEntry destructor
CTextureEntry::~CTextureEntry()
{
if (m_Handle > 0)
tex_free(m_Handle);
GroupVector::iterator it=m_Groups.begin();
for (;it!=m_Groups.end();++it)
(*it)->RemoveTerrain(this);
}
CTextureEntry *CTextureEntry::FromXML(XMBElement node, CXeromyces *pFile)
{
CTextureEntry *thiz=new CTextureEntry();
#define ELMT(x) int elmt_##x = pFile->getElementID(#x)
#define ATTR(x) int attr_##x = pFile->getAttributeID(#x)
ELMT(doodad);
ELMT(passable);
ELMT(event);
// Terrain Attribs
ATTR(tag);
ATTR(skin);
ATTR(parent);
ATTR(mmap);
ATTR(groups);
ATTR(properties);
// Passable Attribs
ATTR(type);
ATTR(speed);
ATTR(effect);
// Doodad Attribs
ATTR(name);
ATTR(max);
// Event attribs
ATTR(on);
#undef ELMT
#undef ATTR
XMBAttributeList attribs = node.getAttributes();
for (int i=0;i<attribs.Count;i++)
{
XMBAttribute attr = attribs.item(i);
if (attr.Name == attr_tag)
thiz->m_Tag = (CStr)attr.Value;
if (attr.Name == attr_parent)
thiz->m_ParentName = (CStr)attr.Value;
else if (attr.Name == attr_skin)
{
thiz->m_TexturePath = (CStr)attr.Value;
}
else if (attr.Name == attr_groups)
{
// Parse a comma-separated list of groups, add the new entry to
// each of them
CParser parser;
CParserLine parserLine;
parser.InputTaskType("GroupList", "<_$value_,>_$value_");
if (!parserLine.ParseString(parser, (CStr)attr.Value))
continue;
for (size_t i=0;i<parserLine.GetArgCount();i++)
{
string value;
if (!parserLine.GetArgString(i, value))
continue;
CTerrainTypeGroup *pType = g_TexMan.FindGroup(value);
thiz->m_Groups.push_back(pType);
pType->AddTerrain(thiz);
}
}
else if (attr.Name == attr_mmap)
{
CColor col;
if (!col.ParseString((CStr)attr.Value, 255))
continue;
// m_BaseColor is RGBA
u8 (&baseColor)[4] = *(u8 (*)[4])&thiz->m_BaseColor;
baseColor[0] = (u8)(col.r*255);
baseColor[1] = (u8)(col.g*255);
baseColor[2] = (u8)(col.b*255);
baseColor[3] = (u8)(col.a*255);
thiz->m_BaseColorValid = true;
}
else if (attr.Name == attr_properties)
{
// TODO Parse a list of properties and store them somewhere
}
}
// TODO Parse information in child nodes and store them somewhere
LOG(NORMAL, LOG_CATEGORY, "CTextureEntry::FromXML(): Terrain type %s (texture %s) loaded", thiz->m_Tag.c_str(), thiz->m_TexturePath.c_str());
return thiz;
}
void CTextureEntry::LoadParent()
{
// Don't do anything at all if we already have a parent, or if we are a root
// entry
if (m_pParent || !m_ParentName.size())
return;
m_pParent = g_TexMan.FindTexture(m_ParentName);
if (!m_pParent)
{
LOG(ERROR, LOG_CATEGORY, "CTextureEntry::LoadParent(): %s: Could not find parent terrain type %s", m_Tag.c_str(), m_ParentName.c_str());
return;
}
m_pParent->LoadParent(); // Make sure we're loaded all the way to our root
}
/////////////////////////////////////////////////////////////////////////////////////
// LoadTexture: actually load the texture resource from file
void CTextureEntry::LoadTexture()
{
if (m_TexturePath.size() == 0)
{
debug_assert(m_pParent);
m_pParent->LoadTexture();
m_Handle = m_pParent->m_Handle;
return;
}
else
{
CTexture texture;
texture.SetName(m_TexturePath);
if (g_Renderer.LoadTexture(&texture,GL_REPEAT)) {
m_Handle=texture.GetHandle();
} else {
m_Handle=0;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
// BuildBaseColor: calculate the root color of the texture, used for coloring minimap, and store
// in m_BaseColor member
void CTextureEntry::BuildBaseColor()
{
// a) We have an XML override: m_BaseColorValid=true, so we never get here
// b) No XML override, overriden texture: use own texture, calc. BaseColor
// c) No XML override, parent texture: use parent BaseColor
// d) No XML override, but parent has: use parent BaseColor
// cases c&d: We don't have our own texture, use parent base color instead
if (m_TexturePath.size() == 0)
{
debug_assert(m_pParent);
m_BaseColor=m_pParent->GetBaseColor();
m_BaseColorValid=true;
return;
}
// case b: Calculate base color by mipmapping our texture
Handle handle=GetHandle();
g_Renderer.BindTexture(0,tex_id(handle));
// get root color for coloring minimap by querying root level of the texture
// (this should decompress any compressed textures for us),
// then scaling it down to a 1x1 size
// - an alternative approach of just grabbing the top level of the mipmap tree fails
// (or gives an incorrect colour) in some cases:
// - suspect bug on Radeon cards when SGIS_generate_mipmap is used
// - any textures without mipmaps
// we'll just take the basic approach here:
int width,height;
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_WIDTH,&width);
glGetTexLevelParameteriv(GL_TEXTURE_2D,0,GL_TEXTURE_HEIGHT,&height);
unsigned char* buf=new unsigned char[width*height*4];
glGetTexImage(GL_TEXTURE_2D,0,GL_BGRA_EXT,GL_UNSIGNED_BYTE,buf);
gluScaleImage(GL_BGRA_EXT,width,height,GL_UNSIGNED_BYTE,buf,
1,1,GL_UNSIGNED_BYTE,&m_BaseColor);
delete[] buf;
m_BaseColorValid=true;
}