or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

extensions.mdindex.mdmath-functions.mdmatrices.mdquaternions.mdrandom-noise.mdtransformations.mdutilities.mdvectors.md

utilities.mddocs/

0

# Utility and Conversion Functions

1

2

Utility functions for type conversion, memory access, testing, packing/unpacking, and interfacing with external libraries. These functions provide essential tools for working with graphics APIs, file formats, and performance-critical applications.

3

4

## Capabilities

5

6

### Memory Access and Pointers

7

8

Functions for accessing the underlying memory of PyGLM types for interfacing with C libraries and graphics APIs.

9

10

```python { .api }

11

def value_ptr(x):

12

"""

13

Get a ctypes pointer to the underlying data of a PyGLM object.

14

15

Args:

16

x: Any PyGLM vector, matrix, or quaternion

17

18

Returns:

19

ctypes pointer to the data (c_float, c_double, c_int, etc.)

20

21

Example:

22

vec = glm.vec3(1, 2, 3)

23

ptr = glm.value_ptr(vec) # c_float pointer

24

# Pass ptr to OpenGL functions like glUniform3fv()

25

"""

26

27

def sizeof(glm_type):

28

"""

29

Get the size in bytes of a PyGLM type.

30

31

Args:

32

glm_type: PyGLM type (vec3, mat4, quat, etc.)

33

34

Returns:

35

Size in bytes

36

37

Example:

38

size = glm.sizeof(glm.vec3) # 12 bytes (3 * 4-byte floats)

39

size = glm.sizeof(glm.mat4) # 64 bytes (16 * 4-byte floats)

40

size = glm.sizeof(glm.dvec3) # 24 bytes (3 * 8-byte doubles)

41

"""

42

```

43

44

### Type Construction from Pointers

45

46

Functions for creating PyGLM objects from memory pointers, useful when interfacing with external libraries.

47

48

```python { .api }

49

def make_vec2(ptr):

50

"""

51

Create a vec2 from a ctypes pointer.

52

53

Args:

54

ptr: ctypes pointer to float data

55

56

Returns:

57

vec2 constructed from the pointer data

58

59

Example:

60

# Create vec2 from existing float array

61

import ctypes

62

data = (ctypes.c_float * 2)(1.0, 2.0)

63

vec = glm.make_vec2(data)

64

"""

65

66

def make_vec3(ptr):

67

"""

68

Create a vec3 from a ctypes pointer.

69

70

Args:

71

ptr: ctypes pointer to float data

72

73

Returns:

74

vec3 constructed from the pointer data

75

"""

76

77

def make_vec4(ptr):

78

"""

79

Create a vec4 from a ctypes pointer.

80

81

Args:

82

ptr: ctypes pointer to float data

83

84

Returns:

85

vec4 constructed from the pointer data

86

"""

87

88

def make_mat2(ptr):

89

"""

90

Create a mat2 from a ctypes pointer.

91

92

Args:

93

ptr: ctypes pointer to float data (4 elements)

94

95

Returns:

96

mat2x2 constructed from the pointer data

97

"""

98

99

def make_mat3(ptr):

100

"""

101

Create a mat3 from a ctypes pointer.

102

103

Args:

104

ptr: ctypes pointer to float data (9 elements)

105

106

Returns:

107

mat3x3 constructed from the pointer data

108

"""

109

110

def make_mat4(ptr):

111

"""

112

Create a mat4 from a ctypes pointer.

113

114

Args:

115

ptr: ctypes pointer to float data (16 elements)

116

117

Returns:

118

mat4x4 constructed from the pointer data

119

"""

120

121

def make_quat(ptr):

122

"""

123

Create a quat from a ctypes pointer.

124

125

Args:

126

ptr: ctypes pointer to float data (4 elements: w, x, y, z)

127

128

Returns:

129

quat constructed from the pointer data

130

"""

131

```

132

133

### Numerical Testing Functions

134

135

Functions for testing special floating-point values and performing epsilon-based comparisons.

136

137

