159 lines
4.0 KiB
C
159 lines
4.0 KiB
C
#include "render.h"
|
|
#include <gint/display.h>
|
|
|
|
//---
|
|
// Camera management
|
|
//---
|
|
|
|
void camera_init(struct camera *c, struct map *m)
|
|
{
|
|
c->zoom = 1;
|
|
|
|
c->limits.x_min = fix(-CAMERA_BORDER);
|
|
c->limits.x_max = fix(m->width + CAMERA_BORDER);
|
|
c->limits.y_min = fix(-CAMERA_BORDER);
|
|
c->limits.y_max = fix(m->height + CAMERA_BORDER);
|
|
|
|
/* Fullscreen */
|
|
c->viewport.x_min = 0;
|
|
c->viewport.x_max = DWIDTH;
|
|
c->viewport.y_min = 0;
|
|
c->viewport.y_max = DHEIGHT;
|
|
|
|
c->width = fix(c->viewport.x_max - c->viewport.x_min) / TILE_WIDTH;
|
|
c->height = fix(c->viewport.y_max - c->viewport.y_min) / TILE_HEIGHT;
|
|
|
|
c->x = (c->limits.x_min + c->limits.x_max) / 2;
|
|
c->y = (c->limits.y_min + c->limits.y_max) / 2;
|
|
}
|
|
|
|
void camera_map2screen(struct camera *c, map_coord_t map_x, map_coord_t map_y,
|
|
int *screen_x, int *screen_y)
|
|
{
|
|
/* Start from center point */
|
|
int sx = DWIDTH / 2;
|
|
int sy = DHEIGHT / 2;
|
|
|
|
map_x -= c->x;
|
|
map_y -= c->y;
|
|
|
|
sx += fround(map_x * TILE_WIDTH * c->zoom);
|
|
sy += fround(map_y * TILE_HEIGHT * c->zoom);
|
|
|
|
if(screen_x) *screen_x = sx;
|
|
if(screen_y) *screen_y = sy;
|
|
}
|
|
|
|
/* Translate screen coordinates to map coordinates */
|
|
void camera_screen2map(struct camera *c, int screen_x, int screen_y,
|
|
map_coord_t *map_x, map_coord_t *map_y)
|
|
{
|
|
/* Start from center point */
|
|
map_coord_t mx = c->x;
|
|
map_coord_t my = c->y;
|
|
|
|
screen_x -= DWIDTH / 2;
|
|
screen_y -= DHEIGHT / 2;
|
|
|
|
mx += fix(screen_x) / TILE_WIDTH / c->zoom;
|
|
my += fix(screen_y) / TILE_HEIGHT / c->zoom;
|
|
|
|
if(map_x) *map_x = mx;
|
|
if(map_y) *map_y = my;
|
|
}
|
|
|
|
/* Lock the camera at the center if set by settings. */
|
|
static bool camera_lock(struct camera *c)
|
|
{
|
|
if(c->zoom == 1 && CAMERA_LOCK_AT_x1)
|
|
{
|
|
c->x = (c->limits.x_min + c->limits.x_max) / 2;
|
|
c->y = (c->limits.y_min + c->limits.y_max) / 2;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/* Bound the camera to the map limits */
|
|
static void camera_bound(struct camera *c)
|
|
{
|
|
/* Project viewport onto the map */
|
|
map_coord_t vx_min, vx_max;
|
|
map_coord_t vy_min, vy_max;
|
|
camera_screen2map(c,c->viewport.x_min,c->viewport.y_min,&vx_min,&vy_min);
|
|
camera_screen2map(c,c->viewport.x_max,c->viewport.y_max,&vx_max,&vy_max);
|
|
|
|
/* Bound viewport to map limits */
|
|
if(vx_min < c->limits.x_min)
|
|
c->x += (c->limits.x_min - vx_min);
|
|
else if(vx_max > c->limits.x_max)
|
|
c->x += (c->limits.x_max - vx_max);
|
|
if(vy_min < c->limits.y_min)
|
|
c->y += (c->limits.y_min - vy_min);
|
|
else if(vy_max > c->limits.y_max)
|
|
c->y += (c->limits.y_max - vy_max);
|
|
}
|
|
|
|
void camera_move(struct camera *c, map_coord_t dx, map_coord_t dy)
|
|
{
|
|
if(camera_lock(c)) return;
|
|
c->x += dx;
|
|
c->y += dy;
|
|
camera_bound(c);
|
|
}
|
|
|
|
void camera_zoom(struct camera *c, int zoom)
|
|
{
|
|
if(zoom < ZOOM_MIN) zoom = ZOOM_MIN;
|
|
if(zoom > ZOOM_MAX) zoom = ZOOM_MAX;
|
|
|
|
c->zoom = zoom;
|
|
if(camera_lock(c)) return;
|
|
camera_bound(c);
|
|
}
|
|
|
|
//---
|
|
// Rendering
|
|
//---
|
|
|
|
static uint16_t darker2(uint16_t color)
|
|
{
|
|
return (color & 0xf7de) >> 1;
|
|
}
|
|
|
|
static uint16_t darker1(uint16_t color)
|
|
{
|
|
int r = (color >> 11);
|
|
int g = (color >> 6) & 0x1f;
|
|
int b = color & 0x1f;
|
|
|
|
return C_RGB(2*r/3, 2*g/3, 2*b/3);
|
|
}
|
|
|
|
void render_map(struct map *m, struct camera *c)
|
|
{
|
|
for(int row = 0; row < m->height; row++)
|
|
for(int col = 0; col < m->width; col++) {
|
|
struct tile *t = map_tile(m, col, row);
|
|
if(!t) continue;
|
|
|
|
int x, y;
|
|
camera_map2screen(c, fix(col), fix(row), &x, &y);
|
|
|
|
/* TODO: render_map: use images */
|
|
uint16_t color_ground = darker1(t->color);
|
|
uint16_t color_wall = darker2(darker2(t->color));
|
|
|
|
int tile_w = c->zoom * TILE_WIDTH;
|
|
int tile_h = c->zoom * TILE_HEIGHT;
|
|
int wall_h = c->zoom * WALL_HEIGHT;
|
|
|
|
drect(x, y, x+tile_w-1, y+tile_h-1, color_ground);
|
|
|
|
struct tile *above = map_tile(m, col, row-1);
|
|
if(above && !t->solid && above->solid) {
|
|
drect(x, y-wall_h, x+tile_w-1, y-1, color_wall);
|
|
}
|
|
}
|
|
}
|