/* work in progress game made using small3dlib, based on Miloslav Ciz's quake-like level */ #include #include #include #include #include #include #include "leveldefines.h" #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; typedef struct mouse { int x, y; // In this case: the position where the mouse is held at short trap; // flag for holding mouse at one place } t_mouse; static t_mouse mouse; 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_WarpMouseGlobal(HALF_SCREEN_WIDTH, HALF_SCREEN_HEIGHT); 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; SDL_SetRelativeMouseMode(SDL_TRUE); 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; } else if (event.type == SDL_MOUSEMOTION) { /* Set x and y to the current mouse position */ int x, y; SDL_GetMouseState(&x, &y); int xdiff = x - mouse.x; // Calculate difference in x int ydiff = y - mouse.y; // Calculate difference in y /* rotate camera relative to what it was before */ scene.camera.transform.rotation.x -= ydiff; scene.camera.transform.rotation.y -= xdiff; mouse.x = x; mouse.y = y; } } 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_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; }