diff options
Diffstat (limited to 'source/blender/editors/space_view3d/drawvolume.c')
-rw-r--r-- | source/blender/editors/space_view3d/drawvolume.c | 597 |
1 files changed, 295 insertions, 302 deletions
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index d6691f431dd..e93d840eddd 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -46,7 +46,9 @@ #include "BIF_gl.h" -#include "GPU_extensions.h" +#include "GPU_debug.h" +#include "GPU_shader.h" +#include "GPU_texture.h" #include "view3d_intern.h" // own include @@ -59,375 +61,366 @@ struct GPUTexture; # include "PIL_time_utildefines.h" #endif -static int intersect_edges(float (*points)[3], float a, float b, float c, float d, float edges[12][2][3]) +static GPUTexture *create_flame_spectrum_texture(void) { - int i; - float t; - int numpoints = 0; - - for (i = 0; i < 12; i++) { - t = -(a * edges[i][0][0] + b * edges[i][0][1] + c * edges[i][0][2] + d) / - (a * edges[i][1][0] + b * edges[i][1][1] + c * edges[i][1][2]); - if ((t > 0) && (t < 1)) { - points[numpoints][0] = edges[i][0][0] + edges[i][1][0] * t; - points[numpoints][1] = edges[i][0][1] + edges[i][1][1] * t; - points[numpoints][2] = edges[i][0][2] + edges[i][1][2] * t; - numpoints++; - } - } - return numpoints; -} - -static bool convex(const float p0[3], const float up[3], const float a[3], const float b[3]) -{ - /* Vec3 va = a-p0, vb = b-p0; */ - float va[3], vb[3], tmp[3]; - sub_v3_v3v3(va, a, p0); - sub_v3_v3v3(vb, b, p0); - cross_v3_v3v3(tmp, va, vb); - return dot_v3v3(up, tmp) >= 0; -} - -void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, - GPUTexture *tex, const float min[3], const float max[3], - const int res[3], float dx, float UNUSED(base_scale), const float viewnormal[3], - GPUTexture *tex_shadow, GPUTexture *tex_flame) -{ - const float ob_sizei[3] = { - 1.0f / fabsf(ob->size[0]), - 1.0f / fabsf(ob->size[1]), - 1.0f / fabsf(ob->size[2])}; - - int i, j, k, n, good_index; - float d /*, d0 */ /* UNUSED */, dd, ds; - float (*points)[3] = NULL; - int numpoints = 0; - float cor[3] = {1.0f, 1.0f, 1.0f}; - int gl_depth = 0, gl_blend = 0; - - const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) != 0; - - /* draw slices of smoke is adapted from c++ code authored - * by: Johannes Schmid and Ingemar Rask, 2006, johnny@grob.org */ - float cv[][3] = { - {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}, - {1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f} - }; - - /* edges have the form edges[n][0][xyz] + t*edges[n][1][xyz] */ - float edges[12][2][3] = { - {{1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, - {{-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, - {{-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, - {{1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, 2.0f}}, - - {{1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, - {{-1.0f, -1.0f, 1.0f}, {0.0f, 2.0f, 0.0f}}, - {{-1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, - {{1.0f, -1.0f, -1.0f}, {0.0f, 2.0f, 0.0f}}, - - {{-1.0f, 1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, - {{-1.0f, -1.0f, 1.0f}, {2.0f, 0.0f, 0.0f}}, - {{-1.0f, -1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}}, - {{-1.0f, 1.0f, -1.0f}, {2.0f, 0.0f, 0.0f}} - }; - - unsigned char *spec_data; - float *spec_pixels; - GPUTexture *tex_spec; - GPUProgram *smoke_program; - int progtype = (sds->active_fields & SM_ACTIVE_COLORS) ? GPU_PROGRAM_SMOKE_COLORED : GPU_PROGRAM_SMOKE; - float size[3]; - - if (!tex) { - printf("Could not allocate 3D texture for 3D View smoke drawing.\n"); - return; - } - -#ifdef DEBUG_DRAW_TIME - TIMEIT_START(draw); -#endif - - /* generate flame spectrum texture */ #define SPEC_WIDTH 256 #define FIRE_THRESH 7 #define MAX_FIRE_ALPHA 0.06f #define FULL_ON_FIRE 100 - spec_data = malloc(SPEC_WIDTH * 4 * sizeof(unsigned char)); - flame_get_spectrum(spec_data, SPEC_WIDTH, 1500, 3000); - spec_pixels = malloc(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float)); + + GPUTexture *tex; + int i, j, k; + float *spec_data = MEM_mallocN(SPEC_WIDTH * 4 * sizeof(float), "spec_data"); + float *spec_pixels = MEM_mallocN(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); + + blackbody_temperature_to_rgb_table(spec_data, SPEC_WIDTH, 1500, 3000); + for (i = 0; i < 16; i++) { for (j = 0; j < 16; j++) { for (k = 0; k < SPEC_WIDTH; k++) { int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4; if (k >= FIRE_THRESH) { - spec_pixels[index] = ((float)spec_data[k * 4]) / 255.0f; - spec_pixels[index + 1] = ((float)spec_data[k * 4 + 1]) / 255.0f; - spec_pixels[index + 2] = ((float)spec_data[k * 4 + 2]) / 255.0f; + spec_pixels[index] = (spec_data[k * 4]); + spec_pixels[index + 1] = (spec_data[k * 4 + 1]); + spec_pixels[index + 2] = (spec_data[k * 4 + 2]); spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); } else { - spec_pixels[index] = spec_pixels[index + 1] = spec_pixels[index + 2] = spec_pixels[index + 3] = 0.0f; + zero_v4(&spec_pixels[index]); } } } } - tex_spec = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); + tex = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); + + MEM_freeN(spec_data); + MEM_freeN(spec_pixels); #undef SPEC_WIDTH #undef FIRE_THRESH #undef MAX_FIRE_ALPHA #undef FULL_ON_FIRE - sub_v3_v3v3(size, max, min); - - /* maxx, maxy, maxz */ - cv[0][0] = max[0]; - cv[0][1] = max[1]; - cv[0][2] = max[2]; - /* minx, maxy, maxz */ - cv[1][0] = min[0]; - cv[1][1] = max[1]; - cv[1][2] = max[2]; - /* minx, miny, maxz */ - cv[2][0] = min[0]; - cv[2][1] = min[1]; - cv[2][2] = max[2]; - /* maxx, miny, maxz */ - cv[3][0] = max[0]; - cv[3][1] = min[1]; - cv[3][2] = max[2]; - - /* maxx, maxy, minz */ - cv[4][0] = max[0]; - cv[4][1] = max[1]; - cv[4][2] = min[2]; - /* minx, maxy, minz */ - cv[5][0] = min[0]; - cv[5][1] = max[1]; - cv[5][2] = min[2]; - /* minx, miny, minz */ - cv[6][0] = min[0]; - cv[6][1] = min[1]; - cv[6][2] = min[2]; - /* maxx, miny, minz */ - cv[7][0] = max[0]; - cv[7][1] = min[1]; - cv[7][2] = min[2]; - - copy_v3_v3(edges[0][0], cv[4]); /* maxx, maxy, minz */ - copy_v3_v3(edges[1][0], cv[5]); /* minx, maxy, minz */ - copy_v3_v3(edges[2][0], cv[6]); /* minx, miny, minz */ - copy_v3_v3(edges[3][0], cv[7]); /* maxx, miny, minz */ - - copy_v3_v3(edges[4][0], cv[3]); /* maxx, miny, maxz */ - copy_v3_v3(edges[5][0], cv[2]); /* minx, miny, maxz */ - copy_v3_v3(edges[6][0], cv[6]); /* minx, miny, minz */ - copy_v3_v3(edges[7][0], cv[7]); /* maxx, miny, minz */ - - copy_v3_v3(edges[8][0], cv[1]); /* minx, maxy, maxz */ - copy_v3_v3(edges[9][0], cv[2]); /* minx, miny, maxz */ - copy_v3_v3(edges[10][0], cv[6]); /* minx, miny, minz */ - copy_v3_v3(edges[11][0], cv[5]); /* minx, maxy, minz */ - - // printf("size x: %f, y: %f, z: %f\n", size[0], size[1], size[2]); - // printf("min[2]: %f, max[2]: %f\n", min[2], max[2]); - - edges[0][1][2] = size[2]; - edges[1][1][2] = size[2]; - edges[2][1][2] = size[2]; - edges[3][1][2] = size[2]; - - edges[4][1][1] = size[1]; - edges[5][1][1] = size[1]; - edges[6][1][1] = size[1]; - edges[7][1][1] = size[1]; - - edges[8][1][0] = size[0]; - edges[9][1][0] = size[0]; - edges[10][1][0] = size[0]; - edges[11][1][0] = size[0]; + return tex; +} - glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); - glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); +typedef struct VolumeSlicer { + float size[3]; + float min[3]; + float max[3]; + float (*verts)[3]; +} VolumeSlicer; - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); +/* *************************** View Aligned Slicing ************************** */ + +/* Code adapted from: + * "GPU-based Volume Rendering, Real-time Volume Graphics", AK Peters/CRC Press + */ +static int create_view_aligned_slices(VolumeSlicer *slicer, + const int num_slices, + const float view_dir[3]) +{ + const int indices[] = { 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5 }; + + const float vertices[8][3] = { + { slicer->min[0], slicer->min[1], slicer->min[2] }, + { slicer->max[0], slicer->min[1], slicer->min[2] }, + { slicer->max[0], slicer->max[1], slicer->min[2] }, + { slicer->min[0], slicer->max[1], slicer->min[2] }, + { slicer->min[0], slicer->min[1], slicer->max[2] }, + { slicer->max[0], slicer->min[1], slicer->max[2] }, + { slicer->max[0], slicer->max[1], slicer->max[2] }, + { slicer->min[0], slicer->max[1], slicer->max[2] } + }; + + const int edges[12][2] = { + { 0, 1 }, { 1, 2 }, { 2, 3 }, + { 3, 0 }, { 0, 4 }, { 1, 5 }, + { 2, 6 }, { 3, 7 }, { 4, 5 }, + { 5, 6 }, { 6, 7 }, { 7, 4 } + }; + + const int edge_list[8][12] = { + { 0, 1, 5, 6, 4, 8, 11, 9, 3, 7, 2, 10 }, + { 0, 4, 3, 11, 1, 2, 6, 7, 5, 9, 8, 10 }, + { 1, 5, 0, 8, 2, 3, 7, 4, 6, 10, 9, 11 }, + { 7, 11, 10, 8, 2, 6, 1, 9, 3, 0, 4, 5 }, + { 8, 5, 9, 1, 11, 10, 7, 6, 4, 3, 0, 2 }, + { 9, 6, 10, 2, 8, 11, 4, 7, 5, 0, 1, 3 }, + { 9, 8, 5, 4, 6, 1, 2, 0, 10, 7, 11, 3 }, + { 10, 9, 6, 5, 7, 2, 3, 1, 11, 4, 8, 0 } + }; - /* find cube vertex that is closest to the viewer */ - for (i = 0; i < 8; i++) { - float x, y, z; + /* find vertex that is the furthest from the view plane */ + int max_index = 0; + float max_dist, min_dist; + min_dist = max_dist = dot_v3v3(view_dir, vertices[0]); - x = cv[i][0] - viewnormal[0] * size[0] * 0.5f; - y = cv[i][1] - viewnormal[1] * size[1] * 0.5f; - z = cv[i][2] - viewnormal[2] * size[2] * 0.5f; + for (int i = 1; i < 8; i++) { + float dist = dot_v3v3(view_dir, vertices[i]); - if ((x >= min[0]) && (x <= max[0]) && - (y >= min[1]) && (y <= max[1]) && - (z >= min[2]) && (z <= max[2])) - { - break; + if (dist > max_dist) { + max_dist = dist; + max_index = i; + } + + if (dist < min_dist) { + min_dist = dist; } } - if (i >= 8) { - /* fallback, avoid using buffer over-run */ - i = 0; + max_dist -= FLT_EPSILON; + min_dist += FLT_EPSILON; + + /* start and direction vectors */ + float vec_start[12][3], vec_dir[12][3]; + /* lambda intersection values */ + float lambda[12], lambda_inc[12]; + float denom = 0.0f; + + float plane_dist = min_dist; + float plane_dist_inc = (max_dist - min_dist) / (float)num_slices; + + /* for all egdes */ + for (int i = 0; i < 12; i++) { + copy_v3_v3(vec_start[i], vertices[edges[edge_list[max_index][i]][0]]); + copy_v3_v3(vec_dir[i], vertices[edges[edge_list[max_index][i]][1]]); + sub_v3_v3(vec_dir[i], vec_start[i]); + + denom = dot_v3v3(vec_dir[i], view_dir); + + if (1.0f + denom != 1.0f) { + lambda_inc[i] = plane_dist_inc / denom; + lambda[i] = (plane_dist - dot_v3v3(vec_start[i], view_dir)) / denom; + } + else { + lambda[i] = -1.0f; + lambda_inc[i] = 0.0f; + } } - // printf("i: %d\n", i); - // printf("point %f, %f, %f\n", cv[i][0], cv[i][1], cv[i][2]); + float intersections[6][3]; + float dL[12]; + int num_points = 0; + /* find intersections for each slice, process them in back to front order */ + for (int i = 0; i < num_slices; i++) { + for (int e = 0; e < 12; e++) { + dL[e] = lambda[e] + i * lambda_inc[e]; + } + + if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) { + madd_v3_v3v3fl(intersections[0], vec_start[0], vec_dir[0], dL[0]); + } + else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) { + madd_v3_v3v3fl(intersections[0], vec_start[1], vec_dir[1], dL[1]); + } + else if ((dL[3] >= 0.0f) && (dL[3] < 1.0f)) { + madd_v3_v3v3fl(intersections[0], vec_start[3], vec_dir[3], dL[3]); + } + else continue; + + if ((dL[2] >= 0.0f) && (dL[2] < 1.0f)) { + madd_v3_v3v3fl(intersections[1], vec_start[2], vec_dir[2], dL[2]); + } + else if ((dL[0] >= 0.0f) && (dL[0] < 1.0f)) { + madd_v3_v3v3fl(intersections[1], vec_start[0], vec_dir[0], dL[0]); + } + else if ((dL[1] >= 0.0f) && (dL[1] < 1.0f)) { + madd_v3_v3v3fl(intersections[1], vec_start[1], vec_dir[1], dL[1]); + } + else { + madd_v3_v3v3fl(intersections[1], vec_start[3], vec_dir[3], dL[3]); + } + + if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) { + madd_v3_v3v3fl(intersections[2], vec_start[4], vec_dir[4], dL[4]); + } + else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) { + madd_v3_v3v3fl(intersections[2], vec_start[5], vec_dir[5], dL[5]); + } + else { + madd_v3_v3v3fl(intersections[2], vec_start[7], vec_dir[7], dL[7]); + } + + if ((dL[6] >= 0.0f) && (dL[6] < 1.0f)) { + madd_v3_v3v3fl(intersections[3], vec_start[6], vec_dir[6], dL[6]); + } + else if ((dL[4] >= 0.0f) && (dL[4] < 1.0f)) { + madd_v3_v3v3fl(intersections[3], vec_start[4], vec_dir[4], dL[4]); + } + else if ((dL[5] >= 0.0f) && (dL[5] < 1.0f)) { + madd_v3_v3v3fl(intersections[3], vec_start[5], vec_dir[5], dL[5]); + } + else { + madd_v3_v3v3fl(intersections[3], vec_start[7], vec_dir[7], dL[7]); + } + + if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) { + madd_v3_v3v3fl(intersections[4], vec_start[8], vec_dir[8], dL[8]); + } + else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) { + madd_v3_v3v3fl(intersections[4], vec_start[9], vec_dir[9], dL[9]); + } + else { + madd_v3_v3v3fl(intersections[4], vec_start[11], vec_dir[11], dL[11]); + } - smoke_program = GPU_shader_get_builtin_program(progtype); - if (smoke_program) { - GPU_program_bind(smoke_program); + if ((dL[10] >= 0.0f) && (dL[10] < 1.0f)) { + madd_v3_v3v3fl(intersections[5], vec_start[10], vec_dir[10], dL[10]); + } + else if ((dL[8] >= 0.0f) && (dL[8] < 1.0f)) { + madd_v3_v3v3fl(intersections[5], vec_start[8], vec_dir[8], dL[8]); + } + else if ((dL[9] >= 0.0f) && (dL[9] < 1.0f)) { + madd_v3_v3v3fl(intersections[5], vec_start[9], vec_dir[9], dL[9]); + } + else { + madd_v3_v3v3fl(intersections[5], vec_start[11], vec_dir[11], dL[11]); + } - /* cell spacing */ - GPU_program_parameter_4f(smoke_program, 0, dx, dx, dx, 1.0); - /* custom parameter for smoke style (higher = thicker) */ - if (sds->active_fields & SM_ACTIVE_COLORS) - GPU_program_parameter_4f(smoke_program, 1, 1.0, 1.0, 1.0, 10.0); - else - GPU_program_parameter_4f(smoke_program, 1, sds->active_color[0], sds->active_color[1], sds->active_color[2], 10.0); + for (int e = 0; e < 12; e++) { + copy_v3_v3(slicer->verts[num_points++], intersections[indices[e]]); + } } - else - printf("Your gfx card does not support 3D View smoke drawing.\n"); - GPU_texture_bind(tex, 0); - if (tex_shadow) - GPU_texture_bind(tex_shadow, 1); - else - printf("No volume shadow\n"); + return num_points; +} - if (tex_flame) { - GPU_texture_bind(tex_flame, 2); - GPU_texture_bind(tex_spec, 3); +void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, + const float min[3], const float max[3], + const float viewnormal[3]) +{ + if (!sds->tex || !sds->tex_shadow) { + fprintf(stderr, "Could not allocate 3D texture for volume rendering!\n"); + return; } - if (!GPU_non_power_of_two_support()) { - cor[0] = (float)res[0] / (float)power_of_2_max_u(res[0]); - cor[1] = (float)res[1] / (float)power_of_2_max_u(res[1]); - cor[2] = (float)res[2] / (float)power_of_2_max_u(res[2]); + const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame; + + GPUShader *shader = GPU_shader_get_builtin_shader( + (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE); + + if (!shader) { + fprintf(stderr, "Unable to create GLSL smoke shader.\n"); + return; } - cor[0] /= size[0]; - cor[1] /= size[1]; - cor[2] /= size[2]; + const float ob_sizei[3] = { + 1.0f / fabsf(ob->size[0]), + 1.0f / fabsf(ob->size[1]), + 1.0f / fabsf(ob->size[2]) + }; + + const float size[3] = { max[0] - min[0], max[1] - min[1], max[2] - min[2] }; + const float invsize[3] = { 1.0f / size[0], 1.0f / size[1], 1.0f / size[2] }; - /* our slices are defined by the plane equation a*x + b*y +c*z + d = 0 - * (a,b,c), the plane normal, are given by viewdir - * d is the parameter along the view direction. the first d is given by - * inserting previously found vertex into the plane equation */ +#ifdef DEBUG_DRAW_TIME + TIMEIT_START(draw); +#endif - /* d0 = (viewnormal[0]*cv[i][0] + viewnormal[1]*cv[i][1] + viewnormal[2]*cv[i][2]); */ /* UNUSED */ - ds = (fabsf(viewnormal[0]) * size[0] + fabsf(viewnormal[1]) * size[1] + fabsf(viewnormal[2]) * size[2]); - dd = max_fff(sds->global_size[0], sds->global_size[1], sds->global_size[2]) / 128.f; - n = 0; - good_index = i; + /* setup smoke shader */ - // printf("d0: %f, dd: %f, ds: %f\n\n", d0, dd, ds); + int soot_location = GPU_shader_get_uniform(shader, "soot_texture"); + int spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); + int shadow_location = GPU_shader_get_uniform(shader, "shadow_texture"); + int flame_location = GPU_shader_get_uniform(shader, "flame_texture"); + int actcol_location = GPU_shader_get_uniform(shader, "active_color"); + int stepsize_location = GPU_shader_get_uniform(shader, "step_size"); + int densityscale_location = GPU_shader_get_uniform(shader, "density_scale"); + int invsize_location = GPU_shader_get_uniform(shader, "invsize"); + int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei"); + int min_location = GPU_shader_get_uniform(shader, "min_location"); - points = MEM_callocN(sizeof(*points) * 12, "smoke_points_preview"); + GPU_shader_bind(shader); - while (1) { - float p0[3]; - float tmp_point[3], tmp_point2[3]; + GPU_texture_bind(sds->tex, 0); + GPU_shader_uniform_texture(shader, soot_location, sds->tex); - if (dd * (float)n > ds) - break; + GPU_texture_bind(sds->tex_shadow, 1); + GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow); - copy_v3_v3(tmp_point, viewnormal); - mul_v3_fl(tmp_point, -dd * ((ds / dd) - (float)n)); - add_v3_v3v3(tmp_point2, cv[good_index], tmp_point); - d = dot_v3v3(tmp_point2, viewnormal); + GPUTexture *tex_spec = NULL; - // printf("my d: %f\n", d); + if (use_fire) { + GPU_texture_bind(sds->tex_flame, 2); + GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame); - /* intersect_edges returns the intersection points of all cube edges with - * the given plane that lie within the cube */ - numpoints = intersect_edges(points, viewnormal[0], viewnormal[1], viewnormal[2], -d, edges); + tex_spec = create_flame_spectrum_texture(); + GPU_texture_bind(tex_spec, 3); + GPU_shader_uniform_texture(shader, spec_location, tex_spec); + } - // printf("points: %d\n", numpoints); + float active_color[3] = { 0.9, 0.9, 0.9 }; + float density_scale = 10.0f; + if ((sds->active_fields & SM_ACTIVE_COLORS) == 0) + mul_v3_v3(active_color, sds->active_color); - if (numpoints > 2) { - copy_v3_v3(p0, points[0]); + GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color); + GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx); + GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale); + GPU_shader_uniform_vector(shader, min_location, 3, 1, min); + GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei); + GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); - /* sort points to get a convex polygon */ - for (i = 1; i < numpoints - 1; i++) { - for (j = i + 1; j < numpoints; j++) { - if (!convex(p0, viewnormal, points[j], points[i])) { - swap_v3_v3(points[i], points[j]); - } - } - } + /* setup slicing information */ - /* render fire slice */ - if (use_fire) { - if (GLEW_VERSION_1_4) - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE); - else - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - - GPU_program_parameter_4f(smoke_program, 2, 1.0, 0.0, 0.0, 0.0); - glBegin(GL_POLYGON); - glColor3f(1.0, 1.0, 1.0); - for (i = 0; i < numpoints; i++) { - glTexCoord3d((points[i][0] - min[0]) * cor[0], - (points[i][1] - min[1]) * cor[1], - (points[i][2] - min[2]) * cor[2]); - glVertex3f(points[i][0] * ob_sizei[0], - points[i][1] * ob_sizei[1], - points[i][2] * ob_sizei[2]); - } - glEnd(); - } + const int max_slices = 256; + const int max_points = max_slices * 12; - /* render smoke slice */ - if (GLEW_VERSION_1_4) - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - else - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - GPU_program_parameter_4f(smoke_program, 2, -1.0, 0.0, 0.0, 0.0); - glBegin(GL_POLYGON); - glColor3f(1.0, 1.0, 1.0); - for (i = 0; i < numpoints; i++) { - glTexCoord3d((points[i][0] - min[0]) * cor[0], - (points[i][1] - min[1]) * cor[1], - (points[i][2] - min[2]) * cor[2]); - glVertex3f(points[i][0] * ob_sizei[0], - points[i][1] * ob_sizei[1], - points[i][2] * ob_sizei[2]); - } - glEnd(); - } - n++; - } + VolumeSlicer slicer; + copy_v3_v3(slicer.min, min); + copy_v3_v3(slicer.max, max); + copy_v3_v3(slicer.size, size); + slicer.verts = MEM_mallocN(sizeof(float) * 3 * max_points, "smoke_slice_vertices"); + + const int num_points = create_view_aligned_slices(&slicer, max_slices, viewnormal); + + /* setup buffer and draw */ + + int gl_depth = 0, gl_blend = 0; + glGetBooleanv(GL_BLEND, (GLboolean *)&gl_blend); + glGetBooleanv(GL_DEPTH_TEST, (GLboolean *)&gl_depth); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + GLuint vertex_buffer; + glGenBuffers(1, &vertex_buffer); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer.verts[0][0], GL_STATIC_DRAW); + + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, NULL); + + glDrawArrays(GL_TRIANGLES, 0, num_points); + + glDisableClientState(GL_VERTEX_ARRAY); #ifdef DEBUG_DRAW_TIME printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw)); TIMEIT_END(draw); #endif - if (tex_shadow) - GPU_texture_unbind(tex_shadow); - GPU_texture_unbind(tex); - if (tex_flame) { - GPU_texture_unbind(tex_flame); - GPU_texture_unbind(tex_spec); - } - GPU_texture_free(tex_spec); + /* cleanup */ + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &vertex_buffer); - free(spec_data); - free(spec_pixels); + GPU_texture_unbind(sds->tex); + GPU_texture_unbind(sds->tex_shadow); - if (smoke_program) - GPU_program_unbind(smoke_program); + if (use_fire) { + GPU_texture_unbind(sds->tex_flame); + GPU_texture_unbind(tex_spec); + GPU_texture_free(tex_spec); + } + MEM_freeN(slicer.verts); - MEM_freeN(points); + GPU_shader_unbind(); if (!gl_blend) { glDisable(GL_BLEND); |