Author Topic: Aleph One  (Read 19113 times)

campusten

  • Guest
Re: Aleph One
« Reply #20 on: October 23, 2010, 09:41:14 pm »
Thanks, nigel!

wy_scorpio

  • Posts: 368
Re: Aleph One
« Reply #21 on: October 25, 2010, 12:49:39 pm »
i cant play this..
i download M1A1 dir and put alephone dir on my card with path "/local/games/alephone"
and i copy M1A1 dir into /local/games/alephone/data
when i run "maraton 1 (M1A1).dge ",it appears error "./.next:line 2:/boot/local/games/alephone/marathon:not found"

where is my wrong?

thanks

Solstice

  • Posts: 367
Re: Aleph One
« Reply #22 on: October 25, 2010, 02:40:48 pm »
Thanks !! im having trouble downloading your lastest link?
Dingoo A320 stock 1.2 + Gmenu

PSP slim 2002 Gen 5.50 D3 Prom4

nigel

  • Guest
Re: Aleph One
« Reply #23 on: October 26, 2010, 12:19:44 am »
Solstice: Odd. Try the ones below then:
http://rapidshare.com/files/427140941/alephone-dingoo-v1.7z
http://www.megaupload.com/?d=OFIGRG5O

wy_scorpio:
That's a weird error. Did you add the link to GMenu2 first? If you're using DMenu or something else you might want to change the 'working directory' to wherever you put alephone. That still wouldn't explain the weirdness in that error message though.

clach04:
Doubt he's happy with that, but for anyone interested (stripped it out of function but should be clear with the extra commenting):
Code: [Select]
// Dingoo scaling function.
// http://www.compuphase.com/graphic/scale.htm
// Excellent example of a 'box filter'. I worked from there. - Nigel
// Put this in a function or so, used to be in one. SDL_Surface source_surface should be what the game outputs
// to as if it were a 640x480 screen and target_surface should be defined with the dingoo screen properties..

        // Bitmask needed adaption. Endianess? I don't know. Now reduces to 13 bit, 3 per channel, looks fine already so
        // didn't bother to see if blue or red could keep an extra bit.
        #define AVERAGE(a, b) (PIXEL)((a) == (b) ? (a) : (((a) & 0xf7deU) + ((b) & 0xf7deU)) >> 1 )

unsigned short p, q;
int x, y, x2, y2, y2p1, y320;

unsigned short* Source = (unsigned short *)source_surface->pixels;
unsigned short* Target = (unsigned short *)target_surface->pixels;

for (y = 0; y < 240; y++)
{
y2 = 2 * y * 640;
y2p1 = (2*y + 1) * 640;
y320 = y*320; //precalculating these two for ~1fps increase.
for (x = 0; x < 320; x++)
{
x2 = 2 * x;

p = AVERAGE(Source[y2 + x2], Source[y2 + x2 + 1]); // Averages out top 2 pixels
q = AVERAGE(Source[y2p1 + x2], Source[y2p1 + x2 + 1]); // Averages out bottom 2 pixels
Target[y320 + x] = AVERAGE(p, q); // Averages results of the above and puts the resulting pixel on the target surface
}
}

SDL_Flip(target_surface); // Puts the surface on the dingoo screen.

Gives this result:




