diff --git a/ISLE/isledebug.cpp b/ISLE/isledebug.cpp index a8950fa3..ec27004b 100644 --- a/ISLE/isledebug.cpp +++ b/ISLE/isledebug.cpp @@ -309,7 +309,7 @@ void IsleDebug_Render() if (ImGui::TreeNode("Sound Manager")) { LegoSoundManager* soundManager = lego->GetSoundManager(); Sint32 oldVolume = soundManager->GetVolume(); - Sint32 volume = oldVolume; + int volume = oldVolume; ImGui::SliderInt("volume", &volume, 0, 100); if (volume != oldVolume) { soundManager->SetVolume(volume); diff --git a/miniwin/src/d3drm/backends/citro3d/renderer.cpp b/miniwin/src/d3drm/backends/citro3d/renderer.cpp index 5db989cd..8ee2f01e 100644 --- a/miniwin/src/d3drm/backends/citro3d/renderer.cpp +++ b/miniwin/src/d3drm/backends/citro3d/renderer.cpp @@ -4,6 +4,7 @@ #include "miniwin/d3d.h" #include "miniwin/d3drm.h" #include "miniwin/windows.h" +#include "vshader_shbin.h" #include <3ds/console.h> #include <3ds/gfx.h> @@ -13,220 +14,120 @@ #include #include #include -#include <3ds.h> #include +#include #include -#include "vshader_shbin.h" +bool g_rendering = false; -int projectionShaderUniformLocation, modelViewUniformLocation; +#define DISPLAY_TRANSFER_FLAGS \ + (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \ + GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \ + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) -typedef struct { - float positions[3]; - float texcoords[2]; - float normals[3]; -} Vertex; +static DVLB_s* vshader_dvlb; +static shaderProgram_s program; +static int uLoc_projection; +static int uLoc_modelView; +static int uLoc_meshColor; +C3D_RenderTarget* target; -// from this wiki: https://github.com/tommai78101/homebrew/wiki/Version-002:-Core-Engine -static const Vertex vertexList[] = +static void sceneInit(void) { - // First face (PZ) - // First triangle - { {-0.5f, -0.5f, +0.5f}, {0.0f, 0.0f}, {0.0f, 0.0f, +1.0f} }, - { {+0.5f, -0.5f, +0.5f}, {1.0f, 0.0f}, {0.0f, 0.0f, +1.0f} }, - { {+0.5f, +0.5f, +0.5f}, {1.0f, 1.0f}, {0.0f, 0.0f, +1.0f} }, - // Second triangle - { {+0.5f, +0.5f, +0.5f}, {1.0f, 1.0f}, {0.0f, 0.0f, +1.0f} }, - { {-0.5f, +0.5f, +0.5f}, {0.0f, 1.0f}, {0.0f, 0.0f, +1.0f} }, - { {-0.5f, -0.5f, +0.5f}, {0.0f, 0.0f}, {0.0f, 0.0f, +1.0f} }, + // Load the vertex shader, create a shader program and bind it + vshader_dvlb = DVLB_ParseFile((u32*) vshader_shbin, vshader_shbin_size); + shaderProgramInit(&program); + shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]); + C3D_BindProgram(&program); - // Second face (MZ) - // First triangle - { {-0.5f, -0.5f, -0.5f}, {0.0f, 0.0f}, {0.0f, 0.0f, -1.0f} }, - { {-0.5f, +0.5f, -0.5f}, {1.0f, 0.0f}, {0.0f, 0.0f, -1.0f} }, - { {+0.5f, +0.5f, -0.5f}, {1.0f, 1.0f}, {0.0f, 0.0f, -1.0f} }, - // Second triangle - { {+0.5f, +0.5f, -0.5f}, {1.0f, 1.0f}, {0.0f, 0.0f, -1.0f} }, - { {+0.5f, -0.5f, -0.5f}, {0.0f, 1.0f}, {0.0f, 0.0f, -1.0f} }, - { {-0.5f, -0.5f, -0.5f}, {0.0f, 0.0f}, {0.0f, 0.0f, -1.0f} }, + // Get the location of the uniforms + uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection"); + uLoc_modelView = shaderInstanceGetUniformLocation(program.vertexShader, "modelView"); + uLoc_meshColor = shaderInstanceGetUniformLocation(program.vertexShader, "meshColor"); - // Third face (PX) - // First triangle - { {+0.5f, -0.5f, -0.5f}, {0.0f, 0.0f}, {+1.0f, 0.0f, 0.0f} }, - { {+0.5f, +0.5f, -0.5f}, {1.0f, 0.0f}, {+1.0f, 0.0f, 0.0f} }, - { {+0.5f, +0.5f, +0.5f}, {1.0f, 1.0f}, {+1.0f, 0.0f, 0.0f} }, - // Second triangle - { {+0.5f, +0.5f, +0.5f}, {1.0f, 1.0f}, {+1.0f, 0.0f, 0.0f} }, - { {+0.5f, -0.5f, +0.5f}, {0.0f, 1.0f}, {+1.0f, 0.0f, 0.0f} }, - { {+0.5f, -0.5f, -0.5f}, {0.0f, 0.0f}, {+1.0f, 0.0f, 0.0f} }, - - // Fourth face (MX) - // First triangle - { {-0.5f, -0.5f, -0.5f}, {0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f} }, - { {-0.5f, -0.5f, +0.5f}, {1.0f, 0.0f}, {-1.0f, 0.0f, 0.0f} }, - { {-0.5f, +0.5f, +0.5f}, {1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f} }, - // Second triangle - { {-0.5f, +0.5f, +0.5f}, {1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f} }, - { {-0.5f, +0.5f, -0.5f}, {0.0f, 1.0f}, {-1.0f, 0.0f, 0.0f} }, - { {-0.5f, -0.5f, -0.5f}, {0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f} }, - - // Fifth face (PY) - // First triangle - { {-0.5f, +0.5f, -0.5f}, {0.0f, 0.0f}, {0.0f, +1.0f, 0.0f} }, - { {-0.5f, +0.5f, +0.5f}, {1.0f, 0.0f}, {0.0f, +1.0f, 0.0f} }, - { {+0.5f, +0.5f, +0.5f}, {1.0f, 1.0f}, {0.0f, +1.0f, 0.0f} }, - // Second triangle - { {+0.5f, +0.5f, +0.5f}, {1.0f, 1.0f}, {0.0f, +1.0f, 0.0f} }, - { {+0.5f, +0.5f, -0.5f}, {0.0f, 1.0f}, {0.0f, +1.0f, 0.0f} }, - { {-0.5f, +0.5f, -0.5f}, {0.0f, 0.0f}, {0.0f, +1.0f, 0.0f} }, - - // Sixth face (MY) - // First triangle - { {-0.5f, -0.5f, -0.5f}, {0.0f, 0.0f}, {0.0f, -1.0f, 0.0f} }, - { {+0.5f, -0.5f, -0.5f}, {1.0f, 0.0f}, {0.0f, -1.0f, 0.0f} }, - { {+0.5f, -0.5f, +0.5f}, {1.0f, 1.0f}, {0.0f, -1.0f, 0.0f} }, - // Second triangle - { {+0.5f, -0.5f, +0.5f}, {1.0f, 1.0f}, {0.0f, -1.0f, 0.0f} }, - { {-0.5f, -0.5f, +0.5f}, {0.0f, 1.0f}, {0.0f, -1.0f, 0.0f} }, - { {-0.5f, -0.5f, -0.5f}, {0.0f, 0.0f}, {0.0f, -1.0f, 0.0f} }, -}; - -void *vbo_data; -void sceneInit(shaderProgram_s* prog) { - MINIWIN_TRACE("set uniform loc"); - projectionShaderUniformLocation = shaderInstanceGetUniformLocation(prog->vertexShader, "projection"); - modelViewUniformLocation = shaderInstanceGetUniformLocation(prog->vertexShader, "modelView"); - - // src: https://github.com/devkitPro/citro3d/blob/9f21cf7b380ce6f9e01a0420f19f0763e5443ca7/test/3ds/source/main.cpp#L122C3-L126C62 - MINIWIN_TRACE("pre attr info"); + // Configure attributes for use with the vertex shader + // Attribute format and element count are ignored in immediate mode C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); - AttrInfo_Init(attrInfo); + AttrInfo_Init(attrInfo); AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v1=texcoord AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 3); // v2=normal - MINIWIN_TRACE("pre alloc"); - vbo_data = linearAlloc(sizeof(vertexList)); - memcpy(vbo_data, vertexList, sizeof(vertexList)); - - //Initialize and configure buffers. - MINIWIN_TRACE("pre buf"); - C3D_BufInfo* bufferInfo = C3D_GetBufInfo(); - BufInfo_Init(bufferInfo); - BufInfo_Add(bufferInfo, vbo_data, sizeof(Vertex), 3, 0x210); - - // this is probably wrong - MINIWIN_TRACE("pre tex"); + // Configure the first fragment shading substage to just pass through the vertex color + // See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvInit(env); C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR); C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); } +static void sceneExit(void) +{ + // Free the shader program + shaderProgramFree(&program); + DVLB_Free(vshader_dvlb); +} + Direct3DRMRenderer* Citro3DRenderer::Create(DWORD width, DWORD height) { - // TODO: Doesn't SDL call this function? - // Actually it's in ctrulib -max - gfxInitDefault(); - gfxSetWide(true); - gfxSet3D(false); - consoleInit(GFX_BOTTOM, nullptr); + gfxInitDefault(); + consoleInit(GFX_BOTTOM, nullptr); C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + // Initialize the render target + target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + + // Initialize the scene + sceneInit(); + return new Citro3DRenderer(width, height); } -// constructor parameters not finalized Citro3DRenderer::Citro3DRenderer(DWORD width, DWORD height) { - static shaderProgram_s program; - DVLB_s *vsh_dvlb; - + SDL_Log("Citro3DRenderer %dx%d", width, height); m_width = width; - m_height = height / 2; + m_height = height; m_virtualWidth = width; - m_virtualHeight = height / 2; - - // FIXME: is this the right pixel format? - - shaderProgramInit(&program); - vsh_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size); - shaderProgramSetVsh(&program, &vsh_dvlb->DVLE[0]); - - // WARNING: This might crash, not sure - SDL_Log("pre bind"); - C3D_BindProgram(&program); - - // todo: move to scene init next - SDL_Log("setting uniform loc"); - sceneInit(&program); - - // TODO: is GPU_RB_RGBA8 correct? - // TODO: is GPU_RB_DEPTH24_STENCIL8 correct? - m_renderTarget = C3D_RenderTargetCreate(width, height, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); - - // TODO: what color should be used, if we shouldn't use 0x777777FF - C3D_RenderTargetClear(m_renderTarget, C3D_CLEAR_ALL, 0x777777FF, 0); - - // TODO: Cleanup as we see what is needed - m_flipVertFlag = 0; - m_outTiledFlag = 0; - m_rawCopyFlag = 0; - - // TODO: correct values? - m_transferInputFormatFlag = GX_TRANSFER_FMT_RGBA8; - m_transferOutputFormatFlag = GX_TRANSFER_FMT_RGB8; - - m_transferScaleFlag = GX_TRANSFER_SCALE_NO; - - m_transferFlags = (GX_TRANSFER_FLIP_VERT(m_flipVertFlag) | GX_TRANSFER_OUT_TILED(m_outTiledFlag) | \ - GX_TRANSFER_RAW_COPY(m_rawCopyFlag) | GX_TRANSFER_IN_FORMAT(m_transferInputFormatFlag) | \ - GX_TRANSFER_OUT_FORMAT(m_transferOutputFormatFlag) | GX_TRANSFER_SCALING(m_transferScaleFlag)); - - C3D_RenderTargetSetOutput(m_renderTarget, GFX_TOP, GFX_LEFT, m_transferFlags); - - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); - MINIWIN_NOT_IMPLEMENTED(); + m_virtualHeight = height; } Citro3DRenderer::~Citro3DRenderer() { - SDL_DestroySurface(m_renderedImage); - C3D_RenderTargetDelete(m_renderTarget); + sceneExit(); + C3D_Fini(); + gfxExit(); } void Citro3DRenderer::PushLights(const SceneLight* lightsArray, size_t count) { - MINIWIN_NOT_IMPLEMENTED(); } void Citro3DRenderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) { - MINIWIN_TRACE("Set projection"); - memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); } void Citro3DRenderer::SetFrustumPlanes(const Plane* frustumPlanes) { - MINIWIN_NOT_IMPLEMENTED(); } -struct TextureDestroyContextC3D { +struct TextureDestroyContextCitro { Citro3DRenderer* renderer; Uint32 textureId; }; void Citro3DRenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture) { - auto* ctx = new TextureDestroyContextC3D{this, id}; + auto* ctx = new TextureDestroyContextCitro{this, id}; texture->AddDestroyCallback( [](IDirect3DRMObject* obj, void* arg) { - auto* ctx = static_cast(arg); - auto& cache = ctx->renderer->m_textures[ctx->textureId]; - if (cache.c3dTex != nullptr) { - C3D_TexDelete(cache.c3dTex); - cache.c3dTex = nullptr; - cache.texture = nullptr; + auto* ctx = static_cast(arg); + auto& entry = ctx->renderer->m_textures[ctx->textureId]; + if (entry.texture) { + C3D_TexDelete(&entry.c3dTex); + entry.texture = nullptr; } delete ctx; }, @@ -234,89 +135,180 @@ void Citro3DRenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* t ); } +static int NearestPowerOfTwoClamp(int val) +{ + static const int sizes[] = {512, 256, 128, 64, 32, 16, 8}; + for (int size : sizes) { + if (val >= size) { + return size; + } + } + return 8; +} + +static SDL_Surface* ConvertAndResizeSurface(SDL_Surface* original) +{ + SDL_Surface* converted = SDL_ConvertSurface(original, SDL_PIXELFORMAT_RGBA8888); + if (!converted) { + return nullptr; + } + + int newW = NearestPowerOfTwoClamp(converted->w); + int newH = NearestPowerOfTwoClamp(converted->h); + + if (converted->w == newW && converted->h == newH) { + return converted; + } + + SDL_Surface* resized = SDL_CreateSurface(newW, newH, SDL_PIXELFORMAT_RGBA8888); + if (!resized) { + SDL_DestroySurface(converted); + return nullptr; + } + + SDL_BlitSurfaceScaled(converted, nullptr, resized, nullptr, SDL_SCALEMODE_NEAREST); + + SDL_DestroySurface(converted); + return resized; +} + +inline int mortonInterleave(int x, int y) +{ + int answer = 0; + for (int i = 0; i < 3; ++i) { + answer |= ((y >> i) & 1) << (2 * i + 1); + answer |= ((x >> i) & 1) << (2 * i); + } + return answer; +} + +static void EncodeTextureLayout(const u8* src, u8* dst, int width, int height) +{ + const int tileSize = 8; + const int bytesPerPixel = 4; + + int tilesPerRow = (width + tileSize - 1) / tileSize; + + for (int tileY = 0; tileY < height; tileY += tileSize) { + for (int tileX = 0; tileX < width; tileX += tileSize) { + int tileIndex = (tileY / tileSize) * tilesPerRow + (tileX / tileSize); + tileIndex *= tileSize * tileSize; + + for (int y = 0; y < tileSize; ++y) { + for (int x = 0; x < tileSize; ++x) { + int srcX = tileX + x; + int srcY = tileY + y; + + if (srcX >= width || srcY >= height) { + continue; + } + + int mortonIndex = mortonInterleave(x, y); + int dstIndex = (tileIndex + mortonIndex) * bytesPerPixel; + int srcIndex = (srcY * width + srcX) * bytesPerPixel; + + std::memcpy(&dst[dstIndex], &src[srcIndex], bytesPerPixel); + } + } + } + } +} + +static bool ConvertAndUploadTexture(C3D_Tex* tex, SDL_Surface* originalSurface) +{ + SDL_Surface* resized = ConvertAndResizeSurface(originalSurface); + if (!resized) { + return false; + } + + int width = resized->w; + int height = resized->h; + + if (!C3D_TexInit(tex, width, height, GPU_RGBA8)) { + SDL_DestroySurface(resized); + return false; + } + + // Allocate buffer for tiled texture + uint8_t* tiledData = (uint8_t*) malloc(width * height * 4); + if (!tiledData) { + SDL_DestroySurface(resized); + return false; + } + + EncodeTextureLayout((const u8*) resized->pixels, tiledData, width, height); + + C3D_TexUpload(tex, tiledData); + C3D_TexSetFilter(tex, GPU_LINEAR, GPU_NEAREST); + + free(tiledData); + SDL_DestroySurface(resized); + return true; +} + Uint32 Citro3DRenderer::GetTextureId(IDirect3DRMTexture* iTexture) { auto texture = static_cast(iTexture); auto surface = static_cast(texture->m_surface); + SDL_Surface* originalSurface = surface->m_surface; + + int originalW = originalSurface->w; + int originalH = originalSurface->h; for (Uint32 i = 0; i < m_textures.size(); ++i) { auto& tex = m_textures[i]; if (tex.texture == texture) { if (tex.version != texture->m_version) { - // This, for some reason, causes the app to close - // instead of crashing the cpu, useful for - // debugging :) - for(i = 0; i < 10000000; i++) - printf("HI IM DAISY"); - - C3D_TexDelete(tex.c3dTex); - - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); - if (!surf) { + C3D_TexDelete(&tex.c3dTex); + if (!ConvertAndUploadTexture(&tex.c3dTex, originalSurface)) { return NO_TEXTURE_ID; } - // TODO: C3D_TexGenerateMipmap or C3D_TexInit? - // glGenTextures(1, &tex.glTextureId); - // FIXME: GPU_RGBA8 may be wrong - C3D_TexInit(tex.c3dTex, surf->w, surf->h, GPU_RGBA8); - - C3D_TexBind(0, tex.c3dTex); - C3D_TexUpload(tex.c3dTex, surf->pixels); - SDL_DestroySurface(surf); tex.version = texture->m_version; + tex.width = originalW; + tex.height = originalH; } return i; } } - C3D_Tex newTex; + C3DTextureCacheEntry entry; + entry.texture = texture; + entry.version = texture->m_version; + entry.width = originalW; + entry.height = originalH; - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); - if (!surf) { + if (!ConvertAndUploadTexture(&entry.c3dTex, originalSurface)) { return NO_TEXTURE_ID; } - C3D_TexInit(&newTex, surf->w, surf->h, GPU_RGBA8); - C3D_TexBind(0, &newTex); - C3D_TexUpload(&newTex, surf->pixels); - SDL_DestroySurface(surf); for (Uint32 i = 0; i < m_textures.size(); ++i) { - auto& tex = m_textures[i]; - if (!tex.texture) { - tex.texture = texture; - tex.version = texture->m_version; - tex.c3dTex = &newTex; + if (!m_textures[i].texture) { + m_textures[i] = std::move(entry); AddTextureDestroyCallback(i, texture); return i; } } - m_textures.push_back({texture, texture->m_version, &newTex}); + m_textures.push_back(std::move(entry)); AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture); return (Uint32) (m_textures.size() - 1); } Uint32 Citro3DRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) { - MINIWIN_NOT_IMPLEMENTED(); return 0; } void Citro3DRenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { - // not sure if this is correct? - MINIWIN_NOT_IMPLEMENTED(); - halDesc->dcmColorModel = D3DCOLORMODEL::RGB; - helDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; - helDesc->dwDeviceZBufferBitDepth = DDBD_24; - helDesc->dwDeviceRenderBitDepth = DDBD_24; - helDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; - helDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; - - // TODO: shouldn't this be bilinear - helDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; + halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; + halDesc->dwDeviceZBufferBitDepth = DDBD_24; + halDesc->dwDeviceRenderBitDepth = DDBD_32; + halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; + halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; + halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; memset(helDesc, 0, sizeof(D3DDEVICEDESC)); } @@ -326,20 +318,23 @@ const char* Citro3DRenderer::GetName() return "Citro3D"; } +void StartFrame() +{ + if (g_rendering) { + return; + } + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + C3D_FrameDrawOn(target); +} + HRESULT Citro3DRenderer::BeginFrame() { - MINIWIN_NOT_IMPLEMENTED(); - gfxFlushBuffers(); - gfxSwapBuffers(); - gspWaitForVBlank(); // FIXME: is this the right place to call, if we should at all? - C3D_FrameBegin(C3D_FRAME_SYNCDRAW); - C3D_FrameDrawOn(m_renderTarget); + StartFrame(); return S_OK; } void Citro3DRenderer::EnableTransparency() { - MINIWIN_NOT_IMPLEMENTED(); } void Citro3DRenderer::SubmitDraw( @@ -351,80 +346,104 @@ void Citro3DRenderer::SubmitDraw( const Appearance& appearance ) { - MINIWIN_NOT_IMPLEMENTED(); } HRESULT Citro3DRenderer::FinalizeFrame() { - MINIWIN_NOT_IMPLEMENTED(); - Mtx_PerspStereoTilt(&this->m_projectionMatrix, 40.0f * (acos(-1) / 180.0f), 400.0f / 240.0f, 0.01f, 1000.0f, 1, 2.0f, false); - Mtx_Translate(&this->m_projectionMatrix, 0.0, 0.0, -10.0, 0); - - //Calculate model view matrix. - C3D_Mtx modelView; - Mtx_Identity(&modelView); - // Mtx_Translate(&modelView, 0.0, 0.0, -2.0 + sinf(this->angleX)); - // Mtx_RotateX(&modelView, this->angleX, true); - // Mtx_RotateY(&modelView, this->angleY, true); - - // if (interOcularDistance >= 0.0f){ - // this->angleX += radian; - // this->angleY += radian; - // } - - //Update uniforms - C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, m_projectionShaderUniformLocation, &this->m_projectionMatrix); - C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, modelViewUniformLocation, &modelView); - - //Draw the vertex buffer objects. - C3D_DrawArrays(GPU_TRIANGLES, 0, sizeof(vertexList)); - C3D_FrameEnd(0); return S_OK; } void Citro3DRenderer::Resize(int width, int height, const ViewportTransform& viewportTransform) { - MINIWIN_NOT_IMPLEMENTED(); m_width = width; m_height = height; m_viewportTransform = viewportTransform; - - SDL_DestroySurface(m_renderedImage); - // FIXME: is this the right pixel format? - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); } void Citro3DRenderer::Clear(float r, float g, float b) { - // FIXME: check colors - C3D_RenderTargetClear(m_renderTarget, C3D_CLEAR_ALL, RGB(static_cast(r * 255), static_cast(g * 255), static_cast(b * 255)), 0); + u32 color = + (static_cast(r * 255) << 24) | (static_cast(g * 255) << 16) | (static_cast(b * 255) << 8) | 255; + C3D_RenderTargetClear(target, C3D_CLEAR_ALL, color, 0); } void Citro3DRenderer::Flip() { - MINIWIN_NOT_IMPLEMENTED(); + C3D_FrameEnd(0); } - void Citro3DRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) { - MINIWIN_NOT_IMPLEMENTED(); - MINIWIN_TRACE("on draw 2d image"); + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + StartFrame(); + C3D_DepthTest(false, GPU_GREATER, GPU_WRITE_COLOR); + float left = -m_viewportTransform.offsetX / m_viewportTransform.scale; float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale; float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; - C3D_Mtx mtx; + C3D_Mtx projection, modelView; + Mtx_OrthoTilt(&projection, left, right, bottom, top, 0.0f, 1.0f, true); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection); + Mtx_Identity(&modelView); + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_modelView, &modelView); - // TODO: isLeftHanded set to false. Should it be true? - MINIWIN_TRACE("pre orthotilt"); - Mtx_OrthoTilt(&mtx, left, right, bottom, top, -1, 1, false); + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_meshColor, 1.0f, 1.0f, 1.0f, 1.0f); - MINIWIN_TRACE("pre fvunifmtx4x4"); - C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, projectionShaderUniformLocation, &mtx); + C3DTextureCacheEntry& texture = m_textures[textureId]; + + C3D_TexBind(0, &texture.c3dTex); + + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvInit(env); + C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR); + C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); + + // Use dstRect size directly for quad size + float quadW = static_cast(dstRect.w); + float quadH = static_cast(dstRect.h); + + float x1 = static_cast(dstRect.x); + float y1 = static_cast(dstRect.y); + float x2 = x1 + quadW; + float y2 = y1 + quadH; + + float u0 = static_cast(srcRect.x) / texture.width; + float u1 = static_cast(srcRect.x + srcRect.w) / texture.width; + float v1 = 1.0f - static_cast(srcRect.y + srcRect.h) / texture.height; + float v0 = 1.0f - static_cast(srcRect.y) / texture.height; + + C3D_ImmDrawBegin(GPU_TRIANGLES); + + // Triangle 1 + C3D_ImmSendAttrib(x1, y1, 0.5f, 0.0f); + C3D_ImmSendAttrib(u0, v0, 0.0f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + + C3D_ImmSendAttrib(x2, y2, 0.5f, 0.0f); + C3D_ImmSendAttrib(u1, v1, 0.0f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + + C3D_ImmSendAttrib(x2, y1, 0.5f, 0.0f); + C3D_ImmSendAttrib(u1, v0, 0.0f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + + // Triangle 2 + C3D_ImmSendAttrib(x2, y2, 0.5f, 0.0f); + C3D_ImmSendAttrib(u1, v1, 0.0f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + + C3D_ImmSendAttrib(x1, y1, 0.5f, 0.0f); + C3D_ImmSendAttrib(u0, v0, 0.0f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + + C3D_ImmSendAttrib(x1, y2, 0.5f, 0.0f); + C3D_ImmSendAttrib(u0, v1, 0.0f, 0.0f); + C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 0.0f); + + C3D_ImmDrawEnd(); } void Citro3DRenderer::Download(SDL_Surface* target) { - MINIWIN_NOT_IMPLEMENTED(); } diff --git a/miniwin/src/d3drm/backends/citro3d/vshader.v.pica b/miniwin/src/d3drm/backends/citro3d/vshader.v.pica index 60a43fc1..e1d39e8d 100644 --- a/miniwin/src/d3drm/backends/citro3d/vshader.v.pica +++ b/miniwin/src/d3drm/backends/citro3d/vshader.v.pica @@ -5,12 +5,7 @@ ; Example PICA200 vertex shader ; Uniforms -.fvec projection[4], modelView[4], texView[2] -.fvec lightVec, lightHalfVec, lightClr, material[4] -.alias mat_amb material[0] -.alias mat_dif material[1] -.alias mat_spe material[2] -.alias mat_emi material[3] +.fvec projection[4], modelView[4], normView[2], meshColor ; Constants .constf myconst(0.0, 1.0, -1.0, -0.5) @@ -45,48 +40,10 @@ dp4 outpos.w, projection[3], r1 ; outtex = intex - dp4 outtc0.x, texView[0], intex - dp4 outtc0.y, texView[1], intex + mov outtc0, intex mov outtc0.zw, myconst.xy - - ; Transform the normal vector with the modelView matrix - ; r1 = normalize(modelView * innrm) - mov r0.xyz, innrm - mov r0.w, zeros - dp4 r1.x, modelView[0], r0 - dp4 r1.y, modelView[1], r0 - dp4 r1.z, modelView[2], r0 - mov r1.w, zeros - dp3 r2, r1, r1 ; r2 = x^2+y^2+z^2 for each component - rsq r2, r2 ; r2 = 1/sqrt(r2) '' - mul r1, r2, r1 ; r1 = r1*r2 - - ; Calculate the diffuse level (r0.x) and the shininess level (r0.y) - ; r0.x = max(0, -(lightVec * r1)) - ; r0.y = max(0, (-lightHalfVec[i]) * r1) ^ 2 - dp3 r0.x, lightVec, r1 - add r0.x, zeros, -r0 - dp3 r0.y, -lightHalfVec, r1 - max r0, zeros, r0 - mul r0.y, r0, r0 - - ; Accumulate the vertex color in r1, initializing it to the emission color - mov r1, mat_emi - - ; r1 += specularColor * lightClr * shininessLevel - mul r2, lightClr, r0.yyyy - mad r1, r2, mat_spe, r1 - - ; r1 += diffuseColor * lightClr * diffuseLevel - mul r2, lightClr, r0.xxxx - mad r1, r2, mat_dif, r1 - - ; r1 += ambientColor * lightClr - mov r2, lightClr - mad r1, r2, mat_amb, r1 - - ; outclr = clamp r1 to [0,1] - min outclr, ones, r1 + ; outclr = ones + mov outclr, meshColor ; We're finished end diff --git a/miniwin/src/d3drm/backends/directx9/renderer.cpp b/miniwin/src/d3drm/backends/directx9/renderer.cpp index 574939f5..15d13594 100644 --- a/miniwin/src/d3drm/backends/directx9/renderer.cpp +++ b/miniwin/src/d3drm/backends/directx9/renderer.cpp @@ -221,7 +221,7 @@ void DirectX9Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) halDesc->dcmColorModel = D3DCOLORMODEL::RGB; halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; halDesc->dwDeviceZBufferBitDepth = DDBD_24; - helDesc->dwDeviceRenderBitDepth = DDBD_32; + halDesc->dwDeviceRenderBitDepth = DDBD_32; halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index cc415de8..dc4f5849 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -314,7 +314,7 @@ void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) halDesc->dcmColorModel = D3DCOLORMODEL::RGB; halDesc->dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH; halDesc->dwDeviceZBufferBitDepth = DDBD_24; - helDesc->dwDeviceRenderBitDepth = DDBD_32; + halDesc->dwDeviceRenderBitDepth = DDBD_32; halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles2/renderer.cpp index 3dbabda2..34fcda90 100644 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles2/renderer.cpp @@ -421,7 +421,7 @@ void OpenGLES2Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) halDesc->dwDeviceZBufferBitDepth |= DDBD_32; } } - helDesc->dwDeviceRenderBitDepth = DDBD_32; + halDesc->dwDeviceRenderBitDepth = DDBD_32; halDesc->dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE; halDesc->dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND; halDesc->dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR; diff --git a/miniwin/src/internal/d3drmrenderer_citro3d.h b/miniwin/src/internal/d3drmrenderer_citro3d.h index bad5d18d..254303d7 100644 --- a/miniwin/src/internal/d3drmrenderer_citro3d.h +++ b/miniwin/src/internal/d3drmrenderer_citro3d.h @@ -15,9 +15,28 @@ DEFINE_GUID(Citro3D_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x struct C3DTextureCacheEntry { IDirect3DRMTexture* texture; Uint32 version; - C3D_Tex* c3dTex; + C3D_Tex c3dTex; + uint16_t width; + uint16_t height; }; +struct C3DMeshCacheEntry { + const MeshGroup* meshGroup = nullptr; + Uint32 version = 0; + bool flat = false; + + C3D_AttrInfo attrInfo; + C3D_BufInfo bufInfo; + + // CPU-side vertex data + std::vector vertices; + std::vector positions; + std::vector normals; + std::vector texcoords; // Only if you have textures + std::vector indices; // Indices for indexed drawing +}; + + class Citro3DRenderer : public Direct3DRMRenderer { public: static Direct3DRMRenderer* Create(DWORD width, DWORD height); @@ -49,14 +68,19 @@ class Citro3DRenderer : public Direct3DRMRenderer { void Flip() override; void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; void Download(SDL_Surface* target) override; + private: + C3DMeshCacheEntry UploadMesh(const MeshGroup& meshGroup); void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); + void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); D3DRMMATRIX4D m_projection; C3D_Mtx m_projectionMatrix; SDL_Surface* m_renderedImage; C3D_RenderTarget* m_renderTarget; int m_projectionShaderUniformLocation; std::vector m_textures; + std::vector m_meshs; + ViewportTransform m_viewportTransform; // TODO: All these flags can likely be cleaned up bool m_flipVertFlag;