void TextEngine::renderText(float x, float y, float scaleX, float scaleY, bool baseline, const char* text) { ssize_t units; uint32_t code; // Configure buffers C3D_BufInfo* bufInfo = C3D_GetBufInfo(); BufInfo_Init(bufInfo); BufInfo_Add(bufInfo, textVtxArray, sizeof(textVertex_s), 2, 0x10); const uint8_t* p = (const uint8_t*)text; float firstX = x; u32 flags = GLYPH_POS_CALC_VTXCOORD | (baseline ? GLYPH_POS_AT_BASELINE : 0); int lastSheet = -1; do { if (!*p) break; units = decode_utf8(&code, p); if (units == -1) break; p += units; if (code == '\n') { x = firstX; y += scaleY*fontGetInfo()->lineFeed; } else if (code > 0) { int glyphIdx = fontGlyphIndexFromCodePoint(code); fontGlyphPos_s data; fontCalcGlyphPos(&data, glyphIdx, flags, scaleX, scaleY); // Bind the correct texture sheet if (data.sheetIndex != lastSheet) { lastSheet = data.sheetIndex; C3D_TexBind(0, &glyphSheets[lastSheet]); } int arrayIndex = textVtxArrayPos; if ((arrayIndex+4) >= TEXT_VTX_ARRAY_COUNT) break; // We can't render more characters // Add the vertices to the array addTextVertex(x+data.vtxcoord.left, y+data.vtxcoord.bottom, data.texcoord.left, data.texcoord.bottom); addTextVertex(x+data.vtxcoord.right, y+data.vtxcoord.bottom, data.texcoord.right, data.texcoord.bottom); addTextVertex(x+data.vtxcoord.left, y+data.vtxcoord.top, data.texcoord.left, data.texcoord.top); addTextVertex(x+data.vtxcoord.right, y+data.vtxcoord.top, data.texcoord.right, data.texcoord.top); // Draw the glyph C3D_DrawArrays(GPU_TRIANGLE_STRIP, arrayIndex, 4); x += data.xAdvance; } } while (code > 0); }
void BackgroundImpl::draw() const { if (options) { // Draw settings background C3D_TexBind(0, &empty_tex); C3D_ImmDrawBegin(GPU_TRIANGLE_STRIP); C3D_ImmSendAttrib(0.0f, 0.0f, 0.5f, 0.0f); C3D_ImmSendAttrib(0.0f, 0.0f, 0.0f, 0.0f); C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 1.0f); C3D_ImmSendAttrib(0.0f, 240.0f, 0.5f, 0.0f); C3D_ImmSendAttrib(0.0f, 0.0f, 0.0f, 0.0f); C3D_ImmSendAttrib(0.0f, 0.0f, 0.0f, 0.0f); C3D_ImmSendAttrib(400.0f, 0.0f, 0.5f, 0.0f); C3D_ImmSendAttrib(0.0f, 0.0f, 0.0f, 0.0f); C3D_ImmSendAttrib(0.0f, 0.0f, 1.0f, 1.0f); C3D_ImmSendAttrib(400.0f, 240.0f, 0.5f, 0.0f); C3D_ImmSendAttrib(0.0f, 0.0f, 0.0f, 0.0f); C3D_ImmSendAttrib(0.0f, 0.0f, 0.0f, 0.0f); C3D_ImmDrawEnd(); } else { // Draw game background C3D_TexBind(0, &background_tex); C3D_ImmDrawBegin(GPU_TRIANGLE_STRIP); C3D_ImmSendAttrib(0.0f, 0.0f, 0.5f, 0.0f); C3D_ImmSendAttrib(0.0f, 0.0f, 0.0f, 0.0f); C3D_ImmSendAttrib(1.0f, 1.0f, 1.0f, 1.0f); C3D_ImmSendAttrib(0.0f, 240.0f, 0.5f, 0.0f); C3D_ImmSendAttrib(0.0f, 240.0f / 256.0f, 0.0f, 0.0f); C3D_ImmSendAttrib(1.0f, 1.0f, 1.0f, 1.0f); C3D_ImmSendAttrib(400.0f, 0.0f, 0.5f, 0.0f); C3D_ImmSendAttrib(400.0f / 512.0f, 0.0f, 0.0f, 0.0f); C3D_ImmSendAttrib(1.0f, 1.0f, 1.0f, 1.0f); C3D_ImmSendAttrib(400.0f, 240.0f, 0.5f, 0.0f); C3D_ImmSendAttrib(400.0f / 512.0f, 240.0f / 256.0f, 0.0f, 0.0f); C3D_ImmSendAttrib(1.0f, 1.0f, 1.0f, 1.0f); C3D_ImmDrawEnd(); } }
void Sprite::render() { if (dirtyPixels) { dirtyPixels = false; GSPGPU_FlushDataCache(pixels, w * h * format.bytesPerPixel); C3D_SafeDisplayTransfer((u32*)pixels, GX_BUFFER_DIM(w, h), (u32*)texture.data, GX_BUFFER_DIM(w, h), TEXTURE_TRANSFER_FLAGS); gspWaitForPPF(); } C3D_TexBind(0, &texture); C3D_BufInfo *bufInfo = C3D_GetBufInfo(); BufInfo_Init(bufInfo); BufInfo_Add(bufInfo, vertices, sizeof(vertex), 2, 0x10); C3D_DrawArrays(GPU_TRIANGLE_STRIP, 0, 4); }
void ctrActivateTexture(C3D_Tex* texture) { if (texture == activeTexture) { return; } if (activeTexture) { ctrFlushBatch(); } activeTexture = texture; C3D_TexBind(0, activeTexture); C3D_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); if (texture->fmt < GPU_LA8) { C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0); C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); } else { C3D_TexEnvSrc(env, C3D_RGB, GPU_PRIMARY_COLOR, 0, 0); C3D_TexEnvSrc(env, C3D_Alpha, GPU_TEXTURE0, GPU_PRIMARY_COLOR, 0); C3D_TexEnvFunc(env, C3D_RGB, GPU_REPLACE); C3D_TexEnvFunc(env, C3D_Alpha, GPU_MODULATE); } env = C3D_GetTexEnv(1); C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); C3D_TexEnvSrc(env, C3D_Both, GPU_PREVIOUS, 0, 0); C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); env = C3D_GetTexEnv(2); C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); C3D_TexEnvSrc(env, C3D_Both, GPU_PREVIOUS, 0, 0); C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); C3D_Mtx textureMtx = { .m = { // Rows are in the order w z y x, because ctrulib 0.0f, 0.0f, 0.0f, 1.0f / activeTexture->width, 0.0f, 0.0f, 1.0f / activeTexture->height, 0.0f } }; C3D_FVUnifMtx2x4(GPU_GEOMETRY_SHADER, GSH_FVEC_textureMtx, &textureMtx); }
void TextImpl::draw() const { C3D_TexBind(0, &text_tex); C3D_ImmDrawBegin(GPU_TRIANGLES); // We have only one color per Text object // TODO color for (unsigned int i = 0; i < m_quads_len; ++i) { C3D_ImmSendAttrib(m_quads[i].verts[0].x, m_quads[i].verts[0].y, 0.5f, 0.0f); C3D_ImmSendAttrib(m_quads[i].verts[0].u, m_quads[i].verts[0].v, 0.0f, 0.0f); C3D_ImmSendAttrib(m_quads[0].verts[0].r, m_quads[0].verts[0].g, m_quads[0].verts[0].b, m_quads[0].verts[0].a); C3D_ImmSendAttrib(m_quads[i].verts[2].x, m_quads[i].verts[2].y, 0.5f, 0.0f); C3D_ImmSendAttrib(m_quads[i].verts[2].u, m_quads[i].verts[2].v, 0.0f, 0.0f); C3D_ImmSendAttrib(m_quads[0].verts[0].r, m_quads[0].verts[0].g, m_quads[0].verts[0].b, m_quads[0].verts[0].a); C3D_ImmSendAttrib(m_quads[i].verts[1].x, m_quads[i].verts[1].y, 0.5f, 0.0f); C3D_ImmSendAttrib(m_quads[i].verts[1].u, m_quads[i].verts[1].v, 0.0f, 0.0f); C3D_ImmSendAttrib(m_quads[0].verts[0].r, m_quads[0].verts[0].g, m_quads[0].verts[0].b, m_quads[0].verts[0].a); C3D_ImmSendAttrib(m_quads[i].verts[0].x, m_quads[i].verts[0].y, 0.5f, 0.0f); C3D_ImmSendAttrib(m_quads[i].verts[0].u, m_quads[i].verts[0].v, 0.0f, 0.0f); C3D_ImmSendAttrib(m_quads[0].verts[0].r, m_quads[0].verts[0].g, m_quads[0].verts[0].b, m_quads[0].verts[0].a); C3D_ImmSendAttrib(m_quads[i].verts[3].x, m_quads[i].verts[3].y, 0.5f, 0.0f); C3D_ImmSendAttrib(m_quads[i].verts[3].u, m_quads[i].verts[3].v, 0.0f, 0.0f); C3D_ImmSendAttrib(m_quads[0].verts[0].r, m_quads[0].verts[0].g, m_quads[0].verts[0].b, m_quads[0].verts[0].a); C3D_ImmSendAttrib(m_quads[i].verts[2].x, m_quads[i].verts[2].y, 0.5f, 0.0f); C3D_ImmSendAttrib(m_quads[i].verts[2].u, m_quads[i].verts[2].v, 0.0f, 0.0f); C3D_ImmSendAttrib(m_quads[0].verts[0].r, m_quads[0].verts[0].g, m_quads[0].verts[0].b, m_quads[0].verts[0].a); } C3D_ImmDrawEnd(); }
//--------------------------------------------------------------------------------- static void sceneInit(void) { //--------------------------------------------------------------------------------- int i; // 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); // Get the location of the uniforms uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection"); // 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_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v2=texcoord // Compute the projection matrix // Note: we're setting top to 240 here so origin is at top left. Mtx_OrthoTilt(&projection, 0.0, 400.0, 240.0, 0.0, 0.0, 1.0); // Configure buffers C3D_BufInfo* bufInfo = C3D_GetBufInfo(); BufInfo_Init(bufInfo); unsigned char* image; unsigned width, height; lodepng_decode32(&image, &width, &height, ballsprites_png, ballsprites_png_size); u8 *gpusrc = linearAlloc(width*height*4); // GX_DisplayTransfer needs input buffer in linear RAM u8* src=image; u8 *dst=gpusrc; // lodepng outputs big endian rgba so we need to convert for(int i = 0; i<width*height; i++) { int r = *src++; int g = *src++; int b = *src++; int a = *src++; *dst++ = a; *dst++ = b; *dst++ = g; *dst++ = r; } // ensure data is in physical ram GSPGPU_FlushDataCache(gpusrc, width*height*4); // Load the texture and bind it to the first texture unit C3D_TexInit(&spritesheet_tex, width, height, GPU_RGBA8); // Convert image to 3DS tiled texture format C3D_SafeDisplayTransfer ((u32*)gpusrc, GX_BUFFER_DIM(width,height), (u32*)spritesheet_tex.data, GX_BUFFER_DIM(width,height), TEXTURE_TRANSFER_FLAGS); gspWaitForPPF(); C3D_TexSetFilter(&spritesheet_tex, GPU_LINEAR, GPU_NEAREST); C3D_TexBind(0, &spritesheet_tex); free(image); linearFree(gpusrc); // Configure the first fragment shading substage to just pass through the texture color // See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight C3D_TexEnv* env = C3D_GetTexEnv(0); C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, 0, 0); C3D_TexEnvOp(env, C3D_Both, 0, 0, 0); C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); srand(time(NULL)); for(i = 0; i < NUM_SPRITES; i++) { //random place and speed sprites[i].x = (rand() % (400 - 32 )) << 8; sprites[i].y = (rand() % (240 - 32 )) << 8 ; sprites[i].dx = (rand() & 0xFF) + 0x100; sprites[i].dy = (rand() & 0xFF) + 0x100; sprites[i].image = rand() & 3; if(rand() & 1) sprites[i].dx = -sprites[i].dx; if(rand() & 1) sprites[i].dy = -sprites[i].dy; } // Configure depth test to overwrite pixels with the same depth (needed to draw overlapping sprites) C3D_DepthTest(true, GPU_GEQUAL, GPU_WRITE_ALL); }
void gfxDrawScreen() { int screenTexSize = 256; u32* transferBuffer = screenBuffer; GPU_TEXTURE_FILTER_PARAM filter = GPU_NEAREST; if(scaleMode != 0 && scaleFilter != 0) { filter = GPU_LINEAR; if(scaleFilter == 2) { screenTexSize = 512; transferBuffer = scale2xBuffer; gfxScale2xRGBA8888(screenBuffer, 256, scale2xBuffer, 512, 256, 224); } } if(!screenInit || screenTexture.width != screenTexSize || screenTexture.height != screenTexSize) { if(screenInit) { C3D_TexDelete(&screenTexture); screenInit = false; } screenInit = C3D_TexInit(&screenTexture, screenTexSize, screenTexSize, GPU_RGBA8); } C3D_TexSetFilter(&screenTexture, filter, filter); GSPGPU_FlushDataCache(transferBuffer, screenTexSize * screenTexSize * sizeof(u32)); if(R_SUCCEEDED(GX_DisplayTransfer(transferBuffer, (u32) GX_BUFFER_DIM(screenTexSize, screenTexSize), (u32*) screenTexture.data, (u32) GX_BUFFER_DIM(screenTexSize, screenTexSize), GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)))) { gspWaitForPPF(); } GSPGPU_InvalidateDataCache(screenTexture.data, screenTexture.size); if(!C3D_FrameBegin(0)) { return; } C3D_RenderTarget* target = gameScreen == 0 ? targetTop : targetBottom; C3D_FrameDrawOn(target); C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, shaderInstanceGetUniformLocation(program.vertexShader, "projection"), gameScreen == 0 ? &projectionTop : &projectionBottom); u16 viewportWidth = target->renderBuf.colorBuf.height; u16 viewportHeight = target->renderBuf.colorBuf.width; // Draw the screen. if(screenInit) { // Calculate the VBO dimensions. int screenWidth = 256; int screenHeight = 224; if(scaleMode == 1) { screenWidth *= 1.25f; screenHeight *= 1.25f; } else if(scaleMode == 2) { screenWidth *= 1.50f; screenHeight *= 1.50f; } else if(scaleMode == 3) { screenWidth *= viewportHeight / (float) screenHeight; screenHeight = viewportHeight; } else if(scaleMode == 4) { screenWidth = viewportWidth; screenHeight = viewportHeight; } // Calculate VBO points. const float x1 = ((int) viewportWidth - screenWidth) / 2.0f; const float y1 = ((int) viewportHeight - screenHeight) / 2.0f; const float x2 = x1 + screenWidth; const float y2 = y1 + screenHeight; static const float baseTX2 = 256.0f / 256.0f; static const float baseTY2 = 224.0f / 256.0f; static const float baseFilterMod = 0.25f / 256.0f; float tx2 = baseTX2; float ty2 = baseTY2; if(scaleMode != 0 && scaleFilter == 1) { tx2 -= baseFilterMod; ty2 -= baseFilterMod; } C3D_TexBind(0, &screenTexture); C3D_ImmDrawBegin(GPU_TRIANGLES); C3D_ImmSendAttrib(x1, y1, 0.5f, 0.0f); C3D_ImmSendAttrib(0, 0, 0.0f, 0.0f); C3D_ImmSendAttrib(x2, y2, 0.5f, 0.0f); C3D_ImmSendAttrib(tx2, ty2, 0.0f, 0.0f); C3D_ImmSendAttrib(x2, y1, 0.5f, 0.0f); C3D_ImmSendAttrib(tx2, 0, 0.0f, 0.0f); C3D_ImmSendAttrib(x1, y1, 0.5f, 0.0f); C3D_ImmSendAttrib(0, 0, 0.0f, 0.0f); C3D_ImmSendAttrib(x1, y2, 0.5f, 0.0f); C3D_ImmSendAttrib(0, ty2, 0.0f, 0.0f); C3D_ImmSendAttrib(x2, y2, 0.5f, 0.0f); C3D_ImmSendAttrib(tx2, ty2, 0.0f, 0.0f); C3D_ImmDrawEnd(); } // Draw the border. if(borderInit && scaleMode != 4) { // Calculate VBO points. int scaledBorderWidth = borderWidth; int scaledBorderHeight = borderHeight; if(borderScaleMode == 1) { if(scaleMode == 1) { scaledBorderWidth *= 1.25f; scaledBorderHeight *= 1.25f; } else if(scaleMode == 2) { scaledBorderWidth *= 1.50f; scaledBorderHeight *= 1.50f; } else if(scaleMode == 3) { scaledBorderWidth *= viewportHeight / 224.0f; scaledBorderHeight *= viewportHeight / 224.0f; } else if(scaleMode == 4) { scaledBorderWidth *= viewportWidth / 256.0f; scaledBorderHeight *= viewportHeight / 224.0f; } } const float x1 = ((int) viewportWidth - scaledBorderWidth) / 2.0f; const float y1 = ((int) viewportHeight - scaledBorderHeight) / 2.0f; const float x2 = x1 + scaledBorderWidth; const float y2 = y1 + scaledBorderHeight; float tx2 = (float) borderWidth / (float) gpuBorderWidth; float ty2 = (float) borderHeight / (float) gpuBorderHeight; C3D_TexBind(0, &borderTexture); C3D_ImmDrawBegin(GPU_TRIANGLES); C3D_ImmSendAttrib(x1, y1, 0.5f, 0.0f); C3D_ImmSendAttrib(0, 0, 0.0f, 0.0f); C3D_ImmSendAttrib(x2, y2, 0.5f, 0.0f); C3D_ImmSendAttrib(tx2, ty2, 0.0f, 0.0f); C3D_ImmSendAttrib(x2, y1, 0.5f, 0.0f); C3D_ImmSendAttrib(tx2, 0, 0.0f, 0.0f); C3D_ImmSendAttrib(x1, y1, 0.5f, 0.0f); C3D_ImmSendAttrib(0, 0, 0.0f, 0.0f); C3D_ImmSendAttrib(x1, y2, 0.5f, 0.0f); C3D_ImmSendAttrib(0, ty2, 0.0f, 0.0f); C3D_ImmSendAttrib(x2, y2, 0.5f, 0.0f); C3D_ImmSendAttrib(tx2, ty2, 0.0f, 0.0f); C3D_ImmDrawEnd(); } C3D_FrameEnd(0); }