2
// This unit is part of the GLScene Engine https://github.com/glscene
5
The object manager is used for registering classes together with a category,
6
description + icon, so that they can be displayed visually. This can then
7
be used by run-time or design-time scene editors for choosing which
8
scene objects to place into a scene.
10
TODO: add some notification code, so that when a scene object is registered/
11
unregistered, any editor that is using the object manager can be notified.
14
11/11/09 - DaStr - Improved FPC compatibility
15
(thanks Predator) (BugtrackerID = 2893580)
16
25/07/09 - DaStr - Added $I GLScene.inc
17
26/03/09 - DanB - Added PopulateMenuWithRegisteredSceneObjects procedure.
18
14/03/09 - DanB - Created by moving TGLObjectManager in from GLSceneRegister.pas,
19
made some slight adjustments to allow resources being loaded
20
from separate packages.
42
PSceneObjectEntry = ^TGLSceneObjectEntry;
43
// holds a relation between an scene object class, its global identification,
44
// its location in the object stock and its icon reference
45
TGLSceneObjectEntry = record
46
ObjectClass: TGLSceneObjectClass;
47
Name: string; // type name of the object
48
Category: string; // category of object
49
Index, // index into "FSceneObjectList"
50
ImageIndex: Integer; // index into "FObjectIcons"
55
TGLObjectManager = class(TComponent)
58
FSceneObjectList: TList;
59
FObjectIcons: TImageList; // a list of icons for scene objects
61
FOverlayIndex, // indices into the object icon list
65
FLightsourceRootIndex,
66
FObjectRootIndex: Integer;
69
procedure DestroySceneObjectList;
70
function FindSceneObjectClass(AObjectClass: TGLSceneObjectClass;
71
const ASceneObject: string = ''): PSceneObjectEntry;
75
constructor Create(AOwner: TComponent); override;
76
destructor Destroy; override;
79
procedure CreateDefaultObjectIcons;
81
function GetClassFromIndex(Index: Integer): TGLSceneObjectClass;
82
function GetImageIndex(ASceneObject: TGLSceneObjectClass): Integer;
83
function GetCategory(ASceneObject: TGLSceneObjectClass): string;
84
procedure GetRegisteredSceneObjects(ObjectList: TStringList);
85
procedure PopulateMenuWithRegisteredSceneObjects(AMenuItem: TMenuItem; aClickEvent: TNotifyEvent);
86
// Registers a stock object and adds it to the stock object list
87
procedure RegisterSceneObject(ASceneObject: TGLSceneObjectClass; const aName, aCategory: string; ResourceModule: Cardinal; ResourceName: string = ''); overload;
89
// Unregisters a stock object and removes it from the stock object list
90
procedure UnRegisterSceneObject(ASceneObject: TGLSceneObjectClass);
92
property ObjectIcons: TImageList read FObjectIcons;
93
property SceneRootIndex: Integer read FSceneRootIndex;
94
property LightsourceRootIndex: Integer read FLightsourceRootIndex;
95
property CameraRootIndex: Integer read FCameraRootIndex;
96
property ObjectRootIndex: Integer read FObjectRootIndex;
98
// ------------------------------------------------------------------
99
// ------------------------------------------------------------------
100
// ------------------------------------------------------------------
102
// ------------------------------------------------------------------
103
// ------------------------------------------------------------------
104
// ------------------------------------------------------------------
106
//----------------- TGLObjectManager ---------------------------------------------
110
constructor TGLObjectManager.Create(AOwner: TComponent);
113
FSceneObjectList := TList.Create;
114
// FObjectIcons Width + Height are set when you add the first bitmap
115
FObjectIcons := TImageList.CreateSize(16, 16);
117
CreateDefaultObjectIcons;
123
destructor TGLObjectManager.Destroy;
125
DestroySceneObjectList;
130
// FindSceneObjectClass
132
function TGLObjectManager.FindSceneObjectClass(AObjectClass: TGLSceneObjectClass;
133
const aSceneObject: string = ''): PSceneObjectEntry;
140
with FSceneObjectList do
142
for I := 0 to Count - 1 do
143
with TGLSceneObjectEntry(Items[I]^) do
144
if (ObjectClass = AObjectClass) and (Length(ASceneObject) = 0)
145
or (CompareText(Name, ASceneObject) = 0) then
157
function TGLObjectManager.GetClassFromIndex(Index: Integer): TGLSceneObjectClass;
161
if Index > FSceneObjectList.Count - 1 then
162
Index := FSceneObjectList.Count - 1;
163
Result := TGLSceneObjectEntry(FSceneObjectList.Items[Index + 1]^).ObjectClass;
168
function TGLObjectManager.GetImageIndex(ASceneObject: TGLSceneObjectClass): Integer;
170
classEntry: PSceneObjectEntry;
172
classEntry := FindSceneObjectClass(ASceneObject);
173
if Assigned(classEntry) then
174
Result := classEntry^.ImageIndex
182
function TGLObjectManager.GetCategory(ASceneObject: TGLSceneObjectClass): string;
184
classEntry: PSceneObjectEntry;
186
classEntry := FindSceneObjectClass(ASceneObject);
187
if Assigned(classEntry) then
188
Result := classEntry^.Category
193
// GetRegisteredSceneObjects
195
procedure TGLObjectManager.GetRegisteredSceneObjects(objectList: TStringList);
199
if Assigned(objectList) then
203
for i := 0 to FSceneObjectList.Count - 1 do
204
with TGLSceneObjectEntry(FSceneObjectList.Items[I]^) do
205
AddObject(Name, Pointer(ObjectClass));
209
procedure TGLObjectManager.PopulateMenuWithRegisteredSceneObjects(AMenuItem: TMenuItem;
210
aClickEvent: TNotifyEvent);
212
objectList: TStringList;
214
item, currentParent: TMenuItem;
215
currentCategory: string;
216
soc: TGLSceneObjectClass;
218
objectList := TStringList.Create;
220
GetRegisteredSceneObjects(objectList);
221
for i := 0 to objectList.Count - 1 do
222
if objectList[i] <> '' then
224
currentCategory := GetCategory(TGLSceneObjectClass(objectList.Objects[i]));
225
if currentCategory = '' then
226
currentParent := AMenuItem
229
currentParent := NewItem(currentCategory, 0, False, True, nil, 0, '');
230
AMenuItem.Add(currentParent);
232
for j := i to objectList.Count - 1 do
233
if objectList[j] <> '' then
235
soc := TGLSceneObjectClass(objectList.Objects[j]);
236
if currentCategory = GetCategory(soc) then
238
item := NewItem(objectList[j], 0, False, True, aClickEvent, 0, '');
239
item.ImageIndex := GetImageIndex(soc);
240
currentParent.Add(item);
242
if currentCategory = '' then
252
// RegisterSceneObject
255
// RegisterSceneObject
258
procedure TGLObjectManager.RegisterSceneObject(ASceneObject: TGLSceneObjectClass;
259
const aName, aCategory: string);
261
resBitmapName: string;
264
// Since no resource name was provided, assume it's the same as class name
265
resBitmapName := ASceneObject.ClassName;
266
bmp := TBitmap.Create;
268
// Try loading bitmap from module that class is in
269
GLLoadBitmapFromInstance(FindClassHInstance(ASceneObject), bmp, resBitmapName);
270
if bmp.Width = 0 then
271
GLLoadBitmapFromInstance(HInstance, bmp, resBitmapName);
272
// If resource was found, register scene object with bitmap
273
if bmp.Width <> 0 then
275
RegisterSceneObject(ASceneObject, aName, aCategory, bmp);
278
// Resource not found, so register without bitmap
279
RegisterSceneObject(ASceneObject, aName, aCategory, nil);
285
// RegisterSceneObject
288
procedure TGLObjectManager.RegisterSceneObject(ASceneObject: TGLSceneObjectClass; const aName, aCategory: string; aBitmap: TBitmap);
290
newEntry: PSceneObjectEntry;
293
if Assigned(RegisterNoIconProc) then
294
RegisterNoIcon([aSceneObject]);
295
with FSceneObjectList do
297
// make sure no class is registered twice
298
if Assigned(FindSceneObjectClass(ASceneObject, AName)) then
304
// object stock stuff
305
// registered objects list stuff
306
ObjectClass := ASceneObject;
307
NewEntry^.Name := aName;
308
NewEntry^.Category := aCategory;
309
Index := FSceneObjectList.Count;
310
if Assigned(aBitmap) then
312
bmp := TBitmap.Create;
314
// If we just add the bitmap, and it has different dimensions, then
315
// all icons will be cleared, so ensure this doesn't happen
316
bmp.PixelFormat := glpf24bit;
317
bmp.Width := FObjectIcons.Width;
318
bmp.Height := FObjectIcons.Height;
319
bmp.Canvas.Draw(0, 0, aBitmap);
320
FObjectIcons.AddMasked(bmp, bmp.Canvas.Pixels[0, 0]);
321
ImageIndex := FObjectIcons.Count - 1;
336
// RegisterSceneObject
339
procedure TGLObjectManager.RegisterSceneObject(ASceneObject: TGLSceneObjectClass; const aName, aCategory: string; ResourceModule: Cardinal; ResourceName: string = '');
342
resBitmapName: string;
344
if ResourceName = '' then
345
resBitmapName := ASceneObject.ClassName
347
resBitmapName := ResourceName;
348
bmp := TBitmap.Create;
351
if (ResourceModule <> 0) then
352
GLLoadBitmapFromInstance(ResourceModule, bmp, resBitmapName);
353
// If the resource was found, then register scene object using the bitmap
354
if bmp.Width > 0 then
355
RegisterSceneObject(ASceneObject, aName, aCategory, bmp)
357
// Register the scene object with no icon
358
RegisterSceneObject(ASceneObject, aName, aCategory, nil);
365
procedure TGLObjectManager.RegisterSceneObject(ASceneObject: TGLSceneObjectClass; const aName, aCategory: string; ResourceModule: Cardinal; ResourceName: string = '');
367
newEntry: PSceneObjectEntry;
369
resBitmapName: string;
371
//>>Lazarus will crash at this function
372
if Assigned(RegisterNoIconProc) then
373
RegisterNoIcon([ASceneObject]);
374
//Writeln('GL Registered ',ASceneObject.classname);
375
Classes.RegisterClass(ASceneObject);
376
with FSceneObjectList do
378
// make sure no class is registered twice
379
if Assigned(FindSceneObjectClass(ASceneObject, AName)) then
382
pic := TPicture.Create;
386
// object stock stuff
387
// registered objects list stuff
388
ObjectClass := ASceneObject;
389
NewEntry^.Name := aName;
390
NewEntry^.Category := aCategory;
391
Index := FSceneObjectList.Count;
392
resBitmapName := ASceneObject.ClassName;
393
if LazarusResources.Find(resBitmapName) <> nil then
396
FObjectIcons.AddLazarusResource(resBitmapName);
399
ImageIndex := FObjectIcons.Count - 1;
414
// UnRegisterSceneObject
417
procedure TGLObjectManager.UnRegisterSceneObject(ASceneObject: TGLSceneObjectClass);
419
oldEntry: PSceneObjectEntry;
421
// find the class in the scene object list
422
OldEntry := FindSceneObjectClass(ASceneObject);
424
if assigned(OldEntry) then
426
// remove its entry from the list of registered objects
427
FSceneObjectList.Remove(OldEntry);
428
// finally free the memory for the entry
433
// CreateDefaultObjectIcons
437
procedure TGLObjectManager.CreateDefaultObjectIcons;
441
if LazarusResources.Find('gls_cross') <> nil then
443
AddLazarusResource('gls_cross');
446
// FOverlayIndex:=Count-1;
447
if LazarusResources.Find('gls_root') <> nil then
449
AddLazarusResource('gls_root');
452
FSceneRootIndex := Count - 1;
453
if LazarusResources.Find('gls_camera') <> nil then
455
AddLazarusResource('gls_camera');
458
FCameraRootIndex := Count - 1;
459
if LazarusResources.Find('gls_lights') <> nil then
461
AddLazarusResource('gls_lights');
464
FLightsourceRootIndex := Count - 1;
465
if LazarusResources.Find('gls_objects') <> nil then
467
AddLazarusResource('gls_objects');
470
FObjectRootIndex := Count - 1;
471
if LazarusResources.Find('gls_objects') <> nil then
473
AddLazarusResource('gls_objects');
479
// DestroySceneObjectList
482
procedure TGLObjectManager.DestroySceneObjectList;
486
with FSceneObjectList do
488
for i := 0 to Count - 1 do
489
Dispose(PSceneObjectEntry(Items[I]));
496
{$I ../../Resources/GLSceneObjects.lrs}