File: texture2d.cpp

package info (click to toggle)
embree 3.13.5%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 27,924 kB
  • sloc: cpp: 180,815; xml: 3,877; ansic: 2,957; python: 1,466; sh: 502; makefile: 229; csh: 42
file content (203 lines) | stat: -rw-r--r-- 6,456 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
// Copyright 2009-2021 Intel Corporation
// SPDX-License-Identifier: Apache-2.0

#include "texture2d.h"

namespace embree {


// Low-level texel accessors
//////////////////////////////////////////////////////////////////////////////

// TODO blocking

inline Vec4f getTexel_RGBA8(const Texture2D *self, const Vec2i i)
{
  assert(self);
  const uint32_t c = ((const uint32_t *)self->data)[i.y*self->size.x + i.x];
  const uint32_t r = c         & 0xff;
  const uint32_t g = (c >>  8) & 0xff;
  const uint32_t b = (c >> 16) & 0xff;
  const uint32_t a = c >> 24;
  return Vec4f((float)r, (float)g, (float)b, (float)a)*(1.f/255.f);
}

inline Vec4f getTexel_RGB8(const Texture2D *self, const Vec2i i)
{
  assert(self);
  const uint8_t *texel = (const uint8_t *)self->data;
  const uint32_t texelOfs = 3*(i.y*self->size.x + i.x);
  const uint32_t r = texel[texelOfs];
  const uint32_t g = texel[texelOfs+1];
  const uint32_t b = texel[texelOfs+2];
  return Vec4f(Vec3fa((float)r, (float)g, (float)b)*(1.f/255.f), 1.f);
}

inline Vec4f getTexel_R8(const Texture2D *self, const Vec2i i)
{
  assert(self);
  const uint8_t c = ((const uint8_t *)self->data)[i.y*self->size.x + i.x];
  return Vec4f(c*(1.f/255.f), 0.0f, 0.0f, 1.f);
}

inline Vec4f getTexel_SRGBA(const Texture2D *self, const Vec2i i)
{
  return srgba_to_linear(getTexel_RGBA8(self, i));
}

inline Vec4f getTexel_SRGB(const Texture2D *self, const Vec2i i)
{
  return srgba_to_linear(getTexel_RGB8(self, i));
}

inline Vec4f getTexel_RGBA32F(const Texture2D *self, const Vec2i i)
{
  assert(self);
  return ((const Vec4f *)self->data)[i.y*self->size.x + i.x];
}

inline Vec4f getTexel_RGB32F(const Texture2D *self, const Vec2i i)
{
  assert(self);
  Vec3fa v = ((const Vec3fa*)self->data)[i.y*self->size.x + i.x];
  return Vec4f(v, 1.f);
}

inline Vec4f getTexel_R32F(const Texture2D *self, const Vec2i i)
{
  assert(self);
  float v = ((const float*)self->data)[i.y*self->size.x + i.x];
  return Vec4f(v, 0.f, 0.f, 1.f);
}


// Texture coordinate utilities
//////////////////////////////////////////////////////////////////////////////

inline Vec2i nearest_coords(const Texture2D *self, const Vec2f p)
{
  // repeat: get remainder within [0..1] parameter space
  Vec2f tc = frac(p);
  tc = max(tc, Vec2f(0.0f)); // filter out inf/NaN

  // scale by texture size
  tc = tc * self->sizef;

  // nearest
  return Vec2i(tc);
}

struct BilinCoords {
  Vec2i st0;
  Vec2i st1;
  Vec2f frac;
};

inline BilinCoords bilinear_coords(const Texture2D *self, const Vec2f p)
{
  BilinCoords coords;

  // repeat: get remainder within [0..1] parameter space
  // lower sample shifted by half a texel
  Vec2f tc = frac(p - self->halfTexel);
  tc = max(tc, Vec2f(0.0f)); // filter out inf/NaN

  // scale by texture size
  tc = tc * self->sizef;
  coords.frac = frac(tc);

  coords.st0 = Vec2i(tc);
  coords.st1 = coords.st0 + 1;
  // handle border cases
  if (coords.st1.x >= self->size.x)
    coords.st1.x = 0;
  if (coords.st1.y >= self->size.y)
    coords.st1.y = 0;

  return coords;
}

inline Vec4f bilerp(const Vec2f frac, const Vec4f c00, const Vec4f c01, const Vec4f c10, const Vec4f c11)
{
  return lerpr(frac.y,
              lerpr(frac.x, c00, c01),
              lerpr(frac.x, c10, c11));
}


// Implementations of Texture2D_get for different formats and filter modi
//////////////////////////////////////////////////////////////////////////////

#define __define_tex_get(FMT)                                                \
                                                                             \
static Vec4f Texture2D_nearest_##FMT(const Texture2D *self,  \
    const Vec2f &p)                                                          \
{                                                                            \
  return getTexel_##FMT(self, nearest_coords(self, p));                      \
}                                                                            \
                                                                             \
static Vec4f Texture2D_bilinear_##FMT(const Texture2D *self, \
    const Vec2f &p)                                                          \
{                                                                            \
  BilinCoords cs = bilinear_coords(self, p);                                 \
                                                                             \
  const Vec4f c00 = getTexel_##FMT(self, Vec2i(cs.st0.x, cs.st0.y));    \
  const Vec4f c01 = getTexel_##FMT(self, Vec2i(cs.st1.x, cs.st0.y));    \
  const Vec4f c10 = getTexel_##FMT(self, Vec2i(cs.st0.x, cs.st1.y));    \
  const Vec4f c11 = getTexel_##FMT(self, Vec2i(cs.st1.x, cs.st1.y));    \
                                                                             \
  return bilerp(cs.frac, c00, c01, c10, c11);                                \
}

#define __define_tex_get_case(FMT) \
  case TEXTURE_##FMT: return filter_nearest ?  &Texture2D_nearest_##FMT : \
                                                   &Texture2D_bilinear_##FMT;

#define __foreach_fetcher(FCT) \
  FCT(RGBA8)                   \
  FCT(SRGBA)                   \
  FCT(RGBA32F)                 \
  FCT(RGB8)                    \
  FCT(SRGB)                    \
  FCT(RGB32F)                  \
  FCT(R8)                      \
  FCT(R32F)   

__foreach_fetcher(__define_tex_get)

static Texture2D_get Texture2D_get_addr(const uint32_t type,
    const bool filter_nearest)
{
  switch (type) {
    __foreach_fetcher(__define_tex_get_case)
  }
  return 0;
};

#undef __define_tex_get
#undef __define_tex_get_addr
#undef __foreach_fetcher


// Exports (called from C++)
//////////////////////////////////////////////////////////////////////////////

extern "C" void *Texture2D_create(Vec2i &size, void *data,
    uint32_t type, uint32_t flags)
{
  Texture2D *self = (Texture2D*) alignedMalloc(sizeof(Texture2D),16);
  self->size      = size;

  // Due to float rounding frac(x) can be exactly 1.0f (e.g. for very small
  // negative x), although it should be strictly smaller than 1.0f. We handle
  // this case by having sizef slightly smaller than size, such that
  // frac(x)*sizef is always < size.
  self->sizef = Vec2f(nextafter((float)size.x, -1.0f), nextafter((float)size.y, -1.0f));
  self->halfTexel = Vec2f(0.5f/size.x, 0.5f/size.y);
  self->data = data;
  self->get = Texture2D_get_addr(type, flags & TEXTURE_FILTER_NEAREST);

  return self;
}

} // namespace embree