Mercurial > games > semicongine
comparison semiconginev2/resources.nim @ 1225:27cd1c21290e compiletime-tests
did: refactor resources
author | sam <sam@basx.dev> |
---|---|
date | Wed, 17 Jul 2024 22:20:59 +0700 |
parents | |
children | 5dcb503ef0c0 |
comparison
equal
deleted
inserted
replaced
1224:a3fa15c25026 | 1225:27cd1c21290e |
---|---|
1 type | |
2 ResourceBundlingType = enum | |
3 Dir # Directories | |
4 Zip # Zip files | |
5 Exe # Embeded in executable | |
6 | |
7 const | |
8 thebundletype = parseEnum[ResourceBundlingType](PACKAGETYPE.toLowerAscii().capitalizeAscii()) | |
9 ASCII_CHARSET = PrintableChars.toSeq.toRunes | |
10 DEFAULT_PACKAGE = "default" | |
11 | |
12 # resource loading | |
13 | |
14 func normalizeDir(dir: string): string = | |
15 result = dir | |
16 if result.startsWith("./"): | |
17 result = result[2 .. ^1] | |
18 if result.startsWith("/"): | |
19 result = result[1 .. ^1] | |
20 result = dir.replace('\\', '/') | |
21 if not result.endsWith("/") and result != "": | |
22 result = result & "/" | |
23 | |
24 when thebundletype == Dir: | |
25 | |
26 proc resourceRoot(): string = | |
27 getAppDir().absolutePath().joinPath(RESOURCEROOT) | |
28 proc packageRoot(package: string): string = | |
29 resourceRoot().joinPath(package) | |
30 | |
31 proc loadResource_intern(path: string, package: string): Stream = | |
32 let realpath = package.packageRoot().joinPath(path) | |
33 if not realpath.fileExists(): | |
34 raise newException(Exception, &"Resource {path} not found (checked {realpath})") | |
35 newFileStream(realpath, fmRead) | |
36 | |
37 proc modList_intern(): seq[string] = | |
38 for kind, file in walkDir(resourceRoot(), relative = true): | |
39 if kind == pcDir: | |
40 result.add file | |
41 | |
42 iterator walkResources_intern(dir: string, package = DEFAULT_PACKAGE): string = | |
43 for file in walkDirRec(package.packageRoot().joinPath(dir), relative = true): | |
44 yield file | |
45 | |
46 iterator ls_intern(dir: string, package: string): tuple[kind: PathComponent, path: string] = | |
47 for i in walkDir(package.packageRoot().joinPath(dir), relative = true): | |
48 yield i | |
49 | |
50 elif thebundletype == Zip: | |
51 | |
52 import ./thirdparty/zippy/zippy/ziparchives | |
53 | |
54 proc resourceRoot(): string = | |
55 absolutePath(getAppDir()).joinPath(RESOURCEROOT) | |
56 proc packageRoot(package: string): string = | |
57 resourceRoot().joinPath(package) | |
58 | |
59 proc loadResource_intern(path: string, package: string): Stream = | |
60 let archive = openZipArchive(package.packageRoot() & ".zip") | |
61 try: | |
62 result = newStringStream(archive.extractFile(path)) | |
63 except ZippyError: | |
64 raise newException(Exception, &"Resource {path} not found") | |
65 archive.close() | |
66 | |
67 proc modList_intern(): seq[string] = | |
68 for kind, file in walkDir(resourceRoot(), relative = true): | |
69 if kind == pcFile and file.endsWith(".zip"): | |
70 result.add file[0 ..< ^4] | |
71 | |
72 iterator walkResources_intern(dir: string, package = DEFAULT_PACKAGE): string = | |
73 let archive = openZipArchive(package.packageRoot() & ".zip") | |
74 let normDir = dir.normalizeDir() | |
75 for i in archive.walkFiles: | |
76 if i.startsWith(normDir): | |
77 yield i | |
78 archive.close() | |
79 | |
80 iterator ls_intern(dir: string, package: string): tuple[kind: PathComponent, path: string] = | |
81 let archive = openZipArchive(package.packageRoot() & ".zip") | |
82 let normDir = dir.normalizeDir() | |
83 var yielded: HashSet[string] | |
84 | |
85 for i in archive.walkFiles: | |
86 if i.startsWith(normDir): | |
87 let components = i[normDir.len .. ^1].split('/', maxsplit = 1) | |
88 if components.len == 1: | |
89 if not (components[0] in yielded): | |
90 yield (kind: pcFile, path: components[0]) | |
91 else: | |
92 if not (components[0] in yielded): | |
93 yield (kind: pcDir, path: components[0]) | |
94 yielded.incl components[0] | |
95 archive.close() | |
96 | |
97 elif thebundletype == Exe: | |
98 | |
99 import std/tables | |
100 | |
101 const BUILD_RESOURCEROOT* {.strdefine.}: string = "" | |
102 | |
103 proc loadResources(): Table[string, Table[string, string]] {.compileTime.} = | |
104 when BUILD_RESOURCEROOT == "": | |
105 {.warning: "BUILD_RESOURCEROOT is empty, no resources will be packaged".} | |
106 return | |
107 else: | |
108 for kind, packageDir in walkDir(BUILD_RESOURCEROOT): | |
109 if kind == pcDir: | |
110 let package = packageDir.splitPath.tail | |
111 result[package] = Table[string, string]() | |
112 for resourcefile in walkDirRec(packageDir, relative = true): | |
113 result[package][resourcefile.replace('\\', '/')] = staticRead(packageDir.joinPath(resourcefile)) | |
114 const bundledResources = loadResources() | |
115 | |
116 proc loadResource_intern(path: string, package: string): Stream = | |
117 if not (path in bundledResources[package]): | |
118 raise newException(Exception, &"Resource {path} not found") | |
119 newStringStream(bundledResources[package][path]) | |
120 | |
121 proc modList_intern(): seq[string] = | |
122 result = bundledResources.keys().toSeq() | |
123 | |
124 iterator walkResources_intern(dir: string, package = DEFAULT_PACKAGE): string = | |
125 for i in bundledResources[package].keys: | |
126 yield i | |
127 | |
128 iterator ls_intern(dir: string, package: string): tuple[kind: PathComponent, path: string] = | |
129 let normDir = dir.normalizeDir() | |
130 var yielded: HashSet[string] | |
131 | |
132 for i in bundledResources[package].keys: | |
133 if i.startsWith(normDir): | |
134 let components = i[normDir.len .. ^1].split('/', maxsplit = 1) | |
135 if components.len == 1: | |
136 if not (components[0] in yielded): | |
137 yield (kind: pcFile, path: components[0]) | |
138 else: | |
139 if not (components[0] in yielded): | |
140 yield (kind: pcDir, path: components[0]) | |
141 yielded.incl components[0] | |
142 | |
143 proc LoadResource*(path: string, package = DEFAULT_PACKAGE): Stream = | |
144 loadResource_intern(path, package = package) | |
145 | |
146 #[ | |
147 proc LoadImage*[T](path: string, package = DEFAULT_PACKAGE): Image[RGBAPixel] = | |
148 if path.splitFile().ext.toLowerAscii == ".bmp": | |
149 loadResource_intern(path, package = package).ReadBMP() | |
150 elif path.splitFile().ext.toLowerAscii == ".png": | |
151 loadResource_intern(path, package = package).ReadPNG() | |
152 else: | |
153 raise newException(Exception, "Unsupported image file type: " & path) | |
154 | |
155 proc LoadJson*(path: string, package = DEFAULT_PACKAGE): JsonNode = | |
156 path.loadResource_intern(package = package).readAll().parseJson() | |
157 | |
158 proc LoadConfig*(path: string, package = DEFAULT_PACKAGE): Config = | |
159 path.loadResource_intern(package = package).loadConfig(filename = path) | |
160 | |
161 proc LoadFont*( | |
162 path: string, | |
163 name = "", | |
164 lineHeightPixels = 80'f32, | |
165 additional_codepoints: openArray[Rune] = [], | |
166 charset = ASCII_CHARSET, | |
167 package = DEFAULT_PACKAGE | |
168 ): Font = | |
169 var thename = name | |
170 if thename == "": | |
171 thename = path.splitFile().name | |
172 loadResource_intern(path, package = package).ReadTrueType(name, charset & additional_codepoints.toSeq, lineHeightPixels) | |
173 | |
174 proc LoadMeshes*(path: string, defaultMaterial: MaterialType, package = DEFAULT_PACKAGE): seq[MeshTree] = | |
175 loadResource_intern(path, package = package).ReadglTF(defaultMaterial) | |
176 | |
177 proc LoadFirstMesh*(path: string, defaultMaterial: MaterialType, package = DEFAULT_PACKAGE): Mesh = | |
178 loadResource_intern(path, package = package).ReadglTF(defaultMaterial)[0].toSeq[0] | |
179 | |
180 ]# | |
181 | |
182 proc Packages*(): seq[string] = | |
183 modList_intern() | |
184 | |
185 proc WalkResources*(dir = "", package = DEFAULT_PACKAGE): seq[string] = | |
186 for i in walkResources_intern(dir, package = package): | |
187 if i.startsWith(dir): | |
188 result.add i | |
189 result.sort() | |
190 | |
191 proc List*(dir: string, package = DEFAULT_PACKAGE): seq[tuple[kind: PathComponent, path: string]] = | |
192 for i in ls_intern(dir = dir, package = package): | |
193 result.add i | |
194 result.sort() |