diff --git a/CMakeLists.txt b/CMakeLists.txt index 2da7c78d..404dc974 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ cmake_minimum_required(VERSION 2.8.5) project(ACE) +set(ACE_DIR ${CMAKE_CURRENT_LIST_DIR} PARENT_SCOPE) # needed for helper fns # Adhere to GNU filesystem layout conventions include(GNUInstallDirs) @@ -46,6 +47,8 @@ set(TARGET_NAME ${PROJECT_NAME_LOWER}) add_library(${TARGET_NAME} ${SOURCES} ${HEADERS}) target_link_libraries(${TARGET_NAME}) +#----------------------------------------------------------------------- INSTALL + install(TARGETS ${TARGET_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ${HEADERS_ACE} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ace) install(FILES ${HEADERS_ACE_GENERIC} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ace/generic) @@ -53,3 +56,88 @@ install(FILES ${HEADERS_ACE_UTILS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ace/u install(FILES ${HEADERS_ACE_MANAGERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ace/managers) install(FILES ${HEADERS_ACE_MANAGERS_VP} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ace/managers/viewport) install(FILES ${HEADERS_FIXMATH} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/fixmath) + +#--------------------------------------------------------------------- FUNCTIONS + +function(toAbsolute PATH_IN) + if(NOT IS_ABSOLUTE ${PATH_IN}) + set(${PATH_IN} "${CMAKE_CURRENT_SOURCE_DIR}/${${PATH_IN}}" PARENT_SCOPE) + endif() +endfunction() + +function(convertPalette TARGET PALETTE_IN PALETTE_OUT) + add_custom_command( + OUTPUT ${PALETTE_OUT} + COMMAND ${ACE_DIR}/tools/bin/palette_conv ${PALETTE_IN} ${PALETTE_OUT} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${PALETTE_IN} + ) + target_sources(${TARGET} PUBLIC ${PALETTE_OUT}) +endfunction() + +function(convertBitmaps) + set(options INTERLEAVED) + set(oneValArgs TARGET PALETTE MASK_COLOR) + set(multiValArgs SOURCES DESTINATIONS MASKS) + cmake_parse_arguments( + convertBitmaps "${options}" "${oneValArgs}" "${multiValArgs}" ${ARGN} + ) + + if(${convertBitmaps_INTERLEAVED}) + set(extraFlags -i) + endif() + + list(LENGTH convertBitmaps_SOURCES srcCount) + list(LENGTH convertBitmaps_DESTINATIONS dstCount) + list(LENGTH convertBitmaps_MASKS maskCount) + if(NOT ${srcCount} EQUAL ${dstCount}) + message(FATAL_ERROR "SOURCES count doesn't match DESTINATIONS count") + endif() + if(${maskCount} AND NOT ${maskCount} EQUAL ${srcCount}) + message(FATAL_ERROR "MASKS count doesn't match SOURCES count") + endif() + if("${convertBitmaps_MASK_COLOR} " STREQUAL " ") + if(${maskCount} GREATER 0) + message(FATAL_ERROR "MASK_COLOR unspecified") + endif() + else() + string(REPLACE "#" "\\#" convertBitmaps_MASK_COLOR "${convertBitmaps_MASK_COLOR}") + endif() + + MATH(EXPR srcCount "${srcCount}-1") + foreach(bitmap_idx RANGE ${srcCount}) # /path/file.png + list(GET convertBitmaps_SOURCES ${bitmap_idx} bitmapPath) + toAbsolute(bitmapPath) + list(GET convertBitmaps_DESTINATIONS ${bitmap_idx} outPath) + toAbsolute(outPath) + if(${maskCount} GREATER 0) + list(GET convertBitmaps_MASKS ${bitmap_idx} maskPath) + toAbsolute(maskPath) + endif() + + if(NOT "${convertBitmaps_MASK_COLOR} " STREQUAL " ") + set(extraFlags ${extraFlags} -mc ${convertBitmaps_MASK_COLOR} -mo ${maskPath}) + endif() + add_custom_command( + OUTPUT ${outPath} ${maskPath} + COMMAND ${ACE_DIR}/tools/bitmap_conv/bitmap_conv ${convertBitmaps_PALETTE} ${bitmapPath} -o ${outPath} ${extraFlags} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${convertBitmaps_PALETTE} ${bitmapPath} + ) + target_sources(${convertBitmaps_TARGET} PUBLIC ${outPath} ${maskPath}) + endforeach() +endfunction() + +function(convertFont TARGET FONT_IN FONT_OUT) +toAbsolute(FONT_IN) +toAbsolute(FONT_OUT) +get_filename_component(ext ${FONT_OUT} EXT) +string(SUBSTRING ${ext} 1 -1 ext) +add_custom_command( + OUTPUT ${FONT_OUT} + COMMAND ${ACE_DIR}/tools/bin/font_conv ${FONT_IN} ${ext} -out ${FONT_OUT} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${FONT_IN} +) +target_sources(${TARGET} PUBLIC ${FONT_OUT}) +endfunction() diff --git a/include/ace/generic/main.h b/include/ace/generic/main.h index 033f4d9a..c2e0d916 100644 --- a/include/ace/generic/main.h +++ b/include/ace/generic/main.h @@ -19,6 +19,24 @@ void genericCreate(void); void genericProcess(void); void genericDestroy(void); +#if defined(__GNUC__) +#include + +#if UINT32_MAX == UINTPTR_MAX +#define STACK_CHK_GUARD 0xe2dee396 +#else +#define STACK_CHK_GUARD 0x595e9fbd94fda766 +#endif + +uintptr_t __stack_chk_guard = STACK_CHK_GUARD; + +__attribute__((noreturn)) +void __stack_chk_fail(void) { + logWrite("ERR: STACK SMASHED\n"); + while(1) {} +} +#endif + int main(void) { systemCreate(); memCreate(); diff --git a/include/ace/managers/joy.h b/include/ace/managers/joy.h index 78cd6b12..80bd9337 100644 --- a/include/ace/managers/joy.h +++ b/include/ace/managers/joy.h @@ -59,11 +59,11 @@ typedef struct { extern tJoyManager g_sJoyManager; /* Functions */ -void joyOpen(void); +void joyOpen(UBYTE is4joy); void joySetState(UBYTE ubJoyCode, UBYTE ubJoyState); -UBYTE joyPeek(UBYTE ubJoyCode); +UBYTE joyCheck(UBYTE ubJoyCode); UBYTE joyUse(UBYTE ubJoyCode); diff --git a/include/ace/managers/viewport/camera.h b/include/ace/managers/viewport/camera.h index b6586f33..d3a15b0b 100644 --- a/include/ace/managers/viewport/camera.h +++ b/include/ace/managers/viewport/camera.h @@ -17,13 +17,16 @@ typedef struct { tVpManager sCommon; - tUwCoordYX uPos; /// Current camera pos - tUwCoordYX uLastPos; /// Previous camera pos - tUwCoordYX uMaxPos; /// Max camera pos: world W&H - camera W&H + tUwCoordYX uPos; ///< Current camera pos + tUwCoordYX uLastPos[2]; ///< Previous camera pos + tUwCoordYX uMaxPos; ///< Max camera pos: world W&H - camera W&H + UBYTE ubBfr; + UBYTE isDblBfr; } tCameraManager; tCameraManager *cameraCreate( - tVPort *pVPort, UWORD uwPosX, UWORD uwPosY, UWORD uwMaxX, UWORD uwMaxY + tVPort *pVPort, UWORD uwPosX, UWORD uwPosY, UWORD uwMaxX, UWORD uwMaxY, + UBYTE isDblBfr ); void cameraDestroy(tCameraManager *pManager); @@ -31,7 +34,7 @@ void cameraProcess(tCameraManager *pManager); void cameraReset( tCameraManager *pManager, - UWORD uwPosX, UWORD uwPosY, UWORD uwMaxX, UWORD uwMaxY + UWORD uwPosX, UWORD uwPosY, UWORD uwMaxX, UWORD uwMaxY, UBYTE isDblBfr ); void cameraSetCoord(tCameraManager *pManager, UWORD uwX, UWORD uwY); diff --git a/include/ace/managers/viewport/scrollbuffer.h b/include/ace/managers/viewport/scrollbuffer.h index d7082ec8..963258a8 100644 --- a/include/ace/managers/viewport/scrollbuffer.h +++ b/include/ace/managers/viewport/scrollbuffer.h @@ -11,7 +11,6 @@ * Scrollable buffer manager * Uses scrolling-trick from aminet to achieve memory-efficient scroll * Must be processed as last, because it calls WaitTOF - * Author: KaiN * Requires viewport managers: * - camera * TODO: make it work without tileBuffer manager @@ -28,40 +27,63 @@ #include #include +// vPort ptr +#define TAG_SCROLLBUFFER_VPORT (TAG_USER|1) +// Scrollable area bounds, in pixels +#define TAG_SCROLLBUFFER_BOUND_WIDTH (TAG_USER|2) +#define TAG_SCROLLBUFFER_BOUND_HEIGHT (TAG_USER|3) +// Buffer bitmap creation flags +#define TAG_SCROLLBUFFER_BITMAP_FLAGS (TAG_USER|4) +#define TAG_SCROLLBUFFER_IS_DBLBUF (TAG_USER|5) +// If in raw mode, offset on copperlist for placing required copper +// instructions, specified in copper instruction count since beginning. +#define TAG_SCROLLBUFFER_COPLIST_OFFSET_START (TAG_USER|6) +#define TAG_SCROLLBUFFER_COPLIST_OFFSET_BREAK (TAG_USER|7) +#define TAG_SCROLLBUFFER_MARGIN_WIDTH (TAG_USER|8) + +#define SCROLLBUFFER_FLAG_COPLIST_RAW 1 + /* Types */ typedef struct { tVpManager sCommon; - tCameraManager *pCameraManager; /// Quick ref to camera - - tBitMap *pBuffer; /// Ptr to buffer bitmap - tCopBlock *pStartBlock; /// Initial data fetch - tCopBlock *pBreakBlock; /// Bitplane ptr reset - tUwCoordYX uBfrBounds; /// Real bounds of buffer (includes height reserved for x-scroll) - UWORD uwBmAvailHeight; /// Avail height of buffer to blit (excludes height reserved for x-scroll) - UWORD uwVpHeightPrev; /// Prev height of related VPort, used to force refresh on change - UWORD uwModulo; /// Bitplane modulo - tAvg *pAvg; + tCameraManager *pCamera; ///< Quick ref to camera + + tBitMap *pFront; ///< Front buffer in double buffering + tBitMap *pBack; ///< Back buffer in double buffering + tCopBlock *pStartBlock; ///< Initial data fetch + tCopBlock *pBreakBlock; ///< Bitplane ptr reset + tUwCoordYX uBfrBounds; ///< Real bounds of buffer (includes height reserved for x-scroll) + UWORD uwBmAvailHeight; ///< Avail height of buffer to blit (excludes height reserved for x-scroll) + UWORD uwVpHeightPrev; ///< Prev height of related VPort, used to force refresh on change + UWORD uwModulo; ///< Bitplane modulo + UBYTE ubFlags; } tScrollBufferManager; /* Globals */ /* Functions */ -tScrollBufferManager *scrollBufferCreate( - tVPort *pVPort, UBYTE ubMarginWidth, - UWORD uwBoundWidth, UWORD uwBoundHeight -); +/** + * Creates scroll manager + */ +tScrollBufferManager *scrollBufferCreate(void *pTags, ...); void scrollBufferDestroy(tScrollBufferManager *pManager); +/** + * Scroll buffer process function + */ void scrollBufferProcess(tScrollBufferManager *pManager); void scrollBufferReset( tScrollBufferManager *pManager, UBYTE ubMarginWidth, - UWORD uwBoundWidth, UWORD uwBoundHeight + UWORD uwBoundWidth, UWORD uwBoundHeight, UBYTE ubBitmapFlags, UBYTE isDblBfr ); +/** + * Uses unsafe blit copy for using out-of-bound X ccord + */ void scrollBufferBlitMask( tBitMap *pSrc, WORD wSrcX, WORD wSrcY, tScrollBufferManager *pDstManager, diff --git a/include/ace/managers/viewport/simplebuffer.h b/include/ace/managers/viewport/simplebuffer.h index f2cc628c..89cd827b 100644 --- a/include/ace/managers/viewport/simplebuffer.h +++ b/include/ace/managers/viewport/simplebuffer.h @@ -13,10 +13,8 @@ */ #include -#include -#include -#include #include +#include #include // vPort ptr @@ -26,19 +24,17 @@ #define TAG_SIMPLEBUFFER_BOUND_HEIGHT (TAG_USER|3) // Buffer bitmap creation flags #define TAG_SIMPLEBUFFER_BITMAP_FLAGS (TAG_USER|4) +#define TAG_SIMPLEBUFFER_IS_DBLBUF (TAG_USER|5) // If in raw mode, offset on copperlist for placing required copper // instructions, specified in copper instruction count since beginning. #define TAG_SIMPLEBUFFER_COPLIST_OFFSET (TAG_USER|6) -// Flags for internal usage. -#define SIMPLEBUFFER_FLAG_X_SCROLLABLE 1 -#define SIMPLEBUFFER_FLAG_COPLIST_RAW 2 - typedef struct { tVpManager sCommon; - tCameraManager *pCameraManager; + tCameraManager *pCamera; // scroll-specific fields - tBitMap *pBuffer; ///< Bitmap buffer + tBitMap *pFront; ///< Currently displayed buffer. + tBitMap *pBack; ///< Buffer for drawing. tCopBlock *pCopBlock; ///< CopBlock containing modulo/shift/bitplane cmds tUwCoordYX uBfrBounds; ///< Buffer bounds in pixels UBYTE ubFlags; ///< Read only. See SIMPLEBUFFER_FLAG_*. diff --git a/include/ace/managers/viewport/tilebuffer.h b/include/ace/managers/viewport/tilebuffer.h index ed407154..299ae4f7 100644 --- a/include/ace/managers/viewport/tilebuffer.h +++ b/include/ace/managers/viewport/tilebuffer.h @@ -9,100 +9,158 @@ /** * Tilemap buffer manager - * Provides memory-efficient tilemap buffer + * Provides speed- and memory-efficient tilemap buffer * Redraws only 1-tile margin beyond viewport in all dirs - * Author: KaiN * Requires viewport managers: * - camera * - scroll */ #include -#include -#include - #include -#include - -#include #include #include +// vPort ptr +#define TAG_TILEBUFFER_VPORT (TAG_USER|1) +// Scrollable area bounds, in pixels +#define TAG_TILEBUFFER_BOUND_TILE_X (TAG_USER|2) +#define TAG_TILEBUFFER_BOUND_TILE_Y (TAG_USER|3) +#define TAG_TILEBUFFER_TILE_SHIFT (TAG_USER|4) +// Buffer bitmap creation flags +#define TAG_TILEBUFFER_BITMAP_FLAGS (TAG_USER|5) +#define TAG_TILEBUFFER_IS_DBLBUF (TAG_USER|6) +// If in raw mode, offset on copperlist for placing required copper +// instructions, specified in copper instruction count since beginning. +#define TAG_TILEBUFFER_COPLIST_OFFSET_START (TAG_USER|7) +#define TAG_TILEBUFFER_COPLIST_OFFSET_BREAK (TAG_USER|8) +// Callbacks, tileset +#define TAG_TILEBUFFER_TILESET (TAG_USER|9) +#define TAG_TILEBUFFER_CALLBACK_TILE_DRAW (TAG_USER|10) +#define TAG_TILEBUFFER_REDRAW_QUEUE_LENGTH (TAG_USER|11) + /* types */ -typedef void (*tCbTileDraw)( +typedef void (*tTileDrawCallback)( UWORD uwTileX, UWORD uwTileY, tBitMap *pBitMap, UWORD uwBitMapX, UWORD uwBitMapY ); typedef struct { - WORD wTileOffs; /// Index of row/col to update - WORD wTileCurr; /// Index of current tile to update in row/col - WORD wTileEnd; /// Index of last+1 tile to update in row/col -} tTileMarginData; + WORD wTilePos; ///< Index of row/col to update + WORD wTileCurr; ///< Index of current tile to update in row/col + WORD wTileEnd; ///< Index of last+1 tile to update in row/col +} tMarginState; + +typedef struct _tRedrawState { + tMarginState sMarginL; ///< Data for left margin + tMarginState sMarginR; ///< Ditto, right + tMarginState sMarginU; ///< Ditto, up + tMarginState sMarginD; ///< Ditto, down + // Vars needed in Process, reset in Create + tMarginState *pMarginX; ///< Idx of X margin to be redrawn + tMarginState *pMarginOppositeX; ///< Opposite margin of pMarginX + tMarginState *pMarginY; ///< Idx of Y margin to be redrawn + tMarginState *pMarginOppositeY; ///< Opposite margin of pMarginY + // Tile redraw queue + tUwCoordYX *pPendingQueue; + UBYTE ubPendingCount; +} tRedrawState; typedef struct { tVpManager sCommon; - tCameraManager *pCameraManager; /// Quick ref to Camera - tScrollBufferManager *pScrollManager; /// Quick ref to Scroll - // Manager vars - tUwCoordYX uTileBounds; /// Tile count in x,y - UBYTE ubTileSize; /// Tile size in pixels - UBYTE ubTileShift; /// Tile size in shift, e.g. 4 for 16: 1 << 4 == 16 - UWORD uwMarginedWidth; /// Width of visible area + margins - UWORD uwMarginedHeight; /// Height of visible area + margins - /// TODO: refresh when scrollbuffer changes - tCbTileDraw cbTileDraw; /// Called when tile is redrawn - UBYTE **pTileData; /// 2D array of tile indices - tBitMap *pTileSet; /// Tileset - // Margin vars - UBYTE ubMarginXLength; /// Tile number in margins: left & right - UBYTE ubMarginYLength; /// Ditto, up & down - tTileMarginData sMarginL; /// Data for left margin - tTileMarginData sMarginR; /// Ditto, right - tTileMarginData sMarginU; /// Ditto, up - tTileMarginData sMarginD; /// Ditto, down - // Vars needed in Process, reset in Create - tTileMarginData *pMarginX; /// Idx of X margin to be redrawn - tTileMarginData *pMarginOppositeX; /// Opposite margin of pMarginX - tTileMarginData *pMarginY; /// Idx of Y margin to be redrawn - tTileMarginData *pMarginOppositeY; /// Opposite margin of pMarginY + tCameraManager *pCamera; ///< Quick ref to Camera + tScrollBufferManager *pScroll; ///< Quick ref to Scroll + // Manager vars + tUwCoordYX uTileBounds; ///< Tile count in x,y + UBYTE ubTileSize; ///< Tile size in pixels + UBYTE ubTileShift; ///< Tile size in shift, e.g. 4 for 16: 1 << 4 == 16 + UWORD uwMarginedWidth; ///< Width of visible area + margins + UWORD uwMarginedHeight; ///< Height of visible area + margins + /// TODO: refresh when scrollbuffer changes + tTileDrawCallback cbTileDraw; ///< Called when tile is redrawn + UBYTE **pTileData; ///< 2D array of tile indices + tBitMap *pTileSet; ///< Tileset - one tile beneath another + // Margin & queue geometry + UBYTE ubMarginXLength; ///< Tile number in margins: left & right + UBYTE ubMarginYLength; ///< Ditto, up & down + UBYTE ubQueueSize; + // Redraw state and double buffering + tRedrawState pRedrawStates[2]; + UBYTE ubStateIdx; + UBYTE ubWidthShift; } tTileBufferManager; /* globals */ /* functions */ -tTileBufferManager *tileBufferCreate( - tVPort *pVPort, - UWORD uwTileX, UWORD uwTileY, UBYTE ubTileShift, - char *szTileSetFileName, tCbTileDraw cbTileDraw -); +void tileBufferQueueProcess(tTileBufferManager *pManager); + +/** + * Tilemap buffer manager create fn + * Be sure to set camera pos, load tile data & then call tileBufferRedraw()! + */ +tTileBufferManager *tileBufferCreate(void *pTags, ...); void tileBufferDestroy(tTileBufferManager *pManager); +/** + * Redraws one tile for each margin - X and Y + * Redraws all remaining margin's tiles when margin is about to be displayed + */ void tileBufferProcess(tTileBufferManager *pManager); void tileBufferReset( - tTileBufferManager *pManager, - UWORD uwTileX, UWORD uwTileY, char *szTileSetFileName + tTileBufferManager *pManager, UWORD uwTileX, UWORD uwTileY, + UBYTE ubBitmapFlags, UBYTE isDblBuf ); -void tileBufferRedraw(tTileBufferManager *pManager); +/** + * Redraws tiles on whole screen + * Use for init or something like that, as it's slooooooooow + */ +void tileBufferInitialDraw(const tTileBufferManager *pManager); +/** + * Redraws selected tile, calls custom redraw callback + * Calculates destination on buffer + * Use for single redraws + */ void tileBufferDrawTile( - tTileBufferManager *pManager, UWORD uwTileIdxX, UWORD uwTileIdxY + const tTileBufferManager *pManager, UWORD uwTileIdxX, UWORD uwTileIdxY ); +/** + * Redraws selected tile, calls custom redraw callback + * Destination coord on buffer must be calculated externally - avoids recalc + * Use for batch redraws with smart uwBfrXY update + */ void tileBufferDrawTileQuick( - tTileBufferManager *pManager, + const tTileBufferManager *pManager, UWORD uwTileIdxX, UWORD uwTileIdxY, UWORD uwBfrX, UWORD uwBfrY ); +/** + * Redraws all tiles intersecting with given rectangle + * Only tiles currently on buffer are redrawn + */ void tileBufferInvalidateRect( tTileBufferManager *pManager, UWORD uwX, UWORD uwY, UWORD uwWidth, UWORD uwHeight ); +void tileBufferInvalidateTile( + tTileBufferManager *pManager, UWORD uwTileX, UWORD uwTileY +); + +UBYTE tileBufferIsTileOnBuffer( + const tTileBufferManager *pManager, UWORD uwTileX, UWORD uwTileY +); + +void tileBufferSetTile( + tTileBufferManager *pManager, UWORD uwX, UWORD uwY, UWORD uwIdx +); + #endif // AMIGA #endif // _ACE_MANAGERS_VIEWPORT_TILEBUFFER_H_ diff --git a/include/ace/types.h b/include/ace/types.h index 5b147f2b..790d1f35 100644 --- a/include/ace/types.h +++ b/include/ace/types.h @@ -24,15 +24,28 @@ typedef int16_t WORD; typedef int32_t LONG; #endif // AMIGA -#if defined(__VBCC__) +#if defined(__CODE_CHECKER__) +// My realtime source checker has problems with GCC asm() expanded from REGARG() +// being in fn arg list, so I just use blank defines for it +#define INTERRUPT +#define INTERRUPT_END do {} while(0) +#define HWINTERRUPT +#define UNUSED_ARG __attribute__((unused)) +#define REGARG(arg, x) arg +#define CHIP +#define FAR +#define FN_HOTSPOT +#define FN_COLDSPOT +#elif defined(__VBCC__) #if defined(CONFIG_SYSTEM_OS_FRIENDLY) #define INTERRUPT __amigainterrupt __saveds #define INTERRUPT_END do {} while(0) #elif defined(CONFIG_SYSTEM_OS_TAKEOVER) -#error "Unimplemented OS takeover for VBCC!" +#define INTERRUPT +#define INTERRUPT_END do {} while(0) #endif -#define HWINTERRUPT __interrupt +#define HWINTERRUPT __interrupt __saveds #define UNUSED_ARG #define REGARG(arg, reg) __reg(reg) arg #define CHIP __chip @@ -58,18 +71,6 @@ typedef int32_t LONG; #define FAR __far #define FN_HOTSPOT __attribute__((hot)) #define FN_COLDSPOT __attribute__((cold)) -#elif defined(__CODE_CHECKER__) -// My realtime source checker has problems with GCC asm() expanded from REGARG() -// being in fn arg list, so I just use blank defines for it -#define INTERRUPT -#define INTERRUPT_END do {} while(0) -#define HWINTERRUPT -#define UNUSED_ARG __attribute__((unused)) -#define REGARG(arg, x) arg -#define CHIP -#define FAR -#define FN_HOTSPOT -#define FN_COLDSPOT #else #error "Compiler not supported!" #endif diff --git a/include/ace/utils/chunky.h b/include/ace/utils/chunky.h index bfcddcf9..0c68bd72 100644 --- a/include/ace/utils/chunky.h +++ b/include/ace/utils/chunky.h @@ -92,4 +92,36 @@ void chunkyToPlanar16(const UBYTE *pIn, UWORD uwX, UWORD uwY, tBitMap *pOut); */ void chunkyToPlanar(const UBYTE ubIn, UWORD uwX, UWORD uwY, tBitMap *pOut); +/** + * @brief Reads given portion of bitmap to chunky buffer. + * + * @param pBitmap Source bitmap image. + * @param pChunky Desitination chunky buffer. + * @param uwSrcOffsX X offset of conversion area, in pixels. + * @param uwSrcOffsY Y offset of conversion area, in pixels. + * @param uwWidth Width of conversion area, in pixels. + * @param uwHeight Height of conversion area, in pixels. + * + * @see chunkyToBitmap + */ +void chunkyFromBitmap( + const tBitMap *pBitmap, UBYTE *pChunky, + UWORD uwSrcOffsX, UWORD uwSrcOffsY, UWORD uwWidth, UWORD uwHeight +); + +/** + * @brief Writes given chunky buffer into specified portion of bitmap + * + * @param pChunky Source chunky data buffer. + * @param pBitmap Destination bitmap. + * @param uwDstOffsX X offset of conversion area, in pixels. + * @param uwDstOffsY Y offset of conversion area, in pixels. + * @param uwWidth Width of conversion area, in pixels. + * @param uwHeight Height of conversion area, in pixels. + */ +void chunkyToBitmap( + const UBYTE *pChunky, tBitMap *pBitmap, + UWORD uwDstOffsX, UWORD uwDstOffsY, UWORD uwWidth, UWORD uwHeight +); + #endif // _ACE_UTILS_CHUNKY_H_ diff --git a/include/ace/utils/custom.h b/include/ace/utils/custom.h index 614d2549..660b20be 100644 --- a/include/ace/utils/custom.h +++ b/include/ace/utils/custom.h @@ -9,13 +9,9 @@ #ifdef AMIGA -/** - * Quick custom chipset struct include - * Moved to separate file cuz multiple pasting of extern custom is messy - */ +#include // Custom chip register addresses #define REGPTR volatile * const -#include // Custom chip register addresses typedef struct Custom tCustom; diff --git a/include/ace/utils/extview.h b/include/ace/utils/extview.h index 2d99b065..7b05ac69 100644 --- a/include/ace/utils/extview.h +++ b/include/ace/utils/extview.h @@ -11,6 +11,7 @@ */ #include +#include #include #include #include diff --git a/include/ace/utils/font.h b/include/ace/utils/font.h index 54501aa6..5df6beae 100644 --- a/include/ace/utils/font.h +++ b/include/ace/utils/font.h @@ -119,6 +119,15 @@ void fontDestroyTextBitMap(tTextBitMap *pTextBitMap); */ tUwCoordYX fontMeasureText(const tFont *pFont, const char *szText); +/** + * @brief Gets width of specified glyph on given font. + * + * @param pFont Font to be used for measurement. + * @param c Glyph to be checked + * @return Width of glyph, in pixels. + */ +UBYTE fontGlyphWidth(const tFont *pFont, char c); + /** * @brief Checks if given text fits inside specified text buffer. * diff --git a/makefile b/makefile index 85826da5..e152e961 100644 --- a/makefile +++ b/makefile @@ -35,14 +35,15 @@ endif CC_FLAGS_COMMON = -I$(ACE_INC_DIR) -DAMIGA $(TARGET_DEFINES) ifeq ($(ACE_CC), vc) - CC_FLAGS = $(CC_FLAGS_COMMON) +kick13 -c99 + CC_FLAGS = +kick13 -c99 $(CC_FLAGS_COMMON) ACE_AS = vc AS_FLAGS = +kick13 -c OBJDUMP = else ifeq ($(ACE_CC), m68k-amigaos-gcc) - CC_FLAGS_NO_O = $(CC_FLAGS_COMMON) -std=gnu11 -DAMIGA \ - -noixemul -Wall -Wextra -fomit-frame-pointer - CC_FLAGS = $(CC_FLAGS_NO_O) $(TARGET_DEFINES) -O3 -fverbose-asm + CC_FLAGS = $(CC_FLAGS_NO_O) $(TARGET_DEFINES) -O3 + CC_FLAGS_NO_O = $(CC_FLAGS_COMMON) -std=gnu11 -noixemul -Wall -Wextra \ + -fomit-frame-pointer -fstack-protector-all + #-fverbose-asm ACE_AS = vasmm68k_mot AS_FLAGS = -quiet -x -m68010 -Faout -ID:\prg\kompilatory\bebbo\m68k-amigaos\sys-include OBJDUMP = m68k-amigaos-objdump -S -l -D $@ > $@.dasm diff --git a/showcase/CMakeLists.txt b/showcase/CMakeLists.txt index 3cde6a73..4dd28dfa 100644 --- a/showcase/CMakeLists.txt +++ b/showcase/CMakeLists.txt @@ -21,9 +21,14 @@ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DACE_DEBUG") file(GLOB_RECURSE SOURCES src/*.c) file(GLOB_RECURSE HEADERS src/*.h) + include_directories( ${PROJECT_SOURCE_DIR}/src -) + ) + +if(ACE_DEBUG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DACE_DEBUG") # For ACE headers with ifdefs +endif() # ACE add_subdirectory(.. ace) @@ -32,4 +37,4 @@ include_directories(../include) # Linux/other UNIX get a lower-case binary name set(TARGET_NAME ${PROJECT_NAME_LOWER}) add_executable(${TARGET_NAME} ${SOURCES} ${HEADERS}) -target_link_libraries(${TARGET_NAME} ace) \ No newline at end of file +target_link_libraries(${TARGET_NAME} ace) diff --git a/showcase/src/input.c b/showcase/src/input.c index f32ed85c..649dae99 100644 --- a/showcase/src/input.c +++ b/showcase/src/input.c @@ -10,7 +10,7 @@ /* Functions */ void inputOpen(void) { - joyOpen(); + joyOpen(0); keyCreate(); } diff --git a/showcase/src/menu/menu.c b/showcase/src/menu/menu.c index ac251fbe..96fbd56c 100644 --- a/showcase/src/menu/menu.c +++ b/showcase/src/menu/menu.c @@ -22,6 +22,7 @@ #include "test/blitsmalldest.h" #include "test/interleaved.h" #include "test/lines.h" +#include "test/buffer_scroll.h" static tView *s_pMenuView; static tVPort *s_pMenuVPort; @@ -64,7 +65,7 @@ void gsMenuCreate(void) { 160, 100, 10, 2, s_pMenuFont, FONT_HCENTER|FONT_COOKIE|FONT_SHADOW, 1, 2, 3, - s_pMenuBfr->pBuffer + s_pMenuBfr->pBack ); menuShowMain(); @@ -145,7 +146,7 @@ void menuDrawBg(void) { for(uwY = 0; uwY <= s_pMenuBfr->uBfrBounds.sUwCoord.uwY - 16; uwY += 16) { for(uwX = 0; uwX <= s_pMenuBfr->uBfrBounds.sUwCoord.uwX - 16; uwX += 16) { UBYTE ubColor = isOdd ? 0 : 4; - blitRect(s_pMenuBfr->pBuffer, uwX, uwY, 16, 16, ubColor); + blitRect(s_pMenuBfr->pBack, uwX, uwY, 16, 16, ubColor); isOdd = !isOdd; } isOdd = !isOdd; @@ -154,10 +155,10 @@ void menuDrawBg(void) { // Draw border UWORD uwMaxX = s_pMenuBfr->uBfrBounds.sUwCoord.uwX-1; UWORD uwMaxY = s_pMenuBfr->uBfrBounds.sUwCoord.uwY-1; - blitLine(s_pMenuBfr->pBuffer, 0, 0, uwMaxX, 0, 1, 0xFFFF, 0); - blitLine(s_pMenuBfr->pBuffer, 0, uwMaxY, uwMaxX, uwMaxY, 1, 0xFFFF, 0); - blitLine(s_pMenuBfr->pBuffer, 0, 0, 0, uwMaxY, 1, 0xFFFF, 0); - blitLine(s_pMenuBfr->pBuffer, uwMaxX, 0, uwMaxX, uwMaxY, 1, 0xFFFF, 0); + blitLine(s_pMenuBfr->pBack, 0, 0, uwMaxX, 0, 1, 0xFFFF, 0); + blitLine(s_pMenuBfr->pBack, 0, uwMaxY, uwMaxX, uwMaxY, 1, 0xFFFF, 0); + blitLine(s_pMenuBfr->pBack, 0, 0, 0, uwMaxY, 1, 0xFFFF, 0); + blitLine(s_pMenuBfr->pBack, uwMaxX, 0, uwMaxX, uwMaxY, 1, 0xFFFF, 0); logBlockEnd("menuDrawBg()"); } @@ -169,7 +170,7 @@ void menuShowMain(void) { // Draw BG menuDrawBg(); fontDrawStr( - s_pMenuBfr->pBuffer, s_pMenuFont, + s_pMenuBfr->pBack, s_pMenuFont, s_pMenuBfr->uBfrBounds.sUwCoord.uwX >> 1, 80, "ACE Showcase", 1, FONT_COOKIE|FONT_CENTER|FONT_SHADOW ); @@ -209,7 +210,7 @@ void menuShowTests(void) { // Draw BG menuDrawBg(); fontDrawStr( - s_pMenuBfr->pBuffer, s_pMenuFont, + s_pMenuBfr->pBack, s_pMenuFont, s_pMenuBfr->uBfrBounds.sUwCoord.uwX >> 1, 80, "Tests", 1, FONT_COOKIE|FONT_CENTER|FONT_SHADOW ); @@ -217,7 +218,7 @@ void menuShowTests(void) { // Prepare new list s_pMenuList->sCoord.sUwCoord.uwX = s_pMenuBfr->uBfrBounds.sUwCoord.uwX >> 1; s_pMenuList->sCoord.sUwCoord.uwY = 100; - menuListResetCount(s_pMenuList, 7); + menuListResetCount(s_pMenuList, 8); menuListSetEntry(s_pMenuList, 0, MENULIST_ENABLED, "Back"); menuListSetEntry(s_pMenuList, 1, MENULIST_ENABLED, "Blits"); menuListSetEntry(s_pMenuList, 2, MENULIST_ENABLED, "Fonts"); @@ -225,6 +226,7 @@ void menuShowTests(void) { menuListSetEntry(s_pMenuList, 4, MENULIST_ENABLED, "Blitter lines"); menuListSetEntry(s_pMenuList, 5, MENULIST_ENABLED, "Blits with small dst"); menuListSetEntry(s_pMenuList, 6, MENULIST_ENABLED, "Interleaved bitmaps"); + menuListSetEntry(s_pMenuList, 7, MENULIST_ENABLED, "Scroll buffer wrap"); s_ubMenuType = MENU_TESTS; // Redraw list @@ -260,6 +262,11 @@ void menuSelectTests(void) { gsTestInterleavedCreate, gsTestInterleavedLoop, gsTestInterleavedDestroy ); break; + case 7: + gameChangeState( + gsTestBufferScrollCreate, gsTestBufferScrollLoop, gsTestBufferScrollDestroy + ); + break; } } @@ -270,7 +277,7 @@ void menuShowExamples(void) { // Draw BG menuDrawBg(); fontDrawStr( - s_pMenuBfr->pBuffer, s_pMenuFont, + s_pMenuBfr->pBack, s_pMenuFont, s_pMenuBfr->uBfrBounds.sUwCoord.uwX >> 1, 80, "Examples", 1, FONT_COOKIE|FONT_CENTER|FONT_SHADOW ); diff --git a/showcase/src/test/blit.c b/showcase/src/test/blit.c index 12ce7393..9f14c197 100644 --- a/showcase/src/test/blit.c +++ b/showcase/src/test/blit.c @@ -68,7 +68,7 @@ void gsTestBlitLoop(void) { //TODO: Restore BG } else { - blitRect(s_pTestBlitBfr->pBuffer, s_uwX, s_uwY, 16, 16, 0); + blitRect(s_pTestBlitBfr->pBack, s_uwX, s_uwY, 16, 16, 0); } // Update type @@ -161,7 +161,7 @@ void gsTestBlitLoop(void) { //TODO: Save BG beneath new bob } // if(s_ubType & TYPE_RECT) { - blitRect(s_pTestBlitBfr->pBuffer, s_uwX, s_uwY, 16, 16, 3); + blitRect(s_pTestBlitBfr->pBack, s_uwX, s_uwY, 16, 16, 3); // } vPortWaitForEnd(s_pTestBlitVPort); } diff --git a/showcase/src/test/blitsmalldest.c b/showcase/src/test/blitsmalldest.c index bb1c4414..afe3d3a4 100644 --- a/showcase/src/test/blitsmalldest.c +++ b/showcase/src/test/blitsmalldest.c @@ -87,13 +87,13 @@ void gsTestBlitSmallDestLoop(void) { if(bUpdate && ubFrameIdx + bUpdate > -1 && ubFrameIdx + bUpdate < 16) { ubFrameIdx += bUpdate; blitRect( - s_pTestBlitBfr->pBuffer, 0, 0, + s_pTestBlitBfr->pBack, 0, 0, s_pTestBlitBfr->uBfrBounds.sUwCoord.uwX, s_pTestBlitBfr->uBfrBounds.sUwCoord.uwY, 0 ); blitCopy(s_pRefBitmap, ubFrameIdx, ubFrameIdx*32, s_pDstBitmap, 0, 0, 32, 32, 0xCA, 0xFF); - blitCopyAligned(s_pDstBitmap, 0, 0, s_pTestBlitBfr->pBuffer, 16, 16, 32, 32); + blitCopyAligned(s_pDstBitmap, 0, 0, s_pTestBlitBfr->pBack, 16, 16, 32, 32); } vPortWaitForEnd(s_pTestBlitVPort); diff --git a/showcase/src/test/buffer_scroll.c b/showcase/src/test/buffer_scroll.c new file mode 100644 index 00000000..c9a2a52c --- /dev/null +++ b/showcase/src/test/buffer_scroll.c @@ -0,0 +1,180 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "buffer_scroll.h" +#include +#include +#include +#include +#include +#include +#include "main.h" +#include "menu/menu.h" + +#define TEST_SCROLL_BPP 6 + +static tView *s_pView; +static tVPort *s_pVPort; +static tCameraManager *s_pCamera; + +static void fillBfr(tBitMap *pBfr, UWORD uwWidth, UWORD uwHeight) { + logBlockBegin( + "fillBfr(pBfr: *%p, uwWidth: %hu, uwHeight: %hu)", + pBfr, uwWidth, uwHeight + ); + uwWidth -= 1; + uwHeight -= 1; + + // Short lines + for(UWORD x = 10; x <= uwWidth; x += 10) { + blitRect(pBfr, x, 0, 1, 3, 7); + blitRect(pBfr, x, uwHeight-3, 1, 3, 7); + } + for(UWORD y = 10; y <= uwHeight; y += 10) { + blitRect(pBfr, 0, y, 3, 1, 7); + blitRect(pBfr, uwWidth-3, y, 3, 1, 7); + } + + // Long lines + for(UWORD x = 100; x <= uwWidth; x += 100) { + blitRect(pBfr, x, 0, 1, 5, 7); + blitRect(pBfr, x, uwHeight-5, 1, 5, 7); + } + for(UWORD y = 100; y <= uwHeight; y += 100) { + blitRect(pBfr, 0, y, 5, 1, 7); + blitRect(pBfr, uwWidth-5, y, 5, 1, 7); + } + + // Border + blitRect(pBfr, 0, 0, uwWidth, 1, 6); + blitRect(pBfr, 0, uwHeight, uwWidth, 1, 6); + blitRect(pBfr, 0, 0, 1, uwHeight, 6); + blitRect(pBfr, uwWidth, 0, 1, uwHeight, 6); + logBlockEnd("fillBfr()"); +} + +void initSimple(void) { + viewLoad(0); + systemUse(); + if(s_pView->pFirstVPort) { + vPortDestroy(s_pView->pFirstVPort); + } + + s_pVPort = vPortCreate(0, + TAG_VPORT_VIEW, s_pView, + TAG_VPORT_BPP, TEST_SCROLL_BPP, + TAG_DONE); + paletteLoad("data/amidb32.plt", s_pVPort->pPalette, 1 << SHOWCASE_BPP); + + tSimpleBufferManager *s_pBfr = simpleBufferCreate(0, + TAG_SIMPLEBUFFER_VPORT, s_pVPort, + TAG_SIMPLEBUFFER_BITMAP_FLAGS, BMF_CLEAR | BMF_INTERLEAVED, + TAG_SIMPLEBUFFER_BOUND_WIDTH, 640, + TAG_SIMPLEBUFFER_BOUND_HEIGHT, 720, + TAG_DONE); + s_pCamera = s_pBfr->pCamera; + + fillBfr(s_pBfr->pBack, 640, 720); + + viewLoad(s_pView); + systemUnuse(); +} + +void initScroll(void) { + viewLoad(0); + systemUse(); + if(s_pView->pFirstVPort) { + vPortDestroy(s_pView->pFirstVPort); + } + + s_pVPort = vPortCreate(0, + TAG_VPORT_VIEW, s_pView, + TAG_VPORT_BPP, TEST_SCROLL_BPP, + TAG_DONE); + paletteLoad("data/amidb32.plt", s_pVPort->pPalette, 1 << SHOWCASE_BPP); + + // This will create buffer which is shorter than 640 with capability of + // wrapped scrolling to simulate bigger buffer size + tScrollBufferManager *s_pBfr = scrollBufferCreate(0, + TAG_SCROLLBUFFER_VPORT, s_pVPort, + TAG_SCROLLBUFFER_BITMAP_FLAGS, BMF_CLEAR | BMF_INTERLEAVED, + TAG_SCROLLBUFFER_BOUND_WIDTH, 640, + TAG_SCROLLBUFFER_BOUND_HEIGHT, 720, + TAG_SCROLLBUFFER_MARGIN_WIDTH, 32, + TAG_DONE); + s_pCamera = s_pBfr->pCamera; + + fillBfr( + s_pBfr->pBack, + bitmapGetByteWidth(s_pBfr->pBack) * 8, s_pBfr->uwBmAvailHeight + ); + + // Ensure that scroll buffer y-wraps nicely + UBYTE ubColor = (1 << TEST_SCROLL_BPP) - 1; + blitRect(s_pBfr->pBack, 0, 508, 1, 1, ubColor); + blitRect(s_pBfr->pBack, 0, 509, 2, 1, ubColor); + blitRect(s_pBfr->pBack, 0, 510, 3, 1, ubColor); + blitRect(s_pBfr->pBack, 0, 511, 4, 1, ubColor); + blitRect(s_pBfr->pBack, 0, 0, 5, 1, ubColor); + blitRect(s_pBfr->pBack, 0, 1, 4, 1, ubColor); + blitRect(s_pBfr->pBack, 0, 2, 3, 1, ubColor); + blitRect(s_pBfr->pBack, 0, 3, 2, 1, ubColor); + blitRect(s_pBfr->pBack, 0, 4, 1, 1, ubColor); + + blitRect(s_pBfr->pBack, 32, 32, 32, 32, 5); + viewLoad(s_pView); + systemUnuse(); +} + +void gsTestBufferScrollCreate(void) { + logBlockBegin("gsTestBufferScrollCreate()"); + + s_pView = viewCreate(0, + TAG_VIEW_GLOBAL_CLUT, 1, + TAG_DONE); + + initScroll(); + logBlockEnd("gsTestBufferScrollCreate()"); + systemUnuse(); +} + +void gsTestBufferScrollLoop(void) { + if (keyUse(KEY_ESCAPE)) { + gameChangeState(gsMenuCreate, gsMenuLoop, gsMenuDestroy); + return; + } + + WORD wDx = 0, wDy = 0; + if(keyCheck(KEY_W)) { + wDy = -1; + } + else if(keyCheck(KEY_S)) { + wDy = 1; + } + if(keyCheck(KEY_A)) { + wDx = -1; + } + if(keyCheck(KEY_D)) { + wDx = 1; + } + + if(keyUse(KEY_1)) { + initSimple(); + } + else if(keyUse(KEY_2)) { + initScroll(); + } + + cameraMoveBy(s_pCamera, wDx, wDy); + viewProcessManagers(s_pView); + copProcessBlocks(); + vPortWaitForEnd(s_pVPort); +} + +void gsTestBufferScrollDestroy(void) { + logBlockBegin("gsTestBufferScrollDestroy()"); + systemUse(); + viewDestroy(s_pView); + logBlockEnd("gsTestBufferScrollDestroy()"); +} diff --git a/showcase/src/test/buffer_scroll.h b/showcase/src/test/buffer_scroll.h new file mode 100644 index 00000000..41beda60 --- /dev/null +++ b/showcase/src/test/buffer_scroll.h @@ -0,0 +1,14 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef _SHOWCASE_TEST_BUFFER_SCROLL_H_ +#define _SHOWCASE_TEST_BUFFER_SCROLL_H_ + +#include + +void gsTestBufferScrollCreate(void); +void gsTestBufferScrollLoop(void); +void gsTestBufferScrollDestroy(void); + +#endif // _SHOWCASE_TEST_BUFFER_SCROLL_H_ diff --git a/showcase/src/test/copper.c b/showcase/src/test/copper.c index 580553de..90f30c13 100644 --- a/showcase/src/test/copper.c +++ b/showcase/src/test/copper.c @@ -87,25 +87,25 @@ void gsTestCopperCreate(void) { UWORD uwMaxX = s_pTestCopperBfr->uBfrBounds.sUwCoord.uwX-1; UWORD uwMaxY = s_pTestCopperBfr->uBfrBounds.sUwCoord.uwY-1; blitRect( - s_pTestCopperBfr->pBuffer, 0,0, + s_pTestCopperBfr->pBack, 0,0, s_pTestCopperBfr->uBfrBounds.sUwCoord.uwX, s_pTestCopperBfr->uBfrBounds.sUwCoord.uwY, TEST_COPPER_COLOR_INSIDE ); blitLine( - s_pTestCopperBfr->pBuffer, 0, 0, uwMaxX, 0, + s_pTestCopperBfr->pBack, 0, 0, uwMaxX, 0, TEST_COPPER_COLOR_BORDER, 0xFFFF, 0 ); blitLine( - s_pTestCopperBfr->pBuffer, 0, uwMaxY, uwMaxX, uwMaxY, + s_pTestCopperBfr->pBack, 0, uwMaxY, uwMaxX, uwMaxY, TEST_COPPER_COLOR_BORDER, 0xFFFF, 0 ); blitLine( - s_pTestCopperBfr->pBuffer, 0, 0, 0, uwMaxY, + s_pTestCopperBfr->pBack, 0, 0, 0, uwMaxY, TEST_COPPER_COLOR_BORDER, 0xFFFF, 0 ); blitLine( - s_pTestCopperBfr->pBuffer, uwMaxX, 0, uwMaxX, uwMaxY, + s_pTestCopperBfr->pBack, uwMaxX, 0, uwMaxX, uwMaxY, TEST_COPPER_COLOR_BORDER, 0xFFFF, 0 ); diff --git a/showcase/src/test/font.c b/showcase/src/test/font.c index 73c4b601..cf94c6ea 100644 --- a/showcase/src/test/font.c +++ b/showcase/src/test/font.c @@ -156,7 +156,7 @@ void testFontDrawTable(void) { // Background blitRect( - s_pTestFontBfr->pBuffer, 0,0, + s_pTestFontBfr->pBack, 0,0, s_pTestFontBfr->uBfrBounds.sUwCoord.uwX, s_pTestFontBfr->uBfrBounds.sUwCoord.uwY, 2 ); @@ -164,14 +164,14 @@ void testFontDrawTable(void) { UWORD uwMaxY = s_pTestFontBfr->uBfrBounds.sUwCoord.uwY-1; for(i = 0; i < 8; ++i) { // Vertical lines - blitLine(s_pTestFontBfr->pBuffer, 40*i, 0, 40*i, uwMaxY, 0, 0xFFFF, 0); + blitLine(s_pTestFontBfr->pBack, 40*i, 0, 40*i, uwMaxY, 0, 0xFFFF, 0); // Horizontal lines - blitLine(s_pTestFontBfr->pBuffer, 0, 32*i, uwMaxX, 32*i, 0, 0xFFFF, 0); + blitLine(s_pTestFontBfr->pBack, 0, 32*i, uwMaxX, 32*i, 0, 0xFFFF, 0); } // Last V line - blitLine(s_pTestFontBfr->pBuffer, uwMaxX, 0, uwMaxX, uwMaxY, 0, 0xFFFF, 0); + blitLine(s_pTestFontBfr->pBack, uwMaxX, 0, uwMaxX, uwMaxY, 0, 0xFFFF, 0); // Last H line - blitLine(s_pTestFontBfr->pBuffer, 0, uwMaxY, uwMaxX, uwMaxY, 0, 0xFFFF, 0); + blitLine(s_pTestFontBfr->pBack, 0, uwMaxY, uwMaxX, uwMaxY, 0, 0xFFFF, 0); for(i = 0; i < 64; ++i) { UBYTE ubCharIdx = s_ubPage*64+i; @@ -184,7 +184,7 @@ void testFontDrawTable(void) { sprintf(szCodeBfr, "%c", ubCharIdx); fontFillTextBitMap(pFont, s_pGlyph, szCodeBfr); fontDrawTextBitMap( - s_pTestFontBfr->pBuffer, s_pGlyph, + s_pTestFontBfr->pBack, s_pGlyph, (i/8)*40+40/2, (i%8)*32+(32/2), 3, FONT_CENTER|FONT_COOKIE ); @@ -194,7 +194,7 @@ void testFontDrawTable(void) { sprintf(szCodeBfr, "%02X", ubCharIdx); fontFillTextBitMap(s_pFontUI, s_pGlyphCode, szCodeBfr); fontDrawTextBitMap( - s_pTestFontBfr->pBuffer, s_pGlyphCode, + s_pTestFontBfr->pBack, s_pGlyphCode, (i/8)*40+40/2, (i%8)*32+32-2, 0, FONT_HCENTER|FONT_BOTTOM|FONT_COOKIE ); diff --git a/showcase/src/test/interleaved.c b/showcase/src/test/interleaved.c index 96565d03..90373f30 100644 --- a/showcase/src/test/interleaved.c +++ b/showcase/src/test/interleaved.c @@ -35,7 +35,7 @@ void gsTestInterleavedCreate(void) { "data/amidb32.plt", s_pTestInterleavedVPort->pPalette, 1 << SHOWCASE_BPP ); bitmapLoadFromFile( - s_pTestInterleavedBfr->pBuffer, "data/32c_pal_interleaved.bm", 0, 0 + s_pTestInterleavedBfr->pBack, "data/32c_pal_interleaved.bm", 0, 0 ); systemUnuse(); diff --git a/showcase/src/test/lines.c b/showcase/src/test/lines.c index ec340dce..41cae27e 100644 --- a/showcase/src/test/lines.c +++ b/showcase/src/test/lines.c @@ -43,13 +43,13 @@ void gsTestLinesCreate(void) { UWORD uwPattern = 0xFFFF; - blitLine(s_pBfrManager->pBuffer, uwMinX, uwMinY, uwMinX, uwMaxY, 1, uwPattern, 0); - blitLine(s_pBfrManager->pBuffer, uwMaxX, uwMinY, uwMaxX, uwMaxY, 1, uwPattern, 0); - blitLine(s_pBfrManager->pBuffer, uwMinX, uwMinY, uwMaxX, uwMinY, 1, uwPattern, 0); - blitLine(s_pBfrManager->pBuffer, uwMinX, uwMaxY, uwMaxX, uwMaxY, 1, uwPattern, 0); + blitLine(s_pBfrManager->pBack, uwMinX, uwMinY, uwMinX, uwMaxY, 1, uwPattern, 0); + blitLine(s_pBfrManager->pBack, uwMaxX, uwMinY, uwMaxX, uwMaxY, 1, uwPattern, 0); + blitLine(s_pBfrManager->pBack, uwMinX, uwMinY, uwMaxX, uwMinY, 1, uwPattern, 0); + blitLine(s_pBfrManager->pBack, uwMinX, uwMaxY, uwMaxX, uwMaxY, 1, uwPattern, 0); - blitRect(s_pBfrManager->pBuffer, 32, 32, 32, 32, 2); - blitLine(s_pBfrManager->pBuffer, 16, 16, 80, 80, 1, uwPattern, 0); + blitRect(s_pBfrManager->pBack, 32, 32, 32, 32, 2); + blitLine(s_pBfrManager->pBack, 16, 16, 80, 80, 1, uwPattern, 0); // Prepare circle vertex positions const uint8_t uwVertCount = 12; @@ -68,7 +68,7 @@ void gsTestLinesCreate(void) { UBYTE v; for(v = 0; v < uwVertCount-1; ++v) { blitLine( - s_pBfrManager->pBuffer, + s_pBfrManager->pBack, pVerts[v].sUwCoord.uwX, pVerts[v].sUwCoord.uwY, pVerts[v+1].sUwCoord.uwX, pVerts[v+1].sUwCoord.uwY, 2, uwPattern, 0 @@ -76,7 +76,7 @@ void gsTestLinesCreate(void) { } // Close the circle blitLine( - s_pBfrManager->pBuffer, + s_pBfrManager->pBack, pVerts[v].sUwCoord.uwX, pVerts[v].sUwCoord.uwY, pVerts[0].sUwCoord.uwX, pVerts[0].sUwCoord.uwY, 2, uwPattern, 0 diff --git a/src/ace/managers/blit.c b/src/ace/managers/blit.c index ceffc3c8..41afab7c 100644 --- a/src/ace/managers/blit.c +++ b/src/ace/managers/blit.c @@ -81,7 +81,7 @@ UBYTE _blitCheck( if(pSrc && (wSrcX < 0 || wSrcWidth < wSrcX+wWidth || pSrc->Rows < wSrcY+wHeight)) { logWrite( "ERR: ILLEGAL BLIT Source out of range: " - "source %p %dx%d, dest: %p %dx%d, blit: %d,%d -> %d,%d %dx%d %s@%u\n", + "source %p %dx%d, dest: %p %dx%d, blit: %d,%d -> %d,%d %dx%d %s @ %u\n", pSrc, wSrcWidth, wSrcHeight, pDst, wDstWidth, wDstHeight, wSrcX, wSrcY, wDstX, wDstY, wWidth, wHeight, szFile, uwLine ); @@ -90,7 +90,7 @@ UBYTE _blitCheck( if(pDst && (wDstY < 0 || wDstWidth < wDstX+wWidth || pDst->Rows < wDstY+wHeight)) { logWrite( "ERR: ILLEGAL BLIT Dest out of range: " - "source %p %dx%d, dest: %p %dx%d, blit: %d,%d -> %d,%d %dx%d %s@%u\n", + "source %p %dx%d, dest: %p %dx%d, blit: %d,%d -> %d,%d %dx%d %s @ %u\n", pSrc, wSrcWidth, wSrcHeight, pDst, wDstWidth, wDstHeight, wSrcX, wSrcY, wDstX, wDstY, wWidth, wHeight, szFile, uwLine ); diff --git a/src/ace/managers/copper.c b/src/ace/managers/copper.c index 820175c6..bc703bd7 100644 --- a/src/ace/managers/copper.c +++ b/src/ace/managers/copper.c @@ -285,7 +285,7 @@ void copBlockEnable(tCopList *pCopList, tCopBlock *pBlock) { } void copBlockDisable(tCopList *pCopList, tCopBlock *pBlock) { - pBlock->ubDisabled = 0; + pBlock->ubDisabled = 1; pBlock->pNext->ubUpdated = 2; pCopList->ubStatus |= STATUS_UPDATE; } @@ -328,15 +328,12 @@ UBYTE copBfrRealloc(void) { } void copReorderBlocks(void) { + tCopList *pCopList = g_sCopManager.pCopList; UBYTE ubDone; - tCopList *pCopList; - tCopBlock *pBlock, *pPrev; - - pCopList = g_sCopManager.pCopList; do { ubDone = 1; - pBlock = pCopList->pFirstBlock; - pPrev = 0; + tCopBlock *pBlock = pCopList->pFirstBlock; + tCopBlock *pPrev = 0; while(pBlock->pNext) { if(pBlock->uWaitPos.ulYX > pBlock->pNext->uWaitPos.ulYX) { if(!pPrev) { @@ -498,7 +495,7 @@ void copBlockWait(tCopList *pCopList, tCopBlock *pBlock, UWORD uwX, UWORD uwY) { pBlock->uWaitPos.sUwCoord.uwX = uwX; pBlock->ubUpdated = 2; - pCopList->ubStatus |= STATUS_UPDATE; + pCopList->ubStatus |= STATUS_UPDATE | STATUS_REORDER; } void copMove(tCopList *pCopList, tCopBlock *pBlock, volatile void *pAddr, UWORD uwValue) { diff --git a/src/ace/managers/game.c b/src/ace/managers/game.c index fe366a39..d25c6835 100644 --- a/src/ace/managers/game.c +++ b/src/ace/managers/game.c @@ -57,7 +57,6 @@ void gamePopState(void) { g_sGameManager.pStateFirst = pGameState->pPrev; memFree(pGameState, sizeof(tGameState)); - viewLoad(0); } void gameChangeState(tGameCb cbCreate, tGameCb cbLoop, tGameCb cbDestroy) { diff --git a/src/ace/managers/joy.c b/src/ace/managers/joy.c index f8624914..11f2ec01 100644 --- a/src/ace/managers/joy.c +++ b/src/ace/managers/joy.c @@ -10,6 +10,7 @@ /* Globals */ tJoyManager g_sJoyManager; +static UBYTE s_is4joy = 0; #if defined(CONFIG_SYSTEM_OS_FRIENDLY) struct Library *MiscBase = 0; @@ -20,58 +21,63 @@ static UBYTE s_ubOldStatusVal; #endif /* Functions */ -void joyOpen(void) { +void joyOpen(UBYTE is4joy) { + s_is4joy = is4joy; #if defined(CONFIG_SYSTEM_OS_FRIENDLY) - // Open misc.resource for 3rd and 4th joy connected to parallel port - static const char *szOwner = "ACE joy manager"; - MiscBase = (struct Library*)OpenResource(MISCNAME); - if(!MiscBase) { - logWrite("ERR: Couldn't open %s\n", MISCNAME); - return; - } + if(s_is4joy) { + // Open misc.resource for 3rd and 4th joy connected to parallel port + static const char *szOwner = "ACE joy manager"; + MiscBase = (struct Library*)OpenResource(MISCNAME); + if(!MiscBase) { + logWrite("ERR: Couldn't open '%s'\n", MISCNAME); + return; + } - // Are data/status line currently used? - char *szCurrentOwner; - szCurrentOwner = AllocMiscResource(MR_PARALLELPORT, szOwner); - if(szCurrentOwner) { - logWrite("ERR: Parallel data lines access blocked by: %s\n", szCurrentOwner); - return; - } - szCurrentOwner = AllocMiscResource(MR_PARALLELBITS, szOwner); - if(szCurrentOwner) { - logWrite("ERR: Parallel status lines access blocked by: %s\n", szCurrentOwner); - // Free what was already allocated - FreeMiscResource(MR_PARALLELPORT); - } + // Are data/status line currently used? + char *szCurrentOwner; + szCurrentOwner = AllocMiscResource(MR_PARALLELPORT, szOwner); + if(szCurrentOwner) { + logWrite("ERR: Parallel data lines access blocked by: '%s'\n", szCurrentOwner); + return; + } + szCurrentOwner = AllocMiscResource(MR_PARALLELBITS, szOwner); + if(szCurrentOwner) { + logWrite("ERR: Parallel status lines access blocked by: '%s'\n", szCurrentOwner); + // Free what was already allocated + FreeMiscResource(MR_PARALLELPORT); + } - // Save old DDR & value regs - s_ubOldDataDdr = g_pCiaA->ddrb; - s_ubOldStatusDdr = g_pCiaB->ddra; - s_ubOldDataVal = g_pCiaA->prb; - s_ubOldStatusVal = g_pCiaB->pra; + // Save old DDR & value regs + s_ubOldDataDdr = g_pCiaA->ddrb; + s_ubOldStatusDdr = g_pCiaB->ddra; + s_ubOldDataVal = g_pCiaA->prb; + s_ubOldStatusVal = g_pCiaB->pra; - // Set data direction register to input. Status lines are as follows: - // bit 0: BUSY - // bit 2: SEL - g_pCiaB->ddra |= BV(0) | BV(2); // Status lines DDR - g_pCiaA->ddrb = 0xFF; // Data lines DDR + // Set data direction register to input. Status lines are as follows: + // bit 0: BUSY + // bit 2: SEL + g_pCiaB->ddra |= BV(0) | BV(2); // Status lines DDR + g_pCiaA->ddrb = 0xFF; // Data lines DDR - g_pCiaB->pra &= 0xFF^(BV(0) | BV(2)); // Status lines values - g_pCiaA->prb = 0; // Data lines values + g_pCiaB->pra &= 0xFF^(BV(0) | BV(2)); // Status lines values + g_pCiaA->prb = 0; // Data lines values + } #endif } void joyClose(void) { #if defined(CONFIG_SYSTEM_OS_FRIENDLY) - // Restore old status/data DDR/val regs - g_pCiaA->prb = s_ubOldDataVal; - g_pCiaB->pra = s_ubOldStatusVal; - g_pCiaA->ddrb= s_ubOldDataDdr; - g_pCiaB->ddra = s_ubOldStatusDdr; - - // Close misc.resource - FreeMiscResource(MR_PARALLELPORT); - FreeMiscResource(MR_PARALLELBITS); + if(s_is4joy) { + // Restore old status/data DDR/val regs + g_pCiaA->prb = s_ubOldDataVal; + g_pCiaB->pra = s_ubOldStatusVal; + g_pCiaA->ddrb= s_ubOldDataDdr; + g_pCiaB->ddra = s_ubOldStatusDdr; + + // Close misc.resource + FreeMiscResource(MR_PARALLELPORT); + FreeMiscResource(MR_PARALLELBITS); + } #endif } @@ -79,7 +85,7 @@ void joySetState(UBYTE ubJoyCode, UBYTE ubJoyState) { g_sJoyManager.pStates[ubJoyCode] = ubJoyState; } -UBYTE joyPeek(UBYTE ubJoyCode) { +UBYTE joyCheck(UBYTE ubJoyCode) { return g_sJoyManager.pStates[ubJoyCode] != JOY_NACTIVE; } @@ -95,8 +101,6 @@ void joyProcess(void) { UBYTE ubCiaAPra = g_pCiaA->pra; UWORD uwJoyDataPort1 = g_pCustom->joy0dat; UWORD uwJoyDataPort2 = g_pCustom->joy1dat; - UBYTE ubParData = g_pCiaA->prb; - UBYTE ubParStatus = g_pCiaB->pra; UWORD pJoyLookup[] = { !BTST(ubCiaAPra, 7), // Joy 1 fire (PORT 2) @@ -110,21 +114,29 @@ void joyProcess(void) { BTST(uwJoyDataPort1 >> 1 ^ uwJoyDataPort1, 0), // Joy 2 down (PORT 1) BTST(uwJoyDataPort1, 9), // Joy 2 left (PORT 1) BTST(uwJoyDataPort1, 1), // Joy 2 right (PORT 1) - - !BTST(ubParStatus, 2), // Joy 3 fire - !BTST(ubParData, 0), // Joy 3 up - !BTST(ubParData, 1), // Joy 3 down - !BTST(ubParData, 2), // Joy 3 left - !BTST(ubParData, 3), // Joy 3 right - - !BTST(ubParStatus , 0), // Joy 4 fire - !BTST(ubParData , 4), // Joy 4 up - !BTST(ubParData , 5), // Joy 4 down - !BTST(ubParData , 6), // Joy 4 left - !BTST(ubParData , 7) // Joy 4 right }; - UBYTE ubJoyCode = 20; + UBYTE ubJoyCode; + if(s_is4joy) { + ubJoyCode = 20; + UBYTE ubParData = g_pCiaA->prb; + UBYTE ubParStatus = g_pCiaB->pra; + + pJoyLookup[10] = !BTST(ubParStatus, 2); // Joy 3 fire + pJoyLookup[11] = !BTST(ubParData, 0); // Joy 3 up + pJoyLookup[12] = !BTST(ubParData, 1); // Joy 3 down + pJoyLookup[13] = !BTST(ubParData, 2); // Joy 3 left + pJoyLookup[14] = !BTST(ubParData, 3); // Joy 3 right + + pJoyLookup[15] = !BTST(ubParStatus , 0); // Joy 4 fire + pJoyLookup[16] = !BTST(ubParData , 4); // Joy 4 up + pJoyLookup[17] = !BTST(ubParData , 5); // Joy 4 down + pJoyLookup[18] = !BTST(ubParData , 6); // Joy 4 left + pJoyLookup[19] = !BTST(ubParData , 7); // Joy 4 right + } + else { + ubJoyCode = 10; + } while (ubJoyCode--) { if (pJoyLookup[ubJoyCode]) { if (g_sJoyManager.pStates[ubJoyCode] == JOY_NACTIVE) { diff --git a/src/ace/managers/key.c b/src/ace/managers/key.c index 77b15026..6dfef210 100644 --- a/src/ace/managers/key.c +++ b/src/ace/managers/key.c @@ -52,12 +52,9 @@ void INTERRUPT keyIntServer( UBYTE ubKeyReleased = ubKeyCode & KEY_RELEASED_BIT; ubKeyCode >>= 1; - if(ubKeyReleased) { - keyIntSetState(pKeyManager, ubKeyCode, KEY_NACTIVE); - } - else { - keyIntSetState(pKeyManager, ubKeyCode, KEY_ACTIVE); - } + keyIntSetState( + pKeyManager, ubKeyCode, ubKeyReleased ? KEY_NACTIVE : KEY_ACTIVE + ); // End handshake UWORD uwDelta; diff --git a/src/ace/managers/memory.c b/src/ace/managers/memory.c index bf030d99..853b9528 100644 --- a/src/ace/managers/memory.c +++ b/src/ace/managers/memory.c @@ -163,12 +163,10 @@ void *_memAllocDbg(ULONG ulSize, ULONG ulFlags, UWORD uwLine, char *szFile) { s_ulChipPeakUsage, s_ulFastPeakUsage ); #ifdef AMIGA - systemUse(); filePrintf( s_pMemLog, "Largest available chunk of given type: %lu\n", AvailMem(ulFlags | MEMF_LARGEST) ); - systemUnuse(); #endif // AMIGA return 0; } @@ -235,7 +233,7 @@ void _memCheckTrash(void *pMem, UWORD uwLine, char *szFile) { } if(pDead[0] != 0xDE || pDead[1] != 0xAD || pDead[2] != 0xBE || pDead[3] != 0xEF) { filePrintf( - s_pMemLog, "ERR: Right mem trashed: %hu%p (%s:%u)\n", + s_pMemLog, "ERR: Right mem trashed: %hu@%p (%s:%u)\n", pEntry->uwId, pMem, uwLine, szFile ); fileFlush(s_pMemLog); diff --git a/src/ace/managers/system.c b/src/ace/managers/system.c index 0bcee200..5ab12c0a 100644 --- a/src/ace/managers/system.c +++ b/src/ace/managers/system.c @@ -66,6 +66,9 @@ const UWORD s_uwOsMinDma = DMAF_DISK | DMAF_BLITTER; //----------------------------------------------------------- INTERRUPT HANDLERS +// All interrupt handlers should clear their flags twice +// http://eab.abime.net/showthread.php?p=834185#post834185 + FN_HOTSPOT void HWINTERRUPT int1Handler(void) { // Soft / diskBlk / TBE (RS232 TX end) @@ -74,31 +77,35 @@ void HWINTERRUPT int1Handler(void) { FN_HOTSPOT void HWINTERRUPT int2Handler(void) { // Parallel, keyboard, mouse, "some of disk functions" - // ACE only uses it for keyboard so no decision taking here atm - // TODO: this could be re-enabled with vblank since we don't need it - // to retrigger during same frame. - UBYTE ubIcrA = g_pCiaA->icr; // Read clears interrupt flags - if(ubIcrA & CIAICR_SERIAL) { - // Keyboard - if(s_pAceInterrupts[INTB_PORTS].pHandler) { - s_pAceInterrupts[INTB_PORTS].pHandler( - g_pCustom, s_pAceInterrupts[INTB_PORTS].pData - ); + UWORD uwIntReq = g_pCustom->intreqr; + if(uwIntReq & INTF_PORTS) { + UBYTE ubIcrA = g_pCiaA->icr; // Read clears interrupt flags + if(ubIcrA & CIAICR_SERIAL) { + // Keyboard + if(s_pAceInterrupts[INTB_PORTS].pHandler) { + s_pAceInterrupts[INTB_PORTS].pHandler( + g_pCustom, s_pAceInterrupts[INTB_PORTS].pData + ); + } } - } - if(ubIcrA & CIAICR_FLAG) { + if(ubIcrA & CIAICR_FLAG) { - } - if(ubIcrA & CIAICR_TIMER_A) { + } + if(ubIcrA & CIAICR_TIMER_A) { - } - if(ubIcrA & CIAICR_TIMER_B) { + } + if(ubIcrA & CIAICR_TIMER_B) { - } - if(ubIcrA & CIAICR_TOD) { + } + if(ubIcrA & CIAICR_TOD) { + } + // TODO: this could be re-enabled in vblank since we don't need it + // to retrigger during same frame. Or perhaps it's needed so that kbd + // controller won't overflow its queue + g_pCustom->intreq = INTF_PORTS; + g_pCustom->intreq = INTF_PORTS; } - g_pCustom->intreq = INTF_PORTS; } FN_HOTSPOT @@ -142,6 +149,7 @@ void HWINTERRUPT int3Handler(void) { uwReqClr |= INTF_BLIT; } g_pCustom->intreq = uwReqClr; + g_pCustom->intreq = uwReqClr; } FN_HOTSPOT @@ -167,8 +175,8 @@ void HWINTERRUPT int7Handler(void) { //-------------------------------------------------------------------- FUNCTIONS void systemKill(const char *szMsg) { - printf("ERR: SYSKILL: %s", szMsg); - logWrite("ERR: SYSKILL: %s", szMsg); + printf("ERR: SYSKILL: '%s'", szMsg); + logWrite("ERR: SYSKILL: '%s'", szMsg); if(GfxBase) { CloseLibrary((struct Library *) GfxBase); @@ -185,13 +193,14 @@ void systemCreate(void) { // Save the system copperlists and flush the view GfxBase = (struct GfxBase *)OpenLibrary((CONST_STRPTR)"graphics.library", 0L); if (!GfxBase) { - return; systemKill("Can't open Gfx Library!\n"); + return; } s_pOsView = GfxBase->ActiView; WaitTOF(); LoadView(0); WaitTOF(); + WaitTOF(); // Wait for interlaced screen to finish // get VBR location on 68010+ machine // TODO VBR diff --git a/src/ace/managers/viewport/camera.c b/src/ace/managers/viewport/camera.c index d0a53bd7..c1b0c97f 100644 --- a/src/ace/managers/viewport/camera.c +++ b/src/ace/managers/viewport/camera.c @@ -5,8 +5,14 @@ #include #include -tCameraManager *cameraCreate(tVPort *pVPort, UWORD uwPosX, UWORD uwPosY, UWORD uwMaxX, UWORD uwMaxY) { - logBlockBegin("cameraCreate(pVPort: %p, uwPosX: %u, uwPosY: %u, uwMaxX: %u, uwMaxY: %u)", pVPort, uwPosX, uwPosY, uwMaxX, uwMaxY); +tCameraManager *cameraCreate( + tVPort *pVPort, UWORD uwPosX, UWORD uwPosY, UWORD uwMaxX, UWORD uwMaxY, + UBYTE isDblBfr +) { + logBlockBegin( + "cameraCreate(pVPort: %p, uwPosX: %u, uwPosY: %u, uwMaxX: %u, uwMaxY: %u, isDblBfr: %hhu)", + pVPort, uwPosX, uwPosY, uwMaxX, uwMaxY, isDblBfr + ); tCameraManager *pManager; pManager = memAllocFastClear(sizeof(tCameraManager)); @@ -17,7 +23,7 @@ tCameraManager *cameraCreate(tVPort *pVPort, UWORD uwPosX, UWORD uwPosY, UWORD u pManager->sCommon.ubId = VPM_CAMERA; logWrite("Resetting camera bounds...\n"); - cameraReset(pManager, uwPosX, uwPosY, uwMaxX, uwMaxY); + cameraReset(pManager, uwPosX, uwPosY, uwMaxX, uwMaxY, isDblBfr); logWrite("Attaching camera to VPort...\n"); vPortAddManager(pVPort, (tVpManager*)pManager); @@ -32,16 +38,29 @@ void cameraDestroy(tCameraManager *pManager) { } void cameraProcess(tCameraManager *pManager) { - pManager->uLastPos.ulYX = pManager->uPos.ulYX; + pManager->uLastPos[pManager->ubBfr].ulYX = pManager->uPos.ulYX; + if(pManager->isDblBfr) { + pManager->ubBfr = !pManager->ubBfr; + } } -void cameraReset(tCameraManager *pManager, UWORD uwStartX, UWORD uwStartY, UWORD uwWidth, UWORD uwHeight) { - logBlockBegin("cameraReset(pManager: %p, uwStartX: %u, uwStartY: %u, uwWidth: %u, uwHeight: %u)", pManager, uwStartX, uwStartY, uwWidth, uwHeight); +void cameraReset( + tCameraManager *pManager, + UWORD uwStartX, UWORD uwStartY, UWORD uwWidth, UWORD uwHeight, UBYTE isDblBfr +) { + logBlockBegin( + "cameraReset(pManager: %p, uwStartX: %u, uwStartY: %u, uwWidth: %u, uwHeight: %u, isDblBfr: %hhu)", + pManager, uwStartX, uwStartY, uwWidth, uwHeight, isDblBfr + ); pManager->uPos.sUwCoord.uwX = uwStartX; pManager->uPos.sUwCoord.uwY = uwStartY; - pManager->uLastPos.sUwCoord.uwX = uwStartX; - pManager->uLastPos.sUwCoord.uwY = uwStartY; + pManager->uLastPos[0].sUwCoord.uwX = uwStartX; + pManager->uLastPos[0].sUwCoord.uwY = uwStartY; + pManager->uLastPos[1].sUwCoord.uwX = uwStartX; + pManager->uLastPos[1].sUwCoord.uwY = uwStartY; + pManager->isDblBfr = isDblBfr; + pManager->ubBfr = 0; // Max camera coords based on viewport size pManager->uMaxPos.sUwCoord.uwX = uwWidth - pManager->sCommon.pVPort->uwWidth; @@ -71,7 +90,7 @@ void cameraCenterAt(tCameraManager *pManager, UWORD uwAvgX, UWORD uwAvgY) { } UBYTE cameraIsMoved(tCameraManager *pManager) { - return pManager->uPos.ulYX != pManager->uLastPos.ulYX; + return pManager->uPos.ulYX != pManager->uLastPos[pManager->ubBfr].ulYX; } UWORD cameraGetXDiff(tCameraManager *pManager) { @@ -83,9 +102,9 @@ UWORD cameraGetYDiff(tCameraManager *pManager) { } WORD cameraGetDeltaX(tCameraManager *pManager) { - return (pManager->uPos.sUwCoord.uwX - pManager->uLastPos.sUwCoord.uwX); + return (pManager->uPos.sUwCoord.uwX - pManager->uLastPos[pManager->ubBfr].sUwCoord.uwX); } WORD cameraGetDeltaY(tCameraManager *pManager) { - return (pManager->uPos.sUwCoord.uwY - pManager->uLastPos.sUwCoord.uwY); + return (pManager->uPos.sUwCoord.uwY - pManager->uLastPos[pManager->ubBfr].sUwCoord.uwY); } diff --git a/src/ace/managers/viewport/scrollbuffer.c b/src/ace/managers/viewport/scrollbuffer.c index 50035564..d913ad93 100644 --- a/src/ace/managers/viewport/scrollbuffer.c +++ b/src/ace/managers/viewport/scrollbuffer.c @@ -3,143 +3,229 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include +#include #ifdef AMIGA -/** - * Creates scroll manager - */ -tScrollBufferManager *scrollBufferCreate(tVPort *pVPort, UBYTE ubMarginWidth, UWORD uwBoundWidth, UWORD uwBoundHeight) { - logBlockBegin("scrollBufferCreate(pVPort: %p, ubMarginWidth: %hu, uwBoundWidth: %u, uwBoundHeight: %u)", pVPort, ubMarginWidth, uwBoundWidth, uwBoundHeight); +static UWORD nearestPowerOf2(UWORD uwVal) { + // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + // Decrease by one and fill result with ones, then increase by one + --uwVal; + uwVal |= uwVal >> 1; + uwVal |= uwVal >> 2; + uwVal |= uwVal >> 4; + uwVal |= uwVal >> 8; + ++uwVal; + return uwVal; +} + +tScrollBufferManager *scrollBufferCreate(void *pTags, ...) { + va_list vaTags; + tCopList *pCopList = 0; tScrollBufferManager *pManager; + UBYTE ubMarginWidth; + UWORD uwBoundWidth, uwBoundHeight; + UBYTE ubBitmapFlags; + UBYTE isCameraCreated = 0; + UBYTE isDblBuf; - // Wype�nienie struktury mened�era - pManager = memAllocFast(sizeof(tScrollBufferManager)); - logWrite("Addr: %p\n", pManager); - pManager->sCommon.pNext = 0; + logBlockBegin("scrollBufferCreate(pTags: %p, ...)", pTags); + va_start(vaTags, pTags); + + // Init manager + pManager = memAllocFastClear(sizeof(tScrollBufferManager)); pManager->sCommon.process = (tVpManagerFn)scrollBufferProcess; pManager->sCommon.destroy = (tVpManagerFn)scrollBufferDestroy; pManager->sCommon.ubId = VPM_SCROLL; + logWrite("Addr: %p\n", pManager); + + tVPort *pVPort = (tVPort*)tagGet(pTags, vaTags, TAG_SCROLLBUFFER_VPORT, 0); + if(!pVPort) { + logWrite("ERR: No parent viewport (TAG_SCROLLBUFFER_VPORT) specified!\n"); + goto fail; + } pManager->sCommon.pVPort = pVPort; - pManager->pBuffer = 0; - pManager->uwModulo = 0; - pManager->pAvg = logAvgCreate("scrollBufferProcess()", 100); + logWrite("Parent VPort: %p\n", pVPort); + + ubMarginWidth = tagGet( + pTags, vaTags, TAG_SCROLLBUFFER_MARGIN_WIDTH, UCHAR_MAX + ); + if(ubMarginWidth == UCHAR_MAX) { + logWrite( + "ERR: No margin width (TAG_SCROLLBUFFER_MARGIN_WIDTH) specified!\n" + ); + goto fail; + } - scrollBufferReset(pManager, ubMarginWidth, uwBoundWidth, uwBoundHeight); + // Buffer bitmap + uwBoundWidth = tagGet( + pTags, vaTags, TAG_SCROLLBUFFER_BOUND_WIDTH, pVPort->uwWidth + ); + uwBoundHeight = tagGet( + pTags, vaTags, TAG_SCROLLBUFFER_BOUND_HEIGHT, pVPort->uwHeight + ); + ubBitmapFlags = tagGet( + pTags, vaTags, TAG_SCROLLBUFFER_BITMAP_FLAGS, BMF_CLEAR + ); + logWrite("Bounds: %ux%u\n", uwBoundWidth, uwBoundHeight); + + isDblBuf = tagGet(pTags, vaTags, TAG_SCROLLBUFFER_IS_DBLBUF, 0); + + // Create copperlist entries + pCopList = pVPort->pView->pCopList; + if(pCopList->ubMode == COPPER_MODE_BLOCK) { + pManager->pStartBlock = copBlockCreate( + pVPort->pView->pCopList, 2 * pVPort->ubBPP + 8, + // Vertically addition from DiWStrt, horizontally a bit before last fetch. + // First to set are ddf, modulos & shift so they are changed during fetch. + 0xE2-7*4, pVPort->uwOffsY + 0x2C-1 + ); + pManager->pBreakBlock = copBlockCreate( + pVPort->pView->pCopList, 2 * pVPort->ubBPP + 2, + // Dummy position - will be updated + 0x7F, 0xFF + ); + } + else { + // TODO Raw mode + logWrite("ERR: Unimplemented %s:%d\n", __FILE__, __LINE__); + goto fail; + } - // Create copperlist - pManager->pStartBlock = copBlockCreate(pVPort->pView->pCopList, 2*pVPort->ubBPP + 8, 0, 0); - pManager->pBreakBlock = copBlockCreate(pVPort->pView->pCopList, 2*pVPort->ubBPP + 2, 0x7F, 0xFF); + scrollBufferReset( + pManager, ubMarginWidth, uwBoundWidth, uwBoundHeight, + ubBitmapFlags, isDblBuf + ); // Must be before camera? Shouldn't be as there are priorities on manager list vPortAddManager(pVPort, (tVpManager*)pManager); // Find camera manager, create if not exists - pManager->pCameraManager = (tCameraManager*)vPortGetManager(pVPort, VPM_CAMERA); - if(!pManager->pCameraManager) { - pManager->pCameraManager = cameraCreate( - pVPort, 0, 0, uwBoundWidth, uwBoundHeight + pManager->pCamera = (tCameraManager*)vPortGetManager(pVPort, VPM_CAMERA); + if(!pManager->pCamera) { + pManager->pCamera = cameraCreate( + pVPort, 0, 0, uwBoundWidth, uwBoundHeight, isDblBuf ); + isCameraCreated = 1; } else { - cameraReset(pManager->pCameraManager, 0,0, uwBoundWidth, uwBoundHeight); + cameraReset(pManager->pCamera, 0,0, uwBoundWidth, uwBoundHeight, isDblBuf); } - // TODO: Set copperlist to current camera pos? + // TODO: Update copperlist with current camera pos? + va_end(vaTags); logBlockEnd("scrollBufferCreate"); return pManager; +fail: + if(isCameraCreated) { + cameraDestroy(pManager->pCamera); + } + if(pCopList && pManager->pStartBlock) { + copBlockDestroy(pCopList, pManager->pStartBlock); + if(pManager->pBreakBlock) { + copBlockDestroy(pCopList, pManager->pBreakBlock); + } + } + + memFree(pManager, sizeof(tScrollBufferManager)); + va_end(vaTags); + logBlockEnd("scrollBufferCreate"); + return 0; } void scrollBufferDestroy(tScrollBufferManager *pManager) { logBlockBegin("scrollBufferDestroy(pManager: %p)", pManager); - logAvgDestroy(pManager->pAvg); copBlockDestroy(pManager->sCommon.pVPort->pView->pCopList, pManager->pStartBlock); copBlockDestroy(pManager->sCommon.pVPort->pView->pCopList, pManager->pBreakBlock); - bitmapDestroy(pManager->pBuffer); + if(pManager->pFront && pManager->pFront != pManager->pBack) { + bitmapDestroy(pManager->pFront); + } + if(pManager->pBack) { + bitmapDestroy(pManager->pBack); + } memFree(pManager, sizeof(tScrollBufferManager)); logBlockEnd("scrollBufferDestroy()"); } -/** - * Scroll buffer process function - */ +FN_HOTSPOT void scrollBufferProcess(tScrollBufferManager *pManager) { - UWORD uwVpHeight; + UWORD uwVpHeight = pManager->sCommon.pVPort->uwHeight; - uwVpHeight = pManager->sCommon.pVPort->uwHeight; - logAvgBegin(pManager->pAvg); - if (cameraIsMoved(pManager->pCameraManager) || pManager->uwVpHeightPrev != uwVpHeight) { - UBYTE i; - UWORD uwScrollX, uwScrollY; - ULONG ulPlaneOffs; - ULONG ulPlaneAddr; - UWORD uwOffsX; - - // convert camera pos to scroll pos - uwScrollX = pManager->pCameraManager->uPos.sUwCoord.uwX; - uwScrollY = pManager->pCameraManager->uPos.sUwCoord.uwY % pManager->uwBmAvailHeight; + // convert camera pos to scroll pos + UWORD uwScrollX = pManager->pCamera->uPos.sUwCoord.uwX; + UWORD uwScrollY = pManager->pCamera->uPos.sUwCoord.uwY & (pManager->uwBmAvailHeight - 1); - // preparations for new copperlist - uwOffsX = 15 - (uwScrollX & 0xF); // Bitplane shift - single - uwOffsX = (uwOffsX << 4) | uwOffsX; // Bitplane shift - PF1 | PF2 + // preparations for new copperlist + UWORD uwShift = (16 - (uwScrollX & 0xF)) & 0xF; // Bitplane shift - single + uwShift = (uwShift << 4) | uwShift; // Bitplane shift - PF1 | PF2 + ULONG ulBplAddX = ((uwScrollX - 1) >> 4) << 1; // must be ULONG! - uwScrollX >>= 3; + tCopList *pCopList = pManager->sCommon.pVPort->pView->pCopList; + if(pManager->ubFlags & SCROLLBUFFER_FLAG_COPLIST_RAW) { + // TODO: Raw mode + logWrite("ERR: Unimplemented %s:%d\n", __FILE__, __LINE__); + } + else { // Initial copper block - tCopList *pCopList = pManager->sCommon.pVPort->pView->pCopList; tCopBlock *pBlock = pManager->pStartBlock; pBlock->uwCurrCount = 0; // Rewind copBlock - copBlockWait(pCopList, pBlock, 0, 0x2C + pManager->sCommon.pVPort->uwOffsY); - copMove(pCopList, pBlock, &g_pCustom->color[0], 0x0F0); - copMove(pCopList, pBlock, &g_pCustom->bplcon1, uwOffsX); // Bitplane shift - ulPlaneOffs = uwScrollX + (pManager->pBuffer->BytesPerRow*uwScrollY); - for (i = pManager->sCommon.pVPort->ubBPP; i--;) { - ulPlaneAddr = (ULONG)(pManager->pBuffer->Planes[i]) + ulPlaneOffs; + copMove(pCopList, pBlock, &g_pCustom->bplcon1, uwShift); + ULONG ulPlaneOffs = ulBplAddX + (pManager->pBack->BytesPerRow*uwScrollY); + for(UBYTE i = pManager->sCommon.pVPort->ubBPP; i--;) { + ULONG ulPlaneAddr = (ULONG)(pManager->pBack->Planes[i]) + ulPlaneOffs; copMove(pCopList, pBlock, &g_pBplFetch[i].uwLo, ulPlaneAddr & 0xFFFF); copMove(pCopList, pBlock, &g_pBplFetch[i].uwHi, ulPlaneAddr >> 16); } - copMove(pCopList, pBlock, &g_pCustom->ddfstrt, 0x30); // Fetch start - copMove(pCopList, pBlock, &g_pCustom->bpl1mod, pManager->uwModulo); // Odd planes modulo - copMove(pCopList, pBlock, &g_pCustom->bpl2mod, pManager->uwModulo); // Even planes modulo - copMove(pCopList, pBlock, &g_pCustom->ddfstop, 0x00D0); // Fetch stop - copMove(pCopList, pBlock, &g_pCustom->color[0], 0x000); + // TODO setting colors before and after copper instructions moved viewport + // one line lower on 4bpp - there will be problem on 5 & 6bpp + pBlock->uwCurrCount += 4; // Add constant part // Copper block after Y-break pBlock = pManager->pBreakBlock; pBlock->uwCurrCount = 0; // Rewind copBlock - if (pManager->uwBmAvailHeight - uwScrollY <= uwVpHeight) { - // logWrite("Break calc: %u - %u == %u, vpHeight: %u\n", pManager->uwBmAvailHeight, uwScrollY, pManager->uwBmAvailHeight - uwScrollY, uwVpHeight); + if(pManager->uwBmAvailHeight - uwScrollY <= uwVpHeight) { + if(pBlock->ubDisabled) { + copBlockEnable(pCopList, pBlock); + } copBlockWait(pCopList, pBlock, 0, 0x2C + pManager->sCommon.pVPort->uwOffsY + pManager->uwBmAvailHeight - uwScrollY); - // copMove(pCopList, pBlock, &g_pCustom->bplcon1, uwOffsX); // potrzebne? - copMove(pCopList, pBlock, &g_pCustom->color[0], 0x0F00); - for (i = pManager->sCommon.pVPort->ubBPP; i--;) { - ulPlaneAddr = (ULONG)(pManager->pBuffer->Planes[i]) + uwScrollX; + for(UBYTE i = pManager->sCommon.pVPort->ubBPP; i--;) { + ULONG ulPlaneAddr = (ULONG)(pManager->pBack->Planes[i]) + ulBplAddX; copMove(pCopList, pBlock, &g_pBplFetch[i].uwHi, ulPlaneAddr >> 16); copMove(pCopList, pBlock, &g_pBplFetch[i].uwLo, ulPlaneAddr & 0xFFFF); } - copMove(pCopList, pBlock, &g_pCustom->color[0], 0x0000); } else { - copBlockWait(pCopList, pBlock, 0x7F, 0xFF); + copBlockDisable(pCopList, pBlock); } - - pManager->uwVpHeightPrev = uwVpHeight; - copProcessBlocks(); } - logAvgEnd(pManager->pAvg); - WaitTOF(); + pManager->uwVpHeightPrev = uwVpHeight; + + // Swap buffers if needed + if(pManager->pBack != pManager->pFront) { + tBitMap *pTmp = pManager->pBack; + pManager->pBack = pManager->pFront; + pManager->pFront = pTmp; + } } -void scrollBufferReset(tScrollBufferManager *pManager, UBYTE ubMarginWidth, UWORD uwBoundWidth, UWORD uwBoundHeight) { +void scrollBufferReset( + tScrollBufferManager *pManager, UBYTE ubMarginWidth, + UWORD uwBoundWidth, UWORD uwBoundHeight, UBYTE ubBitmapFlags, UBYTE isDblBuf +) { UWORD uwVpWidth, uwVpHeight; UWORD uwCalcWidth, uwCalcHeight; - logBlockBegin("scrollBufferReset(pManager: %p, ubMarginWidth: %hu, uwBoundWidth: %u, uwBoundHeight: %u)", pManager, ubMarginWidth, uwBoundWidth, uwBoundHeight); + logBlockBegin( + "scrollBufferReset(pManager: %p, ubMarginWidth: %hu, uwBoundWidth: %u, uwBoundHeight: %u)", + pManager, ubMarginWidth, uwBoundWidth, uwBoundHeight + ); // Helper vars uwVpWidth = pManager->sCommon.pVPort->uwWidth; uwVpHeight = pManager->sCommon.pVPort->uwHeight; @@ -148,25 +234,52 @@ void scrollBufferReset(tScrollBufferManager *pManager, UBYTE ubMarginWidth, UWOR pManager->uwVpHeightPrev = 0; pManager->uBfrBounds.sUwCoord.uwX = uwBoundWidth; pManager->uBfrBounds.sUwCoord.uwY = uwBoundHeight; - pManager->uwBmAvailHeight = ubMarginWidth * blockCountCeil(uwVpHeight, ubMarginWidth) + ubMarginWidth*4; + // Optimize avail height to power of two so that modulo can be an AND + pManager->uwBmAvailHeight = nearestPowerOf2(ubMarginWidth * (blockCountCeil(uwVpHeight, ubMarginWidth) + 4)); // Destroy old buffer bitmap - if(pManager->pBuffer) { - bitmapDestroy(pManager->pBuffer); + if(pManager->pFront && pManager->pFront != pManager->pBack) { + bitmapDestroy(pManager->pFront); + } + if(pManager->pBack) { + bitmapDestroy(pManager->pBack); } // Create new buffer bitmap - uwCalcWidth = uwVpWidth + ubMarginWidth*4; + uwCalcWidth = nearestPowerOf2(uwVpWidth + ubMarginWidth*4); uwCalcHeight = pManager->uwBmAvailHeight + blockCountCeil(uwBoundWidth, uwVpWidth) - 1; - pManager->pBuffer = bitmapCreate(uwCalcWidth, uwCalcHeight, pManager->sCommon.pVPort->ubBPP, BMF_CLEAR); - pManager->uwModulo = pManager->pBuffer->BytesPerRow - (uwVpWidth >> 3) - 2; + pManager->pBack = bitmapCreate( + uwCalcWidth, uwCalcHeight, pManager->sCommon.pVPort->ubBPP, ubBitmapFlags + ); + if(isDblBuf) { + pManager->pFront = bitmapCreate( + uwCalcWidth, uwCalcHeight, pManager->sCommon.pVPort->ubBPP, ubBitmapFlags + ); + } + else { + pManager->pFront = pManager->pBack; + } + pManager->uwModulo = pManager->pBack->BytesPerRow - (uwVpWidth >> 3) - 2; + + // Constant stuff in copperlist + tCopList *pCopList = pManager->sCommon.pVPort->pView->pCopList; + if(pManager->ubFlags & SCROLLBUFFER_FLAG_COPLIST_RAW) { + } + else { + tCopBlock *pBlock = pManager->pStartBlock; + // Set initial WAIT + copBlockWait(pCopList, pBlock, 0, 0x2C + pManager->sCommon.pVPort->uwOffsY); + // After bitplane ptrs & bplcon + pBlock->uwCurrCount = 2 * pManager->sCommon.pVPort->ubBPP + 1; + copMove(pCopList, pBlock, &g_pCustom->ddfstrt, 0x0030); // Fetch start + copMove(pCopList, pBlock, &g_pCustom->bpl1mod, pManager->uwModulo); // Odd planes modulo + copMove(pCopList, pBlock, &g_pCustom->bpl2mod, pManager->uwModulo); // Even planes modulo + copMove(pCopList, pBlock, &g_pCustom->ddfstop, 0x00D0); // Fetch stop + } logBlockEnd("scrollBufferReset()"); } -/** - * Uses unsafe blit copy for using out-of-bound X ccord - */ void scrollBufferBlitMask( tBitMap *pSrc, WORD wSrcX, WORD wSrcY, tScrollBufferManager *pDstManager, WORD wDstX, WORD wDstY, @@ -174,14 +287,13 @@ void scrollBufferBlitMask( ) { // TODO: if area is visible wDstY %= pDstManager->uwBmAvailHeight; - // UBYTE ubAddY = wDstX/(pDstManager->pBuffer->BytesPerRow<<3); - wDstY %= (pDstManager->pBuffer->BytesPerRow<<3); + wDstY %= (pDstManager->pBack->BytesPerRow<<3); if(wDstY + wHeight <= pDstManager->uwBmAvailHeight) { // single blit blitUnsafeCopyMask( pSrc, wSrcX, wSrcY, - pDstManager->pBuffer, wDstX, wDstY, + pDstManager->pBack, wDstX, wDstY, wWidth, wHeight, pMsk ); } @@ -191,12 +303,12 @@ void scrollBufferBlitMask( wPartHeight = pDstManager->uwBmAvailHeight - wDstY; blitUnsafeCopyMask( pSrc, wSrcX, wSrcY, - pDstManager->pBuffer, wDstX, wDstY, + pDstManager->pBack, wDstX, wDstY, wWidth, wPartHeight, pMsk ); blitUnsafeCopyMask( pSrc, wSrcX, wSrcY + wPartHeight, - pDstManager->pBuffer, wDstX, 0, + pDstManager->pBack, wDstX, 0, wWidth, wHeight - wPartHeight, pMsk ); } diff --git a/src/ace/managers/viewport/simplebuffer.c b/src/ace/managers/viewport/simplebuffer.c index fd7149dd..f6b6b445 100644 --- a/src/ace/managers/viewport/simplebuffer.c +++ b/src/ace/managers/viewport/simplebuffer.c @@ -4,17 +4,109 @@ #include #include +#include #ifdef AMIGA -tSimpleBufferManager *simpleBufferCreate( - void *pTags, ... -) { +// Flags for internal usage. +#define SIMPLEBUFFER_FLAG_X_SCROLLABLE 1 +#define SIMPLEBUFFER_FLAG_COPLIST_RAW 2 + +static void simpleBufferSetBack(tSimpleBufferManager *pManager, tBitMap *pBack) { +#if defined(ACE_DEBUG) + if(pManager->pBack && pManager->pBack->Depth != pBack->Depth) { + logWrite("ERR: buffer bitmaps differ in BPP!\n"); + return; + } +#endif + pManager->pBack = pBack; +} + +void simpleBufferSetFront(tSimpleBufferManager *pManager, tBitMap *pFront) { + logBlockBegin( + "simpleBufferSetFront(pManager: %p, pFront: %p)", + pManager, pFront + ); +#if defined(ACE_DEBUG) + if(pManager->pFront && pManager->pFront->Depth != pFront->Depth) { + logWrite("ERR: buffer bitmaps differ in BPP!\n"); + return; + } +#endif + + pManager->uBfrBounds.sUwCoord.uwX = bitmapGetByteWidth(pFront) << 3; + pManager->uBfrBounds.sUwCoord.uwY = pFront->Rows; + pManager->pFront = pFront; + UWORD uwModulo = pFront->BytesPerRow - (pManager->sCommon.pVPort->uwWidth >> 3); + UWORD uwDDfStrt; + if(pManager->uBfrBounds.sUwCoord.uwX <= pManager->sCommon.pVPort->uwWidth) { + uwDDfStrt = 0x0038; + pManager->ubFlags &= ~SIMPLEBUFFER_FLAG_X_SCROLLABLE; + } + else { + pManager->ubFlags |= SIMPLEBUFFER_FLAG_X_SCROLLABLE; + uwDDfStrt = 0x0030; + uwModulo -= 2; + } + logWrite("Modulo: %u\n", uwModulo); + + // Update (rewrite) copperlist + // TODO this could be unified with copBlock being set with copSetMove too + tCopList *pCopList = pManager->sCommon.pVPort->pView->pCopList; + if(pManager->ubFlags & SIMPLEBUFFER_FLAG_COPLIST_RAW) { + // Since simpleBufferProcess only updates bitplane ptrs and shift, + // copperlist must be shaped here. + // WAIT is calc'd in same way as in copBlockCreate in simpleBufferCreate(). + tCopCmd *pCmdList = &pCopList->pBackBfr->pList[pManager->uwCopperOffset]; + logWrite( + "Setting copperlist %p at offs %u\n", + pCopList->pBackBfr, pManager->uwCopperOffset + ); + copSetWait(&pCmdList[0].sWait, 0xE2-7*4, pManager->sCommon.pVPort->uwOffsY + 0x2C-1); + copSetMove(&pCmdList[1].sMove, &g_pCustom->ddfstop, 0x00D0); // Data fetch + copSetMove(&pCmdList[2].sMove, &g_pCustom->ddfstrt, uwDDfStrt); + copSetMove(&pCmdList[3].sMove, &g_pCustom->bpl1mod, uwModulo); // Bitplane modulo + copSetMove(&pCmdList[4].sMove, &g_pCustom->bpl2mod, uwModulo); + copSetMove(&pCmdList[5].sMove, &g_pCustom->bplcon1, 0); // Shift: 0 + UBYTE i; + ULONG ulPlaneAddr; + for (i = 0; i < pManager->sCommon.pVPort->ubBPP; ++i) { + ulPlaneAddr = (ULONG)pManager->pFront->Planes[i]; + copSetMove(&pCmdList[6 + i*2 + 0].sMove, &g_pBplFetch[i].uwHi, ulPlaneAddr >> 16); + copSetMove(&pCmdList[6 + i*2 + 1].sMove, &g_pBplFetch[i].uwLo, ulPlaneAddr & 0xFFFF); + } + // Copy to front buffer since it needs initialization there too + CopyMem( + &pCopList->pBackBfr->pList[pManager->uwCopperOffset], + &pCopList->pFrontBfr->pList[pManager->uwCopperOffset], + (6+2*pManager->sCommon.pVPort->ubBPP)*sizeof(tCopCmd) + ); + } + else { + tCopBlock *pBlock = pManager->pCopBlock; + pBlock->uwCurrCount = 0; // Rewind to beginning + copMove(pCopList, pBlock, &g_pCustom->ddfstop, 0x00D0); // Data fetch + copMove(pCopList, pBlock, &g_pCustom->ddfstrt, uwDDfStrt); + copMove(pCopList, pBlock, &g_pCustom->bpl1mod, uwModulo); // Bitplane modulo + copMove(pCopList, pBlock, &g_pCustom->bpl2mod, uwModulo); + copMove(pCopList, pBlock, &g_pCustom->bplcon1, 0); // Shift: 0 + for (UBYTE i = 0; i < pManager->sCommon.pVPort->ubBPP; ++i) { + ULONG ulPlaneAddr = (ULONG)pManager->pFront->Planes[i]; + copMove(pCopList, pBlock, &g_pBplFetch[i].uwHi, ulPlaneAddr >> 16); + copMove(pCopList, pBlock, &g_pBplFetch[i].uwLo, ulPlaneAddr & 0xFFFF); + } + } + logBlockEnd("simplebufferSetFront()"); +} + +tSimpleBufferManager *simpleBufferCreate(void *pTags, ...) { va_list vaTags; tCopList *pCopList; tSimpleBufferManager *pManager; UWORD uwBoundWidth, uwBoundHeight; UBYTE ubBitmapFlags; + tBitMap *pFront = 0, *pBack = 0; + UBYTE isCameraCreated = 0; logBlockBegin("simpleBufferCreate(pTags: %p, ...)", pTags); va_start(vaTags, pTags); @@ -35,23 +127,42 @@ tSimpleBufferManager *simpleBufferCreate( logWrite("Parent VPort: %p\n", pVPort); // Buffer bitmap - uwBoundWidth = tagGet(pTags, vaTags, TAG_SIMPLEBUFFER_BOUND_WIDTH, pVPort->uwWidth); - uwBoundHeight = tagGet(pTags, vaTags, TAG_SIMPLEBUFFER_BOUND_HEIGHT, pVPort->uwHeight); - ubBitmapFlags = tagGet(pTags, vaTags, TAG_SIMPLEBUFFER_BITMAP_FLAGS, BMF_CLEAR); + uwBoundWidth = tagGet( + pTags, vaTags, TAG_SIMPLEBUFFER_BOUND_WIDTH, pVPort->uwWidth + ); + uwBoundHeight = tagGet( + pTags, vaTags, TAG_SIMPLEBUFFER_BOUND_HEIGHT, pVPort->uwHeight + ); + ubBitmapFlags = tagGet( + pTags, vaTags, TAG_SIMPLEBUFFER_BITMAP_FLAGS, BMF_CLEAR + ); logWrite("Bounds: %ux%u\n", uwBoundWidth, uwBoundHeight); - tBitMap *pBuffer = bitmapCreate( - uwBoundWidth, uwBoundHeight, - pVPort->ubBPP, ubBitmapFlags + pFront = bitmapCreate( + uwBoundWidth, uwBoundHeight, pVPort->ubBPP, ubBitmapFlags ); - if(!pBuffer) { + if(!pFront) { logWrite("ERR: Can't alloc buffer bitmap!\n"); goto fail; } + UBYTE isDblBfr = tagGet(pTags, vaTags, TAG_SIMPLEBUFFER_IS_DBLBUF, 0); + if(isDblBfr) { + pBack = bitmapCreate( + uwBoundWidth, uwBoundHeight, pVPort->ubBPP, ubBitmapFlags + ); + if(!pBack) { + logWrite("ERR: Can't alloc buffer bitmap!\n"); + goto fail; + } + } + // Find camera manager, create if not exists - pManager->pCameraManager = (tCameraManager*)vPortGetManager(pVPort, VPM_CAMERA); - if(!pManager->pCameraManager) { - pManager->pCameraManager = cameraCreate(pVPort, 0, 0, uwBoundWidth, uwBoundHeight); + pManager->pCamera = (tCameraManager*)vPortGetManager(pVPort, VPM_CAMERA); + if(!pManager->pCamera) { + isCameraCreated = 1; + pManager->pCamera = cameraCreate( + pVPort, 0, 0, uwBoundWidth, uwBoundHeight, isDblBfr + ); } pCopList = pVPort->pView->pCopList; @@ -81,7 +192,8 @@ tSimpleBufferManager *simpleBufferCreate( logWrite("Copperlist offset: %u\n", pManager->uwCopperOffset); } - simpleBufferSetBitmap(pManager, pBuffer); + simpleBufferSetFront(pManager, pFront); + simpleBufferSetBack(pManager, pBack ? pBack : pFront); // Add manager to VPort vPortAddManager(pVPort, (tVpManager*)pManager); @@ -90,127 +202,63 @@ tSimpleBufferManager *simpleBufferCreate( return pManager; fail: - logBlockEnd("simpleBufferCreate()"); - va_end(vaTags); - return 0; -} - -void simpleBufferSetBitmap(tSimpleBufferManager *pManager, tBitMap *pBitMap) { - logBlockBegin( - "simpleBufferSetBitmap(pManager: %p, pBitMap: %p)", - pManager, pBitMap - ); - if(pManager->pBuffer && pManager->pBuffer->Depth != pBitMap->Depth) { - logWrite("ERR: buffer bitmaps differ in BPP!\n"); - return; - } - - pManager->uBfrBounds.sUwCoord.uwX = bitmapGetByteWidth(pBitMap) << 3; - pManager->uBfrBounds.sUwCoord.uwY = pBitMap->Rows; - pManager->pBuffer = pBitMap; - UWORD uwModulo = pBitMap->BytesPerRow - (pManager->sCommon.pVPort->uwWidth >> 3); - UWORD uwDDfStrt; - if(pManager->uBfrBounds.sUwCoord.uwX <= pManager->sCommon.pVPort->uwWidth) { - uwDDfStrt = 0x0038; - pManager->ubFlags &= ~SIMPLEBUFFER_FLAG_X_SCROLLABLE; + if(pBack && pBack != pFront) { + bitmapDestroy(pBack); } - else { - pManager->ubFlags |= SIMPLEBUFFER_FLAG_X_SCROLLABLE; - uwDDfStrt = 0x0030; - uwModulo -= 1; - } - logWrite("Modulo: %u\n", uwModulo); - - // Update (rewrite) copperlist - // TODO this could be unified with copBlock being set with copSetMove too - tCopList *pCopList = pManager->sCommon.pVPort->pView->pCopList; - if(pManager->ubFlags & SIMPLEBUFFER_FLAG_COPLIST_RAW) { - // Since simpleBufferProcess only updates bitplane ptrs and shift, - // copperlist must be shaped here. - // WAIT is calc'd in same way as in copBlockCreate in simpleBufferCreate(). - tCopCmd *pCmdList = &pCopList->pBackBfr->pList[pManager->uwCopperOffset]; - logWrite("Setting copperlist %p at offs %u: %p\n", pCopList->pBackBfr, pManager->uwCopperOffset, pCmdList); - copSetWait(&pCmdList[0].sWait, 0xE2-7*4, pManager->sCommon.pVPort->uwOffsY + 0x2C-1); - copSetMove(&pCmdList[1].sMove, &g_pCustom->ddfstop, 0x00D0); // Data fetch - copSetMove(&pCmdList[2].sMove, &g_pCustom->ddfstrt, uwDDfStrt); - copSetMove(&pCmdList[3].sMove, &g_pCustom->bpl1mod, uwModulo); // Bitplane modulo - copSetMove(&pCmdList[4].sMove, &g_pCustom->bpl2mod, uwModulo); - copSetMove(&pCmdList[5].sMove, &g_pCustom->bplcon1, 0); // Shift: 0 - UBYTE i; - ULONG ulPlaneAddr; - for (i = 0; i != pManager->sCommon.pVPort->ubBPP; ++i) { - ulPlaneAddr = (ULONG)pManager->pBuffer->Planes[i]; - copSetMove(&pCmdList[6 + i*2 + 0].sMove, &g_pBplFetch[i].uwHi, ulPlaneAddr >> 16); - copSetMove(&pCmdList[6 + i*2 + 1].sMove, &g_pBplFetch[i].uwLo, ulPlaneAddr & 0xFFFF); - } - // Copy to front buffer since it needs initialization there too - CopyMem( - &pCopList->pBackBfr->pList[pManager->uwCopperOffset], - &pCopList->pFrontBfr->pList[pManager->uwCopperOffset], - (6+2*pManager->sCommon.pVPort->ubBPP)*sizeof(tCopCmd) - ); + if(pFront) { + bitmapDestroy(pFront); } - else { - tCopBlock *pBlock = pManager->pCopBlock; - pBlock->uwCurrCount = 0; // Rewind to beginning - copMove(pCopList, pBlock, &g_pCustom->ddfstop, 0x00D0); // Data fetch - copMove(pCopList, pBlock, &g_pCustom->ddfstrt, uwDDfStrt); - copMove(pCopList, pBlock, &g_pCustom->bpl1mod, uwModulo); // Bitplane modulo - copMove(pCopList, pBlock, &g_pCustom->bpl2mod, uwModulo); - copMove(pCopList, pBlock, &g_pCustom->bplcon1, 0); // Shift: 0 - UBYTE i; - ULONG ulPlaneAddr; - for (i = 0; i != pManager->sCommon.pVPort->ubBPP; ++i) { - ulPlaneAddr = (ULONG)pManager->pBuffer->Planes[i]; - copMove(pCopList, pBlock, &g_pBplFetch[i].uwHi, ulPlaneAddr >> 16); - copMove(pCopList, pBlock, &g_pBplFetch[i].uwLo, ulPlaneAddr & 0xFFFF); + if(pManager) { + if(pManager->pCamera && isCameraCreated) { + cameraDestroy(pManager->pCamera); } + memFree(pManager, sizeof(tSimpleBufferManager)); } - logBlockEnd("simplebufferSetBitmap()"); + logBlockEnd("simpleBufferCreate()"); + va_end(vaTags); + return 0; } void simpleBufferDestroy(tSimpleBufferManager *pManager) { logBlockBegin("simpleBufferDestroy()"); - logWrite("Destroying bitmap...\n"); - bitmapDestroy(pManager->pBuffer); - logWrite("Freeing mem...\n"); + copBlockDestroy(pManager->sCommon.pVPort->pView->pCopList, pManager->pCopBlock); + if(pManager->pBack != pManager->pFront) { + bitmapDestroy(pManager->pBack); + } + bitmapDestroy(pManager->pFront); memFree(pManager, sizeof(tSimpleBufferManager)); logBlockEnd("simpleBufferDestroy()"); } void simpleBufferProcess(tSimpleBufferManager *pManager) { - UBYTE i; UWORD uwShift; ULONG ulBplOffs; ULONG ulPlaneAddr; - tCameraManager *pCameraManager; - tCopList *pCopList; - pCameraManager = pManager->pCameraManager; - pCopList = pManager->sCommon.pVPort->pView->pCopList; + const tCameraManager *pCamera = pManager->pCamera; + tCopList *pCopList = pManager->sCommon.pVPort->pView->pCopList; - // Calculate X movement + // Calculate X movement: bitplane shift, starting word to fetch if(pManager->ubFlags & SIMPLEBUFFER_FLAG_X_SCROLLABLE) { - uwShift = 15-(pCameraManager->uPos.sUwCoord.uwX & 0xF); - uwShift = (uwShift << 4) | uwShift; + uwShift = (16 - (pCamera->uPos.sUwCoord.uwX & 0xF)) & 0xF; // Bitplane shift - single + uwShift = (uwShift << 4) | uwShift; // Bitplane shift - PF1 | PF2 + ulBplOffs = ((pCamera->uPos.sUwCoord.uwX - 1) >> 4) << 1; // Must be ULONG! } else { uwShift = 0; + ulBplOffs = (pCamera->uPos.sUwCoord.uwX >> 4) << 1; } - // X offset on bitplane - ulBplOffs = (pCameraManager->uPos.sUwCoord.uwX >> 4) << 1; - // Calculate Y movement - ulBplOffs += pManager->pBuffer->BytesPerRow*pCameraManager->uPos.sUwCoord.uwY; + ulBplOffs += pManager->pBack->BytesPerRow * pCamera->uPos.sUwCoord.uwY; // Copperlist - regen bitplane ptrs, update shift // TODO could be unified by using copSetMove in copBlock if(pManager->ubFlags & SIMPLEBUFFER_FLAG_COPLIST_RAW) { tCopCmd *pCmdList = &pCopList->pBackBfr->pList[pManager->uwCopperOffset]; copSetMove(&pCmdList[5].sMove, &g_pCustom->bplcon1, uwShift); - for (i = 0; i != pManager->sCommon.pVPort->ubBPP; ++i) { - ulPlaneAddr = ((ULONG)pManager->pBuffer->Planes[i]) + ulBplOffs; + for(UBYTE i = 0; i < pManager->sCommon.pVPort->ubBPP; ++i) { + ulPlaneAddr = ((ULONG)pManager->pBack->Planes[i]) + ulBplOffs; copSetMove(&pCmdList[6 + i*2 + 0].sMove, &g_pBplFetch[i].uwHi, ulPlaneAddr >> 16); copSetMove(&pCmdList[6 + i*2 + 1].sMove, &g_pBplFetch[i].uwLo, ulPlaneAddr & 0xFFFF); } @@ -218,12 +266,19 @@ void simpleBufferProcess(tSimpleBufferManager *pManager) { else { pManager->pCopBlock->uwCurrCount = 4; // Rewind to shift cmd pos copMove(pCopList, pManager->pCopBlock, &g_pCustom->bplcon1, uwShift); - for(i = 0; i != pManager->pBuffer->Depth; ++i) { - ulPlaneAddr = ((ULONG)pManager->pBuffer->Planes[i]) + ulBplOffs; + for(UBYTE i = 0; i < pManager->pBack->Depth; ++i) { + ulPlaneAddr = ((ULONG)pManager->pBack->Planes[i]) + ulBplOffs; copMove(pCopList, pManager->pCopBlock, &g_pBplFetch[i].uwHi, ulPlaneAddr >> 16); copMove(pCopList, pManager->pCopBlock, &g_pBplFetch[i].uwLo, ulPlaneAddr & 0xFFFF); } } + + // Swap buffers if needed + if(pManager->pBack != pManager->pFront) { + tBitMap *pTmp = pManager->pBack; + pManager->pBack = pManager->pFront; + pManager->pFront = pTmp; + } } UBYTE simpleBufferIsRectVisible( @@ -231,10 +286,10 @@ UBYTE simpleBufferIsRectVisible( UWORD uwX, UWORD uwY, UWORD uwWidth, UWORD uwHeight ) { return ( - uwX >= pManager->pCameraManager->uPos.sUwCoord.uwX - uwWidth && - uwX <= pManager->pCameraManager->uPos.sUwCoord.uwX + pManager->sCommon.pVPort->uwWidth && - uwY >= pManager->pCameraManager->uPos.sUwCoord.uwY - uwHeight && - uwY <= pManager->pCameraManager->uPos.sUwCoord.uwY + pManager->sCommon.pVPort->uwHeight + uwX >= pManager->pCamera->uPos.sUwCoord.uwX - uwWidth && + uwX <= pManager->pCamera->uPos.sUwCoord.uwX + pManager->sCommon.pVPort->uwWidth && + uwY >= pManager->pCamera->uPos.sUwCoord.uwY - uwHeight && + uwY <= pManager->pCamera->uPos.sUwCoord.uwY + pManager->sCommon.pVPort->uwHeight ); } diff --git a/src/ace/managers/viewport/tilebuffer.c b/src/ace/managers/viewport/tilebuffer.c index b7521092..96237ac0 100644 --- a/src/ace/managers/viewport/tilebuffer.c +++ b/src/ace/managers/viewport/tilebuffer.c @@ -3,101 +3,181 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include +#include +#include + +static UBYTE shiftFromPowerOfTwo(UWORD uwPot) { + UBYTE ubPower = 0; + while(uwPot > 1) { + uwPot >>= 1; + ++ubPower; + } + return ubPower; +} #ifdef AMIGA -/** - * Tilemap buffer manager - * Provides speed- and memory-efficient tilemap buffer - * Redraws only 1-tile margin beyond viewport in all dirs - * Author: KaiN - * Requires viewport managers: - * - camera - * - scroll - */ - -/** - * Tilemap buffer manager create fn - * Be sure to set camera pos, load tile data & then call tileBufferRedraw()! - */ -tTileBufferManager *tileBufferCreate( - tVPort *pVPort, - UWORD uwTileX, UWORD uwTileY, UBYTE ubTileShift, - char *szTileSetFileName, tCbTileDraw cbTileDraw +static void tileBufferQueueAdd( + tTileBufferManager *pManager, UWORD uwTileX, UWORD uwTileY ) { - logBlockBegin( - "tileBufferCreate(pVPort: %p, uwTileX: %u, uwTileY: %u, ubTileShift: %hu, " - "szTilesetFileName: %s, cbTileDraw: %p)", - pVPort, uwTileX, uwTileY, ubTileShift, szTileSetFileName, cbTileDraw - ); + tRedrawState *pState = &pManager->pRedrawStates[0]; + pState->pPendingQueue[pState->ubPendingCount].sUwCoord.uwX = uwTileX; + pState->pPendingQueue[pState->ubPendingCount].sUwCoord.uwY = uwTileY; + ++pState->ubPendingCount; + pState = &pManager->pRedrawStates[1]; + pState->pPendingQueue[pState->ubPendingCount].sUwCoord.uwX = uwTileX; + pState->pPendingQueue[pState->ubPendingCount].sUwCoord.uwY = uwTileY; + ++pState->ubPendingCount; +} + +void tileBufferQueueProcess(tTileBufferManager *pManager) { + tRedrawState *pState = &pManager->pRedrawStates[pManager->ubStateIdx]; + if(pState->ubPendingCount) { + --pState->ubPendingCount; + UBYTE ubPendingCount = pState->ubPendingCount; + const tUwCoordYX *pTile = &pState->pPendingQueue[ubPendingCount]; + tileBufferDrawTile(pManager, pTile->sUwCoord.uwX, pTile->sUwCoord.uwY); + } +} + +tTileBufferManager *tileBufferCreate(void *pTags, ...) { + va_list vaTags; tTileBufferManager *pManager; + UWORD uwTileX, uwTileY; + UBYTE ubBitmapFlags, isDblBuf; + + logBlockBegin("tileBufferCreate(pTags: %p, ...)", pTags); + va_start(vaTags, pTags); // Feed struct with args - pManager = memAllocFast(sizeof(tTileBufferManager)); - pManager->sCommon.pNext = 0; + pManager = memAllocFastClear(sizeof(tTileBufferManager)); pManager->sCommon.process = (tVpManagerFn)tileBufferProcess; pManager->sCommon.destroy = (tVpManagerFn)tileBufferDestroy; pManager->sCommon.ubId = VPM_TILEBUFFER; + + tVPort *pVPort = (tVPort*)tagGet(pTags, vaTags, TAG_TILEBUFFER_VPORT, 0); + if(!pVPort) { + logWrite("ERR: No parent viewport (TAG_TILEBUFFER_VPORT) specified!\n"); + goto fail; + } pManager->sCommon.pVPort = pVPort; + logWrite("Parent VPort: %p\n", pVPort); + UBYTE ubTileShift = tagGet(pTags, vaTags, TAG_TILEBUFFER_TILE_SHIFT, 0); + if(!ubTileShift) { + logWrite("ERR: No tile shift (TAG_TILEBUFFER_TILE_SHIFT) specified!\n"); + goto fail; + } pManager->ubTileShift = ubTileShift; pManager->ubTileSize = 1 << ubTileShift; - pManager->cbTileDraw = cbTileDraw; + + pManager->cbTileDraw = (tTileDrawCallback)tagGet( + pTags, vaTags, TAG_TILEBUFFER_CALLBACK_TILE_DRAW, 0 + ); + + pManager->pTileSet = (tBitMap*)tagGet(pTags, vaTags, TAG_TILEBUFFER_TILESET, 0); + if(!pManager->pTileSet) { + logWrite("ERR: No tileset (TAG_TILEBUFFER_TILESET) specified!\n"); + goto fail; + } + uwTileX = tagGet(pTags, vaTags, TAG_TILEBUFFER_BOUND_TILE_X, 0); + uwTileY = tagGet(pTags, vaTags, TAG_TILEBUFFER_BOUND_TILE_Y, 0); + if(!uwTileX || !uwTileY) { + logWrite( + "ERR: No tile boundaries (TAG_TILEBUFFER_BOUND_TILE_X or _Y) specified!\n" + ); + goto fail; + } pManager->pTileData = 0; - pManager->pTileSet = 0; - tileBufferReset(pManager, uwTileX, uwTileY, szTileSetFileName); + ubBitmapFlags = tagGet(pTags, vaTags, TAG_TILEBUFFER_BITMAP_FLAGS, BMF_CLEAR); + isDblBuf = tagGet(pTags, vaTags, TAG_TILEBUFFER_IS_DBLBUF, 0); + tileBufferReset(pManager, uwTileX, uwTileY, ubBitmapFlags, isDblBuf); + + pManager->ubQueueSize = tagGet( + pTags, vaTags, TAG_TILEBUFFER_REDRAW_QUEUE_LENGTH, 0 + ); + if(!pManager->ubQueueSize) { + logWrite( + "ERR: No queue size (TAG_TILEBUFFER_REDRAW_QUEUE_LENGTH) specified!\n" + ); + goto fail; + } + // This alloc could be checked in regard of double buffering + // but I want process to be as quick as possible (one 'if' less) + // and redraw queue has no mem footprint at all (256 bytes max?) + pManager->pRedrawStates[0].pPendingQueue = memAllocFast(pManager->ubQueueSize); + pManager->pRedrawStates[1].pPendingQueue = memAllocFast(pManager->ubQueueSize); + if( + !pManager->pRedrawStates[0].pPendingQueue || + !pManager->pRedrawStates[1].pPendingQueue + ) { + goto fail; + } vPortAddManager(pVPort, (tVpManager*)pManager); // find camera manager, create if not exists // camera created in scroll bfr - pManager->pCameraManager = (tCameraManager*)vPortGetManager(pVPort, VPM_CAMERA); - // if(!(pManager->pCameraManager = (tCameraManager*)extVPortGetManager(pVPort, VPM_CAMERA))) { - // pManager->pCameraManager = cameraCreate(pVPort, 0, 0, uwTileX << ubTileShift, uwTileY << ubTileShift); - // } - // TODO: reset camera bounds? + pManager->pCamera = (tCameraManager*)vPortGetManager(pVPort, VPM_CAMERA); - // nie tutaj bo kamera jeszcze musi zosta� ustawiona - // i pTileData ustawione - // a bez sensu dwa razy odrysowywa� ca�y ekran - // tileBufferRedraw(pManager); + // Redraw shouldn't take place here because camera is not in proper pos yet, + // also pTileData is empty + va_end(vaTags); logBlockEnd("tileBufferCreate"); return pManager; +fail: + // TODO: proper fail + if(pManager->pRedrawStates[0].pPendingQueue) { + memFree(pManager->pRedrawStates[0].pPendingQueue, pManager->ubQueueSize); + } + if(pManager->pRedrawStates[1].pPendingQueue) { + memFree(pManager->pRedrawStates[1].pPendingQueue, pManager->ubQueueSize); + } + va_end(vaTags); + logBlockEnd("tileBufferCreate"); + return 0; } void tileBufferDestroy(tTileBufferManager *pManager) { UWORD uwCol; logBlockBegin("tileBufferDestroy(pManager: %p)", pManager); - // Free tileset - bitmapDestroy(pManager->pTileSet); - // Free tile data - for (uwCol = pManager->uTileBounds.sUwCoord.uwX; uwCol--;) + for(uwCol = pManager->uTileBounds.sUwCoord.uwX; uwCol--;) { memFree(pManager->pTileData[uwCol], pManager->uTileBounds.sUwCoord.uwY * sizeof(UBYTE)); + } memFree(pManager->pTileData, pManager->uTileBounds.sUwCoord.uwX * sizeof(UBYTE *)); + if(pManager->pRedrawStates[0].pPendingQueue) { + memFree(pManager->pRedrawStates[0].pPendingQueue, pManager->ubQueueSize); + } + if(pManager->pRedrawStates[1].pPendingQueue) { + memFree(pManager->pRedrawStates[1].pPendingQueue, pManager->ubQueueSize); + } + // Free manager memFree(pManager, sizeof(tTileBufferManager)); logBlockEnd("tileBufferDestroy"); } -void tileBufferReset(tTileBufferManager *pManager, - UWORD uwTileX, UWORD uwTileY, - // UWORD uwCameraX, UWORD uwCameraY, - char *szTileSetFileName - ) { - UWORD uwCol; - UBYTE ubTileShift; - logBlockBegin("tileBufferReset()"); +void tileBufferReset( + tTileBufferManager *pManager, UWORD uwTileX, UWORD uwTileY, + UBYTE ubBitmapFlags, UBYTE isDblBuf +) { + logBlockBegin( + "tileBufferReset(pManager: %p, uwTileX: %hu, uwTileY: %hu, ubBitmapFlags: %hhu, isDblBuf: %hhu)", + pManager, uwTileX, uwTileY, ubBitmapFlags, isDblBuf + ); // Free old tile data if(pManager->pTileData) { - for (uwCol = pManager->uTileBounds.sUwCoord.uwX; uwCol--;) + for(UWORD uwCol = pManager->uTileBounds.sUwCoord.uwX; uwCol--;) { memFree(pManager->pTileData[uwCol], pManager->uTileBounds.sUwCoord.uwY * sizeof(UBYTE)); + } memFree(pManager->pTileData, pManager->uTileBounds.sUwCoord.uwX * sizeof(UBYTE *)); pManager->pTileData = 0; } @@ -106,93 +186,107 @@ void tileBufferReset(tTileBufferManager *pManager, pManager->uTileBounds.sUwCoord.uwX = uwTileX; pManager->uTileBounds.sUwCoord.uwY = uwTileY; if(uwTileX && uwTileY) { - pManager->pTileData = memAllocFast(uwTileX * sizeof(BYTE*)); - for(uwCol = uwTileX; uwCol--;) { + pManager->pTileData = memAllocFast(uwTileX * sizeof(UBYTE*)); + for(UWORD uwCol = uwTileX; uwCol--;) { pManager->pTileData[uwCol] = memAllocFastClear(uwTileY * sizeof(UBYTE)); } } - // Load new tileset - if(szTileSetFileName) { - if(pManager->pTileSet) { - bitmapDestroy(pManager->pTileSet); - } - pManager->pTileSet = bitmapCreateFromFile(szTileSetFileName, 0); - } - // Reset margin redraw structs - ubTileShift = pManager->ubTileShift; - memset(&pManager->sMarginL, 0, sizeof(tTileMarginData)); - memset(&pManager->sMarginR, 0, sizeof(tTileMarginData)); - memset(&pManager->sMarginU, 0, sizeof(tTileMarginData)); - memset(&pManager->sMarginD, 0, sizeof(tTileMarginData)); - pManager->ubMarginXLength = (pManager->sCommon.pVPort->uwHeight >> ubTileShift) + 4; - pManager->ubMarginYLength = (pManager->sCommon.pVPort->uwWidth >> ubTileShift) + 4; - pManager->pMarginX = &pManager->sMarginR; - pManager->pMarginOppositeX = &pManager->sMarginL; - pManager->pMarginY = &pManager->sMarginD; - pManager->pMarginOppositeY = &pManager->sMarginU; + UBYTE ubTileShift = pManager->ubTileShift; + memset(&pManager->pRedrawStates[0], 0, sizeof(tRedrawState)); + memset(&pManager->pRedrawStates[1], 0, sizeof(tRedrawState)); + pManager->pRedrawStates[0].pMarginX = &pManager->pRedrawStates[0].sMarginR; + pManager->pRedrawStates[0].pMarginOppositeX = &pManager->pRedrawStates[0].sMarginL; + pManager->pRedrawStates[0].pMarginY = &pManager->pRedrawStates[0].sMarginD; + pManager->pRedrawStates[0].pMarginOppositeY = &pManager->pRedrawStates[0].sMarginU; + pManager->pRedrawStates[1].pMarginX = &pManager->pRedrawStates[1].sMarginR; + pManager->pRedrawStates[1].pMarginOppositeX = &pManager->pRedrawStates[1].sMarginL; + pManager->pRedrawStates[1].pMarginY = &pManager->pRedrawStates[1].sMarginD; + pManager->pRedrawStates[1].pMarginOppositeY = &pManager->pRedrawStates[1].sMarginU; // Reset scrollManager, create if not exists - if(!(pManager->pScrollManager = (tScrollBufferManager*)vPortGetManager(pManager->sCommon.pVPort, VPM_SCROLL))) { - pManager->pScrollManager = scrollBufferCreate(pManager->sCommon.pVPort, pManager->ubTileSize, uwTileX << ubTileShift, uwTileY << ubTileShift); + pManager->pScroll = (tScrollBufferManager*)vPortGetManager( + pManager->sCommon.pVPort, VPM_SCROLL + ); + if(!(pManager->pScroll)) { + pManager->pScroll = scrollBufferCreate(0, + TAG_SCROLLBUFFER_VPORT, pManager->sCommon.pVPort, + TAG_SCROLLBUFFER_MARGIN_WIDTH, pManager->ubTileSize, + TAG_SCROLLBUFFER_BOUND_WIDTH, uwTileX << ubTileShift, + TAG_SCROLLBUFFER_BOUND_HEIGHT, uwTileY << ubTileShift, + TAG_SCROLLBUFFER_IS_DBLBUF, isDblBuf, + TAG_SCROLLBUFFER_BITMAP_FLAGS, ubBitmapFlags, + TAG_DONE); } else { scrollBufferReset( - pManager->pScrollManager, pManager->ubTileSize, - uwTileX << ubTileShift, uwTileY << ubTileShift + pManager->pScroll, pManager->ubTileSize, + uwTileX << ubTileShift, uwTileY << ubTileShift, ubBitmapFlags, isDblBuf ); } - pManager->uwMarginedWidth = pManager->sCommon.pVPort->uwWidth + (4 << ubTileShift); - pManager->uwMarginedHeight = pManager->pScrollManager->uwBmAvailHeight; + // Scrollin on one of dirs may be disabled - less redraw on other axis margin + pManager->uwMarginedWidth = bitmapGetByteWidth(pManager->pScroll->pFront)*8; + pManager->uwMarginedHeight = pManager->pScroll->uwBmAvailHeight; + pManager->ubWidthShift = shiftFromPowerOfTwo(pManager->uwMarginedWidth); + pManager->ubMarginXLength = MIN( + pManager->uTileBounds.sUwCoord.uwY, + (pManager->sCommon.pVPort->uwHeight >> ubTileShift) + 4 + ); + pManager->ubMarginYLength = MIN( + pManager->uTileBounds.sUwCoord.uwX, + (pManager->sCommon.pVPort->uwWidth >> ubTileShift) + 4 + ); + logWrite( + "Margin sizes: %hhu,%hhu\n", + pManager->ubMarginXLength, pManager->ubMarginYLength + ); logBlockEnd("tileBufferReset()"); } -/** - * Redraws one tile for each margin - X and Y - * Redraws all remaining margin's tiles when margin is about to be displayed - */ +FN_HOTSPOT void tileBufferProcess(tTileBufferManager *pManager) { - WORD wDeltaX, wDeltaY; WORD wTileIdxX, wTileIdxY; UWORD uwTileOffsX, uwTileOffsY; - UBYTE ubTileSize, ubTileShift; UBYTE ubAddY; + tRedrawState *pState = &pManager->pRedrawStates[pManager->ubStateIdx]; - ubTileSize = pManager->ubTileSize; - ubTileShift = pManager->ubTileShift; - wDeltaX = cameraGetDeltaX(pManager->pCameraManager); - wDeltaY = cameraGetDeltaY(pManager->pCameraManager); + UBYTE ubTileSize = pManager->ubTileSize; + UBYTE ubTileShift = pManager->ubTileShift; + WORD wDeltaX = cameraGetDeltaX(pManager->pCamera); + WORD wDeltaY = cameraGetDeltaY(pManager->pCamera); // X movement if (wDeltaX) { // determine movement direction - right or left if (wDeltaX > 0) { - wTileIdxX = ((pManager->pCameraManager->uPos.sUwCoord.uwX + pManager->sCommon.pVPort->uwWidth) >> ubTileShift) +1; // delete +1 to see redraw - pManager->pMarginX = &pManager->sMarginR; - pManager->pMarginOppositeX = &pManager->sMarginL; + wTileIdxX = (( + pManager->pCamera->uPos.sUwCoord.uwX + pManager->sCommon.pVPort->uwWidth + ) >> ubTileShift) +1; // delete +1 to see redraw + pState->pMarginX = &pState->sMarginR; + pState->pMarginOppositeX = &pState->sMarginL; } else { - wTileIdxX = (pManager->pCameraManager->uPos.sUwCoord.uwX >> ubTileShift) -1; - pManager->pMarginX = &pManager->sMarginL; - pManager->pMarginOppositeX = &pManager->sMarginR; + wTileIdxX = (pManager->pCamera->uPos.sUwCoord.uwX >> ubTileShift) -1; + pState->pMarginX = &pState->sMarginL; + pState->pMarginOppositeX = &pState->sMarginR; } // Not redrawing same column on movement side? - if (wTileIdxX != pManager->pMarginX->wTileOffs) { + if (wTileIdxX != pState->pMarginX->wTilePos) { // Not finished redrawing all column tiles? - if(pManager->pMarginX->wTileCurr < pManager->pMarginX->wTileEnd) { - uwTileOffsY = (pManager->pMarginX->wTileCurr << ubTileShift) % pManager->uwMarginedHeight; - ubAddY = (pManager->pMarginX->wTileOffs << ubTileShift) / pManager->uwMarginedWidth; - uwTileOffsX = (pManager->pMarginX->wTileOffs << ubTileShift) % pManager->uwMarginedWidth; + if(pState->pMarginX->wTileCurr < pState->pMarginX->wTileEnd) { + uwTileOffsY = (pState->pMarginX->wTileCurr << ubTileShift) & (pManager->uwMarginedHeight-1); + ubAddY = (pState->pMarginX->wTilePos << ubTileShift) / pManager->uwMarginedWidth; + uwTileOffsX = (pState->pMarginX->wTilePos << ubTileShift) & (pManager->uwMarginedWidth-1); // Redraw remaining tiles - while (pManager->pMarginX->wTileCurr < pManager->pMarginX->wTileEnd) { + while (pState->pMarginX->wTileCurr < pState->pMarginX->wTileEnd) { tileBufferDrawTileQuick( pManager, - pManager->pMarginX->wTileOffs, pManager->pMarginX->wTileCurr, + pState->pMarginX->wTilePos, pState->pMarginX->wTileCurr, uwTileOffsX, uwTileOffsY+ubAddY ); - ++pManager->pMarginX->wTileCurr; + ++pState->pMarginX->wTileCurr; uwTileOffsY = (uwTileOffsY + ubTileSize); if(uwTileOffsY >= pManager->uwMarginedHeight) { uwTileOffsY -= pManager->uwMarginedHeight; @@ -200,73 +294,72 @@ void tileBufferProcess(tTileBufferManager *pManager) { } } // Prepare new column redraw data - pManager->pMarginX->wTileOffs = wTileIdxX; + pState->pMarginX->wTilePos = wTileIdxX; if (wTileIdxX < 0 || wTileIdxX >= pManager->uTileBounds.sUwCoord.uwX) { // Don't redraw if new column is out of map bounds - pManager->pMarginX->wTileCurr = 0; - pManager->pMarginX->wTileEnd = 0; + pState->pMarginX->wTileCurr = 0; + pState->pMarginX->wTileEnd = 0; } else { // Prepare new column for redraw - pManager->pMarginX->wTileCurr = (pManager->pCameraManager->uPos.sUwCoord.uwY >> ubTileShift) - 2; - pManager->pMarginX->wTileEnd = pManager->pMarginX->wTileCurr + pManager->ubMarginXLength; - if(pManager->pMarginX->wTileCurr < 0) { - pManager->pMarginX->wTileCurr = 0; - } + pState->pMarginX->wTileCurr = MAX( + 0, (pManager->pCamera->uPos.sUwCoord.uwY >> ubTileShift) - 2 + ); + pState->pMarginX->wTileEnd = MIN( + pState->pMarginX->wTileCurr + pManager->ubMarginXLength, + pManager->uTileBounds.sUwCoord.uwY + ); } // Modify margin data on opposite side if(wDeltaX < 0) { - --pManager->pMarginOppositeX->wTileCurr; + --pState->pMarginOppositeX->wTileCurr; } else { - ++pManager->pMarginOppositeX->wTileCurr; + ++pState->pMarginOppositeX->wTileCurr; } - pManager->pMarginOppositeX->wTileCurr = 0; - pManager->pMarginOppositeX->wTileEnd = 0; + pState->pMarginOppositeX->wTileCurr = 0; + pState->pMarginOppositeX->wTileEnd = 0; } } // Redraw another X tile - regardless of movement in that direction - if (pManager->pMarginX->wTileCurr < pManager->pMarginX->wTileEnd) { - uwTileOffsX = (pManager->pMarginX->wTileOffs << ubTileShift) % pManager->uwMarginedWidth; - uwTileOffsY = (pManager->pMarginX->wTileCurr << ubTileShift) % pManager->uwMarginedHeight; - ubAddY = (pManager->pMarginX->wTileOffs << ubTileShift) / pManager->uwMarginedWidth; - tileBufferDrawTileQuick( - pManager, - pManager->pMarginX->wTileOffs, pManager->pMarginX->wTileCurr, - uwTileOffsX, uwTileOffsY+ubAddY + if (pState->pMarginX->wTileCurr < pState->pMarginX->wTileEnd) { + tileBufferDrawTile( + pManager, pState->pMarginX->wTilePos, pState->pMarginX->wTileCurr ); - ++pManager->pMarginX->wTileCurr; + ++pState->pMarginX->wTileCurr; } // Y movement if (wDeltaY) { // determine redraw row - down or up if (wDeltaY > 0) { - wTileIdxY = ((pManager->pCameraManager->uPos.sUwCoord.uwY + pManager->sCommon.pVPort->uwHeight) >> ubTileShift) +1; // Delete +1 to see redraw - pManager->pMarginY = &pManager->sMarginD; - pManager->pMarginOppositeY = &pManager->sMarginU; + wTileIdxY = (( + pManager->pCamera->uPos.sUwCoord.uwY + pManager->sCommon.pVPort->uwHeight + ) >> ubTileShift) + 1; // Delete +1 to see redraw + pState->pMarginY = &pState->sMarginD; + pState->pMarginOppositeY = &pState->sMarginU; } else { - wTileIdxY = (pManager->pCameraManager->uPos.sUwCoord.uwY >> ubTileShift) -1; - pManager->pMarginY = &pManager->sMarginU; - pManager->pMarginOppositeY = &pManager->sMarginD; + wTileIdxY = (pManager->pCamera->uPos.sUwCoord.uwY >> ubTileShift) -1; + pState->pMarginY = &pState->sMarginU; + pState->pMarginOppositeY = &pState->sMarginD; } // Not drawing same row? - if (wTileIdxY != pManager->pMarginY->wTileOffs) { + if (wTileIdxY != pState->pMarginY->wTilePos) { // Not finished redrawing all row tiles? - if(pManager->pMarginY->wTileCurr < pManager->pMarginY->wTileEnd) { - uwTileOffsY = (pManager->pMarginY->wTileOffs << ubTileShift) % pManager->uwMarginedHeight; - ubAddY = (pManager->pMarginY->wTileCurr << ubTileShift) / pManager->uwMarginedWidth; - uwTileOffsX = (pManager->pMarginY->wTileCurr << ubTileShift) % pManager->uwMarginedWidth; + if(pState->pMarginY->wTileCurr < pState->pMarginY->wTileEnd) { + uwTileOffsY = (pState->pMarginY->wTilePos << ubTileShift) & (pManager->uwMarginedHeight-1); + ubAddY = (pState->pMarginY->wTileCurr << ubTileShift) >> pManager->ubWidthShift; + uwTileOffsX = (pState->pMarginY->wTileCurr << ubTileShift) & (pManager->uwMarginedWidth-1); // Redraw remaining tiles - while(pManager->pMarginY->wTileCurr < pManager->pMarginY->wTileEnd) { + while(pState->pMarginY->wTileCurr < pState->pMarginY->wTileEnd) { tileBufferDrawTileQuick( pManager, - pManager->pMarginY->wTileCurr, pManager->pMarginY->wTileOffs, + pState->pMarginY->wTileCurr, pState->pMarginY->wTilePos, uwTileOffsX, uwTileOffsY+ubAddY ); - ++pManager->pMarginY->wTileCurr; + ++pState->pMarginY->wTileCurr; uwTileOffsX += ubTileSize; if(uwTileOffsX >= pManager->uwMarginedWidth) { uwTileOffsX -= pManager->uwMarginedWidth; @@ -275,178 +368,195 @@ void tileBufferProcess(tTileBufferManager *pManager) { } } // Prepare new row redraw data - pManager->pMarginY->wTileOffs = wTileIdxY; + pState->pMarginY->wTilePos = wTileIdxY; if (wTileIdxY < 0 || wTileIdxY >= pManager->uTileBounds.sUwCoord.uwY) { // Don't redraw if new row is out of map bounds - pManager->pMarginY->wTileCurr = 0; - pManager->pMarginY->wTileEnd = 0; + pState->pMarginY->wTileCurr = 0; + pState->pMarginY->wTileEnd = 0; } else { // Prepare new row for redraw - pManager->pMarginY->wTileCurr = (pManager->pCameraManager->uPos.sUwCoord.uwX >> ubTileShift) - 2; - pManager->pMarginY->wTileEnd = pManager->pMarginY->wTileCurr + pManager->ubMarginYLength; - if(pManager->pMarginY->wTileCurr < 0) { - pManager->pMarginY->wTileCurr = 0; - } - if(pManager->pMarginY->wTileEnd >= pManager->uTileBounds.sUwCoord.uwX) { - pManager->pMarginY->wTileEnd = pManager->uTileBounds.sUwCoord.uwX-1; - } + pState->pMarginY->wTileCurr = MAX( + 0, (pManager->pCamera->uPos.sUwCoord.uwX >> ubTileShift) - 2 + ); + pState->pMarginY->wTileEnd = MIN( + pState->pMarginY->wTileCurr + pManager->ubMarginYLength, + pManager->uTileBounds.sUwCoord.uwX + ); } // Modify opposite margin data if(wDeltaY > 0) { - ++pManager->pMarginOppositeY->wTileOffs; + ++pState->pMarginOppositeY->wTilePos; } else { - --pManager->pMarginOppositeY->wTileOffs; + --pState->pMarginOppositeY->wTilePos; } - pManager->pMarginOppositeY->wTileCurr = 0; - pManager->pMarginOppositeY->wTileEnd = 0; + pState->pMarginOppositeY->wTileCurr = 0; + pState->pMarginOppositeY->wTileEnd = 0; } } // Redraw another Y tile - regardless of movement in that direction - if (pManager->pMarginY->wTileCurr < pManager->pMarginY->wTileEnd) { - ubAddY = (pManager->pMarginY->wTileCurr << ubTileShift) / pManager->uwMarginedWidth; - uwTileOffsX = (pManager->pMarginY->wTileCurr << ubTileShift) % pManager->uwMarginedWidth; - uwTileOffsY = (pManager->pMarginY->wTileOffs << ubTileShift) % pManager->uwMarginedHeight; - tileBufferDrawTileQuick( - pManager, - pManager->pMarginY->wTileCurr, pManager->pMarginY->wTileOffs, - uwTileOffsX, uwTileOffsY+ubAddY + if (pState->pMarginY->wTileCurr < pState->pMarginY->wTileEnd) { + tileBufferDrawTile( + pManager, pState->pMarginY->wTileCurr, pState->pMarginY->wTilePos ); - ++pManager->pMarginY->wTileCurr; + ++pState->pMarginY->wTileCurr; } + pManager->ubStateIdx = !pManager->ubStateIdx; } -/** - * Redraws tiles on whole screen - * Use for init or something like that, as it's slooooooooow - */ -void tileBufferRedraw(tTileBufferManager *pManager) { - UWORD i,j; - UWORD uwTileOffsX, uwTileOffsY; - WORD wTileIdxX, wTileIdxY; - UBYTE ubAddY; - UBYTE ubTileSize, ubTileShift; - - logBlockBegin("tileBufferRedraw(pManager: %p)", pManager); - ubTileSize = pManager->ubTileSize; - ubTileShift = pManager->ubTileShift; - pManager->uwMarginedWidth = pManager->sCommon.pVPort->uwWidth + (4 << ubTileShift); - pManager->uwMarginedHeight = pManager->pScrollManager->uwBmAvailHeight; - - wTileIdxY = (pManager->pCameraManager->uPos.sUwCoord.uwY >> ubTileShift) -1; - if (wTileIdxY < 0) - wTileIdxY = 0; - uwTileOffsY = (wTileIdxY << ubTileShift) % pManager->uwMarginedHeight; - - for (j = 0; j < pManager->uwMarginedHeight; j += ubTileSize) { - - wTileIdxX = (pManager->pCameraManager->uPos.sUwCoord.uwX >> ubTileShift) -1; - if (wTileIdxX < 0) - wTileIdxX = 0; - ubAddY = (wTileIdxX << ubTileShift) / pManager->uwMarginedWidth; - uwTileOffsX = (wTileIdxX << ubTileShift) % pManager->uwMarginedWidth; - - for (i = 0; i < pManager->uwMarginedWidth; i+= ubTileSize) { - tileBufferDrawTileQuick(pManager, wTileIdxX, wTileIdxY, uwTileOffsX, uwTileOffsY+ubAddY); - ++wTileIdxX; +void tileBufferInitialDraw(const tTileBufferManager *pManager) { + logBlockBegin("tileBufferInitialDraw(pManager: %p)", pManager); + UBYTE ubTileSize = pManager->ubTileSize; + UBYTE ubTileShift = pManager->ubTileShift; + + WORD wStartY = MAX( + 0, (pManager->pCamera->uPos.sUwCoord.uwY >> ubTileShift) -1 + ); + WORD wStartX = MAX( + 0, (pManager->pCamera->uPos.sUwCoord.uwX >> ubTileShift) -1 + ); + // One of bounds may be smaller than viewport + margin size + UWORD uwEndX = MIN( + pManager->uTileBounds.sUwCoord.uwX, + pManager->uwMarginedWidth >> ubTileShift + ); + UWORD uwEndY = MIN( + pManager->uTileBounds.sUwCoord.uwY, + pManager->uwMarginedHeight >> ubTileShift + ); + + UWORD uwTileOffsY = (wStartY << ubTileShift) & (pManager->uwMarginedHeight - 1); + for (UWORD uwTileY = wStartY; uwTileY < uwEndY; ++uwTileY) { + UBYTE ubAddY = (wStartX << ubTileShift) >> pManager->ubWidthShift; + UWORD uwTileOffsX = (wStartX << ubTileShift) & (pManager->uwMarginedWidth-1); + + for (UWORD uwTileX = wStartX; uwTileX < uwEndX; ++uwTileX) { + tileBufferDrawTileQuick( + pManager, uwTileX, uwTileY, uwTileOffsX, uwTileOffsY+ubAddY + ); uwTileOffsX += ubTileSize; if(uwTileOffsX >= pManager->uwMarginedWidth) { ++ubAddY; uwTileOffsX -= pManager->uwMarginedWidth; } } - - ++wTileIdxY; - uwTileOffsY = (uwTileOffsY + ubTileSize) % pManager->uwMarginedHeight; + uwTileOffsY = (uwTileOffsY + ubTileSize) & (pManager->uwMarginedHeight - 1); } - logBlockEnd("tileBufferRedraw()"); + + // Copy from back buffer to front buffer + CopyMemQuick( + pManager->pScroll->pBack->Planes[0], pManager->pScroll->pFront->Planes[0], + pManager->pScroll->pFront->BytesPerRow * pManager->pScroll->pFront->Rows + ); + + logBlockEnd("tileBufferInitialDraw()"); } -/** - * Redraws selected tile, calls custom redraw callback - * Calculates destination on buffer - * Use for single redraws - */ -void tileBufferDrawTile(tTileBufferManager *pManager, UWORD uwTileIdxX, UWORD uwTileIdxY) { +void tileBufferDrawTile( + const tTileBufferManager *pManager, UWORD uwTileIdxX, UWORD uwTileIdxY +) { UWORD uwBfrX, uwBfrY; UBYTE ubAddY; - uwBfrY = (uwTileIdxY << pManager->ubTileShift) % pManager->uwMarginedHeight; - ubAddY = (uwTileIdxX << pManager->ubTileShift) / pManager->uwMarginedWidth; - uwBfrX = (uwTileIdxX << pManager->ubTileShift) % pManager->uwMarginedWidth; + uwBfrY = (uwTileIdxY << pManager->ubTileShift) & (pManager->uwMarginedHeight - 1); + ubAddY = (uwTileIdxX << pManager->ubTileShift) >> pManager->ubWidthShift; + uwBfrX = (uwTileIdxX << pManager->ubTileShift) & (pManager->uwMarginedWidth-1); - tileBufferDrawTileQuick(pManager, uwTileIdxX, uwTileIdxY, uwBfrX, uwBfrY+ubAddY); + tileBufferDrawTileQuick( + pManager, uwTileIdxX, uwTileIdxY, uwBfrX, uwBfrY+ubAddY + ); } -/** - * Redraws selected tile, calls custom redraw callback - * Destination coord on buffer must be calculated externally - avoids recalc - * Use for batch redraws with smart uwBfrXY update - */ -void tileBufferDrawTileQuick(tTileBufferManager *pManager, UWORD uwTileIdxX, UWORD uwTileIdxY, UWORD uwBfrX, UWORD uwBfrY) { +void tileBufferDrawTileQuick( + const tTileBufferManager *pManager, UWORD uwTileX, UWORD uwTileY, + UWORD uwBfrX, UWORD uwBfrY +) { blitCopyAligned( pManager->pTileSet, - 0, pManager->pTileData[uwTileIdxX][uwTileIdxY] << pManager->ubTileShift, - pManager->pScrollManager->pBuffer, uwBfrX, uwBfrY, + 0, pManager->pTileData[uwTileX][uwTileY] << pManager->ubTileShift, + pManager->pScroll->pBack, uwBfrX, uwBfrY, pManager->ubTileSize, pManager->ubTileSize ); if(pManager->cbTileDraw) { - pManager->cbTileDraw(uwTileIdxX, uwTileIdxY, pManager->pScrollManager->pBuffer, uwBfrX, uwBfrY); + pManager->cbTileDraw( + uwTileX, uwTileY, pManager->pScroll->pBack, uwBfrX, uwBfrY + ); } } -/** - * Redraws all tiles intersecting with given rectangle - * Only tiles currently on buffer are redrawn - */ -void tileBufferInvalidateRect(tTileBufferManager *pManager, UWORD uwX, UWORD uwY, UWORD uwWidth, UWORD uwHeight) { - UWORD uwStartX, uwEndX, uwStartY, uwEndY; /// Invalidate tile rect - UWORD uwVisStartX, uwVisEndX, uwVisStartY, uwVisEndY; /// Visible tile rect (excluding invisible margins) - UWORD uwVisX, uwVisY; - UBYTE ubAddY; - - // graniczne indeksy kafli - uwStartX = uwX >> pManager->ubTileShift; - uwEndX = (uwX+uwWidth) >> pManager->ubTileShift; - uwStartY = uwY >> pManager->ubTileShift; - uwEndY = (uwY+uwHeight) >> pManager->ubTileShift; - - uwVisStartX = pManager->pCameraManager->uPos.sUwCoord.uwX >> pManager->ubTileShift; - uwVisStartY = pManager->pCameraManager->uPos.sUwCoord.uwY >> pManager->ubTileShift; - uwVisEndX = uwVisStartX + (pManager->sCommon.pVPort->uwWidth >> pManager->ubTileShift); - uwVisEndY = uwVisStartY + (pManager->sCommon.pVPort->uwHeight >> pManager->ubTileShift); +void tileBufferInvalidateRect( + tTileBufferManager *pManager, UWORD uwX, UWORD uwY, + UWORD uwWidth, UWORD uwHeight +) { + // Tile x/y ranges in given coord + UWORD uwStartX = uwX >> pManager->ubTileShift; + UWORD uwEndX = (uwX+uwWidth) >> pManager->ubTileShift; + UWORD uwStartY = uwY >> pManager->ubTileShift; + UWORD uwEndY = (uwY+uwHeight) >> pManager->ubTileShift; for(uwX = uwStartX; uwX <= uwEndX; ++uwX) { - if(uwX < uwVisStartX) { - continue; - } - if(uwX > uwVisEndX) { - break; - } - ubAddY = (uwX << pManager->ubTileShift) / pManager->uwMarginedWidth; - uwVisX = (uwX << pManager->ubTileShift) % pManager->uwMarginedWidth; - uwVisY = (uwStartY << pManager->ubTileShift) % pManager->uwMarginedHeight; for(uwY = uwStartY; uwY <= uwEndY; ++uwY) { - if(uwY < uwVisStartY) { - continue; - } - if(uwY > uwVisEndY) { - logWrite("\n"); - logWrite("camera Y: %u, uwMarginedHeight: %u\n", pManager->pCameraManager->uPos.sUwCoord.uwY, pManager->uwMarginedHeight); - logWrite("uwStartY: %u, uwY: %u, uwEndY: %u\n", uwStartY, uwY, uwEndY); - logWrite("uwVisStartY: %u, uwVisY: %u, uwVisEndY: %u\n", uwVisStartY, uwVisY, uwVisEndY); - logWrite("uwY > uwVisEndY (%u > %u)\n", uwY, uwVisEndY); - break; - } - tileBufferDrawTileQuick(pManager, uwX, uwY, uwVisX, uwVisY + ubAddY); - uwVisY += pManager->ubTileSize; - if(uwVisY >= pManager->uwMarginedHeight) { - uwVisY -= pManager->uwMarginedHeight; - } + tileBufferInvalidateTile(pManager, uwX, uwY); } } } +void tileBufferInvalidateTile( + tTileBufferManager *pManager, UWORD uwTileX, UWORD uwTileY +) { + // FIXME it ain't working right yet + // if(!tileBufferIsTileOnBuffer(pManager, uwTileX, uwTileY)) { + // return; + // } + + // Previous state will have one more tile to draw, so only check smaller range + // omit if not yet drawn on redraw margin - let manager draw it when it + // will be that tile's turn + // const tRedrawState *pState = &pManager->pRedrawStates[pManager->ubStateIdx]; + // if( + // pState->pMarginX->wTilePos == uwTileX && + // pState->pMarginX->wTileCurr <= uwTileY && + // uwTileY <= pState->pMarginX->wTileEnd + // ) { + // return; + // } + // if( + // pState->pMarginY->wTilePos == uwTileY && + // pState->pMarginY->wTileCurr <= uwTileX && + // uwTileX <= pState->pMarginY->wTileEnd + // ) { + // return; + // } + + // Add to queue + tileBufferQueueAdd(pManager, uwTileX, uwTileY); +} + +UBYTE tileBufferIsTileOnBuffer( + const tTileBufferManager *pManager, UWORD uwTileX, UWORD uwTileY +) { + UBYTE ubTileShift = pManager->ubTileShift; + UWORD uwStartX = MAX(0, (pManager->pCamera->uPos.sUwCoord.uwX >> ubTileShift) -1); + UWORD uwEndX = uwStartX + ((pManager->uwMarginedWidth >> ubTileShift) - 2); + UWORD uwStartY = MAX(0, (pManager->pCamera->uPos.sUwCoord.uwY >> ubTileShift) -1); + UWORD uwEndY = uwStartY + ((pManager->uwMarginedHeight >> ubTileShift) - 2); + + if( + uwStartX <= uwTileX && uwTileX <= uwEndX && uwTileX && + uwStartY <= uwTileY && uwTileY <= uwEndY && uwTileY + ) { + return 1; + } + return 0; +} + +void tileBufferSetTile( + tTileBufferManager *pManager, UWORD uwX, UWORD uwY, UWORD uwIdx +) { + pManager->pTileData[uwX][uwY] = uwIdx; + tileBufferInvalidateTile(pManager, uwX, uwY); +} + #endif // AMIGA diff --git a/src/ace/utils/bitmap.c b/src/ace/utils/bitmap.c index b38d80a9..5190bd53 100644 --- a/src/ace/utils/bitmap.c +++ b/src/ace/utils/bitmap.c @@ -94,13 +94,13 @@ void bitmapLoadFromFile( systemUse(); logBlockBegin( - "bitmapLoadFromFile(pBitMap: %p, szFilePath: %s, uwStartX: %u, uwStartY: %u)", + "bitmapLoadFromFile(pBitMap: %p, szFilePath: '%s', uwStartX: %u, uwStartY: %u)", pBitMap, szFilePath, uwStartX, uwStartY ); // Open source bitmap tFile *pFile = fileOpen(szFilePath, "r"); if(!pFile) { - logWrite("ERR: File does not exist: %s\n", szFilePath); + logWrite("ERR: File does not exist\n", szFilePath); logBlockEnd("bitmapLoadFromFile()"); systemUnuse(); return; @@ -165,7 +165,7 @@ void bitmapLoadFromFile( for(ubPlane = 0; ubPlane != pBitMap->Depth; ++ubPlane) { fileRead( pFile, - &pBitMap->Planes[0][uwWidth*((y*pBitMap->Depth)+ubPlane)+(uwStartX>>3)], + &pBitMap->Planes[0][uwWidth*(((uwStartY + y)*pBitMap->Depth)+ubPlane)+(uwStartX>>3)], ((uwSrcWidth+7)>>3) ); } @@ -195,11 +195,11 @@ tBitMap *bitmapCreateFromFile(const char *szFilePath, UBYTE isFast) { UBYTE ubPlaneCount; // Bitplane count UBYTE i; - logBlockBegin("bitmapCreateFromFile(szFilePath: %s)", szFilePath); + logBlockBegin("bitmapCreateFromFile(szFilePath: '%s')", szFilePath); pFile = fileOpen(szFilePath, "r"); if(!pFile) { fileClose(pFile); - logWrite("ERR: File does not exist: %s\n", szFilePath); + logWrite("ERR: File does not exist\n"); logBlockEnd("bitmapCreateFromFile()"); return 0; } @@ -294,7 +294,7 @@ void bitmapDump(const tBitMap *pBitMap) { void bitmapSave(const tBitMap *pBitMap, const char *szPath) { systemUse(); - logBlockBegin("bitmapSave(pBitMap: %p, szPath: %s)", pBitMap, szPath); + logBlockBegin("bitmapSave(pBitMap: %p, szPath: '%s')", pBitMap, szPath); tFile *pFile = fileOpen(szPath, "wb"); if(!pFile) { @@ -331,28 +331,22 @@ void bitmapSave(const tBitMap *pBitMap, const char *szPath) { fileClose(pFile); logBlockEnd("bitmapSave()"); + systemUnuse(); } void bitmapSaveBmp( const tBitMap *pBitMap, const UWORD *pPalette, const char *szFilePath ) { - UWORD uwOut; - UBYTE ubOut; - ULONG ulOut; - UWORD c; - FILE *pOut; - UWORD uwX, uwY; - UBYTE pIndicesChunk[16]; - UWORD uwWidth; // TODO: EHB support - uwWidth = bitmapGetByteWidth(pBitMap) << 3; - pOut = fileOpen(szFilePath, "w"); + systemUse(); + UWORD uwWidth = bitmapGetByteWidth(pBitMap) << 3; + FILE *pOut = fileOpen(szFilePath, "w"); // BMP header fileWrite(pOut, "BM", 2); - ulOut = endianIntel32((pBitMap->BytesPerRow<<3) * pBitMap->Rows + 14+40+256*4); + ULONG ulOut = endianIntel32((pBitMap->BytesPerRow<<3) * pBitMap->Rows + 14+40+256*4); fileWrite(pOut, &ulOut, sizeof(ULONG)); // BMP file size ulOut = 0; @@ -372,7 +366,7 @@ void bitmapSaveBmp( ulOut = endianIntel32(pBitMap->Rows); fileWrite(pOut, &ulOut, sizeof(ULONG)); // Image height - uwOut = endianIntel16(1); + UWORD uwOut = endianIntel16(1); fileWrite(pOut, &uwOut, sizeof(UWORD)); // Color plane count uwOut = endianIntel16(8); @@ -397,8 +391,9 @@ void bitmapSaveBmp( fileWrite(pOut, &ulOut, sizeof(ULONG)); // Number of important colors - all // Global palette + UWORD c; for(c = 0; c != (1 << pBitMap->Depth); ++c) { - ubOut = pPalette[c] & 0xF; + UBYTE ubOut = pPalette[c] & 0xF; ubOut |= ubOut << 4; fileWrite(pOut, &ubOut, sizeof(UBYTE)); // B @@ -421,12 +416,14 @@ void bitmapSaveBmp( } // Image data - for(uwY = pBitMap->Rows; uwY--;) { + UBYTE pIndicesChunk[16]; + for(UWORD uwY = pBitMap->Rows; uwY--;) { + UWORD uwX; for(uwX = 0; uwX < uwWidth; uwX += 16) { chunkyFromPlanar16(pBitMap, uwX, uwY, pIndicesChunk); fileWrite(pOut, pIndicesChunk, 16*sizeof(UBYTE)); } - ubOut = 0; + UBYTE ubOut = 0; while(uwX & 0x3) {// 4-byte row padding fileWrite(pOut, &ubOut, sizeof(UBYTE)); ++uwX; diff --git a/src/ace/utils/chunky.c b/src/ace/utils/chunky.c index db8801e6..e8c4d938 100644 --- a/src/ace/utils/chunky.c +++ b/src/ace/utils/chunky.c @@ -90,3 +90,30 @@ void chunkyRotate( } } } + +void chunkyFromBitmap( + const tBitMap *pBitmap, UBYTE *pChunky, + UWORD uwSrcOffsX, UWORD uwSrcOffsY, UWORD uwWidth, UWORD uwHeight +) { + for(UWORD y = 0; y < uwHeight; ++y) { + for(UWORD x = 0; x < uwWidth; x += 16) { + chunkyFromPlanar16( + pBitmap, uwSrcOffsX + x, uwSrcOffsY + y, &pChunky[y*uwWidth + x] + ); + } + } +} + +void chunkyToBitmap( + const UBYTE *pChunky, tBitMap *pBitmap, + UWORD uwDstOffsX, UWORD uwDstOffsY, UWORD uwWidth, UWORD uwHeight +) { + for(UWORD y = 0; y < uwHeight; ++y) { + for(UWORD x = 0; x < uwWidth; x += 16) + chunkyToPlanar16( + &pChunky[(y*uwWidth) + x], + uwDstOffsX + x, uwDstOffsY + y, + pBitmap + ); + } +} diff --git a/src/ace/utils/dir.c b/src/ace/utils/dir.c index 4070a602..35b90148 100644 --- a/src/ace/utils/dir.c +++ b/src/ace/utils/dir.c @@ -19,7 +19,6 @@ tDir *dirOpen(const char *szPath) { systemUnuse(); return 0; } - logWrite("dirOpenOk\n"); systemUnuse(); return pDir; } @@ -34,7 +33,6 @@ UBYTE dirRead(tDir *pDir, char *szFileName, UWORD uwFileNameMax) { strncpy(szFileName, pDir->sFileBlock.fib_FileName, uwFileNameMax-1); szFileName[uwFileNameMax-1] = '\0'; - logWrite("dirReadOk %s\n", szFileName); systemUnuse(); return 1; } @@ -43,7 +41,6 @@ void dirClose(tDir *pDir) { systemUse(); UnLock(pDir->pLock); memFree(pDir, sizeof(tDir)); - logWrite("dirCloseOk\n"); systemUnuse(); } diff --git a/src/ace/utils/extview.c b/src/ace/utils/extview.c index 2b86de85..464a1a30 100644 --- a/src/ace/utils/extview.c +++ b/src/ace/utils/extview.c @@ -109,6 +109,7 @@ void viewLoad(tView *pView) { if(!pView) { g_sCopManager.pCopList = g_sCopManager.pBlankList; g_pCustom->bplcon0 = 0; // No output + g_pCustom->bplcon3 = 0; // AGA fix g_pCustom->fmode = 0; // AGA fix for(UBYTE i = 0; i < 6; ++i) { g_pCustom->bplpt[i] = 0; @@ -120,6 +121,7 @@ void viewLoad(tView *pView) { g_sCopManager.pCopList = pView->pCopList; g_pCustom->bplcon0 = (pView->pFirstVPort->ubBPP << 12) | BV(9); // BPP + composite output g_pCustom->fmode = 0; // AGA fix + g_pCustom->bplcon3 = 0; // AGA fix g_pCustom->diwstrt = 0x2C81; // VSTART: 0x2C, HSTART: 0x81 g_pCustom->diwstop = 0x2CC1; // VSTOP: 0x2C, HSTOP: 0xC1 viewUpdateCLUT(pView); diff --git a/src/ace/utils/font.c b/src/ace/utils/font.c index 26a55617..48de79a4 100644 --- a/src/ace/utils/font.c +++ b/src/ace/utils/font.c @@ -9,7 +9,7 @@ /* Functions */ -static inline UBYTE fontGlyphWidth(const tFont *pFont, char c) { +UBYTE fontGlyphWidth(const tFont *pFont, char c) { UBYTE ubIdx = (UBYTE)c; return pFont->pCharOffsets[ubIdx + 1] - pFont->pCharOffsets[ubIdx]; } @@ -17,7 +17,7 @@ static inline UBYTE fontGlyphWidth(const tFont *pFont, char c) { tFont *fontCreate(const char *szFontName) { tFile *pFontFile; tFont *pFont; - logBlockBegin("fontCreate(szFontName: %s)", szFontName); + logBlockBegin("fontCreate(szFontName: '%s')", szFontName); pFontFile = fileOpen(szFontName, "r"); if (!pFontFile) { diff --git a/src/ace/utils/palette.c b/src/ace/utils/palette.c index a2bf356d..8a1882b5 100644 --- a/src/ace/utils/palette.c +++ b/src/ace/utils/palette.c @@ -11,7 +11,7 @@ void paletteLoad(char *szFileName, UWORD *pPalette, UBYTE ubMaxLength) { tFile *pFile; UBYTE ubPaletteLength; - logBlockBegin("paletteLoad(szFileName: %s, pPalette: %p, ubMaxLength: %hu)", szFileName, pPalette, ubMaxLength); + logBlockBegin("paletteLoad(szFileName: '%s', pPalette: %p, ubMaxLength: %hu)", szFileName, pPalette, ubMaxLength); pFile = fileOpen(szFileName, "r"); fileRead(pFile, &ubPaletteLength, sizeof(UBYTE)); diff --git a/tools/src/common/bitmap.cpp b/tools/src/common/bitmap.cpp index 982081ad..2175d024 100644 --- a/tools/src/common/bitmap.cpp +++ b/tools/src/common/bitmap.cpp @@ -8,8 +8,8 @@ #include "../common/lodepng.h" #include "../common/endian.h" -tChunkyBitmap::tChunkyBitmap(uint16_t uwWidth, uint16_t uwHeight): - m_uwWidth(uwWidth), m_uwHeight(uwHeight), m_vData(m_uwWidth * m_uwHeight) +tChunkyBitmap::tChunkyBitmap(uint16_t uwWidth, uint16_t uwHeight, tRgb Bg): + m_uwWidth(uwWidth), m_uwHeight(uwHeight), m_vData(m_uwWidth * m_uwHeight, Bg) { } diff --git a/tools/src/common/bitmap.h b/tools/src/common/bitmap.h index 0e6837da..078fb980 100644 --- a/tools/src/common/bitmap.h +++ b/tools/src/common/bitmap.h @@ -23,7 +23,7 @@ class tChunkyBitmap { const tPlanarBitmap &Planar, const tPalette &vPalette ); - tChunkyBitmap(uint16_t uwWidth, uint16_t uwHeight); + tChunkyBitmap(uint16_t uwWidth, uint16_t uwHeight, tRgb Bg = tRgb(0)); tChunkyBitmap(uint16_t uwWidth, uint16_t uwHeight, const uint8_t *pData); diff --git a/tools/src/common/rgb.cpp b/tools/src/common/rgb.cpp new file mode 100644 index 00000000..2eed38e1 --- /dev/null +++ b/tools/src/common/rgb.cpp @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "rgb.h" +#include + +tRgb::tRgb(const std::string &szCode) +{ + if(szCode[0] == '#') { + if(szCode.length() == 3 + 1) { + this->ubR = std::stoul(szCode.substr(1, 1), nullptr, 16); + this->ubG = std::stoul(szCode.substr(2, 1), nullptr, 16); + this->ubB = std::stoul(szCode.substr(3, 1), nullptr, 16); + } + else if(szCode.length() == 6 + 1) { + this->ubR = std::stoul(szCode.substr(1, 2), nullptr, 16); + this->ubG = std::stoul(szCode.substr(3, 2), nullptr, 16); + this->ubB = std::stoul(szCode.substr(5, 2), nullptr, 16); + } + else { + throw std::runtime_error("Can't convert color code"); + } + } +} diff --git a/tools/src/common/rgb.h b/tools/src/common/rgb.h index 2623f78d..5fbaba2a 100644 --- a/tools/src/common/rgb.h +++ b/tools/src/common/rgb.h @@ -5,7 +5,8 @@ #ifndef _ACE_TOOLS_COMMON_RGB_H_ #define _ACE_TOOLS_COMMON_RGB_H_ -#include +#include +#include struct tRgb { uint8_t ubR, ubG, ubB; @@ -19,6 +20,8 @@ struct tRgb { tRgb(): ubR(0), ubG(0), ubB(0) { } + tRgb(const std::string &szCode); + bool operator == (const tRgb &Rhs) const { return ubB == Rhs.ubB && ubG == Rhs.ubG && ubR == Rhs.ubR; } diff --git a/tools/src/font_conv.cpp b/tools/src/font_conv.cpp index d007fdc7..7d743495 100644 --- a/tools/src/font_conv.cpp +++ b/tools/src/font_conv.cpp @@ -36,7 +36,7 @@ void printUsage(const std::string &szAppName) { print("\tfnt\tACE font file\n"); print("extraOpts:\n"); // -chars - print("\t-chars \"AB D\"\tInclude only 'A', 'B', ' ' and 'D' chars in font.\n"); + print("\t-chars \"AB D\"\tInclude only 'A', 'B', ' ' and 'D' chars in font. Only for TTF input.\n"); print("\t\t\tUse backslash (\\) to escape quote (\") char inside charset specifier\n"); print("\t\t\tDefault charset is: \"{}\"\n", s_szDefaultCharset); // -out @@ -140,6 +140,7 @@ int main(int lArgCount, const char *pArgs[]) } else { nLog::error("Unsupported output type"); + return 1; } } fmt::print("All done!\n"); diff --git a/tools/src/tileset_conv.cpp b/tools/src/tileset_conv.cpp index ecc6a183..38e5deb4 100644 --- a/tools/src/tileset_conv.cpp +++ b/tools/src/tileset_conv.cpp @@ -80,9 +80,9 @@ int main(int lArgCount, const char *pArgs[]) for(uint16_t i = 0; i < 256; ++i) { auto Tile = tChunkyBitmap::fromPng(fmt::format("{}/{}.png", szInPath, i)); if(Tile.m_uwHeight != 0) { - vTiles.push_back(std::move(Tile)); wLastFull = i; } + vTiles.push_back(std::move(Tile)); } vTiles.resize(wLastFull + 1); } @@ -96,7 +96,12 @@ int main(int lArgCount, const char *pArgs[]) fmt::print("Read {} tiles from '{}'\n", uwTileCount, szInPath); std::string szOutExt = nFs::getExt(szOutPath); if(szOutExt == "png" || szOutExt == "bm") { - tChunkyBitmap Out(lTileSize, uwTileCount * lTileSize); + tRgb Bg; + if(Palette.m_vColors.size()) { + Bg = Palette.m_vColors.at(0); + } + fmt::print("Using color for bg: {} {} {}\n", Bg.ubR, Bg.ubG, Bg.ubB); + tChunkyBitmap Out(lTileSize, uwTileCount * lTileSize, Bg); for(uint16_t i = 0; i < uwTileCount; ++i) { auto &Tile = vTiles.at(i); if(Tile.m_uwHeight != 0) {