aboutsummaryrefslogblamecommitdiff
path: root/visualization/extrasmeltutils.cpp
blob: ec9f021f6d271150abba79c597f97194817fd627 (plain) (tree)
1
2
3
4
5
                 
                  
                    
                      
                              


































                                                                               
 

                                            


                                         


                                       


                                        
 
                                                  
 

                                         
 
                                             
 

                                        

 




















                                                                                        
 
                                    
 


                                        
 
                                                                                      
 










                                                                                                                                  
 

                                  




                                                                                                                     
 
                        








                                        
                         


                         

                         










































                                                                                
 
                                    





                                        
                                     




                                                   
                                                                          






                                           
                                                                               











                                              
                                




                              
                               


                   
                                 
 




































































                                                                                                                                            
 
                                 



                                                   

                  


                                  


                          







                                                                                    


                          













                                             



                             













                                    

                           


             
                         


             
                           


             
                          


             
                         


             
                                


             

                                   



                                               

                           


             
                               


                         

                                   


              

                               




                              


                                   




                                


                                 




                               


                               




                              


                                             




                                     


                                                










                                      


                                   




                                


                                           










                                    


                                    



                                        


                                   



                                                        



                             
                                                    


                                            






                                 
 
#include <cstdio>
#include <cstdarg>
#include <algorithm>
#include <smcolor.hpp>
#include "extrasmeltutils.hpp"
SMELT *smEntity3DBuffer::sm = nullptr;
SMELT *smParticle::sm = nullptr;
SMELT *smParticleSystem::sm = nullptr;
smVertex makeVertex(float x, float y, float z, DWORD color, float tx, float ty)
{
    smVertex v;
    v.x = x;
    v.y = y;
    v.z = z;
    v.col = color;
    v.tx = tx;
    v.ty = ty;
    return v;
}
void smEntity3D::addVertices(size_t n, ...)
{
    va_list vl;
    va_start(vl, n);
    for (int i = 0; i < n; ++i)
    {
        smVertex v = va_arg(vl, smVertex);
        vertices.push_back(v);
    }
    va_end(vl);
}
void smEntity3D::addIndices(size_t n, ...)
{
    va_list vl;
    va_start(vl, n);
    for (int i = 0; i < n; ++i)
    {
        int idx = va_arg(vl, int);
        indices.push_back((WORD)idx);
    }
    va_end(vl);
}
smVertex smEntity3D::vertex(size_t idx)const
{
    if (idx > 0 && idx < vertices.size())
        return vertices[idx];
    return smVertex();
}
WORD smEntity3D::index(size_t idx)const
{
    if (idx > 0 && idx < indices.size())
        return indices[idx];
    return 0;
}
void smEntity3D::setVertex(size_t idx, smVertex v)
{
    if (idx > 0 && idx < vertices.size())
        vertices[idx] = v;
}
void smEntity3D::setIndex(size_t idx, WORD i)
{
    if (idx > 0 && idx < indices.size())
        indices[idx] = i;
}

