<commit_before>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => (set_z!($cpu_state,$val);set_s!($cpu_state,$val););
}
macro_rules! set_z {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;);
}
macro_rules! set_s {
    ($cpu_state:expr,$val:expr) => ($cpu_state.S = $val >= 0x80;);
}
macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 as u16 | $cpu_state.sp as u16,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.sp+=1;
            $mem.read8(0x0100 as u16 | $cpu_state.sp as u16)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.sp+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::AND => {
				cpu_state.a = cpu_state.a & cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BCC => {
                if !cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BCS => {
                if cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BEQ => {
                if cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BIT => {
                cpu_state.V = (cpu_state.decode_register.value_final.unwrap() >> 6) & 1 > 0;
                set_z!(cpu_state,cpu_state.decode_register.value_final.unwrap() & cpu_state.a);
                set_s!(cpu_state,cpu_state.decode_register.value_final.unwrap());

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BNE => {
                if !cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BPL => {
                if !cpu_state.S { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BVC => {
                if !cpu_state.V { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BVS => {
                if cpu_state.V { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc+1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {
            },
            // http://wiki.nesdev.com/w/index.php/Status_flags
    		OpcodeClass::PHP => {
                stack_push8!(cpu_state,mem,cpu_state.unpack_flags() | 0x30);
            },
    		OpcodeClass::PLA => {
                cpu_state.a = stack_pull8!(cpu_state,mem).unwrap();
                set_zs!(cpu_state,cpu_state.a);
            },
    		OpcodeClass::RTS => {
                cpu_state.pc = stack_pull16!(cpu_state,mem).unwrap() + 1;
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::SED => {
                cpu_state.D = true;
    		},
    		OpcodeClass::SEI => {
                cpu_state.I = true;
    		},
    		OpcodeClass::STA => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.a));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.x));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<commit_msg>implemented CMP opcode<commit_after>use cpu::common_defs::OpcodeExecInfo;
use cpu::CpuState;
use cpu::DecodeRegister;
use cpu::common_defs::address_mode::AddressMode;
use cpu::common_defs::opcode_class::OpcodeClass;
use memory::Memory;

macro_rules! set_zs {
    ($cpu_state:expr,$val:expr) => (set_z!($cpu_state,$val);set_s!($cpu_state,$val););
}
macro_rules! set_z {
    ($cpu_state:expr,$val:expr) => ($cpu_state.Z = $val == 0;);
}
macro_rules! set_s {
    ($cpu_state:expr,$val:expr) => ($cpu_state.S = $val >= 0x80;);
}
macro_rules! stack_push8 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write8(0x0100 as u16 | $cpu_state.sp as u16,$val)); $cpu_state.sp-=1;);
}
macro_rules! stack_push16 {
    ($cpu_state:expr,$mem:expr,$val:expr) => (try!($mem.write16(0x0100 as u16 | $cpu_state.sp as u16 -1,$val)); $cpu_state.sp-=2;);
}
macro_rules! stack_pull8 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.sp+=1;
            $mem.read8(0x0100 as u16 | $cpu_state.sp as u16)
        }
    }
}
macro_rules! stack_pull16 {
    ($cpu_state:expr,$mem:expr) => {
        {
            $cpu_state.sp+=2;
            $mem.read16(0x0100 as u16 | $cpu_state.sp as u16 -1)
        }
    }
}

#[derive(Debug)]
pub enum ExecutionError {
  MemoryError(::memory::MemoryError),
  UnexpectedOpcode(String),
  UnexpectedAddressMode(String)
}
impl From<::memory::MemoryError> for ExecutionError {
    fn from(err: ::memory::MemoryError) -> ExecutionError {
        ExecutionError::MemoryError(err)
    }
}

pub struct CpuExecutor {
    op_table: Vec<OpcodeExecInfo>,
}

impl CpuExecutor {
	/// Construct a new CpuExecutor.
    pub fn new(opcodes: Vec<OpcodeExecInfo> ) -> CpuExecutor {
        CpuExecutor {
            op_table:  opcodes,
        }
    }

	/// Reset the given cpu_state.
    pub fn power_on(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        self.reset(cpu_state,mem);
    }
	/// Reset the given cpu_state.
    pub fn reset(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) {
        cpu_state.pc = mem.read16(0xFFFC).unwrap();
        cpu_state.sp = 0xFD;
        cpu_state.pack_flags(0x24);
    }

    /// Execute a single instruction in the given memory and cpu_state context.
    pub fn step(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        try!(self.fetch_and_decode(cpu_state,mem));
        try!(self.execute(cpu_state,mem));
        Ok(())
    }

	/// Fetch the next instruction and perform address resolution.
    pub fn fetch_and_decode(self: &CpuExecutor, cpu_state: &mut CpuState,mem:&mut Memory) -> Result<(),ExecutionError> {
        cpu_state.instruction_register = mem.read8(cpu_state.pc).unwrap();
        cpu_state.decode_register = try!(self.decode(cpu_state,mem));
        cpu_state.pc = cpu_state.pc+1;
        Ok(())
    }

    /// Perform address resolution, returning the info in a DecodeRegister.
    fn decode(self: &CpuExecutor, cpu_state: &CpuState, mem: &Memory) -> Result<DecodeRegister,ExecutionError> {
        let mut dr = DecodeRegister {
            info : self.op_table[cpu_state.instruction_register as usize].clone(),
            ..Default::default()
        };
        match dr.info.address_mode {
            // no explicit addresses for the following modes
            AddressMode::Accumulator  => { },
            AddressMode::Implied      => { },

            // explicit addresses from here on out
            AddressMode::Absolute => {
                dr.addr_final  = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteX       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.x as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::AbsoluteY       => {
                dr.addr_final  = Some( ((mem.read16(cpu_state.pc+1).unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Immediate       => {
                dr.addr_final  = Some(cpu_state.pc+1);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Indirect        => {
                dr.addr_intermediate = Some(mem.read16(cpu_state.pc+1).unwrap());
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
            },
            AddressMode::IndexedIndirect => {
                dr.addr_intermediate = Some( (mem.read8(cpu_state.pc+1).unwrap() + cpu_state.x) as u16);
                dr.addr_final        = Some(mem.read16(dr.addr_intermediate.unwrap()).unwrap());
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::IndirectIndexed => {
                dr.addr_init         = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.addr_intermediate = Some(mem.read16(dr.addr_init.unwrap()).unwrap());
                dr.addr_final        = Some( ((dr.addr_intermediate.unwrap() as u32 + cpu_state.y as u32) % 65536) as u16);
                dr.value_final       = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::Relative        => {
                dr.value_final = Some(mem.read8(cpu_state.pc+1).unwrap());

                // NOTE: relative is from the end of the current instruction and relative
                // instructions are 2 bytes long, so we add 2 before adding in the specified offset
                //
                if dr.value_final.unwrap() < 0x80 { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16); }
                else                              { dr.addr_final  = Some(cpu_state.pc + 2 + dr.value_final.unwrap() as u16 - 0x100);}
            },
            AddressMode::ZeroPage        => {
                dr.addr_final  = Some(mem.read8(cpu_state.pc+1).unwrap() as u16);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageX       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.x as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            AddressMode::ZeroPageY       => {
                dr.addr_final  = Some( (mem.read8(cpu_state.pc+1).unwrap() as u16 + cpu_state.y as u16) % 256);
                dr.value_final = Some(mem.read8(dr.addr_final.unwrap()).unwrap());
            },
            _ => { return Err(ExecutionError::UnexpectedAddressMode(format!("unrecognized addressing mode '{:?}' while decoding instruction_register!",dr.info.address_mode))); }
        }

        return Ok(dr);
    }

    /// Perform the current instruction, returning the CpuState after execution.
    pub fn execute(self: &CpuExecutor, cpu_state: &mut CpuState, mem:&mut Memory) -> Result<(),ExecutionError> {
    	// Figure out which opcode is being executed.
    	match cpu_state.decode_register.info.opcode_class {
    		OpcodeClass::ASL => {
				cpu_state.a = cpu_state.a << 1;
				cpu_state.C = (128 & cpu_state.a) > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::AND => {
				cpu_state.a = cpu_state.a & cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BCC => {
                if !cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BCS => {
                if cpu_state.C { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BEQ => {
                if cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BIT => {
                cpu_state.V = (cpu_state.decode_register.value_final.unwrap() >> 6) & 1 > 0;
                set_z!(cpu_state,cpu_state.decode_register.value_final.unwrap() & cpu_state.a);
                set_s!(cpu_state,cpu_state.decode_register.value_final.unwrap());

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::BNE => {
                if !cpu_state.Z { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BPL => {
                if !cpu_state.S { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BVC => {
                if !cpu_state.V { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else            { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::BVS => {
                if cpu_state.V { cpu_state.pc = cpu_state.decode_register.addr_final.unwrap(); }
                else           { cpu_state.pc += cpu_state.decode_register.info.len as u16-1;  }
    		},
    		OpcodeClass::CMP => {
                set_zs!(cpu_state,cpu_state.a - cpu_state.decode_register.value_final.unwrap());
                cpu_state.C = cpu_state.a >= cpu_state.decode_register.value_final.unwrap();

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::CLC => {
                cpu_state.C = false;
    		},
    		OpcodeClass::LDA => {
    			cpu_state.a = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.a);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDX => {
    			cpu_state.x = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.x);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LDY => {
    			cpu_state.y = cpu_state.decode_register.value_final.unwrap();
                set_zs!(cpu_state,cpu_state.y);

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::LSR => {
    			cpu_state.a = cpu_state.a >> 1;
    			cpu_state.C = 1 & cpu_state.a > 0;
    			if cpu_state.a == 0 { cpu_state.Z = true; }

                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::JMP => {
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::JSR => {
                stack_push16!(cpu_state,mem,cpu_state.pc+1);
    			cpu_state.pc = cpu_state.decode_register.addr_final.unwrap();
    		},
    		OpcodeClass::NOP => {
            },
            // http://wiki.nesdev.com/w/index.php/Status_flags
    		OpcodeClass::PHP => {
                stack_push8!(cpu_state,mem,cpu_state.unpack_flags() | 0x30);
            },
    		OpcodeClass::PLA => {
                cpu_state.a = stack_pull8!(cpu_state,mem).unwrap();
                set_zs!(cpu_state,cpu_state.a);
            },
    		OpcodeClass::RTS => {
                cpu_state.pc = stack_pull16!(cpu_state,mem).unwrap() + 1;
            },
    		OpcodeClass::SEC => {
                cpu_state.C = true;
    		},
    		OpcodeClass::SED => {
                cpu_state.D = true;
    		},
    		OpcodeClass::SEI => {
                cpu_state.I = true;
    		},
    		OpcodeClass::STA => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.a));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},
    		OpcodeClass::STX => {
                try!(mem.write8(cpu_state.decode_register.addr_final.unwrap(),cpu_state.x));
                cpu_state.pc += cpu_state.decode_register.info.len as u16-1;
    		},

			_ => { return Err(ExecutionError::UnexpectedOpcode(format!("Unrecognised opcode class: {:?}", cpu_state.decode_register.info.opcode_class)));}

    	}
        Ok(())
    }
}

<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::convert::From;
use serde::{Serialize, Deserialize};
use serde_json::{self, Value};

#[macro_export]
macro_rules! cypher_stmt {
    ( $s:expr ) => { $crate::Statement::new($s) };
    ( $s:expr { $( $k:expr => $v:expr ),+ } ) => {
        $crate::Statement::new($s)
            $(.with_param($k, $v))*
    }
}

#[derive(Clone, Serialize)]
pub struct Statement {
    statement: String,
    parameters: BTreeMap<String, Value>,
}

impl Statement  {
    pub fn new(statement: &str) -> Self {
        Statement {
            statement: statement.to_owned(),
            parameters: BTreeMap::new(),
        }
    }

    pub fn with_param<V: Serialize + Copy>(mut self, key: &str, value: V) -> Self {
        self.add_param(key, value);
        self
    }

    pub fn add_param<V: Serialize + Copy>(&mut self, key: &str, value: V) {
        self.parameters.insert(key.to_owned(), serde_json::value::to_value(&value));
    }

    pub fn get_param<V: Deserialize>(&self, key: &str) -> Option<Result<V, serde_json::error::Error>> {
        self.parameters.get(key.into()).map(|v| serde_json::value::from_value(v.clone()))
    }

    pub fn get_params(&self) -> &BTreeMap<String, Value> {
        &self.parameters
    }

    pub fn set_params<V: Serialize>(&mut self, params: &BTreeMap<String, V>) {
        let mut _params = BTreeMap::new();

        for (k, v) in params.iter() {
            _params.insert(k.to_owned(), serde_json::value::to_value(&v));
        }

        self.parameters = _params;
    }

    pub fn remove_param(&mut self, key: &str) {
        self.parameters.remove(key);
    }
}

impl<'a> From<&'a str> for Statement {
    fn from(stmt: &str) -> Self {
        Statement::new(stmt)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[allow(unused_variables)]
    fn from_str() {
        let stmt = Statement::new("MATCH n RETURN n");
    }

    #[test]
    fn with_param() {
        let statement = Statement::new("MATCH n RETURN n")
            .with_param("param1", "value1")
            .with_param("param2", 2)
            .with_param("param3", 3.0)
            .with_param("param4", [0; 4]);

        assert_eq!(statement.get_params().len(), 4);
    }

    #[test]
    fn add_param() {
        let mut statement = Statement::new("MATCH n RETURN n");
        statement.add_param("param1", "value1");
        statement.add_param("param2", 2);
        statement.add_param("param3", 3.0);
        statement.add_param("param4", [0; 4]);

        assert_eq!(statement.get_params().len(), 4);
    }

    #[test]
    fn remove_param() {
        let mut statement = Statement::new("MATCH n RETURN n")
            .with_param("param1", "value1")
            .with_param("param2", 2)
            .with_param("param3", 3.0)
            .with_param("param4", [0; 4]);

        statement.remove_param("param1");

        assert_eq!(statement.get_params().len(), 3);
    }

    #[test]
    #[allow(unused_variables)]
    fn macro_without_params() {
        let stmt = cypher_stmt!("MATCH n RETURN n");
    }

    #[test]
    fn macro_single_param() {
        let statement1 = cypher_stmt!("MATCH n RETURN n" {
            "name" => "test"
        });

        let param = 1;
        let statement2 = cypher_stmt!("MATCH n RETURN n" {
            "value" => param
        });

        assert_eq!("test", statement1.get_param::<String>("name").unwrap().unwrap());
        assert_eq!(param, statement2.get_param::<i32>("value").unwrap().unwrap());
    }

    #[test]
    fn macro_multiple_params() {
        let param = 3f32;
        let statement = cypher_stmt!("MATCH n RETURN n" {
            "param1" => "one",
            "param2" => 2,
            "param3" => param
        });

        assert_eq!("one", statement.get_param::<String>("param1").unwrap().unwrap());
        assert_eq!(2, statement.get_param::<i32>("param2").unwrap().unwrap());
        assert_eq!(param, statement.get_param::<f32>("param3").unwrap().unwrap());
    }
}
<commit_msg>add #[derive(Debug)] to cypher Statement struct<commit_after>use std::collections::BTreeMap;
use std::convert::From;
use serde::{Serialize, Deserialize};
use serde_json::{self, Value};

#[macro_export]
macro_rules! cypher_stmt {
    ( $s:expr ) => { $crate::Statement::new($s) };
    ( $s:expr { $( $k:expr => $v:expr ),+ } ) => {
        $crate::Statement::new($s)
            $(.with_param($k, $v))*
    }
}

#[derive(Clone, Serialize, Debug)]
pub struct Statement {
    statement: String,
    parameters: BTreeMap<String, Value>,
}

impl Statement  {
    pub fn new(statement: &str) -> Self {
        Statement {
            statement: statement.to_owned(),
            parameters: BTreeMap::new(),
        }
    }

    pub fn with_param<V: Serialize + Copy>(mut self, key: &str, value: V) -> Self {
        self.add_param(key, value);
        self
    }

    pub fn add_param<V: Serialize + Copy>(&mut self, key: &str, value: V) {
        self.parameters.insert(key.to_owned(), serde_json::value::to_value(&value));
    }

    pub fn get_param<V: Deserialize>(&self, key: &str) -> Option<Result<V, serde_json::error::Error>> {
        self.parameters.get(key.into()).map(|v| serde_json::value::from_value(v.clone()))
    }

    pub fn get_params(&self) -> &BTreeMap<String, Value> {
        &self.parameters
    }

    pub fn set_params<V: Serialize>(&mut self, params: &BTreeMap<String, V>) {
        let mut _params = BTreeMap::new();

        for (k, v) in params.iter() {
            _params.insert(k.to_owned(), serde_json::value::to_value(&v));
        }

        self.parameters = _params;
    }

    pub fn remove_param(&mut self, key: &str) {
        self.parameters.remove(key);
    }
}

impl<'a> From<&'a str> for Statement {
    fn from(stmt: &str) -> Self {
        Statement::new(stmt)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[allow(unused_variables)]
    fn from_str() {
        let stmt = Statement::new("MATCH n RETURN n");
    }

    #[test]
    fn with_param() {
        let statement = Statement::new("MATCH n RETURN n")
            .with_param("param1", "value1")
            .with_param("param2", 2)
            .with_param("param3", 3.0)
            .with_param("param4", [0; 4]);

        assert_eq!(statement.get_params().len(), 4);
    }

    #[test]
    fn add_param() {
        let mut statement = Statement::new("MATCH n RETURN n");
        statement.add_param("param1", "value1");
        statement.add_param("param2", 2);
        statement.add_param("param3", 3.0);
        statement.add_param("param4", [0; 4]);

        assert_eq!(statement.get_params().len(), 4);
    }

    #[test]
    fn remove_param() {
        let mut statement = Statement::new("MATCH n RETURN n")
            .with_param("param1", "value1")
            .with_param("param2", 2)
            .with_param("param3", 3.0)
            .with_param("param4", [0; 4]);

        statement.remove_param("param1");

        assert_eq!(statement.get_params().len(), 3);
    }

    #[test]
    #[allow(unused_variables)]
    fn macro_without_params() {
        let stmt = cypher_stmt!("MATCH n RETURN n");
    }

    #[test]
    fn macro_single_param() {
        let statement1 = cypher_stmt!("MATCH n RETURN n" {
            "name" => "test"
        });

        let param = 1;
        let statement2 = cypher_stmt!("MATCH n RETURN n" {
            "value" => param
        });

        assert_eq!("test", statement1.get_param::<String>("name").unwrap().unwrap());
        assert_eq!(param, statement2.get_param::<i32>("value").unwrap().unwrap());
    }

    #[test]
    fn macro_multiple_params() {
        let param = 3f32;
        let statement = cypher_stmt!("MATCH n RETURN n" {
            "param1" => "one",
            "param2" => 2,
            "param3" => param
        });

        assert_eq!("one", statement.get_param::<String>("param1").unwrap().unwrap());
        assert_eq!(2, statement.get_param::<i32>("param2").unwrap().unwrap());
        assert_eq!(param, statement.get_param::<f32>("param3").unwrap().unwrap());
    }
}
<|endoftext|>


<commit_before>//! Create window.

// External crates.
use gfx;
use device;
use collections::Deque;
use collections::ringbuf::RingBuf;
use glfw;
use glfw::Context;
use gl;
use piston::event;
use piston::keyboard;
use piston::mouse;
use piston::GameWindow;
use piston::GameWindowSettings;

/// Contains stuff for game window.
pub struct GameWindowGLFW {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: GameWindowSettings,
    event_queue: RingBuf<event::Event>,
}

impl GameWindowGLFW {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GameWindowGLFW {
        win.set_key_polling(true);
        win.set_mouse_button_polling(true);
        win.set_cursor_pos_polling(true);
        win.set_scroll_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        GameWindowGLFW {
            window: win,
            events: events,
            glfw: glfw,
            settings: GameWindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(settings: GameWindowSettings) -> GameWindowGLFW {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(3, 2));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_key_polling(true);
        window.set_mouse_button_polling(true);
        window.set_cursor_pos_polling(true);
        window.set_scroll_polling(true);
        // or polling all event
        //window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| glfw.get_proc_address(s));

        GameWindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                    if self.settings.exit_on_esc => {
                        self.window.set_should_close(true);
                    },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push(
                        event::KeyPressed(glfw_map_key(key)));
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push(
                        event::KeyReleased(glfw_map_key(key)));
                },
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push(
                        event::MouseButtonPressed(glfw_map_mouse(button)));
                },
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push(
                        event::MouseButtonReleased(glfw_map_mouse(button)));
                },
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push(
                        event::MouseMoved(x, y, None));
                },
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push(
                        event::MouseScrolled(x, y));
                },
                _ => {},
            }
        }
    }

    /// Creates a gfx device and frame.
    pub fn gfx(&self) -> (device::GlDevice, gfx::Frame) {
        let device = device::GlDevice::new(|s|
            self.glfw.get_proc_address(s)
        );
        let (w, h) = self.get_size();
        let frame = gfx::Frame::new(w as u16, h as u16);
        (device, frame)
    }
}

impl GameWindow for GameWindowGLFW {
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn close(&mut self) {
        self.window.set_should_close(true);
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        if enabled {
            self.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            self.window.set_cursor_mode(glfw::CursorNormal)
        }
    }

    fn poll_event(&mut self) -> event::Event {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front().unwrap()
        } else {
            event::NoEvent
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}

<commit_msg>Implemented `GameWindow::get_draw_size`<commit_after>//! Create window.

// External crates.
use gfx;
use device;
use collections::Deque;
use collections::ringbuf::RingBuf;
use glfw;
use glfw::Context;
use gl;
use piston::event;
use piston::keyboard;
use piston::mouse;
use piston::GameWindow;
use piston::GameWindowSettings;

/// Contains stuff for game window.
pub struct GameWindowGLFW {
    /// The window.
    pub window: glfw::Window,
    /// Receives events from window.
    events: Receiver<(f64, glfw::WindowEvent)>,
    /// GLFW context.
    pub glfw: glfw::Glfw,
    /// Game window settings.
    settings: GameWindowSettings,
    event_queue: RingBuf<event::Event>,
}

impl GameWindowGLFW {
    /// Create a new game window from an existing GLFW window.
    pub fn from_pieces(win: glfw::Window, glfw: glfw::Glfw,
                       events: Receiver<(f64, glfw::WindowEvent)>,
                       exit_on_esc: bool) -> GameWindowGLFW {
        win.set_key_polling(true);
        win.set_mouse_button_polling(true);
        win.set_cursor_pos_polling(true);
        win.set_scroll_polling(true);
        win.make_current();

        let (w, h) = win.get_framebuffer_size();
        let fullscreen = win.with_window_mode(|m| match m { glfw::Windowed => true, _ => false });

        GameWindowGLFW {
            window: win,
            events: events,
            glfw: glfw,
            settings: GameWindowSettings {
                title: "<unknown window title, created with from_pieces>".to_string(),
                size: [w as u32, h as u32],
                fullscreen: fullscreen,
                exit_on_esc: exit_on_esc,
            },
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    /// Creates a new game window for GLFW.
    pub fn new(settings: GameWindowSettings) -> GameWindowGLFW {
        use glfw::Context;

        // Initialize GLFW.
        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

        // Make sure we have the right GL version.
        glfw.window_hint(glfw::ContextVersion(3, 2));
        glfw.window_hint(glfw::OpenglForwardCompat(true));
        glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));

        // Create GLFW window.
        let (window, events) = glfw.create_window(
            settings.size[0],
            settings.size[1],
            settings.title.as_slice(), glfw::Windowed
        ).expect("Failed to create GLFW window.");
        window.set_key_polling(true);
        window.set_mouse_button_polling(true);
        window.set_cursor_pos_polling(true);
        window.set_scroll_polling(true);
        // or polling all event
        //window.set_all_polling(true);
        window.make_current();

        // Load the OpenGL function pointers
        gl::load_with(|s| glfw.get_proc_address(s));

        GameWindowGLFW {
            window: window,
            events: events,
            glfw: glfw,
            settings: settings,
            event_queue: RingBuf::<event::Event>::new(),
        }
    }

    fn flush_messages(&mut self) {
        if self.event_queue.len() != 0 {
            return;
        }

        self.glfw.poll_events();
        for (_, event) in glfw::flush_messages(&self.events) {
            match event {
                glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _)
                    if self.settings.exit_on_esc => {
                        self.window.set_should_close(true);
                    },
                glfw::KeyEvent(key, _, glfw::Press, _) => {
                    self.event_queue.push(
                        event::KeyPressed(glfw_map_key(key)));
                },
                glfw::KeyEvent(key, _, glfw::Release, _) => {
                    self.event_queue.push(
                        event::KeyReleased(glfw_map_key(key)));
                },
                glfw::MouseButtonEvent(button, glfw::Press, _) => {
                    self.event_queue.push(
                        event::MouseButtonPressed(glfw_map_mouse(button)));
                },
                glfw::MouseButtonEvent(button, glfw::Release, _) => {
                    self.event_queue.push(
                        event::MouseButtonReleased(glfw_map_mouse(button)));
                },
                glfw::CursorPosEvent(x, y) => {
                    self.event_queue.push(
                        event::MouseMoved(x, y, None));
                },
                glfw::ScrollEvent(x, y) => {
                    self.event_queue.push(
                        event::MouseScrolled(x, y));
                },
                _ => {},
            }
        }
    }

    /// Creates a gfx device and frame.
    pub fn gfx(&self) -> (device::GlDevice, gfx::Frame) {
        let device = device::GlDevice::new(|s|
            self.glfw.get_proc_address(s)
        );
        let (w, h) = self.get_size();
        let frame = gfx::Frame::new(w as u16, h as u16);
        (device, frame)
    }
}

impl GameWindow for GameWindowGLFW {
    fn get_settings<'a>(&'a self) -> &'a GameWindowSettings {
        &self.settings
    }

    fn get_draw_size(&self) -> (u32, u32) {
        let (w, h) = self.window.get_framebuffer_size();
        (w as u32, h as u32)
    }

    fn should_close(&self) -> bool {
        self.window.should_close()
    }

    fn close(&mut self) {
        self.window.set_should_close(true);
    }

    fn swap_buffers(&self) {
        use glfw::Context;

        self.window.swap_buffers();
    }

    fn capture_cursor(&mut self, enabled: bool) {
        if enabled {
            self.window.set_cursor_mode(glfw::CursorDisabled)
        } else {
            self.window.set_cursor_mode(glfw::CursorNormal)
        }
    }

    fn poll_event(&mut self) -> event::Event {
        self.flush_messages();

        if self.event_queue.len() != 0 {
            self.event_queue.pop_front().unwrap()
        } else {
            event::NoEvent
        }
    }
}

fn glfw_map_key(keycode: glfw::Key) -> keyboard::Key {
    match keycode {
        glfw::Key0 => keyboard::D0,
        glfw::Key1 => keyboard::D1,
        glfw::Key2 => keyboard::D2,
        glfw::Key3 => keyboard::D3,
        glfw::Key4 => keyboard::D4,
        glfw::Key5 => keyboard::D5,
        glfw::Key6 => keyboard::D6,
        glfw::Key7 => keyboard::D7,
        glfw::Key8 => keyboard::D8,
        glfw::Key9 => keyboard::D9,
        glfw::KeyA => keyboard::A,
        glfw::KeyB => keyboard::B,
        glfw::KeyC => keyboard::C,
        glfw::KeyD => keyboard::D,
        glfw::KeyE => keyboard::E,
        glfw::KeyF => keyboard::F,
        glfw::KeyG => keyboard::G,
        glfw::KeyH => keyboard::H,
        glfw::KeyI => keyboard::I,
        glfw::KeyJ => keyboard::J,
        glfw::KeyK => keyboard::K,
        glfw::KeyL => keyboard::L,
        glfw::KeyM => keyboard::M,
        glfw::KeyN => keyboard::N,
        glfw::KeyO => keyboard::O,
        glfw::KeyP => keyboard::P,
        glfw::KeyQ => keyboard::Q,
        glfw::KeyR => keyboard::R,
        glfw::KeyS => keyboard::S,
        glfw::KeyT => keyboard::T,
        glfw::KeyU => keyboard::U,
        glfw::KeyV => keyboard::V,
        glfw::KeyW => keyboard::W,
        glfw::KeyX => keyboard::X,
        glfw::KeyY => keyboard::Y,
        glfw::KeyZ => keyboard::Z,
        glfw::KeyApostrophe => keyboard::Unknown,
        glfw::KeyBackslash => keyboard::Backslash,
        glfw::KeyBackspace => keyboard::Backspace,
        glfw::KeyCapsLock => keyboard::CapsLock,
        glfw::KeyDelete => keyboard::Delete,
        glfw::KeyComma => keyboard::Comma,
        glfw::KeyDown => keyboard::Down,
        glfw::KeyEnd => keyboard::End,
        glfw::KeyEnter => keyboard::Return,
        glfw::KeyEqual => keyboard::Equals,
        glfw::KeyEscape => keyboard::Escape,
        glfw::KeyF1 => keyboard::F1,
        glfw::KeyF2 => keyboard::F2,
        glfw::KeyF3 => keyboard::F3,
        glfw::KeyF4 => keyboard::F4,
        glfw::KeyF5 => keyboard::F5,
        glfw::KeyF6 => keyboard::F6,
        glfw::KeyF7 => keyboard::F7,
        glfw::KeyF8 => keyboard::F8,
        glfw::KeyF9 => keyboard::F9,
        glfw::KeyF10 => keyboard::F10,
        glfw::KeyF11 => keyboard::F11,
        glfw::KeyF12 => keyboard::F12,
        glfw::KeyF13 => keyboard::F13,
        glfw::KeyF14 => keyboard::F14,
        glfw::KeyF15 => keyboard::F15,
        glfw::KeyF16 => keyboard::F16,
        glfw::KeyF17 => keyboard::F17,
        glfw::KeyF18 => keyboard::F18,
        glfw::KeyF19 => keyboard::F19,
        glfw::KeyF20 => keyboard::F20,
        glfw::KeyF21 => keyboard::F21,
        glfw::KeyF22 => keyboard::F22,
        glfw::KeyF23 => keyboard::F23,
        glfw::KeyF24 => keyboard::F24,
        // Possibly next code.
        glfw::KeyF25 => keyboard::Unknown,
        glfw::KeyKp0 => keyboard::NumPad0,
        glfw::KeyKp1 => keyboard::NumPad1,
        glfw::KeyKp2 => keyboard::NumPad2,
        glfw::KeyKp3 => keyboard::NumPad3,
        glfw::KeyKp4 => keyboard::NumPad4,
        glfw::KeyKp5 => keyboard::NumPad5,
        glfw::KeyKp6 => keyboard::NumPad6,
        glfw::KeyKp7 => keyboard::NumPad7,
        glfw::KeyKp8 => keyboard::NumPad8,
        glfw::KeyKp9 => keyboard::NumPad9,
        glfw::KeyKpDecimal => keyboard::NumPadDecimal,
        glfw::KeyKpDivide => keyboard::NumPadDivide,
        glfw::KeyKpMultiply => keyboard::NumPadMultiply,
        glfw::KeyKpSubtract => keyboard::NumPadMinus,
        glfw::KeyKpAdd => keyboard::NumPadPlus,
        glfw::KeyKpEnter => keyboard::NumPadEnter,
        glfw::KeyKpEqual => keyboard::NumPadEquals,
        glfw::KeyLeftShift => keyboard::LShift,
        glfw::KeyLeftControl => keyboard::LCtrl,
        glfw::KeyLeftAlt => keyboard::LAlt,
        glfw::KeyLeftSuper => keyboard::LGui,
        glfw::KeyRightShift => keyboard::RShift,
        glfw::KeyRightControl => keyboard::RCtrl,
        glfw::KeyRightAlt => keyboard::RAlt,
        glfw::KeyRightSuper => keyboard::RGui,
        // Map to backslash?
        glfw::KeyGraveAccent => keyboard::Unknown,
        glfw::KeyHome => keyboard::Home,
        glfw::KeyInsert => keyboard::Insert,
        glfw::KeyLeft => keyboard::Left,
        glfw::KeyLeftBracket => keyboard::LeftBracket,
        glfw::KeyMenu => keyboard::Menu,
        glfw::KeyMinus => keyboard::Minus,
        glfw::KeyNumLock => keyboard::NumLockClear,
        glfw::KeyPageDown => keyboard::PageDown,
        glfw::KeyPageUp => keyboard::PageUp,
        glfw::KeyPause => keyboard::Pause,
        glfw::KeyPeriod => keyboard::Period,
        glfw::KeyPrintScreen => keyboard::PrintScreen,
        glfw::KeyRight => keyboard::Right,
        glfw::KeyRightBracket => keyboard::RightBracket,
        glfw::KeyScrollLock => keyboard::ScrollLock,
        glfw::KeySemicolon => keyboard::Semicolon,
        glfw::KeySlash => keyboard::Slash,
        glfw::KeySpace => keyboard::Space,
        glfw::KeyTab => keyboard::Tab,
        glfw::KeyUp => keyboard::Up,
        glfw::KeyWorld1 => keyboard::Unknown,
        glfw::KeyWorld2 => keyboard::Unknown,
        // _ => keyboard::Unknown,
    }
}

fn glfw_map_mouse(mouse_button: glfw::MouseButton) -> mouse::Button {
    match mouse_button {
        glfw::MouseButton1 => mouse::Left,
        glfw::MouseButton2 => mouse::Right,
        glfw::MouseButton3 => mouse::Middle,
        glfw::MouseButton4 => mouse::X1,
        glfw::MouseButton5 => mouse::X2,
        glfw::MouseButton6 => mouse::Button6,
        glfw::MouseButton7 => mouse::Button7,
        glfw::MouseButton8 => mouse::Button8,
    }
}

<|endoftext|>


<commit_before>use std::f32;

use stdout_logger::StdoutLogger;
use telemetry_message::TelemetryMessage;

struct Telemetry<'a> {
    data: &'a mut TelemetryMessage,
    logger: &'a StdoutLogger,

    throttle: f32,
    steering: f32,
}

impl<'a> Telemetry<'a> {
    fn get_raw_data(&self) -> &TelemetryMessage {
        self.data
    }

    fn get_data(&self) -> &TelemetryMessage {
        self.data
    }

    fn process_drive_command(&mut self, throttle:f32, steering:f32) -> () {
        if throttle < -1.0 || throttle > 1.0 {
            self.logger.info("Invalid throttle");
            return;
        }
        if steering < -1.0 || steering > 1.0 {
            self.logger.warning("Invalid steering");
            return;
        }

        self.throttle = throttle;
        self.steering = steering;

        // TODO: Update the filter?
    }

    fn handle_message(&self, message:&TelemetryMessage) -> () {
        // TODO: Save the message
    }
}

/**
 * Rotates a point a number of degrees clockwise around the origin.
 */
fn rotate_degrees_clockwise(point:(f32, f32), degrees:f32) -> (f32, f32) {
    let (pt_x, pt_y) = point;
    let (sine, cosine) = (-degrees).to_radians().sin_cos();

    (pt_x * cosine - pt_y * sine, pt_x * sine + pt_y * cosine)
}

fn equatorial_radius_m() -> f32 {
    6378.1370 * 1000.0
}

fn m_per_latitude_d() -> f32{
    equatorial_radius_m() * f32::consts::PI_2 / 360.0
}

/**
 * Returns the number of meters per degree longitude at a given latitude.
 */
fn latitude_d_to_m_per_longitude_d(latitude_d: f32) -> f32 {
    let radius_m = latitude_d.to_radians().cos() * equatorial_radius_m();
    let circumference_m = f32::consts::PI_2 * radius_m;
    circumference_m / 360.0
}

/**
 * Determines if the vehicle facing a heading in degrees needs to turn left to
 * left to reach a goal heading in degrees.
 */
fn is_turn_left(heading_d: f32, goal_heading_d: f32) -> bool {
    let (pt_1_0, pt_1_1) = rotate_degrees_clockwise((1.0f32, 0.0f32), heading_d);
    let (pt_2_0, pt_2_1) = rotate_degrees_clockwise((1.0f32, 0.0f32), goal_heading_d);
    let cross_product = pt_1_0 * pt_2_1 - pt_1_1 * pt_2_0;
    if cross_product > 0.0 {
        return true;
    }
    return false;
}

/**
 * Computes the relative degrees from the first waypoint to the second, where
 * north is 0.
 */
fn relative_degrees(x_1: f32, y_1: f32, x_2: f32, y_2: f32) -> f32 {
    let relative_x_m = x_2 - x_1;
    let relative_y_m = y_2 - y_1;
    if relative_x_m == 0.0 {
        if relative_y_m > 0.0 {
            return 0.0;
        }
        return 180.0;
    }

    let degrees = (relative_y_m / relative_x_m).atan().to_degrees();
    if relative_x_m > 0.0 {
        return 90.0 - degrees;
    } else {
        return 270.0 - degrees;
    }
}

#[cfg(test)]
mod tests {
    use std::f32;
    use super::equatorial_radius_m;
    use super::is_turn_left;
    use super::latitude_d_to_m_per_longitude_d;
    use super::relative_degrees;
    use super::rotate_degrees_clockwise;

    fn assert_approx_eq(value_1:f32, value_2:f32) -> () {
        // Yeah, I know this is bad, see
        // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

        // This is the best we can do with f32
        let tolerance: f32 = 0.000001;
        let diff = (value_1 - value_2).abs();
        assert!(diff < tolerance, "{} < {} failed", diff, tolerance);
    }

    fn test_rotate(point:(f32, f32), degrees:f32, expected_point:(f32, f32)) -> () {
        let new_point = rotate_degrees_clockwise(point, degrees);
        let (p_1, p_2) = new_point;
        let (ep_1, ep_2) = expected_point;
        assert_approx_eq(p_1, ep_1);
        assert_approx_eq(p_2, ep_2);
    }

    #[test]
    fn test_rotate_degrees_clockwise() {
        let base_x = 1.0f32;
        let base_y = 0.0f32;
        let base = (base_x, base_y);

        test_rotate(base, 0.0, base);
        test_rotate(base, 90.0, (base_y, -base_x));
        test_rotate(base, 180.0, (-base_x, base_y));
        test_rotate(base, 270.0, (base_y, base_x));
        test_rotate(base, 360.0, base);

        test_rotate(base, -90.0, (base_y, base_x));
        test_rotate(base, -180.0, (-base_x, base_y));
        test_rotate(base, -270.0, (base_y, -base_x));
        test_rotate(base, -360.0, base);

        test_rotate(base, 720.0, base);
        test_rotate(base, -720.0, base);

        let skewed_x = 1.0;
        let skewed_y = 2.0;
        let skewed = (skewed_x, skewed_y);

        test_rotate(skewed, 0.0, skewed);
        test_rotate(skewed, 90.0, (skewed_y, -skewed_x));
        test_rotate(skewed, 180.0, (-skewed_x, -skewed_y));
        test_rotate(skewed, 270.0, (-skewed_y, skewed_x));
        test_rotate(skewed, 360.0, skewed);

        test_rotate(skewed, -90.0, (-skewed_y, skewed_x));
        test_rotate(skewed, -180.0, (-skewed_x, -skewed_y));
        test_rotate(skewed, -270.0, (skewed_y, -skewed_x));
        test_rotate(skewed, -360.0, skewed);

        test_rotate(skewed, 720.0, skewed);
        test_rotate(skewed, -720.0, skewed);
    }

    #[test]
    fn test_latitude_d_to_m_per_longitude_d_spherical() {
        // Assume Earth is a sphere
        assert_approx_eq(
            equatorial_radius_m() * f32::consts::PI_2 / 360.0,
            latitude_d_to_m_per_longitude_d(0.0)
        );

        // Should be symmetrical
        for degrees in range(0i32, 85) {
            assert_approx_eq(
                latitude_d_to_m_per_longitude_d(degrees as f32),
                latitude_d_to_m_per_longitude_d(-degrees as f32)
            );
        }

        // At the poles, should be 0
        let diff = (latitude_d_to_m_per_longitude_d(90.0)).abs();
        assert!(diff < 0.01);
    }

    #[test]
    #[should_fail]  // We're using a less accurate spherical method right now
    fn test_latitude_d_to_m_per_longitude_d_oblong() {
        // Known values, from http://www.csgnetwork.com/degreelenllavcalc.html
        // M_PER_D_LATITUDE = 111319.458,
        assert_approx_eq(
            // Boulder
            latitude_d_to_m_per_longitude_d(40.08),
            85294.08886768305,
        );
    }

    #[test]
    fn test_is_turn_left() {
        assert!(is_turn_left(1.0, 0.0));
        assert!(!is_turn_left(0.0, 1.0));

        assert!(is_turn_left(1.0, 359.0));
        assert!(!is_turn_left(359.0, 1.0));

        assert!(is_turn_left(1.0, 270.0));
        assert!(is_turn_left(0.0, 270.0));
        assert!(is_turn_left(359.0, 270.0));

        assert!(!is_turn_left(1.0, 90.0));
        assert!(!is_turn_left(0.0, 90.0));
        assert!(!is_turn_left(359.0, 90.0));
    }

    #[test]
    fn test_relative_degrees() {
        assert_approx_eq(relative_degrees(0.0, 0.0, 1.0, 1.0), 45.0);
        assert_approx_eq(relative_degrees(1.0, 1.0, 0.0, 0.0), 225.0);
        assert_approx_eq(relative_degrees(0.0, 0.0, 2.0, 2.0), 45.0);
        assert_approx_eq(relative_degrees(2.0, 2.0, 0.0, 0.0), 225.0);

        assert_approx_eq(relative_degrees(0.0, 0.0, -1.0, 1.0), 315.0);
        assert_approx_eq(relative_degrees(-1.0, 1.0, 0.0, 0.0), 135.0);
        assert_approx_eq(relative_degrees(0.0, 0.0, -2.0, 2.0), 315.0);
        assert_approx_eq(relative_degrees(-2.0, 2.0, 0.0, 0.0), 135.0);

        assert_approx_eq(relative_degrees(0.0, 0.0, 0.0, 1.0), 0.0);
        assert_approx_eq(relative_degrees(0.0, 1.0, 0.0, 0.0), 180.0);
        assert_approx_eq(relative_degrees(0.0, 0.0, 0.0, 2.0), 0.0);
        assert_approx_eq(relative_degrees(0.0, 2.0, 0.0, 0.0), 180.0);

        assert_approx_eq(relative_degrees(0.0, 0.0, 1.0, 0.0), 90.0);
        assert_approx_eq(relative_degrees(1.0, 0.0, 0.0, 0.0), 270.0);
        assert_approx_eq(relative_degrees(0.0, 0.0, 2.0, 0.0), 90.0);
        assert_approx_eq(relative_degrees(2.0, 0.0, 0.0, 0.0), 270.0);
    }
}
<commit_msg>Add more telemetry module<commit_after>use std::f32;

use stdout_logger::StdoutLogger;
use telemetry_message::TelemetryMessage;

struct Telemetry<'a> {
    data: &'a mut TelemetryMessage,
    logger: &'a StdoutLogger,

    throttle: f32,
    steering: f32,
}

impl<'a> Telemetry<'a> {
    fn get_raw_data(&self) -> &TelemetryMessage {
        self.data
    }

    fn get_data(&self) -> &TelemetryMessage {
        self.data
    }

    fn process_drive_command(&mut self, throttle:f32, steering:f32) -> () {
        if throttle < -1.0 || throttle > 1.0 {
            self.logger.info("Invalid throttle");
            return;
        }
        if steering < -1.0 || steering > 1.0 {
            self.logger.warning("Invalid steering");
            return;
        }

        self.throttle = throttle;
        self.steering = steering;

        // TODO: Update the filter?
    }

    fn handle_message(&self, message:&TelemetryMessage) -> () {
        // TODO: Save the message
    }
}

/**
 * Rotates a point a number of degrees clockwise around the origin.
 */
fn rotate_degrees_clockwise(point:(f32, f32), degrees:f32) -> (f32, f32) {
    let (pt_x, pt_y) = point;
    let (sine, cosine) = (-degrees).to_radians().sin_cos();

    (pt_x * cosine - pt_y * sine, pt_x * sine + pt_y * cosine)
}

fn equatorial_radius_m() -> f32 {
    6378.1370 * 1000.0
}

fn m_per_latitude_d() -> f32{
    equatorial_radius_m() * f32::consts::PI_2 / 360.0
}

/**
 * Returns the number of meters per degree longitude at a given latitude.
 */
fn latitude_d_to_m_per_longitude_d(latitude_d: f32) -> f32 {
    let radius_m = latitude_d.to_radians().cos() * equatorial_radius_m();
    let circumference_m = f32::consts::PI_2 * radius_m;
    circumference_m / 360.0
}

/**
 * Determines if the vehicle facing a heading in degrees needs to turn left to
 * left to reach a goal heading in degrees.
 */
fn is_turn_left(heading_d: f32, goal_heading_d: f32) -> bool {
    let (pt_1_0, pt_1_1) = rotate_degrees_clockwise((1.0f32, 0.0f32), heading_d);
    let (pt_2_0, pt_2_1) = rotate_degrees_clockwise((1.0f32, 0.0f32), goal_heading_d);
    let cross_product = pt_1_0 * pt_2_1 - pt_1_1 * pt_2_0;
    if cross_product > 0.0 {
        return true;
    }
    return false;
}

/**
 * Computes the relative degrees from the first waypoint to the second, where
 * north is 0.
 */
fn relative_degrees(x_1: f32, y_1: f32, x_2: f32, y_2: f32) -> f32 {
    let relative_x_m = x_2 - x_1;
    let relative_y_m = y_2 - y_1;
    if relative_x_m == 0.0 {
        if relative_y_m > 0.0 {
            return 0.0;
        }
        return 180.0;
    }

    let degrees = (relative_y_m / relative_x_m).atan().to_degrees();
    if relative_x_m > 0.0 {
        return 90.0 - degrees;
    } else {
        return 270.0 - degrees;
    }
}

/**
 * Wraps degrees to be in [0..360).
 */
fn wrap_degrees(degrees: f32) -> f32 {
    let dividend = (degrees / 360.0).floor();
    (degrees - dividend * 360.0) % 360.0
}

/**
 * Calculates the absolute difference in degrees between two headings.
 */
fn difference_d(heading_1_d: f32, heading_2_d: f32) -> f32 {
    let wrap_1_d = wrap_degrees(heading_1_d);
    let wrap_2_d = wrap_degrees(heading_2_d);
    let mut diff_d = (wrap_1_d - wrap_2_d).abs();
    if diff_d > 180.0 {
        diff_d = 360.0 - diff_d;
    }
    diff_d
}

#[cfg(test)]
mod tests {
    use std::f32;
    use super::difference_d;
    use super::equatorial_radius_m;
    use super::is_turn_left;
    use super::latitude_d_to_m_per_longitude_d;
    use super::relative_degrees;
    use super::rotate_degrees_clockwise;
    use super::wrap_degrees;

    fn assert_approx_eq(value_1:f32, value_2:f32) -> () {
        // Yeah, I know this is bad, see
        // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/

        // This is the best we can do with f32
        let tolerance: f32 = 0.00001;
        let diff = (value_1 - value_2).abs();
        assert!(diff < tolerance, "{} < {} failed", diff, tolerance);
    }

    fn test_rotate(point:(f32, f32), degrees:f32, expected_point:(f32, f32)) -> () {
        let new_point = rotate_degrees_clockwise(point, degrees);
        let (p_1, p_2) = new_point;
        let (ep_1, ep_2) = expected_point;
        assert_approx_eq(p_1, ep_1);
        assert_approx_eq(p_2, ep_2);
    }

    #[test]
    fn test_rotate_degrees_clockwise() {
        let base_x = 1.0f32;
        let base_y = 0.0f32;
        let base = (base_x, base_y);

        test_rotate(base, 0.0, base);
        test_rotate(base, 90.0, (base_y, -base_x));
        test_rotate(base, 180.0, (-base_x, base_y));
        test_rotate(base, 270.0, (base_y, base_x));
        test_rotate(base, 360.0, base);

        test_rotate(base, -90.0, (base_y, base_x));
        test_rotate(base, -180.0, (-base_x, base_y));
        test_rotate(base, -270.0, (base_y, -base_x));
        test_rotate(base, -360.0, base);

        test_rotate(base, 720.0, base);
        test_rotate(base, -720.0, base);

        let skewed_x = 1.0;
        let skewed_y = 2.0;
        let skewed = (skewed_x, skewed_y);

        test_rotate(skewed, 0.0, skewed);
        test_rotate(skewed, 90.0, (skewed_y, -skewed_x));
        test_rotate(skewed, 180.0, (-skewed_x, -skewed_y));
        test_rotate(skewed, 270.0, (-skewed_y, skewed_x));
        test_rotate(skewed, 360.0, skewed);

        test_rotate(skewed, -90.0, (-skewed_y, skewed_x));
        test_rotate(skewed, -180.0, (-skewed_x, -skewed_y));
        test_rotate(skewed, -270.0, (skewed_y, -skewed_x));
        test_rotate(skewed, -360.0, skewed);

        test_rotate(skewed, 720.0, skewed);
        test_rotate(skewed, -720.0, skewed);
    }

    #[test]
    fn test_latitude_d_to_m_per_longitude_d_spherical() {
        // Assume Earth is a sphere
        assert_approx_eq(
            equatorial_radius_m() * f32::consts::PI_2 / 360.0,
            latitude_d_to_m_per_longitude_d(0.0)
        );

        // Should be symmetrical
        for degrees in range(0i32, 85) {
            assert_approx_eq(
                latitude_d_to_m_per_longitude_d(degrees as f32),
                latitude_d_to_m_per_longitude_d(-degrees as f32)
            );
        }

        // At the poles, should be 0
        let diff = (latitude_d_to_m_per_longitude_d(90.0)).abs();
        assert!(diff < 0.01);
    }

    #[test]
    #[should_fail]  // We're using a less accurate spherical method right now
    fn test_latitude_d_to_m_per_longitude_d_oblong() {
        // Known values, from http://www.csgnetwork.com/degreelenllavcalc.html
        // M_PER_D_LATITUDE = 111319.458,
        assert_approx_eq(
            // Boulder
            latitude_d_to_m_per_longitude_d(40.08),
            85294.08886768305,
        );
    }

    #[test]
    fn test_is_turn_left() {
        assert!(is_turn_left(1.0, 0.0));
        assert!(!is_turn_left(0.0, 1.0));

        assert!(is_turn_left(1.0, 359.0));
        assert!(!is_turn_left(359.0, 1.0));

        assert!(is_turn_left(1.0, 270.0));
        assert!(is_turn_left(0.0, 270.0));
        assert!(is_turn_left(359.0, 270.0));

        assert!(!is_turn_left(1.0, 90.0));
        assert!(!is_turn_left(0.0, 90.0));
        assert!(!is_turn_left(359.0, 90.0));
    }

    #[test]
    fn test_relative_degrees() {
        assert_approx_eq(relative_degrees(0.0, 0.0, 1.0, 1.0), 45.0);
        assert_approx_eq(relative_degrees(1.0, 1.0, 0.0, 0.0), 225.0);
        assert_approx_eq(relative_degrees(0.0, 0.0, 2.0, 2.0), 45.0);
        assert_approx_eq(relative_degrees(2.0, 2.0, 0.0, 0.0), 225.0);

        assert_approx_eq(relative_degrees(0.0, 0.0, -1.0, 1.0), 315.0);
        assert_approx_eq(relative_degrees(-1.0, 1.0, 0.0, 0.0), 135.0);
        assert_approx_eq(relative_degrees(0.0, 0.0, -2.0, 2.0), 315.0);
        assert_approx_eq(relative_degrees(-2.0, 2.0, 0.0, 0.0), 135.0);

        assert_approx_eq(relative_degrees(0.0, 0.0, 0.0, 1.0), 0.0);
        assert_approx_eq(relative_degrees(0.0, 1.0, 0.0, 0.0), 180.0);
        assert_approx_eq(relative_degrees(0.0, 0.0, 0.0, 2.0), 0.0);
        assert_approx_eq(relative_degrees(0.0, 2.0, 0.0, 0.0), 180.0);

        assert_approx_eq(relative_degrees(0.0, 0.0, 1.0, 0.0), 90.0);
        assert_approx_eq(relative_degrees(1.0, 0.0, 0.0, 0.0), 270.0);
        assert_approx_eq(relative_degrees(0.0, 0.0, 2.0, 0.0), 90.0);
        assert_approx_eq(relative_degrees(2.0, 0.0, 0.0, 0.0), 270.0);
    }

    #[test]
    fn test_wrap_degrees() {
        for d in range(0i32, 360) {
            assert_approx_eq(d as f32, wrap_degrees(d as f32));
        }

        assert_approx_eq(0.0, wrap_degrees(0.0));
        assert_approx_eq(0.0, wrap_degrees(360.0));
        assert_approx_eq(359.0, wrap_degrees(-1.0));
        assert_approx_eq(359.0, wrap_degrees(-361.0));
        assert_approx_eq(1.0, wrap_degrees(361.0));
        assert_approx_eq(1.0, wrap_degrees(721.0));
        assert_approx_eq(0.1, wrap_degrees(360.1));
        assert_approx_eq(0.1, wrap_degrees(0.1));
        assert_approx_eq(359.9, wrap_degrees(-0.1));
    }

    #[test]
    fn test_difference_d() {
        assert_approx_eq(difference_d(359.0, 0.0), 1.0);
        assert_approx_eq(difference_d(0.0, 1.0), 1.0);
        assert_approx_eq(difference_d(359.0, 1.0), 2.0);
        assert_approx_eq(difference_d(360.0, 365.0), 5.0);
        assert_approx_eq(difference_d(-355.0, 365.0), 0.0);
    }
}
<|endoftext|>


<commit_before>use core::marker;

use stream::Stream;

use {Async, Poll};

/// Stream that produces the same element repeatedly.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Repeat<T, E>
    where T: Clone
{
    item: T,
    error: marker::PhantomData<E>,
}

/// Create a stream which produces the same item repeatedly.
///
/// Stream never produces an error or EOF.
///
/// ```rust
/// use futures::*;
///
/// let mut stream = stream::repeat::<_, bool>(10);
/// assert_eq!(Ok(Async::Ready(Some(10))), stream.poll());
/// assert_eq!(Ok(Async::Ready(Some(10))), stream.poll());
/// assert_eq!(Ok(Async::Ready(Some(10))), stream.poll());
/// ```
pub fn repeat<T, E>(item: T) -> Repeat<T, E>
    where T: Clone
{
    Repeat {
        item: item,
        error: marker::PhantomData,
    }
}

impl<T, E> Stream for Repeat<T, E>
    where T: Clone
{
    type Item = T;
    type Error = E;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        Ok(Async::Ready(Some(self.item.clone())))
    }
}
<commit_msg>Clarify infinite nature of `repeat`<commit_after>use core::marker;

use stream::Stream;

use {Async, Poll};

/// Stream that produces the same element repeatedly.
///
/// This structure is created by the `stream::repeat` function.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Repeat<T, E>
    where T: Clone
{
    item: T,
    error: marker::PhantomData<E>,
}

/// Create a stream which produces the same item repeatedly.
///
/// Stream never produces an error or EOF. Note that you likely want to avoid
/// usage of `collect` or such on the returned stream as it will exhaust
/// available memory as it tries to just fill up all RAM.
///
/// ```rust
/// use futures::*;
///
/// let mut stream = stream::repeat::<_, bool>(10);
/// assert_eq!(Ok(Async::Ready(Some(10))), stream.poll());
/// assert_eq!(Ok(Async::Ready(Some(10))), stream.poll());
/// assert_eq!(Ok(Async::Ready(Some(10))), stream.poll());
/// ```
pub fn repeat<T, E>(item: T) -> Repeat<T, E>
    where T: Clone
{
    Repeat {
        item: item,
        error: marker::PhantomData,
    }
}

impl<T, E> Stream for Repeat<T, E>
    where T: Clone
{
    type Item = T;
    type Error = E;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        Ok(Async::Ready(Some(self.item.clone())))
    }
}
<|endoftext|>


<commit_before>use gfx;
use gfx::traits::FactoryExt;
use gfx_core::format::*;
use gfx_core::handle::{Texture, ShaderResourceView};
use gfx_core::command::Buffer;
use rshader;

gfx_pipeline!( splat_pipe {
    heights: gfx::TextureSampler<f32> = "heights",
    slopes: gfx::TextureSampler<[f32; 2]> = "slopes",
    noise: gfx::TextureSampler<[f32; 3]> = "noise",
    noise_wavelength: gfx::Global<f32> = "noiseWavelength",
    texture_spacing: gfx::Global<f32> = "textureSpacing",
    texture_resolution: gfx::Global<i32> = "resolution",
    heights_spacing: gfx::Global<f32> = "heightsSpacing",
//    materials: gfx::TextureSampler<[f32; 4]> = "materials",
    out_splat: gfx::RenderTarget<(R8, Uint)> = "OutSplat",
});
gfx_pipeline!( color_pipe {
    heights: gfx::TextureSampler<f32> = "heights",
    slopes: gfx::TextureSampler<[f32; 2]> = "slopes",
    noise: gfx::TextureSampler<[f32; 3]> = "noise",
    noise_wavelength: gfx::Global<f32> = "noiseWavelength",
    texture_spacing: gfx::Global<f32> = "textureSpacing",
    texture_resolution: gfx::Global<i32> = "resolution",
    heights_spacing: gfx::Global<f32> = "heightsSpacing",
//    materials: gfx::TextureSampler<[f32; 4]> = "materials",
    out_color: gfx::RenderTarget<Srgba8> = "OutColor",
});

const RASTERIZER: gfx::state::Rasterizer = gfx::state::Rasterizer {
    front_face: gfx::state::FrontFace::Clockwise,
    cull_face: gfx::state::CullFace::Nothing,
    method: gfx::state::RasterMethod::Fill,
    offset: None,
    samples: None,
};

pub struct Splat<R: gfx::Resources> {
    splat_pso: gfx::PipelineState<R, splat_pipe::Meta>,
    splat_pipeline_data: splat_pipe::Data<R>,
    splat_shader: rshader::Shader<R>,

    color_pso: gfx::PipelineState<R, color_pipe::Meta>,
    color_pipeline_data: color_pipe::Data<R>,
    color_shader: rshader::Shader<R>,

    _splatmap: Texture<R, R8>,
    _colormap: Texture<R, R8_G8_B8_A8>,

    splatmap_view: ShaderResourceView<R, u32>,
    colormap_view: ShaderResourceView<R, [f32; 4]>,
}

impl<R: gfx::Resources> Splat<R> {
    fn create_splat_pso<F: gfx::Factory<R>>(
        factory: &mut F,
        shaders: &gfx::ShaderSet<R>,
    ) -> gfx::PipelineState<R, splat_pipe::Meta> {
        factory
            .create_pipeline_state(
                shaders,
                gfx::Primitive::TriangleList,
                RASTERIZER,
                splat_pipe::new(),
            )
            .unwrap()
    }
    fn create_color_pso<F: gfx::Factory<R>>(
        factory: &mut F,
        shaders: &gfx::ShaderSet<R>,
    ) -> gfx::PipelineState<R, color_pipe::Meta> {
        factory
            .create_pipeline_state(
                shaders,
                gfx::Primitive::TriangleList,
                RASTERIZER,
                color_pipe::new(),
            )
            .unwrap()
    }

    fn update<C: Buffer<R>>(&mut self, encoder: &mut gfx::Encoder<R, C>) {
        let slice = gfx::Slice {
            start: 0,
            end: 6,
            base_vertex: 0,
            instances: None,
            buffer: gfx::IndexBuffer::Auto,
        };
        encoder.draw(&slice, &self.splat_pso, &self.splat_pipeline_data);
        encoder.draw(&slice, &self.color_pso, &self.color_pipeline_data);
        encoder.generate_mipmap(&self.colormap_view);
    }

    pub fn new<F: gfx::Factory<R>, C: Buffer<R>>(
        factory: &mut F,
        encoder: &mut gfx::Encoder<R, C>,
        shaders_watcher: &mut rshader::ShaderDirectoryWatcher,
        resolution: u16,
        texture_spacing: f32,
        heights: ShaderResourceView<R, f32>,
        slopes: ShaderResourceView<R, [f32; 2]>,
        noise: ShaderResourceView<R, [f32; 3]>,
        noise_wavelength: f32,
        heights_spacing: f32,
    ) -> Self {
        let splat_shader = rshader::Shader::simple(
            factory,
            shaders_watcher,
            shader_source!("../shaders/glsl", "version", "fullscreen.glslv"),
            shader_source!("../shaders/glsl", "version", "fractal", "splatmap.glslf"),
        ).unwrap();
        let color_shader = rshader::Shader::simple(
            factory,
            shaders_watcher,
            shader_source!("../shaders/glsl", "version", "fullscreen.glslv"),
            shader_source!("../shaders/glsl", "version", "fractal", "colormap.glslf"),
        ).unwrap();

        let num_mipmaps = 15 - (resolution - 1).leading_zeros() as u8;

        let splatmap = factory
            .create_texture::<R8>(
                gfx::texture::Kind::D2(resolution, resolution, gfx::texture::AaMode::Single),
                1,
                gfx::RENDER_TARGET | gfx::SHADER_RESOURCE,
                gfx::memory::Usage::Dynamic,
                Some(ChannelType::Uint),
            )
            .unwrap();
        let colormap = factory
            .create_texture::<R8_G8_B8_A8>(
                gfx::texture::Kind::D2(resolution, resolution, gfx::texture::AaMode::Single),
                num_mipmaps,
                gfx::RENDER_TARGET | gfx::SHADER_RESOURCE,
                gfx::memory::Usage::Dynamic,
                Some(ChannelType::Unorm),
            )
            .unwrap();

        let splatmap_view = factory
            .view_texture_as_shader_resource::<(R8, Uint)>(&splatmap, (0, 0), Swizzle::new())
            .unwrap();
        let colormap_view = factory
            .view_texture_as_shader_resource::<Rgba8>(&colormap, (0, 0), Swizzle::new())
            .unwrap();

        let sampler_clamp = factory.create_sampler(gfx::texture::SamplerInfo::new(
            gfx::texture::FilterMethod::Bilinear,
            gfx::texture::WrapMode::Clamp,
        ));
        let sampler_wrap = factory.create_sampler(gfx::texture::SamplerInfo::new(
            gfx::texture::FilterMethod::Bilinear,
            gfx::texture::WrapMode::Tile,
        ));

        let mut splat = Self {
            splat_pso: Self::create_splat_pso(factory, splat_shader.as_shader_set()),
            color_pso: Self::create_color_pso(factory, color_shader.as_shader_set()),
            splat_pipeline_data: splat_pipe::Data::<R> {
                heights: (heights.clone(), sampler_clamp.clone()),
                slopes: (slopes.clone(), sampler_clamp.clone()),
                noise: (noise.clone(), sampler_wrap.clone()),
                noise_wavelength,
                texture_spacing,
                texture_resolution: resolution as i32,
                heights_spacing,
                out_splat: factory
                    .view_texture_as_render_target(&splatmap, 0, None)
                    .unwrap(),
            },
            color_pipeline_data: color_pipe::Data::<R> {
                heights: (heights, sampler_clamp.clone()),
                slopes: (slopes, sampler_clamp.clone()),
                noise: (noise, sampler_wrap),
                noise_wavelength,
                texture_spacing,
                texture_resolution: resolution as i32,
                heights_spacing,
                out_color: factory
                    .view_texture_as_render_target(&colormap, 0, None)
                    .unwrap(),
            },
            splat_shader,
            color_shader,
            _splatmap: splatmap,
            splatmap_view,
            _colormap: colormap,
            colormap_view,
        };
        splat.update(encoder);
        splat
    }

    pub fn refresh<F: gfx::Factory<R>, C: Buffer<R>>(
        &mut self,
        factory: &mut F,
        encoder: &mut gfx::Encoder<R, C>,
        shaders_watcher: &mut rshader::ShaderDirectoryWatcher,
    ) -> bool {
        let mut refreshed = false;
        if self.splat_shader.refresh(factory, shaders_watcher) {
            self.splat_pso = Self::create_splat_pso(factory, self.splat_shader.as_shader_set());
            self.update(encoder);
            refreshed = true;
        }

        if self.color_shader.refresh(factory, shaders_watcher) {
            self.color_pso = Self::create_color_pso(factory, self.color_shader.as_shader_set());
            self.update(encoder);
            refreshed = true;
        }

        refreshed
    }

    pub fn splatmap_shader_resource_view(&self) -> ShaderResourceView<R, u32> {
        self.splatmap_view.clone()
    }
    pub fn colormap_shader_resource_view(&self) -> ShaderResourceView<R, [f32; 4]> {
        self.colormap_view.clone()
    }
}
<commit_msg>Cleaned up splat.rs<commit_after>use gfx;
use gfx::traits::FactoryExt;
use gfx::Primitive::TriangleList;
use gfx::texture::FilterMethod::Bilinear;
use gfx::texture::WrapMode::*;
use gfx::texture::SamplerInfo;
use gfx_core::format::*;
use gfx_core::handle::{Texture, ShaderResourceView};
use gfx_core::command::Buffer;
use rshader;

gfx_pipeline!( splat_pipe {
    heights: gfx::TextureSampler<f32> = "heights",
    slopes: gfx::TextureSampler<[f32; 2]> = "slopes",
    noise: gfx::TextureSampler<[f32; 3]> = "noise",
    noise_wavelength: gfx::Global<f32> = "noiseWavelength",
    texture_spacing: gfx::Global<f32> = "textureSpacing",
    texture_resolution: gfx::Global<i32> = "resolution",
    heights_spacing: gfx::Global<f32> = "heightsSpacing",
//    materials: gfx::TextureSampler<[f32; 4]> = "materials",
    out_splat: gfx::RenderTarget<(R8, Uint)> = "OutSplat",
});
gfx_pipeline!( color_pipe {
    heights: gfx::TextureSampler<f32> = "heights",
    slopes: gfx::TextureSampler<[f32; 2]> = "slopes",
    noise: gfx::TextureSampler<[f32; 3]> = "noise",
    noise_wavelength: gfx::Global<f32> = "noiseWavelength",
    texture_spacing: gfx::Global<f32> = "textureSpacing",
    texture_resolution: gfx::Global<i32> = "resolution",
    heights_spacing: gfx::Global<f32> = "heightsSpacing",
//    materials: gfx::TextureSampler<[f32; 4]> = "materials",
    out_color: gfx::RenderTarget<Srgba8> = "OutColor",
});

const RASTERIZER: gfx::state::Rasterizer = gfx::state::Rasterizer {
    front_face: gfx::state::FrontFace::Clockwise,
    cull_face: gfx::state::CullFace::Nothing,
    method: gfx::state::RasterMethod::Fill,
    offset: None,
    samples: None,
};

pub struct Splat<R: gfx::Resources> {
    splat_pso: gfx::PipelineState<R, splat_pipe::Meta>,
    splat_pipeline_data: splat_pipe::Data<R>,
    splat_shader: rshader::Shader<R>,

    color_pso: gfx::PipelineState<R, color_pipe::Meta>,
    color_pipeline_data: color_pipe::Data<R>,
    color_shader: rshader::Shader<R>,

    _splatmap: Texture<R, R8>,
    _colormap: Texture<R, R8_G8_B8_A8>,

    splatmap_view: ShaderResourceView<R, u32>,
    colormap_view: ShaderResourceView<R, [f32; 4]>,
}

impl<R: gfx::Resources> Splat<R> {
    fn create_splat_pso<F: gfx::Factory<R>>(
        factory: &mut F,
        shaders: &gfx::ShaderSet<R>,
    ) -> gfx::PipelineState<R, splat_pipe::Meta> {
        factory
            .create_pipeline_state(shaders, TriangleList, RASTERIZER, splat_pipe::new())
            .unwrap()
    }
    fn create_color_pso<F: gfx::Factory<R>>(
        factory: &mut F,
        shaders: &gfx::ShaderSet<R>,
    ) -> gfx::PipelineState<R, color_pipe::Meta> {
        factory
            .create_pipeline_state(shaders, TriangleList, RASTERIZER, color_pipe::new())
            .unwrap()
    }

    fn update<C: Buffer<R>>(&mut self, encoder: &mut gfx::Encoder<R, C>) {
        let slice = gfx::Slice {
            start: 0,
            end: 6,
            base_vertex: 0,
            instances: None,
            buffer: gfx::IndexBuffer::Auto,
        };
        encoder.draw(&slice, &self.splat_pso, &self.splat_pipeline_data);
        encoder.draw(&slice, &self.color_pso, &self.color_pipeline_data);
        encoder.generate_mipmap(&self.colormap_view);
    }

    pub fn new<F: gfx::Factory<R>, C: Buffer<R>>(
        factory: &mut F,
        encoder: &mut gfx::Encoder<R, C>,
        shaders_watcher: &mut rshader::ShaderDirectoryWatcher,
        resolution: u16,
        texture_spacing: f32,
        heights: ShaderResourceView<R, f32>,
        slopes: ShaderResourceView<R, [f32; 2]>,
        noise: ShaderResourceView<R, [f32; 3]>,
        noise_wavelength: f32,
        heights_spacing: f32,
    ) -> Self {
        let splat_shader = rshader::Shader::simple(
            factory,
            shaders_watcher,
            shader_source!("../shaders/glsl", "version", "fullscreen.glslv"),
            shader_source!("../shaders/glsl", "version", "fractal", "splatmap.glslf"),
        ).unwrap();
        let color_shader = rshader::Shader::simple(
            factory,
            shaders_watcher,
            shader_source!("../shaders/glsl", "version", "fullscreen.glslv"),
            shader_source!("../shaders/glsl", "version", "fractal", "colormap.glslf"),
        ).unwrap();

        let num_mipmaps = 15 - (resolution - 1).leading_zeros() as u8;

        let splatmap = factory
            .create_texture::<R8>(
                gfx::texture::Kind::D2(resolution, resolution, gfx::texture::AaMode::Single),
                1,
                gfx::RENDER_TARGET | gfx::SHADER_RESOURCE,
                gfx::memory::Usage::Dynamic,
                Some(ChannelType::Uint),
            )
            .unwrap();
        let colormap = factory
            .create_texture::<R8_G8_B8_A8>(
                gfx::texture::Kind::D2(resolution, resolution, gfx::texture::AaMode::Single),
                num_mipmaps,
                gfx::RENDER_TARGET | gfx::SHADER_RESOURCE,
                gfx::memory::Usage::Dynamic,
                Some(ChannelType::Unorm),
            )
            .unwrap();

        let splatmap_view = factory
            .view_texture_as_shader_resource::<(R8, Uint)>(&splatmap, (0, 0), Swizzle::new())
            .unwrap();
        let colormap_view = factory
            .view_texture_as_shader_resource::<Rgba8>(&colormap, (0, 0), Swizzle::new())
            .unwrap();

        let sampler_clamp = factory.create_sampler(SamplerInfo::new(Bilinear, Clamp));
        let sampler_wrap = factory.create_sampler(SamplerInfo::new(Bilinear, Tile));

        let mut splat = Self {
            splat_pso: Self::create_splat_pso(factory, splat_shader.as_shader_set()),
            color_pso: Self::create_color_pso(factory, color_shader.as_shader_set()),
            splat_pipeline_data: splat_pipe::Data::<R> {
                heights: (heights.clone(), sampler_clamp.clone()),
                slopes: (slopes.clone(), sampler_clamp.clone()),
                noise: (noise.clone(), sampler_wrap.clone()),
                noise_wavelength,
                texture_spacing,
                texture_resolution: resolution as i32,
                heights_spacing,
                out_splat: factory
                    .view_texture_as_render_target(&splatmap, 0, None)
                    .unwrap(),
            },
            color_pipeline_data: color_pipe::Data::<R> {
                heights: (heights, sampler_clamp.clone()),
                slopes: (slopes, sampler_clamp.clone()),
                noise: (noise, sampler_wrap),
                noise_wavelength,
                texture_spacing,
                texture_resolution: resolution as i32,
                heights_spacing,
                out_color: factory
                    .view_texture_as_render_target(&colormap, 0, None)
                    .unwrap(),
            },
            splat_shader,
            color_shader,
            _splatmap: splatmap,
            splatmap_view,
            _colormap: colormap,
            colormap_view,
        };
        splat.update(encoder);
        splat
    }

    pub fn refresh<F: gfx::Factory<R>, C: Buffer<R>>(
        &mut self,
        factory: &mut F,
        encoder: &mut gfx::Encoder<R, C>,
        shaders_watcher: &mut rshader::ShaderDirectoryWatcher,
    ) -> bool {
        let mut refreshed = false;
        if self.splat_shader.refresh(factory, shaders_watcher) {
            self.splat_pso = Self::create_splat_pso(factory, self.splat_shader.as_shader_set());
            self.update(encoder);
            refreshed = true;
        }

        if self.color_shader.refresh(factory, shaders_watcher) {
            self.color_pso = Self::create_color_pso(factory, self.color_shader.as_shader_set());
            self.update(encoder);
            refreshed = true;
        }

        refreshed
    }

    pub fn splatmap_shader_resource_view(&self) -> ShaderResourceView<R, u32> {
        self.splatmap_view.clone()
    }
    pub fn colormap_shader_resource_view(&self) -> ShaderResourceView<R, [f32; 4]> {
        self.colormap_view.clone()
    }
}
<|endoftext|>