Closed olivieryuyu closed 7 years ago
those wrong texture are also on the planes
Fixed in LLE, seemingly.
in LLE but not HLE? that is odd
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.
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.
TEXTURE MODE - Enable or disable texture filtering It is hardly about reflecting textures.
ok i went to the debug menu, useless indeed.
here with TR64. Seems ok.
I cannot find the source of the plugin though!!
Someone have it?
Please compare with LLE first. It can be another hack.
LLE looks different:
Indeed
😢
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
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 :-)
@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 :)
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.
may i get your email address
You can get it from https://github.com/Gillou68310 ;-)
ah yes indeed :)
merci bien gilles :)
De rien ;-)
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
@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?
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 ...
From what I see those instructions have no impact on tex coords calculation.
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
@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.
@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
@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 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 ;-)
Hmm. Is doLight routine different for Chopper attack? Why result of lighting is different?
Will check
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.
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).
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.
Does chopper attack follow the doLight routine in GLideN64?
If that routine is never used in goldeneye, will forcing it make lighting darker?
The doLight routine is used in both game, it was just not used in the first ucode dump I made from goldeneye.
Ah ok. Thanks so much for the RE work. I can't stress enough how appreciated it is.
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.
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.
@gonetz where can I get vertex processed by rsp from memory in LLE, I'd like to compare both HLE and LLE results.
@Gillou68310 OGLRender::drawTriangles() for HLE triangles OGLRender::drawScreenSpaceTriangle for LLE ones
And where is triangles.dmaVertices filled with data :-) Sorry I'm not used to c++ ;-)
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?
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;
}
just noticed that Jabo is totally correct in HLE with this game. Damn, whata pity there is no source of this plugin!
@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.
@Gillou68310 ok, sorry. gDPLLETriangle deals with data prepared by RSP.
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.
@gonetz and @Gillou68310
It may not be an issue of ucode. See #1232. G_TEXTURE_GEN seems to not work as it should.
@gonetz LLE and HLE triangles are not in the same space coordinate. Do you have any advice in order to compare them?
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.
Well that's painful like you said. Anyway thanks for the tuto ;-)
@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.