English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Language > Coders. C/C++

 
 
Thread Tools
Old 21 July 2017, 14:42   #1
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Using the Copper

I'm playing around with the copper, and I came about this example: https://github.com/weiju/amiga_hardw...-002/startup.c I've attached the source and exe.

I've expanded this code somewhat in order to make the copper list dynamic, ie I want to write a new copper list each frame. So I need a frame loop, and here's what I have:
Code:
 BOOL cont = TRUE;
 volatile UBYTE *ciaa_pra = (volatile UBYTE *) 0xbfe001;
 UWORD currCOL = COL1;
 int currFrame = 0;
 int maxFames = 50;
 while(cont)  // frame loop
 {
  WaitTOF();
  
  currFrame += 1;
  if(currFrame > maxFames)
  {
   currFrame = 0;
   if(currCOL == COL1) currCOL = COL2;
   else currCOL = COL1;
   coplist[7] = currCOL;
  }
  
  if((*ciaa_pra & PRA_FIR0_BIT) == 0) cont = FALSE; // quit when lmb pressed
 }
Is this the proper way to write a frame loop? Are there other possibilities? Say you also wanted to use the blitter at some point, does that change this basic loop?

Also, I'm on a PAL system, so I'm assuming my code runs (exactly) 50 times a second. I've included the color change to occur every 50 frames, but I feel it actually changes quicker than that (so like in 0.8 seconds instead of 1). I've tested in emulation and on real hardware; the behaviour/timing is the same. Can anybody verify this?

I'll need to get this basic timing stuff sorted out, if I ever want to do some seriously swinging copper animations, right..
Attached Files
File Type: zip copper.zip (7.7 KB, 93 views)
guy lateur is offline  
Old 21 July 2017, 15:08   #2
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,409
Quote:
Originally Posted by guy lateur View Post
I'm playing around with the copper, and I came about this example: https://github.com/weiju/amiga_hardw...-002/startup.c I've attached the source and exe.

I've expanded this code somewhat in order to make the copper list dynamic, ie I want to write a new copper list each frame. So I need a frame loop, and here's what I have:
Code:
 BOOL cont = TRUE;
 volatile UBYTE *ciaa_pra = (volatile UBYTE *) 0xbfe001;
 UWORD currCOL = COL1;
 int currFrame = 0;
 int maxFames = 50;
 while(cont)  // frame loop
 {
  WaitTOF();
  
  currFrame += 1;
  if(currFrame > maxFames)
  {
   currFrame = 0;
   if(currCOL == COL1) currCOL = COL2;
   else currCOL = COL1;
   coplist[7] = currCOL;
  }
  
  if((*ciaa_pra & PRA_FIR0_BIT) == 0) cont = FALSE; // quit when lmb pressed
 }
Is this the proper way to write a frame loop? Are there other possibilities? Say you also wanted to use the blitter at some point, does that change this basic loop?
It mostly is, but see below
As for adding the Blitter, I feel that could still be done in this framework, though you probably want to add some form of double buffering to it in that case to avoid screen tearing/missing bobs.

Quote:
Also, I'm on a PAL system, so I'm assuming my code runs (exactly) 50 times a second. I've included the color change to occur every 50 frames, but I feel it actually changes quicker than that (so like in 0.8 seconds instead of 1). I've tested in emulation and on real hardware; the behaviour/timing is the same. Can anybody verify this?

I'll need to get this basic timing stuff sorted out, if I ever want to do some seriously swinging copper animations, right..
I've thought about this a bit. At first it seemed to me that this loop should just work at 50FPS and nothing else. But then I realized something.

If your loop takes less than a scanline (this is possible, though more so on faster processors) it could on occasion hit the WaitTOF so quickly it would still be on the correct scanline and return immediately (depending on how WaitTOF is implemented this can be the case). Which would mean some frames might not actually be waited for at all.

Edit: I've checked the documentation (http://amigadev.elowar.com/read/ADCD.../node033B.html) and it seems really unlikely that WaitTOF will trigger more than once per frame.

