This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenkernel/intern/displist_tangent.c

280 lines
8.3 KiB
C

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** \file
* \ingroup bke
*/
#include "BLI_math.h"
#include "BLI_task.h"
#include "BKE_displist.h"
#include "BKE_displist_tangent.h"
#include "MEM_guardedalloc.h"
/* interface */
#include "mikktspace.h"
typedef struct {
const DispList *dl;
float (*tangent)[4]; /* destination */
/** Face normal for flat shading. */
float (*fnormals)[3];
/** Use by surfaces. Size of the surface in faces. */
int u_len, v_len;
} SGLSLDisplistToTangent;
/** \} */
/* ---------------------------------------------------------------------- */
/** \name DL_INDEX3 tangents
* \{ */
static int dl3_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
return dlt->dl->parts;
}
static int dl3_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
{
UNUSED_VARS(pContext, face_num);
return 3;
}
static void dl3_ts_GetPosition(const SMikkTSpaceContext *pContext,
float r_co[3],
const int face_num,
const int vert_index)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
const float(*verts)[3] = (float(*)[3])dlt->dl->verts;
const int(*idx)[3] = (int(*)[3])dlt->dl->index;
copy_v3_v3(r_co, verts[idx[face_num][vert_index]]);
}
static void dl3_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext,
float r_uv[2],
const int face_num,
const int vert_index)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
const int(*idx)[3] = (int(*)[3])dlt->dl->index;
r_uv[0] = idx[face_num][vert_index] / (float)(dlt->dl->nr - 1);
r_uv[1] = 0.0f;
}
static void dl3_ts_GetNormal(const SMikkTSpaceContext *pContext,
float r_no[3],
const int face_num,
const int vert_index)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
UNUSED_VARS(face_num, vert_index);
copy_v3_v3(r_no, dlt->dl->nors);
}
static void dl3_ts_SetTSpace(const SMikkTSpaceContext *pContext,
const float fvTangent[3],
const float fSign,
const int face_num,
const int vert_index)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
UNUSED_VARS(face_num, vert_index);
copy_v3_v3(dlt->tangent[0], fvTangent);
dlt->tangent[0][3] = fSign;
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name DL_SURF tangents
* \{ */
static int dlsurf_ts_GetNumFaces(const SMikkTSpaceContext *pContext)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
return dlt->v_len * dlt->u_len;
}
static int dlsurf_ts_GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_num)
{
UNUSED_VARS(pContext, face_num);
return 4;
}
static int face_to_vert_index(SGLSLDisplistToTangent *dlt,
const int face_num,
const int vert_index)
{
int u = face_num % dlt->u_len;
int v = face_num / dlt->u_len;
if (vert_index == 0) {
u += 1;
}
else if (vert_index == 1) {
u += 1;
v += 1;
}
else if (vert_index == 2) {
v += 1;
}
/* Cyclic correction. */
u = u % dlt->dl->nr;
v = v % dlt->dl->parts;
return v * dlt->dl->nr + u;
}
static void dlsurf_ts_GetPosition(const SMikkTSpaceContext *pContext,
float r_co[3],
const int face_num,
const int vert_index)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
const float(*verts)[3] = (float(*)[3])dlt->dl->verts;
copy_v3_v3(r_co, verts[face_to_vert_index(dlt, face_num, vert_index)]);
}
static void dlsurf_ts_GetTextureCoordinate(const SMikkTSpaceContext *pContext,
float r_uv[2],
const int face_num,
const int vert_index)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
int idx = face_to_vert_index(dlt, face_num, vert_index);
/* Note: For some reason the shading U and V are swapped compared to the
* one described in the surface format. */
r_uv[0] = (idx / dlt->dl->nr) / (float)(dlt->v_len);
r_uv[1] = (idx % dlt->dl->nr) / (float)(dlt->u_len);
if (r_uv[0] == 0.0f && ELEM(vert_index, 1, 2)) {
r_uv[0] = 1.0f;
}
if (r_uv[1] == 0.0f && ELEM(vert_index, 0, 1)) {
r_uv[1] = 1.0f;
}
}
static void dlsurf_ts_GetNormal(const SMikkTSpaceContext *pContext,
float r_no[3],
const int face_num,
const int vert_index)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
const float(*nors)[3] = (float(*)[3])dlt->dl->nors;
if (dlt->fnormals) {
copy_v3_v3(r_no, dlt->fnormals[face_num]);
}
else {
copy_v3_v3(r_no, nors[face_to_vert_index(dlt, face_num, vert_index)]);
}
}
static void dlsurf_ts_SetTSpace(const SMikkTSpaceContext *pContext,
const float fvTangent[3],
const float fSign,
const int face_num,
const int vert_index)
{
SGLSLDisplistToTangent *dlt = pContext->m_pUserData;
UNUSED_VARS(face_num, vert_index);
float *r_tan = dlt->tangent[face_num * 4 + vert_index];
copy_v3_v3(r_tan, fvTangent);
r_tan[3] = fSign;
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Entry point
* \{ */
void BKE_displist_tangent_calc(const DispList *dl, float (*fnormals)[3], float (**r_tangent)[4])
{
if (dl->type == DL_INDEX3) {
/* INDEX3 have only one tangent so we don't need actual allocation. */
BLI_assert(*r_tangent != NULL);
SGLSLDisplistToTangent mesh2tangent = {
.tangent = *r_tangent,
.dl = dl,
};
SMikkTSpaceContext sContext = {NULL};
SMikkTSpaceInterface sInterface = {NULL};
sContext.m_pUserData = &mesh2tangent;
sContext.m_pInterface = &sInterface;
sInterface.m_getNumFaces = dl3_ts_GetNumFaces;
sInterface.m_getNumVerticesOfFace = dl3_ts_GetNumVertsOfFace;
sInterface.m_getPosition = dl3_ts_GetPosition;
sInterface.m_getTexCoord = dl3_ts_GetTextureCoordinate;
sInterface.m_getNormal = dl3_ts_GetNormal;
sInterface.m_setTSpaceBasic = dl3_ts_SetTSpace;
/* 0 if failed */
genTangSpaceDefault(&sContext);
}
else if (dl->type == DL_SURF) {
SGLSLDisplistToTangent mesh2tangent = {
.dl = dl,
.u_len = dl->nr - ((dl->flag & DL_CYCL_U) ? 0 : 1),
.v_len = dl->parts - ((dl->flag & DL_CYCL_V) ? 0 : 1),
.fnormals = fnormals,
};
int loop_len = mesh2tangent.u_len * mesh2tangent.v_len * 4;
if (*r_tangent == NULL) {
*r_tangent = MEM_mallocN(sizeof(float[4]) * loop_len, "displist tangents");
}
mesh2tangent.tangent = *r_tangent;
SMikkTSpaceContext sContext = {NULL};
SMikkTSpaceInterface sInterface = {NULL};
sContext.m_pUserData = &mesh2tangent;
sContext.m_pInterface = &sInterface;
sInterface.m_getNumFaces = dlsurf_ts_GetNumFaces;
sInterface.m_getNumVerticesOfFace = dlsurf_ts_GetNumVertsOfFace;
sInterface.m_getPosition = dlsurf_ts_GetPosition;
sInterface.m_getTexCoord = dlsurf_ts_GetTextureCoordinate;
sInterface.m_getNormal = dlsurf_ts_GetNormal;
sInterface.m_setTSpaceBasic = dlsurf_ts_SetTSpace;
/* 0 if failed */
genTangSpaceDefault(&sContext);
}
else {
/* Unsupported. */
BLI_assert(0);
}
}
/** \} */