smEntity3D smEntity3D::cube(smvec3d a, smvec3d b, DWORD color, int faces)
{
    smEntity3D ret;
    ret.addVertices(8,
        makeVertex(a.x, a.y, a.z, color, 0, 0), makeVertex(b.x, a.y, a.z, color, 0, 0),
        makeVertex(b.x, b.y, a.z, color, 0, 0), makeVertex(a.x, b.y, a.z, color, 0, 0),
        makeVertex(a.x, a.y, b.z, color, 0, 0), makeVertex(b.x, a.y, b.z, color, 0, 0),
        makeVertex(b.x, b.y, b.z, color, 0, 0), makeVertex(a.x, b.y, b.z, color, 0, 0));
    if (faces & 0x1) //a.z
        ret.addIndices(6, 0, 1, 3, 1, 2, 3);
    if (faces & 0x2) //b.z
        ret.addIndices(6, 4, 5, 7, 5, 6, 7);
    if (faces & 0x4) //a.x
        ret.addIndices(6, 0, 3, 7, 0, 4, 7);
    if (faces & 0x8) //b.x
        ret.addIndices(6, 1, 2, 6, 1, 5, 6);
    if (faces & 0x10) //a.y
        ret.addIndices(6, 0, 1, 4, 1, 4, 5);
    if (faces & 0x20) //b.y
        ret.addIndices(6, 2, 3, 7, 2, 6, 7);
    return ret;
}
smEntity3DBuffer::smEntity3DBuffer()
{
    sm = smGetInterface(SMELT_APILEVEL);
    vertices.clear();
    indices.clear();
}
void smEntity3DBuffer::addTransformedEntity(smEntity3D *entity, smMatrix t, smvec3d p)
{
    if (entity->vertices.size() + vertices.size() > 4000)
        drawBatch();
    for (unsigned i = 0; i < entity->indices.size(); ++i)
        indices.push_back(entity->indices[i] + vertices.size());
    for (unsigned i = 0; i < entity->vertices.size(); ++i)
    {
        smvec3d tp = smvec3d(entity->vertices[i].x, entity->vertices[i].y, entity->vertices[i].z);
        tp = t * tp;
        tp = tp + p;
        vertices.push_back(makeVertex(tp.x, tp.y, tp.z, entity->vertices[i].col, entity->vertices[i].tx, entity->vertices[i].ty));
    }
}
void smEntity3DBuffer::drawBatch()
{
    if (!vertices.size())
        return;
    sm->smDrawCustomIndexedVertices(&vertices[0], &indices[0], vertices.size(), indices.size(), BLEND_ALPHABLEND, 0);
    vertices.clear();
    indices.clear();
}
smParticle::smParticle()
{
    sm = smGetInterface(SMELT_APILEVEL);
    dead = false;
    clifespan = 0;
}
smParticle::~smParticle()
{
    sm->smRelease();
}
void smParticle::render()
{
    sm->smRenderQuad(&q);
}
void smParticle::update()
{
    clifespan += sm->smGetDelta();
    if (clifespan > lifespan)
    {
        dead = true;
        return;
    }
    vel = vel + accel;
    pos = pos + vel;
    rotv = rotv + rota;
    rot = rot + rotv;
    size = clifespan / lifespan * (finalsize - initsize) + initsize;
    smColorRGBA fc(finalcolor), ic(initcolor), cc;
    cc.a = clifespan / lifespan * (fc.a - ic.a) + ic.a;
    cc.r = clifespan / lifespan * (fc.r - ic.r) + ic.r;
    cc.g = clifespan / lifespan * (fc.g - ic.g) + ic.g;
    cc.b = clifespan / lifespan * (fc.b - ic.b) + ic.b;
    color = cc.getHWColor();
    for (int i = 0; i < 4; ++i)
        q.v[i].col = color;
    smMatrix m;
    m.loadIdentity();
    if (lookat)
        m.lookat(pos, lookatpos, smvec3d(0, 0, 1));
    else
    {
        m.rotate(rot.x, 1, 0, 0);
        m.rotate(rot.y, 0, 1, 0);
        m.rotate(rot.z, 0, 0, 1);
    }
    smvec3d v0 = m * smvec3d(-size, -size, 0), v1 = m * smvec3d(size, -size, 0);
    smvec3d v2 = m * smvec3d(size, size, 0), v3 = m * smvec3d(-size, size, 0);
    q.v[0].x = v0.x + pos.x;
    q.v[0].y = v0.y + pos.y;
    q.v[0].z = v0.z + pos.z;
    q.v[1].x = v1.x + pos.x;
    q.v[1].y = v1.y + pos.y;
    q.v[1].z = v1.z + pos.z;
    q.v[2].x = v2.x + pos.x;
    q.v[2].y = v2.y + pos.y;
    q.v[2].z = v2.z + pos.z;
    q.v[3].x = v3.x + pos.x;
    q.v[3].y = v3.y + pos.y;
    q.v[3].z = v3.z + pos.z;
}
smParticleSystem::smParticleSystem()
{
    sm = smGetInterface(SMELT_APILEVEL);
    particles.clear();
    posGenerator = nullptr;
    active = false;
}
smParticleSystem::~smParticleSystem()
{
    for (unsigned i = 0; i < particles.size(); ++i)
        delete particles[i];
    particles.clear();
}
void smParticleSystem::setParticleSystemInfo(smParticleSystemInfo _psinfo)
{
    psinfo = _psinfo;
}
void smParticleSystem::setPos(smvec3d _pos)
{
    pos = _pos;
}
void smParticleSystem::setPSEmissionPosGen(smPSEmissionPositionGenerator *_gen)
{
    posGenerator = _gen;
}
void smParticleSystem::setPSLookAt(smvec3d at)
{
    lookat = true;
    lookatpos = at;
}
void smParticleSystem::unsetPSLookAt()
{
    lookat = false;
}
void smParticleSystem::startPS()
{
    active = true;
    nemdelay = 0;
    re.setSeed(time(nullptr));
}
void smParticleSystem::stopPS()
{
    active = false;
}
void smParticleSystem::updatePS()
{
    cemdelay += sm->smGetDelta();
    if (active && cemdelay > nemdelay && (int)particles.size() < psinfo.maxcount)
    {
        int ec = re.nextInt(psinfo.emissioncount - psinfo.ecvar, psinfo.emissioncount + psinfo.ecvar);
        for (int i = 0; i < ec; ++i)
        {
            smParticle *p = new smParticle();
            p->pos = pos + (posGenerator ? posGenerator->genPos() : smvec3d(0, 0, 0));
            p->vel = smvec3d(
                    re.nextDouble(psinfo.vel.x - psinfo.velvar.x, psinfo.vel.x + psinfo.velvar.x),
                    re.nextDouble(psinfo.vel.y - psinfo.velvar.y, psinfo.vel.y + psinfo.velvar.y),
                    re.nextDouble(psinfo.vel.z - psinfo.velvar.z, psinfo.vel.z + psinfo.velvar.z));
            p->accel = smvec3d(
                    re.nextDouble(psinfo.acc.x - psinfo.accvar.x, psinfo.acc.x + psinfo.accvar.x),
                    re.nextDouble(psinfo.acc.y - psinfo.accvar.y, psinfo.acc.y + psinfo.accvar.y),
                    re.nextDouble(psinfo.acc.z - psinfo.accvar.z, psinfo.acc.z + psinfo.accvar.z));
            p->rotv = smvec3d(
                    re.nextDouble(psinfo.rotv.x - psinfo.rotvvar.x, psinfo.rotv.x + psinfo.rotvvar.x),
                    re.nextDouble(psinfo.rotv.y - psinfo.rotvvar.y, psinfo.rotv.y + psinfo.rotvvar.y),
                    re.nextDouble(psinfo.rotv.z - psinfo.rotvvar.z, psinfo.rotv.z + psinfo.rotvvar.z));
            p->rota = smvec3d(
                    re.nextDouble(psinfo.rota.x - psinfo.rotavar.x, psinfo.rota.x + psinfo.rotavar.x),
                    re.nextDouble(psinfo.rota.y - psinfo.rotavar.y, psinfo.rota.y + psinfo.rotavar.y),
                    re.nextDouble(psinfo.rota.z - psinfo.rotavar.z, psinfo.rota.z + psinfo.rotavar.z));
            p->rot = smvec3d(0, 0, 0);
            if (lookat)
                p->lookat = true, p->lookatpos = lookatpos;
            else p->lookat = false;
            p->lifespan = re.nextDouble(psinfo.lifespan - psinfo.lifespanvar, psinfo.lifespan + psinfo.lifespanvar);
            p->initsize = re.nextDouble(psinfo.initsize - psinfo.initsizevar, psinfo.initsize + psinfo.initsizevar);
            p->finalsize = re.nextDouble(psinfo.finalsize - psinfo.finalsizevar, psinfo.finalsize + psinfo.finalsizevar);
            p->size = p->initsize;
            p->initcolor = ARGB(
                    re.nextInt(GETA(psinfo.initcolor) - GETA(psinfo.initcolorvar), GETA(psinfo.initcolor) + GETA(psinfo.initcolorvar)),
                    re.nextInt(GETR(psinfo.initcolor) - GETR(psinfo.initcolorvar), GETR(psinfo.initcolor) + GETR(psinfo.initcolorvar)),
                    re.nextInt(GETG(psinfo.initcolor) - GETG(psinfo.initcolorvar), GETG(psinfo.initcolor) + GETG(psinfo.initcolorvar)),
                    re.nextInt(GETB(psinfo.initcolor) - GETB(psinfo.initcolorvar), GETB(psinfo.initcolor) + GETB(psinfo.initcolorvar)));
            p->finalcolor = ARGB(
                    re.nextInt(GETA(psinfo.finalcolor) - GETA(psinfo.finalcolorvar), GETA(psinfo.finalcolor) + GETA(psinfo.finalcolorvar)),
                    re.nextInt(GETR(psinfo.finalcolor) - GETR(psinfo.finalcolorvar), GETR(psinfo.finalcolor) + GETR(psinfo.finalcolorvar)),
                    re.nextInt(GETG(psinfo.finalcolor) - GETG(psinfo.finalcolorvar), GETG(psinfo.finalcolor) + GETG(psinfo.finalcolorvar)),
                    re.nextInt(GETB(psinfo.finalcolor) - GETB(psinfo.finalcolorvar), GETB(psinfo.finalcolor) + GETB(psinfo.finalcolorvar)));
            p->color = p->initcolor;
            p->q.tex = psinfo.texture;
            p->q.blend = psinfo.blend;
            p->q.v[0].tx = p->q.v[3].tx = 0;
            p->q.v[0].ty = p->q.v[1].ty = 0;
            p->q.v[1].tx = p->q.v[2].tx = 1;
            p->q.v[2].ty = p->q.v[3].ty = 1;
            particles.push_back(p);
        }
        cemdelay = 0;
        nemdelay = re.nextDouble(psinfo.emissiondelay - psinfo.edvar, psinfo.emissiondelay + psinfo.edvar);
    }
    for (unsigned i = 0, j; i < particles.size() && !particles[i]->dead; ++i)
    {
        particles[i]->update();
        if (particles[i]->dead)
        {
            for (j = particles.size() - 1; j > i && particles[j]->dead; --j);
            std::swap(particles[i], particles[j]);
        }
    }
    while (!particles.empty() && particles.back()->dead)
    {
        delete particles.back();
        particles.back() = nullptr;
        particles.pop_back();
    }
}
void smParticleSystem::renderPS()
{
    for (unsigned i = 0; i < particles.size(); ++i)
        particles[i]->render();
}