However, it may still be a cause for timing issues - the copperlist will change the colour at a set time, but the interrupt handlers could take a variable amount of time. This could mean that some of the copper writes are added in too late for the copper to execute them, so they execute a frame late.

Last edited by roondar; 21 July 2017 at 15:14.
roondar is offline  
Old 21 July 2017, 15:33   #3
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Quote:
Originally Posted by roondar View Post
Edit: I've checked the documentation (http://amigadev.elowar.com/read/ADCD.../node033B.html) and it seems really unlikely that WaitTOF will trigger more than once per frame.

However, it may still be a cause for timing issues - the copperlist will change the colour at a set time, but the interrupt handlers could take a variable amount of time. This could mean that some of the copper writes are added in too late for the copper to execute them, so they execute a frame late.
Well I could understand that if a lot of stuff has to be done every frame, but if this simple color change (in the middle of the screen, btw) is already too slow, than there's no way I can do the more fancy stuff I have in mind..
guy lateur is offline  
Old 21 July 2017, 15:40   #4
alkis
Registered User
 
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
Have a look here https://github.com/voitureblanche/projet-secret
alkis is offline  
Old 21 July 2017, 16:07   #5
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Quote:
Originally Posted by alkis View Post
Heh, thanks, but that will be a little much to digest right now. I quickly looked at main.c, and it ends (what I think is) its frame loop with:
Code:
if (faster_machine) WaitTOF();
As my target is a EC030 @ 50 MHz, I'm supposing it counts as a 'faster' machine, in which case the frame loop is the same as mine.

There's also (before the frame loop) this interesting bit:
Code:
if (!faster_machine) OFF_VBLANK;
I've no idea what this does, though, and I can find no other reference to or definition of OFF_VBLANK in the rest of the files. My compiler (vc) for one doesn't like it..
guy lateur is offline  
Old 21 July 2017, 17:25   #6
alkis
Registered User
 
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
It was more like "do you have more fancy stuff in mind than this?" sort of thing.
alkis is offline  
Old 21 July 2017, 17:48   #7
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Quote:
Originally Posted by alkis View Post
It was more like "do you have more fancy stuff in mind than this?" sort of thing.
Oh I see, you cheeky little devil..
No, that kind of thing should probably suffice for now..
guy lateur is offline  
Old 21 July 2017, 21:40   #8
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Ok, here's an update, see attachment. We have a moving copper bar (vertically, along a sine) with a customisable color gradient -- woohoo!

You will notice that I'm including .c files in my main file. I should probably separate that into libs later on, but for now it should do, I thought. Strange thing is though, it seems to work for colorUtil.c (line 18), but not for sineUtil.c, which gives a 'decalaration expected' error. So even if including .c files isn't ideal in the long run, shouldn't it just work in this case?

You'll also notice a lot of unused functionality in colorUtil.c, btw. Just ignore this for now; I'm just testing stuff out. It's my intention to have a variable height for the bar, so that I can make it look '3D', as if spinning around on a circle. The colors themselves will also be animated, at some point, I hope.

If you have any suggestions or remarks about this code, please speak up. I can only learn so much in a day on my own, you know..
Attached Files
File Type: zip sineCopper.zip (11.4 KB, 107 views)
guy lateur is offline  
Old 21 July 2017, 22:04   #9
alkis
Registered User
 
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
You don't include .c
You include .h

What you put in .h?
The prototypes of the functions you have inside the .c

So, create sineUtil.h and colorUtil.h
Put there the prototypes of the functions you need, include them even in their corresponding .c (i.e. in sineUtil.c include sineUtli.h, and in colorUtil.c include colorUtil.h)

Then include them (the *.h only) in sinecopper.c (which is your "main")
(btw, why is the source code of SampleSineWORD in sinecopper.c? Remove it)

I'll do one example of .h

------ start of sineutil.h
#ifndef SINEUTIL_H
#define SINEUTIL_H
#include <exec/types.h>

