Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411511 Posts in 69375 Topics- by 58430 Members - Latest Member: Jesse Webb

April 26, 2024, 02:25:42 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)What are you programming RIGHT NOW?
Pages: 1 ... 69 70 [71]
Print
Author Topic: What are you programming RIGHT NOW?  (Read 210157 times)
flárátt ljós
Level 0
*


View Profile
« Reply #1400 on: April 08, 2021, 07:46:35 AM »

Spent a week ripping out the FBX SDK from my art pipeline and writing a Blender exporter script that writes directly in the binary format used by the game. Absolutely nothing changed visually but exports are no longer choking on large (over 1 million poly) meshes and it's one less external dependency with code outside my control.
Logged
ThemsAllTook
Administrator
Level 10
******



View Profile WWW
« Reply #1401 on: April 08, 2021, 08:54:43 AM »

Neat! I wrote an export script like that a while back, but it broke in Blender 2.80. Performance wasn't great in my case for objects of a lot less than a million faces... Were you able to get the Python API to handle that much data in a reasonable amount of time, or did you find some other route that lets you work in a more efficient language?
Logged

flárátt ljós
Level 0
*


View Profile
« Reply #1402 on: April 08, 2021, 09:33:18 AM »

The naive implementation is reasonably fast. I'm looping through all the vertices, appending their binary representation (8 floats, consisting of their position, normal and UV coordinates) to a bytearray and then writing that into the file. If it's a skinned mesh, each vertex will additionally contain 4 bone weights and indices. It's actually slower to export animations than it is to export hipoly meshes. It's still reasonably fast for my current use case, i.e. it takes a couple of seconds to export a total of 372 animation frames of 72 bones across 10 different animations, but it feels like that's slower than it should be. In any case, I'm sure it's faster than any of the built-in exporters.
Logged
flárátt ljós
Level 0
*


View Profile
« Reply #1403 on: April 22, 2021, 07:57:16 AM »

I needed to do some repetitive work in Blender today to build the collision geometry for this scene, but since I recently had to use the Python API to write an exporter, I figured I could automate it instead. I wrote a script that goes through each selected object and creates them a decimated parent with a rigid body attached. Here's the scene and what the resulting simplified collision model ended up looking like.



« Last Edit: April 22, 2021, 01:40:36 PM by fláráðr ljós » Logged
flárátt ljós
Level 0
*


View Profile
« Reply #1404 on: April 22, 2021, 08:23:01 AM »

I went back and made some changes to my HTTP server. There was an issue where the server would occasionally stop responding to connections. The server would still be running, but a quick look at the open sockets with lsof -i tcp:80 would reveal that some connections weren't being properly closed.

As you might notice that they are all in the FIN_WAIT2 state. What does this mean? We had closed the send side of the connection by calling shutdown(client, SHUT_WR), but this doesn't necessarily terminate the connection. The connection isn't closed until the other side is done with the connection as well. Some clients never do this, so the proper way to terminate the connection is to close() it instead. I also spent some time adding support for URL encoded filenames.
« Last Edit: April 22, 2021, 01:40:50 PM by fláráðr ljós » Logged
flárátt ljós
Level 0
*


View Profile
« Reply #1405 on: April 22, 2021, 02:38:45 PM »

People were letting me know that they were having trouble loading my images on certain browsers. These browsers block mixed content by default, which means that they refuse to load images over an insecure connection if the website itself was loaded over a secure connection. This meant spending rest of the day adding HTTPS support to the web server. Pretty straightforward, but I dislike having a gigantic dependency to OpenSSL in order to accomplish this.
Logged
ThemsAllTook
Administrator
Level 10
******



View Profile WWW
« Reply #1406 on: June 27, 2021, 09:14:58 AM »

I'm on a little programming journey right now that's taken me to some surprising places.

Where I started: I need to make some sound effects and music for my current game project.

Where I am today: Reading about why I should be calling pselect() instead of select() to sleep my event loop if I'm interrupting it with a signal handler, and implementing some extensions to my API for thread synchronization.

How I got from A to B:

• For a project I made several years ago, I used a port of sfxr made by a friend of mine, which only runs on Mac OS. I saved the parameter files from each effect so I could reimport and modify them in the same tool, and exported the result as Ogg Vorbis so I could load and play it in the game. So far so good.

• On my next project, the tool written by my friend didn't work as well anymore due to operating system updates breaking things. sfxr also had a lot of limitations. I switched to bfxr, which has a few more synthesis parameters and worked a little bit better overall, and kept doing pretty much the same thing.

