276 lines
6.8 KiB
C++
276 lines
6.8 KiB
C++
// asterism.cpp
|
|
//
|
|
// Copyright (C) 2001, Chris Laurel <claurel@shatters.net>
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU General Public License
|
|
// as published by the Free Software Foundation; either version 2
|
|
// of the License, or (at your option) any later version.
|
|
|
|
#include <config.h>
|
|
#include <cstring>
|
|
#include <GL/glew.h>
|
|
#include <celutil/util.h>
|
|
#include <celutil/debug.h>
|
|
#include "asterism.h"
|
|
#include "parser.h"
|
|
#include "render.h"
|
|
|
|
using namespace std;
|
|
|
|
|
|
Asterism::Asterism(string _name) :
|
|
name(_name)
|
|
{
|
|
i18nName = dgettext("celestia_constellations", _name.c_str());
|
|
}
|
|
|
|
string Asterism::getName(bool i18n) const
|
|
{
|
|
return i18n ? i18nName : name;
|
|
}
|
|
|
|
int Asterism::getChainCount() const
|
|
{
|
|
return chains.size();
|
|
}
|
|
|
|
const Asterism::Chain& Asterism::getChain(int index) const
|
|
{
|
|
return *chains[index];
|
|
}
|
|
|
|
void Asterism::addChain(Asterism::Chain& chain)
|
|
{
|
|
chains.push_back(&chain);
|
|
}
|
|
|
|
|
|
/*! Return whether the constellation is visible.
|
|
*/
|
|
bool Asterism::getActive() const
|
|
{
|
|
return active;
|
|
}
|
|
|
|
|
|
/*! Set whether or not the constellation is visible.
|
|
*/
|
|
void Asterism::setActive(bool _active)
|
|
{
|
|
active = _active;
|
|
}
|
|
|
|
|
|
/*! Get the override color for this constellation.
|
|
*/
|
|
Color Asterism::getOverrideColor() const
|
|
{
|
|
return color;
|
|
}
|
|
|
|
|
|
/*! Set an override color for the constellation. If this method isn't
|
|
* called, the constellation is drawn in the render's default color
|
|
* for contellations. Calling unsetOverrideColor will remove the
|
|
* override color.
|
|
*/
|
|
void Asterism::setOverrideColor(Color c)
|
|
{
|
|
color = c;
|
|
useOverrideColor = true;
|
|
}
|
|
|
|
|
|
/*! Make this constellation appear in the default color (undoing any
|
|
* calls to setOverrideColor.
|
|
*/
|
|
void Asterism::unsetOverrideColor()
|
|
{
|
|
useOverrideColor = false;
|
|
}
|
|
|
|
|
|
/*! Return true if this constellation has a custom color, or false
|
|
* if it should be drawn in the default color.
|
|
*/
|
|
bool Asterism::isColorOverridden() const
|
|
{
|
|
return useOverrideColor;
|
|
}
|
|
|
|
/*! Draw visible asterisms.
|
|
*/
|
|
void AsterismList::render(const Color& defaultColor, const Renderer& renderer)
|
|
{
|
|
m_vo.bind();
|
|
if (!m_vo.initialized())
|
|
{
|
|
prepare();
|
|
|
|
if (vtx_num == 0)
|
|
return;
|
|
|
|
m_vo.allocate(vtx_num * 3 * sizeof(GLfloat), vtx_buf);
|
|
cleanup();
|
|
m_vo.setVertices(3, GL_FLOAT, false, 0, 0);
|
|
}
|
|
|
|
CelestiaGLProgram* prog = renderer.getShaderManager().getShader(shadprop);
|
|
if (prog == nullptr)
|
|
return;
|
|
|
|
prog->use();
|
|
prog->color = defaultColor.toVector4();
|
|
m_vo.draw(GL_LINES, vtx_num);
|
|
|
|
ptrdiff_t offset = 0;
|
|
float opacity = defaultColor.alpha();
|
|
for (const auto ast : *this)
|
|
{
|
|
if (!ast->getActive() || !ast->isColorOverridden())
|
|
{
|
|
offset += ast->vertex_count;
|
|
continue;
|
|
}
|
|
|
|
prog->color = Color(ast->getOverrideColor(), opacity).toVector4();
|
|
m_vo.draw(GL_LINES, ast->vertex_count, offset);
|
|
offset += ast->vertex_count;
|
|
}
|
|
|
|
glUseProgram(0);
|
|
m_vo.unbind();
|
|
}
|
|
|
|
|
|
void AsterismList::prepare()
|
|
{
|
|
if (prepared)
|
|
return;
|
|
|
|
// calculate required vertices number
|
|
vtx_num = 0;
|
|
for (const auto ast : *this)
|
|
{
|
|
uint16_t ast_vtx_num = 0;
|
|
for (int k = 0; k < ast->getChainCount(); k++)
|
|
{
|
|
// as we use GL_LINES we should double the number of vertices
|
|
// as we don't need closed figures we have only one copy of
|
|
// the 1st and last vertexes
|
|
auto s = (uint16_t) ast->getChain(k).size();
|
|
if (s > 1)
|
|
ast_vtx_num += 2 * s - 2;
|
|
}
|
|
|
|
ast->vertex_count = ast_vtx_num;
|
|
vtx_num += ast_vtx_num;
|
|
}
|
|
|
|
if (vtx_num == 0)
|
|
return;
|
|
|
|
vtx_buf = new GLfloat[vtx_num * 3];
|
|
GLfloat* ptr = vtx_buf;
|
|
|
|
for (const auto ast : *this)
|
|
{
|
|
for (int k = 0; k < ast->getChainCount(); k++)
|
|
{
|
|
const auto& chain = ast->getChain(k);
|
|
|
|
// skip empty (without starts or only with one star) chains
|
|
if (chain.size() <= 1)
|
|
continue;
|
|
|
|
memcpy(ptr, chain[0].data(), 3 * sizeof(float));
|
|
ptr += 3;
|
|
for (unsigned i = 1; i < chain.size() - 1; i++)
|
|
{
|
|
memcpy(ptr, chain[i].data(), 3 * sizeof(float));
|
|
memcpy(ptr + 3, chain[i].data(), 3 * sizeof(float));
|
|
ptr += 6;
|
|
}
|
|
memcpy(ptr, chain[chain.size() - 1].data(), 3 * sizeof(float));
|
|
ptr += 3;
|
|
}
|
|
}
|
|
|
|
prepared = true;
|
|
}
|
|
|
|
void AsterismList::cleanup()
|
|
{
|
|
delete[] vtx_buf;
|
|
// TODO: delete chains
|
|
}
|
|
|
|
|
|
AsterismList* ReadAsterismList(istream& in, const StarDatabase& stardb)
|
|
{
|
|
auto* asterisms = new AsterismList();
|
|
Tokenizer tokenizer(&in);
|
|
Parser parser(&tokenizer);
|
|
|
|
while (tokenizer.nextToken() != Tokenizer::TokenEnd)
|
|
{
|
|
if (tokenizer.getTokenType() != Tokenizer::TokenString)
|
|
{
|
|
DPRINTF(LOG_LEVEL_ERROR, "Error parsing asterism file.\n");
|
|
for_each(asterisms->begin(), asterisms->end(), deleteFunc<Asterism*>());
|
|
delete asterisms;
|
|
return nullptr;
|
|
}
|
|
|
|
string name = tokenizer.getStringValue();
|
|
Asterism* ast = new Asterism(name);
|
|
|
|
Value* chainsValue = parser.readValue();
|
|
if (chainsValue == nullptr || chainsValue->getType() != Value::ArrayType)
|
|
{
|
|
DPRINTF(LOG_LEVEL_ERROR, "Error parsing asterism %s\n", name.c_str());
|
|
for_each(asterisms->begin(), asterisms->end(), deleteFunc<Asterism*>());
|
|
delete ast;
|
|
delete asterisms;
|
|
delete chainsValue;
|
|
return nullptr;
|
|
}
|
|
|
|
Array* chains = chainsValue->getArray();
|
|
|
|
for (const auto chain : *chains)
|
|
{
|
|
if (chain->getType() == Value::ArrayType)
|
|
{
|
|
Array* a = chain->getArray();
|
|
// skip empty (without or only with a single star) chains
|
|
if (a->size() <= 1)
|
|
continue;
|
|
|
|
Asterism::Chain* new_chain = new Asterism::Chain();
|
|
for (const auto i : *a)
|
|
{
|
|
if (i->getType() == Value::StringType)
|
|
{
|
|
Star* star = stardb.find(i->getString());
|
|
if (star == nullptr)
|
|
star = stardb.find(ReplaceGreekLetterAbbr(i->getString()));
|
|
if (star != nullptr)
|
|
new_chain->push_back(star->getPosition());
|
|
else DPRINTF(LOG_LEVEL_ERROR, "Error loading star \"%s\" for asterism \"%s\".\n", name.c_str(), i->getString().c_str());
|
|
}
|
|
}
|
|
|
|
ast->addChain(*new_chain);
|
|
}
|
|
}
|
|
|
|
asterisms->push_back(ast);
|
|
|
|
delete chainsValue;
|
|
}
|
|
|
|
return asterisms;
|
|
}
|