void SampleSineWORD(WORD * dst, float offset, float amplitude, UWORD nrSamples);
#endif
------- end of sineutil.h

what's the define SINEUTIL_H? https://en.wikipedia.org/wiki/Include_guard
alkis is offline  
Old 21 July 2017, 22:16   #10
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Thanks for clarifying this, alkis, I guess I was a little confused as I assumed this would require extra compilation and linking steps, but I'll probably just need to put the .c files in my make (compile + link). Hang on, I'll give that a go.
Quote:
Originally Posted by alkis View Post
(btw, why is the source code of SampleSineWORD in sinecopper.c? Remove it)
As I said, including the .c didn't work, so..
guy lateur is offline  
Old 21 July 2017, 22:54   #11
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
I've reorganised my code (including a local include/colorUtil.h and src/colorUtil.c), adjusted my makefile to include the extra .c file and to also look for header files in this local directory. It doesn't seem to want to compile though, throwing a 'no declarator and no identifier in prototype' error on the first function definition in colorUtil.c. I'm still doing something wrong, aren't I..
Attached Files
File Type: zip sineCopper.zip (3.8 KB, 89 views)
guy lateur is offline  
Old 22 July 2017, 00:59   #12
alkis
Registered User
 
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
In colorUtil.c you are not including colorUtil.h
Replace #include <math.h> with #include "colorUtil.h"

(the <> is for system includes, "" are used for local includes...just a convention)
alkis is offline  
Old 22 July 2017, 01:11   #13
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Ah crap, I can't believe I missed that.. Thanks again for your help, now it works!
guy lateur is offline  
Old 23 July 2017, 00:30   #14
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Something is not right with my code. ATM, it is supposed to display a pure red bar of 13 lines height, moving from top to bottom and back, following a (precalculated) sine wave. You will notice, however, that it becomes smaller (< 13 lines) when it's moving up, and taller (> 13 lines) when moving down. What?! This is not intended, so something is wrong.

The most obvious thing to consider is that my code to update the copper list is too slow, so the copper reads it (possibly multiple times) while I'm still writing it. But when you think about it, that should give the opposite effect, ie the bar getting smaller when moving down and bigger when moving up. As far as I can see, the only thing that could cause this is my code being too fast (or running too often), so it modifies the list while the copper is still processing it -- and that would probably mean that something's wrong with my frame loop.

As an example, consider the bar moving down. The copper starts reading the current list (starting with the upper bar lines), but I replace the second have of that list with the new copper list (which ends lower down), so the bar would be bigger -- which is what we see. If the copper were faster than me, it would read the beginning of the new list (beginning lower down) and the ending of the old list (stopping higher up) -- so the bar would become smaller, which is not what we see.

Thank you roondar, who has already suggested that my code may be too fast to be good, but how do I solve this? Maybe I could do some easy timing experiments or something? Count to a million here or there?

Code (cleaned up) & exe attached. Note: if you hold the right mouse button, it stops refreshing the copper list, and the bar becomes/stays 13 lines high. This illustrates the problem quite clearly -- and even more so when you lower the animation frame length. At first I thought it was something psycho-visual, you know, but I don't think so..

Just for good measure, here's the frame loop:
Code:
    BOOL cont = TRUE;
    volatile UBYTE *ciaa_pra =         (volatile UBYTE *) 0xbfe001;
    volatile UWORD *someLocation =     (volatile UWORD *) 0xdff016;
    while(cont)        // frame loop
    {
        WaitTOF();
        // ON_VBLANK;
        
        // don't animate/refresh copper if rmb down
        if((*someLocation & RMB_BIT) != 0)
        {
            iAnim += 1;
            if(iAnim >= nrAnimFrames) iAnim = 0;
            centerY = sineTable[iAnim];
            calcCopListLinesY(linesY, centerY);
            refreshCopList(linesY, colors);
        }
        
        if((*ciaa_pra & PRA_FIR0_BIT) == 0) cont = FALSE;
    }
