MW2 Rendering: Difference between revisions

From COD Engine Research
Jakes625 (talk | contribs)
Jakes625 (talk | contribs)
Line 48: Line 48:
Compare funcs: NEVER, LESS, EQUAL, LEQUAL, GREATER, NOTEQUAL, GEQUAL, ALWAYS
Compare funcs: NEVER, LESS, EQUAL, LEQUAL, GREATER, NOTEQUAL, GEQUAL, ALWAYS
Depth funcs seen: ALWAYS, LESS, EQUAL, LEQUAL
Depth funcs seen: ALWAYS, LESS, EQUAL, LEQUAL
</syntaxhighlight>
=== Render Side Usage ===
<syntaxhighlight lang="C">
typedef struct RsxCommand {
    unsigned int method;
    unsigned int value;
    const char *name; // correlated display/debug name
} RsxCommand;
static const GfxStateBits *SelectStateBits(
    const MaterialAsset *material,
    int techniqueSlot)
{
    for (int i = 0; i < 37; i++) {
        MaterialStateBitsEntry e = material->stateBitsEntries[i];
        if (e.techniqueSlot == techniqueSlot &&
            e.stateBitsIndex < material->stateBitsCount) {
            return &material->stateBits[e.stateBitsIndex];
        }
    }
    return 0;
}
static int DecodeMaterialStateBits(
    const GfxStateBits *state,
    RsxCommand *out,
    int maxOut)
{
    int n = 0;
    unsigned int word0 = state->loadBits[0];
    unsigned int word1 = state->loadBits[1];
    // The exact bit extraction still needs to be completed from PS3 traces.
    // These are examples of the bridge destination methods, not final masks.
    out[n++] = (RsxCommand){
        .method = 0x0324,
        .value = /* decoded color mask from word0 */ 0xf,
        .name = "NV30_3D_COLOR_MASK"
    };
    out[n++] = (RsxCommand){
        .method = 0x0A74,
        .value = /* decoded depth-test enable from word1 */ 1,
        .name = "NV30_3D_DEPTH_TEST_ENABLE"
    };
    out[n++] = (RsxCommand){
        .method = 0x0A6C,
        .value = /* lookup decoded depth func */ 0x0201,
        .name = "NV30_3D_DEPTH_FUNC"
    };
    out[n++] = (RsxCommand){
        .method = 0x0310,
        .value = /* decoded blend enable from word0 */ 0,
        .name = "NV30_3D_BLEND_FUNC_ENABLE"
    };
    return n;
}
void DrawGfxWorld(BaseAsset *asset)
{
    if (!asset || asset->kind != ASSET_GFX_WORLD)
        return;
    GfxWorldAsset *world = (GfxWorldAsset *)asset;
    for (unsigned int i = 0; i < world->surfaceCount; i++) {
        GfxSurface *surface = &world->surfaces[i];
        MaterialAsset *material = surface->material;
        if (!material)
            continue;
        int techniqueSlot = 0; // selected by draw path/pass
        const GfxStateBits *state = SelectStateBits(material, techniqueSlot);
        if (state) {
            RsxCommand cmds[64];
            int count = DecodeMaterialStateBits(state, cmds, 64);
            for (int c = 0; c < count; c++) {
                // In the real renderer this becomes Silk/OpenGL state,
                // but the RSX command/value remains the source of truth.
                ApplyOrRecordRsxCommand(cmds[c].method, cmds[c].value, cmds[c].name);
            }
        }
        DrawSurfaceGeometry(surface, material);
    }
}
</syntaxhighlight>
The key relationship is:
<syntaxhighlight>
    GfxWorldAsset
      -> GfxSurface
          -> MaterialAsset
              -> technique slot
                  -> GfxStateBits row
                      -> raw loadBits
                          -> RSX/NV4097 commands
</syntaxhighlight>
</syntaxhighlight>


== Xbox 360 ==
== Xbox 360 ==
<code>n/a</code>
<code>n/a</code>

Revision as of 18:40, 5 July 2026

Rendering

This section is to give you information on how to render surfaces, triangles, maps and apply texture blends and material technique sets per platform.

Playstation 3

The ps3 uses a different translation due to it's RSX chip.

RSX Method Names

Mapped material-state methods:

  • NV30_3D_COLOR_MASK
  • NV30_3D_ALPHA_FUNC_ENABLE
  • NV30_3D_ALPHA_FUNC_FUNC
  • NV30_3D_ALPHA_FUNC_REF
  • NV30_3D_CULL_FACE_ENABLE
  • NV30_3D_CULL_FACE
  • NV30_3D_POLYGON_MODE_FRONT
  • NV30_3D_POLYGON_MODE_BACK
  • NV30_3D_BLEND_FUNC_ENABLE
  • NV40_3D_BLEND_EQUATION
  • NV30_3D_BLEND_FUNC_SRC
  • NV30_3D_BLEND_FUNC_DST
  • NV30_3D_DEPTH_WRITE_ENABLE
  • NV30_3D_DEPTH_TEST_ENABLE
  • NV30_3D_DEPTH_FUNC
  • NV30_3D_POLYGON_OFFSET_FILL_ENABLE
  • NV30_3D_POLYGON_OFFSET_FACTOR
  • NV30_3D_POLYGON_OFFSET_UNITS
  • NV30_3D_STENCIL_ENABLE
  • NV30_3D_STENCIL_OP_FAIL/ZFAIL/ZPASS
  • NV30_3D_STENCIL_FUNC_FUNC

