gonetz / GLideN64

A new generation, open-source graphics plugin for N64 emulators.
Other
769 stars 178 forks source link

chopper attack wrong textures #99

Closed olivieryuyu closed 7 years ago

olivieryuyu commented 9 years ago

chopper

olivieryuyu commented 8 years ago

those wrong texture are also on the planes

AmbientMalice commented 8 years ago

Fixed in LLE, seemingly.

olivieryuyu commented 8 years ago

in LLE but not HLE? that is odd

gonetz commented 8 years ago

Nothing odd. It is modified ucode, which uses non-standard method of Specular Highlights calculation. I can't decipher it. In LLE mode it is processed by RSP.

I hacked it in Glide64, but my hack is incorrect also, so I not included it to GLideN64.

olivieryuyu commented 8 years ago

A modified ucode! the game uses RSP SW Version: 2.0H but it can be misleading indeed.

https://tcrf.net/Chopper_Attack

someone could access this debug menu? texture mode seems interesting.

gonetz commented 8 years ago

TEXTURE MODE - Enable or disable texture filtering It is hardly about reflecting textures.

olivieryuyu commented 8 years ago

ok i went to the debug menu, useless indeed.

dsfdsf

here with TR64. Seems ok.

I cannot find the source of the plugin though!!

Someone have it?

gonetz commented 8 years ago

Please compare with LLE first. It can be another hack.

gonetz commented 8 years ago

LLE looks different:

gliden64_chopper_attack_000

olivieryuyu commented 8 years ago

Indeed

😢

Gillou68310 commented 7 years ago

I extracted the load vertex ucode from both goldeneye and chopper attack in order to compare both ucode.

Here's the diff: Left: goldeneye, right: chopper attack capture

Here's the full load vertex ucode extract: F3D_VTX_chopper.txt F3D_VTX_golden.txt

I also extracted the load vertex ucode from pilot wings and the code is exactly the same as goldeneye.

Now I just have to understand what these diff are about :-)

olivieryuyu commented 7 years ago

@Gillou68310: may i get your email address? I need to give you some docs which should be able to help you out in your work.

Very interesting thing btw, I am looking forward to seeing the results :)

gonetz commented 7 years ago

I also extracted the load vertex ucode from pilot wings and the code is exactly the same as goldeneye.

This is expected result, but anyway good to get the proof. Load vertex for both games works the same in my code. PD is different, but it is not enigma also. Also it is good to get the proof that load vertex for Chopper attack is really different.

Gillou68310 commented 7 years ago

may i get your email address

You can get it from https://github.com/Gillou68310 ;-)

olivieryuyu commented 7 years ago

ah yes indeed :)

merci bien gilles :)

Gillou68310 commented 7 years ago

De rien ;-)

Gillou68310 commented 7 years ago

Well from what I see this only has an impact on the final value of r8 which is then stored in memory for each vertex. sh r8, $0024(r7) The least-significant 16-bit halfword of register r8 is stored in memory at the location r7 + 0x24, which is if I'm correct, the location address of vtx.g

sw r8, $004c(r7) The least-significant 32-bit word of register r8 is stored in memory at the location r7 + 0x4c, which is if I'm correct, the location address of vtx.HWLight, vtx.clip and vtx.flag

Gillou68310 commented 7 years ago

@gonetz this doesn't explain why the logo has wrong tex coords. Is it possible that tex coords are modified after load vertex by another GBI command?

olivieryuyu commented 7 years ago

what is puzzling to me is that there is less asm instructions in Chopper attack than the normal one, right? What are the purpose of those instructions? May be the tex coords calculation are depending on them in the normal ucode? Sorry if I am totally wrong here ...

Gillou68310 commented 7 years ago

From what I see those instructions have no impact on tex coords calculation.

weinerschnitzel commented 7 years ago

What about lighting? LLE is also a lot darker than HLE. Edit: Errr. Duh I can has glasses...

The least-significant 32-bit word of register r8 is stored in memory at the location r7 + 0x4c, which is if I'm correct, the location address of vtx.HWLight, vtx.clip and vtx.flag

gonetz commented 7 years ago

@Gillou68310

Is it possible that tex coords are modified after load vertex by another GBI command?

