mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-01-12 10:41:15 +00:00
Implement 2D rendering via Citro3D
This commit is contained in:
parent
356e40c9f0
commit
f80a55d4fb
@ -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);
|
||||
|
||||
@ -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 <c3d/framebuffer.h>
|
||||
#include <c3d/renderqueue.h>
|
||||
#include <c3d/texture.h>
|
||||
#include <3ds.h>
|
||||
#include <citro3d.h>
|
||||
#include <cstring>
|
||||
#include <tex3ds.h>
|
||||
|
||||
#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<TextureDestroyContextC3D*>(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<TextureDestroyContextCitro*>(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<Direct3DRMTextureImpl*>(iTexture);
|
||||
auto surface = static_cast<DirectDrawSurfaceImpl*>(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<int>(r * 255), static_cast<int>(g * 255), static_cast<int>(b * 255)), 0);
|
||||
u32 color =
|
||||
(static_cast<u32>(r * 255) << 24) | (static_cast<u32>(g * 255) << 16) | (static_cast<u32>(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<float>(dstRect.w);
|
||||
float quadH = static_cast<float>(dstRect.h);
|
||||
|
||||
float x1 = static_cast<float>(dstRect.x);
|
||||
float y1 = static_cast<float>(dstRect.y);
|
||||
float x2 = x1 + quadW;
|
||||
float y2 = y1 + quadH;
|
||||
|
||||
float u0 = static_cast<float>(srcRect.x) / texture.width;
|
||||
float u1 = static_cast<float>(srcRect.x + srcRect.w) / texture.width;
|
||||
float v1 = 1.0f - static_cast<float>(srcRect.y + srcRect.h) / texture.height;
|
||||
float v0 = 1.0f - static_cast<float>(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();
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<D3DRMVERTEX> vertices;
|
||||
std::vector<D3DVECTOR> positions;
|
||||
std::vector<D3DVECTOR> normals;
|
||||
std::vector<TexCoord> texcoords; // Only if you have textures
|
||||
std::vector<uint16_t> 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<C3DTextureCacheEntry> m_textures;
|
||||
std::vector<C3DMeshCacheEntry> m_meshs;
|
||||
ViewportTransform m_viewportTransform;
|
||||
|
||||
// TODO: All these flags can likely be cleaned up
|
||||
bool m_flipVertFlag;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user