or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

camera-system.mdcore-graphics.mdgui-framework.mdindex.mdmath-utilities.mdphysics-engines.mdsound-system.mdspecialized-features.mdsprite-system.mdtexture-management.mdwindow-management.md

texture-management.mddocs/

0

# Texture Management

1

2

Comprehensive texture loading, caching, atlas management, procedural texture generation, and sprite sheet handling for efficient graphics resource management and optimal rendering performance.

3

4

## Capabilities

5

6

### Core Texture Classes

7

8

Base texture classes for managing image data and rendering properties.

9

10

```python { .api }

11

class Texture:

12

"""

13

Main texture class for managing image data, rendering properties, and GPU resources.

14

Textures can be loaded from files, created programmatically, or extracted from sprite sheets.

15

"""

16

def __init__(self, image: PIL.Image.Image, name: str = None, hit_box_algorithm: str = "Simple",

17

hit_box_detail: float = 4.5, hit_box_points: list[tuple[float, float]] = None):

18

"""

19

Create a texture from a PIL Image.

20

21

Args:

22

image: PIL Image object containing texture data

23

name: Optional name for the texture (used for caching/debugging)

24

hit_box_algorithm: Algorithm for calculating hit box ("Simple", "Detailed", or "None")

25

hit_box_detail: Detail level for "Detailed" hit box algorithm

26

hit_box_points: Pre-calculated hit box points

27

"""

28

29

# Properties

30

name: str

31

width: int

32

height: int

33

image: PIL.Image.Image

34

hit_box_points: list[tuple[float, float]]

35

36

# Atlas properties

37

atlas: arcade.TextureAtlasBase

38

atlas_name: str

39

40

def create_empty(name: str, size: tuple[int, int], color: tuple[int, int, int, int] = (0, 0, 0, 0)) -> arcade.Texture:

41

"""

42

Create an empty texture with specified size and color.

43

44

Args:

45

name: Name for the texture

46

size: (width, height) in pixels

47

color: RGBA color tuple (0-255)

48

49

Returns:

50

New Texture instance

51

"""

52

53

def create_filled(name: str, size: tuple[int, int], color: tuple[int, int, int, int]) -> arcade.Texture:

54

"""

55

Create a texture filled with a solid color.

56

57

Args:

58

name: Name for the texture

59

size: (width, height) in pixels

60

color: RGBA color tuple (0-255)

61

62

Returns:

63

New Texture instance

64

"""

65

66

def flip_horizontally(self) -> arcade.Texture:

67

"""

68

Create a horizontally flipped version of this texture.

69

70

Returns:

71

New Texture instance with flipped image

72

"""

73

74

def flip_vertically(self) -> arcade.Texture:

75

"""

76

Create a vertically flipped version of this texture.

77

78

Returns:

79

New Texture instance with flipped image

80

"""

81

82

def flip_diagonally(self) -> arcade.Texture:

83

"""

84

Create a diagonally flipped version of this texture.

85

86

Returns:

87

New Texture instance with flipped image

88

"""

89

90

def rotate_90(self) -> arcade.Texture:

91

"""

92

Create a texture rotated 90 degrees clockwise.

93

94

Returns:

95

New Texture instance with rotated image

96

"""

97

98

def crop(self, x: int, y: int, width: int, height: int) -> arcade.Texture:

99

"""

100

Create a cropped version of this texture.

101

102

Args:

103

x: Left coordinate of crop area

104

y: Bottom coordinate of crop area

105

width: Width of crop area

106

height: Height of crop area

107

108

Returns:

109

New Texture instance with cropped image

110

"""

111

112

def resize(self, new_size: tuple[int, int], resample: int = PIL.Image.LANCZOS) -> arcade.Texture:

113

"""

114

Create a resized version of this texture.

115

116

Args:

117

new_size: (width, height) for resized texture

118

resample: PIL resampling algorithm

119

120

Returns:

121

New Texture instance with resized image

122

"""

123

124

class TextureCacheManager:

125

"""

126

Manages texture caching and memory usage to prevent duplicate texture loading

127

and optimize GPU memory usage.

128

"""

129

def __init__(self):

130

"""Create a texture cache manager."""

131

132

def get_texture_by_name(self, name: str) -> arcade.Texture:

133

"""

134

Get a cached texture by name.

135

136

Args:

137

name: Name of the texture to retrieve

138

139

Returns:

140

Cached Texture instance or None if not found

141

"""

142

143

def put_texture(self, name: str, texture: arcade.Texture) -> None:

144

"""

145

Store a texture in the cache.

146

147

Args:

148

name: Cache key for the texture

149

texture: Texture instance to cache

150

"""

151

152

def clear_cache(self) -> None:

153

"""Clear all cached textures from memory."""

154

155

def get_cache_size(self) -> int:

156

"""

157

Get the number of textures currently cached.

158

159

Returns:

160

Number of cached textures

161

"""

162

```

163

164

### Texture Loading Functions

165

166

Functions for loading textures from files and resources with various options and transformations.

167

168

```python { .api }

169

def load_texture(file_path: str, x: int = 0, y: int = 0, width: int = 0, height: int = 0,

170

flipped_horizontally: bool = False, flipped_vertically: bool = False,

171

flipped_diagonally: bool = False, can_cache: bool = True,

172

hit_box_algorithm: str = "Simple", hit_box_detail: float = 4.5) -> arcade.Texture:

173

"""

174

Load a texture from a file with optional transformations and cropping.

175

176

Args:

177

file_path: Path to image file or resource handle (e.g., ":resources:images/...")

178

x: X offset for cropping (pixels from left)

179

y: Y offset for cropping (pixels from bottom)

180

width: Width of crop area (0 = full width)

181

height: Height of crop area (0 = full height)

182

flipped_horizontally: Mirror texture horizontally

183

flipped_vertically: Mirror texture vertically

184

flipped_diagonally: Mirror texture diagonally

185

can_cache: Whether this texture can be cached

186

hit_box_algorithm: Hit box calculation method

187

hit_box_detail: Detail level for detailed hit boxes

188

189

Returns:

190

Loaded Texture instance

191

"""

192

193

def load_image(file_path: str) -> PIL.Image.Image:

194

"""

195

Load an image file as a PIL Image object.

196

197

Args:

198

file_path: Path to image file

199

200

Returns:

201

PIL Image object

202

"""

203

204

def load_spritesheet(file_path: str, sprite_width: int, sprite_height: int,

205

columns: int, count: int, margin: int = 0, spacing: int = 0) -> list[arcade.Texture]:

206

"""

207

Load a sprite sheet and return individual sprites as textures.

208

209

Args:

210

file_path: Path to sprite sheet image

211

sprite_width: Width of each sprite in pixels

212

sprite_height: Height of each sprite in pixels

213

columns: Number of columns in the sprite sheet

214

count: Total number of sprites to load

215

margin: Margin around the entire sprite sheet

216

spacing: Spacing between individual sprites

217

218

Returns:

219

List of Texture instances, one for each sprite

220

"""

221

222

def get_default_texture() -> arcade.Texture:

223

"""

224

Get the default fallback texture (used when texture loading fails).

225

226

Returns:

227

Default Texture instance (usually a colored square)

228

"""

229

230

def get_default_image() -> PIL.Image.Image:

231

"""

232

Get the default fallback image.

233

234

Returns:

235

Default PIL Image object

236

"""

237

```

238

239

### Procedural Texture Generation

240

241

Functions for creating textures programmatically with various shapes, patterns, and effects.

242

243

