├── waves ├── ex1 │ ├── README.md │ ├── res │ │ ├── resources.res │ │ └── bg │ │ │ └── bg.png │ └── src │ │ └── main.c └── ex2 │ ├── res │ ├── bg │ │ ├── bg.png │ │ └── fg.png │ ├── sprites │ │ └── bubble.png │ └── resources.res │ └── src │ └── main.c ├── 01_SimpleScrolling ├── README.md ├── res │ ├── planes │ │ └── plane_a.png │ ├── sprites │ │ └── ship.png │ └── resources.res └── src │ └── main.c ├── RotatePy ├── ship.png ├── platform.png ├── points.csv ├── crosshairs.png ├── green_bar.png ├── rotate_-5_to_5 │ ├── res │ │ ├── resources.res │ │ └── bg │ │ │ └── platform.png │ └── src │ │ ├── main.c │ │ └── rotation.h ├── rotate_2_degrees │ ├── res │ │ ├── resources.res │ │ └── bg │ │ │ └── platform.png │ └── src │ │ ├── rotation.h │ │ └── main.c ├── green_bar_rotated_15.png ├── green_bar_rotated_2.png ├── rotation_and_translation │ ├── res │ │ ├── resources.res │ │ └── bg │ │ │ └── platform.png │ └── src │ │ ├── main.c │ │ └── rotation.h ├── green_bar_rotated_5_MOAR_ROWS.png ├── green_bar_rotated_5_too_few_rows.png ├── resources.res.jinja ├── main.c.jinja └── sgdk_scroll_rotate.py ├── EndlessScroll ├── bg.png ├── example │ ├── res │ │ ├── resources.res │ │ └── bg │ │ │ └── bg.png │ └── src │ │ └── main.c ├── image.png ├── ceiling.png ├── warp_0.png ├── warp_1.png ├── warp_2.png ├── warp_3.png ├── warp_4.png ├── warp_5.png ├── warp_6.png ├── woodceil.png ├── test_tile.png ├── test_wood.png ├── tilefloor.png ├── DOS │ ├── res │ │ ├── bg │ │ │ ├── bg.png │ │ │ ├── bga.png │ │ │ ├── bgb_0-0_22_6_27.png │ │ │ ├── bgb_1-0_22_13_27.png │ │ │ ├── bgb_2-10_22_19_27.png │ │ │ ├── bgb_3-20_22_29_27.png │ │ │ ├── bgb_4-26_22_39_27.png │ │ │ ├── bgb_5-33_22_49_27.png │ │ │ └── bgb_6-40_22_49_27.png │ │ └── resources.res │ └── src │ │ └── main.c ├── python_win_install.png ├── resources.res.jinja ├── woodfloor_tileceiling.png ├── main.c.jinja ├── main_wide.c.jinja ├── README.md └── sgdk_endless_scroll.py ├── VScrollTiled ├── res │ ├── resources.res │ └── bg │ │ └── planeb.png └── src │ └── main.c ├── HScrollLine ├── res │ ├── bg │ │ └── desert.png │ └── resources.res └── src │ └── main.c ├── RotationDual ├── res │ ├── bg │ │ ├── planea.png │ │ └── planeb.png │ ├── sprites │ │ ├── ship_sheet.png │ │ └── shot_sheet.png │ └── resources.res └── src │ └── main.c ├── HScroll ├── res │ ├── resources.res │ └── planes │ │ └── madmarco_bg.png └── src │ └── main.c ├── HScrollDec ├── res │ ├── planes │ │ ├── numbered.png │ │ └── madmarco_bgb.png │ └── resources.res └── src │ └── main.c ├── Rotation ├── res │ ├── planes │ │ └── boss_truck.png │ └── resources.res └── src │ └── main.c ├── RotationDualPrecalc ├── res │ ├── bg │ │ ├── planea.png │ │ └── planeb.png │ ├── sprites │ │ ├── ship.png │ │ └── crosshairs.png │ └── resources.res └── src │ ├── main.c │ └── rotation.h ├── HScrollTiled ├── res │ ├── planes │ │ ├── madmarco_bga.png │ │ └── madmarco_bgb.png │ └── resources.res └── src │ └── main.c ├── ScrollingWithCamera ├── res │ ├── sprites │ │ ├── rock.png │ │ ├── ship.png │ │ ├── explosion.png │ │ └── shot_sheet.png │ ├── planes │ │ └── plane_a.png │ └── resources.res └── src │ └── main.c ├── RotationWithBackground ├── res │ ├── sprites │ │ ├── tree1.png │ │ ├── gun_bike_b.png │ │ ├── boss_truck_wheel.png │ │ └── gun_bike_rider_b.png │ ├── planes │ │ ├── background.png │ │ └── boss_truck.png │ └── resources.res └── src │ └── main.c ├── go.sh ├── README.md └── LICENSE /waves/ex1/README.md: -------------------------------------------------------------------------------- 1 | # Simple Wave Example 2 | 3 | -------------------------------------------------------------------------------- /01_SimpleScrolling/README.md: -------------------------------------------------------------------------------- 1 | # Simple Scrolling Example. 2 | 3 | -------------------------------------------------------------------------------- /RotatePy/ship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/ship.png -------------------------------------------------------------------------------- /EndlessScroll/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/bg.png -------------------------------------------------------------------------------- /RotatePy/platform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/platform.png -------------------------------------------------------------------------------- /RotatePy/points.csv: -------------------------------------------------------------------------------- 1 | name,x,y 2 | lgun,106,130 3 | rgun,277,130 4 | lvent,176,127 5 | rvent,207,127 6 | -------------------------------------------------------------------------------- /waves/ex1/res/resources.res: -------------------------------------------------------------------------------- 1 | IMAGE bg "bg/bg.png" BEST 2 | PALETTE bg_pal "bg/bg.png" 3 | 4 | 5 | -------------------------------------------------------------------------------- /EndlessScroll/example/res/resources.res: -------------------------------------------------------------------------------- 1 | image plane_b "bg/bg.png" 0 2 | PALETTE plane_b_pal "bg/bg.png" 3 | -------------------------------------------------------------------------------- /EndlessScroll/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/image.png -------------------------------------------------------------------------------- /RotatePy/crosshairs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/crosshairs.png -------------------------------------------------------------------------------- /RotatePy/green_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/green_bar.png -------------------------------------------------------------------------------- /waves/ex1/res/bg/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/waves/ex1/res/bg/bg.png -------------------------------------------------------------------------------- /waves/ex2/res/bg/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/waves/ex2/res/bg/bg.png -------------------------------------------------------------------------------- /waves/ex2/res/bg/fg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/waves/ex2/res/bg/fg.png -------------------------------------------------------------------------------- /EndlessScroll/ceiling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/ceiling.png -------------------------------------------------------------------------------- /EndlessScroll/warp_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/warp_0.png -------------------------------------------------------------------------------- /EndlessScroll/warp_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/warp_1.png -------------------------------------------------------------------------------- /EndlessScroll/warp_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/warp_2.png -------------------------------------------------------------------------------- /EndlessScroll/warp_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/warp_3.png -------------------------------------------------------------------------------- /EndlessScroll/warp_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/warp_4.png -------------------------------------------------------------------------------- /EndlessScroll/warp_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/warp_5.png -------------------------------------------------------------------------------- /EndlessScroll/warp_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/warp_6.png -------------------------------------------------------------------------------- /EndlessScroll/woodceil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/woodceil.png -------------------------------------------------------------------------------- /VScrollTiled/res/resources.res: -------------------------------------------------------------------------------- 1 | IMAGE plane_b "bg/planeb.png" 0 2 | 3 | PALETTE plane_b_pal "bg/planeb.png" 4 | -------------------------------------------------------------------------------- /EndlessScroll/test_tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/test_tile.png -------------------------------------------------------------------------------- /EndlessScroll/test_wood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/test_wood.png -------------------------------------------------------------------------------- /EndlessScroll/tilefloor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/tilefloor.png -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/bg/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/DOS/res/bg/bg.png -------------------------------------------------------------------------------- /HScrollLine/res/bg/desert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/HScrollLine/res/bg/desert.png -------------------------------------------------------------------------------- /RotatePy/rotate_-5_to_5/res/resources.res: -------------------------------------------------------------------------------- 1 | IMAGE platform "bg/platform.png" NONE 2 | PALETTE platform_pal "bg/platform.png" -------------------------------------------------------------------------------- /RotatePy/rotate_2_degrees/res/resources.res: -------------------------------------------------------------------------------- 1 | IMAGE platform "bg/platform.png" NONE 2 | PALETTE platform_pal "bg/platform.png" -------------------------------------------------------------------------------- /RotationDual/res/bg/planea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationDual/res/bg/planea.png -------------------------------------------------------------------------------- /RotationDual/res/bg/planeb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationDual/res/bg/planeb.png -------------------------------------------------------------------------------- /VScrollTiled/res/bg/planeb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/VScrollTiled/res/bg/planeb.png -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/bg/bga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/DOS/res/bg/bga.png -------------------------------------------------------------------------------- /HScroll/res/resources.res: -------------------------------------------------------------------------------- 1 | PALETTE bg_palette "planes/madmarco_bg.png" NONE 2 | IMAGE bg_image "planes/madmarco_bg.png" NONE 3 | -------------------------------------------------------------------------------- /HScrollLine/res/resources.res: -------------------------------------------------------------------------------- 1 | 2 | IMAGE desert "bg/desert.png" BEST 3 | PALETTE desert_pal "bg/desert.png" 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /RotatePy/green_bar_rotated_15.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/green_bar_rotated_15.png -------------------------------------------------------------------------------- /RotatePy/green_bar_rotated_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/green_bar_rotated_2.png -------------------------------------------------------------------------------- /waves/ex2/res/sprites/bubble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/waves/ex2/res/sprites/bubble.png -------------------------------------------------------------------------------- /EndlessScroll/example/res/bg/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/example/res/bg/bg.png -------------------------------------------------------------------------------- /EndlessScroll/python_win_install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/python_win_install.png -------------------------------------------------------------------------------- /HScroll/res/planes/madmarco_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/HScroll/res/planes/madmarco_bg.png -------------------------------------------------------------------------------- /HScrollDec/res/planes/numbered.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/HScrollDec/res/planes/numbered.png -------------------------------------------------------------------------------- /RotatePy/rotation_and_translation/res/resources.res: -------------------------------------------------------------------------------- 1 | IMAGE platform "bg/platform.png" NONE 2 | PALETTE platform_pal "bg/platform.png" -------------------------------------------------------------------------------- /Rotation/res/planes/boss_truck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/Rotation/res/planes/boss_truck.png -------------------------------------------------------------------------------- /HScrollDec/res/planes/madmarco_bgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/HScrollDec/res/planes/madmarco_bgb.png -------------------------------------------------------------------------------- /RotationDualPrecalc/res/bg/planea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationDualPrecalc/res/bg/planea.png -------------------------------------------------------------------------------- /RotationDualPrecalc/res/bg/planeb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationDualPrecalc/res/bg/planeb.png -------------------------------------------------------------------------------- /01_SimpleScrolling/res/planes/plane_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/01_SimpleScrolling/res/planes/plane_a.png -------------------------------------------------------------------------------- /01_SimpleScrolling/res/sprites/ship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/01_SimpleScrolling/res/sprites/ship.png -------------------------------------------------------------------------------- /EndlessScroll/resources.res.jinja: -------------------------------------------------------------------------------- 1 | IMAGE {{ bg_name }} "bg/{{ bg_name }}.png" NONE 2 | 3 | PALETTE {{ bg_name }}_pal "bg/{{ bg_name }}.png" 4 | -------------------------------------------------------------------------------- /EndlessScroll/woodfloor_tileceiling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/woodfloor_tileceiling.png -------------------------------------------------------------------------------- /HScrollTiled/res/planes/madmarco_bga.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/HScrollTiled/res/planes/madmarco_bga.png -------------------------------------------------------------------------------- /HScrollTiled/res/planes/madmarco_bgb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/HScrollTiled/res/planes/madmarco_bgb.png -------------------------------------------------------------------------------- /Rotation/res/resources.res: -------------------------------------------------------------------------------- 1 | IMAGE bg_boss_truck "planes/boss_truck.png" NONE 2 | 3 | PALETTE boss_truck_pal "planes/boss_truck.png" 4 | -------------------------------------------------------------------------------- /RotationDual/res/sprites/ship_sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationDual/res/sprites/ship_sheet.png -------------------------------------------------------------------------------- /RotationDual/res/sprites/shot_sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationDual/res/sprites/shot_sheet.png -------------------------------------------------------------------------------- /RotationDualPrecalc/res/sprites/ship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationDualPrecalc/res/sprites/ship.png -------------------------------------------------------------------------------- /ScrollingWithCamera/res/sprites/rock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/ScrollingWithCamera/res/sprites/rock.png -------------------------------------------------------------------------------- /ScrollingWithCamera/res/sprites/ship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/ScrollingWithCamera/res/sprites/ship.png -------------------------------------------------------------------------------- /RotatePy/green_bar_rotated_5_MOAR_ROWS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/green_bar_rotated_5_MOAR_ROWS.png -------------------------------------------------------------------------------- /RotatePy/rotate_-5_to_5/res/bg/platform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/rotate_-5_to_5/res/bg/platform.png -------------------------------------------------------------------------------- /ScrollingWithCamera/res/planes/plane_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/ScrollingWithCamera/res/planes/plane_a.png -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/bg/bgb_0-0_22_6_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/DOS/res/bg/bgb_0-0_22_6_27.png -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/bg/bgb_1-0_22_13_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/DOS/res/bg/bgb_1-0_22_13_27.png -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/bg/bgb_2-10_22_19_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/DOS/res/bg/bgb_2-10_22_19_27.png -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/bg/bgb_3-20_22_29_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/DOS/res/bg/bgb_3-20_22_29_27.png -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/bg/bgb_4-26_22_39_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/DOS/res/bg/bgb_4-26_22_39_27.png -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/bg/bgb_5-33_22_49_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/DOS/res/bg/bgb_5-33_22_49_27.png -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/bg/bgb_6-40_22_49_27.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/EndlessScroll/DOS/res/bg/bgb_6-40_22_49_27.png -------------------------------------------------------------------------------- /RotatePy/green_bar_rotated_5_too_few_rows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/green_bar_rotated_5_too_few_rows.png -------------------------------------------------------------------------------- /RotatePy/rotate_2_degrees/res/bg/platform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/rotate_2_degrees/res/bg/platform.png -------------------------------------------------------------------------------- /RotationDualPrecalc/res/sprites/crosshairs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationDualPrecalc/res/sprites/crosshairs.png -------------------------------------------------------------------------------- /RotationWithBackground/res/sprites/tree1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationWithBackground/res/sprites/tree1.png -------------------------------------------------------------------------------- /ScrollingWithCamera/res/sprites/explosion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/ScrollingWithCamera/res/sprites/explosion.png -------------------------------------------------------------------------------- /ScrollingWithCamera/res/sprites/shot_sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/ScrollingWithCamera/res/sprites/shot_sheet.png -------------------------------------------------------------------------------- /RotationWithBackground/res/planes/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationWithBackground/res/planes/background.png -------------------------------------------------------------------------------- /RotationWithBackground/res/planes/boss_truck.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationWithBackground/res/planes/boss_truck.png -------------------------------------------------------------------------------- /RotationWithBackground/res/sprites/gun_bike_b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationWithBackground/res/sprites/gun_bike_b.png -------------------------------------------------------------------------------- /RotatePy/rotation_and_translation/res/bg/platform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotatePy/rotation_and_translation/res/bg/platform.png -------------------------------------------------------------------------------- /RotationWithBackground/res/sprites/boss_truck_wheel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationWithBackground/res/sprites/boss_truck_wheel.png -------------------------------------------------------------------------------- /RotationWithBackground/res/sprites/gun_bike_rider_b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radioation/SGDK_Scrolling/HEAD/RotationWithBackground/res/sprites/gun_bike_rider_b.png -------------------------------------------------------------------------------- /HScrollDec/res/resources.res: -------------------------------------------------------------------------------- 1 | PALETTE bg_palette_a "planes/numbered.png" 2 | IMAGE bg_image_a "planes/numbered.png" NONE 3 | IMAGE bg_image_b "planes/madmarco_bgb.png" NONE 4 | -------------------------------------------------------------------------------- /HScrollTiled/res/resources.res: -------------------------------------------------------------------------------- 1 | PALETTE bg_palette_a "planes/madmarco_bga.png" 2 | IMAGE bg_image_a "planes/madmarco_bga.png" NONE 3 | IMAGE bg_image_b "planes/madmarco_bgb.png" NONE 4 | -------------------------------------------------------------------------------- /waves/ex2/res/resources.res: -------------------------------------------------------------------------------- 1 | IMAGE bg "bg/bg.png" BEST 2 | IMAGE fg "bg/fg.png" BEST 3 | 4 | PALETTE bg_pal "bg/bg.png" 5 | PALETTE fg_pal "bg/fg.png" 6 | 7 | SPRITE bubble "sprites/bubble.png" 4 4 NONE 8 | -------------------------------------------------------------------------------- /RotatePy/resources.res.jinja: -------------------------------------------------------------------------------- 1 | IMAGE {{ bg_name }} "bg/{{ bg_name }}.png" NONE 2 | SPRITE {{ sprite_name }} "sprites/{{ sprite_name }}.png" 2 2 NONE 3 | 4 | PALETTE {{ bg_name }}_pal "bg/{{ bg_name }}.png" 5 | PALETTE {{ sprite_name }}_pal "sprites/{{ sprite_name }}.png" 6 | -------------------------------------------------------------------------------- /01_SimpleScrolling/res/resources.res: -------------------------------------------------------------------------------- 1 | TILESET plane_a_tileset "planes/plane_a.png" BEST ALL 2 | MAP plane_a_map "planes/plane_a.png" plane_a_tileset BEST 0 3 | 4 | SPRITE ship "sprites/ship.png" 4 4 NONE 5 | 6 | PALETTE plane_palette "planes/plane_a.png" 7 | PALETTE ship_pal "sprites/ship.png" -------------------------------------------------------------------------------- /RotationDual/res/resources.res: -------------------------------------------------------------------------------- 1 | IMAGE plane_a "bg/planea.png" 0 2 | IMAGE plane_b "bg/planeb.png" 0 3 | 4 | SPRITE ships "sprites/ship_sheet.png" 4 4 NONE 5 | SPRITE shots "sprites/shot_sheet.png" 1 1 NONE 1 6 | 7 | PALETTE plane_a_pal "bg/planea.png" 8 | PALETTE plane_b_pal "bg/planeb.png" 9 | PALETTE ships_pal "sprites/ship_sheet.png" 10 | PALETTE shots_pal "sprites/shot_sheet.png" 11 | -------------------------------------------------------------------------------- /RotationDualPrecalc/res/resources.res: -------------------------------------------------------------------------------- 1 | 2 | IMAGE planea "bg/planea.png" NONE 3 | IMAGE planeb "bg/planeb.png" NONE 4 | 5 | SPRITE ship "sprites/ship.png" 4 4 NONE 6 | SPRITE crosshairs "sprites/crosshairs.png" 2 2 NONE 7 | 8 | PALETTE planea_pal "bg/planea.png" 9 | PALETTE planeb_pal "bg/planeb.png" 10 | PALETTE ship_pal "sprites/ship.png" 11 | PALETTE crosshairs_pal "sprites/crosshairs.png" 12 | -------------------------------------------------------------------------------- /EndlessScroll/DOS/res/resources.res: -------------------------------------------------------------------------------- 1 | #rescomp nodup 2 | IMAGE bga "bg/bga.png" NONE 3 | IMAGE bgb_0 "bg/bgb_0-0_22_6_27.png" NONE 4 | IMAGE bgb_1 "bg/bgb_1-0_22_13_27.png" NONE 5 | IMAGE bgb_2 "bg/bgb_2-10_22_19_27.png" NONE 6 | IMAGE bgb_3 "bg/bgb_3-20_22_29_27.png" NONE 7 | IMAGE bgb_4 "bg/bgb_4-26_22_39_27.png" NONE 8 | IMAGE bgb_5 "bg/bgb_5-33_22_49_27.png" NONE 9 | IMAGE bgb_6 "bg/bgb_6-40_22_49_27.png" NONE 10 | 11 | PALETTE bga_pal "bg/bga.png" 12 | -------------------------------------------------------------------------------- /go.sh: -------------------------------------------------------------------------------- 1 | 2 | FILES=$(find . -name main.c) 3 | 4 | for FILE in ${FILES} 5 | do 6 | sed -i -e 's/fix32ToInt/F32_toInt/g' $FILE 7 | sed -i -e 's/fix32ToInt/F32_toInt/g' $FILE 8 | sed -i -e 's/fix32Div/F32_div/g' $FILE 9 | sed -i -e 's/fix32Mul/F32_mul/g' $FILE 10 | sed -i -e 's/fix16ToInt/F16_toInt/g' $FILE 11 | sed -i -e 's/fix16Mul/F16_mul/g' $FILE 12 | sed -i -e 's/fix16Div/F16_div/g' $FILE 13 | sed -i -e 's/intToFix16/FIX16/g' $FILE 14 | done 15 | -------------------------------------------------------------------------------- /ScrollingWithCamera/res/resources.res: -------------------------------------------------------------------------------- 1 | TILESET plane_a_tileset "planes/plane_a.png" NONE ALL 2 | MAP plane_a_map "planes/plane_a.png" plane_a_tileset NONE 0 3 | 4 | SPRITE ship "sprites/ship.png" 3 3 NONE 5 | SPRITE shot "sprites/shot_sheet.png" 1 1 NONE 2 6 | SPRITE rock "sprites/rock.png" 4 4 NONE 8 7 | SPRITE explosion "sprites/explosion.png" 4 4 NONE 0 8 | 9 | PALETTE shot_pal "sprites/shot_sheet.png" 10 | PALETTE plane_pal "planes/plane_a.png" 11 | PALETTE ship_pal "sprites/ship.png" 12 | PALETTE rock_pal "sprites/rock.png" -------------------------------------------------------------------------------- /RotatePy/rotate_2_degrees/src/rotation.h: -------------------------------------------------------------------------------- 1 | #ifndef _ROTATION_H_ 2 | #define _ROTATION_H_ 3 | 4 | 5 | #define _SCROLL_COUNT 1 6 | #define ROWS_A 21 7 | #define START_ROW_A 93 8 | #define END_ROW_A 113 9 | #define COLS_A 20 10 | #define START_COL_A 0 11 | #define END_COL_A 19 12 | 13 | 14 | s16 _hScroll[] = { 15 | // rotation values for angle 2.000000 starts at 0 16 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 17 | 18 | 19 | s16 _vScroll[] = { 20 | // rotation values for angle 2.000000 starts at 0 21 | -5, -4, -4, -3, -3, -2, -2, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6 22 | }; 23 | 24 | 25 | #endif // _ROTATION_H_ 26 | -------------------------------------------------------------------------------- /RotationWithBackground/res/resources.res: -------------------------------------------------------------------------------- 1 | IMAGE bg_boss_truck "planes/boss_truck.png" NONE 2 | IMAGE bg "planes/background.png" NONE 3 | 4 | SPRITE boss_truck_wheel "sprites/boss_truck_wheel.png" 8 8 NONE 2 NONE TILE 5 | SPRITE gun_bike_big "sprites/gun_bike_b.png" 16 7 NONE 2 NONE TILE 6 | SPRITE gun_bike_rider_big "sprites/gun_bike_rider_b.png" 7 7 NONE 0 NONE TILE 7 | 8 | SPRITE tree "sprites/tree1.png" 3 9 NONE 9 | 10 | PALETTE bg_pal "planes/background.png" 11 | PALETTE gun_bike_pal "sprites/gun_bike_b.png" 12 | PALETTE gun_bike_rider_pal "sprites/gun_bike_rider_b.png" 13 | PALETTE boss_truck_pal "planes/boss_truck.png" 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SGDK_Scrolling 2 | This repo contains code I've written while trying out different ways of scrolling with [SGDK](https://github.com/Stephane-D/SGDK). 3 | 4 | THis code has been compiled against [SGDK 2.11](https://github.com/Stephane-D/SGDK/releases/tag/v2.11). 5 | 6 | ## MAP for Large Images 7 | The folders *ScrollingWithCamera* and *SimpleScrolling* are scrolling examples using the MAP type introduced in version [1.60](https://github.com/Stephane-D/SGDK/releases/tag/v1.60). The code has been updated to compile with SGDK 1.80. So you must have version 1.80 on your system to use this code. 8 | 9 | ## Image Scrolling with `VDP_setTileMap()` 10 | * *HScroll* uses `VDP_setTileMapEx()` to scroll a relatively large image over the default SGDK tilespace. 11 | * *HScrollDec* uses `VDP_setTileMapEx()` and `HSCROLL_PLANE` to scroll two planes. 12 | * *HScrollTiled* uses `VDP_setTileMapEx()` and `HSCROLL_TILE` to demonstrate parallax scrolling with two planes. 13 | 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Greg Gallardo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /VScrollTiled/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | 5 | ///////////////////////////////////////////////////////////////////// 6 | // Vertical Tiled Scrolling 7 | // 8 | // default SGDK width is 512 pixels (64 tiles) 9 | #define PLANE_MAX_PIXEL 384 10 | #define PLANE_MAX_HORIZONTAL_TILE 48 11 | #define PLANE_MAX_VERTICAL_TILE 32 12 | 13 | s16 vScrollB[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 14 | s16 planeBDeltas[20] = {9, 9, 7, 7, 5, 5, 5, 4, 3, 2, 2, 3, 4, 5, 5, 5, 7, 7, 9, 9}; 15 | 16 | 17 | 18 | int main(bool hard) 19 | { 20 | 21 | // SETUP backgroupd 22 | VDP_setBackgroundColor(16); 23 | VDP_setScreenWidth320(); 24 | 25 | // Set Colors 26 | PAL_setPalette(PAL0, plane_b_pal.data, CPU); 27 | PAL_setColor(0, 0x0000); 28 | 29 | // set scrolling modes to support fake rotation 30 | VDP_setScrollingMode(HSCROLL_PLANE, VSCROLL_COLUMN); 31 | 32 | // get initial tile position in VRAM 33 | int ind = TILE_USER_INDEX; 34 | VDP_loadTileSet(plane_b.tileset, ind, DMA); 35 | 36 | // SImple image for BG_B. We're not changing it during the level 37 | VDP_drawImageEx(BG_B, &plane_b, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, ind), 0, 0, FALSE, TRUE); 38 | 39 | 40 | while (TRUE) 41 | { 42 | // scroll the asteroids in BG_B 43 | for (int i = 0; i < 20; i++) 44 | { 45 | vScrollB[i] -= planeBDeltas[i]; 46 | } 47 | 48 | VDP_setVerticalScrollTile(BG_B, 0, vScrollB, 20, DMA); // use array to set plane offsets 49 | SYS_doVBlankProcess(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /RotatePy/rotate_2_degrees/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | #include "rotation.h" 4 | 5 | ///////////////////////////////////////////////////////////////////// 6 | // Scrolling Stuff 7 | #define PLANE_MAX_TILE 64 8 | 9 | int main(bool hard) 10 | { 11 | VDP_setScreenWidth320(); 12 | // set colors 13 | PAL_setPalette( PAL0, platform_pal.data, CPU ); 14 | 15 | // set scrolling mode to LINE for horizontal and TILE for vertical 16 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_COLUMN); 17 | 18 | // get tile positions in VRAM. 19 | int ind = TILE_USER_INDEX; 20 | int indexA = ind; 21 | // Load the plane tiles into VRAM 22 | VDP_loadTileSet(platform.tileset, ind, DMA); 23 | 24 | // setup the tiles 25 | VDP_setTileMapEx(BG_A, platform.tilemap, TILE_ATTR_FULL(PAL0, TRUE, FALSE, FALSE, indexA), 26 | 0, // Plane X destination 27 | 0, // plane Y destination 28 | 0, // Region X start position 29 | 0, // Region Y start position 30 | PLANE_MAX_TILE, // width (went with 64 becasue default width is 64. Viewable screen is 40) 31 | 28, // height 32 | CPU); 33 | 34 | // set SGDK scrolling functions to fake the rotaiton. 35 | VDP_setHorizontalScrollLine(BG_A, START_ROW_A, _hScroll, ROWS_A, CPU); 36 | VDP_setVerticalScrollTile(BG_A, START_COL_A, _vScroll, COLS_A, CPU); 37 | 38 | while (TRUE) 39 | { 40 | // let SGDK do its thing 41 | SYS_doVBlankProcess(); 42 | } 43 | return 0; 44 | } -------------------------------------------------------------------------------- /HScrollLine/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | #define TOTAL_LINES 224 5 | #define FAR 89 6 | #define LAND_LINES TOTAL_LINES - FAR 7 | 8 | int main(bool hard) { 9 | 10 | ////////////////////////////////////////////////////////////// 11 | // setup screen and palettes 12 | VDP_setBackgroundColor(16); 13 | VDP_setScreenWidth320(); 14 | 15 | PAL_setPalette( PAL0, desert_pal.data, CPU ); 16 | 17 | ////////////////////////////////////////////////////////////// 18 | // setup scrolling 19 | int ind = TILE_USER_INDEX; 20 | VDP_drawImageEx(BG_B, &desert, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, ind), 0, 0, FALSE, TRUE); 21 | ind += desert.tileset->numTile; 22 | 23 | // use LINE scroll for horizontal 24 | VDP_setScrollingMode( HSCROLL_LINE, VSCROLL_PLANE); 25 | 26 | s16 hScroll[TOTAL_LINES]; 27 | memset( hScroll, 0, sizeof(hScroll)); 28 | fix16 offsetPlaneSky = FIX16(0); 29 | fix16 landOffsets[LAND_LINES]; 30 | memset( landOffsets, 0, sizeof(landOffsets)); 31 | 32 | while(TRUE) 33 | { 34 | // scroll the sky 35 | offsetPlaneSky = offsetPlaneSky - FIX16(0.05); 36 | for (u16 i = 0; i 2 | #include "resources.h" 3 | 4 | s16 hScrollB[224]; 5 | fix32 fscroll[224]; 6 | s16 scrollStep = 0; 7 | 8 | static void scrollLeft() { 9 | ++scrollStep; 10 | if (scrollStep < {{ far_width|int }} ) { 11 | {% for scrollvals in scroll_left_list %} 12 | fscroll[{{scrollvals[0]}}] = fscroll[{{scrollvals[0]}}] - FIX32( {{'%0.3f' % scrollvals[1]|float }} ); 13 | {%- endfor %} 14 | } else { 15 | scrollStep = 0; 16 | memset(fscroll, 0, sizeof(fscroll)); 17 | } 18 | } 19 | 20 | static void scrollRight() { 21 | --scrollStep; 22 | if (scrollStep >= 0) { 23 | {% for scrollvals in scroll_right_list %} 24 | fscroll[{{scrollvals[0]}}] = fscroll[{{scrollvals[0]}}] + FIX32( {{'%0.3f' % scrollvals[1]|float }} ); 25 | {%- endfor %} 26 | 27 | } else { 28 | scrollStep = {{ far_width|int }}; 29 | {% for scrollvals in scroll_right_reset_list %} 30 | fscroll[{{scrollvals[0]}}] = FIX32({{ '%0.3f' % scrollvals[1]|float }}); 31 | {%- endfor %} 32 | } 33 | } 34 | 35 | int main(bool hard) 36 | { 37 | memset(hScrollB, 0, sizeof(hScrollB)); 38 | memset(fscroll, 0, sizeof(fscroll)); 39 | VDP_setScreenWidth320(); 40 | 41 | PAL_setPalette(PAL0, {{ bg_name }}_pal.data, CPU); 42 | PAL_setColor(0, 0x0000); 43 | // set scrolling modes to support line scrolling. 44 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_PLANE); 45 | 46 | // get initial tile position in VRAM and load image 47 | int ind = TILE_USER_INDEX; 48 | int indexB = ind; 49 | VDP_loadTileSet({{ bg_name }}.tileset, indexB, CPU); 50 | VDP_drawImageEx(BG_B, &{{ bg_name }}, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexB), 0, 0, FALSE, TRUE); 51 | 52 | while (TRUE) 53 | { 54 | scrollLeft(); 55 | //scrollRight(); 56 | for (int i = 0; i < 224; i++) // Not very efficient, but works for a demo 57 | { 58 | hScrollB[i] = fix32ToInt(fscroll[i]); 59 | } 60 | VDP_setHorizontalScrollLine(BG_B, 0, hScrollB, 224, DMA); 61 | SYS_doVBlankProcess(); 62 | } 63 | } 64 | 65 | 66 | -------------------------------------------------------------------------------- /EndlessScroll/example/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | s16 hScrollB[224]; 5 | fix32 fscroll[224]; 6 | s16 scrollStep = 0; 7 | 8 | static scrollLeftLoop() 9 | { 10 | ++scrollStep; 11 | fix32 fStep = FIX32(1.0); 12 | if (scrollStep < 80) 13 | { 14 | for (u16 row = 180; row < 224; ++row) 15 | { 16 | fscroll[row] = fscroll[row] - fStep; 17 | fStep = fStep - FIX32(0.0233); 18 | } 19 | } 20 | else 21 | { 22 | scrollStep = 0; 23 | memset(fscroll, 0, sizeof(fscroll)); 24 | } 25 | } 26 | 27 | static scrollRightLoop() 28 | { 29 | --scrollStep; 30 | fix32 fStep = FIX32(1.0); 31 | if (scrollStep >= 0) 32 | { 33 | for (u16 row = 180; row < 224; ++row) 34 | { 35 | fscroll[row] = fscroll[row] + fStep; 36 | fStep = fStep + FIX32(0.0233); 37 | } 38 | } 39 | else 40 | { 41 | scrollStep = 80; 42 | fix32 scroll = FIX32(-80.0); 43 | for (u16 row = 180; row < 224; ++row) 44 | { 45 | fscroll[row] = scroll; 46 | scroll = scroll - FIX32(1.8605); 47 | } 48 | } 49 | } 50 | 51 | int main(bool hard) 52 | { 53 | memset(hScrollB, 0, sizeof(hScrollB)); 54 | memset(fscroll, 0, sizeof(fscroll)); 55 | VDP_setScreenWidth320(); 56 | 57 | PAL_setPalette(PAL0, plane_b_pal.data, CPU); 58 | PAL_setColor(0, 0x0000); 59 | // set scrolling modes to support fake rotation 60 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_PLANE); 61 | 62 | // get initial tile position in VRAM 63 | int ind = TILE_USER_INDEX; 64 | int indexB = ind; 65 | VDP_loadTileSet(plane_b.tileset, indexB, CPU); 66 | VDP_drawImageEx(BG_B, &plane_b, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexB), 0, 0, FALSE, TRUE); 67 | 68 | while (TRUE) 69 | { 70 | scrollRightLoop(); 71 | //scrollLeftLoop(); 72 | for (int i = 0; i < 224; i++) // Not very efficient. 73 | { 74 | hScrollB[i] = F32_toInt(fscroll[i]); 75 | } 76 | VDP_setHorizontalScrollLine(BG_B, 0, hScrollB, 224, DMA); 77 | SYS_doVBlankProcess(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /HScroll/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | 5 | s16 offset = 0; 6 | s16 imageOffset = 0; 7 | 8 | int main( bool hard ) { 9 | 10 | // load the background palette 11 | PAL_setPalette( PAL1, bg_palette.data, DMA); 12 | 13 | // set scrolling mode. HSCROLL_PLANE Affects the WHOLE plane. 14 | VDP_setScrollingMode( HSCROLL_PLANE, VSCROLL_PLANE); 15 | 16 | // get our position for tiles. 17 | int ind = TILE_USER_INDEX; 18 | 19 | // Load the plane tiles into VRAM at our position 20 | VDP_loadTileSet( bg_image.tileset, ind, DMA ); 21 | 22 | // put out the image 23 | VDP_setTileMapEx(BG_A, bg_image.tilemap, TILE_ATTR_FULL(PAL1, FALSE, FALSE, FALSE, ind), 24 | 0, // Plane X destination 25 | 0, // plane Y destination 26 | 0, // Region X start position 27 | 0, // Region Y start position 28 | 64, // width (went with 64 becasue default width is 64. Viewable screen is 40) 29 | 28, // height 30 | CPU); 31 | 32 | while (TRUE) 33 | { 34 | // tile in memory 35 | offset += 1; 36 | if (offset > 511) 37 | offset = 0; 38 | 39 | // tile from image 40 | imageOffset += 1; 41 | if (imageOffset > 1279) 42 | imageOffset = 0; // bg image is 1280 pixels wide 43 | 44 | if (offset % 8 == 0) 45 | { 46 | s16 dstCol = (offset + 504) / 8; 47 | if (dstCol > 63) 48 | { 49 | dstCol -= 64; // wrap to zero 50 | } 51 | 52 | s16 srcCol = (imageOffset + 512) / 8; 53 | if (srcCol > 159) // 160 8-pixel columns in 1280 pixel width image 54 | { 55 | srcCol -= 160; // wrap to zero 56 | } 57 | 58 | KLog_S2("dstCol: ", dstCol, "srcCol: ", srcCol); 59 | VDP_setTileMapEx(BG_A, bg_image.tilemap, TILE_ATTR_FULL(PAL1, FALSE, FALSE, FALSE, ind), 60 | dstCol, // Plane X destination 61 | 0, // plane Y destination 62 | srcCol, // Region X start position 63 | 0, // Region Y start position 64 | 1, // width 65 | 28, // height 66 | CPU); 67 | } 68 | 69 | VDP_setHorizontalScroll(BG_A, -offset); 70 | 71 | // let SGDK do its thing 72 | SYS_doVBlankProcess(); 73 | } 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /RotatePy/rotate_-5_to_5/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | #include "rotation.h" 4 | 5 | ///////////////////////////////////////////////////////////////////// 6 | // Scrolling Stuff 7 | #define PLANE_MAX_TILE 64 8 | 9 | s16 hScrollA[224]; 10 | s16 vScrollA[20]; 11 | 12 | 13 | int main(bool hard) 14 | { 15 | memset(hScrollA, 0, sizeof(hScrollA)); 16 | memset(vScrollA, 0, sizeof(vScrollA)); 17 | VDP_setScreenWidth320(); 18 | // set colors 19 | PAL_setPalette( PAL0, platform_pal.data, CPU ); 20 | 21 | // set scrolling mode to LINE for horizontal and TILE for vertical 22 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_COLUMN); 23 | 24 | // get tile positions in VRAM. 25 | int ind = TILE_USER_INDEX; 26 | int indexA = ind; 27 | // Load the plane tiles into VRAM 28 | VDP_loadTileSet(platform.tileset, ind, DMA); 29 | 30 | // setup the tiles 31 | VDP_setTileMapEx(BG_A, platform.tilemap, TILE_ATTR_FULL(PAL0, TRUE, FALSE, FALSE, indexA), 32 | 0, // Plane X destination 33 | 0, // plane Y destination 34 | 0, // Region X start position 35 | 0, // Region Y start position 36 | PLANE_MAX_TILE, // width (went with 64 becasue default width is 64. Viewable screen is 40) 37 | 28, // height 38 | CPU); 39 | 40 | s16 currAngle = 5; 41 | s16 stepDir = 1; 42 | u8 angleDelay = 0; 43 | while (TRUE) 44 | { 45 | // handle rotation 46 | ++angleDelay; 47 | if (angleDelay % 6 == 0) 48 | { 49 | currAngle += stepDir; 50 | if (currAngle >= _SCROLL_COUNT) 51 | { 52 | stepDir = -1; 53 | currAngle = 10; 54 | } 55 | else if (currAngle < 0) 56 | { 57 | stepDir = 1; 58 | currAngle = 0; 59 | } 60 | 61 | // Copy current angle offsets into local arrays 62 | memcpy(hScrollA, _hScroll + currAngle * ROWS_A, ROWS_A * sizeof(s16)); 63 | memcpy(vScrollA, _vScroll + currAngle * COLS_A, COLS_A * sizeof(s16)); 64 | } 65 | 66 | // set SGDK scrolling functions with local arrays to fake the rotation. 67 | VDP_setHorizontalScrollLine(BG_A, START_ROW_A, hScrollA, ROWS_A, CPU); 68 | VDP_setVerticalScrollTile(BG_A, START_COL_A, vScrollA, COLS_A, CPU); 69 | 70 | // let SGDK do its thing 71 | SYS_doVBlankProcess(); 72 | } 73 | return 0; 74 | } -------------------------------------------------------------------------------- /waves/ex1/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | #define TOTAL_LINES 224 5 | 6 | 7 | int main(bool hard) { 8 | 9 | ////////////////////////////////////////////////////////////// 10 | // setup screen and palettes 11 | VDP_setBackgroundColor(16); 12 | VDP_setScreenWidth320(); 13 | 14 | PAL_setPalette( PAL0, bg_pal.data, CPU ); 15 | 16 | ////////////////////////////////////////////////////////////// 17 | // setup scrolling 18 | int ind = TILE_USER_INDEX; 19 | VDP_drawImageEx(BG_B, &bg, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, ind), 0, 0, FALSE, TRUE); 20 | ind += bg.tileset->numTile; 21 | 22 | // use LINE scroll for horizontal 23 | VDP_setScrollingMode( HSCROLL_LINE, VSCROLL_PLANE); 24 | 25 | s16 hScroll[TOTAL_LINES]; 26 | memset( hScroll, 0, sizeof(hScroll)); 27 | 28 | u16 sinPerLine = 5; // Elements to jump in sin() per line. Larger values give us faster waves. 29 | fix16 amplitude = FIX16( 10.0 ); // Amplitude sets how big the waves are. 30 | s16 offset = -40; // shift left a bit. 31 | for( u16 i = 0; i < TOTAL_LINES; ++i ) { 32 | hScroll[i] = F16_toInt( F16_mul( sinFix16(i * sinPerLine ), amplitude ) ) + offset; 33 | } 34 | 35 | 36 | ////////////////////////////////////////////////////////////// 37 | // main loop. 38 | u16 sinOffset = 0; // Step basically tells us where we're starting in the sin table. 39 | while(TRUE) 40 | { 41 | // read joypad to set sinewave parameters 42 | u16 joypad = JOY_readJoypad( JOY_1 ); 43 | if( joypad & BUTTON_UP ) { 44 | sinPerLine++; 45 | } else if( joypad & BUTTON_DOWN ) { 46 | sinPerLine--; 47 | } 48 | if( joypad & BUTTON_LEFT ) { 49 | amplitude = amplitude - FIX16(1); 50 | } else if( joypad & BUTTON_RIGHT ) { 51 | amplitude = amplitude + FIX16(1); 52 | } 53 | 54 | if( joypad & BUTTON_A) { 55 | sinPerLine = 5; 56 | amplitude = FIX16( 10.0 ); 57 | } 58 | if( joypad & BUTTON_B) { 59 | sinPerLine = 10; 60 | amplitude = FIX16( 30.0 ); 61 | } 62 | if( joypad & BUTTON_C) { 63 | sinPerLine = 80; 64 | amplitude = FIX16( 0.5 ); 65 | } 66 | 67 | // write params to the screen. 68 | char message[40]; 69 | char amps[5]; 70 | fix16ToStr( amplitude, amps, 1 ); 71 | strclr(message); 72 | sprintf( message, "sin per line: %d amplitude: %s ", sinPerLine, amps ); 73 | VDP_drawText(message, 3, 1 ); 74 | 75 | ////////////////////////////////////////////////////////////// 76 | // This is what matters right here: 77 | // calculate the offsets per line using SGDK's sin table 78 | // and adjust with params 79 | sinOffset++; // move up in the sine table 80 | for( u16 i = 0; i < TOTAL_LINES; ++i ) { 81 | // compute horizontal offsets with sine table. 82 | hScroll[i] = F16_toInt( F16_mul( sinFix16(( i + sinOffset ) * sinPerLine ), amplitude ) ) + offset; 83 | } 84 | 85 | // apply scrolling offsets 86 | VDP_setHorizontalScrollLine (BG_B, 0, hScroll, 223, DMA_QUEUE); 87 | SYS_doVBlankProcess(); 88 | 89 | } 90 | return 0; 91 | 92 | } 93 | -------------------------------------------------------------------------------- /RotatePy/rotation_and_translation/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | #include "rotation.h" 4 | 5 | ///////////////////////////////////////////////////////////////////// 6 | // Scrolling Stuff 7 | #define PLANE_MAX_TILE 64 8 | 9 | 10 | s16 hScrollA[224]; 11 | s16 vScrollA[20]; 12 | 13 | int main(bool hard) 14 | { 15 | memset(hScrollA, 0, sizeof(hScrollA)); 16 | memset(vScrollA, 0, sizeof(vScrollA)); 17 | VDP_setScreenWidth320(); 18 | // set colors 19 | PAL_setPalette( PAL0, platform_pal.data, CPU ); 20 | 21 | // set scrolling mode to LINE for horizontal and TILE for vertical 22 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_COLUMN); 23 | 24 | // get tile positions in VRAM. 25 | int ind = TILE_USER_INDEX; 26 | int indexA = ind; 27 | // Load the plane tiles into VRAM 28 | VDP_loadTileSet(platform.tileset, ind, DMA); 29 | 30 | // setup the tiles 31 | VDP_setTileMapEx(BG_A, platform.tilemap, TILE_ATTR_FULL(PAL0, TRUE, FALSE, FALSE, indexA), 32 | 0, // Plane X destination 33 | 0, // plane Y destination 34 | 0, // Region X start position 35 | 0, // Region Y start position 36 | PLANE_MAX_TILE, // width (went with 64 becasue default width is 64. Viewable screen is 40) 37 | 28, // height 38 | CPU); 39 | 40 | 41 | s16 currAngle = 5; 42 | s16 stepDir = 1; 43 | u8 angleDelay = 0; 44 | 45 | s16 xOffset = 0; 46 | s16 yOffset = 0; 47 | s16 yOffsetDir = 1; 48 | u8 offsetDelay = 0; 49 | 50 | 51 | while (TRUE) 52 | { 53 | 54 | // handle rotation 55 | ++angleDelay; 56 | if (angleDelay % 6 == 0) 57 | { 58 | currAngle += stepDir; 59 | if (currAngle >= _SCROLL_COUNT) 60 | { 61 | stepDir = -1; 62 | currAngle = 10; 63 | } 64 | else if (currAngle < 0) 65 | { 66 | stepDir = 1; 67 | currAngle = 0; 68 | } 69 | } 70 | ++offsetDelay; 71 | if( offsetDelay % 3 == 0 ) { 72 | yOffset += yOffsetDir; 73 | if( yOffset > 40) { 74 | yOffsetDir = -1; 75 | }else if( yOffset < 0 ) { 76 | yOffsetDir = 1; 77 | } 78 | if( currAngle < 4) { 79 | xOffset+=1; 80 | } else if ( currAngle > 6) { 81 | xOffset-=1; 82 | } 83 | } 84 | 85 | 86 | // could unroll loops to eliminate some overhead 87 | for(int i=0; i < ROWS_A; ++i ) { 88 | hScrollA[ i ] = _hScroll[ currAngle * ROWS_A + i] + xOffset; 89 | } 90 | for (int i = 0; i < COLS_A; ++i) 91 | { 92 | vScrollA[i] = _vScroll[currAngle * COLS_A + i] + yOffset; 93 | } 94 | 95 | 96 | // set SGDK scrolling functions to fake the rotation. 97 | s16 startHorizontalScroll = START_ROW_A - yOffset; 98 | s16 totalRows = ROWS_A ; 99 | if( startHorizontalScroll < 0 ) { 100 | totalRows = ROWS_A + startHorizontalScroll; 101 | startHorizontalScroll = 0; 102 | } 103 | VDP_setHorizontalScrollLine(BG_A, startHorizontalScroll, hScrollA, totalRows, DMA); 104 | VDP_setVerticalScrollTile(BG_A, START_COL_A, vScrollA, COLS_A, DMA); 105 | 106 | // let SGDK do its thing 107 | SYS_doVBlankProcess(); 108 | } 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /EndlessScroll/main_wide.c.jinja: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | s16 hScrollB[224]; 5 | fix32 fscroll[224]; 6 | s16 scrollStep = 0; 7 | s16 offset = 0; 8 | s16 imageOffset = 0; 9 | s16 ind = 0; 10 | static void scrollLeft() { 11 | 12 | ++scrollStep; 13 | 14 | if (scrollStep < {{ far_width|int }} ) { 15 | {% for scrollvals in scroll_left_list %} 16 | fscroll[{{scrollvals[0]}}] = fscroll[{{scrollvals[0]}}] - FIX32( {{'%0.3f' % scrollvals[1]|float }} ); 17 | {%- endfor %} 18 | } else { 19 | scrollStep = 0; 20 | offset = 0; 21 | imageOffset = 0; 22 | VDP_setTileMapEx(BG_B, {{ bg_name }}.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, ind), 23 | 0, // Plane X destination 24 | 0, // plane Y destination 25 | 0, // Region X start position 26 | 0, // Region Y start position 27 | 32, // width (went with 64 becasue default width is 64. Viewable screen is 40) 28 | 28, // height 29 | DMA_QUEUE); 30 | memset(fscroll, 0, sizeof(fscroll)); 31 | } 32 | } 33 | 34 | 35 | int main(bool hard) 36 | { 37 | memset(hScrollB, 0, sizeof(hScrollB)); 38 | memset(fscroll, 0, sizeof(fscroll)); 39 | VDP_setScreenWidth320(); 40 | 41 | PAL_setPalette(PAL0, {{ bg_name }}_pal.data, CPU); 42 | PAL_setColor(0, 0x0000); 43 | 44 | // set scrolling modes to support line scrolling. 45 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_PLANE); 46 | 47 | // get initial tile position in VRAM and load image 48 | ind = TILE_USER_INDEX; 49 | int indexB = ind; 50 | VDP_loadTileSet(bg.tileset, indexB, CPU); 51 | 52 | //VDP_drawImageEx(BG_B, &bg, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexB), 0, 0, FALSE, TRUE); 53 | 54 | // put out the image 55 | VDP_setTileMapEx(BG_B, {{ bg_name }}.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, ind), 56 | 0, // Plane X destination 57 | 0, // plane Y destination 58 | 0, // Region X start position 59 | 0, // Region Y start position 60 | 64, // width (went with 64 becasue default width is 64. Viewable screen is 40) 61 | 28, // height 62 | CPU); 63 | 64 | 65 | u16 srcCols = {{ image_width / 8 }}; 66 | while (TRUE) 67 | { 68 | scrollLeft(); 69 | // tile in memory 70 | offset += 1; 71 | if (offset > 511) { 72 | offset = 0; 73 | } 74 | 75 | // tile from image 76 | imageOffset += 1; 77 | if (imageOffset > {{ image_width - 1 }}) { 78 | imageOffset = 0; // bg image is 640 pixels wide 79 | } 80 | 81 | if (offset % 8 == 0 && scrollStep !=0) 82 | { 83 | s16 dstCol = (offset + 504) / 8; 84 | if (dstCol > 63) 85 | { 86 | dstCol -= 64; // wrap to zero 87 | } 88 | 89 | s16 srcCol = (imageOffset + 508) / 8; 90 | if (srcCol > srcCols - 1) 91 | { 92 | srcCol -= srcCols; // wrap to zero 93 | } 94 | 95 | VDP_setTileMapEx(BG_B, {{ bg_name }}.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, ind), 96 | dstCol, // Plane X destination 97 | 0, // plane Y destination 98 | srcCol, // Region X start position 99 | 0, // Region Y start position 100 | 1, // width 101 | 28, // height 102 | DMA_QUEUE); 103 | } 104 | 105 | 106 | //scrollRight(); 107 | for (int i = 0; i < 224; i++) // Not very efficient, but works for a demo 108 | { 109 | hScrollB[i] = fix32ToInt(fscroll[i]); 110 | } 111 | VDP_setHorizontalScrollLine(BG_B, 0, hScrollB, 224, DMA_QUEUE); 112 | SYS_doVBlankProcess(); 113 | } 114 | } 115 | 116 | -------------------------------------------------------------------------------- /RotatePy/main.c.jinja: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | #include "{{ rotation_filename }}" 4 | 5 | ///////////////////////////////////////////////////////////////////// 6 | // Scrolling Stuff 7 | #define PLANE_MAX_TILE 64 8 | 9 | 10 | s16 hScrollA[224]; 11 | s16 vScrollA[20]; 12 | 13 | int main(bool hard) 14 | { 15 | VDP_setScreenWidth320(); 16 | // set colors 17 | PAL_setPalette( PAL0, {{ bg_name}}_pal.data, CPU ); 18 | PAL_setPalette( PAL1, {{ sprite_name }}_pal.data, CPU ); 19 | 20 | // set scrolling mode to LINE for horizontal and TILE for vertical 21 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_2TILE); 22 | 23 | // get tile positions in VRAM. 24 | int ind = TILE_USER_INDEX; 25 | int indexA = ind; 26 | // Load the plane tiles into VRAM 27 | VDP_loadTileSet({{bg_name}}.tileset, ind, DMA); 28 | 29 | // setup the tiles 30 | VDP_setTileMapEx(BG_A, {{ bg_name }}.tilemap, TILE_ATTR_FULL(PAL0, TRUE, FALSE, FALSE, indexA), 31 | 0, // Plane X destination 32 | 0, // plane Y destination 33 | 0, // Region X start position 34 | 0, // Region Y start position 35 | PLANE_MAX_TILE, // width (went with 64 becasue default width is 64. Viewable screen is 40) 36 | 28, // height 37 | CPU); 38 | 39 | 40 | s16 currAngle = 0; 41 | s16 stepDir = 1; 42 | u8 angleDelay = 0; 43 | 44 | s16 xOffset = 0; 45 | s16 yOffset = 0; 46 | s16 yOffsetDir = 1; 47 | u8 offsetDelay = 0; 48 | 49 | {% if target_list|length > 0 %} 50 | SPR_init(); 51 | {% endif %} 52 | 53 | 54 | {% for name in target_list %} 55 | Sprite * {{name}}_sprite = NULL; 56 | int {{name}}_pos_x = {{name}}[currAngle*2]-8; 57 | int {{name}}_pos_y = {{name}}[currAngle*2+1]-8; 58 | {{name}}_sprite = SPR_addSprite( &crosshairs, {{name}}_pos_x, {{name}}_pos_y, TILE_ATTR( PAL1, 1, FALSE, FALSE )); 59 | {% endfor %} 60 | 61 | while (TRUE) 62 | { 63 | 64 | // handle rotation 65 | ++angleDelay; 66 | if( angleDelay % 6 == 0 ) { 67 | currAngle += stepDir; 68 | if( currAngle >= {{ prefix }}_SCROLL_COUNT-2 ) { 69 | stepDir = -1; 70 | currAngle = 9; 71 | }else if (currAngle <0+2 ) { 72 | stepDir = 1; 73 | currAngle = 1; 74 | } 75 | } 76 | ++offsetDelay; 77 | if( offsetDelay % 3 == 0 ) { 78 | yOffset += yOffsetDir; 79 | if( yOffset > 40) { 80 | yOffsetDir = -1; 81 | }else if( yOffset < 0 ) { 82 | yOffsetDir = 1; 83 | } 84 | if( currAngle < 4) { 85 | xOffset+=2; 86 | } else if ( currAngle > 6) { 87 | xOffset-=2; 88 | } 89 | } 90 | 91 | 92 | // could unroll loops to eliminate some overhead 93 | for(int i=0; i < {{ prefix }}_ROWS_A; ++i ) { 94 | hScrollA[ i ] = {{ prefix }}_hScroll[ currAngle * {{ prefix }}_ROWS_A + i] + xOffset; 95 | } 96 | for (int i = 0; i < {{prefix}}_COLS_A; ++i) 97 | { 98 | vScrollA[i] = {{ prefix }}_vScroll[currAngle * {{prefix}}_COLS_A + i] + yOffset; 99 | } 100 | 101 | {% for name in target_list %} 102 | {{name}}_pos_x = {{name}}[currAngle * 2]-8 + xOffset; 103 | {{name}}_pos_y = {{name}}[currAngle * 2 + 1]-8 - yOffset; 104 | SPR_setPosition({{name}}_sprite, {{name}}_pos_x, {{name}}_pos_y); 105 | {% endfor %} 106 | 107 | {% if target_list|length > 0 %} 108 | SPR_update(); 109 | {% endif %} 110 | 111 | // set SGDK scrolling functions to fake the rotaiton. 112 | s16 startHorizontalScroll = {{ prefix }}_START_ROW_A - yOffset; 113 | s16 totalRows = {{ prefix }}_ROWS_A ; 114 | if( startHorizontalScroll < 0 ) { 115 | totalRows = {{ prefix }}_ROWS_A + startHorizontalScroll; 116 | startHorizontalScroll = 0; 117 | } 118 | VDP_setHorizontalScrollLine(BG_A, startHorizontalScroll, hScrollA, totalRows, DMA); 119 | VDP_setVerticalScrollTile(BG_A, {{ prefix }}_START_COL_A, vScrollA, {{prefix}}_COLS_A, DMA); 120 | 121 | // let SGDK do its thing 122 | SYS_doVBlankProcess(); 123 | } 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /Rotation/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | 5 | ///////////////////////////////////////////////////////////////////// 6 | // Joypad Handler 7 | u16 maxAngle = 5; 8 | static void readJoypad( u16 joypadId ) { 9 | u16 joypadState = JOY_readJoypad( joypadId ); 10 | if( joypadState & BUTTON_A ) { 11 | maxAngle = 5; 12 | }else if( joypadState & BUTTON_B ) { 13 | maxAngle = 10; 14 | }else if( joypadState & BUTTON_C ) { 15 | maxAngle = 15; 16 | }else if( joypadState & BUTTON_X ) { 17 | maxAngle = 20; 18 | }else if( joypadState & BUTTON_Y ) { 19 | maxAngle = 30; 20 | }else if( joypadState & BUTTON_Z ) { 21 | maxAngle = 40; 22 | } 23 | } 24 | 25 | 26 | ///////////////////////////////////////////////////////////////////// 27 | // Scrolling Stuff 28 | // 29 | // default SGDK width is 512 pixels (64 tiles) 30 | #define PLANE_MAX_PIXEL 512 31 | #define PLANE_MAX_TILE 64 32 | 33 | #define ROWS_A 200 34 | #define START_ROW_A 24 35 | #define COLS_A 20 36 | #define START_COL_A 0 37 | s16 hScrollA[224]; 38 | s16 vScrollA[20]; 39 | 40 | 41 | 42 | void setAngle( u16 angle, int centerY ) { 43 | // angle is defined as [0..1024] mapped to [0..2PI] range. 44 | // negative rotation will be 1024 down to 512 45 | // each value is ~ 0.35 degrees / 0.0061 radians. 46 | //KLog_F2x( 4, "c: ", cosFix32(angle), " s: ", sinFix32(angle)); 47 | 48 | for( int row = START_ROW_A; row < START_ROW_A + ROWS_A; ++row ){ 49 | fix32 shift = F32_mul(FIX32( (row - centerY) ), sinFix32(angle)); 50 | // KLog_S2( " row: ", row, " off: ", (row - centerY)); 51 | //KLog_F1x( 4, " shift: ", shift ); 52 | hScrollA[row] = F32_toInt( shift ) - 24; 53 | } 54 | 55 | 56 | 57 | // vertical scroll tiles are 16 pixels wide. Using 8 * (col-10) to scale the scrolling effect 58 | // at the extreme left and right of the screen the factor would be -80 and + 80 59 | for( int col = START_COL_A; col < START_COL_A + COLS_A; ++col ){ 60 | fix32 shift = F32_mul(FIX32( 16 * (col - 10) ), sinFix32(angle)); 61 | vScrollA[col] = F32_toInt( shift ); 62 | } 63 | 64 | 65 | } 66 | 67 | 68 | int main(bool hard) 69 | { 70 | VDP_setScreenWidth320(); 71 | // set colors 72 | PAL_setPalette( PAL0, boss_truck_pal.data, CPU ); 73 | 74 | memset( hScrollA, 0, sizeof(hScrollA)); 75 | memset( vScrollA, 0, sizeof(vScrollA)); 76 | 77 | // set scrolling mode to LINE for horizontal and TILE for vertical 78 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_COLUMN); 79 | 80 | // get tile positions in VRAM. 81 | int ind = TILE_USER_INDEX; 82 | int indexA = ind; 83 | // Load the plane tiles into VRAM 84 | VDP_loadTileSet(bg_boss_truck.tileset, ind, DMA); 85 | 86 | // setup the tiles 87 | VDP_setTileMapEx(BG_A, bg_boss_truck.tilemap, TILE_ATTR_FULL(PAL0, TRUE, FALSE, FALSE, indexA), 88 | 0, // Plane X destination 89 | 0, // plane Y destination 90 | 0, // Region X start position 91 | 0, // Region Y start position 92 | PLANE_MAX_TILE, // width (went with 64 becasue default width is 64. Viewable screen is 40) 93 | 28, // height 94 | CPU); 95 | 96 | 97 | 98 | u16 currAngle = 0; 99 | setAngle(currAngle, 150); 100 | int stepDir = 1; 101 | while (TRUE) 102 | { 103 | // read joypad to set max angle dynamically 104 | readJoypad(JOY_1); 105 | 106 | 107 | // handle rotation 108 | currAngle += stepDir; 109 | if( stepDir ==1 && currAngle <512 ) { 110 | if( currAngle > maxAngle) { 111 | stepDir = -1; 112 | } 113 | } else if ( stepDir == -1 && currAngle == 0 ) { 114 | currAngle =1024; 115 | } else if ( stepDir == -1 && currAngle > 512 ) { 116 | if( currAngle < 1024-maxAngle) { 117 | stepDir = 1; 118 | } 119 | } else if ( stepDir == 1 && currAngle > 1024 ) { 120 | currAngle =0; 121 | } 122 | setAngle(currAngle, 130); 123 | 124 | 125 | 126 | // set scrolling to fake the rotaiton. 127 | VDP_setHorizontalScrollLine(BG_A, START_ROW_A, hScrollA, ROWS_A, DMA); 128 | VDP_setVerticalScrollTile(BG_A, START_COL_A, vScrollA, COLS_A, DMA); 129 | 130 | 131 | // let SGDK do its thing 132 | SYS_doVBlankProcess(); 133 | } 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /01_SimpleScrolling/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | 5 | // Map Position Variables. These are what matter in this example. 6 | fix32 mapPosX; 7 | fix32 mapPosY; 8 | 9 | 10 | // sprite variables 11 | #define PLAYER_FRAME_COUNT 16 12 | fix32 deltaX[PLAYER_FRAME_COUNT]; 13 | fix32 deltaY[PLAYER_FRAME_COUNT]; 14 | int rotationIndex; 15 | Sprite* player; 16 | fix32 playerRotation; 17 | #define MAX_ROTATION_INDEX FIX32(15) 18 | #define MIN_ROTATION_INDEX FIX32(0) 19 | 20 | 21 | void handleInput() { 22 | u16 value = JOY_readJoypad(JOY_1); 23 | 24 | if( value & BUTTON_LEFT ) { 25 | playerRotation += FIX32( 0.25 ); // using fixpoint to slow down the rotation speed a bit. 26 | if( playerRotation > MAX_ROTATION_INDEX ) { 27 | playerRotation = MIN_ROTATION_INDEX; 28 | } 29 | rotationIndex = F32_toInt( playerRotation); 30 | SPR_setAnim( player, rotationIndex); 31 | } else if( value & BUTTON_RIGHT ) { 32 | playerRotation -= FIX32( 0.25 ); 33 | if( playerRotation < MIN_ROTATION_INDEX ) { 34 | playerRotation = MAX_ROTATION_INDEX; 35 | } 36 | rotationIndex = F32_toInt( playerRotation); 37 | SPR_setAnim( player, rotationIndex); 38 | } 39 | 40 | if( value & BUTTON_UP ) { 41 | // pushing UP on the joypad applies motion delta to the map position. 42 | mapPosX = mapPosX + deltaX[rotationIndex]; 43 | if( mapPosX < FIX32(0) ) { 44 | mapPosX = FIX32(0); 45 | }else if( mapPosX > FIX32(6079) ) { // full width of map image. 46 | mapPosX = FIX32(6079); 47 | } 48 | mapPosY = mapPosY + deltaY[rotationIndex]; 49 | if( mapPosY < FIX32(0) ) { 50 | mapPosY = FIX32(0); 51 | }else if( mapPosY > FIX32(2239) ) { // this seems to be as far as I cna go without corrupting the map 52 | mapPosY = FIX32(2239); 53 | } 54 | 55 | } 56 | } 57 | 58 | int main( bool hard ) { 59 | 60 | PAL_setPalette( PAL1, plane_palette.data, CPU); 61 | PAL_setPalette( PAL2, ship_pal.data, CPU ); 62 | 63 | // get our position in VRAM. 64 | int ind = TILE_USER_INDEX; 65 | // Load the plane tiles into VRAM 66 | VDP_loadTileSet( &plane_a_tileset, ind, DMA ); 67 | 68 | // init plane 69 | Map *map_a = MAP_create( &plane_a_map, BG_A, TILE_ATTR_FULL( PAL1, FALSE, FALSE, FALSE, ind ) ); 70 | // set initial map position 71 | mapPosX = FIX32(1440); 72 | mapPosY = FIX32(1120); 73 | 74 | MAP_scrollTo( map_a, F32_toInt(mapPosX), F32_toInt(mapPosY ) ); 75 | 76 | 77 | // Init sprite engine with defaults 78 | SPR_init(); 79 | fix32 posX = FIX32( 160 - 16 ); 80 | fix32 posY = FIX32( 112 - 16 ); 81 | player = SPR_addSprite( &ship, F32_toInt(posX), F32_toInt(posY), TILE_ATTR(PAL2, 0, FALSE, FALSE )); 82 | playerRotation = MIN_ROTATION_INDEX; 83 | SPR_setAnim( player, F32_toInt(playerRotation ) ); 84 | 85 | 86 | // setup map motion delta based on index (index is shared with sprite so scrolling motion 87 | // and player direction match) 88 | deltaX[0] = FIX32( 0.000000 ); 89 | deltaY[0] = FIX32( -2.000000 ); 90 | deltaX[1] = FIX32( -0.765367 ); 91 | deltaY[1] = FIX32( -1.847759 ); 92 | deltaX[2] = FIX32( -1.414214 ); 93 | deltaY[2] = FIX32( -1.414214 ); 94 | deltaX[3] = FIX32( -1.847759 ); 95 | deltaY[3] = FIX32( -0.765367 ); 96 | deltaX[4] = FIX32( -2.000000 ); 97 | deltaY[4] = FIX32( -0.000000 ); 98 | deltaX[5] = FIX32( -1.847759 ); 99 | deltaY[5] = FIX32( 0.765367 ); 100 | deltaX[6] = FIX32( -1.414214 ); 101 | deltaY[6] = FIX32( 1.414214 ); 102 | deltaX[7] = FIX32( -0.765367 ); 103 | deltaY[7] = FIX32( 1.847759 ); 104 | deltaX[8] = FIX32( -0.000000 ); 105 | deltaY[8] = FIX32( 2.000000 ); 106 | deltaX[9] = FIX32( 0.765367 ); 107 | deltaY[9] = FIX32( 1.847759 ); 108 | deltaX[10] = FIX32( 1.414214 ); 109 | deltaY[10] = FIX32( 1.414214 ); 110 | deltaX[11] = FIX32( 1.847759 ); 111 | deltaY[11] = FIX32( 0.765367 ); 112 | deltaX[12] = FIX32( 2.000000 ); 113 | deltaY[12] = FIX32( 0.000000 ); 114 | deltaX[13] = FIX32( 1.847759 ); 115 | deltaY[13] = FIX32( -0.765367 ); 116 | deltaX[14] = FIX32( 1.414214 ); 117 | deltaY[14] = FIX32( -1.414214 ); 118 | deltaX[15] = FIX32( 0.765367 ); 119 | deltaY[15] = FIX32( -1.847759 ); 120 | 121 | 122 | while(TRUE) { 123 | // Read Joypad 124 | handleInput(); 125 | 126 | // Update the sprite 127 | SPR_update(); 128 | 129 | // Set the scrolling position 130 | MAP_scrollTo( map_a, F32_toInt(mapPosX), F32_toInt(mapPosY ) ); 131 | 132 | 133 | SYS_doVBlankProcess(); 134 | } 135 | return 0; 136 | } 137 | 138 | -------------------------------------------------------------------------------- /RotatePy/rotate_-5_to_5/src/rotation.h: -------------------------------------------------------------------------------- 1 | #ifndef _ROTATION_H_ 2 | #define _ROTATION_H_ 3 | 4 | 5 | #define _SCROLL_COUNT 11 6 | #define ROWS_A 61 7 | #define START_ROW_A 73 8 | #define END_ROW_A 133 9 | #define COLS_A 20 10 | #define START_COL_A 0 11 | #define END_COL_A 19 12 | 13 | 14 | s16 _hScroll[] = { 15 | // rotation values for angle -5.000000 starts at 0 16 | 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3 17 | // rotation values for angle -4.000000 starts at 61 18 | , 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2 19 | // rotation values for angle -3.000000 starts at 122 20 | , 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2 21 | // rotation values for angle -2.000000 starts at 183 22 | , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 23 | // rotation values for angle -1.000000 starts at 244 24 | , 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1 25 | // rotation values for angle 0.000000 starts at 305 26 | , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 27 | // rotation values for angle 1.000000 starts at 366 28 | , -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 29 | // rotation values for angle 2.000000 starts at 427 30 | , -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 31 | // rotation values for angle 3.000000 starts at 488 32 | , -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 33 | // rotation values for angle 4.000000 starts at 549 34 | , -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 35 | // rotation values for angle 5.000000 starts at 610 36 | , -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3}; 37 | 38 | 39 | s16 _vScroll[] = { 40 | // rotation values for angle -5.000000 starts at 0 41 | 13, 11, 10, 8, 7, 6, 4, 3, 1, 0, -1, -3, -4, -6, -7, -8, -10, -11, -13, -14 42 | // rotation values for angle -4.000000 starts at 20 43 | , 10, 9, 8, 7, 6, 4, 3, 2, 1, 0, -1, -2, -3, -4, -6, -7, -8, -9, -10, -11 44 | // rotation values for angle -3.000000 starts at 40 45 | , 8, 7, 6, 5, 4, 3, 3, 2, 1, 0, -1, -2, -3, -3, -4, -5, -6, -7, -8, -8 46 | // rotation values for angle -2.000000 starts at 60 47 | , 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -6 48 | // rotation values for angle -1.000000 starts at 80 49 | , 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -3, -3 50 | // rotation values for angle 0.000000 starts at 100 51 | , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 52 | // rotation values for angle 1.000000 starts at 120 53 | , -3, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3 54 | // rotation values for angle 2.000000 starts at 140 55 | , -5, -4, -4, -3, -3, -2, -2, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6 56 | // rotation values for angle 3.000000 starts at 160 57 | , -8, -7, -6, -5, -4, -3, -3, -2, -1, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 8 58 | // rotation values for angle 4.000000 starts at 180 59 | , -10, -9, -8, -7, -6, -4, -3, -2, -1, 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11 60 | // rotation values for angle 5.000000 starts at 200 61 | , -13, -11, -10, -8, -7, -6, -4, -3, -1, 0, 1, 3, 4, 6, 7, 8, 10, 11, 13, 14 62 | }; 63 | 64 | 65 | #endif // _ROTATION_H_ 66 | -------------------------------------------------------------------------------- /RotatePy/rotation_and_translation/src/rotation.h: -------------------------------------------------------------------------------- 1 | #ifndef _ROTATION_H_ 2 | #define _ROTATION_H_ 3 | 4 | 5 | #define _SCROLL_COUNT 11 6 | #define ROWS_A 61 7 | #define START_ROW_A 73 8 | #define END_ROW_A 133 9 | #define COLS_A 20 10 | #define START_COL_A 0 11 | #define END_COL_A 19 12 | 13 | 14 | s16 _hScroll[] = { 15 | // rotation values for angle -5.000000 starts at 0 16 | 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3 17 | // rotation values for angle -4.000000 starts at 61 18 | , 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2 19 | // rotation values for angle -3.000000 starts at 122 20 | , 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2 21 | // rotation values for angle -2.000000 starts at 183 22 | , 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 23 | // rotation values for angle -1.000000 starts at 244 24 | , 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1 25 | // rotation values for angle 0.000000 starts at 305 26 | , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 27 | // rotation values for angle 1.000000 starts at 366 28 | , -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 29 | // rotation values for angle 2.000000 starts at 427 30 | , -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 31 | // rotation values for angle 3.000000 starts at 488 32 | , -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2 33 | // rotation values for angle 4.000000 starts at 549 34 | , -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 35 | // rotation values for angle 5.000000 starts at 610 36 | , -3, -3, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3}; 37 | 38 | 39 | s16 _vScroll[] = { 40 | // rotation values for angle -5.000000 starts at 0 41 | 13, 11, 10, 8, 7, 6, 4, 3, 1, 0, -1, -3, -4, -6, -7, -8, -10, -11, -13, -14 42 | // rotation values for angle -4.000000 starts at 20 43 | , 10, 9, 8, 7, 6, 4, 3, 2, 1, 0, -1, -2, -3, -4, -6, -7, -8, -9, -10, -11 44 | // rotation values for angle -3.000000 starts at 40 45 | , 8, 7, 6, 5, 4, 3, 3, 2, 1, 0, -1, -2, -3, -3, -4, -5, -6, -7, -8, -8 46 | // rotation values for angle -2.000000 starts at 60 47 | , 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -6 48 | // rotation values for angle -1.000000 starts at 80 49 | , 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -3, -3 50 | // rotation values for angle 0.000000 starts at 100 51 | , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 52 | // rotation values for angle 1.000000 starts at 120 53 | , -3, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3 54 | // rotation values for angle 2.000000 starts at 140 55 | , -5, -4, -4, -3, -3, -2, -2, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6 56 | // rotation values for angle 3.000000 starts at 160 57 | , -8, -7, -6, -5, -4, -3, -3, -2, -1, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 8 58 | // rotation values for angle 4.000000 starts at 180 59 | , -10, -9, -8, -7, -6, -4, -3, -2, -1, 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11 60 | // rotation values for angle 5.000000 starts at 200 61 | , -13, -11, -10, -8, -7, -6, -4, -3, -1, 0, 1, 3, 4, 6, 7, 8, 10, 11, 13, 14 62 | }; 63 | 64 | 65 | #endif // _ROTATION_H_ 66 | -------------------------------------------------------------------------------- /waves/ex2/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | #define TOTAL_LINES 224 5 | 6 | #define BUBBLE_COUNT 20 7 | 8 | typedef struct 9 | { 10 | Sprite *sprite; 11 | s16 pos_x; 12 | s16 pos_y; 13 | s16 vel_y; 14 | u16 sinPerLine; 15 | fix16 amplitude; 16 | 17 | } CP_SPRITE; 18 | 19 | CP_SPRITE bubbles[BUBBLE_COUNT]; 20 | 21 | void createBubbles() { 22 | for( u16 i=0; i < BUBBLE_COUNT; ++i ) { 23 | bubbles[i].pos_x = random() % ( 320 - 32); 24 | bubbles[i].pos_y = random() % ( 224 - 32); 25 | bubbles[i].vel_y = random() % ( 4) + 1; 26 | bubbles[i].sinPerLine = random() % 5 + 5; 27 | bubbles[i].amplitude = FIX16( random() % 7 + 10 ); 28 | bubbles[i].sprite = SPR_addSprite( &bubble, F16_toInt( bubbles[i].pos_x), bubbles[i].pos_y, TILE_ATTR( PAL1, 0, FALSE, FALSE)); 29 | } 30 | } 31 | 32 | void updateBubbles() { 33 | for( u16 i=0; i < BUBBLE_COUNT; ++i ) { 34 | bubbles[i].pos_y -= bubbles[i].vel_y; 35 | if( bubbles[i].pos_y < -32 ) { 36 | bubbles[i].pos_y = 224; 37 | } 38 | s16 x = F16_toInt( F16_mul( sinFix16( bubbles[i].pos_y * bubbles[i].sinPerLine ), bubbles[i].amplitude ) ) + bubbles[i].pos_x; 39 | SPR_setPosition( bubbles[i].sprite, x, bubbles[i].pos_y); 40 | } 41 | 42 | } 43 | 44 | int main(bool hard) { 45 | 46 | ////////////////////////////////////////////////////////////// 47 | // setup screen and palettes 48 | VDP_setBackgroundColor(16); 49 | VDP_setScreenWidth320(); 50 | 51 | PAL_setPalette( PAL0, bg_pal.data, CPU ); 52 | PAL_setPalette( PAL1, fg_pal.data, CPU ); 53 | 54 | ////////////////////////////////////////////////////////////// 55 | // setup scrolling 56 | int ind = TILE_USER_INDEX; 57 | VDP_drawImageEx(BG_B, &bg, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, ind), 0, 0, FALSE, TRUE); 58 | ind += bg.tileset->numTile; 59 | VDP_drawImageEx(BG_A, &fg, TILE_ATTR_FULL(PAL1, FALSE, FALSE, FALSE, ind), 0, 0, FALSE, TRUE); 60 | ind += fg.tileset->numTile; 61 | 62 | // use LINE scroll for horizontal 63 | VDP_setScrollingMode( HSCROLL_LINE, VSCROLL_PLANE); 64 | 65 | // background 66 | s16 hScrollB[TOTAL_LINES]; 67 | memset( hScrollB, 0, sizeof(hScrollB)); 68 | 69 | 70 | u16 sinPerLine = 5; // Elements to jump in sin() per line. Larger values give us faster waves. 71 | fix16 amplitude = FIX16( 10.0 ); // Amplitude sets how big the waves are. 72 | s16 offsetB = -10; // shift left a bit. 73 | fix16 fOffsetB = FIX16(-10); // shift left a bit. 74 | 75 | 76 | // foreground 77 | s16 hScrollA[TOTAL_LINES]; 78 | s16 offsetA = 0; // shift left a bit. 79 | s16 aDir = -1; 80 | memset( hScrollA, 0, sizeof(hScrollA)); 81 | 82 | 83 | ////////////////////////////////////////////////////////////// 84 | // sprites 85 | SPR_init(); 86 | createBubbles(); 87 | 88 | ////////////////////////////////////////////////////////////// 89 | // main loop. 90 | u16 sinOffset = 0; // Step basically tells us where we're starting in the sin table. 91 | while(TRUE) 92 | { 93 | // read joypad to set horizontal scrolling positions. 94 | u16 joypad = JOY_readJoypad( JOY_1 ); 95 | if( joypad & BUTTON_LEFT ) { 96 | offsetA +=2; 97 | if ( offsetA > 0 ) { 98 | offsetA = 0; 99 | } else { 100 | fOffsetB = fOffsetB + FIX16(0.75); 101 | offsetB = F16_toInt( fOffsetB ); 102 | } 103 | } else if( joypad & BUTTON_RIGHT ) { 104 | offsetA -=2; 105 | if ( offsetA < -158 ) { 106 | offsetA = -158; 107 | } else { 108 | fOffsetB = fOffsetB - FIX16(0.75); 109 | offsetB = F16_toInt( fOffsetB ); 110 | } 111 | } 112 | 113 | 114 | ////////////////////////////////////////////////////////////// 115 | // Wavy scrolling 116 | // calculate the offsets per line using SGDK's sin table 117 | // and adjust with params 118 | sinOffset++; // move up in the sine table 119 | for( u16 i = 0; i < TOTAL_LINES; ++i ) { 120 | // compute horizontal offsets with sine table. 121 | hScrollB[i] = F16_toInt( F16_mul( sinFix16(( i + sinOffset ) * sinPerLine ), amplitude ) ) + offsetB; 122 | hScrollA[i] = offsetA; 123 | } 124 | 125 | 126 | ////////////////////////////////////////////////////////////// 127 | // update sprites 128 | updateBubbles(); 129 | SPR_update(); 130 | 131 | // apply scrolling offsets 132 | VDP_setHorizontalScrollLine (BG_B, 0, hScrollB, 223, DMA_QUEUE); 133 | VDP_setHorizontalScrollLine (BG_A, 0, hScrollA, 223, DMA_QUEUE); 134 | SYS_doVBlankProcess(); 135 | 136 | } 137 | return 0; 138 | 139 | } 140 | -------------------------------------------------------------------------------- /HScrollDec/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | // default SGDK width is 512 pixels (64 tiles) 5 | #define PLANE_MAX_PIXEL 512 6 | #define PLANE_MAX_TILE 64 7 | 8 | // Images in this project are 1280 pixels wide ( tiles) 9 | #define IMAGE_MAX_PIXEL 1280 10 | #define IMAGE_MAX_TILE 160 11 | 12 | fix32 offsetA = FIX32(0); 13 | fix32 imageOffsetA = FIX32(0); 14 | u16 lastSrcColA = -1; 15 | u16 lastDstColA = -1; 16 | 17 | fix32 offsetB = FIX32(0); 18 | fix32 imageOffsetB = FIX32(0); 19 | u16 lastSrcColB = -1; 20 | u16 lastDstColB = -1; 21 | 22 | s16 scrollPlane(VDPPlane plane, const TileMap *tilemap, int index, fix32 speed, fix32 *planeOffset, fix32 *imageOffset, u16 *lastSrcCol, u16 *lastDstCol) 23 | { 24 | // Set the scrolling position 25 | *planeOffset = *planeOffset + speed; 26 | if (*planeOffset >= FIX32(PLANE_MAX_PIXEL)) 27 | *planeOffset = FIX32(0); // plane in memory is 512 pixels wide 28 | *imageOffset = *imageOffset + speed; 29 | if (*imageOffset >= FIX32(IMAGE_MAX_PIXEL)) 30 | *imageOffset = FIX32(0); // bg image is 1280 pixels wide 31 | s16 sPlaneOffset = F32_toInt(*planeOffset); 32 | // check if we need a new tile 33 | if (sPlaneOffset % 8 == 0) 34 | { 35 | // get destination column (in tiles) 36 | s16 dstCol = (sPlaneOffset + PLANE_MAX_PIXEL - 8) / 8; 37 | if (dstCol >= PLANE_MAX_TILE) 38 | { 39 | dstCol -= PLANE_MAX_TILE; // wrap around to the start of the plane 40 | } 41 | 42 | // get source column (in tiles) 43 | s16 sImageOffset = F32_toInt(*imageOffset); 44 | s16 srcCol = (sImageOffset + PLANE_MAX_PIXEL - 8) / 8; 45 | if (srcCol >= IMAGE_MAX_TILE) 46 | { 47 | srcCol -= IMAGE_MAX_TILE; // wrap around to the start of the image 48 | } 49 | KLog_S4("dstCol: ", dstCol, " lastDisCol: ", *lastDstCol, " srcCol: ", srcCol, " lastSrcCol: ", *lastSrcCol); 50 | // if the current destination column is smaller n 51 | // the last one, the region is *notnuous 52 | // Two or more tile moves may be required. 53 | if (dstCol != *lastDstCol) 54 | { 55 | s16 width = dstCol - *lastDstCol; 56 | if (width < 0) 57 | { 58 | width += PLANE_MAX_TILE; 59 | } 60 | // just loop for now ( probably inefficient if there are a lot of columns to copy) 61 | s16 tmpDst = *lastDstCol + 1; 62 | s16 tmpSrc = *lastSrcCol + 1; 63 | for (s16 i = 0; i < width; ++i) 64 | { 65 | if (tmpDst >= PLANE_MAX_TILE) 66 | { 67 | tmpDst = 0; 68 | } 69 | if (tmpSrc >= IMAGE_MAX_TILE) 70 | { 71 | tmpSrc = 0; 72 | } 73 | KLog_S3(" C dst: ", tmpDst, " src: ", tmpSrc, " width ", 1); 74 | VDP_setTileMapEx(plane, tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, index), 75 | tmpDst, // Plane X destination 76 | 0, // plane Y destination 77 | tmpSrc, // Region X start position 78 | 0, // Region Y start position 79 | 1, // width ( will this wrap? ) 80 | 28, // height 81 | CPU); 82 | tmpDst++; 83 | tmpSrc++; 84 | } 85 | *lastDstCol = tmpDst - 1; 86 | *lastSrcCol = tmpSrc - 1; 87 | KLog_S2(" lastDstCol: ", *lastDstCol, " lastSrcCol: ", *lastSrcCol ); 88 | } 89 | } 90 | return sPlaneOffset; 91 | } 92 | 93 | int main(bool hard) 94 | { 95 | 96 | PAL_setPalette(PAL0, bg_palette_a.data, CPU); 97 | 98 | // set scrolling mode. Affects the WHOLE plane 99 | VDP_setScrollingMode(HSCROLL_PLANE, VSCROLL_PLANE); 100 | 101 | // get our position in VRAM. 102 | int ind = TILE_USER_INDEX; 103 | int indexA = ind; 104 | // Load the plane tiles into VRAM 105 | VDP_loadTileSet(bg_image_a.tileset, ind, DMA); 106 | int indexB = ind + bg_image_a.tileset->numTile; // new 107 | VDP_loadTileSet(bg_image_b.tileset, indexB, DMA); 108 | 109 | // put out the image 110 | VDP_setTileMapEx(BG_A, bg_image_a.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexA), 111 | 0, // Plane X destination 112 | 0, // plane Y destination 113 | 0, // Region X start position 114 | 0, // Region Y start position 115 | PLANE_MAX_TILE, // width (went with 64 becasue default width is 64. Viewable screen is 40) 116 | 28, // height 117 | CPU); 118 | lastDstColA = PLANE_MAX_TILE - 1; 119 | lastSrcColA = PLANE_MAX_TILE - 1; 120 | VDP_setTileMapEx(BG_B, bg_image_b.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexB), 121 | 0, 122 | 0, 123 | 0, 124 | 0, 125 | PLANE_MAX_TILE, 126 | 28, 127 | CPU); 128 | lastDstColB = PLANE_MAX_TILE - 1; 129 | lastSrcColB = PLANE_MAX_TILE - 1; 130 | int count = 0; 131 | while (TRUE) 132 | { 133 | s16 sPlaneOffsetA = scrollPlane(BG_A, bg_image_a.tilemap, indexA, FIX32(4.5), &offsetA, &imageOffsetA, &lastSrcColA, &lastDstColA); 134 | KLog_S2("count: ", count, " offset: ", sPlaneOffsetA); 135 | KLog_F1(" offsetA: ", offsetA); 136 | s16 sPlaneOffsetB = scrollPlane(BG_B, bg_image_b.tilemap, indexB, FIX32(0.05), &offsetB, &imageOffsetB, &lastSrcColB, &lastDstColB); 137 | 138 | VDP_setHorizontalScroll(BG_A, -sPlaneOffsetA); // negative moves plane to left, positive to right 139 | VDP_setHorizontalScroll(BG_B, -sPlaneOffsetB); 140 | 141 | // let SGDK do its thing 142 | SYS_doVBlankProcess(); 143 | ++count; 144 | } 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /HScrollTiled/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | // default SGDK width is 512 pixels (64 tiles) 5 | #define PLANE_MAX_PIXEL 512 6 | #define PLANE_MAX_TILE 64 7 | 8 | // Images in this project are 1280 pixels wide ( tiles) 9 | #define IMAGE_MAX_PIXEL 1280 10 | #define IMAGE_MAX_TILE 160 11 | 12 | // 13 | // 0-2 don't scroll. no need 14 | // 3-4 fastest cloud <<<<<< START BG_B 15 | // 5 16 | // 6 17 | // 7-8 slowest cloud <<<<<< START BG_A (21 rows for A) 18 | // 9-11 the distance. slowest of all 19 | // 12-13 slowest land 20 | // 14 <<<<<< END BG_B (15 rows vor B) 21 | // 15 22 | // 16 23 | // 17-19 24 | // 20-27 fastest gorund <<<<<<< END BG_A 25 | #define ROWS_A 21 26 | #define START_ROW_A 7 27 | fix32 speedA[ROWS_A]; 28 | fix32 planeOffsetA[ROWS_A]; 29 | fix32 imageOffsetA[ROWS_A]; 30 | u16 lastSrcColA[ROWS_A]; 31 | u16 lastDstColA[ROWS_A]; 32 | s16 scrollA[ROWS_A]; 33 | 34 | #define ROWS_B 12 35 | #define START_ROW_B 3 36 | fix32 speedB[ROWS_B]; 37 | fix32 planeOffsetB[ROWS_B]; 38 | fix32 imageOffsetB[ROWS_B]; 39 | u16 lastSrcColB[ROWS_B]; 40 | u16 lastDstColB[ROWS_B]; 41 | s16 scrollB[ROWS_B]; 42 | 43 | void updateTiles(VDPPlane plane, const TileMap *tilemap, int index, 44 | fix32 *speed, 45 | fix32 *planeOffset, 46 | fix32 *imageOffset, 47 | u16 *lastSrcCol, 48 | u16 *lastDstCol, 49 | s16 *scroll, 50 | u16 startRow, 51 | u16 rows) 52 | { 53 | 54 | for (s16 row = 0; row < rows; ++row) 55 | { 56 | // Set the scrolling position of plane per row 57 | planeOffset[row] = planeOffset[row] + speed[row]; 58 | if (planeOffset[row] >= FIX32(PLANE_MAX_PIXEL)) // plane in memory is 512 pixels wide 59 | { 60 | planeOffset[row] = FIX32(0); 61 | } 62 | 63 | // keep track of where we are in the image per row 64 | imageOffset[row] = imageOffset[row] + speed[row]; 65 | if (imageOffset[row] >= FIX32(IMAGE_MAX_PIXEL)) // bg image is 1280 pixels wide 66 | { 67 | imageOffset[row] = FIX32(0); 68 | } 69 | s16 sPlaneOffset = F32_toInt(planeOffset[row]); 70 | // check if we need a new tile 71 | if (sPlaneOffset % 8 == 0) 72 | { 73 | // get destination column (in tiles) 74 | s16 dstCol = (sPlaneOffset + PLANE_MAX_PIXEL - 8) / 8; 75 | if (dstCol >= PLANE_MAX_TILE) 76 | { 77 | dstCol -= PLANE_MAX_TILE; // wrap around to the start of the plane 78 | } 79 | 80 | // get source column (in tiles) 81 | s16 sImageOffset = F32_toInt(imageOffset[row]); 82 | s16 srcCol = (sImageOffset + PLANE_MAX_PIXEL - 8) / 8; 83 | if (srcCol >= IMAGE_MAX_TILE) 84 | { 85 | srcCol -= IMAGE_MAX_TILE; // wrap around to the start of the image 86 | } 87 | // if the current destination column is smaller n 88 | // the last one, the region is *notnuous 89 | // Two or more tile moves may be required. 90 | if (dstCol != lastDstCol[row]) 91 | { 92 | s16 width = dstCol - lastDstCol[row]; 93 | if (width < 0) 94 | { 95 | width += PLANE_MAX_TILE; 96 | } 97 | // just loop for now ( probably inefficient if there are a lot of columns to copy) 98 | s16 tmpDst = lastDstCol[row] + 1; 99 | s16 tmpSrc = lastSrcCol[row] + 1; 100 | for (s16 i = 0; i < width; ++i) 101 | { 102 | if (tmpDst >= PLANE_MAX_TILE) 103 | { 104 | tmpDst = 0; 105 | } 106 | if (tmpSrc >= IMAGE_MAX_TILE) 107 | { 108 | tmpSrc = 0; 109 | } 110 | VDP_setTileMapEx(plane, tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, index), 111 | tmpDst, // Plane X destination 112 | startRow + row, // plane Y destination 113 | tmpSrc, // Region X start position 114 | startRow + row, // Region Y start position 115 | 1, // width 116 | 1, // height 117 | CPU); 118 | tmpDst++; 119 | tmpSrc++; 120 | } 121 | lastDstCol[row] = tmpDst - 1; 122 | lastSrcCol[row] = tmpSrc - 1; 123 | } 124 | } 125 | scroll[row] = -sPlaneOffset; 126 | } 127 | } 128 | 129 | void setupA() 130 | { 131 | // setup scrolling vals 132 | for (int row = 0; row < ROWS_A; ++row) 133 | { 134 | planeOffsetA[row] = FIX32(0); 135 | imageOffsetA[row] = FIX32(0); 136 | lastSrcColA[row] = PLANE_MAX_TILE - 1; 137 | lastDstColA[row] = PLANE_MAX_TILE - 1; 138 | scrollA[row] = 0; 139 | } 140 | // 7-15 are 2nd slowest land value 141 | for (int row = 7; row <= 16; ++row) 142 | { 143 | speedA[row - START_ROW_A] = FIX32(2.2); 144 | } 145 | // 17-19 146 | for (int row = 17; row <= 19; ++row) 147 | { 148 | speedA[row - START_ROW_A] = FIX32(3.5); 149 | } 150 | // 20-27 fastest ground 151 | for (int row = 20; row < 23; ++row) 152 | { 153 | speedA[row - START_ROW_A] = FIX32(4.7); 154 | } 155 | for (int row = 23; row <= 27; ++row) 156 | { 157 | speedA[row - START_ROW_A] = FIX32(7.6); 158 | } 159 | } 160 | 161 | void setupB() 162 | { 163 | // setup scrolling vals 164 | for (int row = 0; row < ROWS_B; ++row) 165 | { 166 | planeOffsetB[row] = FIX32(0); 167 | imageOffsetB[row] = FIX32(0); 168 | lastSrcColB[row] = PLANE_MAX_TILE - 1; 169 | lastDstColB[row] = PLANE_MAX_TILE - 1; 170 | scrollB[row] = 0; 171 | } 172 | // 3-4 fastest cloud 173 | speedB[0] = FIX32(6); 174 | speedB[1] = FIX32(6); 175 | // 5 176 | speedB[2] = FIX32(3); 177 | // 6 178 | speedB[3] = FIX32(1.5); 179 | // 7-8 slowest cloud 180 | speedB[4] = FIX32(0.75); 181 | speedB[5] = FIX32(0.75); 182 | // 9-11 the distances 183 | speedB[6] = FIX32(0.075); 184 | speedB[7] = FIX32(0.075); 185 | speedB[8] = FIX32(0.075); 186 | // 12-13 slow land 187 | speedB[9] = FIX32(0.5); 188 | speedB[10] = FIX32(1.0); 189 | // 14 190 | speedB[11] = FIX32(1.5); 191 | } 192 | 193 | int main(bool hard) 194 | { 195 | //setup values 196 | setupA(); 197 | setupB(); 198 | 199 | // set color palette 0 200 | PAL_setPalette(PAL0, bg_palette_a.data, CPU); 201 | 202 | // set scrolling mode to TILE for horizontal. 203 | VDP_setScrollingMode(HSCROLL_TILE, VSCROLL_PLANE); 204 | 205 | // get tile positions in VRAM. 206 | int ind = TILE_USER_INDEX; 207 | int indexA = ind; 208 | // Load the plane tiles into VRAM 209 | VDP_loadTileSet(bg_image_a.tileset, ind, DMA); 210 | int indexB = ind + bg_image_a.tileset->numTile; // new 211 | VDP_loadTileSet(bg_image_b.tileset, indexB, DMA); 212 | 213 | // put out the image 214 | VDP_setTileMapEx(BG_A, bg_image_a.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexA), 215 | 0, // Plane X destination 216 | 0, // plane Y destination 217 | 0, // Region X start position 218 | 0, // Region Y start position 219 | PLANE_MAX_TILE, // width (went with 64 becasue default width is 64. Viewable screen is 40) 220 | 28, // height 221 | CPU); 222 | VDP_setTileMapEx(BG_B, bg_image_b.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexB), 223 | 0, 224 | 0, 225 | 0, 226 | 0, 227 | PLANE_MAX_TILE, 228 | 28, 229 | CPU); 230 | 231 | while (TRUE) 232 | { 233 | updateTiles(BG_A, bg_image_a.tilemap, indexA, 234 | speedA, 235 | planeOffsetA, 236 | imageOffsetA, 237 | lastSrcColA, 238 | lastDstColA, 239 | scrollA, 240 | START_ROW_A, 241 | ROWS_A); 242 | VDP_setHorizontalScrollTile(BG_A, START_ROW_A, scrollA, ROWS_A, CPU); 243 | 244 | updateTiles(BG_B, bg_image_b.tilemap, indexB, 245 | speedB, 246 | planeOffsetB, 247 | imageOffsetB, 248 | lastSrcColB, 249 | lastDstColB, 250 | scrollB, 251 | START_ROW_B, 252 | ROWS_B); 253 | VDP_setHorizontalScrollTile(BG_B, START_ROW_B, scrollB, ROWS_B, CPU); 254 | // let SGDK do its thing 255 | SYS_doVBlankProcess(); 256 | } 257 | return 0; 258 | } 259 | -------------------------------------------------------------------------------- /EndlessScroll/README.md: -------------------------------------------------------------------------------- 1 | # Endless Scroll Image Generation Script 2 | 3 | `sgdk_endless_scroll.py` is a simple Python script that creates endless 4 | scrolling images for use with Sega Genesis / SGDK. You must supply at least 5 | one 16-color indexed image to be warped into a repeating floor pattern. The 6 | generated image can optionally have a ceiling pattern. The ceiling can use 7 | the same image as the floor or a separate image can supplied for the ceiling 8 | pattern. 9 | 10 | ## TODO 11 | The script has some rough edges, but does what I needed it to. There are 12 | some obvious things that could be improved: 13 | 14 | * Check input values for invalid combinations 15 | * Blend pixels at edges of warp pattern (or sample images instead of 16 | using OpenCV's warp) 17 | * Generate code with user configurable scrolling step sizes 18 | * Generate code with lookup tables for scrolling values 19 | 20 | I'll likely add code to check input values and handle odd numbers, but this 21 | script is very low priority. I may never get around to the rest of it. 22 | 23 | 24 | ## Dependencies 25 | The script was written for [Python3](https://www.python.org/downloads/) and requires 26 | [NumPy](https://numpy.org/), [PILLOW](https://python-pillow.org/), and 27 | [OpenCV](https://opencv.org/). 28 | 29 | I'm using WSL and Ubuntu 22.02 on my development machine, but I imagine 30 | most people will be using Windows. I'm going to keep on using WSL, but 31 | I have installed the windows versions to test the script. 32 | 1. Get Python3. I used the Microsoft Store version. 33 | 34 | 2. Install the dependencies. I opened a command line window and typed: 35 | ```cmd 36 | pip3 install numpy 37 | pip3 install pillow 38 | pip3 install opencv-python 39 | pip3 install jinja2 40 | ``` 41 | 3. Run the script with: 42 | ```cmd 43 | python3 sgdk_endless_scroll.py 44 | ``` 45 | 46 | # Basic usage 47 | 48 | ```bash 49 | usage: sgdk_endless_scroll.py [-h] [-v] [-f ARG] [-n ARG] [-s ARG] [-e ARG] 50 | [-i ARG] [-S ARG] [-E ARG] [-I ARG] [-o ARG] 51 | [-p ARG] 52 | 53 | Create parallax scrolling background for SGDK 54 | 55 | options: 56 | -h, --help show this help message and exit 57 | -v, --verbose increase output verbosity 58 | -f ARG, --far_image_reps ARG 59 | How many times to repeat image at far side of floor 60 | -n ARG, --near_image_reps ARG 61 | How many times to repeat image at near side of floor 62 | -s ARG, --start_row ARG 63 | Which row starts the floor 64 | -e ARG, --end_row ARG 65 | Which row ends the floor 66 | -i ARG, --input_filename ARG 67 | input image filename 68 | -S ARG, --start_ceiling_row ARG 69 | Which row starts the ceiling 70 | -E ARG, --end_ceiling_row ARG 71 | Which row ends the ceiling 72 | -I ARG, --input_ceiling_filename ARG 73 | input ceiling image filename 74 | -o ARG, --output_filename ARG 75 | Output filename 76 | -p ARG, --project_directory ARG 77 | Create project directory with resource files and simple SGDK code. 78 | ``` 79 | 80 | # Examples 81 | ## Floor with two near repetitions and four far repetitions 82 | The default behavior is to take an input image named "image.png" and repeated 83 | it twice at the bottom row of the image (row 223) and four times at the top of 84 | the floor pattern (row 80). Type 85 | ```bash 86 | python3 sgdk_endless_scroll.py 87 | ``` 88 | This generates an image called `bg.png` and should output text similar to the 89 | following 90 | ```cmd 91 | Scroll width far: 80.000 92 | Scroll width near: 160.000 93 | Starting row floor: 180 94 | Ending row floor: 223 95 | * Scroll increment floor: 0.0233 96 | * Final Scroll increment floor: 1.8605 97 | Image size 480 x 224 98 | ``` 99 | ![default background](https://raw.githubusercontent.com/radioation/SGDK_Scrolling/main/EndlessScroll/bg.png) 100 | The output gives you information you can use to scroll the image. 101 | * Scroll width far 80.000 : The repeated image takes up 80 pixels at the top row of the floor. 102 | * Scroll width near 160.000 : The repeated image takes up 160 pixels at the bottom row of the floor. 103 | * Starting row floor 180 : The floor starts at row 180 in the output image 104 | * Ending row floor 223 : The floor ends at row 223 in the output image 105 | * Scroll increment floor 0.0233 : The amount each successive scroll line should increase if you're scrolling the top row by one pixel. 106 | * Final Scroll increment floor 1.8605 : The amount each floor row differs by before the scroll values needs to be reset. 107 | * Image size 480 x 224 : The size of the output image. 108 | 109 | 110 | 111 | If you want the floor rows to scroll right to left, you'd move row 80 left 112 | by one pixel, row 81 left by 1.0233 pixels, row 81 by 1.0466, pixels, and so 113 | on. 114 | ```c 115 | ++scrollStep; 116 | fix32 fStep = FIX32(1.0); 117 | for( u16 row=180; row<224; ++row ) { 118 | fscroll[row] = fscroll[row] - fStep; // shift row left 119 | fStep = fStep + FIX32(0.0233); // change shift by 0.0233 pixels 120 | } 121 | ``` 122 | This works up to 80 pixels for the top row. This is because the output image 123 | only has enough pixles drawn to scroll one repetition. To handle this, reset 124 | the scroll values when the top row has moved 80 pixels. 125 | ```c 126 | scrollStep = 0; 127 | memset(fscroll, 0, sizeof(fscroll)); // zero out all scroll values 128 | ``` 129 | Put together: 130 | ```c 131 | static scrollLeftLoop() { 132 | ++scrollStep; 133 | fix32 fStep = FIX32(1.0); 134 | if (scrollStep < 80) { 135 | for( u16 row=180; row<224; ++row ) { 136 | fscroll[row] = fscroll[row] - fStep; 137 | fStep = fStep + FIX32(0.0233); 138 | } 139 | } else { 140 | scrollStep = 0; 141 | memset(fscroll, 0, sizeof(fscroll)); 142 | } 143 | } 144 | ``` 145 | 146 | Scrolling the floor left to right is similar. The main difference is you 147 | move the rows in the opposite direction. Row 80 moves to the right by one 148 | pixel, row 81 right by 1.0233 pixels, row 81 by 1.0466, pixels, etc. 149 | ```c 150 | --scrollStep; 151 | fix32 fStep = FIX32(1.0); 152 | for (u16 row = 180; row < 224; ++row) 153 | { 154 | fscroll[row] = fscroll[row] + fStep; 155 | fStep = fStep + FIX32(0.0233); 156 | } 157 | ``` 158 | Again, this only works up to 80 pixels for the top row. Resetting the scroll 159 | lines is a bit more complex here. You have to put all of the lines at their 160 | Final scroll position. This can be computed with the 'final scroll increment' 161 | value output from the script. In this case: 162 | 163 | `* Final Scroll increment floor: 1.8605` 164 | 165 | ```c 166 | scrollStep = 80; 167 | fix32 scroll = FIX32(-80.0); // scrolled by 80. 168 | for (u16 row = 180; row < 224; ++row) 169 | { 170 | fscroll[row] = scroll; 171 | scroll = scroll - FIX32(1.8605); // decrement by final value 172 | } 173 | ``` 174 | Put together: 175 | ```c 176 | static scrollRightLoop() 177 | { 178 | --scrollStep; 179 | fix32 fStep = FIX32(1.0); 180 | if (scrollStep >= 0) 181 | { 182 | for (u16 row = 180; row < 224; ++row) 183 | { 184 | fscroll[row] = fscroll[row] + fStep; 185 | fStep = fStep + FIX32(0.0233); 186 | } 187 | } 188 | else 189 | { 190 | scrollStep = 80; 191 | fix32 scroll = FIX32(-80.0); 192 | for (u16 row = 180; row < 224; ++row) 193 | { 194 | fscroll[row] = scroll; 195 | scroll = scroll - FIX32(1.8605); 196 | } 197 | } 198 | } 199 | ``` 200 | 201 | ## Floor with four near repetitions and 6 far repetitions 202 | You can increase the number of image repetitions with the `-f` and `-n` 203 | parameters. To have six repetitions at the far side of the floor and four 204 | repetitions at the near side run these parameters: 205 | ```bash 206 | python3 sgdk_endless_scroll.py -i test_tile.png -f 6 -n 4 -o tilefloor.png 207 | ``` 208 | I also specified a different floor image with the `-i` parameter and changed the 209 | output filename with `-o`. 210 | ![Tile Floor](https://raw.githubusercontent.com/radioation/SGDK_Scrolling/main/EndlessScroll/tilefloor.png) 211 | ## Add a ceiling 212 | Adding a ceiling can be done by specifying the start (`-S`) and end (`-E`) rows for the ceiling. 213 | ```bash 214 | python3 sgdk_endless_scroll.py -i test_wood.png -f 6 -n 4 -S 8 -E 48 -o woodceil.png 215 | ``` 216 | ![Wood Ceiling](https://raw.githubusercontent.com/radioation/SGDK_Scrolling/main/EndlessScroll/woodceil.png) 217 | ## Add a ceiling with its own tile images 218 | Specifying `-I` lets you add a second image for the ceiling. 219 | ```bash 220 | python3 sgdk_endless_scroll.py -i test_wood.png -f 6 -n 4 -S 8 -E 48 -I test_tile.png -o woodfloor_tileceiling.png 221 | ``` 222 | ![Wood Floor Tile Ceiling](https://raw.githubusercontent.com/radioation/SGDK_Scrolling/main/EndlessScroll/woodfloor_tileceiling.png) 223 | 224 | ## Create an example project 225 | Specifying a folder with the `-p` parameter will create a project folder with files for SGDK. 226 | If your environment is setup correctly, the project files can be built with: 227 | ```cmd 228 | %GDK%\bin\make -f %GDK%\makefile.gen 229 | ``` 230 | 231 | 232 | 233 | 234 | 235 | -------------------------------------------------------------------------------- /RotationDual/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | 5 | ///////////////////////////////////////////////////////////////////// 6 | // Scrolling 7 | // 8 | // default SGDK width is 512 pixels (64 tiles) 9 | #define PLANE_MAX_PIXEL 384 10 | #define PLANE_MAX_HORIZONTAL_TILE 48 11 | #define PLANE_MAX_VERTICAL_TILE 32 12 | s16 hScrollA[224]; 13 | s16 vScrollA[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 14 | s16 vScrollUpperA[20]; 15 | s16 vScrollLowerA[20]; 16 | s16 planeADeltas[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 17 | 18 | s16 vScrollB[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 19 | s16 planeBDeltas[20] = {9, 9, 7, 7, 5, 5, 5, 4, 3, 2, 2, 3, 4, 5, 5, 5, 7, 7, 9, 9}; 20 | //s16 planeBDeltas[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 21 | 22 | // setup fake rotation by changing the foreground horizontal and vertical scrolling 23 | void setAngle( u16 angle, s16 startY, s16 endY, s16 centerY, s16 vscroll[], s16 hOffset, s16 vOffset ) { 24 | for( int row = startY; row < endY; ++row ){ 25 | fix32 shift = F32_mul(FIX32( (row - centerY)>>1 ), sinFix32(angle)); 26 | hScrollA[row] = F32_toInt( shift ) - 32 + hOffset; 27 | } 28 | 29 | // vertical scroll tiles are 16 pixels wide. Using 8 * (col-10) to scale the scrolling effect 30 | // at the extreme left and right of the screen the factor would be -80 and + 80 31 | for( int col = 1; col < 19; ++col ){ 32 | fix32 shift = F32_mul(FIX32( (col - 9)<<3 ), sinFix32(angle)); 33 | vscroll[col] = F32_toInt( shift ) + vOffset; 34 | } 35 | } 36 | 37 | 38 | 39 | 40 | ///////////////////////////////////////////////////////////////////// 41 | // Interrupt handlers 42 | // 43 | static vu16 lineDisplay = 0; // line position on display screen 44 | 45 | HINTERRUPT_CALLBACK HIntHandler() 46 | { 47 | if( lineDisplay == 104 ) { 48 | // set vertical rotation component for lwoer part of BG_A 49 | memcpy( vScrollA, vScrollLowerA, sizeof(vScrollLowerA)); 50 | VDP_setVerticalScrollTile(BG_A, 0, vScrollA, 20, DMA); 51 | } 52 | // Count raster lines 53 | lineDisplay++; 54 | 55 | } 56 | void VBlankHandler() 57 | { 58 | // Reset to line 0 59 | lineDisplay = 0; 60 | 61 | // set vertical rotation component for upper part of BG_A 62 | memcpy( vScrollA, vScrollUpperA, sizeof(vScrollUpperA)); 63 | VDP_setVerticalScrollTile(BG_A, 0, vScrollA, 20, DMA); 64 | } 65 | 66 | 67 | 68 | ///////////////////////////////////////////////////////////////////// 69 | // Player 70 | #define LEFT_EDGE 0 71 | #define RIGHT_EDGE 320 72 | #define TOP_EDGE 0 73 | #define BOTTOM_EDGE 224 74 | #define MAX_SHOTS 3 75 | 76 | int shipAnim = 5; 77 | // sprite info 78 | struct CP_SPRITE 79 | { 80 | Sprite *sprite; 81 | int pos_x; 82 | int pos_y; 83 | int vel_x; 84 | int vel_y; 85 | 86 | int hitbox_x1; 87 | int hitbox_y1; 88 | int hitbox_x2; 89 | int hitbox_y2; 90 | 91 | bool active; 92 | int state; 93 | }; 94 | 95 | struct CP_SPRITE shipSprite; 96 | struct CP_SPRITE shipShots[MAX_SHOTS]; 97 | 98 | 99 | 100 | static void readJoypad( u16 joypadId ) { 101 | u16 state = JOY_readJoypad( joypadId ); 102 | shipSprite.vel_x = 0; 103 | shipSprite.vel_y = 0; 104 | 105 | // Set player velocity if left or right are pressed; 106 | // set velocity to 0 if no direction is pressed 107 | if (state & BUTTON_RIGHT) 108 | { 109 | shipSprite.vel_x = 2; 110 | } 111 | else if (state & BUTTON_LEFT) 112 | { 113 | shipSprite.vel_x = -2; 114 | } 115 | 116 | if (state & BUTTON_UP) 117 | { 118 | shipSprite.vel_y = -2; 119 | } 120 | else if (state & BUTTON_DOWN) 121 | { 122 | shipSprite.vel_y = 2; 123 | } 124 | } 125 | 126 | void update() 127 | { 128 | // Check horizontal bounds 129 | if (shipSprite.pos_x < LEFT_EDGE) 130 | { 131 | shipSprite.pos_x = LEFT_EDGE; 132 | shipSprite.vel_x = -shipSprite.vel_x; 133 | } 134 | else if (shipSprite.pos_x + (shipSprite.hitbox_x2 - shipSprite.hitbox_x1) > RIGHT_EDGE) 135 | { 136 | shipSprite.pos_x = RIGHT_EDGE - (shipSprite.hitbox_x2 - shipSprite.hitbox_x1); 137 | shipSprite.vel_x = -shipSprite.vel_x; 138 | } 139 | 140 | // Check vertical bounds 141 | if (shipSprite.pos_y < TOP_EDGE) 142 | { 143 | shipSprite.pos_y = TOP_EDGE; 144 | shipSprite.vel_y = -shipSprite.vel_y; 145 | } 146 | else if (shipSprite.pos_y + (shipSprite.hitbox_y2 - shipSprite.hitbox_y1) > BOTTOM_EDGE) 147 | { 148 | shipSprite.pos_y = BOTTOM_EDGE - (shipSprite.hitbox_y2 - shipSprite.hitbox_y1); 149 | shipSprite.vel_y = -shipSprite.vel_y; 150 | } 151 | 152 | // Position the ship 153 | shipSprite.pos_x += shipSprite.vel_x; 154 | shipSprite.pos_y += shipSprite.vel_y; 155 | 156 | } 157 | 158 | 159 | int main(bool hard) 160 | { 161 | 162 | // SETUP backgroupd 163 | VDP_setBackgroundColor(16); 164 | VDP_setScreenWidth320(); 165 | 166 | // Set Colors 167 | PAL_setPalette(PAL0, plane_b_pal.data, CPU); 168 | PAL_setPalette(PAL1, plane_a_pal.data, CPU); 169 | PAL_setPalette(PAL2, ships_pal.data, CPU); 170 | PAL_setPalette(PAL3, shots_pal.data, CPU); 171 | 172 | PAL_setColor(0, 0x0000); 173 | 174 | // set scrolling modes to support fake rotation 175 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_COLUMN); 176 | 177 | // get initial tile position in VRAM 178 | int ind = TILE_USER_INDEX; 179 | int indexA = ind; 180 | VDP_loadTileSet(plane_a.tileset, indexA, DMA); 181 | int indexB = ind + plane_b.tileset->numTile; // AND get next position in VRAM ; 182 | VDP_loadTileSet(plane_b.tileset, indexB, DMA); 183 | 184 | // SImple image for BG_B. We're not changing it during the level 185 | VDP_drawImageEx(BG_B, &plane_b, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexB), 0, 0, FALSE, TRUE); 186 | 187 | // Setup BG_A 188 | VDP_setTileMapEx(BG_A, plane_a.tilemap, TILE_ATTR_FULL(PAL1, TRUE, FALSE, FALSE, indexA), 189 | 0, // Plane X destination 190 | 0, // plane Y destination 191 | 0, // Region X start position 192 | 0, // Region Y start position 193 | PLANE_MAX_HORIZONTAL_TILE, // 194 | PLANE_MAX_VERTICAL_TILE, // 195 | CPU); 196 | 197 | 198 | // setup sprite 199 | SPR_init(); 200 | 201 | shipSprite.pos_x = 144; 202 | shipSprite.pos_y = 160; 203 | shipSprite.vel_x = 0; 204 | shipSprite.vel_y = 0; 205 | shipSprite.active = TRUE; 206 | shipSprite.hitbox_x1 = 0; 207 | shipSprite.hitbox_y1 = 0; 208 | shipSprite.hitbox_x2 = 32; 209 | shipSprite.hitbox_y2 = 32; 210 | shipAnim = 5; 211 | shipSprite.sprite = SPR_addSprite(&ships, shipSprite.pos_x, shipSprite.pos_y, TILE_ATTR(PAL2, 1, FALSE, FALSE)); 212 | SPR_setAnim(shipSprite.sprite, shipAnim); 213 | 214 | SPR_update(); 215 | 216 | JOY_init(); 217 | 218 | 219 | for (int row = 0; row < 224; ++row) 220 | { 221 | hScrollA[row] = -40; 222 | } 223 | 224 | // Setup interrupt handlers 225 | SYS_disableInts(); 226 | { 227 | SYS_setVBlankCallback(VBlankHandler); 228 | SYS_setHIntCallback(HIntHandler); 229 | VDP_setHIntCounter(0); 230 | VDP_setHInterrupt(1); 231 | } 232 | SYS_enableInts(); 233 | 234 | 235 | // pre calc angles to simplify logic later 236 | u16 upperAngles[80]; 237 | u16 upperAnglePos = 0; 238 | for( s16 angle = 20; angle > 0; --angle) { 239 | upperAngles[upperAnglePos] = angle; 240 | upperAngles[79-upperAnglePos] = angle; 241 | ++upperAnglePos; 242 | } 243 | for( s16 angle = 1023; angle > 1003; --angle) { 244 | upperAngles[upperAnglePos] = angle; 245 | upperAngles[79-upperAnglePos] = angle; 246 | ++upperAnglePos; 247 | } 248 | upperAnglePos = 0; 249 | 250 | u16 lowerAngles[60]; 251 | u16 lowerAnglePos = 0; 252 | for( s16 angle = 15; angle > 0; --angle) { 253 | lowerAngles[lowerAnglePos] = angle; 254 | lowerAngles[59-lowerAnglePos] = angle; 255 | ++lowerAnglePos; 256 | } 257 | for( s16 angle = 1023; angle > 1008; --angle) { 258 | lowerAngles[lowerAnglePos] = angle; 259 | lowerAngles[59-lowerAnglePos] = angle; 260 | ++lowerAnglePos; 261 | } 262 | for( int i=0; i < 60; ++i ) { 263 | KLog_U1("angle: ", lowerAngles[i] ); 264 | } 265 | lowerAnglePos = 30; 266 | 267 | s16 upperHShift = 0; 268 | s16 upperVShift = -15; 269 | s16 upperVShiftMax = 5; 270 | s16 upperVShiftMin = -15; 271 | s16 upperVShiftDir = 1; 272 | 273 | s16 lowerVShift = -16; 274 | s16 lowerVShiftMax = 0; 275 | s16 lowerVShiftMin = -16; 276 | s16 lowerVShiftDir = 1; 277 | 278 | u16 delay = 0; 279 | for( s16 angle = 30; angle >= 0; --angle ) { 280 | setAngle(angle, 0, 90, 40, vScrollUpperA, 0, 0 ); 281 | KLog("-----------------------"); 282 | KLog_U1("angle: ", angle ); 283 | for( s16 row = 0; row < 90; ++row ) { 284 | KLog_S2("row:", row, " hScroll:", hScrollA[row]); 285 | } 286 | for( s16 col = 0; col < 20; ++col ) { 287 | KLog_S2("col:", col, " vScroll:", vScrollUpperA[col]); 288 | } 289 | } 290 | 291 | for( u16 angle = 1023; angle >= 994; --angle ) { 292 | setAngle(angle, 0, 90, 40, vScrollUpperA, 0, 0 ); 293 | KLog("-----------------------"); 294 | KLog_U1("angle: ", angle ); 295 | for( s16 row = 0; row < 90; ++row ) { 296 | KLog_S2("row:", row, " hScroll:", hScrollA[row]); 297 | } 298 | for( s16 col = 0; col < 20; ++col ) { 299 | KLog_S2("col:", col, " vScroll:", vScrollUpperA[col]); 300 | } 301 | } 302 | 303 | 304 | while (TRUE) 305 | { 306 | if (delay !=1 ) 307 | { 308 | s16 angle = upperAngles[upperAnglePos]; 309 | if( angle < 1019 && angle > 1003 ) { 310 | ++upperHShift; 311 | } else if( angle > 5 && angle < 21 ) { 312 | --upperHShift; 313 | } 314 | 315 | setAngle(angle, 0, 90, 40+upperVShift, vScrollUpperA, upperHShift, upperVShift ); 316 | ++upperAnglePos; 317 | if (upperAnglePos == 80) 318 | { 319 | upperAnglePos = 0; 320 | } 321 | } 322 | else 323 | { 324 | setAngle(lowerAngles[lowerAnglePos], 144, 224, 200, vScrollLowerA, 0, lowerVShift); 325 | //setAngle(0, 144, 224, 200, vScrollLowerA, 0, lowerVShift); 326 | ++lowerAnglePos; 327 | if (lowerAnglePos == 60) 328 | { 329 | lowerAnglePos = 0; 330 | } 331 | lowerVShift += lowerVShiftDir; 332 | if (lowerVShiftDir > 0 && lowerVShift >= lowerVShiftMax) 333 | { 334 | lowerVShiftDir = -1; 335 | } 336 | else if (lowerVShiftDir < 0 && lowerVShift <= lowerVShiftMin) 337 | { 338 | lowerVShiftDir = +1; 339 | } 340 | 341 | // move the top 342 | upperVShift += upperVShiftDir; 343 | if (upperVShiftDir > 0 && upperVShift >= upperVShiftMax) 344 | { 345 | upperVShiftDir = -1; 346 | } 347 | else if (upperVShiftDir < 0 && upperVShift <= upperVShiftMin) 348 | { 349 | upperVShiftDir = +1; 350 | } 351 | } 352 | ++delay; 353 | if (delay > 3) 354 | { 355 | delay = 0; 356 | } 357 | 358 | // scroll the asteroids in BG_B 359 | for (int i = 0; i < 20; i++) 360 | { 361 | vScrollB[i] -= planeBDeltas[i]; 362 | } 363 | 364 | VDP_setHorizontalScrollLine(BG_A, 0, hScrollA, 224, DMA); 365 | VDP_setVerticalScrollTile(BG_B, 0, vScrollB, 20, DMA); // use array to set plane offsets 366 | 367 | // player object 368 | readJoypad(JOY_1); 369 | update(); 370 | 371 | SPR_setPosition(shipSprite.sprite, shipSprite.pos_x, shipSprite.pos_y); 372 | SPR_update(); 373 | 374 | SYS_doVBlankProcess(); 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /RotationWithBackground/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | 5 | 6 | 7 | ///////////////////////////////////////////////////////////////////// 8 | // Scrolling Stuff 9 | // 10 | // default SGDK width is 512 pixels (64 tiles) 11 | #define PLANE_MAX_PIXEL 512 12 | #define PLANE_MAX_TILE 64 13 | 14 | // Images in this project are 1280 pixels wide ( tiles) 15 | #define IMAGE_MAX_PIXEL 1280 16 | #define IMAGE_MAX_TILE 160 17 | 18 | #define ROWS_A 150 19 | #define START_ROW_A 74 20 | #define COLS_A 20 21 | #define START_COL_A 0 22 | s16 hScrollA[224]; 23 | s16 vScrollA[20]; 24 | 25 | 26 | #define ROWS_B 25 27 | #define START_ROW_B 3 28 | fix32 speedB[ROWS_B]; 29 | fix32 planeOffsetB[ROWS_B]; 30 | fix32 imageOffsetB[ROWS_B]; 31 | u16 lastSrcColB[ROWS_B]; 32 | u16 lastDstColB[ROWS_B]; 33 | s16 hScrollB[ROWS_B*8]; 34 | 35 | // setup fake rotation by changing the foreground horizontal and vertical scrolling 36 | void setAngle( u16 angle, int centerY ) { 37 | // angle is defined as [0..1024] mapped to [0..2PI] range. 38 | // negative rotation will be 1024 down to 512 39 | // each value is ~ 0.35 degrees / 0.0061 radians. 40 | //KLog_S1("angle:",angle); 41 | //KLog_F2x( 4, " c: ", cosFix32(angle), " s: ", sinFix32(angle)); 42 | 43 | for( int row = START_ROW_A; row < START_ROW_A + ROWS_A; ++row ){ 44 | fix32 shift = F32_mul(FIX32( (row - centerY)>>1 ), sinFix32(angle)); 45 | // KLog_S2( " row: ", row, " off: ", (row - centerY)); 46 | //KLog_F1x( 4, " shift: ", shift ); 47 | hScrollA[row-START_ROW_A] = F32_toInt( shift ) - 24; 48 | } 49 | 50 | 51 | // vertical scroll tiles are 16 pixels wide. Using 8 * (col-10) to scale the scrolling effect 52 | // at the extreme left and right of the screen the factor would be -80 and + 80 53 | for( int col = START_COL_A; col < START_COL_A + COLS_A; ++col ){ 54 | fix32 shift = F32_mul(FIX32( (col - 9)<<3 ), sinFix32(angle)); 55 | vScrollA[col] = F32_toInt( shift ); 56 | } 57 | 58 | 59 | } 60 | 61 | 62 | 63 | 64 | // handle horizontal parallax scrolling of background image. 65 | void updateScroll(VDPPlane plane, const TileMap *tilemap, int index, 66 | fix32 *speed, 67 | fix32 *planeOffset, 68 | fix32 *imageOffset, 69 | u16 *lastSrcCol, 70 | u16 *lastDstCol, 71 | s16 *scroll, 72 | u16 startRow, 73 | u16 rows) 74 | { 75 | 76 | for (s16 row = 0; row < rows; ++row) 77 | { 78 | // Set the scrolling position of plane per row 79 | planeOffset[row] = planeOffset[row] + speed[row]; 80 | if (planeOffset[row] >= FIX32(PLANE_MAX_PIXEL)) // plane in memory is 512 pixels wide 81 | { 82 | planeOffset[row] = FIX32(0); 83 | } 84 | 85 | // keep track of where we are in the image per row 86 | imageOffset[row] = imageOffset[row] + speed[row]; 87 | if (imageOffset[row] >= FIX32(IMAGE_MAX_PIXEL)) // bg image is 1280 pixels wide 88 | { 89 | imageOffset[row] = FIX32(0); 90 | } 91 | s16 sPlaneOffset = F32_toInt(planeOffset[row]); 92 | // check if we need a new tile 93 | if (sPlaneOffset % 8 == 0) 94 | { 95 | // get destination column (in tiles) 96 | s16 dstCol = (sPlaneOffset + PLANE_MAX_PIXEL - 8) / 8; 97 | if (dstCol >= PLANE_MAX_TILE) 98 | { 99 | dstCol -= PLANE_MAX_TILE; // wrap around to the start of the plane 100 | } 101 | 102 | // get source column (in tiles) 103 | s16 sImageOffset = F32_toInt(imageOffset[row]); 104 | s16 srcCol = (sImageOffset + PLANE_MAX_PIXEL - 8) / 8; 105 | if (srcCol >= IMAGE_MAX_TILE) 106 | { 107 | srcCol -= IMAGE_MAX_TILE; // wrap around to the start of the image 108 | } 109 | // if the current destination column is smaller n 110 | // the last one, the region is *notnuous 111 | // Two or more tile moves may be required. 112 | if (dstCol != lastDstCol[row]) 113 | { 114 | s16 width = dstCol - lastDstCol[row]; 115 | if (width < 0) 116 | { 117 | width += PLANE_MAX_TILE; 118 | } 119 | // just loop for now ( probably inefficient if there are a lot of columns to copy) 120 | s16 tmpDst = lastDstCol[row] + 1; 121 | s16 tmpSrc = lastSrcCol[row] + 1; 122 | for (s16 i = 0; i < width; ++i) 123 | { 124 | if (tmpDst >= PLANE_MAX_TILE) 125 | { 126 | tmpDst = 0; 127 | } 128 | if (tmpSrc >= IMAGE_MAX_TILE) 129 | { 130 | tmpSrc = 0; 131 | } 132 | VDP_setTileMapEx(plane, tilemap, TILE_ATTR_FULL(PAL0, plane == BG_A ? TRUE : FALSE, FALSE, FALSE, index), 133 | tmpDst, // Plane X destination 134 | startRow + row, // plane Y destination 135 | tmpSrc, // Region X start position 136 | startRow + row, // Region Y start position 137 | 1, // width 138 | 1, // height 139 | CPU); 140 | tmpDst++; 141 | tmpSrc++; 142 | } 143 | lastDstCol[row] = tmpDst - 1; 144 | lastSrcCol[row] = tmpSrc - 1; 145 | } 146 | } 147 | // set offset through all 8 lines for the current "tile" 148 | for( int i=0; i < 8; ++i ) { 149 | scroll[row*8 + i] = -sPlaneOffset; 150 | } 151 | 152 | } 153 | } 154 | 155 | 156 | 157 | void setupB() 158 | { 159 | // setup scrolling vals 160 | for (int row = 0; row < ROWS_B; ++row) 161 | { 162 | planeOffsetB[row] = FIX32(0); 163 | imageOffsetB[row] = FIX32(0); 164 | lastSrcColB[row] = PLANE_MAX_TILE - 1; 165 | lastDstColB[row] = PLANE_MAX_TILE - 1; 166 | hScrollB[row] = 0; 167 | } 168 | // 3-4 fastest cloud 169 | speedB[0] = FIX32(6); 170 | speedB[1] = FIX32(6); 171 | // 5 172 | speedB[2] = FIX32(3); 173 | // 6 174 | speedB[3] = FIX32(1.5); 175 | // 7-8 slowest cloud 176 | speedB[4] = FIX32(0.75); 177 | speedB[5] = FIX32(0.75); 178 | // 9-11 the distances 179 | speedB[6] = FIX32(0.075); 180 | speedB[7] = FIX32(0.075); 181 | speedB[8] = FIX32(0.075); 182 | // 12-13 slow land 183 | speedB[9] = FIX32(0.5); 184 | speedB[10] = FIX32(1.0); 185 | // 14 186 | speedB[11] = FIX32(1.5); 187 | speedB[12] = FIX32(2.2); 188 | speedB[13] = FIX32(3.0); 189 | 190 | // 17-19 191 | for (int row = 17; row <= 19; ++row) 192 | { 193 | speedB[row - START_ROW_B] = FIX32(3.5); 194 | } 195 | // 20-27 fastest ground 196 | for (int row = 20; row < 23; ++row) 197 | { 198 | speedB[row - START_ROW_B] = FIX32(4.7); 199 | } 200 | for (int row = 23; row <= 27; ++row) 201 | { 202 | speedB[row - START_ROW_B] = FIX32(7.6); 203 | } 204 | } 205 | 206 | 207 | ///////////////////////////////////////////////////////////////////// 208 | // Joypad Handler 209 | u16 maxAngle = 7; 210 | static void readJoypad( u16 joypadId ) { 211 | u16 joypadState = JOY_readJoypad( joypadId ); 212 | if( joypadState & BUTTON_A ) { 213 | maxAngle = 7; 214 | }else if( joypadState & BUTTON_B ) { 215 | maxAngle = 10; 216 | }else if( joypadState & BUTTON_C ) { 217 | maxAngle = 15; 218 | }else if( joypadState & BUTTON_X ) { 219 | maxAngle = 20; 220 | }else if( joypadState & BUTTON_Y ) { 221 | maxAngle = 30; 222 | }else if( joypadState & BUTTON_Z ) { 223 | maxAngle = 40; 224 | } 225 | } 226 | 227 | 228 | 229 | int main(bool hard) 230 | { 231 | VDP_setScreenWidth320(); 232 | // set colors 233 | PAL_setPalette( PAL0, bg_pal.data, CPU) ; 234 | PAL_setPalette( PAL1, gun_bike_pal.data, CPU ); 235 | PAL_setPalette( PAL2, gun_bike_rider_pal.data, CPU ); 236 | PAL_setPalette( PAL3, boss_truck_pal.data, CPU ); 237 | 238 | //setup scroll values 239 | setupB(); 240 | 241 | // set scrolling mode to support rotation 242 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_COLUMN); 243 | 244 | // get tile positions in VRAM. 245 | int ind = TILE_USER_INDEX; 246 | int indexA = ind; 247 | // Load the plane tiles into VRAM 248 | VDP_loadTileSet(bg_boss_truck.tileset, ind, DMA); 249 | int indexB = ind + bg_boss_truck.tileset->numTile; // new 250 | VDP_loadTileSet(bg.tileset, indexB, DMA); 251 | 252 | // put out the image 253 | VDP_setTileMapEx(BG_A, bg_boss_truck.tilemap, TILE_ATTR_FULL(PAL3, TRUE, FALSE, FALSE, indexA), 254 | 0, // Plane X destination 255 | 0, // plane Y destination 256 | 0, // Region X start position 257 | 0, // Region Y start position 258 | PLANE_MAX_TILE, // width (went with 64 becasue default width is 64. Viewable screen is 40) 259 | 28, // height 260 | CPU); 261 | 262 | VDP_setTileMapEx(BG_B, bg.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexB), 263 | 0, 264 | 0, 265 | 0, 266 | 0, 267 | PLANE_MAX_TILE, 268 | 28, 269 | CPU); 270 | 271 | 272 | 273 | ////////////////////////////////////////////////////////////// 274 | SPR_init(); 275 | 276 | Sprite * gunbikerider1 = NULL; 277 | Sprite * gunbike1 = NULL; 278 | int gunbikerider1_pos_x = 91; 279 | int gunbikerider1_pos_y = 140; 280 | gunbikerider1 = SPR_addSprite( &gun_bike_rider_big, 281 | gunbikerider1_pos_x, 282 | gunbikerider1_pos_y, 283 | TILE_ATTR( PAL2, 284 | 1, // tile priority 285 | FALSE, // flip sprite vertically 286 | FALSE // flip sprite horizontally 287 | )); 288 | 289 | int gunbike1_pos_x = 55; 290 | int gunbike1_pos_y = 152; 291 | gunbike1 = SPR_addSprite( &gun_bike_big, 292 | gunbike1_pos_x, 293 | gunbike1_pos_y, 294 | TILE_ATTR( PAL1, 295 | 1, 296 | FALSE, 297 | FALSE )); 298 | 299 | 300 | Sprite *truckWheelSprite1 = NULL; 301 | fix32 truckWheelPosX1 = FIX32(55.0); 302 | fix32 truckWheelPosY1 = FIX32(135.0); 303 | truckWheelSprite1 = SPR_addSprite( &boss_truck_wheel, // Sprite defined in resources 304 | F32_toInt(truckWheelPosX1),// starting X position 305 | F32_toInt(truckWheelPosY1),// starting Y position 306 | TILE_ATTR( PAL3, // specify palette 307 | 1, // Tile priority ( with background) 308 | FALSE, // flip the sprite vertically? 309 | FALSE // flip the sprite horizontally 310 | )); 311 | 312 | Sprite *truckWheelSprite2 = NULL; 313 | fix32 truckWheelPosX2 = FIX32(186.0); 314 | fix32 truckWheelPosY2 = FIX32(135.0); 315 | truckWheelSprite2 = SPR_addSprite( &boss_truck_wheel, // Sprite defined in resources 316 | F32_toInt(truckWheelPosX2),// starting X position 317 | F32_toInt(truckWheelPosY2),// starting Y position 318 | TILE_ATTR( PAL3, // specify palette 319 | TRUE, // Tile priority ( with background) 320 | FALSE, // flip the sprite vertically? 321 | FALSE // flip the sprite horizontally 322 | )); 323 | 324 | 325 | Sprite *treeSprite = NULL; 326 | fix32 treePosX = FIX32(152.0); 327 | fix32 treePosY = FIX32(54.0); 328 | treeSprite = SPR_addSprite( &tree, // Sprite defined in resources 329 | F32_toInt(treePosX),// starting X position 330 | F32_toInt(treePosY),// starting Y position 331 | TILE_ATTR( PAL0, // specify palette 332 | FALSE, // Tile priority ( with background) 333 | FALSE, // flip the sprite vertically? 334 | FALSE // flip the sprite horizontally 335 | )); 336 | 337 | 338 | 339 | u16 currAngle = 0; 340 | setAngle(currAngle, 150); 341 | int stepDir = 1; 342 | while (TRUE) 343 | { 344 | // read joypad to set max angle dynamically 345 | readJoypad(JOY_1); 346 | 347 | // sprite 348 | treePosX = treePosX - FIX32(2.2); 349 | SPR_setPosition(treeSprite, F32_toInt(treePosX), 54); 350 | 351 | // Fake rotation 352 | currAngle += stepDir; 353 | if (stepDir == 1 && currAngle < 512) 354 | { 355 | if (currAngle == maxAngle) 356 | { 357 | stepDir = -1; 358 | } 359 | } 360 | else if (stepDir == -1 && currAngle == 0) 361 | { 362 | currAngle = 1024; 363 | } 364 | else if (stepDir == -1 && currAngle > 512) 365 | { 366 | if (currAngle == 1024 - maxAngle) 367 | { 368 | stepDir = 1; 369 | } 370 | } 371 | else if (stepDir == 1 && currAngle == 1024) 372 | { 373 | currAngle = 0; 374 | } 375 | setAngle(currAngle, 130); 376 | 377 | // set scrolling to fake the rotaiton. 378 | VDP_setHorizontalScrollLine(BG_A, START_ROW_A, hScrollA, ROWS_A, DMA); 379 | VDP_setVerticalScrollTile(BG_A, START_COL_A, vScrollA, COLS_A, DMA); 380 | 381 | // parallax scrolling. 382 | updateScroll(BG_B, bg.tilemap, indexB, 383 | speedB, 384 | planeOffsetB, 385 | imageOffsetB, 386 | lastSrcColB, 387 | lastDstColB, 388 | hScrollB, 389 | START_ROW_B, 390 | ROWS_B); 391 | VDP_setHorizontalScrollLine(BG_B, START_ROW_B * 8, hScrollB, ROWS_B * 8, DMA); 392 | 393 | SPR_update(); 394 | 395 | // let SGDK do its thing 396 | SYS_doVBlankProcess(); 397 | } 398 | return 0; 399 | } 400 | -------------------------------------------------------------------------------- /RotationDualPrecalc/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | #include "rotation.h" 4 | 5 | ///////////////////////////////////////////////////////////////////// 6 | // Scrolling Stuff 7 | #define PLANE_MAX_TILE 64 8 | 9 | s16 hScrollA[224]; 10 | s16 vScrollA[20]; 11 | s16 vScrollUpperA[20]; 12 | s16 vScrollLowerA[20]; 13 | 14 | s16 vScrollB[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 15 | s16 planeBDeltas[20] = {9, 9, 7, 7, 5, 5, 5, 4, 3, 2, 2, 3, 4, 5, 5, 5, 7, 7, 9, 9}; 16 | 17 | ///////////////////////////////////////////////////////////////////// 18 | // Player 19 | typedef struct { 20 | Sprite *sprite; 21 | int pos_x; 22 | int pos_y; 23 | int vel_x; 24 | int vel_y; 25 | 26 | int hitbox_x1; 27 | int hitbox_y1; 28 | int hitbox_x2; 29 | int hitbox_y2; 30 | 31 | bool active; 32 | int state; 33 | 34 | 35 | } CP_SPRITE; 36 | 37 | #define PLAYER_FRAME_COUNT 16 38 | #define PLAYER_WIDTH 32 39 | #define PLAYER_HEIGHT 32 40 | 41 | #define LEFT_EDGE 0 42 | #define RIGHT_EDGE 320 43 | #define TOP_EDGE 0 44 | #define BOTTOM_EDGE 224 45 | #define MAX_SHOTS 3 46 | 47 | 48 | 49 | CP_SPRITE shipSprite; 50 | int shipSpriteAnim = 5; 51 | bool doPlayerUpdate; 52 | 53 | 54 | ///////////////////////////////////////////////////////////////////// 55 | // Interrupt handlers 56 | // 57 | static vu16 lineDisplay = 0; // line position on display screen 58 | 59 | HINTERRUPT_CALLBACK HIntHandler() 60 | { 61 | if( lineDisplay == 120 ) { 62 | // set vertical rotation component for lwoer part of BG_A 63 | memcpy( vScrollA, vScrollLowerA, sizeof(vScrollLowerA)); 64 | VDP_setVerticalScrollTile(BG_A, 0, vScrollA, 20, DMA); 65 | } 66 | // Count raster lines 67 | lineDisplay++; 68 | 69 | } 70 | void VBlankHandler() 71 | { 72 | // Reset to line 0 73 | lineDisplay = 0; 74 | 75 | // set vertical rotation component for upper part of BG_A 76 | memcpy( vScrollA, vScrollUpperA, sizeof(vScrollUpperA)); 77 | VDP_setVerticalScrollTile(BG_A, 0, vScrollA, 20, DMA); 78 | } 79 | 80 | 81 | 82 | static void readJoypad( u16 joypadId ) { 83 | u16 state = JOY_readJoypad( joypadId ); 84 | shipSprite.vel_x = 0; 85 | shipSprite.vel_y = 0; 86 | 87 | // Set shipSprite velocity if left or right are pressed; 88 | // set velocity to 0 if no direction is pressed 89 | if (state & BUTTON_RIGHT) 90 | { 91 | shipSprite.vel_x = 2; 92 | } 93 | else if (state & BUTTON_LEFT) 94 | { 95 | shipSprite.vel_x = -2; 96 | } 97 | 98 | if (state & BUTTON_UP) 99 | { 100 | shipSprite.vel_y = -2; 101 | } 102 | else if (state & BUTTON_DOWN) 103 | { 104 | shipSprite.vel_y = 2; 105 | } 106 | } 107 | 108 | 109 | void update() 110 | { 111 | // Check horizontal bounds 112 | if (shipSprite.pos_x < LEFT_EDGE) 113 | { 114 | shipSprite.pos_x = LEFT_EDGE; 115 | shipSprite.vel_x = -shipSprite.vel_x; 116 | } 117 | else if (shipSprite.pos_x + (shipSprite.hitbox_x2 - shipSprite.hitbox_x1) > RIGHT_EDGE) 118 | { 119 | shipSprite.pos_x = RIGHT_EDGE - (shipSprite.hitbox_x2 - shipSprite.hitbox_x1); 120 | shipSprite.vel_x = -shipSprite.vel_x; 121 | } 122 | 123 | // Check vertical bounds 124 | if (shipSprite.pos_y < TOP_EDGE) 125 | { 126 | shipSprite.pos_y = TOP_EDGE; 127 | shipSprite.vel_y = -shipSprite.vel_y; 128 | } 129 | else if (shipSprite.pos_y + (shipSprite.hitbox_y2 - shipSprite.hitbox_y1) > BOTTOM_EDGE) 130 | { 131 | shipSprite.pos_y = BOTTOM_EDGE - (shipSprite.hitbox_y2 - shipSprite.hitbox_y1); 132 | shipSprite.vel_y = -shipSprite.vel_y; 133 | } 134 | 135 | // Position the ship 136 | shipSprite.pos_x += shipSprite.vel_x; 137 | shipSprite.pos_y += shipSprite.vel_y; 138 | 139 | } 140 | 141 | 142 | int main(bool hard) 143 | { 144 | VDP_setScreenWidth320(); 145 | // set colors 146 | PAL_setPalette( PAL0, planea_pal.data, CPU ); 147 | PAL_setPalette( PAL1, planeb_pal.data, CPU ); 148 | PAL_setPalette( PAL2, ship_pal.data, CPU ); 149 | PAL_setPalette( PAL3, crosshairs_pal.data, CPU ); 150 | 151 | // set scrolling mode to LINE for horizontal and TILE for vertical 152 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_COLUMN); 153 | 154 | // get tile positions in VRAM. 155 | int ind = TILE_USER_INDEX; 156 | int indexA = ind; 157 | // Load the plane tiles into VRAM 158 | VDP_loadTileSet(planea.tileset, ind, DMA); 159 | 160 | int indexB = ind + planeb.tileset->numTile; // AND get next position in VRAM ; 161 | VDP_loadTileSet(planeb.tileset, indexB, DMA); 162 | 163 | // Simple image for BG_B, so just draw it. 164 | VDP_drawImageEx(BG_B, &planeb, TILE_ATTR_FULL(PAL1, FALSE, FALSE, FALSE, indexB), 0, 0, FALSE, TRUE); 165 | 166 | 167 | // setup the tiles 168 | VDP_setTileMapEx(BG_A, planea.tilemap, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexA), 169 | 0, // Plane X destination 170 | 0, // plane Y destination 171 | 0, // Region X start position 172 | 0, // Region Y start position 173 | PLANE_MAX_TILE, // width (went with 64 becasue default width is 64. Viewable screen is 40) 174 | 28, // height 175 | CPU); 176 | 177 | 178 | u8 ticks = 0; 179 | 180 | s16 currUpperAngle = 0; 181 | s16 upperStepDir = 1; 182 | s16 xUpperOffset = 0; 183 | s16 yUpperOffset = 0; 184 | s16 yUpperOffsetDir = 1; 185 | 186 | s16 currLowerAngle = 0; 187 | s16 lowerStepDir = 1; 188 | s16 xLowerOffset = 0; 189 | s16 yLowerOffset = -10; 190 | s16 yLowerOffsetDir = 1; 191 | 192 | 193 | for( int row = 0; row < 224; ++row ) { 194 | hScrollA[row] = -40; 195 | } 196 | 197 | 198 | // Setup interrupt handlers 199 | SYS_disableInts(); 200 | { 201 | SYS_setVBlankCallback(VBlankHandler); 202 | SYS_setHIntCallback(HIntHandler); 203 | VDP_setHIntCounter(0); 204 | VDP_setHInterrupt(1); 205 | } 206 | SYS_enableInts(); 207 | 208 | // SPRITES 209 | SPR_init(); 210 | 211 | Sprite * lgun_sprite = NULL; 212 | int lgun_pos_x = lgun[currUpperAngle*2]-8; 213 | int lgun_pos_y = lgun[currUpperAngle*2+1]-8; 214 | lgun_sprite = SPR_addSprite( &crosshairs, lgun_pos_x, lgun_pos_y, TILE_ATTR( PAL3, 1, FALSE, FALSE )); 215 | 216 | Sprite * mgun_sprite = NULL; 217 | int mgun_pos_x = mgun[currUpperAngle*2]-8; 218 | int mgun_pos_y = mgun[currUpperAngle*2+1]-8; 219 | mgun_sprite = SPR_addSprite( &crosshairs, mgun_pos_x, mgun_pos_y, TILE_ATTR( PAL3, 1, FALSE, FALSE )); 220 | 221 | Sprite * rgun_sprite = NULL; 222 | int rgun_pos_x = rgun[currUpperAngle*2]-8; 223 | int rgun_pos_y = rgun[currUpperAngle*2+1]-8; 224 | rgun_sprite = SPR_addSprite( &crosshairs, rgun_pos_x, rgun_pos_y, TILE_ATTR( PAL3, 1, FALSE, FALSE )); 225 | 226 | Sprite * lvent_sprite = NULL; 227 | int lvent_pos_x = lvent[currUpperAngle*2]-8; 228 | int lvent_pos_y = lvent[currUpperAngle*2+1]-8; 229 | lvent_sprite = SPR_addSprite( &crosshairs, lvent_pos_x, lvent_pos_y, TILE_ATTR( PAL3, 1, FALSE, FALSE )); 230 | 231 | Sprite * rvent_sprite = NULL; 232 | int rvent_pos_x = rvent[currUpperAngle*2]-8; 233 | int rvent_pos_y = rvent[currUpperAngle*2+1]-8; 234 | rvent_sprite = SPR_addSprite( &crosshairs, rvent_pos_x, rvent_pos_y, TILE_ATTR( PAL3, 1, FALSE, FALSE )); 235 | 236 | 237 | 238 | Sprite * larray_sprite = NULL; 239 | int larray_pos_x = larray[currLowerAngle*2]-8; 240 | int larray_pos_y = larray[currLowerAngle*2+1]-8; 241 | larray_sprite = SPR_addSprite( &crosshairs, larray_pos_x, larray_pos_y, TILE_ATTR( PAL3, 1, FALSE, FALSE )); 242 | 243 | Sprite * marray_sprite = NULL; 244 | int marray_pos_x = marray[currLowerAngle*2]-8; 245 | int marray_pos_y = marray[currLowerAngle*2+1]-8; 246 | marray_sprite = SPR_addSprite( &crosshairs, marray_pos_x, marray_pos_y, TILE_ATTR( PAL3, 1, FALSE, FALSE )); 247 | 248 | Sprite * rarray_sprite = NULL; 249 | int rarray_pos_x = rarray[currLowerAngle*2]-8; 250 | int rarray_pos_y = rarray[currLowerAngle*2+1]-8; 251 | rarray_sprite = SPR_addSprite( &crosshairs, rarray_pos_x, rarray_pos_y, TILE_ATTR( PAL3, 1, FALSE, FALSE )); 252 | 253 | shipSprite.pos_x = 144; 254 | shipSprite.pos_y = 160; 255 | shipSprite.vel_x = 0; 256 | shipSprite.vel_y = 0; 257 | shipSprite.active = TRUE; 258 | shipSprite.hitbox_x1 = 2; 259 | shipSprite.hitbox_y1 = 12; 260 | shipSprite.hitbox_x2 = 30; 261 | shipSprite.hitbox_y2 = 26; 262 | 263 | shipSprite.sprite = SPR_addSprite( &ship, shipSprite.pos_x, shipSprite.pos_y, TILE_ATTR( PAL2, 0, FALSE,FALSE )); 264 | SPR_setAnim( shipSprite.sprite, shipSpriteAnim ); 265 | 266 | JOY_init(); 267 | 268 | while (TRUE) 269 | { 270 | 271 | ++ticks; 272 | if( ticks % 6 == 0 ) { 273 | currUpperAngle += upperStepDir; 274 | if( currUpperAngle >= lower_SCROLL_COUNT ) { 275 | upperStepDir = -1; 276 | currUpperAngle = 9; 277 | }else if (currUpperAngle <0 ) { 278 | upperStepDir = 1; 279 | currUpperAngle = 1; 280 | } 281 | } 282 | if( ticks % 3 == 0 ) { 283 | yUpperOffset += yUpperOffsetDir; 284 | if( yUpperOffset > 5) { 285 | yUpperOffsetDir = -1; 286 | }else if( yUpperOffset < -15 ) { 287 | yUpperOffsetDir = 1; 288 | } 289 | if( currUpperAngle < 4) { 290 | xUpperOffset+=2; 291 | } else if ( currUpperAngle > 6) { 292 | xUpperOffset-=2; 293 | } 294 | } 295 | 296 | if( ticks % 9 == 0 ) { 297 | currLowerAngle += lowerStepDir; 298 | if( currLowerAngle >= upper_SCROLL_COUNT ) { 299 | lowerStepDir = -1; 300 | currLowerAngle = 9; 301 | }else if (currLowerAngle < 0 ) { 302 | lowerStepDir = 1; 303 | currLowerAngle = 1; 304 | } 305 | } 306 | if( ticks % 12 == 0 ) { 307 | yLowerOffset += yLowerOffsetDir; 308 | if( yLowerOffset > -10) { 309 | yLowerOffsetDir = -1; 310 | }else if( yLowerOffset < -25 ) { 311 | yLowerOffsetDir = 1; 312 | } 313 | if( currLowerAngle < 4) { 314 | xLowerOffset+=1; 315 | } else if ( currLowerAngle > 6) { 316 | xLowerOffset-=1; 317 | } 318 | } 319 | 320 | 321 | // could unroll loops to eliminate some overhead 322 | s16 startUpperHScroll = upper_START_ROW_A - yUpperOffset; 323 | s16 stopUpperRows = upper_END_ROW_A - yUpperOffset; 324 | if( startUpperHScroll < 0 ) { 325 | stopUpperRows = upper_START_ROW_A + upper_ROWS_A + startUpperHScroll; 326 | startUpperHScroll = 0; 327 | } 328 | for(int i=startUpperHScroll, offset=0; i < stopUpperRows; ++i, ++offset ) { 329 | hScrollA[ i ] = upper_hScroll[ currUpperAngle * upper_ROWS_A + offset] + xUpperOffset; 330 | } 331 | 332 | s16 startLowerHScroll = lower_START_ROW_A - yLowerOffset; 333 | s16 stopLowerHScroll = lower_END_ROW_A - yLowerOffset; 334 | if( stopLowerHScroll > 223 ) { 335 | stopLowerHScroll =223; 336 | } 337 | for(int i=startLowerHScroll, offset=0; i <= stopLowerHScroll; ++i, ++offset ) { 338 | hScrollA[ i ] = lower_hScroll[ currLowerAngle * lower_ROWS_A + offset] + xLowerOffset; 339 | } 340 | 341 | 342 | // 343 | for (int i = 0; i < upper_COLS_A; ++i) 344 | { 345 | vScrollUpperA[i] = upper_vScroll[currUpperAngle * upper_COLS_A + i] + yUpperOffset; 346 | } 347 | for (int i = 0; i < lower_COLS_A; ++i) 348 | { 349 | vScrollLowerA[i] = lower_vScroll[currLowerAngle * lower_COLS_A + i] + yLowerOffset; 350 | } 351 | 352 | 353 | 354 | // set SGDK scrolling functions to fake the rotation. 355 | VDP_setHorizontalScrollLine(BG_A, 0, hScrollA, 224, DMA); 356 | 357 | // scroll the asteroids in BG_B 358 | for (int i = 0; i < 20; i++) 359 | { 360 | vScrollB[i] -= planeBDeltas[i]; 361 | } 362 | 363 | VDP_setVerticalScrollTile(BG_B, 0, vScrollB, 20, DMA); // use array to set plane offsets 364 | 365 | 366 | 367 | 368 | lgun_pos_x = lgun[currUpperAngle * 2]-8 + xUpperOffset; 369 | lgun_pos_y = lgun[currUpperAngle * 2 + 1]-8 - yUpperOffset; 370 | SPR_setPosition(lgun_sprite, lgun_pos_x, lgun_pos_y); 371 | 372 | mgun_pos_x = mgun[currUpperAngle * 2]-8 + xUpperOffset; 373 | mgun_pos_y = mgun[currUpperAngle * 2 + 1]-8 - yUpperOffset; 374 | SPR_setPosition(mgun_sprite, mgun_pos_x, mgun_pos_y); 375 | 376 | rgun_pos_x = rgun[currUpperAngle * 2]-8 + xUpperOffset; 377 | rgun_pos_y = rgun[currUpperAngle * 2 + 1]-8 - yUpperOffset; 378 | SPR_setPosition(rgun_sprite, rgun_pos_x, rgun_pos_y); 379 | 380 | lvent_pos_x = lvent[currUpperAngle * 2]-8 + xUpperOffset; 381 | lvent_pos_y = lvent[currUpperAngle * 2 + 1]-8 - yUpperOffset; 382 | SPR_setPosition(lvent_sprite, lvent_pos_x, lvent_pos_y); 383 | 384 | rvent_pos_x = rvent[currUpperAngle * 2]-8 + xUpperOffset; 385 | rvent_pos_y = rvent[currUpperAngle * 2 + 1]-8 - yUpperOffset; 386 | SPR_setPosition(rvent_sprite, rvent_pos_x, rvent_pos_y); 387 | 388 | 389 | 390 | larray_pos_x = larray[currLowerAngle * 2]-8 + xLowerOffset; 391 | larray_pos_y = larray[currLowerAngle * 2 + 1]-8 - yLowerOffset; 392 | SPR_setPosition(larray_sprite, larray_pos_x, larray_pos_y); 393 | 394 | marray_pos_x = marray[currLowerAngle * 2]-8 + xLowerOffset; 395 | marray_pos_y = marray[currLowerAngle * 2 + 1]-8 - yLowerOffset; 396 | SPR_setPosition(marray_sprite, marray_pos_x, marray_pos_y); 397 | 398 | rarray_pos_x = rarray[currLowerAngle * 2]-8 + xLowerOffset; 399 | rarray_pos_y = rarray[currLowerAngle * 2 + 1]-8 - yLowerOffset; 400 | SPR_setPosition(rarray_sprite, rarray_pos_x, rarray_pos_y); 401 | 402 | 403 | readJoypad(JOY_1); 404 | update(); 405 | SPR_setPosition(shipSprite.sprite, shipSprite.pos_x, shipSprite.pos_y); 406 | SPR_update(); 407 | 408 | 409 | // let SGDK do its thing 410 | SYS_doVBlankProcess(); 411 | } 412 | return 0; 413 | } 414 | -------------------------------------------------------------------------------- /RotatePy/sgdk_scroll_rotate.py: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env python 3 | # 4 | 5 | import os, argparse, logging, csv 6 | import math 7 | import numpy as np 8 | from jinja2 import Template 9 | import shutil 10 | from pathlib import Path 11 | from PIL import Image 12 | 13 | 14 | def makeProjectFiles(destDir, rowStart, rowEnd, totalRows, colStart, colEnd, totalCols, centerY, prefixStr, backgroundName, spriteName, targetList, outputFilename ): 15 | # make resource dir and rescomp file 16 | srcFolder = destDir + "/src" 17 | if not os.path.exists(srcFolder): 18 | os.makedirs(srcFolder) 19 | resFolder = destDir + "/res" 20 | if not os.path.exists(resFolder): 21 | os.makedirs(resFolder) 22 | bgFolder = resFolder + "/bg" 23 | if not os.path.exists(bgFolder): 24 | os.makedirs(bgFolder) 25 | spritesFolder = resFolder + "/sprites" 26 | if not os.path.exists(spritesFolder): 27 | os.makedirs(spritesFolder) 28 | 29 | # Copy files to resource folders 30 | shutil.copy( backgroundName + str(".png"), bgFolder ) 31 | shutil.copy( spriteName + str(".png"), spritesFolder ) 32 | shutil.copy( outputFilename, srcFolder + "/" + outputFilename ) 33 | 34 | # Make resources file from template 35 | with open('resources.res.jinja') as resFile: 36 | resTemp = Template( resFile.read() ) 37 | with open( resFolder + "/resources.res", 'w') as outRes: 38 | outRes.write( resTemp.render( 39 | bg_name = backgroundName, 40 | sprite_name = spriteName 41 | )) 42 | 43 | # Make main.c file from template 44 | with open('main.c.jinja') as srcFile: 45 | srcTemp = Template( srcFile.read() ) 46 | with open( srcFolder + "/main.c", 'w') as outSrc: 47 | outSrc.write( srcTemp.render( 48 | rotation_filename = outputFilename, 49 | start_row_a = rowStart, 50 | end_row_a = rowEnd, 51 | rows_a = totalRows, 52 | start_col_a = colStart, 53 | end_col_a = colEnd, 54 | cols_a = totalCols, 55 | prefix = prefixStr, 56 | bg_name = backgroundName, 57 | sprite_name = spriteName, 58 | target_list = targetList 59 | )) 60 | 61 | 62 | def main(args, loglevel): 63 | logging.basicConfig(format="%(levelname)s: %(message)s", level=loglevel) 64 | 65 | logging.debug("Arguments:") 66 | logging.debug(args) 67 | 68 | minRot = args.start_angle 69 | maxRot = args.end_angle 70 | rotStep = args.angle_increment 71 | if minRot > maxRot: 72 | print("Starting angle is larger than end angle") 73 | return 74 | if rotStep <= 0.0: 75 | print("Invalid angle increment") 76 | return 77 | 78 | # default to center 18 columns 79 | colStart = args.column_start 80 | colEnd = args.column_end 81 | totalCols = colEnd - colStart +1 # inclusive total+1 82 | 83 | centerX = args.center_x 84 | 85 | # check background image size if not specified and we're making a project dir 86 | projectDir = args.project_directory 87 | backgroundFilename = args.background_filename 88 | backgroundName = '' 89 | if os.path.isfile( backgroundFilename ): 90 | backgroundName = Path( backgroundFilename ).stem 91 | else: 92 | print('Unable to find ' + backgroundFilename) 93 | return 94 | 95 | if args.image_width: 96 | imageWidth = args.image_width 97 | else: 98 | # if we're creating a project, get the width from the image 99 | if len(projectDir) > 0 and len(backgroundFilename) > 0 : 100 | im = Image.open( backgroundFilename ) 101 | imWidth, imHeight = im.size 102 | if( imWidth > 0 ): 103 | imageWidth = imWidth 104 | else: 105 | # if we're not, assume 320 106 | imageWidth = 320 107 | 108 | 109 | 110 | imageShift = -( imageWidth - 320) / 2; 111 | 112 | # default to all rows. 113 | rowStart = args.row_start 114 | rowEnd = args.row_end 115 | totalRows = rowEnd - rowStart +1 # inclusive total +1 116 | centerY = args.center_y 117 | 118 | # where do we put the file at 119 | outputFilename = args.output_filename 120 | 121 | # naming the variables 122 | prefix = args.prefix 123 | 124 | 125 | # (optional) points to rotate 126 | pointsFilename = args.points_filename 127 | pointsToRotate = { } 128 | isFile = os.path.isfile( pointsFilename ) 129 | if isFile: 130 | with open( pointsFilename ) as csvFile: 131 | csvReader = csv.reader( csvFile, delimiter=',') 132 | for row in csvReader: 133 | if len(row) >= 3 and row[1].strip().isnumeric() and row[2].strip().isnumeric(): 134 | newKey = row[0] 135 | while newKey in pointsToRotate: 136 | newKey = row[0] + str(sn) 137 | sn += 1 138 | pointsToRotate[newKey] = ( float(row[1].strip()), float(row[2].strip()) ) 139 | print('found points to rotate:') 140 | print( pointsToRotate ) 141 | 142 | 143 | spriteFilename = args.sprite_filename 144 | spriteName = '' 145 | if os.path.isfile( spriteFilename ): 146 | spriteName = Path( spriteFilename ).stem 147 | else: 148 | print('Unable to find ' + spriteFilename) 149 | return 150 | 151 | 152 | # Sega specific 153 | COL_WIDTH = 16 # 16 pixel width 154 | ROW_HEIGHT = 1 # rows are 1 pixel in height, might be plausible to do 8 for tiled? 155 | 156 | 157 | logging.info("Parameters") 158 | logging.info("Start angle: %f Stop angle: %f Step size: %f", minRot, maxRot, rotStep) 159 | logging.info("Columns to rotate: %d Center column: %d", totalCols, centerX) 160 | logging.info("Rows to rotate: %d Center row: %d", totalRows, centerY) 161 | 162 | # output C defines for colums and rows in 163 | print("#define ROWS_A %d" % totalRows ) 164 | print("#define START_ROW_A %d" % rowStart ) 165 | print("#define END_ROW_A %d" % rowEnd ) 166 | print("#define COLS_A %d" % totalCols ) 167 | print("#define START_COL_A %d" % colStart ) 168 | print("#define END_COL_A %d" % colEnd ) 169 | 170 | # Check if file exists, exit to force user to make decision to delete isntead of just blowing it away. 171 | isFile = os.path.isfile( outputFilename ) 172 | if isFile: 173 | print("File: %s exists! exiting" % outputFilename) 174 | return 175 | 176 | # open file 177 | outfile = open( outputFilename, 'w') 178 | outfile.write("#ifndef _%s_\n" % outputFilename.upper().replace(".","_") ) 179 | outfile.write("#define _%s_\n" % outputFilename.upper().replace(".","_") ) 180 | outfile.write("\n\n#define %s_SCROLL_COUNT %d\n" % ( prefix.replace(".","_"), int(1+ (maxRot - minRot)/rotStep) )) 181 | outfile.write("#define %s_ROWS_A %d\n" % (prefix, totalRows )) 182 | outfile.write("#define %s_START_ROW_A %d\n" % (prefix, rowStart )) 183 | outfile.write("#define %s_END_ROW_A %d\n" % (prefix, rowEnd )) 184 | outfile.write("#define %s_COLS_A %d\n" % (prefix, totalCols )) 185 | outfile.write("#define %s_START_COL_A %d\n" % (prefix, colStart )) 186 | outfile.write("#define %s_END_COL_A %d\n" % (prefix, colEnd )) 187 | outfile.write("\n\ns16 %s_hScroll[] = {" % (prefix ) ) 188 | # horizontal scrolling values 189 | offset = 0 190 | for deg in np.arange( minRot, maxRot + rotStep, rotStep ): # include end rot 191 | rad = deg * math.pi/180; 192 | outfile.write("\n // rotation values for angle %f starts at %d\n" %( deg, offset) ) 193 | for row in range( rowStart, rowEnd+1, ROW_HEIGHT ): 194 | rowShift = (row-centerY) * math.sin( rad ) + imageShift 195 | logging.debug("HSCROLL deg:%f row: %d scroll value:%d", deg, row, rowShift) 196 | if offset > 0: 197 | outfile.write( ", " ) 198 | outfile.write( str(round(rowShift)) ) 199 | offset +=1 200 | outfile.write("};\n") 201 | 202 | outfile.write("\n\ns16 %svScroll[] = {" % (prefix + "_")) 203 | offset = 0 204 | # vertical scrolling values 205 | for deg in np.arange( minRot, maxRot + rotStep, rotStep ): # include end rot 206 | rad = deg * math.pi/180; 207 | outfile.write("\n // rotation values for angle %f starts at %d\n" % (deg,offset)) 208 | for col in range( colStart, colEnd+1, 1 ): 209 | colShift = 16 * (col - centerX) * math.sin( rad ) 210 | logging.debug("VSCROLL deg:%f col: %d scroll value:%d", deg, col, colShift) 211 | if offset > 0: 212 | outfile.write( ", " ) 213 | outfile.write( str(round(colShift)) ) 214 | offset +=1 215 | outfile.write("\n};\n") 216 | 217 | if len(pointsToRotate) > 0: 218 | # loop over again 219 | for key, val in pointsToRotate.items(): 220 | first = True 221 | outfile.write("\n\ns16 %sX[] = {" % (key)) 222 | for deg in np.arange( minRot, maxRot + rotStep, rotStep ): # include end rot 223 | rad = deg * math.pi/180; 224 | # Using real rotation but Y-flipped due to genesis coordinate system. 225 | newX = centerX* 16 + ( val[0] + imageShift - centerX * 16) * math.cos(rad) - (centerY - val[1]) * math.sin(rad) 226 | if not first: 227 | outfile.write( ", " ) 228 | else: 229 | first = False; 230 | 231 | outfile.write("\n %d" % (round(newX))) 232 | outfile.write("\n};") 233 | 234 | for key, val in pointsToRotate.items(): 235 | first = True 236 | outfile.write("\n\ns16 %sY[] = {" % (key)) 237 | for deg in np.arange( minRot, maxRot + rotStep, rotStep ): # include end rot 238 | rad = deg * math.pi/180; 239 | # find the row current point from y = x sin(theta) + y cos (theta) 240 | newY = centerY - ( ((val[0] + imageShift - centerX * 16) * math.sin(rad) ) + ((centerY - val[1]) * math.cos(rad) ) ) 241 | if not first: 242 | outfile.write( ", " ) 243 | else: 244 | first = False; 245 | 246 | outfile.write("\n %d" % (round(newY))) 247 | outfile.write("\n};") 248 | 249 | outfile.write("\n\n#endif // _%s_\n" % outputFilename.upper().replace(".","_") ) 250 | outfile.close() 251 | 252 | # if defined, create an SGDK project skeleton 253 | if len(projectDir) > 0: 254 | makeProjectFiles(projectDir, rowStart, rowEnd, totalRows, colStart, colEnd, totalCols, centerY, prefix, backgroundName, spriteName, pointsToRotate.keys(), outputFilename ) 255 | 256 | 257 | # Standard boilerplate to call the main() function to begin 258 | # the program. 259 | if __name__ == '__main__': 260 | parser = argparse.ArgumentParser( description = "Generates rotation arrays for SGDK.", 261 | epilog = "As an alternative to the commandline, params can be placed in a file, one per line, and specified on the commandline like '%(prog)s @params.conf'.", 262 | fromfile_prefix_chars = '@' ) 263 | # TODO Specify your real parameters here. 264 | parser.add_argument( "-v", 265 | "--verbose", 266 | help="Print debug messages", 267 | action="store_true") 268 | 269 | parser.add_argument( "-s", 270 | "--start_angle", 271 | default=-5.0, 272 | type=float, 273 | help = "Starting rotation in degrees", 274 | metavar = "ARG") 275 | parser.add_argument( "-e", 276 | "--end_angle", 277 | default=5.0, 278 | type=float, 279 | help = "End rotation angle in degrees", 280 | metavar = "ARG") 281 | parser.add_argument( "-i", 282 | "--angle_increment", 283 | default=1.0, 284 | type=float, 285 | help = "Rotation step size", 286 | metavar = "ARG") 287 | 288 | parser.add_argument( "-c", 289 | "--column_start", 290 | default=0, 291 | type=int, 292 | help = "First column to rotate (default 0)", 293 | metavar = "ARG") 294 | parser.add_argument( "-C", 295 | "--column_end", 296 | default=19, 297 | type=int, 298 | help = "Last column to rotate (default 19)", 299 | metavar = "ARG") 300 | parser.add_argument( "-x", 301 | "--center_x", 302 | default=9, 303 | type=int, 304 | help = "Which column is the center of rotation", 305 | metavar = "ARG") 306 | 307 | parser.add_argument( "-w", 308 | "--image_width", 309 | #default=320, 310 | type=int, 311 | help = "Width of image to rotate", 312 | metavar = "ARG") 313 | 314 | parser.add_argument( "-r", 315 | "--row_start", 316 | default=0, 317 | type=int, 318 | help = "First row to rotate", 319 | metavar = "ARG") 320 | parser.add_argument( "-R", 321 | "--row_end", 322 | default=223, 323 | type=int, 324 | help = "Last row to rotate", 325 | metavar = "ARG") 326 | parser.add_argument( "-y", 327 | "--center_y", 328 | default=112, 329 | type=int, 330 | help = "Which row is the center of rotation", 331 | metavar = "ARG") 332 | 333 | parser.add_argument( "-o", 334 | "--output_filename", 335 | default="rotation.h", 336 | help = "Output filename", 337 | metavar = "ARG") 338 | 339 | parser.add_argument( "-P", 340 | "--prefix", 341 | default="", 342 | help = "Add a prefix to array names", 343 | metavar = "ARG") 344 | 345 | parser.add_argument( "-p", 346 | "--project_directory", 347 | default="", 348 | help = "Create project directory with resource files and simple SGDK code.", 349 | metavar = "ARG") 350 | 351 | parser.add_argument( "-b", 352 | "--background_filename", 353 | default="ship.png", 354 | help = "Specify background image", 355 | metavar = "ARG") 356 | 357 | parser.add_argument( "-t", 358 | "--points_filename", 359 | default="", 360 | help = "Specify CSV file with points to rotate along with bg", 361 | metavar = "ARG") 362 | 363 | parser.add_argument( "-S", 364 | "--sprite_filename", 365 | default="crosshairs.png", 366 | help = "Specify target sprite image", 367 | metavar = "ARG") 368 | 369 | args = parser.parse_args() 370 | 371 | # Setup logging 372 | if args.verbose: 373 | loglevel = logging.DEBUG 374 | else: 375 | loglevel = logging.INFO 376 | 377 | main(args, loglevel) 378 | 379 | 380 | -------------------------------------------------------------------------------- /RotationDualPrecalc/src/rotation.h: -------------------------------------------------------------------------------- 1 | #ifndef _ROTATION_H_ 2 | #define _ROTATION_H_ 3 | 4 | #define upper_SCROLL_COUNT 11 5 | #define upper_ROWS_A 91 6 | #define upper_START_ROW_A 0 7 | #define upper_END_ROW_A 90 8 | #define upper_COLS_A 20 9 | #define upper_START_COL_A 0 10 | #define upper_END_COL_A 19 11 | #define lower_SCROLL_COUNT 11 12 | #define lower_ROWS_A 86 13 | #define lower_START_ROW_A 138 14 | #define lower_END_ROW_A 223 15 | #define lower_COLS_A 20 16 | #define lower_START_COL_A 0 17 | #define lower_END_COL_A 19 18 | 19 | s16 upper_hScroll[] = { 20 | // rotation values for angle -5.000000 starts at 0 21 | -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36 22 | // rotation values for angle -4.000000 starts at 91 23 | , -29, -29, -29, -29, -29, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35 24 | // rotation values for angle -3.000000 starts at 182 25 | , -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -35, -35, -35 26 | // rotation values for angle -2.000000 starts at 273 27 | , -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -34, -34, -34, -34, -34, -34, -34, -34 28 | // rotation values for angle -1.000000 starts at 364 29 | , -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33 30 | // rotation values for angle 0.000000 starts at 455 31 | , -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32 32 | // rotation values for angle 1.000000 starts at 546 33 | , -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31 34 | // rotation values for angle 2.000000 starts at 637 35 | , -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -30, -30, -30, -30, -30, -30, -30, -30 36 | // rotation values for angle 3.000000 starts at 728 37 | , -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -29, -29, -29 38 | // rotation values for angle 4.000000 starts at 819 39 | , -35, -35, -35, -35, -35, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29 40 | // rotation values for angle 5.000000 starts at 910 41 | , -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -28, -28, -28, -28, -28, -28, -28, -28, -28, -28}; 42 | 43 | 44 | s16 upper_vScroll[] = { 45 | // rotation values for angle -5.000000 starts at 0 46 | 13, 11, 10, 8, 7, 6, 4, 3, 1, 0, -1, -3, -4, -6, -7, -8, -10, -11, -13, -14 47 | // rotation values for angle -4.000000 starts at 20 48 | , 10, 9, 8, 7, 6, 4, 3, 2, 1, 0, -1, -2, -3, -4, -6, -7, -8, -9, -10, -11 49 | // rotation values for angle -3.000000 starts at 40 50 | , 8, 7, 6, 5, 4, 3, 3, 2, 1, 0, -1, -2, -3, -3, -4, -5, -6, -7, -8, -8 51 | // rotation values for angle -2.000000 starts at 60 52 | , 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -6 53 | // rotation values for angle -1.000000 starts at 80 54 | , 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -3, -3 55 | // rotation values for angle 0.000000 starts at 100 56 | , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 57 | // rotation values for angle 1.000000 starts at 120 58 | , -3, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3 59 | // rotation values for angle 2.000000 starts at 140 60 | , -5, -4, -4, -3, -3, -2, -2, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6 61 | // rotation values for angle 3.000000 starts at 160 62 | , -8, -7, -6, -5, -4, -3, -3, -2, -1, 0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 8 63 | // rotation values for angle 4.000000 starts at 180 64 | , -10, -9, -8, -7, -6, -4, -3, -2, -1, 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11 65 | // rotation values for angle 5.000000 starts at 200 66 | , -13, -11, -10, -8, -7, -6, -4, -3, -1, 0, 1, 3, 4, 6, 7, 8, 10, 11, 13, 14 67 | }; 68 | 69 | 70 | 71 | 72 | s16 lgun[] = { 73 | 73, 44, 74 | 73, 45, 75 | 74, 46, 76 | 74, 48, 77 | 74, 49, 78 | 74, 50, 79 | 74, 51, 80 | 74, 52, 81 | 75, 54, 82 | 75, 55, 83 | 75, 56 84 | }; 85 | 86 | s16 mgun[] = { 87 | 161, 31, 88 | 161, 31, 89 | 161, 31, 90 | 160, 31, 91 | 160, 30, 92 | 160, 30, 93 | 160, 30, 94 | 160, 29, 95 | 159, 29, 96 | 159, 29, 97 | 159, 29 98 | }; 99 | 100 | s16 rgun[] = { 101 | 244, 59, 102 | 244, 57, 103 | 244, 55, 104 | 245, 54, 105 | 245, 52, 106 | 245, 50, 107 | 245, 48, 108 | 245, 46, 109 | 245, 45, 110 | 245, 43, 111 | 245, 41 112 | }; 113 | 114 | s16 lvent[] = { 115 | 143, 46, 116 | 144, 46, 117 | 144, 46, 118 | 144, 46, 119 | 144, 46, 120 | 144, 46, 121 | 144, 46, 122 | 144, 46, 123 | 144, 46, 124 | 144, 46, 125 | 145, 46 126 | }; 127 | 128 | s16 rvent[] = { 129 | 174, 49, 130 | 175, 48, 131 | 175, 48, 132 | 175, 47, 133 | 175, 47, 134 | 175, 46, 135 | 175, 45, 136 | 175, 45, 137 | 175, 44, 138 | 175, 44, 139 | 175, 43 140 | }; 141 | 142 | 143 | 144 | s16 lower_hScroll[] = { 145 | // rotation values for angle -2.500000 starts at 0 146 | -29, -29, -29, -29, -29, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33 147 | // rotation values for angle -2.000000 starts at 86 148 | , -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -33, -33, -33, -33, -33, -33, -33, -33, -33 149 | // rotation values for angle -1.500000 starts at 172 150 | , -30, -30, -30, -30, -30, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -33, -33, -33, -33 151 | // rotation values for angle -1.000000 starts at 258 152 | , -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32 153 | // rotation values for angle -0.500000 starts at 344 154 | , -31, -31, -31, -31, -31, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32 155 | // rotation values for angle 0.000000 starts at 430 156 | , -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32 157 | // rotation values for angle 0.500000 starts at 516 158 | , -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32 159 | // rotation values for angle 1.000000 starts at 602 160 | , -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32 161 | // rotation values for angle 1.500000 starts at 688 162 | , -34, -34, -34, -34, -34, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -31, -31, -31, -31 163 | // rotation values for angle 2.000000 starts at 774 164 | , -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -31, -31, -31, -31, -31, -31, -31, -31, -31 165 | // rotation values for angle 2.500000 starts at 860 166 | , -35, -35, -35, -35, -35, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -34, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -33, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31, -31}; 167 | 168 | 169 | s16 lower_vScroll[] = { 170 | // rotation values for angle -2.500000 starts at 0 171 | 6, 6, 5, 4, 3, 3, 2, 1, 1, 0, -1, -1, -2, -3, -3, -4, -5, -6, -6, -7 172 | // rotation values for angle -2.000000 starts at 20 173 | , 5, 4, 4, 3, 3, 2, 2, 1, 1, 0, -1, -1, -2, -2, -3, -3, -4, -4, -5, -6 174 | // rotation values for angle -1.500000 starts at 40 175 | , 4, 3, 3, 3, 2, 2, 1, 1, 0, 0, 0, -1, -1, -2, -2, -3, -3, -3, -4, -4 176 | // rotation values for angle -1.000000 starts at 60 177 | , 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -3, -3 178 | // rotation values for angle -0.500000 starts at 80 179 | , 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1 180 | // rotation values for angle 0.000000 starts at 100 181 | , 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 182 | // rotation values for angle 0.500000 starts at 120 183 | , -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 184 | // rotation values for angle 1.000000 starts at 140 185 | , -3, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3 186 | // rotation values for angle 1.500000 starts at 160 187 | , -4, -3, -3, -3, -2, -2, -1, -1, 0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4 188 | // rotation values for angle 2.000000 starts at 180 189 | , -5, -4, -4, -3, -3, -2, -2, -1, -1, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6 190 | // rotation values for angle 2.500000 starts at 200 191 | , -6, -6, -5, -4, -3, -3, -2, -1, -1, 0, 1, 1, 2, 3, 3, 4, 5, 6, 6, 7 192 | }; 193 | 194 | 195 | 196 | s16 larray[] = { 197 | 146, 211, 198 | 146, 211, 199 | 146, 211, 200 | 146, 211, 201 | 146, 211, 202 | 146, 211, 203 | 146, 211, 204 | 146, 211, 205 | 146, 211, 206 | 146, 211, 207 | 146, 211 208 | }; 209 | 210 | s16 marray[] = { 211 | 160, 212, 212 | 160, 212, 213 | 160, 211, 214 | 160, 211, 215 | 160, 211, 216 | 160, 211, 217 | 160, 211, 218 | 160, 211, 219 | 160, 211, 220 | 160, 210, 221 | 160, 210 222 | }; 223 | 224 | s16 rarray[] = { 225 | 172, 212, 226 | 173, 212, 227 | 173, 212, 228 | 173, 212, 229 | 173, 211, 230 | 173, 211, 231 | 173, 211, 232 | 173, 210, 233 | 173, 210, 234 | 173, 210, 235 | 173, 210 236 | }; 237 | 238 | 239 | 240 | #endif // _ROTATION_H_ 241 | -------------------------------------------------------------------------------- /ScrollingWithCamera/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | #define PLAYER_FRAME_COUNT 16 5 | #define MAX_ROTATION_INDEX FIX32(15) 6 | #define MIN_ROTATION_INDEX FIX32(0) 7 | #define PLAYER_WIDTH 24 8 | #define PLAYER_HEIGHT 24 9 | #define PLAYER_SHOT_WIDTH 8 10 | #define PLAYER_SHOT_HEIGHT 8 11 | #define MAX_PLAYER_SHOTS 4 12 | 13 | 14 | #define MAX_ROCKS 18 15 | #define MAX_EXPLOSIONS 6 16 | 17 | #define MAP_WIDTH 1280 18 | #define MAP_HEIGHT 896 19 | 20 | #define SCR_WIDTH 320 21 | #define SCR_HEIGHT 224 22 | 23 | #define CAMERA_PADDING 90 24 | 25 | // Struct for managing sprites 26 | typedef struct { 27 | Sprite *sprite; 28 | fix32 pos_x; 29 | fix32 pos_y; 30 | fix32 vel_x; 31 | fix32 vel_y; 32 | 33 | s32 hitbox_x1; 34 | s32 hitbox_y1; 35 | s32 hitbox_x2; 36 | s32 hitbox_y2; 37 | 38 | bool active; 39 | u16 ticks; 40 | } CP_SPRITE; 41 | 42 | 43 | // map variables 44 | Map *map_a; 45 | s32 camPosX;// Camera position is used to move the MAP 46 | s32 camPosY; 47 | 48 | 49 | // player variables 50 | CP_SPRITE player; 51 | fix32 playerRotation; 52 | bool updatePlayerPosition; 53 | fix32 deltaX[PLAYER_FRAME_COUNT]; 54 | fix32 deltaY[PLAYER_FRAME_COUNT]; 55 | CP_SPRITE playerShots[ MAX_PLAYER_SHOTS ]; 56 | 57 | 58 | // Rocks 59 | CP_SPRITE rocks[MAX_ROCKS]; 60 | 61 | // explosions 62 | CP_SPRITE explosions[MAX_EXPLOSIONS]; 63 | u16 nextExplosion = 0; 64 | 65 | 66 | static void addExplosion( fix32 pos_x, fix32 pos_y ) { 67 | // check if the current explosion is free to use 68 | if( explosions[ nextExplosion ].active == FALSE ){ 69 | // not in use, so place it on screen 70 | explosions[nextExplosion].pos_x = pos_x; 71 | explosions[nextExplosion].pos_y = pos_y; 72 | explosions[nextExplosion].active = TRUE; 73 | explosions[nextExplosion].ticks = 0; 74 | SPR_setVisibility( explosions[nextExplosion].sprite, VISIBLE); 75 | SPR_setPosition( explosions[nextExplosion].sprite,F32_toInt(explosions[nextExplosion].pos_x),F32_toInt(explosions[nextExplosion].pos_y)); 76 | 77 | // update current explosion index for next request 78 | ++nextExplosion; 79 | if( nextExplosion >= MAX_EXPLOSIONS ) { 80 | nextExplosion = 0; 81 | } 82 | } 83 | } 84 | 85 | 86 | 87 | static void updateCameraPos() { 88 | // figure out where the player is. 89 | s32 px = F32_toInt( player.pos_x ); 90 | s32 py = F32_toInt( player.pos_y ); 91 | 92 | s32 playerScreenX = px - camPosX; 93 | s32 playerScreenY = py - camPosY; 94 | 95 | // Adjust new camera X position based on player position 96 | s32 newCamX; 97 | // check if the player X position is too close to the right edge of the screen 98 | if( playerScreenX > SCR_WIDTH - CAMERA_PADDING - PLAYER_WIDTH ) { 99 | newCamX = px - ( SCR_WIDTH - CAMERA_PADDING - PLAYER_WIDTH ); 100 | } else if( playerScreenX < CAMERA_PADDING ) { // check if the player is too close to the left 101 | newCamX = px - CAMERA_PADDING; 102 | } else { 103 | newCamX = camPosX; // no change to camera position. 104 | } 105 | 106 | // Adjust camera Y position based on player position 107 | s32 newCamY; 108 | // check if the player Y position is too close to the bottom edge of the screen 109 | if( playerScreenY > SCR_HEIGHT - CAMERA_PADDING - PLAYER_HEIGHT ) { 110 | newCamY = py - ( SCR_HEIGHT - CAMERA_PADDING - PLAYER_HEIGHT ) ; 111 | } else if( playerScreenY < CAMERA_PADDING ) { // is player too close to the top of the screen? 112 | newCamY = py - CAMERA_PADDING; 113 | } else { 114 | newCamY = camPosY; // no change to camera position. 115 | } 116 | 117 | 118 | // handle camera position at edges 119 | if ( newCamX < 0 ) { // don't move past the left edge of the scroll image. 120 | newCamX = 0; 121 | } else if ( newCamX > (MAP_WIDTH - SCR_WIDTH )) { // don't move past the right edge 122 | newCamX = MAP_WIDTH - SCR_WIDTH ; 123 | } 124 | if ( newCamY < 0 ) { // don't move past the top of the scroll image 125 | newCamY = 0; 126 | } else if ( newCamY > (MAP_HEIGHT - SCR_HEIGHT )) { // don't move past the bottom 127 | newCamY = MAP_HEIGHT - SCR_HEIGHT ; 128 | } 129 | 130 | // Store the values 131 | camPosX = newCamX; 132 | camPosY = newCamY; 133 | // Update the MAP position 134 | MAP_scrollTo( map_a, camPosX, camPosY ); 135 | } 136 | 137 | static void inputCallback( u16 joy, u16 changed, u16 state ) { 138 | // create a shot if available 139 | if( changed & state & BUTTON_A ) { 140 | for( u16 i = 0; i < MAX_PLAYER_SHOTS; ++i ) { 141 | if( playerShots[i].active == FALSE ) { 142 | // create a new one 143 | 144 | u16 rot = F32_toInt( playerRotation); 145 | playerShots[i].pos_x = player.pos_x + FIX32((PLAYER_WIDTH-PLAYER_SHOT_WIDTH)/2) + F32_mul( deltaX[rot], FIX32(2.0)); 146 | playerShots[i].pos_y = player.pos_y + FIX32((PLAYER_HEIGHT-PLAYER_SHOT_WIDTH)/2) + F32_mul( deltaY[rot], FIX32(2.0)); 147 | playerShots[i].vel_x = F32_mul( deltaX[rot], FIX32(2.0)); 148 | playerShots[i].vel_y = F32_mul( deltaY[rot], FIX32(2.0)); 149 | playerShots[i].active = TRUE; 150 | playerShots[i].ticks = 0; 151 | break; 152 | 153 | } 154 | } 155 | } 156 | } 157 | 158 | 159 | static void handleInput() { 160 | u16 value = JOY_readJoypad(JOY_1); 161 | 162 | if( value & BUTTON_LEFT ) { 163 | playerRotation += FIX32( 0.25 ); // using fixed point to slow down rotation speed 164 | if( playerRotation > MAX_ROTATION_INDEX ) { 165 | playerRotation = MIN_ROTATION_INDEX; 166 | } 167 | int rot = F32_toInt( playerRotation); 168 | SPR_setAnim( player.sprite, rot); 169 | } else if( value & BUTTON_RIGHT ) { 170 | playerRotation -= FIX32( 0.25 ); 171 | if( playerRotation < MIN_ROTATION_INDEX ) { 172 | playerRotation = MAX_ROTATION_INDEX; 173 | } 174 | int rot = F32_toInt( playerRotation); 175 | SPR_setAnim( player.sprite, rot); 176 | } 177 | 178 | 179 | if( value & BUTTON_UP ) { 180 | // signal update to uplayer position. 181 | updatePlayerPosition = TRUE; 182 | } else { 183 | updatePlayerPosition = FALSE; 184 | } 185 | 186 | } 187 | 188 | static void update() { 189 | // update player 190 | if( updatePlayerPosition == TRUE ) { 191 | int rot = F32_toInt( playerRotation); 192 | player.pos_x = player.pos_x + deltaX[rot]; 193 | player.pos_y = player.pos_y + deltaY[rot]; 194 | 195 | 196 | if( player.pos_x< FIX32( -6.0 ) ) { 197 | player.pos_x = FIX32( -6.0 ); 198 | } else if( player.pos_x > FIX32( MAP_WIDTH - PLAYER_WIDTH + 6.0 )) { 199 | player.pos_x = FIX32( MAP_WIDTH - PLAYER_WIDTH + 6.0 ); 200 | } 201 | 202 | if( player.pos_y< FIX32( -6.0) ) { 203 | player.pos_y = FIX32( -6.0 ); 204 | } else if( player.pos_y > FIX32( MAP_HEIGHT - PLAYER_HEIGHT + 6.0 )) { 205 | player.pos_y = FIX32( MAP_HEIGHT - PLAYER_HEIGHT + 6.0 ); 206 | } 207 | 208 | 209 | } 210 | 211 | 212 | // move shots 213 | for( u16 i=0; i < MAX_PLAYER_SHOTS; ++i ) { 214 | if( playerShots[i].active == TRUE ) { 215 | playerShots[i].pos_x += playerShots[i].vel_x; 216 | playerShots[i].pos_y += playerShots[i].vel_y; 217 | s32 x = F32_toInt(playerShots[i].pos_x) - camPosX; 218 | s32 y = F32_toInt(playerShots[i].pos_y) - camPosY; 219 | if( x >= 0 && x < SCR_WIDTH && y >= 0 && y < SCR_HEIGHT ) { 220 | SPR_setVisibility( playerShots[i].sprite, VISIBLE); 221 | SPR_setPosition(playerShots[i].sprite, F32_toInt(playerShots[i].pos_x) - camPosX, F32_toInt(playerShots[i].pos_y) - camPosY ); 222 | } else { 223 | // shot reached the screen edge, deactivate and hide it. 224 | playerShots[i].active = FALSE; 225 | SPR_setVisibility( playerShots[i].sprite, HIDDEN); 226 | } 227 | } else { 228 | // hide inactive shots 229 | SPR_setVisibility( playerShots[i].sprite, HIDDEN); 230 | } 231 | } 232 | 233 | 234 | 235 | 236 | // rocks 237 | for( u16 i=0; i < MAX_ROCKS; ++i ) { 238 | if( rocks[i].active == TRUE ) { 239 | rocks[i].pos_x += rocks[i].vel_x; 240 | if( rocks[i].pos_x < FIX32(-32) ) { rocks[i].pos_x = FIX32(MAP_WIDTH);} 241 | else if( rocks[i].pos_x >FIX32(MAP_WIDTH) ) { rocks[i].pos_x = FIX32(-32);} 242 | 243 | rocks[i].pos_y += rocks[i].vel_y; 244 | if( rocks[i].pos_y < FIX32(-32) ) { rocks[i].pos_y = FIX32(MAP_HEIGHT);} 245 | else if( rocks[i].pos_y >FIX32(MAP_HEIGHT) ) { rocks[i].pos_y = FIX32(-32);} 246 | 247 | // only show rock if it's visible. 248 | s32 x = F32_toInt(rocks[i].pos_x) - camPosX; 249 | s32 y = F32_toInt(rocks[i].pos_y) - camPosY; 250 | if( x >= -32 && x < SCR_WIDTH && y >= -32 && y < SCR_HEIGHT ) { 251 | SPR_setVisibility( rocks[i].sprite, VISIBLE); 252 | SPR_setPosition(rocks[i].sprite, F32_toInt(rocks[i].pos_x) - camPosX, F32_toInt(rocks[i].pos_y) - camPosY ); 253 | } else { 254 | // shot reached the screen edge, hide it. 255 | SPR_setVisibility( rocks[i].sprite, HIDDEN); 256 | } 257 | } else { 258 | // hide inactive rocks 259 | SPR_setVisibility( rocks[i].sprite, HIDDEN); 260 | } 261 | } 262 | 263 | for( u16 i=0; i < MAX_EXPLOSIONS; ++i ) { 264 | if( explosions[i].active == TRUE ) { 265 | explosions[i].ticks += 1; 266 | if( explosions[i].ticks < 9 ) { 267 | // SPR_setFrame( explosions[i].sprite, explosions[i].ticks ); 268 | SPR_setPosition(explosions[i].sprite, F32_toInt(explosions[i].pos_x) - camPosX, F32_toInt(explosions[i].pos_y) - camPosY ); 269 | SPR_setAnimAndFrame( explosions[i].sprite, i%4, explosions[i].ticks ); 270 | } 271 | else { 272 | explosions[i].active = FALSE; 273 | SPR_setVisibility( explosions[i].sprite, HIDDEN); 274 | } 275 | } 276 | 277 | } 278 | // set the player position. 279 | SPR_setPosition( player.sprite, F32_toInt( player.pos_x) - camPosX, F32_toInt( player.pos_y ) - camPosY ); 280 | 281 | // change position of the MAP 282 | updateCameraPos(); 283 | } 284 | 285 | static void checkCollisions() { 286 | // simple collision just checks bad sprites against good. 287 | for( u16 i=0; i < MAX_ROCKS; ++i ) { 288 | if( rocks[i].active == TRUE ) { 289 | // check if ship hits a rock 290 | if( (rocks[i].pos_x + rocks[i].hitbox_x1) < (player.pos_x + player.hitbox_x2) && 291 | (rocks[i].pos_x + rocks[i].hitbox_x2) > (player.pos_x + player.hitbox_x1) && 292 | (rocks[i].pos_y + rocks[i].hitbox_y1) < (player.pos_y + player.hitbox_y2) && 293 | (rocks[i].pos_y + rocks[i].hitbox_y2) > (player.pos_y + player.hitbox_y1) ) 294 | { 295 | rocks[i].active = FALSE; 296 | SPR_setVisibility( rocks[i].sprite, HIDDEN); 297 | addExplosion( rocks[i].pos_x, rocks[i].pos_y ); 298 | } 299 | 300 | // check if a player shot hits a rock. 301 | for( u16 j=0; j < MAX_PLAYER_SHOTS; ++j ) { 302 | if( 303 | playerShots[j].active == TRUE && 304 | (rocks[i].pos_x + rocks[i].hitbox_x1) < (playerShots[j].pos_x + FIX32(4)) && 305 | (rocks[i].pos_x + rocks[i].hitbox_x2) > (playerShots[j].pos_x + FIX32(4)) && 306 | (rocks[i].pos_y + rocks[i].hitbox_y1) < (playerShots[j].pos_y + FIX32(4)) && 307 | (rocks[i].pos_y + rocks[i].hitbox_y2) > (playerShots[j].pos_y + FIX32(4)) ) 308 | { 309 | rocks[i].active = FALSE; 310 | SPR_setVisibility( rocks[i].sprite, HIDDEN); 311 | playerShots[j].active = FALSE; 312 | SPR_setVisibility( playerShots[j].sprite, HIDDEN); 313 | addExplosion( rocks[i].pos_x, rocks[i].pos_y ); 314 | break; // stop checking once it's been hit 315 | } 316 | } 317 | } 318 | } 319 | } 320 | 321 | 322 | 323 | 324 | 325 | static void createPlayerShots() { 326 | fix32 xpos = FIX32(-16); 327 | fix32 ypos = FIX32(-16); 328 | 329 | for( u16 i=0; i < MAX_PLAYER_SHOTS; ++i ) { 330 | playerShots[i].pos_x = xpos; 331 | playerShots[i].pos_y = ypos; 332 | playerShots[i].vel_x = FIX32(0.0); 333 | playerShots[i].vel_y = FIX32(0.0); 334 | playerShots[i].active = FALSE; 335 | playerShots[i].hitbox_x1 = FIX32(3); 336 | playerShots[i].hitbox_y1 = FIX32(3); 337 | playerShots[i].hitbox_x2 = FIX32(4); 338 | playerShots[i].hitbox_y2 = FIX32(4); 339 | 340 | playerShots[i].sprite = SPR_addSprite( &shot, xpos, ypos, TILE_ATTR( PAL0, 0, FALSE, FALSE )); 341 | SPR_setAnim( playerShots[i].sprite, 2 ); 342 | } 343 | 344 | } 345 | 346 | static void createRocks() { 347 | fix32 ypos = FIX32(0); 348 | fix32 xpos = FIX32(0); 349 | for( u16 i=0; i < MAX_ROCKS; ++i ) { 350 | rocks[i].pos_x = FIX32(random()%(MAP_WIDTH-32) + i ); // random starting position for rock sprites 351 | rocks[i].pos_y = FIX32(random()%(MAP_HEIGHT-32)+ i); 352 | 353 | // use ranodm direction for rock motion 354 | u16 rot = random() % 16; 355 | fix32 vel = FIX32(0.8); 356 | rocks[i].vel_x = F32_mul( vel, deltaX[rot] ); 357 | rocks[i].vel_y = F32_mul( vel, deltaY[rot] ); 358 | rocks[i].active = TRUE; 359 | rocks[i].hitbox_x1 = FIX32(2); 360 | rocks[i].hitbox_y1 = FIX32(2); 361 | rocks[i].hitbox_x2 = FIX32(30); 362 | rocks[i].hitbox_y2 = FIX32(30); 363 | 364 | //rocks[i].sprite = SPR_addSprite( &rock, -32, -32, TILE_ATTR( PAL3, 0, FALSE, FALSE )); 365 | rocks[i].sprite = SPR_addSprite( &rock, rocks[i].pos_x, rocks[i].pos_y, TILE_ATTR( PAL3, 0, FALSE, FALSE )); 366 | SPR_setAnim( rocks[i].sprite, 0 ); 367 | } 368 | } 369 | 370 | static void createExplosions() { 371 | fix32 xpos = FIX32(0); 372 | fix32 ypos = FIX32(264); 373 | 374 | for( u16 i=0; i < MAX_EXPLOSIONS; ++i ) { 375 | explosions[i].pos_x = xpos; 376 | explosions[i].pos_y = ypos; 377 | explosions[i].vel_x = FIX32(0); 378 | explosions[i].vel_y = FIX32(0); 379 | explosions[i].active = FALSE; 380 | explosions[i].hitbox_x1 = FIX32(0); 381 | explosions[i].hitbox_y1 = FIX32(0); 382 | explosions[i].hitbox_x2 = FIX32(0); 383 | explosions[i].hitbox_y2 = FIX32(0); 384 | 385 | explosions[i].sprite = SPR_addSprite( &explosion, F32_toInt(xpos), F32_toInt(ypos), TILE_ATTR( PAL0, 0, FALSE, FALSE )); 386 | SPR_setAnim( explosions[i].sprite, i % 4 ); 387 | 388 | SPR_setVisibility( explosions[i].sprite, HIDDEN ); 389 | SPR_setDepth( explosions[i].sprite, SPR_MIN_DEPTH ); 390 | } 391 | 392 | } 393 | 394 | 395 | int main( bool hard ) { 396 | 397 | // clear 398 | memset( playerShots, 0, sizeof(playerShots) ); 399 | memset( rocks, 0, sizeof(rocks) ); 400 | memset( explosions, 0, sizeof(explosions) ); 401 | 402 | 403 | PAL_setPalette( PAL0, shot_pal.data, CPU); 404 | PAL_setPalette( PAL1, plane_pal.data, CPU); 405 | PAL_setPalette( PAL2, ship_pal.data, CPU); 406 | PAL_setPalette( PAL3, rock_pal.data, CPU); 407 | 408 | // Load the plane tiles into VRAM 409 | int ind = TILE_USER_INDEX; 410 | VDP_loadTileSet( &plane_a_tileset, ind, DMA ); 411 | 412 | // init plane 413 | map_a = MAP_create( &plane_a_map, BG_A, TILE_ATTR_FULL( PAL1, FALSE, FALSE, FALSE, ind ) ); 414 | camPosX = MAP_WIDTH/2 - SCR_WIDTH/2; 415 | camPosY = MAP_HEIGHT/2 - SCR_HEIGHT/2; 416 | 417 | MAP_scrollTo( map_a, camPosX, camPosY ); 418 | 419 | // Init sprite engine with defaults 420 | SPR_init(); 421 | 422 | // Setup the player sprite 423 | player.pos_x = FIX32( MAP_WIDTH/2 - 12 ); 424 | player.pos_y = FIX32( MAP_HEIGHT/2 - 12 ); 425 | player.sprite = SPR_addSprite( &ship, F32_toInt(player.pos_x) - camPosX, F32_toInt(player.pos_y) - camPosY, TILE_ATTR(PAL2, 0, FALSE, FALSE )); 426 | player.hitbox_x1 = FIX32(5); 427 | player.hitbox_y1 = FIX32(5); 428 | player.hitbox_x2 = FIX32(19); 429 | player.hitbox_y2 = FIX32(19); 430 | playerRotation = MIN_ROTATION_INDEX; 431 | SPR_setAnim( player.sprite, F32_toInt(playerRotation ) ); 432 | 433 | 434 | // setup player motion offset. 435 | deltaX[0] = FIX32( 0.000000 ); 436 | deltaY[0] = FIX32( -2.000000 ); 437 | deltaX[1] = FIX32( -0.765367 ); 438 | deltaY[1] = FIX32( -1.847759 ); 439 | deltaX[2] = FIX32( -1.414214 ); 440 | deltaY[2] = FIX32( -1.414214 ); 441 | deltaX[3] = FIX32( -1.847759 ); 442 | deltaY[3] = FIX32( -0.765367 ); 443 | deltaX[4] = FIX32( -2.000000 ); 444 | deltaY[4] = FIX32( -0.000000 ); 445 | deltaX[5] = FIX32( -1.847759 ); 446 | deltaY[5] = FIX32( 0.765367 ); 447 | deltaX[6] = FIX32( -1.414214 ); 448 | deltaY[6] = FIX32( 1.414214 ); 449 | deltaX[7] = FIX32( -0.765367 ); 450 | deltaY[7] = FIX32( 1.847759 ); 451 | deltaX[8] = FIX32( -0.000000 ); 452 | deltaY[8] = FIX32( 2.000000 ); 453 | deltaX[9] = FIX32( 0.765367 ); 454 | deltaY[9] = FIX32( 1.847759 ); 455 | deltaX[10] = FIX32( 1.414214 ); 456 | deltaY[10] = FIX32( 1.414214 ); 457 | deltaX[11] = FIX32( 1.847759 ); 458 | deltaY[11] = FIX32( 0.765367 ); 459 | deltaX[12] = FIX32( 2.000000 ); 460 | deltaY[12] = FIX32( 0.000000 ); 461 | deltaX[13] = FIX32( 1.847759 ); 462 | deltaY[13] = FIX32( -0.765367 ); 463 | deltaX[14] = FIX32( 1.414214 ); 464 | deltaY[14] = FIX32( -1.414214 ); 465 | deltaX[15] = FIX32( 0.765367 ); 466 | deltaY[15] = FIX32( -1.847759 ); 467 | 468 | createExplosions(); 469 | createPlayerShots(); 470 | createRocks(); 471 | 472 | JOY_setEventHandler( &inputCallback ); 473 | 474 | while(TRUE) { 475 | 476 | handleInput(); 477 | 478 | update(); 479 | 480 | checkCollisions(); 481 | 482 | SPR_update(); 483 | 484 | SYS_doVBlankProcess(); 485 | } 486 | return 0; 487 | } 488 | 489 | -------------------------------------------------------------------------------- /EndlessScroll/sgdk_endless_scroll.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os, argparse, logging 4 | import numpy as np 5 | import math 6 | from PIL import Image, ImageDraw 7 | import cv2 8 | import shutil 9 | from jinja2 import Template 10 | from pathlib import Path 11 | 12 | # 320 x 224 13 | COLS = 320 14 | rows = 224 15 | 16 | 17 | def makeProjectFiles( destDir, imageFilename, endRow, startRow, nearPolyWidth, farPolyWidth, endCeilingRow, startCeilingRow, imageWidth ): 18 | # make resource dir and rescomp file 19 | srcFolder = destDir + "/src" 20 | if not os.path.exists(srcFolder): 21 | os.makedirs(srcFolder) 22 | resFolder = destDir + "/res" 23 | if not os.path.exists(resFolder): 24 | os.makedirs(resFolder) 25 | bgFolder = resFolder + "/bg" 26 | if not os.path.exists(bgFolder): 27 | os.makedirs(bgFolder) 28 | 29 | # copy out image to backtround folder 30 | shutil.copy( imageFilename, bgFolder ) 31 | 32 | # Make resource file 33 | fname = Path( imageFilename ).stem 34 | # Make resources file from template 35 | with open('resources.res.jinja') as resFile: 36 | resTemp = Template( resFile.read() ) 37 | with open( resFolder + "/resources.res", 'w') as outRes: 38 | outRes.write( resTemp.render( 39 | bg_name = fname 40 | )) 41 | 42 | # Make main.c file from template 43 | scrollLeftList=[] 44 | scrollCeilingRows = endCeilingRow - startCeilingRow 45 | scrollCeilingRatio = nearPolyWidth / farPolyWidth 46 | scrollCeilingRowStep = 0 47 | scrollCeilingIncrement = 1.0 48 | 49 | if startCeilingRow > -1 and endCeilingRow > startCeilingRow : 50 | scrollCeilingRowStep = ( scrollCeilingRatio - 1.0 ) / scrollCeilingRows 51 | for r in range( endCeilingRow, startCeilingRow - 1, -1): 52 | #srcfile.write( " fscroll[%d] = fix32Sub( fscroll[%d], FIX32(%.3f));\n" % ( r, r, scrollCeilingIncrement ) ) 53 | scrollLeftList.append( (r, scrollCeilingIncrement ) ) 54 | scrollCeilingIncrement += scrollCeilingRowStep 55 | 56 | 57 | scrollRows = endRow - startRow 58 | scrollRatio = nearPolyWidth / farPolyWidth 59 | scrollRowStep = ( scrollRatio - 1.0 ) / scrollRows 60 | scrollIncrement = 1.0; 61 | for r in range( startRow, endRow + 1, 1): 62 | ##srcfile.write( " fscroll[%d] = fix32Sub( fscroll[%d], FIX32(%.3f));\n" % ( r, r, scrollIncrement ) ) 63 | scrollLeftList.append( (r, scrollIncrement ) ) 64 | scrollIncrement += scrollRowStep 65 | 66 | 67 | scrollRightList = [] 68 | if startCeilingRow > -1 and endCeilingRow > startCeilingRow : 69 | scrollCeilingIncrement = 1.0 70 | scrollCeilingRowStep = ( scrollCeilingRatio - 1.0 ) / scrollCeilingRows 71 | for r in range( endCeilingRow, startCeilingRow - 1, -1): 72 | #srcfile.write( " fscroll[%d] = fix32Add( fscroll[%d], FIX32(%.3f));\n" % ( r, r, scrollCeilingIncrement ) ) 73 | scrollRightList.append( (r, scrollCeilingIncrement ) ) 74 | scrollCeilingIncrement += scrollCeilingRowStep 75 | scrollIncrement = 1.0; 76 | for r in range( startRow, endRow + 1, 1): 77 | #srcfile.write( " fscroll[%d] = fix32Add( fscroll[%d], FIX32(%.3f));\n" % ( r, r, scrollIncrement ) ) 78 | scrollRightList.append( (r, scrollIncrement ) ) 79 | scrollIncrement += scrollRowStep 80 | 81 | scrollRightResetList = [] 82 | 83 | if startCeilingRow > -1 and endCeilingRow > startCeilingRow : 84 | scroll = - int( farPolyWidth) 85 | scrollStep = (nearPolyWidth - farPolyWidth) / scrollCeilingRows 86 | for r in range( endCeilingRow, startCeilingRow , -1): 87 | #srcfile.write( " fscroll[%d] = FIX32(%.3f);\n" % ( r, scroll ) ) 88 | scrollRightResetList.append( (r, scroll ) ) 89 | scroll -= scrollStep 90 | 91 | scroll = - int( farPolyWidth) 92 | finalScrollStep = (nearPolyWidth - farPolyWidth) / scrollRows 93 | for r in range( startRow, endRow + 1, 1): 94 | #srcfile.write( " fscroll[%d] = FIX32(%.3f);\n" % ( r, scroll ) ) 95 | scrollRightResetList.append( (r, scroll ) ) 96 | scroll -= finalScrollStep 97 | 98 | if imageWidth <= 512: 99 | with open('main.c.jinja') as srcFile: 100 | srcTemp = Template( srcFile.read() ) 101 | with open( srcFolder + "/main.c", 'w') as outSrc: 102 | outSrc.write( srcTemp.render( 103 | bg_name = fname, 104 | far_width = farPolyWidth, 105 | scroll_left_list = scrollLeftList, 106 | scroll_right_list = scrollRightList, 107 | scroll_right_reset_list = scrollRightResetList, 108 | 109 | )) 110 | else: 111 | with open('main_wide.c.jinja') as srcFile: 112 | srcTemp = Template( srcFile.read() ) 113 | with open( srcFolder + "/main.c", 'w') as outSrc: 114 | outSrc.write( srcTemp.render( 115 | bg_name = fname, 116 | far_width = farPolyWidth, 117 | scroll_left_list = scrollLeftList, 118 | image_width = imageWidth, 119 | )) 120 | 121 | def createImages( floorImgFilename, ceilImgFilename, rows, outputCols, bottomTotalWidth, farImageReps, farPolyWidth, nearPolyWidth, startRow, endRow, startCeilingRow, endCeilingRow, outputFilename, imageAFilename ): 122 | logging.info("WORKING ON:" + floorImgFilename); 123 | print( outputFilename ) 124 | with Image.open( floorImgFilename ) as im: 125 | inputImg = im.convert('RGB') 126 | inputWidth, inputHeight = im.size 127 | inputCv = np.array(inputImg) 128 | transitionFilename = '' 129 | warpImgs =[] 130 | if len( imageAFilename ) > 0 : 131 | with Image.open( imageAFilename ) as imgA: 132 | inputImgA = imgA.convert('RGB') 133 | tmpImgA = np.array( inputImgA ) 134 | transitionFilename = os.path.splitext(outputFilename)[0] 135 | 136 | pal = im.getpalette() # must have same palettes. 137 | # get source points 138 | srcTopLeft = ( 0, 0 ) 139 | srcTopRight = ( inputWidth-1, 0 ) 140 | srcBottomLeft = ( 0, inputHeight-1 ) 141 | srcBottomRight = ( inputWidth-1, inputHeight-1 ) 142 | srcPts = np.array( [ srcBottomLeft, srcBottomRight, srcTopRight, srcTopLeft] ) 143 | logging.info("srcPts:"); 144 | logging.info(srcPts); 145 | 146 | # work image 147 | tmpImg = Image.new('RGB', (outputCols, rows)) 148 | tmpCv = np.array(tmpImg) 149 | bottomLeftStart = COLS / 2 - bottomTotalWidth / 2 150 | for rep in range( 0, farImageReps +1, 1 ): 151 | # detination points 152 | dstTopLeft = ( rep * farPolyWidth, startRow ) 153 | dstTopRight = ( rep * farPolyWidth + farPolyWidth-0.5, startRow ) 154 | dstBottomLeft = ( bottomLeftStart + rep * nearPolyWidth, endRow ) 155 | dstBottomRight = ( bottomLeftStart + rep * nearPolyWidth + nearPolyWidth-0.5, endRow ) 156 | dstPts = np.array( [ dstBottomLeft, dstBottomRight, dstTopRight, dstTopLeft] ) 157 | dstPoly = np.array( [ dstBottomLeft, dstBottomRight, dstTopRight, dstTopLeft], dtype=np.int32 ) 158 | 159 | logging.info("rep %d dstPts:" % ( rep ) ); 160 | logging.info(dstPts); 161 | 162 | gridTopLeft = ( max( min( dstTopLeft[0] // 8, dstBottomLeft[0]//8), 0 ) , dstTopLeft[1]//8 ) 163 | gridBottomRight = ( min( max( dstBottomRight[0] // 8, dstTopRight[0]//8), (outputCols//8) -1 ) , dstBottomRight[1]//8 ) 164 | logging.info(gridTopLeft); 165 | logging.info(gridBottomRight); 166 | # Get Perspective Transform Algorithm 167 | srcPtsList = np.float32( srcPts.tolist() ) 168 | dstPtsList = np.float32( dstPts.tolist() ) 169 | xfrmMatrix = cv2.getPerspectiveTransform(srcPtsList, dstPtsList) 170 | 171 | # warp it 172 | image_size = (tmpCv.shape[1], tmpCv.shape[0]) 173 | warpCv = cv2.warpPerspective(inputCv, xfrmMatrix, dsize=image_size) 174 | warpImg = Image.fromarray( warpCv ) 175 | if args.output_warped_images: 176 | warpImg.save( "warped_floor_%d.png" %(rep) ) 177 | 178 | 179 | ## create a copy mask 180 | maskCv = np.zeros_like(tmpCv) 181 | maskCv = cv2.fillPoly(maskCv, pts = [dstPoly], color = (255, 255, 255) ) 182 | maskCv = maskCv.all(axis=2) 183 | # copy warped image 184 | tmpCv[maskCv, :] = warpCv[maskCv, :] 185 | warpImgs.append( ( maskCv, warpCv[maskCv, :], gridTopLeft, gridBottomRight ) ) 186 | 187 | if len(transitionFilename) > 0: 188 | for rep in range( farImageReps , -1, -1 ): 189 | tmpImgA[warpImgs[rep][0], :] = warpImgs[rep][1] 190 | maskImgA = Image.fromarray( tmpImgA ) 191 | ImageDraw.floodfill( maskImgA, ( outputCols-1, rows/2), ( pal[0], pal[1], pal[2]) ) 192 | outImgA = maskImgA.quantize( palette = im ) 193 | outImgA.save( "%s_%d.png" %(transitionFilename, rep ) ) 194 | # Get sub region and save it too 195 | cropped = outImgA.crop( ( warpImgs[rep][2][0]*8, warpImgs[rep][2][1]*8, warpImgs[rep][3][0]*8+8, warpImgs[rep][3][1]*8+8 ) ) 196 | cropped.save( "%s_%d-%d_%d_%d_%d.png" %(transitionFilename, rep, warpImgs[rep][2][0], warpImgs[rep][2][1], warpImgs[rep][3][0], warpImgs[rep][3][1] ) ) 197 | 198 | 199 | 200 | # check if ceilng was set. 201 | if startCeilingRow >= 0 and endCeilingRow > 0: 202 | ceilFilename = ceilImgFilename if len(ceilImgFilename) > 0 else floorImgFilename 203 | with Image.open( ceilFilename ) as ceil: 204 | inputCeilingImg = ceil.convert('RGB') 205 | inputWidth, inputHeight = ceil.size 206 | inputCeilingCv = np.array(inputCeilingImg) 207 | # assume old pal 208 | # get source points 209 | srcTopLeft = ( 0, 0 ) 210 | srcTopRight = ( inputWidth-1, 0 ) 211 | srcBottomLeft = ( 0, inputHeight-1 ) 212 | srcBottomRight = ( inputWidth-1, inputHeight-1 ) 213 | srcPts = np.array( [ srcBottomLeft, srcBottomRight, srcTopRight, srcTopLeft] ) 214 | logging.info("srcPts:"); 215 | logging.info(srcPts); 216 | topLeftStart = COLS / 2 - bottomTotalWidth / 2 217 | for rep in range( 0, farImageReps +1, 1 ): 218 | # detination points 219 | dstTopLeft = ( topLeftStart + rep * nearPolyWidth, startCeilingRow ) 220 | dstTopRight = ( topLeftStart + rep * nearPolyWidth + nearPolyWidth, startCeilingRow ) 221 | dstBottomLeft = ( rep * farPolyWidth, endCeilingRow ) 222 | dstBottomRight = ( rep * farPolyWidth + farPolyWidth, endCeilingRow ) 223 | dstPts = np.array( [ dstBottomLeft, dstBottomRight, dstTopRight, dstTopLeft] ) 224 | logging.info("dstPts:"); 225 | logging.info(dstPts); 226 | dstPoly = np.array( [ dstBottomLeft, dstBottomRight, dstTopRight, dstTopLeft], dtype=np.int32 ) 227 | # Get Perspective Transform Algorithm 228 | srcPtsList = np.float32( srcPts.tolist() ) 229 | dstPtsList = np.float32( dstPts.tolist() ) 230 | xfrmMatrix = cv2.getPerspectiveTransform(srcPtsList, dstPtsList) 231 | 232 | # warp it 233 | image_size = (tmpCv.shape[1], tmpCv.shape[0]) 234 | warpCv = cv2.warpPerspective(inputCeilingCv, xfrmMatrix, dsize=image_size) 235 | warpImg = Image.fromarray( warpCv ) 236 | if args.output_warped_images: 237 | warpImg.save( "warped_ceil_%d.png" %(rep) ) 238 | 239 | ## create a copy mask 240 | maskCv = np.zeros_like(tmpCv) 241 | maskCv = cv2.fillPoly(maskCv, pts = [dstPoly], color = (255, 255, 255) ) 242 | maskCv = maskCv.all(axis=2) 243 | # copy warped image 244 | tmpCv[maskCv, :] = warpCv[maskCv, :] 245 | 246 | 247 | # convert backto PIL 248 | maskImg = Image.fromarray( tmpCv ) 249 | ImageDraw.floodfill( maskImg, ( outputCols-1, rows/2), ( pal[0], pal[1], pal[2]) ) 250 | ##maskImg.save( "mask.png") 251 | outImg = maskImg.quantize( palette = im ) 252 | #outImg = Image.new('P', (outputCols, rows)) 253 | #outImg.putpalette(pal) 254 | outImg.save( outputFilename ) 255 | 256 | def main(args, loglevel): 257 | logging.basicConfig(format="%(levelname)s: %(message)s", level=loglevel) 258 | startRow = args.start_row 259 | endRow = args.end_row 260 | if startRow == endRow: 261 | print("Start and end row of floor must differ") 262 | return 263 | elif startRow > endRow: 264 | temp = endRow 265 | endRow = startRow 266 | startRow = temp 267 | 268 | 269 | startCeilingRow = args.start_ceiling_row 270 | endCeilingRow = args.end_ceiling_row 271 | if startCeilingRow == endCeilingRow and startCeilingRow > 0: 272 | print("Start and end row of ceiling must differ") 273 | return 274 | elif startCeilingRow > endCeilingRow: 275 | temp = endCeilingRow 276 | endCeilingRow = startCeilingRow 277 | startCeilingRow = temp 278 | 279 | farImageReps = args.far_image_reps 280 | nearImageReps = args.near_image_reps 281 | if farImageReps <= nearImageReps: 282 | print("Far image reps must be larger than near image reps") 283 | return 284 | 285 | 286 | imageFilename = 'image.png' 287 | imageFilenameB = '' 288 | if len(args.input_filename) > 0 : 289 | imageFilename = args.input_filename[0] 290 | if len(args.input_filename) > 1 : 291 | imageFilenameB = args.input_filename[1] 292 | 293 | 294 | imageCeilingFilename = '' 295 | imageCeilingFilenameB = '' 296 | if len(args.input_ceiling_filename) > 0 : 297 | imageCeilingFilename = args.input_ceiling_filename[0] 298 | if len(args.input_ceiling_filename) > 1 : 299 | imageCeilingFilenameB = args.input_ceiling_filename[1] 300 | 301 | outputFilename = 'bg.png' 302 | outputFilenameB = '' 303 | if len(args.output_filename) > 0 : 304 | outputFilename = args.output_filename[0] 305 | if len(args.output_filename) > 1 : 306 | outputFilenameB = args.output_filename[1] 307 | 308 | 309 | 310 | projectDir = args.project_directory 311 | 312 | 313 | farPolyWidth = COLS / farImageReps 314 | nearPolyWidth = COLS / nearImageReps 315 | 316 | logging.info("Image reps far: %d", farImageReps) 317 | logging.info("Image reps near: %d", nearImageReps) 318 | # always put out image repetition 319 | print("Scroll width far: %.3f" % farPolyWidth) 320 | print("Scroll width near: %.3f" % nearPolyWidth) 321 | print("Starting row floor: %d" % startRow) 322 | print("Ending row floor: %d" % endRow) 323 | scrollRows = endRow - startRow 324 | scrollRatio = nearPolyWidth / farPolyWidth 325 | scrollRowStep = ( scrollRatio - 1.0 ) / scrollRows 326 | print("* Scroll increment floor: %.4f" % scrollRowStep) 327 | finalScrollStep = (nearPolyWidth - farPolyWidth) / scrollRows 328 | print("* Final Scroll increment floor: %.4f" % finalScrollStep) 329 | 330 | 331 | if startCeilingRow > -1 and endCeilingRow > startCeilingRow : 332 | logging.info("Starting row ceiling: %d", startCeilingRow) 333 | logging.info("Ending row ceiling: %d", endCeilingRow) 334 | scrollCeilingRows = endCeilingRow - startCeilingRow 335 | scrollCeilingRatio = nearPolyWidth / farPolyWidth 336 | scrollCeilingRowStep = ( scrollCeilingRatio - 1.0 ) / scrollCeilingRows 337 | print("* Scroll increment ceiling: %.4f" % scrollCeilingRowStep) 338 | 339 | 340 | bottomTotalWidth = nearPolyWidth * farImageReps 341 | offset = farImageReps % 2 != nearImageReps % 2 342 | outputCols = int(COLS + nearPolyWidth) 343 | # must be multiple of 8 for tile breakdown 344 | if outputCols % 8 > 0: 345 | outputCols = (int( outputCols/8) +1) * 8 346 | 347 | print("Image size %d x %d" % ( outputCols,rows ) ) 348 | 349 | createImages( imageFilename, imageCeilingFilename, rows, outputCols, bottomTotalWidth, farImageReps, farPolyWidth, nearPolyWidth, startRow, endRow, startCeilingRow, endCeilingRow, outputFilename, '' ) 350 | 351 | if imageFilenameB: 352 | print("DO SECOND IMAGE") 353 | print(imageFilenameB) 354 | createImages( imageFilenameB, imageCeilingFilenameB, rows, outputCols, bottomTotalWidth, farImageReps, farPolyWidth, nearPolyWidth, startRow, endRow, startCeilingRow, endCeilingRow, outputFilenameB, outputFilename ) 355 | 356 | 357 | if len(projectDir) > 0 : 358 | makeProjectFiles( projectDir, outputFilename, endRow, startRow, nearPolyWidth, farPolyWidth, endCeilingRow, startCeilingRow, outputCols ) 359 | 360 | # the program. 361 | if __name__ == '__main__': 362 | parser = argparse.ArgumentParser( 363 | description = "Create endless scrolling background for SGDK", 364 | epilog = "As an alternative to the commandline, params can be placed in a file, one per line, and specified on the commandline like '%(prog)s @params.conf'.", 365 | fromfile_prefix_chars = '@' ) 366 | # parameter list 367 | parser.add_argument( 368 | "-v", 369 | "--verbose", 370 | help="increase output verbosity", 371 | action="store_true") 372 | 373 | parser.add_argument( "-f", 374 | "--far_image_reps", 375 | default = 4, 376 | type=int, 377 | help = "How many times to repeat image at far side of the floor/ceiling", 378 | metavar = "ARG") 379 | 380 | parser.add_argument( "-n", 381 | "--near_image_reps", 382 | default = 2, 383 | type=int, 384 | help = "How many times to repeat image at near side of the floor/ceiling", 385 | metavar = "ARG") 386 | 387 | parser.add_argument( "-s", 388 | "--start_row", 389 | default = 180, 390 | type=int, 391 | help = "Which row starts the floor", 392 | metavar = "ARG") 393 | 394 | parser.add_argument( "-e", 395 | "--end_row", 396 | default = 223, 397 | type=int, 398 | help = "Which row ends the floor", 399 | metavar = "ARG") 400 | 401 | 402 | 403 | parser.add_argument( "-i", 404 | "--input_filename", 405 | action = 'append', 406 | default = [], 407 | help = "input image filename", 408 | metavar = "ARG") 409 | 410 | 411 | 412 | parser.add_argument( "-S", 413 | "--start_ceiling_row", 414 | default = -1, 415 | type=int, 416 | help = "Which row starts the ceiling", 417 | metavar = "ARG") 418 | 419 | parser.add_argument( "-E", 420 | "--end_ceiling_row", 421 | default = -1, 422 | type=int, 423 | help = "Which row ends the ceiling", 424 | metavar = "ARG") 425 | 426 | parser.add_argument( "-I", 427 | "--input_ceiling_filename", 428 | default = [], 429 | help = "input ceiling image filename", 430 | metavar = "ARG") 431 | 432 | parser.add_argument( "-o", 433 | "--output_filename", 434 | action = 'append', 435 | default = [], 436 | help = "Output filename", 437 | metavar = "ARG") 438 | 439 | parser.add_argument( "-p", 440 | "--project_directory", 441 | default = '', 442 | help = "Create project directory with resource files and simple SGDK code.", 443 | metavar = "ARG") 444 | 445 | parser.add_argument( 446 | "-w", 447 | "--output_warped_images", 448 | help="Output warped images used to create final image.", 449 | action="store_true") 450 | 451 | args = parser.parse_args() 452 | 453 | # Setup logging 454 | if args.verbose: 455 | loglevel = logging.INFO 456 | else: 457 | loglevel = logging.WARNING 458 | 459 | main(args, loglevel) 460 | -------------------------------------------------------------------------------- /EndlessScroll/DOS/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "resources.h" 3 | 4 | s16 hScrollB[224]; 5 | fix32 fscroll[224]; 6 | s16 scrollStep = 0; 7 | 8 | bool doUpdate = false; 9 | int tick = 0; 10 | s16 currentBackgroundStep = 6; 11 | 12 | int indexA = 0; 13 | int indexB_0 = 0; 14 | int indexB_1 = 0; 15 | int indexB_2 = 0; 16 | int indexB_3 = 0; 17 | int indexB_4 = 0; 18 | int indexB_5 = 0; 19 | int indexB_6 = 0; 20 | 21 | void copyTiles6() { 22 | // copy tiles that matter to BG_B 23 | s16 offset = 0; 24 | for(int tx = 0; tx < 9; tx++) 25 | { 26 | u16 tile_id = indexB_6 + offset; 27 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 40 + tx, 22); 28 | ++offset; 29 | } 30 | for(int ty = 1; ty < 6; ty++) 31 | { 32 | for(int tx = 0; tx < 10; tx++) 33 | { 34 | u16 tile_id = indexB_6 + offset; 35 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 40 + tx, 22 + ty); 36 | ++offset; 37 | } 38 | } 39 | } 40 | 41 | void copyTiles5() { 42 | // 17 wide. 43 | s16 offset = 0; 44 | for(int tx = 0; tx < 9; tx++) 45 | { 46 | u16 tile_id = indexB_5 + offset; 47 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 33 + tx, 22); 48 | ++offset; 49 | } 50 | offset+=6; 51 | for(int tx = 0; tx < 10; tx++) 52 | { 53 | u16 tile_id = indexB_5 + offset; 54 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 33 + tx, 23); 55 | ++offset; 56 | } 57 | offset+=7; 58 | offset+=2; 59 | for(int tx = 2; tx < 12; tx++) 60 | { 61 | u16 tile_id = indexB_5 + offset; 62 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 33 + tx, 24); 63 | ++offset; 64 | } 65 | offset+=5; 66 | offset+=3; 67 | for(int tx = 3; tx < 13; tx++) 68 | { 69 | u16 tile_id = indexB_5 + offset; 70 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 33 + tx, 25); 71 | ++offset; 72 | } 73 | offset+=4; 74 | offset+=4; 75 | for(int tx = 4; tx < 16; tx++) 76 | { 77 | u16 tile_id = indexB_5 + offset; 78 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 33 + tx, 26); 79 | ++offset; 80 | } 81 | offset+=1; 82 | offset+=5; 83 | for(int tx = 5; tx < 17; tx++) 84 | { 85 | u16 tile_id = indexB_5 + offset; 86 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 33 + tx, 27); 87 | ++offset; 88 | } 89 | 90 | 91 | 92 | } 93 | 94 | void copyTiles4() { 95 | s16 offset = 0; 96 | for(int tx = 0; tx < 9; tx++) 97 | { 98 | u16 tile_id = indexB_4 + offset; 99 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 26 + tx, 22); 100 | ++offset; 101 | } 102 | offset+=5; 103 | for(int tx = 0; tx < 9; tx++) 104 | { 105 | u16 tile_id = indexB_4 + offset; 106 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 26 + tx, 23); 107 | ++offset; 108 | } 109 | offset+=5; 110 | offset+=1; 111 | for(int tx = 1; tx < 11; tx++) 112 | { 113 | u16 tile_id = indexB_4 + offset; 114 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 26 + tx, 24); 115 | ++offset; 116 | } 117 | offset+=3; 118 | offset+=2; 119 | for(int tx = 2; tx < 12; tx++) 120 | { 121 | u16 tile_id = indexB_4 + offset; 122 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 26 + tx, 25); 123 | ++offset; 124 | } 125 | offset+=2; 126 | offset+=2; 127 | for(int tx = 2; tx < 13; tx++) 128 | { 129 | u16 tile_id = indexB_4 + offset; 130 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 26 + tx, 26); 131 | ++offset; 132 | } 133 | offset+=1; 134 | offset+=3; 135 | for(int tx = 3; tx < 14; tx++) 136 | { 137 | u16 tile_id = indexB_4 + offset; 138 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 26 + tx, 27); 139 | ++offset; 140 | } 141 | 142 | 143 | } 144 | 145 | void copyTiles3() { 146 | s16 offset = 0; 147 | for(int tx = 0; tx < 7; tx++) 148 | { 149 | u16 tile_id = indexB_3 + offset; 150 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 20 + tx, 22); 151 | ++offset; 152 | } 153 | offset+=2; 154 | for(int tx = 0; tx < 8; tx++) 155 | { 156 | u16 tile_id = indexB_3 + offset; 157 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 20 + tx, 23); 158 | ++offset; 159 | } 160 | offset+=2; 161 | for(int tx = 0; tx < 9; tx++) 162 | { 163 | u16 tile_id = indexB_3 + offset; 164 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 20 + tx, 24); 165 | ++offset; 166 | } 167 | offset+=1; 168 | for(int tx = 0; tx < 9; tx++) 169 | { 170 | u16 tile_id = indexB_3 + offset; 171 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 20 + tx, 25); 172 | ++offset; 173 | } 174 | offset+=1; 175 | for(int tx = 0; tx < 10; tx++) 176 | { 177 | u16 tile_id = indexB_3 + offset; 178 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 20 + tx, 26); 179 | ++offset; 180 | } 181 | for(int tx = 0; tx < 10; tx++) 182 | { 183 | u16 tile_id = indexB_3 + offset; 184 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 20 + tx, 27); 185 | ++offset; 186 | } 187 | } 188 | 189 | void copyTiles2() { 190 | s16 offset = 3; 191 | for(int tx = 3; tx < 10; tx++) 192 | { 193 | u16 tile_id = indexB_2 + offset; 194 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 10 + tx, 22); 195 | ++offset; 196 | } 197 | offset+=2; 198 | for(int tx = 2; tx < 10; tx++) 199 | { 200 | u16 tile_id = indexB_2 + offset; 201 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 10 + tx, 23); 202 | ++offset; 203 | } 204 | offset+=1; 205 | for(int tx = 1; tx < 10; tx++) 206 | { 207 | u16 tile_id = indexB_2 + offset; 208 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 10 + tx, 24); 209 | ++offset; 210 | } 211 | offset+=1; 212 | for(int tx = 1; tx < 10; tx++) 213 | { 214 | u16 tile_id = indexB_2 + offset; 215 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 10 + tx, 25); 216 | ++offset; 217 | } 218 | for(int tx = 0; tx < 10; tx++) 219 | { 220 | u16 tile_id = indexB_2 + offset; 221 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 10 + tx, 26); 222 | ++offset; 223 | } 224 | for(int tx = 0; tx < 10; tx++) 225 | { 226 | u16 tile_id = indexB_2 + offset; 227 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), 10 + tx, 27); 228 | ++offset; 229 | } 230 | } 231 | 232 | void copyTiles1() { 233 | s16 offset = 6; 234 | for(s16 tx = 6; tx < 11; tx++) 235 | { 236 | u16 tile_id = indexB_1 + offset; 237 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), tx, 22); 238 | ++offset; 239 | } 240 | 241 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexB_1 + 8), 11, 22); 242 | 243 | for(s16 tx = 12; tx < 14; tx++) 244 | { 245 | u16 tile_id = indexB_1 + offset; 246 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), tx, 22); 247 | ++offset; 248 | } 249 | 250 | 251 | offset+=4; 252 | for(s16 tx = 4; tx < 14; tx++) 253 | { 254 | u16 tile_id = indexB_1 + offset; 255 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), tx, 23); 256 | ++offset; 257 | } 258 | offset+=3; 259 | for(s16 tx = 3; tx < 13; tx++) 260 | { 261 | u16 tile_id = indexB_1 + offset; 262 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), tx, 24); 263 | ++offset; 264 | } 265 | offset+=1; 266 | offset+=2; 267 | for(s16 tx = 2; tx < 12; tx++) 268 | { 269 | u16 tile_id = indexB_1 + offset; 270 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), tx, 25); 271 | ++offset; 272 | } 273 | offset+=2; 274 | offset+=1; 275 | for(s16 tx = 1; tx < 12; tx++) 276 | { 277 | u16 tile_id = indexB_1 + offset; 278 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), tx, 26); 279 | ++offset; 280 | } 281 | offset+=2; 282 | for(s16 tx = 0; tx < 11; tx++) 283 | { 284 | u16 tile_id = indexB_1 + offset; 285 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), tx, 27); 286 | ++offset; 287 | } 288 | 289 | 290 | } 291 | 292 | void copyTiles0() { 293 | s16 offset = 0; 294 | for(s16 ty = 0; ty < 6; ty++) 295 | { 296 | for(s16 tx = 0; tx < 7; tx++) 297 | { 298 | u16 tile_id = indexB_0 + offset; 299 | VDP_setTileMapXY(BG_B, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, tile_id), tx, 22 + ty); 300 | ++offset; 301 | } 302 | } 303 | } 304 | 305 | 306 | static void updateBackground() { 307 | switch( currentBackgroundStep ) { 308 | case 6: 309 | break; 310 | case 5: 311 | break; 312 | default: 313 | break; 314 | } 315 | } 316 | 317 | 318 | static void scrollLeft() { 319 | ++scrollStep; 320 | if (scrollStep < 53 ) { 321 | 322 | fscroll[180] = fscroll[180] - FIX32( 1.000 ); 323 | fscroll[181] = fscroll[181] - FIX32( 1.012 ); 324 | fscroll[182] = fscroll[182] - FIX32( 1.023 ); 325 | fscroll[183] = fscroll[183] - FIX32( 1.035 ); 326 | fscroll[184] = fscroll[184] - FIX32( 1.047 ); 327 | fscroll[185] = fscroll[185] - FIX32( 1.058 ); 328 | fscroll[186] = fscroll[186] - FIX32( 1.070 ); 329 | fscroll[187] = fscroll[187] - FIX32( 1.081 ); 330 | fscroll[188] = fscroll[188] - FIX32( 1.093 ); 331 | fscroll[189] = fscroll[189] - FIX32( 1.105 ); 332 | fscroll[190] = fscroll[190] - FIX32( 1.116 ); 333 | fscroll[191] = fscroll[191] - FIX32( 1.128 ); 334 | fscroll[192] = fscroll[192] - FIX32( 1.140 ); 335 | fscroll[193] = fscroll[193] - FIX32( 1.151 ); 336 | fscroll[194] = fscroll[194] - FIX32( 1.163 ); 337 | fscroll[195] = fscroll[195] - FIX32( 1.174 ); 338 | fscroll[196] = fscroll[196] - FIX32( 1.186 ); 339 | fscroll[197] = fscroll[197] - FIX32( 1.198 ); 340 | fscroll[198] = fscroll[198] - FIX32( 1.209 ); 341 | fscroll[199] = fscroll[199] - FIX32( 1.221 ); 342 | fscroll[200] = fscroll[200] - FIX32( 1.233 ); 343 | fscroll[201] = fscroll[201] - FIX32( 1.244 ); 344 | fscroll[202] = fscroll[202] - FIX32( 1.256 ); 345 | fscroll[203] = fscroll[203] - FIX32( 1.267 ); 346 | fscroll[204] = fscroll[204] - FIX32( 1.279 ); 347 | fscroll[205] = fscroll[205] - FIX32( 1.291 ); 348 | fscroll[206] = fscroll[206] - FIX32( 1.302 ); 349 | fscroll[207] = fscroll[207] - FIX32( 1.314 ); 350 | fscroll[208] = fscroll[208] - FIX32( 1.326 ); 351 | fscroll[209] = fscroll[209] - FIX32( 1.337 ); 352 | fscroll[210] = fscroll[210] - FIX32( 1.349 ); 353 | fscroll[211] = fscroll[211] - FIX32( 1.360 ); 354 | fscroll[212] = fscroll[212] - FIX32( 1.372 ); 355 | fscroll[213] = fscroll[213] - FIX32( 1.384 ); 356 | fscroll[214] = fscroll[214] - FIX32( 1.395 ); 357 | fscroll[215] = fscroll[215] - FIX32( 1.407 ); 358 | fscroll[216] = fscroll[216] - FIX32( 1.419 ); 359 | fscroll[217] = fscroll[217] - FIX32( 1.430 ); 360 | fscroll[218] = fscroll[218] - FIX32( 1.442 ); 361 | fscroll[219] = fscroll[219] - FIX32( 1.453 ); 362 | fscroll[220] = fscroll[220] - FIX32( 1.465 ); 363 | fscroll[221] = fscroll[221] - FIX32( 1.477 ); 364 | fscroll[222] = fscroll[222] - FIX32( 1.488 ); 365 | fscroll[223] = fscroll[223] - FIX32( 1.500 ); 366 | } else { 367 | scrollStep = 0; 368 | memset(fscroll, 0, sizeof(fscroll)); 369 | if( doUpdate ) { 370 | switch ( currentBackgroundStep ) { 371 | case 6: 372 | copyTiles6(); 373 | break; 374 | case 5: 375 | copyTiles5(); 376 | break; 377 | case 4: 378 | copyTiles4(); 379 | break; 380 | case 3: 381 | copyTiles3(); 382 | break; 383 | case 2: 384 | copyTiles2(); 385 | break; 386 | case 1: 387 | copyTiles1(); 388 | break; 389 | case 0: 390 | copyTiles0(); 391 | break; 392 | } 393 | currentBackgroundStep--; 394 | if( currentBackgroundStep < 0 ) { 395 | doUpdate = false; 396 | } 397 | } 398 | } 399 | } 400 | 401 | static void scrollRight() { 402 | --scrollStep; 403 | if (scrollStep >= 0) { 404 | 405 | fscroll[180] = fscroll[180] + FIX32( 1.000 ); 406 | fscroll[181] = fscroll[181] + FIX32( 1.012 ); 407 | fscroll[182] = fscroll[182] + FIX32( 1.023 ); 408 | fscroll[183] = fscroll[183] + FIX32( 1.035 ); 409 | fscroll[184] = fscroll[184] + FIX32( 1.047 ); 410 | fscroll[185] = fscroll[185] + FIX32( 1.058 ); 411 | fscroll[186] = fscroll[186] + FIX32( 1.070 ); 412 | fscroll[187] = fscroll[187] + FIX32( 1.081 ); 413 | fscroll[188] = fscroll[188] + FIX32( 1.093 ); 414 | fscroll[189] = fscroll[189] + FIX32( 1.105 ); 415 | fscroll[190] = fscroll[190] + FIX32( 1.116 ); 416 | fscroll[191] = fscroll[191] + FIX32( 1.128 ); 417 | fscroll[192] = fscroll[192] + FIX32( 1.140 ); 418 | fscroll[193] = fscroll[193] + FIX32( 1.151 ); 419 | fscroll[194] = fscroll[194] + FIX32( 1.163 ); 420 | fscroll[195] = fscroll[195] + FIX32( 1.174 ); 421 | fscroll[196] = fscroll[196] + FIX32( 1.186 ); 422 | fscroll[197] = fscroll[197] + FIX32( 1.198 ); 423 | fscroll[198] = fscroll[198] + FIX32( 1.209 ); 424 | fscroll[199] = fscroll[199] + FIX32( 1.221 ); 425 | fscroll[200] = fscroll[200] + FIX32( 1.233 ); 426 | fscroll[201] = fscroll[201] + FIX32( 1.244 ); 427 | fscroll[202] = fscroll[202] + FIX32( 1.256 ); 428 | fscroll[203] = fscroll[203] + FIX32( 1.267 ); 429 | fscroll[204] = fscroll[204] + FIX32( 1.279 ); 430 | fscroll[205] = fscroll[205] + FIX32( 1.291 ); 431 | fscroll[206] = fscroll[206] + FIX32( 1.302 ); 432 | fscroll[207] = fscroll[207] + FIX32( 1.314 ); 433 | fscroll[208] = fscroll[208] + FIX32( 1.326 ); 434 | fscroll[209] = fscroll[209] + FIX32( 1.337 ); 435 | fscroll[210] = fscroll[210] + FIX32( 1.349 ); 436 | fscroll[211] = fscroll[211] + FIX32( 1.360 ); 437 | fscroll[212] = fscroll[212] + FIX32( 1.372 ); 438 | fscroll[213] = fscroll[213] + FIX32( 1.384 ); 439 | fscroll[214] = fscroll[214] + FIX32( 1.395 ); 440 | fscroll[215] = fscroll[215] + FIX32( 1.407 ); 441 | fscroll[216] = fscroll[216] + FIX32( 1.419 ); 442 | fscroll[217] = fscroll[217] + FIX32( 1.430 ); 443 | fscroll[218] = fscroll[218] + FIX32( 1.442 ); 444 | fscroll[219] = fscroll[219] + FIX32( 1.453 ); 445 | fscroll[220] = fscroll[220] + FIX32( 1.465 ); 446 | fscroll[221] = fscroll[221] + FIX32( 1.477 ); 447 | fscroll[222] = fscroll[222] + FIX32( 1.488 ); 448 | fscroll[223] = fscroll[223] + FIX32( 1.500 ); 449 | 450 | } else { 451 | scrollStep = 53; 452 | 453 | fscroll[180] = FIX32(-53.000); 454 | fscroll[181] = FIX32(-53.620); 455 | fscroll[182] = FIX32(-54.240); 456 | fscroll[183] = FIX32(-54.860); 457 | fscroll[184] = FIX32(-55.481); 458 | fscroll[185] = FIX32(-56.101); 459 | fscroll[186] = FIX32(-56.721); 460 | fscroll[187] = FIX32(-57.341); 461 | fscroll[188] = FIX32(-57.961); 462 | fscroll[189] = FIX32(-58.581); 463 | fscroll[190] = FIX32(-59.202); 464 | fscroll[191] = FIX32(-59.822); 465 | fscroll[192] = FIX32(-60.442); 466 | fscroll[193] = FIX32(-61.062); 467 | fscroll[194] = FIX32(-61.682); 468 | fscroll[195] = FIX32(-62.302); 469 | fscroll[196] = FIX32(-62.922); 470 | fscroll[197] = FIX32(-63.543); 471 | fscroll[198] = FIX32(-64.163); 472 | fscroll[199] = FIX32(-64.783); 473 | fscroll[200] = FIX32(-65.403); 474 | fscroll[201] = FIX32(-66.023); 475 | fscroll[202] = FIX32(-66.643); 476 | fscroll[203] = FIX32(-67.264); 477 | fscroll[204] = FIX32(-67.884); 478 | fscroll[205] = FIX32(-68.504); 479 | fscroll[206] = FIX32(-69.124); 480 | fscroll[207] = FIX32(-69.744); 481 | fscroll[208] = FIX32(-70.364); 482 | fscroll[209] = FIX32(-70.984); 483 | fscroll[210] = FIX32(-71.605); 484 | fscroll[211] = FIX32(-72.225); 485 | fscroll[212] = FIX32(-72.845); 486 | fscroll[213] = FIX32(-73.465); 487 | fscroll[214] = FIX32(-74.085); 488 | fscroll[215] = FIX32(-74.705); 489 | fscroll[216] = FIX32(-75.326); 490 | fscroll[217] = FIX32(-75.946); 491 | fscroll[218] = FIX32(-76.566); 492 | fscroll[219] = FIX32(-77.186); 493 | fscroll[220] = FIX32(-77.806); 494 | fscroll[221] = FIX32(-78.426); 495 | fscroll[222] = FIX32(-79.047); 496 | fscroll[223] = FIX32(-79.667); 497 | } 498 | } 499 | 500 | int main(bool hard) 501 | { 502 | memset(hScrollB, 0, sizeof(hScrollB)); 503 | memset(fscroll, 0, sizeof(fscroll)); 504 | VDP_setScreenWidth320(); 505 | 506 | PAL_setPalette(PAL0, bga_pal.data, CPU); 507 | PAL_setColor(0, 0x0000); 508 | // set scrolling modes to support line scrolling. 509 | VDP_setScrollingMode(HSCROLL_LINE, VSCROLL_PLANE); 510 | 511 | // get initial tile position in VRAM and load image 512 | int ind = TILE_USER_INDEX; 513 | VDP_loadTileSet(bga.tileset, indexA, CPU); 514 | indexA= ind; 515 | indexB_0 = indexA + bga.tileset->numTile; // next position 516 | VDP_loadTileSet(bgb_0.tileset, indexB_0, CPU); 517 | 518 | indexB_1 = indexB_0 + bgb_0.tileset->numTile; // next position 519 | VDP_loadTileSet(bgb_1.tileset, indexB_1, CPU); 520 | 521 | indexB_2 = indexB_1 + bgb_1.tileset->numTile; // next position 522 | VDP_loadTileSet(bgb_2.tileset, indexB_2, CPU); 523 | 524 | indexB_3 = indexB_2 + bgb_2.tileset->numTile; // next position 525 | VDP_loadTileSet(bgb_3.tileset, indexB_3, CPU); 526 | 527 | indexB_4 = indexB_3 + bgb_3.tileset->numTile; // next position 528 | VDP_loadTileSet(bgb_4.tileset, indexB_4, CPU); 529 | 530 | indexB_5 = indexB_4 + bgb_4.tileset->numTile; // next position 531 | VDP_loadTileSet(bgb_5.tileset, indexB_5, CPU); 532 | 533 | indexB_6 = indexB_5 + bgb_5.tileset->numTile; // next position 534 | VDP_loadTileSet(bgb_6.tileset, indexB_6, CPU); 535 | 536 | VDP_drawImageEx(BG_B, &bga, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, indexA), 0, 0, FALSE, TRUE); 537 | 538 | while (TRUE) 539 | { 540 | tick++; 541 | if( tick == 200 ) { 542 | doUpdate = true; 543 | } 544 | /* 545 | if( tick == 100 ) { 546 | // Populate a block using XY or DataRect: 547 | // copyTiles6(); 548 | } else if( tick == 150 ) { 549 | copyTiles5(); 550 | } else if( tick == 200 ) { 551 | copyTiles4(); 552 | } else if( tick == 250 ) { 553 | copyTiles3(); 554 | } else if( tick == 300 ) { 555 | copyTiles2(); 556 | } else if( tick == 350 ) { 557 | copyTiles1(); 558 | } else if( tick == 400 ) { 559 | copyTiles0(); 560 | }*/ 561 | 562 | 563 | scrollLeft(); 564 | //scrollRight(); 565 | for (int i = 0; i < 224; i++) // Not very efficient, but works for a demo 566 | { 567 | hScrollB[i] = F32_toInt(fscroll[i]); 568 | } 569 | VDP_setHorizontalScrollLine(BG_B, 0, hScrollB, 224, DMA); 570 | SYS_doVBlankProcess(); 571 | } 572 | } 573 | 574 | --------------------------------------------------------------------------------