TIA for any tips!
Attached Files
File Type: zip sineCopper.zip (13.4 KB, 96 views)
guy lateur is offline  
Old 23 July 2017, 19:09   #15
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Ok, I'm not 100% sure how, but I got it working as expected, see attached. The major ingredient seems to be the allocation of an extra buffer copper list. You calculate your next copper list in this buffer, and then, at just the right time, point the copper to this buffer. This requires double the amount of chip memory, of course, but I guess I can live with that for now. Here's the new frame loop:
Code:
    while(cont)        // frame loop
    {
        // don't animate/refresh copper if rmb down
        if((*someLocation & RMB_BIT) != 0)
        {
            iAnim += 1;
            if(iAnim >= nrAnimFrames) iAnim = 0;
            centerY = sineTable[iAnim];
            calcCopListLinesY(linesY, centerY);
            
            if(currCopList == copList1) currCopList = copList2;
            else currCopList = copList1;
            refreshCopList(currCopList, linesY, colors);
        }
        
        // ?? don't swap the following 2 lines ?? how does WaitTOF() work, again ??
        custom.cop1lc = (ULONG) currCopList;
        WaitTOF();
        
        if((*ciaa_pra & PRA_FIR0_BIT) == 0) cont = FALSE;            // quit when lmb pressed
    }
Although I can imagine that writing to the current copper list, while not knowing when the copper will be reading it, may be a bad idea, I probably still don't understand how the WaitTOF() function works. I thought it meant 'you should start your work on the copper list now, and you better be ready when I'll be reading it'. So the WaitTOF() comes first. Apparently, even with the buffering, this is not how to interpret it. If you swap lines 116 & 117, you'll get the old/wrong behaviour back. I don't understand why this order is the correct order, tbh.

Anyway, I'm very happy to have it behave correctly, so I can move on to those spectacular effects I have in mind! If anybody could shed some more light on this frame loop thing, though, I'd be even happier!
Attached Files
File Type: zip sineCopper.zip (13.4 KB, 101 views)
guy lateur is offline  
Old 23 July 2017, 23:57   #16
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,409
Quote:
Originally Posted by guy lateur View Post
Well I could understand that if a lot of stuff has to be done every frame, but if this simple color change (in the middle of the screen, btw) is already too slow, than there's no way I can do the more fancy stuff I have in mind..
Ah, I didn't really mean your code was slow or that it couldn't be done.

What I meant was that when the system is running, you can't quite predict at what time during the frame your Copper update would run because the WaitEOF adds your task to the vertical blank interrupt service. Which may or may not be interupted by other interrupts or may or may not have a lot of tasks in it for that particular frame.

You can probably circumvent that problem (if it is actually a problem) by increasing the priority of your task a bit.

Though it did later occur to me that 0.8 seconds for 50 frames is almost exactly what you'd get if you where running a 60Hz display.

Anyway, it seems you got that bit working now so have fun making Copper effects
roondar is offline  
Old 24 July 2017, 14:24   #17
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Quote:
Originally Posted by roondar View Post
What I meant was that when the system is running, you can't quite predict at what time during the frame your Copper update would run because the WaitEOF adds your task to the vertical blank interrupt service. Which may or may not be interupted by other interrupts or may or may not have a lot of tasks in it for that particular frame.
You can probably circumvent that problem (if it is actually a problem) by increasing the priority of your task a bit.
Well it's still slowly beginning to dawn on me how all this stuff fits together, really, especially the interrupt stuff, which I don't know anything about yet. I do remember that Photon has an entire episode on 'turning off the system', and IIRC this involves those interrupts. Maybe I should give that another look.

As for the priority: it's my demo, for crying out loud, so it should always have the highest priority imaginable!

On a side note: I've noticed that when you press RMB to pause the animation, when the program exits, a popup menu is open on the shell I started it from, so this shell also processed this event. I'd say this is actually good news, but not really desired in this case. So I should probably open my own screen or something?

