Skip to content

Commit

Permalink
Improved map:draw a lot, fixed GC issues with ctr.map, changed some t…
Browse files Browse the repository at this point in the history
…hings internally

map:draw should be faster and more flexible.
  • Loading branch information
Reuh committed Apr 22, 2016
1 parent 358b68c commit 4d1e3ec
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 25 deletions.
28 changes: 20 additions & 8 deletions source/gfx.c
Expand Up @@ -17,6 +17,7 @@ The `gfx` module.
#include <lua.h>
#include <lauxlib.h>

#include "gfx.h"
#include "font.h"
#include "texture.h"

Expand All @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
12 changes: 12 additions & 0 deletions source/gfx.h
@@ -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 changes: 56 additions & 17 deletions source/map.c
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand All @@ -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");
Expand All @@ -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");
Expand All @@ -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");
Expand Down

0 comments on commit 4d1e3ec

Please sign in to comment.