mirror of
https://github.com/ctruLua/ctruLua.git
synced 2025-10-27 16:39:29 +00:00
Improved map:draw a lot, fixed GC issues with ctr.map, changed some things internally
map:draw should be faster and more flexible.
This commit is contained in:
parent
358b68c643
commit
4d1e3ec455
3 changed files with 88 additions and 25 deletions
28
source/gfx.c
28
source/gfx.c
|
|
@ -17,6 +17,7 @@ The `gfx` module.
|
|||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include "gfx.h"
|
||||
#include "font.h"
|
||||
#include "texture.h"
|
||||
|
||||
|
|
@ -27,6 +28,13 @@ typedef struct {
|
|||
bool isGfxInitialized = false;
|
||||
bool is3DEnabled = false; //TODO: add a function for this in the ctrulib/sf2dlib.
|
||||
|
||||
// The scissor-test state, as defined in Lua code. When you apply a new scissor in C, remember to get back to this state to avoid unexpected behaviour.
|
||||
scissor_state lua_scissor = {
|
||||
GPU_SCISSOR_DISABLE,
|
||||
0, 0,
|
||||
0, 0
|
||||
};
|
||||
|
||||
/***
|
||||
The `ctr.gfx.color` module.
|
||||
@table color
|
||||
|
|
@ -385,17 +393,21 @@ Calls this function without argument to disable the scissor test.
|
|||
*/
|
||||
static int gfx_scissor(lua_State *L) {
|
||||
if (lua_gettop(L) == 0) {
|
||||
sf2d_set_scissor_test(GPU_SCISSOR_DISABLE, 0, 0, 0, 0);
|
||||
lua_scissor.mode = GPU_SCISSOR_DISABLE;
|
||||
lua_scissor.x = 0;
|
||||
lua_scissor.y = 0;
|
||||
lua_scissor.width = 0;
|
||||
lua_scissor.height = 0;
|
||||
} else {
|
||||
int x = luaL_checkinteger(L, 1);
|
||||
int y = luaL_checkinteger(L, 2);
|
||||
int width = luaL_checkinteger(L, 3);
|
||||
int height = luaL_checkinteger(L, 4);
|
||||
bool invert = lua_toboolean(L, 5);
|
||||
|
||||
sf2d_set_scissor_test(invert ? GPU_SCISSOR_INVERT : GPU_SCISSOR_NORMAL, x, y, width, height);
|
||||
lua_scissor.x = luaL_checkinteger(L, 1);
|
||||
lua_scissor.y = luaL_checkinteger(L, 2);
|
||||
lua_scissor.width = luaL_checkinteger(L, 3);
|
||||
lua_scissor.height = luaL_checkinteger(L, 4);
|
||||
lua_scissor.mode = lua_toboolean(L, 5) ? GPU_SCISSOR_INVERT : GPU_SCISSOR_NORMAL;
|
||||
}
|
||||
|
||||
sf2d_set_scissor_test(lua_scissor.mode, lua_scissor.x, lua_scissor.y, lua_scissor.width, lua_scissor.height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
12
source/gfx.h
Normal file
12
source/gfx.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef GFX_H
|
||||
#define GFX_H
|
||||
|
||||
typedef struct {
|
||||
GPU_SCISSORMODE mode;
|
||||
u32 x; u32 y;
|
||||
u32 width; u32 height;
|
||||
} scissor_state;
|
||||
|
||||
extern scissor_state lua_scissor;
|
||||
|
||||
#endif
|
||||
73
source/map.c
73
source/map.c
|
|
@ -13,7 +13,9 @@ Tile coordinates start at x=0,y=0.
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "gfx.h"
|
||||
#include "texture.h"
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -59,7 +61,16 @@ static int map_load(lua_State *L) {
|
|||
map_userdata *map = lua_newuserdata(L, sizeof(map_userdata));
|
||||
luaL_getmetatable(L, "LMap");
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
|
||||
// Block GC of the texture by keeping a reference to it in the registry
|
||||
// registry[map_userdata] = texture_userdata
|
||||
lua_pushnil(L);
|
||||
lua_copy(L, -2, -1); // map_userdata
|
||||
lua_pushnil(L);
|
||||
lua_copy(L, 2, -1); // texture_userdata
|
||||
lua_settable(L, LUA_REGISTRYINDEX);
|
||||
|
||||
// Init userdata fields
|
||||
map->texture = texture;
|
||||
map->tileSizeX = tileSizeX;
|
||||
map->tileSizeY = tileSizeY;
|
||||
|
|
@ -158,50 +169,81 @@ Map object
|
|||
*/
|
||||
|
||||
/***
|
||||
Draw a map.
|
||||
Draw (a part of) the map on the screen.
|
||||
@function :draw
|
||||
@tparam number x X position
|
||||
@tparam number y Y position
|
||||
@within Methods
|
||||
@tparam integer x X top-left coordinate to draw the map on the screen (pixels)
|
||||
@tparam integer y Y top-left coordinate to draw the map on the screen (pixels)
|
||||
@tparam[opt=0] integer offsetX drawn area X start coordinate on the map (pixels) (x=0,y=0 correspond to the first tile top-left corner)
|
||||
@tparam[opt=0] integer offsetY drawn area Y start coordinate on the map (pixels)
|
||||
@tparam[opt=400] integer width width of the drawn area on the map (pixels)
|
||||
@tparam[opt=240] integer height height of the drawn area on the map (pixels)
|
||||
@usage
|
||||
-- This will draw on the screen at x=5,y=5 a part of the map. The part is the rectangle on the map starting at x=16,y=16 and width=32,height=48.
|
||||
-- For example, if you use 16x16 pixel tiles, this will draw the tiles from 1,1 (top-left corner of the rectangle) to 2,3 (bottom-right corner).
|
||||
map:draw(5, 5, 16, 16, 32, 48)
|
||||
*/
|
||||
static int map_draw(lua_State *L) {
|
||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
||||
int x = luaL_checkinteger(L, 2);
|
||||
int y = luaL_checkinteger(L, 3);
|
||||
int offsetX = luaL_optinteger(L, 4, 0);
|
||||
int offsetY = luaL_optinteger(L, 5, 0);
|
||||
int width = luaL_optinteger(L, 6, 400);
|
||||
int height = luaL_optinteger(L, 7, 240);
|
||||
|
||||
int xI = fmax(floor((double)offsetX / map->tileSizeX), 0); // initial tile X
|
||||
int xF = fmin(ceil((double)(offsetX + width) / map->tileSizeX), map->width); // final tile X
|
||||
|
||||
int yI = fmax(floor((double)offsetY / map->tileSizeY), 0); // initial tile Y
|
||||
int yF = fmin(ceil((double)(offsetY + height) / map->tileSizeY), map->height); // final tile Y
|
||||
|
||||
if (sf2d_get_current_screen() == GFX_TOP)
|
||||
sf2d_set_scissor_test(GPU_SCISSOR_NORMAL, x, y, fmin(width, 400 - x), fmin(height, 240 - y)); // Scissor test doesn't work when x/y + width > screenWidth/Height
|
||||
else
|
||||
sf2d_set_scissor_test(GPU_SCISSOR_NORMAL, x, y, fmin(width, 320 - x), fmin(height, 240 - y));
|
||||
|
||||
int texX = 0;
|
||||
int texY = 0;
|
||||
|
||||
|
||||
if (map->texture->blendColor == 0xffffffff) {
|
||||
for (int xp=0; xp<map->width; xp++) {
|
||||
for (int yp=0; yp<map->height; yp++) {
|
||||
for (int xp = xI; xp < xF; xp++) {
|
||||
for (int yp = yI; yp < yF; yp++) {
|
||||
u16 tile = getTile(map, xp, yp);
|
||||
getTilePos(map, tile, &texX, &texY);
|
||||
sf2d_draw_texture_part(map->texture->texture, (x+(map->tileSizeX*xp)+(xp*map->spaceX)), (y+(map->tileSizeY*yp)+(yp*map->spaceY)), texX, texY, map->tileSizeX, map->tileSizeY);
|
||||
sf2d_draw_texture_part(map->texture->texture, x+(map->tileSizeX*xp)+(xp*map->spaceX)-offsetX, y+(map->tileSizeY*yp)+(yp*map->spaceY)-offsetY, texX, texY, map->tileSizeX, map->tileSizeY);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int xp=0; xp<map->width; xp++) {
|
||||
for (int yp=0; yp<map->height; yp++) {
|
||||
for (int xp = xI; xp < xF; xp++) {
|
||||
for (int yp = yI; yp < yF; yp++) {
|
||||
u16 tile = getTile(map, xp, yp);
|
||||
getTilePos(map, tile, &texX, &texY);
|
||||
sf2d_draw_texture_part_blend(map->texture->texture, (x+(map->tileSizeX*xp)+(xp*map->spaceX)), (y+(map->tileSizeY*yp)+(yp*map->spaceY)), texX, texY, map->tileSizeX, map->tileSizeY, map->texture->blendColor);
|
||||
sf2d_draw_texture_part_blend(map->texture->texture, x+(map->tileSizeX*xp)+(xp*map->spaceX)-offsetX, y+(map->tileSizeY*yp)+(yp*map->spaceY)-offsetY, texX, texY, map->tileSizeX, map->tileSizeY, map->texture->blendColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sf2d_set_scissor_test(lua_scissor.mode, lua_scissor.x, lua_scissor.y, lua_scissor.width, lua_scissor.height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***
|
||||
Unload a map.
|
||||
@function :unload
|
||||
@within Methods
|
||||
*/
|
||||
static int map_unload(lua_State *L) {
|
||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
||||
|
||||
free(map->data);
|
||||
|
||||
// Remove the reference to the texture in the registry
|
||||
// registry[map_userdata] = nil
|
||||
lua_pushnil(L);
|
||||
lua_copy(L, 1, -1); // map_userdata
|
||||
lua_pushnil(L);
|
||||
lua_settable(L, LUA_REGISTRYINDEX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +252,6 @@ Return the size of a map.
|
|||
@function :getSize
|
||||
@treturn number width of the map, in tiles
|
||||
@treturn number height of the map, in tiles
|
||||
@within Methods
|
||||
*/
|
||||
static int map_getSize(lua_State *L) {
|
||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
||||
|
|
@ -227,7 +268,6 @@ Return the value of a tile.
|
|||
@tparam number x X position of the tile (in tiles)
|
||||
@tparam number y Y position of the tile (in tiles)
|
||||
@treturn number value of the tile
|
||||
@within Methods
|
||||
*/
|
||||
static int map_getTile(lua_State *L) {
|
||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
||||
|
|
@ -245,7 +285,6 @@ Set the value of a tile.
|
|||
@tparam number x X position of the tile (in tiles)
|
||||
@tparam number y Y position of the tile (in tiles)
|
||||
@tparam number value new value for the tile
|
||||
@within Methods
|
||||
*/
|
||||
static int map_setTile(lua_State *L) {
|
||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue