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/editors/space_view3d/drawstrands.c')
-rw-r--r--source/blender/editors/space_view3d/drawstrands.c520
1 files changed, 520 insertions, 0 deletions
diff --git a/source/blender/editors/space_view3d/drawstrands.c b/source/blender/editors/space_view3d/drawstrands.c
new file mode 100644
index 00000000000..af2e04ee3a7
--- /dev/null
+++ b/source/blender/editors/space_view3d/drawstrands.c
@@ -0,0 +1,520 @@
+/*
+ * ***** 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) 2014 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/drawstrands.c
+ * \ingroup spview3d
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_math.h"
+
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_editstrands.h"
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_strands.h"
+
+#include "bmesh.h"
+
+#include "ED_screen.h"
+#include "ED_types.h"
+
+#include "UI_resources.h"
+#include "UI_interface_icons.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_draw.h"
+#include "GPU_extensions.h"
+#include "GPU_select.h"
+
+#include "view3d_intern.h"
+
+typedef struct StrandsDrawGLState {
+ GLint polygonmode[2];
+} StrandsDrawGLState;
+
+typedef enum StrandsShadeMode {
+ STRANDS_SHADE_FLAT,
+ STRANDS_SHADE_HAIR,
+} StrandsShadeMode;
+
+static void draw_strands_begin(StrandsDrawGLState *state, short dflag)
+{
+ glGetIntegerv(GL_POLYGON_MODE, state->polygonmode);
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ /* setup gl flags */
+ glEnableClientState(GL_NORMAL_ARRAY);
+
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+// if (part->draw_col == PART_DRAW_COL_MAT)
+// glEnableClientState(GL_COLOR_ARRAY);
+ }
+
+ glColor3f(1,1,1);
+ glEnable(GL_LIGHTING);
+// glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+// glEnable(GL_COLOR_MATERIAL);
+}
+
+static void draw_strands_end(StrandsDrawGLState *state)
+{
+ /* restore & clean up */
+// if (part->draw_col == PART_DRAW_COL_MAT)
+// glDisableClientState(GL_COLOR_ARRAY);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+
+ glLineWidth(1.0f);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+
+ glPolygonMode(GL_FRONT, state->polygonmode[0]);
+ glPolygonMode(GL_BACK, state->polygonmode[1]);
+}
+
+static void draw_strand_lines(Strands *strands, short dflag)
+{
+ const bool has_motion_state = strands->state;
+ StrandsDrawGLState gl_state;
+ StrandIterator it_strand;
+
+ draw_strands_begin(&gl_state, dflag);
+
+ for (BKE_strand_iter_init(&it_strand, strands); BKE_strand_iter_valid(&it_strand); BKE_strand_iter_next(&it_strand)) {
+ if (it_strand.tot <= 0)
+ continue;
+
+ if (has_motion_state) {
+ glVertexPointer(3, GL_FLOAT, sizeof(StrandsMotionState), it_strand.state->co);
+ glNormalPointer(GL_FLOAT, sizeof(StrandsMotionState), it_strand.state->nor);
+ }
+ else {
+ glVertexPointer(3, GL_FLOAT, sizeof(StrandsVertex), it_strand.verts->co);
+ glNormalPointer(GL_FLOAT, sizeof(StrandsVertex), it_strand.verts->nor);
+ }
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+// if (part->draw_col == PART_DRAW_COL_MAT) {
+// glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
+// }
+ }
+
+ glDrawArrays(GL_LINE_STRIP, 0, it_strand.curve->numverts);
+ }
+
+ draw_strands_end(&gl_state);
+}
+
+static void draw_strand_child_lines(StrandsChildren *children, short dflag)
+{
+ StrandsDrawGLState gl_state;
+ StrandChildIterator it_strand;
+
+ draw_strands_begin(&gl_state, dflag);
+
+ for (BKE_strand_child_iter_init(&it_strand, children); BKE_strand_child_iter_valid(&it_strand); BKE_strand_child_iter_next(&it_strand)) {
+ StrandsChildCurve *curve = it_strand.curve;
+ const int numverts = curve->cutoff < 0.0f ? curve->numverts : min_ii(curve->numverts, (int)ceilf(curve->cutoff) + 1);
+
+ if (it_strand.tot <= 0)
+ continue;
+
+ glVertexPointer(3, GL_FLOAT, sizeof(StrandsChildVertex), it_strand.verts->co);
+ glNormalPointer(GL_FLOAT, sizeof(StrandsChildVertex), it_strand.verts->nor);
+
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+// if (part->draw_col == PART_DRAW_COL_MAT) {
+// glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
+// }
+ }
+
+
+ glDrawArrays(GL_LINE_STRIP, 0, numverts);
+ }
+
+ draw_strands_end(&gl_state);
+}
+
+void draw_strands(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar, Object *ob, Strands *strands, StrandsChildren *children, short dflag)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ float imat[4][4];
+
+ invert_m4_m4(imat, rv3d->viewmatob);
+
+// glDepthMask(GL_FALSE);
+// glEnable(GL_BLEND);
+
+ glPushMatrix();
+
+ glLoadMatrixf(rv3d->viewmat);
+ glMultMatrixf(ob->obmat);
+
+ if (children)
+ draw_strand_child_lines(children, dflag);
+ else
+ draw_strand_lines(strands, dflag);
+
+ glPopMatrix();
+
+// glDepthMask(GL_TRUE);
+// glDisable(GL_BLEND);
+}
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct StrandsDrawInfo {
+ bool has_zbuf;
+ bool use_zbuf_select;
+
+ StrandsShadeMode shade_mode;
+ int select_mode;
+
+ float col_base[4];
+ float col_select[4];
+} StrandsDrawInfo;
+
+BLI_INLINE bool strands_use_normals(const StrandsDrawInfo *info)
+{
+ return ELEM(info->shade_mode, STRANDS_SHADE_HAIR);
+}
+
+static void init_draw_info(StrandsDrawInfo *info, View3D *v3d,
+ StrandsShadeMode shade_mode, int select_mode)
+{
+ info->has_zbuf = v3d->zbuf;
+ info->use_zbuf_select = (v3d->flag & V3D_ZBUF_SELECT);
+
+ info->shade_mode = shade_mode;
+ info->select_mode = select_mode;
+
+ /* get selection theme colors */
+ UI_GetThemeColor4fv(TH_VERTEX, info->col_base);
+ UI_GetThemeColor4fv(TH_VERTEX_SELECT, info->col_select);
+}
+
+static void set_opengl_state_strands(const StrandsDrawInfo *info)
+{
+ if (!info->use_zbuf_select)
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+
+ if (ELEM(info->shade_mode, STRANDS_SHADE_HAIR)) {
+ glEnable(GL_LIGHTING);
+ glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+ glEnable(GL_COLOR_MATERIAL);
+ glShadeModel(GL_SMOOTH);
+ }
+ else {
+ glDisable(GL_LIGHTING);
+ }
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ if (strands_use_normals(info))
+ glEnableClientState(GL_NORMAL_ARRAY);
+}
+
+static void set_opengl_state_dots(const StrandsDrawInfo *info)
+{
+ if (!info->use_zbuf_select)
+ glDisable(GL_DEPTH_TEST);
+ glEnable(GL_BLEND);
+
+ glDisable(GL_LIGHTING);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glPointSize(3.0);
+}
+
+static void restore_opengl_state(const StrandsDrawInfo *info)
+{
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glShadeModel(GL_FLAT);
+ if (info->has_zbuf)
+ glEnable(GL_DEPTH_TEST);
+ glLineWidth(1.0f);
+ glPointSize(1.0);
+}
+
+/* ------------------------------------------------------------------------- */
+/* strands */
+
+static void setup_gpu_buffers_strands(BMEditStrands *edit, const StrandsDrawInfo *info)
+{
+ const size_t size_v3 = sizeof(float) * 3;
+ const size_t size_vertex = (strands_use_normals(info) ? 2*size_v3 : size_v3);
+
+// int totstrands = BM_strands_count(edit->bm);
+ int totvert = edit->bm->totvert;
+ int totedge = edit->bm->totedge;
+
+ if (!edit->vertex_glbuf)
+ glGenBuffers(1, &edit->vertex_glbuf);
+ if (!edit->elem_glbuf)
+ glGenBuffers(1, &edit->elem_glbuf);
+
+ glBindBuffer(GL_ARRAY_BUFFER, edit->vertex_glbuf);
+ glBufferData(GL_ARRAY_BUFFER, size_vertex * totvert, NULL, GL_DYNAMIC_DRAW);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, edit->elem_glbuf);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * totedge * 2, NULL, GL_DYNAMIC_DRAW);
+
+ glVertexPointer(3, GL_FLOAT, size_vertex, NULL);
+ if (strands_use_normals(info))
+ glNormalPointer(GL_FLOAT, size_vertex, (GLubyte *)NULL + size_v3);
+}
+
+static void unbind_gpu_buffers_strands(void)
+{
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+static int write_gpu_buffers_strands(BMEditStrands *edit, const StrandsDrawInfo *info)
+{
+ const size_t size_v3 = sizeof(float) * 3;
+ const size_t size_vertex = (strands_use_normals(info) ? 2*size_v3 : size_v3);
+
+ GLubyte *vertex_data;
+ unsigned int *elem_data;
+ BMVert *root, *v, *vprev;
+ BMIter iter, iter_strand;
+ int index, indexprev, index_edge;
+ int k;
+
+ vertex_data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ elem_data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
+ if (!vertex_data || !elem_data)
+ return 0;
+
+ BM_mesh_elem_index_ensure(edit->bm, BM_VERT);
+
+ index_edge = 0;
+ BM_ITER_STRANDS(root, &iter, edit->bm, BM_STRANDS_OF_MESH) {
+ BM_ITER_STRANDS_ELEM_INDEX(v, &iter_strand, root, BM_VERTS_OF_STRAND, k) {
+ size_t offset_co;
+
+ index = BM_elem_index_get(v);
+
+ offset_co = index * size_vertex;
+ copy_v3_v3((float *)(vertex_data + offset_co), v->co);
+
+ if (k > 0) {
+ if (strands_use_normals(info)) {
+ size_t offset_nor = offset_co + size_v3;
+ float nor[3];
+ sub_v3_v3v3(nor, v->co, vprev->co);
+ normalize_v3(nor);
+ copy_v3_v3((float *)(vertex_data + offset_nor), nor);
+
+ if (k == 1) {
+ /* define root normal: same as first segment */
+ size_t offset_root_nor = indexprev * size_vertex + size_v3;
+ copy_v3_v3((float *)(vertex_data + offset_root_nor), nor);
+ }
+ }
+
+ {
+ elem_data[index_edge + 0] = indexprev;
+ elem_data[index_edge + 1] = index;
+ index_edge += 2;
+ }
+ }
+
+ vprev = v;
+ indexprev = index;
+ }
+ }
+
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+
+ return index_edge;
+}
+
+/* ------------------------------------------------------------------------- */
+/* dots */
+
+static void setup_gpu_buffers_dots(BMEditStrands *edit, const StrandsDrawInfo *info, bool selected)
+{
+ const size_t size_v3 = sizeof(float) * 3;
+ const size_t size_vertex = size_v3;
+ BMesh *bm = edit->bm;
+
+ BMVert *v;
+ BMIter iter;
+ int totvert;
+
+ switch (info->select_mode) {
+ case HAIR_SELECT_STRAND:
+ totvert = 0;
+ break;
+ case HAIR_SELECT_VERTEX:
+ totvert = selected ? bm->totvertsel : bm->totvert - bm->totvertsel;
+ break;
+ case HAIR_SELECT_TIP:
+ totvert = 0;
+ BM_ITER_MESH(v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test_bool(v, BM_ELEM_SELECT) != selected)
+ continue;
+ if (!BM_strands_vert_is_tip(v))
+ continue;
+
+ ++totvert;
+ }
+ break;
+ }
+
+ if (totvert == 0)
+ return;
+
+ if (!edit->dot_glbuf)
+ glGenBuffers(1, &edit->dot_glbuf);
+
+ glBindBuffer(GL_ARRAY_BUFFER, edit->dot_glbuf);
+ glBufferData(GL_ARRAY_BUFFER, size_vertex * totvert, NULL, GL_DYNAMIC_DRAW);
+
+ glVertexPointer(3, GL_FLOAT, size_vertex, NULL);
+}
+
+static void unbind_gpu_buffers_dots(void)
+{
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+static int write_gpu_buffers_dots(BMEditStrands *edit, const StrandsDrawInfo *info, bool selected)
+{
+ const size_t size_v3 = sizeof(float) * 3;
+ const size_t size_vertex = size_v3;
+
+ GLubyte *vertex_data;
+ BMVert *v;
+ BMIter iter;
+ int index_dot;
+
+ if (info->select_mode == HAIR_SELECT_STRAND)
+ return 0;
+
+ vertex_data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+ if (!vertex_data)
+ return 0;
+
+ BM_mesh_elem_index_ensure(edit->bm, BM_VERT);
+
+ index_dot = 0;
+ switch (info->select_mode) {
+ case HAIR_SELECT_STRAND:
+ /* already exited, but keep the case for the compiler */
+ break;
+ case HAIR_SELECT_VERTEX:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ size_t offset_co;
+
+ if (BM_elem_flag_test_bool(v, BM_ELEM_SELECT) != selected)
+ continue;
+
+ offset_co = index_dot * size_vertex;
+ copy_v3_v3((float *)(vertex_data + offset_co), v->co);
+ ++index_dot;
+ }
+ break;
+ case HAIR_SELECT_TIP:
+ BM_ITER_MESH(v, &iter, edit->bm, BM_VERTS_OF_MESH) {
+ size_t offset_co;
+
+ if (BM_elem_flag_test_bool(v, BM_ELEM_SELECT) != selected)
+ continue;
+ if (!BM_strands_vert_is_tip(v))
+ continue;
+
+ offset_co = index_dot * size_vertex;
+ copy_v3_v3((float *)(vertex_data + offset_co), v->co);
+ ++index_dot;
+ }
+ break;
+ }
+
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+
+ return index_dot;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void draw_dots(BMEditStrands *edit, const StrandsDrawInfo *info, bool selected)
+{
+ int totelem;
+
+ if (selected)
+ glColor3fv(info->col_select);
+ else
+ glColor3fv(info->col_base);
+
+ setup_gpu_buffers_dots(edit, info, selected);
+ totelem = write_gpu_buffers_dots(edit, info, selected);
+ if (totelem > 0)
+ glDrawArrays(GL_POINTS, 0, totelem);
+}
+
+void draw_strands_edit_hair(Scene *scene, View3D *v3d, ARegion *UNUSED(ar), BMEditStrands *edit)
+{
+ HairEditSettings *settings = &scene->toolsettings->hair_edit;
+
+ StrandsDrawInfo info;
+ int totelem;
+
+ init_draw_info(&info, v3d, STRANDS_SHADE_HAIR, settings->select_mode);
+
+ set_opengl_state_strands(&info);
+ setup_gpu_buffers_strands(edit, &info);
+ totelem = write_gpu_buffers_strands(edit, &info);
+ if (totelem > 0)
+ glDrawElements(GL_LINES, totelem, GL_UNSIGNED_INT, NULL);
+ unbind_gpu_buffers_strands();
+
+ set_opengl_state_dots(&info);
+ draw_dots(edit, &info, false);
+ draw_dots(edit, &info, true);
+ unbind_gpu_buffers_dots();
+
+ restore_opengl_state(&info);
+}