1
0
Fork 0
mirror of https://github.com/ctruLua/ctruLua.git synced 2025-10-27 16:39:29 +00:00

Added missing dependicies

This commit is contained in:
Reuh 2015-08-17 21:10:54 +02:00
parent 03baa21c10
commit ebcd9f00ed
47 changed files with 18405 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,142 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := sf2d
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard
CFLAGS := -g -Wall -O2\
$(ARCH)
CFLAGS += $(INCLUDE) -DARM11 -D_3DS
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/lib/lib$(TARGET).a
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
lib:
@[ -d $@ ] || mkdir -p $@
$(BUILD): lib
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) lib latex html
#---------------------------------------------------------------------------------
install: $(BUILD)
@cp $(OUTPUT) $(CTRULIB)/lib
@cp include/sf2d.h $(CTRULIB)/include
@echo "Installed!"
#---------------------------------------------------------------------------------
docs:
@doxygen Doxyfile
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
# WARNING: This is not the right way to do this! TODO: Do it right!
#---------------------------------------------------------------------------------
%_vsh.h %.vsh.o : %.vsh
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@python ../../../aemstro/aemstro_as.py $< ../$(notdir $<).shbin
@bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h
@echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h
@rm ../$(notdir $<).shbin
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -0,0 +1,39 @@
; setup constants
.const c20, 0.0, 0.0, 0.0, 1.0
; setup outmap
.out o0, result.position, 0xF
.out o1, result.texcoord0, 0x3
.out o2, result.color, 0xF
; setup uniform map (not required)
.uniform c0, c3, projection
.vsh vmain, end_vmain
;code
vmain:
; result.pos = projMtx * in.pos
dp4 o0, c0, v0 (0x0)
dp4 o0, c1, v0 (0x1)
dp4 o0, c2, v0 (0x2)
dp4 o0, c3, v0 (0x3)
; result.texcoord = in.texcoord
mov o1, v1 (0x5)
; result.color = in.color
mov o2, v1 (0x5)
nop
end
end_vmain:
;operand descriptors
.opdesc x___, xyzw, xyzw ; 0x0
.opdesc _y__, xyzw, xyzw ; 0x1
.opdesc __z_, xyzw, xyzw ; 0x2
.opdesc ___w, xyzw, xyzw ; 0x3
.opdesc xyz_, xyzw, xyzw ; 0x4
.opdesc xyzw, xyzw, xyzw ; 0x5
.opdesc x_zw, xyzw, xyzw ; 0x6
.opdesc xyzw, yyyw, xyzw ; 0x7
.opdesc xyz_, wwww, wwww ; 0x8
.opdesc xyz_, yyyy, xyzw ; 0x9

View file

