Recent Posts

Pages: 1 2 [3] 4 5 ... 10
21
Computers & Programming General / Re: Learning C through a fun project?
« Last post by lordpalandus on April 17, 2018, 09:27:39 PM »
I'm assuming multiple inheritance means something like:

great-grandparent->grandparent->parent->child->grandchild ... etc.

Does C++ allow for Composition, like Python does?
22
Outpost 2 Mapper / Re: Outpost 2 mapper auto-tiling ruleset & new tiles
« Last post by leeor_net on April 17, 2018, 05:57:14 PM »
I assumed that there was a lower granularity as Arklon mentioned. I don't think looking at it as individual tiles will work. That's the general feel that I've gotten.

Your mention of the seam issues confirms what I thought I'd noticed in a variety of maps. It tells me that the Dynamix developers went with a "this is good enough" approach. Perhaps we can do the same? It ultimately doesn't need to be perfect, just usable.

I'm also thinking that the way the tiles are set up, an algorithm won't be terribly effective. I imagined a lookup table of sorts... which meshes well with your suggestion of meta data. This is where the ruleset comes into play and we may need to actually manually set up the first set by actually looking at the individual tile indicies and then matching them up based on surrounding tiles. It'll be a bit of a chore but may be the only way to do it effectively.

Quote
Quote
I use a modified version of the OP2Editor code -- basically I stripped out the COM and rewrote the input/output using byte streams in-memory. This was before the work you and Hooman did on the OP2Editor backend so it might be better to dump what I did and replace it with yours.

I would like to see your editor's backend work massaged into OP2Utility so we can unify the backend code between the mapper, OP2MapImager, and OP2Archive in one reusable place. Dumping is probably the wrong word as you may have functions that do not yet exist in OP2Utility that would need to be transferred over. I would be willing to help on this endeavor though it is out of scope for this thread.

Can browse the code in GitHub here: https://github.com/OutpostUniverse/op2-landlord

Relevant files include the MapFile (header, source), TileGroup (header, source), TileSetManager (header, source) and the StreamReader/Writer classes (source directory). Note that StreamWriter is currently just an interface with no actual implementation (I got lazy, don't judge me).

The most interesting (I think) code is in the MapFile class: MapFile::load

NOTE: slight modifications to get the code syntax highlighter working without barfing

Code: [Select]
void MapFile::load(const std::string& filename)
{
    int temp = 0;

    try
    {
        File _f = Utility<Filesystem>::get().open(filename);
        File::RawByteStream stream = _f.raw_bytes();
        StreamReader stream_reader(stream);

        stream_reader.read(&mMapHeadInfo, sizeof(mMapHeadInfo));

        /**  Update map header fields */
        mMapHeadInfo.tileHeight = RoundUpPowerOf2(mMapHeadInfo.tileHeight);

        mTileWidth = 1 << mMapHeadInfo.lgTileWidth; /** Calculate map width */
        mTileHeight = mMapHeadInfo.tileHeight;

        int cellCount = mTileWidth * mTileHeight;
        mTileData = new int[cellCount];

        /**  Read in the tile data */
        stream_reader.read(mTileData, cellCount * MAP_CHUNK_SIZE);
        stream_reader.read(&mClipRect, sizeof(mClipRect));

        mTilesetManager = new TileSetManager(mMapHeadInfo.numTileSets, &stream_reader);

        readTag(&stream_reader, mMapHeadInfo.tag);
        /**  Something about units between reads of the tag. */
        readTag(&stream_reader, mMapHeadInfo.tag);

        /**  Load tile groups from file */
        int group_count = 0;
        stream_reader.read(&group_count, MAP_CHUNK_SIZE);
        stream_reader.read(&temp, MAP_CHUNK_SIZE);

        for (int i = 0; i < group_count; i++)
        {
            int width = 0, height = 0;
            stream_reader.read(&width, MAP_CHUNK_SIZE);
            stream_reader.read(&height, MAP_CHUNK_SIZE);

            /** TileGroupInfo _tgi; */
            TileGroup* _tg = new TileGroup(width, height, mTilesetManager);

            /**  Read in the tile data */
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    stream_reader.read(&temp, MAP_CHUNK_SIZE);
                    _tg->index(x, y, temp);
                }
            }

            _readTileGroupName(stream_reader, *_tg);
        }
    }
    catch (const std::string& errorMsg)
    {
        std::cout << errorMsg << std::endl;
    }
    catch (...)
    {}
}

