Author Topic: [REDUCED RES] Xal's Framework (not an entry...)  (Read 4818 times)

0 Members and 1 Guest are viewing this topic.

Offline Xalthorn

  • Amiga 1200
  • ****
  • Posts: 331
  • Karma: 100
    • View Profile
I've put [REDUCED RES] in the subject so it can be found easily and stays with the entrants, however its obviously not an actual entry :D

I said I'd throw this out to people once the compo had closed, so here it is.  I put a lot of comments through the code but I'll briefly explain what it does as well.  If it doesn't make sense, or I've just confused the issue, let me know and I'll try to explain what I was doing.

Okay, we have a 160x120 display area to draw on, but this drawing area is placed in the centre of a full sized buffer.  It means that if we want to draw something that won't quite fit onto the drawing area, it can overflow without causing memory crashes or give unsightly X-wrapping as it flows to the next line.  There is a dot(x,y,colour) function that handles this tidily for us.

We draw in shades of blue (or grey if you like, but only the blue portion is used) as all we're interested in is a single value from 0-192 (193-255 are pointless as they are the same as 192).  This actually makes some routines easier as we don't have to prepare a full colour code, we can take a single byte value and throw it at the drawing area.

Once we've finished drawing our stuff, three routines take over.  The first one, dither_screen() takes our 0-192 values and turns them into 0-3 values with appropriate dithering patterns.

After that is done, four_colour_screen() converts these 0-3 values into the appropriate rgb() value as determined by our preset colours C1, C2, C3, and C4.

Finally, buffer_convert() takes our little 160x120 drawing area and throws it out to the 640x480 displaybuffer.

These routines take over your colours and make sure that you are only ever drawing in four colours and also mean that you only have to process and draw pixels once, it does the scaling for you.

Sometimes you won't want dithering.  In which case, just make sure you draw pixels using values of 0, 64, 128, and 192.  If you're using photoshop (or something similar) to create images for inclusion in your code, only draw with greys or pure blues with the aforementioned values.

Of course, if you want a cute dithered picture from photoshop, just do a gradual grey gradient and let the routine handle it.  I did this for the xalboy demo, and I've attached images to show what I mean.  However, sometimes it doesn't work.... I was going to have a picture of a dragon and let the routine dither it, but at that resolution it just looked awful.  I've attached the original picture to this post as well.

I've also attached the images I used for the speccy demo in case anyone wants to play with isometric stuff.

I'm going to tidy my stuff up a little and release my entries in full source with images, but that's something for tomorrow I think.

Ah well, I hope it's useful/informative to someone.

Code: [Select]
' ------------------------------------------------------------------------------
' Framework for a 160x120, 4 colour resolution
'
' ------------------------------------------------------------------------------

' ------------------------------------------------------------------------------
' Include any libraries and external code files that we want to use
' ------------------------------------------------------------------------------

'    #define ptc_win
    #Include Once "tinyptc.bi"

    ' Get ourselves set up for good coding practice
    OPTION STATIC
    OPTION EXPLICIT

' ------------------------------------------------------------------------------
' Set up any variables that will never change (they will stay constant)
' ------------------------------------------------------------------------------

    ' Our main display resolution
    CONST XRES=640
    CONST YRES=480
    ' The resolution of our actual drawing area
    CONST DXRES=160
    CONST DYRES=120
    ' An offset to the section that we're drawing on
    CONST OFFX=240
    CONST OFFY=180

' ------------------------------------------------------------------------------
' We need to set up a bunch of variables that can be used anywhere in the code
' ------------------------------------------------------------------------------

    ' Set up an array for our draw buffer
    ' This may confuse a little... why is it a full 640x480 buffer and not
    ' 160x120?  This is because to make our lives so much easier, the 160x120
    ' area that we draw on will be placed right in the middle of a full sized
    ' screen.  This means that we can 'overdraw' things without worrying about
    ' crashing right out of the buffer.  It means you can draw images that
    ' do not need cropping to your viewport, it means you can smoothly scroll
    ' things in and out of the edges, and so on.
    '
    ' An interesting thing to point out is the colours used in your actual
    ' drawing and plotting.  Keep to either greys or blues (blues is easier)
    ' as only the blue channel is used to determine the brightness of a given
    ' pixel.  We're essentially drawing in monochrome and applying a palette
    ' at the end. The simplest way to do this is to simply set colour values
    ' from 0-192.  Values higher than 192 don't have any more effect than 192
    ' as the colour ranges map to the colours as shown below:
    '
    '  0 : first colour (C1)
    ' 64 : second colour (C2)
    '128 : third colour (C3)
    '192 : fourth colour (C4)
    '
    ' Colours between these values will be automatically dithered by the
    ' dithering routine.  So if you do a gradual shade from 0-192, you'll
    ' see the dithering in full effect.
    '
    ' The little demo with the rectangles show the dithering as well. The
    ' rectangles are all given a colour that falls between the 'pure colours'
    ' and are therefore shaded.
    DIM SHARED AS UINTEGER DRAWBUFFER (XRES*YRES)
   
    ' The display buffer, a nice, normal, full sized buffer.  This is the
    ' buffer that is actually displayed to the screen.
    DIM SHARED AS UINTEGER DISPLAYBUFFER (XRES*YRES)

    ' Four colour variables that are set with RGB().  They are used by the
    ' dithering routine to automatically display only four colours at a time.
    ' Don't use these to draw with, they're only used by the dithering routine.
    DIM SHARED AS UINTEGER C1, C2, C3, C4

    ' This is an 8x8 bayer dither array that we will use to do the dithering
    DIM SHARED PATTERN(64) AS UINTEGER

' ------------------------------------------------------------------------------
' Now to declare which subroutines we are going to write
' ------------------------------------------------------------------------------
    DECLARE SUB DITHER_SCREEN()
    DECLARE SUB BUFFER_CONVERT(byval sourcebuffer as uinteger ptr,byval targetbuffer as uinteger ptr)
    DECLARE SUB FOUR_COLOUR_SCREEN()
    DECLARE SUB DOT(byval X AS INTEGER, byval Y AS INTEGER, byval COL AS INTEGER)
    DECLARE SUB INIT()              :'  Set up our variables and arrays
    INIT()

' ------------------------------------------------------------------------------
' Now we're ready to get going, let's try and open a screen. If it fails, there
' is no point in continuing
' ------------------------------------------------------------------------------

    IF ( PTC_OPEN ( "Framework", XRES, YRES ) = 0 ) THEN
        END -1
    END IF

' ------------------------------------------------------------------------------
' We have our variables and arrays set up, we have an open screen display, so
' we can get going.
' ------------------------------------------------------------------------------

' variables for the framework demonstration, remove these when you write your
' own stuff
DIM X,Y,BACKC,BACKCD AS INTEGER
BACKC=0
BACKCD=1

DIM NR AS INTEGER=5
DIM R,RX(NR),RY(NR),RXD(NR),RYD(NR),RC(NR),RW(NR),RH(NR) AS INTEGER
FOR X=0 TO NR-1
    RX(X)=RND*160
    RY(X)=RND*120
    RXD(X)=(RND*4)-2:IF RXD(X)=0 THEN RXD(X)=1
    RYD(X)=(RND*4)-2:IF RYD(X)=0 THEN RYD(X)=1
    RW(X)=(RND*60)+20
    RH(X)=(RND*60)+20
NEXT X

' five rectangles, four with pure colours, one with a dither pattern
' remember that we draw with shades of blue and the dither routine will convert
' the monochrome to our four colours with dithering.
RC(0)=0
RC(1)=64
RC(2)=128
RC(3)=192
RC(4)=100
DO
    ' First of all, clean up the drawbuffer
    ERASE DRAWBUFFER

    ' This is where we would draw what we needed into the drawbuffer


    ' ---------------------------------------------------------------------
    ' Start of sample code, this should all be deleted when you want to do
    ' your own
    ' ---------------------------------------------------------------------

    ' Cycle the background colour
    BACKC+=BACKCD
    IF BACKC>254 THEN
        BACKC=254
        BACKCD=-1
    END IF
    IF BACKC<1 THEN
        BACKC=1
        BACKCD=1
    END IF

    ' Fill the background with the colour and let the dithering routine
    ' work out what it should look like.
    FOR X=0 TO 159
        FOR Y=0 TO 119
            DOT(X,Y,BACKC)
        NEXT Y
    NEXT X

    ' Draw the rectangles on the background and move them around
    FOR R=0 TO NR-1
        FOR X=RX(R) TO RX(R)+RW(R)
            FOR Y=RY(R) TO RY(R)+RH(R)
                DOT(X,Y,RC(R))
            NEXT Y
        NEXT X

        RX(R)+=RXD(R)
        RY(R)+=RYD(R)
        IF RX(R)>160 OR RX(R)<-RW(R) THEN RXD(R)=-RXD(R)
        IF RY(R)>120 OR RY(R)<-RH(R) THEN RYD(R)=-RYD(R)
    NEXT R
   
    ' ---------------------------------------------------------------------
    ' End of sample code, this should all be deleted when you want to do
    ' your own
    ' ---------------------------------------------------------------------
   
   
    ' Now we dither the drawbuffer, leaving pixel values of 0, 1, 2, and 3 in
    ' a dithered pattern if appropriate.
    DITHER_SCREEN()
    ' Now we convert those values into a proper RGB colour code as determined
    ' by our C1, C2, C3, and C4 variables
    FOUR_COLOUR_SCREEN()
    ' Our buffer is now ready to be scaled up and placed on the displaybuffer
    BUFFER_CONVERT(@DRAWBUFFER(0),@DISPLAYBUFFER(0))
    ' Now we display the display buffer
    PTC_UPDATE@DISPLAYBUFFER(0)

    ' If you want to see what is happening with the drawbuffer, comment out
    ' the above line, and uncomment this one.  It's good for debugging
