diff --git a/.gitignore b/.gitignore index 2abc91f..508246c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,8 @@ # ---> C # Prerequisites -*.d +# *.d +build/ # Object files *.o diff --git a/README.md b/README.md index 0fa4761..898f6e6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,11 @@ # dusk -DUsK, a library for gba dev +**dusk**, a library for gba dev + +supported toolchains: +- DevkitARM/C/C++ (version 0.1.x), [view](https://github.com/redthing1/dusk/tree/lang_c) +- DevkitARM/D (version 0.2+) [view](https://github.com/redthing1/dusk/tree/d-port) ## example @@ -11,14 +15,14 @@ DUsK, a library for gba dev ## features -+ simple, intuitive C API ++ simple, intuitive C/D API + library integration + built in support for TONC, GBFS + graphics + scene architecture + 8bpp texture atlas packing + sprite/animation helpers - + tiled map exporter and loader (via Tiled2GBA) + + tiled map exporter and loader + (WIP) saves ## hacking diff --git a/src/dusk/Makefile b/src/dusk/Makefile index 9053804..682d204 100644 --- a/src/dusk/Makefile +++ b/src/dusk/Makefile @@ -3,7 +3,7 @@ # LIBNAME := dusk -VERSION := 0.1.7 +VERSION := 0.2.0 #--------------------------------------------------------------------------------- .SUFFIXES: @@ -18,7 +18,7 @@ endif include $(DEVKITARM)/gba_rules BUILD := build -SRCDIRS := src src/contrib +SRCDIRS := c_src c_src/contrib INCDIRS := include include/contrib DEPFLAGS := -I$(DEVKITPRO)/libtonc/include -L$(DEVKITPRO)/libtonc/lib -ltonc @@ -33,6 +33,10 @@ IARCH := -mthumb-interwork -marm bTEMPS := 0 # Save gcc temporaries (.i and .s files) # DEBUG := 0 # Generate debug info +# get revision id from git +GITVERSION_ID := $(shell printf "r%s" "$(shell git rev-parse --short HEAD)") +$(info build id: $(GITVERSION_ID)) + #--------------------------------------------------------------------------------- # Options for code generation #--------------------------------------------------------------------------------- @@ -46,8 +50,13 @@ ifeq ($(DEBUG),1) CBASE += -g -DDEBUG endif -DEFINES = -DGBA -DDUSK_VERSION=\"$(GITVERSION)\" -CBASE += $(DEFINES) +# add define for gba +EXTRA_DEFINES := -DGBA + +# add EXTRA_DEFINES for version and git version +EXTRA_DEFINES += -DVERSION_ID_DEF="\"$(VERSION)\"" -DLIB_BUILD_ID_DEF="\"$(GITVERSION_ID)\"" + +CBASE += $(EXTRA_DEFINES) RCFLAGS := $(CBASE) $(RARCH) ICFLAGS := $(CBASE) $(IARCH) -mlong-calls #-fno-gcse @@ -130,6 +139,10 @@ $(TARGET): $(OFILES) @echo $(notdir $<) $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(RCFLAGS) -c $< -o $@ +%.o : %.s + @echo $(notdir $<) + $(CC) -MMD -MP -MF $(DEPSDIR)/$*.d $(RCFLAGS) -c $< -o $@ + -include $(DEPENDS) endif diff --git a/src/dusk/c_src/contrib/gbamap.c b/src/dusk/c_src/contrib/gbamap.c new file mode 100644 index 0000000..c79545c --- /dev/null +++ b/src/dusk/c_src/contrib/gbamap.c @@ -0,0 +1,216 @@ +#include +#include "gbamap.h" + +typedef unsigned char u8, byte; +typedef unsigned short u16, hword; +typedef unsigned int u32, word; +typedef unsigned long long u64; + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; + +typedef volatile u8 vu8; +typedef volatile u16 vu16; +typedef volatile u32 vu32; +typedef volatile u64 vu64; + +typedef volatile s8 vs8; +typedef volatile s16 vs16; +typedef volatile s32 vs32; +typedef volatile s64 vs64; + +#define INLINE static inline +#define ALIGN(n) __attribute__((aligned(n))) + +#define TRUE 1 +#define FALSE 0 + +/** + * Defines the general memory locations. + */ + +#define MEMORY_IO 0x04000000 +#define MEMORY_PALETTE 0x05000000 +#define MEMORY_VIDEORAM 0x06000000 +#define MEMORY_OBJECT_ATTRIBUTES 0x07000000 + +#define REGISTER_BASE MEMORY_IO + +#define BIT_FIELD_PREP(x, name) (((x) << name##_SHIFT) & name##_MASK) +#define BIT_FIELD_GET(y, name) (((y)&name##_MASK) >> name##_SHIFT) +#define BIT_FIELD_SET(y, x, name) (y = ((y) & ~name##_MASK) | BIT_FIELD_PREP(x, name)) + +typedef u16 Color; + +#define SCREEN_WIDTH 240 +#define SCREEN_HEIGHT 160 + +#define REGISTER_DISPLAY_CONTROL *(vu32*)(REGISTER_BASE + 0x0000) +#define REGISTER_VERTICAL_COUNT *(vu16*)(REGISTER_BASE + 0x0006) + +#define FLAG_MODE0 0 + +/** + * Wait till the background has been rendered and it is safe to modify it. + **/ +INLINE void videoSync() { + while (REGISTER_VERTICAL_COUNT >= 160) + ; + while (REGISTER_VERTICAL_COUNT < 160) + ; +} + +typedef u16 ScreenEntry; + +typedef struct { + u32 data[8]; +} Tile; + +typedef ScreenEntry ScreenBlock[1024]; +typedef Tile CharBlock[512]; + +#define MEMORY_BACKGROUND_PALETTE ((Color*)MEMORY_PALETTE) +#define MEMORY_BACKGROUND_PALETTE_SIZE 0x00200 + +#define MEMORY_SCREEN_BLOCK ((ScreenBlock*)MEMORY_VIDEORAM) +#define MEMORY_CHAR_BLOCK ((CharBlock*)MEMORY_VIDEORAM) + +#define REGISTER_BACKGROUND_CONTROL ((vu16*)(REGISTER_BASE + 0x0008)) +#define REGISTER_BACKGROUND_OFFSET ((BackgroundPoint*)(REGISTER_BASE + 0x0010)) + +#define FLAG_BACKGROUND_4BPP 0 +#define FLAG_BACKGROUND_8BPP 0x0080 +#define FLAG_BACKGROUND_REGULAR_32x32 0 +#define FLAG_BACKGROUND_REGULAR_64x32 0x4000 +#define FLAG_BACKGROUND_REGULAR_32x64 0x8000 +#define FLAG_BACKGROUND_REGULAR_64x64 0xC000 + +#define MASK_FLAG_BACKGROUND_CHAR_BLOCK 0x000C +#define SHIFT_FLAG_BACKGROUND_CHAR_BLOCK 2 +#define FLAG_BACKGROUND_CHAR_BLOCK(n) ((n) << SHIFT_FLAG_BACKGROUND_CHAR_BLOCK) + +#define MASK_FLAG_BACKGROUND_SCREEN_BLOCK_MASK 0x1F00 +#define SHIFT_FLAG_BACKGROUND_SCREEN_BLOCK 8 +#define FLAG_BACKGROUND_SCREEN_BLOCK(n) ((n) << SHIFT_FLAG_BACKGROUND_SCREEN_BLOCK) + +#define FLAG_BACKGROUND(n) ((0x0100) << n) +#define FLAG_BACKGROUND_PRIORITY(n) ((n * 1) & 0x0003) + +void map_init_registers() { + // turn off all backgrounds + for (u32 layerIndex = MAX_LAYERS; layerIndex-- > 0;) { + REGISTER_BACKGROUND_CONTROL[layerIndex] = 0; + } + + // reset display control + REGISTER_DISPLAY_CONTROL = 0; +} + +Map map_load_from_rom(const u16* map_data) { + Map map; + u16 index = 0; + + map.sizeFlag = map_data[index++]; + + map.paletteLength = map_data[index++]; + map.palette = &map_data[index]; + index += map.paletteLength + 1; + + map.tileSetLength = map_data[index++]; + map.tileSet = &map_data[index]; + index += map.tileSetLength + 1; + + map.terrainMapLength = map_data[index++]; + map.terrainMap = &map_data[index]; + index += map.terrainMapLength; + + map.numLayers = map_data[index++]; + map.numLayers = map.numLayers > MAX_LAYERS ? MAX_LAYERS : map.numLayers; + map.tileMapLength = map_data[index++]; + for (u32 layerIndex = 0; layerIndex < map.numLayers; ++layerIndex) { + map.tileMapLayers[layerIndex] = &map_data[index]; + index += map.tileMapLength; + } + + u16 lengthObjectData = map_data[index++]; + u32 endObjectData = index + lengthObjectData; + u32 objectCount = 0; + while (index != endObjectData) { + MapObject object = map_load_object(map_data, &index); + map.objects[objectCount] = object; + objectCount++; + } + map.numObjects = objectCount; + + return map; +} + +MapObject map_load_object(const u16* object_data, u16* index) { + MapObject object; + object.id = map_load_object_id(object_data, index); + object.position = map_load_object_position(object_data, index); + object.name = map_load_string(object_data, index); + object.type = map_load_string(object_data, index); + return object; +} + +u32 map_load_object_id(const u16* idData, u16* index) { + u32 upperID = map_pop_value(idData, index); + u32 lowerID = map_pop_value(idData, index); + return (upperID << 16) | lowerID; +} + +ObjectPoint map_load_object_position(const u16* positionData, u16* index) { + ObjectPoint position; + position.x = map_pop_value(positionData, index); + position.y = map_pop_value(positionData, index); + return position; +} + +const char* map_load_string(const u16* stringData, u16* index) { + u16 length = map_pop_value(stringData, index); + const char* string = (const char*)&stringData[*index]; + *index += length; + return string; +} + +u16 map_pop_value(const u16* data, u16* index) { + u16 value = data[*index]; + *index += 1; + return value; +} + +void map_set_onscreen(Map map) { + memcpy(MEMORY_BACKGROUND_PALETTE, map.palette, map.paletteLength * 2); + memcpy(&MEMORY_CHAR_BLOCK[0][0], map.tileSet, map.tileSetLength * 2); + + u32 screenBlockStep = map.tileMapLength / ENTRIES_IN_SCREEN_BLOCK; + u32 usedBackgrounds = 0x00; + for (u32 layerIndex = map.numLayers; layerIndex-- > 0;) { + u32 screenBlockIndex = NUM_SCREEN_BLOCKS - screenBlockStep * (layerIndex + 1); + memcpy(&MEMORY_SCREEN_BLOCK[screenBlockIndex][0], map.tileMapLayers[layerIndex], map.tileMapLength * 2); + + REGISTER_BACKGROUND_CONTROL[layerIndex] |= + FLAG_BACKGROUND_CHAR_BLOCK(0) | FLAG_BACKGROUND_SCREEN_BLOCK(screenBlockIndex) | FLAG_BACKGROUND_8BPP | + map.sizeFlag | FLAG_BACKGROUND_PRIORITY(map.numLayers - layerIndex); + usedBackgrounds |= FLAG_BACKGROUND(layerIndex); + } + + REGISTER_DISPLAY_CONTROL |= FLAG_MODE0 | usedBackgrounds; +} + +void map_shift(Map map, BackgroundPoint offset) { + for (u16 layer = 0; layer < map.numLayers; layer++) + map_shift_layer(layer, offset); +} + +void map_shift_layer(u16 layer, BackgroundPoint offset) { REGISTER_BACKGROUND_OFFSET[layer] = offset; } + +void map_shift_objects(MapObject* objects, ObjectPoint shift, u32 count) { + for (u32 index = 0; index < count; index++) { + objects[index].position.x -= shift.x; + objects[index].position.y -= shift.y; + } +} \ No newline at end of file diff --git a/src/dusk/src/contrib/libgbfs.c b/src/dusk/c_src/contrib/libgbfs.c similarity index 100% rename from src/dusk/src/contrib/libgbfs.c rename to src/dusk/c_src/contrib/libgbfs.c diff --git a/src/dusk/src/contrib/mgba.c b/src/dusk/c_src/contrib/mgba.c similarity index 74% rename from src/dusk/src/contrib/mgba.c rename to src/dusk/c_src/contrib/mgba.c index cb3c2e4..bcf3b46 100644 --- a/src/dusk/src/contrib/mgba.c +++ b/src/dusk/c_src/contrib/mgba.c @@ -1,7 +1,10 @@ #include "contrib/mgba.h" +int mgba_is_open = 0; + #ifdef DEBUG void mgba_printf(int level, const char* ptr, ...) { + if (!mgba_is_open) return; va_list args; level &= 0x7; va_start(args, ptr); @@ -12,7 +15,11 @@ void mgba_printf(int level, const char* ptr, ...) { BOOL mgba_open(void) { *REG_DEBUG_ENABLE = 0xC0DE; - return *REG_DEBUG_ENABLE == 0x1DEA; + if (*REG_DEBUG_ENABLE == 0x1DEA) { + mgba_is_open = 1; + return TRUE; + } + return FALSE; } void mgba_close(void) { *REG_DEBUG_ENABLE = 0; } diff --git a/src/dusk/c_src/contrib/posprintf.h b/src/dusk/c_src/contrib/posprintf.h new file mode 100755 index 0000000..def0909 --- /dev/null +++ b/src/dusk/c_src/contrib/posprintf.h @@ -0,0 +1,196 @@ +/* + +posprintf - a condensed version of sprintf for Thumb, esp. GBA +Copyright (C) 2003 Dan Posluns + +The person or persons who have associated work with this document (the "Dedicator" or "Certifier") hereby either (a) +certifies that, to the best of his knowledge, the work of authorship identified is in the public domain of the country +from which the work is published, or (b) hereby dedicates whatever copyright the dedicators holds in the work of +authorship identified below (the "Work") to the public domain. A certifier, moreover, dedicates any copyright interest +he may have in the associated work, and for these purposes, is described as a "dedicator" below. + +A certifier has taken reasonable steps to verify the copyright status of this work. Certifier recognizes that his good +faith efforts may not shield him from liability if in fact the work certified is not in the public domain. + +Dedicator makes this dedication for the benefit of the public at large and to the detriment of the Dedicator's heirs and +successors. Dedicator intends this dedication to be an overt act of relinquishment in perpetuity of all present and +future rights under copyright law, whether vested or contingent, in the Work. Dedicator understands that such +relinquishment of all rights includes the relinquishment of all rights to enforce (by lawsuit or otherwise) those +copyrights in the Work. + +Dedicator recognizes that, once placed in the public domain, the Work may be freely reproduced, distributed, +transmitted, used, modified, built upon, or otherwise exploited by anyone for any purpose, commercial or non-commercial, +and in any way, including by methods that have not yet been invented or conceived. + +Author contact e-mail: dan at danposluns dot com + + +INSTRUCTIONS: + +To call: posprintf(char *dest, const char *src[, param1[, param2[, ... paramN]]]); + +- src must be a valid zero-terminated C string. +- dest must point to a sufficiently large block of memory to contain the result string. + +The following format specifiers are valid: + +%% - print a '%' symbol +%s - print a string; parameter must point to a valid zero-terminated C string +%d - print a 16-bit (short) integer; must be within [-65,535 .. 65,535] +%l - print a 29-bit integer; approximate range [-500,000,000 .. 500,000,000] +%x - print a hexadecimal number (lowercase digits) +%X - print a hexadecimal number (uppercase digits) + +The specifiers %d, %l, %x and %X may be modified as follows: + +- Digits 1 through 9 indicate number of leading spaces to print, eg. + %5d would print the number 123 as " 123" + %5d would print the number 123456 as "123456" (no leading spaces) +- When above digit is prefixed with 0, leading zeros are printed instead of spaces + %05d would print the number 123 as "00123" + %04d would print the number 12345 as "12345" (no leading zeros) +- Negative sign consumes a leading space, eg. + %05d would print the number -123 as "-0123" + (Hexadecimal numbers are considered unsigned) + +IF YOU WANT MORE FUNCTIONALITY THAN THIS, YOU CAN FEEL FREE TO MODIFY THE CODE, +BUT THEN I WOULD SUGGEST MOVING TO A MORE SOPHISTICATED LIBRARY ANYWAY. + +*** CAUTION IF NOT USED ON GAMEBOY ADVANCE *** +Although this is mostly written as general Thumb code, the %l (29-bit print) +specifier code currently uses a software interrupt (SWI) specific to the +Gameboy Advance to perform a division. If you wish to port this to other ARM +machines, you may need to alter this code. I believe that most ARM machines +support SWI 7 as an alternative software divide, although you will have to +swap the numerator/denominator registers (r0 and r1). +*** END CAUTION *** + +My contact e-mail is: dan at danposluns dot com + +*/ + +/* +posprintf Documentation + +What is it? + +posprintf is a function you can call in your Gameboy Advance programs to generate strings. It is basically a somewhat +amputated version of the standard C library function, sprintf. + +Why use it? + +Probably the most significant use of it is to print out and format numbers for display on the screen. In order to do +this, the numbers need to be converted from their internal representation (base 2) to decimal (base 10). posprintf uses +an extremely efficient algorithm scammed off of the 'net to do this, and it is written entirely in Thumb assembler to +run very quickly (without consuming the internal memory needed to run efficiently in ARM mode). + +Other reasons to use it include that it's fast, extremely flexible for most GBA applications, and absolutely free. I +wouldn't say no to a credit if it is used in an application, though, commercial or otherwise. + +How do I use it? + + Include the file posprintf.h in your C source code that you want to call the function. (ie. #include "posprintf.h") + + Call it the same way you would call sprintf, keeping in mind the differences between the two (see the next section). + + Make sure to link the file posprintf.o with your project. Generally this just means including posprintf.o on the +command line when you call gcc. + +That's all there is to it. + +How do I call the function? + +The syntax is as follows: + + posprintf(char *dest, const char *src[, param1[, param2[, ... paramN]]]); + + dest is the address of the string to be printed out to. IMPORTANT: There must be sufficient memory allocated to the +buffer to hold the string, including the terminating zero. + + src is the address of the source string to print. This absolutely must be a valid, zero-terminated C string. + + The optional parameters accompany any format specifiers used in the source string. + +Format Specifiers + +The following are valid format specifiers for use with posprintf: + + %% - print a % character + %s - print a string. The accompanying parameter must be a valid, zero-terminated C string. + %d - print an integer. Important: unlike sprintf, this is only accurate for 16 bits of data, or numbers ranging from +-65,535 to 65,535. %l - print a long integer. Important: unlike sprintf this is only accurate for approximately 29 bits +of data, or numbers ranging from about -500 million to 500 million. %x - print in hexadecimal format. Provided mostly as +a programming tool, since few user applications would probably ever want to print hexadecimal numbers. %X - same as %x, +but prints capital letters for the digits 'a' through 'f'. + +Output Control + +The output of %d, %l, %x and %X tags may optionally be influenced by the following prefixes: + + Digits 1 through 9: Indicate how many leading spaces to include. Examples: + + %5d would print the number 123 as " 123" + %3d would print the number 12345 as "12345" (no leading spaces) + + Digit 0: When prefixing the above number, indicates to print leading zeros instead of leading spaces. Examples: + + %05d would print the number 123 as "00123" + %03d would print the number 12345 as "12345" (no leading zeros) + +Note: If the number printed is negative, then the negative sign will consume a leading space/zero, if there are any. + +Other Notes + +Optimized for GBA development + +One of the big realizations in understanding this code is that few GBA games need to display numbers larger than 65,535, +and when they do these are the minority of numbers, not the majority. The %d specifier is highly optimized to work with +16 bits, and you should use it whenever possible. + +For the minority of occasions when you need to display more than 16 bits worth of numerical data, %l works fine to +numbers well beyond the plus-or-minus 500 million mark. (The actual limit is +/- 655,359,999.) It takes about twice as +long to run as %d, though, and includes a slow SWI call to split the number into two chunks, so you should still use %d +instead whenever you can. + +If you need to display numbers larger than 500 million, then you will either have to heavily alter the code, use a +different utility, or break your number up into sizeable chunks. If you do need to display larger numbers than 500 +million for a GBA game, though, you may want to rethink your game design. + +What about other ARM machines? + +Although posprintf is mostly written as generic Thumb code, the %l (29-bit print) specifier code currently uses a +software interrupt (SWI) specific to the Gameboy Advance to perform a division. If you wish to port this to other ARM +machines, you may need to alter this code. I believe that most ARM machines support SWI 7 as an alternative software +divide, although you will have to swap the numerator/denominator registers (r0 and r1). + +Can't you optimize out the SWI call? Use inverse multiplication, register shifting, or somesuch? + +Not easily. Not in Thumb mode, anyway, which doesn't have the 64-bit multiply instruction. The number has many +significant digits, and is being divided by 10,000, which requires two registers to keep things accurate. My best advice +is to avoid it in the first place by keeping your numbers small and using %d instead, but also not to fret over using %l +as the SWI is only issued once in the entire routine, and everything else is still quite zippy. It is not like you will +have to call it a bazillion times per frame, and it's still a helluva lot faster than what the standard library sprintf +does. If anyone does feel like optimizing this, though, please send me the results. + +If it's displaying 16-bit numbers and they are signed, shouldn't they only be in the range +/- 32767? + +The conversion to base 10 is actually done on the number unsigned, so you get a full range up to 65,535. The sign is +taken from the extension of the number to 32 bits, which happens automatically regardless of whether you pass a short or +not. The same applies to %l. + +What are the terms and restrictions to using posprintf? + +posprintf no longer has a license; it is freely available to use as part of the public domain. + +Why "posprintf"? + +I think the "po" stood for something originally, but now the "pos" is just a play on my last name. Please, no P.O.S. +jokes. :) +*/ + +#ifndef _PSPRINTF_HEADER_ +#define _PSPRINTF_HEADER_ + +extern void posprintf(char*, const char*, ...); + +#endif diff --git a/src/dusk/c_src/contrib/posprintf.s b/src/dusk/c_src/contrib/posprintf.s new file mode 100755 index 0000000..467167e --- /dev/null +++ b/src/dusk/c_src/contrib/posprintf.s @@ -0,0 +1,420 @@ +/* + +posprintf - a condensed version of sprintf for Thumb, esp. GBA +Copyright (C) 2003 Dan Posluns + +The person or persons who have associated work with this document (the "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of his knowledge, the work of authorship identified is in the public domain of the country from which the work is published, or (b) hereby dedicates whatever copyright the dedicators holds in the work of authorship identified below (the "Work") to the public domain. A certifier, moreover, dedicates any copyright interest he may have in the associated work, and for these purposes, is described as a "dedicator" below. + +A certifier has taken reasonable steps to verify the copyright status of this work. Certifier recognizes that his good faith efforts may not shield him from liability if in fact the work certified is not in the public domain. + +Dedicator makes this dedication for the benefit of the public at large and to the detriment of the Dedicator's heirs and successors. Dedicator intends this dedication to be an overt act of relinquishment in perpetuity of all present and future rights under copyright law, whether vested or contingent, in the Work. Dedicator understands that such relinquishment of all rights includes the relinquishment of all rights to enforce (by lawsuit or otherwise) those copyrights in the Work. + +Dedicator recognizes that, once placed in the public domain, the Work may be freely reproduced, distributed, transmitted, used, modified, built upon, or otherwise exploited by anyone for any purpose, commercial or non-commercial, and in any way, including by methods that have not yet been invented or conceived. + +Author contact e-mail: dan at danposluns dot com + + +register map: + +MAIN LOOP: PROCESS16: +r0 <- dest string address r0 <- d0 +r1 <- source string address r1 <- d1 +r2 <- integer to print r2 <- d2 +r3 <- r3 <- d3 +r4 <- current char r4 <- d4 +r5 <- r5 <- work register +r6 <- r6 <- work register +r7 <- r7 <- dest string address +r8 <- number of digits to print r8 <- number of digits to print +r9 <- leading char (' ' or '0') r9 <- leading char (' ' or '0') +r10 <- current parameter pointer r10 <- current parameter ptr +r11 <- r11 <- +r12 <- r12 <- source string address +r14 <- r14 <- lr + +Function parameters: + +r0 <- destination string address +r1 <- source string address +r2 <- param1 +r3 <- param2 + +*/ + + .thumb + .thumb_func + .align + .global posprintf + .type posprintf,function +posprintf: + + push {r3} @ push our second and third parameters + push {r2} @ onto the stack in reverse order + mov r12, sp @ r12 <- first parameter pointer + + push {r4-r7} @ save clobbered registers + mov r4, r8 + mov r5, r9 + mov r6, r10 + push {r4-r6, lr} + mov r10, r12 @ r10 <- first parameter pointer + +.L_STRINGLOOP: + ldrb r4, [r1] @ load a char from r1 + add r1, #1 @ advance pointer to next char + cmp r4, #'%' @ if char == '%' then + beq .L_FORMATENTRY @ handle the format specifier + strb r4, [r0] @ store the char back to memory + add r0, #1 @ advance pointer to next char + cmp r4, #0 @ if char != 0 then + bne .L_STRINGLOOP @ repeat for next char + @ cleanup and exit + pop {r4-r7} @ restore clobbered registers + mov r8, r4 + mov r9, r5 + mov r10, r6 + mov lr, r7 + pop {r4-r7} + add sp, #8 @ remove parameters from stack + bx lr @ return from subroutine + +.L_FORMATENTRY: + mov r5, #0 @ assume no leading character for numbers + mov r6, #' ' @ assume print spaces if we do print leads + mov r8, r5 + mov r9, r6 +.L_FORMATSPEC: + ldrb r4, [r1] @ load the next char from r1 + add r1, #1 @ advance pointer to next char + cmp r4, #'d' @ if char == 'd' + beq .L_PRINT16 @ print 16-bit number + cmp r4, #'s' @ if char == 's' + beq .L_PRINTSTR @ print string + cmp r4, #'0' @ if char == '0' + beq .L_SETLEAD @ print with leading zeros + cmp r4, #'%' @ if char == '%' + beq .L_PRINTSYMBOL @ print '%' character + cmp r4, #'l' @ if char == 'l' + beq .L_PRINT29 @ print 29-bit number + cmp r4, #'X' @ if char == 'X' + beq .L_PRINTHEXUC @ print hexadecimal uppercase + cmp r4, #'x' @ if char == 'x' + beq .L_PRINTHEXLC @ print hexadecimal lowercase + @ we now assume that we are choosing a number of leading digits to display + sub r4, #'0' + mov r8, r4 @ r8 <- char - '0' + b .L_FORMATSPEC + +.L_SETLEAD: + mov r6, #'0' + mov r9, r6 @ print leading zeros instead of spaces + b .L_FORMATSPEC + +.L_PRINTSYMBOL: + strb r4, [r0] @ store '%' symbol to memory + add r0, #1 @ advance pointer to next char + b .L_STRINGLOOP + +.L_PRINTSTR: + mov r4, r10 @ r4 <- current parameter pointer + ldr r2, [r4] @ r2 <- address of string to print + add r4, #4 + mov r10, r4 @ increase parameter pointer +.L_PRINTSTRLOOP: + ldrb r4, [r2] @ load a char from r2 + add r2, #1 @ advance pointer to next char + cmp r4, #0 @ if char == 0 + beq .L_STRINGLOOP @ then we are done + strb r4, [r0] @ store the char back to memory + add r0, #1 @ advance pointer to next char + b .L_PRINTSTRLOOP + +.L_PRINT16: + mov r7, r0 @ r7 <- dest string address + mov r4, r10 @ r4 <- current parameter pointer + ldr r0, [r4] @ r0 <- 16-bit integer to print + add r4, #4 + mov r10, r4 @ increase parameter pointer + mov r3, #0 @ temp marker for L_PRINTSIGN + cmp r0, #0 @ if integer to print is negative + blt .L_PRINTSIGN @ print the sign and adjust +.L_SIGNDONE: + mov lr, pc @ save this location + bl .L_PROCESS16 @ process a 16-bit number + b .L_STRINGLOOP @ return when done + +.L_PRINTSIGN: + mov r4, #'-' + strb r4, [r7] @ print '-' character + add r7, #1 @ advance pointer to next char + neg r0, r0 @ r2 is now positive + mov r4, r8 + sub r4, #1 @ print one fewer character + mov r8, r4 @ r8 <- new value + cmp r3, #0 @ check to see who called us + beq .L_SIGNDONE + b .L_SIGN29DONE + +.L_PRINT29: + mov r7, r0 @ r7 <- dest string address + mov r4, r10 @ r4 <- current parameter pointer + ldr r0, [r4] @ r0 <- 16-bit integer to print + add r4, #4 + mov r10, r4 @ increase parameter pointer + mov r3, #1 @ temp marker for L_PRINTSIGN + cmp r0, #0 @ if integer to print is negative + blt .L_PRINTSIGN @ print the sign and adjust +.L_SIGN29DONE: + mov r12, r1 + mov r1, #0x27 + lsl r1, r1, #8 + add r1, #0x10 @ r1 <- 0x2710 == 10000 + swi 6 @ split number by dividing by 10000 + mov r3, #0 + sub r3, #4 + add r8, r3 @ subtract 4 from digits to display + cmp r0, #0 @ if the first chunk is empty + beq .L_P29SKIP @ then skip it + push {r1} @ save the second number to display + mov r1, r12 + mov lr, pc @ save this location + bl .L_PROCESS16 @ process a 16-bit number + mov r12, r1 + pop {r1} @ load in the second number + mov r3, #0 + mov r8, r3 @ print leading symbols now! + mov r3, #'0' + mov r9, r3 @ make sure they are zeros! +.L_P29SKIP: + mov r0, r1 @ get ready to print second number + mov r1, #4 + add r8, r1 @ add 4 back on to digits + mov r1, r12 + mov lr, pc @ save this location + bl .L_PROCESS16 @ process a 16-bit number + b .L_STRINGLOOP + +.L_PRINTHEXLC: + mov r7, #39 + mov r12, r7 @ lowercase offset + b .L_PRINTHEX +.L_PRINTHEXUC: + mov r7, #7 + mov r12, r7 @ uppercase offset +.L_PRINTHEX: + mov r4, r10 @ r4 <- current parameter pointer + ldr r2, [r4] @ r2 <- integer to print + add r4, #4 + mov r10, r4 @ increase parameter pointer + mov r4, #28 @ r4 <- 8 digits to cycle through + mov r6, #0xF @ r6 <- nibble mask + mov r7, #0 @ r7 <- print flag +.L_PRINTHEXLOOP: + mov r3, r2 + lsr r3, r4 + and r3, r6 @ r3 <- (n >> (cycle * 4)) & 0xF + orr r7, r3 @ if we have not encountered a digit + beq .L_PH_LEADZERO @ then it is a leading zero + add r3, #'0' + mov r5, r12 @ get ready to print a letter + cmp r3, #'9' @ if the digit is in the alpha range + bgt .L_PH_ALPHA @ then print a letter + mov r5, #0 @ else do nothing +.L_PH_ALPHA: + add r3, r5 @ add offset to correct letter + strb r3, [r0] @ store the char in memory + add r0, #1 @ advance pointer to next char + sub r4, #4 @ advance to next digit + bge .L_PRINTHEXLOOP @ loop until done + b .L_STRINGLOOP + +.L_PH_LEADZERO: + lsr r5, r4, #2 @ r5 <- which digit we are on + sub r4, #4 @ if this is our last digit + blt .L_PH_FINAL @ then print a zero for sure + cmp r8, r5 @ if r8 < current digit + ble .L_PRINTHEXLOOP @ then keep looping + mov r5, r9 @ r5 <- leading symbol to print + strb r5, [r0] @ store the char in memory + add r0, #1 @ advance pointer to next char + b .L_PRINTHEXLOOP +.L_PH_FINAL: + mov r3, #'0' @ if n == 0, print at least one 0 + strb r3, [r0] + add r0, #1 + b .L_STRINGLOOP + +.L_PROCESS16: + mov r12, r1 @ free up registers + mov r5, #0xF + lsr r1, r0, #4 + lsr r2, r0, #8 + lsr r3, r0, #12 + and r0, r5 @ r0 <- n & 0xF + and r1, r5 @ r1 <- (n >> 4) & 0xF + and r2, r5 @ r2 <- (n >> 8) & 0xF + and r3, r5 @ r3 <- (n >> 12) & 0xF + mov r6, r3 + add r6, r2 + add r6, r1 + lsl r5, r6, #2 + lsl r6, r6, #1 + add r0, r6 + add r0, r5 @ r0 <- 6 * (d3 + d2 + d1) + d0 + @ divide by ten: multiply by 0x19A shifted right by 12 + lsr r5, r0, #2 + add r5, r0 + lsr r5, r5, #1 @ r5 <- ((d0 >> 2) + i) >> 1 + add r5, r0 + lsr r5, r5, #3 @ r5 = (r5 + d0) >> 3 + add r5, r0 + lsr r5, r5, #1 @ r5 = (r5 + d0) >> 1 + add r5, r0 + lsr r5, r5, #4 @ r5 <- d0 / 10 + @ calculate remainder as d0 + lsl r6, r5, #2 + add r6, r5 + lsl r6, r6, #1 @ r6 <- q * 10 + sub r0, r6 @ r0 <- d0 - (q * 10) + @ finished with d0, now calculate d1 + lsl r6, r3, #3 + add r5, r6 + add r5, r3 @ r5 <- q + 9 * d3 + lsl r6, r2, #2 + add r5, r6 + add r5, r2 @ r5 <- q + 9 * d3 + 5 * d2 + add r1, r5 @ r1 <- d1 + r5 + beq .L_LEAD_D1 + @ divide d1 by ten: multiply by 0x19A shifted right by 12 + lsr r5, r1, #2 + add r5, r1 + lsr r5, r5, #1 + add r5, r1 + lsr r5, r5, #3 + add r5, r1 + lsr r5, r5, #1 + add r5, r1 + lsr r5, r5, #4 @ r5 <- d1 / 10 + @ calculate remainder as d1 + lsl r6, r5, #2 + add r6, r5 + lsl r6, r6, #1 + sub r1, r6 @ r1 <- d1 - (q * 10) + @ finished with d1, now calculate d2 + lsl r2, r2, #1 + add r2, r5 @ r2 <- 2 * d2 + q + mov r5, r2 + orr r5, r3 @ if (!d2) && (!d3) + beq .L_LEAD_D2 @ then skip + @ divide d2 by ten: multiply by 0x1A >> 8 is sufficient + lsr r5, r2, #2 + add r5, r2 + lsr r5, r5, #1 + add r5, r2 + lsr r5, r5, #4 @ r5 <- d2 / 10 + @ calculate remainder as d2 + lsl r6, r5, #2 + add r6, r5 + lsl r6, r6, #1 + sub r2, r6 @ r2 <- d2 - (q * 10) + @ finished with d2, now calculate d3 + lsl r3, r3, #2 + add r3, r5 + beq .L_LEAD_D3 + @ divide d3 by ten: multiply by 0x1A >> 8 is sufficient + lsr r5, r3, #2 + add r5, r3 + lsr r5, r5, #1 + add r5, r3 + lsr r5, r5, #4 @ r5 <- d3 / 10 + @ calculate remainder as d3 + lsl r6, r5, #2 + add r6, r5 + lsl r6, r6, #1 + sub r3, r6 @ r3 <- d3 - (q * 10) + @ finished with d3, d4 will automatically be quotient + mov r4, r5 + beq .L_LEAD_D4 + @ now print any leading digits if we are using all five + mov r5, r8 + mov r6, r9 + sub r5, #4 @ already printed five digits +.L_EXTRA_LEAD_LOOP: + sub r5, #1 + ble .L_DONE_EXTRA_LEAD + strb r6, [r7] @ print a leading character + add r7, #1 + b .L_EXTRA_LEAD_LOOP +.L_DONE_EXTRA_LEAD: + @ now print the fifth digit (d4) + add r4, #'0' @ r4 <- d4 + '0' + strb r4, [r7] @ store a character + add r7, #1 @ advance string pointer +.L_DONE_D4: + add r3, #'0' + strb r3, [r7] + add r7, #1 +.L_DONE_D3: + add r2, #'0' + strb r2, [r7] + add r7, #1 +.L_DONE_D2: + add r1, #'0' + strb r1, [r7] + add r7, #1 +.L_DONE_D1: + add r0, #'0' + strb r0, [r7] + add r7, #1 + @ Done at last! Clean up and return to calling routine + mov r0, r7 @ restore r0 <- dest string address + mov r1, r12 @ restore r1 <- source string address + mov pc, lr @ return from subroutine + +.L_LEAD_D4: + mov r5, r9 @ r5 <- leading character + mov r6, r8 + sub r6, #4 @ r6 <- # of chars to print + ble .L_DONE_D4 +.L_IN_D4: + strb r5, [r7] @ store a character + add r7, #1 @ advance string pointer + sub r6, #1 @ if chars to print > 0 + bgt .L_IN_D4 @ then loop + b .L_DONE_D4 + +.L_LEAD_D3: + mov r5, r9 @ r5 <- leading character + mov r6, r8 + sub r6, #3 @ r6 <- # of chars to print + ble .L_DONE_D3 +.L_IN_D3: + strb r5, [r7] @ store a character + add r7, #1 @ advance string pointer + sub r6, #1 @ if chars to print > 0 + bgt .L_IN_D3 @ then loop + b .L_DONE_D3 + +.L_LEAD_D2: + mov r5, r9 @ r5 <- leading character + mov r6, r8 + sub r6, #2 @ r6 <- # of chars to print + ble .L_DONE_D2 +.L_IN_D2: + strb r5, [r7] @ store a character + add r7, #1 @ advance string pointer + sub r6, #1 @ if chars to print > 0 + bgt .L_IN_D2 @ then loop + b .L_DONE_D2 + +.L_LEAD_D1: + mov r5, r9 @ r5 <- leading character + mov r6, r8 + sub r6, #1 @ r6 <- # of chars to print + ble .L_DONE_D1 +.L_IN_D1: + strb r5, [r7] @ store a character + add r7, #1 @ advance string pointer + sub r6, #1 @ if chars to print > 0 + bgt .L_IN_D1 @ then loop + b .L_DONE_D1 diff --git a/src/dusk/c_src/contrib/rtc.c b/src/dusk/c_src/contrib/rtc.c new file mode 100644 index 0000000..05be9c2 --- /dev/null +++ b/src/dusk/c_src/contrib/rtc.c @@ -0,0 +1,321 @@ +// #include "rtc.h" + +#define RTC_EPOWER ( 1 ) +#define RTC_E12HOUR ( 2 ) +#define RTC_EYEAR ( 3 ) +#define RTC_EMON ( 4 ) +#define RTC_EDAY ( 5 ) +#define RTC_EWDAY ( 6 ) +#define RTC_EHOUR ( 7 ) +#define RTC_EMIN ( 8 ) +#define RTC_ESEC ( 9 ) + +typedef int rtc_time; +typedef long long int rtc_tm; + +int rtc_init(); +int rtc_get_status(); +rtc_time rtc_get_time(); +rtc_tm rtc_get_datetime(); +void rtc_set_time( rtc_time time ); +void rtc_set_datetime( rtc_tm datetime ); + +typedef unsigned short u16; +typedef volatile u16 vu16; + +#define GPIO_PORT_DATA ( *( vu16 * ) 0x080000c4 ) +#define GPIO_PORT_DIRECTION ( *( vu16 * ) 0x080000c6 ) +#define GPIO_PORT_READ_ENABLE ( *( vu16 * ) 0x080000c8 ) + +#define CMD( X ) ( 0x60 | ( ( X ) << 1 ) ) +#define CMD_WR( X ) ( CMD( X ) ) +#define CMD_RD( X ) ( CMD( X ) | 0x1 ) + +#define CMD_RESET ( CMD_WR( 0 ) ) +#define CMD_STATUS_READ ( CMD_RD( 1 ) ) +#define CMD_DATETIME_READ ( CMD_RD( 2 ) ) +#define CMD_TIME_READ ( CMD_RD( 3 ) ) + +#define CMD_STATUS_WRITE ( CMD_WR( 1 ) ) +#define CMD_DATETIME_WRITE ( CMD_WR( 2 ) ) +#define CMD_TIME_WRITE ( CMD_WR( 3 ) ) + +#define RTC_STATUS_INTFE ( 0x01 ) +#define RTC_STATUS_INTME ( 0x02 ) +#define RTC_STATUS_INTAE ( 0x04 ) +#define RTC_STATUS_24HOUR ( 0x40 ) +#define RTC_STATUS_POWER ( 0x80 ) + +#define TIME_BIT_AM_PM ( 0x1 << 23 ) +#define TIME_BIT_TEST ( 0x1 << 7 ) + +#define TM_YEAR( X ) ( ( ( X ) >> 48 ) & 0xff ) +#define TM_YEAR_UNIT( X ) ( ( TM_YEAR( X ) >> 0 ) & 0x0f ) + +#define TM_MONTH( X ) ( ( ( X ) >> 40 ) & 0xff ) +#define TM_MONTH_UNIT( X ) ( ( TM_MONTH( X ) >> 0 ) & 0x0f ) + +#define TM_DAY( X ) ( ( ( X ) >> 32 ) & 0xff ) +#define TM_DAY_UNIT( X ) ( ( TM_DAY( X ) >> 0 ) & 0x0f ) + +#define TM_WDAY( X ) ( ( ( X ) >> 24 ) & 0xff ) +#define TM_WDAY_UNIT( X ) ( ( TM_WDAY( X ) >> 0 ) & 0x0f ) + +#define TM_HOUR( X ) ( ( ( X ) >> 16 ) & 0xff ) +#define TM_HOUR_UNIT( X ) ( ( TM_HOUR( X ) >> 0 ) & 0x0f ) + +#define TM_MIN( X ) ( ( ( X ) >> 8 ) & 0xff ) +#define TM_MIN_UNIT( X ) ( ( TM_MIN( X ) >> 0 ) & 0x0f ) + +#define TM_SEC( X ) ( ( ( X ) >> 0 ) & 0xff ) +#define TM_SEC_UNIT( X ) ( ( TM_SEC( X ) >> 0 ) & 0x0f ) + +static void rtc_reset(); + +int rtc_init() { + GPIO_PORT_READ_ENABLE = 1; + int status = rtc_get_status(); + if ( ( status & RTC_STATUS_POWER ) || ( status & RTC_STATUS_24HOUR ) == 0 ) { + // Reset (also switches to 24-hour mode) + rtc_reset(); + } + + const rtc_time time = rtc_get_time(); + if ( time & TIME_BIT_TEST ) { + // Reset to leave test mode + rtc_reset(); + } + + status = rtc_get_status(); + + if ( status & RTC_STATUS_POWER ) { + GPIO_PORT_READ_ENABLE = 0; + return RTC_EPOWER; + } + + if ( ( status & RTC_STATUS_24HOUR ) == 0 ) { + GPIO_PORT_READ_ENABLE = 0; + return RTC_E12HOUR; + } + + const rtc_tm datetime = rtc_get_datetime(); + + if ( TM_YEAR( datetime ) > 0x9f || TM_YEAR_UNIT( datetime ) > 9 ) { + GPIO_PORT_READ_ENABLE = 0; + return RTC_EYEAR; + } + + if ( TM_MONTH( datetime ) == 0 || TM_MONTH( datetime ) > 0x1f || TM_MONTH_UNIT( datetime ) > 9 ) { + GPIO_PORT_READ_ENABLE = 0; + return RTC_EMON; + } + + if ( TM_DAY( datetime ) == 0 || TM_DAY( datetime ) > 0x3f || TM_DAY_UNIT( datetime ) > 9 ) { + GPIO_PORT_READ_ENABLE = 0; + return RTC_EDAY; + } + + if ( ( TM_WDAY( datetime ) & 0xf8 ) || TM_WDAY_UNIT( datetime ) > 6 ) { + GPIO_PORT_READ_ENABLE = 0; + return RTC_EWDAY; + } + + if ( TM_HOUR( datetime ) > 0x2f || TM_HOUR_UNIT( datetime ) > 9 ) { + GPIO_PORT_READ_ENABLE = 0; + return RTC_EHOUR; + } + + if ( TM_MIN( datetime ) > 0x5f || TM_MIN_UNIT( datetime ) > 9 ) { + GPIO_PORT_READ_ENABLE = 0; + return RTC_EMIN; + } + + if ( TM_SEC( datetime ) > 0x5f || TM_SEC_UNIT( datetime ) > 9 ) { + GPIO_PORT_READ_ENABLE = 0; + return RTC_ESEC; + } + + return 0; +} + +static void rtc_write_command( int cmd ); +static int rtc_read_data8(); + +int rtc_get_status() { + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x5; + GPIO_PORT_DIRECTION = 0x7; + + rtc_write_command( CMD_STATUS_READ ); + + GPIO_PORT_DIRECTION = 0x5; + + const int status = rtc_read_data8(); + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + return status; +} + +static void rtc_write_command( const int cmd ) { + int bit = 7; + do { + const int value = ( ( cmd >> bit ) & 1 ) << 1; + GPIO_PORT_DATA = value | 0x4; + GPIO_PORT_DATA = value | 0x4; + GPIO_PORT_DATA = value | 0x4; + GPIO_PORT_DATA = value | 0x5; + } while ( bit-- ); +} + +static int rtc_read_data8() { + int byte = 0; + int bit = 0; + do { + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x5; + byte |= ( ( GPIO_PORT_DATA & 0x2 ) >> 1 ) << bit; + } while ( ++bit < 8 ); + return byte; +} + +static void rtc_write_data8( int data ); + +void rtc_reset() { + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x5; + GPIO_PORT_DIRECTION = 0x7; + + rtc_write_command( CMD_RESET ); + + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x1; + + // Set initial status + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x5; + GPIO_PORT_DIRECTION = 0x7; + + rtc_write_command( CMD_STATUS_WRITE ); + rtc_write_data8( RTC_STATUS_24HOUR ); + + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x1; +} + +static void rtc_write_data8( const int data ) { + int bit = 0; + do { + const int value = ( ( data >> bit ) & 1 ) << 1; + GPIO_PORT_DATA = value | 0x4; + GPIO_PORT_DATA = value | 0x4; + GPIO_PORT_DATA = value | 0x4; + GPIO_PORT_DATA = value | 0x5; + } while ( ++bit < 8 ); +} + +static int rtc_read_data24(); + +rtc_time rtc_get_time() { + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x5; + GPIO_PORT_DIRECTION = 0x7; + + rtc_write_command( CMD_TIME_READ ); + + GPIO_PORT_DIRECTION = 0x5; + + const int time = rtc_read_data24() & ~TIME_BIT_AM_PM; + + GPIO_PORT_DATA = 1; + GPIO_PORT_DATA = 1; + + return time; +} + +static int rtc_read_data24() { + int word = 0; + int bit = 0; + do { + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x5; + word |= ( ( GPIO_PORT_DATA & 0x2 ) >> 1 ) << bit; + } while ( ++bit < 24 ); + return ( ( word & 0xff0000 ) >> 16 ) | ( ( word & 0xff ) << 16 ) | ( word & 0xff00 ); +} + +static int rtc_read_data32(); + +rtc_tm rtc_get_datetime() { + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x5; + GPIO_PORT_DIRECTION = 0x7; + + rtc_write_command( CMD_DATETIME_READ ); + + GPIO_PORT_DIRECTION = 0x5; + + const rtc_tm date = rtc_read_data24(); + const int time = rtc_read_data32() & ~TIME_BIT_AM_PM; + + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x1; + + return ( date << 32 ) | time; +} + +static int rtc_read_data32() { + int word = 0; + int bit = 0; + do { + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x4; + GPIO_PORT_DATA = 0x5; + word |= ( ( GPIO_PORT_DATA & 0x2 ) >> 1 ) << bit; + } while ( ++bit < 32 ); + return ( int ) ( ( word & 0xff000000 ) >> 24 ) | ( word << 24 ) | ( ( word & 0xff0000 ) >> 8 ) | ( ( word & 0xff00 ) << 8 ); +} + +void rtc_set_time( const rtc_time time ) { + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x5; + GPIO_PORT_DIRECTION = 0x7; + + rtc_write_command( CMD_TIME_WRITE ); + + int bytes = 2; + do { + rtc_write_data8( ( time >> ( bytes * 8 ) ) & 0xff ); + } while ( bytes-- > 0 ); + + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x1; +} + +void rtc_set_datetime( const rtc_tm datetime ) { + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x5; + GPIO_PORT_DIRECTION = 0x7; + + rtc_write_command( CMD_DATETIME_WRITE ); + + int bytes = 6; + do { + rtc_write_data8( ( int ) ( datetime >> ( bytes * 8 ) ) & 0xff ); + } while ( bytes-- > 0 ); + + GPIO_PORT_DATA = 0x1; + GPIO_PORT_DATA = 0x1; +} diff --git a/src/dusk/c_src/version.c b/src/dusk/c_src/version.c new file mode 100644 index 0000000..3152b7d --- /dev/null +++ b/src/dusk/c_src/version.c @@ -0,0 +1,21 @@ +/*** + * + * Version Data (Minimal Library Version) + * + *****************************************************************************/ + +#define LIB_ID "DUSK" +#define RES_LIB_ID "$LIB " LIB_ID + +#ifndef VERSION_ID_DEF +#define VERSION_ID_DEF "unknown" +#endif +#define RES_LIB_VERSION (RES_LIB_ID " $VER " VERSION_ID_DEF) + +#ifndef LIB_BUILD_ID_DEF +#define LIB_BUILD_ID_DEF "unknown" +#endif +#define RES_LIB_BUILD (RES_LIB_ID " $BUILD " LIB_BUILD_ID_DEF) + +__attribute__((used)) const char* DUSK_LIB_VERSION = RES_LIB_VERSION; +__attribute__((used)) const char* DUSK_LIB_BUILD = RES_LIB_BUILD; diff --git a/src/dusk/d_src/dusk/contrib/gbamap.d b/src/dusk/d_src/dusk/contrib/gbamap.d new file mode 100644 index 0000000..1ec7c1f --- /dev/null +++ b/src/dusk/d_src/dusk/contrib/gbamap.d @@ -0,0 +1,58 @@ +module dusk.contrib.gbamap; + +extern (C): + +struct Map { + ushort sizeFlag, + paletteLength, + tileSetLength, + terrainMapLength, + numObjects, + numLayers, + tileMapLength; + + const ushort *palette; + const ushort *tileSet; + const ushort *terrainMap; + + MapObject[256] objects; + + const ushort[3] *tileMapLayers; +} + +align(2) struct BackgroundPoint { + align (2): + short x, y; +} + +enum MAX_LAYERS = 3; +enum ENTRIES_IN_SCREEN_BLOCK = 512; +enum NUM_SCREEN_BLOCKS = 31; + +Map map_load_from_rom(const ushort *map_data); + +void map_init_registers(); +void map_set_onscreen(Map map); +void map_shift(Map map, BackgroundPoint offset); +void map_shift_layer(ushort layer, BackgroundPoint offset); + +align(4) struct ObjectPoint { + align(4): + ushort x, y; +} + +struct MapObject +{ + uint id; + ObjectPoint position; + const char* name; + const char* type; +} + +MapObject map_load_object(const ushort* object_data, ushort* index); +uint map_load_object_id(const ushort* idData, ushort* index); +ObjectPoint map_load_object_position(const ushort* positionData, ushort* index); +char* map_load_string(const ushort* stringData, ushort* index); +ushort map_pop_value(const ushort* data, ushort* index); + +void map_shift_objects(MapObject* objects, ObjectPoint shift, uint count); \ No newline at end of file diff --git a/src/dusk/d_src/dusk/contrib/gbfs.d b/src/dusk/d_src/dusk/contrib/gbfs.d new file mode 100644 index 0000000..50c1ad9 --- /dev/null +++ b/src/dusk/d_src/dusk/contrib/gbfs.d @@ -0,0 +1,87 @@ +module dusk.contrib.gbfs; + +/* gbfs.h + access object in a GBFS file + +Copyright 2002 Damian Yerrick + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +*/ + +/* Dependency on prior include files + +Before you #include "gbfs.h", you should define the following types: + typedef (unsigned 16-bit integer) u16; + typedef (unsigned 32-bit integer) u32; +Your gba.h should do this for you. +*/ + +//\{ + +//\} + +/*! \name Volatile types +* Volatile types for registers +*/ +//\{ + +//\} + +/*! \name Const types +* Const types for const function aprameters +*/ +//\{ + +//\} + +//! 8-word type for fast struct-copies + +//! Type for consting a string as well as the pointer than points to it. + +extern (C): + +/* to make a 300 KB space called samples do GBFS_SPACE(samples, 300) */ + +enum GBFS_ENTRY_SIZE = 24; + +struct GBFS_FILE +{ + char[16] magic; /* "PinEightGBFS\r\n\032\n" */ + uint total_len; /* total length of archive */ + ushort dir_off; /* offset in bytes to directory */ + ushort dir_nmemb; /* number of files */ + char[8] reserved; /* for future use */ +} + +struct GBFS_ENTRY +{ + char[GBFS_ENTRY_SIZE] name; /* filename, nul-padded */ + uint len; /* length of object in bytes */ + uint data_offset; /* in bytes from beginning of file */ +} + +const(GBFS_FILE)* find_first_gbfs_file (const(void)* start); +const(void)* skip_gbfs_file (const(GBFS_FILE)* file); +const(void)* gbfs_get_obj (const(GBFS_FILE)* file, const(char)* name, uint* len); +const(void)* gbfs_get_nth_obj (const(GBFS_FILE)* file, size_t n, char* name, uint* len); +void* gbfs_copy_obj (void* dst, const(GBFS_FILE)* file, const(char)* name); +size_t gbfs_count_objs (const(GBFS_FILE)* file); \ No newline at end of file diff --git a/src/dusk/d_src/dusk/contrib/mgba.d b/src/dusk/d_src/dusk/contrib/mgba.d new file mode 100644 index 0000000..624c13b --- /dev/null +++ b/src/dusk/d_src/dusk/contrib/mgba.d @@ -0,0 +1,23 @@ +module dusk.contrib.mgba; + +import tonc.tonc_types; + +extern (C): + +enum REG_DEBUG_ENABLE = cast(vu16*) 0x4FFF780; +enum REG_DEBUG_FLAGS = cast(vu16*) 0x4FFF700; +enum REG_DEBUG_STRING = cast(char*) 0x4FFF600; + +enum MGBALogLevel +{ + FATAL = 0, + ERROR = 1, + WARN = 2, + INFO = 3, + DEBUG = 4 +} + +__gshared extern int mgba_is_open; +void mgba_printf (int level, const(char)* ptr, ...); +bool mgba_open (); +void mgba_close (); diff --git a/src/dusk/d_src/dusk/contrib/posprintf.d b/src/dusk/d_src/dusk/contrib/posprintf.d new file mode 100644 index 0000000..40f0777 --- /dev/null +++ b/src/dusk/d_src/dusk/contrib/posprintf.d @@ -0,0 +1,5 @@ +module dusk.contrib.posprintf; + +extern (C): + +extern void posprintf(char*, const char*, ...); diff --git a/src/dusk/d_src/dusk/contrib/rtc.d b/src/dusk/d_src/dusk/contrib/rtc.d new file mode 100644 index 0000000..e32348a --- /dev/null +++ b/src/dusk/d_src/dusk/contrib/rtc.d @@ -0,0 +1,120 @@ +module dusk.contrib.rtc; + +import tonc.tonc_types; +import tonc.tonc_memmap; + +// #define RTC_EPOWER ( 1 ) +// #define RTC_E12HOUR ( 2 ) +// #define RTC_EYEAR ( 3 ) +// #define RTC_EMON ( 4 ) +// #define RTC_EDAY ( 5 ) +// #define RTC_EWDAY ( 6 ) +// #define RTC_EHOUR ( 7 ) +// #define RTC_EMIN ( 8 ) +// #define RTC_ESEC ( 9 ) +// enum RTC_EPOWER = 1; +// enum RTC_E12HOUR = 2; +// enum RTC_EYEAR = 3; +// enum RTC_EMON = 4; +// enum RTC_EDAY = 5; +// enum RTC_EWDAY = 6; +// enum RTC_EHOUR = 7; +// enum RTC_EMIN = 8; +// enum RTC_ESEC = 9; + +extern (D) { + // #define RTC_TM_YEAR( X ) ( ( ( X ) >> 48 ) & 0xff ) + // #define RTC_TM_MON( X ) ( ( ( X ) >> 40 ) & 0xff ) + // #define RTC_TM_MDAY( X ) ( ( ( X ) >> 32 ) & 0xff ) + // #define RTC_TM_WDAY( X ) ( ( ( X ) >> 24 ) & 0xff ) + // #define RTC_TM_HOUR( X ) ( ( ( X ) >> 16 ) & 0xff ) + // #define RTC_TM_MIN( X ) ( ( ( X ) >> 8 ) & 0xff ) + // #define RTC_TM_SEC( X ) ( ( ( X ) >> 0 ) & 0xff ) + // #define BCD_DECODE( x ) ( ( ( x ) & 0xfu ) + ( ( ( x ) >> 4u ) * 10u ) ) + // #define BCD_ENCODE( x ) ( ( ( x ) % 10 ) + ( ( ( x ) / 10 ) << 4 ) ) + + auto RTC_TM_YEAR(u64 x) { + return (x >> 48) & 0xff; + } + + auto RTC_TM_MON(u64 x) { + return (x >> 40) & 0xff; + } + + auto RTC_TM_MDAY(u64 x) { + return (x >> 32) & 0xff; + } + + auto RTC_TM_WDAY(u64 x) { + return (x >> 24) & 0xff; + } + + auto RTC_TM_HOUR(u64 x) { + return (x >> 16) & 0xff; + } + + auto RTC_TM_MIN(u64 x) { + return (x >> 8) & 0xff; + } + + auto RTC_TM_SEC(u64 x) { + return (x >> 0) & 0xff; + } + + auto BCD_DECODE(u64 x) { + return (x & 0xfu) + ((x >> 4u) * 10u); + } + + auto BCD_ENCODE(u64 x) { + return (x % 10) + ((x / 10) << 4); + } +} + +// typedef int rtc_time; +// typedef long long int rtc_tm; + +alias rtc_time = int; +alias rtc_tm = s64; + +extern (C) { + int rtc_init(); + int rtc_get_status(); + rtc_time rtc_get_time(); + rtc_tm rtc_get_datetime(); + void rtc_set_time(rtc_time time); + void rtc_set_datetime(rtc_tm datetime); +} + +alias dt_field_size = int; +struct RTCDateTime { + dt_field_size year; + dt_field_size month; + dt_field_size day; + dt_field_size wday; + dt_field_size hour; + dt_field_size min; + dt_field_size sec; +} + +extern (D) RTCDateTime rtc_get_datetime_ex() { + RTCDateTime ret; + + // disable interrupts + auto ime = *REG_IME; + *REG_IME = 0; + // get datetime from rtc hardware + auto rawdt = rtc_get_datetime(); + // re-enable interrupts + *REG_IME = ime; + + ret.year = cast(dt_field_size) BCD_DECODE(RTC_TM_YEAR(rawdt)) + 2000; + ret.month = cast(dt_field_size) BCD_DECODE(RTC_TM_MON(rawdt)); + ret.day = cast(dt_field_size) BCD_DECODE(RTC_TM_MDAY(rawdt)); + ret.wday = cast(dt_field_size) BCD_DECODE(RTC_TM_WDAY(rawdt)); + + ret.hour = cast(dt_field_size) BCD_DECODE(RTC_TM_HOUR(rawdt)); + ret.min = cast(dt_field_size) BCD_DECODE(RTC_TM_MIN(rawdt)); + ret.sec = cast(dt_field_size) BCD_DECODE(RTC_TM_SEC(rawdt)); + + return ret; +} diff --git a/src/dusk/d_src/dusk/dbg.d b/src/dusk/d_src/dusk/dbg.d new file mode 100644 index 0000000..8eec9e8 --- /dev/null +++ b/src/dusk/d_src/dusk/dbg.d @@ -0,0 +1,24 @@ +/* debug utils */ +module dusk.dbg; + +extern (C) nothrow @nogc: +private { + void mgba_printf(int level, const(char)* ptr, ...); + void exit(int status); +} + +pragma(inline, true) void ds_assert_func(bool cond, string msg, string file, int line) { + if (cond) + return; + + version (DEBUG) { + // report fatal error to mgba + mgba_printf(0, "Assertion failed at %s:%d: %s\n", cast(char*) file, line, cast(char*) msg); + } + + exit(1); +} + +void ds_assert(bool cond, string msg = "", string file = __FILE__, int line = __LINE__) { + ds_assert_func(cond, msg, file, line); +} diff --git a/src/dusk/src/load.c b/src/dusk/d_src/dusk/load.d similarity index 50% rename from src/dusk/src/load.c rename to src/dusk/d_src/dusk/load.d index 8adeb6b..315d056 100644 --- a/src/dusk/src/load.c +++ b/src/dusk/d_src/dusk/load.d @@ -1,47 +1,104 @@ -#include -#include -#include -#include -#include "ds_load.h" -#include -#include +module dusk.load; + +extern(C): + +import core.stdc.stdio; +import core.stdc.stdlib; +import core.stdc.stddef; +import core.stdc.string; +import tonc.tonc_types; +import dusk.contrib.gbfs; +import dusk.contrib.gbamap; + +// represents an atlas, with bitmaps for the image and palette +struct SpriteAtlas { + u32* tiles; + u32 tile_sz; + u32* pal; + u32 pal_sz; +} + +struct GritImage { + u32* tiles; + u32 tile_sz; + u32* pal; + u32 pal_sz; + u32* map; + u32 map_sz; +} + +enum ATLAS_ENTRY_LEN = 6; + +/** represents a single entry in the sprite atlas. + * note that names are limited to just 5 chars and a NULL terminator. */ +struct SpriteAtlasEntry { + char[ATLAS_ENTRY_LEN] name; + // all of these are in tiles (8px) + u8 x; + u8 y; + u8 w; + u8 h; +} + +/** represents the layout of items in an atlas (https://github.com/xdrie/crunch#binary-format). + * we only use the first texture because the vram can only hold one */ +struct SpriteAtlasLayout { + u16 width; + u16 height; + u16 num_entries; + SpriteAtlasEntry* entries; +} + +/** initialize loader */ +void dusk_load_init(); + +// - CONTENT LOADERS: pass filename without extension -const GBFS_FILE* gbfs_dat; +// void* dusk_load_raw(char* name, u32* len); +// GritImage dusk_load_image(char* name); +// SpriteAtlas dusk_load_atlas(char* name); +// SpriteAtlasLayout dusk_load_atlas_layout(const char* name); +// SpriteAtlasEntry* dusk_load_atlas_entry(SpriteAtlasLayout* layout, const char* entry_name); +// void dusk_free_atlas_layout(SpriteAtlasLayout* layout); + +// Map dusk_load_map(char* name); + +__gshared static GBFS_FILE* gbfs_dat; void dusk_load_init() { // locate the main GBFS archive - gbfs_dat = find_first_gbfs_file(find_first_gbfs_file); + gbfs_dat = cast(GBFS_FILE*) find_first_gbfs_file(&find_first_gbfs_file); } -const void* dusk_load_raw(char* name, u32* len) { - return gbfs_get_obj(gbfs_dat, name, len); +void* dusk_load_raw(char* name, u32* len) { + return cast(void*) gbfs_get_obj(gbfs_dat, name, len); } GritImage dusk_load_image(char* name) { GritImage img; - char tiles_name[GBFS_ENTRY_SIZE]; - strcpy(tiles_name, name); - strcat(tiles_name, ".img.bin"); - char pal_name[GBFS_ENTRY_SIZE]; - strcpy(pal_name, name); - strcat(pal_name, ".pal.bin"); - char map_name[GBFS_ENTRY_SIZE]; - strcpy(map_name, name); - strcat(map_name, ".map.bin"); - - img.tiles = (u32*)gbfs_get_obj(gbfs_dat, tiles_name, &img.tile_sz); - img.pal = (u32*)gbfs_get_obj(gbfs_dat, pal_name, &img.pal_sz); - img.map = (u32*)gbfs_get_obj(gbfs_dat, map_name, &img.map_sz); + char[GBFS_ENTRY_SIZE] tiles_name; + strcpy(cast(char*)tiles_name, name); + strcat(cast(char*)tiles_name, cast(char*)".img.bin"); + char[GBFS_ENTRY_SIZE] pal_name; + strcpy(cast(char*)pal_name, name); + strcat(cast(char*)pal_name, cast(char*)".pal.bin"); + char[GBFS_ENTRY_SIZE] map_name; + strcpy(cast(char*)map_name, name); + strcat(cast(char*)map_name, cast(char*)".map.bin"); + + img.tiles = cast(u32*)gbfs_get_obj(gbfs_dat, cast(char*)tiles_name, &img.tile_sz); + img.pal = cast(u32*)gbfs_get_obj(gbfs_dat, cast(char*)pal_name, &img.pal_sz); + img.map = cast(u32*)gbfs_get_obj(gbfs_dat, cast(char*)map_name, &img.map_sz); return img; } SpriteAtlas dusk_load_atlas(char* name) { - char atlas_name[GBFS_ENTRY_SIZE]; - strcpy(atlas_name, name); - strcat(atlas_name, "_0"); + char[GBFS_ENTRY_SIZE] atlas_name; + strcpy(cast(char*)atlas_name, name); + strcat(cast(char*)atlas_name, cast(char*)"_0"); - GritImage img = dusk_load_image(atlas_name); + GritImage img = dusk_load_image(cast(char*)atlas_name); SpriteAtlas atlas; atlas.tiles = img.tiles; @@ -55,7 +112,7 @@ SpriteAtlas dusk_load_atlas(char* name) { // NOTE: ASSERT pal_sz >= 2 - u16* pal_raw = (u16*)atlas.pal; // 16-bit color + u16* pal_raw = cast(u16*)atlas.pal; // 16-bit color const int palscan_start = 0; const int palscan_inarow = 6; // how many in a row we're looking for @@ -99,12 +156,12 @@ void seek_until_null(const u8* data, int* pos) { SpriteAtlasLayout dusk_load_atlas_layout(const char* name) { SpriteAtlasLayout layout; - char file_name[GBFS_ENTRY_SIZE]; - strcpy(file_name, name); - strcat(file_name, "_.sht.bin"); + char[GBFS_ENTRY_SIZE] file_name; + strcpy(cast(char*)file_name, name); + strcat(cast(char*)file_name, cast(char*)"_.sht.bin"); u32 data_sz = 0; - const u8* data = gbfs_get_obj(gbfs_dat, file_name, &data_sz); + const u8* data = cast(u8*) gbfs_get_obj(gbfs_dat, cast(char*)file_name, &data_sz); int pos = 0; @@ -122,7 +179,7 @@ SpriteAtlasLayout dusk_load_atlas_layout(const char* name) { pos += 2; layout.num_entries = data[pos] | (data[pos + 1] << 8); - layout.entries = malloc(sizeof(SpriteAtlasEntry) * layout.num_entries); + layout.entries = cast(SpriteAtlasEntry*) malloc((SpriteAtlasEntry.sizeof) * layout.num_entries); pos += 2; // now read blocks @@ -148,37 +205,37 @@ SpriteAtlasLayout dusk_load_atlas_layout(const char* name) { pos += 2; // x,y,w,h are 8-bit so don't overflow! // these are in tile units (the final div by 8) - layout.entries[i].x = x / 8; - layout.entries[i].y = y / 8; - layout.entries[i].w = w / 8; - layout.entries[i].h = h / 8; + layout.entries[i].x = cast(u8) x / 8; + layout.entries[i].y = cast(u8) y / 8; + layout.entries[i].w = cast(u8) w / 8; + layout.entries[i].h = cast(u8) h / 8; } return layout; } SpriteAtlasEntry* dusk_load_atlas_entry(SpriteAtlasLayout* layout, const char* entry_name) { - for (int i = 0; i < layout->num_entries; i++) { - SpriteAtlasEntry* entry = &layout->entries[i]; - if (strncmp(entry_name, entry->name, ATLAS_ENTRY_LEN) == 0) { + for (int i = 0; i < layout.num_entries; i++) { + SpriteAtlasEntry* entry = &layout.entries[i]; + if (strncmp(cast(char*)entry_name, cast(char*)entry.name, ATLAS_ENTRY_LEN) == 0) { return entry; } } - return NULL; + return null; } void dusk_free_atlas_layout(SpriteAtlasLayout* layout) { - layout->num_entries = 0; - free(layout->entries); - layout->entries = NULL; + layout.num_entries = 0; + free(layout.entries); + layout.entries = null; } Map dusk_load_map(char* name) { - char ass_name[GBFS_ENTRY_SIZE]; - strcpy(ass_name, name); - strcat(ass_name, ".bin"); + char[GBFS_ENTRY_SIZE] ass_name; + strcpy(cast(char*)ass_name, name); + strcat(cast(char*)ass_name, cast(char*)".bin"); u32 map_data_sz = 0; - const u16* map_data = gbfs_get_obj(gbfs_dat, ass_name, &map_data_sz); + const u16* map_data = cast(u16*) gbfs_get_obj(gbfs_dat, cast(char*)ass_name, &map_data_sz); return map_load_from_rom(map_data); } diff --git a/src/dusk/d_src/dusk/package.d b/src/dusk/d_src/dusk/package.d new file mode 100644 index 0000000..7da67d4 --- /dev/null +++ b/src/dusk/d_src/dusk/package.d @@ -0,0 +1,9 @@ +module dusk; + +public { + import dusk.load; + import dusk.sys; + import dusk.sprites; + import dusk.save; + import dusk.dbg; +} \ No newline at end of file diff --git a/src/dusk/d_src/dusk/save.d b/src/dusk/d_src/dusk/save.d new file mode 100644 index 0000000..b0d9cb6 --- /dev/null +++ b/src/dusk/d_src/dusk/save.d @@ -0,0 +1,13 @@ +module lib.dusk.src.dusk.d_src.dusk.save; + +// utilities for saving and loading vars + +// #define SV_LOAD_ITEM(var, offset) \ +// memcpy(&var, sram_mem + offset, sizeof(typeof(var))); \ +// offset += sizeof(typeof(var)); + +// #define SV_SAVE_ITEM(var, offset) \ +// memcpy(sram_mem + offset, &var, sizeof(typeof(var))); \ +// offset += sizeof(typeof(var)); + +// utilities for saving and loading vars \ No newline at end of file diff --git a/src/dusk/d_src/dusk/sprites.d b/src/dusk/d_src/dusk/sprites.d new file mode 100644 index 0000000..a3eef9c --- /dev/null +++ b/src/dusk/d_src/dusk/sprites.d @@ -0,0 +1,407 @@ +module dusk.sprites; + +extern (C): + +import dusk.sprites; +import dusk.sys; +import dusk.load; +import tonc; +import ldc.attributes; +import core.stdc.stdlib; +import core.stdc.stdio; +import core.stdc.string; + +enum NUM_SPRITES = 128; +enum NUM_AFFINE_SPRITES = 32; + +enum SPRITEFLAG_PRIORITY_SHIFT = 6; +// #define SPRITEFLAG_PRIORITY_GET(n) ((n >> SPRITEFLAG_PRIORITY_SHIFT) & 0b11) +// #define SPRITEFLAG_PRIORITY(n) ((n << SPRITEFLAG_PRIORITY_SHIFT) & 0b11) +u8 SPRITEFLAG_PRIORITY_GET(u8 n) { + return (n >> SPRITEFLAG_PRIORITY_SHIFT) & 0b11; +} + +u8 SPRITEFLAG_PRIORITY(u8 n) { + return (n << SPRITEFLAG_PRIORITY_SHIFT) & 0b11; +} + +enum DUSKSPRITE_FLAGS_VISIBLE = (0x1 << 0); + +/** sprite data */ +struct Sprite { + /** the screen x and y of the sprite */ + s16 x, y; + /** the number of tiles taken up by this sprite */ + u8 tile_sz; + /** the raw tid of the top left corner tile of spritesheet frame 0 */ + u16 base_tid; + /** the frame index of the spritesheet */ + u8 page; + /** flags: 0/0/0/0/0/0/0/visible */ + u8 flags; + + /** initialize a sprite struct */ + static Sprite init(s16 x, s16 y, u8 page = 0, u8 flags = 0) { + Sprite s; + s.x = x; + s.y = y; + s.tile_sz = 1; + s.base_tid = 0; + s.page = page; + s.flags = flags; + return s; + } +} + +/** animation metadata */ +struct Anim { + /** which page in the sprite the animation starts */ + u8 start; + /** number of pages in this animation */ + u8 len; + /** (60/fps), or how many frames each page lasts */ + u8 rate; +} + +/** background data */ +struct Background { + s16 x, y; + int cbb, sbb; +} + +/** define an animation, given a starting frame and frame count, and fps */ +// #define MAKE_ANIM_EX(st, le, fps) \ +// (Anim) { .start = st, .len = le, .rate = (60 / fps) } +Anim make_anim_ex(u8 start, u8 len, u8 fps) { + return Anim(start, len, 60 / fps); +} +/** define an animation, given a starting frame and frame count, at 10 fps */ +// #define MAKE_ANIM(st, le) MAKE_ANIM_EX(st, le, 10) +Anim make_anim(u8 start, u8 len) { + return make_anim_ex(start, len, 10); +} + +// /** initialize sprite and OAM memory */ +// void dusk_sprites_init(); +// /** set mode options for dusk sprites */ +// void dusk_sprites_configure(bool bpp8); +// /** upload a sprite atlas to tile and palette memory */ +// void dusk_sprites_upload_atlas(SpriteAtlas* atlas); +// /** upload a sprite atlas section to tile and palette memory */ +// void dusk_sprites_upload_atlas_section(SpriteAtlasLayout* layout, SpriteAtlas* atlas, SpriteAtlasEntry* entry, u16 pal_offset, u16 tile_offset); +// /** create a sprite and store it in index of sprite memory */ +// Sprite* dusk_sprites_make(int index, u8 width, u8 height, Sprite spr); +// /** synchronize a sprite from the sprites array to OAM block (vram) */ +// void dusk_sprites_sync(int index); +// /** synchronize all sprites to OAM block, then upload OAM block to vram */ +// void dusk_sprites_update(); +// /** play an animation on a sprite */ +// void dusk_sprites_anim_play(Sprite* spr, Anim* anim); +// /** calculate the tid of a sprite given pos and sheet dimens */ +// u16 dusk_sprites_pos_to_tid(u16 x, u16 y, u16 sheet_width, u16 sheet_height); +// /** upload image data to background tile vram */ +// void dusk_background_upload_raw(GritImage* img, int cbb, int sbb); +// /** create a background and display it */ +// void dusk_background_make(u8 bg_id, u16 size, Background bg); + +// mixin(EWRAM_DATA!("OBJ_ATTR[NUM_SPRITES]", "obj_buffer")); +// static OBJ_ATTR[NUM_SPRITES] obj_buffer; +@(ldc.attributes.section(".ewram")) __gshared OBJ_ATTR[NUM_SPRITES] obj_buffer; +// OBJ_AFFINE* obj_aff_buffer = cast(OBJ_AFFINE*) obj_buffer; +__gshared OBJ_AFFINE* obj_aff_buffer() { + return cast(OBJ_AFFINE*) obj_buffer; +} + +/** memory block used to track sprites */ +// mixin(EWRAM_DATA!("Sprite[NUM_SPRITES]", "sprites")); +// static Sprite[NUM_SPRITES] sprites; +@(ldc.attributes.section(".ewram")) __gshared Sprite[NUM_SPRITES] sprites; + +/** when true, 8BPP, when false, 4BPP */ +__gshared bool sprites_bpp8 = true; + +void dusk_sprites_init() { + // initialize object buffer + oam_init(cast(OBJ_ATTR*) obj_buffer, NUM_SPRITES); + memset(cast(void*) sprites, 0, (Sprite.sizeof) * NUM_SPRITES); + + // reset bpp to default + sprites_bpp8 = true; + + // enable sprite display + *REG_DISPCNT |= DCNT_OBJ | DCNT_OBJ_1D; +} + +void dusk_sprites_configure(bool bpp8) { + sprites_bpp8 = bpp8; +} + +void dusk_sprites_upload_atlas(SpriteAtlas* atlas) { + // 1. upload the atlas tile palette to palette memory + // object/sprite palette, in 8bpp stores 256 colors + memcpy(&pal_obj_bank[0], atlas.pal, atlas.pal_sz); + // 2. upload the atlas tiles to tile memory + // tile memory (can store 1024 tiles (32x32 tiles or 256x256px) + // VRAM is charblocks 4 and 5, so &tile_mem[4][0] points to the first tile in object VRAM + memcpy(&tile_mem[4][0], atlas.tiles, atlas.tile_sz); +} + +void dusk_sprites_upload_atlas_section(SpriteAtlasLayout* layout, SpriteAtlas* atlas, SpriteAtlasEntry* entry, + u16 pal_offset, u16 tile_offset) { + + // 1. upload the palette (palettes are 16-bit highcolor) + memcpy(&pal_obj_bank[0][pal_offset], &atlas.pal[0], atlas.pal_sz); + + // pal_obj_bank[0][4] = CLR_YELLOW; + // 2. upload the tiles + int entry_firsttid = + dusk_sprites_pos_to_tid(entry.x, entry.y, layout.width, layout.height); // tid of entry start in atlas + int entry_tilecount = (entry.w) * (entry.h); // entry size in tiles + int raw_firsttid = entry_firsttid * entry_tilecount * 2; // read offset + // int raw_tilecount = entry_tilecount * 2; + int raw_tileoffset = tile_offset * 2; // write offset + + // printf("ro: %d. wo: %d, n: %d\n", raw_firsttid, raw_tileoffset, raw_tilecount); // debug print tile r/w + + // memcpy(&tile_mem[4][raw_tileoffset], &atlas.tiles[raw_firsttid], entry_tilecount * 64); + + // 3. fix tiles to point at right palette + // for (int i = 0; i < raw_tilecount; i += 2) { + // TILE8 new_tile; + // // TILE8 tile.data consists of 16 u32s (a total of 64 bytes) + // // new_tile.data[j] = atlas.tiles[(entry_firsttid + i) * 2]; + // u32* rt = &atlas.tiles[raw_firsttid + i]; // read tile + + // for (int j = 0; j < 16; j++) { + // new_tile.data[j] = rt[j]; + // // new_tile.data[j] = 0x04040404; + // } + // // copy in tile + // memcpy(&tile_mem[4][raw_tileoffset + i], &new_tile, 64); + // } + + // unroll malloc + // memcpy(&tile_mem[4][raw_tileoffset], &atlas.tiles[raw_firsttid], 64); + + // reinterpret as byte pointers + u8* loc_twrite = cast(u8*)&tile_mem[4][raw_tileoffset]; + u8* loc_tread = cast(u8*)&atlas.tiles[raw_firsttid]; + for (int i = 0; i < entry_tilecount; i += 1) { + int c = i * 64; + u8[64] tile; // create temp tile + memcpy(&tile[0], loc_tread + c, 64); // read tile + + // fix tile + for (int j = 0; j < 64; j++) { + tile[j] = cast(ubyte)(tile[j] + pal_offset); + } + + memcpy(loc_twrite + c, &tile[0], 64); // write tile + } +} + +Sprite* dusk_sprites_make(int index, u8 width, u8 height, Sprite spr) { + // automatically figure out sprite size/shape attributes + u16 shape_attr = 0; + if (height > width) { + shape_attr = ATTR0_TALL; + } else if (width > height) { + shape_attr = ATTR0_WIDE; + } else if (width == height) { + shape_attr = ATTR0_SQUARE; + } + u16 size_attr = 0; + if (shape_attr == ATTR0_TALL) { + if (width == 8 && height == 16) + size_attr = ATTR1_SIZE_8x16; + if (width == 8 && height == 32) + size_attr = ATTR1_SIZE_8x32; + if (width == 16 && height == 32) + size_attr = ATTR1_SIZE_16x32; + if (width == 16 && height == 64) + size_attr = ATTR1_SIZE_32x64; + } + if (shape_attr == ATTR0_WIDE) { + if (width == 16 && height == 8) + size_attr = ATTR1_SIZE_16x8; + if (width == 32 && height == 8) + size_attr = ATTR1_SIZE_32x8; + if (width == 32 && height == 16) + size_attr = ATTR1_SIZE_32x16; + if (width == 64 && height == 32) + size_attr = ATTR1_SIZE_64x32; + } + if (shape_attr == ATTR0_SQUARE) { + if (width == 8 && height == 8) + size_attr = ATTR1_SIZE_8x8; + if (width == 16 && height == 16) + size_attr = ATTR1_SIZE_16x16; + if (width == 32 && height == 32) + size_attr = ATTR1_SIZE_32x32; + if (width == 64 && height == 64) + size_attr = ATTR1_SIZE_64x64; + } + + // calculate the number of tiles used by one frame of this sprite (divide width and height by 8) + spr.tile_sz = cast(ubyte)((width >> 3) * (height >> 3)); + + // set main attributes + // leave tile id (attr2) null, it will be set in sync + u16 bpp_flag = (sprites_bpp8 == 1) ? ATTR0_8BPP : ATTR0_4BPP; + obj_set_attr(&obj_buffer[index], ATTR0_REG | shape_attr | bpp_flag, size_attr, 0); + + // set default flags + spr.flags |= (DUSKSPRITE_FLAGS_VISIBLE); + + // save sprite metadata + sprites[index] = spr; + + // sync other attributes + dusk_sprites_sync(index); + + // return pointer to this sprite + return &sprites[index]; +} + +pragma(inline) void dusk_sprites_sync(int i) { + Sprite* sprite = &sprites[i]; + OBJ_ATTR* obj = &obj_buffer[i]; + // position + obj_set_pos(obj, sprite.x, sprite.y); + + // visibility + if ((sprite.flags & DUSKSPRITE_FLAGS_VISIBLE) > 0) { + obj_unhide(obj, ATTR0_REG); + } else { + obj_hide(obj); + } + + // main attrs + + // logical base tid mode + // obj_set_attr(obj, obj.attr0, obj.attr1, (sprite.tid + sprite.page) * sprite.tile_sz * 2); + + // raw base tid mode + int bpp_mult = (sprites_bpp8 == 1) ? 2 : 1; + u16 tid = cast(u16)((sprite.base_tid + (sprite.page * sprite.tile_sz)) * bpp_mult); + obj_set_attr(obj, obj.attr0, obj.attr1, cast(u16)(ATTR2_ID!u16(tid) | ATTR2_PALBANK!u16(0))); +} + +void dusk_sprites_update() { + // sync all sprites + for (int i = 0; i < NUM_SPRITES; i++) { + dusk_sprites_sync(i); + } + + // upload shadow oam to vram + + oam_copy(oam_mem, cast(OBJ_ATTR*) obj_buffer, NUM_SPRITES); + // CpuFastSet(obj_buffer, oam_mem, NUM_SPRITES * 2); +} + +void dusk_sprites_anim_play(Sprite* spr, Anim* anim) { + // make sure page is within anim range + if (spr.page < anim.start || spr.page >= (anim.start + anim.len)) { + spr.page = anim.start; // reset to first + } + int ix = spr.page - anim.start; + if (frame_count % anim.rate == 0) { + ix = (ix + 1) % anim.len; + } + // set new frame + spr.page = cast(u8)(anim.start + ix); +} + +u16 dusk_sprites_pos_to_tid(u16 x, u16 y, u16 sheet_width, u16 sheet_height) { + // calculate corner tile id + // first get x and y in tile coords + u16 xt = x; + u16 yt = y; + u16 imw = sheet_width >> 3; // compute with bitshift (sheet_width / 8) + // u16 imh = sheet_height >> 3; + u16 tid = cast(u16)((yt * imw) + xt); + return tid; +} + +void enable_bg(u8 bg_id) { + int bg_flag = 0; + switch (bg_id) { + case 0: + bg_flag = DCNT_BG0; + break; + case 1: + bg_flag = DCNT_BG1; + break; + case 2: + bg_flag = DCNT_BG2; + break; + case 3: + bg_flag = DCNT_BG3; + break; + default: + assert(0); + } + + *REG_DISPCNT |= bg_flag; +} + +vu16* dusk_get_background_register(u8 bg_id) { + switch (bg_id) { + case 0: + return REG_BG0CNT; + case 1: + return REG_BG1CNT; + case 2: + return REG_BG2CNT; + case 3: + return REG_BG3CNT; + default: + return null; + } +} + +void dusk_background_upload_raw(GritImage* img, int cbb, int sbb, int pal_offset = 0) { + // TODO: support selecting slot + + // copy palette and se + memcpy32(&pal_bg_mem[pal_offset], img.pal, img.pal_sz / 4); + memcpy32(&se_mem[sbb][0], img.map, img.map_sz / 4); + + // copy tiles + auto tile_data = cast(u8*) img.tiles; + + if (pal_offset > 0) { + // we need to copy tiles to ram so we can edit them + tile_data = cast(u8*) malloc(img.tile_sz); + memcpy(tile_data, img.tiles, img.tile_sz); + + // fix tiles to point at new palette pos + for (int i = 0; i < img.tile_sz; i += 64) { + for (int j = 0; j < 64; j++) { + tile_data[i + j] += pal_offset; + } + } + } + + // copy tiles to vram + version (USE_DMA) { + dma3_cpy(&tile_mem[cbb][0], tile_data, img.tile_sz); + } else { + memcpy32(&tile_mem[cbb][0], tile_data, img.tile_sz / 4); + } + + if (pal_offset > 0) { + // free the working tile data we copied + free(tile_data); + } +} + +void dusk_background_make(u8 bg_id, u16 size, Background bg) { + // set bg on screen enabled + enable_bg(bg_id); + // set control flags + vu16* bg_reg = dusk_get_background_register(bg_id); + + // u16 bpp_flag = (sprites_bpp8 == 1) ? BG_8BPP : BG_4BPP; + *bg_reg |= BG_CBB(bg.cbb) | BG_SBB(bg.sbb) | BG_8BPP | size; +} diff --git a/src/dusk/d_src/dusk/sys.d b/src/dusk/d_src/dusk/sys.d new file mode 100644 index 0000000..f64ef25 --- /dev/null +++ b/src/dusk/d_src/dusk/sys.d @@ -0,0 +1,90 @@ +module dusk.sys; + +extern(C): + +import core.stdc.stdio; +import tonc; +import dusk.load; + +struct Scene { + void function() start; + void function() end; + void function() update; +} + +// /** initialize the system for using DUSK */ +// void dusk_init_all(); +// /** initialize mode0 graphics */ +// void dusk_init_graphics_mode0(); +// /** initialize mode3 graphics */ +// void dusk_init_graphics_mode3(); +// /** vsync */ +// void dusk_frame(); +// void dusk_scene_set(Scene next); +// void dusk_scene_update(); + +__gshared static uint frame_count; + +void dusk_clear_vidmem() { + // clear video memory (vram region) + memset32(vid_mem, 0, VRAM_BG_SIZE / 4); + // pal mem + memset32(pal_bg_mem, 0, 0x00200 / 4); + memset32(pal_obj_mem, 0, 0x00200 / 4); +} + +void dusk_reset_irq() { + irq_init(null); + irq_add(IrqIndex.VBLANK, null); +} + +void dusk_init_all() { + // 1. initialize system graphics + dusk_init_graphics_mode0(); + + dusk_reset_irq(); + + // initialize loader + dusk_load_init(); +} + +void dusk_init_graphics_mode0() { + dusk_clear_vidmem(); + // dusk_reset_irq(); + + // reset registers + *REG_DISPCNT = DCNT_MODE0; + *REG_BG0CNT = 0; + *REG_BG1CNT = 0; + *REG_BG2CNT = 0; + *REG_BG3CNT = 0; +} + +void dusk_init_graphics_mode3() { *REG_DISPCNT = DCNT_MODE3 | DCNT_BG2; } + +void dusk_frame() { + // vid_vsync(); + VBlankIntrWait(); + frame_count++; +} + +__gshared static bool scene_changed = false; +__gshared static void nothing() {} + +__gshared static Scene next_scene = Scene(¬hing, ¬hing, ¬hing); +__gshared static Scene current_scene = Scene(¬hing, ¬hing, ¬hing); + +void dusk_scene_set(Scene next) { + scene_changed = true; + next_scene = next; +} + +void dusk_scene_update() { + if (scene_changed) { + scene_changed = false; + current_scene.end(); + current_scene = next_scene; + current_scene.start(); + } + current_scene.update(); +} diff --git a/src/dusk/include/contrib/gbamap.h b/src/dusk/include/contrib/gbamap.h index 6c2f3ae..92a7b86 100644 --- a/src/dusk/include/contrib/gbamap.h +++ b/src/dusk/include/contrib/gbamap.h @@ -1,24 +1,33 @@ #ifndef MAP_H #define MAP_H -#include "gbamap_object.h" +typedef struct { + unsigned short x, y; +} __attribute__((aligned(4))) ObjectPoint; + +typedef struct { + unsigned int id; + ObjectPoint position; + const char* name; + const char* type; +} MapObject; + +MapObject map_load_object(const unsigned short* object_data, unsigned short* index); +unsigned int map_load_object_id(const unsigned short* idData, unsigned short* index); +ObjectPoint map_load_object_position(const unsigned short* positionData, unsigned short* index); +const char* map_load_string(const unsigned short* stringData, unsigned short* index); +unsigned short map_pop_value(const unsigned short* data, unsigned short* index); + +void map_shift_objects(MapObject* objects, ObjectPoint shift, unsigned int count); typedef struct Map { - unsigned short sizeFlag, - paletteLength, - tileSetLength, - terrainMapLength, - numObjects, - numLayers, - tileMapLength; - - const unsigned short *palette, - *tileSet, - *terrainMap; + unsigned short sizeFlag, paletteLength, tileSetLength, terrainMapLength, numObjects, numLayers, tileMapLength; + + const unsigned short *palette, *tileSet, *terrainMap; MapObject objects[256]; - const unsigned short *tileMapLayers[3]; + const unsigned short* tileMapLayers[3]; } Map; typedef struct BackgroundPoint { @@ -29,7 +38,7 @@ typedef struct BackgroundPoint { #define ENTRIES_IN_SCREEN_BLOCK 512 #define NUM_SCREEN_BLOCKS 31 -Map map_load_from_rom(const unsigned short *map_data); +Map map_load_from_rom(const unsigned short* map_data); void map_init_registers(); void map_set_onscreen(Map map); diff --git a/src/dusk/include/contrib/gbamap_object.h b/src/dusk/include/contrib/gbamap_object.h deleted file mode 100644 index e666853..0000000 --- a/src/dusk/include/contrib/gbamap_object.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MAP_OBJECT_H -#define MAP_OBJECT_H - -typedef struct { - unsigned short x, y; -} __attribute__((aligned(4))) ObjectPoint; - -typedef struct -{ - unsigned int id; - ObjectPoint position; - const char* name; - const char* type; -} MapObject; - -MapObject map_load_object(const unsigned short* object_data, unsigned short* index); -unsigned int map_load_object_id(const unsigned short* idData, unsigned short* index); -ObjectPoint map_load_object_position(const unsigned short* positionData, unsigned short* index); -const char* map_load_string(const unsigned short* stringData, unsigned short* index); -unsigned short map_pop_value(const unsigned short* data, unsigned short* index); - -void map_shift_objects(MapObject* objects, ObjectPoint shift, unsigned int count); - -#endif \ No newline at end of file diff --git a/src/dusk/include/contrib/gbfs.d b/src/dusk/include/contrib/gbfs.d new file mode 100644 index 0000000..51ead63 --- /dev/null +++ b/src/dusk/include/contrib/gbfs.d @@ -0,0 +1,116 @@ +/* gbfs.h + access object in a GBFS file + +Copyright 2002 Damian Yerrick + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. + +*/ + +/* Dependency on prior include files + +Before you #include "gbfs.h", you should define the following types: + typedef (unsigned 16-bit integer) u16; + typedef (unsigned 32-bit integer) u32; +Your gba.h should do this for you. +*/ + +//\{ + +//\} + +/*! \name Volatile types +* Volatile types for registers +*/ +//\{ + +//\} + +/*! \name Const types +* Const types for const function aprameters +*/ +//\{ + +//\} + +//! 8-word type for fast struct-copies + +//! Type for consting a string as well as the pointer than points to it. + +extern (C): + +alias uchar = ubyte; +alias echar = ubyte; +alias hword = ushort; +alias eshort = ushort; +alias word = uint; +alias eint = uint; +alias vu8 = ubyte; +alias vu16 = ushort; +alias vu32 = uint; +alias vu64 = ulong; +alias vs8 = byte; +alias vs16 = short; +alias vs32 = int; +alias vs64 = long; +alias cu8 = const ubyte; +alias cu16 = const ushort; +alias cu32 = const uint; +alias cu64 = const ulong; +alias cs8 = const byte; +alias cs16 = const short; +alias cs32 = const int; +alias cs64 = const long; + +struct BLOCK +{ + uint[8] data; +} + +alias CSTR = const char*; + +/* to make a 300 KB space called samples do GBFS_SPACE(samples, 300) */ + +enum GBFS_ENTRY_SIZE = 24; + +struct GBFS_FILE +{ + char[16] magic; /* "PinEightGBFS\r\n\032\n" */ + uint total_len; /* total length of archive */ + ushort dir_off; /* offset in bytes to directory */ + ushort dir_nmemb; /* number of files */ + char[8] reserved; /* for future use */ +} + +struct GBFS_ENTRY +{ + char[GBFS_ENTRY_SIZE] name; /* filename, nul-padded */ + uint len; /* length of object in bytes */ + uint data_offset; /* in bytes from beginning of file */ +} + +const(GBFS_FILE)* find_first_gbfs_file (const(void)* start); +const(void)* skip_gbfs_file (const(GBFS_FILE)* file); +const(void)* gbfs_get_obj (const(GBFS_FILE)* file, const(char)* name, uint* len); +const(void)* gbfs_get_nth_obj (const(GBFS_FILE)* file, size_t n, char* name, uint* len); +void* gbfs_copy_obj (void* dst, const(GBFS_FILE)* file, const(char)* name); +size_t gbfs_count_objs (const(GBFS_FILE)* file); + diff --git a/src/dusk/include/ds_load.h b/src/dusk/include/ds_load.h deleted file mode 100644 index 259befa..0000000 --- a/src/dusk/include/ds_load.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - DUSK: LOADER -*/ - -#pragma once - -#include "contrib/gbfs.h" -#include "contrib/gbamap.h" - -extern const GBFS_FILE* gbfs_dat; - -// represents an atlas, with bitmaps for the image and palette -typedef struct SpriteAtlas { - u32* tiles; - u32 tile_sz; - u32* pal; - u32 pal_sz; -} SpriteAtlas; - -typedef struct GritImage { - u32* tiles; - u32 tile_sz; - u32* pal; - u32 pal_sz; - u32* map; - u32 map_sz; -} GritImage; - -#define ATLAS_ENTRY_LEN 6 - -/** represents a single entry in the sprite atlas. - * note that names are limited to just 5 chars and a NULL terminator. */ -typedef struct SpriteAtlasEntry { - char name[ATLAS_ENTRY_LEN]; - // all of these are in tiles (8px) - u8 x; - u8 y; - u8 w; - u8 h; -} SpriteAtlasEntry; - -/** represents the layout of items in an atlas (https://github.com/xdrie/crunch#binary-format). - * we only use the first texture because the vram can only hold one */ -typedef struct SpriteAtlasLayout { - u16 width; - u16 height; - u16 num_entries; - SpriteAtlasEntry* entries; -} SpriteAtlasLayout; - -/** initialize loader */ -void dusk_load_init(); - -// - CONTENT LOADERS: pass filename without extension - -const void* dusk_load_raw(char* name, u32* len); -GritImage dusk_load_image(char* name); -SpriteAtlas dusk_load_atlas(char* name); -SpriteAtlasLayout dusk_load_atlas_layout(const char* name); -SpriteAtlasEntry* dusk_load_atlas_entry(SpriteAtlasLayout* layout, const char* entry_name); -void dusk_free_atlas_layout(SpriteAtlasLayout* layout); - -Map dusk_load_map(char* name); \ No newline at end of file diff --git a/src/dusk/include/ds_sav.h b/src/dusk/include/ds_sav.h deleted file mode 100644 index 7144094..0000000 --- a/src/dusk/include/ds_sav.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - DUSK: SAVE UTIL -*/ - -#pragma once - -// utilities for saving and loading vars - -#define SV_LOAD_ITEM(var, offset) \ - memcpy(&var, sram_mem + offset, sizeof(typeof(var))); \ - offset += sizeof(typeof(var)); - -#define SV_SAVE_ITEM(var, offset) \ - memcpy(sram_mem + offset, &var, sizeof(typeof(var))); \ - offset += sizeof(typeof(var)); - -// utilities for saving and loading vars \ No newline at end of file diff --git a/src/dusk/include/ds_spr.h b/src/dusk/include/ds_spr.h deleted file mode 100644 index bb1a806..0000000 --- a/src/dusk/include/ds_spr.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - DUSK: SPRITES -*/ - -#pragma once - -#include -#include -#include "ds_load.h" - -#define NUM_SPRITES 128 -#define NUM_AFFINE_SPRITES 32 -extern OBJ_ATTR obj_buffer[NUM_SPRITES]; -extern OBJ_AFFINE* obj_aff_buffer; - -#define SPRITEFLAG_PRIORITY_SHIFT 6 -#define SPRITEFLAG_PRIORITY_GET(n) ((n >> SPRITEFLAG_PRIORITY_SHIFT) & 0b11) -#define SPRITEFLAG_PRIORITY(n) ((n << SPRITEFLAG_PRIORITY_SHIFT) & 0b11) - -#define DUSKSPRITE_FLAGS_VISIBLE (0x1 << 0) -/** sprite data */ -typedef struct Sprite { - s16 x, y; - /** the number of tiles taken up by this sprite */ - u8 tile_sz; - /** the raw tid of the top left corner tile of spritesheet frame 0 */ - u16 base_tid; - /** the frame index of the spritesheet */ - u8 page; - /** flags: 0/0/0/0/0/0/0/visible */ - u8 flags; -} Sprite; - -/** animation metadata */ -typedef struct Anim { - /** which page in the sprite the animation starts */ - u8 start; - /** number of pages in this animation */ - u8 len; - /** (60/fps), or how many frames each page lasts */ - u8 rate; -} Anim; - -/** background data */ -typedef struct Background { - s16 x, y; - int cbb, sbb; -} Background; - -/** define an animation, given a starting frame and frame count, and fps */ -#define MAKE_ANIM_EX(st, le, fps) \ - (Anim) { .start = st, .len = le, .rate = (60 / fps) } -/** define an animation, given a starting frame and frame count, at 10 fps */ -#define MAKE_ANIM(st, le) MAKE_ANIM_EX(st, le, 10) - -/** memory block used to track sprites */ -extern Sprite sprites[NUM_SPRITES]; - -/** initialize sprite and OAM memory */ -void dusk_sprites_init(); -/** set mode options for dusk sprites */ -void dusk_sprites_configure(BOOL bpp8); -/** upload a sprite atlas to tile and palette memory */ -void dusk_sprites_upload_atlas(SpriteAtlas* atlas); -/** upload a sprite atlas section to tile and palette memory */ -void dusk_sprites_upload_atlas_section(SpriteAtlasLayout* layout, SpriteAtlas* atlas, SpriteAtlasEntry* entry, u16 pal_offset, u16 tile_offset); -/** create a sprite and store it in index of sprite memory */ -Sprite* dusk_sprites_make(int index, u8 width, u8 height, Sprite spr); -/** synchronize a sprite from the sprites array to OAM block (vram) */ -void dusk_sprites_sync(int index); -/** synchronize all sprites to OAM block, then upload OAM block to vram */ -void dusk_sprites_update(); -/** play an animation on a sprite */ -void dusk_sprites_anim_play(Sprite* spr, Anim* anim); -/** calculate the tid of a sprite given pos and sheet dimens */ -u16 dusk_sprites_pos_to_tid(u16 x, u16 y, u16 sheet_width, u16 sheet_height); -/** upload image data to background tile vram */ -void dusk_background_upload_raw(GritImage* img, int cbb, int sbb); -/** create a background and display it */ -void dusk_background_make(u8 bg_id, u16 size, Background bg); \ No newline at end of file diff --git a/src/dusk/include/ds_sys.h b/src/dusk/include/ds_sys.h deleted file mode 100644 index d7c8afb..0000000 --- a/src/dusk/include/ds_sys.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - DUSK: SYSTEM -*/ - -#pragma once - -extern uint frame_count; - -typedef struct Scene { - void (*start)(void); - void (*end)(void); - void (*update)(void); -} Scene; - -/** initialize the system for using DUSK */ -void dusk_init_all(); -/** initialize mode0 graphics */ -void dusk_init_graphics_mode0(); -/** initialize mode3 graphics */ -void dusk_init_graphics_mode3(); -/** vsync */ -void dusk_frame(); -void dusk_scene_set(Scene next); -void dusk_scene_update(); \ No newline at end of file diff --git a/src/dusk/include/dusk.h b/src/dusk/include/dusk.h deleted file mode 100644 index b1168f3..0000000 --- a/src/dusk/include/dusk.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - DUSK: MASTER HEADER -*/ - -#pragma once - -#include -#include "ds_load.h" -#include "ds_sys.h" -#include "ds_spr.h" -#include "ds_sav.h" \ No newline at end of file diff --git a/src/dusk/src/contrib/background.h b/src/dusk/src/contrib/background.h deleted file mode 100644 index 1eafaf2..0000000 --- a/src/dusk/src/contrib/background.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef BACKGROUND_H -#define BACKGROUND_H - -#include "./video.h" - -/** - * Defines the background control. - */ - -typedef u16 ScreenEntry; - -typedef struct { - u32 data[8]; -} Tile; - -typedef ScreenEntry ScreenBlock[1024]; -typedef Tile CharBlock[512]; - -#define MEMORY_BACKGROUND_PALETTE ((Color*)MEMORY_PALETTE) -#define MEMORY_BACKGROUND_PALETTE_SIZE 0x00200 - -#define MEMORY_SCREEN_BLOCK ((ScreenBlock*)MEMORY_VIDEORAM) -#define MEMORY_CHAR_BLOCK ((CharBlock*)MEMORY_VIDEORAM) - -#define REGISTER_BACKGROUND_CONTROL ((vu16*)(REGISTER_BASE+0x0008)) -#define REGISTER_BACKGROUND_OFFSET ((BackgroundPoint*)(REGISTER_BASE+0x0010)) - -#define FLAG_BACKGROUND_4BPP 0 -#define FLAG_BACKGROUND_8BPP 0x0080 -#define FLAG_BACKGROUND_REGULAR_32x32 0 -#define FLAG_BACKGROUND_REGULAR_64x32 0x4000 -#define FLAG_BACKGROUND_REGULAR_32x64 0x8000 -#define FLAG_BACKGROUND_REGULAR_64x64 0xC000 - -#define MASK_FLAG_BACKGROUND_CHAR_BLOCK 0x000C -#define SHIFT_FLAG_BACKGROUND_CHAR_BLOCK 2 -#define FLAG_BACKGROUND_CHAR_BLOCK(n) ((n)<>name##_SHIFT ) -#define BIT_FIELD_SET(y, x, name) (y = ((y)&~name##_MASK) | BIT_FIELD_PREP(x,name) ) - -#endif \ No newline at end of file diff --git a/src/dusk/src/contrib/initMapRegisters.c b/src/dusk/src/contrib/initMapRegisters.c deleted file mode 100644 index e626227..0000000 --- a/src/dusk/src/contrib/initMapRegisters.c +++ /dev/null @@ -1,12 +0,0 @@ -#include "gbamap.h" -#include "./background.h" - -void map_init_registers() { - // turn off all backgrounds - for (u32 layerIndex = MAX_LAYERS; layerIndex-- > 0;) { - REGISTER_BACKGROUND_CONTROL[layerIndex] = 0; - } - - // reset display control - REGISTER_DISPLAY_CONTROL = 0; -} \ No newline at end of file diff --git a/src/dusk/src/contrib/loadMapFromROM.c b/src/dusk/src/contrib/loadMapFromROM.c deleted file mode 100644 index e83b833..0000000 --- a/src/dusk/src/contrib/loadMapFromROM.c +++ /dev/null @@ -1,43 +0,0 @@ -#include "gbamap.h" -#include -#include "./types.h" - -Map map_load_from_rom(const u16 *map_data) { - Map map; - u16 index = 0; - - map.sizeFlag = map_data[index++]; - - map.paletteLength = map_data[index++]; - map.palette = &map_data[index]; - index += map.paletteLength + 1; - - map.tileSetLength = map_data[index++]; - map.tileSet = &map_data[index]; - index += map.tileSetLength + 1; - - map.terrainMapLength = map_data[index++]; - map.terrainMap = &map_data[index]; - index += map.terrainMapLength; - - map.numLayers = map_data[index++]; - map.numLayers = map.numLayers > MAX_LAYERS ? MAX_LAYERS : map.numLayers; - map.tileMapLength = map_data[index++]; - for (u32 layerIndex = 0; layerIndex < map.numLayers; ++layerIndex) - { - map.tileMapLayers[layerIndex] = &map_data[index]; - index += map.tileMapLength; - } - - u16 lengthObjectData = map_data[index++]; - u32 endObjectData = index + lengthObjectData; - u32 objectCount = 0; - while (index != endObjectData) { - MapObject object = map_load_object(map_data, &index); - map.objects[objectCount] = object; - objectCount++; - } - map.numObjects = objectCount; - - return map; -} diff --git a/src/dusk/src/contrib/loadObject.c b/src/dusk/src/contrib/loadObject.c deleted file mode 100644 index 7cedb1c..0000000 --- a/src/dusk/src/contrib/loadObject.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "gbamap_object.h" -#include "./types.h" - -MapObject map_load_object(const u16* object_data, u16* index) { - MapObject object; - object.id = map_load_object_id(object_data, index); - object.position = map_load_object_position(object_data, index); - object.name = map_load_string(object_data, index); - object.type = map_load_string(object_data, index); - return object; -} \ No newline at end of file diff --git a/src/dusk/src/contrib/loadObjectID.c b/src/dusk/src/contrib/loadObjectID.c deleted file mode 100644 index 4329f2a..0000000 --- a/src/dusk/src/contrib/loadObjectID.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "gbamap_object.h" -#include "./types.h" - -u32 map_load_object_id(const u16* idData, u16* index) { - u32 upperID = map_pop_value(idData, index); - u32 lowerID = map_pop_value(idData, index); - return (upperID << 16) | lowerID; -} \ No newline at end of file diff --git a/src/dusk/src/contrib/loadPosition.c b/src/dusk/src/contrib/loadPosition.c deleted file mode 100644 index cc01073..0000000 --- a/src/dusk/src/contrib/loadPosition.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "gbamap_object.h" -#include "./types.h" - -ObjectPoint map_load_object_position(const u16* positionData, u16* index) { - ObjectPoint position; - position.x = map_pop_value(positionData, index); - position.y = map_pop_value(positionData, index); - return position; -} \ No newline at end of file diff --git a/src/dusk/src/contrib/loadString.c b/src/dusk/src/contrib/loadString.c deleted file mode 100644 index c3c98cc..0000000 --- a/src/dusk/src/contrib/loadString.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "gbamap_object.h" -#include "./types.h" - -const char* map_load_string(const u16* stringData, u16* index) { - u16 length = map_pop_value(stringData, index); - const char* string = (const char*) &stringData[*index]; - *index += length; - return string; -} \ No newline at end of file diff --git a/src/dusk/src/contrib/memoryMap.h b/src/dusk/src/contrib/memoryMap.h deleted file mode 100644 index 11e1bef..0000000 --- a/src/dusk/src/contrib/memoryMap.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef MEMORY_MAP_H -#define MEMORY_MAP_H - -#include "types.h" - -/** - * Defines the general memory locations. - */ - -#define MEMORY_IO 0x04000000 -#define MEMORY_PALETTE 0x05000000 -#define MEMORY_VIDEORAM 0x06000000 -#define MEMORY_OBJECT_ATTRIBUTES 0x07000000 - -#define REGISTER_BASE MEMORY_IO - -#endif // MEMORY_MAP_H diff --git a/src/dusk/src/contrib/popValue.c b/src/dusk/src/contrib/popValue.c deleted file mode 100644 index a797d7b..0000000 --- a/src/dusk/src/contrib/popValue.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "gbamap_object.h" -#include "./types.h" - -u16 map_pop_value(const u16* data, u16* index) { - u16 value = data[*index]; - *index += 1; - return value; -} \ No newline at end of file diff --git a/src/dusk/src/contrib/setMapOnScreen.c b/src/dusk/src/contrib/setMapOnScreen.c deleted file mode 100644 index 05d21c7..0000000 --- a/src/dusk/src/contrib/setMapOnScreen.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "./background.h" -#include "gbamap.h" -#include - -void map_set_onscreen(Map map) { - memcpy(MEMORY_BACKGROUND_PALETTE, map.palette, map.paletteLength * 2); - memcpy(&MEMORY_CHAR_BLOCK[0][0], map.tileSet, map.tileSetLength * 2); - - u32 screenBlockStep = map.tileMapLength / ENTRIES_IN_SCREEN_BLOCK; - u32 usedBackgrounds = 0x00; - for (u32 layerIndex = map.numLayers; layerIndex-- > 0;) - { - u32 screenBlockIndex = NUM_SCREEN_BLOCKS - screenBlockStep * (layerIndex + 1); - memcpy(&MEMORY_SCREEN_BLOCK[screenBlockIndex][0], map.tileMapLayers[layerIndex], map.tileMapLength * 2); - - REGISTER_BACKGROUND_CONTROL[layerIndex] |= FLAG_BACKGROUND_CHAR_BLOCK(0) | - FLAG_BACKGROUND_SCREEN_BLOCK(screenBlockIndex) | - FLAG_BACKGROUND_8BPP | - map.sizeFlag | - FLAG_BACKGROUND_PRIORITY(map.numLayers - layerIndex); - usedBackgrounds |= FLAG_BACKGROUND(layerIndex); - } - - REGISTER_DISPLAY_CONTROL |= FLAG_MODE0 | usedBackgrounds; -} diff --git a/src/dusk/src/contrib/shiftMap.c b/src/dusk/src/contrib/shiftMap.c deleted file mode 100644 index 7856ad9..0000000 --- a/src/dusk/src/contrib/shiftMap.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "gbamap.h" -#include "./background.h" - -void map_shift(Map map, BackgroundPoint offset) -{ - for (u16 layer = 0; layer < map.numLayers; layer++) - map_shift_layer(layer, offset); -} diff --git a/src/dusk/src/contrib/shiftMapLayer.c b/src/dusk/src/contrib/shiftMapLayer.c deleted file mode 100644 index 51d6050..0000000 --- a/src/dusk/src/contrib/shiftMapLayer.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "./background.h" -#include "gbamap.h" - -void map_shift_layer(u16 layer, BackgroundPoint offset) -{ - REGISTER_BACKGROUND_OFFSET[layer] = offset; -} diff --git a/src/dusk/src/contrib/shiftMapObjects.c b/src/dusk/src/contrib/shiftMapObjects.c deleted file mode 100644 index f85434c..0000000 --- a/src/dusk/src/contrib/shiftMapObjects.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "gbamap_object.h" -#include "./types.h" - -void map_shift_objects(MapObject* objects, ObjectPoint shift, u32 count) -{ - for (u32 index = 0; index < count; index++) - { - objects[index].position.x -= shift.x; - objects[index].position.y -= shift.y; - } -} \ No newline at end of file diff --git a/src/dusk/src/contrib/types.h b/src/dusk/src/contrib/types.h deleted file mode 100644 index fabd40f..0000000 --- a/src/dusk/src/contrib/types.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef TYPES_H -#define TYPES_H - -/** - * Defines general data types and useful macros. - */ - -typedef unsigned char u8, byte; -typedef unsigned short u16, hword; -typedef unsigned int u32, word; -typedef unsigned long long u64; - -typedef signed char s8; -typedef signed short s16; -typedef signed int s32; -typedef signed long long s64; - -typedef volatile u8 vu8; -typedef volatile u16 vu16; -typedef volatile u32 vu32; -typedef volatile u64 vu64; - -typedef volatile s8 vs8; -typedef volatile s16 vs16; -typedef volatile s32 vs32; -typedef volatile s64 vs64; - -#define INLINE static inline -#define ALIGN(n) __attribute__((aligned(n))) - -#define TRUE 1 -#define FALSE 0 - -#endif // TYPES_H diff --git a/src/dusk/src/contrib/video.h b/src/dusk/src/contrib/video.h deleted file mode 100644 index 7b4e22e..0000000 --- a/src/dusk/src/contrib/video.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef VIDEO_H -#define VIDEO_H - -#include "./memoryMap.h" - -/** - * Defines general video control. - */ - -typedef u16 Color; - -#define SCREEN_WIDTH 240 -#define SCREEN_HEIGHT 160 - -#define REGISTER_DISPLAY_CONTROL *(vu32*)(REGISTER_BASE+0x0000) -#define REGISTER_VERTICAL_COUNT *(vu16*)(REGISTER_BASE+0x0006) - -#define FLAG_MODE0 0 - -/** - * Wait till the background has been rendered and it is safe to modify it. - **/ -INLINE void videoSync() -{ - while(REGISTER_VERTICAL_COUNT >= 160); - while(REGISTER_VERTICAL_COUNT < 160); -} - -#endif // VIDEO_H diff --git a/src/dusk/src/sprites.c b/src/dusk/src/sprites.c deleted file mode 100644 index cdf6fa2..0000000 --- a/src/dusk/src/sprites.c +++ /dev/null @@ -1,269 +0,0 @@ -#include "ds_spr.h" -#include "ds_sys.h" -#include -#include "stdio.h" - -EWRAM_DATA OBJ_ATTR obj_buffer[NUM_SPRITES]; -OBJ_AFFINE* obj_aff_buffer = (OBJ_AFFINE*)obj_buffer; - -EWRAM_DATA Sprite sprites[NUM_SPRITES]; - -/** when true, 8BPP, when false, 4BPP */ -BOOL sprites_bpp8 = TRUE; - -void dusk_sprites_init() { - // initialize object buffer - oam_init(obj_buffer, NUM_SPRITES); - memset(sprites, 0, sizeof(Sprite) * NUM_SPRITES); - - // reset bpp to default - sprites_bpp8 = TRUE; - - // enable sprite display - REG_DISPCNT |= DCNT_OBJ | DCNT_OBJ_1D; -} - -void dusk_sprites_configure(BOOL bpp8) { sprites_bpp8 = bpp8; } - -void dusk_sprites_upload_atlas(SpriteAtlas* atlas) { - // 1. upload the atlas tile palette to palette memory - // object/sprite palette, in 8bpp stores 256 colors - memcpy(&pal_obj_bank[0], atlas->pal, atlas->pal_sz); - // 2. upload the atlas tiles to tile memory - // tile memory (can store 1024 tiles (32x32 tiles or 256x256px) - // VRAM is charblocks 4 and 5, so &tile_mem[4][0] points to the first tile in object VRAM - memcpy(&tile_mem[4][0], atlas->tiles, atlas->tile_sz); -} - -void dusk_sprites_upload_atlas_section(SpriteAtlasLayout* layout, SpriteAtlas* atlas, SpriteAtlasEntry* entry, - u16 pal_offset, u16 tile_offset) { - - // 1. upload the palette (palettes are 16-bit highcolor) - memcpy(&pal_obj_bank[0][pal_offset], &atlas->pal[0], atlas->pal_sz); - - // pal_obj_bank[0][4] = CLR_YELLOW; - // 2. upload the tiles - int entry_firsttid = - dusk_sprites_pos_to_tid(entry->x, entry->y, layout->width, layout->height); // tid of entry start in atlas - int entry_tilecount = (entry->w) * (entry->h); // entry size in tiles - int raw_firsttid = entry_firsttid * entry_tilecount * 2; // read offset - // int raw_tilecount = entry_tilecount * 2; - int raw_tileoffset = tile_offset * 2; // write offset - - // printf("ro: %d. wo: %d, n: %d\n", raw_firsttid, raw_tileoffset, raw_tilecount); // debug print tile r/w - - // memcpy(&tile_mem[4][raw_tileoffset], &atlas->tiles[raw_firsttid], entry_tilecount * 64); - - // 3. fix tiles to point at right palette - // for (int i = 0; i < raw_tilecount; i += 2) { - // TILE8 new_tile; - // // TILE8 tile.data consists of 16 u32s (a total of 64 bytes) - // // new_tile.data[j] = atlas->tiles[(entry_firsttid + i) * 2]; - // u32* rt = &atlas->tiles[raw_firsttid + i]; // read tile - - // for (int j = 0; j < 16; j++) { - // new_tile.data[j] = rt[j]; - // // new_tile.data[j] = 0x04040404; - // } - // // copy in tile - // memcpy(&tile_mem[4][raw_tileoffset + i], &new_tile, 64); - // } - - // unroll malloc - // memcpy(&tile_mem[4][raw_tileoffset], &atlas->tiles[raw_firsttid], 64); - - // reinterpret as byte pointers - u8* loc_twrite = (u8*)&tile_mem[4][raw_tileoffset]; - u8* loc_tread = (u8*)&atlas->tiles[raw_firsttid]; - for (int i = 0; i < entry_tilecount; i += 1) { - int c = i * 64; - u8 tile[64]; // create temp tile - memcpy(&tile[0], loc_tread + c, 64); // read tile - - // fix tile - for (int j = 0; j < 64; j++) { - tile[j] = tile[j] + pal_offset; - } - - memcpy(loc_twrite + c, &tile[0], 64); // write tile - } -} - -Sprite* dusk_sprites_make(int index, u8 width, u8 height, Sprite spr) { - // automatically figure out sprite size/shape attributes - u16 shape_attr = 0; - if (height > width) { - shape_attr = ATTR0_TALL; - } else if (width > height) { - shape_attr = ATTR0_WIDE; - } else if (width == height) { - shape_attr = ATTR0_SQUARE; - } - u16 size_attr = 0; - if (shape_attr == ATTR0_TALL) { - if (width == 8 && height == 16) - size_attr = ATTR1_SIZE_8x16; - if (width == 8 && height == 32) - size_attr = ATTR1_SIZE_8x32; - if (width == 16 && height == 32) - size_attr = ATTR1_SIZE_16x32; - if (width == 16 && height == 64) - size_attr = ATTR1_SIZE_32x64; - } - if (shape_attr == ATTR0_WIDE) { - if (width == 16 && height == 8) - size_attr = ATTR1_SIZE_16x8; - if (width == 32 && height == 8) - size_attr = ATTR1_SIZE_32x8; - if (width == 32 && height == 16) - size_attr = ATTR1_SIZE_32x16; - if (width == 64 && height == 32) - size_attr = ATTR1_SIZE_64x32; - } - if (shape_attr == ATTR0_SQUARE) { - if (width == 8 && height == 8) - size_attr = ATTR1_SIZE_8x8; - if (width == 16 && height == 16) - size_attr = ATTR1_SIZE_16x16; - if (width == 32 && height == 32) - size_attr = ATTR1_SIZE_32x32; - if (width == 64 && height == 64) - size_attr = ATTR1_SIZE_64x64; - } - - // calculate the number of tiles used by one frame of this sprite (divide width and height by 8) - spr.tile_sz = (width >> 3) * (height >> 3); - - // set main attributes - // leave tile id (attr2) null, it will be set in sync - u16 bpp_flag = (sprites_bpp8 == 1) ? ATTR0_8BPP : ATTR0_4BPP; - obj_set_attr(&obj_buffer[index], ATTR0_REG | shape_attr | bpp_flag, size_attr, 0); - - // set default flags - spr.flags = (DUSKSPRITE_FLAGS_VISIBLE); - - // save sprite metadata - sprites[index] = spr; - - // sync other attributes - dusk_sprites_sync(index); - - // return pointer to this sprite - return &sprites[index]; -} - -inline void dusk_sprites_sync(int i) { - Sprite* sprite = &sprites[i]; - OBJ_ATTR* obj = &obj_buffer[i]; - // position - obj_set_pos(obj, sprite->x, sprite->y); - - // visibility - if ((sprite->flags & DUSKSPRITE_FLAGS_VISIBLE) > 0) { - obj_unhide(obj, ATTR0_REG); - } else { - obj_hide(obj); - } - - // main attrs - - // logical base tid mode - // obj_set_attr(obj, obj->attr0, obj->attr1, (sprite->tid + sprite->page) * sprite->tile_sz * 2); - - // raw base tid mode - int bpp_mult = (sprites_bpp8 == 1) ? 2 : 1; - u16 tid = (sprite->base_tid + (sprite->page * sprite->tile_sz)) * bpp_mult; - obj_set_attr(obj, obj->attr0, obj->attr1, ATTR2_ID(tid) | ATTR2_PALBANK(0)); -} - -void dusk_sprites_update() { - // sync all sprites - for (int i = 0; i < NUM_SPRITES; i++) { - dusk_sprites_sync(i); - } - - // upload shadow oam to vram - - oam_copy(oam_mem, obj_buffer, NUM_SPRITES); - // CpuFastSet(obj_buffer, oam_mem, NUM_SPRITES * 2); -} - -void dusk_sprites_anim_play(Sprite* spr, Anim* anim) { - // make sure page is within anim range - if (spr->page < anim->start || spr->page >= (anim->start + anim->len)) { - spr->page = anim->start; // reset to first - } - int ix = spr->page - anim->start; - if (frame_count % anim->rate == 0) { - ix = (ix + 1) % anim->len; - } - // set new frame - spr->page = anim->start + ix; -} - -u16 dusk_sprites_pos_to_tid(u16 x, u16 y, u16 sheet_width, u16 sheet_height) { - // calculate corner tile id - // first get x and y in tile coords - u16 xt = x; - u16 yt = y; - u16 imw = sheet_width >> 3; // compute with bitshift (sheet_width / 8) - // u16 imh = sheet_height >> 3; - u16 tid = (yt * imw) + xt; - return tid; -} - -void enable_bg(u8 bg_id) { - int bg_flag = 0; - switch (bg_id) { - case 0: - bg_flag = DCNT_BG0; - break; - case 1: - bg_flag = DCNT_BG1; - break; - case 2: - bg_flag = DCNT_BG2; - break; - case 3: - bg_flag = DCNT_BG3; - break; - } - - REG_DISPCNT |= bg_flag; -} - -vu16* dusk_get_background_register(u8 bg_id) { - switch (bg_id) { - case 0: - return ®_BG0CNT; - case 1: - return ®_BG1CNT; - case 2: - return ®_BG2CNT; - case 3: - return ®_BG3CNT; - default: - return NULL; - } -} - -void dusk_background_upload_raw(GritImage* img, int cbb, int sbb) { - // TODO: support selecting slot - - // 1. upload the atlas tile palette to bg palette memory - memcpy(&pal_bg_bank[0], img->pal, img->pal_sz); - // 2. upload the atlas tiles to bg tile memory (CBB) - memcpy(&tile_mem[cbb][0], img->tiles, img->tile_sz); - // 3. upload the map (SBB) - memcpy(&se_mem[sbb][0], img->map, img->map_sz); -} - -void dusk_background_make(u8 bg_id, u16 size, Background bg) { - // set bg on screen enabled - enable_bg(bg_id); - // set control flags - vu16* bg_reg = dusk_get_background_register(bg_id); - - // u16 bpp_flag = (sprites_bpp8 == 1) ? BG_8BPP : BG_4BPP; - *bg_reg |= BG_CBB(bg.cbb) | BG_SBB(bg.sbb) | BG_8BPP | size; -} \ No newline at end of file diff --git a/src/dusk/src/sys.c b/src/dusk/src/sys.c deleted file mode 100644 index c844472..0000000 --- a/src/dusk/src/sys.c +++ /dev/null @@ -1,79 +0,0 @@ -#include "stdio.h" -#include -#include "ds_sys.h" -#include "ds_load.h" - -__attribute__((used)) const char* _DUSK_LIB_VERSION = ("$DUSK " DUSK_VERSION); - -uint frame_count; - -void dusk_clear_vidmem() { - // clear video memory (vram region) - memset32(vid_mem, 0, VRAM_BG_SIZE / 4); - // pal mem - memset32(pal_bg_mem, 0, 0x00200 / 4); - memset32(pal_obj_mem, 0, 0x00200 / 4); -} - -void dusk_reset_irq() { - irq_init(NULL); - irq_add(II_VBLANK, NULL); -} - -void dusk_init_all() { - // 1. initialize system graphics - dusk_init_graphics_mode0(); - - dusk_reset_irq(); - - // initialize loader - dusk_load_init(); -} - -void dusk_init_graphics_mode0() { - dusk_clear_vidmem(); - // dusk_reset_irq(); - - // reset registers - REG_DISPCNT = DCNT_MODE0; - REG_BG0CNT = 0; - REG_BG1CNT = 0; - REG_BG2CNT = 0; - REG_BG3CNT = 0; -} - -void dusk_init_graphics_mode3() { REG_DISPCNT = DCNT_MODE3 | DCNT_BG2; } - -void dusk_frame() { - // vid_vsync(); - VBlankIntrWait(); - frame_count++; -} - -static bool scene_changed = false; -static void nothing(void) {} -static Scene next_scene = { - .start = nothing, - .end = nothing, - .update = nothing, -}; -static Scene current_scene = { - .start = nothing, - .end = nothing, - .update = nothing, -}; - -void dusk_scene_set(Scene next) { - scene_changed = true; - next_scene = next; -} - -void dusk_scene_update() { - if (scene_changed) { - scene_changed = false; - current_scene.end(); - current_scene = next_scene; - current_scene.start(); - } - current_scene.update(); -}