/** WIP raycasting demo for Pokitto. Don't forget to compile with -O3! author: Miloslav "drummyfish" Ciz license: CC0 */ //#define RAYCAST_TINY #include #include "raycastlib.h" #include "Pokitto.h" #include #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); } 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; } if (pixel.isWall) c = sampleImage(image,pixel.hit.textureCoord,pixel.textureCoordY); 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; }