Code: [Select]
readTag()
can be found in Common.cpp -- it's just a simple helper function.

Much of this is unchanged from the original implementation but with changes regarding the use of the StreamReader class which was modified to remove COM and use a 'raw byte stream' (basically just an unsigned char* buffer implemented as a std::string for memory management).

So basically, to sum up an overly verbose post, I removed the non-portable Windows stuff from the code and reimplemented some functions through a virtual fileystem (via NAS2D) and changed the drawing code to also take advantage of NAS2D. The filesystem stuff can be replaced with calls to C++11/C++17 filesystem calls instead (which is probably much more portable). The raw byte stream is basically just an unsigned char* buffer.
23
Computers & Programming General / Re: Learning C through a fun project?
« Last post by leeor_net on April 17, 2018, 05:24:19 PM »
Multiple inheritance (especially the way C++ does it) leads to all sorts of ways to create massive (and very expensive) headaches.

My general rule of thumb is "If you're using multiple inheritance, you're doing it wrong". Granted there are edge cases where it makes sense but the second you run into the Diamond ProblemTM you find ways to build better inheritance graphs.
24
Outpost 2 Mapper / Re: Outpost 2 mapper auto-tiling ruleset & new tiles
« Last post by lordpalandus on April 17, 2018, 11:39:18 AM »
Looks like an interesting jigsaw puzzle to me. Hope you guys figure it out!
25
Projects / Re: OP2Archive Application Development
« Last post by Vagabond on April 17, 2018, 08:40:58 AM »
I went ahead and merged the Archive change that removed the internalName argument from the CreateVolume function.

A new branch and merge request were created for sorting filesToPack alphabetically inside the CreateVolume function.

This is the last change I currently had in mind for OP2Utility. If Leeor is looking to move is OP2-Landlord code to using OP2Utility, we could start looking at the differences between OP2Utility and his code base for merging. Otherwise, I'll look to release a new version of OP2Archive. Unless Hooman has something else he wants to review, change, fix, etc.

Quote
Vagabond, I've merged the branch.

I'm thinking about the workflow right now. In the future, it probably makes sense for you as the project owner to do the merge, and was probably silly of me to request your review after opening the pull request. I think requesting review is more suitable when there is no main project owner, or when the project owner wants code reviewed by someone else. For a lot of single author projects, opening a pull request is in a way requesting review and inclusion by the project owner.

I suppose I'm still figuring out GitHub and GitHub etiquette.

I figured you just tagged me for review since I wrote the original code as a courtesy. Which is why I keep tagging you in changes to the Archive code since you wrote it. I don't really consider myself the owner of the code. You wrote all of the archive code which is the largest piece. We co-wrote the code to load a map into memory, but we used all your notes that would have otherwise made it impossible for me to write.

Thanks,
-Brett
26
Computers & Programming General / Re: Learning C through a fun project?
« Last post by Hooman on April 17, 2018, 02:23:19 AM »
Yeah, I was thinking embedded stuff. That seems to be the main use case for C these days. A C compiler is a bit easier to write than a full C++ compiler, so it may have more support for various low end and embedded systems. There's also less going on under the hood to surprise developers with hidden performance costs. That can sometimes be an issue with C++, especially for people who are less experienced with it.

A possibly fun and educational project might be to figure out how C++ features can be implemented in C. Such as how classes can be implemented with structs. How virtual functions work. How function overloads work. How namespaces work. If you're really looking for trouble, you can look into how multiple inheritance works. Though I should note, most post C++ languages dropped the concept of multiple inheritance, at least outside the more limited concept of multiple interfaces.
27
Projects / Re: OP2Archive Application Development
« Last post by Hooman on April 17, 2018, 02:12:08 AM »
Quote
Plus I imagine even with said move semantics compiler developers wouldn't strip out optimizations regarding references.

Yes, you're right, there is of course no reason to remove old optimizations, but that's kind of missing the point. There are certain cases where the old way of doing things couldn't be optimized, which can be optimized with move semantics. Consider the case of copying and holding a string into an internal data buffer. You might still declare such a parameter as const &, as the original, doesn't need to be modified by the called function. It might however be modified or deallocated later by the caller, hence a copy is stored rather than a reference to the original. But if the input parameter was a temporary, you can avoid the copy by simply taking ownership of the string buffer. This is where move semantics help. The compiler knows to call either the copy operator or the move operator based on whether the source object is a variable (lvalue), or a temporary (rvalue). The optimization goes beyond just the point of the call, taking into account the lifetimes of the objects.

There are also some convenience and syntax benefits, such as passing literals that have no associate memory address. Declaring a parameter as const & requires the parameter to have a memory address. That doesn't work so well for literals, such as 5. If you've ever found yourself declaring a variable just to pass a constant into a function, you know how annoying this is.

Quote
That muddiness is something I as a developer don't appreciate

Heh, I tend to agree. I'm not a fan when languages have multiple syntax options for the same thing. I've noticed Ruby violated that principle a few times to ill effect. I'm also rather against aliases to account for different spellings in different regions, such as US versus UK spellings of function names. I would prefer there only being one correct way.



Vagabond, I've merged the branch.

I'm thinking about the workflow right now. In the future, it probably makes sense for you as the project owner to do the merge, and was probably silly of me to request your review after opening the pull request. I think requesting review is more suitable when there is no main project owner, or when the project owner wants code reviewed by someone else. For a lot of single author projects, opening a pull request is in a way requesting review and inclusion by the project owner.

I suppose I'm still figuring out GitHub and GitHub etiquette.
28
Outpost 2 Mapper / Re: Outpost 2 mapper auto-tiling ruleset & new tiles
« Last post by Hooman on April 17, 2018, 01:25:00 AM »
We really need this. This would be a wonderful project if we got this sorted out.

The TileGroups do contain transition sets, as Leeor has pointed out, though the pattern is not clear. It's tantalizing though, as there does seem to be a pattern when comparing different transition sets, though there was some irregularity with one of them.

I think Arklon is right, in that Dynamix probably had an automated way to do the transitions. I'm just not certain what pattern they used, or if it's even really a pattern. Maybe there was some additional metadata about the tiles that aided transitions.

I see this more as a creating/recreating metadata problem, rather than a tileset extension problem. I think there are sufficient tiles there for decent results, it just might not present itself in an obvious way.

There is room for extending the tileset, though that feels like opening a whole new can of worms. I would rather not rely on tileset extensions to get smooth auto transitions. I wouldn't mind if we had a metadata approach that could accommodate new transition tiles, I just don't want to require that.

As an aside, maps can use a portion of the tiles from a tileset. If you wanted to work around the tile limit, you could do so by selectively using tiles from tilesets.


Related projects are the AutoMapMaker, TileSetOrganizer, and VirMask.

The AutoMapMaker scanned the existing maps to see which tiles have appeared next to each other, and used that data to create the fitness lists. The problem is, existing maps contain many errors and graphical glitches. As such, the fitness lists contained lots of errors.

The TileSetOrganizer was meant to classify the various TileGroups, though didn't include a breakdown of transitions within the transition groups.

The VirMask simulates the light/darkness and blight overlay. It uses a 2x2 grid to produce the correct overlay tiles. You may want to take note of the pattern. This relates to Arklon's comment about the 2x2, 3x3, or whatever-size block granularity comment.

Curiously though, the transition groups are 6x8 tiles = 48 tiles. This is not a power of 2. Most transition algorithms seem to work with on/off adjacent tile switches, and produce a power of 2 list of tiles for the transitions. They clearly did something else here.

One thing I had noticed, was some tiles appear to be a diagonal transition along the same edge, or like there was some variation in tiles for an otherwise identical adjacency. I never delved too deeply into this. Though it seems you've just pointed this out yourself.

Another point worth considering, is the pattern used for walls and tubes. That is another regular binary on/off adjacency algorithm. It's different from VirMask, as it's a different set of adjacent tiles that matter.


Cliffs are an even messier looking problem.
29
Outpost 2 Mapper / Re: Outpost 2 mapper auto-tiling ruleset & new tiles
« Last post by Vagabond on April 17, 2018, 01:03:27 AM »
Quote
I use a modified version of the OP2Editor code -- basically I stripped out the COM and rewrote the input/output using byte streams in-memory. This was before the work you and Hooman did on the OP2Editor backend so it might be better to dump what I did and replace it with yours.

I would like to see your editor's backend work massaged into OP2Utility so we can unify the backend code between the mapper, OP2MapImager, and OP2Archive in one reusable place. Dumping is probably the wrong word as you may have functions that do not yet exist in OP2Utility that would need to be transferred over. I would be willing to help on this endeavor though it is out of scope for this thread.

Quote
Given that some dumb unused maps like the DIE! BUT HAVE A NICE DAY one still have decent tile transitions, I think Dynamix's map editor had an automated way to do it. But yeah, the tiles don't line up nicely for that, as least the way you'd typically think. Perhaps you need to think of the transitions at the 2x2, 3x3, or whatever-size block granularity, instead of the individual tile granularity?

I hadn't thought about working in multiple tiles for the transition. This concept would be more difficult to implement automated, but I think maybe you are right on how Outpost 2 did it originally. This is how the cliffs are done, where you line up chunks of 2x2, 3x2, etc tiles instead of automapping at the individual tile level.

After carefully reviewing the tile sets in OP2 Mapper, I put the images below together trying to unify individual transition tiles. It looks like we are missing 3 needed tiles on each transition to make it work. Also, tile 'L' on the dirt-rock transition does work, but maybe could be replaced by a better tile. If multiple tiles could satisfy a particular transition, they are displayed next to the tile they could replace. IE tile 'B' in the dirt-rock transition set had 2 tiles that seemed to transition in the same location.




This approach of looking at individual tiles would also discard a large number of the more interesting transition tiles unless they were touched in manually. However, if they were grouped into tile chunks as suggested by Arklon, they would be easier to add after the auto-tiler laid down a generic transition, even if the auto-tiler didn't take into account the tile chunks.

I'd still have to look at the rock-sand and the rock-lavaRock transitions as well. Assuming they are missing about 3-4 each, that would be a total of about 12-15 tiles that would be needed to make it work on a single tile transition solution.

Thanks,
-Brett
30
Outpost 2 Mapper / Re: Outpost 2 mapper auto-tiling ruleset & new tiles
« Last post by Arklon on April 16, 2018, 06:46:50 PM »
Given that some dumb unused maps like the DIE! BUT HAVE A NICE DAY one still have decent tile transitions, I think Dynamix's map editor had an automated way to do it. But yeah, the tiles don't line up nicely for that, as least the way you'd typically think. Perhaps you need to think of the transitions at the 2x2, 3x3, or whatever-size block granularity, instead of the individual tile granularity?

Making new tileset graphics is probably never going to happen, unless you want them to look like the tacked-on MS Paint water and bridges in Mcshay's Greenworld maps (base Greenworld was just ripped from Total Annihilation).
Pages: 1 2 [3] 4 5 ... 10