370 lines
12 KiB
C++
370 lines
12 KiB
C++
/**
|
|
WIP raycasting demo for Pokitto.
|
|
|
|
Don't forget to compile with -O3!
|
|
|
|
author: Miloslav "drummyfish" Ciz
|
|
license: CC0
|
|
*/
|
|
|
|
//#define RAYCAST_TINY
|
|
|
|
#include <stdio.h>
|
|
#include "raycastlib.h"
|
|
#include "Pokitto.h"
|
|
#include <stdlib.h>
|
|
|
|
#define SUBSAMPLE 2
|
|
|
|
const unsigned char image[] =
|
|
{ 32, 32 // width, height
|
|
,0x12,0x12,0x12,0x12,0x12,0x12,0x00,0x09,0x00,0x12,0x12,0x12,0x12,0x12
|
|
,0x09,0x00,0x12,0x12,0x12,0x00,0x12,0x00,0x12,0x12,0x12,0x00,0x12,0x00
|
|
,0x12,0x12,0x09,0x00,0x65,0x5b,0x24,0x24,0x64,0x65,0x64,0x5b,0x09,0x64
|
|
,0x64,0x6d,0x6d,0x63,0x5b,0x00,0x24,0x64,0x64,0x64,0x64,0x64,0x6d,0x63
|
|
,0x64,0x65,0x6d,0x64,0x64,0x64,0x5b,0x00,0x65,0x5b,0x5b,0x5b,0x5b,0x5c
|
|
,0x52,0x09,0x00,0x64,0x5b,0x5b,0x5b,0x5b,0x11,0x00,0x64,0x64,0x52,0x64
|
|
,0x5b,0x63,0x5b,0x5b,0x5a,0x52,0x5b,0x5b,0x52,0x5b,0x12,0x09,0x6d,0x5b
|
|
,0x5b,0x5b,0x52,0x52,0x52,0x09,0x00,0x6d,0x64,0x52,0x5b,0x5a,0x08,0x00
|
|
,0x65,0x5b,0x5c,0x5b,0x64,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x5b,0x52
|
|
,0x52,0x09,0x24,0x52,0x5b,0x52,0x09,0x5a,0x52,0x09,0x00,0x24,0x12,0x5a
|
|
,0x12,0x09,0x09,0x00,0x24,0x5b,0x5b,0x52,0x52,0x5b,0x5b,0x5b,0x52,0x5b
|
|
,0x5b,0x52,0x5b,0x5b,0x52,0x12,0x64,0x5b,0x5b,0x5a,0x11,0x5b,0x52,0x09
|
|
,0x00,0x5b,0x12,0x12,0x11,0x5b,0x09,0x00,0x64,0x5b,0x64,0x5b,0x5b,0x52
|
|
,0x5b,0x5b,0x5b,0x52,0x5b,0x5a,0x5b,0x5b,0x09,0x00,0x5b,0x5b,0x09,0x12
|
|
,0x12,0x51,0x5b,0x09,0x00,0x5b,0x12,0x09,0x12,0x11,0x09,0x12,0x64,0x64
|
|
,0x5b,0x5b,0x52,0x52,0x5b,0x52,0x5b,0x11,0x5a,0x5b,0x5b,0x52,0x09,0x12
|
|
,0x12,0x52,0x11,0x09,0x09,0x09,0x09,0x09,0x00,0x09,0x08,0x09,0x09,0x08
|
|
,0x08,0x00,0x5b,0x52,0x51,0x09,0x49,0x09,0x09,0x08,0x08,0x09,0x11,0x09
|
|
,0x09,0x09,0x09,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x00
|
|
,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x12,0x00,0x12,0x00,0x00
|
|
,0x00,0x09,0x00,0x12,0x12,0x00,0x00,0x00,0x64,0x64,0x64,0x5b,0x12,0x64
|
|
,0x6d,0x65,0x5b,0x5b,0x00,0x65,0x65,0x65,0x64,0x5b,0x5b,0x6d,0x6d,0x65
|
|
,0x64,0x64,0x64,0x5c,0x5b,0x00,0x6d,0x6d,0x6d,0x5b,0x6d,0x64,0x5b,0x64
|
|
,0x5b,0x52,0x00,0x6d,0x5b,0x5b,0x64,0x5a,0x00,0x64,0x5b,0x5b,0x64,0x5b
|
|
,0x5b,0x5b,0x5b,0x64,0x5b,0x5b,0x11,0x52,0x52,0x00,0x6d,0x64,0x12,0x5b
|
|
,0x5b,0x52,0x5b,0x52,0x5b,0x09,0x12,0x6d,0x5b,0x5b,0x5b,0x52,0x12,0x6d
|
|
,0x64,0x5b,0x5b,0x5b,0x52,0x52,0x52,0x5b,0x52,0x5b,0x5a,0x5b,0x09,0x00
|
|
,0x24,0x5a,0x5b,0x52,0x52,0x5b,0x12,0x52,0x5a,0x12,0x00,0x5c,0x52,0x5b
|
|
,0x09,0x52,0x09,0x6d,0x5b,0x52,0x5b,0x52,0x5b,0x5b,0x5b,0x52,0x52,0x52
|
|
,0x52,0x5b,0x09,0x00,0x64,0x5b,0x12,0x11,0x52,0x52,0x51,0x52,0x09,0x09
|
|
,0x00,0x65,0x5b,0x52,0x5b,0x09,0x00,0x64,0x5b,0x5b,0x5b,0x52,0x5b,0x52
|
|
,0x52,0x5b,0x5b,0x11,0x5b,0x52,0x09,0x12,0x64,0x5b,0x52,0x5b,0x12,0x5b
|
|
,0x12,0x5b,0x09,0x09,0x00,0x64,0x51,0x5b,0x52,0x08,0x09,0x64,0x5b,0x52
|
|
,0x5b,0x5b,0x52,0x52,0x11,0x52,0x51,0x5b,0x52,0x52,0x09,0x00,0x5b,0x5b
|
|
,0x5b,0x12,0x12,0x52,0x09,0x00,0x08,0x09,0x08,0x09,0x09,0x09,0x09,0x09
|
|
,0x00,0x5b,0x52,0x52,0x09,0x09,0x09,0x08,0x09,0x09,0x09,0x09,0x09,0x08
|
|
,0x09,0x08,0x5b,0x5b,0x52,0x09,0x09,0x09,0x00,0x09,0x00,0x00,0x09,0x00
|
|
,0x00,0x00,0x09,0x12,0x12,0x00,0x00,0x00,0x00,0x12,0x00,0x00,0x00,0x12
|
|
,0x09,0x00,0x00,0x08,0x09,0x00,0x00,0x00,0x09,0x08,0x08,0x09,0x6d,0x6d
|
|
,0x5b,0x24,0x64,0x24,0x1b,0x64,0x5b,0x5b,0x24,0x5a,0x00,0x65,0x5b,0x65
|
|
,0x64,0x5b,0x64,0x64,0x5b,0x00,0x5b,0x5b,0x24,0x5b,0x5a,0x5a,0x5a,0x5b
|
|
,0x11,0x00,0x6d,0x5b,0x5b,0x5a,0x5b,0x64,0x5b,0x12,0x11,0x52,0x5a,0x08
|
|
,0x12,0x6d,0x5b,0x5b,0x5b,0x5b,0x5a,0x64,0x09,0x00,0x5a,0x52,0x52,0x52
|
|
,0x12,0x11,0x09,0x5a,0x00,0x00,0x6d,0x5a,0x5b,0x5a,0x51,0x5b,0x12,0x63
|
|
,0x52,0x11,0x52,0x08,0x12,0x64,0x5b,0x5b,0x5b,0x52,0x64,0x64,0x09,0x00
|
|
,0x63,0x51,0x09,0x51,0x52,0x52,0x51,0x09,0x49,0x00,0x24,0x5b,0x5a,0x5b
|
|
,0x12,0x09,0x12,0x5b,0x09,0x5a,0x12,0x09,0x12,0x65,0x5b,0x5b,0x12,0x52
|
|
,0x5b,0x52,0x09,0x00,0x5a,0x09,0x12,0x09,0x12,0x09,0x09,0x51,0x09,0x00
|
|
,0x5b,0x5b,0x64,0x51,0x11,0x12,0x12,0x12,0x12,0x11,0x12,0x09,0x09,0x64
|
|
,0x5b,0x52,0x52,0x5b,0x52,0x09,0x08,0x00,0x23,0x52,0x09,0x09,0x09,0x12
|
|
,0x09,0x52,0x00,0x09,0x5b,0x5a,0x12,0x12,0x12,0x11,0x12,0x5b,0x09,0x12
|
|
,0x12,0x08,0x00,0x64,0x52,0x5b,0x5a,0x52,0x5b,0x5c,0x09,0x00,0x12,0x5a
|
|
,0x52,0x09,0x12,0x09,0x09,0x12,0x09,0x00,0x52,0x51,0x51,0x08,0x08,0x00
|
|
,0x09,0x09,0x08,0x08,0x08,0x09,0x00,0x5b,0x52,0x09,0x09,0x09,0x08,0x08
|
|
,0x12,0x09,0x00,0x09,0x08,0x09,0x08,0x09,0x09,0x08,0x00,0x00,0x12,0x12
|
|
,0x00,0x09,0x09,0x09,0x12,0x00,0x00,0x08,0x12,0x00,0x00,0x00,0x00,0x00
|
|
,0x12,0x00,0x00,0x00,0x00,0x12,0x12,0x00,0x00,0x00,0x00,0x09,0x09,0x00
|
|
,0x00,0x00,0x5b,0x64,0x64,0x25,0x64,0x64,0x5b,0x00,0x1b,0x1b,0x1b,0x5b
|
|
,0x5a,0x5b,0x64,0x63,0x24,0x1b,0x11,0x00,0x6d,0x6d,0x6d,0x6d,0x5b,0x64
|
|
,0x5b,0x00,0x5c,0x5b,0x6d,0x64,0x52,0x5b,0x5b,0x5b,0x5a,0x5b,0x11,0x00
|
|
,0x1b,0x52,0x12,0x5a,0x52,0x12,0x51,0x5a,0x52,0x52,0x09,0x00,0x24,0x64
|
|
,0x5b,0x52,0x5a,0x5b,0x12,0x00,0x64,0x5b,0x12,0x52,0x5b,0x52,0x52,0x52
|
|
,0x5b,0x52,0x09,0x00,0x23,0x52,0x5a,0x11,0x52,0x09,0x52,0x51,0x52,0x51
|
|
,0x49,0x00,0x6d,0x5b,0x11,0x11,0x52,0x52,0x09,0x00,0x6d,0x11,0x5b,0x5b
|
|
,0x12,0x5b,0x52,0x5b,0x12,0x52,0x11,0x00,0x1b,0x5b,0x49,0x51,0x09,0x11
|
|
,0x52,0x51,0x09,0x5a,0x08,0x00,0x24,0x52,0x5b,0x52,0x12,0x52,0x09,0x00
|
|
,0x1b,0x5b,0x52,0x5b,0x5b,0x52,0x11,0x52,0x12,0x12,0x09,0x09,0x5a,0x5a
|
|
,0x5a,0x51,0x52,0x09,0x52,0x51,0x52,0x52,0x09,0x00,0x64,0x64,0x64,0x5b
|
|
,0x5b,0x09,0x09,0x12,0x24,0x5b,0x5b,0x52,0x52,0x5b,0x09,0x11,0x09,0x12
|
|
,0x09,0x00,0x5b,0x09,0x52,0x5a,0x09,0x09,0x09,0x5a,0x52,0x09,0x00,0x00
|
|
,0x64,0x5b,0x64,0x52,0x5b,0x5b,0x08,0x12,0x64,0x5b,0x52,0x52,0x09,0x08
|
|
,0x09,0x09,0x09,0x08,0x09,0x00,0x11,0x09,0x09,0x09,0x09,0x09,0x00,0x08
|
|
,0x08,0x09,0x09,0x00,0x5b,0x52,0x52,0x09,0x09,0x09,0x09,0x12,0x08,0x08
|
|
,0x09,0x09
|
|
};
|
|
|
|
uint8_t sampleImage(const unsigned char *image, Unit x, Unit y)
|
|
{
|
|
int32_t index = clamp(
|
|
image[1] * ((image[1] * y) / UNITS_PER_SQUARE) +
|
|
(image[0] * x) / UNITS_PER_SQUARE,
|
|
0, image[0] * image[1] - 1);
|
|
|
|
return image[2 + index];
|
|
}
|
|
|
|
// r: 3 bits, g: 3 bits, b: 2 bits
|
|
inline uint8_t rgbToIndex(uint8_t r, uint8_t g, uint8_t b)
|
|
{
|
|
return (r & 0b00000111) | ((g & 0b00000111) << 3) | ((b & 0b00000011) << 6);
|
|
}
|
|
|
|
inline uint8_t darkenColor(uint8_t color, uint8_t intensity)
|
|
{
|
|
uint8_t r = color & 0b00000111;
|
|
uint8_t g = (color & 0b00111000) >> 3;
|
|
uint8_t b = (color & 0b11000000) >> 6;
|
|
|
|
r += intensity;
|
|
r = r > 7 ? 7 : r;
|
|
|
|
g += intensity;
|
|
g = g > 7 ? 7 : g;
|
|
|
|
b += intensity / 2;
|
|
b = b > 3 ? 3 : b;
|
|
|
|
return rgbToIndex(r,g,b);
|
|
}
|
|
|
|
class Level
|
|
{
|
|
public:
|
|
int16_t getHeight(int16_t x, int16_t y)
|
|
{
|
|
if (x > 12 || y > 12)
|
|
return max(x,y) - 10;
|
|
|
|
if (y < 5 && y > 0)
|
|
{
|
|
return y > 2 ? x : -x;
|
|
}
|
|
|
|
return (x < 0 || y < 0 || x > 9 || y > 9) ? 4 : 0;
|
|
}
|
|
};
|
|
|
|
class Character
|
|
{
|
|
public:
|
|
Camera mCamera;
|
|
|
|
Character()
|
|
{
|
|
mCamera.position.x = 14337; // UNITS_PER_SQUARE * 4;
|
|
mCamera.position.y = 7963; //UNITS_PER_SQUARE * 5;
|
|
mCamera.direction = -340; //0;
|
|
mCamera.fovAngle = UNITS_PER_SQUARE / 4;
|
|
mCamera.height = 2756; //UNITS_PER_SQUARE / 2;
|
|
mCamera.resolution.x = 110 / SUBSAMPLE;
|
|
mCamera.resolution.y = 88;
|
|
}
|
|
};
|
|
|
|
Pokitto::Core p;
|
|
Character player;
|
|
Level level;
|
|
|
|
Unit heightFunc(int16_t x, int16_t y)
|
|
{
|
|
return level.getHeight(x,y) * UNITS_PER_SQUARE / 4;
|
|
}
|
|
|
|
bool dither(uint8_t intensity, uint32_t x, uint32_t y)
|
|
{
|
|
switch (intensity)
|
|
{
|
|
case 0: return false; break;
|
|
case 1: return x % 2 == 0 && y % 2 == 0; break;
|
|
case 2: return x % 2 == y % 2; break;
|
|
case 3: return x % 2 != 0 || y % 2 != 0; break;
|
|
default: return true; break;
|
|
}
|
|
}
|
|
|
|
inline void pixelFunc(PixelInfo pixel)
|
|
{
|
|
|
|
uint8_t c;
|
|
|
|
#if 0
|
|
c = pixel.isWall ? pixel.hit.direction + 4 : 1;
|
|
|
|
for (uint8_t i = 0; i < SUBSAMPLE; ++i)
|
|
p.display.drawPixel(pixel.position.x * SUBSAMPLE + i,pixel.position.y,c);
|
|
|
|
#else
|
|
Unit depth = pixel.depth - UNITS_PER_SQUARE;
|
|
|
|
if (depth < 0)
|
|
depth = 0;
|
|
|
|
int intensity = 7 - (depth * 7) / (UNITS_PER_SQUARE * 5);
|
|
|
|
if (intensity < 0)
|
|
intensity = 0;
|
|
|
|
|
|
|
|
if (pixel.isWall)
|
|
{
|
|
if ((pixel.hit.direction == 0 || pixel.hit.direction == 2))
|
|
intensity -= 2;
|
|
|
|
if (intensity < 0)
|
|
intensity = 0;
|
|
|
|
c = sampleImage(image,pixel.hit.textureCoord,pixel.textureCoordY);
|
|
c = darkenColor(c,intensity);
|
|
}
|
|
else
|
|
c = rgbToIndex(intensity,intensity,intensity / 2);
|
|
|
|
uint8_t *buf = p.display.screenbuffer;
|
|
|
|
buf += pixel.position.x * SUBSAMPLE;
|
|
buf += pixel.position.y * p.display.width;
|
|
|
|
for (uint8_t i = 0; i < SUBSAMPLE - 1; ++i)
|
|
*buf++ = c;
|
|
|
|
*buf = c;
|
|
#endif
|
|
|
|
}
|
|
|
|
unsigned short pal[256];
|
|
|
|
void draw()
|
|
{
|
|
|
|
/*
|
|
uint8_t a = 0;
|
|
for (uint8_t j = 0; j < 88; ++j)
|
|
for (uint8_t i = 0; i < 110; ++i)
|
|
{
|
|
p.display.drawPixel(i,j,sampleImage(image,i * 10,j * 9));
|
|
++a;
|
|
}
|
|
return;
|
|
*/
|
|
|
|
RayConstraints c;
|
|
|
|
c.maxHits = 16;
|
|
c.maxSteps = 16;
|
|
|
|
render(player.mCamera,heightFunc,pixelFunc,c);
|
|
|
|
/*
|
|
p.display.setCursor(1,1);
|
|
p.display.print(player.mCamera.position.x);
|
|
p.display.print(' ');
|
|
p.display.print(player.mCamera.position.y);
|
|
p.display.print(' ');
|
|
p.display.print(player.mCamera.height);
|
|
p.display.print(' ');
|
|
p.display.print(player.mCamera.direction);
|
|
*/
|
|
}
|
|
|
|
int main()
|
|
{
|
|
p.begin();
|
|
|
|
/*
|
|
int a,s,r,g,b;
|
|
for(a=0; a<=63; a++){
|
|
s = 0; r = a; g = 63-a; b = 0; pal[a+s] = p.display.RGBto565(r*4,g*4,b*4);
|
|
s = 64; r = 63-a; g = 0; b = a; pal[a+s] = p.display.RGBto565(r*4,g*4,b*4);
|
|
s = 128; r = 0; g = 0; b = 63-a; pal[a+s] = p.display.RGBto565(r*4,g*4,b*4);
|
|
s = 192; r = 0; g = a; b = 0; pal[a+s] = p.display.RGBto565(r*4,g*4,b*4);
|
|
}
|
|
*/
|
|
|
|
for (uint8_t r = 0; r < 8; ++r)
|
|
for (uint8_t g = 0; g < 8; ++g)
|
|
for (uint8_t b = 0; b < 4; ++b)
|
|
{
|
|
pal[rgbToIndex(r,g,b)] = p.display.RGBto565(36 * r, 36 * g, 85 * b);
|
|
}
|
|
|
|
/*
|
|
for (int i = 0; i < 16; ++i)
|
|
pal[i] = p.display.RGBto565(255-i,255-i,255-i);
|
|
|
|
pal[0] = p.display.RGBto565(0,0,0);
|
|
pal[1] = p.display.RGBto565(64,0,0);
|
|
pal[2] = p.display.RGBto565(128,0,0);
|
|
pal[3] = p.display.RGBto565(192,0,0);
|
|
pal[4] = p.display.RGBto565(0,64,0);
|
|
pal[5] = p.display.RGBto565(0,128,0);
|
|
pal[6] = p.display.RGBto565(0,192,0);
|
|
pal[7] = p.display.RGBto565(0,0,64);
|
|
pal[8] = p.display.RGBto565(0,0,128);
|
|
pal[9] = p.display.RGBto565(0,0,192);
|
|
pal[10] = p.display.RGBto565(64,64,0);
|
|
pal[11] = p.display.RGBto565(128,128,0);
|
|
pal[12] = p.display.RGBto565(192,192,0);
|
|
pal[13] = p.display.RGBto565(64,64,64);
|
|
pal[14] = p.display.RGBto565(128,128,128);
|
|
pal[15] = p.display.RGBto565(192,192,192);
|
|
*/
|
|
|
|
p.display.load565Palette(&pal[0]); // load a palette the same way as any other palette in any other screen mode
|
|
|
|
p.display.persistence = 1;
|
|
|
|
p.setFrameRate(60);
|
|
|
|
p.display.setFont(fontTiny);
|
|
|
|
while (p.isRunning())
|
|
{
|
|
if (p.update())
|
|
{
|
|
draw();
|
|
|
|
const int16_t step = max(UNITS_PER_SQUARE / 10,1);
|
|
const int16_t step2 = max(UNITS_PER_SQUARE / 50,1);
|
|
|
|
Vector2D d = angleToDirection(player.mCamera.direction);
|
|
|
|
d.x = (d.x * step) / UNITS_PER_SQUARE;
|
|
d.y = (d.y * step) / UNITS_PER_SQUARE;
|
|
|
|
if (d.x == 0 && d.y == 0)
|
|
{
|
|
d.x = d.x > 0 ? step : -step;
|
|
d.y = d.y > 0 ? step : -step;
|
|
}
|
|
|
|
if (p.upBtn())
|
|
{
|
|
player.mCamera.position.x += d.x;
|
|
player.mCamera.position.y += d.y;
|
|
}
|
|
else if (p.downBtn())
|
|
{
|
|
player.mCamera.position.x -= d.x;
|
|
player.mCamera.position.y -= d.y;
|
|
}
|
|
|
|
if (p.rightBtn())
|
|
player.mCamera.direction += step2;
|
|
else if (p.leftBtn())
|
|
player.mCamera.direction -= step2;
|
|
|
|
if (p.aBtn())
|
|
player.mCamera.height += step;
|
|
else if (p.bBtn())
|
|
player.mCamera.height -= step;
|
|
|
|
player.mCamera.height =
|
|
max(heightFunc(player.mCamera.position.x / UNITS_PER_SQUARE,player.mCamera.position.y / UNITS_PER_SQUARE) + UNITS_PER_SQUARE / 2,player.mCamera.height);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|