File: gl_objreader.pp

package info (click to toggle)
gearhead2 0.628-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, squeeze, wheezy
  • size: 7,380 kB
  • ctags: 33
  • sloc: pascal: 52,411; makefile: 72; sh: 12
file content (311 lines) | stat: -rw-r--r-- 8,052 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
unit gl_objreader;
	{ This unit contains one function: a Wavefront .obj file reader. }
	{ The mesh is loaded from disk and stored as an opengl display list. }

	{ OpenGL should be initialized before this unit is called! Very important, that... }
{
	GearHead2, a roguelike mecha CRPG
	Copyright (C) 2005 Joseph Hewitt

	This library is free software; you can redistribute it and/or modify it
	under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation; either version 2.1 of the License, or (at
	your option) any later version.

	The full text of the LGPL can be found in license.txt.

	This library is distributed in the hope that it will be useful, but
	WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
	General Public License for more details. 

	You should have received a copy of the GNU Lesser General Public License
	along with this library; if not, write to the Free Software Foundation,
	Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
}
{$LONGSTRINGS ON}

interface

uses texutil,gl;

const
	Mesh_Dirname = 'mesh';
	Mesh_Directory = Mesh_Dirname + DirectorySeparator;

type
	SensibleMeshPtr = ^SensibleMesh;
	SensibleMesh = Record
		Name: String;
		DLID: Integer;
		Next: SensibleMeshPtr;
	end;

var
	Game_Meshes: SensibleMeshPtr;


Procedure Load_Obj_Mesh( const fname: String; DLID: Integer );

Function LocateMesh( Name: String ): SensibleMeshPtr;
Function SensibleMeshID( const Name: String ): GLUInt;
Procedure RemoveMesh( var LMember: SensibleMeshPtr );


implementation

type
	gl_point = Record
		X,Y,Z: GLFLoat;
	end;
	glpointarray = Array of gl_point;


Procedure Load_Obj_Mesh( const fname: String; DLID: Integer );
	{ Load this object from disk. Store it as a display list with the provided }
	{ display list ID. }
