Issues with your account? Bug us in the Discord!

Starshatter Demo 3.0.3

[b]Starshatter Demo 3.0.3 is now available at the official website [url="http://www.starshatter.com"]http://www.starshatter.com[/url][/b]

The new demo features several new ships, two new solar systems, some new missions, and the beginnings of the dynamic campaign engine. I've also squeezed in a bit of a facelift with new explosion graphics and a cooler HUD style.

The new demo is also more easily mod-able than previous versions, and tutorials for creating user designed ships and missions have been posted on the Starshatter message board.

Also, there are twelve (mostly) new screenshots available on the screenshot page.

As always, please send bug reports and/or suggestions to milo@starshatter.com


Enjoy!


[This message has been edited by milod (edited 03-08-2002).]
«1

Comments

  • samuelksamuelk The Unstoppable Mr. 'K'
    Awesome work, milo.
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    Woo! More stuff to download!
    And new solar systems as well!

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • A2597A2597 Fanboy
    WOOT! [img]http://216.15.145.59/mainforums/smile.gif[/img]
    Thanks!

    ------------------
    [b]whitestar90: [/b]"it would give the computer a heartattack just looking at it" -
    [b]Sanfam: [/b]"And Drazi didn't like it one bit.-
    [b]Mr.Bungle: [/b][i]"So that's where the forum went..."[/i]-
    ---
    [b][i]ahhh, the good old days of HTML.[/i][/b]
  • RickRick Sector 14 Studios
    You realize, of course, Milo, that you're probably getting very close to an engine you could license out...

    BTW-- it's great to hear from you. Don't be a stranger.

    -Rick

    ------------------
    [i]"...Never start a fight...but [b]always[/b] finish it."[/i]
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    I wish my engine was that advanced.

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • NickNick Earthforce Officer
    My engine is the stock 3.0 that comes with a 95 ford taurus. It still humms at 127000+ and it never had a tune up. Oh yeah baby!
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    My engine consists of a large number of text files and some compiled code, plus a half full workbook (always use a workbook!).

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • milodmilod Ranger
    [quote]Originally posted by Rick:
    [b]You realize, of course, Milo, that you're probably getting very close to an engine you could license out...[/b][/quote]

    Yeah, 'cause combat space sims have been such a hugely lucrative market of late and all...

    Oh, wait. Nevermind.

    Seriously, there's plenty of mod support in there. If people want to use the engine to make other games, I'm sure that something could be arranged. It's just not my main focus at the moment. It's hard enough just finishing my own project without worrying about licensing, y'know?

    How's life treating you, by the way?



    ------------------
    --milo
    [url="http://www.starshatter.com"]http://www.starshatter.com[/url]
  • Adam EvansAdam Evans Earthforce Officer
    looks cool I'll try to dl it over the weekend. Im stuck on 56k :P
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    milod: Just a quick question since this is what I'm working on right now... How did you handle fonts in your engine?

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • milodmilod Ranger
    [quote]Originally posted by Biggles:
    [b]milod: Just a quick question since this is what I'm working on right now... How did you handle fonts in your engine?[/b][/quote]

    Each font is stored in a 256x256 bitmap divided into a 16x16 grid. This allows each glyph to be upto 16x16 pixels. There is a datafile associated with each font that indicates basic information like character height, baseline, spacewidth, and whether the font is proportional or monospaced.

    The font engine in the game loads the bitmap and scans the extents of each character to build a kerning table. For each glyph, it looks at each row of pixels and determines the left and right extents (using floating point if the font is antialiased). Then it compares the right extents of one glyph to the left extents of every other glyph. This is used to calculate the number of pixels to offset the second glyph from the first when they appear in a string.

    There are two font rendering engines in the game - one for software and one for hardware. The software renderer is used throughout the 2D GUI screens and occasionally in the 3D view when it is inconvenient to use the 3D renderer. The 3D renderer is used in the Heads-Up Display and 3D tactical displays.

    The 3D renderer loads the font bitmap into a texture and creates a bunch of adjacent polygons to hold the glyphs. It then computes texture coordinates for each character from the 16x16 grid.

    In order to get things to alpha-blend properly, I actually load the glyphs into the alpha channel of the texture, and fill the color channels with whatever color I want to render the font with.

    Hope this helps,




    ------------------
    --milo
    [url="http://www.starshatter.com"]http://www.starshatter.com[/url]
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    Up to the kerning point, that's pretty similar to how my system works. Probably because it's a standard method for fonts.
    Your method of kerning is interesting. The only way I could think to do it was that way (which I thought would be too slow) or to store it in the font data file.

    What's the difference between the software and hardware font rendering systems?

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • milodmilod Ranger
    Too slow? You only need to do this once, on startup. A typical CPU can execute about half a billion instructions per second. Even if it takes a whole second to do the kerning (it probably takes less than a tenth of a second, I haven't timed it), who really cares? Optimize stuff that you need to do often - like every frame.

    The difference between the software renderer and the hardware renderer is who draws the pixels. The software renderer locks the frame buffer and uses the CPU to alpha blend each pixel of each glyph. You will probably need something like this for the menu / options / loading screens that the player uses before entering the game world.
    The hardware renderer loads the font into a texture and uses the 3D card to alpha blend the pixels.

    The interesting part about this is where in the pipeline the drawing actually occurs. When you use the software renderer (e.g. window->Print(100, 100, "Goodbye cruel world"); ) the game locks the frame and renders those glyphs to the frame buffer right then. If you use the hardware renderer (e.g. text3D_message->SetText("Goodbye cruel world in 3D"); ) the polygons for the message get added to the 3D scene and inserted into the rendering pipeline to be drawn on the next frame.
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    So why do you need to do it two different ways, given that they both give you the same transparency effect?

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • milodmilod Ranger
    Performance.

    It's faster to use the 3D card to do the alpha blending than it is to do the same effect in the CPU. Also, in order to draw text on top of the 3D scene with the CPU, you need to wait until the 3D card is finished with the entire scene so that you can lock the frame buffer. This is bad for the pipeline. It means you are waiting for the 3D card instead of doing useful work in parallel with it.

    If you do your [b]entire[/b] user interface in 3D, then you could get away with just the 3D hardware renderer. But if you want to support 2D graphics cards, or if you designed your GUI to use a conventional window library, you will probably need a 2D font renderer for at least the GUI.

    ------------------
    --milo
    [url="http://www.starshatter.com"]http://www.starshatter.com[/url]
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    Ah OK then. My GUI is handled entirely in 3D using the orthographic view matrix abilities to do 2D stuff.

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • FreejackFreejack Jake the Not-so-Wise
    Thanks guys,

    I know nothing about programming, yet I find these conversations extremely informative.

    Jake
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    Let's see if we can get this one up to 8 pages as well. [img]http://216.15.145.59/mainforums/biggrin.gif[/img]

    How do you handle your 2D stuff, milod?

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • milodmilod Ranger
    Wow, there's a broad and open-ended question...

    To place the answer in context, remember that I started this project almost five years ago. Back in '97, most computers didn't have 3D cards. Many of the ones that did had crappy first generation cards that were slower than software renderers. 3Dfx rendering bilinear filtered polys at 640x480x16 was bleeding-edge state-of-the-art stuff. Windows 98 didn't exist yet, and Direct X was on version 3, with version 4 nowhere in sight. The game engine behind Starshatter was designed to support 640x480x8 with software rendering of 3D graphics as a minimum. At the time, I thought that might be pretty close to the maximum as well.

    The engine includes a very simple window manager. The basic interface classes are Screen, Window, and View. A Screen is the entire game screen - either in a desktop window or in fullscreen mode (two different concrete implementations of the Screen interface). A Window is an abstract base class representing a rectangular area of the Screen. The Window may be opaque or transparent. The Screen object calls Paint on each Window to redraw the game screen once each frame.

    To keep things simple, the game engine does not use a dirty-rectangle approach. The entire screen is copied to the frame buffer on every frame. Each window maintains a backing store of its pixels. If the window is not marked "dirty", the paint routine simply blits that backing store to the frame buffer. If the window is marked dirty, then it calls its own Draw routine to update the backing store before sending it to the frame buffer.

    This technique neatly avoids mouse-droppings and other update-related artifacts but is a performance nightmare. It is quite easy to blit 640x480x8 each frame, but gets a bit dicey at 800x600x32 on low-spec machines. I may have to go back and redesign the screen update approach to move fewer pixels to the frame buffer.

    A Window has a list of Views that get called, in back-to-front order during the Draw method (which is called from within Paint when the window is dirty). The Views decide what to draw into the window rect based on application specific data. The Views use Window methods like DrawLine or DrawBitmap or DrawText to do the actual pixel-pushing.

    The 2D GUI screens in Starshatter are created using a set of subclasses of Window that stem from the ActiveWindow class. ActiveWindow represents a generic GUI control that can respond to and generate AWEvents. There is an EventDispatch object that monitors the mouse and keyboard and tracks input focus to a particular ActiveWindow. The EventDispatcher calls methods on the input focus such as OnMouseMove or OnKeyDown to notify the ActiveWindow of user input.

    The ActiveWindow class includes a list of clients that are to be notified when Events occur. There are a set of macros (something like MFC message maps) that simplify hooking up clients to ActiveWindows. The client class defines a callback method which it then registers with a particular ActiveWindow instance for a particular event. When the event occurs on that ActiveWindow, the window calls the registered method on the client.

    ActiveWindow subclasses include Button, EditBox, ListBox, ComboBox, and Form. The Form class is analogous to a Windows Dialog - it is an ActiveWindow that can contain other ActiveWindows called controls. There is a specialized version of this class called FormEx that can be loaded from a text description of the form layout.

    Does that help?


    ------------------
    --milo
    [url="http://www.starshatter.com"]http://www.starshatter.com[/url]
  • JackNJackN <font color=#99FF99>Lightwave Alien</font>
    My God!

    I just got shivers down my spine!

    [img]http://216.15.145.59/mainforums/biggrin.gif[/img]

    Although I wouldn't know the first thing about how to code all this, I understood 98% of it!

    heh heh!
  • RickRick Sector 14 Studios
    [quote]Originally posted by JackN:
    [b]My God!

    I just got shivers down my spine!

    [img]http://216.15.145.59/mainforums/biggrin.gif[/img]

    Although I wouldn't know the first thing about how to code all this, I understood 98% of it!

    heh heh![/b][/quote]

    HAHAHAHAHA! Jack [img]http://216.15.145.59/mainforums/smile.gif[/img]

    Wory when you understand Marketing lingo. Look what it did to me [img]http://216.15.145.59/mainforums/wink.gif[/img]

    -R.

    ------------------
    [i]"...Never start a fight...but [b]always[/b] finish it."[/i]
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    Milod: What do you define as a client that the ActiveWindow class calls when it gets events?

    My GUI system is a lot simpler, mainly because I'm still learning a lot about it. Version 1 of my engine will probably stick with the simple version, while in v2 I'll implement a more powerful GUI system.
    Currently, I have a MenuSystem object that encapsulates all the GUI stuff. Within this menu system is a list of windows, a mouse cursor object and a GUI status update function. Every frame, I call the Update() method of the menu system and pass it the engine's mouse object. If the menu (note that I use "menu" to mean any GUI interface currently being shown, just that the system will be mainly used for menus) is not currently active then it will simply return immediatly. Otherwise, it updates the cursor object's coordinates and button info. Then it runs the status update function.
    This function (and the whole GUI system) is essentially a state machine. The function checks the current state of the cursor and what windows it may be interacting with. (Boy I'm glad I copied that to the clipboard after accidentally closing the window.) If an event occurs for a window (eg MouseDown) then it calls the appropriate handler for that window. The window will then perform the required actions to handle that event. For example, if the window is a button and it receives the MouseUp event then it will check if the MouseDown event occured for the window first. If it did, it will perform some action. I don't have any kind of event queue like the Win32 system uses, I decided that was probably a bit too complex for me.
    What I haven't worked out yet is how the event handlers will perform their actions to change things in the engine. The current idea I have is to have some kind of global event handling system for the engine that the window objects can call functions off to do stuff.
    All my windows (including subclassed windows like buttons) use quads for drawing and are drawn by Direct3D using orthoganal projections. They are drawn every frame (so I don't have to worry about complex dirtying windows stuff yet). Text is also drawn using quads (one for each letter).

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    Stuff I forgot to add to the end:

    I've considered (for later versions of the engine) making the game view inherit from the basic window object and have it as part of the GUI system. Then I could have the GUI system either handle all input for the engine and call event handlers on the game object, or I could have the GUI system take what input it needs and pass the remainder on the game system. Come to think of it, I could probably do the second option for input now if I wanted. Hmmm.
    Anyway, my current system doesn't allow for very tight integration between the GUI system and the game world, so ingame GUIs would be difficult to do unless I can think of a good way to handle window events.

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    Just out of curiosity milod, do you implement any sort of z-buffering in your 2D system?

    And a quick question: how do you handle render state changes? In case you arn't using DirectX and so may call them something else, these are when you change things like what the colour channel for a pixel comes from (vertex colour, texture, etc), how it's blended, etc.

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • milodmilod Ranger
    [quote]Originally posted by milod:
    [b]The entire screen is copied to the frame buffer on every frame. Each window maintains a backing store of its pixels. If the window is not marked "dirty", the paint routine simply blits that backing store to the frame buffer. [...]

    This technique neatly avoids mouse-droppings and other update-related artifacts but is a performance nightmare. It is quite easy to blit 640x480x8 each frame, but gets a bit dicey at 800x600x32 on low-spec machines. I may have to go back and redesign the screen update approach to move fewer pixels to the frame buffer.
    [/b][/quote]

    A minor update to the above - I placed a frame counter on my 2D screen at 800x600x32 and noticed that it was hovering around 15 FPS. This is pretty darn slow, and makes the mouse almost too jerky to use. It messes up your hand-eye coordination and makes it hard to hit the buttons.

    I pulled out the old calculator and determined that 800x600x32 is about 1.9 MBytes or more than six times the size of a 640x480x8 display. At first I thought, "well that explains why the screen repaint is so darned slow..." But then I dug a little deeper.

    I mentioned above that each window has a "backing store" that holds its image. Each frame, the backing store is BLTed to the frame buffer using the DirectX function BackBuffer->Blt(). The question was: how can DirectX easily manage 50-70 FPS when filling the screen with 3D polygons, but only 15 FPS when BLTing 2D bitmaps? That just doesn't make sense - if anything it should be faster to do a 2D BLT than to do a perspective correct rendering of a 3D texture...

    And it would have been faster too, if I had created the backing store as DDSCAPS_VIDEOMEMORY instead of SYSTEM memory. D'OH!!!

    The 2D screens are much faster now.

    [quote][b]What do you define as a client that the ActiveWindow class calls when it gets events?[/b][/quote]

    That's kind of complicated, which is why I wrote a bunch of macros to hide the complexity. The short version is that the clients are also ActiveWindows (usually instances of a Form subclass). There is an AWMap structure that connects an event type, a client object, and the callback method (via a C helper function).

    And no, there is no Z-buffering in the 2D window system. Windows are added to the screen in back-to-front order and refreshed the same way.

    ------------------
    --milo
    [url="http://www.starshatter.com"]http://www.starshatter.com[/url]
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    OK, so what your one does is store in this big structure a function pointer to call when an event occurs for a certain client?

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • milodmilod Ranger
    Yeah, except it's not a very big struct:
    [code]

    typedef void (*PFVAWE)(ActiveWindow*, AWEvent*);

    struct AWMap
    {
    AWMap() : eid(0), client(0), func(0) { }
    AWMap(int e, ActiveWindow* w, PFVAWE f) : eid(e), client(w), func(f) { }

    int operator == (const AWMap& m) const { return (eid == m.eid) &&
    (client == m.client); }

    int eid;
    ActiveWindow* client;
    PFVAWE func;
    };


    // create a C-style helper function to call the client's callback:

    #define DEF_MAP_CLIENT(cname, fname)\
    void Map##cname##fname(ActiveWindow* client, AWEvent* event) \
    { cname* c = (cname*) client; c->fname(event); }

    #define REGISTER_CLIENT(eid, ctrl, cname, fname)\
    ctrl->RegisterClient(eid, this, Map##cname##fname);

    void
    ActiveWindow::RegisterClient(int eid, ActiveWindow* client, PFVAWE callback)
    {
    AWMap* map = new AWMap(eid, client, callback);
    clients.append(map);
    }
    [/code]
  • BigglesBiggles <font color=#AAFFAA>The Man Without a Face</font>
    OK, so do you have a list of these structures then?

    ------------------
    [b][url="http://www.minbari.co.uk/log12.2263/"]Required reading[/url][/b]
    Never eat anything bigger than your own head.
    The Balance provides. The Balance protects.

    "Nonono...Is not [i]Great[/i] Machine. Is...[i]Not[/i]-so-Great Machine. It make good snow cone though." - Zathras
  • milodmilod Ranger
    Yes. The "clients" member of the [b]ActiveWindow[/b] class is defined as [b]List&ltAWMap>[/b] clients;. That is why the last line in the [b]RegisterClient[/b] method shown in my previous post appends an [b]AWMap[/b] structure to the clients list.

    The event dispatcher then calls the following function on the [b]ActiveWindow[/b] to send it the event:


    [code]
    void ActiveWindow::ClientEvent(int eid, int x, int y)
    {
    event.window = this;
    event.eid = eid;
    event.x = x;
    event.y = y;

    ListIter map = clients;

    while (++map) {
    if (map->eid == eid)
    map->func(map->client, &event);
    }
    }

    [/code]

    The last line in the while loop calls through the map structure's function pointer to notify each registered client that the event occurred. The active window keeps a copy of the event in a member variable for future reference, just in case.

    Hope this helps,

    --milo [url="http://www.starshatter.com"]http://www.starshatter.com[/url]

    [This message has been edited by milod (edited 04-04-2002).]
  • JackNJackN <font color=#99FF99>Lightwave Alien</font>
    Milod:

    You've mentioned before that you are not against MOD'ing your game, and even have mentioned making it easier to do that.

    At some point I'd like to be able to use your engine to test out game models and surfacing. Maybe even MOD it for use in a hybrid game project idea that I have that is sorta like a mixture of Homeworld, Tradewars, and B5:Itf all bundled together with it's own brand new universe and ship designs.

    So, I am curious as to what are your point and polygon budgets for ship models like fighters and capital ships, and what kind of texture sizes and mapping techniques do you use?

    What 3D program are you using to create your models? MAX, Lightwave, Maya ?
Sign In or Register to comment.