```python { .api }

244

def make_circle_texture(diameter: int, color: arcade.types.Color, name: str = "circle") -> arcade.Texture:

245

"""

246

Generate a circular texture with solid color.

247

248

Args:

249

diameter: Diameter of the circle in pixels

250

color: Circle color as RGB or RGBA tuple (0-255)

251

name: Name for the generated texture

252

253

Returns:

254

Generated Texture instance

255

"""

256

257

def make_soft_circle_texture(diameter: int, color: arcade.types.Color,

258

center_alpha: int = 255, outer_alpha: int = 0,

259

name: str = "soft_circle") -> arcade.Texture:

260

"""

261

Generate a circular texture with soft, gradient edges.

262

263

Args:

264

diameter: Diameter of the circle in pixels

265

color: Base color as RGB tuple (0-255)

266

center_alpha: Alpha value at circle center (0-255)

267

outer_alpha: Alpha value at circle edge (0-255)

268

name: Name for the generated texture

269

270

Returns:

271

Generated Texture instance with gradient alpha

272

"""

273

274

def make_soft_square_texture(size: int, color: arcade.types.Color,

275

center_alpha: int = 255, outer_alpha: int = 0,

276

name: str = "soft_square") -> arcade.Texture:

277

"""

278

Generate a square texture with soft, gradient edges.

279

280

Args:

281

size: Size of the square in pixels

282

color: Base color as RGB tuple (0-255)

283

center_alpha: Alpha value at square center (0-255)

284

outer_alpha: Alpha value at square edges (0-255)

285

name: Name for the generated texture

286

287

Returns:

288

Generated Texture instance with gradient alpha

289

"""

290

```

291

292

### Sprite Sheet Management

293

294

Classes and functions for working with sprite sheets and texture atlases.

295

296

```python { .api }

297

class SpriteSheet:

298

"""

299

Manages sprite sheets for extracting individual sprites and optimizing texture usage.

300

"""

301

def __init__(self, file_path: str, sprite_width: int, sprite_height: int,

302

columns: int = None, rows: int = None, margin: int = 0, spacing: int = 0):

303

"""

304

Create a sprite sheet manager.

305

306

Args:

307

file_path: Path to sprite sheet image file

308

sprite_width: Width of each individual sprite

309

sprite_height: Height of each individual sprite

310

columns: Number of columns (auto-calculated if None)

311

rows: Number of rows (auto-calculated if None)

312

margin: Margin around the entire sheet

313

spacing: Spacing between individual sprites

314

"""

315

316

# Properties

317

file_path: str

318

sprite_width: int

319

sprite_height: int

320

columns: int

321

rows: int

322

margin: int

323

spacing: int

324

325

def get_texture(self, column: int, row: int) -> arcade.Texture:

326

"""

327

Extract a single sprite texture from the sheet.

328

329

Args:

330

column: Column index (0-based)

331

row: Row index (0-based)

332

333

Returns:

334

Texture for the sprite at the specified position

335

"""

336

337

def get_textures(self, start_column: int = 0, start_row: int = 0,

338

end_column: int = None, end_row: int = None) -> list[arcade.Texture]:

339

"""

340

Extract multiple sprite textures from a range.

341

342

Args:

343

start_column: Starting column (inclusive)

344

start_row: Starting row (inclusive)

345

end_column: Ending column (inclusive, None = last column)

346

end_row: Ending row (inclusive, None = last row)

347

348

Returns:

349

List of Texture instances for the specified range

350

"""

351

352

def get_texture_list(self) -> list[arcade.Texture]:

353

"""

354

Get all sprites from the sheet as a list.

355

356

Returns:

357

List of all Texture instances in the sheet

358

"""

359

```

360

361

### Texture Atlas System

362

363

Advanced texture management for optimizing GPU memory and rendering performance.

364

365

