#include #include #include #include #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; }