Instead of this (pickle's fast gp2x scaler):




fps display is not accurate by the way, the new scaler in v1 is certainly 20-25% slower on this game even though it's not really noticeable. In theory this code should be at least 3 times slower. But I haven't benchmarked it without anything else running so I can't really compare.


On another note, I've looked at the lack of item/damage flashes, underwater colors, etc. It all comes down to one thing: Dingux SDL doesn't do 'SDL_SetGammaRamp'. SDL_Set_Gamma doesn't do anything either, but both return 'true'. Unfortunately AlephOne appears to use this feature to do the screen coloring/flashing.

I do not know how to work around this or fix this - other than to render in 8 bit instead of 16 which makes it revert to a CLUT table method though this definitely won't scale nicely - so you'd better be watching your health meter, raising lava levels and whatnot. It's a pity. But, on the bright side, if this magically starts working on future dingux versions a new release will not be needed.
« Last Edit: October 26, 2010, 01:49:34 am by nigel »

nigel

  • Guest
Re: Aleph One
« Reply #24 on: October 26, 2010, 12:33:44 am »
Hit 'quote' instead of 'edit'. Ignore this post :(

rip

  • Posts: 45
Re: Aleph One
« Reply #25 on: October 26, 2010, 01:50:57 pm »
Thanks for you work, nigel.

campusten

  • Guest
Re: Aleph One
« Reply #26 on: October 26, 2010, 05:15:04 pm »
I definitely think with the new scaler that it's ready for the 'releases' forum.  

EDIT: Oops, it was already put there. Nevermind!
« Last Edit: October 26, 2010, 07:49:20 pm by campusten »

mth

  • Posts: 317
Re: Aleph One
« Reply #27 on: October 26, 2010, 05:54:03 pm »
On another note, I've looked at the lack of item/damage flashes, underwater colors, etc. It all comes down to one thing: Dingux SDL doesn't do 'SDL_SetGammaRamp'. SDL_Set_Gamma doesn't do anything either, but both return 'true'. Unfortunately AlephOne appears to use this feature to do the screen coloring/flashing.

The documentation of SDL_SetGammaRamp says it returns -1 when programmable gamma correction is not supported and -1 evaluates to 'true'.

The ILI9331 has a programmable gamma curve, but the kernel does not expose this functionality to user space. However, if I read the data sheet correctly, the ILI9331 applies the same curve to red, green and blue, so the SDL functions could not be supported anyway.

I do not know how to work around this or fix this - other than to render in 8 bit instead of 16 which makes it revert to a CLUT table method though this definitely won't scale nicely - so you'd better be watching your health meter, raising lava levels and whatnot. It's a pity. But, on the bright side, if this magically starts working on future dingux versions a new release will not be needed.

You could implement your own color lookup as part of the scaler routine: map a 16-bit color value to another 16-bit color value. It would cost some performance, but you could do it only for non-default colors (have two separate routines or some macro tricks), so most of the time this step would be skipped.

About the scale routine: you could replace "y320 + x" by a single pointer that is incremented after each pixel written. This would save you from recomputing "y320" after each line. Probably not a noticeable speedup though.

In the AVERAGE macro, is the equals test needed for accuracy or is it for performance? In the latter case, it would be worth it to try without, since a jump might be slower than doing the computation always.

Also it might help to fetch the two original pixels in one go and then apply the average function to a single 32-bit value like this:
Code: [Select]
inline static unsigned short average2(unsigned int twopix)
{
    unsigned int masked = twopix & 0xf7def7de; // clear lowest bit of R/G/B
    return (unsigned short)((masked >> 17) + (masked >> 1));
}

Another thing that would be worth trying is to compute two neighboring pixels and then write them to memory as a single 32-bit value.

nigel

  • Guest
Re: Aleph One
« Reply #28 on: October 26, 2010, 10:57:35 pm »
Thanks for the information!

The documentation of SDL_SetGammaRamp says it returns -1 when programmable gamma correction is not supported and -1 evaluates to 'true'.
I didn't even know that (-1 = true). Should have, considering I am writing quite a bit of php.

Pity about the gamma curve, but nothing that can be helped. I've looked at the unmodified Mac source released in 2000 when MS took over Bungie, but that one doesn't help much. They're using Quickdraw and 'valkyrie acceleration' instructions do do the flashes in 16 and 32 bit. Must have been very fast since that game ran great on a 66MHz PPC machine already using higher colour modes.

You could implement your own color lookup as part of the scaler routine: map a 16-bit color value to another 16-bit color value. It would cost some performance, but you could do it only for non-default colors (have two separate routines or some macro tricks), so most of the time this step would be skipped.
I've thought about that, but currently it's way, WAY beyond my capabilities. Actually I'm still surprised I came so far :P. I've read about this method on google. Perhaps in a few months if I actually get the hang of this C++ thing. Performance will be important though. This game uses long fades, but also does overlays using the gamma function for when underwater. You spend a lot of time underwater in some levels...

As for the scaling speedups, the AVERAGE equal check was there in the example for retaining quality. Since the whole main game window is double-pixeled (that's what the game does in 'lo-res' mode, the Mac didn't support anything lower than 640x480) I thought it might be speedier to leave it in. Actually I didn't change much except for the bitmask above to take away 3 pixels instead of 2. I'll try taking it out, see what it does.
With that and capturing/writing two pixels in one go as you suggested it might match the speed of the 'drop 3 pixels' downscaler Pickle used. That'd be quite awesome indeed!


Even though I thought this was the last update I could do (who am I kidding, been there before with v0), I've already found out some other things. I've verified 256 color mode working fine without any 16 bit conversion afterwards (SDL does this internally it appears, 8 bit is not supported on the hardware for sure). I do need to trace down a few more menu and image color table change calls to get those displayed right, but otherwise the game runs fine - albeit ugly and I'd still have to write some source 8 to 16, scale to temp with box scaler, convert to 8 and move to destination, blit with correct color table thing to keep the terminals which require this to be even remotely readable... well, readable. Perhaps the 16 bit to something else mapping like you suggested isn't such a bad idea after all.

I've also managed to hook something to the overhead map code, so I've reassigned L and R to 'zoom in/out' when the map is active on the screen. They'll revert back to whatever they're assigned to when not viewing the map. That means all vital game buttons are mapped and mapped correctly now :).

nigel

  • Guest
Re: Aleph One
« Reply #29 on: October 28, 2010, 03:58:20 pm »


Went on with this stuff from another perspective. I decided the scaling thing needed to go away. I first made a version that switched between 8 and 16 bit for smooth terminals/map, which worked fine (8 bit for flashes/overlays) but I wasn't happy with it. What you see here is all native 320x240 rendering. The game renderer was already capable of this, as was the map renderer surprisingly. Terminal and HUD needed modifications, as did the positioning of all these elements on the screen but the terminal code already dealt with text-reflowing spanning text over multiple pages if it doesn't fit. Never knew that A1 was capable of that and it certainly ain't documented anywhere but it was a very pleasant surprise.

The HUD is scaled before rendering, as are the pictures inside the terminals but not the terminals themselves. And yes, the text will stay at that size/font for now. My head still hurts from squeezing on the 'readable' terminals in v2 :P.

Don't expect a release too soon. As you see there are still quite a few things to cleanup. Speeds are very nice. Full 30fps @ native 336 clock when running in 16 bit mode. Downside of 16 bit mode is that you have no screen flashes overlays at that depth - although it's now very possible due to great speed I still think the gammaramp thing is over my head. The game also runs in 8 bit as seen in the screens above. It's a little faster than V2 in that mode (Dingoo doesn't do 8 bit, so SDL autoconverts to 16 internally losing some speed).

