Pokitto-Raycasting/general.hpp
2018-09-08 15:53:11 +02:00

224 lines
4.7 KiB
C++

/**
General definitions for Pokitto raycasting demos.
author: Miloslav "drummyfish" Ciz
license: CC0 1.0
*/
#ifndef RAYCAST_DEMO_GENERAL_HPP
#define RAYCAST_DEMO_GENERAL_HPP
#include "stdio.h" // for debugging raycastlibg
#define VERTICAL_FOV UNITS_PER_SQUARE // redefine camera vertical FOV
#include "raycastlib.h"
#include "Pokitto.h"
Pokitto::Core pokitto;
#ifndef FPS
#define FPS 30
#endif
#ifndef PLAYER_SPEED
#define PLAYER_SPEED (2 * UNITS_PER_SQUARE)
#endif
#ifndef PLAYER_ROTATION_SPEED
#define PLAYER_ROTATION_SPEED (UNITS_PER_SQUARE / 2)
#endif
#ifndef GRAVITY_ACCELERATION
#define GRAVITY_ACCELERATION ((3 * UNITS_PER_SQUARE) / 2)
#endif
#define SCREEN_WIDTH 110
#define SCREEN_HEIGHT 88
#define MIDDLE_ROW (SCREEN_HEIGHT / 2)
#define MIDDLE_COLUMN (SCREEN_WIDTH / 2)
#ifndef SUBSAMPLE
#define SUBSAMPLE 2
#endif
#define SUBSAMPLED_WIDTH (SCREEN_WIDTH / SUBSAMPLE)
#define TRANSPARENT_COLOR 0b00000111
Unit zBuffer[SUBSAMPLED_WIDTH]; ///< 1D z-buffer for visibility determination.
unsigned short palette[256];
/**
Gets (the index of) color by specified RGB components.
@param r red, 3 bits (0 to 7)
@param g green, 3 bits (0 to 7)
@param b blue, 2 bits (0 to 3)
@return palette index of the color
*/
inline uint8_t rgbToIndex(uint8_t r, uint8_t g, uint8_t b)
{
return (r & 0b00000111) | ((g & 0b00000111) << 3) | ((b & 0b00000011) << 6);
}
/**
Inits and loads a general 256 color palette.
*/
void initPalette()
{
for (uint8_t r = 0; r < 8; ++r)
for (uint8_t g = 0; g < 8; ++g)
for (uint8_t b = 0; b < 4; ++b)
palette[rgbToIndex(r,g,b)] =
pokitto.display.RGBto565(36 * r, 36 * g, 85 * b);
pokitto.display.load565Palette(palette);
}
/**
Adds given intensity to a color.
@param color input color
@param intensity intensity to add, 3 bit (0 to 7)
@return new color
*/
inline uint8_t addIntensity(uint8_t color, int intensity)
{
uint8_t r = color & 0b00000111;
uint8_t g = (color & 0b00111000) >> 3;
uint8_t b = (color & 0b11000000) >> 6;
if (intensity >= 0)
{
r += intensity;
r = r > 7 ? 7 : r;
g += intensity;
g = g > 7 ? 7 : g;
b += intensity / 2;
b = b > 3 ? 3 : b;
}
else
{
intensity *= -1;
r = (intensity > r) ? 0 : r - intensity;
g = (intensity > g) ? 0 : g - intensity;
intensity /= 2;
b = intensity > b ? 0 : b - intensity;
}
return rgbToIndex(r,g,b);
}
/**
Samples an image by normalized coordinates - each coordinate is in range
0 to UNITS_PER_SQUARE (from raycastlib).
*/
inline uint8_t sampleImage(const unsigned char *image, Unit x, Unit y)
{
// TODO: optimize
x = wrap(x,UNITS_PER_SQUARE);
y = wrap(y,UNITS_PER_SQUARE);
int32_t index =
image[1] * ((image[1] * x) / UNITS_PER_SQUARE) + (image[0] * y) /
UNITS_PER_SQUARE;
return image[2 + index];
}
void inline drawSprite(const unsigned char *sprite, int16_t x, int16_t y, Unit depth, int16_t size)
{
// TODO: optimize
x -= size / 2;
y -= size / 2;
Unit step = UNITS_PER_SQUARE / size;
uint8_t c;
int16_t jTo = size - max(0,y + size - 88);
int16_t iTo = size - max(0,x + size - 110);
for (Unit i = max(-1 * x,0); i < iTo; ++i)
{
int16_t xPos = x + i;
if (zBuffer[xPos / SUBSAMPLE] <= depth)
continue;
for (Unit j = max(-1 * y,0); j < jTo; ++j)
{
c = sampleImage(sprite,(i * UNITS_PER_SQUARE) / size,(j * UNITS_PER_SQUARE) / size);
if (c != TRANSPARENT_COLOR)
pokitto.display.drawPixel(xPos,y + j,c);
}
}
}
class Player
{
public:
Camera mCamera;
Unit mVericalSpeed;
Player()
{
mCamera.position.x = 0;
mCamera.position.y = 0;
mCamera.direction = 0;
mCamera.height = UNITS_PER_SQUARE * 3;
mCamera.resolution.x = SCREEN_WIDTH / SUBSAMPLE;
mCamera.resolution.y = SCREEN_HEIGHT;
mCamera.shear = 0;
mVericalSpeed = 0;
}
void setPosition(Unit x, Unit y)
{
mCamera.position.x = x;
mCamera.position.y = y;
}
void setPositionSquare(int16_t squareX, int16_t squareY)
{
setPosition(
squareX * UNITS_PER_SQUARE + UNITS_PER_SQUARE / 2,
squareY * UNITS_PER_SQUARE + UNITS_PER_SQUARE / 2);
}
};
class Sprite
{
public:
Sprite(const unsigned char *image, int16_t squareX, int16_t squareY, Unit z,
Unit pixelSize):
mImage(image),
mPixelSize(pixelSize)
{
mPosition.x = squareX * UNITS_PER_SQUARE + UNITS_PER_SQUARE / 2;
mPosition.y = squareY * UNITS_PER_SQUARE + UNITS_PER_SQUARE / 2;
mHeight = z * UNITS_PER_SQUARE + UNITS_PER_SQUARE / 2;
}
Sprite():
mImage(0), mHeight(0), mPixelSize(1)
{
mPosition.x = 0;
mPosition.y = 0;
}
const unsigned char *mImage;
Vector2D mPosition;
Unit mHeight;
Unit mPixelSize;
};
#endif