```python { .api }

366

class DefaultTextureAtlas:

367

"""

368

Default texture atlas implementation for batching textures into a single GPU texture

369

to improve rendering performance and reduce GPU memory usage.

370

"""

371

def __init__(self, size: tuple[int, int] = (2048, 2048), auto_resize: bool = True,

372

ctx: arcade.ArcadeContext = None):

373

"""

374

Create a texture atlas.

375

376

Args:

377

size: (width, height) of the atlas texture in pixels

378

auto_resize: Whether to automatically resize when full

379

ctx: OpenGL context (uses current context if None)

380

"""

381

382

# Properties

383

size: tuple[int, int]

384

auto_resize: bool

385

ctx: arcade.ArcadeContext

386

387

def add(self, texture: arcade.Texture) -> bool:

388

"""

389

Add a texture to the atlas.

390

391

Args:

392

texture: Texture to add

393

394

Returns:

395

True if successfully added, False if atlas is full

396

"""

397

398

def remove(self, texture: arcade.Texture) -> bool:

399

"""

400

Remove a texture from the atlas.

401

402

Args:

403

texture: Texture to remove

404

405

Returns:

406

True if successfully removed, False if not found

407

"""

408

409

def clear(self) -> None:

410

"""Remove all textures from the atlas."""

411

412

def resize(self, new_size: tuple[int, int]) -> None:

413

"""

414

Resize the atlas texture.

415

416

Args:

417

new_size: New (width, height) for the atlas

418

"""

419

420

def get_texture_count(self) -> int:

421

"""

422

Get the number of textures currently in the atlas.

423

424

Returns:

425

Number of textures in the atlas

426

"""

427

428

def get_usage_percent(self) -> float:

429

"""

430

Get the percentage of atlas space currently used.

431

432

Returns:

433

Usage percentage (0.0 to 100.0)

434

"""

435

436

class TextureAtlasBase:

437

"""

438

Base class for texture atlas implementations.

439

"""

440

def __init__(self):

441

"""Create base texture atlas."""

442

443

def add(self, texture: arcade.Texture) -> bool:

444

"""Add a texture to the atlas."""

445

446

def remove(self, texture: arcade.Texture) -> bool:

447

"""Remove a texture from the atlas."""

448

449

def clear(self) -> None:

450

"""Clear all textures from the atlas."""

451

452

class AtlasRegion:

453

"""

454

Represents a region within a texture atlas containing a specific texture.

455

"""

456

def __init__(self, atlas: arcade.TextureAtlasBase, x: int, y: int, width: int, height: int):

457

"""

458

Create an atlas region.

459

460

Args:

461

atlas: The texture atlas containing this region

462

x: X coordinate within the atlas

463

y: Y coordinate within the atlas

464

width: Width of the region

465

height: Height of the region

466

"""

467

468

atlas: arcade.TextureAtlasBase

469

x: int

470

y: int

471

width: int

472

height: int

473

```

474

475

## Usage Examples

476

477

### Basic Texture Loading and Usage

478

479

```python

480

import arcade

481

482

class TextureExample(arcade.Window):

483

def __init__(self):

484

super().__init__(800, 600, "Texture Example")

485

486

self.texture_list = []

487

self.sprite_list = arcade.SpriteList()

488

489

def setup(self):

490

# Load individual textures

491

player_texture = arcade.load_texture(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png")

492

493

# Load with transformations

494

flipped_texture = arcade.load_texture(

495

":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png",

496

flipped_horizontally=True

497

)

498

499

# Load cropped portion

500

cropped_texture = arcade.load_texture(

501

":resources:images/tiles/grassMid.png",

502

x=0, y=0, width=32, height=32

503

)

504

505

# Create sprites using loaded textures

506

player = arcade.Sprite(texture=player_texture, scale=0.5)

507

player.center_x = 200

508

player.center_y = 300

509

self.sprite_list.append(player)

510

511

flipped_player = arcade.Sprite(texture=flipped_texture, scale=0.5)

512

flipped_player.center_x = 400

513

flipped_player.center_y = 300

514

self.sprite_list.append(flipped_player)

515

516

# Generate procedural textures

517

circle_texture = arcade.make_circle_texture(50, arcade.color.RED)

518

circle_sprite = arcade.Sprite(texture=circle_texture)

519

circle_sprite.center_x = 600

520

circle_sprite.center_y = 300

521

self.sprite_list.append(circle_sprite)

522

523

# Soft circle with gradient

524

soft_texture = arcade.make_soft_circle_texture(80, arcade.color.BLUE, 255, 50)

525

soft_sprite = arcade.Sprite(texture=soft_texture)

526

soft_sprite.center_x = 200

527

soft_sprite.center_y = 150

528

self.sprite_list.append(soft_sprite)

529

530

def on_draw(self):

531

self.clear()

532

self.sprite_list.draw()

533

534

def main():

535

game = TextureExample()

536

game.setup()

537

arcade.run()

538

539

if __name__ == "__main__":

540

main()

541

```

542

543

### Sprite Sheet Animation

544

545