• For unrelated reasons, I switched to Linux as my primary operating system, making it very inconvenient to have a Mac-only program anywhere in my workflow. Even if I was OK with getting out my old Mac in any event where I needed to re-export my sfxr audio files, there was the looming threat of losing access to the tool due to events outside my control, or at least having it become so inconvenient as to be impractical. I had similar longevity concerns about bfxr, and both tools had some data integrity problems causing me to lose some of my work. Not great.

• Conveniently, sfxr and bfxr are both open source, so I was able to take their audio synthesis functions and combine them together into a single utility program of my own making (porting the relevant parts of bfxr from ActionScript to C in the process), which builds and runs in all the same places as the games that use its output. Longevity problem solved, and any remaining data integrity problems could only be of my own making.

• Now that I have full control of my audio synthesis, I can start extending its capability to fit my needs that weren't fulfilled by sfxr and bfxr. I implemented a music sequencer in the tool which can use synthesized sounds as its instruments and composite them into a full song.

• While editing the synthesizer parameters of an instrument, I had the thought that it would be nice if I could update my waveform view live so I could see exactly what was happening to the output while dragging sliders. Resynthesizing the sample while dragging worked OK in some places, but the performance wasn't sufficient for longer ones to be done in real time. OK, I guess I need to spin synthesis off into a secondary thread so that the UI can keep updating while it works on the ones that take a bit too long. I'll signal to the synth thread that there's work to do when a parameter change is made, and then display its result whenever it signals back to me that it's done.

• Signaling to the thread is relatively straightforward - when I spawn it, it immediately blocks on a semaphore which I can post to whenever I want to request that it run the synthesis function. Once it's done with its work, however, I realized I didn't have a good mechanism for waking up the main thread with the notification that the waveform can be redisplayed. I added a new API function to my thread abstraction library to queue up a callback to be invoked from the main thread when it returns to the main event loop.

• This function need a platform-specific implementation for each system my framework supports, so I went off to write the Linux version of it first. The way my run loop works right now is that if there are no events pending or timers running, it sleeps until something it needs to know about happens. This was done with a call to select() on the socket used by X11 for event handling. A quick web search warned me away from trying to just post an XEvent from a secondary thread, so I needed a different communication mechanism that would be thread-safe.

• After some basic research, I ended up at this Stack Overflow post which discusses more or less what I'm trying to do. I read the select() man page to try to understand better how it works so that I could interrupt it from another thread, and somehow ended up at this article about pselect() and how it could be used to wait for both a file descriptor and a signal at the same time. Seems like what I want.

Then the slight absurdity of what I was doing hit me, and I went off to write this forum post to organize my thoughts and make sure it still seemed like what I was doing made sense. I haven't fully verified yet that using a signal to interrupt pselect() will work for my purposes, but so far it looks like the thing that I need.

This whole process of digging all the way down to the bottom of what I need to know to solve a particular problem is always really satisfying. Even though it takes a while, I learn a lot, and understanding all of the nuances gives me confidence in the final implementation and the knowledge necessary to fix it when things go wrong. This kind of stuff is totally my jam.
Logged

oahda
Level 10
*****



View Profile
« Reply #1407 on: June 27, 2021, 12:46:13 PM »

While I don't understand the specifics of what you're doing, I know the feeling! Hope it works out Smiley
Logged

els
Level 0
**


View Profile
« Reply #1408 on: August 29, 2021, 01:40:19 PM »

I just removed my attempt at more accurate texture mapping again because I got frustrated figuring out how to do it right. While I think I got the concept, I couldn't really figure out if the depth factor is meant to be clip plane distance or camera center distance, and other details, while getting all the more just-slightly-wrong results. Oof...
Logged

just a coding gal
ThemsAllTook
Administrator
Level 10
******



View Profile WWW
« Reply #1409 on: October 19, 2021, 09:29:56 AM »

I had a prickly little arithmetic problem that I was working on the other day...

I'm writing an audio synthesis tool, and I needed to combine together multiple waveforms in a few different ways. I have a function that can take an arbitrary number of waveforms and take the average, sum, minimum, maximum, or multiplication of them. A simple sum for one sample would look something like this:

Code:
// sum
float result = 0.0f;
for (unsigned int waveIndex = 0; waveIndex < waveCount; waveIndex++) {
    result += waveSamples[waveIndex];
}

Average looks the same, with a division by waveformCount at the end. Multiplication looks pretty similar, with a different operator in the middle. I initialize result with the first sample so that I'm not multiplying everything that comes after by 0:

Code:
// multiply
float result = waveSamples[0];
for (unsigned int waveIndex = 1; waveIndex < waveCount; waveIndex++) {
    result *= waveSamples[waveIndex];
}

Min and max work as you'd expect:

Code:
// min
float result = waveSamples[0];
for (unsigned int waveIndex = 1; waveIndex < waveCount; waveIndex++) {
    result = fminf(result, waveSamples[waveIndex]);
}

// max
float result = waveSamples[0];
for (unsigned int waveIndex = 1; waveIndex < waveCount; waveIndex++) {
    result = fmaxf(result, waveSamples[waveIndex]);
}

Next, I wanted to be able to separately adjust the influence of each waveform in the output, with a continuous value from 0 to 1. For sum and average, this is as simple as adding a multiplication (and summing the weights for the average divisor instead of dividing by waveCount):

Code:
// sum with influence
float result = 0.0f;
for (unsigned int waveIndex = 0; waveIndex < waveCount; waveIndex++) {
    result += waveSamples[waveIndex] * waveInfluence[waveIndex];
}

For multiplication, min, and max, though, it's not quite as simple. This code is incorrect:

Code:
// multiplication with influence applied incorrectly
float result = waveSamples[0] * waveInfluence[0];
for (unsigned int waveIndex = 1; waveIndex < waveCount; waveIndex++) {
    result *= waveSamples[waveIndex] * waveInfluence[waveIndex];
}

What I want is for an influence value of 0 to be as if the waveform isn't included in the list, rather than for it to scale down the operand, which in the case of multiplication would cause everything to be multiplied by 0, erasing all the other parts of the result. Values between 0 and 1 should linearly interpolate between these two states. This is better, but still not quite right:

Code:
// multiplication with influence applied semi-correctly
float result = waveSamples[0] * waveInfluence[0];
for (unsigned int waveIndex = 1; waveIndex < waveCount; waveIndex++) {
    result = result * (1.0f - waveInfluence[waveIndex]) +
             result * waveSamples[waveIndex] * waveInfluence[waveIndex];
}

This is now using an interpolation to only affect the result in each step by an amount proportional to the influence value. The problem is, it's order dependent: As long as the first influence value is 1, everything works, but drop that to 0 and once again all of the results get erased.

So, here's what I have now:

Code:
// multiplication with influence applied correctly???
float lastInfluence = waveInfluence[0];
float result = waveSamples[0] * lastInfluence;
for (unsigned int waveIndex = 1; waveIndex < waveCount; waveIndex++) {
    result = result * (1.0f - waveInfluence[waveIndex]) +
             result * waveSamples[waveIndex] * waveInfluence[waveIndex] +
             waveSamples[waveIndex] * waveInfluence[waveIndex] * (1.0f - lastInfluence);
    lastInfluence = fmaxf(lastInfluence, waveInfluence[waveIndex]);
}

It now does a 3-component interpolation, between previous result, result multiplied with the new sample, and the new sample by itself, weighted by the maximum of the previously encountered influence values. Min and max work the exact same way, with a different operator replacing the multiplication of result and the new sample. As far as I can tell, this works, but taking the max encountered influence seems kind of dodgy - I feel like it could have incorrect results in some cases where multiple early influence values are less than 1, but I haven't so far identified a case where my result looks wrong. It's hard enough to wrap my head around it that I can't be sure either way. Seems to be close enough for what I need, at least!
Logged

Guntha
Level 0
***


View Profile WWW
« Reply #1410 on: May 21, 2022, 03:47:33 PM »

Today I wrapped up a first version of a tool to build versions of my games.

First it updates the working copy of the game from the version control server (in my case SVN), or it does a full checkout to make sure I have a "clean" working copy.
Then it rebuilds the code (currently using MSBuild, since I've been using only Visual Studio for a while to work on them, so I'm sure I'll get the exact same result as when compiling from the IDE. And my games are Windows-only for now. This might change if I change my workflow later.)
Then it create a zip file containing everything required to run the game.

There are a few things I want to add, notably a "baking" step before the zipping step, to bake assets that are not part of the repository (and quick enough to build to be able to afford to re-bake them every time), and also a "local" build mode, that doesn't rely at all on version control to work.

It's written in "C/C++" (a mostly procedural usage of C++), I use the SVN API for all my version-control stuff (my builder assumes you have TortoiseSVN installed and links to its DLLs), minizip for the final zip file creation, rapidjson (the config files are written in json, which is my go-to format for this kind of stuff ^^'), and some things straight from my games' engine's code (string/path manipulation, reading/writing files, creating directories...)

I plan to release a compilation with all my jam games (along with an "up-to-date" version for each game, so I would need to automatically build like 10 games anytime I want to release an update), this will be very useful to avoid mistakes when packaging builds Smiley (It would already be very useful for single games ^^')
Logged

Pages: 1 ... 69 70 [71]
Print
Jump to:  

Theme orange-lt created by panic