@ -0,0 +1,496 @@
/**
* @file sf2d.h
* @author Sergi Granell (xerpi)
* @date 22 March 2015
* @brief sf2dlib header
*/
#ifndef SF2D_H
#define SF2D_H
#include <3ds.h>
#ifdef __cplusplus
extern "C" {
#endif
// Defines
/**
* @brief Creates a new RGBA8 color
* @param r the red component of the color to create
* @param g the green component of the color to create
* @param b the blue component of the color to create
* @param a the alpha component of the color to create
*/
#define RGBA8(r, g, b, a) ((((r)&0xFF)<<24) | (((g)&0xFF)<<16) | (((b)&0xFF)<<8) | (((a)&0xFF)<<0))
/**
* @brief Default size of the GPU commands FIFO buffer
*/
#define SF2D_GPUCMD_DEFAULT_SIZE 0x80000
/**
* @brief Default size of the temporary memory pool
*/
#define SF2D_TEMPPOOL_DEFAULT_SIZE 0x80000
/**
* @brief Default depth (Z coordinate) to draw the textures to
*/
#define SF2D_DEFAULT_DEPTH 0.5f
// Enums
/**
* @brief Represents a texture format
*/
typedef enum {
TEXFMT_RGBA8 = 0,
TEXFMT_RGB8 = 1,
TEXFMT_RGB5A1 = 2,
TEXFMT_RGB565 = 3,
TEXFMT_RGBA4 = 4,
TEXFMT_IA8 = 5,
TEXFMT_I8 = 7,
TEXFMT_A8 = 8,
TEXFMT_IA4 = 9,
TEXFMT_I4 = 10,
TEXFMT_A4 = 11,
TEXFMT_ETC1 = 12,
TEXFMT_ETC1A4 = 13
} sf2d_texfmt;
/**
* @brief Data allocated on the RAM or VRAM
*/
typedef enum {
SF2D_PLACE_RAM, /**< RAM allocated */
SF2D_PLACE_VRAM, /**< VRAM allocated */
SF2D_PLACE_TEMP /**< Temporary memory pool allocated */
} sf2d_place;
// Structs
/**
* @brief Represents a two dimensional float vector
*/
typedef struct {
float u; /**< First component of the vector */
float v; /**< Second component of the vector */
} sf2d_vector_2f;
/**
* @brief Represents a three dimensional float vector
*/
typedef struct {
float x; /**< First component of the vector */
float y; /**< Second component of the vector */
float z; /**< Third component of the vector */
} sf2d_vector_3f;
/**
* @brief Represents a four dimensional float vector
*/
typedef struct {
float r; /**< Red component of the vector/color */
float g; /**< Green component of the vector/color */
float b; /**< Blue component of the vector/color */
float a; /**< Alpha component of the vector/color */
} sf2d_vector_4f;
/**
* @brief Represents a vertex containing position and color attributes
*/
typedef struct {
sf2d_vector_3f position; /**< Position of the vertex */
sf2d_vector_4f color; /**< Color of the vertex */
} sf2d_vertex_pos_col;
/**
* @brief Represents a vertex containing position and texture coordinates
*/
typedef struct {
sf2d_vector_3f position; /**< Position of the vertex */
sf2d_vector_2f texcoord; /**< Texture coordinates of the vertex */
} sf2d_vertex_pos_tex;
/**
* @brief Represents a texture
*/
typedef struct {
sf2d_place place; /**< Where the texture data resides, RAM or VRAM */
int tiled; /**< Whether the tetxure is tiled or not */
sf2d_texfmt pixel_format; /**< Pixel format */
int width; /**< Texture width */
int height; /**< Texture height */
int pow2_w; /**< Nearest power of 2 >= width */
int pow2_h; /**< Nearest power of 2 >= height */
int data_size; /**< Size of the raw texture data */
void *data; /**< Pointer to the data */
} sf2d_texture;
// Basic functions
/**
* @brief Initializates the library
* @return Whether the initialization has been successful or not
*/
int sf2d_init();
/**
* @brief Initializates the library (with advanced settings)
* @param gpucmd_size the size of the GPU FIFO
* @param temppool_size the size of the temporary pool
* @return Whether the initialization has been successful or not
*/
int sf2d_init_advanced(int gpucmd_size, int temppool_size);
/**
* @brief Finishes the library
* @return Whether the finalization has been successful or not
*/
int sf2d_fini();
/**
* @brief Enables or disables the 3D
* @param enable whether to enable or disable the 3D
*/
void sf2d_set_3D(int enable);
/**
* @brief Starts a frame
* @param screen target screen
* @param side target eye (only for top screen)
*/
void sf2d_start_frame(gfxScreen_t screen, gfx3dSide_t side);
/**
* @brief Ends a frame, should be called on pair with sf2d_start_frame
*/
void sf2d_end_frame();
/**
* @brief Swaps the framebuffers, should be called once after all the frames have been finished
*/
void sf2d_swapbuffers();
/**
* @brief Enables or disables the VBlank waiting
* @param enable whether to enable or disable the VBlank waiting
*/
void sf2d_set_vblank_wait(int enable);
/**
* @brief Returns the FPS (frames per second)
* @return the current FPS
*/
float sf2d_get_fps();
/**
* @brief Allocates memory from a temporary pool. The pool will be emptied after a sf2d_swapbuffers call
* @param size the number of bytes to allocate
*/
void *sf2d_pool_malloc(u32 size);
/**
* @brief Allocates aligned memory from a temporary pool. Works as sf2d_pool_malloc
* @param size the number of bytes to allocate
* @param alignment the alignment to where allocate the memory
*/
void *sf2d_pool_memalign(u32 size, u32 alignment);
/**
* @brief Returns the temporary pool's free space
* @return the temporary pool's free space
*/
unsigned int sf2d_pool_space_free();
/**
* @brief Empties the temporary pool
*/
void sf2d_pool_reset();
/**
* @brief Sets the screen clear color
* @param color the color
*/
void sf2d_set_clear_color(u32 color);
// Draw functions
/**
* @brief Draws a line
* @param x0 x coordinate of the first dot
* @param y0 y coordinate of the first dot
* @param x1 x coordinate of the second dot
* @param y1 y coordinate of the sceond dot
* @param color the color to draw the line
*/
void sf2d_draw_line(int x0, int y0, int x1, int y1, u32 color);
/**
* @brief Draws a rectangle
* @param x x coordinate of the top left corner of the rectangle
* @param y y coordinate of the top left corner of the rectangle
* @param w rectangle width
* @param h rectangle height
* @param color the color to draw the rectangle
*/
void sf2d_draw_rectangle(int x, int y, int w, int h, u32 color);
/**
* @brief Draws a rotated rectangle
* @param x x coordinate of the top left corner of the rectangle
* @param y y coordinate of the top left corner of the rectangle
* @param w rectangle width
* @param h rectangle height
* @param color the color to draw the rectangle
* @param rad rotation (in radians) to draw the rectangle
*/
void sf2d_draw_rectangle_rotate(int x, int y, int w, int h, u32 color, float rad);
/**
* @brief Draws a filled circle
* @param x x coordinate of the center of the circle
* @param y y coordinate of the center of the circle
* @param radius the radius of the circle
* @param color the color to draw the circle
*/
void sf2d_draw_fill_circle(int x, int y, int radius, u32 color);
// Texture
/**
* @brief Creates an empty texture.
* The returned texture has the data allocated,
* this means that the raw pixel data can be filled
* just after the return.
* @param width the width of the texture
* @param height the height of the texture
* @param pixel_format the pixel_format of the texture
* @param place where to allocate the texture
* @return a pointer to the newly created texture
*/
sf2d_texture *sf2d_create_texture(int width, int height, sf2d_texfmt pixel_format, sf2d_place place);
/**
* @brief Frees a texture
* @param texture pointer to the texture to freeze
*/
void sf2d_free_texture(sf2d_texture *texture);
/**
* @brief Fills an already allocated texture from a RGBA8 source
* @param dst pointer to the destination texture to fill
* @param rgba8 pointer to the RGBA8 data to fill from
* @param source_w width (in pixels) of the RGAB8 source
* @param source_h height (in pixels) of the RGAB8 source
*/
void sf2d_fill_texture_from_RGBA8(sf2d_texture *dst, const void *rgba8, int source_w, int source_h);
/**
* @brief Creates a texture and fills it from a RGBA8 memory source.
* The returned texture is already tiled.
* @param src_buffer pointer to the RGBA8 data to fill from
* @param src_w width (in pixels) of the RGAB8 source
* @param src_h height (in pixels) of the RGAB8 source
* @param pixel_format the pixel_format of the texture to create
* @param place where to allocate the texture
* @return a pointer to the newly created, filled, and tiled texture
*/
sf2d_texture *sf2d_create_texture_mem_RGBA8(const void *src_buffer, int src_w, int src_h, sf2d_texfmt pixel_format, sf2d_place place);
/**
* @brief Binds a texture to a GPU texture unit
* @param texture the texture to bind
* @param unit GPU texture unit to bind to
*/
void sf2d_bind_texture(const sf2d_texture *texture, GPU_TEXUNIT unit);
/**
* @brief Binds a texture to a GPU texture unit with a constant color
* @param texture the texture to bind
* @param unit GPU texture unit to bind to
* @param color the color the bind with the texture
*/
void sf2d_bind_texture_color(const sf2d_texture *texture, GPU_TEXUNIT unit, u32 color);
/**
* @brief Binds a texture to a GPU texture unit with custom parameters
* @param texture the texture to bind
* @param unit GPU texture unit to bind to
* @param params the parameters the bind with the texture
*/
void sf2d_bind_texture_parameters(const sf2d_texture *texture, GPU_TEXUNIT unit, unsigned int params);
/**
* @brief Draws a texture
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
*/
void sf2d_draw_texture(const sf2d_texture *texture, int x, int y);
/**
* @brief Draws a texture with rotation
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param rad rotation (in radians) to draw the texture
*/
void sf2d_draw_texture_rotate(const sf2d_texture *texture, int x, int y, float rad);
/**
* @brief Draws a part of a texture
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param tex_x the starting point (x coordinate) where to start drawing
* @param tex_y the starting point (y coordinate) where to start drawing
* @param tex_w the width to draw from the starting point
* @param tex_h the height to draw from the starting point
*/
void sf2d_draw_texture_part(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h);
/**
* @brief Draws a texture with scaling
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param x_scale the x scale
* @param y_scale the y scale
*/
void sf2d_draw_texture_scale(const sf2d_texture *texture, int x, int y, float x_scale, float y_scale);
/**
* @brief Draws a part of a texture, with rotation and scaling
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param rad rotation (in radians) to draw the texture
* @param tex_x the starting point (x coordinate) where to start drawing
* @param tex_y the starting point (y coordinate) where to start drawing
* @param tex_w the width to draw from the starting point
* @param tex_h the height to draw from the starting point
* @param x_scale the x scale
* @param y_scale the y scale
*/
void sf2d_draw_texture_rotate_cut_scale(const sf2d_texture *texture, int x, int y, float rad, int tex_x, int tex_y, int tex_w, int tex_h, float x_scale, float y_scale);
/**
* @brief Draws a texture blended with a color
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param color the color to blend with the texture
*/
void sf2d_draw_texture_blend(const sf2d_texture *texture, int x, int y, u32 color);
/**
* @brief Draws a part of a texture blended with a color
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param tex_x the starting point (x coordinate) where to start drawing
* @param tex_y the starting point (y coordinate) where to start drawing
* @param tex_w the width to draw from the starting point
* @param tex_h the height to draw from the starting point
* @param color the color to blend with the texture
*/
void sf2d_draw_texture_part_blend(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h, u32 color);
/**
* @brief Draws a texture blended in a certain depth
* @param texture the texture to draw
* @param x the x coordinate to draw the texture to
* @param y the y coordinate to draw the texture to
* @param z the depth to draw the texture to
* @note The z parameter is a value in the [-32768, +32767] range,
* where -32768 is the deepest and +32767 the toppest.
* By default, the textures are drawn at z = 0.
* Keep in mind that this function won't do
* Order-independent transparency (OIT), so you should use fully
* opaque textures to get good results.
*/
void sf2d_draw_texture_depth(const sf2d_texture *texture, int x, int y, signed short z);
/**
* @brief Draws a texture using custom texture coordinates and parameters
* @param texture the texture to draw
* @param left the left coordinate of the texture to start drawing
* @param top the top coordinate of the texture to start drawing
* @param width the width to draw from the starting left coordinate
* @param height the height to draw from the starting top coordinate
* @param u0 the U texture coordinate of the left vertices
* @param v0 the V texture coordinate of the top vertices
* @param u1 the U texture coordinate of the right vertices
* @param v1 the V texture coordinate of the bottom vertices
* @param params the parameters to draw the texture with
*/
void sf2d_draw_quad_uv(const sf2d_texture *texture, float left, float top, float right, float bottom,
float u0, float v0, float u1, float v1, unsigned int params);
/**
* @brief Changes a pixel of the texture
* @param texture the texture to change the pixel
* @param x the x coordinate to change the pixel
* @param y the y coordinate to change the pixel
* @param new_color the new color to set to the pixel at (x, y)
*/
void sf2d_set_pixel(sf2d_texture *texture, int x, int y, u32 new_color);
/**
* @brief Gets a pixel of the texture
* @param texture the texture to get the pixel
* @param x the x coordinate to get the pixel
* @param y the y coordinate to get the pixel
* @return the pixel at (x, y)
*/
u32 sf2d_get_pixel(sf2d_texture *texture, int x, int y);
/**
* @brief Tiles a texture
* @param texture the texture to tile
*/
void sf2d_texture_tile32(sf2d_texture *texture);
/**
* @brief Sets the scissor test
* @param mode the test mode (disable, invert or normal)
* @param x the starting x coordinate of the scissor
* @param y the starting y coordinate of the scissor
* @param w the width of the scissor rectangle
* @param h the height of the scissor rectangle
* @note This function should be called after sf2d_start_frame.
* The scissor will remain active until the sf2d_end_frame call.
*/
void sf2d_set_scissor_test(GPU_SCISSORMODE mode, u32 x, u32 y, u32 w, u32 h);
/**
* @brief Returns the current screen (latest call to sf2d_start_frame)
* @note The returned value can be GFX_TOP or GFX_BOTTOM.
*/
gfxScreen_t sf2d_get_current_screen();
/**
* @brief Returns the current screen side (latest call to sf2d_start_frame)
* @note The returned value can be GFX_LEFT or GFX_RIGHT.
*/
gfx3dSide_t sf2d_get_current_side();
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,29 @@
#ifndef SF2D_PRIVATE_H
#define SF2D_PRIVATE_H
#include <3ds.h>
#include "sf2d.h"
void GPU_SetDummyTexEnv(u8 num);
// Vector operations
void vector_mult_matrix4x4(const float *msrc, const sf2d_vector_3f *vsrc, sf2d_vector_3f *vdst);
// Matrix operations
void matrix_copy(float *dst, const float *src);
void matrix_identity4x4(float *m);
void matrix_mult4x4(const float *src1, const float *src2, float *dst);
void matrix_set_z_rotation(float *m, float rad);
void matrix_rotate_z(float *m, float rad);
void matrix_set_scaling(float *m, float x_scale, float y_scale, float z_scale);
void matrix_swap_xy(float *m);
void matrix_init_orthographic(float *m, float left, float right, float bottom, float top, float near, float far);
void matrix_gpu_set_uniform(const float *m, u32 startreg);
unsigned int next_pow2(unsigned int v);
#endif

View file

@ -0,0 +1,303 @@
#include "sf2d.h"
#include "sf2d_private.h"
#include "shader_vsh_shbin.h"
static int sf2d_initialized = 0;
static u32 clear_color = RGBA8(0x00, 0x00, 0x00, 0xFF);
static u32 *gpu_cmd = NULL;
//GPU init variables
static int gpu_cmd_size = 0;
// Temporary memory pool
static void *pool_addr = NULL;
static u32 pool_index = 0;
static u32 pool_size = 0;
//GPU framebuffer address
static u32 *gpu_fb_addr = NULL;
//GPU depth buffer address
static u32 *gpu_depth_fb_addr = NULL;
//VBlank wait
static int vblank_wait = 1;
//FPS calculation
static float current_fps = 0.0f;
static unsigned int frames = 0;
static u64 last_time = 0;
//Current screen/side
static gfxScreen_t cur_screen = GFX_TOP;
static gfx3dSide_t cur_side = GFX_LEFT;
//Shader stuff
static DVLB_s *dvlb = NULL;
static shaderProgram_s shader;
static u32 projection_desc = -1;
//Matrix
static float ortho_matrix_top[4*4];
static float ortho_matrix_bot[4*4];
//Apt hook cookie
static aptHookCookie apt_hook_cookie;
//Functions
static void apt_hook_func(int hook, void* param);
static void reset_gpu_apt_resume();
int sf2d_init()
{
return sf2d_init_advanced(
SF2D_GPUCMD_DEFAULT_SIZE,
SF2D_TEMPPOOL_DEFAULT_SIZE);
}
int sf2d_init_advanced(int gpucmd_size, int temppool_size)
{
if (sf2d_initialized) return 0;
gpu_fb_addr = vramMemAlign(400*240*8, 0x100);
gpu_depth_fb_addr = vramMemAlign(400*240*8, 0x100);
gpu_cmd = linearAlloc(gpucmd_size * 4);
pool_addr = linearAlloc(temppool_size);
pool_size = temppool_size;
gpu_cmd_size = gpucmd_size;
gfxInitDefault();
GPU_Init(NULL);
gfxSet3D(false);
GPU_Reset(NULL, gpu_cmd, gpucmd_size);
//Setup the shader
dvlb = DVLB_ParseFile((u32 *)shader_vsh_shbin, shader_vsh_shbin_size);
shaderProgramInit(&shader);
shaderProgramSetVsh(&shader, &dvlb->DVLE[0]);
//Get shader uniform descriptors
projection_desc = shaderInstanceGetUniformLocation(shader.vertexShader, "projection");
shaderProgramUse(&shader);
matrix_init_orthographic(ortho_matrix_top, 0.0f, 400.0f, 0.0f, 240.0f, 0.0f, 1.0f);
matrix_init_orthographic(ortho_matrix_bot, 0.0f, 320.0f, 0.0f, 240.0f, 0.0f, 1.0f);
matrix_gpu_set_uniform(ortho_matrix_top, projection_desc);
//Register the apt callback hook
aptHook(&apt_hook_cookie, apt_hook_func, NULL);
vblank_wait = 1;
current_fps = 0.0f;
frames = 0;
last_time = osGetTime();
cur_screen = GFX_TOP;
cur_side = GFX_LEFT;
GPUCMD_Finalize();
GPUCMD_FlushAndRun(NULL);
gspWaitForP3D();
sf2d_pool_reset();
sf2d_initialized = 1;
return 1;
}
int sf2d_fini()
{
if (!sf2d_initialized) return 0;
aptUnhook(&apt_hook_cookie);
gfxExit();
shaderProgramFree(&shader);
DVLB_Free(dvlb);
linearFree(pool_addr);
linearFree(gpu_cmd);
vramFree(gpu_fb_addr);
vramFree(gpu_depth_fb_addr);
sf2d_initialized = 0;
return 1;
}
void sf2d_set_3D(int enable)
{
gfxSet3D(enable);
}
void sf2d_start_frame(gfxScreen_t screen, gfx3dSide_t side)
{
sf2d_pool_reset();
GPUCMD_SetBufferOffset(0);
// Only upload the uniform if the screen changes
if (screen != cur_screen) {
if (screen == GFX_TOP) {
matrix_gpu_set_uniform(ortho_matrix_top, projection_desc);
} else {
matrix_gpu_set_uniform(ortho_matrix_bot, projection_desc);
}
cur_screen = screen;
}
int screen_w;
if (screen == GFX_TOP) {
screen_w = 400;
cur_side = side;
} else {
screen_w = 320;
}
GPU_SetViewport((u32 *)osConvertVirtToPhys((u32)gpu_depth_fb_addr),
(u32 *)osConvertVirtToPhys((u32)gpu_fb_addr),
0, 0, 240, screen_w);
GPU_DepthMap(-1.0f, 0.0f);
GPU_SetFaceCulling(GPU_CULL_NONE);
GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00);
GPU_SetStencilOp(GPU_KEEP, GPU_KEEP, GPU_KEEP);
GPU_SetBlendingColor(0,0,0,0);
GPU_SetDepthTestAndWriteMask(true, GPU_GEQUAL, GPU_WRITE_ALL);
GPUCMD_AddMaskedWrite(GPUREG_0062, 0x1, 0);
GPUCMD_AddWrite(GPUREG_0118, 0);
GPU_SetAlphaBlending(
GPU_BLEND_ADD,
GPU_BLEND_ADD,
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA,
GPU_ONE, GPU_ZERO
);
GPU_SetAlphaTest(false, GPU_ALWAYS, 0x00);
GPU_SetDummyTexEnv(1);
GPU_SetDummyTexEnv(2);
GPU_SetDummyTexEnv(3);
GPU_SetDummyTexEnv(4);
GPU_SetDummyTexEnv(5);
}
void sf2d_end_frame()
{
GPU_FinishDrawing();
GPUCMD_Finalize();
GPUCMD_FlushAndRun(NULL);
gspWaitForP3D();
//Copy the GPU rendered FB to the screen FB
if (cur_screen == GFX_TOP) {
GX_SetDisplayTransfer(NULL, gpu_fb_addr, GX_BUFFER_DIM(240, 400),
(u32 *)gfxGetFramebuffer(GFX_TOP, cur_side, NULL, NULL),
GX_BUFFER_DIM(240, 400), 0x1000);
} else {
GX_SetDisplayTransfer(NULL, gpu_fb_addr, GX_BUFFER_DIM(240, 320),
(u32 *)gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL),
GX_BUFFER_DIM(240, 320), 0x1000);
}
gspWaitForPPF();
//Clear the screen
GX_SetMemoryFill(NULL, gpu_fb_addr, clear_color, &gpu_fb_addr[0x2EE00],
0x201, gpu_depth_fb_addr, 0x00000000, &gpu_depth_fb_addr[0x2EE00], 0x201);
gspWaitForPSC0();
}
void sf2d_swapbuffers()
{
gfxSwapBuffersGpu();
if (vblank_wait) {
gspWaitForEvent(GSPEVENT_VBlank0, false);
}
//Calculate FPS
frames++;
u64 delta_time = osGetTime() - last_time;
if (delta_time >= 1000) {
current_fps = frames/(delta_time/1000.0f);
frames = 0;
last_time = osGetTime();
}
}
void sf2d_set_vblank_wait(int enable)
{
vblank_wait = enable;
}
float sf2d_get_fps()
{
return current_fps;
}
void *sf2d_pool_malloc(u32 size)
{
if ((pool_index + size) < pool_size) {
void *addr = (void *)((u32)pool_addr + pool_index);
pool_index += size;
return addr;
}
return NULL;
}
void *sf2d_pool_memalign(u32 size, u32 alignment)
{
u32 new_index = (pool_index + alignment - 1) & ~(alignment - 1);
if ((new_index + size) < pool_size) {
void *addr = (void *)((u32)pool_addr + new_index);
pool_index = new_index + size;
return addr;
}
return NULL;
}
unsigned int sf2d_pool_space_free()
{
return pool_size - pool_index;
}
void sf2d_pool_reset()
{
pool_index = 0;
}
void sf2d_set_clear_color(u32 color)
{
clear_color = color;
}
void sf2d_set_scissor_test(GPU_SCISSORMODE mode, u32 x, u32 y, u32 w, u32 h)
{
if (cur_screen == GFX_TOP) {
GPU_SetScissorTest(mode, 240 - (y + h), 400 - (x + w), 240 - y, 400 - x);
} else {
GPU_SetScissorTest(mode, 240 - (y + h), 320 - (x + w), 240 - y, 320 - x);
}
}
gfxScreen_t sf2d_get_current_screen()
{
return cur_screen;
}
gfx3dSide_t sf2d_get_current_side()
{
return cur_side;
}
static void apt_hook_func(int hook, void* param)
{
if (hook == APTHOOK_ONRESTORE) {
reset_gpu_apt_resume();
}
}
static void reset_gpu_apt_resume()
{
GPU_Reset(NULL, gpu_cmd, gpu_cmd_size); // Only required for custom GPU cmd sizes
shaderProgramUse(&shader);
if (cur_screen == GFX_TOP) {
matrix_gpu_set_uniform(ortho_matrix_top, projection_desc);
} else {
matrix_gpu_set_uniform(ortho_matrix_bot, projection_desc);
}
GPUCMD_Finalize();
GPUCMD_FlushAndRun(NULL);
gspWaitForP3D();
}