Seems this game can get the port it deserves after all :).

Solstice

  • Posts: 367
Re: Aleph One
« Reply #30 on: October 28, 2010, 07:30:05 pm »
Great work!! 30fps nice
Dingoo A320 stock 1.2 + Gmenu

PSP slim 2002 Gen 5.50 D3 Prom4

nigel

  • Guest
Re: Aleph One
« Reply #31 on: October 31, 2010, 10:43:11 pm »
You could implement your own color lookup as part of the scaler routine: map a 16-bit color value to another 16-bit color value. It would cost some performance, but you could do it only for non-default colors (have two separate routines or some macro tricks), so most of the time this step would be skipped.

Whoooo, finally pulled it off. And you were right, it is doable in both speed and coding difficulty (took me a while - days - before I understood that a 'gammaramp' is nothing more than a glorified color lookup array, heh). As long as you don't do it with SDL functions. What I've done is hooking something into the code that generates the gamma array to create an array with  32-5/64-6/32-5 values and I've hooked something in the (now native 320x240, or rather, 320x160 for just the game view) rendering code to update the pixels with just shifts and ands. Costs 5 frames/sec max, and I can still gain by eliminating the r, g and b vars which I don't need.


Code below. Forgive me for the mess, I just got it working and still have to clean up.

Here's the AlephOne function that creates the gamma colour tables that normally go into SDL_SetGammaRamp() with hack:
Code: [Select]
void animate_screen_clut(struct color_table *color_table, bool full_screen)
{
if (bit_depth == 8) {
SDL_Color colors[256];
build_sdl_color_table(color_table, colors);
SDL_SetPalette(main_surface, SDL_PHYSPAL, colors, 0, 256); // 8 bit flashes work -- Nigel
} else if (!option_nogamma)
{
// Begin Dingoo software gammaramp hack -- Nigel

Uint8 c = 0;
// Red and blue are 5 bit instead of 16.
printf("%d_", color_table->colors[31].red);
for (int i=0; i<color_table->color_count; i+=8) {
gammatablered[c] = (color_table->colors[i].red >> 11); // This should give a 5 bit int
gammatableblue[c] = (color_table->colors[i].blue >> 11);
c++;
}

// Green, on the other hand, is 6 bit in RGB565/16 bit color.
c=0;
for (int i=0; i<color_table->color_count; i+=4) {
gammatablegreen[c] = (color_table->colors[i].green >> 10); // And this 6 bit.
c++;
}
do_dingoogamma = true;
// printf("count:%d\n", color_table->color_count);
/* uint16 red[256], green[256], blue[256]; // Moved to global space, Dingoo sw gammaramp - Nigel
for (int i=0; i<color_table->color_count; i++) { // [marker] color_count appears to be 256 always andSDL_SetGammaRamp() needs all those 256 colors as well(?), so why not just state '256'?
red[i] = color_table->colors[i].red;
green[i] = color_table->colors[i].green;
blue[i] = color_table->colors[i].blue;
}
if (!option_nogamma)
SDL_SetGammaRamp(red, green, blue); // Gets executed without error, but doesn't work on the dingoo, nor does SDL_SetGamma() ffs!! -Nigel
*/
// END Dingoo hack
}


}

