home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 5164 / miletos.7z / particleemitter.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2011-04-02  |  8.4 KB  |  320 lines

  1. #define __MILETOS_PARTICLE_EMITTER_CPP__
  2.  
  3. //
  4. // Libmiletos
  5. //
  6. // Copyright (C) Lauris Kaplinski 2007
  7. //
  8.  
  9. #include <malloc.h>
  10. #include <stdlib.h>
  11.  
  12. #include <elea/line.h>
  13.  
  14. #include <sehle/engine.h>
  15. #include <sehle/graph.h>
  16. #include <sehle/light.h>
  17. #include <sehle/renderable.h>
  18. #include <sehle/commonmaterials.h>
  19.  
  20. #include "xml/base.h"
  21. #include "sphere.h"
  22.  
  23. #include "particleemitter.h"
  24.  
  25. namespace Miletos {
  26.  
  27. // ParticleEmitter
  28.  
  29. ParticleEmitter::ParticleEmitter (void)
  30. : Item(0), radius(0.25f), numlights(0), lights(NULL), vertices(NULL), nindices(0), indices(NULL),
  31. cutoffDistance(2), constantAttenuation(1), linearAttenuation(0), quadraticAttenuation(64),
  32. maxparticles(100), numparticles(0), coords(NULL), velocities(NULL), ages(NULL), colors(NULL),
  33. lasttime(0), lastcreation(0)
  34. {
  35.     static u32 ival[] = { 0, 1, 2, 0, 2, 3, 1, 0, 4, 1, 4, 5, 2, 1, 5, 2, 5, 6, 3, 2, 6, 3, 6, 7, 0, 3, 7, 0, 7, 4, 5, 4, 7, 5, 7, 6 };
  36.     nindices = 12 * 3;
  37.     if (!indices) indices = (u32 *) malloc (nindices * sizeof (u32));
  38.     memcpy (indices, ival, nindices * sizeof (u32));
  39.  
  40.     coords = (Elea::Vector3f *) malloc (maxparticles * sizeof (Elea::Vector3f));
  41.     memset (coords, 0, maxparticles * sizeof (Elea::Vector3f));
  42.     velocities = (Elea::Vector3f *) malloc (maxparticles * sizeof (Elea::Vector3f));
  43.     memset (velocities, 0, maxparticles * sizeof (Elea::Vector3f));
  44.     ages = (float *) malloc (maxparticles * sizeof (float));
  45.     memset (ages, 0, maxparticles * sizeof (float));
  46.     colors = (Elea::Color4f *) malloc (maxparticles * sizeof (Elea::Color4f));
  47.     memset (colors, 0, maxparticles * sizeof (Elea::Color4f));
  48. }
  49.  
  50. ParticleEmitter::~ParticleEmitter (void)
  51. {
  52.     if (vertices) free (vertices);
  53.     if (indices) free (indices);
  54.     if (coords) free (coords);
  55.     if (velocities) free (velocities);
  56.     if (ages) free (ages);
  57.     if (colors) free (colors);
  58. }
  59.  
  60. static Object *
  61. particleemitter_factory (void)
  62. {
  63.     return new ParticleEmitter();
  64. }
  65.  
  66. const Object::Type *
  67. ParticleEmitter::objectType (void)
  68. {
  69.     return type ();
  70. }
  71.  
  72. const Object::Type *
  73. ParticleEmitter::type (void)
  74. {
  75.     static Type *mytype = NULL;
  76.     if (!mytype) mytype = new Type(Item::type (), "ParticleEmitter", "particleEmitter", particleemitter_factory, 0, NULL);
  77.     return mytype;
  78. }
  79.  
  80. void
  81. ParticleEmitter::build (Thera::Node *pnode, Document *doc, BuildCtx *ctx)
  82. {
  83.     Item::build (pnode, doc, ctx);
  84.  
  85.     document->addTimer (this);
  86. }
  87.  
  88. void
  89. ParticleEmitter::release (void)
  90. {
  91.     document->removeTimer (this);
  92.  
  93.     Item::release ();
  94. }
  95.  
  96. void
  97. ParticleEmitter::set (const char *attrid, const char *val)
  98. {
  99.     Item::set (attrid, val);
  100. }
  101.  
  102. void
  103. ParticleEmitter::write (const char *attrid)
  104. {
  105.     Item::write (attrid);
  106. }
  107.  
  108. void
  109. ParticleEmitter::update (UpdateCtx *ctx, unsigned int flags)
  110. {
  111.     Elea::Cuboid3f q(-radius, -radius, -radius, radius, radius, radius);
  112.     bbox.set (ctx->i2w.transform (q));
  113.  
  114.     Item::update (ctx, flags);
  115.  
  116.     updateVolume ();
  117.     if (lights) updateLights ();
  118. }
  119.  
  120. Sehle::Renderable *
  121. ParticleEmitter::show (Sehle::Graph *graph, Sehle::u32 contextmask)
  122. {
  123.     // Create Sehle light block
  124.     lights = graph->newPointLights (maxparticles, 0);
  125.     numlights = maxparticles;
  126.     updateLights ();
  127.  
  128.     // Create mesh
  129.     Sehle::StaticMesh *mesh = new Sehle::StaticMesh(graph, contextmask);
  130.  
  131.     int nvertices;
  132.     int nindices;
  133.     Sphere::generateMesh (NULL, 0, NULL, 0, NULL, 0, NULL, radius, 3, 1, nvertices, nindices);
  134.     if (!mesh->vbuffer) mesh->vbuffer = mesh->graph->engine->getVertexBuffer (NULL);
  135.     mesh->vbuffer->setUp (nvertices, 8);
  136.     mesh->vbuffer->setOffset (Sehle::VertexBuffer::COORDINATES, 0);
  137.     mesh->vbuffer->setOffset (Sehle::VertexBuffer::NORMALS, 3);
  138.     mesh->vbuffer->setOffset (Sehle::VertexBuffer::TEXCOORDS, 6);
  139.     Sehle::f32 *attributes = mesh->vbuffer->map (Sehle::VertexBuffer::WRITE);
  140.     if (!mesh->ibuffer) mesh->ibuffer = mesh->graph->engine->getIndexBuffer (NULL);
  141.     mesh->ibuffer->resize (nindices);
  142.     Sehle::u32 *indices = mesh->ibuffer->map (Sehle::IndexBuffer::WRITE);
  143.     Sphere::generateMesh (attributes, mesh->vbuffer->stride * sizeof (Sehle::f32),
  144.         attributes + 3, mesh->vbuffer->stride * sizeof (Sehle::f32),
  145.         attributes + 6, mesh->vbuffer->stride * sizeof (Sehle::f32),
  146.         indices, radius, 3, 1, nvertices, nindices);
  147.     mesh->vbuffer->unMap ();
  148.     mesh->ibuffer->unMap ();
  149.  
  150.     mesh->resizeMaterials (1);
  151.     // mesh->setMaterial (0, WireMaterial::newWireMaterial (engine, NULL));
  152.     mesh->setMaterial (0, Sehle::ColorMaterial::newColorMaterial (mesh->graph->engine, NULL));
  153.     mesh->resizeFragments (1);
  154.     mesh->frags[0].first = 0;
  155.     mesh->frags[0].nindices = nindices;
  156.     mesh->frags[0].matidx = 0;
  157.  
  158.     return mesh;
  159. }
  160.  
  161. void
  162. ParticleEmitter::hide (Sehle::RenderableGroup *pgroup)
  163. {
  164.     numlights = 0;
  165.     graph->deletePointLights ((Sehle::PointLight *) lights);
  166.     lights = NULL;
  167.  
  168.     Item::hide (pgroup);
  169. }
  170.  
  171. Item *
  172. ParticleEmitter::trace (const Elea::Line3f *wray, unsigned int mask, float *distance)
  173. {
  174.     Elea::Cuboid3f bbox(-radius, -radius, -radius, radius, radius, radius);
  175.     Elea::Line3f rl = _w2i.transform (*wray);
  176.  
  177.     // i2w.transformInPlace (bbox);
  178.     float p0, p1;
  179.     if (bbox.getIntersection (rl, p0, p1) && (p0 > 0)) {
  180.         *distance = p0;
  181.         return this;
  182.     }
  183.  
  184.     return NULL;
  185. }
  186.  
  187. void
  188. ParticleEmitter::updateLights (void)
  189. {
  190.     if (!graph) return;
  191.     if (numlights != maxparticles) {
  192.         if (numlights) {
  193.             graph->deletePointLights ((Sehle::PointLight *) lights);
  194.             lights = NULL;
  195.         }
  196.         if (maxparticles) {
  197.             lights = graph->newPointLights (maxparticles, 0);
  198.         }
  199.         numlights = maxparticles;
  200.     }
  201.     for (u32 i = 0; i < numparticles; i++) {
  202.         Sehle::PointLight *point = (Sehle::PointLight *) &lights[i];
  203.         point->highlightmask = Miletos::Item::OPAQUE | TRANSPARENT;
  204.         point->hasshadow = 0;
  205.         point->hasdensity = 0;
  206.         point->ambient = Elea::Color4fBlack;
  207.         float intensity = pow (1 / (1 + exp (ages[i] - 8)), 8);
  208.         point->diffuse = Elea::Color4f(intensity * colors[i][0], intensity * colors[i][1], intensity * colors[i][2], 1);
  209.         point->direct = Elea::Color4fBlack;
  210.         point->vertices = vertices;
  211.         point->nindices = nindices;
  212.         point->indices = indices;
  213.         // fixme: Use parameter for bound/free particles
  214.         point->l2w = Elea::Matrix4x4f::translation (coords[i]);
  215.         point->constantAttenuation = constantAttenuation;
  216.         point->linearAttenuation = linearAttenuation;
  217.         point->quadraticAttenuation = quadraticAttenuation;
  218.     }
  219. }
  220.  
  221. void
  222. ParticleEmitter::updateVolume (void)
  223. {
  224.     float maxdist = cutoffDistance;
  225.     // maxdist = 20;
  226.     if ((quadraticAttenuation >= 0) && ((linearAttenuation > 0) || (quadraticAttenuation > 0))) {
  227.         // Find distance where I1 == 0.001
  228.         // constAtt + linAtt * d + quadAtt * d * d = 1000
  229.         double a = quadraticAttenuation;
  230.         double b = linearAttenuation;
  231.         double c = constantAttenuation - 1000;
  232.         double q = b * b - 4 * a * c;
  233.         if (q >= 0) {
  234.             double distance = (-b + sqrt (q)) / (2 * a);
  235.             if (distance < maxdist) maxdist = (float) distance;
  236.         }
  237.     }
  238.     float l = maxdist;
  239.  
  240.     if (!vertices) vertices = (Elea::Vector3f *) malloc (8 * sizeof (Elea::Vector3f));
  241.     vertices[0].set (-l, -l, -l);
  242.     vertices[1].set (l, -l, -l);
  243.     vertices[2].set (l, l, -l);
  244.     vertices[3].set (-l, l, -l);
  245.     vertices[4].set (-l, -l, l);
  246.     vertices[5].set (l, -l, l);
  247.     vertices[6].set (l, l, l);
  248.     vertices[7].set (-l, l, l);
  249. }
  250.  
  251. void
  252. ParticleEmitter::start (double time)
  253. {
  254.     lasttime = time;
  255.     numlights = 0;
  256.     updateLights ();
  257. }
  258.  
  259. void
  260. ParticleEmitter::timeStep (double time)
  261. {
  262.     // fixme:
  263.     if (!lasttime) {
  264.         lasttime = time;
  265.         lastcreation = time;
  266.         return;
  267.     }
  268.     u32 i = 0;
  269.     float dtime = (float) (time - lasttime);
  270.     while (i < numparticles) {
  271.         if ((ages[i] + dtime) > 10) {
  272.             // Retire
  273.             coords[i] = coords[numparticles - 1];
  274.             velocities[i] = velocities[numparticles - 1];
  275.             ages[i] = ages[numparticles - 1];
  276.             numparticles -= 1;
  277.         } else {
  278.             coords[i] = coords[i] + dtime * velocities[i];
  279.             ages[i] += dtime;
  280.             i += 1;
  281.         }
  282.     }
  283.     float dcreation = (float) (time - lastcreation);
  284.     for (float c = 0.2f; c < dcreation; c += 0.2f) {
  285.         if (numparticles >= maxparticles) break;
  286.         coords[numparticles] = _i2w.getTranslation ();
  287.         float x = (float) ((double) rand () / RAND_MAX) - 0.5f;
  288.         float y = (float) ((double) rand () / RAND_MAX) - 0.5f;
  289.         // float z = (float) ((double) rand () / RAND_MAX);
  290.         x = x * 4;
  291.         y = y * 4;
  292.         velocities[numparticles] = Elea::Vector3f(x, y, 0);
  293.         ages[numparticles] = 0;
  294.         float r = (float) ((double) rand () / RAND_MAX);
  295.         float g = (float) ((double) rand () / RAND_MAX);
  296.         float b = (float) ((double) rand () / RAND_MAX);
  297.         float max = r;
  298.         if (g > max) max = g;
  299.         if (b > max) max = b;
  300.         r = r * 10 / max;
  301.         g = g * 10 / max;
  302.         b = b * 10 / max;
  303.         colors[numparticles] = Elea::Color4f(r, g, b, 1);
  304.  
  305.         numparticles += 1;
  306.         lastcreation = time;
  307.     }
  308.     lasttime = time;
  309.     updateLights ();
  310. }
  311.  
  312. void
  313. ParticleEmitter::stop (double time)
  314. {
  315.     numlights = 0;
  316.     updateLights ();
  317. }
  318.  
  319. } // Namespace Miletos
  320.