Jump to content


Photo

How GM 8.1.141 stores d3d models in memory


  • Please log in to reply
1 reply to this topic

#1 Master Xilo

Master Xilo

    GMC Member

  • GMC Member
  • 379 posts
  • Version:GM8

Posted 18 July 2012 - 08:49 PM

Here's some things I recently figured out when trying to improve the d3d model loading speed of the Game Maker with a dll. I thought this might be quite useful


I first called the model creation functions from within C++ using a stripped down GMAPI which already helped a lot, but then realized that these just copy around some memory, so I figured out the data structure.

Relevant parts of the disassembly:
Spoiler


And now the C struct and offsets (for version 8.1.141):
// Debugger work - found out by looking at d3d_model_vertex_normal_texture_color and the bottom most function it calls
// And the bottom most function that this calls (which just copies the data).
// 

enum VCType {
    vc_primitive_begin = 0,// "d3d_model_primitive_begin",
    vc_primitive_end = 1, // "d3d_model_primitive_end",
    vc_vertex = 2, // "d3d_model_vertex",
    vc_vertex_color = 3, //"d3d_model_vertex_color",
    vc_vertex_texture = 4, //"d3d_model_vertex_texture",
    vc_vertex_texture_color = 5, //"d3d_model_vertex_texture_color",
    vc_vertex_normal = 6, //"d3d_model_vertex_normal",
    vc_vertex_normal_color = 7, //"d3d_model_vertex_normal_color",
    vc_vertex_normal_texture = 8, //"d3d_model_vertex_normal_texture",
    vc_vertex_normal_texture_color = 9, //"d3d_model_vertex_normal_texture_color"
};


// A vertex command entry. Found in Game Maker memory and my compiled format (1 to 1 memory copy)
struct GMVertexCommand {
    unsigned long long commandType; //__int64,  0 to 9, any of VCType
    double data[10]; // The arguments passed to the according VCType function.
};

struct GMModel {
    void* unknown;//classInstance; // / a constant??? (6713788?)
    int vertexCommandCount;
    GMVertexCommand* data; //
    void* gpuData; // 0 if the model was not transferred to the GPU yet
};

GMModel*** gmModels = (GMModel***)0x88E294; // Offset for Game Maker version 8.1.141 (r11549) -- TODO (?) find by pattern

GMModel* gmModel(int modelIndex) {
    return (*gmModels)[modelIndex];
}

Here's how you can use this to make a 3D model a blend between two other ones:
// target and data1/2 may overlap. (point to same data)
void vertexdataBlend(unsigned int commandCount, GMVertexCommand* target, GMVertexCommand* data1, GMVertexCommand* data2, real factor) {
    lineIdToFloatVarCount_TABLE

    dprintf("blending %i vertices\n", commandCount);
    // Interpolate all relevant data blindly.
    double invFactor = 1-factor;

    for (unsigned int i = 0; i < commandCount; i++) {
        int ct = data1[i].commandType;
        target[i].commandType = ct;
  
        if (ct == vc_primitive_begin) 
            target[i].data[0] = data1[i].data[0];
        else if (ct >= vc_vertex) { // assert == data2[i].commandType
            for (unsigned int j = 0; j < lineIdToFloatVarCount[ct]; j++) {
                target[i].data[j] = invFactor*data1[i].data[j] + factor*data2[i].data[j];
            }
        }

    }
}

// Makes modelindex a blend between modelindex1 and modelindex2, may overlap. modelindex must be write enabled. All three models must have the same amount of vertices.
// modelindex1 and modelindex2 should have the same order of vertices for this to make sense.
// Copies the command and primitive begin types of modelindex1 to the target (modelindex)
RESULT_REAL d3d_model_merge(real modelindex, real modelindex1, real modelindex2, real factor) {
    GMModel* t  = gmModel((int)modelindex);
    GMModel* m1 = gmModel((int)modelindex1);
    GMModel* m2 = gmModel((int)modelindex2);
    //system("pause");
    vertexdataBlend(t->vertexCommandCount, t->data, m1->data, m2->data, factor);

    RETURN_VOID;
}

Note that this memory internal format matches the .d3d file format exactly.

It is also important to note that this data will only be used when initially transferring the model to the GPU when it is first rendered with d3d_model_draw - later modification will have no effect.

I'm using this information for writing an extension with a much faster d3d_model_load function (500 ms versus 0.1 ms for a 60k vertex model) and functions to modify the vertices of loaded models, as well as the ability to load and merge two models to generate intermediate frames for per frame 3D model animation.

I'm also hoping to use this to write a voxel terrain engine that runs at acceptable speed: http://gmc.yoyogames...dpost&p=3913192

Regards,
- Paul

Edited by Master Xilo, 19 July 2012 - 01:20 AM.

  • 0

#2 Master Xilo

Master Xilo

    GMC Member

  • GMC Member
  • 379 posts
  • Version:GM8

Posted 19 July 2012 - 04:10 AM

First application: d3d_model_load_fast Extension
  • 0




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users