📄 r_model.pas
字号:
procedure Mod_LoadPlanes(l: lump_p);
var
i, j: Integer;
_out: mplane_p;
_in: dplane_p;
count: Integer;
bits: Integer;
begin
_in := Pointer(Integer(mod_base) + l^.fileofs);
if (l^.filelen mod SizeOf(_in^)) <> 0 then
ri.Sys_Error(ERR_DROP, PChar('MOD_LoadBmodel: funny lump size in ' + string(loadmodel^.name)));
count := Trunc(l^.filelen / sizeof(_in^));
_out := Hunk_Alloc((count + 6) * sizeof(_out^)); // extra for skybox
loadmodel^.planes := _out;
loadmodel^.numplanes := count;
for i := 0 to count - 1 do
begin
bits := 0;
for j := 0 to 2 do
begin
_out^.normal[j] := LittleFloat(_in^.normal[j]);
if _out^.normal[j] < 0 then
bits := bits or (1 shl j);
end {next j};
_out^.dist := LittleFloat(_in^.dist);
_out^._type := LittleLong(_in^._type);
_out^.signbits := bits;
inc(Integer(_in), SizeOf(_in^));
inc(Integer(_out), SizeOf(_out^));
end;
end;
(*
=================
Mod_LoadBrushModel
=================
*)
procedure Mod_LoadBrushModel(_mod: model_p; buffer: Pointer);
var
i: Integer;
header: dheader_p;
bm: dmodel_p;
starmod: model_p;
begin
loadmodel^._type := mod_brush;
if loadmodel <> @mod_known[0] then
ri.Sys_Error(ERR_DROP, 'Loaded a brush model after the world');
header := dheader_p(buffer);
i := LittleLong(header^.version);
if i <> BSPVERSION then
ri.Sys_Error(ERR_DROP, PChar('Mod_LoadBrushModel: ' + string(_mod^.name) + ' has wrong version number (' + IntToStr(i) + ' should be ' + IntToStr(BSPVERSION) + ')'));
// swap all the lumps
mod_base := PByte(header);
for i := 0 to (sizeof(dheader_t) div 4) - 1 do
PIntegerArray(header)^[i] := LittleLong(PIntegerArray(header)^[i]);
// load into heap
Mod_LoadVertexes(@header^.lumps[LUMP_VERTEXES]);
Mod_LoadEdges(@header^.lumps[LUMP_EDGES]);
Mod_LoadSurfedges(@header^.lumps[LUMP_SURFEDGES]);
Mod_LoadLighting(@header^.lumps[LUMP_LIGHTING]);
Mod_LoadPlanes(@header^.lumps[LUMP_PLANES]);
Mod_LoadTexinfo(@header^.lumps[LUMP_TEXINFO]);
Mod_LoadFaces(@header^.lumps[LUMP_FACES]);
Mod_LoadMarksurfaces(@header^.lumps[LUMP_LEAFFACES]);
Mod_LoadVisibility(@header^.lumps[LUMP_VISIBILITY]);
Mod_LoadLeafs(@header^.lumps[LUMP_LEAFS]);
Mod_LoadNodes(@header^.lumps[LUMP_NODES]);
Mod_LoadSubmodels(@header^.lumps[LUMP_MODELS]);
r_numvisleafs := 0;
R_NumberLeafs(loadmodel^.nodes);
//
// set up the submodels
//
for i := 0 to _mod^.numsubmodels - 1 do
begin
bm := dmodel_p(Integer(_mod^.submodels) + (i * SizeOf(dmodel_t)));
starmod := @mod_inline[i];
starmod^ := loadmodel^;
starmod^.firstmodelsurface := bm^.firstface;
starmod^.nummodelsurfaces := bm^.numfaces;
starmod^.firstnode := bm^.headnode;
if starmod^.firstnode >= loadmodel^.numnodes then
ri.Sys_Error(ERR_DROP, PChar('Inline model ' + IntToStr(i) + ' has bad firstnode'));
VectorCopy(bm^.maxs, starmod^.maxs);
VectorCopy(bm^.mins, starmod^.mins);
if i = 0 then
loadmodel^ := starmod^;
end {next i};
R_InitSkyBox;
end;
(*
==============================================================================
ALIAS MODELS
==============================================================================
*)
(*
=================
Mod_LoadAliasModel
=================
*)
procedure Mod_LoadAliasModel(_mod: model_p; buffer: Pointer);
var
i, j: Integer;
pinmodel, pheader: dmdl_p;
pinst, poutst: dstvert_p;
pintri, pouttri: dtriangle_p;
pinframe, poutframe: daliasframe_p;
pincmd, poutcmd: PInteger;
version: Integer;
begin
pinmodel := dmdl_p(buffer);
version := LittleLong(pinmodel^.version);
if version <> ALIAS_VERSION then
ri.Sys_Error(ERR_DROP, PChar(string(_mod^.name) + ' has wrong version number (' + IntToStr(version) + ' should be ' + IntToStr(ALIAS_VERSION)));
pheader := Hunk_Alloc(LittleLong(pinmodel^.ofs_end));
// byte swap the header fields and sanity check
for i := 0 to (sizeof(dmdl_t) div 4) - 1 do
PIntegerArray(pheader)^[i] := LittleLong(PIntegerArray(buffer)^[i]);
if pheader^.skinheight > MAX_LBM_HEIGHT then
ri.Sys_Error(ERR_DROP, PChar('model ' + string(_mod^.name) + ' has a skin taller than ' + IntToStr(MAX_LBM_HEIGHT)));
if pheader^.num_xyz <= 0 then
ri.Sys_Error(ERR_DROP, PChar('model ' + string(_mod^.name) + ' has no vertices'));
if pheader^.num_xyz > MAX_VERTS then
ri.Sys_Error(ERR_DROP, PChar('model ' + string(_mod^.name) + ' has too many vertices'));
if pheader^.num_st <= 0 then
ri.Sys_Error(ERR_DROP, PChar('model ' + string(_mod^.name) + ' has no st vertices'));
if pheader^.num_tris <= 0 then
ri.Sys_Error(ERR_DROP, PChar('model ' + string(_mod^.name) + ' has no triangles'));
if pheader.num_frames <= 0 then
ri.Sys_Error(ERR_DROP, PChar('model ' + string(_mod^.name) + ' has no frames'));
//
// load base s and t vertices (not used in gl version)
//
pinst := dstvert_p(Integer(pinmodel) + pheader^.ofs_st);
poutst := dstvert_p(Integer(pheader) + pheader^.ofs_st);
for i := 0 to pheader^.num_st - 1 do
begin
poutst^.s := LittleShort(pinst^.s);
poutst^.t := LittleShort(pinst^.t);
Inc(Integer(pinst), SizeOf(dstvert_t));
Inc(Integer(poutst), SizeOf(dstvert_t));
// dstvert_a(poutst)[i].s := LittleShort(dstvert_a(pinst)[i].s);
// dstvert_a(poutst)[i].t := LittleShort(dstvert_a(pinst)[i].t);
end {next i};
//
// load triangle lists
//
pintri := dtriangle_p(Integer(pinmodel) + pheader^.ofs_tris);
pouttri := dtriangle_p(Integer(pheader) + pheader^.ofs_tris);
for i := 0 to pheader^.num_tris - 1 do
begin
for j := 0 to 2 do
begin
pouttri^.index_xyz[j] := LittleShort(pintri^.index_xyz[j]);
pouttri^.index_st[j] := LittleShort(pintri^.index_st[j]);
// dtriangle_a(pouttri)[i].index_xyz[j] := LittleShort(dtriangle_a(pintri)[i].index_xyz[j]);
// dtriangle_a(pouttri)[i].index_st[j] := LittleShort(dtriangle_a(pintri)[i].index_st[j]);
end {next j};
Inc(Integer(pouttri), SizeOf(pouttri^));
Inc(Integer(pintri), SizeOf(pintri^));
end {next i};
//
// load the frames
//
for i := 0 to pheader^.num_frames - 1 do
begin
pinframe := daliasframe_p(Integer(pinmodel) + pheader^.ofs_frames + i * pheader^.framesize);
poutframe := daliasframe_p(Integer(pheader) + pheader^.ofs_frames + i * pheader^.framesize);
Move(pinframe^.name, poutframe^.name, SizeOf(poutframe^.name));
for j := 0 to 2 do
begin
poutframe^.scale[j] := LittleFloat(pinframe^.scale[j]);
poutframe^.translate[j] := LittleFloat(pinframe^.translate[j]);
end {next j};
// verts are all 8 bit, so no swapping needed
move(pinframe^.verts[0], poutframe^.verts[0], pheader^.num_xyz * sizeof(dtrivertx_t));
end {next i};
_mod^._type := mod_alias;
//
// load the glcmds
//
pincmd := PInteger(Integer(pinmodel) + pheader^.ofs_glcmds);
poutcmd := PInteger(Integer(pheader) + pheader^.ofs_glcmds);
for i := 0 to pheader^.num_glcmds - 1 do
PIntegerArray(poutcmd)^[i] := LittleLong(PIntegerArray(pincmd)^[i]);
// register all skins
move(PChar(Integer(pinmodel) + pheader^.ofs_skins)^,
PChar(Integer(pheader) + pheader^.ofs_skins)^,
pheader^.num_skins * MAX_SKINNAME);
for i := 0 to pheader.num_skins - 1 do
begin
_mod^.skins[i] := R_FindImage(PChar(Integer(pheader) + pheader.ofs_skins + i * MAX_SKINNAME), it_skin);
end {next i};
end {procedure};
(*
==============================================================================
SPRITE MODELS
==============================================================================
*)
(*
=================
Mod_LoadSpriteModel
=================
*)
procedure Mod_LoadSpriteModel(_mod: model_p; buffer: Pointer);
var
sprin: dsprite_p;
sprout: dsprite_p;
i: Integer;
begin
sprin := dsprite_p(buffer);
sprout := Hunk_Alloc(modfilelen);
sprout^.ident := LittleLong(sprin^.ident);
sprout^.version := LittleLong(sprin^.version);
sprout^.numframes := LittleLong(sprin^.numframes);
if sprout^.version <> SPRITE_VERSION then
ri.Sys_Error(ERR_DROP, PChar(string(_mod^.name) + ' has wrong version number (' + IntToStr(sprout^.version) + ' should be ' + IntToStr(SPRITE_VERSION) + ')'));
if sprout^.numframes > MAX_MD2SKINS then
ri.Sys_Error(ERR_DROP, PChar(string(_mod^.name) + ' has too many frames (' + IntToStr(sprout^.numframes) + ' > ' + IntToStr(MAX_MD2SKINS) + ')'));
// byte swap everything
for i := 0 to sprout^.numframes - 1 do
begin
sprout^.frames[i].width := LittleLong(sprin^.frames[i].width);
sprout^.frames[i].height := LittleLong(sprin^.frames[i].height);
sprout^.frames[i].origin_x := LittleLong(sprin^.frames[i].origin_x);
sprout^.frames[i].origin_y := LittleLong(sprin^.frames[i].origin_y);
move(sprin^.frames[i].name[0], sprout^.frames[i].name[0], MAX_SKINNAME);
_mod^.skins[i] := R_FindImage(sprout^.frames[i].name, it_sprite);
end;
_mod^._type := mod_sprite;
end {procedure};
//=============================================================================
(*
@@@@@@@@@@@@@@@@@@@@@
R_BeginRegistration
Specifies the model that will be used as the world
@@@@@@@@@@@@@@@@@@@@@
*)
procedure R_BeginRegistration(model: PChar); cdecl;
var
fullname: array[0..MAX_QPATH - 1] of Char;
flushmap: cvar_p;
begin
inc(registration_sequence);
r_oldviewcluster := -1; // force markleafs
Com_sprintf(fullname, sizeof(fullname), 'maps/%s.bsp', [model]);
D_FlushCaches;
// explicitly free the old map if different
// this guarantees that mod_known[0] is the world map
flushmap := ri.Cvar_Get('flushmap', '0', 0);
if (strcomp(PChar(@mod_known[0].name), fullname) <> 0) or (flushmap^.value <> 0.0) then
Mod_Free(@mod_known[0]);
r_worldmodel := R_RegisterModel(fullname);
R_NewMap;
end {procedure};
(*
@@@@@@@@@@@@@@@@@@@@@
R_RegisterModel
@@@@@@@@@@@@@@@@@@@@@
*)
function R_RegisterModel(name: PChar): Pointer;
var
_mod: model_p;
i: Integer;
sprout: dsprite_p;
pheader: dmdl_p;
begin
_mod := Mod_ForName(name, false);
if _mod <> nil then
begin
_mod^.registration_sequence := registration_sequence;
// register any images used by the models
if _mod^._type = mod_sprite then
begin
sprout := dsprite_p(_mod^.extradata);
for i := 0 to sprout^.numframes - 1 do
_mod^.skins[i] := R_FindImage(PChar(@sprout^.frames[i].name), it_sprite);
end
else
if _mod^._type = mod_alias then
begin
pheader := dmdl_p(_mod^.extradata);
for i := 0 to pheader^.num_skins - 1 do
_mod^.skins[i] := R_FindImage(PChar(Integer(pheader) + pheader^.ofs_skins + i * MAX_SKINNAME), it_skin);
//PGM
_mod^.numframes := pheader^.num_frames;
//PGM
end
else
if _mod^._type = mod_brush then
begin
for i := 0 to _mod^.numtexinfo - 1 do
mtexinfo_p(Integer(_mod^.texinfo) + (i * SizeOf(mtexinfo_t)))^.image^.registration_sequence := registration_sequence;
end;
end;
Result := _mod;
end;
(*
@@@@@@@@@@@@@@@@@@@@@
R_EndRegistration
@@@@@@@@@@@@@@@@@@@@@
*)
procedure R_EndRegistration;
var
i: Integer;
_mod: model_p;
begin
_mod := @mod_known[0];
for i := 0 to mod_numknown - 1 do
begin
if _mod^.name[0] = #0 then
begin
Inc(Integer(_mod), SizeOf(_mod^));
continue;
end;
if _mod^.registration_sequence <> registration_sequence then
begin
// don't need this model
Hunk_Free(_mod^.extradata);
FillChar(_mod^, sizeof(_mod^), 0);
end
else
begin
// make sure it is paged in
Com_PageInMemory(_mod^.extradata, _mod^.extradatasize);
end;
Inc(Integer(_mod), SizeOf(_mod^));
end;
R_FreeUnusedImages;
end;
//=============================================================================
(*
================
Mod_Free
================
*)
procedure Mod_Free(_mod: model_p);
begin
Hunk_Free(_mod^.extradata);
FillChar(_mod^, sizeof(_mod^), 0);
end {procedure};
(*
================
Mod_FreeAll
================
*)
procedure Mod_FreeAll;
var
i: Integer;
begin
for i := 0 to mod_numknown - 1 do
begin
if mod_known[i].extradatasize <> 0 then
begin
Mod_Free(@mod_known[i]);
end {if};
end {next i};
end {procedure};
initialization
// Check the size of types defined in r_model.h
Assert(sizeof(mvertex_t) = 12);
Assert(sizeof(mplane_t) = 20);
Assert(sizeof(medge_t) = 8);
Assert(sizeof(mtexinfo_t) = 52);
Assert(sizeof(msurface_t) = 68);
Assert(sizeof(mnode_t) = 40);
Assert(sizeof(mleaf_t) = 44);
Assert(sizeof(modtype_t) = 4);
Assert(sizeof(model_t) = 368);
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -