Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/intern/draw_cache_impl_particles.c')
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c348
1 files changed, 348 insertions, 0 deletions
diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c
new file mode 100644
index 00000000000..f4b16f1873a
--- /dev/null
+++ b/source/blender/draw/intern/draw_cache_impl_particles.c
@@ -0,0 +1,348 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2017 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file draw_cache_impl_particles.c
+ * \ingroup draw
+ *
+ * \brief Particle API for render engines
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_math_vector.h"
+
+#include "DNA_particle_types.h"
+
+#include "BKE_particle.h"
+
+#include "GPU_batch.h"
+
+#include "draw_cache_impl.h" /* own include */
+
+static void particle_batch_cache_clear(ParticleSystem *psys);
+
+/* ---------------------------------------------------------------------- */
+/* Particle Batch Cache */
+
+typedef struct ParticleBatchCache {
+ VertexBuffer *pos;
+ ElementList *segments;
+
+ Batch *hairs;
+
+ int segment_count;
+ int point_count;
+
+ /* settings to determine if cache is invalid */
+ bool is_dirty;
+} ParticleBatchCache;
+
+/* Batch cache management. */
+
+static bool particle_batch_cache_valid(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = psys->batch_cache;
+
+ if (cache == NULL) {
+ return false;
+ }
+
+ if (cache->is_dirty == false) {
+ return true;
+ }
+ else {
+ return false;
+ }
+
+ return true;
+}
+
+static void particle_batch_cache_init(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = psys->batch_cache;
+
+ if (!cache) {
+ cache = psys->batch_cache = MEM_callocN(sizeof(*cache), __func__);
+ }
+ else {
+ memset(cache, 0, sizeof(*cache));
+ }
+
+ cache->is_dirty = false;
+}
+
+static ParticleBatchCache *particle_batch_cache_get(ParticleSystem *psys)
+{
+ if (!particle_batch_cache_valid(psys)) {
+ particle_batch_cache_clear(psys);
+ particle_batch_cache_init(psys);
+ }
+ return psys->batch_cache;
+}
+
+void DRW_particle_batch_cache_dirty(ParticleSystem *psys, int mode)
+{
+ ParticleBatchCache *cache = psys->batch_cache;
+ if (cache == NULL) {
+ return;
+ }
+ switch (mode) {
+ case BKE_PARTICLE_BATCH_DIRTY_ALL:
+ cache->is_dirty = true;
+ break;
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void particle_batch_cache_clear(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = psys->batch_cache;
+ if (!cache) {
+ return;
+ }
+
+ BATCH_DISCARD_SAFE(cache->hairs);
+
+ VERTEXBUFFER_DISCARD_SAFE(cache->pos);
+ ELEMENTLIST_DISCARD_SAFE(cache->segments);
+}
+
+void DRW_particle_batch_cache_free(ParticleSystem *psys)
+{
+ particle_batch_cache_clear(psys);
+ MEM_SAFE_FREE(psys->batch_cache);
+}
+
+static void ensure_seg_pt_count(ParticleSystem *psys, ParticleBatchCache *cache)
+{
+ if (cache->pos == NULL || cache->segments == NULL) {
+ cache->segment_count = 0;
+ cache->point_count = 0;
+
+ if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
+ for (int i = 0; i < psys->totpart; i++) {
+ ParticleCacheKey *path = psys->pathcache[i];
+
+ if (path->segments > 0) {
+ cache->segment_count += path->segments;
+ cache->point_count += path->segments + 1;
+ }
+ }
+ }
+
+ if (psys->childcache) {
+ int child_count = psys->totchild * psys->part->disp / 100;
+
+ for (int i = 0; i < child_count; i++) {
+ ParticleCacheKey *path = psys->childcache[i];
+
+ if (path->segments > 0) {
+ cache->segment_count += path->segments;
+ cache->point_count += path->segments + 1;
+ }
+ }
+ }
+ }
+}
+
+/* Batch cache usage. */
+static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, ParticleBatchCache *cache)
+{
+ if (cache->pos == NULL || cache->segments == NULL) {
+ int curr_point = 0;
+
+ VERTEXBUFFER_DISCARD_SAFE(cache->pos);
+ ELEMENTLIST_DISCARD_SAFE(cache->segments);
+
+ static VertexFormat format = { 0 };
+ static struct { uint pos, tan, ind; } attr_id;
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ attr_id.pos = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT);
+ attr_id.tan = VertexFormat_add_attrib(&format, "tang", COMP_F32, 3, KEEP_FLOAT);
+ attr_id.ind = VertexFormat_add_attrib(&format, "ind", COMP_I32, 1, KEEP_INT);
+ }
+
+ cache->pos = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(cache->pos, cache->point_count);
+
+ ElementListBuilder elb;
+ ElementListBuilder_init(&elb, PRIM_LINES, cache->segment_count, cache->point_count);
+
+ if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) {
+ for (int i = 0; i < psys->totpart; i++) {
+ ParticleCacheKey *path = psys->pathcache[i];
+
+ if (path->segments > 0) {
+ float tangent[3];
+
+ for (int j = 0; j < path->segments; j++) {
+ if (j == 0) {
+ sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
+ }
+ else {
+ sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co);
+ }
+
+ VertexBuffer_set_attrib(cache->pos, attr_id.pos, curr_point, path[j].co);
+ VertexBuffer_set_attrib(cache->pos, attr_id.tan, curr_point, tangent);
+ VertexBuffer_set_attrib(cache->pos, attr_id.ind, curr_point, &i);
+
+ add_line_vertices(&elb, curr_point, curr_point + 1);
+
+ curr_point++;
+ }
+
+ sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
+
+ VertexBuffer_set_attrib(cache->pos, attr_id.pos, curr_point, path[path->segments].co);
+ VertexBuffer_set_attrib(cache->pos, attr_id.tan, curr_point, tangent);
+ VertexBuffer_set_attrib(cache->pos, attr_id.ind, curr_point, &i);
+
+ curr_point++;
+ }
+ }
+ }
+
+ if (psys->childcache) {
+ int child_count = psys->totchild * psys->part->disp / 100;
+
+ for (int i = 0, x = psys->totpart; i < child_count; i++, x++) {
+ ParticleCacheKey *path = psys->childcache[i];
+ float tangent[3];
+
+ if (path->segments > 0) {
+ for (int j = 0; j < path->segments; j++) {
+ if (j == 0) {
+ sub_v3_v3v3(tangent, path[j + 1].co, path[j].co);
+ }
+ else {
+ sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co);
+ }
+
+ VertexBuffer_set_attrib(cache->pos, attr_id.pos, curr_point, path[j].co);
+ VertexBuffer_set_attrib(cache->pos, attr_id.tan, curr_point, tangent);
+ VertexBuffer_set_attrib(cache->pos, attr_id.ind, curr_point, &x);
+
+ add_line_vertices(&elb, curr_point, curr_point + 1);
+
+ curr_point++;
+ }
+
+ sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co);
+
+ VertexBuffer_set_attrib(cache->pos, attr_id.pos, curr_point, path[path->segments].co);
+ VertexBuffer_set_attrib(cache->pos, attr_id.tan, curr_point, tangent);
+ VertexBuffer_set_attrib(cache->pos, attr_id.ind, curr_point, &x);
+
+ curr_point++;
+ }
+ }
+ }
+
+ cache->segments = ElementList_build(&elb);
+ }
+}
+
+static void particle_batch_cache_ensure_pos(ParticleSystem *psys, ParticleBatchCache *cache)
+{
+ if (cache->pos == NULL) {
+ static VertexFormat format = { 0 };
+ static unsigned pos_id, rot_id, val_id;
+ int i, curr_point;
+ ParticleData *pa;
+
+ VERTEXBUFFER_DISCARD_SAFE(cache->pos);
+ ELEMENTLIST_DISCARD_SAFE(cache->segments);
+
+ if (format.attrib_ct == 0) {
+ /* initialize vertex format */
+ pos_id = VertexFormat_add_attrib(&format, "pos", COMP_F32, 3, KEEP_FLOAT);
+ rot_id = VertexFormat_add_attrib(&format, "rot", COMP_F32, 4, KEEP_FLOAT);
+ val_id = VertexFormat_add_attrib(&format, "val", COMP_F32, 1, KEEP_FLOAT);
+ }
+
+ cache->pos = VertexBuffer_create_with_format(&format);
+ VertexBuffer_allocate_data(cache->pos, psys->totpart);
+
+ for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) {
+ if (pa->state.time >= pa->time && pa->state.time < pa->dietime &&
+ !(pa->flag & (PARS_NO_DISP | PARS_UNEXIST)))
+ {
+ float val;
+
+ VertexBuffer_set_attrib(cache->pos, pos_id, curr_point, pa->state.co);
+ VertexBuffer_set_attrib(cache->pos, rot_id, curr_point, pa->state.rot);
+
+ switch (psys->part->draw_col) {
+ case PART_DRAW_COL_VEL:
+ val = len_v3(pa->state.vel) / psys->part->color_vec_max;
+ break;
+ case PART_DRAW_COL_ACC:
+ val = len_v3v3(pa->state.vel, pa->prev_state.vel) / ((pa->state.time - pa->prev_state.time) * psys->part->color_vec_max);
+ break;
+ default:
+ val = -1.0f;
+ break;
+ }
+
+ VertexBuffer_set_attrib(cache->pos, val_id, curr_point, &val);
+
+ curr_point++;
+ }
+ }
+
+ if (curr_point != psys->totpart) {
+ VertexBuffer_resize_data(cache->pos, curr_point);
+ }
+ }
+}
+
+Batch *DRW_particles_batch_cache_get_hair(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = particle_batch_cache_get(psys);
+
+ if (cache->hairs == NULL) {
+ ensure_seg_pt_count(psys, cache);
+ particle_batch_cache_ensure_pos_and_seg(psys, cache);
+ cache->hairs = Batch_create(PRIM_LINES, cache->pos, cache->segments);
+ }
+
+ return cache->hairs;
+}
+
+Batch *DRW_particles_batch_cache_get_dots(ParticleSystem *psys)
+{
+ ParticleBatchCache *cache = particle_batch_cache_get(psys);
+
+ if (cache->hairs == NULL) {
+ particle_batch_cache_ensure_pos(psys, cache);
+ cache->hairs = Batch_create(PRIM_POINTS, cache->pos, NULL);
+ }
+
+ return cache->hairs;
+}