Quote:
Originally Posted by roondar View Post
Anyway, it seems you got that bit working now so have fun making Copper effects
Off I go, happy as a child..
guy lateur is offline  
Old 25 July 2017, 13:00   #18
hooverphonique
ex. demoscener "Bigmama"
 
Join Date: Jun 2012
Location: Fyn / Denmark
Posts: 1,624
Quote:
Originally Posted by guy lateur View Post
On a side note: I've noticed that when you press RMB to pause the animation, when the program exits, a popup menu is open on the shell I started it from, so this shell also processed this event. I'd say this is actually good news, but not really desired in this case. So I should probably open my own screen or something?
A screen cannot capture input, but a window can, however. Otherwise, I think you can use input.device to capture input (mouse/keyboard) for yourself - I've never bothered with that in my demos/intros, though...
hooverphonique is offline  
Old 25 July 2017, 22:33   #19
roondar
Registered User
 
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,409
Quote:
Originally Posted by guy lateur View Post
Well it's still slowly beginning to dawn on me how all this stuff fits together, really, especially the interrupt stuff, which I don't know anything about yet. I do remember that Photon has an entire episode on 'turning off the system', and IIRC this involves those interrupts. Maybe I should give that another look.
You can indeed disable all interrupts and that does prevent the OS from doing anything at all. Do note however that WaitTOF(), WaitBlitter(), disk IO and pretty much all other Wait() or signal response type functions the OS provides only work when the correct interrupts are available and if used while interrupts are disabled they may either hang or re-enable interrupts, neither of which is what you want.

My personal view these days is that you either use the OS (to do timing, IO, input, etc) or you don't use the OS at all. Manually disabling interrupts can have detrimental effects on system stability, especially so the system has a 3rd party harddisk controller or any form of network card.

That said, it is possible to selectively switch the OS on and off. However, if you wish the OS to stay on... You can change the priority instead and only use OS supported functions to dabble with interrupts (meaning no Forbid()/Permit() and no manual interrupt vectors except through Exec)

Quote:
As for the priority: it's my demo, for crying out loud, so it should always have the highest priority imaginable!
Well, that is possible, just use SetTaskPri() with a value of 127, which is the highest possible. Do note that doing so can cause IO requests and other OS activity to stall while waiting on your task as it pretty much is the only thing running.

Usually a priority of 5 or 10 is plenty.

Anyway, even when using a high priority Wait() functions of any type will return to the OS at least temporarily. However, since your task priority is high, your task will get a slot ahead of pretty much everything else.

Last edited by roondar; 25 July 2017 at 22:44. Reason: Grammar update ;)
roondar is offline  
Old 25 July 2017, 22:39   #20
guy lateur
Registered User
 
guy lateur's Avatar
 
Join Date: May 2017
Location: Belgium
Age: 50
Posts: 334
Here's another update. It has the '3D' effect, a customisable gradient (and ellipsoid path) for the bar, a fov for the camera and so on.

It still has some hard coded screen/view/whatever parameters, though, like lineTop/Bottom and such. I should probably get that from the system/screen/.. I'd also like it to go beyond line 255, someday, btw..

I'm not complaining, though, everything's still working as expected, for now..
Attached Files
File Type: zip sineCopper.zip (20.6 KB, 101 views)
guy lateur is offline  
 


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools

Similar Threads
Thread Thread Starter Forum Replies Last Post
Combining copper scrolling with copper background phx Coders. Asm / Hardware 16 13 February 2021 12:41
Best way to mix blitting with copper and copper effects roondar Coders. Asm / Hardware 3 12 September 2016 13:12
copper ? turrican3 Coders. Asm / Hardware 10 27 January 2016 09:10
Blitter using the copper... h0ffman Coders. Asm / Hardware 9 23 February 2012 08:25
Understanding the Copper BippyM Coders. Tutorials 38 04 September 2010 12:18

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 09:45.

Top

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Page generated in 0.39740 seconds with 16 queries