diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_draw.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_draw.c | 297 |
1 files changed, 232 insertions, 65 deletions
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index 7902c5296aa..685b929ac93 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -62,7 +62,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "BKE_bmfont.h" +#include "BKE_colorband.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_main.h" @@ -883,6 +883,192 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i BKE_image_release_ibuf(ima, ibuf, NULL); } +/* *************************** Transfer functions *************************** */ + +enum { + TFUNC_FLAME_SPECTRUM = 0, + TFUNC_COLOR_RAMP = 1, +}; + +#define TFUNC_WIDTH 256 + +#ifdef WITH_SMOKE +static void create_flame_spectrum_texture(float *data) +{ +#define FIRE_THRESH 7 +#define MAX_FIRE_ALPHA 0.06f +#define FULL_ON_FIRE 100 + + float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); + + blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000); + + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + for (int k = 0; k < TFUNC_WIDTH; k++) { + int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4; + if (k >= FIRE_THRESH) { + spec_pixels[index] = (data[k * 4]); + spec_pixels[index + 1] = (data[k * 4 + 1]); + spec_pixels[index + 2] = (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 { + zero_v4(&spec_pixels[index]); + } + } + } + } + + memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH); + + MEM_freeN(spec_pixels); + +#undef FIRE_THRESH +#undef MAX_FIRE_ALPHA +#undef FULL_ON_FIRE +} + +static void create_color_ramp(const ColorBand *coba, float *data) +{ + for (int i = 0; i < TFUNC_WIDTH; i++) { + BKE_colorband_evaluate(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); + } +} + +static GPUTexture *create_transfer_function(int type, const ColorBand *coba) +{ + float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__); + + switch (type) { + case TFUNC_FLAME_SPECTRUM: + create_flame_spectrum_texture(data); + break; + case TFUNC_COLOR_RAMP: + create_color_ramp(coba, data); + break; + } + + GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, GPU_RGBA8, data, NULL); + + MEM_freeN(data); + + return tex; +} + +static void swizzle_texture_channel_rrrr(GPUTexture *tex) +{ + GPU_texture_bind(tex, 0); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_unbind(tex); +} + +static GPUTexture *create_field_texture(SmokeDomainSettings *sds) +{ + float *field = NULL; + + switch (sds->coba_field) { + case FLUID_FIELD_DENSITY: field = smoke_get_density(sds->fluid); break; + case FLUID_FIELD_HEAT: field = smoke_get_heat(sds->fluid); break; + case FLUID_FIELD_FUEL: field = smoke_get_fuel(sds->fluid); break; + case FLUID_FIELD_REACT: field = smoke_get_react(sds->fluid); break; + case FLUID_FIELD_FLAME: field = smoke_get_flame(sds->fluid); break; + case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break; + case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break; + case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break; + case FLUID_FIELD_COLOR_R: field = smoke_get_color_r(sds->fluid); break; + case FLUID_FIELD_COLOR_G: field = smoke_get_color_g(sds->fluid); break; + case FLUID_FIELD_COLOR_B: field = smoke_get_color_b(sds->fluid); break; + case FLUID_FIELD_FORCE_X: field = smoke_get_force_x(sds->fluid); break; + case FLUID_FIELD_FORCE_Y: field = smoke_get_force_y(sds->fluid); break; + case FLUID_FIELD_FORCE_Z: field = smoke_get_force_z(sds->fluid); break; + default: return NULL; + } + + GPUTexture *tex = GPU_texture_create_nD( + sds->res[0], sds->res[1], sds->res[2], 3, + field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + + swizzle_texture_channel_rrrr(tex); + return tex; +} + +static GPUTexture *create_density_texture(SmokeDomainSettings *sds, int highres) +{ + float *data = NULL, *source; + int cell_count = (highres) ? smoke_turbulence_get_cells(sds->wt) : sds->total_cells; + const bool has_color = (highres) ? smoke_turbulence_has_colors(sds->wt) : smoke_has_colors(sds->fluid); + int *dim = (highres) ? sds->res_wt : sds->res; + GPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8; + + if (has_color) { + data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture"); + } + + if (highres) { + if (has_color) { + smoke_turbulence_get_rgba(sds->wt, data, 0); + } + else { + source = smoke_turbulence_get_density(sds->wt); + } + } + else { + if (has_color) { + smoke_get_rgba(sds->fluid, data, 0); + } + else { + source = smoke_get_density(sds->fluid); + } + } + + GPUTexture *tex = GPU_texture_create_nD( + dim[0], dim[1], dim[2], 3, + (data) ? data : source, + format, GPU_DATA_FLOAT, 0, true, NULL); + if (data) { + MEM_freeN(data); + } + + if (format == GPU_R8) { + /* Swizzle the RGBA components to read the Red channel so + * that the shader stay the same for colored and non color + * density textures. */ + swizzle_texture_channel_rrrr(tex); + } + return tex; +} + +static GPUTexture *create_flame_texture(SmokeDomainSettings *sds, int highres) +{ + float *source = NULL; + const bool has_fuel = (highres) ? smoke_turbulence_has_fuel(sds->wt) : smoke_has_fuel(sds->fluid); + int *dim = (highres) ? sds->res_wt : sds->res; + + if (!has_fuel) + return NULL; + + if (highres) { + source = smoke_turbulence_get_flame(sds->wt); + } + else { + source = smoke_get_flame(sds->fluid); + } + + GPUTexture *tex = GPU_texture_create_nD( + dim[0], dim[1], dim[2], 3, + source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + + swizzle_texture_channel_rrrr(tex); + + return tex; +} +#endif /* WITH_SMOKE */ + void GPU_free_smoke(SmokeModifierData *smd) { if (smd->type & MOD_SMOKE_TYPE_DOMAIN && smd->domain) { @@ -897,85 +1083,66 @@ void GPU_free_smoke(SmokeModifierData *smd) if (smd->domain->tex_flame) GPU_texture_free(smd->domain->tex_flame); smd->domain->tex_flame = NULL; + + if (smd->domain->tex_flame_coba) + GPU_texture_free(smd->domain->tex_flame_coba); + smd->domain->tex_flame_coba = NULL; + + if (smd->domain->tex_coba) + GPU_texture_free(smd->domain->tex_coba); + smd->domain->tex_coba = NULL; + + if (smd->domain->tex_field) + GPU_texture_free(smd->domain->tex_field); + smd->domain->tex_field = NULL; } } -void GPU_create_smoke(SmokeModifierData *smd, int highres) +void GPU_create_smoke_coba_field(SmokeModifierData *smd) { #ifdef WITH_SMOKE if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { SmokeDomainSettings *sds = smd->domain; - if (!sds->tex && !highres) { - /* rgba texture for color + density */ - if (smoke_has_colors(sds->fluid)) { - float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture"); - smoke_get_rgba(sds->fluid, data, 0); - sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], GPU_RGBA8, data, NULL); - MEM_freeN(data); - } - /* density only */ - else { - sds->tex = GPU_texture_create_3D( - sds->res[0], sds->res[1], sds->res[2], - GPU_R8, smoke_get_density(sds->fluid), NULL); - - /* Swizzle the RGBA components to read the Red channel so - * that the shader stay the same for colored and non color - * density textures. */ - GPU_texture_bind(sds->tex, 0); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); - GPU_texture_unbind(sds->tex); - } - sds->tex_flame = ( - smoke_has_fuel(sds->fluid) ? - GPU_texture_create_3D( - sds->res[0], sds->res[1], sds->res[2], - GPU_R8, smoke_get_flame(sds->fluid), NULL) : - NULL); + + if (!sds->tex_field) { + sds->tex_field = create_field_texture(sds); } - else if (!sds->tex && highres) { - /* rgba texture for color + density */ - if (smoke_turbulence_has_colors(sds->wt)) { - float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture"); - smoke_turbulence_get_rgba(sds->wt, data, 0); - sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], GPU_RGBA8, data, NULL); - MEM_freeN(data); - } - /* density only */ - else { - sds->tex = GPU_texture_create_3D( - sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], - GPU_R8, smoke_turbulence_get_density(sds->wt), NULL); - - /* Swizzle the RGBA components to read the Red channel so - * that the shader stay the same for colored and non color - * density textures. */ - GPU_texture_bind(sds->tex, 0); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); - GPU_texture_unbind(sds->tex); - } - sds->tex_flame = ( - smoke_turbulence_has_fuel(sds->wt) ? - GPU_texture_create_3D( - sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], - GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL) : - NULL); + if (!sds->tex_coba) { + sds->tex_coba = create_transfer_function(TFUNC_COLOR_RAMP, sds->coba); } + } +#else // WITH_SMOKE + smd->domain->tex_field = NULL; +#endif // WITH_SMOKE +} - sds->tex_shadow = GPU_texture_create_3D( - sds->res[0], sds->res[1], sds->res[2], - GPU_R8, sds->shadow, NULL); +void GPU_create_smoke(SmokeModifierData *smd, int highres) +{ +#ifdef WITH_SMOKE + if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { + SmokeDomainSettings *sds = smd->domain; + + if (!sds->tex) { + sds->tex = create_density_texture(sds, highres); + } + if (!sds->tex_flame) { + sds->tex_flame = create_flame_texture(sds, highres); + } + if (!sds->tex_flame_coba && sds->tex_flame) { + sds->tex_flame_coba = create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL); + } + if (!sds->tex_shadow) { + sds->tex_shadow = GPU_texture_create_nD( + sds->res[0], sds->res[1], sds->res[2], 3, + sds->shadow, + GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + } } #else // WITH_SMOKE (void)highres; smd->domain->tex = NULL; smd->domain->tex_flame = NULL; + smd->domain->tex_flame_coba = NULL; smd->domain->tex_shadow = NULL; #endif // WITH_SMOKE } |