diff --git a/deps/libvita2d/include/vita2d.h b/deps/libvita2d/include/vita2d.h index 9072949390..c19ac6ed5a 100644 --- a/deps/libvita2d/include/vita2d.h +++ b/deps/libvita2d/include/vita2d.h @@ -35,6 +35,10 @@ typedef struct vita2d_texture { SceGxmTexture gxm_tex; SceUID data_UID; SceUID palette_UID; + SceGxmRenderTarget *gxm_rtgt; + SceGxmColorSurface gxm_sfc; + SceGxmDepthStencilSurface gxm_sfd; + SceUID depth_UID; } vita2d_texture; typedef struct vita2d_font vita2d_font; @@ -42,6 +46,7 @@ typedef struct vita2d_pgf vita2d_pgf; int vita2d_init(); int vita2d_init_advanced(unsigned int temp_pool_size); +int vita2d_init_advanced_with_msaa(unsigned int temp_pool_size, SceGxmMultisampleMode msaa); void vita2d_wait_rendering_done(); int vita2d_fini(); @@ -49,6 +54,7 @@ void vita2d_clear_screen(); void vita2d_swap_buffers(); void vita2d_start_drawing(); +void vita2d_start_drawing_advanced(vita2d_texture *target, unsigned int flags); void vita2d_end_drawing(); int vita2d_common_dialog_update(); @@ -56,10 +62,21 @@ int vita2d_common_dialog_update(); void vita2d_set_clear_color(unsigned int color); unsigned int vita2d_get_clear_color(); +void vita2d_set_clear_color(unsigned int color); +unsigned int vita2d_get_clear_color(); void vita2d_set_vblank_wait(int enable); void *vita2d_get_current_fb(); +SceGxmContext *vita2d_get_context(); +SceGxmShaderPatcher *vita2d_get_shader_patcher(); +const uint16_t *vita2d_get_linear_indices(); void vita2d_set_region_clip(SceGxmRegionClipMode mode, unsigned int x_min, unsigned int y_min, unsigned int x_max, unsigned int y_max); +void vita2d_enable_clipping(); +void vita2d_disable_clipping(); +int vita2d_get_clipping_enabled(); +void vita2d_set_clip_rectangle(int x_min, int y_min, int x_max, int y_max); +void vita2d_get_clip_rectangle(int *x_min, int *y_min, int *x_max, int *y_max); +void vita2d_set_blend_mode_add(int enable); void *vita2d_pool_malloc(unsigned int size); void *vita2d_pool_memalign(unsigned int size, unsigned int alignment); @@ -70,9 +87,14 @@ void vita2d_draw_pixel(float x, float y, unsigned int color); void vita2d_draw_line(float x0, float y0, float x1, float y1, unsigned int color); void vita2d_draw_rectangle(float x, float y, float w, float h, unsigned int color); void vita2d_draw_fill_circle(float x, float y, float radius, unsigned int color); +void vita2d_draw_array(SceGxmPrimitiveType mode, const vita2d_color_vertex *vertices, size_t count); +void vita2d_texture_set_alloc_memblock_type(SceKernelMemBlockType type); +SceKernelMemBlockType vita2d_texture_get_alloc_memblock_type(); vita2d_texture *vita2d_create_empty_texture(unsigned int w, unsigned int h); vita2d_texture *vita2d_create_empty_texture_format(unsigned int w, unsigned int h, SceGxmTextureFormat format); +vita2d_texture *vita2d_create_empty_texture_rendertarget(unsigned int w, unsigned int h, SceGxmTextureFormat format); + void vita2d_free_texture(vita2d_texture *texture); unsigned int vita2d_texture_get_width(const vita2d_texture *texture); @@ -93,6 +115,7 @@ void vita2d_draw_texture_part(const vita2d_texture *texture, float x, float y, f void vita2d_draw_texture_part_scale(const vita2d_texture *texture, float x, float y, float tex_x, float tex_y, float tex_w, float tex_h, float x_scale, float y_scale); void vita2d_draw_texture_scale_rotate_hotspot(const vita2d_texture *texture, float x, float y, float x_scale, float y_scale, float rad, float center_x, float center_y); void vita2d_draw_texture_scale_rotate(const vita2d_texture *texture, float x, float y, float x_scale, float y_scale, float rad); +void vita2d_draw_texture_part_scale_rotate(const vita2d_texture *texture, float x, float y, float tex_x, float tex_y, float tex_w, float tex_h, float x_scale, float y_scale, float rad); void vita2d_draw_texture_tint(const vita2d_texture *texture, float x, float y, unsigned int color); void vita2d_draw_texture_tint_rotate(const vita2d_texture *texture, float x, float y, float rad, unsigned int color); @@ -102,6 +125,8 @@ void vita2d_draw_texture_tint_part(const vita2d_texture *texture, float x, float void vita2d_draw_texture_tint_part_scale(const vita2d_texture *texture, float x, float y, float tex_x, float tex_y, float tex_w, float tex_h, float x_scale, float y_scale, unsigned int color); void vita2d_draw_texture_tint_scale_rotate_hotspot(const vita2d_texture *texture, float x, float y, float x_scale, float y_scale, float rad, float center_x, float center_y, unsigned int color); void vita2d_draw_texture_tint_scale_rotate(const vita2d_texture *texture, float x, float y, float x_scale, float y_scale, float rad, unsigned int color); +void vita2d_draw_texture_part_tint_scale_rotate(const vita2d_texture *texture, float x, float y, float tex_x, float tex_y, float tex_w, float tex_h, float x_scale, float y_scale, float rad, unsigned int color); +void vita2d_draw_array_textured(const vita2d_texture *texture, SceGxmPrimitiveType mode, const vita2d_texture_vertex *vertices, size_t count, unsigned int color); /** ADVANCED **/ void vita2d_texture_set_wvp(float x, float y, float width, float height); diff --git a/deps/libvita2d/source/vita2d.c b/deps/libvita2d/source/vita2d.c index 2192a2a374..878c97ba0b 100644 --- a/deps/libvita2d/source/vita2d.c +++ b/deps/libvita2d/source/vita2d.c @@ -25,7 +25,6 @@ #define DISPLAY_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8 #define DISPLAY_BUFFER_COUNT 3 #define DISPLAY_MAX_PENDING_SWAPS 2 -#define MSAA_MODE SCE_GXM_MULTISAMPLE_NONE #define DEFAULT_TEMP_POOL_SIZE (1 * 1024 * 1024) typedef struct vita2d_display_data { @@ -56,8 +55,14 @@ static const SceGxmProgram *const textureTintFragmentProgramGxp = &texture_tint_ static int vita2d_initialized = 0; static float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; -static unsigned int clear_color_u = 0xff000000; +static unsigned int clear_color_u = 0xFF000000; +static int clip_rect_x_min = 0; +static int clip_rect_y_min = 0; +static int clip_rect_x_max = DISPLAY_WIDTH; +static int clip_rect_y_max = DISPLAY_HEIGHT; static int vblank_wait = 1; +static int drawing = 0; +static int clipping_enabled = 0; static SceUID vdmRingBufferUid; static SceUID vertexRingBufferUid; @@ -72,8 +77,10 @@ static SceUID displayBufferUid[DISPLAY_BUFFER_COUNT]; static SceGxmColorSurface displaySurface[DISPLAY_BUFFER_COUNT]; static SceGxmSyncObject *displayBufferSync[DISPLAY_BUFFER_COUNT]; static SceUID depthBufferUid; +static SceUID stencilBufferUid; static SceGxmDepthStencilSurface depthSurface; static void *depthBufferData = NULL; +static void *stencilBufferData = NULL; static unsigned int backBufferIndex = 0; static unsigned int frontBufferIndex = 0; @@ -95,9 +102,9 @@ static SceUID patcherVertexUsseUid; static SceUID patcherFragmentUsseUid; static SceUID clearVerticesUid; -static SceUID clearIndicesUid; +static SceUID linearIndicesUid; static vita2d_clear_vertex *clearVertices = NULL; -static uint16_t *clearIndices = NULL; +static uint16_t *linearIndices = NULL; /* Shared with other .c */ float _vita2d_ortho_matrix[4*4]; @@ -112,6 +119,17 @@ const SceGxmProgramParameter *_vita2d_colorWvpParam = NULL; const SceGxmProgramParameter *_vita2d_textureWvpParam = NULL; const SceGxmProgramParameter *_vita2d_textureTintColorParam = NULL; +typedef struct vita2d_fragment_programs { + SceGxmFragmentProgram *color; + SceGxmFragmentProgram *texture; + SceGxmFragmentProgram *textureTint; +} vita2d_fragment_programs; + +struct { + vita2d_fragment_programs blend_mode_normal; + vita2d_fragment_programs blend_mode_add; +} _vita2d_fragmentPrograms; + // Temporary memory pool static void *pool_addr = NULL; static SceUID poolUid; @@ -149,12 +167,54 @@ static void display_callback(const void *callback_data) } } -int vita2d_init() +static void _vita2d_free_fragment_programs(vita2d_fragment_programs *out) { - return vita2d_init_advanced(DEFAULT_TEMP_POOL_SIZE); + sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, out->color); + sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, out->texture); + sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, out->textureTint); } -int vita2d_init_advanced(unsigned int temp_pool_size) +static void _vita2d_make_fragment_programs(vita2d_fragment_programs *out, + const SceGxmBlendInfo *blend_info, SceGxmMultisampleMode msaa) +{ + int err; + (void)err; + + err = sceGxmShaderPatcherCreateFragmentProgram( + shaderPatcher, + colorFragmentProgramId, + SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, + msaa, + blend_info, + colorVertexProgramGxp, + &out->color); + + VITA2D_DEBUG("color sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err); + + err = sceGxmShaderPatcherCreateFragmentProgram( + shaderPatcher, + textureFragmentProgramId, + SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, + msaa, + blend_info, + textureVertexProgramGxp, + &out->texture); + + VITA2D_DEBUG("texture sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err); + + err = sceGxmShaderPatcherCreateFragmentProgram( + shaderPatcher, + textureTintFragmentProgramId, + SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, + msaa, + blend_info, + textureVertexProgramGxp, + &out->textureTint); + + VITA2D_DEBUG("texture_tint sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err); +} + +static int vita2d_init_internal(unsigned int temp_pool_size, SceGxmMultisampleMode msaa) { int err; unsigned int i, x, y; @@ -227,7 +287,7 @@ int vita2d_init_advanced(unsigned int temp_pool_size) renderTargetParams.width = DISPLAY_WIDTH; renderTargetParams.height = DISPLAY_HEIGHT; renderTargetParams.scenesPerFrame = 1; - renderTargetParams.multisampleMode = MSAA_MODE; + renderTargetParams.multisampleMode = msaa; renderTargetParams.multisampleLocations = 0; renderTargetParams.driverMemBlock = -1; // Invalid UID @@ -258,7 +318,7 @@ int vita2d_init_advanced(unsigned int temp_pool_size) &displaySurface[i], DISPLAY_COLOR_FORMAT, SCE_GXM_COLOR_SURFACE_LINEAR, - (MSAA_MODE == SCE_GXM_MULTISAMPLE_NONE) ? SCE_GXM_COLOR_SURFACE_SCALE_NONE : SCE_GXM_COLOR_SURFACE_SCALE_MSAA_DOWNSCALE, + (msaa == SCE_GXM_MULTISAMPLE_NONE) ? SCE_GXM_COLOR_SURFACE_SCALE_NONE : SCE_GXM_COLOR_SURFACE_SCALE_MSAA_DOWNSCALE, SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT, DISPLAY_WIDTH, DISPLAY_HEIGHT, @@ -274,11 +334,11 @@ int vita2d_init_advanced(unsigned int temp_pool_size) const unsigned int alignedHeight = ALIGN(DISPLAY_HEIGHT, SCE_GXM_TILE_SIZEY); unsigned int sampleCount = alignedWidth*alignedHeight; unsigned int depthStrideInSamples = alignedWidth; - if (MSAA_MODE == SCE_GXM_MULTISAMPLE_4X) { + if (msaa == SCE_GXM_MULTISAMPLE_4X) { // samples increase in X and Y sampleCount *= 4; depthStrideInSamples *= 2; - } else if (MSAA_MODE == SCE_GXM_MULTISAMPLE_2X) { + } else if (msaa == SCE_GXM_MULTISAMPLE_2X) { // samples increase in Y only sampleCount *= 2; } @@ -291,6 +351,14 @@ int vita2d_init_advanced(unsigned int temp_pool_size) SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, &depthBufferUid); + // allocate the stencil buffer + stencilBufferData = gpu_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, + 4*sampleCount, + SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, + SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, + &stencilBufferUid); + // create the SceGxmDepthStencilSurface structure err = sceGxmDepthStencilSurfaceInit( &depthSurface, @@ -298,7 +366,19 @@ int vita2d_init_advanced(unsigned int temp_pool_size) SCE_GXM_DEPTH_STENCIL_SURFACE_TILED, depthStrideInSamples, depthBufferData, - NULL); + stencilBufferData); + + // set the stencil test reference (this is currently assumed to always remain 1 after here for region clipping) + sceGxmSetFrontStencilRef(_vita2d_context, 1); + // set the stencil function (this wouldn't actually be needed, as the set clip rectangle function has to call this at the begginning of every scene) + sceGxmSetFrontStencilFunc( + _vita2d_context, + SCE_GXM_STENCIL_FUNC_ALWAYS, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + 0xFF, + 0xFF); // set buffer sizes for this sample const unsigned int patcherBufferSize = 64*1024; @@ -393,8 +473,18 @@ int vita2d_init_advanced(unsigned int temp_pool_size) .alphaFunc = SCE_GXM_BLEND_FUNC_ADD, .colorSrc = SCE_GXM_BLEND_FACTOR_SRC_ALPHA, .colorDst = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaSrc = SCE_GXM_BLEND_FACTOR_SRC_ALPHA, + .alphaDst = SCE_GXM_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorMask = SCE_GXM_COLOR_MASK_ALL + }; + + static const SceGxmBlendInfo blend_info_add = { + .colorFunc = SCE_GXM_BLEND_FUNC_ADD, + .alphaFunc = SCE_GXM_BLEND_FUNC_ADD, + .colorSrc = SCE_GXM_BLEND_FACTOR_ONE, + .colorDst = SCE_GXM_BLEND_FACTOR_ONE, .alphaSrc = SCE_GXM_BLEND_FACTOR_ONE, - .alphaDst = SCE_GXM_BLEND_FACTOR_ZERO, + .alphaDst = SCE_GXM_BLEND_FACTOR_ONE, .colorMask = SCE_GXM_COLOR_MASK_ALL }; @@ -428,7 +518,7 @@ int vita2d_init_advanced(unsigned int temp_pool_size) shaderPatcher, clearFragmentProgramId, SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, - MSAA_MODE, + msaa, NULL, clearVertexProgramGxp, &clearFragmentProgram); @@ -443,12 +533,20 @@ int vita2d_init_advanced(unsigned int temp_pool_size) SCE_GXM_MEMORY_ATTRIB_READ, &clearVerticesUid); - clearIndices = (uint16_t *)gpu_alloc( + // Allocate a 64k * 2 bytes = 128 KiB buffer and store all possible + // 16-bit indices in linear ascending order, so we can use this for + // all drawing operations where we don't want to use indexing. + linearIndices = (uint16_t *)gpu_alloc( SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, - 3*sizeof(uint16_t), - 2, + UINT16_MAX*sizeof(uint16_t), + sizeof(uint16_t), SCE_GXM_MEMORY_ATTRIB_READ, - &clearIndicesUid); + &linearIndicesUid); + + // Range of i must be greater than uint16_t, this doesn't endless-loop + for (uint32_t i=0; i<=UINT16_MAX; ++i) { + linearIndices[i] = i; + } clearVertices[0].x = -1.0f; clearVertices[0].y = -1.0f; @@ -457,10 +555,6 @@ int vita2d_init_advanced(unsigned int temp_pool_size) clearVertices[2].x = -1.0f; clearVertices[2].y = 3.0f; - clearIndices[0] = 0; - clearIndices[1] = 1; - clearIndices[2] = 2; - const SceGxmProgramParameter *paramColorPositionAttribute = sceGxmProgramFindParameterByName(colorVertexProgramGxp, "aPosition"); VITA2D_DEBUG("aPosition sceGxmProgramFindParameterByName(): %p\n", paramColorPositionAttribute); @@ -498,17 +592,6 @@ int vita2d_init_advanced(unsigned int temp_pool_size) VITA2D_DEBUG("color sceGxmShaderPatcherCreateVertexProgram(): 0x%08X\n", err); - err = sceGxmShaderPatcherCreateFragmentProgram( - shaderPatcher, - colorFragmentProgramId, - SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, - MSAA_MODE, - &blend_info, - colorVertexProgramGxp, - &_vita2d_colorFragmentProgram); - - VITA2D_DEBUG("color sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err); - const SceGxmProgramParameter *paramTexturePositionAttribute = sceGxmProgramFindParameterByName(textureVertexProgramGxp, "aPosition"); VITA2D_DEBUG("aPosition sceGxmProgramFindParameterByName(): %p\n", paramTexturePositionAttribute); @@ -547,27 +630,12 @@ int vita2d_init_advanced(unsigned int temp_pool_size) VITA2D_DEBUG("texture sceGxmShaderPatcherCreateVertexProgram(): 0x%08X\n", err); - err = sceGxmShaderPatcherCreateFragmentProgram( - shaderPatcher, - textureFragmentProgramId, - SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, - MSAA_MODE, - &blend_info, - textureVertexProgramGxp, - &_vita2d_textureFragmentProgram); + // Create variations of the fragment program based on blending mode + _vita2d_make_fragment_programs(&_vita2d_fragmentPrograms.blend_mode_normal, &blend_info, msaa); + _vita2d_make_fragment_programs(&_vita2d_fragmentPrograms.blend_mode_add, &blend_info_add, msaa); - VITA2D_DEBUG("texture sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err); - - err = sceGxmShaderPatcherCreateFragmentProgram( - shaderPatcher, - textureTintFragmentProgramId, - SCE_GXM_OUTPUT_REGISTER_FORMAT_UCHAR4, - MSAA_MODE, - &blend_info, - textureVertexProgramGxp, - &_vita2d_textureTintFragmentProgram); - - VITA2D_DEBUG("texture_tint sceGxmShaderPatcherCreateFragmentProgram(): 0x%08X\n", err); + // Default to "normal" blending mode (non-additive) + vita2d_set_blend_mode_add(0); // find vertex uniforms by name and cache parameter information _vita2d_clearClearColorParam = sceGxmProgramFindParameterByName(clearFragmentProgramGxp, "uClearColor"); @@ -590,6 +658,7 @@ int vita2d_init_advanced(unsigned int temp_pool_size) sizeof(void *), SCE_GXM_MEMORY_ATTRIB_READ, &poolUid); + matrix_init_orthographic(_vita2d_ortho_matrix, 0.0f, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0.0f, 0.0f, 1.0f); @@ -605,6 +674,21 @@ int vita2d_init_advanced(unsigned int temp_pool_size) return 1; } +int vita2d_init() +{ + return vita2d_init_internal(DEFAULT_TEMP_POOL_SIZE, SCE_GXM_MULTISAMPLE_NONE); +} + +int vita2d_init_advanced(unsigned int temp_pool_size) +{ + return vita2d_init_internal(temp_pool_size, SCE_GXM_MULTISAMPLE_NONE); +} + +int vita2d_init_advanced_with_msaa(unsigned int temp_pool_size, SceGxmMultisampleMode msaa) +{ + return vita2d_init_internal(temp_pool_size, msaa); +} + void vita2d_wait_rendering_done() { sceGxmFinish(_vita2d_context); @@ -625,12 +709,13 @@ int vita2d_fini() // clean up allocations sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, clearFragmentProgram); sceGxmShaderPatcherReleaseVertexProgram(shaderPatcher, clearVertexProgram); - sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, _vita2d_colorFragmentProgram); sceGxmShaderPatcherReleaseVertexProgram(shaderPatcher, _vita2d_colorVertexProgram); - sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, _vita2d_textureFragmentProgram); - sceGxmShaderPatcherReleaseFragmentProgram(shaderPatcher, _vita2d_textureTintFragmentProgram); sceGxmShaderPatcherReleaseVertexProgram(shaderPatcher, _vita2d_textureVertexProgram); - gpu_free(clearIndicesUid); + + _vita2d_free_fragment_programs(&_vita2d_fragmentPrograms.blend_mode_normal); + _vita2d_free_fragment_programs(&_vita2d_fragmentPrograms.blend_mode_add); + + gpu_free(linearIndicesUid); gpu_free(clearVerticesUid); // wait until display queue is finished before deallocating display buffers @@ -647,8 +732,9 @@ int vita2d_fini() sceGxmSyncObjectDestroy(displayBufferSync[i]); } - // free the depth buffer + // free the depth and stencil buffer gpu_free(depthBufferUid); + gpu_free(stencilBufferUid); // unregister programs and destroy shader patcher sceGxmShaderPatcherUnregisterProgram(shaderPatcher, clearFragmentProgramId); @@ -701,7 +787,7 @@ void vita2d_clear_screen() // draw the clear triangle sceGxmSetVertexStream(_vita2d_context, 0, clearVertices); - sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLES, SCE_GXM_INDEX_FORMAT_U16, clearIndices, 3); + sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLES, SCE_GXM_INDEX_FORMAT_U16, linearIndices, 3); } void vita2d_swap_buffers() @@ -723,23 +809,129 @@ void vita2d_swap_buffers() void vita2d_start_drawing() { - /* Reset the temporary memory pool */ vita2d_pool_reset(); + vita2d_start_drawing_advanced(NULL, 0); +} - sceGxmBeginScene( +void vita2d_start_drawing_advanced(vita2d_texture *target, unsigned int flags) +{ + + if (target == NULL) { + sceGxmBeginScene( _vita2d_context, - 0, + flags, renderTarget, NULL, NULL, displayBufferSync[backBufferIndex], &displaySurface[backBufferIndex], &depthSurface); + } else { + sceGxmBeginScene( + _vita2d_context, + flags, + target->gxm_rtgt, + NULL, + NULL, + NULL, + &target->gxm_sfc, + &target->gxm_sfd); + } + + drawing = 1; + // in the current way, the library keeps the region clip across scenes + if (clipping_enabled) { + vita2d_set_clip_rectangle(clip_rect_x_min, clip_rect_y_min, clip_rect_x_max, clip_rect_y_max); + } } void vita2d_end_drawing() { sceGxmEndScene(_vita2d_context, NULL, NULL); + drawing = 0; +} + +void vita2d_enable_clipping() +{ + clipping_enabled = 1; + vita2d_set_clip_rectangle(clip_rect_x_min, clip_rect_y_min, clip_rect_x_max, clip_rect_y_max); +} + +void vita2d_disable_clipping() +{ + clipping_enabled = 0; + sceGxmSetFrontStencilFunc( + _vita2d_context, + SCE_GXM_STENCIL_FUNC_ALWAYS, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + 0xFF, + 0xFF); +} + +int vita2d_get_clipping_enabled() +{ + return clipping_enabled; +} + +void vita2d_set_clip_rectangle(int x_min, int y_min, int x_max, int y_max) +{ + clip_rect_x_min = x_min; + clip_rect_y_min = y_min; + clip_rect_x_max = x_max; + clip_rect_y_max = y_max; + // we can only draw during a scene, but we can cache the values since they're not going to have any visible effect till the scene starts anyways + if(drawing) { + // clear the stencil buffer to 0 + sceGxmSetFrontStencilFunc( + _vita2d_context, + SCE_GXM_STENCIL_FUNC_NEVER, + SCE_GXM_STENCIL_OP_ZERO, + SCE_GXM_STENCIL_OP_ZERO, + SCE_GXM_STENCIL_OP_ZERO, + 0xFF, + 0xFF); + vita2d_draw_rectangle(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0); + // set the stencil to 1 in the desired region + sceGxmSetFrontStencilFunc( + _vita2d_context, + SCE_GXM_STENCIL_FUNC_NEVER, + SCE_GXM_STENCIL_OP_REPLACE, + SCE_GXM_STENCIL_OP_REPLACE, + SCE_GXM_STENCIL_OP_REPLACE, + 0xFF, + 0xFF); + vita2d_draw_rectangle(x_min, y_min, x_max - x_min, y_max - y_min, 0); + if(clipping_enabled) { + // set the stencil function to only accept pixels where the stencil is 1 + sceGxmSetFrontStencilFunc( + _vita2d_context, + SCE_GXM_STENCIL_FUNC_EQUAL, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + 0xFF, + 0xFF); + } else { + sceGxmSetFrontStencilFunc( + _vita2d_context, + SCE_GXM_STENCIL_FUNC_ALWAYS, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + SCE_GXM_STENCIL_OP_KEEP, + 0xFF, + 0xFF); + } + } +} + +void vita2d_get_clip_rectangle(int *x_min, int *y_min, int *x_max, int *y_max) +{ + *x_min = clip_rect_x_min; + *y_min = clip_rect_y_min; + *x_max = clip_rect_x_max; + *y_max = clip_rect_y_max; } int vita2d_common_dialog_update() @@ -769,7 +961,8 @@ void vita2d_set_clear_color(unsigned int color) clear_color_u = color; } -unsigned int vita2d_get_clear_color(){ +unsigned int vita2d_get_clear_color() +{ return clear_color_u; } @@ -783,6 +976,21 @@ void *vita2d_get_current_fb() return displayBufferData[frontBufferIndex]; } +SceGxmContext *vita2d_get_context() +{ + return _vita2d_context; +} + +SceGxmShaderPatcher *vita2d_get_shader_patcher() +{ + return shaderPatcher; +} + +const uint16_t *vita2d_get_linear_indices() +{ + return linearIndices; +} + void vita2d_set_region_clip(SceGxmRegionClipMode mode, unsigned int x_min, unsigned int y_min, unsigned int x_max, unsigned int y_max) { sceGxmSetRegionClip(_vita2d_context, mode, x_min, y_min, x_max, y_max); @@ -818,3 +1026,13 @@ void vita2d_pool_reset() { pool_index = 0; } + +void vita2d_set_blend_mode_add(int enable) +{ + vita2d_fragment_programs *in = enable ? &_vita2d_fragmentPrograms.blend_mode_add + : &_vita2d_fragmentPrograms.blend_mode_normal; + + _vita2d_colorFragmentProgram = in->color; + _vita2d_textureFragmentProgram = in->texture; + _vita2d_textureTintFragmentProgram = in->textureTint; +} \ No newline at end of file diff --git a/deps/libvita2d/source/vita2d_texture.c b/deps/libvita2d/source/vita2d_texture.c index 452bd4e51e..8fc1e6d475 100644 --- a/deps/libvita2d/source/vita2d_texture.c +++ b/deps/libvita2d/source/vita2d_texture.c @@ -7,6 +7,7 @@ #include "shared.h" #define GXM_TEX_MAX_SIZE 4096 +static SceKernelMemBlockType MemBlockType = SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW; static int tex_format_to_bytespp(SceGxmTextureFormat format) { @@ -36,12 +37,22 @@ static int tex_format_to_bytespp(SceGxmTextureFormat format) } } +void vita2d_texture_set_alloc_memblock_type(SceKernelMemBlockType type) +{ + MemBlockType = (type == 0) ? SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW : type; +} + +SceKernelMemBlockType vita2d_texture_get_alloc_memblock_type() +{ + return MemBlockType; +} + vita2d_texture *vita2d_create_empty_texture(unsigned int w, unsigned int h) { return vita2d_create_empty_texture_format(w, h, SCE_GXM_TEXTURE_FORMAT_A8B8G8R8); } -vita2d_texture *vita2d_create_empty_texture_format(unsigned int w, unsigned int h, SceGxmTextureFormat format) +static vita2d_texture *_vita2d_create_empty_texture_format_advanced(unsigned int w, unsigned int h, SceGxmTextureFormat format, unsigned int isRenderTarget) { if (w > GXM_TEX_MAX_SIZE || h > GXM_TEX_MAX_SIZE) return NULL; @@ -54,10 +65,10 @@ vita2d_texture *vita2d_create_empty_texture_format(unsigned int w, unsigned int /* Allocate a GPU buffer for the texture */ void *texture_data = gpu_alloc( - SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, + MemBlockType, tex_size, SCE_GXM_TEXTURE_ALIGNMENT, - SCE_GXM_MEMORY_ATTRIB_READ, + SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, &texture->data_UID); if (!texture_data) { @@ -66,7 +77,7 @@ vita2d_texture *vita2d_create_empty_texture_format(unsigned int w, unsigned int } /* Clear the texture */ - //memset(texture_data, 0, tex_size); + memset(texture_data, 0, tex_size); /* Create the gxm texture */ sceGxmTextureInitLinear( @@ -82,7 +93,7 @@ vita2d_texture *vita2d_create_empty_texture_format(unsigned int w, unsigned int const int pal_size = 256 * sizeof(uint32_t); void *texture_palette = gpu_alloc( - SCE_KERNEL_MEMBLOCK_TYPE_USER_CDRAM_RW, + MemBlockType, pal_size, SCE_GXM_PALETTE_ALIGNMENT, SCE_GXM_MEMORY_ATTRIB_READ, @@ -94,19 +105,107 @@ vita2d_texture *vita2d_create_empty_texture_format(unsigned int w, unsigned int return NULL; } - //memset(texture_palette, 0, pal_size); + memset(texture_palette, 0, pal_size); sceGxmTextureSetPalette(&texture->gxm_tex, texture_palette); } else { texture->palette_UID = 0; } + if (isRenderTarget) { + + int err = sceGxmColorSurfaceInit( + &texture->gxm_sfc, + SCE_GXM_COLOR_FORMAT_A8B8G8R8, + SCE_GXM_COLOR_SURFACE_LINEAR, + SCE_GXM_COLOR_SURFACE_SCALE_NONE, + SCE_GXM_OUTPUT_REGISTER_SIZE_32BIT, + w, + h, + w, + texture_data + ); + + if (err < 0) { + vita2d_free_texture(texture); + return NULL; + } + + // create the depth/stencil surface + const uint32_t alignedWidth = ALIGN(w, SCE_GXM_TILE_SIZEX); + const uint32_t alignedHeight = ALIGN(h, SCE_GXM_TILE_SIZEY); + uint32_t sampleCount = alignedWidth*alignedHeight; + uint32_t depthStrideInSamples = alignedWidth; + + // allocate it + void *depthBufferData = gpu_alloc( + SCE_KERNEL_MEMBLOCK_TYPE_USER_RW_UNCACHE, + 4*sampleCount, + SCE_GXM_DEPTHSTENCIL_SURFACE_ALIGNMENT, + SCE_GXM_MEMORY_ATTRIB_READ | SCE_GXM_MEMORY_ATTRIB_WRITE, + &texture->depth_UID); + + // create the SceGxmDepthStencilSurface structure + err = sceGxmDepthStencilSurfaceInit( + &texture->gxm_sfd, + SCE_GXM_DEPTH_STENCIL_FORMAT_S8D24, + SCE_GXM_DEPTH_STENCIL_SURFACE_TILED, + depthStrideInSamples, + depthBufferData, + NULL); + + if (err < 0) { + vita2d_free_texture(texture); + return NULL; + } + + SceGxmRenderTarget *tgt = NULL; + + // set up parameters + SceGxmRenderTargetParams renderTargetParams; + memset(&renderTargetParams, 0, sizeof(SceGxmRenderTargetParams)); + renderTargetParams.flags = 0; + renderTargetParams.width = w; + renderTargetParams.height = h; + renderTargetParams.scenesPerFrame = 1; + renderTargetParams.multisampleMode = SCE_GXM_MULTISAMPLE_NONE; + renderTargetParams.multisampleLocations = 0; + renderTargetParams.driverMemBlock = -1; + + // create the render target + err = sceGxmCreateRenderTarget(&renderTargetParams, &tgt); + + texture->gxm_rtgt = tgt; + + if (err < 0) { + vita2d_free_texture(texture); + return NULL; + } + + } + return texture; } +vita2d_texture * vita2d_create_empty_texture_format(unsigned int w, unsigned int h, SceGxmTextureFormat format) +{ + return _vita2d_create_empty_texture_format_advanced(w, h, format, 0); +} + +vita2d_texture * vita2d_create_empty_texture_rendertarget(unsigned int w, unsigned int h, SceGxmTextureFormat format) +{ + return _vita2d_create_empty_texture_format_advanced(w, h, format, 1); +} + void vita2d_free_texture(vita2d_texture *texture) { if (texture) { + if (texture->gxm_rtgt) { + sceGxmDestroyRenderTarget(texture->gxm_rtgt); + } + if (texture->depth_UID) { + gpu_free(texture->depth_UID); + } if (texture->palette_UID) { gpu_free(texture->palette_UID); } @@ -178,7 +277,6 @@ static inline void set_texture_wvp_uniform() { void *vertex_wvp_buffer; sceGxmReserveVertexDefaultUniformBuffer(_vita2d_context, &vertex_wvp_buffer); - //matrix_init_orthographic(_vita2d_ortho_matrix, 0.0f, DISPLAY_WIDTH, DISPLAY_HEIGHT, 0.0f, 0.0f, 1.0f); sceGxmSetUniformDataF(vertex_wvp_buffer, _vita2d_textureWvpParam, 0, 16, _vita2d_ortho_matrix); } @@ -205,10 +303,6 @@ static inline void draw_texture_generic(const vita2d_texture *texture, float x, 4 * sizeof(vita2d_texture_vertex), // 4 vertices sizeof(vita2d_texture_vertex)); - uint16_t *indices = (uint16_t *)vita2d_pool_memalign( - 4 * sizeof(uint16_t), // 4 indices - sizeof(uint16_t)); - const float w = vita2d_texture_get_width(texture); const float h = vita2d_texture_get_height(texture); @@ -236,16 +330,11 @@ static inline void draw_texture_generic(const vita2d_texture *texture, float x, vertices[3].u = 1.0f; vertices[3].v = 1.0f; - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 3; - // Set the texture to the TEXUNIT0 sceGxmSetFragmentTexture(_vita2d_context, 0, &texture->gxm_tex); sceGxmSetVertexStream(_vita2d_context, 0, vertices); - sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, indices, 4); + sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, vita2d_get_linear_indices(), 4); } void vita2d_draw_texture(const vita2d_texture *texture, float x, float y) @@ -284,10 +373,6 @@ static inline void draw_texture_rotate_hotspot_generic(const vita2d_texture *tex 4 * sizeof(vita2d_texture_vertex), // 4 vertices sizeof(vita2d_texture_vertex)); - uint16_t *indices = (uint16_t *)vita2d_pool_memalign( - 4 * sizeof(uint16_t), // 4 indices - sizeof(uint16_t)); - const float w = vita2d_texture_get_width(texture); const float h = vita2d_texture_get_height(texture); @@ -325,16 +410,11 @@ static inline void draw_texture_rotate_hotspot_generic(const vita2d_texture *tex vertices[i].y = _x*s + _y*c + y; } - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 3; - // Set the texture to the TEXUNIT0 sceGxmSetFragmentTexture(_vita2d_context, 0, &texture->gxm_tex); sceGxmSetVertexStream(_vita2d_context, 0, vertices); - sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, indices, 4); + sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, vita2d_get_linear_indices(), 4); } void vita2d_draw_texture_rotate_hotspot(const vita2d_texture *texture, float x, float y, float rad, float center_x, float center_y) @@ -358,10 +438,6 @@ static inline void draw_texture_scale_generic(const vita2d_texture *texture, flo 4 * sizeof(vita2d_texture_vertex), // 4 vertices sizeof(vita2d_texture_vertex)); - uint16_t *indices = (uint16_t *)vita2d_pool_memalign( - 4 * sizeof(uint16_t), // 4 indices - sizeof(uint16_t)); - const float w = x_scale * vita2d_texture_get_width(texture); const float h = y_scale * vita2d_texture_get_height(texture); @@ -389,16 +465,11 @@ static inline void draw_texture_scale_generic(const vita2d_texture *texture, flo vertices[3].u = 1.0f; vertices[3].v = 1.0f; - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 3; - // Set the texture to the TEXUNIT0 sceGxmSetFragmentTexture(_vita2d_context, 0, &texture->gxm_tex); sceGxmSetVertexStream(_vita2d_context, 0, vertices); - sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, indices, 4); + sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, vita2d_get_linear_indices(), 4); } void vita2d_draw_texture_scale(const vita2d_texture *texture, float x, float y, float x_scale, float y_scale) @@ -423,10 +494,6 @@ static inline void draw_texture_part_generic(const vita2d_texture *texture, floa 4 * sizeof(vita2d_texture_vertex), // 4 vertices sizeof(vita2d_texture_vertex)); - uint16_t *indices = (uint16_t *)vita2d_pool_memalign( - 4 * sizeof(uint16_t), // 4 indices - sizeof(uint16_t)); - const float w = vita2d_texture_get_width(texture); const float h = vita2d_texture_get_height(texture); @@ -459,16 +526,11 @@ static inline void draw_texture_part_generic(const vita2d_texture *texture, floa vertices[3].u = u1; vertices[3].v = v1; - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 3; - // Set the texture to the TEXUNIT0 sceGxmSetFragmentTexture(_vita2d_context, 0, &texture->gxm_tex); sceGxmSetVertexStream(_vita2d_context, 0, vertices); - sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, indices, 4); + sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, vita2d_get_linear_indices(), 4); } void vita2d_draw_texture_part(const vita2d_texture *texture, float x, float y, float tex_x, float tex_y, float tex_w, float tex_h) @@ -492,10 +554,6 @@ static inline void draw_texture_part_scale_generic(const vita2d_texture *texture 4 * sizeof(vita2d_texture_vertex), // 4 vertices sizeof(vita2d_texture_vertex)); - uint16_t *indices = (uint16_t *)vita2d_pool_memalign( - 4 * sizeof(uint16_t), // 4 indices - sizeof(uint16_t)); - const float w = vita2d_texture_get_width(texture); const float h = vita2d_texture_get_height(texture); @@ -531,16 +589,11 @@ static inline void draw_texture_part_scale_generic(const vita2d_texture *texture vertices[3].u = u1; vertices[3].v = v1; - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 3; - // Set the texture to the TEXUNIT0 sceGxmSetFragmentTexture(_vita2d_context, 0, &texture->gxm_tex); sceGxmSetVertexStream(_vita2d_context, 0, vertices); - sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, indices, 4); + sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, vita2d_get_linear_indices(), 4); } void vita2d_draw_texture_part_scale(const vita2d_texture *texture, float x, float y, float tex_x, float tex_y, float tex_w, float tex_h, float x_scale, float y_scale) @@ -564,10 +617,6 @@ static inline void draw_texture_scale_rotate_hotspot_generic(const vita2d_textur 4 * sizeof(vita2d_texture_vertex), // 4 vertices sizeof(vita2d_texture_vertex)); - uint16_t *indices = (uint16_t *)vita2d_pool_memalign( - 4 * sizeof(uint16_t), // 4 indices - sizeof(uint16_t)); - const float w = x_scale * vita2d_texture_get_width(texture); const float h = y_scale * vita2d_texture_get_height(texture); const float center_x_scaled = x_scale * center_x; @@ -607,16 +656,11 @@ static inline void draw_texture_scale_rotate_hotspot_generic(const vita2d_textur vertices[i].y = _x*s + _y*c + y + center_y_scaled; } - indices[0] = 0; - indices[1] = 1; - indices[2] = 2; - indices[3] = 3; - // Set the texture to the TEXUNIT0 sceGxmSetFragmentTexture(_vita2d_context, 0, &texture->gxm_tex); sceGxmSetVertexStream(_vita2d_context, 0, vertices); - sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, indices, 4); + sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, vita2d_get_linear_indices(), 4); } void vita2d_draw_texture_scale_rotate_hotspot(const vita2d_texture *texture, float x, float y, float x_scale, float y_scale, float rad, float center_x, float center_y) @@ -650,43 +694,95 @@ void vita2d_draw_texture_tint_scale_rotate(const vita2d_texture *texture, float vita2d_texture_get_height(texture)/2.0f, color); } -void vita2d_texture_set_wvp(float x, float y, float width, float height) +static inline void draw_texture_part_scale_rotate_generic(const vita2d_texture *texture, float x, float y, + float tex_x, float tex_y, float tex_w, float tex_h, float x_scale, float y_scale, float rad) { - void *vertex_wvp_buffer; - matrix_init_orthographic(_vita2d_ortho_matrix, x, width, height, y, 0.0f, 1.0f); - sceGxmReserveVertexDefaultUniformBuffer(_vita2d_context, &vertex_wvp_buffer); - sceGxmSetUniformDataF(vertex_wvp_buffer, _vita2d_textureWvpParam, 0, 16, _vita2d_ortho_matrix); -} + vita2d_texture_vertex *vertices = (vita2d_texture_vertex *)vita2d_pool_memalign( + 4 * sizeof(vita2d_texture_vertex), // 4 vertices + sizeof(vita2d_texture_vertex)); -void vita2d_texture_set_program(){ - set_texture_program(); -} + const float w_full = vita2d_texture_get_width(texture); + const float h_full = vita2d_texture_get_height(texture); -void vita2d_texture_set_tint_program(){ - set_texture_tint_program(); -} + const float w_half = (tex_w * x_scale) / 2.0f; + const float h_half = (tex_h * y_scale) / 2.0f; -void vita2d_texture_set_tint_color_uniform(unsigned int color){ - set_texture_tint_color_uniform(color); -} + const float u0 = tex_x / w_full; + const float v0 = tex_y / h_full; + const float u1 = (tex_x + tex_w) / w_full; + const float v1 = (tex_y + tex_h) / h_full; + vertices[0].x = -w_half; + vertices[0].y = -h_half; + vertices[0].z = +0.5f; + vertices[0].u = u0; + vertices[0].v = v0; -void vita2d_draw_texture_part_generic(const vita2d_texture *texture, SceGxmPrimitiveType type, vita2d_texture_vertex *vertices, unsigned int num_vertices) -{ + vertices[1].x = w_half; + vertices[1].y = -h_half; + vertices[1].z = +0.5f; + vertices[1].u = u1; + vertices[1].v = v0; - uint16_t *indices = (uint16_t *)vita2d_pool_memalign( - num_vertices * sizeof(uint16_t), // 4 indices - sizeof(uint16_t)); + vertices[2].x = -w_half; + vertices[2].y = h_half; + vertices[2].z = +0.5f; + vertices[2].u = u0; + vertices[2].v = v1; - for(int n = 0; n < num_vertices; n++){ - indices[n] = n; + vertices[3].x = w_half; + vertices[3].y = h_half; + vertices[3].z = +0.5f; + vertices[3].u = u1; + vertices[3].v = v1; + + const float c = cosf(rad); + const float s = sinf(rad); + int i; + for (i = 0; i < 4; ++i) { // Rotate and translate + float _x = vertices[i].x; + float _y = vertices[i].y; + vertices[i].x = _x*c - _y*s + x; + vertices[i].y = _x*s + _y*c + y; } - - // Set the texture to the TEXUNIT0 sceGxmSetFragmentTexture(_vita2d_context, 0, &texture->gxm_tex); sceGxmSetVertexStream(_vita2d_context, 0, vertices); - sceGxmDraw(_vita2d_context, type, SCE_GXM_INDEX_FORMAT_U16, indices, 4); + sceGxmDraw(_vita2d_context, SCE_GXM_PRIMITIVE_TRIANGLE_STRIP, SCE_GXM_INDEX_FORMAT_U16, vita2d_get_linear_indices(), 4); } + +void vita2d_draw_texture_part_scale_rotate(const vita2d_texture *texture, float x, float y, + float tex_x, float tex_y, float tex_w, float tex_h, float x_scale, float y_scale, float rad) +{ + set_texture_program(); + set_texture_wvp_uniform(); + draw_texture_part_scale_rotate_generic(texture, x, y, + tex_x, tex_y, tex_w, tex_h, x_scale, y_scale, rad); +} + +void vita2d_draw_texture_part_tint_scale_rotate(const vita2d_texture *texture, float x, float y, + float tex_x, float tex_y, float tex_w, float tex_h, float x_scale, float y_scale, float rad, unsigned int color) +{ + set_texture_tint_program(); + set_texture_wvp_uniform(); + set_texture_tint_color_uniform(color); + draw_texture_part_scale_rotate_generic(texture, x, y, + tex_x, tex_y, tex_w, tex_h, x_scale, y_scale, rad); +} + +void vita2d_draw_array_textured(const vita2d_texture *texture, SceGxmPrimitiveType mode, const vita2d_texture_vertex *vertices, size_t count, unsigned int color) +{ + set_texture_tint_program(); + set_texture_wvp_uniform(); + set_texture_tint_color_uniform(color); + + sceGxmSetBackPolygonMode(_vita2d_context, SCE_GXM_POLYGON_MODE_TRIANGLE_FILL); + + // Set the texture to the TEXUNIT0 + sceGxmSetFragmentTexture(_vita2d_context, 0, &texture->gxm_tex); + + sceGxmSetVertexStream(_vita2d_context, 0, vertices); + sceGxmDraw(_vita2d_context, mode, SCE_GXM_INDEX_FORMAT_U16, vita2d_get_linear_indices(), count); +} \ No newline at end of file