View file

@ -0,0 +1,212 @@
#include "sf2d.h"
#include "sf2d_private.h"
#include <math.h>
void sf2d_draw_line(int x0, int y0, int x1, int y1, u32 color)
{
sf2d_vertex_pos_col *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_col));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x0+1.0f, (float)y0+1.0f, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x0-1.0f, (float)y0-1.0f, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x1+1.0f, (float)y1+1.0f, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x1-1.0f, (float)y1-1.0f, SF2D_DEFAULT_DEPTH};
u8 r = (color>>24) & 0xFF;
u8 g = (color>>16) & 0xFF;
u8 b = (color>>8) & 0xFF;
u8 a = color & 0xFF;
vertices[0].color = (sf2d_vector_4f){r/255.0f, g/255.0f, b/255.0f, a/255.0f};
vertices[1].color = vertices[0].color;
vertices[2].color = vertices[0].color;
vertices[3].color = vertices[0].color;
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 4, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_rectangle(int x, int y, int w, int h, u32 color)
{
sf2d_vertex_pos_col *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_col));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+w, (float)y+h, SF2D_DEFAULT_DEPTH};
u8 r = (color>>24) & 0xFF;
u8 g = (color>>16) & 0xFF;
u8 b = (color>>8) & 0xFF;
u8 a = color & 0xFF;
vertices[0].color = (sf2d_vector_4f){r/255.0f, g/255.0f, b/255.0f, a/255.0f};
vertices[1].color = vertices[0].color;
vertices[2].color = vertices[0].color;
vertices[3].color = vertices[0].color;
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 4, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_rectangle_rotate(int x, int y, int w, int h, u32 color, float rad)
{
sf2d_vertex_pos_col *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_col));
if (!vertices) return;
int w2 = w/2.0f;
int h2 = h/2.0f;
vertices[0].position = (sf2d_vector_3f){(float)-w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float) w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)-w2, (float) h2, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float) w2, (float) h2, SF2D_DEFAULT_DEPTH};
u8 r = (color>>24) & 0xFF;
u8 g = (color>>16) & 0xFF;
u8 b = (color>>8) & 0xFF;
u8 a = color & 0xFF;
vertices[0].color = (sf2d_vector_4f){r/255.0f, g/255.0f, b/255.0f, a/255.0f};
vertices[1].color = vertices[0].color;
vertices[2].color = vertices[0].color;
vertices[3].color = vertices[0].color;
float m[4*4];
matrix_set_z_rotation(m, rad);
sf2d_vector_3f rot[4];
int i;
for (i = 0; i < 4; i++) {
vector_mult_matrix4x4(m, &vertices[i].position, &rot[i]);
vertices[i].position = (sf2d_vector_3f){rot[i].x + x + w2, rot[i].y + y + h2, rot[i].z};
}
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 4, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_fill_circle(int x, int y, int radius, u32 color)
{
static const int num_segments = 100;
sf2d_vertex_pos_col *vertices = sf2d_pool_malloc((num_segments + 2) * sizeof(sf2d_vertex_pos_col));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
u8 r = (color>>24) & 0xFF;
u8 g = (color>>16) & 0xFF;
u8 b = (color>>8) & 0xFF;
u8 a = color & 0xFF;
vertices[0].color = (sf2d_vector_4f){r/255.0f, g/255.0f, b/255.0f, a/255.0f};
float theta = 2 * M_PI / (float)num_segments;
float c = cosf(theta);
float s = sinf(theta);
float t;
float xx = radius;
float yy = 0;
int i;
for (i = 1; i <= num_segments; i++) {
vertices[i].position = (sf2d_vector_3f){(float)(x + xx), (float)(y + yy), SF2D_DEFAULT_DEPTH};
vertices[i].color = vertices[0].color;
t = xx;
xx = c * xx - s * yy;
yy = s * t + c * yy;
}
vertices[num_segments + 1].position = vertices[1].position;
vertices[num_segments + 1].color = vertices[1].color;
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVSOURCES(GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 4, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_FAN, num_segments + 2);
}