Alephone function that renders the gameworld (sans hud) with hack to apply software gammaramp:
Code: [Select]
static void update_screen(SDL_Rect &source, SDL_Rect &destination, bool hi_rez)
{
// BEGIN Dingoo software gamma hack. For now, we won't do the whole screen but only the game world, this saves processing -- Nigel
if (do_dingoogamma)
{
Uint8 r; // These can go away later.
Uint8 g;
Uint8 b;

Uint32 totalpixels = world_pixels->w * world_pixels->h; // Total pixel count of gameworld.
Uint16* Source = (Uint16 *)world_pixels->pixels; // Yes, that's copypaste with uints and unsigned shorts :P
Uint16* Target = (Uint16 *)world_pixels->pixels;

for (int curpixel = 0; curpixel < totalpixels; curpixel++)
{
/* SDL_GetRGB(*Source, world_pixels->format, &r, &g, &b); // Get RGB of pixel
 * Source++;
 * // Do software gammatable lookup and write pixel.
 * *Target = SDL_MapRGB (world_pixels->format, gammatablered[r], gammatablegreen[g], gammatableblue[b]);
 * Target++;*/

// OK, that isn't doable. What about this?
         r = (*Source >> 11) & 0x1F; //red <<verified>>
         g = (*Source >> 5) & 0x3F; //green is 6 in RGB565, also explains the '11' above <<verified>>
         b = *Source & 0x1F; //blue <<verified>>
Source++;

//*Target = ((gammatablered[r] & 0x1F) << 11 | (gammatablegreen[g] & 0x3F) << 5 | (gammatableblue[b] & 0x1F));
*Target = (gammatablered[r] << 11 | gammatablegreen[g] << 5 | gammatableblue[b]);
Target++;
}
}
// END Dingoo gamma hack

if (hi_rez) {
SDL_BlitSurface(world_pixels, NULL, main_surface, &destination);
}
else {
if (SDL_MUSTLOCK(main_surface))
{
if (SDL_LockSurface(main_surface) < 0) return;
}
switch (world_pixels->format->BytesPerPixel) {
case 1:
quadruple_surface((pixel8 *)world_pixels->pixels, world_pixels->pitch, (pixel8 *)main_surface->pixels, main_surface->pitch, destination);
break;
case 2:
quadruple_surface((pixel16 *)world_pixels->pixels, world_pixels->pitch, (pixel16 *)main_surface->pixels, main_surface->pitch, destination);
break;
case 4:
quadruple_surface((pixel32 *)world_pixels->pixels, world_pixels->pitch, (pixel32 *)main_surface->pixels, main_surface->pitch, destination);
break;
}

if (SDL_MUSTLOCK(main_surface)) {
 SDL_UnlockSurface(main_surface);
}
}
SDL_UpdateRects(main_surface, 1, &destination);
}

Hope this is useful to other C++ beginners. Again, it's more than fast enough. As it is now, the game applies gamma for every frame, even when no effects are in place because it also does default monitor gamma correction or so. I'm gonna fix that later with this do_gamma bool later but this gave me a good idea of the overall speed.


As for the rest of the game, nearly everything is completed for 320x240. Only remaining issues are:
- Main menu, it's scaled to 320 but the clickable areas aren't. You don't notice unless you activate the mouse driver and try to click a button in vain but it'd be nice to fix
- Automap - Zooms out too little for 320x240, I want to add another zoom step
- Sprite clipping issues - Aleph one problem on all platforms, fixed in the 2010 release but that one freezes on the Dingoo and I haven't been able to figure out why - gdb is still arcane magic to me so I'll try to backport the rendering code changes instead to fix this.

Expect a release + source code soon.


EDIT:
Cleaned up:
Code: [Select]
// Put these somewhere in the global scope
uint8 gammatablered[32],  gammatablegreen[64], gammatableblue[32];


// Hook something like this where the program normally calls/builds arrays for SDL_SetGammaRamp()
Uint8 c = 0; // We only need 32 out of 256
for (int i=0; i<256; i+=8) // Red and blue are 5 bit in RGB565/16 bit color.
{
gammatablered[c] = (red-array-normally-passed-to-sdl-setgammaramp[i] >> 11); // This gives you a 5 bit int (original is 16).
gammatableblue[c] = (blue-array-normally-passed-to-sdl-setgammaramp[i] >> 11);
c++;
}
c=0;  // We only need 64 out of 256
for (int i=0; i<256; i+=4)  // Green is 6 bit in RGB565/16 bit color.
{
gammatablegreen[c] = (green-array-normally-passed-to-sdl-setgammaramp[i] >> 10); // This gives you a 6 bit int.
c++;
}


// Call this function to apply the gammaramp to a 16 bit surface (no endianess check!). If you need to apply directly to the screen instead
// of just one or two surfaces that are blitted to the screen additional code is required.
void dingoo_swgammaramp(SDL_Surface *s)
{
Uint32 pixelcount = s->w * s->h; // Total pixel count
Uint16* Source = (Uint16 *)s->pixels;
Uint16* Target = (Uint16 *)s->pixels;

for (Uint32 curpixel = 0; curpixel < pixelcount; curpixel++)
{
*Target = (gammatablered[*Source >> 11 & 0x1F] << 11 | gammatablegreen[*Source >> 5 & 0x3F] << 5 | gammatableblue[*Source & 0x1F]);
Source++; Target++; // You could use one pointer instead of two, this is a bit more clear to read though.
}
}
« Last Edit: November 01, 2010, 03:09:39 am by nigel »

EXL

  • Posts: 29
Re: Aleph One
« Reply #32 on: November 03, 2010, 03:27:16 pm »
Hello, nigel!
Thank you for this wonderful port! :o
How soon will a new version and the source?

nigel

  • Guest
Re: Aleph One
« Reply #33 on: November 04, 2010, 01:50:59 am »
Very soon. Everything is finished, it's just that M1A1 started crashing on launch for unknown reasons - while everything else is doing fine, been pulling my hair out about that one for a day already. But other than that there's nothing to be done.

EDIT: OK, that one is solved too (libsndfile accidentally slipped in again). Everything is done, but it's 5 AM. Will package and put it up (bin+src) later.

EDIT 2: It happened. Hope I didn't overlook anything to include in the zips.
« Last Edit: November 04, 2010, 02:54:18 pm by nigel »