```python

546

import arcade

547

548

class AnimationExample(arcade.Window):

549

def __init__(self):

550

super().__init__(800, 600, "Sprite Sheet Animation")

551

552

self.player_list = arcade.SpriteList()

553

self.walk_textures = []

554

555

def setup(self):

556

# Load walking animation frames from sprite sheet

557

self.walk_textures = arcade.load_spritesheet(

558

":resources:images/animated_characters/female_adventurer/femaleAdventurer_walk.png",

559

sprite_width=128,

560

sprite_height=128,

561

columns=8,

562

count=8

563

)

564

565

# Alternative: Load individual frames

566

# self.walk_textures = []

567

# for i in range(8):

568

# texture = arcade.load_texture(f":resources:images/animated_characters/female_adventurer/femaleAdventurer_walk{i}.png")

569

# self.walk_textures.append(texture)

570

571

# Create animated player

572

self.player = arcade.Sprite()

573

self.player.center_x = 400

574

self.player.center_y = 300

575

self.player.scale = 0.5

576

577

# Set initial texture

578

self.player.texture = self.walk_textures[0]

579

self.player_list.append(self.player)

580

581

# Animation state

582

self.current_frame = 0

583

self.frame_timer = 0

584

self.frame_duration = 0.1 # seconds per frame

585

586

def on_draw(self):

587

self.clear()

588

self.player_list.draw()

589

590

# Draw frame counter

591

arcade.draw_text(f"Frame: {self.current_frame}", 10, 550, arcade.color.WHITE, 16)

592

593

def on_update(self, delta_time):

594

# Update animation

595

self.frame_timer += delta_time

596

597

if self.frame_timer >= self.frame_duration:

598

self.frame_timer = 0

599

self.current_frame = (self.current_frame + 1) % len(self.walk_textures)

600

self.player.texture = self.walk_textures[self.current_frame]

601

602

def main():

603

game = AnimationExample()

604

game.setup()

605

arcade.run()

606

607

if __name__ == "__main__":

608

main()

609

```

610

611

### Texture Atlas Management

612

613

```python

614

import arcade

615

616

class AtlasExample(arcade.Window):

617

def __init__(self):

618

super().__init__(800, 600, "Texture Atlas Example")

619

620

self.sprite_list = arcade.SpriteList(use_spatial_hash=True)

621

self.atlas = None

622

623

def setup(self):

624

# Create texture atlas for optimal rendering

625

self.atlas = arcade.DefaultTextureAtlas(size=(1024, 1024))

626

627

# Load various textures

628

textures = [

629

arcade.load_texture(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"),

630

arcade.load_texture(":resources:images/animated_characters/male_adventurer/maleAdventurer_idle.png"),

631

arcade.load_texture(":resources:images/enemies/bee.png"),

632

arcade.load_texture(":resources:images/items/coinGold.png"),

633

]

634

635

# Add textures to atlas

636

for texture in textures:

637

success = self.atlas.add(texture)

638

print(f"Added texture '{texture.name}' to atlas: {success}")

639

640

# Create sprites using atlas textures

641

for i, texture in enumerate(textures):

642

for j in range(10):

643

sprite = arcade.Sprite(texture=texture, scale=0.3)

644

sprite.center_x = 100 + (i * 150) + (j * 15)

645

sprite.center_y = 300

646

self.sprite_list.append(sprite)

647

648

# Print atlas statistics

649

print(f"Atlas usage: {self.atlas.get_usage_percent():.1f}%")

650

print(f"Textures in atlas: {self.atlas.get_texture_count()}")

651

652

def on_draw(self):

653

self.clear()

654

self.sprite_list.draw()

655

656

# Draw atlas info

657

if self.atlas:

658

usage = self.atlas.get_usage_percent()

659

texture_count = self.atlas.get_texture_count()

660

arcade.draw_text(f"Atlas Usage: {usage:.1f}%", 10, 550, arcade.color.WHITE, 16)

661

arcade.draw_text(f"Textures: {texture_count}", 10, 525, arcade.color.WHITE, 16)

662

663

def main():

664

game = AtlasExample()

665

game.setup()

666

arcade.run()

667

668

if __name__ == "__main__":

669

main()

670

```