Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Drawing Tools Subs or Functions with Demo
#42
I have dived deeper into this rabbit hole and come up with even faster (much faster) code for the fake sphere mapping.

This time the code creates a precalculated x coordinate translation array which removes the need to calculate latitude and longitude coordinates every time the sphere is redrawn. Next, the translation array and images are all handled in memory using _MEM commands for speed.

I'm getting very close to 100 frames per second rotating a 953x953 sphere!

I'm exploring ways of turning this proof on concept code into a workable subroutine or function.

The downside to this approach is that the map image needs to be doubled in width. Essentially two of the images need to be next to each other since there is no way to do what MOD is performing in the previous code above. I'm exploring ways of overcoming this as well, perhaps through some clever memory address manipulation.

The ZIP file below contains the world map image that is 954 pixels high.

Code: (Select All)
' Fake Sphere Mapping
'
' Proof of concept using a precalculated x coordinate translation array and _MEM memory buffers.
' This demo achieves almost 100 frames per second creating and rotating a 953x953 spehere.
' This was achieved on an older test system running an i7-6700K at 4Ghz.
' Results on more modern equipment should be even more impressive.

OPTION _EXPLICIT

DIM imageWidth AS INTEGER '     width of initial image
DIM imageHeight AS INTEGER '    height of initial image
DIM baseImage AS LONG '         initial image (temporary)
DIM image AS LONG '             working image (2 base images next to each other)
DIM sphere AS LONG '            output image
DIM Mapx AS INTEGER '           calculation map x coordinate
DIM x AS INTEGER '              horizontal counter
DIM y AS INTEGER '              vertical counter
DIM xOffset AS INTEGER '        horizontal drawing offset within image
DIM mMap AS _MEM '              texture map x coordinate array
DIM mMapOffset AS _OFFSET '     memory location of calculation map array
DIM mImage AS _MEM '            image array
DIM mImageOffset AS _OFFSET '   memory location of image array
DIM mSphere AS _MEM '           sphere output image array
DIM mSphereOffset AS _OFFSET '  memory location of sphere output image array
DIM Pixel AS _UNSIGNED LONG '   image pixel

baseImage = _LOADIMAGE("worldmap2.png", 32) '                                load image to map
imageWidth = _WIDTH(baseImage) '                                             record image width
imageHeight = _HEIGHT(baseImage) '                                           record image height
image = _NEWIMAGE(imageWidth * 2, imageHeight, 32) '                         create texture image (2 base images side by side)
_PUTIMAGE (0, 0), baseImage, image '                                         draw first image onto texture image
_PUTIMAGE (imageWidth, 0), baseImage, image '                                draw second image onto texture image
_FREEIMAGE baseImage '                                                       map image no longer needed
mImage = _MEMIMAGE(image) '                                                  create image array in memory from texture image
sphere = _NEWIMAGE(imageHeight, imageHeight, 32) '                           create image array in memory from output image
mMap = _MEMNEW(imageHeight * imageHeight * 2) '                              create texture map x coordinate array in memory
mSphere = _MEMIMAGE(sphere) '                                                create sphere array in memory
SCREEN _NEWIMAGE(imageHeight, imageHeight, 32) '                             screen same height as output image
initMapPos '                                                                 create texture map x coordinate array
xOffset = 0 '                                                                reset image x offset
DO '                                                                         begin demo
    $CHECKING:OFF
    y = 0 '                                                                  reset vertical counter
    DO '                                                                     begin vertical loop
        mMapOffset = mMap.OFFSET + (y * imageHeight * 2) '                   start memory location of horizontal line within map
        mSphereOffset = mSphere.OFFSET + (y * imageHeight * 4) '             start memory location of horizontal line within sphere
        mImageOffset = mImage.OFFSET + (y * imageWidth * 8) '                start memory location of horizontal line within image
        x = 0 '                                                              reset horizontal counter
        DO '                                                                 begin horizontal loop
            _MEMGET mMap, mMapOffset + (x * 2), Mapx '                       get x texture coordinate
            IF Mapx <> -1 THEN '                                             valid coordinate?
                _MEMGET mImage, mImageOffset + (Mapx + xOffset) * 4, Pixel ' yes, get pixel from image
                _MEMPUT mSphere, mSphereOffset + (x * 4), Pixel '            apply pixel to output image
            END IF
            x = x + 1 '                                                      increment horizontal counter
        LOOP UNTIL x = imageHeight '                                         leave when entire horizontal line processed
        y = y + 1 '                                                          increment vertical counter
    LOOP UNTIL y = imageHeight '                                             leave when entire vertical line processed
    xOffset = xOffset + 1 '                                                  increment image x offset
    IF xOffset > imageWidth - 1 THEN xOffset = 0 '                           reset image x offset when needed
    _PUTIMAGE (0, 0), sphere '                                               display output image
    _DISPLAY '                                                               update screen with changes
    '_LIMIT 60
    $CHECKING:ON
LOOP UNTIL _KEYDOWN(27) '                                                    leave demo when ESC pressed
_MEMFREE mMap '                                                              free memory assets
_MEMFREE mSphere
_MEMFREE mImage
_FREEIMAGE image '                                                           free image assets
_FREEIMAGE sphere
SYSTEM '                                                                     return to operating system


'-----------------------------------------------------------------------------------------------------------------------------------------+
SUB initMapPos () '                                                                                                                       |
    '+------------------------------------------------------------------------------------------------------------------------------------+
    '| Create an x coordinate translation array so latitude and longitude calculations only need to be peformed once.                     |
    '+------------------------------------------------------------------------------------------------------------------------------------+

    CONST HALFPI = _PI * .5 '         half of Pi
    CONST rPI = 1 / _PI '             Pi reciprocated
    SHARED imageWidth AS INTEGER '    need width of image
    SHARED imageHeight AS INTEGER '   need height of image
    SHARED mMap AS _MEM '             need access to texture map x coordinate array
    DIM radius AS SINGLE '            sphere radius
    DIM Index AS _UNSIGNED LONG '     array memory offset for each value
    DIM sLongitude AS SINGLE '        sine longitude calculation
    DIM longitude AS SINGLE '         longitude calculation
    DIM x AS INTEGER '                horizontal counter
    DIM y AS INTEGER '                vertical counter

    radius = imageHeight * .5 '                                                        calculate sphere radius
    y = 0 '                                                                            reset vertical counter
    DO '                                                                               begin vetical loop
        x = 0 '                                                                        reset horizontal counter
        DO '                                                                           begin horizontal loop
            Index = (y * imageHeight + x) * 2 '                                        value memory location
            sLongitude = (x - radius) / (radius * COS(_ASIN((y - radius) / radius))) ' calculate sine longitude of pixel
            IF sLongitude >= -1 AND sLongitude <= 1 THEN '                             is pixel inside the circle?
                longitude = _ASIN(sLongitude) + HALFPI '                               yes, complete longitude calculation
                _MEMPUT mMap, mMap.OFFSET + Index, (longitude * imageWidth * .5) * rPI AS INTEGER ' store corresponding image x coordinate
            ELSE '                                                                     no, pixel is outside of circle
                _MEMPUT mMap, mMap.OFFSET + Index, -1 AS INTEGER '                     mark x coordinate as outside of circle
            END IF
            x = x + 1 '                                                                increment horizontal counter
        LOOP UNTIL x = imageHeight '                                                   leave when entire horizontal line processed
        y = y + 1 '                                                                    increment vertical counter
    LOOP UNTIL y = imageHeight '                                                       leave when entire vertical line processed

END SUB


Attached Files
.zip   Worldmap2.zip (Size: 373.14 KB / Downloads: 8)
There are two ways to write error-free programs; only the third one works.
QB64 Tutorial
Reply


Messages In This Thread
RE: Drawing Tools Subs or Functions with Demo - by TerryRitchie - 09-09-2024, 02:39 AM



Users browsing this thread: 17 Guest(s)