]> icculus.org git repositories - btb/d2x.git/blob - main/editor/mine.c
Move old logs to ChangeLog-old
[btb/d2x.git] / main / editor / mine.c
1 /* $Id: mine.c,v 1.2 2004-12-19 14:52:48 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14
15 /*
16  *
17  * Mine specific editing functions, such as load_mine, save_mine
18  *
19  */
20
21
22 #ifdef RCS
23 static char rcsid[] = "$Id: mine.c,v 1.2 2004-12-19 14:52:48 btb Exp $";
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include <string.h>
30
31 #include "mono.h"
32 #include "key.h"
33 #include "gr.h"
34
35 #include "bm.h"                 // for MAX_TEXTURES
36
37 #include "inferno.h"
38 #include "segment.h"
39 #include "editor.h"
40 #include "error.h"
41 #include "textures.h"
42 #include "object.h"
43
44 #include "gamemine.h"
45 #include "gameseg.h"
46
47 #include "ui.h"                 // Because texpage.h need UI_WINDOW type
48 #include "texpage.h"            // For texpage_goto_first
49                          
50 #include "medwall.h"
51 #include "switch.h"
52
53 #include "nocfile.h"
54 #include "fuelcen.h"
55
56 #define REMOVE_EXT(s)  (*(strchr( (s), '.' ))='\0')
57
58 int CreateDefaultNewSegment();
59 int save_mine_data(CFILE * SaveFile);
60 int save_mine_data_compiled_new(FILE * SaveFile);
61
62 static char      current_tmap_list[MAX_TEXTURES][13];
63
64 // -----------------------------------------------------------------------------
65 // Save mine will:
66 // 1. Write file info, header info, editor info, vertex data, segment data,
67 //    and new_segment in that order, marking their file offset.
68 // 2. Go through all the fields and fill in the offset, size, and sizeof
69 //    values in the headers.
70
71 int med_save_mine(char * filename)
72 {
73         FILE * SaveFile;
74         char ErrorMessage[256];
75
76         SaveFile = cfopen( filename, CF_WRITE_MODE );
77         if (!SaveFile)
78         {
79 #ifndef __LINUX__
80                 char fname[20];
81                 _splitpath( filename, NULL, NULL, fname, NULL );
82
83                 sprintf( ErrorMessage, \
84                         "ERROR: Cannot write to '%s'.\nYou probably need to check out a locked\nversion of the file. You should save\nthis under a different filename, and then\ncheck out a locked copy by typing\n\'co -l %s.lvl'\nat the DOS prompt.\n" 
85                         , filename, fname);
86 #endif
87                 sprintf( ErrorMessage, "ERROR: Unable to open %s\n", filename );
88                 MessageBox( -2, -2, 1, ErrorMessage, "Ok" );
89                 return 1;
90         }
91
92         save_mine_data(SaveFile);
93         
94         //==================== CLOSE THE FILE =============================
95         cfclose(SaveFile);
96
97         return 0;
98
99 }
100
101 // -----------------------------------------------------------------------------
102 // saves to an already-open file
103 int save_mine_data(CFILE * SaveFile)
104 {
105         int  header_offset, editor_offset, vertex_offset, segment_offset, doors_offset, texture_offset, walls_offset, triggers_offset; //, links_offset;
106         int  newseg_verts_offset;
107         int  newsegment_offset;
108         int  i;
109
110         med_compress_mine();
111         warn_if_concave_segments();
112         
113         for (i=0;i<NumTextures;i++)
114                 strncpy(current_tmap_list[i], TmapInfo[i].filename, 13);
115
116         //=================== Calculate offsets into file ==================
117
118         header_offset = cftell(SaveFile) + sizeof(mine_fileinfo);
119         editor_offset = header_offset + sizeof(mine_header);
120         texture_offset = editor_offset + sizeof(mine_editor);
121         vertex_offset  = texture_offset + (13*NumTextures);
122         segment_offset = vertex_offset + (sizeof(vms_vector)*Num_vertices);
123         newsegment_offset = segment_offset + (sizeof(segment)*Num_segments);
124         newseg_verts_offset = newsegment_offset + sizeof(segment);
125         walls_offset = newseg_verts_offset + (sizeof(vms_vector)*8);
126         triggers_offset =       walls_offset + (sizeof(wall)*Num_walls);
127         doors_offset = triggers_offset + (sizeof(trigger)*Num_triggers);
128
129         //===================== SAVE FILE INFO ========================
130
131         mine_fileinfo.fileinfo_signature=       0x2884;
132         mine_fileinfo.fileinfo_version  =   MINE_VERSION;
133         mine_fileinfo.fileinfo_sizeof   =   sizeof(mine_fileinfo);
134         mine_fileinfo.header_offset     =   header_offset;
135         mine_fileinfo.header_size       =   sizeof(mine_header);
136         mine_fileinfo.editor_offset     =   editor_offset;
137         mine_fileinfo.editor_size       =   sizeof(mine_editor);
138         mine_fileinfo.vertex_offset     =   vertex_offset;
139         mine_fileinfo.vertex_howmany    =   Num_vertices;
140         mine_fileinfo.vertex_sizeof     =   sizeof(vms_vector);
141         mine_fileinfo.segment_offset    =   segment_offset;
142         mine_fileinfo.segment_howmany   =   Num_segments;
143         mine_fileinfo.segment_sizeof    =   sizeof(segment);
144         mine_fileinfo.newseg_verts_offset     =   newseg_verts_offset;
145         mine_fileinfo.newseg_verts_howmany    =   8;
146         mine_fileinfo.newseg_verts_sizeof     =   sizeof(vms_vector);
147         mine_fileinfo.texture_offset    =   texture_offset;
148         mine_fileinfo.texture_howmany   =   NumTextures;
149         mine_fileinfo.texture_sizeof    =   13;  // num characters in a name
150         mine_fileinfo.walls_offset                =     walls_offset;
151         mine_fileinfo.walls_howmany       =     Num_walls;
152         mine_fileinfo.walls_sizeof                =     sizeof(wall);  
153         mine_fileinfo.triggers_offset     =     triggers_offset;
154         mine_fileinfo.triggers_howmany  =       Num_triggers;
155         mine_fileinfo.triggers_sizeof     =     sizeof(trigger);  
156
157         // Write the fileinfo
158         cfwrite( &mine_fileinfo, sizeof(mine_fileinfo), 1, SaveFile );
159
160         //===================== SAVE HEADER INFO ========================
161
162         mine_header.num_vertices        =   Num_vertices;
163         mine_header.num_segments        =   Num_segments;
164
165         // Write the editor info
166         if (header_offset != cftell(SaveFile))
167                 Error( "OFFSETS WRONG IN MINE.C!" );
168
169         cfwrite( &mine_header, sizeof(mine_header), 1, SaveFile );
170
171         //===================== SAVE EDITOR INFO ==========================
172         mine_editor.current_seg         =   Cursegp - Segments;
173         mine_editor.newsegment_offset   =   newsegment_offset; 
174         mine_editor.newsegment_size     =   sizeof(segment);
175
176         // Next 3 vars added 10/07 by JAS
177         mine_editor.Curside             =   Curside;
178         if (Markedsegp)
179                 mine_editor.Markedsegp       =   Markedsegp - Segments;
180         else                                                                      
181                 mine_editor.Markedsegp       =   -1;
182         mine_editor.Markedside          =   Markedside;
183         for (i=0;i<10;i++)
184                 mine_editor.Groupsegp[i]          =     Groupsegp[i] - Segments;
185         for (i=0;i<10;i++)
186                 mine_editor.Groupside[i]     =  Groupside[i];
187
188         if (editor_offset != cftell(SaveFile))
189                 Error( "OFFSETS WRONG IN MINE.C!" );
190         cfwrite( &mine_editor, sizeof(mine_editor), 1, SaveFile );
191
192         //===================== SAVE TEXTURE INFO ==========================
193
194         if (texture_offset != cftell(SaveFile))
195                 Error( "OFFSETS WRONG IN MINE.C!" );
196         cfwrite( current_tmap_list, 13, NumTextures, SaveFile );
197         
198         //===================== SAVE VERTEX INFO ==========================
199
200         if (vertex_offset != cftell(SaveFile))
201                 Error( "OFFSETS WRONG IN MINE.C!" );
202         cfwrite( Vertices, sizeof(vms_vector), Num_vertices, SaveFile );
203
204         //===================== SAVE SEGMENT INFO =========================
205
206         if (segment_offset != cftell(SaveFile))
207                 Error( "OFFSETS WRONG IN MINE.C!" );
208         cfwrite( Segments, sizeof(segment), Num_segments, SaveFile );
209
210         //===================== SAVE NEWSEGMENT INFO ======================
211
212         if (newsegment_offset != cftell(SaveFile))
213                 Error( "OFFSETS WRONG IN MINE.C!" );
214         cfwrite( &New_segment, sizeof(segment), 1, SaveFile );
215
216         if (newseg_verts_offset != cftell(SaveFile))
217                 Error( "OFFSETS WRONG IN MINE.C!" );
218         cfwrite( &Vertices[New_segment.verts[0]], sizeof(vms_vector), 8, SaveFile );
219
220         //==================== CLOSE THE FILE =============================
221
222         return 0;
223
224 }
225
226
227
228 #define COMPILED_MINE_VERSION 0
229
230 void dump_fix_as_short( fix value, int nbits, CFILE * SaveFile )
231 {
232         int int_value=0; 
233         short short_value;
234
235         int_value = (int)(value>>nbits);
236         if( int_value > 0x7fff ) {
237                 short_value = 0x7fff;
238                 mprintf((1, "Warning: Fix (%8x) won't fit in short.  Saturating to %8x.\n", int_value, short_value<<nbits));
239         }
240         else if( int_value < -0x7fff ) {
241                 short_value = -0x7fff;
242                 mprintf((1, "Warning: Fix (%8x) won't fit in short.  Saturating to %8x.\n", int_value, short_value<<nbits));
243         }
244         else
245                 short_value = (short)int_value;
246
247         cfwrite( &short_value, sizeof(short_value), 1, SaveFile );
248 }
249
250 //version of dump for unsigned values
251 void dump_fix_as_ushort( fix value, int nbits, CFILE * SaveFile )
252 {
253         uint int_value=0;
254         ushort short_value;
255
256         if (value < 0) {
257                 mprintf((1, "Warning: fix (%8x) is signed...setting to zero.\n", value));
258                 Int3();         //hey---show this to Matt
259                 value = 0;
260         }
261         else
262                 int_value = value >> nbits;
263
264         if( int_value > 0xffff ) {
265                 short_value = 0xffff;
266                 mprintf((1, "Warning: Fix (%8x) won't fit in unsigned short.  Saturating to %8x.\n", int_value, short_value<<nbits));
267         }
268         else
269                 short_value = int_value;
270
271         cfwrite( &short_value, sizeof(short_value), 1, SaveFile );
272 }
273
274 int     New_file_format_save = 1;
275
276 // -----------------------------------------------------------------------------
277 // saves compiled mine data to an already-open file...
278 int save_mine_data_compiled(FILE * SaveFile)
279 {
280         short i,segnum,sidenum;
281         ubyte version = COMPILED_MINE_VERSION;
282
283 #ifndef SHAREWARE
284         if (New_file_format_save)
285                 return save_mine_data_compiled_new(SaveFile);
286 #endif
287
288         med_compress_mine();
289         warn_if_concave_segments();
290
291         if (Highest_segment_index >= MAX_GAME_SEGMENTS) {
292                 char    message[128];
293                 sprintf(message, "Error: Too many segments (%i > %i) for game (not editor)", Highest_segment_index+1, MAX_GAME_SEGMENTS);
294                 MessageBox( -2, -2, 1, message, "Ok" );
295         }
296
297         if (Highest_vertex_index >= MAX_GAME_VERTICES) {
298                 char    message[128];
299                 sprintf(message, "Error: Too many vertices (%i > %i) for game (not editor)", Highest_vertex_index+1, MAX_GAME_VERTICES);
300                 MessageBox( -2, -2, 1, message, "Ok" );
301         }
302
303         //=============================== Writing part ==============================
304         cfwrite( &version, sizeof(ubyte), 1, SaveFile );                                                // 1 byte = compiled version
305         cfwrite( &Num_vertices, sizeof(int), 1, SaveFile );                                     // 4 bytes = Num_vertices
306         cfwrite( &Num_segments, sizeof(int), 1, SaveFile );                                             // 4 bytes = Num_segments
307         cfwrite( Vertices, sizeof(vms_vector), Num_vertices, SaveFile );
308
309         for (segnum=0; segnum<Num_segments; segnum++ )  {
310                 // Write short Segments[segnum].children[MAX_SIDES_PER_SEGMENT]
311                 cfwrite( &Segments[segnum].children, sizeof(short), MAX_SIDES_PER_SEGMENT, SaveFile );
312                 // Write short Segments[segnum].verts[MAX_VERTICES_PER_SEGMENT]
313                 cfwrite( &Segments[segnum].verts, sizeof(short), MAX_VERTICES_PER_SEGMENT, SaveFile );
314                 // Write ubyte  Segments[segnum].special
315                 cfwrite( &Segments[segnum].special, sizeof(ubyte), 1, SaveFile );
316                 // Write byte   Segments[segnum].matcen_num
317                 cfwrite( &Segments[segnum].matcen_num, sizeof(ubyte), 1, SaveFile );
318                 // Write short  Segments[segnum].value
319                 cfwrite( &Segments[segnum].value, sizeof(short), 1, SaveFile );
320                 // Write fix    Segments[segnum].static_light (shift down 5 bits, write as short)
321                 dump_fix_as_ushort( Segments[segnum].static_light, 4, SaveFile );
322                 //cfwrite( &Segments[segnum].static_light , sizeof(fix), 1, SaveFile );
323         
324                 // Write the walls as a 6 byte array
325                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++ )      {
326                         uint wallnum;
327                         ubyte byte_wallnum;
328                         if (Segments[segnum].sides[sidenum].wall_num<0)
329                                 wallnum = 255;          // Use 255 to mark no walls
330                         else {
331                                 wallnum = Segments[segnum].sides[sidenum].wall_num;
332                                 Assert( wallnum < 255 );                // Get John or Mike.. can only store up to 255 walls!!! 
333                         }
334                         byte_wallnum = (ubyte)wallnum;
335                         cfwrite( &byte_wallnum, sizeof(ubyte), 1, SaveFile );
336                 }
337
338                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++ )      {
339                         if ( (Segments[segnum].children[sidenum]==-1) || (Segments[segnum].sides[sidenum].wall_num!=-1) )       {
340                                 // Write short Segments[segnum].sides[sidenum].tmap_num;
341                                 cfwrite( &Segments[segnum].sides[sidenum].tmap_num, sizeof(short), 1, SaveFile );
342                                 // Write short Segments[segnum].sides[sidenum].tmap_num2;
343                                 cfwrite( &Segments[segnum].sides[sidenum].tmap_num2, sizeof(short), 1, SaveFile );
344                                 // Write uvl Segments[segnum].sides[sidenum].uvls[4] (u,v>>5, write as short, l>>1 write as short)
345                                 for (i=0; i<4; i++ )    {
346                                         dump_fix_as_short( Segments[segnum].sides[sidenum].uvls[i].u, 5, SaveFile );
347                                         dump_fix_as_short( Segments[segnum].sides[sidenum].uvls[i].v, 5, SaveFile );
348                                         dump_fix_as_ushort( Segments[segnum].sides[sidenum].uvls[i].l, 1, SaveFile );
349                                         //cfwrite( &Segments[segnum].sides[sidenum].uvls[i].l, sizeof(fix), 1, SaveFile );
350                                 }       
351                         }
352                 }
353
354         }
355
356         return 0;
357 }
358
359 // -----------------------------------------------------------------------------
360 // saves compiled mine data to an already-open file...
361 int save_mine_data_compiled_new(FILE * SaveFile)
362 {
363         short           i, segnum, sidenum, temp_short;
364         ubyte   version = COMPILED_MINE_VERSION;
365         ubyte           bit_mask = 0;
366
367         med_compress_mine();
368         warn_if_concave_segments();
369
370         if (Highest_segment_index >= MAX_GAME_SEGMENTS) {
371                 char    message[128];
372                 sprintf(message, "Error: Too many segments (%i > %i) for game (not editor)", Highest_segment_index+1, MAX_GAME_SEGMENTS);
373                 MessageBox( -2, -2, 1, message, "Ok" );
374         }
375
376         if (Highest_vertex_index >= MAX_GAME_VERTICES) {
377                 char    message[128];
378                 sprintf(message, "Error: Too many vertices (%i > %i) for game (not editor)", Highest_vertex_index+1, MAX_GAME_VERTICES);
379                 MessageBox( -2, -2, 1, message, "Ok" );
380         }
381
382         //=============================== Writing part ==============================
383         cfwrite( &version, sizeof(ubyte), 1, SaveFile );                                                // 1 byte = compiled version
384         temp_short = Num_vertices;
385         cfwrite( &temp_short, sizeof(short), 1, SaveFile );                                     // 2 bytes = Num_vertices
386         temp_short = Num_segments;
387         cfwrite( &temp_short, sizeof(short), 1, SaveFile );                                     // 2 bytes = Num_segments
388         cfwrite( Vertices, sizeof(vms_vector), Num_vertices, SaveFile );
389
390         for (segnum=0; segnum<Num_segments; segnum++ )  {
391
392                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
393                         if (Segments[segnum].children[sidenum] != -1)
394                                 bit_mask |= (1 << sidenum);
395                 }
396
397                 if ((Segments[segnum].special != 0) || (Segments[segnum].matcen_num != 0) || (Segments[segnum].value != 0))
398                         bit_mask |= (1 << MAX_SIDES_PER_SEGMENT);
399
400                 cfwrite( &bit_mask, sizeof(ubyte), 1, SaveFile );
401
402                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
403                         if (bit_mask & (1 << sidenum))
404                                 cfwrite( &Segments[segnum].children[sidenum], sizeof(short), 1, SaveFile );
405                 }
406
407                 cfwrite( &Segments[segnum].verts, sizeof(short), MAX_VERTICES_PER_SEGMENT, SaveFile );
408
409                 if (bit_mask & (1 << MAX_SIDES_PER_SEGMENT)) {
410                         cfwrite( &Segments[segnum].special, sizeof(ubyte), 1, SaveFile );
411                         cfwrite( &Segments[segnum].matcen_num, sizeof(ubyte), 1, SaveFile );
412                         cfwrite( &Segments[segnum].value, sizeof(short), 1, SaveFile );
413                 }
414
415                 dump_fix_as_ushort( Segments[segnum].static_light, 4, SaveFile );
416         
417                 // Write the walls as a 6 byte array
418                 bit_mask = 0;
419                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++ )      {
420                         uint wallnum;
421                         if (Segments[segnum].sides[sidenum].wall_num >= 0) {
422                                 bit_mask |= (1 << sidenum);
423                                 wallnum = Segments[segnum].sides[sidenum].wall_num;
424                                 Assert( wallnum < 255 );                // Get John or Mike.. can only store up to 255 walls!!! 
425                         }
426                 }
427                 cfwrite( &bit_mask, sizeof(ubyte), 1, SaveFile );
428
429                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++ )      {
430                         if (bit_mask & (1 << sidenum))
431                                 cfwrite( &Segments[segnum].sides[sidenum].wall_num, sizeof(ubyte), 1, SaveFile );
432                 }
433
434                 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++ )      {
435                         if ( (Segments[segnum].children[sidenum]==-1) || (Segments[segnum].sides[sidenum].wall_num!=-1) )       {
436                                 ushort  tmap_num, tmap_num2;
437
438                                 tmap_num = Segments[segnum].sides[sidenum].tmap_num;
439                                 tmap_num2 = Segments[segnum].sides[sidenum].tmap_num2;
440                                 if (tmap_num2 != 0)
441                                         tmap_num |= 0x8000;
442
443                                 cfwrite( &tmap_num, sizeof(ushort), 1, SaveFile );
444                                 if (tmap_num2 != 0)
445                                         cfwrite( &tmap_num2, sizeof(ushort), 1, SaveFile );
446
447                                 for (i=0; i<4; i++ )    {
448                                         dump_fix_as_short( Segments[segnum].sides[sidenum].uvls[i].u, 5, SaveFile );
449                                         dump_fix_as_short( Segments[segnum].sides[sidenum].uvls[i].v, 5, SaveFile );
450                                         dump_fix_as_ushort( Segments[segnum].sides[sidenum].uvls[i].l, 1, SaveFile );
451                                 }       
452                         }
453                 }
454
455         }
456
457         return 0;
458 }
459
460