{HACER QUE TODO TPOINT APUNTE SIEMPRE A SUS VERTICES Y QUE DEJE DE HACERLO SI UN VERTICE SE DESPRENDE} {ELIMINAR CAMPO REFERENCES DE TPOINT} {3D object handling. this unit is related to uRickGL Tentity: an entity or object tface: a face of an entity, each entity has many faces Tvertex: a vertex of a face, each face has many vertices. By: Ricardo Sarmiento delphiman@hotmail.com } unit U3Dpolys; interface Uses classes, SysUtils, GL, GLU; {MWMWMWMWMWMWMWMWMWMW Classes definition MWMWMWMWMWMWMWMWMWMWMWMW} type tface=Class; Tpoint = Class; Ttexture = Class; Tentity = Class(Tobject) {entity or object or 3D mesh} Faces:TList; {2D polygons list belonging to the mesh} Points:Tlist; {list of all the vertices of the entity} R,G,B:Byte; {default color to use } OriPosi:array[1..3] of single; {original position to reduce numerical error} OriPosi_changed: boolean; {original position is changed?} Position:array[1..3] of single; {position of entity in space X,Y,Z} rotation:array[1..3] of single; {Orientation, Rx,Ry,Rz} id:GLuInt; {entity's identIfier, optional} Texture:Ttexture; {pointer to a texture} constructor Create; {create a zero-polygon entity} Destructor Destroy; override; Procedure Load(st:String); {load from propietary file format} Procedure Save(st:String); {not yet implemented} Procedure SetColor(iR,iG,iB:Byte); {change entityīs color} Procedure Move(X,Y,Z:single); {move entity to new position} Procedure Rotate(Rx,Ry,Rz:single); {turn entity to new orientation} Procedure Redraw; {construct the entity using OpenGL commands} Procedure LoadDXF(st:String); {Read DXF file in ST and generate the mesh} Procedure CalcNormals; {calculate normals for each vertex} Procedure Center; {find the geometric center of the entity and put it at 0,0,0} Function AddFace:tface; {add a new, empty face to the entity} Function FindPoint(ix,iy,iz:single):Tpoint; {search for a point near ix,iy,iz} Function CreateTexture:TTexture; {create and assign a texture to the entity} end; {Tentity} {useful when rotating entity around itīs center} tface=Class(Tobject) {a face or polygon of an entity} Vertices:Tlist; {the meshīs vertex list} r,g,b:Byte; {face color} Owner:Tentity; {points to the owner entity} ApplyTexture:boolean; {use texturing or not in this face} constructor Create(iOwner:Tentity); {create the face and assign its owner entity} Destructor Destroy; override; Procedure AddVertex(x,y,z,nx,ny,nz:single); {add vertex at X,Y,Z with normal nx,ny,nz} Procedure Redraw; {draw face using OpenGL commands} {calculate normal given 3 points of the face, normally not called directly} Procedure CalcNormal(uno,dos,tres:integer;var inx,iny,inz:single); Procedure SetColor(ir,ig,ib:Byte); {set the desired color of the face} end; {tface} Tpoint = Class(Tobject) {a colored point in space} x,y,z:single; {position x,y,z} r,g,b:Byte; {vertexīs color, rgb} References:Byte; {number of vertices using the point for color and position} Vertices:Tlist; Constructor Create(ix,iy,iz:single); {set position and References to 0} Destructor Destroy; override; Procedure SetColor(ir,ig,ib:Byte); {set the desired color of the point} Procedure SetPosition(ix,iy,iz:single); {move the point to a dIfferent place} end; {Tpoint} Tvertex = Class(Tobject) {a vertex of a flat polygon} nx,ny,nz:single; {normal vector, each vertex has itīs own normal vector, this is useful for certain tricks} point:Tpoint; {points to position and color data} Owner:Tface; {points to the face that owns the vertex} Tx,Tz:single; {Texture X and Z coordinates} constructor Create(iowner:Tface;inx,iny,inz:single); {create vertex with its normal} Procedure SetColor(ir,ig,ib:Byte); {set the desired individual color of the vertex} Procedure SetPosition(ix,iy,iz:single); {move individually the vertex to a dIfferent place} Procedure MakeCopy; {create a new Tpoint instance, so that the vertex can modIfy individualy the color and position} end; {Tvertex} Ttexture = Class(Tobject) {a texture} Automatic:boolean; {use or not automatic texture coordinates generation} AutoXmult:array[0..3] of GLint; {multiply values for X coordinate} AutoZmult:array[0..3] of GLint; {multiply values for Z coordinate} AutoGenModeX:GLint; {coordinate calculation algorithm to be used: } AutoGenModeZ:GLint; {GL_object_linear, GL_Eye_linear or GL_Sphere_map} WrapSMode:Glint; WrapTMode:Glint; MagFilter:Glint; MinFilter:Glint; EnvironmentMode:GLint; {decal, modulate or blend} EnvBlendColor:Array[0..3] of byte; {RGBA color if EnvironmentMode is blend} Owner:Tentity; {a texture can be owned by an Entity} MyList:GLsizei; {number of the display list for this texture} Constructor Create(iowner:Tentity); {set defaults for all fields} Destructor destroy; override;{destroy the display list} Function LoadTexture(st:string):shortint; {load a new texture file, return 0 if ok, negative number if error} Procedure Redraw; {call the display list, itīs not really a redraw, itīs part of one} end; {Ttexture} Const {global constants} MinimalDistance=0.0001; {If two points are this far from each other, they can be considered to be in the same position} var {global variables} // this two variables are used in this unit and in unit UrickGL: PutNames:boolean; {If true put names to vertex and entity primitives when rendering} ActualVertexNumber:LongInt; {used to mark every vertex with a dIfferent name in every entity} implementation {MWMWMWMWMWMWMWMWMWMW IMPLEMENTATION of the CLASSES MWMWMWMWMWMWMWMWMWMWMWMW} constructor Tentity.create; begin inherited create; id:=0; {initiallly this value has no importance} Faces:=Tlist.create; Points:=Tlist.create; SetColor(128,128,128); {use a medium grey color} end; Destructor Tentity.destroy; begin Points.Free; Faces.Free; inherited Destroy; end; Procedure Tentity.Load; var f:file; numFaces, NumPoints, NumTextures, i,j:LongInt; IdData:array[0..3] of char; Reserved:array[1..20] of Byte; ix,iy,iz:single; inx,iny,inz:single; ir,ig,ib:Byte; Point:Tpoint; Face:Tface; Vertex:Tvertex; PointNum:longint; numVertices:byte; {this limits the vertex count for each polygon to less than 255 vertices, more than enough} Version, SubVersion:byte; begin assignFile(f,st); If not FileExists(st) then exit; Reset(f,1); BlockRead(f,IdData,sizeof(IdData)); BlockRead(f,Version,sizeof(version)); BlockRead(f,SubVersion,sizeof(SubVersion)); if version=1 then begin {first clear old data stored in object} Faces.Clear; Points.Clear; {then, begin to read new data} BlockRead(f,ir,sizeof(ir)); BlockRead(f,ig,sizeof(ig)); BlockRead(f,ib,sizeof(ib)); SetColor(ir,ig,ib); BlockRead(f,numFaces,sizeof(numFaces)); BlockRead(f,numPoints,sizeof(numPoints)); BlockRead(f,numTextures,sizeof(numTextures)); {not used yet} BlockRead(f,Reserved,sizeof(Reserved)); {for future purposes} {read Points} i:=0; while ix3) or (y4<>y3) or (z4<>z3) then DivRectangle else begin Face:=AddFace; Face.AddVertex(x3,y3,z3,0,0,1); Face.AddVertex(x2,y2,z2,0,0,1); Face.AddVertex(x1,y1,z1,0,0,1); end; end; end; {case} kind:=0; end; If st2 ='3DFACE' then kind:=1; {line} If kind>0 then analyzing:=true; end; 10: val(st2,x1,err); 20: val(st2,y1,err); 30: val(st2,z1,err); 11: val(st2,x2,err); 21: val(st2,y2,err); 31: val(st2,z2,err); 12: val(st2,x3,err); 22: val(st2,y3,err); 32: val(st2,z3,err); 13: val(st2,x4,err); 23: val(st2,y4,err); 33: val(st2,z4,err); end; {of case} until eof(f); closefile(f); end; Procedure Tentity.CalcNormals; var Face:tface; i,j,numFaces,NumVertices:integer; inx,iny,inz:single; begin i:=0; numFaces:=Faces.Count; while imaxX then maxX:=x; If ymaxy then maxy:=y; If zmaxz then maxz:=z; inc(j); end; {calculate the center coordinates} cx:=minx+(maxx-minx)/2; cy:=miny+(maxy-miny)/2; cz:=minz+(maxz-minz)/2; {now move the vertices} NumPoints:=Points.Count; j:=0; while jr) or (point.g<>g) or (point.b<>b) then {a near, same color point was not found} begin Point:=Tpoint.Create(x,y,z); Point.SetColor(r,g,b); Owner.Points.Add(Point); end; Vertex.Point:=Point; {reference the point...} Point.vertices.add(vertex); {...and the point also references the vertex} inc(Point.References); {now the vertex is referencing the point} Vertices.Add(Vertex); end; Procedure tface.Redraw; var i,num:LongInt; manual:boolean; begin If PutNames then {each face has itīs own name} begin GlLoadName(ActualVertexNumber); GlPassThrough(ActualVertexNumber); {it should be: GLfloat(ActualVertexNumber), but it wouldnīt compile} end; if not ApplyTexture or not Assigned(owner.texture) then begin gldisable(GL_texture_2d); manual:=true; end else begin glenable(gl_texture_2d); manual:=not owner.texture.automatic; end; glBegin(GL_POLYGON); i:=0; num:=Vertices.count; while i1 then {check If the copy is really necesary} begin {the vertex is sharing the point, so letīs create its own point} dec(Point.References); {this vertex wonīt use that point again} NewPoint:=Tpoint.Create(Point.x,Point.y,Point.z); Owner.Owner.points.add(newPoint); with NewPoint do begin References:=1; {inc the references on the new point} r:=Point.r; g:=Point.g; b:=Point.b; end; Point:=newPoint; end; {now we are ready to set the individual values of our vertex} end; Procedure Tvertex.SetColor; begin MakeCopy; {If itīs necessary, the point will be duplicated so that the individual color can be modIfied} Point.r:=iR; Point.g:=iG; Point.b:=iB; end; Procedure Tvertex.SetPosition; begin MakeCopy; {If itīs necessary, the point will be duplicated so that the individual position can be modIfied} Point.x:=iX; Point.y:=iY; Point.z:=iZ; end; Constructor TTexture.Create; {set defaults for all fields} begin Owner:=iOwner; MyList:=glgenlists(1); {generate an empty list for this texture} WrapSmode:=gl_repeat; {tile the texture in X} WrapTmode:=gl_repeat; {tile the texture in Z} MagFilter:=gl_nearest; {texture using the nearest texel} MinFilter:=gl_nearest; {texture using the nearest texel} Automatic:=False; {by default the texture coordinates have to be calculated by hand} AutoGenModeX:=gl_object_linear; AutoGenModeZ:=gl_object_linear; AutoXmult[0]:=1; AutoXmult[1]:=0; AutoXmult[2]:=0; AutoXmult[3]:=0; AutoZmult[0]:=0; AutoZmult[1]:=0; AutoZmult[2]:=1; AutoZmult[3]:=0; EnvironmentMode:=GL_decal; {like the decals in a racing car} end; Destructor Ttexture.destroy; begin inherited destroy; GLdeleteLists(MyList,1); {destroy the display list of the texture} end; Function TTexture.LoadTexture(st:string):shortint; Const MB=19778; var f:file; Buffer:pointer; {$A-} header:record FileType:Word; {always MB} size:longint; Reserved1, Reserved2:word; {reserved for future purposes} offset:longint; {offset to image in bytes} end; {header} BMPInfo:record size:longint; {size of BMPinfo in bytes} width:longint; {width of the image in pixels} height:longint; {height of the image in pixels} planes:word; {number of planes (always 1)} Colorbits:word; {number of bits used to describe color in each pixel} compression:longint; {compression used} ImageSize:longint; {image size in bytes} XpixPerMeter:longint; {pixels per meter in X} YpixPerMeter:longint; {pixels per meter in Y} ColorUsed:longint; {number of the color used ŋŋŋ???} Important:longint; {number of "important" colors} end; {info} {$A+} begin if Not FileExists(st) then begin result:=-1; {file not found} exit; end; assignfile(f,st); reset(f,1); blockread(f,header,sizeof(header)); blockread(f,BMPinfo,sizeof(BMPinfo)); if header.FileType <> MB then begin result:=-2; {file type is not BMP} exit; end; header.size:=header.size-sizeof(header)-sizeof(BMPinfo); { for j:=1 to 32 do for i:=1 to 32 do begin blockread(f,buff[j,i].g,1); blockread(f,buff[j,i].r,1); blockread(f,buff[j,i].b,1); if i>16 then Buff[j,i].a:=i*j div 4 //semitransparent, 255 completely opaque else Buff[j,i].a:=255; //completely transparent end;} Getmem(Buffer,header.size); Blockread(f,buffer^,header.size); closefile(f); GlNewList(MyList,gl_compile); glpixelstorei(gl_unpack_alignment,4); {OpenGL 1.0 ignores this one} glpixelstorei(gl_unpack_row_length,0); glpixelstorei(gl_unpack_skip_rows,0); glpixelstorei(gl_unpack_skip_pixels,0); {for GLteximage2D the parameters are: gl_Texture_2d, level of detail (0 unless using mipmapped textures) components: 3 for RGB, 4 for RGBA 1 for indexed 256 color width, height border: width of the border, between 0 and 2. Format: gl_color_index, GL_RGB, GL_rgbA, GL_luminance are the most used type of the data for each pixel pointer to image data} gltexImage2d(gl_texture_2d,0,3,BMPinfo.width,BMPinfo.height,0,gl_rgb,gl_unsigned_byte,buffer^); glendlist; result:=0; {no error} end; Procedure TTexture.redraw; {call the display list, itīs not really a redraw, itīs part of one} begin if Automatic then {automatic texture coordinates generation} begin gltexgenf (GL_s,gl_texture_gen_mode,AutoGenModeX); gltexgenfv(GL_s,gl_object_plane,addr(AutoXmult)); gltexgenf (GL_t,gl_texture_gen_mode,AutoGenModeZ); gltexgenfv(GL_t,gl_object_plane,addr(AutoZmult)); end; gltexparameteri(gl_texture_2d,gl_texture_wrap_s,WrapSmode); gltexparameteri(gl_texture_2d,gl_texture_wrap_t,WrapTmode); gltexparameteri(gl_texture_2d,gl_texture_mag_filter,MagFilter); gltexparameteri(gl_texture_2d,gl_texture_min_filter,MinFilter); gltexEnvi(gl_texture_env,gl_texture_env_mode,EnvironmentMode); glcalllist(MyList); end; initialization PutNames:=false; {initially, the primitives will not be named} end.