View file

@ -0,0 +1,155 @@
#include <string.h>
#include <math.h>
#include "sf2d_private.h"
//stolen from staplebutt
void GPU_SetDummyTexEnv(u8 num)
{
GPU_SetTexEnv(num,
GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0),
GPU_TEVSOURCES(GPU_PREVIOUS, 0, 0),
GPU_TEVOPERANDS(0,0,0),
GPU_TEVOPERANDS(0,0,0),
GPU_REPLACE,
GPU_REPLACE,
0xFFFFFFFF);
}
void vector_mult_matrix4x4(const float *msrc, const sf2d_vector_3f *vsrc, sf2d_vector_3f *vdst)
{
vdst->x = msrc[0*4 + 0]*vsrc->x + msrc[0*4 + 1]*vsrc->y + msrc[0*4 + 2]*vsrc->z + msrc[0*4 + 3];
vdst->y = msrc[1*4 + 0]*vsrc->x + msrc[1*4 + 1]*vsrc->y + msrc[1*4 + 2]*vsrc->z + msrc[1*4 + 3];
vdst->z = msrc[2*4 + 0]*vsrc->x + msrc[2*4 + 1]*vsrc->y + msrc[2*4 + 2]*vsrc->z + msrc[2*4 + 3];
}
void matrix_gpu_set_uniform(const float *m, u32 startreg)
{
float mu[4*4];
int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
mu[i*4 + j] = m[i*4 + (3-j)];
}
}
GPU_SetFloatUniform(GPU_VERTEX_SHADER, startreg, (u32 *)mu, 4);
}
void matrix_copy(float *dst, const float *src)
{
memcpy(dst, src, sizeof(float)*4*4);
}
void matrix_identity4x4(float *m)
{
m[0] = m[5] = m[10] = m[15] = 1.0f;
m[1] = m[2] = m[3] = 0.0f;
m[4] = m[6] = m[7] = 0.0f;
m[8] = m[9] = m[11] = 0.0f;
m[12] = m[13] = m[14] = 0.0f;
}
void matrix_mult4x4(const float *src1, const float *src2, float *dst)
{
int i, j, k;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
dst[i*4 + j] = 0.0f;
for (k = 0; k < 4; k++) {
dst[i*4 + j] += src1[i*4 + k]*src2[k*4 + j];
}
}
}
}
void matrix_set_z_rotation(float *m, float rad)
{
float c = cosf(rad);
float s = sinf(rad);
matrix_identity4x4(m);
m[0] = c;
m[1] = -s;
m[4] = s;
m[5] = c;
}
void matrix_rotate_z(float *m, float rad)
{
float mr[4*4], mt[4*4];
matrix_set_z_rotation(mr, rad);
matrix_mult4x4(mr, m, mt);
matrix_copy(m, mt);
}
void matrix_set_scaling(float *m, float x_scale, float y_scale, float z_scale)
{
matrix_identity4x4(m);
m[0] = x_scale;
m[5] = y_scale;
m[10] = z_scale;
}
void matrix_swap_xy(float *m)
{
float ms[4*4], mt[4*4];
matrix_identity4x4(ms);
ms[0] = 0.0f;
ms[1] = 1.0f;
ms[4] = 1.0f;
ms[5] = 0.0f;
matrix_mult4x4(ms, m, mt);
matrix_copy(m, mt);
}
void matrix_init_orthographic(float *m, float left, float right, float bottom, float top, float near, float far)
{
float mo[4*4], mp[4*4];
mo[0x0] = 2.0f/(right-left);
mo[0x1] = 0.0f;
mo[0x2] = 0.0f;
mo[0x3] = -(right+left)/(right-left);
mo[0x4] = 0.0f;
mo[0x5] = 2.0f/(top-bottom);
mo[0x6] = 0.0f;
mo[0x7] = -(top+bottom)/(top-bottom);
mo[0x8] = 0.0f;
mo[0x9] = 0.0f;
mo[0xA] = -2.0f/(far-near);
mo[0xB] = (far+near)/(far-near);
mo[0xC] = 0.0f;
mo[0xD] = 0.0f;
mo[0xE] = 0.0f;
mo[0xF] = 1.0f;
matrix_identity4x4(mp);
mp[0xA] = 0.5;
mp[0xB] = -0.5;
//Convert Z [-1, 1] to [-1, 0] (PICA shiz)
matrix_mult4x4(mp, mo, m);
// Rotate 180 degrees
matrix_rotate_z(m, M_PI);
// Swap X and Y axis
matrix_swap_xy(m);
}
//Grabbed from: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
unsigned int next_pow2(unsigned int v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return v+1;
}

