nitedrvr.cpp: removed tagmap lookups and other very minor cleanups

This commit is contained in:
Ivan Vangelista 2021-05-22 12:35:05 +02:00
parent af08fad91c
commit c9debe9adf
5 changed files with 125 additions and 103 deletions

View File

@ -2,7 +2,7 @@
// copyright-holders:Derrick Renaud
/*************************************************************************
audio\nitedrvr.c
audio\nitedrvr.cpp
*************************************************************************/
#include "emu.h"
@ -10,24 +10,24 @@
#include "sound/discrete.h"
/* Discrete Sound Emulation */
// Discrete Sound Emulation
static const discrete_lfsr_desc nitedrvr_lfsr =
{
DISC_CLK_IS_FREQ,
16, /* Bit Length */
0, /* Reset Value */
0, /* Use Bit 0 as XOR input 0 */
14, /* Use Bit 14 as XOR input 1 */
DISC_LFSR_XNOR, /* Feedback stage1 is XNOR */
DISC_LFSR_OR, /* Feedback stage2 is just stage 1 output OR with external feed */
DISC_LFSR_REPLACE, /* Feedback stage3 replaces the shifted register contents */
0x000001, /* Everything is shifted into the first bit only */
0, /* Output is already inverted by XNOR */
15 /* Output bit */
16, // Bit Length
0, // Reset Value
0, // Use Bit 0 as XOR input 0
14, // Use Bit 14 as XOR input 1
DISC_LFSR_XNOR, // Feedback stage1 is XNOR
DISC_LFSR_OR, // Feedback stage2 is just stage 1 output OR with external feed
DISC_LFSR_REPLACE, // Feedback stage3 replaces the shifted register contents
0x000001, // Everything is shifted into the first bit only
0, // Output is already inverted by XNOR
15 // Output bit
};
/* Nodes - Sounds */
// Nodes - Sounds
#define NITEDRVR_NOISE NODE_10
#define NITEDRVR_BANG_SND NODE_11
#define NITEDRVR_MOTOR_SND NODE_12
@ -36,7 +36,7 @@ static const discrete_lfsr_desc nitedrvr_lfsr =
DISCRETE_SOUND_START(nitedrvr_discrete)
/************************************************/
/* nitedrvr Effects Relataive Gain Table */
/* nitedrvr Effects Relative Gain Table */
/* */
/* Effect V-ampIn Gain ratio Relative */
/* Bang 3.8 5/(5+6.8) 1000.0 */
@ -48,7 +48,7 @@ DISCRETE_SOUND_START(nitedrvr_discrete)
/************************************************/
/* Input register mapping for nitedrvr */
/************************************************/
/* NODE GAIN OFFSET INIT */
// NODE GAIN OFFSET INIT
DISCRETE_INPUTX_DATA (NITEDRVR_BANG_DATA, 1000.0/15, 0.0, 0.0)
DISCRETE_INPUT_LOGIC (NITEDRVR_SKID1_EN)
DISCRETE_INPUT_LOGIC (NITEDRVR_SKID2_EN)
@ -62,7 +62,7 @@ DISCRETE_SOUND_START(nitedrvr_discrete)
/* */
/* Motor sound circuit is based on a 556 VCO */
/* with the input frequency set by the MotorSND */
/* latch (4 bit). This freqency is then used to */
/* latch (4 bit). This frequency is then used to*/
/* driver a modulo 12 counter, with div6, 4 & 3 */
/* summed as the output of the circuit. */
/* VCO Output is Sq wave = 27-382Hz */
@ -77,7 +77,7 @@ DISCRETE_SOUND_START(nitedrvr_discrete)
/* to a 2.2uf capacitor on the R-ladder. */
/* Note the VCO freq. is controlled by a 250k */
/* pot. The freq. used here is for the pot set */
/* to 125k. The low freq is allways the same. */
/* to 125k. The low freq is always the same. */
/* This adjusts the high end. */
/* 0k = 214Hz. 250k = 4416Hz */
/************************************************/
@ -85,15 +85,15 @@ DISCRETE_SOUND_START(nitedrvr_discrete)
DISCRETE_ADJUSTMENT(NODE_21, (214.0-27.0)/12/31, (4416.0-27.0)/12/31, DISC_LOGADJ, "MOTOR")
DISCRETE_MULTIPLY(NODE_22, NODE_20, NODE_21)
DISCRETE_MULTADD(NODE_23, NODE_22, 2, 27.0/6) /* F1 = /12*2 = /6 */
DISCRETE_MULTADD(NODE_23, NODE_22, 2, 27.0/6) // F1 = /12*2 = /6
DISCRETE_SQUAREWAVE(NODE_24, 1, NODE_23, (786.7/3), 50.0, 0, 0)
DISCRETE_RCFILTER(NODE_25, NODE_24, 10000, 1e-7)
DISCRETE_MULTADD(NODE_26, NODE_22, 3, 27.0/4) /* F2 = /12*3 = /4 */
DISCRETE_MULTADD(NODE_26, NODE_22, 3, 27.0/4) // F2 = /12*3 = /4
DISCRETE_SQUAREWAVE(NODE_27, 1, NODE_26, (786.7/3), 50.0, 0, 0)
DISCRETE_RCFILTER(NODE_28, NODE_27, 10000, 1e-7)
DISCRETE_MULTADD(NODE_29, NODE_22, 4, 27.0/3) /* F3 = /12*4 = /3 */
DISCRETE_MULTADD(NODE_29, NODE_22, 4, 27.0/3) // F3 = /12*4 = /3
DISCRETE_SQUAREWAVE(NODE_30, 1, NODE_29, (786.7/3), 100.0/3, 0, 360.0/3)
DISCRETE_RCFILTER(NODE_31, NODE_30, 10000, 1e-7)
@ -133,8 +133,8 @@ DISCRETE_SOUND_START(nitedrvr_discrete)
DISCRETE_MULTADD(NODE_72, NODE_71, 940.0-630.0, ((940.0-630.0)/2)+630.0)
DISCRETE_SQUAREWAVE(NITEDRVR_SCREECH1_SND, NITEDRVR_SKID1_EN, NODE_72, 226.9, 31.5, 0, 0.0)
DISCRETE_MULTADD(NODE_75, NODE_71, 1380.0-626.0, 626.0+((1380.0-626.0)/2)) /* Frequency */
DISCRETE_MULTADD(NODE_76, NODE_71, 32.0-13.0, 13.0+((32.0-13.0)/2)) /* Duty */
DISCRETE_MULTADD(NODE_75, NODE_71, 1380.0-626.0, 626.0+((1380.0-626.0)/2)) // Frequency
DISCRETE_MULTADD(NODE_76, NODE_71, 32.0-13.0, 13.0+((32.0-13.0)/2)) // Duty
DISCRETE_SQUAREWAVE(NITEDRVR_SCREECH2_SND, NITEDRVR_SKID2_EN, NODE_75, 226.9, NODE_76, 0, 0.0)
/************************************************/

View File

@ -46,25 +46,25 @@
#include "screen.h"
#include "speaker.h"
/* Memory Map */
// Memory Map
void nitedrvr_state::nitedrvr_map(address_map &map)
void nitedrvr_state::main_map(address_map &map)
{
map(0x0000, 0x00ff).ram().mirror(0x100); // SCRAM
map(0x0200, 0x027f).nopr().ram().mirror(0x180).share("videoram"); // PFW
map(0x0400, 0x042f).nopr().writeonly().mirror(0x1c0).share("hvc"); // POSH, POSV, CHAR
map(0x0200, 0x027f).nopr().ram().mirror(0x180).share(m_videoram); // PFW
map(0x0400, 0x042f).nopr().writeonly().mirror(0x1c0).share(m_hvc); // POSH, POSV, CHAR
map(0x0430, 0x043f).w("watchdog", FUNC(watchdog_timer_device::reset_w)).mirror(0x1c0);
map(0x0600, 0x07ff).r(FUNC(nitedrvr_state::nitedrvr_in0_r));
map(0x0800, 0x09ff).r(FUNC(nitedrvr_state::nitedrvr_in1_r));
map(0x0a00, 0x0bff).w(FUNC(nitedrvr_state::nitedrvr_out0_w));
map(0x0c00, 0x0dff).w(FUNC(nitedrvr_state::nitedrvr_out1_w));
map(0x8000, 0x807f).nopw().ram().mirror(0x380).share("videoram"); // PFR
map(0x8400, 0x87ff).rw(FUNC(nitedrvr_state::nitedrvr_steering_reset_r), FUNC(nitedrvr_state::nitedrvr_steering_reset_w));
map(0x0600, 0x07ff).r(FUNC(nitedrvr_state::in0_r));
map(0x0800, 0x09ff).r(FUNC(nitedrvr_state::in1_r));
map(0x0a00, 0x0bff).w(FUNC(nitedrvr_state::out0_w));
map(0x0c00, 0x0dff).w(FUNC(nitedrvr_state::out1_w));
map(0x8000, 0x807f).nopw().ram().mirror(0x380).share(m_videoram); // PFR
map(0x8400, 0x87ff).rw(FUNC(nitedrvr_state::steering_reset_r), FUNC(nitedrvr_state::steering_reset_w));
map(0x9000, 0x9fff).rom(); // ROM1-ROM2
map(0xfff0, 0xffff).rom(); // ROM2 for 6502 vectors
}
/* Input Ports */
// Input Ports
static INPUT_PORTS_START( nitedrvr )
PORT_START("DSW0") // fake
@ -119,7 +119,7 @@ static INPUT_PORTS_START( nitedrvr )
PORT_ADJUSTER( 60, "Motor RPM" )
INPUT_PORTS_END
/* Graphics Layouts */
// Graphics Layouts
static const gfx_layout charlayout =
{
@ -132,43 +132,43 @@ static const gfx_layout charlayout =
8*8
};
/* Graphics Decode Information */
// Graphics Decode Information
static GFXDECODE_START( gfx_nitedrvr )
GFXDECODE_ENTRY( "gfx1", 0, charlayout, 0, 1 )
GFXDECODE_END
/* Machine Driver */
// Machine Driver
void nitedrvr_state::nitedrvr(machine_config &config)
{
/* basic machine hardware */
// basic machine hardware
M6502(config, m_maincpu, 12.096_MHz_XTAL / 12); // 1 MHz
m_maincpu->set_addrmap(AS_PROGRAM, &nitedrvr_state::nitedrvr_map);
m_maincpu->set_addrmap(AS_PROGRAM, &nitedrvr_state::main_map);
m_maincpu->set_vblank_int("screen", FUNC(nitedrvr_state::irq0_line_hold));
WATCHDOG_TIMER(config, "watchdog").set_vblank_count("screen", 3);
TIMER(config, "crash_timer").configure_periodic(FUNC(nitedrvr_state::nitedrvr_crash_toggle_callback), PERIOD_OF_555_ASTABLE(RES_K(180), 330, CAP_U(1)));
TIMER(config, "crash_timer").configure_periodic(FUNC(nitedrvr_state::crash_toggle_callback), PERIOD_OF_555_ASTABLE(RES_K(180), 330, CAP_U(1)));
/* video hardware */
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_raw(12.096_MHz_XTAL / 2, 384, 0, 256, 262, 0, 240);
// PROM derives VRESET, VBLANK, VSYNC, IRQ from vertical scan count and last VBLANK
screen.set_screen_update(FUNC(nitedrvr_state::screen_update_nitedrvr));
screen.set_screen_update(FUNC(nitedrvr_state::screen_update));
screen.set_palette(m_palette);
GFXDECODE(config, m_gfxdecode, m_palette, gfx_nitedrvr);
PALETTE(config, m_palette, palette_device::MONOCHROME);
/* sound hardware */
// sound hardware
SPEAKER(config, "mono").front_center();
DISCRETE(config, m_discrete, nitedrvr_discrete).add_route(ALL_OUTPUTS, "mono", 1.0);
}
/* ROMs */
// ROMs
/*
ROM_START( nitedrvo ) // early revision has the program code stored in 8 chips
@ -197,6 +197,6 @@ ROM_START( nitedrvr )
ROM_LOAD( "006559-01.h7", 0x0000, 0x0100, CRC(5a8d0e42) SHA1(772220c4c24f18769696ddba26db2bc2e5b0909d) ) // PROM, Sync
ROM_END
/* Game Drivers */
// Game Drivers
GAME( 1976, nitedrvr, 0, nitedrvr, nitedrvr, nitedrvr_state, empty_init, ROT0, "Atari", "Night Driver", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )

View File

@ -14,7 +14,7 @@
#include "sound/discrete.h"
#include "emupal.h"
/* Discrete Sound Input Nodes */
// Discrete Sound Input Nodes
#define NITEDRVR_BANG_DATA NODE_01
#define NITEDRVR_SKID1_EN NODE_02
#define NITEDRVR_SKID2_EN NODE_03
@ -28,39 +28,53 @@ class nitedrvr_state : public driver_device
public:
nitedrvr_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_videoram(*this, "videoram"),
m_hvc(*this, "hvc"),
m_maincpu(*this, "maincpu"),
m_discrete(*this, "discrete"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_led(*this, "led")
m_videoram(*this, "videoram"),
m_hvc(*this, "hvc"),
m_steer(*this, "STEER"),
m_gears(*this, "GEARS"),
m_in0(*this, "IN0"),
m_dsw(*this, "DSW%u", 0U),
m_led(*this, "led"),
m_track_sel(*this, "track%u", 1U),
m_gear_sel(*this, "gear%u", 1U)
{ }
void nitedrvr(machine_config &config);
private:
uint8_t nitedrvr_steering_reset_r();
void nitedrvr_steering_reset_w(uint8_t data);
uint8_t nitedrvr_in0_r(offs_t offset);
uint8_t nitedrvr_in1_r(offs_t offset);
void nitedrvr_out0_w(uint8_t data);
void nitedrvr_out1_w(uint8_t data);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
uint32_t screen_update_nitedrvr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
TIMER_DEVICE_CALLBACK_MEMBER(nitedrvr_crash_toggle_callback);
private:
uint8_t steering_reset_r();
void steering_reset_w(uint8_t data);
uint8_t in0_r(offs_t offset);
uint8_t in1_r(offs_t offset);
void out0_w(uint8_t data);
void out1_w(uint8_t data);
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
TIMER_DEVICE_CALLBACK_MEMBER(crash_toggle_callback);
void draw_box(bitmap_ind16 &bitmap, const rectangle &cliprect, int bx, int by, int ex, int ey);
void draw_roadway(bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_tiles(bitmap_ind16 &bitmap, const rectangle &cliprect);
int nitedrvr_steering();
void nitedrvr_map(address_map &map);
int steering();
void main_map(address_map &map);
/* memory pointers */
// devices
required_device<cpu_device> m_maincpu;
required_device<discrete_device> m_discrete;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
// memory pointers
required_shared_ptr<uint8_t> m_videoram;
required_shared_ptr<uint8_t> m_hvc;
/* input */
// input
uint8_t m_gear;
uint8_t m_track;
int32_t m_steering_buf;
@ -70,16 +84,16 @@ private:
uint8_t m_crash_data_en; // IC D8
uint8_t m_ac_line;
int32_t m_last_steering_val;
required_ioport m_steer, m_gears, m_in0;
required_ioport_array<3> m_dsw;
/* devices */
required_device<cpu_device> m_maincpu;
required_device<discrete_device> m_discrete;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
// output
output_finder<> m_led;
output_finder<3> m_track_sel;
output_finder<4> m_gear_sel;
};
/*----------- defined in audio/nitedrvr.c -----------*/
//----------- defined in audio/nitedrvr.cpp -----------
DISCRETE_SOUND_EXTERN( nitedrvr_discrete );
#endif // MAME_INCLUDES_NITEDRVR_H

View File

@ -20,9 +20,9 @@ because D6 and D7 are apparently checked at different times, and a
change in-between can affect the direction you move.
***************************************************************************/
int nitedrvr_state::nitedrvr_steering( )
int nitedrvr_state::steering()
{
int this_val = ioport("STEER")->read();
int this_val = m_steer->read();
int delta = this_val - m_last_steering_val;
m_last_steering_val = this_val;
@ -32,7 +32,7 @@ int nitedrvr_state::nitedrvr_steering( )
else if (delta < -128)
delta += 256;
/* Divide by four to make our steering less sensitive */
// Divide by four to make our steering less sensitive
m_steering_buf += (delta / 4);
if (m_steering_buf > 0)
@ -54,23 +54,23 @@ int nitedrvr_state::nitedrvr_steering( )
}
/***************************************************************************
nitedrvr_steering_reset
steering_reset
***************************************************************************/
uint8_t nitedrvr_state::nitedrvr_steering_reset_r()
uint8_t nitedrvr_state::steering_reset_r()
{
m_steering_val = 0;
return 0;
}
void nitedrvr_state::nitedrvr_steering_reset_w(uint8_t data)
void nitedrvr_state::steering_reset_w(uint8_t data)
{
m_steering_val = 0;
}
/***************************************************************************
nitedrvr_in0_r
in0_r
Night Driver looks for the following:
A: $00
@ -97,22 +97,25 @@ Night Driver looks for the following:
Fill in the steering and gear bits in a special way.
***************************************************************************/
uint8_t nitedrvr_state::nitedrvr_in0_r(offs_t offset)
uint8_t nitedrvr_state::in0_r(offs_t offset)
{
int gear = ioport("GEARS")->read();
int gear = m_gears->read();
if (gear & 0x10) m_gear = 1;
else if (gear & 0x20) m_gear = 2;
else if (gear & 0x40) m_gear = 3;
else if (gear & 0x80) m_gear = 4;
for (uint8_t i = 0; i < 4; i++)
m_gear_sel[i] = ((m_gear == (i + 1)) ? 1 : 0);
switch (offset & 0x03)
{
case 0x00: /* No remapping necessary */
return ioport("DSW0")->read();
case 0x01: /* No remapping necessary */
return ioport("DSW1")->read();
case 0x02: /* Remap our gear shift */
case 0x00: // No remapping necessary
return m_dsw[0]->read();
case 0x01: // No remapping necessary
return m_dsw[1]->read();
case 0x02: // Remap our gear shift
if (m_gear == 1)
return 0xe0;
else if (m_gear == 2)
@ -121,15 +124,15 @@ uint8_t nitedrvr_state::nitedrvr_in0_r(offs_t offset)
return 0xb0;
else
return 0x70;
case 0x03: /* Remap our steering */
return (ioport("DSW2")->read() | nitedrvr_steering());
case 0x03: // Remap our steering
return (m_dsw[2]->read() | steering());
default:
return 0xff;
}
}
/***************************************************************************
nitedrvr_in1_r
in1_r
Night Driver looks for the following:
A: $00
@ -160,9 +163,9 @@ Night Driver looks for the following:
Fill in the track difficulty switch and special signal in a special way.
***************************************************************************/
uint8_t nitedrvr_state::nitedrvr_in1_r(offs_t offset)
uint8_t nitedrvr_state::in1_r(offs_t offset)
{
int port = ioport("IN0")->read();
int port = m_in0->read();
m_ac_line = (m_ac_line + 1) % 3;
@ -170,6 +173,9 @@ uint8_t nitedrvr_state::nitedrvr_in1_r(offs_t offset)
else if (port & 0x20) m_track = 1;
else if (port & 0x40) m_track = 2;
for (uint8_t i = 0; i < 3; i++)
m_track_sel[i] = (m_track == i ? 1 : 0);
switch (offset & 0x07)
{
case 0x00:
@ -185,7 +191,7 @@ uint8_t nitedrvr_state::nitedrvr_in1_r(offs_t offset)
case 0x05:
if (m_track == 0) return 0x80; else return 0x00;
case 0x06:
/* TODO: fix alternating signal? */
// TODO: fix alternating signal?
if (m_ac_line==0) return 0x80; else return 0x00;
case 0x07:
return 0x00;
@ -195,7 +201,7 @@ uint8_t nitedrvr_state::nitedrvr_in1_r(offs_t offset)
}
/***************************************************************************
nitedrvr_out0_w
out0_w
Sound bits:
@ -207,7 +213,7 @@ D4 = SKID1
D5 = SKID2
***************************************************************************/
void nitedrvr_state::nitedrvr_out0_w(uint8_t data)
void nitedrvr_state::out0_w(uint8_t data)
{
m_discrete->write(NITEDRVR_MOTOR_DATA, data & 0x0f); // Motor freq data
m_discrete->write(NITEDRVR_SKID1_EN, data & 0x10); // Skid1 enable
@ -215,7 +221,7 @@ void nitedrvr_state::nitedrvr_out0_w(uint8_t data)
}
/***************************************************************************
nitedrvr_out1_w
out1_w
D0 = !CRASH - also drives a video invert signal
D1 = ATTRACT
@ -225,7 +231,7 @@ D4 = LED START
D5 = Spare (Not used)
***************************************************************************/
void nitedrvr_state::nitedrvr_out1_w(uint8_t data)
void nitedrvr_state::out1_w(uint8_t data)
{
m_led = BIT(data, 4);
@ -236,18 +242,18 @@ void nitedrvr_state::nitedrvr_out1_w(uint8_t data)
if (!m_crash_en)
{
/* Crash reset, set counter high and enable output */
// Crash reset, set counter high and enable output
m_crash_data_en = 1;
m_crash_data = 0x0f;
/* Invert video */
m_palette->set_pen_color(1, rgb_t(0x00,0x00,0x00)); /* BLACK */
m_palette->set_pen_color(0, rgb_t(0xff,0xff,0xff)); /* WHITE */
// Invert video
m_palette->set_pen_color(1, rgb_t(0x00, 0x00, 0x00)); // BLACK
m_palette->set_pen_color(0, rgb_t(0xff, 0xff, 0xff)); // WHITE
}
m_discrete->write(NITEDRVR_BANG_DATA, m_crash_data_en ? m_crash_data : 0); // Crash Volume
}
TIMER_DEVICE_CALLBACK_MEMBER(nitedrvr_state::nitedrvr_crash_toggle_callback)
TIMER_DEVICE_CALLBACK_MEMBER(nitedrvr_state::crash_toggle_callback)
{
if (m_crash_en && m_crash_data_en)
{
@ -258,15 +264,15 @@ TIMER_DEVICE_CALLBACK_MEMBER(nitedrvr_state::nitedrvr_crash_toggle_callback)
if (m_crash_data & 0x01)
{
/* Invert video */
m_palette->set_pen_color(1, rgb_t(0x00,0x00,0x00)); /* BLACK */
m_palette->set_pen_color(0, rgb_t(0xff,0xff,0xff)); /* WHITE */
// Invert video
m_palette->set_pen_color(1, rgb_t(0x00, 0x00, 0x00)); // BLACK
m_palette->set_pen_color(0, rgb_t(0xff, 0xff, 0xff)); // WHITE
}
else
{
/* Normal video */
m_palette->set_pen_color(0, rgb_t(0x00,0x00,0x00)); /* BLACK */
m_palette->set_pen_color(1, rgb_t(0xff,0xff,0xff)); /* WHITE */
// Normal video
m_palette->set_pen_color(0, rgb_t(0x00,0x00,0x00)); // BLACK
m_palette->set_pen_color(1, rgb_t(0xff,0xff,0xff)); // WHITE
}
}
}
@ -274,6 +280,8 @@ TIMER_DEVICE_CALLBACK_MEMBER(nitedrvr_state::nitedrvr_crash_toggle_callback)
void nitedrvr_state::machine_start()
{
m_led.resolve();
m_track_sel.resolve();
m_gear_sel.resolve();
save_item(NAME(m_gear));
save_item(NAME(m_track));

View File

@ -46,7 +46,7 @@ void nitedrvr_state::draw_tiles(bitmap_ind16 &bitmap, const rectangle &cliprect)
}
}
uint32_t nitedrvr_state::screen_update_nitedrvr(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
uint32_t nitedrvr_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0, cliprect);
draw_tiles(bitmap, cliprect);