Skip to content

Commit

Permalink
push april newsletter draft with images content
Browse files Browse the repository at this point in the history
  • Loading branch information
Skytrias committed Apr 8, 2024
1 parent b6da266 commit fa0c713
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 0 deletions.
210 changes: 210 additions & 0 deletions content/news/2024-04.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
---
title: April 2024 Newsletter
summary: Highlights for April - Showcasing ***4*** Community Projects
slug: newsletter-2024-04
author: Michael Kutowski
date: '2024-04-01'
draft: true
categories:
- newsletter
- odin
---

Read up on the compiler changes in the [monthly release](https://github.com/odin-lang/Odin/releases/tag/dev-2024-04) notes.

## Game Releases

Im proud to announce that two games have been released this month! We've mentioned both of these before so please check them out.

<div id="contenedor">
<iframe src="https://store.steampowered.com/widget/2754920/" frameborder="0" width="100%" height="190"></iframe>
</div>

<hr>

<div id="contenedor">
<iframe src="https://store.steampowered.com/widget/2781210/" frameborder="0" width="100%" height="190"></iframe>
</div>

## Streamer Cakez tried out Odin

{{<youtube braSC-5wAwk>}}

## Awesome-Odin

I'd like to mention [awesome-odin](https://github.com/jakubtomsu/awesome-odin) as another collection of projects, summarized by categories!

<div class="d-flex justify-content-center">
<a target="_blank" rel="noreferrer noopener" href="https://github.com/jakubtomsu/awesome-odin">
<img src="/images/news/awesome-odin.png" class="figure-img img-fluid">
</a>
</div>

## Projects shared this month

| Project Name | Description |
| --- | --- |
| [ncurses](https://github.com/RaphGL/Ncurses.odin) | Ncurses bindings |
| [Edo](https://github.com/RaphGL/Edo) | Minimal text editor |
| [box2d](https://github.com/cr1sth0fer/odin-box2d) | box2d 3.0 bindings |
| [timealloc](https://github.com/antogp24/timealloc) | time management app |
| [performance_aware](https://github.com/iansimonson/performance_aware) | performance aware course solutions |
| [graphql-parser](https://github.com/thetarnav/odin-graphql-parser) | graphql-parser currently only schema |
| [websocket-client](https://github.com/FreerGit/websocket-client) | websocket client with SSL |

## Project Showcase

We're going with the same layout as last month, let's see how it goes again.

## RePico

RePico is small tool that allows user to replace visual shell of PNG carts used by PICO-8 fantasy console. It's my project made for the sake of practice writing something useful with Odin language and Raylib.
It was actually inspired by another project that did the same thing made with Godot engine: https://www.lexaloffle.com/bbs/?tid=50563

<div class="d-flex justify-content-center">
<img src="/images/news/2024-04-nefrace1.png" class="">
</div>

I didn't really bother with styling that thing. It's just basic Raygui theme. You can drag-and-drop images into the slots and convert the cart! There's also a rudimental file explorer and the whole command line interface if you don't want to touch mouse and click GUI buttons!

<img src="/images/news/2024-04-nefrace2.png" class="figure-img img-fluid">

### What do you mean "replace visual shell"?

Everyone who's familiar with PICO-8 fantasy console knows that the game carts it can read and write can be PNG images. Not everyone knows how it stores date inside these images.
The core of data storage here is a technique called "steganography". Basically it means "store some information inside other information". In case of the image we can embed some binary data inside the pixels of the image itself! PICO-8 carts use 2 least significant bits of every channel of the image to store ROM data. And the trick is to get another image that's similar in size and replace it's 2 least significant bits with the ones from original cart.

### Why even bother if such tool already exists?

For practice of course! You don't need to make something unique if you're just learning stuff.

### Why Odin?

Because I found it really cool and that's it actually. I really like Odin language and don't have much experience beside one small game for some small game jam. I wanted to try make a somewhat "useful" tool with it.

My two main programming languages are GDScript for games and Golang for everything else (also a bunch of HTML/JS for web). I want to explore the low level worlds a bit more and get some understanding of how things work here.

### What i liked about coding with Odin?

Kinda everything! From the perspective of someone who only used garbage-collected and interpreted languages Odin is somewhat easy to jump in and write useful code. And Raylib makes it really easy to create simple GUI applications or games. Maybe I should've used Microui but it doesn't really matter right now. Just initialize window, grab input events, do some stuff with that and draw something! I've even learned a lot about how C code works, library linking and memory management. I've never wrote a line of working code in C or C++ before.

Also the performance you get from writing native code is just awesome. The applications starts instantly even on some really old machines and works flawlessly!

I've made first iteration of RePico in 2 hours and it was able to load images dropped onto the window and replace the shell to the file with hardcoded name.

{{<youtube dtHY7EQ2lK4>}}

Then there were some QoL features I wanted to try to implement. The first one was CLI mode and it was much easier than the original GUI one (who would have guessed). And then there was file explorer that was made just because I wanted one.

### The quirks of raygui

{{<youtube 2TwC4LX_nIY>}}

The first thing i've added is the ability to write your own filename for the output. And the problem was with the fact that the `raylib.GuiTextBox` procedure takes `cstring` as an argument to store the value of the input box you're writing in. And if you'll just write something like that:

```raylib
// In the head of file
myInput : cstring
// In main loop
raylib.GuiTextBox({0, 0, 200, 30}, myInput, 255, true)
```

It will segfault the moment you'll try to type or delete a letter. And you can't just pass a pointer to this string — the compiler wouldn't let you.

But the friendly community helped me out with that case. All I need to do is create a buffer memory for that string before using it:

```odin
maxSize := 255
buf: [maxSize]byte
str := cstring(&buf[0])
// In main loop
raylib.GuiTextBox({0, 0, 200, 30}, str, maxSize, true)
```

There's also a way with dynamic allocation but I didn't bother to try that :shrug:

Another problem was with file explorer. Raylib has two methods of getting the contents of directory:

- `LoadDirectoryFiles` which just gets the path and returns a bunch of file paths
- `LoadDirectoryFilesEx` which can also filter for some extensions and scan directories recursively.

The problem is that the output is not sorted in any way! And there's also no way to set filter to include `.png` files **and** directories.

So I've implemented my own kind of wrapper for the first method and merged it with the functionality of current changing directory:

```odin
// Some trick from community to get "dynamic array" without dynamic allocation
filesBuf : [1024*8]cstring
files : [dynamic]cstring
// We need that thing to put as an argument to raylib.GuiListViewEx
filesPtr : [^]cstring
filesCount : i32 = 0
cd :: proc(dir: cstring) -> (result: bool) {
result = rl.ChangeDirectory(dir)
rl.UnloadDirectoryFiles(fileList)
clear(&files)
fileList = rl.LoadDirectoryFiles(".")
for fname in fileList.paths[:fileList.count] {
if rl.DirectoryExists(fname) || rl.GetFileExtension(fname) == ".png" {
append(&files, fname)
}
}
// Funky sorting procedure to show directories first
slice.sort_by(files[:], proc(i,j:cstring) -> bool {
a := string(i)
b := string(j)
adir := rl.DirectoryExists(i)
bdir := rl.DirectoryExists(j)
if (adir && bdir) || (!adir && !bdir) {
return strings.compare(a, b) == -1
}
return adir && !bdir
})
filesPtr = raw_data(files)
filesCount = auto_cast len(files)
fileListScrolling = 0
fileListActive = -1
fileListFocus = -1
}
```
There's a lot of potential problems with that code but hey! It works fine for me now.

Also this file explorer is not very comfortable to use because you can't just double-click an item to open it. Raygui does not provide it out of the box and I haven't tried to implement it yet.

### Afterthoughts

Odin took a special place in my heart and I really wanna explore it more. I think I need to finish that project and then I wanna start making a game with Raylib. There are many things that are still not easy to understand for me in the world of low level programming with manual memory management but Odin really helped me out with that.

The not-so-pretty source code of RePico is available at [Github](https://github.com/nefrace/repico). I'm planning to release it on Itch after cleaning things up. Or maybe i'll try to replace Raylib with MicroUI, who knows (:

<hr>

## Soap Glider

Soap Glider is a game where you're a kid in the bathtub, playing with the soap, tossing it around and leaving trails of bubbles (and sometimes you're an octopus). It's inspired by an old Android game called Run and borrows somewhat from Osu. On the gameplay side, my goal is to explore what makes rhythm games interesting and fun, and on the graphical side, I seek to learn how to employ real-time ray-tracing for drawing the scenes while keeping it responsive enough for the fast-paced gameplay. When it's done, Soap Glider will be released on Itchio along with the source code.

The game uses the `OpenGL` and `glfw` packages for rendering and `miniaudio` for sound.

<div class="d-flex justify-content-center">
<img src="/images/news/2024-04-nikio001.gif" class="img-fluid rounded">
</div>


### Platforming

The platforms are constructed in GLSL shader code by projecting and extruding 2D SDFs onto the surface of a cylinder. To get the geometry of the scene for the gameplay logic procedure, I place a cheap camera beneath the soap and take a low-res photo, which is copied from the OpenGL context to a multi-dimensional array and parsed to determine how much of the soap is over a platform and update its polar coordinates accordingly. I use array programming extensively to update the positions of the soap and the camera.

### Why Odin

I discovered Odin through my research into Data Oriented Programming. This is the 3rd game I've programmed in Odin. What I like about Odin is how a lot of the tedious work you had to do manually in C is delegated to the compiler or built into the language—there's no need for function declarations, no need to worry about the order of definitions, no need to name all the source files and all the libraries as arguments to the build command. A great example of this is the explicit procedure overloading: you can refer to a set of procedures by the same name and the compiler can determine which one you wanted to call by the arguments you provided, or panic otherwise.

One weakness is that much of the standard library is missing human-language descriptions of what procedures do and examples of how to use them, but they are quite sensibly named and whatever you can't infer from the type schema and the name, you can find out from reading the source code and Odin code is quite readable.

### Testing

I used the `testing` package to write a simple procedure to benchmark the game's performance. In just 5 lines of code I would read the best bench from disk, test for statistically-significant improvement from best bench to current bench, write the better bench to disk, and log the results.
Binary file added static/images/news/2024-04-nefrace1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/news/2024-04-nefrace2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/news/2024-04-nikio001.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/news/awesome-odin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit fa0c713

Please sign in to comment.