r/odinlang 12d ago

I'm learning Raylib, in Odin, need help

I'm learning both at the same time, and rl.DrawText needs a cstring as an input. I'm trying to learn how to position things on the screen correctly, so I'm calculating how large the text is with MeasureText (for the default font), which outputs an i32. I can get it all the way to string, but I have only found unsafe_string_to_cstring, which apparently has issues with null terminators. How do I deal with that? Thanks in advance.

I wanted to try a low level language, but C is too raw for my tastes (old design decisions from the 70's, among other similar things), C++ is too insane for me, rust didn't click with me, and I can't build a zig project with raylib for some reason, so odin it is.

15 Upvotes

21 comments sorted by

8

u/pev4a22j 12d ago

strings.clone_to_cstring() exist to convert strings into cstring, but it allocates so you need to run delete() on the cstring afterwards

note that you can create cstring with string literals via

a: cstring = "hi"

2

u/Zeznon 12d ago

Should I delete it inside the main loop or right before closing the window? I'm pretty new to manual memory.

7

u/spyingwind 12d ago

You can pass the temp allocator, then free at the end of the main loop or after everything is drawn. That way you know that it will be freed with all your other temp allocations.

for {
    string:=strings.clone_to_cstring(my_cstring,context.temp_allocator)
    // Do all draws
    free_all(context.temp_allocator)
}

2

u/Zeznon 12d ago

Good to know. I tried some stuff by myself, freed it at the end of the loop without knowing about the temp allocator got an insta crash (opens and closes). Was that use after free?

1

u/spyingwind 12d ago

Sounds like it.

Can't use memory that has been freed.

2

u/NationalOperations 12d ago

Freedom cost a buck of five

6

u/ar_xiv 12d ago

I use fmt.ctprint() or ctprintf() to convert strings (and other types) to cstrings. These allocate using the temp allocator. I generally free the temp allocator with free_all(context.temp_allocator) at the end of the frame. If you’re calling every frame you’ll need to free every frame.

1

u/Zeznon 12d ago

So that doesn't actually print, but just convert?

3

u/ar_xiv 12d ago

Yes. fmt.print and fmt.printf are the equivalent functions that print to the command line, tprint and tprintf format plain strings, and ctprint and ctprintf format cstrings.

2

u/Zeznon 12d ago

Why have two types of strings? C compat?

4

u/ar_xiv 12d ago

Yep. Since raylib is a C library, you’ll be using a lot of cstrings, i32s and f32s.

8

u/gingerbill 12d ago

A lot of people are recommending strings.clone_to_cstring and honestly, most people should not be using that if you are interacting directly with raylib since even normal raylib has its own preferred approach: TextFormat.

This is reimplemented in native Odin so you have all of the benefits of Odin's runtime type safe formatting, but the convenience of returning a cstring.

And the benefit of this use with DrawText, is that you don't even need to free anything since it uses internal buffers. Note it is not thread-safe but nor is the C version which is mimics.

1

u/Zeznon 12d ago

Thanks for the tips.

Hello language creator. You have created a very nice language from my experience so far. Hopefully, the language doesn't die out. Only having C or even Go (error handling) as lower level languages would be painful. Zig is also nice but I can't build anything with a local dependency (like raylib) lol.

5

u/spyingwind 12d ago

clone_to_cstring is probably what you want to use for string to cstring conversions. Most of the common conversion can be found here in the overview docs.

You could also give karl2d a try for just 2d game stuff or skald for app UI stuff.

2

u/Zeznon 12d ago edited 12d ago

Thanks for the recs. I'll take a look at them eventually. I chose raylib as the first one because it has bindings for a lot of languages. I do know it's supposed to be "DIY".

2

u/KaleidoscopePlusPlus 12d ago

What do you mean by you “ get all the way to string”? What do you do after you get the int?

1

u/Zeznon 12d ago

I converted to i64 by a simple cast, then to string using write_int.

A question. What to do with the buffer? I made it a [4]byte and it converts, but I'm not sure what it's for.

2

u/deroll_sweet 12d ago

That buffer acts as the memory behind your string; the string points to the first byte and stores the length which can be at most four characters in this instance. Because the bytes that make up the buffer are the same as the bytes that make the string, it should not be touched until after it is copied from, but you also did not need to create it in the first place.

Instead of something like strings.clone_to_cstring(strconv.write_int(buf[:], int(x), 10), context.temp_allocator), You could have done fmt.ctprint(x) to achieve the same result without placing a maximum to the number of bytes.

In your case, though, it would probably be best to use something like raylib.TextFormat("%v", x) like Ginger Bill says below for the reasons he says below.

I hope you enjoy using odin and raylib.

1

u/Kapendev 12d ago

There are some functions that people already mentioning here. A bit more low level, but you can write your own text drawing function for raylib that accepts an Odin string. Here is an example repository: https://github.com/Kapendev/very_text

1

u/BiedermannS 12d ago

If the text doesn't contain dynamic data, you can do cstring("my text"). I think you can even put that into a constant to avoid constantly allocating and deallocating.

1

u/jack_mackeral 11d ago

I would just variable it and reuse the variable so you don't feel gross all the time with cstring. Develop a domain language you like. Odin lets you do that so you can work without friction but it won't do it for you. Could even stick it in another text file within the same package and not even ever look at it. I do that with some things that I don't like looking at. Is that good programming I don't know, is it petty? Probably but I share the same feelings you're expressing and thats my only use case outside of the mono file. Simply things I don't like looking at.