diff --git a/src/Makefile b/src/Makefile index 9762848b3..991111110 100644 --- a/src/Makefile +++ b/src/Makefile @@ -22,6 +22,8 @@ # - Android (ARM, ARM64) # > PLATFORM_DREAMCAST: # - Sega Dreamcast (SH4) +# > PLATFORM_NINTENDO64: +# - Nintendo 64 (MIPS4300) # # Many thanks to Milan Nikolic (@gen2brain) for implementing Android platform pipeline. # Many thanks to Emanuele Petriglia for his contribution on GNU/Linux pipeline. @@ -52,7 +54,7 @@ # Define required environment variables #------------------------------------------------------------------------------------------------ -# Define target platform: PLATFORM_DESKTOP, PLATFORM_DRM, PLATFORM_ANDROID, PLATFORM_WEB, PLATFORM_DREAMCAST +# Define target platform: PLATFORM_DESKTOP, PLATFORM_DRM, PLATFORM_ANDROID, PLATFORM_WEB, PLATFORM_DREAMCAST, PLATFORM_NINTENDO64 PLATFORM ?= PLATFORM_DREAMCAST # Define required raylib variables @@ -224,6 +226,12 @@ ifeq ($(PLATFORM),PLATFORM_DREAMCAST) PLATFORM_SHELL = sh endif +#Nintendo64 +ifeq ($(PLATFORM),PLATFORM_NINTENDO64) + PLATFORM_OS = NINTENDO64 + PLATFORM_SHELL = sh +endif + # Define raylib graphics api depending on selected platform ifeq ($(PLATFORM),PLATFORM_DESKTOP) # By default use OpenGL 3.3 on desktop platforms @@ -255,6 +263,12 @@ ifeq ($(PLATFORM),PLATFORM_DREAMCAST) # By default use OpenGL 1.1 on DREAMCAST GRAPHICS = GRAPHICS_API_OPENGL_11 endif + +ifeq ($(PLATFORM),PLATFORM_NINTENDO64) + # By default use OpenGL 1.1 on NINTENDO64 + GRAPHICS = GRAPHICS_API_OPENGL_11 +endif + # Define default C compiler and archiver to pack library: CC, AR #------------------------------------------------------------------------------------------------ CC = gcc @@ -302,6 +316,12 @@ ifeq ($(PLATFORM),PLATFORM_ANDROID) AR = $(ANDROID_TOOLCHAIN)/bin/llvm-ar endif +ifeq ($(PLATFORM),PLATFORM_NINTENDO64) +include $(N64_INST)/include/raylib4Nintendo64.mk + CC = $(N64_CC) + AR = $(N64_AR) +endif + ifeq ($(PLATFORM),PLATFORM_DREAMCAST) CC = $(KOS_CC) AR = $(KOS_AR) @@ -453,6 +473,11 @@ endif #------------------------------------------------------------------------------------------------ INCLUDE_PATHS = -I. +ifeq ($(PLATFORM),PLATFORM_NINTENDO64) + CFLAGS = $(N64_CFLAGS) -D$(PLATFORM) -D$(GRAPHICS) + INCLUDE_PATHS = $(N64_INCLUDEDIR) +endif + ifeq ($(PLATFORM),PLATFORM_DREAMCAST) CFLAGS = $(KOS_CFLAGS) -D$(PLATFORM) -D$(GRAPHICS) INCLUDE_PATHS = $(KOS_INC_PATHS) @@ -765,6 +790,9 @@ android_native_app_glue.o : $(NATIVE_APP_GLUE)/android_native_app_glue.c # RAYLIB_INSTALL_PATH should be the desired full path to libraylib. No relative paths. #DESTDIR ?= /usr/local +ifeq ($(PLATFORM),PLATFORM_NINTENDO64) +PREFIX ?= $(N64_ROOTDIR)/mips64-elf +endif ifeq ($(PLATFORM),PLATFORM_DREAMCAST) PREFIX ?= $(KOS_PORTS) endif diff --git a/src/config.h b/src/config.h index 4c230c2d2..f70d6ab77 100644 --- a/src/config.h +++ b/src/config.h @@ -154,7 +154,7 @@ #define SUPPORT_FILEFORMAT_GIF 1 #define SUPPORT_FILEFORMAT_QOI 1 //#define SUPPORT_FILEFORMAT_PSD 1 -#define SUPPORT_FILEFORMAT_DDS 1 +//#define SUPPORT_FILEFORMAT_DDS 1 //#define SUPPORT_FILEFORMAT_HDR 1 //#define SUPPORT_FILEFORMAT_PIC 1 //#define SUPPORT_FILEFORMAT_KTX 1 diff --git a/src/platforms/rcore_nintendo64.c b/src/platforms/rcore_nintendo64.c new file mode 100644 index 000000000..f90ce1b5f --- /dev/null +++ b/src/platforms/rcore_nintendo64.c @@ -0,0 +1,707 @@ +/********************************************************************************************** +* +* rcore_dreamcast - Functions to manage window, graphics device and inputs +* +* PLATFORM: NINTENDO64 +* - Nintendo 64 +* +* LIMITATIONS: +* - Limitation 01 +* - Limitation 02 +* +* POSSIBLE IMPROVEMENTS: +* - Improvement 01 +* - Improvement 02 +* +* ADDITIONAL NOTES: +* - Port done by Antonio Jose Ramos Marquez aka bigboss @psxdev +* +* CONFIGURATION: +* #define RCORE_PLATFORM_CUSTOM_FLAG +* Custom flag for rcore on target platform -not used- +* +* DEPENDENCIES: +* Nintendo64 libdragon and toolchains - Provides C API to access Nintendo 64 homebrew functionality +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2013-2023 Ramon Santamaria (@raysan5) and contributors +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ +#include + +#include +#include +#include + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef struct rayFontN64 +{ + Texture2D fontGLTextures[224]; + surface_t fontSurfaces[224]; + +}RayFontN64; +#define RAYLIB4N64_MAX_SURFACE_LIMIT 10 //You can change this limit +typedef struct { + // TODO: Define the platform specific variables required + surface_t zbuffer; + surface_t *disp; + RayFontN64 rayFonts; + surface_t surfaces[RAYLIB4N64_MAX_SURFACE_LIMIT]; + unsigned int surface_index; + // Display data + //EGLDisplay device; // Native display device (physical screen connection) + //EGLSurface surface; // Surface to draw on, framebuffers (connected to context) + //EGLContext context; // Graphic context, mode in which drawing can be done + //EGLConfig config; // Graphic config +} PlatformData; + +#define SUPPORT_DEFAULT_FONT 1 +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +extern CoreData CORE; // Global CORE state context + +static PlatformData platform = { 0 }; // Platform specific data + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +int InitPlatform(void); // Initialize platform (graphics, inputs and more) +bool InitGraphicsDevice(void); // Initialize graphics device +Texture2D rayDefaultFontsGetTextureFromGlyph(int index); +void rayDefaultFontsInitSurfaceBuffers(); +void rayDefaultFontGliphGlTextureInit(Font font,int index); +Texture2D getFontGLTextureId(char *text); + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +// NOTE: Functions declaration is provided by raylib.h + +//---------------------------------------------------------------------------------- +// Module Functions Definition: Window and Graphics Device +//---------------------------------------------------------------------------------- + +// Check if application should close +bool WindowShouldClose(void) +{ + if (CORE.Window.ready) return CORE.Window.shouldClose; + else return true; +} + +// Toggle fullscreen mode +void ToggleFullscreen(void) +{ + TRACELOG(LOG_WARNING, "ToggleFullscreen() not available on target platform"); +} + +// Toggle borderless windowed mode +void ToggleBorderlessWindowed(void) +{ + TRACELOG(LOG_WARNING, "ToggleBorderlessWindowed() not available on target platform"); +} + +// Set window state: maximized, if resizable +void MaximizeWindow(void) +{ + TRACELOG(LOG_WARNING, "MaximizeWindow() not available on target platform"); +} + +// Set window state: minimized +void MinimizeWindow(void) +{ + TRACELOG(LOG_WARNING, "MinimizeWindow() not available on target platform"); +} + +// Set window state: not minimized/maximized +void RestoreWindow(void) +{ + TRACELOG(LOG_WARNING, "RestoreWindow() not available on target platform"); +} + +// Set window configuration state using flags +void SetWindowState(unsigned int flags) +{ + TRACELOG(LOG_WARNING, "SetWindowState() not available on target platform"); +} + +// Clear window configuration state flags +void ClearWindowState(unsigned int flags) +{ + TRACELOG(LOG_WARNING, "ClearWindowState() not available on target platform"); +} + +// Set icon for window +void SetWindowIcon(Image image) +{ + TRACELOG(LOG_WARNING, "SetWindowIcon() not available on target platform"); +} + +// Set icon for window +void SetWindowIcons(Image *images, int count) +{ + TRACELOG(LOG_WARNING, "SetWindowIcons() not available on target platform"); +} + +// Set title for window +void SetWindowTitle(const char *title) +{ + CORE.Window.title = title; +} + +// Set window position on screen (windowed mode) +void SetWindowPosition(int x, int y) +{ + TRACELOG(LOG_WARNING, "SetWindowPosition() not available on target platform"); +} + +// Set monitor for the current window +void SetWindowMonitor(int monitor) +{ + TRACELOG(LOG_WARNING, "SetWindowMonitor() not available on target platform"); +} + +// Set window minimum dimensions (FLAG_WINDOW_RESIZABLE) +void SetWindowMinSize(int width, int height) +{ + CORE.Window.screenMin.width = width; + CORE.Window.screenMin.height = height; +} + +// Set window maximum dimensions (FLAG_WINDOW_RESIZABLE) +void SetWindowMaxSize(int width, int height) +{ + CORE.Window.screenMax.width = width; + CORE.Window.screenMax.height = height; +} + +// Set window dimensions +void SetWindowSize(int width, int height) +{ + TRACELOG(LOG_WARNING, "SetWindowSize() not available on target platform"); +} + +// Set window opacity, value opacity is between 0.0 and 1.0 +void SetWindowOpacity(float opacity) +{ + TRACELOG(LOG_WARNING, "SetWindowOpacity() not available on target platform"); +} + +// Set window focused +void SetWindowFocused(void) +{ + TRACELOG(LOG_WARNING, "SetWindowFocused() not available on target platform"); +} + +// Get native window handle +void *GetWindowHandle(void) +{ + TRACELOG(LOG_WARNING, "GetWindowHandle() not implemented on target platform"); + return NULL; +} + +// Get number of monitors +int GetMonitorCount(void) +{ + TRACELOG(LOG_WARNING, "GetMonitorCount() not implemented on target platform"); + return 1; +} + +// Get number of monitors +int GetCurrentMonitor(void) +{ + TRACELOG(LOG_WARNING, "GetCurrentMonitor() not implemented on target platform"); + return 0; +} + +// Get selected monitor position +Vector2 GetMonitorPosition(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorPosition() not implemented on target platform"); + return (Vector2){ 0, 0 }; +} + +// Get selected monitor width (currently used by monitor) +int GetMonitorWidth(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorWidth() not implemented on target platform"); + return 0; +} + +// Get selected monitor height (currently used by monitor) +int GetMonitorHeight(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorHeight() not implemented on target platform"); + return 0; +} + +// Get selected monitor physical width in millimetres +int GetMonitorPhysicalWidth(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorPhysicalWidth() not implemented on target platform"); + return 0; +} + +// Get selected monitor physical height in millimetres +int GetMonitorPhysicalHeight(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorPhysicalHeight() not implemented on target platform"); + return 0; +} + +// Get selected monitor refresh rate +int GetMonitorRefreshRate(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorRefreshRate() not implemented on target platform"); + return 0; +} + +// Get the human-readable, UTF-8 encoded name of the selected monitor +const char *GetMonitorName(int monitor) +{ + TRACELOG(LOG_WARNING, "GetMonitorName() not implemented on target platform"); + return ""; +} + +// Get window position XY on monitor +Vector2 GetWindowPosition(void) +{ + TRACELOG(LOG_WARNING, "GetWindowPosition() not implemented on target platform"); + return (Vector2){ 0, 0 }; +} + +// Get window scale DPI factor for current monitor +Vector2 GetWindowScaleDPI(void) +{ + TRACELOG(LOG_WARNING, "GetWindowScaleDPI() not implemented on target platform"); + return (Vector2){ 1.0f, 1.0f }; +} + +// Set clipboard text content +void SetClipboardText(const char *text) +{ + TRACELOG(LOG_WARNING, "SetClipboardText() not implemented on target platform"); +} + +// Get clipboard text content +// NOTE: returned string is allocated and freed by GLFW +const char *GetClipboardText(void) +{ + TRACELOG(LOG_WARNING, "GetClipboardText() not implemented on target platform"); + return NULL; +} + +// Show mouse cursor +void ShowCursor(void) +{ + CORE.Input.Mouse.cursorHidden = false; +} + +// Hides mouse cursor +void HideCursor(void) +{ + CORE.Input.Mouse.cursorHidden = true; +} + +// Enables cursor (unlock cursor) +void EnableCursor(void) +{ + // Set cursor position in the middle + SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); + + CORE.Input.Mouse.cursorHidden = false; +} + +// Disables cursor (lock cursor) +void DisableCursor(void) +{ + // Set cursor position in the middle + SetMousePosition(CORE.Window.screen.width/2, CORE.Window.screen.height/2); + + CORE.Input.Mouse.cursorHidden = true; +} + +// Swap back buffer with front buffer (screen drawing) +void SwapScreenBuffer(void) +{ + gl_context_end(); + rdpq_detach_show(); +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition: Misc +//---------------------------------------------------------------------------------- + +// Get elapsed time measure in seconds since InitTimer() +double GetTime(void) +{ + disable_interrupts(); + double time=(double)(get_ticks_us() - CORE.Time.base)*1e-6; + enable_interrupts(); + return time; +} + +// Open URL with default system browser (if available) +// NOTE: This function is only safe to use if you control the URL given. +// A user could craft a malicious string performing another action. +// Only call this function yourself not with user input or make sure to check the string yourself. +// Ref: https://github.com/raysan5/raylib/issues/686 +void OpenURL(const char *url) +{ + // Security check to (partially) avoid malicious code on target platform + if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + else + { + // TODO: + } +} + +//---------------------------------------------------------------------------------- +// Module Functions Definition: Inputs +//---------------------------------------------------------------------------------- + +// Set internal gamepad mappings +int SetGamepadMappings(const char *mappings) +{ + TRACELOG(LOG_WARNING, "SetGamepadMappings() not implemented on target platform"); + return 0; +} + +// Set mouse position XY +void SetMousePosition(int x, int y) +{ + CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; + CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; +} + +// Set mouse cursor +void SetMouseCursor(int cursor) +{ + TRACELOG(LOG_WARNING, "SetMouseCursor() not implemented on target platform"); +} + +// Register all input events +void PollInputEvents(void) +{ + joypad_style_t style; + joypad_accessory_type_t accessory_type; + bool rumble_supported; + bool rumble_active; + joypad_inputs_t inputs; + +#if defined(SUPPORT_GESTURES_SYSTEM) + // NOTE: Gestures update must be called every frame to reset gestures correctly + // because ProcessGestureEvent() is just called on an event, not every frame + UpdateGestures(); +#endif + + // Reset keys/chars pressed registered + CORE.Input.Keyboard.keyPressedQueueCount = 0; + CORE.Input.Keyboard.charPressedQueueCount = 0; + + // Reset key repeats + for (int i = 0; i < MAX_KEYBOARD_KEYS; i++) CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; + + // Reset last gamepad button/axis registered state + CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN + //CORE.Input.Gamepad.axisCount = 0; + + // Register previous touch states + for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.previousTouchState[i] = CORE.Input.Touch.currentTouchState[i]; + + + // TODO: Add callbacks for connect / disconnected pads + + // Reset touch positions + // TODO: It resets on target platform the mouse position and not filled again until a move-event, + // so, if mouse is not moved it returns a (0, 0) position... this behaviour should be reviewed! + //for (int i = 0; i < MAX_TOUCH_POINTS; i++) CORE.Input.Touch.position[i] = (Vector2){ 0, 0 }; + + // Register previous keys states + // NOTE: Android supports up to 260 keys + //for (int i = 0; i < 260; i++) + //{ + // CORE.Input.Keyboard.previousKeyState[i] = CORE.Input.Keyboard.currentKeyState[i]; + // CORE.Input.Keyboard.keyRepeatInFrame[i] = 0; + //} + + // TODO: Poll input events for current plaform +/*TODO N64 + joypad_poll(); + + JOYPAD_PORT_FOREACH (port) + { + style = joypad_get_style(port); + accessory_type = joypad_get_accessory_type(port); + rumble_supported = joypad_get_rumble_supported(port); + rumble_active = joypad_get_rumble_active(port); + inputs = joypad_get_inputs(port); + + if (rumble_supported) + { + if (inputs.btn.a && !rumble_active) + { + joypad_set_rumble_active(port, true); + } + else if (!inputs.btn.a && rumble_active) + { + joypad_set_rumble_active(port, false); + } + } + } +*/ + +} + +void CustomLog(int msgType, const char *text, va_list args) +{ + char buffer[1024] = { 0 }; + + + vsnprintf(buffer,1024, text, args); + buffer[1024-1] = 0; + + + switch (msgType) + { + case LOG_TRACE: debugf("[N64][TRACE]: %s\n",buffer); break; + case LOG_DEBUG: debugf("[N64][DEBUG]: %s\n",buffer); break; + case LOG_INFO: debugf("[N64][INFO]: %s\n",buffer); break; + case LOG_WARNING: debugf("[N64][WARNING]: %s\n",buffer); break; + case LOG_ERROR: debugf("[N64][ERROR]: %s\n",buffer); break; + case LOG_FATAL: debugf("[N64][FATAL]: %s\n",buffer); break; + default: break; + } +} +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +//Set all surface buffer for each glyph to NULL +void rayDefaultFontsInitSurfaceBuffers() +{ + for(int i=0;i<224;i++) + { + platform.rayFonts.fontSurfaces[i].buffer=NULL; + } +} + +void rlLoadTextureN64(const void *data, int width, int height, int format, int mipmapCount) +{ + + if(platform.surface_index>=RAYLIB4N64_MAX_SURFACE_LIMIT) + { + TraceLog(LOG_ERROR,"Limit for surfaces in raylib4Nintendo64 is %d",RAYLIB4N64_MAX_SURFACE_LIMIT); + return 0; + } + //todo load different mipmap level using mipmapCount by now we wil use only level 0 + //todo using different GL format to transform to supported internal format by now we will use only FMT_RGBA32 + + platform.surfaces[platform.surface_index].flags = FMT_RGBA32 | SURFACE_FLAGS_OWNEDBUFFER; + + platform.surfaces[platform.surface_index].width = (uint32_t)width; + + platform.surfaces[platform.surface_index].height = (uint32_t)height; + + platform.surfaces[platform.surface_index].stride = TEX_FORMAT_PIX2BYTES(FMT_RGBA32, width); + + platform.surfaces[platform.surface_index].buffer = data; + + glSurfaceTexImageN64(GL_TEXTURE_2D, 0, &(platform.surfaces[platform.surface_index]), &(rdpq_texparms_t){.s.repeats = 0, .t.repeats = 0}); + + + platform.surface_index++; + +} +void rayDefaultFontGliphGlTextureInit(Font font,int index) +{ + //If gliph was not initialized before generate texture from glyph image + if(platform.rayFonts.fontSurfaces[index].buffer==NULL) + { + + platform.rayFonts.fontSurfaces[index].flags = FMT_RGBA32 | SURFACE_FLAGS_OWNEDBUFFER; + + platform.rayFonts.fontSurfaces[index].width = (uint32_t) (font.recs[index].width); + + platform.rayFonts.fontSurfaces[index].height = (uint32_t)(font.recs[index].height); + + platform.rayFonts.fontSurfaces[index].stride = TEX_FORMAT_PIX2BYTES(FMT_RGBA32, platform.rayFonts.fontSurfaces[index].width); + + platform.rayFonts.fontSurfaces[index].buffer = (font.glyphs[index].image.data); + + glGenTextures(1,&(platform.rayFonts.fontGLTextures[index].id)); + + glBindTexture(GL_TEXTURE_2D, platform.rayFonts.fontGLTextures[index].id); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // Set texture to repeat on x-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Set texture to repeat on y-axis + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Alternative: GL_LINEAR + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // Alternative: GL_LINEAR*/ + + glSurfaceTexImageN64(GL_TEXTURE_2D, 0, &(platform.rayFonts.fontSurfaces[index]), &(rdpq_texparms_t){.s.repeats = 0, .t.repeats = 0}); + + + platform.rayFonts.fontGLTextures[index].width=font.recs[index].width; + + platform.rayFonts.fontGLTextures[index].height= font.recs[index].height; + + platform.rayFonts.fontGLTextures[index].mipmaps=1; + + platform.rayFonts.fontGLTextures[index].format=PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + + } + +} +Texture2D getFontGLTextureId(char *text) +{ + int codepointByteCount; + int codepoint = GetCodepointNext(text, &codepointByteCount); + int index = GetGlyphIndex(GetFontDefault(), codepoint); + if(platform.rayFonts.fontGLTextures[index].id==0) + { + TraceLog(LOG_ERROR, "%s texture not initalized for %s", __FUNCTION__,text); + rayDefaultFontGliphGlTextureInit(GetFontDefault(),index); + } + else + { + //TraceLog(LOG_INFO, "%s textureinitalized for %s ", __FUNCTION__,text); + } + return platform.rayFonts.fontGLTextures[index]; +} +Texture2D rayDefaultFontsGetTextureFromGlyph(int index) +{ + Texture2D texture = { 0 }; + texture.id = platform.rayFonts.fontGLTextures[index].id; + texture.width = platform.rayFonts.fontGLTextures[index].width; + texture.height = platform.rayFonts.fontGLTextures[index].height; + texture.mipmaps = platform.rayFonts.fontGLTextures[index].mipmaps; + texture.format = platform.rayFonts.fontGLTextures[index].format; + return texture; +} +// Initialize platform: graphics, inputs and more +int InitPlatform(void) +{ + SetTraceLogCallback(CustomLog); + + + + debug_init_isviewer(); + debug_init_usblog(); + TRACELOG(LOG_INFO, "Initializing raylib %s", RAYLIB_VERSION); + TRACELOG(LOG_INFO, "Platform backend: NINTENDO64"); + TRACELOG(LOG_INFO, "PLATFORM: Nintendo 64 init"); + + dfs_init(DFS_DEFAULT_LOCATION); + + display_init(RESOLUTION_320x240, DEPTH_16_BPP, 3, GAMMA_NONE, FILTERS_RESAMPLE_ANTIALIAS_DEDITHER); + + rdpq_init(); + gl_init(); + +#if DEBUG_RDP + rdpq_debug_start(); + rdpq_debug_log(true); +#endif + + joypad_init(); + + rayDefaultFontsInitSurfaceBuffers(); + platform.zbuffer = surface_alloc(FMT_RGBA16, display_get_width(), display_get_height()); + + + platform.disp = display_get(); + + rdpq_attach(platform.disp, &platform.zbuffer); + + gl_context_begin(); + + + CORE.Window.fullscreen = true; + CORE.Window.flags |= FLAG_FULLSCREEN_MODE; + + CORE.Window.display.width = 320;//CORE.Window.screen.width; // User desired width + CORE.Window.display.height = 240;//CORE.Window.screen.height; // User desired height + CORE.Window.screen.width=314; + CORE.Window.screen.height=240; + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; + CORE.Window.eventWaiting = false; + CORE.Window.screenScale = MatrixIdentity(); // No draw scaling required by default + CORE.Window.currentFbo.width = CORE.Window.screen.width; + CORE.Window.currentFbo.height = CORE.Window.screen.height; + CORE.Input.Mouse.currentPosition.x = (float)CORE.Window.screen.width/2.0f; + CORE.Input.Mouse.currentPosition.y = (float)CORE.Window.screen.height/2.0f; + CORE.Input.Mouse.scale = (Vector2){ 1.0f, 1.0f }; + + + + + // At this point we need to manage render size vs screen size + // NOTE: This function use and modify global module variables: + // -> CORE.Window.screen.width/CORE.Window.screen.height + // -> CORE.Window.render.width/CORE.Window.render.height + // -> CORE.Window.screenScale + SetupFramebuffer(CORE.Window.display.width, CORE.Window.display.height); + + //ANativeWindow_setBuffersGeometry(platform.app->window, CORE.Window.render.width, CORE.Window.render.height, displayFormat); + //ANativeWindow_setBuffersGeometry(platform.app->window, 0, 0, displayFormat); // Force use of native display size + + + { + CORE.Window.render.width = CORE.Window.screen.width; + CORE.Window.render.height = CORE.Window.screen.height; + CORE.Window.currentFbo.width = CORE.Window.render.width; + CORE.Window.currentFbo.height = CORE.Window.render.height; + + TRACELOG(LOG_INFO, "PLATFORM: Device initialized successfully"); + TRACELOG(LOG_INFO, " > Display size: %i x %i", CORE.Window.display.width, CORE.Window.display.height); + TRACELOG(LOG_INFO, " > Screen size: %i x %i", CORE.Window.screen.width, CORE.Window.screen.height); + TRACELOG(LOG_INFO, " > Render size: %i x %i", CORE.Window.render.width, CORE.Window.render.height); + TRACELOG(LOG_INFO, " > Viewport offsets: %i, %i", CORE.Window.renderOffset.x, CORE.Window.renderOffset.y); + } + + // Load OpenGL extensions + // NOTE: GL procedures address loader is required to load extensions + //rlLoadExtensions(eglGetProcAddress); + //const char *gl_exts = (char *) glGetString(GL_EXTENSIONS); + //TRACELOG(LOG_INFO,"PLATFORM: GL_VENDOR: \"%s\"", glGetString(GL_VENDOR)); + //TRACELOG(LOG_INFO,"PLATFORM: GL_VERSION: \"%s\"", glGetString(GL_VERSION)); + //TRACELOG(LOG_INFO,"PLATFORM: GL_RENDERER: \"%s\"", glGetString(GL_RENDERER)); + //TRACELOG(LOG_INFO,"PLATFORM: SL_VERSION: \"%s\"", glGetString(GL_SHADING_LANGUAGE_VERSION)); + CORE.Window.ready = true; + + // Initialize hi-res timer + InitTimer(); + + // Initialize base path for storage + CORE.Storage.basePath = GetWorkingDirectory(); + TRACELOG(LOG_INFO, "PLATFORM: Initialized"); + + return 0; +} + +// Close platform +void ClosePlatform(void) +{ + // TODO: De-initialize graphics, inputs and more +} + +// EOF diff --git a/src/rcore.c b/src/rcore.c index 8495bc6ca..07be29df4 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -21,7 +21,8 @@ * - Android (ARM, ARM64) * > PLATFORM_DREAMCAST: * - Sega Dreamcast (SH4) -* +* > PLATFORM_NINTENDO64: +* - Nintendo 64 (MIPS4300) * CONFIGURATION: * #define SUPPORT_DEFAULT_FONT (default) * Default font is loaded on window initialization to be available for the user to render simple text. @@ -182,9 +183,13 @@ __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigne #define DIRENT_FREE RL_FREE #include "external/dirent.h" // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()] +#else +#if defined(PLATFORM_NINTENDO64) +//avoid dirent on Nintendo 64 #else #include // Required for: DIR, opendir(), closedir() [Used in LoadDirectoryFiles()] #endif +#endif #if defined(_WIN32) #include // Required for: _getch(), _chdir() @@ -503,6 +508,8 @@ const char *TextFormat(const char *text, ...); // Formatting of tex #include "platforms/rcore_android.c" #elif defined(PLATFORM_DREAMCAST) #include "platforms/rcore_dreamcast.c" +#elif defined(PLATFORM_NINTENDO64) + #include "platforms/rcore_nintendo64.c" #else // TODO: Include your custom platform backend! // i.e software rendering backend or console backend! @@ -573,6 +580,8 @@ void InitWindow(int width, int height, const char *title) TRACELOG(LOG_INFO, "Platform backend: ANDROID"); #elif defined(PLATFORM_DREAMCAST) TRACELOG(LOG_INFO, "Platform backend: DREAMCAST"); +#elif defined(PLATFORM_NINTENDO64) + TRACELOG(LOG_INFO, "Platform backend: NINTENDO64"); #else // TODO: Include your custom platform backend! // i.e software rendering backend or console backend! @@ -641,7 +650,11 @@ void InitWindow(int width, int height, const char *title) #if defined(SUPPORT_MODULE_RSHAPES) // Set font white rectangle for shapes drawing, so shapes and text can be batched together // WARNING: rshapes module is required, if not available, default internal white rectangle is used + #if defined(PLATFORM_NINTENDO64) + Rectangle rec=(Rectangle){ 0.0f, 0.0f, 5.0f, 10.0f }; + #else Rectangle rec = GetFontDefault().recs[95]; + #endif if (CORE.Window.flags & FLAG_MSAA_4X_HINT) { // NOTE: We try to maxime rec padding to avoid pixel bleeding on MSAA filtering @@ -676,6 +689,9 @@ void InitWindow(int width, int height, const char *title) // Initialize random seed SetRandomSeed((unsigned int)time(NULL)); + #if defined(PLATFORM_NINTENDO64) + SwapScreenBuffer(); + #endif } // Close window and unload OpenGL context @@ -831,7 +847,13 @@ void BeginDrawing(void) { // WARNING: Previously to BeginDrawing() other render textures drawing could happen, // consequently the measure for update vs draw is not accurate (only the total frame time is accurate) + #if defined(PLATFORM_NINTENDO64) + platform.disp = display_get(); + rdpq_attach(platform.disp, &platform.zbuffer); + + gl_context_begin(); + #endif CORE.Time.current = GetTime(); // Number of elapsed seconds since InitTimer() CORE.Time.update = CORE.Time.current - CORE.Time.previous; CORE.Time.previous = CORE.Time.current; @@ -1886,6 +1908,7 @@ bool IsFileExtension(const char *fileName, const char *ext) bool DirectoryExists(const char *dirPath) { bool result = false; + #if !defined(PLATFORM_VITA) && !defined(PLATFORM_ORBIS) && !defined(PLATFORM_PROSPERO) && !defined(PLATFORM_NINTENDO64) DIR *dir = opendir(dirPath); if (dir != NULL) @@ -1893,7 +1916,7 @@ bool DirectoryExists(const char *dirPath) result = true; closedir(dir); } - + #endif return result; } @@ -2059,9 +2082,11 @@ const char *GetWorkingDirectory(void) { static char currentDir[MAX_FILEPATH_LENGTH] = { 0 }; memset(currentDir, 0, MAX_FILEPATH_LENGTH); - + #if !defined(PLATFORM_VITA) && !defined(PLATFORM_ORBIS) && !defined(PLATFORM_PROSPERO) && !defined(PLATFORM_NINTENDO64) char *path = GETCWD(currentDir, MAX_FILEPATH_LENGTH - 1); - + #else + char *path="."; + #endif return path; } @@ -2151,6 +2176,7 @@ FilePathList LoadDirectoryFiles(const char *dirPath) unsigned int fileCounter = 0; struct dirent *entity; + #if !defined(PLATFORM_VITA) && !defined(PLATFORM_ORBIS) && !defined(PLATFORM_PROSPERO) && !defined(PLATFORM_NINTENDO64) DIR *dir = opendir(dirPath); if (dir != NULL) // It's a directory @@ -2177,7 +2203,7 @@ FilePathList LoadDirectoryFiles(const char *dirPath) if (files.count != files.capacity) TRACELOG(LOG_WARNING, "FILEIO: Read files count do not match capacity allocated"); } else TRACELOG(LOG_WARNING, "FILEIO: Failed to open requested directory"); // Maybe it's a file... - + #endif return files; } @@ -2210,10 +2236,13 @@ void UnloadDirectoryFiles(FilePathList files) // Change working directory, returns true on success bool ChangeDirectory(const char *dir) { + #if !defined(PLATFORM_VITA) && !defined(PLATFORM_ORBIS) && !defined(PLATFORM_PROSPERO) && !defined(PLATFORM_NINTENDO64) bool result = CHDIR(dir); if (result != 0) TRACELOG(LOG_WARNING, "SYSTEM: Failed to change to directory: %s", dir); - + #else + bool result=1; + #endif return (result == 0); } @@ -3081,7 +3110,11 @@ void InitTimer(void) } else TRACELOG(LOG_WARNING, "TIMER: Hi-resolution timer not available"); #endif - +#if defined(PLATFORM_NINTENDO64) + disable_interrupts(); + CORE.Time.base = get_ticks_us(); + enable_interrupts(); +#endif CORE.Time.previous = GetTime(); // Get time as double } @@ -3106,7 +3139,7 @@ void SetupViewport(int width, int height) // Set orthographic projection to current framebuffer size // NOTE: Configured top-left corner as (0, 0) - #if defined(PLATFORM_DREAMCAST) + #if defined(PLATFORM_DREAMCAST) || defined(PLATFORM_NINTENDO64) rlOrtho(0, CORE.Window.render.width, CORE.Window.render.height, 0, -1.0f, 1.0f); #else rlOrtho(0, CORE.Window.render.width, CORE.Window.render.height, 0, 0.0f, 1.0f); @@ -3200,7 +3233,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const { static char path[MAX_FILEPATH_LENGTH] = { 0 }; memset(path, 0, MAX_FILEPATH_LENGTH); - + #if !defined(PLATFORM_VITA) && !defined(PLATFORM_ORBIS) && !defined(PLATFORM_PROSPERO) && !defined(PLATFORM_NINTENDO64) struct dirent *dp = NULL; DIR *dir = opendir(basePath); @@ -3236,6 +3269,7 @@ static void ScanDirectoryFiles(const char *basePath, FilePathList *files, const closedir(dir); } else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath); + #endif } // Scan all files and directories recursively from a base path @@ -3243,7 +3277,7 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi { char path[MAX_FILEPATH_LENGTH] = { 0 }; memset(path, 0, MAX_FILEPATH_LENGTH); - + #if !defined(PLATFORM_VITA) && !defined(PLATFORM_ORBIS) && !defined(PLATFORM_PROSPERO) && !defined(PLATFORM_NINTENDO64) struct dirent *dp = NULL; DIR *dir = opendir(basePath); @@ -3289,6 +3323,7 @@ static void ScanDirectoryFilesRecursively(const char *basePath, FilePathList *fi closedir(dir); } else TRACELOG(LOG_WARNING, "FILEIO: Directory cannot be opened (%s)", basePath); + #endif } #if defined(SUPPORT_AUTOMATION_EVENTS) diff --git a/src/rlgl.h b/src/rlgl.h index b18573f0f..7ff98d65f 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1837,7 +1837,13 @@ void rlEnableBackfaceCulling(void) { glEnable(GL_CULL_FACE); } void rlDisableBackfaceCulling(void) { glDisable(GL_CULL_FACE); } // Set color mask active for screen read/draw -void rlColorMask(bool r, bool g, bool b, bool a) { glColorMask(r, g, b, a); } +void rlColorMask(bool r, bool g, bool b, bool a) +{ +#if defined(PLATFORM_NINTENDO64) +#else + glColorMask(r, g, b, a); +#endif +} // Set face culling mode void rlSetCullFace(int mode) @@ -1873,7 +1879,7 @@ void rlEnablePointMode(void) #if defined(GRAPHICS_API_OPENGL_11) || defined(GRAPHICS_API_OPENGL_33) // NOTE: glPolygonMode() not available on OpenGL ES glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); - #if defined(PLATFORM_DREAMCAST) //fix needed on gldc by now hardcoded here to avoid compiling errors + #if defined(PLATFORM_DREAMCAST) || defined(PLATFORM_NINTENDO64)//fix needed on gldc by now hardcoded here to avoid compiling errors. Also Not defined in libdragon glEnable(0x8642/*GL_PROGRAM_POINT_SIZE*/); #else glEnable(GL_PROGRAM_POINT_SIZE); @@ -2180,7 +2186,11 @@ void rlglInit(int width, int height) // Initialize OpenGL default states //---------------------------------------------------------- // Init state: Depth test - glDepthFunc(GL_LEQUAL); // Type of depth testing to apply + #if defined(PLATFORM_NINTENDO64) //to review in libdragon + glDepthFunc(GL_LESS_INTERPENETRATING_N64); // Type of depth testing to apply + #else + glDepthFunc(GL_LEQUAL); + #endif // Type of depth testing to apply glDisable(GL_DEPTH_TEST); // Disable depth testing for 2D (only used for 3D) // Init state: Blending mode @@ -3081,12 +3091,13 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, TRACELOGD("TEXTURE: Load mipmap level %i (%i x %i), size: %i, offset: %i", i, mipWidth, mipHeight, mipSize, mipOffset); if (glInternalFormat != 0) - { + { + #if !defined(PLATFORM_NINTENDO64) if (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB) glTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, glFormat, glType, dataPtr); #if !defined(GRAPHICS_API_OPENGL_11) else glCompressedTexImage2D(GL_TEXTURE_2D, i, glInternalFormat, mipWidth, mipHeight, 0, mipSize, dataPtr); #endif - + #endif #if defined(GRAPHICS_API_OPENGL_33) if (format == RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) { @@ -3147,7 +3158,9 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); } #endif - + #if defined(PLATFORM_NINTENDO64) //glTextParameter must be set before upload to gpu + rlLoadTextureN64(data,width,height,format,mipmapCount); + #endif // At this point we have the texture loaded in GPU and texture parameters configured // NOTE: If mipmaps were not in data, they are not generated automatically @@ -3304,7 +3317,10 @@ void rlUpdateTexture(unsigned int id, int offsetX, int offsetY, int width, int h if ((glInternalFormat != 0) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)) { + #if defined(PLATFORM_NINTENDO64) + #else glTexSubImage2D(GL_TEXTURE_2D, 0, offsetX, offsetY, width, height, glFormat, glType, data); + #endif } else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Failed to update for current texture format (%i)", id, format); } @@ -3449,7 +3465,10 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) if ((glInternalFormat != 0) && (format < RL_PIXELFORMAT_COMPRESSED_DXT1_RGB)) { pixels = RL_MALLOC(size); + #if defined(PLATFORM_NINTENDO64) + #else glGetTexImage(GL_TEXTURE_2D, 0, glFormat, glType, pixels); + #endif } else TRACELOG(RL_LOG_WARNING, "TEXTURE: [ID %i] Data retrieval not suported for pixel format (%i)", id, format); @@ -3492,8 +3511,10 @@ unsigned char *rlReadScreenPixels(int width, int height) // NOTE 1: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer // NOTE 2: We are getting alpha channel! Be careful, it can be transparent if not cleared properly! + #if defined(PLATFORM_NINTENDO64) + #else glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, screenData); - + #endif // Flip image vertically! unsigned char *imgData = (unsigned char *)RL_MALLOC(width*height*4*sizeof(unsigned char)); diff --git a/src/rshapes.c b/src/rshapes.c index d73373669..e2fc49649 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -59,8 +59,9 @@ #include // Required for: FLT_EPSILON #include // Required for: RL_FREE +#if defined(PLATFORM_DREAMCAST)|| defined(PLATFORM_NINTENDO64) #include "utils.h" // Required for: TRACELOG() macros used when i was testing on Dreamcast - +#endif //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- diff --git a/src/rtext.c b/src/rtext.c index 97b4ea710..bfb33e717 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -151,6 +151,11 @@ extern void LoadFontDefault(void); extern void UnloadFontDefault(void); #endif +#if defined(PLATFORM_NINTENDO64) +void rayDefaultFontsInitSurfaceBuffers(); +void rayDefaultFontGliphGlTextureInit(Font font,int index); +Texture2D rayDefaultFontsGetTextureFromGlyph(int index); +#endif //---------------------------------------------------------------------------------- // Module Functions Definition //---------------------------------------------------------------------------------- @@ -227,7 +232,7 @@ extern void LoadFontDefault(void) // Re-construct image from defaultFontData and generate OpenGL texture //---------------------------------------------------------------------- - #if defined(PLATFORM_DREAMCAST) + #if defined(PLATFORM_DREAMCAST) || defined(PLATFORM_NINTENDO64) Image imFont = { .data = RL_CALLOC(128*128, 4), // 4 bytes per pixel (rgb + alpha) there are some issues with different format in Dreamcast so to avoid problems for text by now we will use this .width = 128, @@ -247,7 +252,16 @@ extern void LoadFontDefault(void) // we must consider data as little-endian order (alpha + gray) ((unsigned int *)imFont.data)[i + j] = 0xffffffff; } - else ((unsigned int *)imFont.data)[i + j] = 0x000000ff; + else + { + #if defined(PLATFORM_DREAMCAST) + ((unsigned int *)imFont.data)[i + j] = 0x000000ff; + #endif + #if defined(PLATFORM_NINTENDO64) + ((unsigned int *)imFont.data)[i + j] = 0xff000000; + #endif + + } } counter++; @@ -278,7 +292,14 @@ extern void LoadFontDefault(void) counter++; } #endif + #if defined(PLATFORM_NINTENDO64) + defaultFont.texture.width = imFont.width; + defaultFont.texture.height = imFont.height; + defaultFont.texture.mipmaps = 1; + defaultFont.texture.format = imFont.format; + #else defaultFont.texture = LoadTextureFromImage(imFont); + #endif // Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount //------------------------------------------------------------------------------ @@ -322,7 +343,10 @@ extern void LoadFontDefault(void) // Fill character image data from fontClear data defaultFont.glyphs[i].image = ImageFromImage(imFont, defaultFont.recs[i]); } - + #if defined(PLATFORM_NINTENDO64) //We load only glyph 95 to use with shapes + rayDefaultFontGliphGlTextureInit(defaultFont,95); + defaultFont.texture = rayDefaultFontsGetTextureFromGlyph(95); + #endif UnloadImage(imFont); defaultFont.baseSize = (int)defaultFont.recs[0].height; @@ -1200,6 +1224,9 @@ void DrawTextEx(Font font, const char *text, Vector2 position, float fontSize, f { if ((codepoint != ' ') && (codepoint != '\t')) { + #if defined(PLATFORM_NINTENDO64) + rayDefaultFontGliphGlTextureInit(font,index); + #endif DrawTextCodepoint(font, codepoint, (Vector2){ position.x + textOffsetX, position.y + textOffsetY }, fontSize, tint); } @@ -1242,11 +1269,17 @@ void DrawTextCodepoint(Font font, int codepoint, Vector2 position, float fontSiz // Character source rectangle from font texture atlas // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects + #if defined(PLATFORM_NINTENDO64) + Rectangle srcRec = { 0.0f - (float)font.glyphPadding, 0.0f - (float)font.glyphPadding, + font.recs[index].width + 2.0f*font.glyphPadding, font.recs[index].height + 2.0f*font.glyphPadding }; + // Draw the character texture on the screen + DrawTexturePro(rayDefaultFontsGetTextureFromGlyph(index), srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint); + #else Rectangle srcRec = { font.recs[index].x - (float)font.glyphPadding, font.recs[index].y - (float)font.glyphPadding, font.recs[index].width + 2.0f*font.glyphPadding, font.recs[index].height + 2.0f*font.glyphPadding }; - // Draw the character texture on the screen DrawTexturePro(font.texture, srcRec, dstRec, (Vector2){ 0, 0 }, 0.0f, tint); + #endif } // Draw multiple character (codepoints)