lazarus/components/fpvectorial/examples/fpv3d_mainform.pas
sekelsenmat 1586f97486 fpvectorial: Fixes compilation of 3d viewer
git-svn-id: trunk@47256 -
2014-12-27 18:55:16 +00:00

368 lines
10 KiB
ObjectPascal

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.