-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #114 from karl-zylinski/code-generation
Code generation
- Loading branch information
Showing
8 changed files
with
184 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
This shows some basic code generation / meta programming. | ||
|
||
The code generation is done by running a separate program that generates some Odin code. | ||
|
||
Generate `images.odin` by running: | ||
|
||
``` | ||
odin run generate_image_info | ||
``` | ||
|
||
The following will build the program that actually uses `images.odin`: | ||
|
||
``` | ||
odin run . | ||
``` | ||
|
||
It will print: | ||
|
||
``` | ||
Long_Cat is 9 x 46 pixels and 183 bytes large | ||
Round_Cat is 20 x 24 pixels and 317 bytes large | ||
Round_Cat has width > 15, so we loaded it! | ||
The loaded PNG image is indeed 20 pixels wide! | ||
Tuna is 24 x 20 pixels and 318 bytes large | ||
Tuna has width > 15, so we loaded it! | ||
The loaded PNG image is indeed 24 pixels wide! | ||
``` |
83 changes: 83 additions & 0 deletions
83
code_generation/generate_image_info/generate_image_info.odin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
This program generates `images.odin` by going through the `images` folder and | ||
opening each file. From each PNG file in there it will: | ||
- Generate a pretty enum name for it | ||
- Make a list of images where it maps each pretty enum name to an Image struct | ||
- The Image struct contains the width and the height. This is determined by | ||
opening the PNG files. | ||
- The Image struct also contains a `data = #load(THE_FILENAME)` field. That will | ||
make the compiler that later tries to compile `images.odin` load the file | ||
data at compile-time. | ||
*/ | ||
package generate_image_info | ||
|
||
import "core:os" | ||
import "core:strings" | ||
import "core:fmt" | ||
import "core:path/slashpath" | ||
import "core:image/png" | ||
import "core:image" | ||
|
||
// Avoids 'unused import' error: "core:image/png" needs to be imported in order | ||
// to make `img.load_from_bytes` understand PNG format. | ||
_ :: png | ||
|
||
INPUT_DIR :: "images" | ||
OUTPUT_FILE :: "images.odin" | ||
|
||
main :: proc() { | ||
d, d_err := os.open(INPUT_DIR, os.O_RDONLY) | ||
assert(d_err == nil, "Failed opening '" + INPUT_DIR + "' folder") | ||
defer os.close(d) | ||
|
||
input_files, _ := os.read_dir(d, -1) | ||
|
||
f, _ := os.open(OUTPUT_FILE, os.O_WRONLY | os.O_CREATE | os.O_TRUNC) | ||
defer os.close(f) | ||
|
||
images: [dynamic]os.File_Info | ||
|
||
for i in input_files { | ||
if !strings.has_suffix(i.name, ".png") { | ||
continue | ||
} | ||
|
||
append(&images, i) | ||
} | ||
|
||
fmt.fprintln(f, | ||
`// This file is generated. Re-generate it by running: | ||
// odin run generate_image_info | ||
package image_viewer | ||
Image :: struct { | ||
width: int, | ||
height: int, | ||
data: []u8, | ||
} | ||
Image_Name :: enum {`, | ||
) | ||
|
||
for i in images { | ||
fmt.fprintfln(f, " %v,", strings.to_ada_case(slashpath.name(i.name))) | ||
} | ||
|
||
fmt.fprintln(f, | ||
`} | ||
images := [Image_Name]Image {`, | ||
) | ||
|
||
for i in images { | ||
img, img_err := image.load_from_file(i.fullpath) | ||
|
||
if img_err == nil { | ||
enum_name := strings.to_ada_case(slashpath.name(i.name)) | ||
fmt.fprintfln(f, " .%v = {{ data = #load(\"images/%v\"), width = %v, height = %v }},", enum_name, i.name, img.width, img.height) | ||
} | ||
} | ||
|
||
fmt.fprintln(f, "}") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// This file is generated. Re-generate it by running: | ||
// odin run generate_image_info | ||
package image_viewer | ||
|
||
Image :: struct { | ||
width: int, | ||
height: int, | ||
data: []u8, | ||
} | ||
|
||
Image_Name :: enum { | ||
Long_Cat, | ||
Round_Cat, | ||
Tuna, | ||
} | ||
|
||
images := [Image_Name]Image { | ||
.Long_Cat = { data = #load("images/long_cat.png"), width = 9, height = 46 }, | ||
.Round_Cat = { data = #load("images/round_cat.png"), width = 20, height = 24 }, | ||
.Tuna = { data = #load("images/tuna.png"), width = 24, height = 20 }, | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package image_viewer | ||
|
||
import "core:image" | ||
import "core:image/png" | ||
|
||
// Avoids 'unused import' error: "core:image/png" needs to be imported in order | ||
// to make `img.load_from_bytes` understand PNG format. | ||
_ :: png | ||
|
||
import "core:fmt" | ||
|
||
/* | ||
This program prints: | ||
Long_Cat is 9 x 46 pixels and 183 bytes large | ||
Round_Cat is 20 x 24 pixels and 317 bytes large | ||
Round_Cat has width > 15 we loaded it! | ||
It is indeed 20 pixels wide! | ||
Tuna is 24 x 20 pixels and 318 bytes large | ||
Tuna has width > 15 we loaded it! | ||
It is indeed 24 pixels wide! | ||
Note how it knows width and height before it loads the file. That was written | ||
into `images.odin` by the code generation program in the `generate_image_info` | ||
folder. It also knows the file size: `img.data` contains the data (i.e. the file | ||
contents) for that image. That data is put into the executable at compile time | ||
using the built-in `#load` procedure. The path of the image send into `#load` | ||
is written by the code generation program. | ||
*/ | ||
main :: proc() { | ||
for &img, name in images { | ||
fmt.printfln("%v is %v x %v pixels and %v bytes large", name, img.width, img.height, len(img.data)) | ||
|
||
// Make decisions based pre-computed data before actually loading the image | ||
if img.width > 15 { | ||
loaded_img, loaded_img_err := image.load_from_bytes(img.data) | ||
|
||
if loaded_img_err == nil { | ||
fmt.printfln("%v has width > 15, so we loaded it!", name) | ||
fmt.printfln("The loaded PNG image is indeed %v pixels wide!", loaded_img.width) | ||
} | ||
} | ||
|
||
fmt.println() | ||
} | ||
} |