'    PTC_UPDATE@DRAWBUFFER(0)
LOOP UNTIL INKEY$=CHR$(27)

' We're all done now, we pressed escape, time to finish things up
END
PTC_CLOSE()

' ------------------------------------------------------------------------------
' DITHER_SCREEN
'
'  Using the Bayer dither patter, run through the entire display area of the
'  drawbuffer, applying the pattern where appropriate, which will leave us with
'  an area of the screen with colour values of 0, 1, 2, and 3
' ------------------------------------------------------------------------------
SUB DITHER_SCREEN()
    DIM X,Y,XX,YY,P,PP,PIX
   
    FOR Y=0 TO DYRES-1
        YY=Y MOD 8
        FOR X=0 TO DXRES-1
            XX=X MOD 8
            PP=PATTERN(YY*8+XX)
            P=(Y+OFFY)*XRES+X+OFFX
            PIX=DRAWBUFFER(P)+PP
            IF PIX>255 THEN PIX=255
            PIX=PIX AND 192
            PIX=PIX SHR 6
            DRAWBUFFER(P)=PIX
        NEXT X
    NEXT Y
END SUB

' ------------------------------------------------------------------------------
' FOUR_COLOUR_SCREEN
'
'   Running through the display area of the drawbuffer, convert all values of
'   0, 1, 2, and 3 to the appropriate colour values C1, C2, C3, C4.  This won't
'   really work unless you have already called DITHER_SCREEN()
' ------------------------------------------------------------------------------
SUB FOUR_COLOUR_SCREEN()
    DIM P,X,Y,C AS UINTEGER
    FOR Y=0 TO DYRES-1
        FOR X=0 TO DXRES-1
            P=(Y+OFFY)*XRES+X+OFFX
            C=DRAWBUFFER(P)
            IF C=0 THEN DRAWBUFFER(P)=C1
            IF C=1 THEN DRAWBUFFER(P)=C2
            IF C=2 THEN DRAWBUFFER(P)=C3
            IF C=3 THEN DRAWBUFFER(P)=C4
        NEXT X
    NEXT Y
END SUB

' ------------------------------------------------------------------------------
' BUFFER_CONVERT
'
'   Scale and write the drawbuffer to the displaybuffer
' ------------------------------------------------------------------------------
SUB BUFFER_CONVERT(byval sourcebuffer as uinteger ptr,byval targetbuffer as uinteger ptr)
    DIM HEIGHT,LENGTH AS UINTEGER
    LENGTH=160
    HEIGHT=120
    SOURCEBUFFER=SOURCEBUFFER+(OFFY*XRES)+OFFX

    asm
        ' now we have done the fire buffer, throw the results back
        mov esi, [SOURCEBUFFER]
        mov edi, [TARGETBUFFER]
        ' load ax with the height for the yloop
        mov ax, [HEIGHT]
    BCYloop2:
        push eax
        ' load BX with the screen width for the XLoop
        mov bx,[LENGTH]
    BCXloop2:
        push ebx
        mov eax,[esi]
        mov [edi],eax
        mov [edi+4],eax
        mov [edi+8],eax
        mov [edi+12],eax
        mov [edi+2560],eax
        mov [edi+2564],eax
        mov [edi+2568],eax
        mov [edi+2572],eax
        mov [edi+5120],eax
        mov [edi+5124],eax
        mov [edi+5128],eax
        mov [edi+5132],eax
        mov [edi+7680],eax
        mov [edi+7684],eax
        mov [edi+7688],eax
        mov [edi+7692],eax
        add edi,16
        add esi,4
        ' still running the xloop?           
        pop ebx
        dec bx
        jnz BCXloop2
        add esi,1920
        ' still running the yloop?
        add edi,7680
        pop eax
        dec ax
        jnz BCYloop2
    end asm   
