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 <lua.h>
|
||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
|
|
||||||
|
#include "gfx.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
|
|
||||||
|
|
@ -27,6 +28,13 @@ typedef struct {
|
||||||
bool isGfxInitialized = false;
|
bool isGfxInitialized = false;
|
||||||
bool is3DEnabled = false; //TODO: add a function for this in the ctrulib/sf2dlib.
|
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.
|
The `ctr.gfx.color` module.
|
||||||
@table color
|
@table color
|
||||||
|
|
@ -385,17 +393,21 @@ Calls this function without argument to disable the scissor test.
|
||||||
*/
|
*/
|
||||||
static int gfx_scissor(lua_State *L) {
|
static int gfx_scissor(lua_State *L) {
|
||||||
if (lua_gettop(L) == 0) {
|
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 {
|
} else {
|
||||||
int x = luaL_checkinteger(L, 1);
|
lua_scissor.x = luaL_checkinteger(L, 1);
|
||||||
int y = luaL_checkinteger(L, 2);
|
lua_scissor.y = luaL_checkinteger(L, 2);
|
||||||
int width = luaL_checkinteger(L, 3);
|
lua_scissor.width = luaL_checkinteger(L, 3);
|
||||||
int height = luaL_checkinteger(L, 4);
|
lua_scissor.height = luaL_checkinteger(L, 4);
|
||||||
bool invert = lua_toboolean(L, 5);
|
lua_scissor.mode = lua_toboolean(L, 5) ? GPU_SCISSOR_INVERT : GPU_SCISSOR_NORMAL;
|
||||||
|
|
||||||
sf2d_set_scissor_test(invert ? GPU_SCISSOR_INVERT : GPU_SCISSOR_NORMAL, x, y, width, height);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sf2d_set_scissor_test(lua_scissor.mode, lua_scissor.x, lua_scissor.y, lua_scissor.width, lua_scissor.height);
|
||||||
|
|
||||||
return 0;
|
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
|
||||||
67
source/map.c
67
source/map.c
|
|
@ -13,7 +13,9 @@ Tile coordinates start at x=0,y=0.
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "gfx.h"
|
||||||
#include "texture.h"
|
#include "texture.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -60,6 +62,15 @@ static int map_load(lua_State *L) {
|
||||||
luaL_getmetatable(L, "LMap");
|
luaL_getmetatable(L, "LMap");
|
||||||
lua_setmetatable(L, -2);
|
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->texture = texture;
|
||||||
map->tileSizeX = tileSizeX;
|
map->tileSizeX = tileSizeX;
|
||||||
map->tileSizeY = tileSizeY;
|
map->tileSizeY = tileSizeY;
|
||||||
|
|
@ -158,50 +169,81 @@ Map object
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/***
|
/***
|
||||||
Draw a map.
|
Draw (a part of) the map on the screen.
|
||||||
@function :draw
|
@function :draw
|
||||||
@tparam number x X position
|
@tparam integer x X top-left coordinate to draw the map on the screen (pixels)
|
||||||
@tparam number y Y position
|
@tparam integer y Y top-left coordinate to draw the map on the screen (pixels)
|
||||||
@within Methods
|
@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) {
|
static int map_draw(lua_State *L) {
|
||||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
||||||
int x = luaL_checkinteger(L, 2);
|
int x = luaL_checkinteger(L, 2);
|
||||||
int y = luaL_checkinteger(L, 3);
|
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 texX = 0;
|
||||||
int texY = 0;
|
int texY = 0;
|
||||||
|
|
||||||
if (map->texture->blendColor == 0xffffffff) {
|
if (map->texture->blendColor == 0xffffffff) {
|
||||||
for (int xp=0; xp<map->width; xp++) {
|
for (int xp = xI; xp < xF; xp++) {
|
||||||
for (int yp=0; yp<map->height; yp++) {
|
for (int yp = yI; yp < yF; yp++) {
|
||||||
u16 tile = getTile(map, xp, yp);
|
u16 tile = getTile(map, xp, yp);
|
||||||
getTilePos(map, tile, &texX, &texY);
|
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 {
|
} else {
|
||||||
for (int xp=0; xp<map->width; xp++) {
|
for (int xp = xI; xp < xF; xp++) {
|
||||||
for (int yp=0; yp<map->height; yp++) {
|
for (int yp = yI; yp < yF; yp++) {
|
||||||
u16 tile = getTile(map, xp, yp);
|
u16 tile = getTile(map, xp, yp);
|
||||||
getTilePos(map, tile, &texX, &texY);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
Unload a map.
|
Unload a map.
|
||||||
@function :unload
|
@function :unload
|
||||||
@within Methods
|
|
||||||
*/
|
*/
|
||||||
static int map_unload(lua_State *L) {
|
static int map_unload(lua_State *L) {
|
||||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
||||||
|
|
||||||
free(map->data);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,7 +252,6 @@ Return the size of a map.
|
||||||
@function :getSize
|
@function :getSize
|
||||||
@treturn number width of the map, in tiles
|
@treturn number width of the map, in tiles
|
||||||
@treturn number height of the map, in tiles
|
@treturn number height of the map, in tiles
|
||||||
@within Methods
|
|
||||||
*/
|
*/
|
||||||
static int map_getSize(lua_State *L) {
|
static int map_getSize(lua_State *L) {
|
||||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
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 x X position of the tile (in tiles)
|
||||||
@tparam number y Y position of the tile (in tiles)
|
@tparam number y Y position of the tile (in tiles)
|
||||||
@treturn number value of the tile
|
@treturn number value of the tile
|
||||||
@within Methods
|
|
||||||
*/
|
*/
|
||||||
static int map_getTile(lua_State *L) {
|
static int map_getTile(lua_State *L) {
|
||||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
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 x X position of the tile (in tiles)
|
||||||
@tparam number y Y position of the tile (in tiles)
|
@tparam number y Y position of the tile (in tiles)
|
||||||
@tparam number value new value for the tile
|
@tparam number value new value for the tile
|
||||||
@within Methods
|
|
||||||
*/
|
*/
|
||||||
static int map_setTile(lua_State *L) {
|
static int map_setTile(lua_State *L) {
|
||||||
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
map_userdata *map = luaL_checkudata(L, 1, "LMap");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue