diff --git a/demo2.cpp b/demo2.cpp index e06fed5..6a2c33d 100644 --- a/demo2.cpp +++ b/demo2.cpp @@ -820,7 +820,7 @@ void draw() perspectiveScale(64,pos.depth)); } - drawImage(imageBar,0,INFO_BAR_START - 4); + drawImage(imageBar,0,INFO_BAR_START - 3); } int main() diff --git a/demo3.cpp b/demo3.cpp new file mode 100644 index 0000000..1191be2 --- /dev/null +++ b/demo3.cpp @@ -0,0 +1,215 @@ +/** + WIP raycasting demo for Pokitto. + + Don't forget to compile with -O3! + + author: Miloslav "drummyfish" Ciz + license: CC0 1.0 +*/ + +// redefine player's height +#define CAMERA_COLL_HEIGHT_BELOW ((3 * UNITS_PER_SQUARE) / 2) + +#include "general.hpp" + +#define LEVEL_X_RES 29 +#define LEVEL_Y_RES 21 + +Player player; + +#define SPRITE_MAX_DISTANCE 5 * UNITS_PER_SQUARE + +#define JUMP_SPEED 500 + +char floorColor = 0; +char ceilingColor = 0; + +#define HEIGHT_PROFILE_LENGTH 256 +const int8_t heightProfile[] = { +9,9,9,10,10,10,11,11,12,13,13,14,14,14,15,15,15,16,16,16,16,16,15,15,15,14,14,13,13,12,11,10,10,9,9,9,8,8,8,8,8,8,7,7,7,6,5,4,4,3,3,3,3,3,3,4,5,7,8,10,11,12,12,13,13,13,14,16,19,20,21,21,22,22,22,23,23,23,23,22 +,22,21,20,19,18,18,17,17,17,17,16,16,16,16,16,16,16,15,15,15,14,14,13,12,11,10,8,7,6,5,5,5,4,4,4,4,4,5,5,5,6,6,7,7,7,8,8,8,8,8,8,8,7,7,7,7,6,6,5,4,4,3,2,2,2,1,1,1,1,2,3,5,6,7,9,13,13,13,18,18 +,22,22,22,22,22,22,21,21,20,20,19,16,16,16,14,14,14,15,15,15,15,15,16,17,17,18,18,18,16,16,16,16,15,15,15,14,14,13,12,8,7,7,7,8,9,11,12,12,13,13,13,12,11,10,10,10,10,11,11,12,13,13,12,12,11,11,10,10,9,9,9,9,9,9,10,10,11,12,13,13 +,14,14,14,14,14,13,13,12,11,11,11,11,10,10,10,10}; + +Unit floorHeightAt(int16_t x, int16_t y) +{ + return (heightProfile[absVal(x) % HEIGHT_PROFILE_LENGTH] + + heightProfile[absVal(y + 20) % HEIGHT_PROFILE_LENGTH]) * + UNITS_PER_SQUARE; +} + +/** + Function for drawing a single pixel (like fragment shader). +*/ +inline void pixelFunc(PixelInfo pixel) +{ + uint8_t c; + + int16_t intensity = pixel.depth / (UNITS_PER_SQUARE * 5); + + if (pixel.isWall) + { + c = 50; + intensity += (pixel.hit.direction % 2 == 0 ? 2 : 0); + } + else + c = pixel.isFloor && pixel.depth < UNITS_PER_SQUARE * 16 ? + floorColor : ceilingColor; + + if (c != ceilingColor) + c = addRGB(c,intensity / 2,intensity / 2,intensity / 2); + + uint8_t *buf = pokitto.display.screenbuffer; + + buf += pixel.position.x * SUBSAMPLE; + buf += pixel.position.y * SCREEN_WIDTH; + + for (uint8_t i = 0; i < SUBSAMPLE - 1; ++i) + *buf++ = c; + + *buf = c; +} + +void draw() +{ + RayConstraints c; + + c.maxHits = 6; + c.maxSteps = 15; + c.computeTextureCoords = 1; + + render(player.mCamera,floorHeightAt,0,0,pixelFunc,c); +/* +pokitto.display.setColor(rgbToIndex(7,7,3)); +pokitto.display.setCursor(1,1); +pokitto.display.print(player.mCamera.position.x); +pokitto.display.print(" "); +pokitto.display.print(player.mCamera.position.y); +pokitto.display.print(" "); +pokitto.display.print(player.mCamera.direction); +*/ +} + +bool runReleased = false; + +int main() +{ + initGeneral(); + + floorColor = rgbToIndex(4,2,0); + ceilingColor = rgbToIndex(2,2,3); + + player.setPositionSquare(4,5); + + uint32_t previousTime = 0; + uint32_t dt; + + while (pokitto.isRunning()) + { + if (pokitto.update()) + { + draw(); + + uint32_t timeNow = pokitto.getTime(); + dt = timeNow - previousTime; + previousTime = timeNow; + + int16_t horizontalStep = (dt * PLAYER_SPEED * (player.mRunning ? 2 : 1)) / 1000; + int16_t rotationStep = (dt * PLAYER_ROTATION_SPEED) / 1000; + + Vector2D d = angleToDirection(player.mCamera.direction); + + Vector2D moveOffset; + + moveOffset.x = 0; + moveOffset.y = 0; + + d.x = (d.x * horizontalStep) / UNITS_PER_SQUARE; + d.y = (d.y * horizontalStep) / UNITS_PER_SQUARE; + + if (d.x == 0 && d.y == 0) + { + d.x = d.x > 0 ? horizontalStep : -1 * horizontalStep; + d.y = d.y > 0 ? horizontalStep : -1 * horizontalStep; + } + + bool aButton = pokitto.aBtn(); + + if (pokitto.cBtn()) + { + if (runReleased) + { + player.mRunning = !player.mRunning; + runReleased = false; + } + } + else + runReleased = true; + + if (pokitto.upBtn()) + { + if (aButton) + player.mCamera.shear = min(player.mCamera.shear + 10,60); + else + moveOffset = d; + } + else if (pokitto.downBtn()) + { + if (aButton) + player.mCamera.shear = max(player.mCamera.shear - 10,-60); + else + { + moveOffset.x = -1 * d.x; + moveOffset.y = -1 * d.y; + } + } + else + player.mCamera.shear /= 2; + + if (!aButton) + player.mCamera.shear /= 2; + + int addition = 0; + + if (pokitto.rightBtn()) + addition = 1; + else if (pokitto.leftBtn()) + addition = -1; + + if (aButton) + { + d = angleToDirection(player.mCamera.direction + UNITS_PER_SQUARE / 4); + d.x = (d.x * horizontalStep * addition) / UNITS_PER_SQUARE; + d.y = (d.y * horizontalStep * addition) / UNITS_PER_SQUARE; + + moveOffset = d; + } + else + player.mCamera.direction += addition * rotationStep; + + Unit prevHeight = player.mCamera.height; + + moveCameraWithCollision(&player.mCamera,moveOffset,player.mVericalSpeed, + floorHeightAt, 0, 1); + + Unit heightDiff = player.mCamera.height - prevHeight; + + if (heightDiff == 0) + player.mVericalSpeed = 0; // hit floor/ceiling + + if (player.mVericalSpeed == 0 && pokitto.bBtn()) + { + int16_t camX = divRoundDown(player.mCamera.position.x,UNITS_PER_SQUARE); + int16_t camY = divRoundDown(player.mCamera.position.y,UNITS_PER_SQUARE); + + if (player.mCamera.height - CAMERA_COLL_HEIGHT_BELOW - + floorHeightAt(camX,camY) < 2) + player.mVericalSpeed = JUMP_SPEED; // jump + } + + player.mVericalSpeed -= (dt * GRAVITY_ACCELERATION) / 1000; // gravity + } + } + + return 0; +} diff --git a/general.hpp b/general.hpp index 27e7660..fb51edb 100644 --- a/general.hpp +++ b/general.hpp @@ -85,7 +85,7 @@ void initPalette() @param intensity intensity to add, 3 bit (0 to 7) @return new color */ -inline uint8_t addIntensity(uint8_t color, int intensity) +inline uint8_t addIntensity(uint8_t color, int16_t intensity) { uint8_t r = color & 0b00000111; uint8_t g = (color & 0b00111000) >> 3; @@ -114,6 +114,19 @@ inline uint8_t addIntensity(uint8_t color, int intensity) return rgbToIndex(r,g,b); } +inline uint8_t addRGB(uint8_t color, int16_t red, int16_t green, int16_t blue) +{ + int8_t r = color & 0b00000111; + int8_t g = (color & 0b00111000) >> 3; + int8_t b = (color & 0b11000000) >> 6; + + r = clamp(r + red,0,7); + g = clamp(g + green,0,7); + b = clamp(b + blue,0,3); + + return rgbToIndex(r,g,b); +} + /** Samples an image by normalized coordinates - each coordinate is in range 0 to UNITS_PER_SQUARE (from raycastlib). diff --git a/height_profile.py b/height_profile.py new file mode 100644 index 0000000..85c3950 --- /dev/null +++ b/height_profile.py @@ -0,0 +1,37 @@ +# Convert png image of height profile to number array. +# +# author: Miloslav Ciz +# license: CC0 + +import sys +from PIL import Image + +image = Image.open(sys.argv[1]) +pixels = image.load() + +sys.stdout.write("const int8_t heightProfile[] = {") + +first = True + +count = 0; + +for x in range(image.size[0]): + if count % 80 == 0: + print("") + + count += 1 + + if first: + first = False + else: + sys.stdout.write(",") + + for y in range(image.size[1]): + p = pixels[x,y] + + if p[0] == 0: + sys.stdout.write(str(image.size[1] - y)) + break + +print("};") +