unit fpv3d_mainform; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, OpenGLContext, Forms, Controls, Graphics, Dialogs, EditBtn, StdCtrls, ComCtrls, fpvectorial, gl, glu, FPimage, Math, lasvectorialreader; type { TformFPV3D } TformFPV3D = class(TForm) Button1: TButton; btnConvert3DPointArrayToHeightMap: TButton; btnRotY: TButton; buttonCutFile: TButton; buttonRotZ: TButton; buttonZoomIn: TButton; buttonZoomOut: TButton; buttonLoad: TButton; editFileName: TFileNameEdit; glControl: TOpenGLControl; labelStatus: TLabel; progressBar: TProgressBar; procedure btnConvert3DPointArrayToHeightMapClick(Sender: TObject); procedure btnRotYClick(Sender: TObject); procedure Button1Click(Sender: TObject); procedure buttonCutFileClick(Sender: TObject); procedure buttonLoadClick(Sender: TObject); procedure buttonRotZClick(Sender: TObject); procedure buttonZoomInClick(Sender: TObject); procedure buttonZoomOutClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure glControlPaint(Sender: TObject); procedure HandleVecDocProgress(APercentage: Byte); private { private declarations } procedure Render3DPointsArrayAlternative1(); // function GetMapHeight(X, Y: Integer): Byte; procedure SetVertexColor(bRenderPolygons: Boolean; x, y: Integer); procedure RenderHeightMapV1Helper(bRenderPolygons: Boolean); procedure RenderHeightMapV1; public { public declarations } VecDoc: TvVectorialDocument; glAltitude: Integer; glRotateAngleY, glRotateAngleZ: Double; HeightMap: TvRasterImage; end; const STEP_SIZE = 16; // Width And Height Of Each Quad (NEW) HEIGHT_RATIO = 1.5; // Ratio That The Y Is Scaled According To The X And Z (NEW) var formFPV3D: TformFPV3D; implementation {$R *.lfm} { TformFPV3D } procedure TformFPV3D.glControlPaint(Sender: TObject); begin glControl.SwapBuffers; //Render3DPointsArrayAlternative1; RenderHeightMapV1(); end; procedure TformFPV3D.HandleVecDocProgress(APercentage: Byte); begin progressBar.Position := APercentage; Application.ProcessMessages; end; procedure TformFPV3D.Render3DPointsArrayAlternative1; var VecPage: TvVectorialPage; i: Integer; lPoint1, lPoint2, lPoint3: TvPoint; lEntity: TvEntity; lPos1, lPos2, lPos3: T3DPoint; lColor: TFPColor; begin glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, double(width) / height, 0.1, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0,-glAltitude); if glRotateAngleY <> 0 then glRotatef(glRotateAngleY, 0, 1, 0); if glRotateAngleZ <> 0 then glRotatef(glRotateAngleZ, 0, 0, 1); VecPage := VecDoc.GetCurrentPageAsVectorial(); if VecPage = nil then Exit; for i := 0 to VecPage.GetEntitiesCount() - 3 do begin lEntity := VecPage.GetEntity(i); if not (lEntity is TvPoint) then Continue; lPoint1 := lEntity as TvPoint; lEntity := VecPage.GetEntity(i+1); if not (lEntity is TvPoint) then Continue; lPoint2 := lEntity as TvPoint; lEntity := VecPage.GetEntity(i+2); if not (lEntity is TvPoint) then Continue; lPoint3 := lEntity as TvPoint; glBegin(GL_TRIANGLES); // Drawing Using Triangles lPos1 := lPoint1.GetNormalizedPos(VecPage, -1, 1); lPos2 := lPoint2.GetNormalizedPos(VecPage, -1, 1); lPos3 := lPoint3.GetNormalizedPos(VecPage, -1, 1); lColor := lPoint1.Pen.Color; glColor3f(lColor.Red / $FFFF, lColor.Green / $FFFF, lColor.Blue / $FFFF); glVertex3f(lPos1.X, lPos1.Y, lPos1.Z); glVertex3f(lPos2.X, lPos2.Y, lPos2.Z); glVertex3f(lPos3.X, lPos3.Y, lPos3.Z); glEnd(); // Finished Drawing end; end; function TformFPV3D.GetMapHeight(X, Y: Integer): Byte; var lPos: TPoint; begin lPos.X := Min(X, HeightMap.RasterImage.Width-1); lPos.Y := Min(Y, HeightMap.RasterImage.Height-1); Result := Byte(HeightMap.RasterImage.Colors[lPos.X, lPos.Y].Red div $FF); end; {-----------------------------------------------------------------------------} { Sets The Color Value For A Particular Index, Depending On The Height Index } {-----------------------------------------------------------------------------} procedure TformFPV3D.SetVertexColor(bRenderPolygons: Boolean; x, y : Integer); var fColor : glFloat; begin fColor :=-0.2 + GetMapHeight(X, Y) / $FF; // Assign This Blue Shade To The Current Vertex if bRenderPolygons then glColor3f((220-104*fColor)/256, (220-110*abs(fColor-0.4))/256, (220-200*abs(fColor-0.6))/256) else glColor3i(0, 0, 0); end; procedure TformFPV3D.RenderHeightMapV1Helper(bRenderPolygons: Boolean); var X, Y : Integer; x2, y2, z2 : Integer; begin if HeightMap = nil then Exit; if HeightMap.RasterImage = nil then Exit; if (bRenderPolygons) then // What We Want To Render glBegin( GL_QUADS ) // Render Polygons else glBegin( GL_LINES ); // Render Lines Instead X :=0; while X < HeightMap.RasterImage.Width-1 do begin Y :=0; while Y < HeightMap.RasterImage.Height-1 do begin // Get The (X, Y, Z) Value For The Bottom Left Vertex x2 := X; y2 := GetMapHeight(X, Y); z2 := Y; // Set The Color Value Of The Current Vertex SetVertexColor(bRenderPolygons, x2, z2); // Send This Vertex To OpenGL To Be Rendered (Integer Points Are Faster) glVertex3i(x2, y2, z2); // Get The (X, Y, Z) Value For The Top Left Vertex x2 := X; y2 := GetMapHeight(X, Y + STEP_SIZE); z2 := Y + STEP_SIZE ; // Set The Color Value Of The Current Vertex SetVertexColor(bRenderPolygons, x2, z2); // Send This Vertex To OpenGL To Be Rendered glVertex3i(x2, y2, z2); // Get The (X, Y, Z) Value For The Top Right Vertex x2 := X + STEP_SIZE; y2 := GetMapHeight(X + STEP_SIZE, Y + STEP_SIZE); z2 := Y + STEP_SIZE ; // Set The Color Value Of The Current Vertex SetVertexColor(bRenderPolygons, x2, z2); // Send This Vertex To OpenGL To Be Rendered glVertex3i(x2, y2, z2); // Get The (X, Y, Z) Value For The Bottom Right Vertex x2 := X + STEP_SIZE; y2 := GetMapHeight(X + STEP_SIZE, Y ); z2 := Y; // Set The Color Value Of The Current Vertex SetVertexColor(bRenderPolygons, x2, z2); // Send This Vertex To OpenGL To Be Rendered glVertex3i(x2, y2, z2); Y :=Y + STEP_SIZE end; X := X + STEP_SIZE end; glEnd(); glColor4f(1.0, 1.0, 1.0, 1.0); // Reset The Color end; procedure TformFPV3D.RenderHeightMapV1(); var ScaleValue: Double; begin // Init glClearColor(0.0, 0.0, 0.0, 0.5); // Black Background glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading glClearDepth(1.0); // Depth Buffer Setup glEnable(GL_DEPTH_TEST); // Enable Depth Buffer glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do glDisable(GL_TEXTURE_2D); // Disable Texture Mapping glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //Realy Nice perspective calculations // Resize glViewport(0, 0, Width, Height); // Set the viewport for the OpenGL window glMatrixMode(GL_PROJECTION); // Change Matrix Mode to Projection glLoadIdentity(); // Reset View gluPerspective(45.0, glControl.Width/glControl.Height, 1.0, 500.0); // Do the perspective calculations. Last value = max clipping depth glMatrixMode(GL_MODELVIEW); // Return to the modelview matrix glLoadIdentity(); // Reset View //bRender :=TRUE; ScaleValue := 0.18 - glAltitude * 0.01; // Paint repetition glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer glLoadIdentity(); // Reset The View // Position View Up Vector gluLookAt(212, 60, 194, 186, 55, 171, 0, 1, 0); // This Determines Where The Camera's Position And View Is glScalef(scaleValue, scaleValue * HEIGHT_RATIO, scaleValue); // Rotation if glRotateAngleY <> 0 then glRotatef(glRotateAngleY, 0, 1, 0); if glRotateAngleZ <> 0 then glRotatef(glRotateAngleZ, 0, 0, 1); RenderHeightMapV1Helper(True); RenderHeightMapV1Helper(False); end; procedure TformFPV3D.FormCreate(Sender: TObject); begin VecDoc := TvVectorialDocument.Create; glAltitude := 3; end; procedure TformFPV3D.buttonLoadClick(Sender: TObject); begin labelStatus.Caption := 'Loading file'; VecDoc.OnProgress := @HandleVecDocProgress; VecDoc.ReadFromFile(editFileName.FileName); labelStatus.Caption := 'Done'; glControl.Invalidate; end; procedure TformFPV3D.buttonRotZClick(Sender: TObject); begin glRotateAngleZ := glRotateAngleZ + 10; glControl.Invalidate; end; procedure TformFPV3D.buttonZoomInClick(Sender: TObject); begin Dec(glAltitude); if glAltitude < 1 then glAltitude := 1; glControl.Invalidate; end; procedure TformFPV3D.buttonZoomOutClick(Sender: TObject); begin Inc(glAltitude); glControl.Invalidate; end; procedure TformFPV3D.Button1Click(Sender: TObject); begin glControl.Invalidate; end; procedure TformFPV3D.btnConvert3DPointArrayToHeightMapClick(Sender: TObject); var lRasterImage: TvRasterImage; lPage: TvVectorialPage; lFile: TFileStream; x, y: Integer; lRed: Word; begin lPage := VecDoc.GetPageAsVectorial(0); lRasterImage := TvRasterImage.Create(lPage); HeightMap := lRasterImage; lPage.AddEntity(lRasterImage); lRasterImage.InitializeWithConvertionOf3DPointsToHeightMap(lPage, 1024, 1024); lFile := TFileStream.Create('Terrain.raw', fmCreate); try for x := 0 to 1023 do for y := 0 to 1023 do begin lRed := lRasterImage.RasterImage.Colors[x, y].Red; lFile.WriteByte(Byte(lRed div $FF)); end; finally lFile.Free; end; glControl.Invalidate; end; procedure TformFPV3D.btnRotYClick(Sender: TObject); begin glRotateAngleY := glRotateAngleY + 10; glControl.Invalidate; end; procedure TformFPV3D.buttonCutFileClick(Sender: TObject); var lPage: TvVectorialPage; begin VecDoc.ReadFromFile(editFileName.FileName); //lPage := VecDoc.GetPage(0); //while lPage.DeleteEntity(20000) do ; VecDoc.WriteToFile(editFileName.FileName + 'smaller.las'); end; procedure TformFPV3D.FormDestroy(Sender: TObject); begin VecDoc.Free; end; end.