diff options
Diffstat (limited to 'source/blender/editors/space_view3d/drawobject.c')
-rw-r--r-- | source/blender/editors/space_view3d/drawobject.c | 1206 |
1 files changed, 1198 insertions, 8 deletions
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 8b2738914d9..46d682233ed 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -37,7 +37,6 @@ #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" -#include "DNA_object_force.h" #include "DNA_rigidbody_types.h" #include "DNA_scene_types.h" #include "DNA_smoke_types.h" @@ -72,6 +71,8 @@ #include "BKE_movieclip.h" #include "BKE_object.h" #include "BKE_paint.h" +#include "BKE_particle.h" +#include "BKE_pointcache.h" #include "BKE_scene.h" #include "BKE_subsurf.h" #include "BKE_unit.h" @@ -94,6 +95,7 @@ #include "GPU_matrix.h" #include "ED_mesh.h" +#include "ED_particle.h" #include "ED_screen.h" #include "ED_sculpt.h" #include "ED_types.h" @@ -4737,7 +4739,12 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D * with the background. */ if ((dflag & DRAW_CONSTCOLOR) == 0) { - glColor3ubv(ob_wire_col); + if (is_obact && (ob->mode & OB_MODE_PARTICLE_EDIT)) { + ob_wire_color_blend_theme_id(ob_wire_col, TH_BACK, 0.15f); + } + else { + glColor3ubv(ob_wire_col); + } } /* If drawing wire and drawtype is not OB_WIRE then we are @@ -5784,6 +5791,1113 @@ static bool drawDispList(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *ba } /* *********** drawing for particles ************* */ +static void draw_particle_arrays(int draw_as, int totpoint, int ob_dt, int select) +{ + /* draw created data arrays */ + switch (draw_as) { + case PART_DRAW_AXIS: + case PART_DRAW_CROSS: + glDrawArrays(GL_LINES, 0, 6 * totpoint); + break; + case PART_DRAW_LINE: + glDrawArrays(GL_LINES, 0, 2 * totpoint); + break; + case PART_DRAW_BB: + if (ob_dt <= OB_WIRE || select) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + else + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + glDrawArrays(GL_QUADS, 0, 4 * totpoint); + break; + default: + glDrawArrays(GL_POINTS, 0, totpoint); + break; + } +} +static void draw_particle(ParticleKey *state, int draw_as, short draw, float pixsize, + float imat[4][4], const float draw_line[2], ParticleBillboardData *bb, ParticleDrawData *pdd) +{ + float vec[3], vec2[3]; + float *vd = NULL; + float *cd = NULL; + float ma_col[3] = {0.0f, 0.0f, 0.0f}; + + /* null only for PART_DRAW_CIRC */ + if (pdd) { + vd = pdd->vd; + cd = pdd->cd; + + if (pdd->ma_col) { + copy_v3_v3(ma_col, pdd->ma_col); + } + } + + switch (draw_as) { + case PART_DRAW_DOT: + { + if (vd) { + copy_v3_v3(vd, state->co); pdd->vd += 3; + } + if (cd) { + copy_v3_v3(cd, pdd->ma_col); + pdd->cd += 3; + } + break; + } + case PART_DRAW_CROSS: + case PART_DRAW_AXIS: + { + vec[0] = 2.0f * pixsize; + vec[1] = vec[2] = 0.0; + mul_qt_v3(state->rot, vec); + if (draw_as == PART_DRAW_AXIS) { + if (cd) { + cd[1] = cd[2] = cd[4] = cd[5] = 0.0; + cd[0] = cd[3] = 1.0; + cd[6] = cd[8] = cd[9] = cd[11] = 0.0; + cd[7] = cd[10] = 1.0; + cd[13] = cd[12] = cd[15] = cd[16] = 0.0; + cd[14] = cd[17] = 1.0; + pdd->cd += 18; + } + + copy_v3_v3(vec2, state->co); + } + else { + if (cd) { + cd[0] = cd[3] = cd[6] = cd[9] = cd[12] = cd[15] = ma_col[0]; + cd[1] = cd[4] = cd[7] = cd[10] = cd[13] = cd[16] = ma_col[1]; + cd[2] = cd[5] = cd[8] = cd[11] = cd[14] = cd[17] = ma_col[2]; + pdd->cd += 18; + } + sub_v3_v3v3(vec2, state->co, vec); + } + + add_v3_v3(vec, state->co); + copy_v3_v3(pdd->vd, vec); pdd->vd += 3; + copy_v3_v3(pdd->vd, vec2); pdd->vd += 3; + + vec[1] = 2.0f * pixsize; + vec[0] = vec[2] = 0.0; + mul_qt_v3(state->rot, vec); + if (draw_as == PART_DRAW_AXIS) { + copy_v3_v3(vec2, state->co); + } + else { + sub_v3_v3v3(vec2, state->co, vec); + } + + add_v3_v3(vec, state->co); + copy_v3_v3(pdd->vd, vec); pdd->vd += 3; + copy_v3_v3(pdd->vd, vec2); pdd->vd += 3; + + vec[2] = 2.0f * pixsize; + vec[0] = vec[1] = 0.0f; + mul_qt_v3(state->rot, vec); + if (draw_as == PART_DRAW_AXIS) { + copy_v3_v3(vec2, state->co); + } + else { + sub_v3_v3v3(vec2, state->co, vec); + } + + add_v3_v3(vec, state->co); + + copy_v3_v3(pdd->vd, vec); pdd->vd += 3; + copy_v3_v3(pdd->vd, vec2); pdd->vd += 3; + break; + } + case PART_DRAW_LINE: + { + copy_v3_v3(vec, state->vel); + normalize_v3(vec); + if (draw & PART_DRAW_VEL_LENGTH) + mul_v3_fl(vec, len_v3(state->vel)); + madd_v3_v3v3fl(pdd->vd, state->co, vec, -draw_line[0]); pdd->vd += 3; + madd_v3_v3v3fl(pdd->vd, state->co, vec, draw_line[1]); pdd->vd += 3; + if (cd) { + cd[0] = cd[3] = ma_col[0]; + cd[1] = cd[4] = ma_col[1]; + cd[2] = cd[5] = ma_col[2]; + pdd->cd += 6; + } + break; + } + case PART_DRAW_CIRC: + { + drawcircball(GL_LINE_LOOP, state->co, pixsize, imat); + break; + } + case PART_DRAW_BB: + { + float xvec[3], yvec[3], zvec[3], bb_center[3]; + if (cd) { + cd[0] = cd[3] = cd[6] = cd[9] = ma_col[0]; + cd[1] = cd[4] = cd[7] = cd[10] = ma_col[1]; + cd[2] = cd[5] = cd[8] = cd[11] = ma_col[2]; + pdd->cd += 12; + } + + copy_v3_v3(bb->vec, state->co); + copy_v3_v3(bb->vel, state->vel); + + psys_make_billboard(bb, xvec, yvec, zvec, bb_center); + + add_v3_v3v3(pdd->vd, bb_center, xvec); + add_v3_v3(pdd->vd, yvec); pdd->vd += 3; + + sub_v3_v3v3(pdd->vd, bb_center, xvec); + add_v3_v3(pdd->vd, yvec); pdd->vd += 3; + + sub_v3_v3v3(pdd->vd, bb_center, xvec); + sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3; + + add_v3_v3v3(pdd->vd, bb_center, xvec); + sub_v3_v3v3(pdd->vd, pdd->vd, yvec); pdd->vd += 3; + + copy_v3_v3(pdd->nd, zvec); pdd->nd += 3; + copy_v3_v3(pdd->nd, zvec); pdd->nd += 3; + copy_v3_v3(pdd->nd, zvec); pdd->nd += 3; + copy_v3_v3(pdd->nd, zvec); pdd->nd += 3; + break; + } + } +} +static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d, + ParticleKey *state, int draw_as, + float imat[4][4], ParticleBillboardData *bb, ParticleDrawData *pdd, + const float ct, const float pa_size, const float r_tilt, const float pixsize_scale) +{ + ParticleSettings *part = psys->part; + float pixsize; + + if (psys->parent) + mul_m4_v3(psys->parent->obmat, state->co); + + /* create actual particle data */ + if (draw_as == PART_DRAW_BB) { + bb->offset[0] = part->bb_offset[0]; + bb->offset[1] = part->bb_offset[1]; + bb->size[0] = part->bb_size[0] * pa_size; + if (part->bb_align == PART_BB_VEL) { + float pa_vel = len_v3(state->vel); + float head = part->bb_vel_head * pa_vel; + float tail = part->bb_vel_tail * pa_vel; + bb->size[1] = part->bb_size[1] * pa_size + head + tail; + /* use offset to adjust the particle center. this is relative to size, so need to divide! */ + if (bb->size[1] > 0.0f) + bb->offset[1] += (head - tail) / bb->size[1]; + } + else { + bb->size[1] = part->bb_size[1] * pa_size; + } + bb->tilt = part->bb_tilt * (1.0f - part->bb_rand_tilt * r_tilt); + bb->time = ct; + } + + pixsize = ED_view3d_pixel_size(rv3d, state->co) * pixsize_scale; + + draw_particle(state, draw_as, part->draw, pixsize, imat, part->draw_line, bb, pdd); +} +/* unified drawing of all new particle systems draw types except dupli ob & group + * mostly tries to use vertex arrays for speed + * + * 1. check that everything is ok & updated + * 2. start initializing things + * 3. initialize according to draw type + * 4. allocate drawing data arrays + * 5. start filling the arrays + * 6. draw the arrays + * 7. clean up + */ +static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d, + Base *base, ParticleSystem *psys, + const char ob_dt, const short dflag) +{ + Object *ob = base->object; + ParticleEditSettings *pset = PE_settings(scene); + ParticleSettings *part = psys->part; + ParticleData *pars = psys->particles; + ParticleData *pa; + ParticleKey state, *states = NULL; + ParticleBillboardData bb; + ParticleSimulationData sim = {NULL}; + ParticleDrawData *pdd = psys->pdd; + Material *ma; + float vel[3], imat[4][4]; + float timestep, pixsize_scale = 1.0f, pa_size, r_tilt, r_length; + float pa_time, pa_birthtime, pa_dietime, pa_health, intensity; + float cfra; + float ma_col[3] = {0.0f, 0.0f, 0.0f}; + int a, totpart, totpoint = 0, totve = 0, drawn, draw_as, totchild = 0; + bool select = (ob->flag & SELECT) != 0, create_cdata = false, need_v = false; + GLint polygonmode[2]; + char numstr[32]; + unsigned char tcol[4] = {0, 0, 0, 255}; + +/* 1. */ + if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering)) + return; + + if (pars == NULL) return; + + /* don't draw normal paths in edit mode */ + if (psys_in_edit_mode(scene, psys) && (pset->flag & PE_DRAW_PART) == 0) + return; + + if (part->draw_as == PART_DRAW_REND) + draw_as = part->ren_as; + else + draw_as = part->draw_as; + + if (draw_as == PART_DRAW_NOT) + return; + + /* prepare curvemapping tables */ + if ((psys->part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && psys->part->clumpcurve) + curvemapping_changed_all(psys->part->clumpcurve); + if ((psys->part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && psys->part->roughcurve) + curvemapping_changed_all(psys->part->roughcurve); + +/* 2. */ + sim.scene = scene; + sim.ob = ob; + sim.psys = psys; + sim.psmd = psys_get_modifier(ob, psys); + + if (part->phystype == PART_PHYS_KEYED) { + if (psys->flag & PSYS_KEYED) { + psys_count_keyed_targets(&sim); + if (psys->totkeyed == 0) + return; + } + } + + if (select) { + select = false; + if (psys_get_current(ob) == psys) + select = true; + } + + psys->flag |= PSYS_DRAWING; + + if (part->type == PART_HAIR && !psys->childcache) + totchild = 0; + else + totchild = psys->totchild * part->disp / 100; + + ma = give_current_material(ob, part->omat); + + if (v3d->zbuf) glDepthMask(1); + + if ((ma) && (part->draw_col == PART_DRAW_COL_MAT)) { + rgb_float_to_uchar(tcol, &(ma->r)); + copy_v3_v3(ma_col, &ma->r); + } + + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glColor3ubv(tcol); + } + + timestep = psys_get_timestep(&sim); + + if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) { + float mat[4][4]; + mul_m4_m4m4(mat, ob->obmat, psys->imat); + glMultMatrixf(mat); + } + + /* needed for text display */ + invert_m4_m4(ob->imat, ob->obmat); + + totpart = psys->totpart; + + cfra = BKE_scene_frame_get(scene); + + if (draw_as == PART_DRAW_PATH && psys->pathcache == NULL && psys->childcache == NULL) + draw_as = PART_DRAW_DOT; + +/* 3. */ + glLineWidth(1.0f); + + switch (draw_as) { + case PART_DRAW_DOT: + if (part->draw_size) + glPointSize(part->draw_size); + else + glPointSize(2.0); /* default dot size */ + break; + case PART_DRAW_CIRC: + /* calculate view aligned matrix: */ + copy_m4_m4(imat, rv3d->viewinv); + normalize_v3(imat[0]); + normalize_v3(imat[1]); + /* fall-through */ + case PART_DRAW_CROSS: + case PART_DRAW_AXIS: + /* lets calculate the scale: */ + + if (part->draw_size == 0.0) + pixsize_scale = 2.0f; + else + pixsize_scale = part->draw_size; + + if (draw_as == PART_DRAW_AXIS) + create_cdata = 1; + break; + case PART_DRAW_OB: + if (part->dup_ob == NULL) + draw_as = PART_DRAW_DOT; + else + draw_as = 0; + break; + case PART_DRAW_GR: + if (part->dup_group == NULL) + draw_as = PART_DRAW_DOT; + else + draw_as = 0; + break; + case PART_DRAW_BB: + if (v3d->camera == NULL && part->bb_ob == NULL) { + printf("Billboards need an active camera or a target object!\n"); + + draw_as = part->draw_as = PART_DRAW_DOT; + + if (part->draw_size) + glPointSize(part->draw_size); + else + glPointSize(2.0); /* default dot size */ + } + else if (part->bb_ob) + bb.ob = part->bb_ob; + else + bb.ob = v3d->camera; + + bb.align = part->bb_align; + bb.anim = part->bb_anim; + bb.lock = part->draw & PART_DRAW_BB_LOCK; + break; + case PART_DRAW_PATH: + break; + case PART_DRAW_LINE: + need_v = 1; + break; + } + if (part->draw & PART_DRAW_SIZE && part->draw_as != PART_DRAW_CIRC) { + copy_m4_m4(imat, rv3d->viewinv); + normalize_v3(imat[0]); + normalize_v3(imat[1]); + } + + if (ELEM(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) && + (part->draw_col > PART_DRAW_COL_MAT)) + { + create_cdata = 1; + } + + if (!create_cdata && pdd && pdd->cdata) { + MEM_freeN(pdd->cdata); + pdd->cdata = pdd->cd = NULL; + } + +/* 4. */ + if (draw_as && ELEM(draw_as, PART_DRAW_PATH, PART_DRAW_CIRC) == 0) { + int tot_vec_size = (totpart + totchild) * 3 * sizeof(float); + int create_ndata = 0; + + if (!pdd) + pdd = psys->pdd = MEM_callocN(sizeof(ParticleDrawData), "ParticleDrawData"); + + if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) { + tot_vec_size *= part->trail_count; + psys_make_temp_pointcache(ob, psys); + } + + switch (draw_as) { + case PART_DRAW_AXIS: + case PART_DRAW_CROSS: + tot_vec_size *= 6; + if (draw_as != PART_DRAW_CROSS) + create_cdata = 1; + break; + case PART_DRAW_LINE: + tot_vec_size *= 2; + break; + case PART_DRAW_BB: + tot_vec_size *= 4; + create_ndata = 1; + break; + } + + if (pdd->tot_vec_size != tot_vec_size) + psys_free_pdd(psys); + + if (!pdd->vdata) + pdd->vdata = MEM_callocN(tot_vec_size, "particle_vdata"); + if (create_cdata && !pdd->cdata) + pdd->cdata = MEM_callocN(tot_vec_size, "particle_cdata"); + if (create_ndata && !pdd->ndata) + pdd->ndata = MEM_callocN(tot_vec_size, "particle_ndata"); + + if (part->draw & PART_DRAW_VEL && draw_as != PART_DRAW_LINE) { + if (!pdd->vedata) + pdd->vedata = MEM_callocN(2 * (totpart + totchild) * 3 * sizeof(float), "particle_vedata"); + + need_v = 1; + } + else if (pdd->vedata) { + /* velocity data not needed, so free it */ + MEM_freeN(pdd->vedata); + pdd->vedata = NULL; + } + + pdd->vd = pdd->vdata; + pdd->ved = pdd->vedata; + pdd->cd = pdd->cdata; + pdd->nd = pdd->ndata; + pdd->tot_vec_size = tot_vec_size; + } + else if (psys->pdd) { + psys_free_pdd(psys); + MEM_freeN(psys->pdd); + pdd = psys->pdd = NULL; + } + + if (pdd) { + pdd->ma_col = ma_col; + } + + psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); + + /* circles don't use drawdata, so have to add a special case here */ + if ((pdd || draw_as == PART_DRAW_CIRC) && draw_as != PART_DRAW_PATH) { + /* 5. */ + if (pdd && (pdd->flag & PARTICLE_DRAW_DATA_UPDATED) && + (pdd->vedata || part->draw & (PART_DRAW_SIZE | PART_DRAW_NUM | PART_DRAW_HEALTH)) == 0) + { + totpoint = pdd->totpoint; /* draw data is up to date */ + } + else { + for (a = 0, pa = pars; a < totpart + totchild; a++, pa++) { + /* setup per particle individual stuff */ + if (a < totpart) { + if (totchild && (part->draw & PART_DRAW_PARENT) == 0) continue; + if (pa->flag & PARS_NO_DISP || pa->flag & PARS_UNEXIST) continue; + + pa_time = (cfra - pa->time) / pa->lifetime; + pa_birthtime = pa->time; + pa_dietime = pa->dietime; + pa_size = pa->size; + if (part->phystype == PART_PHYS_BOIDS) + pa_health = pa->boid->data.health; + else + pa_health = -1.0; + + r_tilt = 2.0f * (psys_frand(psys, a + 21) - 0.5f); + r_length = psys_frand(psys, a + 22); + + if (part->draw_col > PART_DRAW_COL_MAT) { + switch (part->draw_col) { + case PART_DRAW_COL_VEL: + intensity = len_v3(pa->state.vel) / part->color_vec_max; + break; + case PART_DRAW_COL_ACC: + intensity = len_v3v3(pa->state.vel, pa->prev_state.vel) / ((pa->state.time - pa->prev_state.time) * part->color_vec_max); + break; + default: + intensity = 1.0f; /* should never happen */ + BLI_assert(0); + break; + } + CLAMP(intensity, 0.0f, 1.0f); + weight_to_rgb(ma_col, intensity); + } + } + else { + ChildParticle *cpa = &psys->child[a - totpart]; + + pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime); + pa_size = psys_get_child_size(psys, cpa, cfra, NULL); + + pa_health = -1.0; + + r_tilt = 2.0f * (psys_frand(psys, a + 21) - 0.5f); + r_length = psys_frand(psys, a + 22); + } + + drawn = 0; + if (part->draw_as == PART_DRAW_REND && part->trail_count > 1) { + float length = part->path_end * (1.0f - part->randlength * r_length); + int trail_count = part->trail_count * (1.0f - part->randlength * r_length); + float ct = ((part->draw & PART_ABS_PATH_TIME) ? cfra : pa_time) - length; + float dt = length / (trail_count ? (float)trail_count : 1.0f); + int i = 0; + + ct += dt; + for (i = 0; i < trail_count; i++, ct += dt) { + + if (part->draw & PART_ABS_PATH_TIME) { + if (ct < pa_birthtime || ct > pa_dietime) + continue; + } + else if (ct < 0.0f || ct > 1.0f) + continue; + + state.time = (part->draw & PART_ABS_PATH_TIME) ? -ct : -(pa_birthtime + ct * (pa_dietime - pa_birthtime)); + psys_get_particle_on_path(&sim, a, &state, need_v); + + draw_particle_data(psys, rv3d, + &state, draw_as, imat, &bb, psys->pdd, + ct, pa_size, r_tilt, pixsize_scale); + + totpoint++; + drawn = 1; + } + } + else { + state.time = cfra; + if (psys_get_particle_state(&sim, a, &state, 0)) { + + draw_particle_data(psys, rv3d, + &state, draw_as, imat, &bb, psys->pdd, + pa_time, pa_size, r_tilt, pixsize_scale); + + totpoint++; + drawn = 1; + } + } + + if (drawn) { + /* additional things to draw for each particle + * (velocity, size and number) */ + if ((part->draw & PART_DRAW_VEL) && pdd && pdd->vedata) { + copy_v3_v3(pdd->ved, state.co); + pdd->ved += 3; + mul_v3_v3fl(vel, state.vel, timestep); + add_v3_v3v3(pdd->ved, state.co, vel); + pdd->ved += 3; + + totve++; + } + + if (part->draw & PART_DRAW_SIZE) { + setlinestyle(3); + drawcircball(GL_LINE_LOOP, state.co, pa_size, imat); + setlinestyle(0); + } + + + if ((part->draw & PART_DRAW_NUM || part->draw & PART_DRAW_HEALTH) && + (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) + { + size_t numstr_len; + float vec_txt[3]; + char *val_pos = numstr; + numstr[0] = '\0'; + + if (part->draw & PART_DRAW_NUM) { + if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) { + numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d:%.2f", a, pa_health); + } + else { + numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%d", a); + } + } + else { + if (a < totpart && (part->draw & PART_DRAW_HEALTH) && (part->phystype == PART_PHYS_BOIDS)) { + numstr_len = BLI_snprintf_rlen(val_pos, sizeof(numstr), "%.2f", pa_health); + } + } + + if (numstr[0]) { + /* in path drawing state.co is the end point + * use worldspace because object matrix is already applied */ + mul_v3_m4v3(vec_txt, ob->imat, state.co); + view3d_cached_text_draw_add(vec_txt, numstr, numstr_len, + 10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol); + } + } + } + } + } + } +/* 6. */ + + glGetIntegerv(GL_POLYGON_MODE, polygonmode); + glEnableClientState(GL_VERTEX_ARRAY); + + if (draw_as == PART_DRAW_PATH) { + ParticleCacheKey **cache, *path; + float *cdata2 = NULL; + + /* setup gl flags */ + if (1) { //ob_dt > OB_WIRE) { + glEnableClientState(GL_NORMAL_ARRAY); + + if ((dflag & DRAW_CONSTCOLOR) == 0) { + if (part->draw_col == PART_DRAW_COL_MAT) + glEnableClientState(GL_COLOR_ARRAY); + } + + // XXX test + GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); + } + + if (totchild && (part->draw & PART_DRAW_PARENT) == 0) + totpart = 0; + else if (psys->pathcache == NULL) + totpart = 0; + + /* draw actual/parent particles */ + cache = psys->pathcache; + for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { + path = cache[a]; + if (path->segments > 0) { + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); + + if (1) { //ob_dt > OB_WIRE) { + glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); + 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, path->segments + 1); + } + } + + if (part->type == PART_HAIR) { + if (part->draw & PART_DRAW_GUIDE_HAIRS) { + DerivedMesh *hair_dm = psys->hair_out_dm; + + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { + if (pa->totkey > 1) { + HairKey *hkey = pa->hair; + + glVertexPointer(3, GL_FLOAT, sizeof(HairKey), hkey->world_co); + +#if 0 /* XXX use proper theme color here */ + UI_ThemeColor(TH_NORMAL); +#else + glColor3f(0.58f, 0.67f, 1.0f); +#endif + + glDrawArrays(GL_LINE_STRIP, 0, pa->totkey); + } + } + + if (hair_dm) { + MVert *mvert = hair_dm->getVertArray(hair_dm); + int i; + + glColor3f(0.9f, 0.4f, 0.4f); + + glBegin(GL_LINES); + for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { + for (i = 1; i < pa->totkey; ++i) { + float v1[3], v2[3]; + + copy_v3_v3(v1, mvert[pa->hair_index + i - 1].co); + copy_v3_v3(v2, mvert[pa->hair_index + i].co); + + mul_m4_v3(ob->obmat, v1); + mul_m4_v3(ob->obmat, v2); + + glVertex3fv(v1); + glVertex3fv(v2); + } + } + glEnd(); + } + + glEnableClientState(GL_NORMAL_ARRAY); + if ((dflag & DRAW_CONSTCOLOR) == 0) + if (part->draw_col == PART_DRAW_COL_MAT) + glEnableClientState(GL_COLOR_ARRAY); + } + + if (part->draw & PART_DRAW_HAIR_GRID) { + ClothModifierData *clmd = psys->clmd; + if (clmd) { + float *gmin = clmd->hair_grid_min; + float *gmax = clmd->hair_grid_max; + int *res = clmd->hair_grid_res; + int i; + + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + if (select) + UI_ThemeColor(TH_ACTIVE); + else + UI_ThemeColor(TH_WIRE); + glBegin(GL_LINES); + glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmin[2]); + glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmin[2]); + glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmin[2]); + glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmin[2]); + + glVertex3f(gmin[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmin[1], gmax[2]); + glVertex3f(gmax[0], gmin[1], gmax[2]); glVertex3f(gmax[0], gmax[1], gmax[2]); + glVertex3f(gmax[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmax[1], gmax[2]); + glVertex3f(gmin[0], gmax[1], gmax[2]); glVertex3f(gmin[0], gmin[1], gmax[2]); + + glVertex3f(gmin[0], gmin[1], gmin[2]); glVertex3f(gmin[0], gmin[1], gmax[2]); + glVertex3f(gmax[0], gmin[1], gmin[2]); glVertex3f(gmax[0], gmin[1], gmax[2]); + glVertex3f(gmin[0], gmax[1], gmin[2]); glVertex3f(gmin[0], gmax[1], gmax[2]); + glVertex3f(gmax[0], gmax[1], gmin[2]); glVertex3f(gmax[0], gmax[1], gmax[2]); + glEnd(); + + if (select) + UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -100); + else + UI_ThemeColorShadeAlpha(TH_WIRE, 0, -100); + glEnable(GL_BLEND); + glBegin(GL_LINES); + for (i = 1; i < res[0] - 1; ++i) { + float f = interpf(gmax[0], gmin[0], (float)i / (float)(res[0] - 1)); + glVertex3f(f, gmin[1], gmin[2]); glVertex3f(f, gmax[1], gmin[2]); + glVertex3f(f, gmax[1], gmin[2]); glVertex3f(f, gmax[1], gmax[2]); + glVertex3f(f, gmax[1], gmax[2]); glVertex3f(f, gmin[1], gmax[2]); + glVertex3f(f, gmin[1], gmax[2]); glVertex3f(f, gmin[1], gmin[2]); + } + for (i = 1; i < res[1] - 1; ++i) { + float f = interpf(gmax[1], gmin[1], (float)i / (float)(res[1] - 1)); + glVertex3f(gmin[0], f, gmin[2]); glVertex3f(gmax[0], f, gmin[2]); + glVertex3f(gmax[0], f, gmin[2]); glVertex3f(gmax[0], f, gmax[2]); + glVertex3f(gmax[0], f, gmax[2]); glVertex3f(gmin[0], f, gmax[2]); + glVertex3f(gmin[0], f, gmax[2]); glVertex3f(gmin[0], f, gmin[2]); + } + for (i = 1; i < res[2] - 1; ++i) { + float f = interpf(gmax[2], gmin[2], (float)i / (float)(res[2] - 1)); + glVertex3f(gmin[0], gmin[1], f); glVertex3f(gmax[0], gmin[1], f); + glVertex3f(gmax[0], gmin[1], f); glVertex3f(gmax[0], gmax[1], f); + glVertex3f(gmax[0], gmax[1], f); glVertex3f(gmin[0], gmax[1], f); + glVertex3f(gmin[0], gmax[1], f); glVertex3f(gmin[0], gmin[1], f); + } + glEnd(); + glDisable(GL_BLEND); + + glEnableClientState(GL_NORMAL_ARRAY); + if ((dflag & DRAW_CONSTCOLOR) == 0) + if (part->draw_col == PART_DRAW_COL_MAT) + glEnableClientState(GL_COLOR_ARRAY); + } + } + } + + /* draw child particles */ + cache = psys->childcache; + for (a = 0; a < totchild; a++) { + path = cache[a]; + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); + + if (1) { //ob_dt > OB_WIRE) { + glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel); + 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, path->segments + 1); + } + + /* restore & clean up */ + if (1) { //ob_dt > OB_WIRE) { + if (part->draw_col == PART_DRAW_COL_MAT) + glDisableClientState(GL_COLOR_ARRAY); + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + } + + if (cdata2) { + MEM_freeN(cdata2); + cdata2 = NULL; + } + + if ((part->draw & PART_DRAW_NUM) && (v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) { + cache = psys->pathcache; + + for (a = 0, pa = psys->particles; a < totpart; a++, pa++) { + float vec_txt[3]; + size_t numstr_len = BLI_snprintf_rlen(numstr, sizeof(numstr), "%i", a); + /* use worldspace because object matrix is already applied */ + mul_v3_m4v3(vec_txt, ob->imat, cache[a]->co); + view3d_cached_text_draw_add(vec_txt, numstr, numstr_len, + 10, V3D_CACHE_TEXT_WORLDSPACE | V3D_CACHE_TEXT_ASCII, tcol); + } + } + } + else if (pdd && ELEM(draw_as, 0, PART_DRAW_CIRC) == 0) { + glDisableClientState(GL_COLOR_ARRAY); + + /* enable point data array */ + if (pdd->vdata) { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, pdd->vdata); + } + else + glDisableClientState(GL_VERTEX_ARRAY); + + if ((dflag & DRAW_CONSTCOLOR) == 0) { + if (select) { + UI_ThemeColor(TH_ACTIVE); + + if (part->draw_size) + glPointSize(part->draw_size + 2); + else + glPointSize(4.0); + + glLineWidth(3.0); + + draw_particle_arrays(draw_as, totpoint, ob_dt, 1); + } + + /* restore from select */ + glColor3fv(ma_col); + } + + glPointSize(part->draw_size ? part->draw_size : 2.0); + glLineWidth(1.0); + + /* enable other data arrays */ + + /* billboards are drawn this way */ + if (pdd->ndata && ob_dt > OB_WIRE) { + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, 0, pdd->ndata); + GPU_basic_shader_colors(NULL, NULL, 0.0f, 1.0f); + GPU_basic_shader_bind(GPU_SHADER_LIGHTING | GPU_SHADER_USE_COLOR); + } + + if ((dflag & DRAW_CONSTCOLOR) == 0) { + if (pdd->cdata) { + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(3, GL_FLOAT, 0, pdd->cdata); + } + } + + draw_particle_arrays(draw_as, totpoint, ob_dt, 0); + + pdd->flag |= PARTICLE_DRAW_DATA_UPDATED; + pdd->totpoint = totpoint; + } + + if (pdd && pdd->vedata) { + if ((dflag & DRAW_CONSTCOLOR) == 0) { + glDisableClientState(GL_COLOR_ARRAY); + cpack(0xC0C0C0); + } + + glVertexPointer(3, GL_FLOAT, 0, pdd->vedata); + + glDrawArrays(GL_LINES, 0, 2 * totve); + } + + glPolygonMode(GL_FRONT, polygonmode[0]); + glPolygonMode(GL_BACK, polygonmode[1]); + +/* 7. */ + + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + + if (states) + MEM_freeN(states); + + psys->flag &= ~PSYS_DRAWING; + + /* draw data can't be saved for billboards as they must update to target changes */ + if (draw_as == PART_DRAW_BB) { + psys_free_pdd(psys); + pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; + } + + if (psys->lattice_deform_data) { + end_latt_deform(psys->lattice_deform_data); + psys->lattice_deform_data = NULL; + } + + if (pdd) { + /* drop references to stack memory */ + pdd->ma_col = NULL; + } + + if ((base->flag & OB_FROMDUPLI) && (ob->flag & OB_FROMGROUP)) { + glLoadMatrixf(rv3d->viewmat); + } +} + +static void draw_update_ptcache_edit(Scene *scene, Object *ob, PTCacheEdit *edit) +{ + if (edit->psys && edit->psys->flag & PSYS_HAIR_UPDATED) + PE_update_object(scene, ob, 0); + + /* create path and child path cache if it doesn't exist already */ + if (edit->pathcache == NULL) + psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering); +} + +static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) +{ + ParticleCacheKey **cache, *path, *pkey; + PTCacheEditPoint *point; + PTCacheEditKey *key; + ParticleEditSettings *pset = PE_settings(scene); + int i, k, totpoint = edit->totpoint, timed = (pset->flag & PE_FADE_TIME) ? pset->fade_frames : 0; + int totkeys = 1; + float sel_col[3]; + float nosel_col[3]; + float *pathcol = NULL, *pcol; + + if (edit->pathcache == NULL) + return; + + PE_hide_keys_time(scene, edit, CFRA); + + /* opengl setup */ + if ((v3d->flag & V3D_ZBUF_SELECT) == 0) + glDisable(GL_DEPTH_TEST); + + /* get selection theme colors */ + UI_GetThemeColor3fv(TH_VERTEX_SELECT, sel_col); + UI_GetThemeColor3fv(TH_VERTEX, nosel_col); + + /* draw paths */ + totkeys = (*edit->pathcache)->segments + 1; + + glEnable(GL_BLEND); + pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data"); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + if (pset->brushtype == PE_BRUSH_WEIGHT) + glLineWidth(2.0f); + + cache = edit->pathcache; + for (i = 0, point = edit->points; i < totpoint; i++, point++) { + path = cache[i]; + glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co); + + if (point->flag & PEP_HIDE) { + for (k = 0, pcol = pathcol; k < totkeys; k++, pcol += 4) { + copy_v3_v3(pcol, path->col); + pcol[3] = 0.25f; + } + + glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol); + } + else if (timed) { + for (k = 0, pcol = pathcol, pkey = path; k < totkeys; k++, pkey++, pcol += 4) { + copy_v3_v3(pcol, pkey->col); + pcol[3] = 1.0f - fabsf((float)(CFRA) -pkey->time) / (float)pset->fade_frames; + } + + glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol); + } + else + glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col); + + glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1); + } + + if (pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; } + + + /* draw edit vertices */ + if (pset->selectmode != SCE_SELECT_PATH) { + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + + if (pset->selectmode == SCE_SELECT_POINT) { + float *pd = NULL, *pdata = NULL; + float *cd = NULL, *cdata = NULL; + int totkeys_visible = 0; + + for (i = 0, point = edit->points; i < totpoint; i++, point++) + if (!(point->flag & PEP_HIDE)) + totkeys_visible += point->totkey; + + if (totkeys_visible) { + if (edit->points && !(edit->points->keys->flag & PEK_USE_WCO)) + pd = pdata = MEM_callocN(totkeys_visible * 3 * sizeof(float), "particle edit point data"); + cd = cdata = MEM_callocN(totkeys_visible * (timed ? 4 : 3) * sizeof(float), "particle edit color data"); + } + + for (i = 0, point = edit->points; i < totpoint; i++, point++) { + if (point->flag & PEP_HIDE) + continue; + + for (k = 0, key = point->keys; k < point->totkey; k++, key++) { + if (pd) { + copy_v3_v3(pd, key->co); + pd += 3; + } + + if (key->flag & PEK_SELECT) { + copy_v3_v3(cd, sel_col); + } + else { + copy_v3_v3(cd, nosel_col); + } + + if (timed) + *(cd + 3) = 1.0f - fabsf((float)CFRA - *key->time) / (float)pset->fade_frames; + + cd += (timed ? 4 : 3); + } + } + cd = cdata; + pd = pdata; + for (i = 0, point = edit->points; i < totpoint; i++, point++) { + if (point->flag & PEP_HIDE || point->totkey == 0) + continue; + + if (point->keys->flag & PEK_USE_WCO) + glVertexPointer(3, GL_FLOAT, sizeof(PTCacheEditKey), point->keys->world_co); + else + glVertexPointer(3, GL_FLOAT, 3 * sizeof(float), pd); + + glColorPointer((timed ? 4 : 3), GL_FLOAT, (timed ? 4 : 3) * sizeof(float), cd); + + glDrawArrays(GL_POINTS, 0, point->totkey); + + pd += pd ? 3 * point->totkey : 0; + cd += (timed ? 4 : 3) * point->totkey; + } + if (pdata) { MEM_freeN(pdata); pd = pdata = NULL; } + if (cdata) { MEM_freeN(cdata); cd = cdata = NULL; } + } + else if (pset->selectmode == SCE_SELECT_END) { + glBegin(GL_POINTS); + for (i = 0, point = edit->points; i < totpoint; i++, point++) { + if ((point->flag & PEP_HIDE) == 0 && point->totkey) { + key = point->keys + point->totkey - 1; + glColor3fv((key->flag & PEK_SELECT) ? sel_col : nosel_col); + /* has to be like this.. otherwise selection won't work, have try glArrayElement later..*/ + glVertex3fv((key->flag & PEK_USE_WCO) ? key->world_co : key->co); + } + } + glEnd(); + } + } + + glDisable(GL_BLEND); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + if (v3d->zbuf) glEnable(GL_DEPTH_TEST); +} static void ob_draw_RE_motion(float com[3], float rotscale[3][3], float itw, float ith, float drw_size) { @@ -7459,12 +8573,15 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short Object *ob = base->object; Curve *cu; RegionView3D *rv3d = ar->regiondata; + unsigned int col = 0; unsigned char _ob_wire_col[4]; /* dont initialize this */ const unsigned char *ob_wire_col = NULL; /* dont initialize this, use NULL crashes as a way to find invalid use */ bool zbufoff = false, is_paint = false, empty_object = false; const bool is_obact = (ob == OBACT); const bool render_override = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0; const bool is_picking = (G.f & G_PICKSEL) != 0; + const bool has_particles = (ob->particlesystem.first != NULL); + bool skip_object = false; /* Draw particles but not their emitter object. */ SmokeModifierData *smd = NULL; if (ob != scene->obedit) { @@ -7475,11 +8592,31 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (ob->restrictflag & OB_RESTRICT_RENDER) return; - if (ob->transflag & (OB_DUPLI & ~OB_DUPLIFRAMES)) + if (!has_particles && (ob->transflag & (OB_DUPLI & ~OB_DUPLIFRAMES))) return; } } + if (has_particles) { + /* XXX particles are not safe for simultaneous threaded render */ + if (G.is_rendering) { + return; + } + + if (ob->mode == OB_MODE_OBJECT) { + ParticleSystem *psys; + + skip_object = render_override; + for (psys = ob->particlesystem.first; psys; psys = psys->next) { + /* Once we have found a psys which renders its emitter object, we are done. */ + if (psys->part->draw & PART_DRAW_EMITTER) { + skip_object = false; + break; + } + } + } + } + if (((base->flag & OB_FROMDUPLI) == 0) && (md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) @@ -7505,8 +8642,8 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short /* xray delay? */ if ((dflag & DRAW_PICKING) == 0 && (base->flag & OB_FROMDUPLI) == 0 && (v3d->flag2 & V3D_RENDER_SHADOW) == 0) { - /* sync with master */ - { + /* don't do xray in particle mode, need the z-buffer */ + if (!(ob->mode & OB_MODE_PARTICLE_EDIT)) { /* xray and transp are set when it is drawing the 2nd/3rd pass */ if (!v3d->xray && !v3d->transp && (ob->dtx & OB_DRAWXRAY) && !(ob->dtx & OB_DRAWTRANSP)) { ED_view3d_after_add(&v3d->afterdraw_xray, base, dflag); @@ -7608,8 +8745,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short } } - /* sync with master */ - { + if (!skip_object) { /* draw outline for selected objects, mesh does itself */ if ((v3d->flag & V3D_SELECT_OUTLINE) && !render_override && ob->type != OB_MESH) { if (dt > OB_WIRE && (ob->mode & OB_MODE_EDIT) == 0 && (dflag & DRAW_SCENESET) == 0) { @@ -7758,6 +8894,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (!render_override) { drawaxes(rv3d->viewmatob, 1.0, OB_ARROWS, ob_wire_col); } + break; } /* TODO Viewport: some elements are being drawn for object selection only */ @@ -7787,10 +8924,63 @@ afterdraw: } } + /* code for new particle system */ + if ((ob->particlesystem.first) && + (ob != scene->obedit)) + { + ParticleSystem *psys; + + if ((dflag & DRAW_CONSTCOLOR) == 0) { + /* for visibility, also while wpaint */ + if (col || (ob->flag & SELECT)) { + cpack(0xFFFFFF); + } + } + //glDepthMask(GL_FALSE); + + glLoadMatrixf(rv3d->viewmat); + + view3d_cached_text_draw_begin(); + + for (psys = ob->particlesystem.first; psys; psys = psys->next) { + /* run this so that possible child particles get cached */ + if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) { + PTCacheEdit *edit = PE_create_current(scene, ob); + if (edit && edit->psys == psys) + draw_update_ptcache_edit(scene, ob, edit); + } + + draw_new_particle_system(scene, v3d, rv3d, base, psys, dt, dflag); + } + invert_m4_m4(ob->imat, ob->obmat); + view3d_cached_text_draw_end(v3d, ar, 0, NULL); + + glMultMatrixf(ob->obmat); + + //glDepthMask(GL_TRUE); + if (col) cpack(col); + } + + /* draw edit particles last so that they can draw over child particles */ + if ((dflag & DRAW_PICKING) == 0 && + (!scene->obedit)) + { + + if (ob->mode & OB_MODE_PARTICLE_EDIT && is_obact) { + PTCacheEdit *edit = PE_create_current(scene, ob); + if (edit) { + glLoadMatrixf(rv3d->viewmat); + draw_update_ptcache_edit(scene, ob, edit); + draw_ptcache_edit(scene, v3d, edit); + glMultMatrixf(ob->obmat); + } + } + } + /* draw code for smoke, only draw domains */ if (smd && smd->domain) { SmokeDomainSettings *sds = smd->domain; - const bool show_smoke = true; /* XXX was checking cached frame range before */ + const bool show_smoke = (CFRA >= sds->point_cache[0]->startframe); float viewnormal[3]; glLoadMatrixf(rv3d->viewmat); |