Last active
October 23, 2025 08:20
-
-
Save ste2425/ed48f1c0bb07cb39762fdde4a84ce556 to your computer and use it in GitHub Desktop.
glib2d prx issue repro
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Define the exports for the prx | |
| PSP_BEGIN_EXPORTS | |
| # These four lines are mandatory (although you can add other functions like module_stop) | |
| # syslib is a psynonym for the single mandatory export. | |
| PSP_EXPORT_START(syslib, 0, 0x8000) | |
| PSP_EXPORT_FUNC(module_start) | |
| PSP_EXPORT_FUNC(module_stop) | |
| PSP_EXPORT_VAR(module_info) | |
| PSP_EXPORT_END | |
| PSP_END_EXPORTS |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * gLib2D - A simple, fast, light-weight 2D graphics library. | |
| * | |
| * Copyright 2012 Clément Guérin <[email protected]> | |
| * | |
| * This program is free software: you can redistribute it and/or modify | |
| * it under the terms of the GNU Lesser General Public License as published by | |
| * the Free Software Foundation, either version 3 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public License | |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| */ | |
| #include "glib2d.h" | |
| #include <pspdisplay.h> | |
| #include <pspkernel.h> | |
| #include <pspgu.h> | |
| #include <vram.h> | |
| #include <math.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| /* Defines */ | |
| #define DLIST_SIZE (524288) | |
| #define LINE_SIZE (512) | |
| #define PIXEL_SIZE (4) | |
| #define FRAMEBUFFER_SIZE (LINE_SIZE * G2D_SCR_H * PIXEL_SIZE) | |
| #define MALLOC_STEP (128) | |
| #define TSTACK_MAX (64) | |
| #define SLICE_WIDTH (64.f) | |
| #define M_180_PI (57.29578f) | |
| #define M_PI_180 (0.017453292f) | |
| #define DEFAULT_SIZE (10) | |
| #define DEFAULT_COORD_MODE (G2D_UP_LEFT) | |
| #define DEFAULT_X (0.f) | |
| #define DEFAULT_Y (0.f) | |
| #define DEFAULT_Z (0.f) | |
| #define DEFAULT_COLOR (WHITE) | |
| #define DEFAULT_ALPHA (0xFF) | |
| #define OBJ rctx.obj[rctx.n - 1] | |
| #define OBJ_I rctx.obj[i] | |
| #define TRANSFORM tstack[tstack_size - 1] | |
| /* Enumerations */ | |
| typedef enum { | |
| RECTS, LINES, QUADS, POINTS | |
| } Obj_Type; | |
| /* Structures */ | |
| typedef struct { | |
| float x, y, z; | |
| float rot, rot_sin, rot_cos; | |
| float scale_w, scale_h; | |
| } Transform; | |
| typedef struct { | |
| float x, y, z; | |
| float rot_x, rot_y; // Rotation center | |
| float rot, rot_sin, rot_cos; | |
| int crop_x, crop_y; | |
| int crop_w, crop_h; | |
| float scale_w, scale_h; | |
| g2dColor color; | |
| g2dAlpha alpha; | |
| } Object; | |
| typedef struct { | |
| Object *obj; | |
| Object cur_obj; | |
| unsigned int n; | |
| Obj_Type type; | |
| g2dTexture *tex; | |
| bool use_strip; | |
| bool use_z; | |
| bool use_vert_color; | |
| bool use_rot; | |
| bool use_tex_linear; | |
| bool use_tex_repeat; | |
| bool use_int; | |
| unsigned int color_count; | |
| g2dCoord_Mode coord_mode; | |
| } RenderContext; | |
| /* Local variables */ | |
| static int *dlist; | |
| static RenderContext rctx; | |
| static Transform tstack[TSTACK_MAX]; | |
| static unsigned int tstack_size; | |
| static bool init = false; | |
| static bool start = false; | |
| static bool begin = false; | |
| static bool zclear = true; | |
| static bool scissor = false; | |
| static float global_scale; | |
| /* Global variables */ | |
| g2dTexture g2d_draw_buffer = { | |
| 512, 512, | |
| G2D_SCR_W, G2D_SCR_H, | |
| (float)G2D_SCR_W/G2D_SCR_H, | |
| false, | |
| (g2dColor *)FRAMEBUFFER_SIZE | |
| }; | |
| g2dTexture g2d_disp_buffer = { | |
| 512, 512, | |
| G2D_SCR_W, G2D_SCR_H, | |
| (float)G2D_SCR_W/G2D_SCR_H, | |
| false, | |
| (g2dColor *)0 | |
| }; | |
| /* Internal functions */ | |
| static void _g2dStart(void) { | |
| if (!init) | |
| g2dInit(); | |
| sceKernelDcacheWritebackRange(dlist, DLIST_SIZE); | |
| sceGuStart(GU_DIRECT, dlist); | |
| start = true; | |
| } | |
| static void *_g2dSetVertex(void *vp, int i, float vx, float vy) { | |
| // Vertex order: [texture uv] [color] [coord] | |
| short *vp_short; | |
| g2dColor *vp_color; | |
| float *vp_float; | |
| // Texture coordinates | |
| vp_short = (short *)vp; | |
| if (rctx.tex != NULL) { | |
| *(vp_short++) = OBJ_I.crop_x + vx * OBJ_I.crop_w; | |
| *(vp_short++) = OBJ_I.crop_y + vy * OBJ_I.crop_h; | |
| } | |
| // Color | |
| vp_color = (g2dColor*)vp_short; | |
| if (rctx.use_vert_color) | |
| *(vp_color++) = OBJ_I.color; | |
| // Coordinates | |
| vp_float = (float *)vp_color; | |
| vp_float[0] = OBJ_I.x; | |
| vp_float[1] = OBJ_I.y; | |
| if (rctx.type == RECTS) { | |
| vp_float[0] += vx * OBJ_I.scale_w; | |
| vp_float[1] += vy * OBJ_I.scale_h; | |
| if (rctx.use_rot) {// Apply a rotation | |
| float tx = vp_float[0] - OBJ_I.rot_x; | |
| float ty = vp_float[1] - OBJ_I.rot_y; | |
| vp_float[0] = OBJ_I.rot_x - OBJ_I.rot_sin*ty + OBJ_I.rot_cos*tx, | |
| vp_float[1] = OBJ_I.rot_y + OBJ_I.rot_cos*ty + OBJ_I.rot_sin*tx; | |
| } | |
| } | |
| if (rctx.use_int) {// Pixel perfect | |
| vp_float[0] = floorf(vp_float[0]); | |
| vp_float[1] = floorf(vp_float[1]); | |
| } | |
| vp_float[2] = OBJ_I.z; | |
| return (void*)(vp_float + 3); | |
| } | |
| void vfpu_sincosf(float x, float *s, float *c) { | |
| __asm__ volatile ( | |
| "mtv %2, s000\n" // s000 = x | |
| "vcst.s s001, VFPU_2_PI\n" // s001 = 2/pi | |
| "vmul.s s000, s000, s001\n" // s000 = s000*s001 | |
| "vrot.p c010, s000, [s, c]\n" // s010 = sinf(s000), s011 = cosf(s000) | |
| "mfv %0, s010\n" // *s = s010 | |
| "mfv %1, S011\n" // *c = s011 | |
| : "=r"(*s), "=r"(*c) : "r"(x) | |
| ); | |
| } | |
| /* Main functions */ | |
| void g2dInit(void) { | |
| if (init) | |
| return; | |
| // Display list allocation | |
| dlist = malloc(DLIST_SIZE); | |
| // Setup GU | |
| sceGuInit(); | |
| sceGuStart(GU_DIRECT, dlist); | |
| sceGuDrawBuffer(GU_PSM_8888, g2d_draw_buffer.data, LINE_SIZE); | |
| sceGuDispBuffer(G2D_SCR_W, G2D_SCR_H, g2d_disp_buffer.data, LINE_SIZE); | |
| sceGuDepthBuffer((void *)(FRAMEBUFFER_SIZE * 2), LINE_SIZE); | |
| sceGuOffset(2048 - G2D_SCR_W / 2, 2048 - G2D_SCR_H / 2); | |
| sceGuViewport(2048, 2048, G2D_SCR_W, G2D_SCR_H); | |
| g2d_draw_buffer.data = vabsptr(g2d_draw_buffer.data); | |
| g2d_disp_buffer.data = vabsptr(g2d_disp_buffer.data); | |
| sceGuDepthRange(65535, 0); | |
| sceGuClearDepth(65535); | |
| sceGuAlphaFunc(GU_GREATER, 0, 255); | |
| sceGuDepthFunc(GU_LEQUAL); | |
| sceGuBlendFunc(GU_ADD, GU_SRC_ALPHA, GU_ONE_MINUS_SRC_ALPHA, 0, 0); | |
| sceGuTexFunc(GU_TFX_MODULATE, GU_TCC_RGBA); | |
| sceGuTexFilter(GU_LINEAR, GU_LINEAR); | |
| sceGuShadeModel(GU_SMOOTH); | |
| sceGuDisable(GU_CULL_FACE); | |
| sceGuDisable(GU_CLIP_PLANES); | |
| sceGuDisable(GU_DITHER); | |
| sceGuEnable(GU_ALPHA_TEST); | |
| sceGuEnable(GU_SCISSOR_TEST); | |
| sceGuEnable(GU_BLEND); | |
| g2dResetGlobalScale(); | |
| g2dResetScissor(); | |
| sceGuFinish(); | |
| sceGuSync(GU_SYNC_FINISH, GU_SYNC_WHAT_DONE); | |
| sceDisplayWaitVblankStart(); | |
| sceGuDisplay(GU_TRUE); | |
| init = true; | |
| } | |
| void g2dTerm(void) { | |
| if (!init) | |
| return; | |
| sceGuTerm(); | |
| free(dlist); | |
| init = false; | |
| } | |
| void g2dClear(g2dColor color) { | |
| if (!start) | |
| _g2dStart(); | |
| sceGuClearColor(color); | |
| sceGuClear(GU_COLOR_BUFFER_BIT | GU_FAST_CLEAR_BIT | (zclear ? GU_DEPTH_BUFFER_BIT : 0)); | |
| zclear = false; | |
| } | |
| void g2dClearZ(void) { | |
| if (!start) | |
| _g2dStart(); | |
| sceGuClear(GU_DEPTH_BUFFER_BIT | GU_FAST_CLEAR_BIT); | |
| zclear = true; | |
| } | |
| static void _g2dBeginCommon(Obj_Type type, g2dTexture *tex) { | |
| if (begin) | |
| return; | |
| if (!start) | |
| _g2dStart(); | |
| // Reset render context | |
| rctx.obj = realloc(rctx.obj, MALLOC_STEP * sizeof(Object)); | |
| rctx.n = 0; | |
| rctx.type = type; | |
| rctx.tex = tex; | |
| rctx.use_strip = false; | |
| rctx.use_z = false; | |
| rctx.use_vert_color = false; | |
| rctx.use_rot = false; | |
| rctx.use_tex_linear = true; | |
| rctx.use_tex_repeat = false; | |
| rctx.use_int = false; | |
| rctx.color_count = 0; | |
| rctx.coord_mode = DEFAULT_COORD_MODE; | |
| // Reset current object | |
| g2dReset(); | |
| begin = true; | |
| } | |
| void g2dBeginRects(g2dTexture *tex) { | |
| _g2dBeginCommon(RECTS, tex); | |
| } | |
| void g2dBeginLines(g2dLine_Mode mode) { | |
| _g2dBeginCommon(LINES, NULL); | |
| rctx.use_strip = (mode & G2D_STRIP); | |
| } | |
| void g2dBeginQuads(g2dTexture *tex) { | |
| _g2dBeginCommon(QUADS, tex); | |
| } | |
| void g2dBeginPoints(void) { | |
| _g2dBeginCommon(POINTS, NULL); | |
| } | |
| static void _g2dEndRects(void) { | |
| // Define vertices properties | |
| int v_prim = (rctx.use_rot ? GU_TRIANGLES : GU_SPRITES); | |
| int v_obj_nbr = (rctx.use_rot ? 6 : 2); | |
| int v_nbr; | |
| int v_coord_size = 3; | |
| int v_tex_size = (rctx.tex != NULL ? 2 : 0); | |
| int v_color_size = (rctx.use_vert_color ? 1 : 0); | |
| int v_size = v_tex_size * sizeof(short) + v_color_size * sizeof(g2dColor) + v_coord_size * sizeof(float); | |
| int v_type = GU_VERTEX_32BITF | GU_TRANSFORM_2D; | |
| int i; | |
| if (rctx.tex != NULL) | |
| v_type |= GU_TEXTURE_16BIT; | |
| if (rctx.use_vert_color) | |
| v_type |= GU_COLOR_8888; | |
| // Count how many vertices to allocate. | |
| if (rctx.tex == NULL || rctx.use_rot) // No slicing | |
| v_nbr = v_obj_nbr * rctx.n; | |
| else { // Can use texture slicing for tremendous performance :) | |
| v_nbr = 0; | |
| for (i = 0; i < rctx.n; i++) | |
| v_nbr += v_obj_nbr * ceilf(OBJ_I.crop_w/SLICE_WIDTH); | |
| } | |
| // Allocate vertex list memory | |
| void *v = sceGuGetMemory(v_nbr * v_size); | |
| void *vi = v; | |
| // Build the vertex list | |
| for (i = 0; i < rctx.n; i += 1) { | |
| if (rctx.use_rot) { // Two triangles per object | |
| vi = _g2dSetVertex(vi, i, 0.f, 0.f); | |
| vi = _g2dSetVertex(vi, i, 1.f, 0.f); | |
| vi = _g2dSetVertex(vi, i, 0.f, 1.f); | |
| vi = _g2dSetVertex(vi, i, 0.f, 1.f); | |
| vi = _g2dSetVertex(vi, i, 1.f, 0.f); | |
| vi = _g2dSetVertex(vi, i, 1.f, 1.f); | |
| } | |
| else if (rctx.tex == NULL) { // One sprite per object | |
| vi = _g2dSetVertex(vi, i, 0.f, 0.f); | |
| vi = _g2dSetVertex(vi, i, 1.f, 1.f); | |
| } | |
| else { // Several sprites per object for a better texture cache use | |
| float step = SLICE_WIDTH/OBJ_I.crop_w; | |
| float u; | |
| for (u = 0.f; u < 1.f; u += step) { | |
| vi = _g2dSetVertex(vi, i, u, 0.f); | |
| vi = _g2dSetVertex(vi, i, (u + step > 1.f ? 1.f : u+step), 1.f); | |
| } | |
| } | |
| } | |
| // Then put it in the display list. | |
| sceGuDrawArray(v_prim, v_type, v_nbr, NULL, v); | |
| } | |
| static void _g2dEndLines(void) { | |
| // Define vertices properties | |
| int v_prim = (rctx.use_strip ? GU_LINE_STRIP : GU_LINES); | |
| int v_obj_nbr = (rctx.use_strip ? 1 : 2); | |
| int v_nbr = v_obj_nbr * (rctx.use_strip ? rctx.n : rctx.n/2); | |
| int v_coord_size = 3; | |
| int v_color_size = (rctx.use_vert_color ? 1 : 0); | |
| int v_size = v_color_size * sizeof(g2dColor) + v_coord_size * sizeof(float); | |
| int v_type = GU_VERTEX_32BITF | GU_TRANSFORM_2D; | |
| int i; | |
| if (rctx.use_vert_color) | |
| v_type |= GU_COLOR_8888; | |
| // Allocate vertex list memory | |
| void *v = sceGuGetMemory(v_nbr * v_size); | |
| void *vi = v; | |
| // Build the vertex list | |
| if (rctx.use_strip) { | |
| vi = _g2dSetVertex(vi, 0, 0.f, 0.f); | |
| for (i = 1; i < rctx.n; i += 1) | |
| vi = _g2dSetVertex(vi, i, 0.f, 0.f); | |
| } | |
| else | |
| { | |
| for (i = 0; i + 1 < rctx.n; i += 2) { | |
| vi = _g2dSetVertex(vi, i , 0.f, 0.f); | |
| vi = _g2dSetVertex(vi, i + 1, 0.f, 0.f); | |
| } | |
| } | |
| // Then put it in the display list. | |
| sceGuDrawArray(v_prim, v_type, v_nbr, NULL, v); | |
| } | |
| static void _g2dEndQuads(void) { | |
| // Define vertices properties | |
| int v_prim = GU_TRIANGLES; | |
| int v_obj_nbr = 6; | |
| int v_nbr = v_obj_nbr * (rctx.n / 4); | |
| int v_coord_size = 3; | |
| int v_tex_size = (rctx.tex != NULL ? 2 : 0); | |
| int v_color_size = (rctx.use_vert_color ? 1 : 0); | |
| int v_size = v_tex_size * sizeof(short) + v_color_size * sizeof(g2dColor) + v_coord_size * sizeof(float); | |
| int v_type = GU_VERTEX_32BITF | GU_TRANSFORM_2D; | |
| int i; | |
| if (rctx.tex != NULL) | |
| v_type |= GU_TEXTURE_16BIT; | |
| if (rctx.use_vert_color) | |
| v_type |= GU_COLOR_8888; | |
| // Allocate vertex list memory | |
| void *v = sceGuGetMemory(v_nbr * v_size); | |
| void *vi = v; | |
| // Build the vertex list | |
| for (i = 0; i + 3 < rctx.n; i += 4) { | |
| vi = _g2dSetVertex(vi, i, 0.f, 0.f); | |
| vi = _g2dSetVertex(vi, i + 1, 1.f, 0.f); | |
| vi = _g2dSetVertex(vi, i + 3, 0.f, 1.f); | |
| vi = _g2dSetVertex(vi, i + 3, 0.f, 1.f); | |
| vi = _g2dSetVertex(vi, i + 1, 1.f, 0.f); | |
| vi = _g2dSetVertex(vi, i + 2, 1.f, 1.f); | |
| } | |
| // Then put it in the display list. | |
| sceGuDrawArray(v_prim, v_type, v_nbr, NULL, v); | |
| } | |
| static void _g2dEndPoints(void) { | |
| // Define vertices properties | |
| int v_prim = GU_POINTS; | |
| int v_obj_nbr = 1; | |
| int v_nbr = v_obj_nbr * rctx.n; | |
| int v_coord_size = 3; | |
| int v_color_size = (rctx.use_vert_color ? 1 : 0); | |
| int v_size = v_color_size * sizeof(g2dColor) + v_coord_size * sizeof(float); | |
| int v_type = GU_VERTEX_32BITF | GU_TRANSFORM_2D; | |
| int i; | |
| if (rctx.use_vert_color) | |
| v_type |= GU_COLOR_8888; | |
| // Allocate vertex list memory | |
| void *v = sceGuGetMemory(v_nbr * v_size); | |
| void *vi = v; | |
| // Build the vertex list | |
| for (i = 0; i < rctx.n; i += 1) | |
| vi = _g2dSetVertex(vi, i, 0.f, 0.f); | |
| // Then put it in the display list. | |
| sceGuDrawArray(v_prim, v_type, v_nbr, NULL, v); | |
| } | |
| void g2dEnd(void) { | |
| if (!begin || rctx.n == 0) { | |
| begin = false; | |
| return; | |
| } | |
| // Manage pspgu extensions | |
| if (rctx.use_z) | |
| sceGuEnable(GU_DEPTH_TEST); | |
| else | |
| sceGuDisable(GU_DEPTH_TEST); | |
| if (rctx.use_vert_color) | |
| sceGuColor(WHITE); | |
| else | |
| sceGuColor(rctx.cur_obj.color); | |
| if (rctx.tex == NULL) | |
| sceGuDisable(GU_TEXTURE_2D); | |
| else { | |
| sceGuEnable(GU_TEXTURE_2D); | |
| if (rctx.use_tex_linear) | |
| sceGuTexFilter(GU_LINEAR, GU_LINEAR); | |
| else | |
| sceGuTexFilter(GU_NEAREST, GU_NEAREST); | |
| if (rctx.use_tex_repeat) | |
| sceGuTexWrap(GU_REPEAT, GU_REPEAT); | |
| else | |
| sceGuTexWrap(GU_CLAMP, GU_CLAMP); | |
| // Load texture | |
| sceGuTexMode(GU_PSM_8888, 0, 0, rctx.tex->swizzled); | |
| sceGuTexImage(0, rctx.tex->tw, rctx.tex->th, rctx.tex->tw, rctx.tex->data); | |
| } | |
| switch (rctx.type) { | |
| case RECTS: | |
| _g2dEndRects(); | |
| break; | |
| case LINES: | |
| _g2dEndLines(); | |
| break; | |
| case QUADS: | |
| _g2dEndQuads(); | |
| break; | |
| case POINTS: | |
| _g2dEndPoints(); | |
| break; | |
| } | |
| sceGuColor(WHITE); | |
| if (rctx.use_z) | |
| zclear = true; | |
| begin = false; | |
| } | |
| void g2dReset(void) { | |
| g2dResetCoord(); | |
| g2dResetScale(); | |
| g2dResetColor(); | |
| g2dResetAlpha(); | |
| g2dResetRotation(); | |
| g2dResetCrop(); | |
| g2dResetTex(); | |
| } | |
| void g2dFlip(g2dFlip_Mode mode) { | |
| if (scissor) | |
| g2dResetScissor(); | |
| sceGuFinish(); | |
| sceGuSync(GU_SYNC_FINISH, GU_SYNC_WHAT_DONE); | |
| if (mode & G2D_VSYNC) | |
| sceDisplayWaitVblankStart(); | |
| g2d_disp_buffer.data = g2d_draw_buffer.data; | |
| g2d_draw_buffer.data = vabsptr(sceGuSwapBuffers()); | |
| start = false; | |
| } | |
| void g2dAdd(void) { | |
| if (!begin || rctx.cur_obj.scale_w == 0.f || rctx.cur_obj.scale_h == 0.f) | |
| return; | |
| if (rctx.n % MALLOC_STEP == 0) | |
| rctx.obj = realloc(rctx.obj, (rctx.n+MALLOC_STEP) * sizeof(Object)); | |
| rctx.n++; | |
| OBJ = rctx.cur_obj; | |
| // Coordinate mode stuff | |
| OBJ.rot_x = OBJ.x; | |
| OBJ.rot_y = OBJ.y; | |
| switch (rctx.coord_mode) { | |
| case G2D_UP_RIGHT: | |
| OBJ.x -= OBJ.scale_w; | |
| break; | |
| case G2D_DOWN_RIGHT: | |
| OBJ.x -= OBJ.scale_w; | |
| OBJ.y -= OBJ.scale_h; | |
| break; | |
| case G2D_DOWN_LEFT: | |
| OBJ.y -= OBJ.scale_h; | |
| break; | |
| case G2D_CENTER: | |
| OBJ.x -= OBJ.scale_w / 2.f; | |
| OBJ.y -= OBJ.scale_h / 2.f; | |
| break; | |
| case G2D_UP_LEFT: | |
| default: | |
| break; | |
| }; | |
| // Alpha stuff | |
| OBJ.color = G2D_MODULATE(OBJ.color, 255, rctx.cur_obj.alpha); | |
| } | |
| void g2dPush(void) { | |
| if (tstack_size >= TSTACK_MAX) | |
| return; | |
| tstack_size++; | |
| TRANSFORM.x = rctx.cur_obj.x; | |
| TRANSFORM.y = rctx.cur_obj.y; | |
| TRANSFORM.z = rctx.cur_obj.z; | |
| TRANSFORM.rot = rctx.cur_obj.rot; | |
| TRANSFORM.rot_sin = rctx.cur_obj.rot_sin; | |
| TRANSFORM.rot_cos = rctx.cur_obj.rot_cos; | |
| TRANSFORM.scale_w = rctx.cur_obj.scale_w; | |
| TRANSFORM.scale_h = rctx.cur_obj.scale_h; | |
| } | |
| void g2dPop(void) { | |
| if (tstack_size <= 0) | |
| return; | |
| rctx.cur_obj.x = TRANSFORM.x; | |
| rctx.cur_obj.y = TRANSFORM.y; | |
| rctx.cur_obj.z = TRANSFORM.z; | |
| rctx.cur_obj.rot = TRANSFORM.rot; | |
| rctx.cur_obj.rot_sin = TRANSFORM.rot_sin; | |
| rctx.cur_obj.rot_cos = TRANSFORM.rot_cos; | |
| rctx.cur_obj.scale_w = TRANSFORM.scale_w; | |
| rctx.cur_obj.scale_h = TRANSFORM.scale_h; | |
| tstack_size--; | |
| if (rctx.cur_obj.rot != 0.f) | |
| rctx.use_rot = true; | |
| if (rctx.cur_obj.z != 0.f) | |
| rctx.use_z = true; | |
| } | |
| /* Coord functions */ | |
| void g2dResetCoord(void) { | |
| rctx.cur_obj.x = DEFAULT_X; | |
| rctx.cur_obj.y = DEFAULT_Y; | |
| rctx.cur_obj.z = DEFAULT_Z; | |
| } | |
| void g2dSetCoordMode(g2dCoord_Mode mode) { | |
| if (mode > G2D_CENTER) | |
| return; | |
| rctx.coord_mode = mode; | |
| } | |
| void g2dGetCoordXYZ(float *x, float *y, float *z) { | |
| if (x != NULL) *x = rctx.cur_obj.x; | |
| if (y != NULL) *y = rctx.cur_obj.y; | |
| if (z != NULL) *z = rctx.cur_obj.z; | |
| } | |
| void g2dSetCoordXY(float x, float y) { | |
| rctx.cur_obj.x = x * global_scale; | |
| rctx.cur_obj.y = y * global_scale; | |
| rctx.cur_obj.z = 0.f; | |
| } | |
| void g2dSetCoordXYZ(float x, float y, float z) { | |
| rctx.cur_obj.x = x * global_scale; | |
| rctx.cur_obj.y = y * global_scale; | |
| rctx.cur_obj.z = z * global_scale; | |
| if (z != 0.f) | |
| rctx.use_z = true; | |
| } | |
| void g2dSetCoordXYRelative(float x, float y) { | |
| float inc_x = x; | |
| float inc_y = y; | |
| if (rctx.cur_obj.rot_cos != 1.f) { | |
| inc_x = -rctx.cur_obj.rot_sin*y + rctx.cur_obj.rot_cos*x; | |
| inc_y = rctx.cur_obj.rot_cos*y + rctx.cur_obj.rot_sin*x; | |
| } | |
| rctx.cur_obj.x += inc_x * global_scale; | |
| rctx.cur_obj.y += inc_y * global_scale; | |
| } | |
| void g2dSetCoordXYZRelative(float x, float y, float z) { | |
| g2dSetCoordXYRelative(x, y); | |
| rctx.cur_obj.z += z * global_scale; | |
| if (z != 0.f) | |
| rctx.use_z = true; | |
| } | |
| void g2dSetCoordInteger(bool use) { | |
| rctx.use_int = use; | |
| } | |
| /* Scale functions */ | |
| void g2dResetGlobalScale(void) { | |
| global_scale = 1.f; | |
| } | |
| void g2dResetScale(void) { | |
| if (rctx.tex == NULL) { | |
| rctx.cur_obj.scale_w = DEFAULT_SIZE; | |
| rctx.cur_obj.scale_h = DEFAULT_SIZE; | |
| } | |
| else { | |
| rctx.cur_obj.scale_w = rctx.tex->w; | |
| rctx.cur_obj.scale_h = rctx.tex->h; | |
| } | |
| rctx.cur_obj.scale_w *= global_scale; | |
| rctx.cur_obj.scale_h *= global_scale; | |
| } | |
| void g2dGetGlobalScale(float *scale) { | |
| if (scale != NULL) | |
| *scale = global_scale; | |
| } | |
| void g2dGetScaleWH(float *w, float *h) { | |
| if (w != NULL) | |
| *w = rctx.cur_obj.scale_w; | |
| if (h != NULL) | |
| *h = rctx.cur_obj.scale_h; | |
| } | |
| void g2dSetGlobalScale(float scale) { | |
| global_scale = scale; | |
| } | |
| void g2dSetScale(float w, float h) { | |
| g2dResetScale(); | |
| g2dSetScaleRelative(w, h); | |
| } | |
| void g2dSetScaleWH(float w, float h) { | |
| rctx.cur_obj.scale_w = w * global_scale; | |
| rctx.cur_obj.scale_h = h * global_scale; | |
| // A trick to prevent an unexpected behavior when mirroring with GU_SPRITES. | |
| if (rctx.cur_obj.scale_w < 0 || rctx.cur_obj.scale_h < 0) | |
| rctx.use_rot = true; | |
| } | |
| void g2dSetScaleRelative(float w, float h) { | |
| rctx.cur_obj.scale_w *= w; | |
| rctx.cur_obj.scale_h *= h; | |
| if (rctx.cur_obj.scale_w < 0 || rctx.cur_obj.scale_h < 0) | |
| rctx.use_rot = true; | |
| } | |
| void g2dSetScaleWHRelative(float w, float h) { | |
| rctx.cur_obj.scale_w += w * global_scale; | |
| rctx.cur_obj.scale_h += h * global_scale; | |
| if (rctx.cur_obj.scale_w < 0 || rctx.cur_obj.scale_h < 0) | |
| rctx.use_rot = true; | |
| } | |
| /* Color functions */ | |
| void g2dResetColor(void) { | |
| rctx.cur_obj.color = DEFAULT_COLOR; | |
| } | |
| void g2dResetAlpha(void) { | |
| rctx.cur_obj.alpha = DEFAULT_ALPHA; | |
| } | |
| void g2dGetAlpha(g2dAlpha *alpha) { | |
| if (alpha != NULL) | |
| *alpha = rctx.cur_obj.alpha; | |
| } | |
| void g2dSetColor(g2dColor color) { | |
| rctx.cur_obj.color = color; | |
| if (++rctx.color_count > 1) | |
| rctx.use_vert_color = true; | |
| } | |
| void g2dSetAlpha(g2dAlpha alpha) { | |
| if (alpha < 0) | |
| alpha = 0; | |
| if (alpha > 255) | |
| alpha = 255; | |
| rctx.cur_obj.alpha = alpha; | |
| if (++rctx.color_count > 1) | |
| rctx.use_vert_color = true; | |
| } | |
| void g2dSetAlphaRelative(int alpha) { | |
| g2dSetAlpha(rctx.cur_obj.alpha + alpha); | |
| } | |
| /* Rotation functions */ | |
| void g2dResetRotation(void) { | |
| rctx.cur_obj.rot = 0.f; | |
| rctx.cur_obj.rot_sin = 0.f; | |
| rctx.cur_obj.rot_cos = 1.f; | |
| } | |
| void g2dGetRotationRad(float *radians) { | |
| if (radians != NULL) | |
| *radians = rctx.cur_obj.rot; | |
| } | |
| void g2dGetRotation(float *degrees) { | |
| if (degrees != NULL) | |
| *degrees = rctx.cur_obj.rot * M_180_PI; | |
| } | |
| void g2dSetRotationRad(float radians) { | |
| if (radians == rctx.cur_obj.rot) | |
| return; | |
| rctx.cur_obj.rot = radians; | |
| vfpu_sincosf(radians, &rctx.cur_obj.rot_sin, &rctx.cur_obj.rot_cos); | |
| if (radians != 0.f) | |
| rctx.use_rot = true; | |
| } | |
| void g2dSetRotation(float degrees) { | |
| g2dSetRotationRad(degrees * M_PI_180); | |
| } | |
| void g2dSetRotationRadRelative(float radians) { | |
| g2dSetRotationRad(rctx.cur_obj.rot + radians); | |
| } | |
| void g2dSetRotationRelative(float degrees) { | |
| g2dSetRotationRadRelative(degrees * M_PI_180); | |
| } | |
| /* Crop functions */ | |
| void g2dResetCrop(void) { | |
| if (rctx.tex == NULL) | |
| return; | |
| rctx.cur_obj.crop_x = 0; | |
| rctx.cur_obj.crop_y = 0; | |
| rctx.cur_obj.crop_w = rctx.tex->w; | |
| rctx.cur_obj.crop_h = rctx.tex->h; | |
| } | |
| void g2dGetCropXY(int *x, int *y) { | |
| if (rctx.tex == NULL) | |
| return; | |
| if (x != NULL) | |
| *x = rctx.cur_obj.crop_x; | |
| if (y != NULL) | |
| *y = rctx.cur_obj.crop_y; | |
| } | |
| void g2dGetCropWH(int *w, int *h) { | |
| if (rctx.tex == NULL) | |
| return; | |
| if (w != NULL) | |
| *w = rctx.cur_obj.crop_w; | |
| if (h != NULL) | |
| *h = rctx.cur_obj.crop_h; | |
| } | |
| void g2dSetCropXY(int x, int y) { | |
| if (rctx.tex == NULL) | |
| return; | |
| rctx.cur_obj.crop_x = x; | |
| rctx.cur_obj.crop_y = y; | |
| } | |
| void g2dSetCropWH(int w, int h) { | |
| if (rctx.tex == NULL) | |
| return; | |
| rctx.cur_obj.crop_w = w; | |
| rctx.cur_obj.crop_h = h; | |
| } | |
| void g2dSetCropXYRelative(int x, int y) { | |
| if (rctx.tex == NULL) | |
| return; | |
| g2dSetCropXY(rctx.cur_obj.crop_x + x, rctx.cur_obj.crop_y + y); | |
| } | |
| void g2dSetCropWHRelative(int w, int h) { | |
| if (rctx.tex == NULL) | |
| return; | |
| g2dSetCropWH(rctx.cur_obj.crop_w + w, rctx.cur_obj.crop_h + h); | |
| } | |
| /* Texture functions */ | |
| void g2dResetTex(void) { | |
| if (rctx.tex == NULL) | |
| return; | |
| rctx.use_tex_repeat = false; | |
| rctx.use_tex_linear = true; | |
| } | |
| void g2dSetTexRepeat(bool use) { | |
| if (rctx.tex == NULL) | |
| return; | |
| rctx.use_tex_repeat = use; | |
| } | |
| void g2dSetTexLinear(bool use) { | |
| if (rctx.tex == NULL) | |
| return; | |
| rctx.use_tex_linear = use; | |
| } | |
| /* Texture management */ | |
| static unsigned int _getNextPower2(unsigned int n) { | |
| n--; | |
| n |= n >> 1; | |
| n |= n >> 2; | |
| n |= n >> 4; | |
| n |= n >> 8; | |
| n |= n >> 16; | |
| return n + 1; | |
| } | |
| static void _swizzle(unsigned char *dest, unsigned char *source, int width, int height) { | |
| int i, j; | |
| int rowblocks = (width / 16); | |
| int rowblocks_add = (rowblocks-1) * 128; | |
| unsigned int block_address = 0; | |
| unsigned int *img = (unsigned int*)source; | |
| for (j = 0; j < height; j++) { | |
| unsigned int *block = (unsigned int *)(dest + block_address); | |
| for (i = 0; i < rowblocks; i++) { | |
| *block++ = *img++; | |
| *block++ = *img++; | |
| *block++ = *img++; | |
| *block++ = *img++; | |
| block += 28; | |
| } | |
| if ((j & 0x7) == 0x7) | |
| block_address += rowblocks_add; | |
| block_address += 16; | |
| } | |
| } | |
| g2dTexture *g2dTexCreate(int w, int h) { | |
| g2dTexture *tex = malloc(sizeof(g2dTexture)); | |
| if (!tex) | |
| return NULL; | |
| tex->tw = _getNextPower2(w); | |
| tex->th = _getNextPower2(h); | |
| tex->w = w; | |
| tex->h = h; | |
| tex->ratio = (float)w / h; | |
| tex->swizzled = false; | |
| tex->data = malloc(tex->tw * tex->th * sizeof(g2dColor)); | |
| if (!tex->data) { | |
| free(tex); | |
| return NULL; | |
| } | |
| return tex; | |
| } | |
| void g2dTexFree(g2dTexture **tex) { | |
| if (tex == NULL) | |
| return; | |
| if (*tex == NULL) | |
| return; | |
| free((*tex)->data); | |
| free((*tex)); | |
| *tex = NULL; | |
| } | |
| static g2dTexture *_g2dTexLoadData(void *data, int width, int height) { | |
| g2dTexture *tex = g2dTexCreate(width, height); | |
| if (!tex) | |
| return NULL; | |
| g2dColor *src = data; | |
| for (u32 y = 0; y < tex->h; ++y) { | |
| for (u32 x = 0; x < tex->w; ++x) { | |
| tex->data[y * tex->tw + x] = src[y * tex->w + x]; | |
| } | |
| } | |
| return tex; | |
| } | |
| g2dTexture *g2dTexLoad(void *data, int width, int height, g2dTex_Mode mode) { | |
| if (!data) | |
| return NULL; | |
| g2dTexture *tex = _g2dTexLoadData(data, width, height); | |
| if (!tex) | |
| return NULL; | |
| if (tex->w > 512 || tex->h > 512) | |
| goto error; | |
| u32 tex_size = tex->tw * tex->th * PIXEL_SIZE; | |
| if ((mode & G2D_SWIZZLE) && (tex->w >= 16 || tex->h >= 16)) { | |
| u8 *tmp = malloc(tex_size); | |
| if (!tmp) | |
| goto error; | |
| _swizzle(tmp, (u8*)tex->data, tex->tw * PIXEL_SIZE, tex->th); | |
| free(tex->data); | |
| tex->data = (g2dColor*)tmp; | |
| tex->swizzled = true; | |
| } | |
| sceKernelDcacheWritebackRange(tex->data, tex_size); | |
| return tex; | |
| error: | |
| g2dTexFree(&tex); | |
| return NULL; | |
| } | |
| /* Scissor functions */ | |
| void g2dResetScissor(void) { | |
| g2dSetScissor(0, 0, G2D_SCR_W, G2D_SCR_H); | |
| scissor = false; | |
| } | |
| void g2dSetScissor(int x, int y, int w, int h) { | |
| sceGuScissor(x, y, x+w, y+h); | |
| scissor = true; | |
| } | |
| // EOF |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** \mainpage gLib2D Documentation | |
| * | |
| * \section intro Introduction | |
| * | |
| * gLib2D by Geecko - A simple, fast, light-weight 2D graphics library. \n\n | |
| * This library has been designed to replace the old graphics.c library | |
| * and to simplify the use of pspgu.\n | |
| * The goals : keep it simple, keep it small, keep it fast. | |
| * | |
| * \section limits Known limitations | |
| * | |
| * - Draw & display buffers can't actually be used as real textures. Just a way | |
| * to get the vram pointer. | |
| * - No support for multiples contexts (e.g. sharing coordinates beetween | |
| * textures using some gBegin calls at a time). | |
| * - Manipulating textures (clear, get pixel info...) is not possible. | |
| * - When some 512*512 rotated, colorized and scaled textures are rendered | |
| * at a time, the framerate *could* go under 60 fps. | |
| * | |
| * \section install Installation | |
| * | |
| * - Simply put glib2d.c and glib2d.h in your source directory. \n | |
| * - Then add glib2d.o and link "-lpng -ljpeg -lz -lpspgu -lm -lpspvram" | |
| * in your Makefile. | |
| * - You're done ! | |
| * | |
| * \section copyright License | |
| * | |
| * This work is licensed under the LGPLv3 License. \n | |
| * See the LICENSE file for more details. \n | |
| * You can support the library by marking your homebrew with | |
| * "Using gLib2D by Geecko". | |
| * | |
| * \section contact Contact | |
| * | |
| * Please report bugs or submit ideas at : \n [email protected] \n\n | |
| * Get the full documentation on : \n http://geecko.dev.free.fr \n\n | |
| * Also stay tuned on... \n | |
| * https://github.com/GeeckoDev (contributors would be a plus!) \n | |
| * http://twitter.com/GeeckoDev | |
| */ | |
| /** | |
| * \file glib2d.h | |
| * \brief gLib2D Header | |
| * \version Beta 5 | |
| */ | |
| #ifndef GLIB2D_H | |
| #define GLIB2D_H | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| #include <stdbool.h> | |
| /** | |
| * \def G2D_SCR_W | |
| * \brief Screen width constant, in pixels. | |
| */ | |
| /** | |
| * \def G2D_SCR_H | |
| * \brief Screen height constant, in pixels. | |
| */ | |
| #define G2D_SCR_W (480) | |
| #define G2D_SCR_H (272) | |
| /** | |
| * \def G2D_RGBA(r,g,b,a) | |
| * \brief Create a g2dColor. | |
| * | |
| * This macro creates a g2dColor from 4 values, red, green, blue and alpha. | |
| * Input range is from 0 to 255. | |
| */ | |
| #define G2D_RGBA(r, g, b, a) ((r)|((g)<<8)|((b)<<16)|((a)<<24)) | |
| /** | |
| * \def G2D_GET_R(color) | |
| * \brief Get red channel value from a g2dColor. | |
| */ | |
| /** | |
| * \def G2D_GET_G(color) | |
| * \brief Get green channel value from a g2dColor. | |
| */ | |
| /** | |
| * \def G2D_GET_B(color) | |
| * \brief Get blue channel value from a g2dColor. | |
| */ | |
| /** | |
| * \def G2D_GET_A(color) | |
| * \brief Get alpha channel value from a g2dColor. | |
| */ | |
| #define G2D_GET_R(color) (((color) ) & 0xFF) | |
| #define G2D_GET_G(color) (((color) >> 8) & 0xFF) | |
| #define G2D_GET_B(color) (((color) >> 16) & 0xFF) | |
| #define G2D_GET_A(color) (((color) >> 24) & 0xFF) | |
| /** | |
| * \def G2D_MODULATE(color,luminance,alpha) | |
| * \brief g2dColor modulation. | |
| * | |
| * This macro modulates the luminance & alpha of a g2dColor. | |
| * Input range is from 0 to 255. | |
| */ | |
| #define G2D_MODULATE(color,luminance,alpha) \ | |
| G2D_RGBA((int)(luminance) * G2D_GET_R(color) / 255, \ | |
| (int)(luminance) * G2D_GET_G(color) / 255, \ | |
| (int)(luminance) * G2D_GET_B(color) / 255, \ | |
| (int)(alpha ) * G2D_GET_A(color) / 255) | |
| /** | |
| * \enum g2dColors | |
| * \brief Colors enumeration. | |
| * | |
| * Primary, secondary, tertiary and grayscale colors are defined. | |
| */ | |
| enum g2dColors { | |
| // Primary colors | |
| RED = 0xFF0000FF, | |
| GREEN = 0xFF00FF00, | |
| BLUE = 0xFFFF0000, | |
| // Secondary colors | |
| CYAN = 0xFFFFFF00, | |
| MAGENTA = 0xFFFF00FF, | |
| YELLOW = 0xFF00FFFF, | |
| // Tertiary colors | |
| AZURE = 0xFFFF7F00, | |
| VIOLET = 0xFFFF007F, | |
| ROSE = 0xFF7F00FF, | |
| ORANGE = 0xFF007FFF, | |
| CHARTREUSE = 0xFF00FF7F, | |
| SPRING_GREEN = 0xFF7FFF00, | |
| // Grayscale | |
| WHITE = 0xFFFFFFFF, | |
| LITEGRAY = 0xFFBFBFBF, | |
| GRAY = 0xFF7F7F7F, | |
| DARKGRAY = 0xFF3F3F3F, | |
| BLACK = 0xFF000000 | |
| }; | |
| /** | |
| * \enum g2dCoord_Mode | |
| * \brief Coordinates modes enumeration. | |
| * | |
| * Choose where the coordinates correspond in the object. | |
| * Can only be used with g2dSetCoordMode. | |
| */ | |
| /** | |
| * \enum g2dLine_Mode | |
| * \brief Line modes enumeration. | |
| * | |
| * Change line draw properties. | |
| * Can only be used with g2dBeginLines. | |
| */ | |
| /** | |
| * \enum g2dFlip_Mode | |
| * \brief Flip modes enumeration. | |
| * | |
| * Change flip properties. | |
| * Can only be used with g2dFlip. | |
| */ | |
| /** | |
| * \enum g2dTex_Mode | |
| * \brief Texture modes enumeration. | |
| * | |
| * Change texture properties. | |
| * Can only be used with g2dTexLoad. | |
| */ | |
| typedef enum { | |
| G2D_UP_LEFT, | |
| G2D_UP_RIGHT, | |
| G2D_DOWN_RIGHT, | |
| G2D_DOWN_LEFT, | |
| G2D_CENTER | |
| } g2dCoord_Mode; | |
| typedef enum { | |
| G2D_STRIP = 1 /**< Make a line strip. */ | |
| } g2dLine_Mode; | |
| typedef enum { | |
| G2D_VSYNC = 1 /**< Limit the FPS to 60 (synchronized with the screen). | |
| Better quality and less power consumption. */ | |
| } g2dFlip_Mode; | |
| typedef enum { | |
| G2D_SWIZZLE = 1 /**< Recommended. Use it to speedup rendering. */ | |
| } g2dTex_Mode; | |
| /** | |
| * \var g2dAlpha | |
| * \brief Alpha type. | |
| */ | |
| /** | |
| * \var g2dColor | |
| * \brief Color type. | |
| */ | |
| typedef int g2dAlpha; | |
| typedef unsigned int g2dColor; | |
| /** | |
| * \struct g2dTexture | |
| * \brief Texture structure. | |
| */ | |
| typedef struct { | |
| int tw; /**< Real texture width. A power of two. */ | |
| int th; /**< Real texture height. A power of two. */ | |
| int w; /**< Texture width, as seen when drawing. */ | |
| int h; /**< Texture height, as seen when drawing. */ | |
| float ratio; /**< Width/height ratio. */ | |
| bool swizzled; /**< Is the texture swizzled ? */ | |
| g2dColor *data; /**< Pointer to raw data. */ | |
| } g2dTexture; | |
| /** | |
| * \var g2d_draw_buffer | |
| * \brief The current draw buffer as a texture. | |
| */ | |
| /** | |
| * \var g2d_disp_buffer | |
| * \brief The current display buffer as a texture. | |
| */ | |
| extern g2dTexture g2d_draw_buffer; | |
| extern g2dTexture g2d_disp_buffer; | |
| /** | |
| * \brief Initializes the library. | |
| * | |
| * This function will create a GU context and setup the display buffers. | |
| * Automatically called by the other functions. | |
| */ | |
| void g2dInit(void); | |
| /** | |
| * \brief Shutdowns the library. | |
| * | |
| * This function will destroy the GU context. | |
| */ | |
| void g2dTerm(void); | |
| /** | |
| * \brief Clears screen & depth buffer. | |
| * @param color Screen clear color | |
| * | |
| * This function clears the screen, and clears the zbuffer if depth coordinate | |
| * is used in the loop. Will automatically init the GU if needed. | |
| */ | |
| void g2dClear(g2dColor color); | |
| /** | |
| * \brief Clears depth buffer. | |
| * | |
| * This function clears the zbuffer to zero (z range 0-65535). | |
| * Will automatically init the GU if needed. | |
| */ | |
| void g2dClearZ(void); | |
| /** | |
| * \brief Begins rectangles rendering. | |
| * @param tex Pointer to a texture, pass NULL to get a colored rectangle. | |
| * | |
| * This function begins object rendering. Resets all properties. | |
| * One g2dAdd() call per object. | |
| * Only one texture can be used, but multiple objects can be rendered at a time. | |
| * g2dBegin*() / g2dEnd() couple can be called multiple times in the loop, | |
| * to render multiple textures. | |
| */ | |
| void g2dBeginRects(g2dTexture *tex); | |
| /** | |
| * \brief Begins lines rendering. | |
| * @param line_mode A g2dLine_Mode constant. | |
| * | |
| * This function begins object rendering. Calls g2dReset(). | |
| * Two g2dAdd() calls per object. | |
| * Pass G2D_LINE_STRIP to make a line strip (two calls, then one per object). | |
| */ | |
| void g2dBeginLines(g2dLine_Mode mode); | |
| /** | |
| * \brief Begins quads rendering. | |
| * @param tex Pointer to a texture, pass NULL to get a colored quad. | |
| * | |
| * This function begins object rendering. Resets all properties. | |
| * Four g2dAdd() calls per object, first for the up left corner, then clockwise. | |
| * Only one texture can be used, but multiple objects can be rendered at a time. | |
| * g2dBegin*() / g2dEnd() couple can be called multiple times in the loop, | |
| * to render multiple textures. | |
| */ | |
| void g2dBeginQuads(g2dTexture *tex); | |
| /** | |
| * \brief Begins points rendering. | |
| * | |
| * This function begins object rendering. Resets all properties. | |
| * One g2dAdd() call per object. | |
| */ | |
| void g2dBeginPoints(void); | |
| /** | |
| * \brief Ends object rendering. | |
| * | |
| * This function ends object rendering. Must be called after g2dBegin*() to add | |
| * objects to the display list. Automatically adapts pspgu functionnalities | |
| * to get the best performance possible. | |
| */ | |
| void g2dEnd(void); | |
| /** | |
| * \brief Resets current transformation and attribution. | |
| * | |
| * This function must be called during object rendering. | |
| * Calls g2dResetCoord(), g2dResetRotation(), g2dResetScale(), | |
| * g2dResetColor(), g2dResetAlpha(), g2dResetCrop() and g2dResetTex(). | |
| */ | |
| void g2dReset(void); | |
| /** | |
| * \brief Flips the screen. | |
| * @param flip_mode A g2dFlip_Mode constant. | |
| * | |
| * This function must be called at the end of the loop. | |
| * Renders the whole display list to the draw buffer. | |
| * Inverts framebuffers to display the whole thing. | |
| */ | |
| void g2dFlip(g2dFlip_Mode mode); | |
| /** | |
| * \brief Pushes the current transformation & attribution to a new object. | |
| * | |
| * This function must be called during object rendering. | |
| */ | |
| void g2dAdd(void); | |
| /** | |
| * \brief Saves the current transformation to stack. | |
| * | |
| * This function must be called during object rendering. | |
| * The stack is 64 saves high. | |
| * Use it like the OpenGL one. | |
| */ | |
| void g2dPush(void); | |
| /** | |
| * \brief Restore the current transformation from stack. | |
| * | |
| * This function must be called during object rendering. | |
| * The stack is 64 saves high. | |
| * Use it like the OpenGL one. | |
| */ | |
| void g2dPop(void); | |
| /** | |
| * \brief Creates a new blank texture. | |
| * @param w Width of the texture. | |
| * @param h Height of the texture. | |
| * | |
| * This function returns NULL on allocation fail. | |
| */ | |
| g2dTexture* g2dTexCreate(int w, int h); | |
| /** | |
| * \brief Frees a texture & set its pointer to NULL. | |
| * @param tex Pointer to the variable which contains the texture pointer. | |
| * | |
| * This function is used to gain memory when a texture is useless. | |
| * Must pass the pointer to the variable which contains the pointer, | |
| * to set it to NULL (passing NULL to a g2dBegin* function is safe). | |
| */ | |
| void g2dTexFree(g2dTexture **tex); | |
| /** | |
| * \brief Loads an image. | |
| * @param data RGBA texture buffer. | |
| * @param width Texture width. | |
| * @param height Texture height. | |
| * @param tex_mode A g2dTex_Mode constant. | |
| * @returns Pointer to the generated texture. | |
| * | |
| * Swizzling is enabled only for 16*16+ textures (useless on small textures), pass G2D_SWIZZLE to enable it. | |
| * Texture supported up to 512*512 in size only (hardware limitation). | |
| */ | |
| g2dTexture *g2dTexLoad(void *data, int width, int height, g2dTex_Mode mode); | |
| /** | |
| * \brief Resets the current coordinates. | |
| * | |
| * This function must be called during object rendering. | |
| * Sets g2dSetCoordMode() to G2D_UP_LEFT and g2dSetCoordXYZ() to (0,0,0). | |
| */ | |
| void g2dResetCoord(void); | |
| /** | |
| * \brief Set coordinate mode. | |
| * @param coord_mode A gCoord_Mode. | |
| * | |
| * This function must be called during object rendering. | |
| * Defines where the coordinates correspond in the object. | |
| */ | |
| void g2dSetCoordMode(g2dCoord_Mode mode); | |
| /** | |
| * \brief Gets the current position. | |
| * @param x Pointer to save the current x (in pixels). | |
| * @param y Pointer to save the current y (in pixels). | |
| * @param z Pointer to save the current z (in pixels). | |
| * | |
| * This function must be called during object rendering. | |
| * Parameters are pointers to float, not int ! | |
| * Pass NULL if not needed. | |
| */ | |
| void g2dGetCoordXYZ(float *x, float *y, float *z); | |
| /** | |
| * \brief Sets the new position. | |
| * @param x New x, in pixels. | |
| * @param y New y, in pixels. | |
| * | |
| * This function must be called during object rendering. | |
| */ | |
| void g2dSetCoordXY(float x, float y); | |
| /** | |
| * \brief Sets the new position, with depth support. | |
| * @param x New x, in pixels. | |
| * @param y New y, in pixels. | |
| * @param z New z, in pixels. (front 0-65535 back) | |
| * | |
| * This function must be called during object rendering. | |
| */ | |
| void g2dSetCoordXYZ(float x, float y, float z); | |
| /** | |
| * \brief Sets the new position, relative to the current. | |
| * @param x New x increment, in pixels. | |
| * @param y New y increment, in pixels. | |
| * | |
| * This function must be called during object rendering. | |
| */ | |
| void g2dSetCoordXYRelative(float x, float y); | |
| /** | |
| * \brief Sets the new position, with depth support, relative to the current. | |
| * @param x New x increment, in pixels. | |
| * @param y New y increment, in pixels. | |
| * @param z New z increment, in pixels. | |
| * | |
| * This function must be called during object rendering. | |
| */ | |
| void g2dSetCoordXYZRelative(float x, float y, float z); | |
| /** | |
| * \brief Use integer coordinates. | |
| * @param use false to desactivate (better look, by default), | |
| true to activate (can be useful when you have glitches). | |
| * | |
| * This function must be called during object rendering. | |
| */ | |
| void g2dSetCoordInteger(bool use); | |
| /** | |
| * \brief Resets the global scale. | |
| * | |
| * This function resets the global scale to 1.f. | |
| * Translations and scales are multiplied by this factor. | |
| */ | |
| void g2dResetGlobalScale(void); | |
| /** | |
| * \brief Resets the current scale. | |
| * | |
| * This function must be called during object rendering. | |
| * Sets the scale to the current texture size or (10,10). | |
| */ | |
| void g2dResetScale(void); | |
| /** | |
| * \brief Gets the global scale. | |
| * @param scale Pointer to save the global scale (factor). | |
| * | |
| * Pass NULL if not needed. | |
| */ | |
| void g2dGetGlobalScale(float *scale); | |
| /** | |
| * \brief Gets the current scale. | |
| * @param w Pointer to save the current width (in pixels). | |
| * @param h Pointer to save the current height (in pixels). | |
| * | |
| * This function must be called during object rendering. | |
| * Parameters are pointers to float, not int ! | |
| * Pass NULL if not needed. | |
| */ | |
| void g2dGetScaleWH(float *w, float *h); | |
| /** | |
| * \brief Sets the global scale. | |
| * | |
| * Translations and scales are multiplied by this factor. | |
| */ | |
| void g2dSetGlobalScale(float scale); | |
| /** | |
| * \brief Sets the new scale. | |
| * @param w Width scale factor. | |
| * @param h Height scale factor. | |
| * | |
| * This function must be called during object rendering. | |
| * g2dResetScale() is called, then width & height scale are | |
| * multiplied by these values. | |
| * Negative values can be passed to invert the texture. | |
| */ | |
| void g2dSetScale(float w, float h); | |
| /** | |
| * \brief Sets the new scale, in pixels. | |
| * @param w New width, in pixels. | |
| * @param h New height, in pixels. | |
| * | |
| * This function must be called during object rendering. | |
| * Negative values can be passed to invert the texture. | |
| */ | |
| void g2dSetScaleWH(float w, float h); | |
| /** | |
| * \brief Sets the new scale, relative to the current. | |
| * @param w Width scale factor. | |
| * @param h Height scale factor. | |
| * | |
| * This function must be called during object rendering. | |
| * Current width & height scale are multiplied by these values. | |
| * Negative values can be passed to invert the texture. | |
| */ | |
| void g2dSetScaleRelative(float w, float h); | |
| /** | |
| * \brief Sets the new scale, in pixels, relative to the current. | |
| * @param w New width to increment, in pixels. | |
| * @param h New height to increment, in pixels. | |
| * | |
| * This function must be called during object rendering. | |
| * Negative values can be passed to invert the texture. | |
| */ | |
| void g2dSetScaleWHRelative(float w, float h); | |
| /** | |
| * \brief Resets the current color. | |
| * | |
| * This function must be called during object rendering. | |
| * Sets g2dSetColor() to WHITE. | |
| */ | |
| void g2dResetColor(void); | |
| /** | |
| * \brief Resets the current alpha. | |
| * | |
| * This function must be called during object rendering. | |
| * Sets g2dSetAlpha() to 255. | |
| */ | |
| void g2dResetAlpha(void); | |
| /** | |
| * \brief Gets the current alpha. | |
| * @param alpha Pointer to save the current alpha (0-255). | |
| * | |
| * This function must be called during object rendering. | |
| * Pass NULL if not needed. | |
| */ | |
| void g2dGetAlpha(g2dAlpha *alpha); | |
| /** | |
| * \brief Sets the new color. | |
| * @param color The new color. | |
| * | |
| * This function must be called during object rendering. | |
| * Can be used to colorize any object. | |
| */ | |
| void g2dSetColor(g2dColor color); | |
| /** | |
| * \brief Sets the new alpha. | |
| * @param alpha The new alpha (0-255). | |
| * | |
| * This function must be called during object rendering. | |
| * Can be used to make any object transparent. | |
| */ | |
| void g2dSetAlpha(g2dAlpha alpha); | |
| /** | |
| * \brief Sets the new alpha, relative to the current alpha. | |
| * @param alpha The new alpha increment. | |
| * | |
| * This function must be called during object rendering. | |
| * Can be used to make any object transparent. | |
| */ | |
| void g2dSetAlphaRelative(int alpha); | |
| /** | |
| * \brief Resets the current rotation. | |
| * | |
| * This function must be called during object rendering. | |
| * Sets g2dSetRotation() to 0°. | |
| */ | |
| void g2dResetRotation(void); | |
| /** | |
| * \brief Gets the current rotation, in radians. | |
| * @param radians Pointer to save the current rotation. | |
| * | |
| * This function must be called during object rendering. | |
| * Pass NULL if not needed. | |
| */ | |
| void g2dGetRotationRad(float *radians); | |
| /** | |
| * \brief Gets the current rotation, in degrees. | |
| * @param degrees Pointer to save the current rotation. | |
| * | |
| * This function must be called during object rendering. | |
| * Pass NULL if not needed. | |
| */ | |
| void g2dGetRotation(float *degrees); | |
| /** | |
| * \brief Sets the new rotation, in radians. | |
| * @param radians The new angle. | |
| * | |
| * This function must be called during object rendering. | |
| * The rotation center is the actual coordinates. | |
| */ | |
| void g2dSetRotationRad(float radians); | |
| /** | |
| * \brief Sets the new rotation, in degrees. | |
| * @param degrees The new angle. | |
| * | |
| * This function must be called during object rendering. | |
| * The rotation center is the actual coordinates. | |
| */ | |
| void g2dSetRotation(float degrees); | |
| /** | |
| * \brief Sets the new rotation, relative to the current, in radians. | |
| * @param radians The new angle increment. | |
| * | |
| * This function must be called during object rendering. | |
| * The rotation center is the actual coordinates. | |
| */ | |
| void g2dSetRotationRadRelative(float radians); | |
| /** | |
| * \brief Sets the new rotation, relative to the current, in degrees. | |
| * @param degrees The new angle increment. | |
| * | |
| * This function must be called during object rendering. | |
| * The rotation center is the actual coordinates. | |
| */ | |
| void g2dSetRotationRelative(float degrees); | |
| /** | |
| * \brief Resets the current crop. | |
| * | |
| * This function must be called during object rendering. | |
| * Sets g2dSetCropXY() to (0;0) and g2dSetCropWH() to (tex->w,tex->h). | |
| */ | |
| void g2dResetCrop(void); | |
| /** | |
| * \brief Gets the current crop position. | |
| * @param x Pointer to save the current crop x. | |
| * @param y Pointer to save the current crop y. | |
| * | |
| * This function must be called during object rendering. | |
| * Pass NULL if not needed. | |
| */ | |
| void g2dGetCropXY(int *x, int *y); | |
| /** | |
| * \brief Gets the current crop scale. | |
| * @param w Pointer to save the current crop width. | |
| * @param h Pointer to save the current crop height. | |
| * | |
| * This function must be called during object rendering. | |
| * Pass NULL if not needed. | |
| */ | |
| void g2dGetCropWH(int *w, int *h); | |
| /** | |
| * \brief Sets the new crop position. | |
| * @param x New x, in pixels. | |
| * @param y New y, in pixels. | |
| * | |
| * This function must be called during object rendering. Defines crop position. | |
| * If the rectangle is larger or next to the texture, it will be repeated | |
| * when g2dSetTexRepeat is enabled. Useful for a tileset. | |
| */ | |
| void g2dSetCropXY(int x, int y); | |
| /** | |
| * \brief Sets the new crop size. | |
| * @param w New width, in pixels. | |
| * @param h New height, in pixels. | |
| * | |
| * This function must be called during object rendering. Defines crop size. | |
| * If the rectangle is larger or next to the texture, it will be repeated | |
| * when g2dSetTexRepeat is enabled. Useful for a tileset. | |
| */ | |
| void g2dSetCropWH(int w, int h); | |
| /** | |
| * \brief Sets the new crop position, relative to the current. | |
| * @param x New x increment, in pixels. | |
| * @param y New y increment, in pixels. | |
| * | |
| * This function must be called during object rendering. Defines crop position. | |
| * If the rectangle is larger or next to the texture, texture will be repeated | |
| * when g2dSetTexRepeat is enabled. Useful for a tileset. | |
| */ | |
| void g2dSetCropXYRelative(int x, int y); | |
| /** | |
| * \brief Sets the new crop size, relative to the current. | |
| * @param w New width increment, in pixels. | |
| * @param h New height increment, in pixels. | |
| * | |
| * This function must be called during object rendering. Defines crop size. | |
| * If the rectangle is larger or next to the texture, texture will be repeated | |
| * when g2dSetTexRepeat is enabled. Useful for a tileset. | |
| */ | |
| void g2dSetCropWHRelative(int w, int h); | |
| /** | |
| * \brief Resets texture properties. | |
| * | |
| * This function must be called during object rendering. | |
| */ | |
| void g2dResetTex(void); | |
| /** | |
| * \brief Set texture wrap. | |
| * @param use true to repeat, false to clamp (by default). | |
| * | |
| * This function must be called during object rendering. | |
| */ | |
| void g2dSetTexRepeat(bool use); | |
| /** | |
| * \brief Use the bilinear filter with the texture. | |
| * @param use true to activate (better look, by default). | |
| false to desactivate (better performance). | |
| * | |
| * This function must be called during object rendering. | |
| * Only useful when scaling. | |
| */ | |
| void g2dSetTexLinear(bool use); | |
| /** | |
| * \brief Resets the draw zone to the entire screen. | |
| * | |
| * This function can be called everywhere in the loop. | |
| */ | |
| void g2dResetScissor(void); | |
| /** | |
| * \brief Sets the draw zone. | |
| * @param x New x position. | |
| * @param y New y position. | |
| * @param w New width. | |
| * @param h New height. | |
| * | |
| * This function can be called everywhere in the loop. | |
| * Pixel draw will be skipped outside this rectangle. | |
| */ | |
| void g2dSetScissor(int x, int y, int w, int h); | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
| #endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <pspdisplay.h> | |
| #include <pspsdk.h> | |
| #include <psptypes.h> | |
| #include <pspkerror.h> | |
| #include <pspkerneltypes.h> | |
| #include <pspthreadman.h> | |
| #include <pspiofilemgr.h> | |
| #include <stdbool.h> | |
| #include <inttypes.h> | |
| #include <glib2d.h> | |
| #include <string.h> | |
| #define MODULE_NAME "test" | |
| #define MAJOR_VER 1 | |
| #define MINOR_VER 1 | |
| #define MODULE_OK 0 | |
| #define MODULE_ERROR 1 | |
| SceUID g_uiThreadId = -1; | |
| uint8_t g_running = 1; | |
| #define LOG_PATH "ms0:/SEPLUGINS/debug2.log" | |
| // | |
| // PSP SDK | |
| // | |
| // We are building a kernel mode prx plugin | |
| PSP_MODULE_INFO(MODULE_NAME, PSP_MODULE_KERNEL, MAJOR_VER, MINOR_VER); | |
| // We don't allocate any heap memory, so set this to 0. | |
| PSP_HEAP_SIZE_KB(0); | |
| // We don't need a main thread since we only do basic setup during module start and won't stall module loading. | |
| // This will make us be called from the module loader thread directly, instead of a secondary kernel thread. | |
| PSP_NO_CREATE_MAIN_THREAD(); | |
| // We don't need any of the newlib features since we're not calling into stdio or stdlib etc | |
| PSP_DISABLE_NEWLIB(); | |
| int write(const char *filename, const char *text) { | |
| SceUID fd = sceIoOpen(filename, PSP_O_WRONLY | PSP_O_CREAT | PSP_O_APPEND, 0777); | |
| if (fd < 0) { | |
| return fd; // error opening file | |
| } | |
| int result = sceIoWrite(fd, text, strlen(text)); | |
| sceIoClose(fd); | |
| return result; // return number of bytes written or error code | |
| } | |
| void DrawRect(float x, float y, float width, float height, g2dColor colour) { | |
| g2dBeginRects(nullptr); { | |
| g2dSetColor(colour); | |
| g2dSetScaleWH(width, height); | |
| g2dSetCoordXY(x, y); | |
| g2dAdd(); | |
| } | |
| g2dEnd(); | |
| } | |
| static | |
| int gui_thread(SceSize args, void *argp) | |
| { | |
| while( g_running) { | |
| if (sceDisplayWaitVblankStart() < 0) | |
| break; | |
| DrawRect(30, 30, 200, 200, G2D_RGBA(255, 255, 255, 255)); | |
| } | |
| return 0; | |
| } | |
| static | |
| int start_GUI_thread(void) | |
| { | |
| int result; | |
| SceUID thid; | |
| // name, entry, initPriority, stackSize, PspThreadAttributes, SceKernelThreadOptParam | |
| thid = sceKernelCreateThread(MODULE_NAME "GUIThread", gui_thread, 0x11, 0x800, 0, 0); | |
| if (thid >= 0) { | |
| result = sceKernelStartThread(thid, 0, 0); | |
| g_uiThreadId = thid; | |
| } | |
| else { | |
| result = thid; | |
| } | |
| return result; | |
| } | |
| static | |
| int stop_gui_thread(void) | |
| { | |
| int result = 0; | |
| SceUID thid = g_uiThreadId; | |
| g_running = 0; | |
| if(thid >= 0) { | |
| // Wait for the main thread to clean up and exit | |
| result = sceKernelWaitThreadEnd(thid, NULL); | |
| if(result < 0) { | |
| result = sceKernelTerminateDeleteThread(thid); | |
| if(result >= 0) { | |
| g_uiThreadId = -1; | |
| } | |
| } | |
| else { | |
| // Thead stopped cleanly, delete it | |
| result = sceKernelDeleteThread(thid); | |
| if(result >= 0) { | |
| g_uiThreadId = -1; | |
| } | |
| } | |
| } | |
| return result; | |
| } | |
| // Called during module init | |
| int module_start(SceSize args, void *argp) | |
| { | |
| write(LOG_PATH, "I'm in\n"); // never logs | |
| // ive while (true) here too expecting it to lock the PSP if it runs | |
| // yet it doesnt lock the PSP so i assume is not running | |
| start_GUI_thread(); | |
| return MODULE_OK; | |
| } | |
| // Called during module deinit | |
| int module_stop(SceSize args, void *argp) | |
| { | |
| stop_gui_thread(); | |
| return MODULE_OK; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| TARGET = testg2d | |
| OBJS = glib2d.o main.o exports.o | |
| BUILD_PRX = 1 | |
| PRX_EXPORTS = exports.exp | |
| # Use the kernel's small inbuilt libc | |
| #USE_KERNEL_LIBC = 1 | |
| # Use only kernel libraries | |
| #USE_KERNEL_LIBS = 1 | |
| CFLAGS = -Os -G0 -Wall -fno-builtin-printf | |
| CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti | |
| ASFLAGS = $(CFLAGS) | |
| LIBS = -lz -lpspgu -lm -lpspvram -lpsphprm_driver -lpspdebug -lpspdisplay | |
| #LDFLAGS = -nostartfiles | |
| PSPSDK=$(shell psp-config --pspsdk-path) | |
| include $(PSPSDK)/lib/build_prx.mak |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment