The goal is to make it more explicit and centralized operation to assign and steal buffer data, with proper ownership tracking. The buffers and ownership flags are wrapped into their dedicated structures now. There should be no functional changes currently, it is a preparation for allowing implicit sharing of the ImBuf buffers. Additionally, in the future it is possible to more buffer-specific information (such as color space) next to the buffer data itself. It is also possible to clean up the allocation flags (IB_rect, ...) to give them more clear naming and not have stored in the ImBuf->flags as they are only needed for allocation. The most dangerous part of this change is the change of byte buffer data from `int*` to `uint8_t*`. In a lot of cases the byte buffer was cast to `uchar*`, so those casts are now gone. But some code is operating on `int*` so now there are casts in there. In practice this should be fine, since we only support 64bit platforms, so allocations are aligned. The real things to watch out for here is the fact that allocation and offsetting from the byte buffer now need an explicit 4 channel multiplier. Once everything is C++ it will be possible to simplify public functions even further. Pull Request: https://projects.blender.org/blender/blender/pulls/107609
1375 lines
37 KiB
C
1375 lines
37 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
|
|
|
|
/** \file
|
|
* \ingroup render
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "BLI_math.h"
|
|
#include "BLI_noise.h"
|
|
#include "BLI_rand.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "DNA_anim_types.h"
|
|
#include "DNA_image_types.h"
|
|
#include "DNA_light_types.h"
|
|
#include "DNA_material_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_node_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_texture_types.h"
|
|
|
|
#include "IMB_colormanagement.h"
|
|
#include "IMB_imbuf_types.h"
|
|
|
|
#include "BKE_colorband.h"
|
|
#include "BKE_image.h"
|
|
#include "BKE_material.h"
|
|
#include "BKE_node.h"
|
|
#include "BKE_scene.h"
|
|
#include "BKE_texture.h"
|
|
|
|
#include "NOD_texture.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "texture_common.h"
|
|
|
|
#include "RE_texture.h"
|
|
|
|
static RNG_THREAD_ARRAY *random_tex_array;
|
|
|
|
void RE_texture_rng_init(void)
|
|
{
|
|
random_tex_array = BLI_rng_threaded_new();
|
|
}
|
|
|
|
void RE_texture_rng_exit(void)
|
|
{
|
|
if (random_tex_array == NULL) {
|
|
return;
|
|
}
|
|
BLI_rng_threaded_free(random_tex_array);
|
|
random_tex_array = NULL;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static int blend(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
float x, y, t;
|
|
|
|
if (tex->flag & TEX_FLIPBLEND) {
|
|
x = texvec[1];
|
|
y = texvec[0];
|
|
}
|
|
else {
|
|
x = texvec[0];
|
|
y = texvec[1];
|
|
}
|
|
|
|
if (tex->stype == TEX_LIN) { /* Linear. */
|
|
texres->tin = (1.0f + x) / 2.0f;
|
|
}
|
|
else if (tex->stype == TEX_QUAD) { /* Quadratic. */
|
|
texres->tin = (1.0f + x) / 2.0f;
|
|
if (texres->tin < 0.0f) {
|
|
texres->tin = 0.0f;
|
|
}
|
|
else {
|
|
texres->tin *= texres->tin;
|
|
}
|
|
}
|
|
else if (tex->stype == TEX_EASE) { /* Ease. */
|
|
texres->tin = (1.0f + x) / 2.0f;
|
|
if (texres->tin <= 0.0f) {
|
|
texres->tin = 0.0f;
|
|
}
|
|
else if (texres->tin >= 1.0f) {
|
|
texres->tin = 1.0f;
|
|
}
|
|
else {
|
|
t = texres->tin * texres->tin;
|
|
texres->tin = (3.0f * t - 2.0f * t * texres->tin);
|
|
}
|
|
}
|
|
else if (tex->stype == TEX_DIAG) { /* Diagonal. */
|
|
texres->tin = (2.0f + x + y) / 4.0f;
|
|
}
|
|
else if (tex->stype == TEX_RAD) { /* Radial. */
|
|
texres->tin = (atan2f(y, x) / (float)(2 * M_PI) + 0.5f);
|
|
}
|
|
else { /* sphere TEX_SPHERE */
|
|
texres->tin = 1.0f - sqrtf(x * x + y * y + texvec[2] * texvec[2]);
|
|
if (texres->tin < 0.0f) {
|
|
texres->tin = 0.0f;
|
|
}
|
|
if (tex->stype == TEX_HALO) {
|
|
texres->tin *= texres->tin; /* Halo. */
|
|
}
|
|
}
|
|
|
|
BRICONT;
|
|
|
|
return TEX_INT;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* ************************************************************************* */
|
|
|
|
/* newnoise: all noise-based types now have different noise-bases to choose from. */
|
|
|
|
static int clouds(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
int rv = TEX_INT;
|
|
|
|
texres->tin = BLI_noise_generic_turbulence(tex->noisesize,
|
|
texvec[0],
|
|
texvec[1],
|
|
texvec[2],
|
|
tex->noisedepth,
|
|
(tex->noisetype != TEX_NOISESOFT),
|
|
tex->noisebasis);
|
|
|
|
if (tex->stype == TEX_COLOR) {
|
|
texres->trgba[0] = texres->tin;
|
|
texres->trgba[1] = BLI_noise_generic_turbulence(tex->noisesize,
|
|
texvec[1],
|
|
texvec[0],
|
|
texvec[2],
|
|
tex->noisedepth,
|
|
(tex->noisetype != TEX_NOISESOFT),
|
|
tex->noisebasis);
|
|
texres->trgba[2] = BLI_noise_generic_turbulence(tex->noisesize,
|
|
texvec[1],
|
|
texvec[2],
|
|
texvec[0],
|
|
tex->noisedepth,
|
|
(tex->noisetype != TEX_NOISESOFT),
|
|
tex->noisebasis);
|
|
BRICONTRGB;
|
|
texres->trgba[3] = 1.0;
|
|
return (rv | TEX_RGB);
|
|
}
|
|
|
|
BRICONT;
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* creates a sine wave */
|
|
static float tex_sin(float a)
|
|
{
|
|
a = 0.5f + 0.5f * sinf(a);
|
|
|
|
return a;
|
|
}
|
|
|
|
/* creates a saw wave */
|
|
static float tex_saw(float a)
|
|
{
|
|
const float b = 2 * M_PI;
|
|
|
|
int n = (int)(a / b);
|
|
a -= n * b;
|
|
if (a < 0) {
|
|
a += b;
|
|
}
|
|
return a / b;
|
|
}
|
|
|
|
/* creates a triangle wave */
|
|
static float tex_tri(float a)
|
|
{
|
|
const float b = 2 * M_PI;
|
|
const float rmax = 1.0;
|
|
|
|
a = rmax - 2.0f * fabsf(floorf((a * (1.0f / b)) + 0.5f) - (a * (1.0f / b)));
|
|
|
|
return a;
|
|
}
|
|
|
|
/* computes basic wood intensity value at x,y,z */
|
|
static float wood_int(const Tex *tex, float x, float y, float z)
|
|
{
|
|
float wi = 0;
|
|
/* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */
|
|
short wf = tex->noisebasis2;
|
|
/* wood type: TEX_BAND=0, TEX_RING=1, TEX_BANDNOISE=2, TEX_RINGNOISE=3 */
|
|
short wt = tex->stype;
|
|
|
|
float (*waveform[3])(float); /* create array of pointers to waveform functions */
|
|
waveform[0] = tex_sin; /* assign address of tex_sin() function to pointer array */
|
|
waveform[1] = tex_saw;
|
|
waveform[2] = tex_tri;
|
|
|
|
if ((wf > TEX_TRI) || (wf < TEX_SIN)) {
|
|
wf = 0; /* check to be sure noisebasis2 is initialized ahead of time */
|
|
}
|
|
|
|
if (wt == TEX_BAND) {
|
|
wi = waveform[wf]((x + y + z) * 10.0f);
|
|
}
|
|
else if (wt == TEX_RING) {
|
|
wi = waveform[wf](sqrtf(x * x + y * y + z * z) * 20.0f);
|
|
}
|
|
else if (wt == TEX_BANDNOISE) {
|
|
wi = tex->turbul *
|
|
BLI_noise_generic_noise(
|
|
tex->noisesize, x, y, z, (tex->noisetype != TEX_NOISESOFT), tex->noisebasis);
|
|
wi = waveform[wf]((x + y + z) * 10.0f + wi);
|
|
}
|
|
else if (wt == TEX_RINGNOISE) {
|
|
wi = tex->turbul *
|
|
BLI_noise_generic_noise(
|
|
tex->noisesize, x, y, z, (tex->noisetype != TEX_NOISESOFT), tex->noisebasis);
|
|
wi = waveform[wf](sqrtf(x * x + y * y + z * z) * 20.0f + wi);
|
|
}
|
|
|
|
return wi;
|
|
}
|
|
|
|
static int wood(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
int rv = TEX_INT;
|
|
|
|
texres->tin = wood_int(tex, texvec[0], texvec[1], texvec[2]);
|
|
|
|
BRICONT;
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* computes basic marble intensity at x,y,z */
|
|
static float marble_int(const Tex *tex, float x, float y, float z)
|
|
{
|
|
float n, mi;
|
|
short wf = tex->noisebasis2; /* wave form: TEX_SIN=0, TEX_SAW=1, TEX_TRI=2 */
|
|
short mt = tex->stype; /* marble type: TEX_SOFT=0, TEX_SHARP=1, TEX_SHAPER=2 */
|
|
|
|
float (*waveform[3])(float); /* create array of pointers to waveform functions */
|
|
waveform[0] = tex_sin; /* assign address of tex_sin() function to pointer array */
|
|
waveform[1] = tex_saw;
|
|
waveform[2] = tex_tri;
|
|
|
|
if ((wf > TEX_TRI) || (wf < TEX_SIN)) {
|
|
wf = 0; /* check to be sure noisebasis2 isn't initialized ahead of time */
|
|
}
|
|
|
|
n = 5.0f * (x + y + z);
|
|
|
|
mi = n + tex->turbul * BLI_noise_generic_turbulence(tex->noisesize,
|
|
x,
|
|
y,
|
|
z,
|
|
tex->noisedepth,
|
|
(tex->noisetype != TEX_NOISESOFT),
|
|
tex->noisebasis);
|
|
|
|
if (mt >= TEX_SOFT) { /* TEX_SOFT always true */
|
|
mi = waveform[wf](mi);
|
|
if (mt == TEX_SHARP) {
|
|
mi = sqrtf(mi);
|
|
}
|
|
else if (mt == TEX_SHARPER) {
|
|
mi = sqrtf(sqrtf(mi));
|
|
}
|
|
}
|
|
|
|
return mi;
|
|
}
|
|
|
|
static int marble(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
int rv = TEX_INT;
|
|
|
|
texres->tin = marble_int(tex, texvec[0], texvec[1], texvec[2]);
|
|
|
|
BRICONT;
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static int magic(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
float x, y, z, turb;
|
|
int n;
|
|
|
|
n = tex->noisedepth;
|
|
turb = tex->turbul / 5.0f;
|
|
|
|
x = sinf((texvec[0] + texvec[1] + texvec[2]) * 5.0f);
|
|
y = cosf((-texvec[0] + texvec[1] - texvec[2]) * 5.0f);
|
|
z = -cosf((-texvec[0] - texvec[1] + texvec[2]) * 5.0f);
|
|
if (n > 0) {
|
|
x *= turb;
|
|
y *= turb;
|
|
z *= turb;
|
|
y = -cosf(x - y + z);
|
|
y *= turb;
|
|
if (n > 1) {
|
|
x = cosf(x - y - z);
|
|
x *= turb;
|
|
if (n > 2) {
|
|
z = sinf(-x - y - z);
|
|
z *= turb;
|
|
if (n > 3) {
|
|
x = -cosf(-x + y - z);
|
|
x *= turb;
|
|
if (n > 4) {
|
|
y = -sinf(-x + y + z);
|
|
y *= turb;
|
|
if (n > 5) {
|
|
y = -cosf(-x + y + z);
|
|
y *= turb;
|
|
if (n > 6) {
|
|
x = cosf(x + y + z);
|
|
x *= turb;
|
|
if (n > 7) {
|
|
z = sinf(x + y - z);
|
|
z *= turb;
|
|
if (n > 8) {
|
|
x = -cosf(-x - y + z);
|
|
x *= turb;
|
|
if (n > 9) {
|
|
y = -sinf(x - y + z);
|
|
y *= turb;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (turb != 0.0f) {
|
|
turb *= 2.0f;
|
|
x /= turb;
|
|
y /= turb;
|
|
z /= turb;
|
|
}
|
|
texres->trgba[0] = 0.5f - x;
|
|
texres->trgba[1] = 0.5f - y;
|
|
texres->trgba[2] = 0.5f - z;
|
|
|
|
texres->tin = (1.0f / 3.0f) * (texres->trgba[0] + texres->trgba[1] + texres->trgba[2]);
|
|
|
|
BRICONTRGB;
|
|
texres->trgba[3] = 1.0f;
|
|
|
|
return TEX_RGB;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
/* newnoise: stucci also modified to use different noisebasis */
|
|
static int stucci(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
float b2, ofs;
|
|
int retval = TEX_INT;
|
|
|
|
b2 = BLI_noise_generic_noise(tex->noisesize,
|
|
texvec[0],
|
|
texvec[1],
|
|
texvec[2],
|
|
(tex->noisetype != TEX_NOISESOFT),
|
|
tex->noisebasis);
|
|
|
|
ofs = tex->turbul / 200.0f;
|
|
|
|
if (tex->stype) {
|
|
ofs *= (b2 * b2);
|
|
}
|
|
|
|
texres->tin = BLI_noise_generic_noise(tex->noisesize,
|
|
texvec[0],
|
|
texvec[1],
|
|
texvec[2] + ofs,
|
|
(tex->noisetype != TEX_NOISESOFT),
|
|
tex->noisebasis);
|
|
|
|
if (tex->stype == TEX_WALLOUT) {
|
|
texres->tin = 1.0f - texres->tin;
|
|
}
|
|
|
|
if (texres->tin < 0.0f) {
|
|
texres->tin = 0.0f;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* newnoise: musgrave terrain noise types */
|
|
|
|
static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
int rv = TEX_INT;
|
|
float (*mgravefunc)(float, float, float, float, float, float, int);
|
|
|
|
if (tex->stype == TEX_MFRACTAL) {
|
|
mgravefunc = BLI_noise_mg_multi_fractal;
|
|
}
|
|
else {
|
|
mgravefunc = BLI_noise_mg_fbm;
|
|
}
|
|
|
|
texres->tin = tex->ns_outscale * mgravefunc(texvec[0],
|
|
texvec[1],
|
|
texvec[2],
|
|
tex->mg_H,
|
|
tex->mg_lacunarity,
|
|
tex->mg_octaves,
|
|
tex->noisebasis);
|
|
|
|
BRICONT;
|
|
|
|
return rv;
|
|
}
|
|
|
|
static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
int rv = TEX_INT;
|
|
float (*mgravefunc)(float, float, float, float, float, float, float, float, int);
|
|
|
|
if (tex->stype == TEX_RIDGEDMF) {
|
|
mgravefunc = BLI_noise_mg_ridged_multi_fractal;
|
|
}
|
|
else {
|
|
mgravefunc = BLI_noise_mg_hybrid_multi_fractal;
|
|
}
|
|
|
|
texres->tin = tex->ns_outscale * mgravefunc(texvec[0],
|
|
texvec[1],
|
|
texvec[2],
|
|
tex->mg_H,
|
|
tex->mg_lacunarity,
|
|
tex->mg_octaves,
|
|
tex->mg_offset,
|
|
tex->mg_gain,
|
|
tex->noisebasis);
|
|
|
|
BRICONT;
|
|
|
|
return rv;
|
|
}
|
|
|
|
static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
int rv = TEX_INT;
|
|
|
|
texres->tin = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0],
|
|
texvec[1],
|
|
texvec[2],
|
|
tex->mg_H,
|
|
tex->mg_lacunarity,
|
|
tex->mg_octaves,
|
|
tex->mg_offset,
|
|
tex->noisebasis);
|
|
|
|
BRICONT;
|
|
|
|
return rv;
|
|
}
|
|
|
|
static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
int rv = TEX_INT;
|
|
|
|
texres->tin = BLI_noise_mg_variable_lacunarity(
|
|
texvec[0], texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2);
|
|
|
|
BRICONT;
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* newnoise: Voronoi texture type
|
|
*
|
|
* probably the slowest, especially with minkovsky, bump-mapping, could be done another way.
|
|
*/
|
|
|
|
static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres)
|
|
{
|
|
int rv = TEX_INT;
|
|
float da[4], pa[12]; /* distance and point coordinate arrays of 4 nearest neighbors */
|
|
float aw1 = fabsf(tex->vn_w1);
|
|
float aw2 = fabsf(tex->vn_w2);
|
|
float aw3 = fabsf(tex->vn_w3);
|
|
float aw4 = fabsf(tex->vn_w4);
|
|
float sc = (aw1 + aw2 + aw3 + aw4);
|
|
if (sc != 0.0f) {
|
|
sc = tex->ns_outscale / sc;
|
|
}
|
|
|
|
BLI_noise_voronoi(texvec[0], texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm);
|
|
texres->tin = sc * fabsf(dot_v4v4(&tex->vn_w1, da));
|
|
|
|
if (tex->vn_coltype) {
|
|
float ca[3]; /* cell color */
|
|
BLI_noise_cell_v3(pa[0], pa[1], pa[2], ca);
|
|
texres->trgba[0] = aw1 * ca[0];
|
|
texres->trgba[1] = aw1 * ca[1];
|
|
texres->trgba[2] = aw1 * ca[2];
|
|
BLI_noise_cell_v3(pa[3], pa[4], pa[5], ca);
|
|
texres->trgba[0] += aw2 * ca[0];
|
|
texres->trgba[1] += aw2 * ca[1];
|
|
texres->trgba[2] += aw2 * ca[2];
|
|
BLI_noise_cell_v3(pa[6], pa[7], pa[8], ca);
|
|
texres->trgba[0] += aw3 * ca[0];
|
|
texres->trgba[1] += aw3 * ca[1];
|
|
texres->trgba[2] += aw3 * ca[2];
|
|
BLI_noise_cell_v3(pa[9], pa[10], pa[11], ca);
|
|
texres->trgba[0] += aw4 * ca[0];
|
|
texres->trgba[1] += aw4 * ca[1];
|
|
texres->trgba[2] += aw4 * ca[2];
|
|
if (tex->vn_coltype >= 2) {
|
|
float t1 = (da[1] - da[0]) * 10;
|
|
if (t1 > 1) {
|
|
t1 = 1;
|
|
}
|
|
if (tex->vn_coltype == 3) {
|
|
t1 *= texres->tin;
|
|
}
|
|
else {
|
|
t1 *= sc;
|
|
}
|
|
texres->trgba[0] *= t1;
|
|
texres->trgba[1] *= t1;
|
|
texres->trgba[2] *= t1;
|
|
}
|
|
else {
|
|
texres->trgba[0] *= sc;
|
|
texres->trgba[1] *= sc;
|
|
texres->trgba[2] *= sc;
|
|
}
|
|
}
|
|
|
|
if (tex->vn_coltype) {
|
|
BRICONTRGB;
|
|
texres->trgba[3] = 1.0;
|
|
return (rv | TEX_RGB);
|
|
}
|
|
|
|
BRICONT;
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static int texnoise(const Tex *tex, TexResult *texres, int thread)
|
|
{
|
|
float div = 3.0;
|
|
int val, ran, loop, shift = 29;
|
|
|
|
ran = BLI_rng_thread_rand(random_tex_array, thread);
|
|
|
|
loop = tex->noisedepth;
|
|
|
|
/* start from top bits since they have more variance */
|
|
val = ((ran >> shift) & 3);
|
|
|
|
while (loop--) {
|
|
shift -= 2;
|
|
val *= ((ran >> shift) & 3);
|
|
div *= 3.0f;
|
|
}
|
|
|
|
texres->tin = ((float)val) / div;
|
|
|
|
BRICONT;
|
|
return TEX_INT;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static int cubemap_glob(const float n[3], float x, float y, float z, float *adr1, float *adr2)
|
|
{
|
|
float x1, y1, z1, nor[3];
|
|
int ret;
|
|
|
|
if (n == NULL) {
|
|
nor[0] = x;
|
|
nor[1] = y;
|
|
nor[2] = z; /* use local render coord */
|
|
}
|
|
else {
|
|
copy_v3_v3(nor, n);
|
|
}
|
|
|
|
x1 = fabsf(nor[0]);
|
|
y1 = fabsf(nor[1]);
|
|
z1 = fabsf(nor[2]);
|
|
|
|
if (z1 >= x1 && z1 >= y1) {
|
|
*adr1 = (x + 1.0f) / 2.0f;
|
|
*adr2 = (y + 1.0f) / 2.0f;
|
|
ret = 0;
|
|
}
|
|
else if (y1 >= x1 && y1 >= z1) {
|
|
*adr1 = (x + 1.0f) / 2.0f;
|
|
*adr2 = (z + 1.0f) / 2.0f;
|
|
ret = 1;
|
|
}
|
|
else {
|
|
*adr1 = (y + 1.0f) / 2.0f;
|
|
*adr2 = (z + 1.0f) / 2.0f;
|
|
ret = 2;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
static void do_2d_mapping(
|
|
const MTex *mtex, float texvec[3], const float n[3], float dxt[3], float dyt[3])
|
|
{
|
|
Tex *tex;
|
|
float fx, fy, fac1, area[8];
|
|
int ok, proj, areaflag = 0, wrap;
|
|
|
|
/* #MTex variables localized, only cube-map doesn't cooperate yet. */
|
|
wrap = mtex->mapping;
|
|
tex = mtex->tex;
|
|
|
|
if (!(dxt && dyt)) {
|
|
|
|
if (wrap == MTEX_FLAT) {
|
|
fx = (texvec[0] + 1.0f) / 2.0f;
|
|
fy = (texvec[1] + 1.0f) / 2.0f;
|
|
}
|
|
else if (wrap == MTEX_TUBE) {
|
|
map_to_tube(&fx, &fy, texvec[0], texvec[1], texvec[2]);
|
|
}
|
|
else if (wrap == MTEX_SPHERE) {
|
|
map_to_sphere(&fx, &fy, texvec[0], texvec[1], texvec[2]);
|
|
}
|
|
else {
|
|
cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
|
|
}
|
|
|
|
/* repeat */
|
|
if (tex->extend == TEX_REPEAT) {
|
|
if (tex->xrepeat > 1) {
|
|
float origf = fx *= tex->xrepeat;
|
|
|
|
if (fx > 1.0f) {
|
|
fx -= (int)(fx);
|
|
}
|
|
else if (fx < 0.0f) {
|
|
fx += 1 - (int)(fx);
|
|
}
|
|
|
|
if (tex->flag & TEX_REPEAT_XMIR) {
|
|
int orig = (int)floor(origf);
|
|
if (orig & 1) {
|
|
fx = 1.0f - fx;
|
|
}
|
|
}
|
|
}
|
|
if (tex->yrepeat > 1) {
|
|
float origf = fy *= tex->yrepeat;
|
|
|
|
if (fy > 1.0f) {
|
|
fy -= (int)(fy);
|
|
}
|
|
else if (fy < 0.0f) {
|
|
fy += 1 - (int)(fy);
|
|
}
|
|
|
|
if (tex->flag & TEX_REPEAT_YMIR) {
|
|
int orig = (int)floor(origf);
|
|
if (orig & 1) {
|
|
fy = 1.0f - fy;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* crop */
|
|
if (tex->cropxmin != 0.0f || tex->cropxmax != 1.0f) {
|
|
fac1 = tex->cropxmax - tex->cropxmin;
|
|
fx = tex->cropxmin + fx * fac1;
|
|
}
|
|
if (tex->cropymin != 0.0f || tex->cropymax != 1.0f) {
|
|
fac1 = tex->cropymax - tex->cropymin;
|
|
fy = tex->cropymin + fy * fac1;
|
|
}
|
|
|
|
texvec[0] = fx;
|
|
texvec[1] = fy;
|
|
}
|
|
else {
|
|
|
|
if (wrap == MTEX_FLAT) {
|
|
fx = (texvec[0] + 1.0f) / 2.0f;
|
|
fy = (texvec[1] + 1.0f) / 2.0f;
|
|
dxt[0] /= 2.0f;
|
|
dxt[1] /= 2.0f;
|
|
dxt[2] /= 2.0f;
|
|
dyt[0] /= 2.0f;
|
|
dyt[1] /= 2.0f;
|
|
dyt[2] /= 2.0f;
|
|
}
|
|
else if (ELEM(wrap, MTEX_TUBE, MTEX_SPHERE)) {
|
|
/* exception: the seam behind (y<0.0) */
|
|
ok = 1;
|
|
if (texvec[1] <= 0.0f) {
|
|
fx = texvec[0] + dxt[0];
|
|
fy = texvec[0] + dyt[0];
|
|
if (fx >= 0.0f && fy >= 0.0f && texvec[0] >= 0.0f) {
|
|
/* pass */
|
|
}
|
|
else if (fx <= 0.0f && fy <= 0.0f && texvec[0] <= 0.0f) {
|
|
/* pass */
|
|
}
|
|
else {
|
|
ok = 0;
|
|
}
|
|
}
|
|
|
|
if (ok) {
|
|
if (wrap == MTEX_TUBE) {
|
|
map_to_tube(area, area + 1, texvec[0], texvec[1], texvec[2]);
|
|
map_to_tube(
|
|
area + 2, area + 3, texvec[0] + dxt[0], texvec[1] + dxt[1], texvec[2] + dxt[2]);
|
|
map_to_tube(
|
|
area + 4, area + 5, texvec[0] + dyt[0], texvec[1] + dyt[1], texvec[2] + dyt[2]);
|
|
}
|
|
else {
|
|
map_to_sphere(area, area + 1, texvec[0], texvec[1], texvec[2]);
|
|
map_to_sphere(
|
|
area + 2, area + 3, texvec[0] + dxt[0], texvec[1] + dxt[1], texvec[2] + dxt[2]);
|
|
map_to_sphere(
|
|
area + 4, area + 5, texvec[0] + dyt[0], texvec[1] + dyt[1], texvec[2] + dyt[2]);
|
|
}
|
|
areaflag = 1;
|
|
}
|
|
else {
|
|
if (wrap == MTEX_TUBE) {
|
|
map_to_tube(&fx, &fy, texvec[0], texvec[1], texvec[2]);
|
|
}
|
|
else {
|
|
map_to_sphere(&fx, &fy, texvec[0], texvec[1], texvec[2]);
|
|
}
|
|
dxt[0] /= 2.0f;
|
|
dxt[1] /= 2.0f;
|
|
dyt[0] /= 2.0f;
|
|
dyt[1] /= 2.0f;
|
|
}
|
|
}
|
|
else {
|
|
|
|
proj = cubemap_glob(n, texvec[0], texvec[1], texvec[2], &fx, &fy);
|
|
|
|
if (proj == 1) {
|
|
SWAP(float, dxt[1], dxt[2]);
|
|
SWAP(float, dyt[1], dyt[2]);
|
|
}
|
|
else if (proj == 2) {
|
|
float f1 = dxt[0], f2 = dyt[0];
|
|
dxt[0] = dxt[1];
|
|
dyt[0] = dyt[1];
|
|
dxt[1] = dxt[2];
|
|
dyt[1] = dyt[2];
|
|
dxt[2] = f1;
|
|
dyt[2] = f2;
|
|
}
|
|
|
|
dxt[0] *= 0.5f;
|
|
dxt[1] *= 0.5f;
|
|
dxt[2] *= 0.5f;
|
|
|
|
dyt[0] *= 0.5f;
|
|
dyt[1] *= 0.5f;
|
|
dyt[2] *= 0.5f;
|
|
}
|
|
|
|
/* If area, then recalculate `dxt[]` and `dyt[]` */
|
|
if (areaflag) {
|
|
fx = area[0];
|
|
fy = area[1];
|
|
dxt[0] = area[2] - fx;
|
|
dxt[1] = area[3] - fy;
|
|
dyt[0] = area[4] - fx;
|
|
dyt[1] = area[5] - fy;
|
|
}
|
|
|
|
/* repeat */
|
|
if (tex->extend == TEX_REPEAT) {
|
|
float max = 1.0f;
|
|
if (tex->xrepeat > 1) {
|
|
float origf = fx *= tex->xrepeat;
|
|
|
|
/* TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call */
|
|
if (tex->texfilter == TXF_BOX) {
|
|
if (fx > 1.0f) {
|
|
fx -= (int)(fx);
|
|
}
|
|
else if (fx < 0.0f) {
|
|
fx += 1 - (int)(fx);
|
|
}
|
|
|
|
if (tex->flag & TEX_REPEAT_XMIR) {
|
|
int orig = (int)floor(origf);
|
|
if (orig & 1) {
|
|
fx = 1.0f - fx;
|
|
}
|
|
}
|
|
}
|
|
|
|
max = tex->xrepeat;
|
|
|
|
dxt[0] *= tex->xrepeat;
|
|
dyt[0] *= tex->xrepeat;
|
|
}
|
|
if (tex->yrepeat > 1) {
|
|
float origf = fy *= tex->yrepeat;
|
|
|
|
/* TXF: omit mirror here, see comments in do_material_tex() after do_2d_mapping() call */
|
|
if (tex->texfilter == TXF_BOX) {
|
|
if (fy > 1.0f) {
|
|
fy -= (int)(fy);
|
|
}
|
|
else if (fy < 0.0f) {
|
|
fy += 1 - (int)(fy);
|
|
}
|
|
|
|
if (tex->flag & TEX_REPEAT_YMIR) {
|
|
int orig = (int)floor(origf);
|
|
if (orig & 1) {
|
|
fy = 1.0f - fy;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (max < tex->yrepeat) {
|
|
max = tex->yrepeat;
|
|
}
|
|
|
|
dxt[1] *= tex->yrepeat;
|
|
dyt[1] *= tex->yrepeat;
|
|
}
|
|
if (max != 1.0f) {
|
|
dxt[2] *= max;
|
|
dyt[2] *= max;
|
|
}
|
|
}
|
|
/* crop */
|
|
if (tex->cropxmin != 0.0f || tex->cropxmax != 1.0f) {
|
|
fac1 = tex->cropxmax - tex->cropxmin;
|
|
fx = tex->cropxmin + fx * fac1;
|
|
dxt[0] *= fac1;
|
|
dyt[0] *= fac1;
|
|
}
|
|
if (tex->cropymin != 0.0f || tex->cropymax != 1.0f) {
|
|
fac1 = tex->cropymax - tex->cropymin;
|
|
fy = tex->cropymin + fy * fac1;
|
|
dxt[1] *= fac1;
|
|
dyt[1] *= fac1;
|
|
}
|
|
|
|
texvec[0] = fx;
|
|
texvec[1] = fy;
|
|
}
|
|
}
|
|
|
|
/* ************************************** */
|
|
|
|
static int multitex(Tex *tex,
|
|
const float texvec[3],
|
|
float dxt[3],
|
|
float dyt[3],
|
|
int osatex,
|
|
TexResult *texres,
|
|
const short thread,
|
|
const short which_output,
|
|
struct ImagePool *pool,
|
|
const bool skip_load_image,
|
|
const bool texnode_preview,
|
|
const bool use_nodes)
|
|
{
|
|
float tmpvec[3];
|
|
int retval = 0; /* return value, TEX_INT or TEX_RGB. */
|
|
|
|
texres->talpha = false; /* is set when image texture returns alpha (considered premul) */
|
|
|
|
if (use_nodes && tex->use_nodes && tex->nodetree) {
|
|
const float cfra = 1.0f; /* This was only set for Blender Internal render before. */
|
|
retval = ntreeTexExecTree(tex->nodetree,
|
|
texres,
|
|
texvec,
|
|
dxt,
|
|
dyt,
|
|
osatex,
|
|
thread,
|
|
tex,
|
|
which_output,
|
|
cfra,
|
|
texnode_preview,
|
|
NULL);
|
|
}
|
|
else {
|
|
switch (tex->type) {
|
|
case 0:
|
|
texres->tin = 0.0f;
|
|
return 0;
|
|
case TEX_CLOUDS:
|
|
retval = clouds(tex, texvec, texres);
|
|
break;
|
|
case TEX_WOOD:
|
|
retval = wood(tex, texvec, texres);
|
|
break;
|
|
case TEX_MARBLE:
|
|
retval = marble(tex, texvec, texres);
|
|
break;
|
|
case TEX_MAGIC:
|
|
retval = magic(tex, texvec, texres);
|
|
break;
|
|
case TEX_BLEND:
|
|
retval = blend(tex, texvec, texres);
|
|
break;
|
|
case TEX_STUCCI:
|
|
retval = stucci(tex, texvec, texres);
|
|
break;
|
|
case TEX_NOISE:
|
|
retval = texnoise(tex, texres, thread);
|
|
break;
|
|
case TEX_IMAGE:
|
|
if (osatex) {
|
|
retval = imagewraposa(
|
|
tex, tex->ima, NULL, texvec, dxt, dyt, texres, pool, skip_load_image);
|
|
}
|
|
else {
|
|
retval = imagewrap(tex, tex->ima, texvec, texres, pool, skip_load_image);
|
|
}
|
|
if (tex->ima) {
|
|
BKE_image_tag_time(tex->ima);
|
|
}
|
|
break;
|
|
case TEX_MUSGRAVE:
|
|
/* newnoise: musgrave types */
|
|
|
|
/* NOTE(@ton): added this, for Blender convention reason.
|
|
* NOTE(@artificer): added the use of tmpvec to avoid scaling texvec. */
|
|
copy_v3_v3(tmpvec, texvec);
|
|
mul_v3_fl(tmpvec, 1.0f / tex->noisesize);
|
|
|
|
switch (tex->stype) {
|
|
case TEX_MFRACTAL:
|
|
case TEX_FBM:
|
|
retval = mg_mFractalOrfBmTex(tex, tmpvec, texres);
|
|
break;
|
|
case TEX_RIDGEDMF:
|
|
case TEX_HYBRIDMF:
|
|
retval = mg_ridgedOrHybridMFTex(tex, tmpvec, texres);
|
|
break;
|
|
case TEX_HTERRAIN:
|
|
retval = mg_HTerrainTex(tex, tmpvec, texres);
|
|
break;
|
|
}
|
|
break;
|
|
/* newnoise: voronoi type */
|
|
case TEX_VORONOI:
|
|
/* NOTE(@ton): added this, for Blender convention reason.
|
|
* NOTE(@artificer): added the use of tmpvec to avoid scaling texvec. */
|
|
copy_v3_v3(tmpvec, texvec);
|
|
mul_v3_fl(tmpvec, 1.0f / tex->noisesize);
|
|
|
|
retval = voronoiTex(tex, tmpvec, texres);
|
|
break;
|
|
case TEX_DISTNOISE:
|
|
/* NOTE(@ton): added this, for Blender convention reason.
|
|
* NOTE(@artificer): added the use of tmpvec to avoid scaling texvec. */
|
|
copy_v3_v3(tmpvec, texvec);
|
|
mul_v3_fl(tmpvec, 1.0f / tex->noisesize);
|
|
|
|
retval = mg_distNoiseTex(tex, tmpvec, texres);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tex->flag & TEX_COLORBAND) {
|
|
float col[4];
|
|
if (BKE_colorband_evaluate(tex->coba, texres->tin, col)) {
|
|
texres->talpha = true;
|
|
copy_v4_v4(texres->trgba, col);
|
|
retval |= TEX_RGB;
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
static int multitex_nodes_intern(Tex *tex,
|
|
const float texvec[3],
|
|
float dxt[3],
|
|
float dyt[3],
|
|
int osatex,
|
|
TexResult *texres,
|
|
const short thread,
|
|
short which_output,
|
|
MTex *mtex,
|
|
struct ImagePool *pool,
|
|
const bool scene_color_manage,
|
|
const bool skip_load_image,
|
|
const bool texnode_preview,
|
|
const bool use_nodes)
|
|
{
|
|
if (tex == NULL) {
|
|
memset(texres, 0, sizeof(TexResult));
|
|
return 0;
|
|
}
|
|
|
|
if (mtex) {
|
|
which_output = mtex->which_output;
|
|
}
|
|
|
|
if (tex->type == TEX_IMAGE) {
|
|
int retval;
|
|
|
|
if (mtex) {
|
|
float texvec_l[3];
|
|
copy_v3_v3(texvec_l, texvec);
|
|
/* we have mtex, use it for 2d mapping images only */
|
|
do_2d_mapping(mtex, texvec_l, NULL, dxt, dyt);
|
|
retval = multitex(tex,
|
|
texvec_l,
|
|
dxt,
|
|
dyt,
|
|
osatex,
|
|
texres,
|
|
thread,
|
|
which_output,
|
|
pool,
|
|
skip_load_image,
|
|
texnode_preview,
|
|
use_nodes);
|
|
|
|
if (mtex->mapto & MAP_COL) {
|
|
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
|
|
|
|
/* don't linearize float buffers, assumed to be linear */
|
|
if (ibuf != NULL && ibuf->float_buffer.data == NULL && (retval & TEX_RGB) &&
|
|
scene_color_manage) {
|
|
IMB_colormanagement_colorspace_to_scene_linear_v3(texres->trgba, ibuf->rect_colorspace);
|
|
}
|
|
|
|
BKE_image_pool_release_ibuf(tex->ima, ibuf, pool);
|
|
}
|
|
}
|
|
else {
|
|
/* we don't have mtex, do default flat 2d projection */
|
|
MTex localmtex;
|
|
float texvec_l[3], dxt_l[3], dyt_l[3];
|
|
|
|
localmtex.mapping = MTEX_FLAT;
|
|
localmtex.tex = tex;
|
|
localmtex.object = NULL;
|
|
localmtex.texco = TEXCO_ORCO;
|
|
|
|
copy_v3_v3(texvec_l, texvec);
|
|
if (dxt && dyt) {
|
|
copy_v3_v3(dxt_l, dxt);
|
|
copy_v3_v3(dyt_l, dyt);
|
|
}
|
|
else {
|
|
zero_v3(dxt_l);
|
|
zero_v3(dyt_l);
|
|
}
|
|
|
|
do_2d_mapping(&localmtex, texvec_l, NULL, dxt_l, dyt_l);
|
|
retval = multitex(tex,
|
|
texvec_l,
|
|
dxt_l,
|
|
dyt_l,
|
|
osatex,
|
|
texres,
|
|
thread,
|
|
which_output,
|
|
pool,
|
|
skip_load_image,
|
|
texnode_preview,
|
|
use_nodes);
|
|
|
|
{
|
|
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
|
|
|
|
/* don't linearize float buffers, assumed to be linear */
|
|
if (ibuf != NULL && ibuf->float_buffer.data == NULL && (retval & TEX_RGB) &&
|
|
scene_color_manage) {
|
|
IMB_colormanagement_colorspace_to_scene_linear_v3(texres->trgba, ibuf->rect_colorspace);
|
|
}
|
|
|
|
BKE_image_pool_release_ibuf(tex->ima, ibuf, pool);
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
return multitex(tex,
|
|
texvec,
|
|
dxt,
|
|
dyt,
|
|
osatex,
|
|
texres,
|
|
thread,
|
|
which_output,
|
|
pool,
|
|
skip_load_image,
|
|
texnode_preview,
|
|
use_nodes);
|
|
}
|
|
|
|
int multitex_nodes(Tex *tex,
|
|
const float texvec[3],
|
|
float dxt[3],
|
|
float dyt[3],
|
|
int osatex,
|
|
TexResult *texres,
|
|
const short thread,
|
|
short which_output,
|
|
MTex *mtex,
|
|
struct ImagePool *pool)
|
|
{
|
|
return multitex_nodes_intern(tex,
|
|
texvec,
|
|
dxt,
|
|
dyt,
|
|
osatex,
|
|
texres,
|
|
thread,
|
|
which_output,
|
|
mtex,
|
|
pool,
|
|
true,
|
|
false,
|
|
false,
|
|
true);
|
|
}
|
|
|
|
int multitex_ext(Tex *tex,
|
|
float texvec[3],
|
|
float dxt[3],
|
|
float dyt[3],
|
|
int osatex,
|
|
TexResult *texres,
|
|
const short thread,
|
|
struct ImagePool *pool,
|
|
bool scene_color_manage,
|
|
const bool skip_load_image)
|
|
{
|
|
return multitex_nodes_intern(tex,
|
|
texvec,
|
|
dxt,
|
|
dyt,
|
|
osatex,
|
|
texres,
|
|
thread,
|
|
0,
|
|
NULL,
|
|
pool,
|
|
scene_color_manage,
|
|
skip_load_image,
|
|
false,
|
|
true);
|
|
}
|
|
|
|
int multitex_ext_safe(Tex *tex,
|
|
const float texvec[3],
|
|
TexResult *texres,
|
|
struct ImagePool *pool,
|
|
bool scene_color_manage,
|
|
const bool skip_load_image)
|
|
{
|
|
return multitex_nodes_intern(tex,
|
|
texvec,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
texres,
|
|
0,
|
|
0,
|
|
NULL,
|
|
pool,
|
|
scene_color_manage,
|
|
skip_load_image,
|
|
false,
|
|
false);
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype)
|
|
{
|
|
float in = 0.0, facm, col, scf;
|
|
int flip = (facg < 0.0f);
|
|
|
|
facg = fabsf(facg);
|
|
|
|
fact *= facg;
|
|
facm = 1.0f - fact;
|
|
if (flip) {
|
|
SWAP(float, fact, facm);
|
|
}
|
|
|
|
switch (blendtype) {
|
|
case MTEX_BLEND:
|
|
in = fact * tex + facm * out;
|
|
break;
|
|
|
|
case MTEX_MUL:
|
|
facm = 1.0f - facg;
|
|
in = (facm + fact * tex) * out;
|
|
break;
|
|
|
|
case MTEX_SCREEN:
|
|
facm = 1.0f - facg;
|
|
in = 1.0f - (facm + fact * (1.0f - tex)) * (1.0f - out);
|
|
break;
|
|
|
|
case MTEX_OVERLAY:
|
|
facm = 1.0f - facg;
|
|
if (out < 0.5f) {
|
|
in = out * (facm + 2.0f * fact * tex);
|
|
}
|
|
else {
|
|
in = 1.0f - (facm + 2.0f * fact * (1.0f - tex)) * (1.0f - out);
|
|
}
|
|
break;
|
|
|
|
case MTEX_SUB:
|
|
fact = -fact;
|
|
ATTR_FALLTHROUGH;
|
|
case MTEX_ADD:
|
|
in = fact * tex + out;
|
|
break;
|
|
|
|
case MTEX_DIV:
|
|
if (tex != 0.0f) {
|
|
in = facm * out + fact * out / tex;
|
|
}
|
|
break;
|
|
|
|
case MTEX_DIFF:
|
|
in = facm * out + fact * fabsf(tex - out);
|
|
break;
|
|
|
|
case MTEX_DARK:
|
|
in = min_ff(out, tex) * fact + out * facm;
|
|
break;
|
|
|
|
case MTEX_LIGHT:
|
|
col = fact * tex;
|
|
if (col > out) {
|
|
in = col;
|
|
}
|
|
else {
|
|
in = out;
|
|
}
|
|
break;
|
|
|
|
case MTEX_SOFT_LIGHT:
|
|
scf = 1.0f - (1.0f - tex) * (1.0f - out);
|
|
in = facm * out + fact * ((1.0f - out) * tex * out) + (out * scf);
|
|
break;
|
|
|
|
case MTEX_LIN_LIGHT:
|
|
if (tex > 0.5f) {
|
|
in = out + fact * (2.0f * (tex - 0.5f));
|
|
}
|
|
else {
|
|
in = out + fact * (2.0f * tex - 1.0f);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return in;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
bool RE_texture_evaluate(const MTex *mtex,
|
|
const float vec[3],
|
|
const int thread,
|
|
struct ImagePool *pool,
|
|
const bool skip_load_image,
|
|
const bool texnode_preview,
|
|
/* Return arguments. */
|
|
float *r_intensity,
|
|
float r_rgba[4])
|
|
{
|
|
Tex *tex;
|
|
TexResult texr;
|
|
float dxt[3], dyt[3], texvec[3];
|
|
int rgb;
|
|
|
|
tex = mtex->tex;
|
|
if (tex == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
/* placement */
|
|
if (mtex->projx) {
|
|
texvec[0] = mtex->size[0] * (vec[mtex->projx - 1] + mtex->ofs[0]);
|
|
}
|
|
else {
|
|
texvec[0] = mtex->size[0] * (mtex->ofs[0]);
|
|
}
|
|
|
|
if (mtex->projy) {
|
|
texvec[1] = mtex->size[1] * (vec[mtex->projy - 1] + mtex->ofs[1]);
|
|
}
|
|
else {
|
|
texvec[1] = mtex->size[1] * (mtex->ofs[1]);
|
|
}
|
|
|
|
if (mtex->projz) {
|
|
texvec[2] = mtex->size[2] * (vec[mtex->projz - 1] + mtex->ofs[2]);
|
|
}
|
|
else {
|
|
texvec[2] = mtex->size[2] * (mtex->ofs[2]);
|
|
}
|
|
|
|
/* texture */
|
|
if (tex->type == TEX_IMAGE) {
|
|
do_2d_mapping(mtex, texvec, NULL, dxt, dyt);
|
|
}
|
|
|
|
rgb = multitex(tex,
|
|
texvec,
|
|
dxt,
|
|
dyt,
|
|
0,
|
|
&texr,
|
|
thread,
|
|
mtex->which_output,
|
|
pool,
|
|
skip_load_image,
|
|
texnode_preview,
|
|
true);
|
|
|
|
if (rgb) {
|
|
texr.tin = IMB_colormanagement_get_luminance(texr.trgba);
|
|
}
|
|
else {
|
|
copy_v3_fl3(texr.trgba, mtex->r, mtex->g, mtex->b);
|
|
}
|
|
|
|
*r_intensity = texr.tin;
|
|
copy_v4_v4(r_rgba, texr.trgba);
|
|
|
|
return (rgb != 0);
|
|
}
|