Geometry Nodes: Make simulation caching optional #107767

Merged
Hans Goudey merged 13 commits from HooglyBoogly/blender:simulation-use-cache-option into main 2023-05-10 16:01:44 +02:00
40 changed files with 296 additions and 4587 deletions
Showing only changes of commit 1cf894701d - Show all commits

View File

@ -567,6 +567,7 @@ const bTheme U_theme_default = {
.handle_vertex_size = 4,
.anim_active = RGBA(0x4d272766),
.anim_preview_range = RGBA(0xa14d0066),
.simulated_frames = RGBA(0x721e65ff),
},
.space_nla = {
.back = RGBA(0x30303000),

View File

@ -720,7 +720,7 @@ typedef struct PBVHFaceIter {
const struct BMesh *bm;
CCGKey subdiv_key_;
int last_face_index_;
int last_poly_index_;
} PBVHFaceIter;
void BKE_pbvh_face_iter_init(PBVH *pbvh, PBVHNode *node, PBVHFaceIter *fd);

View File

@ -162,7 +162,7 @@ static void mesh_recalc_looptri__single_threaded(const Span<int> corner_verts,
const float (*poly_normals)[3])
{
MemArena *pf_arena = nullptr;
uint tri_index = 0;
uint looptri_i = 0;
if (poly_normals != nullptr) {
for (const int64_t i : polys.index_range()) {
@ -170,17 +170,17 @@ static void mesh_recalc_looptri__single_threaded(const Span<int> corner_verts,
polys,
positions,
uint(i),
&mlooptri[tri_index],
&mlooptri[looptri_i],
&pf_arena,
poly_normals[i]);
tri_index += uint(polys[i].size() - 2);
looptri_i += uint(polys[i].size() - 2);
}
}
else {
for (const int64_t i : polys.index_range()) {
mesh_calc_tessellation_for_face(
corner_verts, polys, positions, uint(i), &mlooptri[tri_index], &pf_arena);
tri_index += uint(polys[i].size() - 2);
corner_verts, polys, positions, uint(i), &mlooptri[looptri_i], &pf_arena);
looptri_i += uint(polys[i].size() - 2);
}
}
@ -188,7 +188,7 @@ static void mesh_recalc_looptri__single_threaded(const Span<int> corner_verts,
BLI_memarena_free(pf_arena);
pf_arena = nullptr;
}
BLI_assert(tri_index == uint(poly_to_tri_count(int(polys.size()), int(corner_verts.size()))));
BLI_assert(looptri_i == uint(poly_to_tri_count(int(polys.size()), int(corner_verts.size()))));
}
struct TessellationUserData {
@ -213,12 +213,12 @@ static void mesh_calc_tessellation_for_face_fn(void *__restrict userdata,
{
const TessellationUserData *data = static_cast<const TessellationUserData *>(userdata);
TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls->userdata_chunk);
const int tri_index = poly_to_tri_count(index, int(data->polys[index].start()));
const int looptri_i = poly_to_tri_count(index, int(data->polys[index].start()));
mesh_calc_tessellation_for_face_impl(data->corner_verts,
data->polys,
data->positions,
uint(index),
&data->mlooptri[tri_index],
&data->mlooptri[looptri_i],
&tls_data->pf_arena,
false,
nullptr);
@ -230,12 +230,12 @@ static void mesh_calc_tessellation_for_face_with_normal_fn(void *__restrict user
{
const TessellationUserData *data = static_cast<const TessellationUserData *>(userdata);
TessellationUserTLS *tls_data = static_cast<TessellationUserTLS *>(tls->userdata_chunk);
const int tri_index = poly_to_tri_count(index, int(data->polys[index].start()));
const int looptri_i = poly_to_tri_count(index, int(data->polys[index].start()));
mesh_calc_tessellation_for_face_impl(data->corner_verts,
data->polys,
data->positions,
uint(index),
&data->mlooptri[tri_index],
&data->mlooptri[looptri_i],
&tls_data->pf_arena,
true,
data->poly_normals[index]);

View File

@ -1660,7 +1660,7 @@ static void sculpt_update_persistent_base(Object *ob)
}
static void sculpt_update_object(
Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool need_pmap, bool is_paint_tool)
Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool /*need_pmap*/, bool is_paint_tool)
{
Scene *scene = DEG_get_input_scene(depsgraph);
Sculpt *sd = scene->toolsettings->sculpt;
@ -1766,13 +1766,13 @@ static void sculpt_update_object(
sculpt_attribute_update_refs(ob);
sculpt_update_persistent_base(ob);
if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
if (ob->type == OB_MESH && !ss->pmap) {
BKE_mesh_vert_poly_map_create(
&ss->pmap, &ss->pmap_mem, me->polys(), me->corner_verts().data(), me->totvert);
}
if (ss->pbvh) {
BKE_pbvh_pmap_set(ss->pbvh, ss->pmap);
}
if (ss->pbvh) {
BKE_pbvh_pmap_set(ss->pbvh, ss->pmap);
}
if (ss->deform_modifiers_active) {

View File

@ -11,10 +11,13 @@
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_math_vector.hh"
#include "BLI_rand.h"
#include "BLI_task.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"
#include "BLI_vector_set.hh"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@ -199,10 +202,10 @@ static int partition_indices_faces(int *prim_indices,
int i1 = lo, i2 = 0;
while (i1 < hi) {
int poly = looptri_polys[prim_scratch[i2]];
const int poly_i = looptri_polys[prim_scratch[i2]];
bool side = prim_bbc[prim_scratch[i2]].bcentroid[axis] >= mid;
while (i1 < hi && looptri_polys[prim_scratch[i2]] == poly) {
while (i1 < hi && looptri_polys[prim_scratch[i2]] == poly_i) {
prim_indices[side ? hi2-- : lo2++] = prim_scratch[i2];
i1++;
i2++;
@ -229,10 +232,10 @@ static int partition_indices_grids(int *prim_indices,
int i1 = lo, i2 = 0;
while (i1 < hi) {
int poly = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, prim_scratch[i2]);
int poly_i = BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, prim_scratch[i2]);
bool side = prim_bbc[prim_scratch[i2]].bcentroid[axis] >= mid;
while (i1 < hi && BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, prim_scratch[i2]) == poly) {
while (i1 < hi && BKE_subdiv_ccg_grid_to_face_index(subdiv_ccg, prim_scratch[i2]) == poly_i) {
prim_indices[side ? hi2-- : lo2++] = prim_scratch[i2];
i1++;
i2++;
@ -513,21 +516,21 @@ static void test_face_boundaries(PBVH *pbvh)
switch (BKE_pbvh_type(pbvh)) {
case PBVH_FACES: {
for (int j = 0; j < node->totprim; j++) {
int poly = pbvh->looptri_polys[node->prim_indices[j]];
int poly_i = pbvh->looptri_polys[node->prim_indices[j]];
if (node_map[poly] >= 0 && node_map[poly] != i) {
int old_i = node_map[poly];
if (node_map[poly_i] >= 0 && node_map[poly_i] != i) {
int old_i = node_map[poly_i];
int prim_i = node->prim_indices - pbvh->prim_indices + j;
printf("PBVH split error; poly: %d, prim_i: %d, node1: %d, node2: %d, totprim: %d\n",
poly,
poly_i,
prim_i,
old_i,
i,
node->totprim);
}
node_map[poly] = i;
node_map[poly_i] = i;
}
break;
}
@ -791,16 +794,16 @@ static void pbvh_validate_node_prims(PBVH *pbvh)
}
for (int j = 0; j < node->totprim; j++) {
int poly;
int poly_i;
if (pbvh->header.type == PBVH_FACES) {
poly = pbvh->looptri_polys[node->prim_indices[j]];
poly_i = pbvh->looptri_polys[node->prim_indices[j]];
}
else {
poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
poly_i = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
}
totface = max_ii(totface, poly + 1);
totface = max_ii(totface, poly_i + 1);
}
}
@ -818,23 +821,23 @@ static void pbvh_validate_node_prims(PBVH *pbvh)
}
for (int j = 0; j < node->totprim; j++) {
int poly;
int poly_i;
if (pbvh->header.type == PBVH_FACES) {
poly = pbvh->looptri_polys[node->prim_indices[j]];
poly_i = pbvh->looptri_polys[node->prim_indices[j]];
}
else {
poly = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
poly_i = BKE_subdiv_ccg_grid_to_face_index(pbvh->subdiv_ccg, node->prim_indices[j]);
}
if (facemap[poly] != -1 && facemap[poly] != i) {
if (facemap[poly_i] != -1 && facemap[poly_i] != i) {
printf("%s: error: face spanned multiple nodes (old: %d new: %d)\n",
__func__,
facemap[poly],
facemap[poly_i],
i);
}
facemap[poly] = i;
facemap[poly_i] = i;
}
}
MEM_SAFE_FREE(facemap);
@ -862,7 +865,10 @@ void BKE_pbvh_update_mesh_pointers(PBVH *pbvh, Mesh *mesh)
/* Make sure cached normals start out calculated. */
mesh->vert_normals();
mesh->poly_normals();
pbvh->vert_normals = BKE_mesh_vert_normals_for_write(mesh);
pbvh->poly_normals = mesh->runtime->poly_normals;
pbvh->vdata = &mesh->vdata;
pbvh->ldata = &mesh->ldata;
@ -1367,7 +1373,6 @@ struct PBVHUpdateData {
PBVH *pbvh;
Span<PBVHNode *> nodes;
float (*vert_normals)[3] = nullptr;
int flag = 0;
bool show_sculpt_face_sets = false;
PBVHAttrReq *attrs = nullptr;
@ -1376,133 +1381,66 @@ struct PBVHUpdateData {
PBVHUpdateData(PBVH *pbvh_, Span<PBVHNode *> nodes_) : pbvh(pbvh_), nodes(nodes_) {}
};
static void pbvh_update_normals_clear_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict /*tls*/)
{
PBVHUpdateData *data = static_cast<PBVHUpdateData *>(userdata);
PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
float(*vert_normals)[3] = data->vert_normals;
if (node->flag & PBVH_UpdateNormals) {
const int *verts = node->vert_indices;
const int totvert = node->uniq_verts;
for (int i = 0; i < totvert; i++) {
const int v = verts[i];
if (pbvh->vert_bitmap[v]) {
zero_v3(vert_normals[v]);
}
}
}
}
static void pbvh_update_normals_accum_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict /*tls*/)
{
PBVHUpdateData *data = static_cast<PBVHUpdateData *>(userdata);
PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
float(*vert_normals)[3] = data->vert_normals;
if (node->flag & PBVH_UpdateNormals) {
uint mpoly_prev = UINT_MAX;
blender::float3 fn;
const int *faces = node->prim_indices;
const int totface = node->totprim;
for (int i = 0; i < totface; i++) {
const int tri_index = faces[i];
const int poly_index = pbvh->looptri_polys[tri_index];
const MLoopTri *lt = &pbvh->looptri[faces[i]];
const int vtri[3] = {
pbvh->corner_verts[lt->tri[0]],
pbvh->corner_verts[lt->tri[1]],
pbvh->corner_verts[lt->tri[2]],
};
const int sides = 3;
/* Face normal and mask */
if (poly_index != mpoly_prev) {
const blender::IndexRange poly = pbvh->polys[poly_index];
fn = blender::bke::mesh::poly_normal_calc(
{reinterpret_cast<const blender::float3 *>(pbvh->vert_positions), pbvh->totvert},
{&pbvh->corner_verts[poly.start()], poly.size()});
mpoly_prev = poly_index;
}
for (int j = sides; j--;) {
const int v = vtri[j];
if (pbvh->vert_bitmap[v]) {
/* NOTE: This avoids `lock, add_v3_v3, unlock`
* and is five to ten times quicker than a spin-lock.
* Not exact equivalent though, since atomicity is only ensured for one component
* of the vector at a time, but here it shall not make any sensible difference. */
for (int k = 3; k--;) {
atomic_add_and_fetch_fl(&vert_normals[v][k], fn[k]);
}
}
}
}
}
}
static void pbvh_update_normals_store_task_cb(void *__restrict userdata,
const int n,
const TaskParallelTLS *__restrict /*tls*/)
{
PBVHUpdateData *data = static_cast<PBVHUpdateData *>(userdata);
PBVH *pbvh = data->pbvh;
PBVHNode *node = data->nodes[n];
float(*vert_normals)[3] = data->vert_normals;
if (node->flag & PBVH_UpdateNormals) {
const int *verts = node->vert_indices;
const int totvert = node->uniq_verts;
for (int i = 0; i < totvert; i++) {
const int v = verts[i];
/* No atomics necessary because we are iterating over uniq_verts only,
* so we know only this thread will handle this vertex. */
if (pbvh->vert_bitmap[v]) {
normalize_v3(vert_normals[v]);
pbvh->vert_bitmap[v] = false;
}
}
node->flag &= ~PBVH_UpdateNormals;
}
}
static void pbvh_faces_update_normals(PBVH *pbvh, Span<PBVHNode *> nodes)
{
/* subtle assumptions:
* - We know that for all edited vertices, the nodes with faces
* adjacent to these vertices have been marked with PBVH_UpdateNormals.
* This is true because if the vertex is inside the brush radius, the
* bounding box of its adjacent faces will be as well.
* - However this is only true for the vertices that have actually been
* edited, not for all vertices in the nodes marked for update, so we
* can only update vertices marked in the `vert_bitmap`.
*/
using namespace blender;
using namespace blender::bke;
const Span<float3> positions(reinterpret_cast<const float3 *>(pbvh->vert_positions),
pbvh->totvert);
const OffsetIndices polys = pbvh->polys;
const Span<int> corner_verts(pbvh->corner_verts, pbvh->mesh->totloop);
PBVHUpdateData data(pbvh, nodes);
data.pbvh = pbvh;
data.nodes = nodes;
data.vert_normals = pbvh->vert_normals;
MutableSpan<bool> update_tags(pbvh->vert_bitmap, pbvh->totvert);
TaskParallelSettings settings;
BKE_pbvh_parallel_range_settings(&settings, true, nodes.size());
VectorSet<int> polys_to_update;
for (const PBVHNode *node : nodes) {
for (const int vert : Span(node->vert_indices, node->uniq_verts)) {
if (update_tags[vert]) {
polys_to_update.add_multiple({pbvh->pmap[vert].indices, pbvh->pmap[vert].count});
}
}
}
/* Zero normals before accumulation. */
BLI_task_parallel_range(0, nodes.size(), &data, pbvh_update_normals_clear_task_cb, &settings);
BLI_task_parallel_range(0, nodes.size(), &data, pbvh_update_normals_accum_task_cb, &settings);
BLI_task_parallel_range(0, nodes.size(), &data, pbvh_update_normals_store_task_cb, &settings);
if (polys_to_update.is_empty()) {
return;
}
MutableSpan<float3> vert_normals(reinterpret_cast<float3 *>(pbvh->vert_normals), pbvh->totvert);
MutableSpan<float3> poly_normals = pbvh->poly_normals;
VectorSet<int> verts_to_update;
threading::parallel_invoke(
[&]() {
threading::parallel_for(polys_to_update.index_range(), 512, [&](const IndexRange range) {
for (const int i : polys_to_update.as_span().slice(range)) {
poly_normals[i] = mesh::poly_normal_calc(positions, corner_verts.slice(polys[i]));
}
});
},
[&]() {
/* Update all normals connected to affected faces faces, even if not explicitly tagged. */
verts_to_update.reserve(polys_to_update.size());
for (const int poly : polys_to_update) {
verts_to_update.add_multiple(corner_verts.slice(polys[poly]));
}
for (const int vert : verts_to_update) {
update_tags[vert] = false;
}
for (PBVHNode *node : nodes) {
node->flag &= ~PBVH_UpdateNormals;
}
});
threading::parallel_for(verts_to_update.index_range(), 1024, [&](const IndexRange range) {
for (const int vert : verts_to_update.as_span().slice(range)) {
float3 normal(0.0f);
for (const int poly : Span(pbvh->pmap[vert].indices, pbvh->pmap[vert].count)) {
normal += poly_normals[poly];
}
vert_normals[vert] = math::normalize(normal);
}
});
}
static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata,
@ -2532,17 +2470,17 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
{
const float(*positions)[3] = pbvh->vert_positions;
const int *corner_verts = pbvh->corner_verts;
const int *faces = node->prim_indices;
int totface = node->totprim;
const int *looptris = node->prim_indices;
int looptris_num = node->totprim;
bool hit = false;
float nearest_vertex_co[3] = {0.0f};
for (int i = 0; i < totface; i++) {
const int tri_index = faces[i];
const MLoopTri *lt = &pbvh->looptri[tri_index];
for (int i = 0; i < looptris_num; i++) {
const int looptri_i = looptris[i];
const MLoopTri *lt = &pbvh->looptri[looptri_i];
const int *face_verts = node->face_vert_indices[i];
if (paint_is_face_hidden(pbvh->looptri_polys, pbvh->hide_poly, tri_index)) {
if (paint_is_face_hidden(pbvh->looptri_polys, pbvh->hide_poly, looptri_i)) {
continue;
}
@ -2578,7 +2516,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) {
copy_v3_v3(nearest_vertex_co, co[j]);
r_active_vertex->i = corner_verts[lt->tri[j]];
*r_active_face_index = pbvh->looptri_polys[tri_index];
*r_active_face_index = pbvh->looptri_polys[looptri_i];
}
}
}
@ -2843,16 +2781,16 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
{
const float(*positions)[3] = pbvh->vert_positions;
const int *corner_verts = pbvh->corner_verts;
const int *faces = node->prim_indices;
int i, totface = node->totprim;
const int *looptris = node->prim_indices;
int i, looptris_num = node->totprim;
bool hit = false;
for (i = 0; i < totface; i++) {
const int tri_index = faces[i];
const MLoopTri *lt = &pbvh->looptri[tri_index];
for (i = 0; i < looptris_num; i++) {
const int looptri_i = looptris[i];
const MLoopTri *lt = &pbvh->looptri[looptri_i];
const int *face_verts = node->face_vert_indices[i];
if (paint_is_face_hidden(pbvh->looptri_polys, pbvh->hide_poly, tri_index)) {
if (paint_is_face_hidden(pbvh->looptri_polys, pbvh->hide_poly, looptri_i)) {
continue;
}
@ -3635,15 +3573,15 @@ static void pbvh_face_iter_step(PBVHFaceIter *fd, bool do_step)
}
case PBVH_GRIDS:
case PBVH_FACES: {
int face_index = 0;
int poly_i = 0;
if (do_step) {
fd->prim_index_++;
while (fd->prim_index_ < fd->node_->totprim) {
face_index = face_iter_prim_to_face(fd, fd->node_->prim_indices[fd->prim_index_]);
poly_i = face_iter_prim_to_face(fd, fd->node_->prim_indices[fd->prim_index_]);
if (face_index != fd->last_face_index_) {
if (poly_i != fd->last_poly_index_) {
break;
}
@ -3651,24 +3589,24 @@ static void pbvh_face_iter_step(PBVHFaceIter *fd, bool do_step)
}
}
else if (fd->prim_index_ < fd->node_->totprim) {
face_index = face_iter_prim_to_face(fd, fd->node_->prim_indices[fd->prim_index_]);
poly_i = face_iter_prim_to_face(fd, fd->node_->prim_indices[fd->prim_index_]);
}
if (fd->prim_index_ >= fd->node_->totprim) {
return;
}
fd->last_face_index_ = face_index;
const int poly_start = fd->poly_offsets_[face_index];
const int poly_size = fd->poly_offsets_[face_index + 1] - poly_start;
fd->last_poly_index_ = poly_i;
const int poly_start = fd->poly_offsets_[poly_i];
const int poly_size = fd->poly_offsets_[poly_i + 1] - poly_start;
fd->face.i = fd->index = face_index;
fd->face.i = fd->index = poly_i;
if (fd->face_sets_) {
fd->face_set = fd->face_sets_ + face_index;
fd->face_set = fd->face_sets_ + poly_i;
}
if (fd->hide_poly_) {
fd->hide = fd->hide_poly_ + face_index;
fd->hide = fd->hide_poly_ + poly_i;
}
pbvh_face_iter_verts_reserve(fd, poly_size);
@ -3715,7 +3653,7 @@ void BKE_pbvh_face_iter_init(PBVH *pbvh, PBVHNode *node, PBVHFaceIter *fd)
fd->looptri_polys_ = pbvh->looptri_polys;
fd->hide_poly_ = pbvh->hide_poly;
fd->face_sets_ = pbvh->face_sets;
fd->last_face_index_ = -1;
fd->last_poly_index_ = -1;
break;
case PBVH_BMESH:
@ -3799,8 +3737,8 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh)
&mesh->pdata, CD_PROP_BOOL, ".hide_poly", mesh->totpoly));
bool delete_hide_poly = true;
for (const int face_index : polys.index_range()) {
const blender::IndexRange poly = polys[face_index];
for (const int poly_i : polys.index_range()) {
const blender::IndexRange poly = polys[poly_i];
bool hidden = false;
for (int loop_index = 0; !hidden && loop_index < poly.size(); loop_index++) {
@ -3827,7 +3765,7 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh)
if (hide_poly) {
delete_hide_poly = delete_hide_poly && !hidden;
hide_poly[face_index] = hidden;
hide_poly[poly_i] = hidden;
}
}

View File

@ -3,6 +3,8 @@
#pragma once
#include "BLI_vector.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_span.hh"
/** \file
* \ingroup bke
@ -155,6 +157,7 @@ struct PBVH {
/* NOTE: Normals are not `const` because they can be updated for drawing by sculpt code. */
float (*vert_normals)[3];
blender::MutableSpan<blender::float3> poly_normals;
bool *hide_vert;
float (*vert_positions)[3];
blender::OffsetIndices<int> polys;

View File

@ -704,7 +704,7 @@ static bool do_versions_sequencer_init_retiming_tool_data(Sequence *seq, void *u
SeqRetimingHandle *handle = &seq->retiming_handles[seq->retiming_handle_num - 1];
handle->strip_frame_index = round_fl_to_int(content_length / seq->speed_factor);
seq->speed_factor = 0.0f;
seq->speed_factor = 1.0f;
return true;
}
@ -1174,7 +1174,8 @@ void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
SOCK_OBJECT,
SOCK_COLLECTION,
SOCK_TEXTURE,
SOCK_MATERIAL)) {
SOCK_MATERIAL))
{
link->tosock = link->tosock->next;
}
}
@ -1786,6 +1787,18 @@ static bool version_set_seq_single_frame_content(Sequence *seq, void * /*user_da
return true;
}
static bool version_seq_fix_broken_sound_strips(Sequence *seq, void * /*user_data*/)
{
if (seq->type != SEQ_TYPE_SOUND_RAM || seq->speed_factor != 0.0f) {
return true;
}
seq->speed_factor = 1.0f;
SEQ_retiming_data_clear(seq);
seq->startofs = 0.0f;
return true;
}
/* Those `version_liboverride_rnacollections_*` functions mimic the old, pre-3.0 code to find
* anchor and source items in the given list of modifiers, constraints etc., using only the
* `subitem_local` data of the override property operation.
@ -2633,7 +2646,8 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 300, 17)) {
if (!DNA_struct_elem_find(
fd->filesdna, "View3DOverlay", "float", "normals_constant_screen_size")) {
fd->filesdna, "View3DOverlay", "float", "normals_constant_screen_size"))
{
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
@ -2661,7 +2675,8 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
if (!MAIN_VERSION_ATLEAST(bmain, 300, 18)) {
if (!DNA_struct_elem_find(
fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library_ref")) {
fd->filesdna, "WorkSpace", "AssetLibraryReference", "asset_library_ref"))
{
LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
BKE_asset_library_reference_init_default(&workspace->asset_library_ref);
}
@ -4354,5 +4369,13 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
*/
{
/* Keep this block, even when empty. */
/* Fix sound strips with speed factor set to 0. See #107289. */
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
Editing *ed = SEQ_editing_get(scene);
if (ed != nullptr) {
SEQ_for_each_callback(&ed->seqbase, version_seq_fix_broken_sound_strips, nullptr);
}
}
}
}

View File

@ -109,6 +109,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
{
/* Keep this block, even when empty. */
FROM_DEFAULT_V4_UCHAR(space_node.node_zone_simulation);
FROM_DEFAULT_V4_UCHAR(space_action.simulated_frames);
}
#undef FROM_DEFAULT_V4_UCHAR

View File

@ -30,7 +30,7 @@ void PlaneTrackDeformNode::convert_to_operations(NodeConverter &converter,
warp_image_operation->set_tracking_object(data->tracking_object);
warp_image_operation->set_plane_track_name(data->plane_track_name);
warp_image_operation->set_framenumber(frame_number);
if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
if (data->flag & CMP_NODE_PLANE_TRACK_DEFORM_FLAG_MOTION_BLUR) {
warp_image_operation->set_motion_blur_samples(data->motion_blur_samples);
warp_image_operation->set_motion_blur_shutter(data->motion_blur_shutter);
}
@ -44,7 +44,7 @@ void PlaneTrackDeformNode::convert_to_operations(NodeConverter &converter,
plane_mask_operation->set_tracking_object(data->tracking_object);
plane_mask_operation->set_plane_track_name(data->plane_track_name);
plane_mask_operation->set_framenumber(frame_number);
if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
if (data->flag & CMP_NODE_PLANE_TRACK_DEFORM_FLAG_MOTION_BLUR) {
plane_mask_operation->set_motion_blur_samples(data->motion_blur_samples);
plane_mask_operation->set_motion_blur_shutter(data->motion_blur_shutter);
}

View File

@ -191,9 +191,10 @@ struct PBVHBatches {
switch (args->pbvh_type) {
case PBVH_FACES: {
for (int i = 0; i < args->totprim; i++) {
int face_index = args->looptri_polys[args->prim_indices[i]];
const int looptri_i = args->prim_indices[i];
const int poly_i = args->looptri_polys[looptri_i];
if (args->hide_poly && args->hide_poly[face_index]) {
if (args->hide_poly && args->hide_poly[poly_i]) {
continue;
}
@ -336,8 +337,8 @@ struct PBVHBatches {
int last_poly = -1;
bool flat = false;
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int tri) {
const int poly_i = args->looptri_polys[tri];
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int looptri_i) {
const int poly_i = args->looptri_polys[looptri_i];
if (poly_i != last_poly) {
last_poly = poly_i;
flat = sharp_faces && sharp_faces[poly_i];
@ -545,20 +546,20 @@ struct PBVHBatches {
{
const blender::Span<int> corner_verts = args->corner_verts;
auto foreach_faces =
[&](std::function<void(int buffer_i, int tri_i, int vertex_i, const int tri)> func) {
[&](std::function<void(int buffer_i, int tri_i, int vertex_i, const int /*looptri_i*/)>
func) {
int buffer_i = 0;
for (int i : IndexRange(args->totprim)) {
int face_index = args->looptri_polys[args->prim_indices[i]];
const int looptri_i = args->prim_indices[i];
const int poly_i = args->looptri_polys[looptri_i];
if (args->hide_poly && args->hide_poly[face_index]) {
if (args->hide_poly && args->hide_poly[poly_i]) {
continue;
}
const int tri = args->prim_indices[i];
for (int j : IndexRange(3)) {
func(buffer_i, j, corner_verts[args->mlooptri[tri].tri[j]], tri);
func(buffer_i, j, corner_verts[args->mlooptri[looptri_i].tri[j]], looptri_i);
buffer_i++;
}
}
@ -580,7 +581,7 @@ struct PBVHBatches {
switch (vbo.type) {
case CD_PBVH_CO_TYPE:
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int /*tri*/) {
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int /*looptri_i*/) {
*static_cast<float3 *>(GPU_vertbuf_raw_step(&access)) = args->vert_positions[vertex_i];
});
break;
@ -592,14 +593,17 @@ struct PBVHBatches {
CustomData_get_layer(args->vdata, CD_PAINT_MASK));
if (mask) {
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int /*tri*/) {
*static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = uchar(mask[vertex_i] * 255.0f);
});
foreach_faces(
[&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int /*looptri_i*/) {
*static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = uchar(mask[vertex_i] *
255.0f);
});
}
else {
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int /*vertex_i*/, const int /*tri*/) {
*static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = 0;
});
foreach_faces(
[&](int /*buffer_i*/, int /*tri_i*/, int /*vertex_i*/, const int /*looptri_i*/) {
*static_cast<uchar *>(GPU_vertbuf_raw_step(&access)) = 0;
});
}
break;
}
@ -611,31 +615,34 @@ struct PBVHBatches {
int last_poly = -1;
uchar fset_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int /*vertex_i*/, const int tri) {
const int poly_i = args->looptri_polys[tri];
if (last_poly != poly_i) {
last_poly = poly_i;
foreach_faces(
[&](int /*buffer_i*/, int /*tri_i*/, int /*vertex_i*/, const int looptri_i) {
const int poly_i = args->looptri_polys[looptri_i];
if (last_poly != poly_i) {
last_poly = poly_i;
const int fset = face_sets[poly_i];
const int fset = face_sets[poly_i];
if (fset != args->face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(fset, args->face_sets_color_seed, fset_color);
}
else {
/* Skip for the default color face set to render it white. */
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
}
}
if (fset != args->face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(
fset, args->face_sets_color_seed, fset_color);
}
else {
/* Skip for the default color face set to render it white. */
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
}
}
*static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = fset_color;
});
*static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = fset_color;
});
}
else {
uchar fset_color[4] = {255, 255, 255, 255};
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int /*vertex_i*/, const int /*tri*/) {
*static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = fset_color;
});
foreach_faces(
[&](int /*buffer_i*/, int /*tri_i*/, int /*vertex_i*/, const int /*looptri_i*/) {
*static_cast<uchar3 *>(GPU_vertbuf_raw_step(&access)) = fset_color;
});
}
break;
@ -645,25 +652,26 @@ struct PBVHBatches {
const MPropCol *mpropcol = static_cast<const MPropCol *>(
CustomData_get_layer_named(args->vdata, CD_PROP_COLOR, vbo.name.c_str()));
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int /*tri*/) {
ushort color[4];
const MPropCol *col = mpropcol + vertex_i;
foreach_faces(
[&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int /*looptri_i*/) {
ushort color[4];
const MPropCol *col = mpropcol + vertex_i;
color[0] = unit_float_to_ushort_clamp(col->color[0]);
color[1] = unit_float_to_ushort_clamp(col->color[1]);
color[2] = unit_float_to_ushort_clamp(col->color[2]);
color[3] = unit_float_to_ushort_clamp(col->color[3]);
color[0] = unit_float_to_ushort_clamp(col->color[0]);
color[1] = unit_float_to_ushort_clamp(col->color[1]);
color[2] = unit_float_to_ushort_clamp(col->color[2]);
color[3] = unit_float_to_ushort_clamp(col->color[3]);
*static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = color;
});
*static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = color;
});
}
else if (vbo.domain == ATTR_DOMAIN_CORNER) {
const MPropCol *mpropcol = static_cast<const MPropCol *>(
CustomData_get_layer_named(args->ldata, CD_PROP_COLOR, vbo.name.c_str()));
foreach_faces([&](int /*buffer_i*/, int tri_i, int /*vertex_i*/, const int tri) {
foreach_faces([&](int /*buffer_i*/, int tri_i, int /*vertex_i*/, const int looptri_i) {
ushort color[4];
const MPropCol *col = mpropcol + args->mlooptri[tri].tri[tri_i];
const MPropCol *col = mpropcol + args->mlooptri[looptri_i].tri[tri_i];
color[0] = unit_float_to_ushort_clamp(col->color[0]);
color[1] = unit_float_to_ushort_clamp(col->color[1]);
@ -679,25 +687,26 @@ struct PBVHBatches {
const MLoopCol *mbytecol = static_cast<const MLoopCol *>(
CustomData_get_layer_named(args->vdata, CD_PROP_BYTE_COLOR, vbo.name.c_str()));
foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int /*tri*/) {
ushort color[4];
const MLoopCol *col = mbytecol + vertex_i;
foreach_faces(
[&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const int /*looptri_i*/) {
ushort color[4];
const MLoopCol *col = mbytecol + vertex_i;
color[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->r]);
color[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->g]);
color[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->b]);
color[3] = col->a * 257;
color[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->r]);
color[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->g]);
color[2] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->b]);
color[3] = col->a * 257;
*static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = color;
});
*static_cast<ushort4 *>(GPU_vertbuf_raw_step(&access)) = color;
});
}
else if (vbo.domain == ATTR_DOMAIN_CORNER) {
const MLoopCol *mbytecol = static_cast<const MLoopCol *>(
CustomData_get_layer_named(args->ldata, CD_PROP_BYTE_COLOR, vbo.name.c_str()));
foreach_faces([&](int /*buffer_i*/, int tri_i, int /*vertex_i*/, const int tri) {
foreach_faces([&](int /*buffer_i*/, int tri_i, int /*vertex_i*/, const int looptri_i) {
ushort color[4];
const MLoopCol *col = mbytecol + args->mlooptri[tri].tri[tri_i];
const MLoopCol *col = mbytecol + args->mlooptri[looptri_i].tri[tri_i];
color[0] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->r]);
color[1] = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[col->g]);
@ -712,9 +721,9 @@ struct PBVHBatches {
const float2 *mloopuv = static_cast<const float2 *>(
CustomData_get_layer_named(args->ldata, CD_PROP_FLOAT2, vbo.name.c_str()));
foreach_faces([&](int /*buffer_i*/, int tri_i, int /*vertex_i*/, const int tri) {
foreach_faces([&](int /*buffer_i*/, int tri_i, int /*vertex_i*/, const int looptri_i) {
*static_cast<float2 *>(
GPU_vertbuf_raw_step(&access)) = mloopuv[args->mlooptri[tri].tri[tri_i]];
GPU_vertbuf_raw_step(&access)) = mloopuv[args->mlooptri[looptri_i].tri[tri_i]];
});
break;
}
@ -965,8 +974,9 @@ struct PBVHBatches {
CustomData_get_layer_named(args->pdata, CD_PROP_INT32, "material_index"));
if (mat_index && args->totprim) {
int poly_index = args->looptri_polys[args->prim_indices[0]];
material_index = mat_index[poly_index];
const int looptri_i = args->prim_indices[0];
const int poly_i = args->looptri_polys[looptri_i];
material_index = mat_index[poly_i];
}
const blender::Span<blender::int2> edges = args->me->edges();
@ -974,13 +984,13 @@ struct PBVHBatches {
/* Calculate number of edges. */
int edge_count = 0;
for (int i = 0; i < args->totprim; i++) {
const int tri_i = args->prim_indices[i];
const int poly_i = args->looptri_polys[tri_i];
const int looptri_i = args->prim_indices[i];
const int poly_i = args->looptri_polys[looptri_i];
if (args->hide_poly && args->hide_poly[poly_i]) {
continue;
}
const MLoopTri *lt = args->mlooptri + args->prim_indices[i];
const MLoopTri *lt = &args->mlooptri[looptri_i];
int r_edges[3];
BKE_mesh_looptri_get_real_edges(
edges.data(), args->corner_verts.data(), args->corner_edges.data(), lt, r_edges);
@ -1001,13 +1011,13 @@ struct PBVHBatches {
int vertex_i = 0;
for (int i = 0; i < args->totprim; i++) {
const int tri_i = args->prim_indices[i];
const int poly_i = args->looptri_polys[tri_i];
const int looptri_i = args->prim_indices[i];
const int poly_i = args->looptri_polys[looptri_i];
if (args->hide_poly && args->hide_poly[poly_i]) {
continue;
}
const MLoopTri *lt = args->mlooptri + args->prim_indices[i];
const MLoopTri *lt = &args->mlooptri[looptri_i];
int r_edges[3];
BKE_mesh_looptri_get_real_edges(
edges.data(), args->corner_verts.data(), args->corner_edges.data(), lt, r_edges);
@ -1059,8 +1069,8 @@ struct PBVHBatches {
CustomData_get_layer_named(args->pdata, CD_PROP_INT32, "material_index"));
if (mat_index && args->totprim) {
int poly_index = BKE_subdiv_ccg_grid_to_face_index(args->subdiv_ccg, args->grid_indices[0]);
material_index = mat_index[poly_index];
int poly_i = BKE_subdiv_ccg_grid_to_face_index(args->subdiv_ccg, args->grid_indices[0]);
material_index = mat_index[poly_i];
}
needs_tri_index = true;

View File

@ -180,6 +180,7 @@ typedef enum ThemeColorID {
TH_NODE_ATTRIBUTE,
TH_NODE_ZONE_SIMULATION,
TH_SIMULATED_FRAMES,
TH_CONSOLE_OUTPUT,
TH_CONSOLE_INPUT,

View File

@ -644,6 +644,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
case TH_NODE_ZONE_SIMULATION:
cp = ts->node_zone_simulation;
break;
case TH_SIMULATED_FRAMES:
cp = ts->simulated_frames;
break;
case TH_SEQ_MOVIE:
cp = ts->movie;

View File

@ -18,10 +18,12 @@
#include "DNA_curve_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_object.h"
@ -53,6 +55,7 @@ typedef struct UndoLattice {
char typeu, typev, typew;
float fu, fv, fw;
float du, dv, dw;
MDeformVert *dvert;
size_t undo_size;
} UndoLattice;
@ -68,6 +71,14 @@ static void undolatt_to_editlatt(UndoLattice *ult, EditLatt *editlatt)
memcpy(editlatt->latt->def, ult->def, sizeof(BPoint) * len_src);
}
/* Even for the same amount of points we dont just copy memory for MDeformVert, relations to
* MDeformWeight might have changed. */
if (editlatt->latt->dvert && ult->dvert) {
BKE_defvert_array_free(editlatt->latt->dvert, len_dst);
editlatt->latt->dvert = MEM_mallocN(sizeof(MDeformVert) * len_src, "Lattice MDeformVert");
BKE_defvert_array_copy(editlatt->latt->dvert, ult->dvert, len_src);
}
editlatt->latt->pntsu = ult->pntsu;
editlatt->latt->pntsv = ult->pntsv;
editlatt->latt->pntsw = ult->pntsw;
@ -106,6 +117,13 @@ static void *undolatt_from_editlatt(UndoLattice *ult, EditLatt *editlatt)
ult->dv = editlatt->latt->dv;
ult->dw = editlatt->latt->dw;
if (editlatt->latt->dvert) {
const int tot = ult->pntsu * ult->pntsv * ult->pntsw;
ult->dvert = MEM_mallocN(sizeof(MDeformVert) * tot, "Undo Lattice MDeformVert");
BKE_defvert_array_copy(ult->dvert, editlatt->latt->dvert, tot);
ult->undo_size += sizeof(*ult->dvert) * tot;
}
ult->undo_size += sizeof(*ult->def) * ult->pntsu * ult->pntsv * ult->pntsw;
return ult;
@ -116,6 +134,10 @@ static void undolatt_free_data(UndoLattice *ult)
if (ult->def) {
MEM_freeN(ult->def);
}
if (ult->dvert) {
BKE_defvert_array_free(ult->dvert, ult->pntsu * ult->pntsv * ult->pntsw);
ult->dvert = NULL;
}
}
#if 0

View File

@ -665,7 +665,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
int island_index = 0;
data->tool = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_SMOOTH) ?
UV_SCULPT_TOOL_RELAX :
ts->uvsculpt->paint.brush->uv_sculpt_tool;
eBrushUVSculptTool(ts->uvsculpt->paint.brush->uv_sculpt_tool);
data->invert = (RNA_enum_get(op->ptr, "mode") == BRUSH_STROKE_INVERT) ? 1 : 0;
data->uvsculpt = &ts->uvsculpt->paint;

View File

@ -691,17 +691,18 @@ static void timeline_cache_draw_simulation_nodes(
GPU_matrix_scale_2f(1.0, height);
float color[4];
UI_GetThemeColor4fv(TH_SIMULATED_FRAMES, color);
switch (cache.cache_state()) {
case blender::bke::sim::CacheState::Invalid: {
copy_v4_fl4(color, 0.8, 0.8, 0.2, 0.3);
color[3] = 0.4f;
break;
}
case blender::bke::sim::CacheState::Valid: {
copy_v4_fl4(color, 0.8, 0.8, 0.2, 1.0);
color[3] = 0.7f;
break;
}
case blender::bke::sim::CacheState::Baked: {
copy_v4_fl4(color, 1.0, 0.6, 0.2, 1.0);
color[3] = 1.0f;
break;
}
}

View File

@ -125,7 +125,8 @@ class ParamsBuilder {
const int param_index = this->current_param_index();
const ParamType &param_type = signature_->params[param_index].type;
BLI_assert(param_type.category() == ParamCategory::SingleOutput);
const CPPType &type = param_type.data_type().single_type();
const DataType data_type = param_type.data_type();
const CPPType &type = data_type.single_type();
if (bool(signature_->params[param_index].flag & ParamFlag::SupportsUnusedOutput)) {
/* An empty span indicates that this is ignored. */

View File

@ -1,621 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. */
#include <BLI_sys_types.h> /* For `uint`. */
#include <BlockDXT.h>
#include <ColorBlock.h>
#include <Common.h>
#include <Stream.h>
/* ---------------------------------------------------------------------------
* BlockDXT1
* --------------------------------------------------------------------------*/
uint BlockDXT1::evaluatePalette(Color32 color_array[4]) const
{
/* Does bit expansion before interpolation. */
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
color_array[0].g = (col0.g << 2) | (col0.g >> 4);
color_array[0].r = (col0.r << 3) | (col0.r >> 2);
color_array[0].a = 0xFF;
/* @@ Same as above, but faster?
* Color32 c;
* c.u = ((col0.u << 3) & 0xf8) | ((col0.u << 5) & 0xfc00) | ((col0.u << 8) & 0xf80000);
* c.u |= (c.u >> 5) & 0x070007;
* c.u |= (c.u >> 6) & 0x000300;
* color_array[0].u = c.u; */
color_array[1].r = (col1.r << 3) | (col1.r >> 2);
color_array[1].g = (col1.g << 2) | (col1.g >> 4);
color_array[1].b = (col1.b << 3) | (col1.b >> 2);
color_array[1].a = 0xFF;
/* @@ Same as above, but faster?
* c.u = ((col1.u << 3) & 0xf8) | ((col1.u << 5) & 0xfc00) | ((col1.u << 8) & 0xf80000);
* c.u |= (c.u >> 5) & 0x070007;
* c.u |= (c.u >> 6) & 0x000300;
* color_array[1].u = c.u; */
if (col0.u > col1.u) {
/* Four-color block: derive the other two colors. */
color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3;
color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
color_array[2].a = 0xFF;
color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3;
color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
color_array[3].a = 0xFF;
return 4;
}
/* Three-color block: derive the other color. */
color_array[2].r = (color_array[0].r + color_array[1].r) / 2;
color_array[2].g = (color_array[0].g + color_array[1].g) / 2;
color_array[2].b = (color_array[0].b + color_array[1].b) / 2;
color_array[2].a = 0xFF;
/* Set all components to 0 to match DXT specs. */
color_array[3].r = 0x00; /* color_array[2].r; */
color_array[3].g = 0x00; /* color_array[2].g; */
color_array[3].b = 0x00; /* color_array[2].b; */
color_array[3].a = 0x00;
return 3;
}
uint BlockDXT1::evaluatePaletteNV5x(Color32 color_array[4]) const
{
/* Does bit expansion before interpolation. */
color_array[0].b = (3 * col0.b * 22) / 8;
color_array[0].g = (col0.g << 2) | (col0.g >> 4);
color_array[0].r = (3 * col0.r * 22) / 8;
color_array[0].a = 0xFF;
color_array[1].r = (3 * col1.r * 22) / 8;
color_array[1].g = (col1.g << 2) | (col1.g >> 4);
color_array[1].b = (3 * col1.b * 22) / 8;
color_array[1].a = 0xFF;
int gdiff = color_array[1].g - color_array[0].g;
if (col0.u > col1.u) {
/* Four-color block: derive the other two colors. */
color_array[2].r = ((2 * col0.r + col1.r) * 22) / 8;
color_array[2].g = (256 * color_array[0].g + gdiff / 4 + 128 + gdiff * 80) / 256;
color_array[2].b = ((2 * col0.b + col1.b) * 22) / 8;
color_array[2].a = 0xFF;
color_array[3].r = ((2 * col1.r + col0.r) * 22) / 8;
color_array[3].g = (256 * color_array[1].g - gdiff / 4 + 128 - gdiff * 80) / 256;
color_array[3].b = ((2 * col1.b + col0.b) * 22) / 8;
color_array[3].a = 0xFF;
return 4;
}
/* Three-color block: derive the other color. */
color_array[2].r = ((col0.r + col1.r) * 33) / 8;
color_array[2].g = (256 * color_array[0].g + gdiff / 4 + 128 + gdiff * 128) / 256;
color_array[2].b = ((col0.b + col1.b) * 33) / 8;
color_array[2].a = 0xFF;
/* Set all components to 0 to match DXT specs. */
color_array[3].r = 0x00; /* color_array[2].r; */
color_array[3].g = 0x00; /* color_array[2].g; */
color_array[3].b = 0x00; /* color_array[2].b; */
color_array[3].a = 0x00;
return 3;
}
void BlockDXT1::evaluatePalette3(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
color_array[0].g = (col0.g << 2) | (col0.g >> 4);
color_array[0].r = (col0.r << 3) | (col0.r >> 2);
color_array[0].a = 0xFF;
color_array[1].r = (col1.r << 3) | (col1.r >> 2);
color_array[1].g = (col1.g << 2) | (col1.g >> 4);
color_array[1].b = (col1.b << 3) | (col1.b >> 2);
color_array[1].a = 0xFF;
/* Three-color block: derive the other color. */
color_array[2].r = (color_array[0].r + color_array[1].r) / 2;
color_array[2].g = (color_array[0].g + color_array[1].g) / 2;
color_array[2].b = (color_array[0].b + color_array[1].b) / 2;
color_array[2].a = 0xFF;
/* Set all components to 0 to match DXT specs. */
color_array[3].r = 0x00; /* color_array[2].r; */
color_array[3].g = 0x00; /* color_array[2].g; */
color_array[3].b = 0x00; /* color_array[2].b; */
color_array[3].a = 0x00;
}
void BlockDXT1::evaluatePalette4(Color32 color_array[4]) const
{
color_array[0].b = (col0.b << 3) | (col0.b >> 2);
color_array[0].g = (col0.g << 2) | (col0.g >> 4);
color_array[0].r = (col0.r << 3) | (col0.r >> 2);
color_array[0].a = 0xFF;
color_array[1].r = (col1.r << 3) | (col1.r >> 2);
color_array[1].g = (col1.g << 2) | (col1.g >> 4);
color_array[1].b = (col1.b << 3) | (col1.b >> 2);
color_array[1].a = 0xFF;
/* Four-color block: derive the other two colors. */
color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3;
color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
color_array[2].a = 0xFF;
color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3;
color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
color_array[3].a = 0xFF;
}
void BlockDXT1::decodeBlock(ColorBlock *block) const
{
/* Decode color block. */
Color32 color_array[4];
evaluatePalette(color_array);
/* Write color block. */
for (uint j = 0; j < 4; j++) {
for (uint i = 0; i < 4; i++) {
uint idx = (row[j] >> (2 * i)) & 3;
block->color(i, j) = color_array[idx];
}
}
}
void BlockDXT1::decodeBlockNV5x(ColorBlock *block) const
{
/* Decode color block. */
Color32 color_array[4];
evaluatePaletteNV5x(color_array);
/* Write color block. */
for (uint j = 0; j < 4; j++) {
for (uint i = 0; i < 4; i++) {
uint idx = (row[j] >> (2 * i)) & 3;
block->color(i, j) = color_array[idx];
}
}
}
void BlockDXT1::setIndices(const int *idx)
{
indices = 0;
for (uint i = 0; i < 16; i++) {
indices |= (idx[i] & 3) << (2 * i);
}
}
inline void BlockDXT1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
inline void BlockDXT1::flip2()
{
swap(row[0], row[1]);
}
/* ---------------------------------------------------------------------------
* BlockDXT3
* ---------------------------------------------------------------------------*/
void BlockDXT3::decodeBlock(ColorBlock *block) const
{
/* Decode color. */
color.decodeBlock(block);
/* Decode alpha. */
alpha.decodeBlock(block);
}
void BlockDXT3::decodeBlockNV5x(ColorBlock *block) const
{
color.decodeBlockNV5x(block);
alpha.decodeBlock(block);
}
void AlphaBlockDXT3::decodeBlock(ColorBlock *block) const
{
block->color(0x0).a = (alpha0 << 4) | alpha0;
block->color(0x1).a = (alpha1 << 4) | alpha1;
block->color(0x2).a = (alpha2 << 4) | alpha2;
block->color(0x3).a = (alpha3 << 4) | alpha3;
block->color(0x4).a = (alpha4 << 4) | alpha4;
block->color(0x5).a = (alpha5 << 4) | alpha5;
block->color(0x6).a = (alpha6 << 4) | alpha6;
block->color(0x7).a = (alpha7 << 4) | alpha7;
block->color(0x8).a = (alpha8 << 4) | alpha8;
block->color(0x9).a = (alpha9 << 4) | alpha9;
block->color(0xA).a = (alphaA << 4) | alphaA;
block->color(0xB).a = (alphaB << 4) | alphaB;
block->color(0xC).a = (alphaC << 4) | alphaC;
block->color(0xD).a = (alphaD << 4) | alphaD;
block->color(0xE).a = (alphaE << 4) | alphaE;
block->color(0xF).a = (alphaF << 4) | alphaF;
}
void AlphaBlockDXT3::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
void AlphaBlockDXT3::flip2()
{
swap(row[0], row[1]);
}
void BlockDXT3::flip4()
{
alpha.flip4();
color.flip4();
}
void BlockDXT3::flip2()
{
alpha.flip2();
color.flip2();
}
/* ---------------------------------------------------------------------------
* BlockDXT5
* ---------------------------------------------------------------------------*/
void AlphaBlockDXT5::evaluatePalette(uint8 alpha[8]) const
{
if (alpha0() > alpha1()) {
evaluatePalette8(alpha);
}
else {
evaluatePalette6(alpha);
}
}
void AlphaBlockDXT5::evaluatePalette8(uint8 alpha[8]) const
{
/* 8-alpha block: derive the other six alphas.
* Bit code 000 = alpha0, 001 = alpha1, others are interpolated. */
alpha[0] = alpha0();
alpha[1] = alpha1();
alpha[2] = (6 * alpha[0] + 1 * alpha[1]) / 7; /* bit code 010 */
alpha[3] = (5 * alpha[0] + 2 * alpha[1]) / 7; /* bit code 011 */
alpha[4] = (4 * alpha[0] + 3 * alpha[1]) / 7; /* bit code 100 */
alpha[5] = (3 * alpha[0] + 4 * alpha[1]) / 7; /* bit code 101 */
alpha[6] = (2 * alpha[0] + 5 * alpha[1]) / 7; /* bit code 110 */
alpha[7] = (1 * alpha[0] + 6 * alpha[1]) / 7; /* bit code 111 */
}
void AlphaBlockDXT5::evaluatePalette6(uint8 alpha[8]) const
{
/* 6-alpha block.
* Bit code 000 = alpha0, 001 = alpha1, others are interpolated. */
alpha[0] = alpha0();
alpha[1] = alpha1();
alpha[2] = (4 * alpha[0] + 1 * alpha[1]) / 5; /* Bit code 010 */
alpha[3] = (3 * alpha[0] + 2 * alpha[1]) / 5; /* Bit code 011 */
alpha[4] = (2 * alpha[0] + 3 * alpha[1]) / 5; /* Bit code 100 */
alpha[5] = (1 * alpha[0] + 4 * alpha[1]) / 5; /* Bit code 101 */
alpha[6] = 0x00; /* Bit code 110 */
alpha[7] = 0xFF; /* Bit code 111 */
}
void AlphaBlockDXT5::indices(uint8 index_array[16]) const
{
index_array[0x0] = bits0();
index_array[0x1] = bits1();
index_array[0x2] = bits2();
index_array[0x3] = bits3();
index_array[0x4] = bits4();
index_array[0x5] = bits5();
index_array[0x6] = bits6();
index_array[0x7] = bits7();
index_array[0x8] = bits8();
index_array[0x9] = bits9();
index_array[0xA] = bitsA();
index_array[0xB] = bitsB();
index_array[0xC] = bitsC();
index_array[0xD] = bitsD();
index_array[0xE] = bitsE();
index_array[0xF] = bitsF();
}
uint AlphaBlockDXT5::index(uint index) const
{
int offset = (3 * index + 16);
return uint((this->u >> offset) & 0x7);
}
void AlphaBlockDXT5::setIndex(uint index, uint value)
{
int offset = (3 * index + 16);
uint64 mask = uint64(0x7) << offset;
this->u = (this->u & ~mask) | (uint64(value) << offset);
}
void AlphaBlockDXT5::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
evaluatePalette(alpha_array);
uint8 index_array[16];
indices(index_array);
for (uint i = 0; i < 16; i++) {
block->color(i).a = alpha_array[index_array[i]];
}
}
void AlphaBlockDXT5::flip4()
{
uint64 *b = (uint64 *)this;
/* @@ The masks might have to be byte swapped. */
uint64 tmp = (*b & (uint64)(0x000000000000FFFFLL));
tmp |= (*b & (uint64)(0x000000000FFF0000LL)) << 36;
tmp |= (*b & (uint64)(0x000000FFF0000000LL)) << 12;
tmp |= (*b & (uint64)(0x000FFF0000000000LL)) >> 12;
tmp |= (*b & (uint64)(0xFFF0000000000000LL)) >> 36;
*b = tmp;
}
void AlphaBlockDXT5::flip2()
{
uint *b = (uint *)this;
/* @@ The masks might have to be byte swapped. */
uint tmp = (*b & 0xFF000000);
tmp |= (*b & 0x00000FFF) << 12;
tmp |= (*b & 0x00FFF000) >> 12;
*b = tmp;
}
void BlockDXT5::decodeBlock(ColorBlock *block) const
{
/* Decode color. */
color.decodeBlock(block);
/* Decode alpha. */
alpha.decodeBlock(block);
}
void BlockDXT5::decodeBlockNV5x(ColorBlock *block) const
{
/* Decode color. */
color.decodeBlockNV5x(block);
/* Decode alpha. */
alpha.decodeBlock(block);
}
void BlockDXT5::flip4()
{
alpha.flip4();
color.flip4();
}
void BlockDXT5::flip2()
{
alpha.flip2();
color.flip2();
}
void BlockATI1::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
alpha.evaluatePalette(alpha_array);
uint8 index_array[16];
alpha.indices(index_array);
for (uint i = 0; i < 16; i++) {
Color32 &c = block->color(i);
c.b = c.g = c.r = alpha_array[index_array[i]];
c.a = 255;
}
}
void BlockATI1::flip4()
{
alpha.flip4();
}
void BlockATI1::flip2()
{
alpha.flip2();
}
void BlockATI2::decodeBlock(ColorBlock *block) const
{
uint8 alpha_array[8];
uint8 index_array[16];
x.evaluatePalette(alpha_array);
x.indices(index_array);
for (uint i = 0; i < 16; i++) {
Color32 &c = block->color(i);
c.r = alpha_array[index_array[i]];
}
y.evaluatePalette(alpha_array);
y.indices(index_array);
for (uint i = 0; i < 16; i++) {
Color32 &c = block->color(i);
c.g = alpha_array[index_array[i]];
c.b = 0;
c.a = 255;
}
}
void BlockATI2::flip4()
{
x.flip4();
y.flip4();
}
void BlockATI2::flip2()
{
x.flip2();
y.flip2();
}
void BlockCTX1::evaluatePalette(Color32 color_array[4]) const
{
/* Does bit expansion before interpolation. */
color_array[0].b = 0x00;
color_array[0].g = col0[1];
color_array[0].r = col0[0];
color_array[0].a = 0xFF;
color_array[1].r = 0x00;
color_array[1].g = col0[1];
color_array[1].b = col1[0];
color_array[1].a = 0xFF;
color_array[2].r = 0x00;
color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
color_array[2].a = 0xFF;
color_array[3].r = 0x00;
color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
color_array[3].a = 0xFF;
}
void BlockCTX1::decodeBlock(ColorBlock *block) const
{
/* Decode color block. */
Color32 color_array[4];
evaluatePalette(color_array);
/* Write color block. */
for (uint j = 0; j < 4; j++) {
for (uint i = 0; i < 4; i++) {
uint idx = (row[j] >> (2 * i)) & 3;
block->color(i, j) = color_array[idx];
}
}
}
void BlockCTX1::setIndices(const int *idx)
{
indices = 0;
for (uint i = 0; i < 16; i++) {
indices |= (idx[i] & 3) << (2 * i);
}
}
inline void BlockCTX1::flip4()
{
swap(row[0], row[3]);
swap(row[1], row[2]);
}
inline void BlockCTX1::flip2()
{
swap(row[0], row[1]);
}
void mem_read(Stream &mem, BlockDXT1 &block)
{
mem_read(mem, block.col0.u);
mem_read(mem, block.col1.u);
mem_read(mem, block.indices);
}
void mem_read(Stream &mem, AlphaBlockDXT3 &block)
{
for (ushort &alpha : block.row) {
mem_read(mem, alpha);
}
}
void mem_read(Stream &mem, BlockDXT3 &block)
{
mem_read(mem, block.alpha);
mem_read(mem, block.color);
}
void mem_read(Stream &mem, AlphaBlockDXT5 &block)
{
mem_read(mem, block.u);
}
void mem_read(Stream &mem, BlockDXT5 &block)
{
mem_read(mem, block.alpha);
mem_read(mem, block.color);
}
void mem_read(Stream &mem, BlockATI1 &block)
{
mem_read(mem, block.alpha);
}
void mem_read(Stream &mem, BlockATI2 &block)
{
mem_read(mem, block.x);
mem_read(mem, block.y);
}
void mem_read(Stream &mem, BlockCTX1 &block)
{
mem_read(mem, block.col0[0]);
mem_read(mem, block.col0[1]);
mem_read(mem, block.col1[0]);
mem_read(mem, block.col1[1]);
mem_read(mem, block.indices);
}

View File

@ -1,310 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. */
#pragma once
#include <Color.h>
#include <ColorBlock.h>
#include <Common.h>
#include <Stream.h>
/** DXT1 block. */
struct BlockDXT1 {
Color16 col0;
Color16 col1;
union {
uint8 row[4];
uint indices;
};
bool isFourColorMode() const;
uint evaluatePalette(Color32 color_array[4]) const;
uint evaluatePaletteNV5x(Color32 color_array[4]) const;
/** Evaluate palette assuming 3 color block. */
void evaluatePalette3(Color32 color_array[4]) const;
/** Evaluate palette assuming 4 color block. */
void evaluatePalette4(Color32 color_array[4]) const;
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
void setIndices(const int *idx);
/** Flip DXT1 block vertically. */
void flip4();
/** Flip half DXT1 block vertically. */
void flip2();
};
/** Return true if the block uses four color mode, false otherwise. */
inline bool BlockDXT1::isFourColorMode() const
{
return col0.u > col1.u;
}
/** DXT3 alpha block with explicit alpha. */
struct AlphaBlockDXT3 {
union {
struct {
uint alpha0 : 4;
uint alpha1 : 4;
uint alpha2 : 4;
uint alpha3 : 4;
uint alpha4 : 4;
uint alpha5 : 4;
uint alpha6 : 4;
uint alpha7 : 4;
uint alpha8 : 4;
uint alpha9 : 4;
uint alphaA : 4;
uint alphaB : 4;
uint alphaC : 4;
uint alphaD : 4;
uint alphaE : 4;
uint alphaF : 4;
};
uint16 row[4];
};
void decodeBlock(ColorBlock *block) const;
/** Flip DXT3 alpha block vertically. */
void flip4();
/** Flip half DXT3 alpha block vertically. */
void flip2();
};
/** DXT3 block. */
struct BlockDXT3 {
AlphaBlockDXT3 alpha;
BlockDXT1 color;
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
/** Flip DXT3 block vertically. */
void flip4();
/** Flip half DXT3 block vertically. */
void flip2();
};
/** DXT5 alpha block. */
struct AlphaBlockDXT5 {
/* uint64 unions do not compile on all platforms */
#if 0
union {
struct {
uint64 alpha0 : 8; /* 8 */
uint64 alpha1 : 8; /* 16 */
uint64 bits0 : 3; /* 3 - 19 */
uint64 bits1 : 3; /* 6 - 22 */
uint64 bits2 : 3; /* 9 - 25 */
uint64 bits3 : 3; /* 12 - 28 */
uint64 bits4 : 3; /* 15 - 31 */
uint64 bits5 : 3; /* 18 - 34 */
uint64 bits6 : 3; /* 21 - 37 */
uint64 bits7 : 3; /* 24 - 40 */
uint64 bits8 : 3; /* 27 - 43 */
uint64 bits9 : 3; /* 30 - 46 */
uint64 bitsA : 3; /* 33 - 49 */
uint64 bitsB : 3; /* 36 - 52 */
uint64 bitsC : 3; /* 39 - 55 */
uint64 bitsD : 3; /* 42 - 58 */
uint64 bitsE : 3; /* 45 - 61 */
uint64 bitsF : 3; /* 48 - 64 */
};
uint64 u;
};
#endif
uint64 u;
uint8 alpha0() const
{
return u & 0xffLL;
}
uint8 alpha1() const
{
return (u >> 8) & 0xffLL;
}
uint8 bits0() const
{
return (u >> 16) & 0x7LL;
}
uint8 bits1() const
{
return (u >> 19) & 0x7LL;
}
uint8 bits2() const
{
return (u >> 22) & 0x7LL;
}
uint8 bits3() const
{
return (u >> 25) & 0x7LL;
}
uint8 bits4() const
{
return (u >> 28) & 0x7LL;
}
uint8 bits5() const
{
return (u >> 31) & 0x7LL;
}
uint8 bits6() const
{
return (u >> 34) & 0x7LL;
}
uint8 bits7() const
{
return (u >> 37) & 0x7LL;
}
uint8 bits8() const
{
return (u >> 40) & 0x7LL;
}
uint8 bits9() const
{
return (u >> 43) & 0x7LL;
}
uint8 bitsA() const
{
return (u >> 46) & 0x7LL;
}
uint8 bitsB() const
{
return (u >> 49) & 0x7LL;
}
uint8 bitsC() const
{
return (u >> 52) & 0x7LL;
}
uint8 bitsD() const
{
return (u >> 55) & 0x7LL;
}
uint8 bitsE() const
{
return (u >> 58) & 0x7LL;
}
uint8 bitsF() const
{
return (u >> 61) & 0x7LL;
}
void evaluatePalette(uint8 alpha[8]) const;
void evaluatePalette8(uint8 alpha[8]) const;
void evaluatePalette6(uint8 alpha[8]) const;
void indices(uint8 index_array[16]) const;
uint index(uint index) const;
void setIndex(uint index, uint value);
void decodeBlock(ColorBlock *block) const;
void flip4();
void flip2();
};
/** DXT5 block. */
struct BlockDXT5 {
AlphaBlockDXT5 alpha;
BlockDXT1 color;
void decodeBlock(ColorBlock *block) const;
void decodeBlockNV5x(ColorBlock *block) const;
/** Flip DXT5 block vertically. */
void flip4();
/** Flip half DXT5 block vertically. */
void flip2();
};
/** ATI1 block. */
struct BlockATI1 {
AlphaBlockDXT5 alpha;
/** Decode ATI1 block. */
void decodeBlock(ColorBlock *block) const;
/** Flip ATI1 block vertically. */
void flip4();
/** Flip half ATI1 block vertically. */
void flip2();
};
/** ATI2 block. */
struct BlockATI2 {
AlphaBlockDXT5 x;
AlphaBlockDXT5 y;
/** Decode ATI2 block. */
void decodeBlock(ColorBlock *block) const;
/** Flip ATI2 block vertically. */
void flip4();
/** Flip half ATI2 block vertically. */
void flip2();
};
/** CTX1 block. */
struct BlockCTX1 {
uint8 col0[2];
uint8 col1[2];
union {
uint8 row[4];
uint indices;
};
void evaluatePalette(Color32 color_array[4]) const;
void setIndices(const int *idx);
void decodeBlock(ColorBlock *block) const;
/** Flip CTX1 block vertically. */
void flip4();
/** Flip half CTX1 block vertically. */
void flip2();
};
void mem_read(Stream &mem, BlockDXT1 &block);
void mem_read(Stream &mem, AlphaBlockDXT3 &block);
void mem_read(Stream &mem, BlockDXT3 &block);
void mem_read(Stream &mem, AlphaBlockDXT5 &block);
void mem_read(Stream &mem, BlockDXT5 &block);
void mem_read(Stream &mem, BlockATI1 &block);
void mem_read(Stream &mem, BlockATI2 &block);
void mem_read(Stream &mem, BlockCTX1 &block);

View File

@ -1,47 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright 2006 Blender Foundation
set(INC
.
..
../..
../../../blenkernel
../../../blenlib
../../../makesdna
../../../../../intern/guardedalloc
../../../../../intern/utfconv
)
set(INC_SYS
)
set(SRC
BlockDXT.h
Color.h
ColorBlock.h
Common.h
DirectDrawSurface.h
FlipDXT.h
Image.h
PixelFormat.h
Stream.h
dds_api.h
BlockDXT.cpp
ColorBlock.cpp
DirectDrawSurface.cpp
FlipDXT.cpp
Image.cpp
Stream.cpp
dds_api.cpp
)
set(LIB
)
if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
blender_add_lib(bf_imbuf_dds "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@ -1,92 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain -- <castanyo@yahoo.es> */
#pragma once
/** 32 bit color stored as BGRA. */
class Color32 {
public:
Color32() {}
Color32(const Color32 &) = default;
Color32(unsigned char R, unsigned char G, unsigned char B)
{
setRGBA(R, G, B, 0xFF);
}
Color32(unsigned char R, unsigned char G, unsigned char B, unsigned char A)
{
setRGBA(R, G, B, A);
}
#if 0
Color32(unsigned char c[4])
{
setRGBA(c[0], c[1], c[2], c[3]);
}
Color32(float R, float G, float B)
{
setRGBA(uint(R * 255), uint(G * 255), uint(B * 255), 0xFF);
}
Color32(float R, float G, float B, float A)
{
setRGBA(uint(R * 255), uint(G * 255), uint(B * 255), uint(A * 255));
}
#endif
Color32(unsigned int U) : u(U) {}
void setRGBA(unsigned char R, unsigned char G, unsigned char B, unsigned char A)
{
r = R;
g = G;
b = B;
a = A;
}
void setBGRA(unsigned char B, unsigned char G, unsigned char R, unsigned char A = 0xFF)
{
r = R;
g = G;
b = B;
a = A;
}
operator unsigned int() const
{
return u;
}
union {
struct {
unsigned char b, g, r, a;
};
unsigned int u;
};
};
/** 16 bit 565 BGR color. */
class Color16 {
public:
Color16() {}
Color16(const Color16 &c) : u(c.u) {}
explicit Color16(unsigned short U) : u(U) {}
union {
struct {
unsigned short b : 5;
unsigned short g : 6;
unsigned short r : 5;
};
unsigned short u;
};
};

View File

@ -1,468 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain - <castanyo@yahoo.es> */
#include <ColorBlock.h>
#include <Common.h>
#include <Image.h>
#if 0
/* Get approximate luminance. */
inline static uint colorLuminance(Color32 c)
{
return c.r + c.g + c.b;
}
/* Get the euclidean distance between the given colors. */
inline static uint colorDistance(Color32 c0, Color32 c1)
{
return (c0.r - c1.r) * (c0.r - c1.r) + (c0.g - c1.g) * (c0.g - c1.g) +
(c0.b - c1.b) * (c0.b - c1.b);
}
#endif
ColorBlock::ColorBlock(const uint *linearImage)
{
for (uint i = 0; i < 16; i++) {
color(i) = Color32(linearImage[i]);
}
}
ColorBlock::ColorBlock(const ColorBlock &block)
{
for (uint i = 0; i < 16; i++) {
color(i) = block.color(i);
}
}
ColorBlock::ColorBlock(const Image *img, uint x, uint y)
{
init(img, x, y);
}
void ColorBlock::init(const Image *img, uint x, uint y)
{
init(img->width(), img->height(), (const uint *)img->pixels(), x, y);
}
void ColorBlock::init(uint w, uint h, const uint *data, uint x, uint y)
{
const uint bw = MIN(w - x, 4U);
const uint bh = MIN(h - y, 4U);
/* Blocks that are smaller than 4x4 are handled by repeating the pixels.
* @@ That's only correct when block size is 1, 2 or 4, but not with 3. :(
* @@ Ideally we should zero the weights of the pixels out of range. */
for (uint i = 0; i < 4; i++) {
const int by = i % bh;
for (uint e = 0; e < 4; e++) {
const int bx = e % bw;
const uint idx = (y + by) * w + x + bx;
color(e, i).u = data[idx];
}
}
}
void ColorBlock::init(uint w, uint h, const float *data, uint x, uint y)
{
const uint bw = MIN(w - x, 4U);
const uint bh = MIN(h - y, 4U);
/* Blocks that are smaller than 4x4 are handled by repeating the pixels.
* @@ That's only correct when block size is 1, 2 or 4, but not with 3. :(
* @@ Ideally we should zero the weights of the pixels out of range. */
uint srcPlane = w * h;
for (uint i = 0; i < 4; i++) {
const uint by = i % bh;
for (uint e = 0; e < 4; e++) {
const uint bx = e % bw;
const uint idx = ((y + by) * w + x + bx);
Color32 &c = color(e, i);
/* @@ Is this the right way to quantize floats to bytes? */
c.r = uint8(255 * CLAMP(data[idx + 0 * srcPlane], 0.0f, 1.0f));
c.g = uint8(255 * CLAMP(data[idx + 1 * srcPlane], 0.0f, 1.0f));
c.b = uint8(255 * CLAMP(data[idx + 2 * srcPlane], 0.0f, 1.0f));
c.a = uint8(255 * CLAMP(data[idx + 3 * srcPlane], 0.0f, 1.0f));
}
}
}
static inline uint8 component(Color32 c, uint i)
{
if (i == 0) {
return c.r;
}
if (i == 1) {
return c.g;
}
if (i == 2) {
return c.b;
}
if (i == 3) {
return c.a;
}
if (i == 4) {
return 0xFF;
}
return 0;
}
void ColorBlock::swizzle(uint x, uint y, uint z, uint w)
{
for (Color32 &color : m_color) {
const Color32 c = color;
color.r = component(c, x);
color.g = component(c, y);
color.b = component(c, z);
color.a = component(c, w);
}
}
bool ColorBlock::isSingleColor(Color32 mask /*= Color32(0xFF, 0xFF, 0xFF, 0x00) */) const
{
uint u = m_color[0].u & mask.u;
for (int i = 1; i < 16; i++) {
if (u != (m_color[i].u & mask.u)) {
return false;
}
}
return true;
}
#if 0
/** Returns true if the block has a single color, ignoring transparent pixels. */
bool ColorBlock::isSingleColorNoAlpha() const
{
Color32 c;
int i;
for (i = 0; i < 16; i++) {
if (m_color[i].a != 0) {
c = m_color[i];
}
}
Color32 mask(0xFF, 0xFF, 0xFF, 0x00);
uint u = c.u & mask.u;
for (; i < 16; i++) {
if (u != (m_color[i].u & mask.u)) {
return false;
}
}
return true;
}
#endif
#if 0
/** Count number of unique colors in this color block. */
uint ColorBlock::countUniqueColors() const
{
uint count = 0;
/* @@ This does not have to be o(n^2) */
for (int i = 0; i < 16; i++) {
bool unique = true;
for (int j = 0; j < i; j++) {
if (m_color[i] != m_color[j]) {
unique = false;
}
}
if (unique) {
count++;
}
}
return count;
}
#endif
#if 0
/** Get average color of the block. */
Color32 ColorBlock::averageColor() const
{
uint r, g, b, a;
r = g = b = a = 0;
for (uint i = 0; i < 16; i++) {
r += m_color[i].r;
g += m_color[i].g;
b += m_color[i].b;
a += m_color[i].a;
}
return Color32(uint8(r / 16), uint8(g / 16), uint8(b / 16), uint8(a / 16));
}
#endif
bool ColorBlock::hasAlpha() const
{
for (const auto &i : m_color) {
if (i.a != 255) {
return true;
}
}
return false;
}
#if 0
/** Get diameter color range. */
void ColorBlock::diameterRange(Color32 *start, Color32 *end) const
{
Color32 c0, c1;
uint best_dist = 0;
for (int i = 0; i < 16; i++) {
for (int j = i + 1; j < 16; j++) {
uint dist = colorDistance(m_color[i], m_color[j]);
if (dist > best_dist) {
best_dist = dist;
c0 = m_color[i];
c1 = m_color[j];
}
}
}
*start = c0;
*end = c1;
}
/** Get luminance color range. */
void ColorBlock::luminanceRange(Color32 *start, Color32 *end) const
{
Color32 minColor, maxColor;
uint minLuminance, maxLuminance;
maxLuminance = minLuminance = colorLuminance(m_color[0]);
for (uint i = 1; i < 16; i++) {
uint luminance = colorLuminance(m_color[i]);
if (luminance > maxLuminance) {
maxLuminance = luminance;
maxColor = m_color[i];
}
else if (luminance < minLuminance) {
minLuminance = luminance;
minColor = m_color[i];
}
}
*start = minColor;
*end = maxColor;
}
/** Get color range based on the bounding box. */
void ColorBlock::boundsRange(Color32 *start, Color32 *end) const
{
Color32 minColor(255, 255, 255);
Color32 maxColor(0, 0, 0);
for (uint i = 0; i < 16; i++) {
if (m_color[i].r < minColor.r) {
minColor.r = m_color[i].r;
}
if (m_color[i].g < minColor.g) {
minColor.g = m_color[i].g;
}
if (m_color[i].b < minColor.b) {
minColor.b = m_color[i].b;
}
if (m_color[i].r > maxColor.r) {
maxColor.r = m_color[i].r;
}
if (m_color[i].g > maxColor.g) {
maxColor.g = m_color[i].g;
}
if (m_color[i].b > maxColor.b) {
maxColor.b = m_color[i].b;
}
}
/* Offset range by 1/16 of the extents */
Color32 inset;
inset.r = (maxColor.r - minColor.r) >> 4;
inset.g = (maxColor.g - minColor.g) >> 4;
inset.b = (maxColor.b - minColor.b) >> 4;
minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
*start = minColor;
*end = maxColor;
}
/** Get color range based on the bounding box. */
void ColorBlock::boundsRangeAlpha(Color32 *start, Color32 *end) const
{
Color32 minColor(255, 255, 255, 255);
Color32 maxColor(0, 0, 0, 0);
for (uint i = 0; i < 16; i++) {
if (m_color[i].r < minColor.r) {
minColor.r = m_color[i].r;
}
if (m_color[i].g < minColor.g) {
minColor.g = m_color[i].g;
}
if (m_color[i].b < minColor.b) {
minColor.b = m_color[i].b;
}
if (m_color[i].a < minColor.a) {
minColor.a = m_color[i].a;
}
if (m_color[i].r > maxColor.r) {
maxColor.r = m_color[i].r;
}
if (m_color[i].g > maxColor.g) {
maxColor.g = m_color[i].g;
}
if (m_color[i].b > maxColor.b) {
maxColor.b = m_color[i].b;
}
if (m_color[i].a > maxColor.a) {
maxColor.a = m_color[i].a;
}
}
/* Offset range by 1/16 of the extents */
Color32 inset;
inset.r = (maxColor.r - minColor.r) >> 4;
inset.g = (maxColor.g - minColor.g) >> 4;
inset.b = (maxColor.b - minColor.b) >> 4;
inset.a = (maxColor.a - minColor.a) >> 4;
minColor.r = (minColor.r + inset.r <= 255) ? minColor.r + inset.r : 255;
minColor.g = (minColor.g + inset.g <= 255) ? minColor.g + inset.g : 255;
minColor.b = (minColor.b + inset.b <= 255) ? minColor.b + inset.b : 255;
minColor.a = (minColor.a + inset.a <= 255) ? minColor.a + inset.a : 255;
maxColor.r = (maxColor.r >= inset.r) ? maxColor.r - inset.r : 0;
maxColor.g = (maxColor.g >= inset.g) ? maxColor.g - inset.g : 0;
maxColor.b = (maxColor.b >= inset.b) ? maxColor.b - inset.b : 0;
maxColor.a = (maxColor.a >= inset.a) ? maxColor.a - inset.a : 0;
*start = minColor;
*end = maxColor;
}
#endif
#if 0
/** Sort colors by absolute value in their 16 bit representation. */
void ColorBlock::sortColorsByAbsoluteValue()
{
/* Dummy selection sort. */
for (uint a = 0; a < 16; a++) {
uint max = a;
Color16 cmax(m_color[a]);
for (uint b = a + 1; b < 16; b++) {
Color16 cb(m_color[b]);
if (cb.u > cmax.u) {
max = b;
cmax = cb;
}
}
swap(m_color[a], m_color[max]);
}
}
#endif
#if 0
/** Find extreme colors in the given axis. */
void ColorBlock::computeRange(Vector3::Arg axis, Color32 *start, Color32 *end) const
{
int mini, maxi;
mini = maxi = 0;
float min, max;
min = max = dot(Vector3(m_color[0].r, m_color[0].g, m_color[0].b), axis);
for (uint i = 1; i < 16; i++) {
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
float val = dot(vec, axis);
if (val < min) {
mini = i;
min = val;
}
else if (val > max) {
maxi = i;
max = val;
}
}
*start = m_color[mini];
*end = m_color[maxi];
}
#endif
#if 0
/** Sort colors in the given axis. */
void ColorBlock::sortColors(const Vector3 &axis)
{
float luma_array[16];
for (uint i = 0; i < 16; i++) {
const Vector3 vec(m_color[i].r, m_color[i].g, m_color[i].b);
luma_array[i] = dot(vec, axis);
}
/* Dummy selection sort. */
for (uint a = 0; a < 16; a++) {
uint min = a;
for (uint b = a + 1; b < 16; b++) {
if (luma_array[b] < luma_array[min]) {
min = b;
}
}
swap(luma_array[a], luma_array[min]);
swap(m_color[a], m_color[min]);
}
}
#endif
#if 0
/** Get the volume of the color block. */
float ColorBlock::volume() const
{
Box bounds;
bounds.clearBounds();
for (int i = 0; i < 16; i++) {
const Vector3 point(m_color[i].r, m_color[i].g, m_color[i].b);
bounds.addPointToBounds(point);
}
return bounds.volume();
}
#endif

View File

@ -1,83 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain -- <castanyo@yahoo.es> */
#pragma once
#include <Color.h>
#include <Image.h>
/** Uncompressed 4x4 color block. */
struct ColorBlock {
ColorBlock() = default;
/** Initialize the color block from an array of colors. */
ColorBlock(const uint *linearImage);
/** Initialize the color block with the contents of the given block. */
ColorBlock(const ColorBlock &block);
/** Initialize this color block. */
ColorBlock(const Image *img, uint x, uint y);
void init(const Image *img, uint x, uint y);
void init(uint w, uint h, const uint *data, uint x, uint y);
void init(uint w, uint h, const float *data, uint x, uint y);
void swizzle(uint x, uint y, uint z, uint w); /* 0=r, 1=g, 2=b, 3=a, 4=0xFF, 5=0 */
/** Returns true if the block has a single color. */
bool isSingleColor(Color32 mask = Color32(0xFF, 0xFF, 0xFF, 0x00)) const;
/** Return true if the block is not fully opaque. */
bool hasAlpha() const;
/* Accessors */
const Color32 *colors() const;
Color32 color(uint i) const;
Color32 &color(uint i);
Color32 color(uint x, uint y) const;
Color32 &color(uint x, uint y);
private:
Color32 m_color[4 * 4];
};
/** Get pointer to block colors. */
inline const Color32 *ColorBlock::colors() const
{
return m_color;
}
/** Get block color. */
inline Color32 ColorBlock::color(uint i) const
{
return m_color[i];
}
/** Get block color. */
inline Color32 &ColorBlock::color(uint i)
{
return m_color[i];
}
/** Get block color. */
inline Color32 ColorBlock::color(uint x, uint y) const
{
return m_color[y * 4 + x];
}
/** Get block color. */
inline Color32 &ColorBlock::color(uint x, uint y)
{
return m_color[y * 4 + x];
}

View File

@ -1,36 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
#pragma once
#ifndef MIN
# define MIN(a, b) ((a) <= (b) ? (a) : (b))
#endif
#ifndef MAX
# define MAX(a, b) ((a) >= (b) ? (a) : (b))
#endif
#ifndef CLAMP
# define CLAMP(x, a, b) MIN(MAX((x), (a)), (b))
#endif
template<typename T> inline void swap(T &a, T &b)
{
T tmp = a;
a = b;
b = tmp;
}
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint;
typedef unsigned int uint32;
typedef unsigned long long uint64;
// copied from nvtt src/nvimage/nvimage.h
inline uint computePitch(uint w, uint bitsize, uint alignment)
{
return ((w * bitsize + 8 * alignment - 1) / (8 * alignment)) * alignment;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,175 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE. */
#pragma once
#include <ColorBlock.h>
#include <Common.h>
#include <Image.h>
#include <Stream.h>
struct DDSPixelFormat {
uint size;
uint flags;
uint fourcc;
uint bitcount;
uint rmask;
uint gmask;
uint bmask;
uint amask;
};
struct DDSCaps {
uint caps1;
uint caps2;
uint caps3;
uint caps4;
};
/** DDS file header for DX10. */
struct DDSHeader10 {
uint dxgiFormat;
uint resourceDimension;
uint miscFlag;
uint arraySize;
uint reserved;
};
/** DDS file header. */
struct DDSHeader {
uint fourcc;
uint size;
uint flags;
uint height;
uint width;
uint pitch;
uint depth;
uint mipmapcount;
uint reserved[11];
DDSPixelFormat pf;
DDSCaps caps;
uint notused;
DDSHeader10 header10;
/* Helper methods. */
DDSHeader();
void setWidth(uint w);
void setHeight(uint h);
void setDepth(uint d);
void setMipmapCount(uint count);
void setTexture2D();
void setTexture3D();
void setTextureCube();
void setLinearSize(uint size);
void setPitch(uint pitch);
void setFourCC(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
void setFormatCode(uint code);
void setSwizzleCode(uint8 c0, uint8 c1, uint8 c2, uint8 c3);
void setPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);
void setDX10Format(uint format);
void setNormalFlag(bool b);
void setSrgbFlag(bool b);
void setHasAlphaFlag(bool b);
void setUserVersion(int version);
// void swapBytes();
bool hasDX10Header() const;
uint signature() const;
uint toolVersion() const;
uint userVersion() const;
bool isNormalMap() const;
bool isSrgb() const;
bool hasAlpha() const;
uint d3d9Format() const;
};
/** DirectDraw Surface. (DDS) */
class DirectDrawSurface {
public:
DirectDrawSurface(unsigned char *mem, uint size);
bool isValid() const;
bool isSupported() const;
bool hasAlpha() const;
uint mipmapCount() const;
uint fourCC() const;
uint width() const;
uint height() const;
uint depth() const;
bool isTexture1D() const;
bool isTexture2D() const;
bool isTexture3D() const;
bool isTextureCube() const;
void setNormalFlag(bool b);
void setHasAlphaFlag(bool b);
void setUserVersion(int version);
void mipmap(Image *img, uint f, uint m);
/**
* It was easier to copy this function from upstream than to resync.
* This should be removed if a resync ever occurs.
*/
void *readData(uint &size);
// void mipmap(FloatImage *img, uint f, uint m);
void printInfo() const;
private:
uint blockSize() const;
uint faceSize() const;
uint mipmapSize(uint m) const;
uint offset(uint f, uint m);
void readLinearImage(Image *img);
void readBlockImage(Image *img);
void readBlock(ColorBlock *rgba);
private:
/** Memory where DDS file resides. */
Stream stream;
DDSHeader header;
};
void mem_read(Stream &mem, DDSPixelFormat &pf);
void mem_read(Stream &mem, DDSCaps &caps);
void mem_read(Stream &mem, DDSHeader &header);
void mem_read(Stream &mem, DDSHeader10 &header);

View File

@ -1,247 +0,0 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright 2009 Google Inc. All rights reserved. */
/** \file
* \ingroup imbdds
* This file comes from the chromium project, adapted to Blender to add DDS
* flipping to OpenGL convention for Blender.
*/
#include "IMB_imbuf_types.h"
#include <cstring>
#include <BlockDXT.h>
#include <ColorBlock.h>
#include <Common.h>
#include <FlipDXT.h>
#include <Stream.h>
/* A function that flips a DXTC block. */
using FlipBlockFunction = void (*)(uint8_t *block);
/* Flips a full DXT1 block in the y direction. */
static void FlipDXT1BlockFull(uint8_t *block)
{
/* A DXT1 block layout is:
* [0-1] color0.
* [2-3] color1.
* [4-7] color bitmap, 2 bits per pixel.
* So each of the 4-7 bytes represents one line, flipping a block is just
* flipping those bytes. */
uint8_t tmp = block[4];
block[4] = block[7];
block[7] = tmp;
tmp = block[5];
block[5] = block[6];
block[6] = tmp;
}
/* Flips the first 2 lines of a DXT1 block in the y direction. */
static void FlipDXT1BlockHalf(uint8_t *block)
{
/* See layout above. */
uint8_t tmp = block[4];
block[4] = block[5];
block[5] = tmp;
}
/* Flips a full DXT3 block in the y direction. */
static void FlipDXT3BlockFull(uint8_t *block)
{
/* A DXT3 block layout is:
* [0-7] alpha bitmap, 4 bits per pixel.
* [8-15] a DXT1 block. */
/* We can flip the alpha bits at the byte level (2 bytes per line). */
uint8_t tmp = block[0];
block[0] = block[6];
block[6] = tmp;
tmp = block[1];
block[1] = block[7];
block[7] = tmp;
tmp = block[2];
block[2] = block[4];
block[4] = tmp;
tmp = block[3];
block[3] = block[5];
block[5] = tmp;
/* And flip the DXT1 block using the above function. */
FlipDXT1BlockFull(block + 8);
}
/* Flips the first 2 lines of a DXT3 block in the y direction. */
static void FlipDXT3BlockHalf(uint8_t *block)
{
/* See layout above. */
uint8_t tmp = block[0];
block[0] = block[2];
block[2] = tmp;
tmp = block[1];
block[1] = block[3];
block[3] = tmp;
FlipDXT1BlockHalf(block + 8);
}
/* Flips a full DXT5 block in the y direction. */
static void FlipDXT5BlockFull(uint8_t *block)
{
/* A DXT5 block layout is:
* [0] alpha0.
* [1] alpha1.
* [2-7] alpha bitmap, 3 bits per pixel.
* [8-15] a DXT1 block. */
/* The alpha bitmap doesn't easily map lines to bytes, so we have to
* interpret it correctly. Extracted from
* http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
*
* The 6 "bits" bytes of the block are decoded into one 48-bit integer:
*
* bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
* 256 * (bits_4 + 256 * bits_5))))
*
* bits is a 48-bit unsigned-integer, from which a three-bit control code
* is extracted for a texel at location (x,y) in the block using:
*
* code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
*
* where bit 47 is the most significant and bit 0 is the least
* significant bit. */
uint line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
uint line_2_3 = block[5] + 256 * (block[6] + 256 * block[7]);
/* swap lines 0 and 1 in line_0_1. */
uint line_1_0 = ((line_0_1 & 0x000fff) << 12) | ((line_0_1 & 0xfff000) >> 12);
/* swap lines 2 and 3 in line_2_3. */
uint line_3_2 = ((line_2_3 & 0x000fff) << 12) | ((line_2_3 & 0xfff000) >> 12);
block[2] = line_3_2 & 0xff;
block[3] = (line_3_2 & 0xff00) >> 8;
block[4] = (line_3_2 & 0xff0000) >> 16;
block[5] = line_1_0 & 0xff;
block[6] = (line_1_0 & 0xff00) >> 8;
block[7] = (line_1_0 & 0xff0000) >> 16;
/* And flip the DXT1 block using the above function. */
FlipDXT1BlockFull(block + 8);
}
/* Flips the first 2 lines of a DXT5 block in the y direction. */
static void FlipDXT5BlockHalf(uint8_t *block)
{
/* See layout above. */
uint line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
uint line_1_0 = ((line_0_1 & 0x000fff) << 12) | ((line_0_1 & 0xfff000) >> 12);
block[2] = line_1_0 & 0xff;
block[3] = (line_1_0 & 0xff00) >> 8;
block[4] = (line_1_0 & 0xff0000) >> 16;
FlipDXT1BlockHalf(block + 8);
}
int FlipDXTCImage(uint width,
uint height,
uint levels,
int fourcc,
uint8_t *data,
int data_size,
uint *r_num_valid_levels)
{
*r_num_valid_levels = 0;
/* Must have valid dimensions. */
if (width == 0 || height == 0) {
return 0;
}
/* Height must be a power-of-two. */
if ((height & (height - 1)) != 0) {
return 0;
}
FlipBlockFunction full_block_function;
FlipBlockFunction half_block_function;
uint block_bytes = 0;
switch (fourcc) {
case FOURCC_DXT1:
full_block_function = FlipDXT1BlockFull;
half_block_function = FlipDXT1BlockHalf;
block_bytes = 8;
break;
case FOURCC_DXT3:
full_block_function = FlipDXT3BlockFull;
half_block_function = FlipDXT3BlockHalf;
block_bytes = 16;
break;
case FOURCC_DXT5:
full_block_function = FlipDXT5BlockFull;
half_block_function = FlipDXT5BlockHalf;
block_bytes = 16;
break;
default:
return 0;
}
*r_num_valid_levels = levels;
uint mip_width = width;
uint mip_height = height;
const uint8_t *data_end = data + data_size;
for (uint i = 0; i < levels; i++) {
uint blocks_per_row = (mip_width + 3) / 4;
uint blocks_per_col = (mip_height + 3) / 4;
uint blocks = blocks_per_row * blocks_per_col;
if (data + block_bytes * blocks > data_end) {
/* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
* on a malformed files. */
*r_num_valid_levels = i;
break;
}
if (mip_height == 1) {
/* no flip to do, and we're done. */
break;
}
if (mip_height == 2) {
/* flip the first 2 lines in each block. */
for (uint i = 0; i < blocks_per_row; i++) {
half_block_function(data + i * block_bytes);
}
}
else {
/* flip each block. */
for (uint i = 0; i < blocks; i++) {
full_block_function(data + i * block_bytes);
}
/* Swap each block line in the first half of the image with the
* corresponding one in the second half.
* note that this is a no-op if mip_height is 4. */
uint row_bytes = block_bytes * blocks_per_row;
uint8_t *temp_line = new uint8_t[row_bytes];
for (uint y = 0; y < blocks_per_col / 2; y++) {
uint8_t *line1 = data + y * row_bytes;
uint8_t *line2 = data + (blocks_per_col - y - 1) * row_bytes;
memcpy(temp_line, line1, row_bytes);
memcpy(line1, line2, row_bytes);
memcpy(line2, temp_line, row_bytes);
}
delete[] temp_line;
}
/* mip levels are contiguous. */
data += block_bytes * blocks;
mip_width = MAX(1U, mip_width >> 1);
mip_height = MAX(1U, mip_height >> 1);
}
return 1;
}

View File

@ -1,18 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BLI_sys_types.h"
/**
* Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate.
*
* Use to flip vertically to fit OpenGL convention.
*/
int FlipDXTCImage(unsigned int width,
unsigned int height,
unsigned int levels,
int fourcc,
uint8_t *data,
int data_size,
unsigned int *r_num_valid_levels);

View File

@ -1,106 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain -- <castanyo@yahoo.es>. */
#include <Color.h>
#include <Image.h>
#include <cstdio> /* printf */
Image::Image() : m_width(0), m_height(0), m_format(Format_RGB), m_data(nullptr) {}
Image::~Image()
{
free();
}
void Image::allocate(uint w, uint h)
{
free();
m_width = w;
m_height = h;
m_data = new Color32[w * h];
}
void Image::free()
{
delete[] m_data;
m_data = nullptr;
}
uint Image::width() const
{
return m_width;
}
uint Image::height() const
{
return m_height;
}
const Color32 *Image::scanline(uint h) const
{
if (h >= m_height) {
printf("DDS: scanline beyond dimensions of image\n");
return m_data;
}
return m_data + h * m_width;
}
Color32 *Image::scanline(uint h)
{
if (h >= m_height) {
printf("DDS: scanline beyond dimensions of image\n");
return m_data;
}
return m_data + h * m_width;
}
const Color32 *Image::pixels() const
{
return m_data;
}
Color32 *Image::pixels()
{
return m_data;
}
const Color32 &Image::pixel(uint idx) const
{
if (idx >= m_width * m_height) {
printf("DDS: pixel beyond dimensions of image\n");
return m_data[0];
}
return m_data[idx];
}
Color32 &Image::pixel(uint idx)
{
if (idx >= m_width * m_height) {
printf("DDS: pixel beyond dimensions of image\n");
return m_data[0];
}
return m_data[idx];
}
Image::Format Image::format() const
{
return m_format;
}
void Image::setFormat(Image::Format f)
{
m_format = f;
}

View File

@ -1,76 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* This code is in the public domain -- <castanyo@yahoo.es> */
#pragma once
#include "Color.h"
#include "Common.h"
/** 32 bit RGBA image. */
class Image {
public:
enum Format {
Format_RGB,
Format_ARGB,
};
Image();
~Image();
void allocate(uint w, uint h);
#if 0
bool load(const char *name);
void wrap(void *data, uint w, uint h);
void unwrap();
#endif
uint width() const;
uint height() const;
const Color32 *scanline(uint h) const;
Color32 *scanline(uint h);
const Color32 *pixels() const;
Color32 *pixels();
const Color32 &pixel(uint idx) const;
Color32 &pixel(uint idx);
const Color32 &pixel(uint x, uint y) const;
Color32 &pixel(uint x, uint y);
Format format() const;
void setFormat(Format f);
private:
void free();
private:
uint m_width;
uint m_height;
Format m_format;
Color32 *m_data;
};
inline const Color32 &Image::pixel(uint x, uint y) const
{
return pixel(y * width() + x);
}
inline Color32 &Image::pixel(uint x, uint y)
{
return pixel(y * width() + x);
}

View File

@ -1,117 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/*
* This file is based on a similar file from the NVIDIA texture tools
* (http://nvidia-texture-tools.googlecode.com/)
*
* Original license from NVIDIA follows.
*/
/* Copyright NVIDIA Corporation 2007 -- Ignacio Castano <icastano@nvidia.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "Common.h"
namespace PixelFormat {
/** Convert component \a c having \a inbits to the returned value having \a outbits. */
inline uint convert(uint c, uint inbits, uint outbits)
{
if (inbits == 0) {
return 0;
}
else if (inbits >= outbits) {
/* truncate */
return c >> (inbits - outbits);
}
else {
/* bitexpand */
return (c << (outbits - inbits)) | convert(c, inbits, outbits - inbits);
}
}
/* Get pixel component shift and size given its mask. */
inline void maskShiftAndSize(uint mask, uint *shift, uint *size)
{
if (!mask) {
*shift = 0;
*size = 0;
return;
}
*shift = 0;
while ((mask & 1) == 0) {
++(*shift);
mask >>= 1;
}
*size = 0;
while ((mask & 1) == 1) {
++(*size);
mask >>= 1;
}
}
inline float quantizeCeil(float f, int inbits, int outbits)
{
#if 0
uint i = f * (float(1 << inbits) - 1);
i = convert(i, inbits, outbits);
float result = float(i) / (float(1 << outbits) - 1);
nvCheck(result >= f);
#endif
float result;
int offset = 0;
do {
uint i = offset + uint(f * (float(1 << inbits) - 1));
i = convert(i, inbits, outbits);
result = float(i) / (float(1 << outbits) - 1);
offset++;
} while (result < f);
return result;
}
#if 0
inline float quantizeRound(float f, int bits)
{
float scale = float(1 << bits);
return fround(f * scale) / scale;
}
inline float quantizeFloor(float f, int bits)
{
float scale = float(1 << bits);
return floor(f * scale) / scale;
}
#endif
} /* namespace PixelFormat */

View File

@ -1,105 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
#include "BLI_sys_types.h" /* For `uint`. */
#include <Stream.h>
#include <cstdio> /* printf */
#include <cstring> /* memcpy */
static const char *msg_error_seek = "DDS: trying to seek beyond end of stream (corrupt file?)";
static const char *msg_error_read = "DDS: trying to read beyond end of stream (corrupt file?)";
inline bool is_read_within_bounds(const Stream &mem, uint count)
{
if (mem.pos >= mem.size) {
/* No more data remained in the memory buffer. */
return false;
}
if (count > mem.size - mem.pos) {
/* Reading past the memory bounds. */
return false;
}
return true;
}
uint Stream::seek(uint p)
{
if (p > size) {
set_failed(msg_error_seek);
}
else {
pos = p;
}
return pos;
}
uint mem_read(Stream &mem, unsigned long long &i)
{
if (!is_read_within_bounds(mem, 8)) {
mem.set_failed(msg_error_seek);
return 0;
}
memcpy(&i, mem.mem + mem.pos, 8); /* TODO: make sure little endian. */
mem.pos += 8;
return 8;
}
uint mem_read(Stream &mem, uint &i)
{
if (!is_read_within_bounds(mem, 4)) {
mem.set_failed(msg_error_read);
return 0;
}
memcpy(&i, mem.mem + mem.pos, 4); /* TODO: make sure little endian. */
mem.pos += 4;
return 4;
}
uint mem_read(Stream &mem, ushort &i)
{
if (!is_read_within_bounds(mem, 2)) {
mem.set_failed(msg_error_read);
return 0;
}
memcpy(&i, mem.mem + mem.pos, 2); /* TODO: make sure little endian. */
mem.pos += 2;
return 2;
}
uint mem_read(Stream &mem, uchar &i)
{
if (!is_read_within_bounds(mem, 1)) {
mem.set_failed(msg_error_read);
return 0;
}
i = (mem.mem + mem.pos)[0];
mem.pos += 1;
return 1;
}
uint mem_read(Stream &mem, uchar *i, uint count)
{
if (!is_read_within_bounds(mem, count)) {
mem.set_failed(msg_error_read);
return 0;
}
memcpy(i, mem.mem + mem.pos, count);
mem.pos += count;
return count;
}
void Stream::set_failed(const char *msg)
{
if (!failed) {
puts(msg);
failed = true;
}
}

View File

@ -1,25 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
/* simple memory stream functions with buffer overflow check */
#pragma once
struct Stream {
unsigned char *mem; /* location in memory */
unsigned int size; /* size */
unsigned int pos; /* current position */
bool failed; /* error occurred when seeking */
Stream(unsigned char *m, unsigned int s) : mem(m), size(s), pos(0), failed(false) {}
unsigned int seek(unsigned int p);
void set_failed(const char *msg);
};
unsigned int mem_read(Stream &mem, unsigned long long &i);
unsigned int mem_read(Stream &mem, unsigned int &i);
unsigned int mem_read(Stream &mem, unsigned short &i);
unsigned int mem_read(Stream &mem, unsigned char &i);
unsigned int mem_read(Stream &mem, unsigned char *i, unsigned int count);

View File

@ -1,193 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
#include "BLI_utildefines.h"
#include <DirectDrawSurface.h>
#include <FlipDXT.h>
#include <Stream.h>
#include <cstddef>
#include <cstdio> /* printf */
#include <dds_api.h>
#include <fstream>
#if defined(WIN32)
# include "utfconv.h"
#endif
#include "IMB_allocimbuf.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "imbuf.h"
#include "IMB_colormanagement.h"
#include "IMB_colormanagement_intern.h"
extern "C" {
bool imb_save_dds(struct ImBuf *ibuf, const char *filepath, int /*flags*/)
{
return false; /* TODO: finish this function. */
/* check image buffer */
if (ibuf == nullptr) {
return false;
}
if (ibuf->rect == nullptr) {
return false;
}
/* open file for writing */
std::ofstream fildes;
#if defined(WIN32)
wchar_t *wname = alloc_utf16_from_8(filepath, 0);
fildes.open(wname);
free(wname);
#else
fildes.open(filepath);
#endif
/* write header */
fildes << "DDS ";
fildes.close();
return true;
}
bool imb_is_a_dds(const uchar *mem, const size_t size)
{
if (size < 8) {
return false;
}
/* heuristic check to see if mem contains a DDS file */
/* header.fourcc == FOURCC_DDS */
if ((mem[0] != 'D') || (mem[1] != 'D') || (mem[2] != 'S') || (mem[3] != ' ')) {
return false;
}
/* header.size == 124 */
if ((mem[4] != 124) || mem[5] || mem[6] || mem[7]) {
return false;
}
return true;
}
struct ImBuf *imb_load_dds(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
struct ImBuf *ibuf = nullptr;
DirectDrawSurface dds((uchar *)mem, size); /* reads header */
uchar bits_per_pixel;
uint *rect;
Image img;
uint numpixels = 0;
int col;
uchar *cp = (uchar *)&col;
Color32 pixel;
Color32 *pixels = nullptr;
/* OCIO_TODO: never was able to save DDS, so can't test loading
* but profile used to be set to sRGB and can't see rect_float here, so
* default byte space should work fine
*/
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
if (!imb_is_a_dds(mem, size)) {
return nullptr;
}
/* check if DDS is valid and supported */
if (!dds.isValid()) {
/* no need to print error here, just testing if it is a DDS */
if (flags & IB_test) {
return nullptr;
}
printf("DDS: not valid; header follows\n");
dds.printInfo();
return nullptr;
}
if (!dds.isSupported()) {
printf("DDS: format not supported\n");
return nullptr;
}
if ((dds.width() > 65535) || (dds.height() > 65535)) {
printf("DDS: dimensions too large\n");
return nullptr;
}
/* convert DDS into ImBuf */
dds.mipmap(&img, 0, 0); /* load first face, first mipmap */
pixels = img.pixels();
numpixels = dds.width() * dds.height();
bits_per_pixel = 24;
if (img.format() == Image::Format_ARGB) {
/* check that there is effectively an alpha channel */
for (uint i = 0; i < numpixels; i++) {
pixel = pixels[i];
if (pixel.a != 255) {
bits_per_pixel = 32;
break;
}
}
}
ibuf = IMB_allocImBuf(dds.width(), dds.height(), bits_per_pixel, 0);
if (ibuf == nullptr) {
return nullptr; /* memory allocation failed */
}
ibuf->ftype = IMB_FTYPE_DDS;
ibuf->dds_data.fourcc = dds.fourCC();
ibuf->dds_data.nummipmaps = dds.mipmapCount();
if ((flags & IB_test) == 0) {
if (!imb_addrectImBuf(ibuf)) {
return ibuf;
}
if (ibuf->rect == nullptr) {
return ibuf;
}
rect = ibuf->rect;
cp[3] = 0xff; /* default alpha if alpha channel is not present */
for (uint i = 0; i < numpixels; i++) {
pixel = pixels[i];
cp[0] = pixel.r; /* set R component of col */
cp[1] = pixel.g; /* set G component of col */
cp[2] = pixel.b; /* set B component of col */
if (dds.hasAlpha()) {
cp[3] = pixel.a; /* set A component of col */
}
rect[i] = col;
}
if (ibuf->dds_data.fourcc != FOURCC_DDS) {
ibuf->dds_data.data = (uchar *)dds.readData(ibuf->dds_data.size);
/* flip compressed texture */
if (ibuf->dds_data.data) {
FlipDXTCImage(dds.width(),
dds.height(),
ibuf->dds_data.nummipmaps,
dds.fourCC(),
ibuf->dds_data.data,
ibuf->dds_data.size,
&ibuf->dds_data.nummipmaps);
}
}
else {
ibuf->dds_data.data = nullptr;
ibuf->dds_data.size = 0;
}
/* flip uncompressed texture */
IMB_flipy(ibuf);
}
return ibuf;
}
} /* extern "C" */

View File

@ -1,24 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbdds
*/
#pragma once
#include "../../IMB_imbuf.h"
#ifdef __cplusplus
extern "C" {
#endif
bool imb_is_a_dds(const unsigned char *mem, size_t size);
bool imb_save_dds(struct ImBuf *ibuf, const char *filepath, int flags);
struct ImBuf *imb_load_dds(const unsigned char *mem,
size_t size,
int flags,
char colorspace[IM_MAX_SPACE]);
#ifdef __cplusplus
}
#endif

View File

@ -2143,11 +2143,12 @@ typedef enum CMPNodeStabilizeInverse {
CMP_NODE_STABILIZE_FLAG_INVERSE = 1,
} CMPNodeStabilizeInverse;
/* Plane track deform node. */
#define CMP_NODE_PLANE_TRACK_DEFORM_MOTION_BLUR_SAMPLES_MAX 64
enum {
CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR = 1,
};
/* Plane track deform node. */
typedef enum CMPNodePlaneTrackDeformFlags {
CMP_NODE_PLANE_TRACK_DEFORM_FLAG_MOTION_BLUR = 1,
} CMPNodePlaneTrackDeformFlags;
/* Set Alpha Node. */
@ -2176,8 +2177,6 @@ typedef enum CMPNodeCombSepColorMode {
CMP_NODE_COMBSEP_COLOR_YUV = 4,
} CMPNodeCombSepColorMode;
#define CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX 64
/* Point Density shader node */
enum {

View File

@ -345,7 +345,7 @@ typedef struct ThemeSpace {
unsigned char nodeclass_geometry[4], nodeclass_attribute[4];
unsigned char node_zone_simulation[4];
char _pad8[4];
unsigned char simulated_frames[4];
/** For sequence editor. */
unsigned char movie[4], movieclip[4], mask[4], image[4], scene[4], audio[4];

View File

@ -9213,12 +9213,12 @@ static void def_cmp_planetrackdeform(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CMP_NODE_PLANE_TRACK_DEFORM_FLAG_MOTION_BLUR);
RNA_def_property_ui_text(prop, "Motion Blur", "Use multi-sampled motion blur of the mask");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 1, CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX);
RNA_def_property_range(prop, 1, CMP_NODE_PLANE_TRACK_DEFORM_MOTION_BLUR_SAMPLES_MAX);
RNA_def_property_ui_text(prop, "Samples", "Number of motion blur samples");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");

View File

@ -3563,6 +3563,12 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "Interpolation Line", "Color of lines showing non-bezier interpolation modes");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
prop = RNA_def_property(srna, "simulated_frames", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "simulated_frames");
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Simulated Frames", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
}
static void rna_def_userdef_theme_space_nla(BlenderRNA *brna)

View File

@ -102,7 +102,7 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
}
uiItemR(layout, ptr, "use_motion_blur", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
if (data->flag & CMP_NODE_PLANE_TRACK_DEFORM_FLAG_MOTION_BLUR) {
uiItemR(layout, ptr, "motion_blur_samples", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
uiItemR(layout, ptr, "motion_blur_shutter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}

View File

@ -75,6 +75,18 @@ if(WITH_TBB)
endif()
endif()
if(WITH_USD)
# USD links libMaterialX, when using pre-compiled libraries
# ensures `usd_ms` can find `MaterialXRender` and friends.
#
# NOTE: This is _only_ needed when linking blender before the install target runs.
# Once MATERIALX libraries have been copied into `TARGETDIR_LIB` then Blender will link.
# Don't rely on this though as failing on a fresh build is no good and the library
# files could get outdated too.
if(DEFINED LIBDIR)
link_directories(${LIBDIR}/materialx/lib)
endif()
endif()
if(WITH_PYTHON)
list(APPEND INC ../blender/python)