fractex 0.1.1__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. {fractex-0.1.1/fractex.egg-info → fractex-0.2.0}/PKG-INFO +1 -1
  2. {fractex-0.1.1 → fractex-0.2.0}/fractex/cli.py +1 -0
  3. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/__init__.py +1 -0
  4. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/architecture_pattern.py +1 -0
  5. fractex-0.2.0/fractex/examples/fire_flame.py +141 -0
  6. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/splash.py +5 -1
  7. {fractex-0.1.1 → fractex-0.2.0}/fractex/interactive.py +11 -1
  8. {fractex-0.1.1 → fractex-0.2.0/fractex.egg-info}/PKG-INFO +1 -1
  9. {fractex-0.1.1 → fractex-0.2.0}/fractex.egg-info/SOURCES.txt +1 -0
  10. {fractex-0.1.1 → fractex-0.2.0}/pyproject.toml +1 -1
  11. {fractex-0.1.1 → fractex-0.2.0}/LICENSE +0 -0
  12. {fractex-0.1.1 → fractex-0.2.0}/MANIFEST.in +0 -0
  13. {fractex-0.1.1 → fractex-0.2.0}/README.md +0 -0
  14. {fractex-0.1.1 → fractex-0.2.0}/fractex/3d.py +0 -0
  15. {fractex-0.1.1 → fractex-0.2.0}/fractex/__init__.py +0 -0
  16. {fractex-0.1.1 → fractex-0.2.0}/fractex/advanced.py +0 -0
  17. {fractex-0.1.1 → fractex-0.2.0}/fractex/core.py +0 -0
  18. {fractex-0.1.1 → fractex-0.2.0}/fractex/dynamic_textures_3d.py +0 -0
  19. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/3d.py +0 -0
  20. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/3d_integration.py +0 -0
  21. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/3d_integration_2d.py +0 -0
  22. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/_output.py +0 -0
  23. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/atmosphere.py +0 -0
  24. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/composite_material.py +0 -0
  25. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/crystal_cave.py +0 -0
  26. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/custom_pattern.py +0 -0
  27. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/game_integration.py +0 -0
  28. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/game_texture.py +0 -0
  29. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/integration.py +0 -0
  30. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/physic_integration.py +0 -0
  31. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/terrain.py +0 -0
  32. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/underwater.py +0 -0
  33. {fractex-0.1.1 → fractex-0.2.0}/fractex/examples/underwater_volkano.py +0 -0
  34. {fractex-0.1.1 → fractex-0.2.0}/fractex/geometric_patterns_3d.py +0 -0
  35. {fractex-0.1.1 → fractex-0.2.0}/fractex/simplex_noise.py +0 -0
  36. {fractex-0.1.1 → fractex-0.2.0}/fractex/texture_blending.py +0 -0
  37. {fractex-0.1.1 → fractex-0.2.0}/fractex/volume_scattering.py +0 -0
  38. {fractex-0.1.1 → fractex-0.2.0}/fractex/volume_textures.py +0 -0
  39. {fractex-0.1.1 → fractex-0.2.0}/fractex.egg-info/dependency_links.txt +0 -0
  40. {fractex-0.1.1 → fractex-0.2.0}/fractex.egg-info/entry_points.txt +0 -0
  41. {fractex-0.1.1 → fractex-0.2.0}/fractex.egg-info/requires.txt +0 -0
  42. {fractex-0.1.1 → fractex-0.2.0}/fractex.egg-info/top_level.txt +0 -0
  43. {fractex-0.1.1 → fractex-0.2.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fractex
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Fractal texture engine for procedural and infinite-detail textures.
5
5
  Author-email: Timur Isanov <tisanov@yahoo.com>
6
6
  License: MIT License
@@ -11,6 +11,7 @@ from typing import List
11
11
  def _examples() -> List[str]:
12
12
  return [
13
13
  "splash",
14
+ "fire_flame",
14
15
  "custom_pattern",
15
16
  "architecture_pattern",
16
17
  "composite_material",
@@ -10,6 +10,7 @@ from typing import List, Optional
10
10
  def list_examples() -> List[str]:
11
11
  return [
12
12
  "splash",
13
+ "fire_flame",
13
14
  "custom_pattern",
14
15
  "architecture_pattern",
15
16
  "composite_material",
@@ -2,6 +2,7 @@
2
2
  import sys
3
3
  from pathlib import Path
4
4
  import argparse
5
+ import numpy as np
5
6
 
6
7
  ROOT = Path(__file__).resolve().parents[2]
7
8
  if str(ROOT) not in sys.path:
@@ -0,0 +1,141 @@
1
+ import sys
2
+ from pathlib import Path
3
+ import argparse
4
+ import numpy as np
5
+
6
+ ROOT = Path(__file__).resolve().parents[2]
7
+ if str(ROOT) not in sys.path:
8
+ sys.path.insert(0, str(ROOT))
9
+ EXAMPLES_DIR = Path(__file__).resolve().parent
10
+ if str(EXAMPLES_DIR) not in sys.path:
11
+ sys.path.insert(0, str(EXAMPLES_DIR))
12
+
13
+ from fractex.simplex_noise import SimplexNoise
14
+ from fractex.interactive import add_interactive_args, InteractiveConfig, run_interactive
15
+ from _output import save_ppm
16
+
17
+
18
+ def _render_flame(t: float, w: int, h: int, noise: SimplexNoise) -> np.ndarray:
19
+ x = np.linspace(-1.0, 1.0, w)
20
+ y = np.linspace(0.0, 2.0, h)
21
+ xx, yy = np.meshgrid(x, y)
22
+ taper = 1.0 - 0.5 * np.clip(yy / 2.0, 0, 1)
23
+ xx_t = xx * taper
24
+ zz = np.ones_like(xx) * (t * 0.15)
25
+
26
+ base = noise.noise_3d(xx_t * 1.5, yy * 1.2, zz)
27
+ detail = noise.noise_3d(xx_t * 5.0, yy * 4.0, zz * 1.8)
28
+ micro = noise.noise_3d(xx_t * 14.0, yy * 10.0, zz * 5.0)
29
+ warp = noise.noise_3d(xx_t * 1.2, yy * 1.0, zz * 0.8)
30
+ turbulence = base * 0.45 + detail * 0.3 + micro * 0.2 + warp * 0.05
31
+ turbulence = (turbulence + 1) * 0.5
32
+
33
+ # Центральное ядро + вытянутая форма вверх (с повышенным контрастом)
34
+ core = np.exp(-((xx_t * 1.8) ** 2)) * np.clip(2.6 - yy, 0, 1)
35
+ # Языки с резкими краями (степень для контраста)
36
+ tongues_raw = np.exp(-((xx_t * 5.0 + warp * 1.6) ** 2)) * np.clip(3.0 - yy, 0, 1)
37
+ tongues = np.clip(tongues_raw * 1.5 - 0.2, 0, 1) ** 0.7
38
+ lobe_raw = np.exp(-((xx_t * 6.0) ** 2)) * np.clip(3.2 - yy, 0, 1) * (0.6 + 0.4 * np.sin(t * 0.7 + yy * 4.0))
39
+ lobe = np.clip(lobe_raw * 1.4 - 0.15, 0, 1) ** 0.8
40
+ jets_raw = np.clip(turbulence - 0.15, 0, 1) * np.exp(-((xx_t * 7.0 + warp * 1.8) ** 2)) * np.clip(3.4 - yy, 0, 1)
41
+ jets = np.clip(jets_raw * 1.6 - 0.1, 0, 1) ** 0.6
42
+ rips = np.clip(turbulence * 1.4 - 0.35, 0, 1) * np.exp(-((xx_t * 4.2) ** 2)) * np.clip(2.2 - yy, 0, 1)
43
+
44
+ # Усиленные языки у основания (резкие)
45
+ base_tongues_raw = np.exp(-((xx_t * 3.5 + warp * 2.0) ** 2)) * np.clip(1.0 - yy * 0.6, 0, 1)
46
+ base_tongues = np.clip(base_tongues_raw * 1.5 - 0.15, 0, 1) ** 0.7
47
+ base_flicker = (0.7 + 0.3 * np.sin(t * 2.5 + xx * 8.0)) * np.clip(0.8 - yy, 0, 1)
48
+ base_texture = np.clip(detail * 0.8 + micro * 0.4, 0, 1) * np.exp(-((xx_t * 2.0) ** 2)) * np.clip(0.6 - yy * 0.5, 0, 1)
49
+
50
+ # Языки пламени веером от центра основания к краям
51
+ yy_safe = np.maximum(yy, 0.05) # избегаем деления на 0
52
+ # Больше языков под меньшими углами (более вертикальные)
53
+ tongue_angles = [-0.2, -0.13, -0.07, 0.0, 0.07, 0.13, 0.2] # 7 языков, узкий веер
54
+ tongues_radial = np.zeros_like(xx)
55
+ for i, ta in enumerate(tongue_angles):
56
+ # Ось языка с динамическим колебанием
57
+ wobble = noise.noise_3d(np.full_like(xx, i * 0.7), yy * 1.5 - t * 0.6, zz) * 0.08
58
+ tongue_axis = yy_safe * (ta + wobble)
59
+ dist_from_axis = np.abs(xx_t - tongue_axis)
60
+ # Ширина: больше у основания, сужается вверх
61
+ width = 0.10 * np.clip(1.0 - yy * 0.35, 0.25, 1.0)
62
+ tongue_shape = np.exp(-((dist_from_axis / width) ** 2))
63
+ # Контрастность: резкие края
64
+ tongue_shape = np.clip(tongue_shape * 1.5 - 0.2, 0, 1) ** 0.7
65
+ # Яркость: сильнее у основания, центральный язык ярче
66
+ center_boost = 1.0 + 0.4 * np.exp(-(ta * 8) ** 2) # центр ярче
67
+ brightness = np.clip(2.0 - yy * 1.0, 0, 1) * (0.8 + 0.2 * np.sin(t * 2.0 + i * 1.0)) * center_boost
68
+ tongues_radial += tongue_shape * brightness
69
+ tongues_radial = np.clip(tongues_radial * 0.6, 0, 1)
70
+
71
+ flame = np.clip(core * (0.2 + 1.0 * turbulence) + tongues * 1.0 + lobe * 0.7 + jets * 0.7 + rips * 0.4 + base_tongues * 0.8 + base_flicker * 0.4 + base_texture * 0.5 + tongues_radial * 0.7, 0, 1)
72
+ flame = np.clip((flame - 0.1) * 1.6, 0, 1)
73
+
74
+ # Подсветка ядра
75
+ core_glow = np.exp(-((xx_t * 3.2) ** 2 + (yy * 1.6) ** 2)) * np.clip(1.6 - yy, 0, 1)
76
+
77
+ # Дым: только в верхней части (выше yy=1.0) - полностью чистый низ
78
+ smoke_vertical = np.clip((yy - 1.0) * 2.0, 0, 1) # маска: 0 внизу, 1 вверху
79
+ smoke = np.clip((yy - 1.5) * 0.7, 0, 1) * (0.2 + 0.5 * turbulence)
80
+ side_mask = np.clip((np.abs(xx) * 1.8 - 0.5), 0, 1)
81
+ smoke = smoke * np.exp(-((xx_t * 1.5 + warp * 0.6) ** 2)) * side_mask
82
+ trail = np.exp(-((xx_t * 0.8 + warp * 0.6) ** 2)) * np.clip(yy - 1.2, 0, 1)
83
+ trail = trail * (0.3 + 0.5 * turbulence) * (0.5 + 0.5 * np.sin(t * 0.3 + yy * 1.5))
84
+ smoke = np.clip((smoke + trail * 0.4) * smoke_vertical, 0, 1)
85
+
86
+ # Искры: у основания без маски, выше - только по краям
87
+ spark_mask = np.clip(micro - 0.7, 0, 1)
88
+ edge = np.clip(np.abs(xx_t) * 2.0, 0, 1)
89
+ bottom_zone = np.clip(1.0 - yy, 0, 1)
90
+ sparks = spark_mask ** 2 * (bottom_zone * 1.2 + (1 - bottom_zone) * edge * 0.5)
91
+
92
+ rgb = np.full((h, w, 3), np.array([0.55, 0.27, 0.20], dtype=np.float32), dtype=np.float32)
93
+ heat = np.clip(flame * 1.2, 0, 1)
94
+
95
+ # Температурный градиент: краснее/оранжевее у основания, белее к ядру
96
+ vertical = np.clip(1.2 - yy, 0, 1)
97
+ temp = np.clip(vertical * 0.6 + heat * 0.7, 0, 1)
98
+ cold_color = np.array([1.0, 0.35, 0.02], dtype=np.float32) # более насыщенный оранжево-красный
99
+ hot_color = np.array([1.0, 0.92, 0.8], dtype=np.float32)
100
+ temp_rgb = cold_color * (1 - temp)[..., None] + hot_color * temp[..., None]
101
+ base_boost = np.clip(1.0 - yy * 0.3, 0.75, 1.0)
102
+ base_heat = np.clip(1.0 - yy * 0.5, 0, 1) * np.exp(-((xx_t * 1.8) ** 2))
103
+ # Дополнительная оранжевая текстура у основания (усилена)
104
+ orange_base = np.clip(detail * 0.5 + 0.5, 0, 1) * np.clip(0.8 - yy * 0.45, 0, 1) * np.exp(-((xx_t * 1.5) ** 2))
105
+ # Красное свечение у самого основания
106
+ red_base = np.clip(0.5 - yy * 0.6, 0, 1) * np.exp(-((xx_t * 1.2) ** 2)) * (0.7 + 0.3 * turbulence)
107
+
108
+ core_boost = 1.0 + 0.5 * core_glow
109
+ core_ripple = 0.85 + 0.15 * np.sin(t * 1.4 + (xx_t + yy) * 3.5) * core_glow
110
+ rgb[..., 0] = np.clip(temp_rgb[..., 0] * heat * core_boost * core_ripple * (1.15 * base_boost) + base_heat * 0.55 + orange_base * 0.7 + red_base * 0.5 + sparks * 1.6 + core_glow * 0.35, 0, 1)
111
+ rgb[..., 1] = np.clip(temp_rgb[..., 1] * heat * core_boost * core_ripple * (1.08 * base_boost) + base_heat * 0.35 + orange_base * 0.35 + red_base * 0.15 + sparks * 0.8 + core_glow * 0.2, 0, 1)
112
+ rgb[..., 2] = np.clip(temp_rgb[..., 2] * heat * (0.9 + 0.3 * core_glow) * core_ripple * (0.95 * base_boost) + base_heat * 0.03 + core_glow * 0.06, 0, 1)
113
+
114
+ # Добавляем дым как серо-синий слой
115
+ rgb[..., 0] = np.clip(rgb[..., 0] * (1 - smoke) + smoke * 0.3, 0, 1)
116
+ rgb[..., 1] = np.clip(rgb[..., 1] * (1 - smoke) + smoke * 0.35, 0, 1)
117
+ rgb[..., 2] = np.clip(rgb[..., 2] * (1 - smoke) + smoke * 0.4, 0, 1)
118
+ return rgb
119
+
120
+
121
+ def main():
122
+ parser = argparse.ArgumentParser(description="Fire flame example")
123
+ add_interactive_args(parser)
124
+ args = parser.parse_args()
125
+
126
+ noise = SimplexNoise(seed=42)
127
+
128
+ if args.interactive:
129
+ config = InteractiveConfig.from_args(args, title="fractex")
130
+
131
+ def render_frame(t, w, h):
132
+ return _render_flame(t, w, h, noise)
133
+
134
+ run_interactive(render_frame, config)
135
+ else:
136
+ image = _render_flame(0.0, 512, 512, noise)
137
+ save_ppm(image, EXAMPLES_DIR / "output" / "fire_flame.ppm", stretch=True)
138
+
139
+
140
+ if __name__ == "__main__":
141
+ main()
@@ -58,7 +58,11 @@ def main():
58
58
  dpi = fig.get_dpi()
59
59
  fig.set_size_inches(screen_width / dpi, screen_height / dpi)
60
60
  ax.axis("off")
61
- ax.set_title(f"Fractex Splash ({selected or 'auto'})")
61
+ ax.set_title("fractex")
62
+ try:
63
+ fig.canvas.manager.set_window_title("fractex")
64
+ except Exception:
65
+ pass
62
66
 
63
67
  texture = textures[presets[0]]
64
68
  width = max(64, int(screen_width * max(0.1, args.scale)))
@@ -104,6 +104,7 @@ def run_interactive(
104
104
  try:
105
105
  import matplotlib.pyplot as plt
106
106
  from matplotlib.animation import FuncAnimation
107
+ import matplotlib as mpl
107
108
  except Exception:
108
109
  print("matplotlib is not available; cannot display interactive output.")
109
110
  return
@@ -114,12 +115,21 @@ def run_interactive(
114
115
  width = max(config.min_render, width)
115
116
  height = max(config.min_render, height)
116
117
 
118
+ mpl.rcParams["toolbar"] = "None"
117
119
  fig, ax = plt.subplots()
118
120
  dpi = fig.get_dpi()
119
121
  fig.set_size_inches(width / dpi, height / dpi)
120
122
  ax.axis("off")
121
- ax.set_title(config.title)
123
+ ax.set_title("fractex")
122
124
  fig.subplots_adjust(left=0, right=1, top=1, bottom=0)
125
+ try:
126
+ fig.canvas.manager.toolbar.setVisible(False)
127
+ except Exception:
128
+ pass
129
+ try:
130
+ fig.canvas.manager.set_window_title("fractex")
131
+ except Exception:
132
+ pass
123
133
 
124
134
  target_ms = 1000.0 / max(1.0, config.target_fps)
125
135
  render_scale = 1.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fractex
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Fractal texture engine for procedural and infinite-detail textures.
5
5
  Author-email: Timur Isanov <tisanov@yahoo.com>
6
6
  License: MIT License
@@ -30,6 +30,7 @@ fractex/examples/atmosphere.py
30
30
  fractex/examples/composite_material.py
31
31
  fractex/examples/crystal_cave.py
32
32
  fractex/examples/custom_pattern.py
33
+ fractex/examples/fire_flame.py
33
34
  fractex/examples/game_integration.py
34
35
  fractex/examples/game_texture.py
35
36
  fractex/examples/integration.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "fractex"
7
- version = "0.1.1"
7
+ version = "0.2.0"
8
8
  description = "Fractal texture engine for procedural and infinite-detail textures."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes