diff options
Diffstat (limited to 'src/level.c')
-rw-r--r-- | src/level.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/src/level.c b/src/level.c new file mode 100644 index 0000000..80df73f --- /dev/null +++ b/src/level.c @@ -0,0 +1,317 @@ +/* + Example program for small3dlib, showing a Quake-like level. + + author: Miloslav Ciz + license: CC0 1.0 +*/ + +#define TEXTURES 1 // whether to use textures for the level +#define FOG 1 + +#include <SDL2/SDL.h> +#include <stdio.h> +#include <time.h> + +#define S3L_NEAR_CROSS_STRATEGY 3 + +#if TEXTURES + #define S3L_PERSPECTIVE_CORRECTION 2 +#else + #define S3L_PERSPECTIVE_CORRECTION 0 +#endif + +#define S3L_NEAR (S3L_FRACTIONS_PER_UNIT / 5) + +#define S3L_USE_WIDER_TYPES 0 +#define S3L_FLAT 0 +#define S3L_SORT 0 +#define S3L_Z_BUFFER 1 +#define S3L_MAX_TRIANGES_DRAWN 512 + +#define S3L_PIXEL_FUNCTION drawPixel + +#define S3L_MAX_PIXELS (1024 * 1024) + +#include "small3dlib.h" + +#include "levelModel.h" +#include "levelTextures.h" + +S3L_Scene scene; + +S3L_Vec4 teleportPoint; + +uint32_t pixels[S3L_MAX_PIXELS]; + +uint32_t frame = 0; +uint8_t *texture = 0; +uint32_t previousTriangle = 1000; +S3L_Vec4 uv0, uv1, uv2; + +void clearScreen() +{ + memset(pixels,255,S3L_MAX_PIXELS * sizeof(uint32_t)); +} + +static inline void setPixel(int x, int y, uint8_t red, uint8_t green, uint8_t blue) +{ + uint8_t *p = ((uint8_t *) pixels) + (y * S3L_resolutionX + x) * 4 + 1; + + *p = blue; + ++p; + *p = green; + ++p; + *p = red; +} + +void sampleTexture(S3L_Unit u, S3L_Unit v, uint8_t *r, uint8_t *g, uint8_t *b) +{ + u = (u * LEVEL_TEXTURE_WIDTH) / S3L_FRACTIONS_PER_UNIT; + v = (v * LEVEL_TEXTURE_HEIGHT) / S3L_FRACTIONS_PER_UNIT; + + u = S3L_wrap(u,LEVEL_TEXTURE_WIDTH); + v = S3L_wrap(v,LEVEL_TEXTURE_HEIGHT); + + const uint8_t *t = texture + (v * LEVEL_TEXTURE_WIDTH + u) * 3; + + *r = *t; + t++; + *g = *t; + t++; + *b = *t; +} + +void drawTeleport(int16_t x, int16_t y, S3L_ScreenCoord size) +{ + int16_t halfSize = size / 2; + + S3L_ScreenCoord x0 = S3L_max(0,x - halfSize); + S3L_ScreenCoord x1 = S3L_min(S3L_resolutionX,x + halfSize); + S3L_ScreenCoord y0 = S3L_max(0,y - halfSize); + S3L_ScreenCoord y1 = S3L_min(S3L_resolutionY,y + halfSize); + + S3L_ScreenCoord row = y0 - (y - halfSize); + + for (S3L_ScreenCoord j = y0; j < y1; ++j) + { + S3L_ScreenCoord i0, i1; + + if (row <= halfSize) + { + i0 = S3L_max(x0,x - row); + i1 = S3L_min(x1,x + row); + } + else + { + i0 = S3L_max(x0,x - size + row); + i1 = S3L_min(x1,x + size - row); + } + + for (S3L_ScreenCoord i = i0; i < i1; ++i) + if (rand() % 8 == 0) + setPixel(i,j,255,0,0); + + row++; + } +} + +void drawPixel(S3L_PixelInfo *p) +{ + uint8_t r, g, b; + +#if TEXTURES + if (p->triangleID != previousTriangle) + { + uint8_t material = levelMaterials[p->triangleIndex]; + + switch (material) + { + case 0: + texture = level1Texture; + break; + + case 1: + texture = level2Texture; + break; + + case 2: + default: + texture = level3Texture; + break; + } + + S3L_getIndexedTriangleValues(p->triangleIndex,levelUVIndices,levelUVs,2,&uv0,&uv1,&uv2); + previousTriangle = p->triangleID; + } + + S3L_Unit uv[2]; + + uv[0] = S3L_interpolateBarycentric(uv0.x,uv1.x,uv2.x,p->barycentric); + uv[1] = S3L_interpolateBarycentric(uv0.y,uv1.y,uv2.y,p->barycentric); + + sampleTexture(uv[0],uv[1],&r,&g,&b); +#else + switch (p->modelIndex) + { + case 0: r = 255; g = 0; b = 0; break; + case 1: r = 0; g = 255; b = 0; break; + case 2: + default: r = 0; g = 0; b = 255; break; + } +#endif + +#if FOG + S3L_Unit fog = (p->depth * +#if TEXTURES + 8 +#else + 16 +#endif + ) / S3L_FRACTIONS_PER_UNIT; + + r = S3L_clamp(((S3L_Unit) r) - fog,0,255); + g = S3L_clamp(((S3L_Unit) g) - fog,0,255); + b = S3L_clamp(((S3L_Unit) b) - fog,0,255); +#endif + + setPixel(p->x,p->y,r,g,b); +} + +S3L_Transform3D modelTransform; +S3L_DrawConfig conf; + +clock_t nextT; + +int fps = 0; + +void draw() +{ + S3L_newFrame(); + + clearScreen(); + + S3L_drawScene(scene); + + S3L_Vec4 screenPoint; + + project3DPointToScreen(teleportPoint,scene.camera,&screenPoint); + + if (screenPoint.w > 0 && + screenPoint.x >= 0 && screenPoint.x < S3L_resolutionX && + screenPoint.y >= 0 && screenPoint.y < S3L_resolutionY && + screenPoint.z < S3L_zBufferRead(screenPoint.x,screenPoint.y)) + drawTeleport(screenPoint.x,screenPoint.y,screenPoint.w); + + clock_t nowT = clock(); + + double timeDiff = ((double) (nowT - nextT)) / CLOCKS_PER_SEC; + + fps++; + + if (timeDiff >= 1.0) + { + nextT = nowT; + printf("FPS: %d\n",fps); + + printf("camera: "); + S3L_logTransform3D(scene.camera.transform); + fps = 0; + } +} + +int main() +{ + S3L_resolutionX = 1000; + S3L_resolutionY = 600; + + SDL_Window *window = SDL_CreateWindow("level demo", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, S3L_resolutionX, S3L_resolutionY, SDL_WINDOW_SHOWN); + SDL_Renderer *renderer = SDL_CreateRenderer(window,-1,0); + SDL_Texture *texture = SDL_CreateTexture(renderer,SDL_PIXELFORMAT_RGBX8888, SDL_TEXTUREACCESS_STATIC, S3L_resolutionX, S3L_resolutionY); + SDL_Surface *screenSurface = SDL_GetWindowSurface(window); + SDL_Event event; + + teleportPoint.x = 6 * S3L_FRACTIONS_PER_UNIT; + teleportPoint.y = -3 * S3L_FRACTIONS_PER_UNIT; + teleportPoint.z = 3 * S3L_FRACTIONS_PER_UNIT / 2; + teleportPoint.w = S3L_FRACTIONS_PER_UNIT; + + nextT = clock(); + + levelModelInit(); + + S3L_sceneInit(&levelModel,1,&scene); + + int running = 1; + + while (running) // main loop + { + int newWidth = -1, newHeight = -1; + + draw(); + SDL_UpdateTexture(texture,NULL,pixels,S3L_resolutionX * sizeof(uint32_t)); + + while (SDL_PollEvent(&event)) + if (event.type == SDL_QUIT) + running = 0; + + S3L_Vec4 camF, camR; + + S3L_rotationToDirections(scene.camera.transform.rotation,20,&camF,&camR,0); + + const uint8_t *state = SDL_GetKeyboardState(NULL); + + if (state[SDL_SCANCODE_A]) + scene.camera.transform.rotation.y += 1; + else if (state[SDL_SCANCODE_D]) + scene.camera.transform.rotation.y -= 1; + else if (state[SDL_SCANCODE_W]) + scene.camera.transform.rotation.x += 1; + else if (state[SDL_SCANCODE_S]) + scene.camera.transform.rotation.x -= 1; + + if (state[SDL_SCANCODE_UP]) + S3L_vec3Add(&scene.camera.transform.translation,camF); + else if (state[SDL_SCANCODE_DOWN]) + S3L_vec3Sub(&scene.camera.transform.translation,camF); + else if (state[SDL_SCANCODE_LEFT]) + S3L_vec3Sub(&scene.camera.transform.translation,camR); + else if (state[SDL_SCANCODE_RIGHT]) + S3L_vec3Add(&scene.camera.transform.translation,camR); + + if (state[SDL_SCANCODE_K]) + newHeight = S3L_resolutionY + 4; + else if (state[SDL_SCANCODE_I]) + newHeight = S3L_resolutionY - 4; + else if (state[SDL_SCANCODE_J]) + newWidth = S3L_resolutionX - 4; + else if (state[SDL_SCANCODE_L]) + newWidth = S3L_resolutionX + 4; + + if ( + ( + (newWidth != -1 && newWidth > 0) || + (newHeight != -1 && newHeight > 0) + ) && + (newWidth * S3L_resolutionY <= S3L_MAX_PIXELS) && + (newHeight * S3L_resolutionX <= S3L_MAX_PIXELS)) + { + if (newWidth != -1) + S3L_resolutionX = newWidth; + + if (newHeight != -1) + S3L_resolutionY = newHeight; + + SDL_DestroyTexture(texture); + texture = SDL_CreateTexture(renderer,SDL_PIXELFORMAT_RGBX8888, SDL_TEXTUREACCESS_STATIC, S3L_resolutionX, S3L_resolutionY); + SDL_SetWindowSize(window,S3L_resolutionX,S3L_resolutionY); + } + + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer,texture,NULL,NULL); + SDL_RenderPresent(renderer); + + frame++; + } + + return 0; +} |