Solved

3D Studio - Delphi App

Posted on 2000-02-17
19
364 Views
Last Modified: 2010-04-04
Hi,
   Is there an application (with source) out there that will let me load in a 3D studio file and let me manipulate it?  

What I need is a program that will load in a .3ds file or any other 3D Studio file and let me navigate though it using the mouse.  I also need to detect mouse clicks.  i.e. If I load in a house I want to click on the door and know that I clicked the Door object.  Hope this makes sense.

Any comments welcome!!!

I should mention it must use OpenGL.

Help ?????????

Cheers
Woody.
0
Comment
Question by:WoodyJ3
19 Comments
 
LVL 10

Expert Comment

by:Lischke
ID: 2530887
Woody, today is your lucky day ;-) Just go straight to my homepage www.lischke-online.de/3DS.html and download Delphi sources for a 3ds import library.

There's a demo project which almost fullfills all your requests and comes with source too. The only thing you have to implement yourself is picking. But compared to the huge work already been done this should be something you can manage alone, I think.

Ciao, Mike
0
 
LVL 8

Expert Comment

by:ZifNab
ID: 2530901
Lische,

you did a really nice job! Nice page too.

Zif.
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2530922
Thanks Zif, writing this monster was a though job, I can tell you... (btw. it is for weeks now under the top 20 downloads on www.delphipages.com).

Ciao, Mike
0
 
LVL 5

Expert Comment

by:TheNeil
ID: 2531221
Jesus Mike that's excellent. Lotsa work in that

The Neil
0
 
LVL 17

Expert Comment

by:inthe
ID: 2533924
hehe
mike is waiting all year for this question :-)

now anybody know where a great treeview component is?   ;-)
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2534076
Aaah, you got me Barry :-) Hope you all have fun with my stuff!

Ciao, Mike
0
 

Author Comment

by:WoodyJ3
ID: 2534281
Yes, I must agree that is brilliant.  My only question is now.  How do I do the picking?  I'm still learning OpenGL and the routines for picking I've found don't seem to work with the "opener".  

Any Ideas?

I'll leave this question open for a while, then I'll give Mike the points.

Cheers
Woody.
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2534304
Hi Woody,

picking is not so hard as it may seem. Here's the code I use in GLScene (my OpenGL library you also can download for free from my homepage):

procedure TGLSceneViewer.PickObjects(var Rect: TRect; PickList: TGLPickList;
                                   objectCountGuess: Integer);
type
   { TODO : local type to remove }
   PCardinalVector = ^TCardinalVector;
   TCardinalVector = array[0..0] of Cardinal;
var
   buffer : PCardinalVector;
   hits : Integer;
   i : Integer;
   current, next : Cardinal;
   szmin, szmax : Single;
begin
   Assert((FState = dsNone));
   Assert(Assigned(PickList));
   ActivateRenderingContext(FCanvas.Handle, FRenderingContext);
   FState := dsPicking;
   try
      glMatrixMode(GL_PROJECTION);
      glPushMatrix;
      buffer := nil;
      try
         glLoadIdentity;
         gluPickMatrix(Rect.Left, Height - Rect.Top,
                       Abs(Rect.Right - Rect.Left), Abs(Rect.Bottom - Rect.Top),
                       TVector4i(FViewport));
         FCamera.ApplyPerspective(FViewport, Width, Height,
                                  GetDeviceCaps(Canvas.Handle, LOGPIXELSX));
         // check countguess, memory waste is not an issue here
         if objectCountGuess<8 then objectCountGuess:=8;
         hits:=-1;
         repeat
            if hits < 0 then begin
               // Allocate 4 integers per row (Egg : dunno why 4)
               // Add 32 integers of slop (an extra cache line) to end for buggy
               // hardware that uses DMA to return select results but that sometimes
               // overrun the buffer.  Yuck.
               ReallocMem(buffer, objectCountGuess * 4 * SizeOf(Integer) + 32 * 4);
               // increase buffer by 50% if we get nothing
               Inc(objectCountGuess, objectCountGuess shr 1);
            end;
            // pass buffer to opengl and prepare render
            glSelectBuffer(objectCountGuess*4, @Buffer^);
            glRenderMode(GL_SELECT);
            glInitNames;
{ TODO : glPushName(0) with no glPopName, bug ? }
            glPushName(0);
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity;
            // render the scene (in select mode, nothing is drawn)
            if Assigned(FCamera) and Assigned(FCamera.FScene) then
               with FCamera.FScene do begin
                  ValidateTransformation(Camera);
                  RenderScene(Self);
               end;
            glFlush;
            Hits := glRenderMode(GL_RENDER);
         until Hits > -1; // try again with larger selection buffer
         Next := 0;
         PickList.Clear;
         PickList.Capacity := Hits;
         for I := 0 to Hits-1 do begin
            Current := Next;
            Next := Current + Buffer[Current] + 3;
            szmin := (Buffer[current + 1] shr 1) / MaxInt;
            szmax := (Buffer[current + 2] shr 1) / MaxInt;
            PickList.AddHit(TGLCustomSceneObject(Buffer[Current + 3]), szmin, szmax);
         end;
      finally
         FreeMem(Buffer);
         glMatrixMode(GL_PROJECTION);
         glPopMatrix;
      end;
   finally
      FState := dsNone;
      DeactivateRenderingContext;
   end;
end;


TGLPickList is just a TList with a record as data holding a scene object reference and the limits (as indicated in the PickList.AddHit call above).

Ciao, Mike
0
 

Author Comment

by:WoodyJ3
ID: 2534562
Thanks I'll let you know how I get on.

ta
Woody.
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

Author Comment

by:WoodyJ3
ID: 2541888
I couldn't seem to get that to work.  I wasn't geting any hits at all.

Any thoughts?
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2541907
mmh, then I need to have a look at your project. There are too many potential problems so can't say from "don't get any hits at all" what's wrong (send it to public@lischke-online.de).

Ciao, Mike
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2541909
PS: Please send only a stripped down version so I can focus on the picking problem.
0
 

Author Comment

by:WoodyJ3
ID: 2542117
the procedure you sent me...  Commented out some bits...

procedure TForm_Main.PickObjects(var Rect: TRect; PickList: {TGLPickList} Tlist;
                                                                    objectCountGuess: Integer);
type
      { TODO : local type to remove }
      PCardinalVector = ^TCardinalVector;
   TCardinalVector = array[0..0] of Cardinal;
var
   buffer : PCardinalVector;
   hits : Integer;
   i : Integer;
   current, next : Cardinal;
   szmin, szmax : Single;
begin
//   Assert((FState = dsNone));
//   Assert(Assigned(PickList));
      ActivateRenderingContext(Canvas.Handle, FRenderingContext);
try
      glMatrixMode(GL_PROJECTION);
      glPushMatrix;
      buffer := nil;
      try
         glLoadIdentity;
         gluPickMatrix(Rect.Left, Height - Rect.Top,
                       Abs(Rect.Right - Rect.Left), Abs(Rect.Bottom - Rect.Top),
                       TVector4i(FViewport));

                  // check countguess, memory waste is not an issue here
                  if objectCountGuess<8 then objectCountGuess:=8;
                  hits:=-1;
         repeat
            if hits < 0 then begin
               // Allocate 4 integers per row (Egg : dunno why 4)
               // Add 32 integers of slop (an extra cache line) to end for buggy
               // hardware that uses DMA to return select results but that sometimes
               // overrun the buffer.  Yuck.
               ReallocMem(buffer, objectCountGuess * 4 * SizeOf(Integer) + 32 * 4);
               // increase buffer by 50% if we get nothing
               Inc(objectCountGuess, objectCountGuess shr 1);
            end;
            // pass buffer to opengl and prepare render
            glSelectBuffer(objectCountGuess*4, @Buffer^);
            glRenderMode(GL_SELECT);
            glInitNames;
{ TODO : glPushName(0) with no glPopName, bug ? }
            glPushName(0);
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity;
            // render the scene (in select mode, nothing is drawn)

            glFlush;
            Hits := glRenderMode(GL_RENDER);
         until Hits > -1; // try again with larger selection buffer
         Next := 0;
//         PickList.Clear;
//         PickList.Capacity := Hits;
                  for I := 0 to Hits-1 do begin
                        Current := Next;
                        Next := Current + Buffer[Current] + 3;
                        szmin := (Buffer[current + 1] shr 1) / MaxInt;
                        szmax := (Buffer[current + 2] shr 1) / MaxInt;
                        ShowMessage('john');
//            PickList.AddHit(TGLCustomSceneObject(Buffer[Current + 3]), szmin, szmax);
                  end;
            finally
                  FreeMem(Buffer);
         glMatrixMode(GL_PROJECTION);
         glPopMatrix;
      end;
   finally
//      FState := dsNone;
//      DeactivateRenderingContext;
   end;
end;


the call im using...


procedure TForm_Main.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
Var
a : trect;
begin
      SetFocus;
      FLastX := X;
      FLastY := Y;

      a.Left := 1;
      a.Top := 1;
      a.Bottom := height;
      a.Right := width;
      PickObjects(a, nil, 10);
end;


i think notepad has screwed the indents.  Sorry.

Am I calling this procedure correctly?

Cheers
Woody
0
 

Author Comment

by:WoodyJ3
ID: 2542121
Sorry, didn't read it correctly.  I'll send the email shortly.

John.
0
 
LVL 10

Accepted Solution

by:
Lischke earned 380 total points
ID: 2545678
Hi John,

sorry for being so late, but it took me a while to figure out what was wrong. I'll send you the changed main form so you can see all changes I made.

There are several important points. First is: don't take out the check for OpenGL errors. This may sometimes be a good indicator of there's something wrong. You RedrawScene and whatever calls are very likely candidates to ruin all you other precious code. Just call MainForm.Invalidate and all should be fine. DON'T call BeginPaint/EndPaint unless you are directly in WM_PAINT (not OnPaint or however they may be called). This is an absolute no-no and can cause serious trouble on certain graphic boards if BeginPaint etc. are called in a nested manner (and they are already called when entering OnPaint etc.)!

Furthermore, you cannot expect to get any result when you take out the actual render code from PickObjects. You have to render the scene normally but with a slightly different projection matrix, which is created by the gluPickMatrix call. I have changed the core functions to:

procedure TForm_Main.DoRender;

// This is the main paint routine. If there's no data assigned yet then an empty window is drawn else the data stored
// in the various lists. These lists must already be set up.

var
  Scale: Single;

begin
  ClearBuffersAndBackground;

  if FCameraChanged or FPicking then
  begin
    FCameraChanged := False;
    // set up projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity;

    if FPicking then gluPickMatrix(FLastX, FLastY, 3, 3, TVector4i(FViewport));
    ApplyPerspective(FViewport, Width, ClientHeight, FDPI);
  end;

  // initialize transformation pipeline
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;

  // lights
  Scale := 1000 / 1000;
  if FLightSourcesChanged then
  begin
    glScalef(Scale, Scale, Scale);
    SetupLights;
    glLoadIdentity;
  end;

  // camera
  gluLookAt(0, 0, 50,
            0, 0, -10,
            0, 1, 0);

  // objects
  if Abs(1 - Scale) > 0.1 then
  begin
    glEnable(GL_NORMALIZE);  // this will half the frame rate but is necessary for changing overall
                             // scale on the fly and still get the correct lighting
    glScalef(Scale, Scale, Scale);
  end
  else glDisable(GL_NORMALIZE);
  glMultMatrixf(@FSceneMatrix);

  if FMainList <> 0 then glCallList(FMainList);

end;

//----------------------------------------------------------------------------------------------------------------------

procedure TForm_Main.FormPaint(Sender: TObject);

begin
  // Note: We don't need to activate   DoRender;
  // copy back buffer to front
  SwapBuffers(Canvas.Handle);
end;

//----------------------------------------------------------------------------------------------------------------------

procedure TForm_Main.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

begin
      SetFocus;
      FLastX := X;
      FLastY := Y;
      PickObjects(nil, 10);
end;

//----------------------------------------------------------------------------------------------------------------------


Finally, you need to indicate whenever an object/vertex/mesh is drawn to get it also back. I did this in Use3DSData when building the display lists for all meshs:

    for I := 0 to FLists.Count - 1 do
    begin
      Mesh := FLists[I];
      with Mesh^ do
      begin
        // allocate a new display list
        ListName := glGenLists(1);
        // now compile mesh data into this list
        glNewList(ListName, GL_COMPILE);

:

        // finished compiling this display list
        glLoadName(I);
        glEndList;
//        CheckOpenGLError;
      end;
    end;

Note the glLoadName call. This number is returned in the pick code.

This was quite tough stuff, but I think I have it all now.

Ciao, Mike
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2545685
Oops, FormPaint should actually look so:

procedure TForm_Main.FormPaint(Sender: TObject);

begin
  DoRender;
  // copy back buffer to front
  SwapBuffers(Canvas.Handle);
end;

Ciao, Mike
0
 

Author Comment

by:WoodyJ3
ID: 2549917
Adjusted points to 385
0
 

Author Comment

by:WoodyJ3
ID: 2549918
Thanks very much.

I think Im gonna have to buy several books on this openGL stuff.  When I finished this project I'll send it you.

Thanks again.  You can have all of my points.

John.
0
 
LVL 10

Expert Comment

by:Lischke
ID: 2550026
Thank you for the points and the A grading. Well, after you have read all those books you will have gotton lots of new points, I'm sure ;-))

Ciao, Mike
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi 2 48
can't find the executable in Simulator 1 80
Performance of SQL statement 37 98
SUM 2 INTEGER ARRAYS INTO 1 10 93
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In this video I am going to show you how to back up and restore Office 365 mailboxes using CodeTwo Backup for Office 365. Learn more about the tool used in this video here: http://www.codetwo.com/backup-for-office-365/ (http://www.codetwo.com/ba…
With the power of JIRA, there's an unlimited number of ways you can customize it, use it and benefit from it. With that in mind, there's bound to be things that I wasn't able to cover in this course. With this summary we'll look at some places to go…

920 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now