```python { .api }

138

def isinf(x):

139

"""

140

Test if value(s) are infinite.

141

142

Args:

143

x: Scalar or vector input

144

145

Returns:

146

Boolean or boolean vector indicating infinity

147

148

Example:

149

isinf(float('inf')) # True

150

isinf(glm.vec3(1, float('inf'), 3)) # bvec3(False, True, False)

151

"""

152

153

def isnan(x):

154

"""

155

Test if value(s) are NaN (Not a Number).

156

157

Args:

158

x: Scalar or vector input

159

160

Returns:

161

Boolean or boolean vector indicating NaN

162

163

Example:

164

isnan(float('nan')) # True

165

isnan(glm.vec2(1.0, float('nan'))) # bvec2(False, True)

166

"""

167

168

def epsilonEqual(x, y, epsilon):

169

"""

170

Compare values using epsilon tolerance.

171

172

Args:

173

x: First value (scalar or vector)

174

y: Second value (same type as x)

175

epsilon: Tolerance value (scalar or vector)

176

177

Returns:

178

Boolean or boolean vector indicating equality within epsilon

179

180

Example:

181

epsilonEqual(1.0001, 1.0002, 0.001) # True

182

epsilonEqual(glm.vec3(1, 2, 3), glm.vec3(1.01, 2.01, 3.01), 0.02) # bvec3(True, True, True)

183

"""

184

185

def epsilonNotEqual(x, y, epsilon):

186

"""

187

Compare values for inequality using epsilon tolerance.

188

189

Args:

190

x: First value (scalar or vector)

191

y: Second value (same type as x)

192

epsilon: Tolerance value (scalar or vector)

193

194

Returns:

195

Boolean or boolean vector indicating inequality beyond epsilon

196

197

Example:

198

epsilonNotEqual(1.0, 1.1, 0.05) # True (difference > epsilon)

199

"""

200

```

201

202

### Bit Manipulation and Packing

203

204

Functions for packing and unpacking floating-point values and performing bit-level operations.

205

206

```python { .api }

207

def floatBitsToInt(value):

208

"""

209

Reinterpret float bits as signed integer.

210

211

Args:

212

value: Float value (scalar or vector)

213

214

Returns:

215

Integer with same bit pattern as input float

216

217

Example:

218

int_bits = glm.floatBitsToInt(1.0)

219

# Useful for bit manipulation or hashing

220

"""

221

222

def intBitsToFloat(value):

223

"""

224

Reinterpret integer bits as float.

225

226

Args:

227

value: Integer value (scalar or vector)

228

229

Returns:

230

Float with same bit pattern as input integer

231

232

Example:

233

float_val = glm.intBitsToFloat(1065353216) # Should be 1.0

234

"""

235

236

def floatBitsToUint(value):

237

"""

238

Reinterpret float bits as unsigned integer.

239

240

Args:

241

value: Float value (scalar or vector)

242

243

Returns:

244

Unsigned integer with same bit pattern as input float

245

"""

246

247

def uintBitsToFloat(value):

248

"""

249

Reinterpret unsigned integer bits as float.

250

251

Args:

252

value: Unsigned integer value (scalar or vector)

253

254

Returns:

255

Float with same bit pattern as input unsigned integer

256

"""

257

```

258

259

### Half-Precision Packing

260

261

Functions for packing and unpacking 16-bit half-precision floating-point values.

262

263

```python { .api }

264

def packHalf2x16(v):

265

"""

266

Pack two 32-bit floats into a single 32-bit unsigned integer as half-precision values.

267

268

Args:

269

v: vec2 containing two float values

270

271

Returns:

272

32-bit unsigned integer containing packed half-precision values

273

274

Example:

275

packed = glm.packHalf2x16(glm.vec2(1.0, -2.5))

276

# Useful for reducing memory usage in shaders

277

"""

278

279

def unpackHalf2x16(p):

280

"""

281

Unpack 32-bit unsigned integer into two half-precision floats.

282

283

Args:

284

p: 32-bit unsigned integer containing packed half-precision values

285

286

Returns:

287

vec2 containing the unpacked float values

288

289

Example:

290

unpacked = glm.unpackHalf2x16(packed_value) # Returns vec2

291

"""

292

293

def packHalf4x16(v):

294

"""

295

Pack four 32-bit floats into two 32-bit unsigned integers as half-precision values.

296

297

Args:

298

v: vec4 containing four float values

299

300

Returns:

301

uvec2 containing packed half-precision values

302

303

Example:

304

packed = glm.packHalf4x16(glm.vec4(1, 2, 3, 4))

305

"""

306

307

def unpackHalf4x16(p):

308

"""

309

Unpack two 32-bit unsigned integers into four half-precision floats.

310

311

Args:

312

p: uvec2 containing packed half-precision values

313

314

Returns:

315

vec4 containing the unpacked float values

316

"""

317

```

318

319

### Normalized Value Packing

320

321

Functions for packing normalized floating-point values into integer formats.

322

323

```python { .api }

324

def packUnorm2x16(v):

325

"""

326

Pack two normalized floats [0,1] into 16-bit unsigned integers.

327

328

Args:

329

v: vec2 with values in range [0, 1]

330

331

Returns:

332

32-bit unsigned integer containing packed values

333

334

Example:

335

packed = glm.packUnorm2x16(glm.vec2(0.5, 1.0))

336

"""

337

338

def unpackUnorm2x16(p):

339

"""

340

Unpack 32-bit unsigned integer into two normalized floats.

341

342

Args:

343

p: 32-bit unsigned integer containing packed values

344

345

Returns:

346

vec2 with values in range [0, 1]

347

"""

348

349

def packSnorm2x16(v):

350

"""

351

Pack two signed normalized floats [-1,1] into 16-bit signed integers.

352

353

Args:

354

v: vec2 with values in range [-1, 1]

355

356

Returns:

357

32-bit unsigned integer containing packed values

358

359

Example:

360

packed = glm.packSnorm2x16(glm.vec2(-0.5, 1.0))

361

"""

362

363

def unpackSnorm2x16(p):

364

"""

365

Unpack 32-bit unsigned integer into two signed normalized floats.

366

367

Args:

368

p: 32-bit unsigned integer containing packed values

369

370

Returns:

371

vec2 with values in range [-1, 1]

372

"""

373

374

def packUnorm4x8(v):

375

"""

376

Pack four normalized floats [0,1] into 8-bit unsigned integers.

377

378

Args:

379

v: vec4 with values in range [0, 1]

380

381

Returns:

382

32-bit unsigned integer containing packed values

383

384

Example:

385

# Pack RGBA color

386

color = glm.vec4(1.0, 0.5, 0.25, 1.0) # Red, half green, quarter blue, full alpha

387

packed_color = glm.packUnorm4x8(color)

388

"""

389

390

def unpackUnorm4x8(p):

391

"""

392

Unpack 32-bit unsigned integer into four normalized floats.

393

394

Args:

395

p: 32-bit unsigned integer containing packed values

396

397

Returns:

398

vec4 with values in range [0, 1]

399

"""

400

401

def packSnorm4x8(v):

402

"""

403

Pack four signed normalized floats [-1,1] into 8-bit signed integers.

404

405

Args:

406

v: vec4 with values in range [-1, 1]

407

408

Returns:

409

32-bit unsigned integer containing packed values

410

"""

411

412

def unpackSnorm4x8(p):

413

"""

414

Unpack 32-bit unsigned integer into four signed normalized floats.

415

416

Args:

417

p: 32-bit unsigned integer containing packed values

418

419

Returns:

420

vec4 with values in range [-1, 1]

421

"""

422

```

423

424

### Double-Precision Packing

425

426

Functions for packing and unpacking double-precision floating-point values.

427

428

```python { .api }

429

def packDouble2x32(v):

430

"""

431

Pack a double-precision float into two 32-bit unsigned integers.

432

433

Args:

434

v: Double-precision float value

435

436

Returns:

437

uvec2 containing the packed double

438

439

Example:

440

packed_double = glm.packDouble2x32(3.141592653589793)

441

"""

442

443

def unpackDouble2x32(p):

444

"""

445

Unpack two 32-bit unsigned integers into a double-precision float.

446

447

Args:

448

p: uvec2 containing packed double-precision value

449

450

Returns:

451

Double-precision float value

452

"""

453

```

454

455

### Bit Manipulation Functions

456

457

Advanced bit manipulation functions for integer operations.

458

459