gSPModifyVertex can be used to change any attribute of a vertex. However, it never used to modify generated texture coordinates. Texture coordinates for reflective surfaces generated on vertex load as function of angle between light direction and normal to the surface. If this difference in ucodes not related to vertex texture coordinates (s, t), it is possible that my implementation of texgen functionality is somehow incomplete or does not take into account some important stuff. In that case it also would be useful to decode that part of ucode and find how it works in reality.

gonetz commented 7 years ago

@Gillou68310

sw r8, $004c(r7) The least-significant 32-bit word of register r8 is stored in memory at the location r7 + 0x4c, which is if I'm correct, the location address of vtx.HWLight, vtx.clip and vtx.flag

It is wrong idea to consider SPVertex struct as N64 structure. Actual vertex structure is different, see GBI.h for Vtx_t, Vtx_tn, Vtx

gonetz commented 7 years ago

@Gillou68310

Well from what I see this only has an impact on the final value of r8 which is then stored in memory for each vertex.

This difference in calculations should explain, why Chopper Attack lighting code produces darker result. What instructions, which are missing in Chopper Attack ucode, do?

olivieryuyu commented 7 years ago

:)

Gillou68310 commented 7 years ago

@olivieryuyu shared some usefull ressources with me yesterday.

Here's the original source code of the microcode:

#ifdef NEAR_CLIP_OFF
    ; draw stuff even when it is in front of the near clipping plane
    vmudn   voutbakf, vout12f, voutbaki[0]  ; mult x frustrum
    mfc2    flg1, vout12i[6]                ;n w comp of vtx 1
    andi    flg1, flg1, 0x8000              ;n  neg bit
    srl     flg1, flg1, 13                  ;n  in place
    vmadh   voutbaki, vout12i, voutbaki[0]  ;
    mfc2    flg2, vout12i[14]               ; w comp of vtx 2
    andi    flg2, flg2, 0x8000              ;  neg bit
    srl     flg2, flg2, 9                   ;  in place
    vch     vtmp, vout12i, vout12i[3h]      ; rejection clipcodes
    or      flg2, flg2, flg1                ;n  vtx 1 & 2
    vcl     vtmp, vout12f, vout12f[3h]      ; rejection clipcodes
    cfc2    flg1, $vcc                      ; rejection clipcodes
    vch     vtmp, vout12i, voutbaki[3h]     ; clip/accept clipcodes
    vcl     vtmp, vout12f, voutbakf[3h]     ; clip/accept clipcodes
;n  andi    tmp,  flg1, 0x0707              ; reject clipcodes - vtx 1
;n  andi    flg1, flg1, 0x7070              ; reject clipcodes - vtx 2
    andi    tmp,  flg1, 0x0703              ;n reject clipcodes - vtx 1
    andi    flg1, flg1, 0x7030              ;n reject clipcodes - vtx 2
    or      flg1, flg1, flg2                ;n complete with nearclip
    sll     tmp,  tmp,  4                   ; vtx 1 in 0x00007070
    sll     flg1, flg1, 16                  ; vtx 2 in 0x70700000
    or      flg1, flg1, tmp                 ; all reject clipcodes in place
#else ; NEAR_CLIP_OFF
    ; Don't draw anything in front of the near clipping plane
    vmudn   voutbakf, vout12f, voutbaki[0]  ; mult x frustrum
    vmadh   voutbaki, vout12i, voutbaki[0]  ;
    vch     vtmp, vout12i, vout12i[3h]      ; rejection clipcodes
    vcl     vtmp, vout12f, vout12f[3h]      ; rejection clipcodes
    cfc2    flg1, $vcc                      ; rejection clipcodes
    vch     vtmp, vout12i, voutbaki[3h]     ; clip/accept clipcodes
    vcl     vtmp, vout12f, voutbakf[3h]     ; clip/accept clipcodes
    andi    tmp,  flg1, 0x0707              ; reject clipcodes - vtx 1
    andi    flg1, flg1, 0x7070              ; reject clipcodes - vtx 2
    sll     tmp,  tmp,  4                   ; vtx 1 in 0x00007070
    sll     flg1, flg1, 16                  ; vtx 2 in 0x70700000
    or      flg1, flg1, tmp                 ; all reject clipcodes in place
#endif ; NEAR_CLIP_OFF

As you can see this describes both goldeneye and chopper attack situation. So the only difference between both ucodes is that NEAR_CLIP_OFF is defined for goldeneye and not defined for chopper attack.

Also I made a mistake in the ucode extract I provided. 040015D8 bne r1, 0, $04001774 <- load code if not loaded yet

This is actually jumping to the doLight routine, loading the routine code to IMEM if not loaded yet ;-)

sh r8, $0024(r7) The least-significant 16-bit halfword of register r8 is stored in memory at the location r7 + 0x24, which is if I'm correct, the location address of vtx.g

sw r8, $004c(r7) The least-significant 32-bit word of register r8 is stored in memory at the location r7 + 0x4c, which is if I'm correct, the location address of vtx.HWLight, vtx.clip and vtx.flag

This was also incorrect, those addresses are pointing to the points buffer structure, 2 points are defined, 40 bytes per point, here's the structure definition:

 #  bytes:
 #  0   1   2   3   4   5   6   7   8   9   10  11  12  13  14  15
 #  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .
 #  -----------------------------------------------------------------
 #  | x.int | y.int | z.int | w.int | x.frac| y.frac| z.frac| w.frac|
 #  ----------------------------------------------------------------|
 #  | r | g | b | a |   s   |   t   | xscr  | yscr  | zscr.i|zscr.f |
 #  -----------------------------------------------------------------
 #  | 1/w.i | 1/w.f |  0c0c |flg| 00|
 #  ---------------------------------

If this difference in ucodes not related to vertex texture coordinates (s, t), it is possible that my implementation of texgen functionality is somehow incomplete or does not take into account some important stuff. In that case it also would be useful to decode that part of ucode and find how it works in reality.

That's what I'm going to do next ;-)

gonetz commented 7 years ago

Hmm. Is doLight routine different for Chopper attack? Why result of lighting is different?

Gillou68310 commented 7 years ago

Will check

Gillou68310 commented 7 years ago

Hum I need to make another ucode dump for goldeneye because the path is never taken in the dump I made. However I compared the doLight routine from the chopper attack ucode dump and the one from the original source code and they are identical.

olivieryuyu commented 7 years ago

Golden eye is may be not the best one as it may use a customs ucode for the sky. I do recommend Super Mario 64 Shindou Edition (not the original ones as there may have apparently some differences with the standard ucode for texrec).

Gillou68310 commented 7 years ago

Golden eye is may be not the best one as it may use a customs ucode for the sky. I do recommend Super Mario 64 Shindou Edition (not the original ones as there may have apparently some differences with the standard ucode for texrec).

Too late I already checked with goldeneye ;-)

This was expected but the doLight routine used in goldeneye and chopper attack are identical.

If this difference in ucodes not related to vertex texture coordinates (s, t), it is possible that my implementation of texgen functionality is somehow incomplete or does not take into account some important stuff.

This seems to be our last bullet.

weinerschnitzel commented 7 years ago

Does chopper attack follow the doLight routine in GLideN64?

If that routine is never used in goldeneye, will forcing it make lighting darker?

Gillou68310 commented 7 years ago

The doLight routine is used in both game, it was just not used in the first ucode dump I made from goldeneye.

weinerschnitzel commented 7 years ago

Ah ok. Thanks so much for the RE work. I can't stress enough how appreciated it is.

gonetz commented 7 years ago

The doLight routine is used in both game

Strange. Lighting calculation works correct for all games with standard ucodes. Only Chopper Attack logo is wrong, ingame is ok.

olivieryuyu commented 7 years ago

Yes only this logo seems to be darker, the rest is fine indeed.

The texture issue is also visible on the cockpit of the planes. It is clearly visible when selecting planes in menu. Here no light issue I think both issues may not be link.

What is odd is that only this blue texture is incorrect and all other textures works fine. May be the format of this texture is not properly apprehended, dunno.

Gillou68310 commented 7 years ago

@gonetz where can I get vertex processed by rsp from memory in LLE, I'd like to compare both HLE and LLE results.

gonetz commented 7 years ago

@Gillou68310 OGLRender::drawTriangles() for HLE triangles OGLRender::drawScreenSpaceTriangle for LLE ones

Gillou68310 commented 7 years ago

And where is triangles.dmaVertices filled with data :-) Sorry I'm not used to c++ ;-)

LegendOfDragoon commented 7 years ago

Hum I need to make another ucode dump for goldeneye because the path is never taken in the dump I made.

So I guess the dump I had for Goldeneye is incomplete?

gonetz commented 7 years ago

And where is triangles.dmaVertices filled with data :-) Sorry I'm not used to c++ ;-)

If you use Visual Studio, set breakpoint in drawScreenSpaceTriangle and in debugger you can place triangles.dmaVertices to Watch and see its content. Or use debugPrint to output content of SPVertex to console. For example:

    for (u32 i = 0; i < _numVtx; ++i) {
        SPVertex & vtx = triangles.dmaVertices[i];
        debugPrint("vtx[%d].x = %f\n", i, vtx.x);
        vtx.modify = MODIFY_ALL;
    }
olivieryuyu commented 7 years ago

just noticed that Jabo is totally correct in HLE with this game. Damn, whata pity there is no source of this plugin!

Gillou68310 commented 7 years ago

@gonetz lol I know how to watch the content of triangles.dmaVertices :-) What I want to know is where in your code are vertex processed by rsp copied from rdram to the triangles.dmaVertices vector.

gonetz commented 7 years ago

@Gillou68310 ok, sorry. gDPLLETriangle deals with data prepared by RSP.

Gillou68310 commented 7 years ago

I see it now. I got fooled by the getDMAVerticesData method. I though this was returning a pointer to the vertex data, while it's actually returning a pointer to where vertex data are going to be stored. Sorry for wasting your time.

olivieryuyu commented 7 years ago

@gonetz and @Gillou68310

It may not be an issue of ucode. See #1232. G_TEXTURE_GEN seems to not work as it should.

Gillou68310 commented 7 years ago

@gonetz LLE and HLE triangles are not in the same space coordinate. Do you have any advice in order to compare them?

gonetz commented 7 years ago

You need to transform model space coordinates to screen space, like this

void OGLRender::drawTriangles()
{
...
    for (int i = 0; i < triangles.num; ++i) {
        SPVertex & v = getVertex(triangles.elements[i]);
        float x = gSP.viewport.vtrans[0] + (v.x / v.w) * gSP.viewport.vscale[0];
        float y = gSP.viewport.vtrans[1] + (v.y / v.w) * -gSP.viewport.vscale[1];
        float z = (gSP.viewport.vtrans[2] + (v.z / v.w) * gSP.viewport.vscale[2]) * 32768.0f;
        debugPrint(...);
    }

Note, that due to clipping and precision errors you will not get one-to-one correspondence with LLE triangles. Most likely that even not-clipped triangles will be out in different order in HLE and LLE. It was a pain for me to compare. I usually dumped some portion of vertices in HLE and LLE , copied dump to text file and sorted by coordinates (x and y coordinates logged first) using bash shell: cat log.txt | sort -u > log.out Then I visually compared LLE and HLE dumps for records with the same coordinates, comparing only integer part of coordinates.

Gillou68310 commented 7 years ago

Well that's painful like you said. Anyway thanks for the tuto ;-)

olivieryuyu commented 7 years ago

@Gillou68310

the microcode source of the texture transformation/reflection mapping is in the GFLIGHT.S.

It is in TEXTURE COORDINATE GENERATION / REFLECTION MAPPING, in the texGenRet (which stands for regular method as explained in the N64 programming manual here: https://level42.ca/projects/ultra64/Documentation/man/pro-man/pro11/11-07.html).

The code is complex compared to linear.

IN GlideN64 gSP.cpp it is here I think:

if (gSP.geometryMode & G_TEXTURE_GEN_LINEAR) { vtx.s = acosf(-x) * 325.94931f; vtx.t = acosf(-y) * 325.94931f; } else { // G_TEXTURE_GEN vtx.s = (x + 1.0f) * 512.0f; vtx.t = (y + 1.0f) * 512.0f;

Is it possible to do a comparison? May it could help on this issue and #1232.