December 24th, 2011
I realized yesterday that the last log page had been going on for six months and contained more than half of all the screenshots from the project, so it was probably time to start a new page. So here we go. I'm working on bugfixing.
got hex at -4, 3; render space: -180.00, 0.00, 52.00
got hex at -5, 4; render space: -225.00, 0.00, 78.00
got hex at -6, 4; render space: -270.00, 0.00, 52.00
got hex at -7, 5; render space: -315.00, 0.00, 78.00
got hex at -8, 5; render space: -360.00, 0.00, 52.00
got hex at 8, -3; render space: 574740.00, 0.00, -610220.00
got hex that didn't intersect with line at all :/ (the 6-th)
Yeah, that would do it. Now to figure out why distances are being calculated like that.
Long and tedious story short, I'm bad at geometry. I wrote a rather slapdash piece of code that properly calculates the distance between two arbitrary hexes, but it still doesn't work in some pretty major cases (crossing world poles) and is, sadly, unrelated to another coordinate math issue that's been causing problems. But it's one thing down.
Much shorter story: I think the out-of-bounds errors I was getting for certain arches was caused entirely by a "generate a random position" function that didn't check if it caused out of bounds coordinates, so having fixed that I think that should be the last of that particular problem. What's still left: half-imprinted arches.
December 26th, 2011
Actually solving problems is hard, so I spent a few days working on fiddly things like making the memory debugging code slightly less incredibly inefficient.
Plus, I figured that it would be pointless to get all this picking/map loading stuff working if I had to change it all up again once I added something else, so I decided to work on parts of that something else.
It's been MY DREAM to make the hexes less regular for a long time. I kind of want to mimic Dungeon Keeper 2 with this — more "natural" terrain is less regular, but if you go and build walls they're going to be more rigid and regular. More generally, material types would have a jitter percentage that would determine how off from true their vertices are, and there would be some kind of math done over the three component hexes that each vertex touches. There also might be an... attenuation value, that would make the vertical pillars curve inward or bulge outward, and that would also require fiddly path over the adjacent hexes to get right. Right now there's just jitter.
The jitter is based on the seed of the world and it's the same for each platter, since I didn't really want to have to generate a few hundred vectors for each platter and then have to stitch them together across platter edges. Right now it's kind of noticable that it's a repeating pattern, because the platter edges are still jagged and every platter has the same highlight pattern, but hopefully when the terrain starts looking a little more varied it'll be less obvious.
You can kick up the jitter until the hexagons totally decohere, and it really doesn't take very long for that to happen. The big issue is that the jitter has to be small enough so that it's never possible for the hexagons to become concave, because that could mess up all kinds of things while rendering. Well, "could", but since I don't know a thing about rendering all I know is the OpenGL spec says rendering concave polygons in a single rendering object invokes undefined behavior.
This vertex variation makes a lot of things depend less on the abstract geometry of a hexagonal grid and more on the specific hexagons you're standing on— this is why I wanted to do this before fixing the "what hex am I on" code, since obviously it's no longer valid to use the old algorithm at all. Sadly I have not actually gotten around to that.
Really, what I wanna do now is add some more materials and have an arch or two that affects the world actively in some way. We'll see how that goes; there's an ever-growing pile of bugs to fix and weird behavior to alter.
December 28th, 2011
So I got picking more working — it does actual collision tests against the hex surfaces now — so it's now reasonably accurate at calculating the hex your cursor is pointed at. The remaining issues fall into two types: the hex the player is standing on is calculated incorrectly, leading to absolute failure, the difference between a regular hexagon and the irregular hexagons actually drawn leads to the wrong hex being picked. There are also some currently purely hypothetical problems: the hex surface collision test is done with a plane test against a flat regular hexagon, so if the hex surface is sloped the picking will be wrong. Also, there's no calculation done against hex walls at all, so looking at those tends to make the ray pass through a bunch of hexes until it finally intersects with a hex surface. So that's bad. But even will all those issues it's still pretty generally useful. I'm going to start working on blueprints, I think, now that I could hypothetically place them.
Oh yeah, and there was a problem with picking working wrong on hexes with elevation, but I fixed it and now that works right. Which is good, because in the near future all hexes are going to have some elevation.
Also I made hex materials a bit more useful and started using them. I got really tired of everything being grey, although now everything is weirdly pastel and I'm not sure how much better that is.
Why didn't I start messing around with landscapes made with multiple materials before this? Ugh. So much wasted time!
Sadly before I can really get into that, I've gotta fix the old huge having to do with hidden surface removal, because, well. Because rendering is hugely inefficient already; I don't need a billion extra hidden surfaces being rendered in every frame to make things even slower than before.
Okay, so that fixes that longstanding bug. The code that does this, though... let's just say "it's inefficient" and leave it at that. I keep planning on rewriting the rendering code using modern, fully-supported OpenGL code (evidently the style of rendering I'm using right now is so old and deprecated it is not actually supported on many video architectures, so making it more modern will make it more portable) and with this latest addition to the rendering code, well. I'd like to do that if only so I can stop recalculating all this stuff every frame.
This code might break when it comes to rendering sloped hexes, although it shouldn't, and it will probably break when rendering floating hexes. I haven't had any of either to test against, so it's hard to work out.
As a final note for tonight, I got the picking code to always start with the right hex, so there are no longer any weird picking failures. This doesn't mean picking is working quite right yet; there's still the issue of resolving which surface on a hex is hit. But still, it's a step forward, especially since as of this morning, well, scroll up. Things were substantially less useful.
December 29th, 2011
So I put together a few parts of the pattern code — I still have mostly no idea how it's going to work — but then I figured I should probably figure out why certain arches aren't imprinted correctly in certain locations. I had thought it was due to platter lookup failing, but a little poking around revealed that the issue was in the distance metric code — the arch wasn't getting imprinted correctly because the distance check was saying platters in certain configurations were much further away than they actually were.
This is weird, because the same distance metric is being used to calculate actual render coordinates, and given that visually the platters line up correctly it ought to follow that their distances are calculating correctly, too.
In the process of trying to figure out what's up, I generated multiple terrifying broken worlds. Here's one of them. The huge pit is the platters where the distance metric was messed up; the height is based on proximity to the centre of the arch, so it ought to be a steady slope down in all directions.
December 30th, 2011
0: 1, 0 0, 1 -1, 1 -1, 0 0, -1 1, -1.
1: 9, 8 -8, 17 -17, 9 -9, -8 8, -17 17, -9.
2: 9, 8 -8, 17 -17, 9 -9, -8 8, -17 17, -9.
3: -174, 641 -641, 467 -467, -174 174, -641 641, -467 467, 174.
It would take a while to explain exactly what this means so let's just say "you see how the numbers are repeated for lines one and two? That's what's wrong". (I also have no clue if the third line's numbers are correct, but I'll work that out afterwards.)
Sadly, out of curiousity I made it calculate 4+ and the results are not promising:
4: -22893, 21821 -21821, -1072 1072, -22893 22893, -21821 21821, 1072 -1072, 22893.
5: -22893, 21821 -21821, -1072 1072, -22893 22893, -21821 21821, 1072 -1072, 22893.
6: -22893, 21821 -21821, -1072 1072, -22893 22893, -21821 21821, 1072 -1072, 22893.
7: -22893, 21821 -21821, -1072 1072, -22893 22893, -21821 21821, 1072 -1072, 22893.
At least all this is confined to a single function. But it's a very important function and it's written in a very convoluted way, so I think I might just entirely rewrite it rather than figure out how to fix the broken part (which has to do with loop value initialization)
0: 1, 0 1, 0 0, 1 0, 1 -1, 1 -1, 1.
1: 9, 8 -8, 17 -17, 9 -9, -8 8, -17 17, -9.
2: -174, 641 -641, 467 -467, -174 174, -641 641, -467 467, 174.
3: -22893, 21821 -21821, -1072 1072, -22893 22893, -21821 21821, 1072 -1072, 22893.
4: -949023, 182834 -182834, -766189 766189, -949023 949023, -182834 182834, 766189 -766189, 949023.
Well, this at least looks more accurate, although I have no idea if it's actually right. The increase seems a little steep. Only one way to find out!
I'm going with "no".
But then, yes! Not that it really means anything, but the accurate scaling in this case is as follows:
0: 1, 0 1, 0 0, 1 0, 1 -1, 1 -1, 1.
1: 9, 8 -8, 17 -17, 9 -9, -8 8, -17 17, -9.
2: 17, 208 -208, 225 -225, 17 -17, -208 208, -225 225, -17.
3: -1511, 3672 -3672, 2161 -2161, -1511 1511, -3672 3672, -2161 2161, 1511.
and it uses a very simple formula to calculate. The function is shorter, a lot more legible, and has fewer branches. All-in-all: success! However... this seems to have broken picking. For some reason.
This is confusing, but hopefully just looking at the picking code should make it obvious what's up. I hope.
Oh, it was my own dumb fault as usual. The new scaling code set the row-zero values incorrectly, and those values were used by the picking code, so it messed up. It's all fixed now, and fixing that part of the function let me shave another ten lines or so off. The old function was 97 lines; the new function is 49 lines. Much better.
Things to hopefully accomplish today: a pattern structure that's used for something, because once that's in place I can start thinking about how the simulation/generation thing is really gonna go. Also then I get to add things to the game instead of fiddle around with system code forever.
January 4th, 2012
Happy new year! Belatedly. I spent a lot of time playing Terraria and not doing anything productive. This trend hasn't really been broken.
I spent some time updating the font code to use the freetype2 code I wrote for one of my monthly projects instead of my own homespun bitmap rendering, because let's face it, that was a really ugly font. This also gave me a chance to fix one of the rendering issues with the new font code, namely that the text would alias at the edges in a really ugly way due to the way I was copying the glyph data over — I'm using a luminance/alpha texture for the letters, and previously I was fading both out at the edges, which meant all the partially-transparent antialiased pixels were correspondingly dark. With the luminance set to 0xff constantly, the color is correct. This makes a surprisingly large difference in the appearance of the glyphs, even on a dark background. They look so much better.
Anyway, my priority list hasn't changed since last update: get patterns working, get blueprints existing, work on the simulation/generation aspect of the patterns.
Oh yeah, and I changed the skybox to be one flat color; I got really tired of the garish colors now that the landscape looks vaguely "realistic".
January 6th, 2012
Okay, so, I took the first steps down the path of actually using pattern data to determine how arches work. Firstly, okay, there are a lot of issues with the way my hex column code works — all the code is pretty much filler that barely does anything — and there are still no decent hex manipulation functions. This is part of why I've mostly been using flat hexes of one type, because while the data structure and rendering code supports a lot more complex shapes than that there's just no decent way to set that data.
That's not in any way meant to understate just how buggy the code is, though. It's real buggy. This is what the world looks like when you are inexplicably walking around underneath it! There's some kind of issue dealing with the fakey terrain-following; sometimes when a hex column has multiple steps the wrong one is used to calculate the height. So in this case the one that was used was the one set at 0 when the actual surface was at 127 or something.
I also finally got around to checking to see if floating hexes work. They, uh. Don't. More specifically there were three issues, all with the same root cause: when there's an air step, it's treated in many ways as an opaque block even though all its polygons are drawn as entirely transparent. So, it had edge walls drawn, and it didn't draw the surface of the step below it, and it didn't draw the underside of the surface of the step above it (if it exists)
This caused some interesting-looking bugs though.
Anyway, fixed it. I realize that this hidden surface removal isn't super complex but I'm still proud that it works, because for a long time all my rendering code would have drawn this scene as a huge mess of hidden surfaces.
Sadly I did not actually get around to making patterns pattern; I need to make some decisions about the nature of the world and the way data is stored before I can move on to the more interesting parts. Thankfully those decisions are easy to make, but still, I do have to write up a bunch of code and test it and all that.
January 7th, 2012
And so instead of working on patterns I immediately get to work making the hidden surface removal work better. Before, it had worked properly only in very trivial cases, and making slightly more complex hex configurations turned things into a nightmare of missing walls open the void or dense lattices of drawn hidden surfaces.
Now it's finally at a point where it handles all the standard cases properly, which means I have a slightly increased capacity to just throw geometry down and trust it'll render right (and thus that any weirdness is a result of the generation code, not the rendering code)
This is also the point where I start to worry about hidden volumes. So here only the surfaces exposed to air are drawn, but it ignores that there are two distinct volumes of air here: one is the overworld that goes on infinitely (well, unboundedly) and contains all the surface hexes, and the other is a small underground pocket that contains the undersides and walls of some surface hexes as well as some underground hexes, and when you are in either one it's never possible to see anything that's being rendered in the other.
This is a much trickier problem to solve than just removing hidden surfaces, and it requires a very different solution — if you want to check if any part of a hex is exposed to air all that requires is checking its immediate surroundings, but if you want to check if a hex is visible to the player, that requires... other things. I have no clue if it's going to be worthwhile to code up a system to cull hexes in separate volumes from the player, and it's really complex, and there are more important things to be doing, so right now I'm not even going to bother. Time to work on patterns!
Maybe I spoke too soon.
OKAY.
TIME TO WORK ON PATTERNS.
Patterns so far: not very interesting! All you can really do is affect height (add height, remove height, set the height to slope in a few ways, etc) and change the material type, and you can only affect things in a perfect circle and you can't spawn subpatterns. Still no sloping hexes — as it turns out that's a little more complex than I'd thought, given the way platters have their pattern stuff imprinted. But there's something there at least; pattern data is being read from the patterns file and put to use, even if in the most faltering possible ways.
Also it's finally a chance to start messing around with hex editing. My current hex editing code is awful, and it's a chore to do anything, but that's partly because I've never had to edit hexes in a large-scale fashion before. Now that I'm finally getting around to doing it I'm sure some things will come to me.
One of the big things that's occuring to me is how useful it would be to be able to specify some kind of equation, volumetric or flat, and then be able to alter any hexes where the equation density is above (or below) a certain value. Problem: I would have to write code that would parse those equations, and honestly I am not even really sure what a volumetric field equation looks like.
Even without some complex volumetric shape definition, though, there would be a huge benefit of simply having shapes other than circles, most specifically straight lines or rectangles between two patterns. One of the big conceptual things for the game is that patterns can be linked together and that linkage itself can have a pattern attached, so that you could do things like make a road between two points.
I don't really know how to do any of that right now, but now that I've conclusively hit the stage of development where I'm actually making content it's in my best interest to just throw as much geometry code into the pattern definitions as possible, since the more flexible the patterns are the more interesting things can be done with them.
January 8th, 2012
After the excitement of yesterday, today was kind of boring. I want to get some more complex shapes to work with for patterns, so I decided to start down that path by getting plants working again — they use l-systems and turtle drawing to do their thing, and both of those could be really useful general world-constructing tools.
Currently plants aren't much to look at — they draw in the same way they've always drawn (which is bad from both a visuals standpoint and a technical standpoint), and they have the same problem of ultimately becoming gigantic and monstrously fractal in appearance. I have plans to solve that, and to make them render in a way that fits with the general aesthetic I have going so far, but that'll have to wait for tomorrow.
Oh, and in the process of writing the plant component I messed with the position code to make it sufficiently general to be used by a component that really doesn't know anything about a position aside from it has one, which is good. We'll see how well that goes when I have to write a few more components.
January 12th, 2012
OH RIGHT. I've still been working on this — kind of — but I haven't been doing anything particuarly interesting or useful (by which I mean, patterns) so I haven't really felt moved to write an update log.
Firstly I decided to see if I could rewrite some of the font code to use "modern" OpenGL — as mentioned previously, I think, I've been doing all the rendering in immediate mode and that works really, really badly on some architectures and cards. This has required a lot of reading manuals and getting in completely over my head and the short answer to "is it drawing in a modern fashion now?" is "no". All the manuals I've found so far are either technical documentation or they spend five pages explaining GLSL (which I don't really care about right this moment) while never mentioning how to use textures with vertex arrays, or even the difference between vertex arrays and element arrays and aaah.
What I did manage to do is rewrite the font code to generate a single texture per font, instead of generating a separate texture for each glyph. This means I can draw lines without changing the bound texture, which I assume has some benefit for rendering, but honestly I have no clue and in all likelihood that was not a bottleneck in the first place.
So that wasn't very useful but it was fairly productive, I guess. I still want to figure out how to use all this fancy modern OpenGL but I'm suspecting I won't be able to do that unless I start using one of those "draw a triangle" demos from the ground up.
After that I decided to try to do something marginally more practical, which is to cache a bunch of rendering calculations. Once again, I don't actually know if this is a substantial bottleneck (probably not) but given that currently all the calculations are redone for every hex, every frame, I'm pretty sure it's significant at least. More importantly, this same information has to be used for collision-detecting and picking, so there are some real, concrete benefits to storing this data.
Let's just say that it's still a work in progress as I write this. I fixed all the issues I was aware of as to hidden surface removal, and I tested it by generating a fairly noisy landscape, which all worked fine (eventually) but then I tried adding hex slope and everything broke. This isn't very surprising; I haven't ever tried using sloped tiles with this latest map-drawing code, I think, so it's all very untested.
Oh this looks perfect, guess it was easier to fix than I had thought, let me just turn the floating hexes back on to see if those are all right too —
oh
hmmmm
Rather annoyingly, I iron out those issues but fail to fix the case of when there are multiple adjacent hex steps stacked vertically. Part of it is that I'm not really sure how that should be handled — I can generate a continuous surface geometry but use multiple polygons to do so (well, I theoretically could; in practice I'm not getting the math right), or generate a geometry with hidden surfaces but use only one polygon. And given that this information is going to be used for picking and collision, I'm not which (or any) option is the right thing to do.
So then I decided to get arch expansion working. "Working"; there's a very distinct limit to how useful expansion is going to be until I get shapes and sizes parsing correctly. Right now all patterns are the same size and shape (circle eight hexes in radius) so while subpatterns ought to be smaller and contained within the hull of their parent pattern (hence subpattern) currently they're the same size and scattered randomly around roughly close to the original pattern. Still, it gives me a slightly less boring environment and gives me some obvious features to add in.
January 13th, 2012
Pattern shapes and sizes work! Not in any particularly useful way, again, but it's something. This opens up the next issue, which is getting subpatterns to generate only within their parent pattern. Currently there's no good way to do it aside from making a vague guess, comparing it to the distance metric, and then throwing out the position if it's not. This is exactly the kind of thing I want to avoid in the world generation step (generating arbitrary data and then throwing it out unless it fits right) so I'm going to try and get a more useful "generate position within the bounds of [x] shape" function working.
This shot also exhibits another distance-calculation bug, hopefully one of the last of its time: the dirt circle to the left is sliced off at a platter boundary. This is because this particular spawn is at the very, very edge of a pole; it's effectively straddling the equator. Distance calculations are still messed up here, because the poles are the highest-level platters and they connect to each other across multiple edges: given any two coordinates on different platters there are three different accurate distance metrics that can be calculated, depending on which pole edge the distance is calculated across. Right now the distance code uses only one of them, and usually this doesn't matter, but it's more and more inaccurate the further from the edge that's being checked the distance is, and this is basically the degenerate case: the hexes on either side of the pole line are considered roughly two poles away from each other, even though they're actually adjacent. This causes issues with pattern imprinting, with picking, and even in a weird way with rendering. So that's also on the list of things to fix.
January 14th, 2012
Fixed the distance metric. Now pole-crossing should be seamless in all cases. Now imprinting, picking, and calculating render-space coordinates all work across poles. Hooray.
distance of render platter 0: 0.00, 0.00, 0.00
distance of render platter 1: 405.00, 0.00, 650.00
distance of render platter 2: -360.00, 0.00, 676.00
distance of render platter 3: -765.00, 0.00, 26.00
distance of render platter 4: 9720.00, 0.00, 4316.00
distance of render platter 5: -9000.00, 0.00, 5616.00
I also decided to remove the ground.
I had previously been forcing hexes to generate with a rock layer, a dirt layer, and a grass layer, but on further reflection all of that was generation stuff that hasn't been coded yet. So now the ground is nonexistant except where patterns have effected it.
Still not really sure how patterns will actually work, though. I think my plan is to shrink down the world to be two platters tall (which is like maybe a few thousand square feet) and start messing with some patterns that move around and leave hexes behind, just so I can see how they would operate on a "global" scale.
January 15th, 2012
Trying to throw together some kind of NPC simulation stuff so see if/how I can tie that into the pattern specifications.
This NPC is supposed to be chasing me around, but due to issues in the facing code (I have forgotten everything I ever knew about how to use quaternions) it tends to spiral around and then abruptly skew off in different directions, so I ended up chasing it out into the abyss where nothing has been generated.
Also those red lines are platter centres being used as barycentric weights; I'm not really sure but I think I might use them for something. Right now all it does is highlight the three platter centres a body is between and draw that red line as the relative weight.
January 17th, 2012
WAIT NEVERMIND I TOTALLY SWITCHED AROUND MY GOAL YET AGAIN.
I'm throwing things at the wall in the hopes some of it sticks so I can have something to show off by the end of the month; that hopefully explains the frantic switching between aspects of the code. What I'm doing now is working on the map view again — I'd like to be able to visualize any arch/world data instead of having to wander around the world to look at how it's going.
This is also happening because I've been thinking about how the Dwarf Fortress world generation goes and that has somewhat bolstered me in my plan of generating complex landscapes by recursively adding detail to the world as it's generated. This was apparently my idea to begin with; there's a lot of map and pattern code that doesn't make sense unless patterns are simulated at a specific span level, which is something I had completely forgotten about or pushed aside or something.
So: maps. I'm reusing the older code, as you can probably tell, and it's pretty bad, as you can probably also tell. What I have done is added input focus, so that navigating the menu no longer moves the player in the game world as well.
As you can see, my 2D texture drawing code is still pretty lacking.
My ultimate goal here is to make the map view robust enough it can show off the map as it's being generated. There's quite a ways to go.
One of these days I need to get the hex platter rotation calculated correctly so I can make seamless maps. In the mean time, there's this.
This is mildly interactive, although it's still laid out horribly. It's possible to select from all the span levels and then highlight tiles based on the map data values. Ideally the map data values would be entirely generated and used by patterns, but I think I'm going to try a hardcoded generation first, just to see what kind of processes are involved. One of them, as you can see, is going to be temperature. I might add some noise for height and then try to calculate weather cells and rain shadow based on that, and use all that to put together some ecology junk, but until I can take that final step and use the data to generate a local landscape (that's not incredibly boring) it's pretty much a waste.
Which is why tomorrow I'm going to try to expand the material and data imprinting process to make something not entirely tedious. Here's hoping.
January 18th, 2012
(In which I start throwing noise at the problem.)
If you recall, ages ago (by which I mean four months) I tried doing some height value imprinting I eventually stopped due to the many, many issues with hidden surface removal turning the game into a slide-show when I started generating overlapping surfaces (and also in disappointment when overlapping surfaces didn't turn out exactly as I had imagined instantly) but hey, those problems are solved now!
So once again I started setting some noise as map height values and then adding that to the imprinting process, before any arches are imprinted. The results aren't exactly overwhelming, but now with a little more understanding of what I want to get out of world generation I continue tweaking the process.
This tweaking is not without its own issues.
Also, not satisfied with my existing rendering code I decided to add water, just to make things a total hassle again. I don't think it's possible to get hexes drawing in depth-order (or at least get translucent hexes drawing in depth-order) without entirely rewriting my rendering code. When I do that, however, I'd rather get it up to modern OpenGL standards in the same motion so I don't have to rewrite it twice. Problem: I still have no clue how modern OpenGL works or even if it can work on my computer.
Lesson learned: you cannot construct environments by just throwing raw noise at it.
This is how water works, right. Half the problem here was floating-point rounding; that caused the hollow "ground" spots at regular intervals in the ocean. The other half was my extremely bad coast-detection code.
It's also worth noting that there are polygons being drawn behind the water, it's just due to the vagaries of translucent polygons and blending you have to draw them in a separate pass or else they end up occluding things behind them and letting the skybox peek through. So there is a sand/silt layer of hexes under the water, you just can't see them because my rendering code is terrible.
Pictured: an attempt to improve the rendering code. The surface removal is gonna require some tweaks to get it to consider the edge of some water as visible but have internal edges between water tiles invisible.
Currently this is flat-out a heightmap: half the elevation is underwater, and the material type of the hexes is based on its displacement from sea level plus a slight random value. This is... not good. Partly because it's always been my intent to generate worlds that are vastly more interesting and irregular than noise archpelagos, partly because this makes it look strongly like a knockoff Minecraft clone, partly because throwing noise and heightmaps at world generation is exactly the kind of thing I wanted to avoid.
At this point though I'd settle for having a worldgen; I can make it less terrible later. And while I'm using noise and heightmaps I can still try to fix up a few issues that'll crop up in the future no matter what method of world generation I use.
By which I mean I'm finally going to start working on getting sloped hexes to be generated naturally within the world. Partly because I'm tired of everything being staggered and partly because the game is rendering slow and slopes will lower the poly count pretty drastically. Another thing to work on is ways of disguising platter centres — I'm doing linear barycentric interpolation on heights, and that means it's possible for there to be a sharp hexagonal "peak" that's always centred on a platter centre. This also leads to bad-looking landscapes; you can't really tell in the shots I've posted recently but the landscape is really obviously sharply mathematical.
It takes a few tries to get hex sloping working in a way that looks nice. It does certainly make things look... different.
Huh. This actually looks... nice. Like, really nice.
I mean the aesthetic I want to go for here is pretty stylized (hence the hexagons), something that brings out the mathematical structure in organic shapes, and while the landscape itself is still aggressively flat and linear I quite like the shingle effect going on. It reminds me of Dr. Seuss landscapes.
Also it makes all these low-lying islands look like caterpillars.
The unfortunate thing is that my extremely slapdash sloping code isn't that accurate — there are a few places where it's perfect, but that's far outweighed by the places where it scallops weirdly. I really like that, actually; I think the map would lose a lot of character if all the slopes were perfect. But I'd like to be able to make it more or less uniform, instead of having an accidental mishmash of edges.
Trying to make rendering at least two-pass so I can see through translucent things. I turn off translucency rendering to find that oh, huh, the sea floor isn't rendering at all. Because all my hidden surface code is designed with an opaque/transparent binary with no room for translucency.
Good news: two pass rendering is perfectly decent. (If you recall minecraft had/had this issue where translucent tiles wouldn't be rendered behind other translucent tiles; this is because they are doing the exact same terrible two-pass rendering as I am. That same bug now exists in this code, too.) This also gives me another thing to add to the cache, instead of doing two passes through every single hex in case it happens to have something translucent on it.
Bad news: two translucent surfaces next to each other don't cull their hidden surfaces. Water is a horrible mess of hidden surfaces.
Whoooo. This was fundamentally easy enough; all that was needed was to expand the previously binary opaque/transparent setting to a continuum of opaque/translucent/transparent. This will cause problems with two different translucent materials placed next to each other, though. But that is perhaps an issue to consider once I have more than one translucent material. (Of course, that particular bug will crop up the instant I add ice to the game, so...)
My framerate is in the ballpark of 1 FPS though, so... I'm not really sure if there's anything to be done about that. See if immediate mode is actually way less efficient. Cache the hexes that are translucent so I don't have to run a whole two passes through the hex structures. This is where having CPU% metrics would really come in handy; I have no clue where the various bottlenecks in the code are.
There are a bunch of weird visual issues going on given the way the code is currently constructed. The most obvious in my mind is the water-repelling sand; I'm not really sure how to fix that. Thinking about water at all just brings to mind the whole scary field of fluid dynamics in a world made of hexagons, because... well.
Also the world is still obviously mathematical all over. That doesn't look weird at all. I don't really know if it's possible to do smooth barycentric interpolation in the same way you can do sinusoidal or cubic interpolation, but that would be a start. (answer: yes, of course, but it's sufficiently advanced I will never figure out how to do it on my own.) But that's the thing I don't want to start doing; I want to make something that looks natural in the first place, not get noise and then smooth it until it's vaguely natural-looking.
Anyway now that a world generator exists it's time to smooth out the edges and see if I can make a fancy loading screen or something, because the current loading screen is...
Extremely professional.
(the blue box is there because I was trying to get a black backdrop drawing but for some reason it wasn't showing up. the reason it was not showing up, as I only discovered a few days ago, was because I have a very bad habit of leaving textures bound at the end of drawing functions and this resulted in some texture or other being bound, and that meant any polygon that expected to be drawn as a flat box got blended into oblivion.)
The loading code... let's just say that the system-level loading code was one of the first parts of the system code I wrote, and given that I've never really used it to do anything non-trivial usually it's not even on screen for even a frame. All this world generation has given me ample time to stare at the loading screen and wonder how it manages to be so broken. Part of the problem is due to the fundamental structure of the main loop, which is unfortunate since I have very little clue how to rewrite the main loop to be less terrible. Part of it's due to really bad timer code. Both of these are really old and really fundamental parts of the game, so, I'm not really sure what to do on that front. Remove the blue box, at least.
And then I rewrote the font code to use vertex/texture arrays. In the most awful, inefficient way — every frame a vertex and texture array is generated for each text fragment, used once, and then destroyed — but at the very least that one small part of the rendering code has escaped the shackles of immediate mode. Next I'll make it cache those arrays as part of the UI code, since, you know, why not.
The reason I'm kind of fretting about rendering code is that back in the day when I tried to get some other code project to compile on a Windows system it ended up being unable to render anything — it would compile, run, and respond to input, all without ever showing anything other than a black screen — and I suspect the reason for that is because these days most computers don't support OpenGL immediate mode very well or at all. I don't really know that, but knowing what I do about the way rendering works it seems at least plausible.
So I guess I'm gonna be moving on up to OpenGL 2.0 sometime soon-ish, if I can manage. But before that... well, I need to get the world doing something (anything!) and that means back to thinking about arches and how the player and NPCs and arches interact with the world. Ugh.
January 19th, 2012
You know, yesterday's entry is really, really repetitive in parts. Probably because I kept trying to write general overview every time I made some changes and all those general overviews say the same thing.
Anyway with a clear mind today I fixed the sloping so I have complete control over the smoothness of the hexes.
There are three general "classes" of slope: one, the first, is a perfect slope. Every vertex is the average height of the three hexes that it is a part of. This means absolutely no joins are drawn unless there happens to be a height difference of greater than 15 units, since that's the maximal slope of a hex.
The second type is a downward shingling. Hexes are sloped towards each other, but not enough so that they touch. This creates a very distinctive pattern that I quite like.
The third type is an upward shingling. Hexes are sloped past each other, which creates a kind of... spiky fish-scale pattern when looking down a slope. Worth noting is that due to a bug in the join calculation code the joins are drawn using the wrong material. I guess I should fix that.
Anyway right now I have it set to the perfectly smooth style, since that's the one that results in the least amount of polygons being drawn. I really want to figure out a way to simplify the geometry, but, uh, that's a pretty big challenge given that there are basically no constraints whatsoever on the shape of hex blobs and I've never written a simplification algorithm in my entire life.
I guess goals for today: get picking working right on sloped hexes and hex joins; maybe try to update some more of the rendering code to use vertex arrays. uh. think about how patterns and arches are gonna work some more. I could write a entire lengthy, boring essay about the fundamental issue I'm having with adding things of interest to the world, but the short form is "if the world is generated wholly from arches and their actions on the map data layer then how does that keep happening when the player starts playing the game and altering things in the world", like, if there's a forest and the player cuts down a tree or makes a clearing or builds a house there how does that affect the forest arch. For that matter, how do simulation-level things change the arches in general; if you have a forest and you sit around it for an in-game year and the trees all grow and push the border outwards how does that affect the forest arch, especially since arches do have very specific boundary limits that they can't grow beyond.
aaah.
Anyway that's why I'm focusing on small things like picking and rendering today.
January 23rd, 2012
And then I didn't accomplish much for several days. Go me.
What I did today was add some really rudimentary and pointless hex occupying code, mostly to see if I could figure out how to get plants that aren't just weird fractal growths working. I also rewrote some parts of the position code, in the hopes of making it more general — now from a data-storage perspective it's prepared to be perfectly general, which would let active entities wander off into less-loaded areas. There are two reasons why that's a good thing: the big one is during the worldgen the entire world is less-loaded (as in only high-span platters are loaded) and if I want active arches wandering around building the world they have to be able to operate and move in a less than perfect fidelity environment. The secondary one is that currently NPCs who leave a low-span platter for a partially-loaded, high-span one crash the game. So I'd like to fix that too.
So not much in term of actual accomplishment was done today, but it's a start.
January 27th, 2012
That is some skillful layout going on right there.
Slightly better. I just realized I'm going to need confirm/cancel buttons, too. Layout is hard :(
Oh right, where was I. So I spent another few days doing not much and then had a short conversation about the merits and flaws of going open source, so, uh, I guess I'm going to go open source. Gj, go me, now to thoroughly disassociate my internet persona as a coder from my internet persona as someone who writes fetish porn fanfiction. (I mean, not that it's liable to come up but come on look at the document root of this website, seriously. Or don't.)
More relevantly, though, it also means I've gotta fix up some of the particularly awful aspects of the code before I post it so that I'm not a laughingstock. This kind of means bugfixing, but mostly it's just... internals stuff. Code that's old and sprawling and confusing. So far I've updated the input system and started loading input and video options from a config file; still on the list is in-game options (which I am testing here as a "generate new world" config prompt), some incredibly convoluted and probably really inefficient parts of the position/camera code, a lot of the position code in general, an improved main loop, and replacing the very old-style ui code with something more modern. I'm going to attempt adding map saving and loading and some more varied in-game structures, too, if I have time, which I probably won't. The tentative "release date" (as in the day I upload the code in a big mess to github) is February 14th, because I think I might do a think where I only update on holidays or something, w/e. This gives me some time; enough to potentially fix all the things on my to-do list and then some, but, well, we'll see how that goes.
January 29th, 2012
ah yes.
My favorite part of this is that due to some extremely poorly-forethought code, trying to close the options screen opened the world map, without making the player lose focus, so that it was possible to navigate the menu and walk around the world at the same time. Trying to close that sent unfocus events to both the player and the map, meaning the game locked up almost entirely.
UI code is still very much a work in progress.
There was also a crash bug that apparently has been around for a while but only showed itself now, where trying to print the empty string would segfault due to trying to allocate zero bytes and address the resulting pointer. (IIRC it's valid C to malloc (0) but you get a pointer that you can never dereference.)
There's also this new bug. Or at least I think it's new. Sometimes despite the map loading all being forced some of it just... doesn't load. Until you move, then it works fine, it's just the initial one doesn't work. Not sure why this is; the position isn't on a pole edge or anything like that. Mysterious!
According to the map view there are some weirdly-loaded hexes. This seems like it could maybe be a distance metric issue, except that I'm almost certain that code's 100% correct now.
Honestly most of what I did was just get the settings/option code to be read by the world generation code. It's still not possible to alter the values. But once I figure out how to handle GUI input it'll be possible to specify the world span value (from 2 to 255), the file to pull pattern definitions from, and the seed to use.
February 4th, 2012
And then I... didn't write updates for a few days? Let's see if I can summarize what I've done since the last update.
Firstly, I got GUI stuff slightly more working — you can click on those 'confirm' and 'cancel' options and they'll work, since means all the UI stuff now actually responds to input. You still can't change the options values, since... that's kind of complex and involves figuring out how to display certain data value types (e.g., the world size option is a number and thus should only accept numeric input) which isn't really hard but my limited amount of focus went into getting the GUI screens to have a working layout and general-purpose interactivity. Which they do now! It's just very half-finished.
Then I turned my attention to getting map loading and unloading working. This is also very half-finished and broken right now, but it's an improvement over the system that used to exist, which was "never unload map platters ever". Currently all the loading is forced as you step between platters, so there can or will be a noticable hitch in the game at those points, but honestly I'd currently just like to have it work and then later make it load smoothly in the background.
Currently it crashes hard if you move far enough away that the platter you start on is unloaded; this is I suspect because either the arch reference becomes invalid (likely) or because the camera has very broken position component and it never technically moves off of that starting platter (less likely but still needs to be fixed).
And to think I'm going to be posting all the source in ten days. Augh. Gotta get to work!
February 5th, 2012
Wrote a bunch of GUI code. It's mostly there; all that's left is writing some option-specific code and a whole lot of polishing. Like, not to imply the polishing isn't much; it's going to be a lot of work, but the code GUI interface is there and working well now.
I had some screenshots but they're all boring text panels and stuff so I'm not going to post them.
February 6th, 2012
wHAT IS HAPPENING
I promptly use the ability to mess with world parameters to make a span-1 world, fully expecting it to crash -- for various reasons having to do with the rendering system it's pretty much impossible to build a span-1 world, even if for some reason you feel like creating a world the size of a small room. But it didn't crash. Instead, this happened.
The thing on the to-do list today is to finally finally finish the GUI code: get it interacting nicely, get option loading and saving working, and remove all traces of the old GUI code, which is still being used for the title menu -- that's why it's in such a different style.
February 7th, 2012
Got map loading/unloading working.