end sub


' ------------------------------------------------------------------------------
' DOT
'
'   If it is safe to do so, draw a single dot into the drawbuffer.  Use values
'   from 0-159 for X and 0-119 for Y, the routine moves it to the correct
'   position for you
' ------------------------------------------------------------------------------
SUB DOT(byval X AS INTEGER, byval Y AS INTEGER, byval C AS INTEGER)
  IF X>=0 AND X<DXRES AND Y>=0 AND Y<DYRES THEN DRAWBUFFER(((Y+OFFY)*XRES)+OFFX+X)=C
END SUB

' ------------------------------------------------------------------------------
' INIT
'
'   This is where we will initialise all of our variables and arrays.  It is
'   kept at the end of the code to keep the front tidy
' ------------------------------------------------------------------------------
SUB INIT()
    DIM A AS INTEGER

    ' Let's read in the bayer dither pattern
    FOR A=0 TO 63
        READ PATTERN(A)
    NEXT A
   
    ' Let's set the four colours that we intend to use.  These variables are
    ' global, so you can set them anywhere you like in the program and know
    ' that you will never be displaying more than four colours.
    C1=RGB(120,  0,  0)
    C2=RGB(  0,120,  0)
    C3=RGB(  0,  0,120)
    C4=RGB(120,120,  0)
END SUB

' Bayer dither pattern
DATA  0,32, 8,40, 2,34,10,42
DATA 48,16,56,24,50,18,58,26
DATA 12,44, 4,36,14,46, 6,38
DATA 60,28,52,20,62,30,54,22
DATA  3,35,11,43, 1,33, 9,41
DATA 51,19,59,27,49,17,57,25
DATA 15,47, 7,39,13,45, 5,37
DATA 63,31,55,23,61,29,53,21
Challenge Trophies Won:

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17414
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Re: [REDUCED RES] Xal's Framework (not an entry...)
« Reply #1 on: August 31, 2008 »
Thanks for this Xal :) Hope that lots of people give you karma for it! It's really nicely done and very well commented.
Shockwave ^ Codigos
Challenge Trophies Won:

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: [REDUCED RES] Xal's Framework (not an entry...)
« Reply #2 on: August 31, 2008 »
yes, karma++  :cheers:
Challenge Trophies Won:

Offline benny!

  • Senior Member
  • DBF Aficionado
  • ********
  • Posts: 4384
  • Karma: 228
  • in this place forever!
    • View Profile
    • bennyschuetz.com - mycroBlog
Re: [REDUCED RES] Xal's Framework (not an entry...)
« Reply #3 on: August 31, 2008 »
inc K
[ mycroBLOG - POUET :: whatever keeps us longing - for another breath of air - is getting rare ]

Challenge Trophies Won:

gooner

  • Guest
Re: [REDUCED RES] Xal's Framework (not an entry...)
« Reply #4 on: August 31, 2008 »
Thanks a lot Xalthorn for releasing your framework. :buddies:
This will definitely help me in my learning process. :clap:
Cheers mate :cheers:
Special K to you

Offline Xalthorn

  • Amiga 1200
  • ****
  • Posts: 331
  • Karma: 100
    • View Profile
Re: [REDUCED RES] Xal's Framework (not an entry...)
« Reply #5 on: August 31, 2008 »
Thanks a lot Xalthorn for releasing your framework. :buddies:
This will definitely help me in my learning process. :clap:
Cheers mate :cheers:
Special K to you

Glad to help mate :D
Challenge Trophies Won:

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
Re: [REDUCED RES] Xal's Framework (not an entry...)
« Reply #6 on: September 02, 2008 »
Have some karma for being a man of your word :D. its great that you got this working as well as it does and even better that you chose to share it with everyone

Challenge Trophies Won: