一. mission_objects
object_type = ['prop', 'entry', 'item', 'unused', 'plant', 'passage']
object = {
'type': object_type[type], 类型,场景物/出生点/通道
'id': id, ID.scene_props.py定义ID
'garbage': '%0#x' % garbage,
'rotation_matrix': [mtx_a, mtx_b, mtx_c], 旋转矩阵(右手坐标系,ZXY顺序旋转),转化后获得沿XYZ旋转角度
'pos': pos, 世界坐标系坐标
'str': str, spr_torch等标识
'entry_no': entry_no, (若为prop则prop_instance_get_variation_id获取)
'menu_entry_no': menu_item_no,(若为prop则prop_instance_get_variation_id_2获取)
'scale': scale, 伸缩变换比例
}
/* -- scene objects */
struct
{
int object_count; /* swy: number of scene/mission objects/props that follow */
struct obj
{
enum <uint32> /* swy: as shown in the edit mode scene editor combobox; same order */
{
Prop = 0, /* Scene Prop */
Entry = 1, /* Entry Point */
Item = 2, /* Item Kind */
Unused = 3,
Plant = 4, /* Flora */
Passage = 5
} type <bgcolor=cBlue>;
/* swy: the index from (ID_scene_props.py or ID_items.py) that (hopefully) matches the
string constant; depending on the object type */
uint32 id;
/* swy: some kind of universal flag that depends on the game version? don't ask me */
enum <uint32>
{
Const_MB_SWC_old = 0x952EFEC,
Const_MB_SWC_c = 0x99EF47C,
Const_MB_SWC_d = 0x387F7E0,
Const_MB_SWC = 0x9A3F034,
Const_MB_a = 0x930F6C4,
Const_MB_TLD = 0x930F6D4,
Const_MB_c = 0x930F6DC,
Const_WB = 0x94AEF80,
Const_MB_Native = 0x3A4EF9C,
Const_WB_Standalo = 0x317F2C0,
Const_MB_Native_a = 0x386F7E8,
Const_MB_Native_b = 0x397F154,
Const_MB_Native_d = 0x940EFD0,
Const_MB_Native_e = 0x947EF90,
Const_MB_Native_f = 0x94FEF94,
} unk <format=hex>; /* swy: looking at the Site::save_site_objects() -> Mission_object::write(rglIO_Stream&) function decompilation, it seems to write weird uninitialized stack garbage */
float mtx_row_a[3]; /* affine 3x3 row-major matrix; encodes rotation and maybe shearing (rglMat3) */
float mtx_row_b[3];
float mtx_row_c[3];
float pos[3]; /* translation; x, y, z */
/* swy: it's set to zero for things without constant; like entry points or passages
the constant hopefully should match the ID. Keep in mind that the game
doesn't seem to use this string field for retrieving anything, only
IDs, so they should be remapped manually after re-shuffling. */
rgltag str <fgcolor=cWhite, bgcolor=cDkBlue>;
/* swy: as shown in the edit mode scene editor; entry number is used for entry point indexes,
while the menu item is used to map passages to city menus */
uint32 entry_no;
uint32 menu_item_no;
float scale[3]; /* scaling multiplier, per axis; x, y, z */
} objects[object_count] <optimize=false, read=sceneprop_read>;
} mission_objects;
二. AI_mesh
静态网格由点/线/面组成,无UV/法向等相关信息.
/* -- ai mesh vertices; probably */
struct
{
uint32 section_size <format=hex>; /* swy: this seems more like a relative offset to skip the block altogether */
uint32 vertex_count;
struct
{
float x;
float y;
float height; /* swy: z is height/up */
} vertex[vertex_count];
uint32 edge_count;
struct
{
int32 face_count; /* swy: adjacency count for nearby polys we are a part of; either 1 or 2 faces, sometimes an edge is used in a single poly */
int32 vtx_a;
int32 vtx_b;
int32 face_idx_r; /* swy: one of these is set to -10000 when some_count is 1 */
int32 face_idx_l; /* mainly the bottom one here, I think it's a main face back-reference */
} edge[edge_count];
uint32 face_count;
struct
{
uint vtx_and_edge_count <bgcolor=cDkGreen>;
uint vertices[vtx_and_edge_count] <bgcolor=cBlue>;
uint edges [vtx_and_edge_count] <bgcolor=cDkBlue>;
uint has_more <bgcolor=cRed>;
if (has_more)
uint ai_mesh_id <bgcolor=cWhite>;
} face[face_count] <optimize=false>;
} ai_mesh;
三. terrain/ground layer
ground_elevation:地形高度增量,PFM Format Description,使用PFM文件进行存储
ground_leveling:地形顶点着色RGB.PPM Format Specification,使用PPM文件进行存储
ground_leveling:着色面积/大小.PGM Format SpecificationPGM文件存储.
struct
{
rglmarker magic <bgcolor=cDkRed>; /* ¦ÑJÿ / 0xff4ad1a6 / ground_paint_saved_magic */
uint32 section_size; /* swy: or a relative offset to the end */
uint32 num_layers;
uint32 scene_width;
uint32 scene_height;
/* swy: if every terrain layer has something in common is that there is
a static number of width * height cells for every type */
local uint block_count = scene_width * scene_height;
struct ground_block
{
enum <int32>
{
gray_stone = 0,
brown_stone = 1,
turf = 2,
steppe = 3,
snow = 4,
earth = 5,
desert = 6, /* swy: sometimes missing, depending on the map; why not just disable it/make it empty */
forest = 7,
pebbles = 8,
village = 9,
path = 10,
ground_elevation = -7793, /* swy: wtfbbq?! */
ground_leveling = -12565, /* swy: more like vertex_coloring */
} index <bgcolor=cBlue>;
rgltag str <fgcolor=cWhite, bgcolor=cDkBlue>;
uint32 enabled;
if (enabled)
{
local int remaining_blocks = block_count;
while (remaining_blocks > 0)
{
struct
{
int rle; /* swy: empty blocks to skip; substract from the total and exit early if no blocks left */
remaining_blocks -= rle;
if (remaining_blocks <= 0)
break;
uint32 elem_count;
//Printf("remaining_blocks = %u -= (%u + %u == %u)\n", remaining_blocks, rle, elem_count, rle + elem_count);
remaining_blocks -= elem_count;
if (index == ground_elevation) float elem[elem_count];
else if (index == ground_leveling) rglcolor elem[elem_count]; /* swy: thanks, scn_village_81.sco, you are a great and terse example of ground_leveling :-) */
else ubyte elem[elem_count] <format=hex>;
/* swconquest-git\SceneObj\scn_mainplanet_sarapin_land_battle.sco */
/* ground_elevation_floats -> 6347 floats / 25388 bytes */
} blockb[1] <optimize=false>;
}
}
} named_block[num_layers] <optimize=false, read=block_read>;
} terrain;