View file

@ -0,0 +1,620 @@
#include <stdlib.h>
#include <string.h>
#include "sf2d.h"
#include "sf2d_private.h"
#define TEX_MIN_SIZE 8
static unsigned int nibbles_per_pixel(sf2d_texfmt format)
{
switch (format) {
case TEXFMT_RGBA8:
return 8;
case TEXFMT_RGB8:
return 6;
case TEXFMT_RGB5A1:
case TEXFMT_RGB565:
case TEXFMT_RGBA4:
case TEXFMT_IA8:
return 4;
case TEXFMT_A4:
return 1;
case TEXFMT_I8:
case TEXFMT_A8:
case TEXFMT_IA4:
default:
return 2;
}
}
static int calc_buffer_size(sf2d_texfmt pixel_format, int width, int height)
{
return width * height * (nibbles_per_pixel(pixel_format)>>1);
}
sf2d_texture *sf2d_create_texture(int width, int height, sf2d_texfmt pixel_format, sf2d_place place)
{
int pow2_w = next_pow2(width);
int pow2_h = next_pow2(height);
if (pow2_w < TEX_MIN_SIZE) pow2_w = TEX_MIN_SIZE;
if (pow2_h < TEX_MIN_SIZE) pow2_h = TEX_MIN_SIZE;
int data_size = calc_buffer_size(pixel_format, pow2_w, pow2_h);
void *data;
if (place == SF2D_PLACE_RAM) {
// If there's not enough linear heap space, return
if (linearSpaceFree() < data_size) {
return NULL;
}
data = linearMemAlign(data_size, 0x80);
} else if (place == SF2D_PLACE_VRAM) {
// If there's not enough VRAM heap space, return
if (vramSpaceFree() < data_size) {
return NULL;
}
data = vramMemAlign(data_size, 0x80);
} else if (place == SF2D_PLACE_TEMP) {
if (sf2d_pool_space_free() < data_size) {
return NULL;
}
data = sf2d_pool_memalign(data_size, 0x80);
} else {
//wot?
return NULL;
}
sf2d_texture *texture = malloc(sizeof(*texture));
texture->tiled = 0;
texture->place = place;
texture->pixel_format = pixel_format;
texture->width = width;
texture->height = height;
texture->pow2_w = pow2_w;
texture->pow2_h = pow2_h;
texture->data_size = data_size;
texture->data = data;
memset(texture->data, 0, texture->data_size);
return texture;
}
void sf2d_free_texture(sf2d_texture *texture)
{
if (texture) {
if (texture->place == SF2D_PLACE_RAM) {
linearFree(texture->data);
} else if (texture->place == SF2D_PLACE_VRAM) {
vramFree(texture->data);
}
free(texture);
}
}
void sf2d_fill_texture_from_RGBA8(sf2d_texture *dst, const void *rgba8, int source_w, int source_h)
{
// TODO: add support for non-RGBA8 textures
u8 *tmp = linearAlloc(dst->pow2_w * dst->pow2_h * 4);
int i, j;
for (i = 0; i < source_h; i++) {
for (j = 0; j < source_w; j++) {
((u32 *)tmp)[i*dst->pow2_w + j] = ((u32 *)rgba8)[i*source_w + j];
}
}
memcpy(dst->data, tmp, dst->pow2_w*dst->pow2_h*4);
linearFree(tmp);
sf2d_texture_tile32(dst);
}
sf2d_texture *sf2d_create_texture_mem_RGBA8(const void *src_buffer, int src_w, int src_h, sf2d_texfmt pixel_format, sf2d_place place)
{
sf2d_texture *tex = sf2d_create_texture(src_w, src_h, pixel_format, place);
if (tex == NULL) return NULL;
sf2d_fill_texture_from_RGBA8(tex, src_buffer, src_w, src_h);
return tex;
}
void sf2d_bind_texture(const sf2d_texture *texture, GPU_TEXUNIT unit)
{
GPU_SetTextureEnable(unit);
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, GPU_TEXTURE0),
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, GPU_TEXTURE0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetTexture(
unit,
(u32 *)osConvertVirtToPhys((u32)texture->data),
texture->pow2_w,
texture->pow2_h,
GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST),
texture->pixel_format
);
}
void sf2d_bind_texture_color(const sf2d_texture *texture, GPU_TEXUNIT unit, u32 color)
{
GPU_SetTextureEnable(unit);
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_CONSTANT),
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_CONSTANT, GPU_CONSTANT),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_MODULATE, GPU_MODULATE,
__builtin_bswap32(color) //RGBA8 -> ABGR8
);
GPU_SetTexture(
unit,
(u32 *)osConvertVirtToPhys((u32)texture->data),
texture->pow2_w,
texture->pow2_h,
GPU_TEXTURE_MAG_FILTER(GPU_NEAREST) | GPU_TEXTURE_MIN_FILTER(GPU_NEAREST),
texture->pixel_format
);
}
void sf2d_bind_texture_parameters(const sf2d_texture *texture, GPU_TEXUNIT unit, unsigned int params)
{
GPU_SetTextureEnable(unit);
GPU_SetTexEnv(
0,
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, GPU_TEXTURE0),
GPU_TEVSOURCES(GPU_TEXTURE0, GPU_TEXTURE0, GPU_TEXTURE0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_TEVOPERANDS(0, 0, 0),
GPU_REPLACE, GPU_REPLACE,
0xFFFFFFFF
);
GPU_SetTexture(
unit,
(u32 *)osConvertVirtToPhys((u32)texture->data),
texture->pow2_w,
texture->pow2_h,
params,
texture->pixel_format
);
}
void sf2d_draw_texture(const sf2d_texture *texture, int x, int y)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int w = texture->width;
int h = texture->height;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+w, (float)y+h, SF2D_DEFAULT_DEPTH};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_rotate(const sf2d_texture *texture, int x, int y, float rad)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int w2 = texture->width/2.0f;
int h2 = texture->height/2.0f;
vertices[0].position = (sf2d_vector_3f){(float)-w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float) w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)-w2, (float) h2, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float) w2, (float) h2, SF2D_DEFAULT_DEPTH};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
float m[4*4];
matrix_set_z_rotation(m, rad);
sf2d_vector_3f rot[4];
int i;
for (i = 0; i < 4; i++) {
vector_mult_matrix4x4(m, &vertices[i].position, &rot[i]);
vertices[i].position = (sf2d_vector_3f){rot[i].x + x + w2, rot[i].y + y + h2, rot[i].z};
}
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_part(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+tex_w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+tex_h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+tex_w, (float)y+tex_h, SF2D_DEFAULT_DEPTH};
float u0 = tex_x/(float)texture->pow2_w;
float v0 = tex_y/(float)texture->pow2_h;
float u1 = (tex_x+tex_w)/(float)texture->pow2_w;
float v1 = (tex_y+tex_h)/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){u0, v0};
vertices[1].texcoord = (sf2d_vector_2f){u1, v0};
vertices[2].texcoord = (sf2d_vector_2f){u0, v1};
vertices[3].texcoord = (sf2d_vector_2f){u1, v1};
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_scale(const sf2d_texture *texture, int x, int y, float x_scale, float y_scale)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int ws = texture->width * x_scale;
int hs = texture->height * y_scale;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+ws, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+hs, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+ws, (float)y+hs, SF2D_DEFAULT_DEPTH};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_rotate_cut_scale(const sf2d_texture *texture, int x, int y, float rad, int tex_x, int tex_y, int tex_w, int tex_h, float x_scale, float y_scale)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
//Don't even try to understand what I'm doing here (because I don't even understand it).
//Matrices are boring.
int w2 = (tex_w * x_scale)/2.0f;
int h2 = (tex_h * y_scale)/2.0f;
vertices[0].position = (sf2d_vector_3f){(float)-w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float) w2, (float)-h2, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)-w2, (float) h2, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float) w2, (float) h2, SF2D_DEFAULT_DEPTH};
float u0 = tex_x/(float)texture->pow2_w;
float v0 = tex_y/(float)texture->pow2_h;
float u1 = (tex_x+tex_w)/(float)texture->pow2_w;
float v1 = (tex_y+tex_h)/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){u0, v0};
vertices[1].texcoord = (sf2d_vector_2f){u1, v0};
vertices[2].texcoord = (sf2d_vector_2f){u0, v1};
vertices[3].texcoord = (sf2d_vector_2f){u1, v1};
float m[4*4];
matrix_set_z_rotation(m, rad);
sf2d_vector_3f rot[4];
int i;
for (i = 0; i < 4; i++) {
vector_mult_matrix4x4(m, &vertices[i].position, &rot[i]);
vertices[i].position = (sf2d_vector_3f){rot[i].x + x + w2, rot[i].y + y + h2, rot[i].z};
}
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_blend(const sf2d_texture *texture, int x, int y, u32 color)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int w = texture->width;
int h = texture->height;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+w, (float)y+h, SF2D_DEFAULT_DEPTH};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
sf2d_bind_texture_color(texture, GPU_TEXUNIT0, color);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_part_blend(const sf2d_texture *texture, int x, int y, int tex_x, int tex_y, int tex_w, int tex_h, u32 color)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){(float)x+tex_w, (float)y, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+tex_h, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){(float)x+tex_w, (float)y+tex_h, SF2D_DEFAULT_DEPTH};
float u0 = tex_x/(float)texture->pow2_w;
float v0 = tex_y/(float)texture->pow2_h;
float u1 = (tex_x+tex_w)/(float)texture->pow2_w;
float v1 = (tex_y+tex_h)/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){u0, v0};
vertices[1].texcoord = (sf2d_vector_2f){u1, v0};
vertices[2].texcoord = (sf2d_vector_2f){u0, v1};
vertices[3].texcoord = (sf2d_vector_2f){u1, v1};
sf2d_bind_texture_color(texture, GPU_TEXUNIT0, color);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_texture_depth(const sf2d_texture *texture, int x, int y, signed short z)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
int w = texture->width;
int h = texture->height;
float depth = z/32768.0f + 0.5f;
vertices[0].position = (sf2d_vector_3f){(float)x, (float)y, depth};
vertices[1].position = (sf2d_vector_3f){(float)x+w, (float)y, depth};
vertices[2].position = (sf2d_vector_3f){(float)x, (float)y+h, depth};
vertices[3].position = (sf2d_vector_3f){(float)x+w, (float)y+h, depth};
float u = texture->width/(float)texture->pow2_w;
float v = texture->height/(float)texture->pow2_h;
vertices[0].texcoord = (sf2d_vector_2f){0.0f, 0.0f};
vertices[1].texcoord = (sf2d_vector_2f){u, 0.0f};
vertices[2].texcoord = (sf2d_vector_2f){0.0f, v};
vertices[3].texcoord = (sf2d_vector_2f){u, v};
sf2d_bind_texture(texture, GPU_TEXUNIT0);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
void sf2d_draw_quad_uv(const sf2d_texture *texture, float left, float top, float right, float bottom, float u0, float v0, float u1, float v1, unsigned int params)
{
sf2d_vertex_pos_tex *vertices = sf2d_pool_malloc(4 * sizeof(sf2d_vertex_pos_tex));
if (!vertices) return;
vertices[0].position = (sf2d_vector_3f){left, top, SF2D_DEFAULT_DEPTH};
vertices[1].position = (sf2d_vector_3f){right, top, SF2D_DEFAULT_DEPTH};
vertices[2].position = (sf2d_vector_3f){left, bottom, SF2D_DEFAULT_DEPTH};
vertices[3].position = (sf2d_vector_3f){right, bottom, SF2D_DEFAULT_DEPTH};
vertices[0].texcoord = (sf2d_vector_2f){u0, v0};
vertices[1].texcoord = (sf2d_vector_2f){u1, v0};
vertices[2].texcoord = (sf2d_vector_2f){u0, v1};
vertices[3].texcoord = (sf2d_vector_2f){u1, v1};
sf2d_bind_texture_parameters(texture, GPU_TEXUNIT0, params);
GPU_SetAttributeBuffers(
2, // number of attributes
(u32*)osConvertVirtToPhys((u32)vertices),
GPU_ATTRIBFMT(0, 3, GPU_FLOAT) | GPU_ATTRIBFMT(1, 2, GPU_FLOAT),
0xFFFC, //0b1100
0x10,
1, //number of buffers
(u32[]){0x0}, // buffer offsets (placeholders)
(u64[]){0x10}, // attribute permutations for each buffer
(u8[]){2} // number of attributes for each buffer
);
GPU_DrawArray(GPU_TRIANGLE_STRIP, 4);
}
// Grabbed from Citra Emulator (citra/src/video_core/utils.h)
static inline u32 morton_interleave(u32 x, u32 y)
{
u32 i = (x & 7) | ((y & 7) << 8); // ---- -210
i = (i ^ (i << 2)) & 0x1313; // ---2 --10
i = (i ^ (i << 1)) & 0x1515; // ---2 -1-0
i = (i | (i >> 7)) & 0x3F;
return i;
}
//Grabbed from Citra Emulator (citra/src/video_core/utils.h)
static inline u32 get_morton_offset(u32 x, u32 y, u32 bytes_per_pixel)
{
u32 i = morton_interleave(x, y);
unsigned int offset = (x & ~7) * 8;
return (i + offset) * bytes_per_pixel;
}
void sf2d_set_pixel(sf2d_texture *texture, int x, int y, u32 new_color)
{
y = (texture->pow2_h - 1 - y);
if (texture->tiled) {
u32 coarse_y = y & ~7;
u32 offset = get_morton_offset(x, y, 4) + coarse_y * texture->pow2_w * 4;
*(u32 *)(texture->data + offset) = __builtin_bswap32(new_color);
} else {
((u32 *)texture->data)[x + y * texture->pow2_w] = __builtin_bswap32(new_color);
}
}
u32 sf2d_get_pixel(sf2d_texture *texture, int x, int y)
{
y = (texture->pow2_h - 1 - y);
if (texture->tiled) {
u32 coarse_y = y & ~7;
u32 offset = get_morton_offset(x, y, 4) + coarse_y * texture->pow2_w * 4;
return __builtin_bswap32(*(u32 *)(texture->data + offset));
} else {
return __builtin_bswap32(((u32 *)texture->data)[x + y * texture->pow2_w]);
}
}
void sf2d_texture_tile32(sf2d_texture *texture)
{
if (texture->tiled) return;
// TODO: add support for non-RGBA8 textures
u8 *tmp = linearAlloc(texture->pow2_w * texture->pow2_h * 4);
int i, j;
for (j = 0; j < texture->pow2_h; j++) {
for (i = 0; i < texture->pow2_w; i++) {
u32 coarse_y = j & ~7;
u32 dst_offset = get_morton_offset(i, j, 4) + coarse_y * texture->pow2_w * 4;
u32 v = ((u32 *)texture->data)[i + (texture->pow2_h - 1 - j)*texture->pow2_w];
*(u32 *)(tmp + dst_offset) = __builtin_bswap32(v);
}
}
memcpy(texture->data, tmp, texture->pow2_w*texture->pow2_h*4);
linearFree(tmp);
texture->tiled = 1;
}