CAST II is a so called "data driven" engine. The only right way to use it is to prepare your data (scenes in case of an engine) and pass it to the engine. The engine should convert the data to optimal format and give an interface for in-game logic to make manipulations on the scene without loss of optimizations.
If you will load models, call API functions to change textures and other states and so on, an engine will be unable to optimize anything.
If you have two models and a landscape it's not a problem (and may be you do not need an engine in that case), but if you making a serious game with thousands of objects and materials, it is. And it's almost impossible to load and setup all these objects in code. Therefore any good engine should have an editor to do that work.
Of course, there is a way to load assets properly.
Here is a code from CASTEd which loads .obj model:
// Loads one or more .obj files making them a child noted to ParentNode.
// If number of files is more than one them can be used as frames for animation (vertex morphing).
procedure TFResTools.LoadObjFiles(ParentNode: TItem; AFiles: TStrings);
var
i: Integer;
VRes: array of TVerticesResource; // Vertex resources for models
IRes: array of TIndicesResource; // Index resources for models
TRes: TImageResource; // Texture resource
Actor: TMesh; // Scene item in case of non-animated model
AnimActor: TMorphedItem; // Scene item in case of vertex morphing animated model
Props: TProperties; // Properties
Mat: TMaterial; // Material item
Garbage: IRefcountedContainer;
Animated: Boolean;
SnapIndex: Integer; // Index of vertex to snap vertex morphing animated model to
// Creates and sets up a default material with texture in TRes
procedure AddMaterial;
var Tech: TTechnique; Pass: TRenderPass;
begin
Pass := TRenderPass.Create(Core); // First and only pass
Tech := TTechnique.Create(Core); // Default technique
Mat := TMaterial.Create(Core); // Material itself
Mat.Name := GetFileName(AFiles[0]);
ParentNode.AddChild(Mat); // Add material to scene
Mat.AddChild(Tech); // Also technique
Tech.AddChild(Pass); // And pass
// Set up technique properties
Props.Clear;
Props.Add('Total passes', vtInt, [], '1', '');
Props.Add('Pass #0', vtObjectLink, [], Pass.GetFullName, ''); // Add link to the pass
Tech.SetProperties(Props); // Apply properties
// Set up material properties
Props.Clear;
Props.Add('Total techniques', vtInt, [], '1', '');
Props.Add('Technique #0', vtObjectLink, [], Tech.GetFullName, ''); // Add link to the technique
Mat.SetProperties(Props); // Apply properties
// Set up pass properties
Props.Add('Total stages', vtNat, [], '1', '');
if Assigned(TRes) then begin
ParentNode.AddChild(TRes);
Props.Add('Stage #0\Texture', vtObjectLink, [], TRes.GetFullName, ''); // Add link to texture
end;
Pass.SetProperties(Props); // Apply properties
Pass.State := Pass.State + [isVisible]; // Make the pass visible
end;
const GeomPrefix = 'Geometry\Frame #%D '; // Use in Format()
begin
Mat := nil;
Props := TProperties.Create;
// setup garbage collector
Garbage := CreateRefcountedContainer;
Garbage.AddObject(Props);
Animated := False;
case AFiles.Count of
0: Exit;
1: ;
else if ModelLoadF.ShowModal = mrOK then begin // Let a user to choose if the model has animation
Animated := ModelLoadF.PageControl1.ActivePageIndex = 1;
if ModelLoadF.SnapCBox.Checked then
SnapIndex := StrToIntDef(ModelLoadF.SnapIndexEdit.Text, -1) else
SnapIndex := -1;
end else Exit;
end;
// Create a scene item for a model with animation
if Animated then begin
AnimActor := TMorphedItem.Create(Core);
AnimActor.Name := GetFileName(AFiles[0]);
ParentNode.AddChild(AnimActor);
AnimActor.TotalFrames := AFiles.Count;
end;
SetLength(VRes, AFiles.Count);
SetLength(IRes, AFiles.Count);
// For each file
for i := 0 to AFiles.Count-1 do begin
// Try to load model
if not LoadObj(AFiles[i], VRes[i], IRes[i], TRes) then begin
{$IFDEF LOGGING} Log.Log('Failed to load file "' + AFiles[i] + '"', lkError); {$ENDIF}
Continue;
end;
// Setup material
if not Animated then
AddMaterial
else if not Assigned(Mat) then begin
AddMaterial;
if Assigned(Mat) then Props.Add('Material', vtObjectLink, [], Mat.GetFullName, '');
end;
Actor := nil;
if Assigned(VRes) then begin
ParentNode.AddChild(VRes[i]); // Add resource containing vertices to scene
if Animated then begin // Setup vertices and indices for animated models
Props.Add(Format(GeomPrefix + 'vertices', [i]), vtObjectLink, [], VRes[i].GetFullName, '');
if Assigned(IRes) then begin
ParentNode.AddChild(IRes[i]);
Props.Add(Format(GeomPrefix + 'indices', [i]), vtObjectLink, [], IRes[i].GetFullName, '');
end;
if (SnapIndex >= 0) and (i > 0) then // Snap model to the specified vertex
ScaleForm.MoveVertices(VRes[i], SubVector3s(VRes[0].VertexCoords[SnapIndex], VRes[i].VertexCoords[SnapIndex]));
end else begin // Setup vertices and indices for non-animated models
Props.Clear;
Actor := TMesh.Create(Core); // Create a new scene item for model
Actor.Name := GetFileName(AFiles[0]);
ParentNode.AddChild(Actor); // Add to scene
// Setup material property
if Assigned(Mat) then Props.Add('Material', vtObjectLink, [], Mat.GetFullName, '');
end;
// Setup vertex and index resources for model
if not Animated or (i = 0) then begin
Props.Add('Geometry\Vertices', vtObjectLink, [], VRes[i].GetFullName, '');
if Assigned(IRes) then begin
ParentNode.AddChild(IRes[i]);
Props.Add('Geometry\Indices', vtObjectLink, [], IRes[i].GetFullName, '');
end;
end;
end;
end;
// Apply properties to item
if Animated then begin
AnimActor.SetProperties(Props);
AnimActor.SetFrames(0, 0, 0);
end else
Actor.SetProperties(Props);
// Refresh items tree of CASTEd
MainF.ItemsFrame1.RefreshTree;
if Assigned(Actor) then MainF.ItemsFrame1.SelectItem(Actor, False);
// Show up model manipulation tools
ScaleForm.Show;
end;
Thank you for pointing on a problem with .bpl. I'll update the files to fix it now.