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