Files
BlitzNext/Runtime/blitz3d/brush.cpp
T
Michael Fabian 'Xaymar' Dirks 2196cb8419 runtime: Formatting
2019-01-18 17:04:17 +01:00

241 lines
4.6 KiB
C++

#include "brush.hpp"
#include "std.hpp"
#include "../gxruntime/gxgraphics.hpp"
struct Brush::Rep {
union {
int ref_cnt;
Rep* next;
};
int blend, max_tex;
bool blend_valid;
gxScene::RenderState rs;
Texture texs[gxScene::MAX_TEXTURES];
static Rep* pool;
Rep() : ref_cnt(1), blend(0), max_tex(0), blend_valid(true)
{
memset(&rs, 0, sizeof(rs));
rs.blend = gxScene::BLEND_REPLACE;
rs.color[0] = rs.color[1] = rs.color[2] = rs.alpha = 1;
}
Rep(const Rep& t) : ref_cnt(1), blend(t.blend), max_tex(t.max_tex), rs(t.rs), blend_valid(t.blend_valid)
{
for (int k = 0; k < max_tex; ++k)
texs[k] = t.texs[k];
}
void* operator new(size_t sz)
{
static const int GROW = 64;
if (!pool) {
pool = new Rep[GROW];
for (int k = 0; k < GROW - 1; ++k)
pool[k].next = &pool[k + 1];
pool[GROW - 1].next = 0;
}
Rep* p = pool;
pool = p->next;
return p;
}
void operator delete(void* q)
{
Rep* p = (Rep*)q;
p->next = pool;
pool = p;
}
};
Brush::Rep* Brush::Rep::pool;
Brush::Brush() : rep(new Rep()) {}
Brush::Brush(const Brush& t) : rep(t.rep)
{
++rep->ref_cnt;
}
Brush::Brush(const Brush& a, const Brush& b) : rep(new Rep(*a.rep))
{
*(Vector*)rep->rs.color *= *(Vector*)b.rep->rs.color;
rep->rs.alpha *= b.rep->rs.alpha;
rep->rs.shininess += b.rep->rs.shininess;
if (b.rep->blend)
rep->blend = b.rep->blend;
rep->rs.fx |= b.rep->rs.fx;
if (b.rep->max_tex > rep->max_tex)
rep->max_tex = b.rep->max_tex;
for (int k = 0; k < rep->max_tex; ++k) {
if (b.rep->rs.tex_states[k].canvas) {
rep->rs.tex_states[k].canvas = b.rep->rs.tex_states[k].canvas;
rep->texs[k] = b.rep->texs[k];
}
}
rep->blend_valid = false;
}
Brush::~Brush()
{
if (!--rep->ref_cnt)
delete rep;
}
Brush& Brush::operator=(const Brush& t)
{
++t.rep->ref_cnt;
if (!--rep->ref_cnt)
delete rep;
rep = t.rep;
return *this;
}
Brush::Rep* Brush::write() const
{
if (rep->ref_cnt > 1) {
--rep->ref_cnt;
rep = new Rep(*rep);
}
return rep;
}
void Brush::setColor(const Vector& color)
{
*(Vector*)write()->rs.color = color;
}
void Brush::setAlpha(float alpha)
{
float a = rep->rs.alpha;
write()->rs.alpha = alpha;
if ((a < 1) != (alpha < 1))
rep->blend_valid = false;
}
void Brush::setShininess(float n)
{
write()->rs.shininess = n;
}
void Brush::setBlend(int blend)
{
write()->blend = blend;
rep->blend_valid = false;
}
void Brush::setFX(int fx)
{
write()->rs.fx = fx;
rep->blend_valid = false;
}
void Brush::setTexture(int index, const Texture& t, int n)
{
write();
gxScene::RenderState& rs = rep->rs;
rep->texs[index] = t;
rs.tex_states[index].canvas = t.getCanvas(n);
rep->max_tex = 0;
for (int k = 0; k < gxScene::MAX_TEXTURES; ++k) {
if (rs.tex_states[k].canvas)
rep->max_tex = k + 1;
}
rep->blend_valid = false;
}
const Vector& Brush::getColor() const
{
return *(Vector*)rep->rs.color;
}
float Brush::getAlpha() const
{
return rep->rs.alpha;
}
float Brush::getShininess() const
{
return rep->rs.shininess;
}
int Brush::getBlend() const
{
if (rep->blend_valid)
return rep->rs.blend;
rep->blend_valid = true; //well, it will be...
gxScene::RenderState& rs = rep->rs;
//alphatest
if (rep->texs[0].getCanvasFlags() & gxCanvas::CANVAS_TEX_MASK) {
rs.fx |= gxScene::FX_ALPHATEST;
} else {
rs.fx &= ~gxScene::FX_ALPHATEST;
}
//0 = default/replace
//1 = alpha
//2 = multiply
//3 = add
if (rep->blend) {
if (rep->blend != gxScene::BLEND_ALPHA) {
return rs.blend = rep->blend;
}
for (int k = 0; k < rep->max_tex; ++k) {
if (rep->texs[k].isTransparent()) {
return rs.blend = gxScene::BLEND_ALPHA;
}
}
} else if (rep->max_tex == 1 && rep->texs[0].isTransparent()) {
//single transparent texture?
return rs.blend = gxScene::BLEND_ALPHA;
}
//vertex alpha or entityalpha?
if ((rs.fx & gxScene::FX_VERTEXALPHA) || rs.alpha < 1) {
return rs.blend = gxScene::BLEND_ALPHA;
}
return rs.blend = gxScene::BLEND_REPLACE;
}
int Brush::getFX() const
{
return rep->rs.fx;
}
Texture Brush::getTexture(int index) const
{
return rep->texs[index];
}
const gxScene::RenderState& Brush::getRenderState() const
{
getBlend();
for (int k = 0; k < rep->max_tex; ++k) {
gxScene::RenderState::TexState* ts = &rep->rs.tex_states[k];
ts->matrix = rep->texs[k].getMatrix();
ts->blend = rep->texs[k].getBlend();
ts->flags = rep->texs[k].getFlags();
}
return rep->rs;
}
bool Brush::operator<(const Brush& t) const
{
return memcmp(&getRenderState(), &t.getRenderState(), sizeof(gxScene::RenderState)) < 0;
}