```python { .api }

460

def bitfieldExtract(value, offset, bits):

461

"""

462

Extract a range of bits from an integer.

463

464

Args:

465

value: Integer value (scalar or vector)

466

offset: Bit offset (least significant bit = 0)

467

bits: Number of bits to extract

468

469

Returns:

470

Extracted bits as integer

471

"""

472

473

def bitfieldInsert(base, insert, offset, bits):

474

"""

475

Insert bits into a range of an integer.

476

477

Args:

478

base: Base integer value

479

insert: Integer containing bits to insert

480

offset: Bit offset for insertion

481

bits: Number of bits to insert

482

483

Returns:

484

Integer with bits inserted

485

"""

486

487

def bitfieldReverse(value):

488

"""

489

Reverse the bits in an integer.

490

491

Args:

492

value: Integer value (scalar or vector)

493

494

Returns:

495

Integer with bits reversed

496

"""

497

498

def bitCount(value):

499

"""

500

Count the number of 1 bits in an integer.

501

502

Args:

503

value: Integer value (scalar or vector)

504

505

Returns:

506

Number of set bits

507

"""

508

509

def findLSB(value):

510

"""

511

Find the index of the least significant set bit.

512

513

Args:

514

value: Integer value (scalar or vector)

515

516

Returns:

517

Index of LSB, or -1 if no bits set

518

"""

519

520

def findMSB(value):

521

"""

522

Find the index of the most significant set bit.

523

524

Args:

525

value: Integer value (scalar or vector)

526

527

Returns:

528

Index of MSB, or -1 if no bits set

529

"""

530

```

531

532

### Extended Integer Functions

533

534

Functions for extended precision integer arithmetic.

535

536

```python { .api }

537

def uaddCarry(x, y, carry):

538

"""

539

Add two unsigned integers with carry detection.

540

541

Args:

542

x: First unsigned integer

543

y: Second unsigned integer

544

carry: Output parameter for carry bit

545

546

Returns:

547

Sum of x and y

548

"""

549

550

def usubBorrow(x, y, borrow):

551

"""

552

Subtract two unsigned integers with borrow detection.

553

554

Args:

555

x: First unsigned integer (minuend)

556

y: Second unsigned integer (subtrahend)

557

borrow: Output parameter for borrow bit

558

559

Returns:

560

Difference of x and y

561

"""

562

563

def umulExtended(x, y, msb, lsb):

564

"""

565

Multiply two unsigned integers producing extended precision result.

566

567

Args:

568

x: First unsigned integer

569

y: Second unsigned integer

570

msb: Output parameter for most significant bits

571

lsb: Output parameter for least significant bits

572

573

Returns:

574

Extended precision product

575

"""

576

577

def imulExtended(x, y, msb, lsb):

578

"""

579

Multiply two signed integers producing extended precision result.

580

581

Args:

582

x: First signed integer

583

y: Second signed integer

584

msb: Output parameter for most significant bits

585

lsb: Output parameter for least significant bits

586

587

Returns:

588

Extended precision product

589

"""

590

591

def iround(x):

592

"""

593

Round float to nearest integer (signed).

594

595

Args:

596

x: Float value (scalar or vector)

597

598

Returns:

599

Rounded integer value

600

"""

601

602

def uround(x):

603

"""

604

Round float to nearest unsigned integer.

605

606

Args:

607

x: Float value (scalar or vector)

608

609

Returns:

610

Rounded unsigned integer value

611

"""

612

```

613

614

### Control Functions

615

616

Functions for controlling PyGLM behavior and warnings.

617

618

```python { .api }

619

def silence(id):

620

"""

621

Silence specific PyGLM warnings.

622

623

Args:

624

id: Warning ID to silence (0 = silence all warnings)

625

626

Example:

627

glm.silence(1) # Silence warning ID 1

628

glm.silence(0) # Silence all warnings

629

"""

630

```

631

632

### Usage Examples

633

634

