Jump to content
IGNORED

Lightguns


Matthias

Recommended Posts

Seeing JagZombies 2 coming inspired me to order a Sega Light Phaser and wire up a prototype-quality adapter using leftover parts from my VGA cable and BJL adapter projects:

 

light_phaser_adapter.thumb.jpg.1f2668f41f0d4ec5847b9334e662804a.jpg

 

Using an XOR gate to invert the light pen signal before feeding it back to the Jaguar.  Seems to work pretty well with @Matthias's balloons demo, but the gun has some trouble near the center of the screen (Seems to be impossible to target the middle ~10-20 pixels of the screen, it jumps back and forth between either side in those areas).

 

Anyone done anything else on the SW side since this thread?  Everyone seemed to be all excited, then it looks like nothing came of it.  I love light gun games, so I was going to try to write up a little bit of code that handled things besides over-saturated screens (Yes, by adding back the cursed flashing).

 

I've also been considering ideas for two-player (Two light guns plugged into one controller port, switch between them with a gate on the adapter when the trigger button is pressed, with the console ensuring the switch doesn't happen too fast for it to sample by using one of the joystick select lines as a semaphore of sorts).  I think this is roughly how Lethal Enforcers worked on the SNES, which my brother and I loved.  Player 2's gun was plugged into player 1's gun, which in turn plugged into the console.  Poor player 2's gun would get starved IIRC if player 1 was shooting too fast.

  • Like 1
Link to comment
Share on other sites

On 8/11/2020 at 9:05 AM, cubanismo said:

Anyone done anything else on the SW side since this thread?

 

Quote

*crickets*

 

Guess not ?

 

I've written a little mini-library of code to handle lightgun input based on the description of how things work in this thread and my own analysis/testing.  It doesn't have the issue I had with balloons where I can't target the middle of the screen (I suspect @Matthias used roughly the same algorithm I came up with, but likely hard-coded PAL values?  I think in theory this would explain the problem).  I've posted the code here:

 

https://github.com/cubanismo/bullets

 

So far, it's just a little demo that prints the lightgun coordinates on screen and draws a pixel where the gun is pointing, making it a very crappy, black-and-white version of Mario Paint for the Jaguar that uses a lightgun instead of a mouse.  I'd like to extend it into a full demo that lets you shoot bullet holes into an arbitrary bitmap background image.  I have some more coding to do there, but I wanted to share it here as-is for a few reasons:

  • It'd be good if someone using a PAL CRT + lightgun could try this out, potentially tweaking the hard-coded calibration variable (See lightgun.s XXX comments) as needed.
  • I was hoping someone could check my math: As noted, there's an arbitrary calibration value in the code right now that adjusts the theoretically-correct X coordinate of the lightgun to make it line up with the screen in practice.  I don't know why this is needed.  It doesn't fall out of the math I came up with based on my current understanding of the Jaguar's lightgun hardware from the comments in this thread and a revisionist interpretation of the Jaguar docs.  I'm pasting a slightly modified version of the massive verbose commit message from the github repo below explaining the algorithm for analysis/feedback.  However, if you prefer, just look at the heavily-commented 68k assembly code in lightgun.s for the more-optimized version.
Quote

Convert lightpen registers to framebuffer (x,y):


The math used is as follows:

LPH = latched HC value, NOT horizontal position
      in pixels, as the manual states.

LPV = latched VC value, more or less matching
      the documentation.

Given LPH is is defined as a sampled value from
the HC register, we know it counts from zero to
the value in HP, or the horizontal period
register, which is the number of pixel/video
clock cycles in HALF of a scanline.  When it
wraps for the second half of a scanline, the
11th bit is set, so the first task we have is
to reconstruct the full-scanline pixel clock
count from LPH:

  raw = LPH
  hpcc = raw & ((1 << 10) - 1)
  if (raw & (1 << 1)) hpcc += HP

(hpcc: "Horizontal Pixel Clock Count")

However, we can't read HP (It's write-only).
Luckily, HP should be either NTSC_HMID or
PAL_HMID, so we can deduce it by checking the
NTSC/PAL config bit.

Next we want to convert from video clock ticks
to a pixel count, so we divide by the PWIDTH
field of VMODE.  The current code always assumes
PWIDTH4.  This should give us a scanline position
in pixels.

Now we need to map that pixel count onto the
framebuffer used by the object processor.  This
requires a lot of input variables, so I've
simplified as mentioned above by assuming a
framebuffer centered on the scanline horizontally.
The object processor's BITMAP object type contains
the field XPOS, which is defined as an offset in
pixels from the start of the line buffer.  OK, but
where is the line buffer positioned?  At HDB1/2 of
course!  Another write-only register, so back to
analyzing startup.s, we see it exports a_hdb, a
variable containing the value programmed in
HDB1 and HDB2.  Of course, a_hdb is in raw video
clocks, and XPOS is in pixels, so we need to take
care when combining them (Again, assuming PWIDTH4
here):

  framebuffer X origin = a_hdb + (XPOS * 4)

Where framebuffer X origin is in video clock
units.  How do we get XPOS?  We could pull it out
of the object list, pass it as a parameter, or
just re-calculate it from the framebuffer width
in pixels if we make the above assumptions about
a centered framebuffer, which is what I've done
here.

I call this value "xoff4" since it is the value
subtracted from the above hpcc value to obtain
the video clock offset within the framebuffer.
The result of that subtraction is then divided
by 4 to obtain the x coordinate within the
framebuffer image.

  fb_x = (hpcc - xoff4) / 4

Or that's how it *should* work in theory.  In
practice, I have to skew xoff4 a bit to the left:

  xoff4 -= 170
  ...
  fb_x = (hpcc - xoff4) / 4

...

The vertical position is much easier.  Just mask
off the "field" bit of LPV, divide it by two to
get the raw scanline count.

  vslc = (LPV & ((1 << 11) - 1)) / 2

(vslc: Vertical ScanLine Count)

From there, recalculate the YPOS object processor
value, which luckily is a raw offset from scanline
zero (though in half-scanlines, because everything
has to be hard on Jaguar) so the only inputs we
need here are the framebuffer height and the video
mode middle line, the latter of which is either
PAL_VMID or NTSC_VMID, which are also in half-
lines.

  framebuffer Y origin =
      (VMID - ((fb_height * 2) / 2)) / 2

or,

  framebuffer Y origin = (VMID - fb_height) / 2

We'll call this value yoff, similar to above for
the horizontal offset value, giving us the
following equation:

  fb_y = vslc - yoff

And there we have it, (fb_x, fb_y) is where the
light gun was pointed in the framebuffer! Simple,
right? Yeah... right...

Oh, and in case you just want to play with the little demo/test it on your CRT without needing to compile anything, I've attached it here as well:

bullets.cof

Edited by cubanismo
Attached the bullets.cof file
  • Like 2
Link to comment
Share on other sites

On 8/11/2020 at 5:05 PM, cubanismo said:

Anyone done anything else on the SW side since this thread?  Everyone seemed to be all excited, then it looks like nothing came of it.  I love light gun games, so I was going to try to write up a little bit of code that handled things besides over-saturated screens (Yes, by adding back the cursed flashing).

 

I've also been considering ideas for two-player (Two light guns plugged into one controller port, switch between them with a gate on the adapter when the trigger button is pressed, with the console ensuring the switch doesn't happen too fast for it to sample by using one of the joystick select lines as a semaphore of sorts).  I think this is roughly how Lethal Enforcers worked on the SNES, which my brother and I loved.  Player 2's gun was plugged into player 1's gun, which in turn plugged into the console.  Poor player 2's gun would get starved IIRC if player 1 was shooting too fast.

Probably because CRTs were on their way out and those old light guns do not work well with LDC screens, plus having to modify them to be Jagaur compatible and lack of supporting game software probably meant people thought it was more trouble than it was worth to peruse it.

 

If regard to getting two guns working if the LP signal is hard wired to latching the counter data that would be tricky, if it relies in the LP signal being read into the JoyButs register then perhaps you could simply read each controller on alternate frames and when controller 2 generates an LP input set the relevant bit of the Controller 2 Joybuts register to trigger the counter latching.

Alternatively, if you can read the counter anytime then read it just before the controller read, then perform the controller read, it should take a fined amount of time to perform a controller read so you should not how much to add to the previously read counter value to generate a correct value when an LP input is detected. Again you would need to read the controllers on alternate frames.  

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...