Texture/program names:

  • NV30_3D_TEX_OFFSET
  • NV30_3D_TEX_FORMAT
  • NV30_3D_TEX_NPOT_SIZE
  • NV40_3D_TEX_SIZE1
  • NV30_3D_TEX_SWIZZLE
  • NV30_3D_TEX_ENABLE
  • NV30_3D_TEX_FILTER
  • NV30_3D_TEX_WRAP
  • NV30_3D_FP_ACTIVE_PROGRAM

Enum/Payload Names

From the TOC[-0x7174] lookup table:

Blend equation: FUNC_ADD, FUNC_SUBTRACT, FUNC_REVERSE_SUBTRACT, MIN, MAX
Blend factors: SRC_COLOR, ONE_MINUS_SRC_COLOR, SRC_ALPHA, ONE_MINUS_SRC_ALPHA, DST_ALPHA, ONE_MINUS_DST_ALPHA, DST_COLOR, ONE_MINUS_DST_COLOR
Stencil ops: KEEP, REPLACE, INCR, DECR, INVERT, INCR_WRAP, DECR_WRAP
Compare funcs: NEVER, LESS, EQUAL, LEQUAL, GREATER, NOTEQUAL, GEQUAL, ALWAYS
Depth funcs seen: ALWAYS, LESS, EQUAL, LEQUAL

Render Side Usage

typedef struct RsxCommand {
    unsigned int method;
    unsigned int value;
    const char *name; // correlated display/debug name
} RsxCommand;

static const GfxStateBits *SelectStateBits(
    const MaterialAsset *material,
    int techniqueSlot)
{
    for (int i = 0; i < 37; i++) {
        MaterialStateBitsEntry e = material->stateBitsEntries[i];

        if (e.techniqueSlot == techniqueSlot &&
            e.stateBitsIndex < material->stateBitsCount) {
            return &material->stateBits[e.stateBitsIndex];
        }
    }

    return 0;
}

static int DecodeMaterialStateBits(
    const GfxStateBits *state,
    RsxCommand *out,
    int maxOut)
{
    int n = 0;

    unsigned int word0 = state->loadBits[0];
    unsigned int word1 = state->loadBits[1];

    // The exact bit extraction still needs to be completed from PS3 traces.
    // These are examples of the bridge destination methods, not final masks.

    out[n++] = (RsxCommand){
        .method = 0x0324,
        .value = /* decoded color mask from word0 */ 0xf,
        .name = "NV30_3D_COLOR_MASK"
    };

    out[n++] = (RsxCommand){
        .method = 0x0A74,
        .value = /* decoded depth-test enable from word1 */ 1,
        .name = "NV30_3D_DEPTH_TEST_ENABLE"
    };

    out[n++] = (RsxCommand){
        .method = 0x0A6C,
        .value = /* lookup decoded depth func */ 0x0201,
        .name = "NV30_3D_DEPTH_FUNC"
    };

    out[n++] = (RsxCommand){
        .method = 0x0310,
        .value = /* decoded blend enable from word0 */ 0,
        .name = "NV30_3D_BLEND_FUNC_ENABLE"
    };

    return n;
}

void DrawGfxWorld(BaseAsset *asset)
{
    if (!asset || asset->kind != ASSET_GFX_WORLD)
        return;

    GfxWorldAsset *world = (GfxWorldAsset *)asset;

    for (unsigned int i = 0; i < world->surfaceCount; i++) {
        GfxSurface *surface = &world->surfaces[i];
        MaterialAsset *material = surface->material;

        if (!material)
            continue;

        int techniqueSlot = 0; // selected by draw path/pass
        const GfxStateBits *state = SelectStateBits(material, techniqueSlot);

        if (state) {
            RsxCommand cmds[64];
            int count = DecodeMaterialStateBits(state, cmds, 64);

            for (int c = 0; c < count; c++) {
                // In the real renderer this becomes Silk/OpenGL state,
                // but the RSX command/value remains the source of truth.
                ApplyOrRecordRsxCommand(cmds[c].method, cmds[c].value, cmds[c].name);
            }
        }

        DrawSurfaceGeometry(surface, material);
    }
}

The key relationship is:

    GfxWorldAsset
      -> GfxSurface
          -> MaterialAsset
              -> technique slot
                  -> GfxStateBits row
                      -> raw loadBits
                          -> RSX/NV4097 commands

Xbox 360

n/a