```python

635

from pyglm import glm

636

import ctypes

637

638

# === Memory Access for Graphics APIs ===

639

640

# Pass matrix to OpenGL uniform

641

model_matrix = glm.mat4()

642

model_matrix = glm.rotate(model_matrix, glm.radians(45), glm.vec3(0, 1, 0))

643

644

# Get pointer for OpenGL

645

matrix_ptr = glm.value_ptr(model_matrix)

646

# In OpenGL: glUniformMatrix4fv(location, 1, GL_FALSE, matrix_ptr)

647

648

# Get size information

649

matrix_size = glm.sizeof(glm.mat4) # 64 bytes

650

vector_size = glm.sizeof(glm.vec3) # 12 bytes

651

652

# === Creating Types from External Data ===

653

654

# Create PyGLM vector from C array

655

float_array = (ctypes.c_float * 3)(1.0, 2.0, 3.0)

656

vec3_from_array = glm.make_vec3(float_array)

657

658

# Create matrix from external data

659

matrix_data = (ctypes.c_float * 16)(*[1 if i == j else 0 for i in range(4) for j in range(4)])

660

identity_matrix = glm.make_mat4(matrix_data)

661

662

# === Numerical Testing ===

663

664

# Test for special values

665

values = glm.vec4(1.0, float('inf'), float('nan'), -5.0)

666

inf_test = glm.isinf(values) # bvec4(False, True, False, False)

667

nan_test = glm.isnan(values) # bvec4(False, False, True, False)

668

669

# Epsilon comparisons for floating-point equality

670

a = glm.vec3(1.0, 2.0, 3.0)

671

b = glm.vec3(1.0001, 1.9999, 3.0001)

672

epsilon = 0.001

673

674

equal_test = glm.epsilonEqual(a, b, epsilon) # bvec3(True, True, True)

675

not_equal_test = glm.epsilonNotEqual(a, b, epsilon) # bvec3(False, False, False)

676

677

# === Bit Manipulation ===

678

679

# Convert between float and integer bit representations

680

float_val = 1.0

681

int_bits = glm.floatBitsToInt(float_val) # 1065353216

682

back_to_float = glm.intBitsToFloat(int_bits) # 1.0

683

684

# Useful for bit manipulation or hashing

685

def simple_hash(vec):

686

# Convert vector components to integer bits for hashing

687

x_bits = glm.floatBitsToInt(vec.x)

688

y_bits = glm.floatBitsToInt(vec.y)

689

z_bits = glm.floatBitsToInt(vec.z)

690

return hash((x_bits, y_bits, z_bits))

691

692

position = glm.vec3(1.5, 2.7, 3.1)

693

position_hash = simple_hash(position)

694

695

# === Half-Precision Packing for Memory Efficiency ===

696

697

# Pack two floats into half-precision for storage

698

original_vec2 = glm.vec2(1.5, -2.25)

699

packed_half = glm.packHalf2x16(original_vec2) # Stores in 32 bits instead of 64

700

unpacked_vec2 = glm.unpackHalf2x16(packed_half) # Slight precision loss

701

702

# Pack four floats into half-precision

703

original_vec4 = glm.vec4(1.0, 2.0, 3.0, 4.0)

704

packed_half4 = glm.packHalf4x16(original_vec4) # Returns uvec2

705

unpacked_vec4 = glm.unpackHalf4x16(packed_half4)

706

707

# === Normalized Value Packing ===

708

709

# Pack RGBA color values efficiently

710

color = glm.vec4(1.0, 0.5, 0.25, 1.0) # Red, half green, quarter blue, full alpha

711

packed_color = glm.packUnorm4x8(color) # Pack into 32-bit integer

712

unpacked_color = glm.unpackUnorm4x8(packed_color) # Unpack back to vec4

713

714

# Pack normal vectors (commonly in range [-1, 1])

715

normal = glm.vec3(-0.5, 0.707, 0.5) # Normalized normal vector

716

# Extend to vec4 for packing

717

normal_vec4 = glm.vec4(normal.x, normal.y, normal.z, 0.0)

718

packed_normal = glm.packSnorm4x8(normal_vec4)

719

unpacked_normal = glm.unpackSnorm4x8(packed_normal)

720

721

# === Double-Precision Packing ===

722

723

# Pack double-precision value for storage or transmission

724

double_val = 3.141592653589793

725

packed_double = glm.packDouble2x32(double_val) # Returns uvec2

726

unpacked_double = glm.unpackDouble2x32(packed_double)

727

728

# === Practical Example: Vertex Data Compression ===

729

730

class CompressedVertex:

731

def __init__(self, position, normal, uv, color):

732

# Store position as-is (high precision needed)

733

self.position = position

734

735

# Pack normal into 32-bit integer (normals are in [-1,1] range)

736

normal_vec4 = glm.vec4(normal.x, normal.y, normal.z, 0.0)

737

self.packed_normal = glm.packSnorm4x8(normal_vec4)

738

739

# Pack UV coordinates into 32-bit integer (UVs are in [0,1] range)

740

uv_vec4 = glm.vec4(uv.x, uv.y, 0.0, 0.0) # Pad to vec4

741

self.packed_uv = glm.packUnorm4x8(uv_vec4)

742

743

# Pack color into 32-bit integer

744

self.packed_color = glm.packUnorm4x8(color)

745

746

def get_normal(self):

747

unpacked = glm.unpackSnorm4x8(self.packed_normal)

748

return glm.vec3(unpacked.x, unpacked.y, unpacked.z)

749

750

def get_uv(self):

751

unpacked = glm.unpackUnorm4x8(self.packed_uv)

752

return glm.vec2(unpacked.x, unpacked.y)

753

754

def get_color(self):

755

return glm.unpackUnorm4x8(self.packed_color)

756

757

# Create compressed vertex

758

original_position = glm.vec3(1.0, 2.0, 3.0)

759

original_normal = glm.vec3(0.0, 1.0, 0.0)

760

original_uv = glm.vec2(0.5, 0.75)

761

original_color = glm.vec4(1.0, 0.5, 0.25, 1.0)

762

763

compressed = CompressedVertex(original_position, original_normal, original_uv, original_color)

764

765

# Retrieve data (with some precision loss from compression)

766

retrieved_normal = compressed.get_normal()

767

retrieved_uv = compressed.get_uv()

768

retrieved_color = compressed.get_color()

769

770

# === OpenGL Integration Example ===

771

772

def upload_matrix_to_gpu(matrix, uniform_location):

773

"""Upload matrix to OpenGL uniform."""

774

# Get pointer to matrix data

775

matrix_ptr = glm.value_ptr(matrix)

776

matrix_size = glm.sizeof(type(matrix))

777

778

# Determine matrix dimensions and upload

779

if matrix_size == 64: # mat4

780

# glUniformMatrix4fv(uniform_location, 1, GL_FALSE, matrix_ptr)

781

pass

782

elif matrix_size == 36: # mat3

783

# glUniformMatrix3fv(uniform_location, 1, GL_FALSE, matrix_ptr)

784

pass

785

# etc.

786

787

# === Performance Monitoring ===

788

789

def compare_storage_sizes():

790

"""Compare storage sizes of different representations."""

791

792

# Original vec4

793

original = glm.vec4(1.0, 0.5, 0.25, 1.0)

794

original_size = glm.sizeof(glm.vec4) # 16 bytes

795

796

# Half-precision packed

797

packed_half = glm.packHalf4x16(original)

798

packed_half_size = glm.sizeof(glm.uvec2) # 8 bytes

799

800

# Normalized packed

801

packed_norm = glm.packUnorm4x8(original)

802

packed_norm_size = 4 # 4 bytes (single uint32)

803

804

print(f"Original: {original_size} bytes")

805

print(f"Half-precision: {packed_half_size} bytes ({packed_half_size/original_size:.1%} of original)")

806

print(f"Normalized: {packed_norm_size} bytes ({packed_norm_size/original_size:.1%} of original)")

807

808

compare_storage_sizes()

809

810

# === Error Handling and Warnings ===

811

812

# Silence specific warnings

813

glm.silence(1) # Silence warning with ID 1

814

815

# Silence all warnings

816

glm.silence(0)

817

818

# Example function that might generate warnings

819

def risky_operation():

820

# Some operation that might trigger frexp warning

821

result = glm.frexp(glm.vec3(1.5, 2.0, 3.0))

822

return result

823

824

# Call without warnings (if silenced)

825

result = risky_operation()

826

```

827

828

### Integration Best Practices

829

830

1. **Memory Management**: Always ensure that ctypes arrays remain in scope when using `make_*` functions

831

2. **Precision Trade-offs**: Understand precision loss when using packed formats - test with your specific data ranges

832

3. **Performance**: Use packed formats for large datasets (vertex buffers, texture data) but full precision for calculations

833

4. **Graphics API Integration**: Use `value_ptr()` to pass data directly to OpenGL, Vulkan, and other graphics APIs

834

5. **Error Handling**: Use numerical testing functions (`isinf`, `isnan`) when working with computed values

835

6. **Bit Manipulation**: Be careful with bit manipulation functions - they're primarily for specialized use cases