Author |
Message |
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2095 Location: Canada
|
I figured out the top-left corner thing and now graphics display as they should. I added point plot capability to the accelerator as the test system has to deal with pixels not aligned on byte boundaries. For the original core plotting individual pixels was done faster using the processor's regular load and store operations. However, with bit aligned data involving divides and shifts to plot pixels this is not the case. Quote: If the the original orgfx core used pixels not packed on bit boundaries, were there unused bits, then, used as padding to reach a byte boundary? The original core supported only 8,16, or 32 bit pixel color depths (actually only 16 bits was supported fully), so everything was nicely evenly aligned on byte boundaries with no "wasted" bits. That made addressing the pixels simple. That also made it possible for the core to use write-only memory cycles. A couple of nice features. I felt this was too restrictive so I altered the core to be more elaborate. A number of smaller less expensive devices have limited memory and display capability. I have for instance an LCD display with 9 bits per pixel color depth. Using 16 bits of memory to store a pixel would be almost 50% wasted. By packing 14 pixels into 128 bits the amount of memory "wasted" is reduced to 1.6%. Quote: And can you elaborate on the divisor factor, please?
The screen resolution of the WXGA screen (1366x768 for instance) is divided down into a lower resolution by assigning multiple clock ticks and multiple scan lines to each displayed pixel. The color information for the pixel is simply repeated for each tick within the pixel so the display resolution appears to be reduced, although the actual display timing hasn't changed. There is a pair of horizontal and vertical pixel size counters in the display circuit that do this. These two counters have programmable max counts. By setting the max count to 3 for instance, three clock ticks are required to pass before the pixel column is incremented. The counters are independently programmable with allowed max counts from 1 to 7. The display circuit addresses memory based on the pixel row and column (not the vertical/horizontal counters). When there are more than one scanline per pixel, the display circuit reads memory only during the first scanline, and remembers (caches) the pixels for displaying on subsequent scan lines. Using a lower resolution reduces the memory bandwidth required to display a screen. It's the peak memory bandwidth required for horizontal display that limits the display resolution. Since the horizontal display is divided down, it's also made available to the vertical display so that pixels are more symmetrical. One could in theory have a 340x768 screen but it just seems to make more sense to set it to 340x256. For the test system, because of memory bandwidth limitations the max resolution is 680x768x6 bpp. I tried 680x8bpp but it didn't work. In theory full resolution could be supported (1344x768x3bpp) but only at 3 bits per pixel. I'm using the display on the Nexy4 board which has 12 bpp max. color depth. In the past I've used boards with 6,8, and 9 bits color depth. It would waste a fair amount of memory (25%) to use 16bpp pixels.
_________________Robert Finch http://www.finitron.ca
|
Fri May 08, 2015 2:51 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
Cray Ze
Joined: Fri May 08, 2015 6:22 pm Posts: 61
|
robfinch wrote: The screen resolution of the WXGA screen (1366x768 for instance) is divided down into a lower resolution by assigning multiple clock ticks and multiple scan lines to each displayed pixel. The color information for the pixel is simply repeated for each tick within the pixel so the display resolution appears to be reduced, although the actual display timing hasn't changed. There is a pair of horizontal and vertical pixel size counters in the display circuit that do this. These two counters have programmable max counts. By setting the max count to 3 for instance, three clock ticks are required to pass before the pixel column is incremented. The counters are independently programmable with allowed max counts from 1 to 7. The display circuit addresses memory based on the pixel row and column (not the vertical/horizontal counters). When there are more than one scanline per pixel, the display circuit reads memory only during the first scanline, and remembers (caches) the pixels for displaying on subsequent scan lines. Using a lower resolution reduces the memory bandwidth required to display a screen. It's the peak memory bandwidth required for horizontal display that limits the display resolution. Since the horizontal display is divided down, it's also made available to the vertical display so that pixels are more symmetrical. One could in theory have a 340x768 screen but it just seems to make more sense to set it to 340x256. For the test system, because of memory bandwidth limitations the max resolution is 680x768x6 bpp. I tried 680x8bpp but it didn't work. In theory full resolution could be supported (1344x768x3bpp) but only at 3 bits per pixel. I'm using the display on the Nexy4 board which has 12 bpp max. color depth. In the past I've used boards with 6,8, and 9 bits color depth. It would waste a fair amount of memory (25%) to use 16bpp pixels. Hi Rob, Dr Jefyll mentioned you had an interesting project taking form over here. Another way of scaling could be to pass your pixel row and column data through a 2D matrix transformation, giving the freedom to scale any resolution to any display size. You'd get the added bonus of being able to flip the screen or even rotate it. Basically just a handfull of adders. Scale pixels to parsecs ![Smile :)](./images/smilies/icon_e_smile.gif) I currently don't have a verilog example, I'll try to put something together (need to unbury my FPGA boards first). I do have some simple code in VHDL though if it's of interest. In it's current form it runs from the vertical/horizontal counters but may still be useful.
|
Fri May 08, 2015 7:17 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2095 Location: Canada
|
Hi Cray Ze, that code would be of interest. Quote: I do have some simple code in VHDL though if it's of interest. In it's current form it runs from the vertical/horizontal counters but may still be useful. The C64 compiler has been modified to support passing structures and arrays to functions. Previously it only accepted pointers to arrays or structures. While it's generally a bad idea to pass structures or arrays as values on the stack, it is sometimes done. The compiler still doesn't return structure variables as anything other than pointers however. To implement structure and array passing the compiler has to generate calls to the memcpy() routine while passing parameters; passing a structure or array forces the function to be a non-leaf function as memcpy() is called implicitly. The problem with returning a structure or array is that the compiler has to be able to allocate temporary storage for the return value. This could be an implicit call to malloc() or a statically allocated buffer. As I haven't actually got memory management functionality on the target system yet, I've put off modifying the compiler to return structures. A consequence is that some of the orgfx graphics library functions need to be modified to return pointers to structures rather than structures themselves. My simple graphics demo program hangs after about 10 to 15 minutes of displaying graphics. I don't know why yet, but I'm guessing it's a hardware bug in the graphics accelerator. The accelerator has been modified to support having a core clock rate different than the memory bus rate. The core uses a system of ack's and nack's between the different clock domains. In this case the memory bus rate is faster than the core clock rate.
_________________Robert Finch http://www.finitron.ca
|
Sat May 09, 2015 11:49 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
Cray Ze
Joined: Fri May 08, 2015 6:22 pm Posts: 61
|
robfinch wrote: Hi Cray Ze, that code would be of interest. Quote: I do have some simple code in VHDL though if it's of interest. In it's current form it runs from the vertical/horizontal counters but may still be useful. Just looking at a section of code in rtfBitmapController1364x768.v that might be a good place. It might just be a case of feeding vctr1 and hctr1 into the matrix and setting pixelRow and pixelCol from the output of the matrix (X0 and Y0 in my VHDL example). Looking at this section of code: Code: // Pixel row and column are derived from the horizontal and vertical counts. always @(vctr1) pixelRow = vctr1[11:0]; always @(hctr1) case(hres) 2'b00: pixelCol = hctr1[11:0]; 2'b01: pixelCol = hctr1[11:1]; 2'b10: pixelCol = hctr1[11:2]; default: pixelCol = hctr1[11:2]; endcase VHDL example (with a huge matrix, you really won't need 16 bits). I've just clipped this out of some code I wrote a while back and changed a few names to match your code. This will take vctr1 and hctr1 into the transformation. Then set pixelRow and pixelCol from Y0 and X0 instead of from vctr1 and hctr1. eg. (I changed the range a bit otherwise your screen image would be smaller than a pixel). pixelRow = Y0[15:4]; pixelCol = X0[15:4]; Code: signal X0, X1, Y0, Y1 : unsigned(15 downto 0):="0000000000000000"; -- 16bit 65536 x 65536 matrix
Matrix: process (vclk, reset)
begin if (rising_edge(vclk)) then
-- Matrix Transformation if vctr1 = 0 then X0 <= "0000000000000000"; Y0 <= "0000000000000000"; X1 <= "0000000000000000"; Y1 <= "0000000000000000"; elsif hctr1 = 0 then X0 <= X1 - 65280; Y0 <= Y1 + 65280; X1 <= X1 - 65280; Y1 <= Y1 + 65280; else X0 <= X0 + 65280; Y0 <= Y0 + 65280; end if;
end if; end process; The magic is in the add & subtracts, altering the steppings will give whatever scaling factor you need. The number can be expanded into trig functions to get a propper rotozoom but we don't need that here, which simplifys things. Changing all the steps, but keeping them the same size as each other will change the scale of the displayed image on screen. It is possible that I've misinterpreted something in your verilog and am off track here, I'm a little rusty and Verilog was never one of my strong points. Ok, so it's slightly more than a handfull of adders. EDIT: Actually, I think this will prevent burst mode access to RAM so it's not really what you want.
|
Sat May 09, 2015 1:27 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2095 Location: Canada
|
Hey thanks, that's a good piece of code. I think I get how it works, similar to a harmonic frequency synthesizer (DDS?). I'm very tempted to use the code. Do you have to worry about jitter in the pixel size ? I would think with smaller pixel sizes there might be an effect of the pixel size varying by one depending on the scaling factor. I had not thought much about the screen size. What if one had a 4000+ pixels screen ? Quote: EDIT: Actually, I think this will prevent burst mode access to RAM so it's not really what you want. It should work fine with burst mode provided it's okay to start the burst for the scanline at the horizontal reset. As long as the burst fill can stay ahead of the readback it should work. With the latest bitmap controller (rftBitmapController3 - there's a #4 version now), it uses pixel width, height counters to allow a better range of pixel sizes, it doesn't pull from the horizontal / vertical count. The controller also doesn't use burst mode anymore. It reads 128 bits at a time using a normal read cycle. Shown below is pixel sizing code in the horizontal, vertical works the same way. pe_hsync is the positive edge of the horizontal sync pulse. hres is divisor factor (1 to 7) hrefdelay determines when pixels appear on the screen (pixelCol must be positive for pixels to display, it starts out negative the reference delay). Code: reg [3:0] hc; always @(posedge vclk) if (rst_i) hc <= 4'd1; else if (pe_hsync) begin hc <= 4'd1; pixelCol <= -hrefdelay; end else begin if (hc==hres) begin hc <= 4'd1; pixelCol <= pixelCol + 1; end else hc <= hc + 4'd1; end
_________________Robert Finch http://www.finitron.ca
|
Sat May 09, 2015 8:03 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
Cray Ze
Joined: Fri May 08, 2015 6:22 pm Posts: 61
|
robfinch wrote: Hey thanks, that's a good piece of code. I think I get how it works, similar to a harmonic frequency synthesizer (DDS?). I'm very tempted to use the code. Do you have to worry about jitter in the pixel size ? I would think with smaller pixel sizes there might be an effect of the pixel size varying by one depending on the scaling factor. I had not thought much about the screen size. What if one had a 4000+ pixels screen ?
I can't take credit for the code, a search result jiggled my memory a little, the original source of that snippit of code was some verilog on fpga4fun.com. http://www.fpga4fun.com/GraphicLCDpanel3.htmlI hadn't thought of it in relation to a DDS, I guess it looks a bit like a phase accumulator though it is different. Jitter, it depends what you call jitter, expanding a 640x480 display to 800x600 will give you some larger and smaller pixels in the same way a 640x480 signal gets displayed fullscreen on an 800x600 native LCD panel. The size of any indevidual displayed pixel will remain stable though. Scalling can work either way, scaling up to 4000+ would work, with the 16bits in the example you can scale up to 65536x65536 if you had the screen. I was running it the other way around, it's useful for scaling huge plots of mathematical functions down to view on the screen. I was playing with a res of 2 parsecs x 2 parsecs at one point. In effect, the transformation function gives you a window into an enormous virtual space, a bit like a playing card tossed onto a football field, only, in this case, you can scale the card. A practical example: You have a peice of code that's not playing nice with your CPU design. You hit a special hot key and the display shrinks ( animated for effect ![Wink ;)](./images/smilies/icon_e_wink.gif) ) up to the top left quarter of the screen, under the display you see a HEX display of memory and on the right half of the screen a mnemonic display of the current instruction stream, you're in single step mode, press space. While you might have your normal ram-backed display in one part of the virtual space, you can use other parts of the space for hardware based per pixel (non ram-backed) functions or blockram based image data. robfinch wrote: It should work fine with burst mode provided it's okay to start the burst for the scanline at the horizontal reset. As long as the burst fill can stay ahead of the readback it should work. With the latest bitmap controller (rftBitmapController3 - there's a #4 version now), it uses pixel width, height counters to allow a better range of pixel sizes, it doesn't pull from the horizontal / vertical count. The controller also doesn't use burst mode anymore. It reads 128 bits at a time using a normal read cycle. Shown below is pixel sizing code in the horizontal, vertical works the same way. pe_hsync is the positive edge of the horizontal sync pulse. hres is divisor factor (1 to 7) hrefdelay determines when pixels appear on the screen (pixelCol must be positive for pixels to display, it starts out negative the reference delay). Code: reg [3:0] hc; always @(posedge vclk) if (rst_i) hc <= 4'd1; else if (pe_hsync) begin hc <= 4'd1; pixelCol <= -hrefdelay; end else begin if (hc==hres) begin hc <= 4'd1; pixelCol <= pixelCol + 1; end else hc <= hc + 4'd1; end
The reason I think burst would have been unusable was because even an expansion from 640x480 to 800x600, not rotated, would give you some of those double width pixels requiring accessing the same memory twice, and while you probably wouldn't use it in this case, rotation would be a problem as memory space would be accessed diagonally, which doesn't fit well with 128 bit reads either. I'll have a look at the more recent code and see if I can spot any way around it. Your curent method, while not as freeform, is probably the sane option, it's certainly alot easier on the RAM access. The Matrix output X0,Y0 is always positive referenced to the top left of screen.
|
Sun May 10, 2015 12:32 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
Cray Ze
Joined: Fri May 08, 2015 6:22 pm Posts: 61
|
While I'm not sure if the memory will keep up, what happens if you do something like this. Replace pixelCol and pixelRow with realpixelCol and realpixelRow in these sections as such. Code: reg [3:0] hc; always @(posedge vclk) if (rst_i) hc <= 4'd1; else if (pe_hsync) begin hc <= 4'd1; realpixelCol <= -hrefdelay; end else begin if (hc==hres) begin hc <= 4'd1; realpixelCol <= realpixelCol + 1; end else hc <= hc + 4'd1; end reg [3:0] vc; always @(posedge vclk) if (rst_i) vc <= 4'd1; else if (pe_vsync) begin vc <= 4'd1; realpixelRow <= -vrefdelay; end else begin if (pe_hsync) begin vc <= vc + 4'd1; if (vc==vres) begin vc <= 4'd1; realpixelRow <= realpixelRow + 1; end end end And then add in something like this, internal block is still untranslated from VHDL. Might want to reduce all the 65280's, the display might end up the size of a pixel otherwise. Code: always @(posedge vclk) if (rst_i)
-- Matrix Transformation - This block still in VHDL. if pixelRow = 0 then X0 <= "0000000000000000"; Y0 <= "0000000000000000"; X1 <= "0000000000000000"; Y1 <= "0000000000000000"; elsif pixelCol = 0 then X0 <= X1 - 65280; Y0 <= Y1 + 65280; X1 <= X1 - 65280; Y1 <= Y1 + 65280; else X0 <= X0 + 65280; Y0 <= Y0 + 65280; end if;
pixelCol <= X0; pixelRow <= Y0;
end
|
Sun May 10, 2015 4:17 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2095 Location: Canada
|
Ok, so I wasn't following the idea properly. I would need to see more of the code to really understand. I thought your original reference to parsecs was a jest as a parsec is quite large. But I gather there's a display window into a parsecs sized mathematical field. I wonder wouldn't one need to scale with multiplications and divisions as opposed to add/subtract in the transform function ? The following lines of code have me a little confused yet (but perhaps they need more context). Code: else X0 <= X0 + 65280; Y0 <= Y0 + 65280; end if;
It looks like this would give a diagonal of some sort if both X and Y are incremented at the same time. Having the screen zoom in and out is a neat idea. The screen could be made to shrink by displaying every 2nd, 3rd, or 4 th pixel etc. But running the display through a transform including color might give better results. Quote: You have a peice of code that's not playing nice with your CPU design. You hit a special hot key and the display shrinks ( animated for effect ![Wink ;)](./images/smilies/icon_e_wink.gif) ) up to the top left quarter of the screen, under the display you see a HEX display of memory and on the right half of the screen a mnemonic display of the current instruction stream, you're in single step mode, press space. What system have you seen this on ? I have a text mode display using block ram resources that displays at the same time as the bitmapped display (ontop of the bitmap display). I could almost set that up as you suggest.
_________________Robert Finch http://www.finitron.ca
|
Sun May 10, 2015 10:46 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
Cray Ze
Joined: Fri May 08, 2015 6:22 pm Posts: 61
|
robfinch wrote: Ok, so I wasn't following the idea properly. I would need to see more of the code to really understand. I thought your original reference to parsecs was a jest as a parsec is quite large. But I gather there's a display window into a parsecs sized mathematical field. I wonder wouldn't one need to scale with multiplications and divisions as opposed to add/subtract in the transform function ?
That's it exactly, a window onto a mathematical plane, onto wich anything can be ploted, either mathematically (at the expense of FPGA resources) or from bitmap data in fast memory. No multiplications and divisions are involved, that's the beauty of it. Another plus is that we're only really doing anything for pixels in the visible window. robfinch wrote: The following lines of code have me a little confused yet (but perhaps they need more context). Code: else X0 <= X0 + 65280; Y0 <= Y0 + 65280; end if;
It looks like this would give a diagonal of some sort if both X and Y are incremented at the same time. Having the screen zoom in and out is a neat idea. The screen could be made to shrink by displaying every 2nd, 3rd, or 4 th pixel etc. But running the display through a transform including color might give better results. The two additions are correct, though I agree that it looks odd. The numbers expand to a mix of 'sine of the angle x scale factor' and 'cosine of the angle x scale factor'. By just using identical values, the cos and sin cancel each other out, locking the rotation at 0 degrees, leaving just the scaling factor. robfinch wrote: Quote: You have a peice of code that's not playing nice with your CPU design. You hit a special hot key and the display shrinks ( animated for effect ![Wink ;)](./images/smilies/icon_e_wink.gif) ) up to the top left quarter of the screen, under the display you see a HEX display of memory and on the right half of the screen a mnemonic display of the current instruction stream, you're in single step mode, press space. What system have you seen this on ? I have a text mode display using block ram resources that displays at the same time as the bitmapped display (ontop of the bitmap display). I could almost set that up as you suggest. I haven't seen it anywhere but was thinking of implementing it with one of the 6502 cores, just seems like something that would be nice to have. I've also got some text to screen plotting code, though I wrote it initially when playing with CPLD's so no blockram, just an array of defines forming a small ROM with hardware. Part of my decimal number display, this puts a single 8x8 character on the display. Code: if CharMap(to_integer(Hundreds))(to_integer(not pixelv(2 downto 0)¬ pixelh(2 downto 0)))='1' then Cyan_Pixel <='1'; end if; You can find a better explaination of the transform stuff at these links, though some of them may as well be written in an alien language. My mind ends up twisted into a pretzel trying to follow some of it. https://mzsolt.wordpress.com/2007/09/07/rotozoom/https://www.siggraph.org/education/mate ... 2drota.htmhttp://en.wikipedia.org/wiki/Rotation_matrixhttp://en.wikipedia.org/wiki/Transformation_matrixSome C code here: http://www.pygame.org/pcr/rotozoom/Original in french (linked via google translate) http://translate.google.com.au/translat ... rev=search
|
Sun May 10, 2015 1:02 pm |
|
![](./styles/serenity/theme/images/spacer.gif) |
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2095 Location: Canada
|
After studying roto-zoom for a bit, I decided to try moving the bitmap controller back to using pixel positions calculated from horizontal and vertical timing counters. But this time rather than using a multiplex and shift on the counts, fixed point multiplies take place. This is a step closer to roto-zoom capability - this gives the screen limited zoom capability. The problem with roto-zoom for this system is the memory bandwidth requirements. Essentially random access to individual pixels is required to implement roto-zoom. Roto-zoom may be achievable using the FPGA block ram resources rather than the DDR ram. The FPGA in use does have about 512kB block ram, and a low res screen (340x256x12bpp) would only require about 128kB. (680x384x8bpp) would require 256kB. The following code calculates the pixel row and column from display timing counters. Code: always @(posedge vclk) if (rst_i) hctr <= 4'd1; else if (pe_hsync) hctr <= hFlip ? hDisplayed : 4'd1; else hctr <= hFlip ? hctr - 4'd1 : hctr + 4'd1;
always @(posedge vclk) if (rst_i) vctr <= 4'd1; else if (pe_vsync) vctr <= vFlip ? vDisplayed : 4'd1; else if (pe_hsync) vctr <= vFlip ? vctr - 4'd1 : vctr + 4'd1;
// hScale and vScale are 24 bit fixed point numbers with 12 bits on each side // of the decimal point. wire signed [27:0] pixelC = $signed(hctr1) * hScale; wire [15:0] pixelCol = pixelC[27:12]; wire signed [27:0] pixelR = $signed(vctr1) * vScale; wire [15:0] pixelRow = pixelR[27:12]; reg [15:0] opixelCol; always @(posedge vclk) opixelCol <= pixelCol;
The scaling factors are currently initialized thus: Code: hScale <= 24'b0_010000000000; // 1/4 display vScale <= 24'b0_010101010101; // 1/3 display
The plan is to grow the bitmap controller into something with roto-zoom capability using step-wise refinements to the controller. It's just too cool an effect to pass up.
_________________Robert Finch http://www.finitron.ca
|
Tue May 12, 2015 3:23 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
Cray Ze
Joined: Fri May 08, 2015 6:22 pm Posts: 61
|
robfinch wrote: After studying roto-zoom for a bit, I decided to try moving the bitmap controller back to using pixel positions calculated from horizontal and vertical timing counters. But this time rather than using a multiplex and shift on the counts, fixed point multiplies take place. This is a step closer to roto-zoom capability - this gives the screen limited zoom capability. The problem with roto-zoom for this system is the memory bandwidth requirements. Essentially random access to individual pixels is required to implement roto-zoom. Roto-zoom may be achievable using the FPGA block ram resources rather than the DDR ram. The FPGA in use does have about 512kB block ram, and a low res screen (340x256x12bpp) would only require about 128kB. (680x384x8bpp) would require 256kB. The following code calculates the pixel row and column from display timing counters. Code: always @(posedge vclk) if (rst_i) hctr <= 4'd1; else if (pe_hsync) hctr <= hFlip ? hDisplayed : 4'd1; else hctr <= hFlip ? hctr - 4'd1 : hctr + 4'd1;
always @(posedge vclk) if (rst_i) vctr <= 4'd1; else if (pe_vsync) vctr <= vFlip ? vDisplayed : 4'd1; else if (pe_hsync) vctr <= vFlip ? vctr - 4'd1 : vctr + 4'd1;
// hScale and vScale are 24 bit fixed point numbers with 12 bits on each side // of the decimal point. wire signed [27:0] pixelC = $signed(hctr1) * hScale; wire [15:0] pixelCol = pixelC[27:12]; wire signed [27:0] pixelR = $signed(vctr1) * vScale; wire [15:0] pixelRow = pixelR[27:12]; reg [15:0] opixelCol; always @(posedge vclk) opixelCol <= pixelCol;
Linear scaling is certainly alot easier on the memory access. You could probably use the lower bits of pixelR to determine the mode of the line buffer, 'repeat line' or 'new line'. robfinch wrote: The scaling factors are currently initialized thus: Code: hScale <= 24'b0_010000000000; // 1/4 display vScale <= 24'b0_010101010101; // 1/3 display
An interesting feature for a bitmap controller could be to have the ability of applying different scaling attributes to different rectangular sections of the screen. It would be nice for applications such as font and bitmap editing, retro system and arcade emulators, etc. It would both simplify the application code and provide more memory bandwidth when drawing low res areas or the screen. It would however complicate the linebuffer by needing to track if the scaling on a line has changed from the last. robfinch wrote: The plan is to grow the bitmap controller into something with roto-zoom capability using step-wise refinements to the controller. It's just too cool an effect to pass up. Rotozoom is certainly a cool effect, though the rotation side of it has limited application as opposed to scaling. One application where the rotation could be nice is in hand held devices, currently a change in orientation causes a pause then a flip. By tracking X,Y and rotation with the devices accelerometer, the image would remain steady throughout rotation, and also be easy to read in bumpy, jiggly environments. What about sprites, scalable roto-sprites could be a very cool idea, saving lots of spritemap data (or lots of sprite rotation and scale code). I wonder how hard it would be to give sprites a forward, back, left, right motion control based on angle of rotation as opposed to the usual absolute possitioning.
|
Tue May 12, 2015 7:07 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
Cray Ze
Joined: Fri May 08, 2015 6:22 pm Posts: 61
|
I finally unburied some FPGA boards. I had a little play. https://www.youtube.com/watch?v=RLm2oiaGVYIWhat's your plan for circles?
|
Thu May 14, 2015 12:45 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2095 Location: Canada
|
Quote: An interesting feature for a bitmap controller could be to have the ability of applying different scaling attributes to different rectangular sections of the screen. It would be nice for applications such as font and bitmap editing, retro system and arcade emulators, etc. It would both simplify the application code and provide more memory bandwidth when drawing low res areas or the screen. It would however complicate the linebuffer by needing to track if the scaling on a line has changed from the last.
One way to implement it would be to have multiple bitmap controllers, which store the bitmap in their own private block RAM. This would keep the buffering simple. Assuming secondary bitmaps are low res it might not take up that much block ram. 32X32 cell bitmap to edit a bitmap font for instance takes only 1024 words of block RAM. The control logic for a bitmap controller isn't that large so having several controllers probably isn't a problem. I finally got the roto-zoom code completed for the bitmap controller. But it doesn't work that well (it's buggy yet). The first test, displaying the screen at a rotation of zero degrees, caused the screen display to drop about 50 scanlines downwards for some reason. An screen garbage was present along the left side of the screen. Rather than debug the code I'm going to leave the rorozoom code in as a `ifdef block and leave the debugging for another day. Quote: What about sprites, scalable roto-sprites could be a very cool idea, saving lots of spritemap data (or lots of sprite rotation and scale code). I wonder how hard it would be to give sprites a forward, back, left, right motion control based on angle of rotation as opposed to the usual absolute possitioning. It would probably be a lot of logic to have scalable roto-sprites implemented to work in real-time. All those multiplies and sin lookups would have to be done for each sprite. The spritecontroller as it is, allows for multiple images to be fed into the sprite's buffer. Which can then be accessed by updating an image pointer. The idea was to allow some simple animations to be performed simply by changing the image pointer. The multiple sprite images stored could be a single image which is precalculated to different rotations. As for the sprite positioning maybe a processor instruction that supports the movement along an angle could be used. Fed into the instruction would be distance and angle of motion and output would be dx, and dy. This is really almost a polar to Cartesian co-ordinate translation instruction.
_________________Robert Finch http://www.finitron.ca
|
Thu May 14, 2015 1:12 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
robfinch
Joined: Sat Feb 02, 2013 9:40 am Posts: 2095 Location: Canada
|
Quote: What's your plan for circles? No plan. I was wondering about that and other shapes not supported by orgfx. It is possible to draw Bezier curves with orgfx. I think by combining two curves properly one could draw a circle. I'd also like to be able to draw arbitrary polygons, I have a piece of software code to draw filled polygons, and have been studying what it would take to do in hardware. With a development board with 12 bit RGB output is it possible to output more than 4096 colors ? I think that maybe the least significant bit of each color component could be pulse-width modulated at high frequency to generate an additional bit(s). PWM can't be applied to more significant bits as it would result in repeated bit values, but the LSB could be modulated. The pixel clock in use is about 42 MHz. Using a 4x or more clock (168MHz) a pulse stream could be sent on the LSB for each desired color. '1111' would be full on, '0000' would be full off. But one could also send '1010' 1/2 power or '1000' 1/4 power or '1110' 3/4 power for the LSB. Using fractional amounts of power an additional bit could be generated. The problem with this approach is relying on the DAC's R's and C's time constant to generate fractional signal levels. The time constant may make the required frequency too high to be practical. On the other hand the development board could be modified to support it.
_________________Robert Finch http://www.finitron.ca
|
Sat May 16, 2015 4:18 am |
|
![](./styles/serenity/theme/images/spacer.gif) |
BigEd
Joined: Wed Jan 09, 2013 6:54 pm Posts: 1783
|
I'm not sure modern displays would play well with that idea - I think they digitise their inputs, sampling on their locally-generated pixel clock. But you might be able to do it by (automatically) dithering the LSB field by field. Or line by line, if you are line doubling on the generation side.
|
Sat May 16, 2015 4:30 am |
|
|
Who is online |
Users browsing this forum: No registered users and 113 guests |
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum
|
|