var
	F: Text;
	TheLine, cmd: String;
	v_list,vt_list,vn_list: glpointarray;
	v_n,v_length,vt_n,vt_length,vn_n,vn_length: Integer;

	Procedure ReadVertex( var Ver_List: glpointarray; var Ver_N, Ver_Length: INteger );
		{ Read a vertex from TheLine. This procedure works for normal }
		{ verticies, normals, and texture coordinates... I realize texture coords }
		{ only have two coordinates instead of three, but the third one will be }
		{ zero and no-one cares. }
	begin
		if ver_n >= ver_length then begin
			ver_length := ver_length * 2;
			SetLength( ver_list , ver_length );
		end;

		ver_list[ver_n].X := ExtractReal( TheLine );
		ver_list[ver_n].Y := ExtractReal( TheLine );
		ver_list[ver_n].Z := ExtractReal( TheLine );
		Inc( ver_n );
	end;

	Function ExtractSlashValue( var S: String ): Integer;
		{ Extract a string beginning at the first character and continuing }
		{ until either the end of the string or until a slash is detected. }
	var
		A2: Integer;
		S2: String;
	begin
		A2 := Pos('/',S);
		if A2 = 0 then A2 := Length( S ) + 1;
		S2 := Copy( S , 1 , A2 - 1 );
		S := Copy( S , A2 + 1 , Length( S ) );
		ExtractSlashValue := ExtractValue( S2 );
	end;

	Procedure AddFace;
		{ We've just encountered a "F". Go through those silly three-pronged }
		{ number-lumps and draw everything as intended. }
	var
		TPNLump: String;	{ What? What was I supposed to call it? }
		V,VN,VT: Integer;
	begin
		{ To start with, begin a polygon. }
		glBegin( GL_POLYGON );

		{ Keep going until we run out of points to process. }
		while TheLine <> '' do begin
			{ Extract the next triple-pronged number lump. }
			TPNLump := ExtractWord( TheLine );

			{ Extract the three coords needed from it. }
			V := ExtractSlashValue( TPNLump ) - 1;
			VT := ExtractSlashValue( TPNLump ) - 1;
			VN := ExtractSlashValue( TPNLump ) - 1;

			{ Do the drawing. }
			glTexCoord2f( 1 - vt_list[ vt ].X , 1 - vt_list[ vt ].Y );
			glNormal3f( vn_list[ vn ].X , vn_list[ vn ].Y , vn_list[ vn ].Z );
			glVertex3f( v_list[ v ].X , v_list[ v ].Y , v_list[ v ].Z );
		end;

		{ End the shape. }
		glEnd;
	end;
begin
	{ Initialize the point arrays. }
	SetLength( v_list , 100 );
	SetLength( vt_list , 100 );
	SetLength( vn_list , 100 );
	v_n := 0;
	vt_n := 0;
	vn_n := 0;
	v_length := 100;
	vt_length := 100;
	vn_length := 100;

	Assign( F , fname );

	Reset( F );
	glNewList( DLID , GL_COMPILE );

	while not Eof( F ) do begin
		readln(F,TheLine);
		DeleteWhiteSpace(TheLine);

		{ If this isn't a comment or an empty line, process the commands. }
		if ( TheLine <> '' ) and ( TheLine[1] <> '#' ) then begin
			while TheLine <> '' do begin
				cmd := UpCase( ExtractWord( TheLine ) );

				if cmd = 'V' then begin
					ReadVertex( v_list , v_n , v_length );

				end else if cmd = 'VN' then begin
					ReadVertex( vn_list , vn_n , vn_length );

				end else if cmd = 'VT' then begin
					ReadVertex( vt_list , vt_n , vt_length );

				end else if cmd = 'F' then begin
					{ FACE- the BIG one!!! }
					AddFace;

				end;
			end;
		end;
	end;

	glEndList();
	Close( F );
end;

Function NewMesh: SensibleMeshPtr;
	{ Add an empty mesh description to the list. }
	{ Give it a mesh name. }
var
	it: SensibleMeshPtr;
begin
	{ Allocate a SensibleMesh and initialize it. }
	New(it);
	if it = Nil then exit( Nil );
	{Initialize values.}
	it^.DLID := glGenLists( 1 );
	if it^.DLID = 0 then begin
		Dispose( it );
		Exit( Nil );
	end else begin
		it^.Next := Game_Meshes;
		Game_Meshes := it;
		NewMesh := it;
	end;
end;

Function AddSensibleMesh( Name: String ): SensibleMeshPtr;
	{ Add a mesh to the list. }
var
	MyMesh: SensibleMeshPtr;
	T: Integer;
begin
	{ Allocate a new mesh. }
	MyMesh := NewMesh;
	MyMesh^.Name := LowerCase( Name );

	{ Load the object referenced by the name. }
	Load_Obj_Mesh( Mesh_Directory + Name , MyMesh^.DLID );

	AddSensibleMesh := MyMesh;
end;


Function LocateMesh( Name: String ): SensibleMeshPtr;
	{ Get the number of the texture identified by the provided ID number. }
var
	T,it: SensibleMeshPtr;
begin
	T := Game_Meshes;
	it := Nil;
	name := LowerCase( Name );
	while T <> Nil do begin
		if ( T^.name = name ) then it := T;
		T := T^.Next;
	end;
	if it = Nil then it := AddSensibleMesh( name );
	LocateMesh := it;
end;

Function SensibleMeshID( const Name: String ): GLUInt;
	{ Return the ID for the requested mesh. }
var
	SM: SensibleMeshPtr;
begin
	SM := LocateMesh( name );
	SensibleMeshID := SM^.DLID;
end;

Procedure RemoveMesh( var LMember: SensibleMeshPtr );
	{Locate and extract member LMember from list LList.}
	{Then, dispose of LMember.}
var
	a,b: SensibleMeshPtr;
begin
	{Initialize A and B}
	B := Game_Meshes;
	A := Nil;

	{Locate LMember in the list. A will thereafter be either Nil,}
	{if LMember if first in the list, or it will be equal to the}
	{element directly preceding LMember.}
	while (B <> LMember) and (B <> Nil) do begin
		A := B;
		B := B^.next;
	end;

	if B = Nil then begin
		{Major FUBAR. The member we were trying to remove can't}
		{be found in the list.}
		writeln('ERROR- RemoveMesh asked to remove a mesh that doesnt exist.');
		end
	else if A = Nil then begin
		{There's no element before the one we want to remove,}
		{i.e. it's the first one in the list.}
		Game_Meshes := B^.Next;
		B^.Next := Nil;

		glDeleteLists( B^.DLID , 1 );
		Dispose( B );

		end
	else begin
		{We found the attribute we want to delete and have another}
		{one standing before it in line. Go to work.}
		A^.next := B^.next;
		B^.Next := Nil;

		glDeleteLists( B^.DLID , 1 );
		Dispose( B );
	end;
end;

Procedure DisposeMeshList(var LList: SensibleMeshPtr);
	{Dispose of the list, freeing all associated system resources.}
var
	LTemp: SensibleMeshPtr;
begin
	while LList <> Nil do begin
		LTemp := LList^.Next;

		glDeleteLists( LList^.DLID , 1 );

		Dispose(LList);
		LList := LTemp;
	end;
end;



initialization
	Game_Meshes := Nil;

finalization
	DisposeMeshList( Game_Meshes );

end.