Announcement

Collapse
No announcement yet.

WorldSpawn official WIP thread

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • My engine can now concoct and export a wad file from a bsp (via a boolean in the descriptor) and also use a wad as a source of replacement textures. Pak is about done as well - both directions - read pak/convert current level to pak. It has to be that way for now cause this isn't intended as a pakscape replacement. Actually, I'm not really sure what convert-level-to-pak is good for, maybe nothing, but, in begat out and it is what it is.

    regarding collision detection - I'm detecting. I spent 3 days reading collision solutions and the accompanying math. I just need some more time for it to stew and I will write my own "physics" from scratch with no reference. I could totally rip and port from some quake source but, I have managed to keep 99.999% of my code quake sourceless and I intend to keep it that way.

    Also, my PVS system is about to be different. I have an idea of how to convert leaves to portals. This is necessary. Spike and I had a mini-discussion in my Real Flash Quake thread and the "hybrid solution" was to essentially treat a bsp like a collection of texture models...marking visible textures at any given point and dumping the non-visible ones from the buffer. That way isn't bad but it isn't good either. Consider a bullet with an RTL attached. Currently, that light has to be applied to every visible texture in the map simultaneously. If I'm rendering a whole lot of world that isn't even visible, firing that bullet becomes unnecessarily expensive. I have a hybrid-hybrid solution that still considers the bsp as a bunch of texture models but chops it up into portals as well. There will still be some unnecessary geometry rendered, just far less of it. From there, I will spin my own file type of BSP "results". I did this a long time ago when I first started this project but quickly dumped it due to not being sure of what "results" will actually be. Now that I have some actual direction to my pvs and what-not I can contour the results to compliment my system. The "file-type" is nothing mysterious. It's nothing more than a flash object saved as bytes. My engine will still totally support all the BSPs that it already does but, can unify and export all that to one big generic object of "instant" results. This will speed some things up because there wont be a parsing stage. Unless you consider this a parse

    var bspObjectbject = bspObjectBytes.readObject();
    //assign children to geometry

    My hope is to finish my collision detection, physics & pvs systems at about the same time, rounding my engine off to be a completely viable game engine. From there it should just be a bunch of HUD crap and Map entities hanging. I'm sure I will find some way to make that take forever. IDC. It's not a race. I'd rather program it to death and have rock solid results than just "whip something up" that isn't worth shit. Honestly, when I get to the point where I am "done", I will probably go back from the ground up of my entire source and make sure there is no possible way I could do it better. Then start stripping the entire away3d api down to the barely-any-of-it that I'm using and move those classes into my engine. I didn't realize how little of the API I was using until the other day. Lights and Materials are about it and barely any of the Materials (like 2 out of like 20). I wrote my own Geometry classes a long time ago.

    edit: woops - Lights, Materials and PARTICLES. I will not strip the particle engine out and merge it into my source. Lights and Materials are nothing fantastic and I could totally write those classes myself. Particles, on the other hand, were programmed to death by someone really talented and I wouldn't feel right making it seem like it is built into my engine. Particles will be the only external package to my source.
    Last edited by MadGypsy; 10-31-2016, 07:32 AM.
    http://www.nextgenquake.com

    Comment




    • here is the early concept for my vis.

      let's say we start at leaf 1, and let's pretend that all we can see from 1 is 2 and 3. 1, 2 and 3 become assumed to be one big leaf BUT then we go to 2 and 3 and find the visible leafs. Let's assume that we end up with 1,2,3,4,5 & 6 as the total visible leafs... all of that becomes 1 portal. Then we skip ahead to the next leaf that has not already been used. Let's assume that is 7. From 7 we can see 8 & 9 but from 8 we can see 6. 6 is already used so portal 2 becomes 7,8 & 9 with portal 1 visible. Meaning if portal 1 is visible, portal 2 will be as well and vise versa. Let's assume there was a 3rd portal above portal 2 in my image and it shared leafs with 2. When you are in portal 3, portal 2 would be visible but portal 1 would not unless some portion of portal 1 was visible from portal 3. This means that it is entirely possible that some portion of portal 2 may be missing even though it is visible from portal 3 (due to sharing). This may solve itself by being considered a portal 1 visibility and simply make portals 1, 2 and 3 visible.

      This is just my early idea though and through implementation I could probably work out any problems that I end up having. The end result should be something along the lines of - the room your are in and immediately surrounding rooms are visible (in the render buffer) while the entire rest of the map is not. By expanding the leafs to portals I can still batch textures more optimally than leafs but (hopefully) remove a lot of unnecessary geometry. Of course the plan is to ultimately precompute these portals and store those results in my bspByteObject file.

      Maybe my system could even be further figured into bigger portals based on any portals that are always visible and invisible together. It's not so much about trying to get the smallest amount of data possible as it is about removing a large portion of completely unnecessary geometry. Of course if I was trying to only get the actually visible stuff it would be ideal in a processing sense but, it would have to be too versatile to simply pack buffers with texture groups. By trying to be that optimal I end up right back at "leaf models" and I don't have to run any tests at all to know that will run like shit.
      Last edited by MadGypsy; 10-31-2016, 08:29 AM.
      http://www.nextgenquake.com

      Comment


      • I've started stripping out certain utilities that are programmed into my engine. An example would be spitting out wad2 or wad3 files from a bsp. I'm doing this because I don't want these functions embedded in my engine source. The end result will be a "quake tech utility" with a somewhat motley set of features. Some of the features will be specific to my engine, like precomputing everything I intend to do to a BSP, for example. Other features will be useful to people using any quake engine. One example is:

        I wrote an algorithm last night that approximates any image against a palette. It's not too shabby. I have ideas on how to make it better.

        Anyway, some time in the very near future I'll have some little simple tool that anyone can use. It will primarily manipulate image related data regarding replacement textures, bsp textures and wad(2/3) textures. Maybe not as useful but definitely available will be all the tools and features that I invented for auditing and manipulating a bsp directly. I find these tools essential. Especially if you don't know or understand the bsp format and are of a mind to read thousands of lines of numbers and gain understanding from them. Boring as fuck? Absolutely but, I have had so many various "Aha's" and ideas reading this stuff that I refuse to believe it's useless. It's most helpful when you make small tester BSPs that force certain results so you can understand accompanying results.

        Within this separation I intend to write a new BSP parser. My parser works like everybody else's parser. Segregate the bsp data into "structs" and then process the structs. I've been wanting to rewrite it in a way that starts processing the results straight out of the bsp...literally performing the math directly on the read bytes. It will be "impossible" to read my final code but, I'm curious if it would be faster to completely skip the part that is only necessary to make the bytes logical to humans.

        it has to be... consider this
        read all bytes
        chop into lumps
        further chop lumps into a series of objects
        process objects into geometry, textures, pvs, etc

        now consider this
        directly process bsp bytes into geometry, textures, pvs, etc

        in the first example you end up going over the same data at least twice. It has to be faster to not do that. Also (in flash at least) there is nothing faster than bytes. Essentially, I currently parse the fastest stuff to slower stuff and then use the slower stuff to build the BSP. When I say faster/slower are we actually talking about numbers that make a difference? IDK. Maybe I will shave a quarter of a millisecond total. Maybe I'll shave a quarter of a millisecond per operation. I really don't know and can't find information this specific about the types.


        ooooh that gives me another idea....
        Last edited by MadGypsy; 11-01-2016, 01:38 PM.
        http://www.nextgenquake.com

        Comment


        • For anybody that would like to parse wad2 files but is stuck on the part that the main fucking thing isn't documented anywhere...here are the answers. Between sloppy-as-fuck netradiant code, shitty shitty docs for wad2 and wad3 and some trial and error, I was able to figure it out. And how do you like this... I didn't have to spread it all out over like 10 different .cpp/.h files (middle finger @ netradiant). It's just one damn function.

          note: "all" was added to suppress the cache'ing of all mip levels. If all is false only the full-size image gets cached. Which is congruent with my engine handling mips on it's own.

          todo: create a switch/case block for entry.type and segregate the current code to case 0x44 ('D' or miptex), followed by creating the cases for the 3 remaining types (or at least the palette ('@' or 0x40) since the rest is hud/console stuff)

          Code:
          public static function parse(bytes:ByteArray, all:Boolean = true):Boolean
          {
          	if ((bytes == null) || (bytes.length == 0)) return false;
          	
          	//vars we'll need
          	var i:int, n:int, width:int, height:int;
          	var name:String, newName:String;
          	var image:ByteArray, img_ofs:Array;
          	var obj:Object;
          	
          	//set bytestream pointer to the beginning
          	bytes.position = 0;
          	
          	//read version
          	var magic:String	= bytes.readMultiByte(4, "iso-8559-1");
          	if (!(/wad2|wad3/i).test(magic)) return false;
          	
          	//read number of entries and first entry lump offset
          	var numentries:int	= bytes.readInt();
          	var offset:int		= bytes.readInt();
          	
          	//prime entry vector and fix it's length
          	entries = new Vector.<Object>(numentries, true);
          	
          	//store all entry data
          	for (n = 0; n < numentries; ++n)
          	{
          		bytes.position  = offset + (n << 5);
          		obj = {
          			filepos:bytes.readInt(),
          			disksize:bytes.readInt(),
          			size:bytes.readInt(),
          			type:bytes.readByte(),
          			compression:bytes.readByte(),
          			pad:bytes.readShort(),
          			name:bytes.readMultiByte(16, "iso-8559-i")
          		}
          		entries[n] = obj;
          	}
          	
          	//loop over entries and gather miptex data
          	entries.forEach(function(entry:Object, ni:int, self:Vector.<Object>):void 
          	{
          		if (entry["filepos"] != undefined)
          		{	
          			//set the bytestream pointer
          			bytes.position = entry["filepos"];
          			
          			//read simple properties
          			name	= bytes.readMultiByte(16, "iso-8559-1");
          			width	= bytes.readInt();
          			height	= bytes.readInt();
          			
          			//read miptex offsets
          			img_ofs = [bytes.readInt(), bytes.readInt(), bytes.readInt(), bytes.readInt()];
          			
          			//loop over offsets
          			img_ofs.forEach(function(ofs:int, nn:int, self:Array):void
          			{	image = new ByteArray();
          				
          				if((nn<1)||(all))
          				{	//set bytestream pointer
          					bytes.position = entry["filepos"] + ofs;
          					
          					//store uint from palette
          					i = ((height >> nn) * (width >> nn)) + 1;
          					while(--i) image.writeUnsignedInt(Palette.hexARGB[bytes.readUnsignedByte()]);
          					
          					//append >0 mipnum to name and store image in lib
          					newName = (nn>0)?name+(1<<nn):name;
          					ContentManager.setByteImage(newName, width >> nn, height >> nn, image);
          				}
          			});
          		}
          		
          	});
          	
          	//get rid of everything
          	entries = null;
          	bytes.clear();
          	
          	return true;
          }
          ignore all the STATE stuff. That's just there in case I needed to load more stuff in STATE 0... as it fires an Event.COMPLETE it would skip to STATE 1 case where I would tell it to do more stuff. I'm not actually using that system for this experiment. It's just there if I need it.


          tidbit:
          If reversing this to save a wad, to generate the proper size/disksize - use this formula

          Code:
          var size:int = (width*height)+((width*height)>>2)+((width*height)>>4)+((width*height)>>6)+40
          or in a loop

          Code:
          var n:int = 4;
          var size:int = 40;//size of miptex header
          while((--n) > -1) size += (width*height) >> (n+n);
          also to create miptex offsets use this formula
          Code:
          var i:int = -1; var ofs:int = 40;
          byteMiptex.writeInt(ofs); 			//prime first entry offset
          
          while ((++i) < 3)
          {	ofs += (width * height) >> (i+i);
          	byteMiptex.writeInt(ofs);		//mip offsets
          }
          Last edited by MadGypsy; 11-02-2016, 01:23 PM.
          http://www.nextgenquake.com

          Comment


          • Very very nice.. everything
            The gemstone of gaming is Quake, so load it up and play some

            Comment


            • Thank you, Gem!
              http://www.nextgenquake.com

              Comment


              • hello MG, what about fullbrightness textures?? ( i mean glow textures)
                the invasion has begun! hide your children, grab the guns, and pack sandwiches.

                syluxman2803

                Comment


                • @nahuel

                  Good question...I have no idea. According to wad specs (all of them) you get palette, mips, console & screen. I'm not sure where your question fits into that paradigm.
                  http://www.nextgenquake.com

                  Comment


                  • and here's the code for ripping wad2 from a bsp. Even though an entry in a miptex lump from a bsp is seemingly identical to a wad image entry, writing those bytes (from name to end of last mip) flat out doesn't work. miptex lump uses unsigned_long and wad uses long for many values. I didn't think that was a big deal but, I couldn't get this to work til I specifically read as uint and wrote as int.


                    Code:
                    /** RIP_WAD_FROM_BSP
                     * 
                     * @param	byName - library name of bsp file
                     * @return	true/false success
                     */
                    public static function wadFromBsp(byName:String):Boolean
                    {
                    	var bsp:ByteArray;
                    	if ((bsp = ContentManager.getBsp(byName)) == null) return false;
                    	bsp.position = 20; //skip to miptex offest/length
                    	
                    	//store miptex lump
                    	var miptex:ByteArray = new ByteArray();
                    	miptex.endian = Endian.LITTLE_ENDIAN;
                    	miptex.writeBytes(bsp, bsp.readUnsignedInt(), bsp.readUnsignedInt());
                    	
                    	//"dispose" the bsp stream
                    	bsp.clear();
                    	
                    	//prime for entry data
                    	var entries:ByteArray = new ByteArray();
                    	entries.endian = Endian.LITTLE_ENDIAN;
                    	
                    	//prime for image data
                    	var images:ByteArray = new ByteArray();
                    	images.endian = Endian.LITTLE_ENDIAN;
                    	
                    	//prime positions
                    	miptex.position = entries.position = 0;
                    	
                    	//store image offsets
                    	var image_offsets:Vector.<int> = new Vector.<int>(miptex.readInt(), true);
                    	image_offsets.forEach(function(na:int, n:int, self:Vector.<int>):void {	//	loop through empty indexes
                    		self[n] = miptex.readInt();					//	assign this index the offset from the miptex bytestream
                    	});
                    	
                    	//init size and prime offset
                    	var size:int, offset:int = 12;
                    	
                    	//this is actually arbitrary and primarily used as a fancy loop
                    	var directory:Vector.<Object> = new Vector.<Object>(image_offsets.length, true);
                    	
                    	directory.forEach(function(entry:Object, n:int, self:Vector.<Object>):void
                    	{
                    		//bsp stores all this as u_long...*
                    		miptex.position = image_offsets[n] + 16;			//skip the name - written to images
                    		entry =
                    		{	width:miptex.readUnsignedInt(),
                    			height:miptex.readUnsignedInt(),
                    			offsets:[miptex.readUnsignedInt(), miptex.readUnsignedInt(), miptex.readUnsignedInt(), miptex.readUnsignedInt()]
                    		}
                    		
                    		//*...but wad expects long
                    		images.position = images.length;
                    		images.writeBytes(miptex, image_offsets[n], 16);	//get it straight from the miptex lump FTW! Eat that, null!
                    		images.writeInt(entry.width);
                    		images.writeInt(entry.height);
                    		
                    		entry.offsets.forEach(function(img_ofs:int, ni:int, self:Array):void{ images.writeInt(img_ofs); });
                    		
                    		//write the entire length of miptex data for this image 
                    		size = (entry.width * entry.height) + ((entry.width * entry.height) >> 2) + ((entry.width * entry.height) >> 4) + ((entry.width * entry.height) >> 6);
                    		images.writeBytes(miptex, image_offsets[n] + 40,  size);
                    		
                    		//increment size by header size
                    		size+= 40;
                    		
                    		entries.position = entries.length;
                    		entries.writeInt(offset);			//filepos
                    		entries.writeInt(size);				//disksize
                    		entries.writeInt(size);				//size
                    		entries.writeByte(0x44);			//type - mip 0x44 | pal 0x40 | stat 0x43 | con 0x45
                    		entries.writeByte(0x00);			//compression
                    		entries.writeShort(0x0000);			//pad
                    		//name16
                    		entries.writeBytes(miptex, image_offsets[n], 16);
                    		
                    		offset += size;
                    		
                    	}); 
                    	
                    	directory = null;	//like it never even happened
                    	
                    	images.position = entries.position = 0;
                    	
                    	//combine images and entries into a final wad
                    	var wad:ByteArray = new ByteArray();
                    	wad.endian = Endian.LITTLE_ENDIAN;
                    	wad.writeMultiByte("WAD2", "iso-8559-1");
                    	wad.writeInt(image_offsets.length);
                    	wad.writeInt(12+images.length);
                    	wad.writeBytes(images);
                    	wad.writeBytes(entries);
                    	
                    	ExportManager.export("wads/" + byName + ".wad", wad); 
                    	
                    	return true;
                    }
                    In the below image ~ I ran wadFromBSP() on the start map for Arcane Dimensions. I then reversed the commenting, recompiled and ran parse() on the wad that was just created


                    it was tested, and works in radiant
                    Last edited by MadGypsy; 11-02-2016, 08:55 PM.
                    http://www.nextgenquake.com

                    Comment


                    • Originally posted by nahuel View Post
                      hello MG, what about fullbrightness textures?? ( i mean glow textures)
                      8-bit textures found in Quake .wad files don't have specific glow/luma additional textures. They don't need them since the fullbrights are dictated by the palette (fullbright colors are in the last 2 rows at the bottom). The luma textures are for 24-bit textures that override the palette.
                      Last edited by Mugwump; 11-02-2016, 10:23 PM.
                      ♪ I'm skiiiiiiinnin' in the pain, just skiiiiiiinnin' in the pain ♪
                      ♪ What a glorious feelin' I'm haaaaaaappy again ♪

                      Comment


                      • This is almost definitive. Below is the whole wad script. For ripping wads out of a bsp it polishes it off by writing a palette to the wad. For just parsing a wad I have everything covered except console (cause I can't find a wad that uses console). I also tidied up the script.

                        Code:
                        package gypsy.files.wad 
                        {
                        	import flash.utils.ByteArray;
                        	import flash.utils.Endian;
                        	
                        	/**
                        	 * ...
                        	 * @author OneMadGypsy
                        	 */
                        	public class Wad 
                        	{
                        		private static var palette:Boolean = false;
                        		
                        		private static const PAL:int  = 0x40;
                        		private static const STAT:int = 0x42;
                        		private static const MIPS:int = 0x44;
                        		private static const CONS:int = 0x45;
                        		
                        		public static function parse(bytes:ByteArray, all:Boolean = true):Boolean
                        		{
                        			if ((bytes == null) || (bytes.length == 0)) return false;
                        			
                        			//vars we'll need
                        			var width:int, height:int, length:int;
                        			var name:String, namei:String;
                        			var image:ByteArray, image_offsets:Array;
                        			
                        			//set bytestream pointer to the beginning
                        			bytes.position = 0;
                        			
                        			//read version
                        			var magic:String	= bytes.readMultiByte(4, "iso-8559-1");
                        			if (!(/wad2|wad3/i).test(magic)) return false;
                        			
                        			//read number of entries and first entry lump offset
                        			var numentries:int	= bytes.readInt();
                        			var offset:int		= bytes.readInt();
                        			
                        			//prime entry vector and fix it's length
                        			var entries:Vector.<Object> = new Vector.<Object>(numentries, true);
                        			
                        			//store all entry data
                        			entries.forEach(function(entry:Object, n:int, self:Vector.<Object>):void 
                        			{
                        				bytes.position  = offset + (n << 5);
                        				
                        				self[n] = {
                        					filepos:bytes.readInt(),
                        					disksize:bytes.readInt(),
                        					size:bytes.readInt(),
                        					type:bytes.readByte(),
                        					compression:bytes.readByte(),
                        					pad:bytes.readShort(),
                        					name:bytes.readMultiByte(16, "iso-8559-i")
                        				}
                        				
                        				//grab palette as we come across it
                        				if ((self[n].type == PAL) && (!palette))
                        				{	palette = true;
                        					bytes.position = self[n].filepos;
                        					Palette.hexARGB.forEach(function(col:uint, ci:int, self:Vector.<uint>):void{
                        						self[ci] = (0xFF << 24 | bytes.readByte() << 16 | bytes.readByte() << 8 | bytes.readByte());
                        					});
                        				}
                        			});
                        			
                        			//loop over entries and gather image data
                        			entries.forEach(function(entry:Object, n:int, self:Vector.<Object>):void 
                        			{
                        				if ((entry["filepos"] != undefined) && (entry["type"] != undefined))
                        				{	//set the bytestream pointer
                        					bytes.position = entry["filepos"];
                        					
                        					switch (entry["type"])
                        					{
                        						case PAL:
                        							//do nothing
                        							break;
                        						case STAT:
                        							width	= bytes.readInt();
                        							height	= bytes.readInt();
                        							length = (width * height)+1;
                        							
                        							image = new ByteArray();
                        							while (--length) image.writeUnsignedInt(Palette.hexARGB[bytes.readUnsignedByte()]);
                        							
                        							ContentManager.setByteImage(entry.name, width, height, image);
                        							break;
                        						case CONS:
                        							trace("Congratulations! You have the only wad in the universe that uses this!");
                        							break;
                        						case MIPS:
                        							//read simple properties
                        							name	= bytes.readMultiByte(16, "iso-8559-1");
                        							
                        							if((/[a-z0-9]/i).test(name))
                        							{	width	= bytes.readInt();
                        								height	= bytes.readInt();
                        								
                        								//read miptex offsets
                        								image_offsets = [bytes.readInt(), bytes.readInt(), bytes.readInt(), bytes.readInt()];
                        								
                        								//loop over offsets
                        								image_offsets.forEach(function(ofs:int, mip:int, self:Array):void
                        								{	image = new ByteArray();
                        									
                        									if( (!Boolean(mip)) || all )
                        									{	//set bytestream pointer
                        										bytes.position = entry["filepos"] + ofs;
                        										
                        										//store uint from palette
                        										length = ((height >> mip) * (width >> mip)) + 1;
                        										while (--length) image.writeUnsignedInt(Palette.hexARGB[bytes.readUnsignedByte()]);
                        										
                        										//append >0 mipnum to name and store image in lib
                        										namei = (mip>0)?name+(1<<mip):name;
                        										ContentManager.setByteImage(namei, width >> mip, height >> mip, image);
                        									}
                        								});
                        							} else {
                        								//nameless miptexes
                        								bytes.position = entry["filepos"];
                        								width  = height = Math.sqrt(entry.size);
                        								length = entry.size+1;
                        								
                        								image = new ByteArray();
                        								while (--length) image.writeUnsignedInt(Palette.hexARGB[bytes.readUnsignedByte()]);
                        							
                        								ContentManager.setByteImage(entry.name, width, height, image);
                        							}
                        							break
                        					}
                        				}
                        			});
                        			
                        			//get rid of everything
                        			entries = null;
                        			bytes.clear();
                        			
                        			return true;
                        		}
                        		
                        		/** RIP_WAD_FROM_BSP
                        		 * 
                        		 * @param	byName - library name of bsp file
                        		 * @return	true/false success
                        		 */
                        		public static function wadFromBsp(byName:String):Boolean
                        		{
                        			var bsp:ByteArray;
                        			if ((bsp = ContentManager.getBsp(byName)) == null) return false;
                        			bsp.position = 20; //skip to miptex offest/length
                        			
                        			//store miptex lump
                        			var miptex:ByteArray = new ByteArray();
                        			miptex.endian = Endian.LITTLE_ENDIAN;
                        			miptex.writeBytes(bsp, bsp.readUnsignedInt(), bsp.readUnsignedInt());
                        			
                        			//"dispose" the bsp stream
                        			bsp.clear();
                        			
                        			//prime for entry data
                        			var entries:ByteArray = new ByteArray();
                        			entries.endian = Endian.LITTLE_ENDIAN;
                        			
                        			//prime for image data
                        			var images:ByteArray = new ByteArray();
                        			images.endian = Endian.LITTLE_ENDIAN;
                        			
                        			//prime positions
                        			miptex.position = entries.position = 0;
                        			
                        			//store image offsets
                        			var image_offsets:Vector.<int> = new Vector.<int>(miptex.readInt(), true);
                        			image_offsets.forEach(function(na:int, n:int, self:Vector.<int>):void {		//	loop through empty indexes
                        				self[n] = miptex.readInt();												//	assign this index the offset from the miptex bytestream
                        			});
                        			
                        			//init size and prime offset
                        			var size:int, offset:int = 12;
                        			
                        			//this is actually arbitrary and primarily used as a fancy loop
                        			var directory:Vector.<Object> = new Vector.<Object>(image_offsets.length, true);
                        			
                        			var bname:ByteArray = new ByteArray();
                        			directory.forEach(function(entry:Object, n:int, self:Vector.<Object>):void
                        			{
                        				//store the name as bytes so I don't have to deal with padding later
                        				if (bname.length > 0) bname.clear();
                        				bname.writeBytes(miptex, image_offsets[n], 16);	//get it straight from the miptex lump FTW! Eat that, null!
                        				
                        				//bsp stores all this as u_long...*
                        				miptex.position = image_offsets[n] + 16;		//skip the name
                        				entry =
                        				{	width:miptex.readUnsignedInt(),
                        					height:miptex.readUnsignedInt(),
                        					offsets:[miptex.readUnsignedInt(), miptex.readUnsignedInt(), miptex.readUnsignedInt(), miptex.readUnsignedInt()]
                        				}
                        				
                        				//*...but wad expects long
                        				images.position = images.length;
                        				images.writeBytes(bname, 0, 16);
                        				images.writeInt(entry.width);
                        				images.writeInt(entry.height);
                        				
                        				entry.offsets.forEach(function(img_ofs:int, ni:int, self:Array):void{ images.writeInt(img_ofs); });
                        				
                        				//write the entire length of miptex data for this image 
                        				size = (entry.width * entry.height) + ((entry.width * entry.height) >> 2) + ((entry.width * entry.height) >> 4) + ((entry.width * entry.height) >> 6);
                        				images.writeBytes(miptex, image_offsets[n] + 40,  size);
                        				
                        				//add an entry for the current image
                        				addEntry(entries, offset, size, bname, MIPS);
                        				
                        				//increment offset 
                        				offset = 12+images.length;
                        			}); 
                        			
                        			directory = null;	//like it never even happened
                        			
                        			//grab palette
                        			var pal:ByteArray = Palette.bytes;
                        			
                        			//make useless name for palette
                        			bname.clear();
                        			bname.writeMultiByte("PALETTEWAD2PALET", "iso-8559-1");
                        			
                        			//add an entry for the palette
                        			addEntry(entries, 12 + images.length, pal.length, bname, PAL);
                        			
                        			//add the palette to the images stream
                        			images.position = images.length;
                        			images.writeBytes(pal);
                        			
                        			//reset positions
                        			images.position = entries.position = 0;
                        			
                        			//compose final wad
                        			var wad:ByteArray = new ByteArray();
                        			wad.endian = Endian.LITTLE_ENDIAN;
                        			wad.writeMultiByte("WAD2", "iso-8559-1");
                        			wad.writeInt(entries.length >> 5);
                        			wad.writeInt(12+images.length);
                        			wad.writeBytes(images);
                        			wad.writeBytes(entries);
                        			
                        			//save the wad to the wads directory
                        			ExportManager.export("wads/" + byName + ".wad", wad); 
                        			
                        			return true;
                        		}
                        		
                        		private static function addEntry(entry_stream:ByteArray, offset:int, size:int, name:ByteArray, type:int = MIPS):void
                        		{	entry_stream.position = entry_stream.length;
                        			entry_stream.writeInt(offset);			//filepos
                        			entry_stream.writeInt(size);			//disksize
                        			entry_stream.writeInt(size);			//size
                        			entry_stream.writeByte(type);			//type - mip 0x44 | pal 0x40 | stat 0x42 | con 0x45
                        			entry_stream.writeByte(0x00);			//compression
                        			entry_stream.writeShort(0x0000);		//pad
                        			entry_stream.writeBytes(name, 0, 16);	//name16
                        		}
                        	}
                        }
                        an illustration of parsing gfx.wad - which is filled primarily with status bar types instead of miptex or palette ones.
                        Last edited by MadGypsy; 11-03-2016, 02:53 AM.
                        http://www.nextgenquake.com

                        Comment


                        • pbbbt - this lil image tried so hard to hide. Like this is my first time or summin'. Script updated.


                          Maybe I should explain how I figure stupid shit like this out. First off an error is thrown. It doesn't tell me much except the line that threw the error and a very general description of the problem (ie End Of File). That being said, I start checking the variables before that line. I like to start at the top. Before this exception was added, miptex type took for granted that it's entry will have a name, width & height. I check the name...there is no name. Ok, that's fine. I write an exception based on mips not having a name. I then check that the entry for this image has a name. It did, "CONCHARS". I then reset the byte stream to it's offset for this image and check for a height and width. I get 0, 0. I undo that and check the entry size. It says 16k+. OK, so now I have a 0, 0 width/height but a 16k size. Apparently the first few bytes aren't height and width. I undo height/width reading and squareRoot the entry size instead. I then for shits and giggles read entry size number of bytes from the beginning of the offset. Voila'!
                          Last edited by MadGypsy; 11-03-2016, 02:31 AM.
                          http://www.nextgenquake.com

                          Comment


                          • Originally posted by MadGypsy View Post
                            trace("Congratulations! You have the only wad in the universe that uses this!")
                            I chuckled.

                            entry_stream.writeInt(size); //disksize
                            entry_stream.writeInt(size); //size
                            The 2 lines are identical, so what's the diff between disksize and size and how can the program tell which is which?
                            Last edited by Mugwump; 11-03-2016, 11:02 AM.
                            ♪ I'm skiiiiiiinnin' in the pain, just skiiiiiiinnin' in the pain ♪
                            ♪ What a glorious feelin' I'm haaaaaaappy again ♪

                            Comment


                            • size and disksize represent the compressed and uncompressed size of the entry. However, compression is never used so these numbers are always the same.

                              Wad2 is a very sloppy format.
                              http://www.nextgenquake.com

                              Comment


                              • Dealing With The Palette:

                                I've seen some nutty shit In and Out to compensate for a missing palette or to reconfigure the palette to be stored in a wad. One script I read went as far as to break the palette down into each channel as an array.

                                ex: ~alpha channel is not stored in the wad palette
                                original = [0xFFDDEECC]
                                brokeDown = [0xDD, 0xEE, 0xCC]

                                That is retarded. Let's consider this. If the palette is missing then you simply point the images to your stored palette. There is basically nothing to do in that scenario. If the palette isn't missing overwrite your stored one with the new one. Still nothing to do ~ ie you don't write some stupid special palette that mirrors the expected wad bytes of palette.

                                In the case where you need to add your palette to a wad, you still do not write some special palette of broken down channels. Instead, you learn how to use bitwise operators and write bytes of the appropriate format against your one stored palette.

                                Last edited by MadGypsy; 11-03-2016, 05:07 PM.
                                http://www.nextgenquake.com

                                Comment

                                Working...
                                X