#include "std.hpp" #include "brush.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;knext; 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;kmax_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;kmax_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;kmax_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;kmax_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; }