smColor::smColor()
{
    r = g = b = h = s = v = a = 0;
}

void smColor::update_rgb()
{
    auto f = [this](float n)
    {
        float k = fmodf(n + 6.0f * this->h, 6.0f);
        return this->v - this->v * this->s * max(0.0f, min(1.0f, min(k, 4.0f - k)));
    };
    r = f(5);
    g = f(3);
    b = f(1);
}
void smColor::update_hsv()
{
    v = max(r, max(g, b));
    float vm = min(r, min(g, b));
    float chroma = v - vm;
    if (v - vm < EPSF)
        h = 0;
    else if (v - r < EPSF)
        h = (0.0f + (g - b) / chroma) / 6.0f;
    else if (v - g < EPSF)
        h = (2.0f + (b - r) / chroma) / 6.0f;
    else if (v - b < EPSF)
        h = (4.0f + (r - g) / chroma) / 6.0f;
    if (v < EPSF)
        s = 0;
    else s = chroma / v;
}

void smColor::clamp(bool hsv)
{
    if (hsv)
    {
        h = min(1.0f, max(0.0f, h));
        s = min(1.0f, max(0.0f, s));
        v = min(1.0f, max(0.0f, v));
        update_rgb();
    }
    else
    {
        r = min(1.0f, max(0.0f, r));
        g = min(1.0f, max(0.0f, g));
        b = min(1.0f, max(0.0f, b));
        update_hsv();
    }
}
float smColor::alpha()const
{
    return a;
}
float smColor::red()const
{
    return r;
}
float smColor::green()const
{
    return g;
}
float smColor::blue()const
{
    return b;
}
float smColor::hue()const
{
    return h;
}
float smColor::saturation()const
{
    return s;
}
float smColor::hslSaturation()const
{
    float l = lightness();
    if (fabsf(l) < EPSF || fabsf(l - 1) < EPSF)
        return 0;
    return (v - l) / min(l, 1 - l);
}
float smColor::value()const
{
    return v;
}
float smColor::lightness()const
{
    return v - v * s / 2;
}

void smColor::setAlpha(float alpha)
{
    a = alpha;
}
void smColor::setRed(float red)
{
    if (fabsf(r - red) > EPSF)
    {
        r = red;
        update_hsv();
    }
}
void smColor::setGreen(float green)
{
    if (fabsf(g - green) > EPSF)
    {
        g = green;
        update_hsv();
    }
}
void smColor::setBlue(float blue)
{
    if (fabsf(b - blue) > EPSF)
    {
        b = blue;
        update_hsv();
    }
}
void smColor::setHue(float hue)
{
    if (fabsf(h - hue) > EPSF)
    {
        h = hue;
        update_rgb();
    }
}
void smColor::setSaturation(float saturation)
{
    if (fabsf(s - saturation) > EPSF)
    {
        s = saturation;
        update_rgb();
    }
}
void smColor::setHSLSaturation(float saturation)
{
    float ss = hslSaturation();
    float l = lightness();
    if (fabsf(ss - saturation) > EPSF)
    {
        ss = saturation;
        v = l + ss * min(l, 1 - l);
        if (v < EPSF)
            s = 0;
        else s = 2 - 2 * l / v;
        update_rgb();
    }
}
void smColor::setValue(float value)
{
    if (fabsf(v - value) > EPSF)
    {
        v = value;
        update_rgb();
    }
}
void smColor::setLightness(float lightness)
{
    float ss = hslSaturation();
    float l = this->lightness();
    if (fabsf(l - lightness) > EPSF)
    {
        l = lightness;
        v = l + ss * min(l, 1 - l);
        if (v < EPSF)
            s = 0;
        else s = 2 - 2 * l / v;
        update_rgb();
    }
}
smColor smColor::lighter(int factor)
{
    smColor ret(*this);
    ret.setValue(v * (factor / 100.0f));
    ret.clamp(true);
    return ret;
}
smColor smColor::darker(int factor)
{
    smColor ret(*this);
    ret.setValue(factor ? (v / (factor / 100.0f)) : 1.);
    ret.clamp(true);
    return ret;
}

uint32_t smColor::toHWColor()
{
    return RGBA(r * 255, g * 255, b * 255, a * 255);
}
smColor smColor::fromHWColor(uint32_t color)
{
    smColor ret;
    ret.r = GETR(color) / 255.0f;
    ret.g = GETG(color) / 255.0f;
    ret.b = GETB(color) / 255.0f;
    ret.a = GETA(color) / 255.0f;
    ret.update_hsv();
    return ret;
}