Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\src\file.cpp":
- #include <stdio.h>
- #include <scene.hpp>
- //#include <file.hpp>
- //#include <memory.hpp>
- namespace file {
- bool exists(const char* filePath){
- if(filePath == nullptr) throw "filePath = nullptr";
- FILE* file = fopen(filePath, "rb");
- if(file != nullptr){
- fclose(file);
- return true;
- } else {
- return false;
- }
- }
- s32 getSize(const char* filePath){
- if(!exists(filePath)) throw fstr("file \"%s\" does not exist", filePath);
- FILE* file = fopen(filePath, "rb");
- if(file == nullptr) throw "failed to open file";
- fseek(file, 0L, SEEK_END);
- s32 fileSize = ftell(file);
- fclose(file);
- return fileSize;
- }
- }; /* namespace file */
- BinaryData::BinaryData(const char* filePath){
- s64 _fileSize = file::getSize(filePath); //also checks to see if file exists
- size_t fileSize = (size_t)_fileSize;
- if(_fileSize < 0 ) throw "file size < 0";
- if(_fileSize == 0 ) throw "file size = 0";
- if(_fileSize > INT_S32_MAX) throw "file size > INT_MAX";
- *(char**)&data = (char*)memory::alloc(fileSize);
- if(data == nullptr) throw "failed to allocate memory for data";
- FILE* file = fopen(filePath, "rb");
- if(file == nullptr) throw "failed to open file";
- size_t bytesRead = fread(data, sizeof(char), fileSize, file);
- const char* err_msg = nullptr;
- if(bytesRead != fileSize){
- if( feof(file)) err_msg = "unexpected EOF";
- else if(ferror(file)) err_msg = "failed to read file";
- else err_msg = "bytes read != file size";
- char* _data = (char*)data;
- memory::free(&_data);
- }
- fclose(file);
- *(size_t*)&data_len = fileSize;
- if(err_msg != nullptr) throw err_msg;
- }
- BinaryData::~BinaryData(){
- char* _data = (char*)data;
- memory::free(&_data);
- }
- void BinaryData::loadFromMemory(const void* data, size_t dataSize){
- if(!dataSize) throw "dataSize = 0";
- char* _data = (char*)data;
- char* _data_new = (char*)memory::realloc(&_data, dataSize);
- if(_data_new == nullptr) throw "failed to allocate memory for data";
- if(_data != nullptr) memcpy(_data_new, _data, MIN(dataSize, data_len));
- *(char**)data = _data_new;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\src\main.cpp":
- #define SDL_MAIN_HANDLED
- #include <scene.hpp>
- int sceneMain(int argc, char** argv);
- int main(int argc, char** argv){
- int returnStatus = -1;
- try {
- //i will uncomment this when my dumb ass gets around to putting in SIMD functionality
- //if(!SDL_HasAVX()) throw "this program requires AVX, which this CPU doesn't support";
- if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)<0) throw SDL_GetError();
- //should be redundant, but just in case
- SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "nearest");
- if(file::exists("geotex.bmp")){
- geometrySrf = SDL_LoadBMP("geotex.bmp");
- if(!geometrySrf) throw SDL_GetError();
- }
- // /*
- else throw "\"geotex.bmp\" does not exist!";
- // */
- canvas = new Canvas(WIN_W,WIN_H, CNV_W,CNV_H,
- WIN_TITLE " " TRAP_PROMPT);
- //SDL_ShowWindow(canvas->getWin()); //done inside sceneMain
- if(geometrySrf){
- geometryTex = SDL_CreateTextureFromSurface(canvas->getRnd(), geometrySrf);
- if(!geometryTex) throw SDL_GetError();
- }
- text_p = new Text("font8x8.bmp");
- returnStatus = sceneMain(argc, argv);
- SAFE_DELETE(text_p);
- if(geometryTex) SDL_DestroyTexture(geometryTex);
- delete canvas;
- if(geometrySrf) SDL_FreeSurface(geometrySrf);
- scene_ori.freeAll();
- scene_wka.freeAll();
- scene_wkb.freeAll();
- } catch(const char* errorText){
- #ifdef _DEBUG
- Log("Error = \"%s\"", errorText);
- #else
- SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "THE GAME CRASHED!", errorText, nullptr);
- #endif
- }
- Log("# OF ALLOCATIONS = %lu", (unsigned)memory::getNumAllocations());
- SDL_Quit();
- return returnStatus;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\src\memory.cpp":
- #include <stdlib.h>
- #include <memory.hpp>
- #ifdef free
- #undef free
- #endif /* free */
- #ifdef realloc
- #undef realloc
- #endif /* realloc */
- //turns something into a void**
- //(this makes some code here easier for me to read)
- #define VPP(_ptr_p) ((void**)(_ptr_p))
- static size_t numAllocations = 0;
- void* memory::alloc(size_t size){
- void* newHeapMemory = malloc(size);
- if(newHeapMemory != nullptr) ++numAllocations;
- return newHeapMemory;
- }
- void memory::_free_real(void* ptr_p){
- if(VPP(ptr_p) != nullptr && *VPP(ptr_p) != nullptr){
- --numAllocations;
- free(*VPP(ptr_p));
- *VPP(ptr_p) = nullptr;
- }
- }
- void* memory::_realloc_real(void* ptr_p, size_t newSize){
- void* ptr_new = nullptr;
- if(VPP(ptr_p) != nullptr){
- ptr_new = realloc(*VPP(ptr_p), newSize);
- if(ptr_new != nullptr){
- if(*VPP(ptr_p) == nullptr) ++numAllocations;
- *VPP(ptr_p) = ptr_new;
- }
- }
- return ptr_new;
- }
- size_t memory::getNumAllocations(){
- return numAllocations;
- }
- void* memory::allocSIMD(size_t size){
- void* newHeapMemory = SDL_SIMDAlloc(size);
- if(newHeapMemory != nullptr) ++numAllocations;
- return newHeapMemory;
- }
- void memory::freeSIMD(void* ptr_p){
- if(VPP(ptr_p) != nullptr && *VPP(ptr_p) != nullptr){
- --numAllocations;
- SDL_SIMDFree(*VPP(ptr_p));
- *VPP(ptr_p) = nullptr;
- }
- }
- void* memory::reallocSIMD(void* ptr_p, size_t newSize){
- void* ptr_new = nullptr;
- if(VPP(ptr_p) != nullptr){
- ptr_new = SDL_SIMDRealloc(*VPP(ptr_p), newSize);
- if(ptr_new != nullptr){
- if(*VPP(ptr_p) == nullptr) ++numAllocations;
- *VPP(ptr_p) = ptr_new;
- }
- }
- return ptr_new;
- }
- size_t memory::getSIMDAlignment(){
- return SDL_SIMDGetAlignment();
- }
- #define DONT_USE_AVX
- void* memory::set(void* _dst, char v, size_t size){
- #ifdef DONT_USE_AVX
- return memset(_dst, (int)v, size);
- #else
- //tbd
- if(!size) return _dst;
- size_t offset_fnt = size
- size_t offset_bck = size
- //skip if there's nothing left to set
- if(size >= 32){
- __m256i write_block = _mm256_set1_epi8(v);
- }
- return _dst;
- #endif
- }
- void* memory::copy(void* dst, const void* src, size_t size){
- #ifdef DONT_USE_AVX
- return memcpy(dst, src, size);
- #else
- #endif
- }
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\src\sceneMain.cpp":
- #include <scene.hpp>
- //1 ship, 1 'skybox', 1 gear icon, 1 door, <bullet_count> bullets,
- //4 asteroids, 16 mini-asteroids, and 64 micro-asteroids
- #define bullet_count 4
- #define asteroid_count (4 + 4*4 + 4*4*4)
- MeshSimple* meshes[1 + 1 + 1 + 1 + bullet_count + asteroid_count];
- #define meshes_len (sizeof(meshes)/sizeof(MeshSimple*))
- #define bullet_offset 4
- #define asteroid_offset (bullet_offset+bullet_count)
- #define _mesh_ship (meshes[0])
- #define _mesh_skybox (meshes[1])
- #define _mesh_gear (meshes[2])
- #define _mesh_door (meshes[3])
- #define _mesh_bullet(which) (meshes[bullet_offset+(which)])
- #define _mesh_asteroid(which) (meshes[asteroid_offset+(which)])
- #define mesh_ship (*_mesh_ship)
- #define mesh_skybox (*_mesh_skybox)
- #define mesh_gear (*_mesh_gear)
- #define mesh_door (*_mesh_door)
- #define mesh_bullet(which) (*_mesh_bullet(which))
- #define mesh_asteroid(which) (*_mesh_asteroid(which))
- #define asteroid_normal(which) mesh_asteroid( which )
- #define asteroid_mini(which) mesh_asteroid(4+ (which))
- #define asteroid_micro(which) mesh_asteroid(4+16+(which))
- #define asteroid_menu asteroid_micro
- #define state_normal(which) state.asteroids[ which ]
- #define state_mini(which) state.asteroids[4+ (which)]
- #define state_micro(which) state.asteroids[4+16+(which)]
- #define bullet_size 0.25f
- #define nrml_siz 1.00f
- #define mini_siz 0.75f
- #define mcro_siz 0.50f
- #define menu_siz mcro_siz
- //application of values are as follows:
- //camera's current position = old*mod + new*(1.0f-mod)
- //old = camera's current position
- #define camera_mod 0.85f
- #define camera_lpf(_member) \
- camera_old._member*camera_mod + camera_new._member*(1.0f-camera_mod)
- Location camera_old;
- Location camera_cur; //subject to different rules to that of scene_camera
- Location camera_new;
- #define bullet_speed 0.60f
- #define ship_speed_x 0.15f
- #define ship_speed_y 0.15f
- #define ship_speed_z 0.15f
- #define ship_camera_distance 1.3f
- #define ship_camera_y_offset 0.25f
- #define ship_camera_down_tilt 0.02f
- #define ship_decay_multiplier_a 0.88f
- #define ship_decay_multiplier_b 0.5f
- #define CFG_FILENAME "./config.bin"
- #define CFG_VERSION 5
- struct _cfg_s {
- int version = CFG_VERSION;
- float high_score = 0.0f;
- #define BIND_COUNT 6
- SDL_Scancode bind_right = SDL_SCANCODE_D;
- SDL_Scancode bind_left = SDL_SCANCODE_A;
- SDL_Scancode bind_forward = SDL_SCANCODE_W;
- SDL_Scancode bind_back = SDL_SCANCODE_S;
- SDL_Scancode bind_up = SDL_SCANCODE_LSHIFT;
- SDL_Scancode bind_down = SDL_SCANCODE_LCTRL;
- int win_w = WIN_W, win_h = WIN_H;
- float lastrand = 0.9f; //used to modify srand when starting a game
- //maximum number of normal asteroids that can exist at once
- //(takes into account mini and micro asteroids,
- //assuming one or more normal ones have split)
- int num_asteroids = 4;
- float sensitivity = 1.0f; //mouse look sensitivity
- bool invert_y = false; //inverts vertical mouse input
- bool maximized = false;
- bool fullscreen = false;
- };
- _cfg_s cfg;
- //WEIRD POINTER STUFF LMAOOO
- SDL_Scancode* bind_array = (SDL_Scancode*)(&cfg.high_score+1);
- SDL_Scancode bind_array_defaults[BIND_COUNT];
- const char* bind_names[] = {
- "right",
- "left",
- "forward",
- "back",
- "up",
- "down",
- };
- #define MENU_REBINDING -3
- #define MENU_DEAD -2
- #define MENU_PLAYING -1
- #define MENU_QUIT 0
- #define MENU_PLAY 1
- #define MENU_ASTEROIDS 2
- #define MENU_REBIND 3
- #define MENU_MAX MENU_REBIND
- struct bulletElement {
- Vec3 vel = {0,0,0};
- bool active = false;
- };
- enum asteroidTypeEnum { ATYPE_NORMAL = 0, ATYPE_MINI, ATYPE_MICRO, };
- struct asteroidElement {
- asteroidElement* children = nullptr;
- Vec3 vel = {0,0,0};
- char parent_id = -1;
- char children_active = -1;
- char type = -1; //asteroidTypeEnum
- bool active = false;
- };
- struct _state_s {
- bulletElement bullets[bullet_count];
- int active_bullets = 0;
- asteroidElement asteroids[asteroid_count];
- int active_asteroids = 0;
- int menu = MENU_PLAY;
- int which_rebind = 0;
- bool pressed_right = false;
- bool pressed_left = false;
- bool pressed_forward = false;
- bool pressed_back = false;
- bool pressed_up = false;
- bool pressed_down = false;
- bool quit = false;
- };
- _state_s state;
- bool* pressed_array = (bool*)(&state.which_rebind+1);
- #define skybox_bounds ((CLIP_FAR/32) - 1.0f)
- static inline bool keepInBounds(Location& loc){
- bool wrappedAround = false;
- if(fabsf(loc.x)>skybox_bounds){ loc.x = (1-2*(loc.x>=0))*skybox_bounds; wrappedAround = true; }
- if(fabsf(loc.y)>skybox_bounds){ loc.y = (1-2*(loc.y>=0))*skybox_bounds; wrappedAround = true; }
- if(fabsf(loc.z)>skybox_bounds){ loc.z = (1-2*(loc.z>=0))*skybox_bounds; wrappedAround = true; }
- return wrappedAround;
- }
- template<class T> inline T umod(T a, int b){
- a %= b;
- if(a < 0) a += b;
- return a;
- }
- #define SQR(thing) ((thing)*(thing))
- static inline float locHypot(const Location& loc){
- return sqrtf(SQR(loc.x)+SQR(loc.y)+SQR(loc.z));
- }
- static inline float locDistance(const Location& l_a, const Location& l_b){
- return sqrtf(SQR(l_b.x-l_a.x)+SQR(l_b.y-l_a.y)+SQR(l_b.z-l_a.z));
- }
- //assumes RAND_MAX is 32767
- static inline float randf(){
- return (float)(rand()<<15|rand())/0x3fffffff;
- }
- static inline float randf2(){
- return randf()*2.0f - 1.0f;
- }
- bool cursorIsTrapped = false;
- void trapCursor(bool enable){
- if(enable == cursorIsTrapped) return;
- SDL_SetWindowTitle(canvas->getWin(), fstr(WIN_TITLE " %s", (enable) ? UNTRAP_PROMPT : TRAP_PROMPT));
- if(SDL_SetRelativeMouseMode((enable) ? SDL_TRUE : SDL_FALSE)<0) throw SDL_GetError();
- cursorIsTrapped = enable;
- }
- void setFullscreen(bool enable){
- SDL_SetWindowFullscreen(canvas->getWin(), (enable) ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
- cfg.fullscreen = enable;
- }
- void mouseMoved(s32 dx, s32 dy);
- void mouseButton(u8 button, bool clicked);
- void keyPress(SDL_Keysym key, bool pressed, u16 modifiers);
- //returns false if state.quit gets flipped
- bool handleEvents(){
- SDL_Event evt;
- while(SDL_PollEvent(&evt))
- switch(evt.type){
- case SDL_QUIT: state.quit = true; SDL_ShowCursor(true); return false;
- case SDL_WINDOWEVENT: {
- switch(evt.window.event){
- case SDL_WINDOWEVENT_FOCUS_LOST: trapCursor(false); break;
- case SDL_WINDOWEVENT_RESIZED: cfg.win_w = evt.window.data1, cfg.win_h = evt.window.data2; break;
- case SDL_WINDOWEVENT_RESTORED: cfg.maximized = false; break;
- case SDL_WINDOWEVENT_MAXIMIZED: cfg.maximized = true; break;
- default: ;//Log("%X", evt.window.event);
- }
- } break;
- case SDL_KEYDOWN: {
- if(evt.key.repeat) break;
- if(evt.key.keysym.sym == SDLK_ESCAPE){ trapCursor(false); break; }
- if(evt.key.keysym.sym == SDLK_F11){ setFullscreen(!cfg.fullscreen); break; }
- } SDL_FALLTHROUGH;
- case SDL_KEYUP: {
- keyPress(evt.key.keysym,
- (evt.key.state == SDL_PRESSED) ? true : false,
- evt.key.keysym.mod);
- } break;
- case SDL_MOUSEBUTTONDOWN:{
- if(cursorIsTrapped)
- mouseButton(evt.button.button, evt.button.state == SDL_PRESSED);
- if(evt.button.button == SDL_BUTTON_LEFT)
- trapCursor(true);
- } break;
- case SDL_MOUSEMOTION: {
- if(cfg.invert_y) evt.motion.yrel = -evt.motion.yrel;
- if(cursorIsTrapped) mouseMoved(evt.motion.xrel, evt.motion.yrel);
- } break;
- default: ;//Log("%X", evt.type);
- }
- return !state.quit;
- }
- Vec3 rotatePRY(float pitch, float roll, float yaw,
- float x_0, float y_0, float z_0)
- {
- const float cosPitch = cosf(pitch);
- const float sinPitch = sinf(pitch);
- const float cosRoll = cosf(roll );
- const float sinRoll = sinf(roll );
- const float cosYaw = cosf(yaw );
- const float sinYaw = sinf(yaw );
- float y_1 = cosPitch*y_0 - sinPitch*z_0;
- float z_1 = sinPitch*y_0 + cosPitch*z_0;
- float x_2 = cosRoll*x_0 - sinRoll*y_1;
- float y_2 = sinRoll*x_0 + cosRoll*y_1;
- float x_3 = cosYaw*x_2 + sinYaw*z_1;
- float z_2 = -sinYaw*x_2 + cosYaw*z_1;
- return Vec3(x_3, y_2, z_2);
- }
- //motion is relative to camera's current direction
- static inline void moveCamera(float x_0, float y_0, float z_0){
- Vec3 motion = rotatePRY(-camera_cur.pitch,
- -camera_cur.roll,
- -camera_cur.yaw,
- x_0, y_0, z_0);
- camera_cur.x += motion.x;
- camera_cur.y += motion.y;
- camera_cur.z += motion.z;
- }
- bool fireBullet(){
- if(state.active_bullets >= bullet_count) return false; //max bullets reached
- int which = -1;
- for(int i=0; i<bullet_count; ++i){
- if(!state.bullets[i].active){ which = i; break; }
- }
- if(which == -1)
- throw "could not find empty spot in bullet queue, despite active bullets being < maximum"; //return false;
- Vec3 direction = rotatePRY(-camera_cur.pitch,
- -camera_cur.roll,
- -camera_cur.yaw,
- 0.0f, 0.0f, 1.0f);
- mesh_bullet(which).p.x = -camera_cur.x + direction.x;
- mesh_bullet(which).p.y = -camera_cur.y + direction.y;
- mesh_bullet(which).p.z = -camera_cur.z + direction.z;
- mesh_bullet(which).p.pitch = -camera_cur.pitch;
- mesh_bullet(which).p.roll = -camera_cur.roll;
- mesh_bullet(which).p.yaw = -camera_cur.yaw;
- state.bullets[which].vel = direction;
- state.bullets[which].vel *= bullet_speed;
- //lol
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
- state.bullets[which].active = true;
- #pragma GCC diagnostic pop
- ++state.active_bullets;
- return true;
- }
- #define max_asteroid_speed 0.1
- void asteroidCreate(int which){
- Location newloc = mesh_asteroid(which).p;
- do {
- newloc.x = randf()*skybox_bounds*2 - skybox_bounds;
- newloc.y = randf()*skybox_bounds*2 - skybox_bounds;
- newloc.z = randf()*skybox_bounds*2 - skybox_bounds;
- } while( locDistance(newloc, camera_cur) < (skybox_bounds/3) );
- float max_type_speed = max_asteroid_speed*(1+state.asteroids[which].type);
- mesh_asteroid(which).p = newloc;
- state.asteroids[which].vel.x = randf2() * max_type_speed;
- state.asteroids[which].vel.y = randf2() * max_type_speed;
- state.asteroids[which].vel.z = randf2() * max_type_speed;
- state.asteroids[which].active = true;
- }
- void asteroidSplit(int which){
- /*
- asteroidElement* ast = state.asteroids[which];
- while(ast->children){
- }
- */
- /*
- if(ast->type == ATYPE_MICRO){
- ast->
- } else if(ast->type == ATYPE_MINI){
- } else {
- }*/
- }
- //
- #define mdelta_divisor_a 200
- #define mdelta_divisor_b 200
- #define mdelta_divisor_c 1000
- void mouseMoved(s32 dx, s32 dy){
- if(state.menu != MENU_PLAYING) return;
- #define rotmod(value) fmodf(value, _2pi)
- #define rotclamp(value) CLAMP(value, -_pi, _pi)
- #define rotclamph(value) CLAMP(value, -(_pi/2), (_pi/2))
- camera_cur.yaw = rotmod( camera_cur.yaw -((float)dx/mdelta_divisor_a)*cfg.sensitivity);
- camera_cur.pitch = rotclamph(camera_cur.pitch+((float)dy/mdelta_divisor_a)*cfg.sensitivity);
- mesh_ship.p.roll = rotclamph(mesh_ship.p.roll -((float)dx/mdelta_divisor_b)*cfg.sensitivity);
- mesh_ship.p.pitch = rotclamph(mesh_ship.p.pitch-((float)dy/mdelta_divisor_b)*cfg.sensitivity);
- }
- void mouseButton(u8 button, bool clicked){
- if(state.menu != MENU_PLAYING) return;
- if(button == SDL_BUTTON_LEFT && clicked) fireBullet();
- }
- static inline bool bindingIsValid(SDL_Scancode scancode, unsigned index){
- if(index > INT_S32_MAX) //just in case
- throw "bindingIsValid(): index > 2147483647";
- //bindings shouldn't share the same scancode,
- //so check current bindings until right before current index (not BIND_COUNT)
- for(unsigned i=0; i<index; ++i) //loop shouldn't start at all if index is 0
- if(bind_array[i] == scancode) return false;
- return true;
- }
- void keyPress(SDL_Keysym key, bool pressed, u16 modifiers){
- //Log("0x%02X, %i, 0x%04X", key.scancode, pressed, modifiers);
- if(state.menu == MENU_PLAYING){
- for(unsigned i=0; i<BIND_COUNT; ++i){
- if(key.scancode == bind_array[i])
- pressed_array[i] = pressed;
- }
- if(pressed){
- if(key.sym == SDLK_SPACE ) fireBullet();
- if(key.sym == SDLK_BACKSPACE) state.menu = MENU_PLAY;
- }
- } else if(state.menu == MENU_REBINDING){
- if(!pressed) return;
- if(key.sym == SDLK_RETURN || key.sym == SDLK_SPACE) return;
- if( key.sym == SDLK_UP || key.sym == SDLK_DOWN ||
- key.sym == SDLK_LEFT || key.sym == SDLK_RIGHT )
- {
- return;
- }
- if(key.sym == SDLK_BACKSPACE){
- for(int i=0; i<BIND_COUNT; ++i) bind_array[i] = bind_array_defaults[i];
- state.menu = MENU_REBIND;
- return;
- }
- if(bindingIsValid(key.scancode, state.which_rebind)){
- bind_array[state.which_rebind] = key.scancode;
- ++state.which_rebind;
- }
- if(state.which_rebind >= BIND_COUNT) state.menu = MENU_REBIND;
- } else if(state.menu >= 0){
- if(!pressed) return;
- if(key.sym == SDLK_RETURN || key.sym == SDLK_SPACE){
- switch(state.menu){
- case MENU_QUIT : state.quit = true; break;
- case MENU_PLAY : state.menu = MENU_PLAYING; break;
- case MENU_ASTEROIDS: cfg.num_asteroids = cfg.num_asteroids%4+1; break;
- case MENU_REBIND : state.menu = MENU_REBINDING; state.which_rebind = 0; break;
- default:;
- }
- } else if(key.scancode == cfg.bind_left || key.scancode == SDL_SCANCODE_LEFT){
- state.menu = umod(state.menu-1, MENU_MAX+1);
- } else if(key.scancode == cfg.bind_right || key.scancode == SDL_SCANCODE_RIGHT){
- state.menu = umod(state.menu+1, MENU_MAX+1);
- } else switch(state.menu){
- #ifdef _DEBUG
- case MENU_QUIT: {
- if(key.scancode == SDL_SCANCODE_RSHIFT) mesh_ship.p.yaw = 0.0f;
- } break;
- #endif
- case MENU_ASTEROIDS: {
- if(key.scancode == cfg.bind_back || key.scancode == SDL_SCANCODE_DOWN)
- cfg.num_asteroids = MAX(cfg.num_asteroids-1, 1);
- else if(key.scancode == cfg.bind_forward || key.scancode == SDL_SCANCODE_UP)
- cfg.num_asteroids = MIN(cfg.num_asteroids+1, 4);
- } break;
- default:;
- }
- } else {
- }
- }
- int sceneMain(int argc, char** argv){
- /************************************ INIT ************************************/
- _mesh_ship = new MeshSimple("ship.obj");
- _mesh_skybox = new MeshSimple("skybox.obj");
- _mesh_gear = new MeshSimple("gear.obj");
- _mesh_door = new MeshSimple("door.obj");
- for(unsigned i=0; i<bullet_count; ++i)
- _mesh_bullet(i) = new MeshSimple("bullet.obj");
- for(unsigned i=0; i<asteroid_count; ++i)
- _mesh_asteroid(i) = new MeshSimple("asteroid.obj");
- for(int i=0; i<BIND_COUNT; ++i)
- bind_array_defaults[i] = bind_array[i];
- cfg.version = CFG_VERSION;
- if(file::exists(CFG_FILENAME)){
- BinaryData _cfg_file(CFG_FILENAME);
- _cfg_s* cfg_file = (_cfg_s*)_cfg_file.data;
- //always make sure high score carries over, since i won't be changing its
- //placement between changes to the overall structure of _cfg_s
- cfg.high_score = cfg_file->high_score;
- if( _cfg_file.data_len == sizeof(cfg) &&
- cfg_file->version == cfg.version )
- {
- cfg = *cfg_file;
- }
- }
- sceneRebuild(meshes, meshes_len);
- for(unsigned i=0; i<bullet_count; ++i) mesh_bullet(i).p.scale = bullet_size;
- for(unsigned i=0; i< 4; ++i) mesh_asteroid( i).p.scale = nrml_siz; //normal
- for(unsigned i=0; i<16; ++i) mesh_asteroid( 4+i).p.scale = mini_siz; //mini
- for(unsigned i=0; i<64; ++i) mesh_asteroid(16+4+i).p.scale = mcro_siz; //micro
- state.menu = -1;
- if(cfg.maximized) SDL_MaximizeWindow(canvas->getWin());
- else SDL_SetWindowSize(canvas->getWin(), cfg.win_w, cfg.win_h);
- setFullscreen(cfg.fullscreen);
- SDL_ShowWindow(canvas->getWin());
- canvas->clear();
- canvas->present(0);
- Uint64 startTime;
- SDL_RWops* cfg_file;
- float viewport_fov = 75; //degrees of vertical field of view
- float viewport_mod = tan(viewport_fov/(360.0f/_pi));
- SDL_Rect crosshair = {CNV_W/2-1, CNV_H/2-1, 2, 2};
- for(int n=0; n<4; ++n){
- state_normal(n).children = &state_mini(n*4);
- state_normal(n).vel = Vec3(0.0f, 0.0f, 0.0f);
- state_normal(n).parent_id = -1;
- state_normal(n).children_active = 0;
- state_normal(n).type = ATYPE_NORMAL;
- state_normal(n).active = false;
- }
- for(int m=0; m<16; ++m){
- state_mini(m).children = &state_micro(m*4);
- state_mini(m).vel = Vec3(0.0f, 0.0f, 0.0f);
- state_mini(m).parent_id = m>>2;
- state_mini(m).children_active = 0;
- state_mini(m).type = ATYPE_MINI;
- state_mini(m).active = false;
- }
- for(int u=0; u<64; ++u){
- state_micro(u).children = nullptr;
- state_micro(u).vel = Vec3(0.0f, 0.0f, 0.0f);
- state_micro(u).parent_id = 4 + (u>>2);
- state_micro(u).children_active = -1;
- state_micro(u).type = ATYPE_MICRO;
- state_micro(u).active = false;
- }
- /**********************************/ _MENU: /**********************************/
- #define menu_mesh_spacing 3.0f
- memory::set(&scene_camera, 0, sizeof(scene_camera));
- scene_camera.scale = 1.0f/16;
- scene_camera.pitch = 0.3f;
- scene_camera.y = 0.25f;
- scene_camera.z = -0.25f;
- memory::set(&mesh_ship.p, 0, sizeof(mesh_ship.p));
- mesh_ship.p.scale = 1.0f;
- mesh_ship.p.x = menu_mesh_spacing*MENU_PLAY;
- mesh_ship.p.z = 1.0f;
- memory::set(&mesh_skybox.p, 0, sizeof(mesh_skybox.p));
- memory::set(&mesh_gear.p, 0, sizeof(mesh_gear.p));
- mesh_gear.p.scale = 1.0f;
- mesh_gear.p.x = menu_mesh_spacing*MENU_REBIND;
- mesh_gear.p.z = 1.0f;
- memory::set(&mesh_door.p, 0, sizeof(mesh_door.p));
- mesh_door.p.scale = 1.0f;
- mesh_door.p.x = menu_mesh_spacing*MENU_QUIT;
- mesh_door.p.z = 1.0f;
- for(unsigned i=0; i<bullet_count; ++i){
- mesh_bullet(i).p.y = CLIP_FAR*2;
- state.bullets[i].active = false;
- }
- state.active_bullets = 0;
- for(unsigned i=0; i<asteroid_count; ++i){
- mesh_asteroid(i).p.x = menu_mesh_spacing*MENU_ASTEROIDS;
- mesh_asteroid(i).p.y = CLIP_FAR*2;
- mesh_asteroid(i).p.z = 1.0f;
- }
- asteroid_menu(0).p.x += -menu_siz/2; //bottom-left
- asteroid_menu(0).p.y = -menu_siz/2; //
- asteroid_menu(1).p.x += menu_siz/2; //bottom-right
- asteroid_menu(1).p.y = -menu_siz/2; //
- asteroid_menu(2).p.x += -menu_siz/2; //top-left
- asteroid_menu(2).p.y = menu_siz/2; //
- asteroid_menu(3).p.x += menu_siz/2; //top-right
- asteroid_menu(3).p.y = menu_siz/2; //
- if(state.menu < 0) state.menu = MENU_PLAY;
- camera_old.x = menu_mesh_spacing * state.menu;
- camera_new.x = camera_old.x;
- scene_camera.x = camera_old.x;
- while(!state.quit && state.menu != MENU_PLAYING){
- startTime = SDL_GetTicks64();
- if(!handleEvents()) break;
- if(state.menu >= 0){
- mesh_ship.p.yaw += _2pi/60/8;
- mesh_gear.p.yaw = mesh_ship.p.yaw;
- mesh_door.p.yaw = mesh_ship.p.yaw;
- for(unsigned i=0; i<4; ++i)
- asteroid_menu(i).p.yaw = mesh_ship.p.yaw;
- camera_new.x = menu_mesh_spacing * state.menu;
- scene_camera.x = camera_lpf(x);
- camera_old.x = scene_camera.x;
- asteroid_menu(0).p.z = (cfg.num_asteroids >= 1) ? 1.0f : -100.0f;
- asteroid_menu(1).p.z = (cfg.num_asteroids >= 2) ? 1.0f : -100.0f;
- asteroid_menu(2).p.z = (cfg.num_asteroids >= 3) ? 1.0f : -100.0f;
- asteroid_menu(3).p.z = (cfg.num_asteroids >= 4) ? 1.0f : -100.0f;
- //putting this in this code block technically causes a graphical glitch
- //where the framebuffer elements related to geometry gradually fade
- //out when rebinding controls, but i'll include it until something
- //inexplicably breaks, just because the effect looks so cool
- scene_wka.setAll(scene_ori);
- for(unsigned i=0; i<meshes_len; ++i)
- if(meshes[i]) sceneApplyTransform(meshes[i]);
- sceneApplyTransform(nullptr);
- //(to fix this, simply move the previous 4 lines out of this code block)
- }
- canvas->clear();
- sceneRender(viewport_mod*((float)cfg.win_w/cfg.win_h), viewport_mod);
- #define text_margin (16/(CNV_DIV))
- text_box(CENTER_TEXT, text_margin, 0, WIN_TITLE);
- switch(state.menu){
- case MENU_QUIT : {
- //text_box(CENTER_TEXT, CENTER_TEXT, 0, "(there's supposed to be a\nspinning door here, but i\nhaven't modeled that yet)");
- text_box(CENTER_TEXT, -text_margin-1, 0,
- " \n- QUIT GAME >\n");
- } break;
- case MENU_PLAY : {
- text_box(CENTER_TEXT, -text_margin-1, 0,
- " \n< START GAME >\n");
- } break;
- case MENU_ASTEROIDS: {
- textf_box(CENTER_TEXT, -text_margin-1,
- " ^\n< # OF ASTEROIDS: %i >\n V", cfg.num_asteroids);
- } break;
- case MENU_REBIND : {
- text_box(CENTER_TEXT, -text_margin-1, 0,
- " \n< REBIND CONTROLS -\n");
- } break;
- case MENU_REBINDING: {
- textf_box(CENTER_TEXT, CENTER_TEXT,
- "Press a key for \"%s\"\n(backspace will reset all bindings to their defaults!)", bind_names[state.which_rebind]);
- } break;
- default:;
- }
- canvas->present((unsigned)(MAX(1, (16-(int)(SDL_GetTicks64()-startTime)) )));
- }
- if(state.quit) goto _QUIT;
- while(!cursorIsTrapped){
- if(!handleEvents()) break;
- text_box(CENTER_TEXT, CENTER_TEXT, 0, "(click in the window to start)");
- canvas->present(16);
- }
- srand((unsigned)( SDL_GetTicks64() + (unsigned)(cfg.lastrand*10000) ));
- cfg.lastrand = randf();
- if(!state.quit) goto _GAME;
- /**********************************/ _QUIT: /**********************************/
- cfg_file = SDL_RWFromFile(CFG_FILENAME, "wb");
- if(!cfg_file) throw SDL_GetError();
- if(SDL_RWwrite(cfg_file, &cfg, 1, sizeof(cfg))<sizeof(cfg)) throw SDL_GetError();
- if(SDL_RWclose(cfg_file)<0) throw SDL_GetError();
- for(unsigned i=0; i<meshes_len; ++i)
- SAFE_DELETE(meshes[i]);
- return 0;
- /**********************************/ _GAME: /**********************************/
- mesh_skybox.p.scale = skybox_bounds*2;
- mesh_gear.p.scale = 0.0f;
- mesh_door.p.scale = 0.0f;
- asteroid_menu(0).p.y = CLIP_FAR*2;
- asteroid_menu(1).p.y = CLIP_FAR*2;
- asteroid_menu(2).p.y = CLIP_FAR*2;
- asteroid_menu(3).p.y = CLIP_FAR*2;
- memory::set(&camera_old, 0, sizeof(camera_old));
- memory::set(&camera_cur, 0, sizeof(camera_cur));
- memory::set(&camera_new, 0, sizeof(camera_new));
- memory::set(&mesh_ship.p, 0, sizeof(mesh_ship.p));
- mesh_ship.p.scale = 1.0f;
- scene_camera.yaw = 0.0f;
- scene_camera.pitch = ship_camera_down_tilt;
- scene_camera.roll = 0.0f;
- scene_camera.x = 0.0f;
- scene_camera.y = ship_camera_y_offset;
- scene_camera.z = -ship_camera_distance;
- unsigned ship_offset = mesh_ship.verts_len;
- unsigned num_normal = cfg.num_asteroids ;
- unsigned num_mini = cfg.num_asteroids* 4;
- unsigned num_micro = cfg.num_asteroids*16;
- state.active_asteroids = 0;
- for(int i=0; i<asteroid_count; ++i) state.asteroids[i].active = false;
- _out_of_game_loop: //jumped to for the purpose of forcefully breaking the loop
- while(!state.quit && state.menu == MENU_PLAYING){
- startTime = SDL_GetTicks64();
- if(!handleEvents()) break;
- for(unsigned i=0; i<bullet_count; ++i){
- if(state.bullets[i].active){
- mesh_bullet(i).p.x += state.bullets[i].vel.x;
- mesh_bullet(i).p.y += state.bullets[i].vel.y;
- mesh_bullet(i).p.z += state.bullets[i].vel.z;
- if(keepInBounds(mesh_bullet(i).p)){
- mesh_bullet(i).p.y = CLIP_FAR*2;
- state.bullets[i].active = false;
- --state.active_bullets;
- }
- }
- }
- Vec3 moveVector(0.0f, 0.0f, 0.0f);
- if(state.pressed_right ) moveVector.x += ship_speed_x;
- if(state.pressed_left ) moveVector.x -= ship_speed_x;
- if(state.pressed_forward) moveVector.z += ship_speed_z;
- if(state.pressed_back ) moveVector.z -= ship_speed_z;
- if(state.pressed_up ) moveVector.y += ship_speed_y;
- if(state.pressed_down ) moveVector.y -= ship_speed_y;
- moveCamera(-moveVector.x, -moveVector.y, -moveVector.z);
- keepInBounds(camera_cur);
- for(int b=-1; b<bullet_count; ++b){
- if(b >= 0 && !state.bullets[b].active) continue;
- Location loc = (b>=0) ? mesh_bullet(b).p : camera_cur;
- float l_dist = (b>=0) ? bullet_size/2 : 0.5f;
- for(unsigned n=0; n<num_normal; ++n){
- if(!state_normal(n).active) continue;
- asteroid_normal(n).p.x += state_normal(n).vel.x;
- asteroid_normal(n).p.y += state_normal(n).vel.y;
- asteroid_normal(n).p.z += state_normal(n).vel.z;
- if(locDistance(loc,asteroid_normal(n).p)<(l_dist+nrml_siz)){
- if(b>=0){
- asteroidSplit(n);
- mesh_bullet(b).p.y = CLIP_FAR*2;
- state.bullets[b].active = false;
- --state.active_bullets;
- } else {
- state.menu = MENU_DEAD;
- goto _out_of_game_loop;
- }
- }
- }
- for(unsigned m=0; m<num_mini; ++m){
- if(!state_mini(m).active) continue;
- asteroid_mini(m).p.x += state_mini(m).vel.x;
- asteroid_mini(m).p.y += state_mini(m).vel.y;
- asteroid_mini(m).p.z += state_mini(m).vel.z;
- if(locDistance(loc,asteroid_mini(m).p)<(l_dist+mini_siz)){
- if(b>=0){
- asteroidSplit(4+m);
- mesh_bullet(b).p.y = CLIP_FAR*2;
- state.bullets[b].active = false;
- --state.active_bullets;
- } else {
- state.menu = MENU_DEAD;
- goto _out_of_game_loop;
- }
- }
- }
- for(unsigned u=0; u<num_micro; ++u){
- if(!state_micro(u).active) continue;
- asteroid_micro(u).p.x += state_micro(u).vel.x;
- asteroid_micro(u).p.y += state_micro(u).vel.y;
- asteroid_micro(u).p.z += state_micro(u).vel.z;
- if(locDistance(loc,asteroid_micro(u).p)<(l_dist+mcro_siz)){
- if(b>=0){
- asteroidSplit(4+16+u);
- mesh_bullet(b).p.y = CLIP_FAR*2;
- state.bullets[b].active = false;
- --state.active_bullets;
- } else {
- state.menu = MENU_DEAD;
- goto _out_of_game_loop;
- }
- }
- }
- }
- mesh_ship.p.roll *= ship_decay_multiplier_a;
- mesh_ship.p.pitch *= ship_decay_multiplier_a;
- scene_wka.setAll(scene_ori);
- for(unsigned i=1; i<meshes_len; ++i)
- if(meshes[i]) sceneApplyTransform(meshes[i]);
- //rotate all but the ship's verts
- translateWka(camera_cur, ship_offset, LOOP_END_MAX);
- rotateWka(camera_cur, ship_offset, LOOP_END_MAX);
- meshTransform(mesh_ship);
- sceneApplyTransform(nullptr);
- canvas->clear();
- sceneRender(viewport_mod*((float)cfg.win_w/cfg.win_h), viewport_mod);
- canvas->renderFillRect(&crosshair, 0xffffffff);
- #define brr_width 20
- #define brr_height 40
- #define brr_height_b (int)( (1.0f-((float)(state.active_bullets)/bullet_count))*brr_height )
- SDL_Rect bullets_remaining_rect = {CNV_W-brr_width, CNV_H-brr_height,
- brr_width, brr_height};
- canvas->renderFillRectBordered(bullets_remaining_rect);
- bullets_remaining_rect.w -= 2;
- bullets_remaining_rect.h = MAX(brr_height_b-2, 0);
- bullets_remaining_rect.x += 1;
- bullets_remaining_rect.y = CNV_H-bullets_remaining_rect.h-1;
- canvas->renderFillRect(&bullets_remaining_rect, 0x00ff00);
- textf(4-brr_width/2, 3-brr_height/2, "%u", bullet_count-state.active_bullets);
- //textf_box(0,0,"(backspace returns\nto the main menu)");
- #ifdef _DEBUG
- //bullet queue
- int b=0; for(int i=0; i<bullet_count; ++i) b += state.bullets[i].active;
- textf_box(0,10, "actually active bullets = %u", b);
- #endif
- canvas->present((unsigned)(MAX(1, (16-(int)(SDL_GetTicks64()-startTime)) )));
- }
- //while(!state.quit && state.menu == MENU_DEAD){ }
- //if(state.quit) goto _QUIT;
- if(state.quit) goto _QUIT;
- else goto _MENU;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\src\scene_stuff.cpp":
- #include <scene.hpp>
- Canvas* canvas = nullptr;
- SDL_Surface* geometrySrf = nullptr;
- SDL_Texture* geometryTex = nullptr;
- GeometryBuffer scene_ori; //original state
- GeometryBuffer scene_wka; //work buffer a
- GeometryBuffer scene_wkb; //work buffer b
- Location scene_camera; //camera's position, rotation, and scale
- //does not clean up already allocated stuff on throwing here bc i'm lazy
- Canvas::Canvas(int winW, int winH, int cnvW, int cnvH, const char* title){
- win = SDL_CreateWindow((title) ? title : "",
- SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,
- winW, winH, SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE);
- if(!win){ _throw_sdlerr: throw SDL_GetError(); }
- SDL_SetWindowMinimumSize(win, cnvW, cnvH);
- rnd = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED |
- SDL_RENDERER_TARGETTEXTURE /*|
- SDL_RENDERER_PRESENTVSYNC*/);
- if(!rnd) goto _throw_sdlerr;
- cnv = SDL_CreateTexture(rnd, SDL_PIXELFORMAT_ABGR8888,
- SDL_TEXTUREACCESS_TARGET, cnvW, cnvH);
- if(!cnv) goto _throw_sdlerr;
- //SDL_ShowWindow(win); //done inside sceneMain
- }
- Canvas::~Canvas(){
- if(cnv){ SDL_DestroyTexture (cnv); cnv = nullptr; }
- if(rnd){ SDL_DestroyRenderer(rnd); rnd = nullptr; }
- if(win){ SDL_DestroyWindow (win); win = nullptr; }
- }
- //only triangle faces are allowed! also, any material data is ignored!
- MeshSimple::MeshSimple(const char* fileName){
- if(!file::exists(fileName)) throw fstr("obj file \"%s\" does not exist", fileName);
- //note: vertex data counts include the padding at index 0,
- //so a single triangle would actually have a count of 4
- //furthermore, the positions array has a length of count*3,
- //so the first vertex would actually start at index 3
- //(this goes for texcoords and normals too, though
- // texcoords has a length of count*2 instead of count*3)
- //(THIS ALSO GOES FOR INDICES)
- fastObjMesh* msh = fast_obj_read(fileName);
- if(!msh) throw "failed to read obj file";
- first_index = -1; //placeholder
- p.yaw = 0.0f;
- p.pitch = 0.0f;
- p.roll = 0.0f;
- p.scale = 1.0f;
- p.x=p.y=p.z = 0.0f;
- verts_len = msh->face_count * 3;
- verts = (Vertex*)memory::allocSIMD(verts_len * sizeof(Vertex));
- memory::set(verts, 255, verts_len * sizeof(Vertex));
- int faces_len = msh->face_count;
- Triangle* faces = (Triangle*)verts;
- const fastObjIndex* indices = msh->indices;
- const Vec3* positions = (Vec3*)msh->positions;
- const Vec2* texcoords = (Vec2*)msh->texcoords;
- const Vec3* normals = (Vec3*)msh->normals;
- for(int i=0; i<faces_len; ++i){
- if(msh->face_vertices[i] != 3)
- throw "obj cannot have non-triangle faces";
- fastObjIndex index_a = indices[i*3 + 0];
- fastObjIndex index_b = indices[i*3 + 1];
- fastObjIndex index_c = indices[i*3 + 2];
- faces[i].a.p = positions[index_a.p];
- faces[i].b.p = positions[index_b.p];
- faces[i].c.p = positions[index_c.p];
- faces[i].a.t = texcoords[index_a.t];
- faces[i].b.t = texcoords[index_b.t];
- faces[i].c.t = texcoords[index_c.t];
- faces[i].a.n = normals[index_a.n];
- faces[i].b.n = normals[index_b.n];
- faces[i].c.n = normals[index_c.n];
- }
- fast_obj_destroy(msh);
- }
- MeshSimple::~MeshSimple(){
- SAFE_FREE_SIMD(verts);
- }
- void sceneRebuild(MeshSimple** meshes, int meshes_len){
- if(!meshes) throw "meshes = nullptr";
- unsigned vert_count_total = 0;
- for(int m=0; m<meshes_len; ++m){
- if(!meshes[m]) continue;
- meshes[m]->first_index = vert_count_total;
- vert_count_total += meshes[m]->verts_len;
- }
- scene_ori.reallocAll(vert_count_total);
- scene_wka.reallocAll(vert_count_total);
- scene_wkb.reallocAll(vert_count_total);
- scene_camera.yaw = 0.0f;
- scene_camera.pitch = 0.0f;
- scene_camera.roll = 0.0f;
- scene_camera.scale = 1.0f;
- scene_camera.x = 0.0f;
- scene_camera.y = 0.0f;
- scene_camera.z = 0.0f;
- int vo = 0;
- for(int m=0; m<meshes_len; ++m){
- MeshSimple* mesh = meshes[m];
- if(!mesh) continue;
- Vertex* verts = mesh->verts;
- unsigned verts_len = mesh->verts_len;
- for(unsigned v=0; v<verts_len; ++v){
- Vertex vert = verts[v];
- scene_ori.p[vo].x = vert.px;
- scene_ori.p[vo].y = vert.py;
- scene_ori.colors[vo] = vert.color;
- scene_ori.t[vo].x = vert.t.x;
- //the uv coords seem to be flipped on the y axis for some reason
- scene_ori.t[vo].y = 1.0f-vert.t.y;
- scene_ori.p_z[vo] = vert.pz;
- scene_ori.n[vo] = vert.n;
- scene_ori.indices[vo] = vo;
- //make uv coords wrap around if outside range of 0.0f -> 1.0f
- #if UV_COORD_WRAPAROUND == 1
- scene_ori.t[vo].x = fmodf(scene_ori.t[vo].x, 1.0f);
- scene_ori.t[vo].y = fmodf(scene_ori.t[vo].y, 1.0f);
- if(scene_ori.t[vo].x < 0.0f) scene_ori.t[vo].x += 1.0f;
- if(scene_ori.t[vo].y < 0.0f) scene_ori.t[vo].y += 1.0f;
- #endif
- ++vo;
- }
- }
- }
- void rotateWka(Location p, unsigned loop_start, unsigned loop_end){
- loop_end = MIN(loop_end, scene_wka.num_vertices);
- loop_start = MIN(loop_start, loop_end);
- const float cosYaw = cosf(p.yaw );
- const float sinYaw = sinf(p.yaw );
- const float cosPitch = cosf(p.pitch);
- const float sinPitch = sinf(p.pitch);
- const float cosRoll = cosf(p.roll );
- const float sinRoll = sinf(p.roll );
- for(unsigned i=loop_start; i<loop_end; ++i){
- //vertex positions
- float x0 = scene_wka.p[i].x;
- float y0 = scene_wka.p[i].y;
- float z0 = scene_wka.p_z[i];
- float x1 = cosYaw *x0 + sinYaw *z0;
- float z1 = -sinYaw *x0 + cosYaw *z0;
- float y1 = cosPitch*y0 - sinPitch*z1;
- scene_wka.p_z[i] = sinPitch*y0 + cosPitch*z1;
- scene_wka.p[i].x = cosRoll *x1 - sinRoll *y1;
- scene_wka.p[i].y = sinRoll *x1 + cosRoll *y1;
- //vertex normals (currently unused)
- /* tbd: uncomment these once they start being used
- x0 = scene_wka.n[i].x;
- y0 = scene_wka.n[i].y;
- z0 = scene_wka.n[i].z;
- x1 = cosYaw *x0 + sinYaw *z0;
- z1 = -sinYaw *x0 + cosYaw *z0;
- y1 = cosPitch*y0 - sinPitch*z1;
- scene_wka.n[i].x = sinPitch*y0 + cosPitch*z1;
- scene_wka.n[i].y = cosRoll *x1 - sinRoll *y1;
- scene_wka.n[i].z = sinRoll *x1 + cosRoll *y1;
- */
- }
- }
- void scaleWka(Location p, unsigned loop_start, unsigned loop_end){
- loop_end = MIN(loop_end, scene_wka.num_vertices);
- loop_start = MIN(loop_start, loop_end);
- if(p.scale != 0.0f){
- for(unsigned i=loop_start; i<loop_end; ++i){
- scene_wka.p[i].x *= p.scale;
- scene_wka.p[i].y *= p.scale;
- scene_wka.p_z[i] *= p.scale;
- }
- } else {
- memory::set(&scene_wka.p[loop_start], 0,
- (loop_end-loop_start)*sizeof(scene_wka.p[loop_start]));
- memory::set(&scene_wka.p_z[loop_start], 0,
- (loop_end-loop_start)*sizeof(scene_wka.p_z[loop_start]));
- }
- }
- void translateWka(Location p, unsigned loop_start, unsigned loop_end){
- loop_end = MIN(loop_end, scene_wka.num_vertices);
- loop_start = MIN(loop_start, loop_end);
- for(unsigned i=loop_start; i<loop_end; ++i){
- scene_wka.p[i].x += p.x;
- scene_wka.p[i].y += p.y;
- scene_wka.p_z[i] += p.z;
- }
- }
- //operates on scene_wka, while assuming that
- //the contents of scene_ori were just copied
- //if mesh == nullptr, translate camera (AKA the entirety of wka)
- void sceneApplyTransform(MeshSimple* mesh){
- if(mesh != nullptr){
- const Location p = mesh->p;
- const unsigned loop_start = mesh->first_index;
- const unsigned loop_end = loop_start + mesh->verts_len;
- const bool shouldRotate = p.yaw || p.pitch || p.roll;
- const bool shouldScale = p.scale != 1.0f;
- const bool shouldTranslate = p.x || p.y || p.z;
- //if mesh is to be transformed, order is: rotate, scale, translate
- if(shouldRotate ) rotateWka (p, loop_start, loop_end);
- if(shouldScale ) scaleWka (p, loop_start, loop_end);
- if(shouldTranslate) translateWka(p, loop_start, loop_end);
- } else {
- Location _p = scene_camera;
- _p.yaw = -_p.yaw;
- _p.pitch = -_p.pitch;
- _p.roll = -_p.roll;
- if(_p.scale != 0.0f) _p.scale = 1.0f/_p.scale;
- _p.x = -_p.x;
- _p.y = -_p.y;
- _p.z = -_p.z;
- const Location p = _p;
- const unsigned loop_start = 0;
- const unsigned loop_end = scene_wka.num_vertices;
- const bool shouldRotate = p.yaw || p.pitch || p.roll;
- const bool shouldScale = p.scale != 1.0f;
- const bool shouldTranslate = p.x || p.y || p.z;
- //if camera is to be transformed, order is: translate, rotate, scale
- if(shouldTranslate) translateWka(p, loop_start, loop_end);
- if(shouldRotate ) rotateWka (p, loop_start, loop_end);
- if(shouldScale ) scaleWka (p, loop_start, loop_end);
- }
- }
- #define CBF_ADD_VERT { \
- scene_wkb.p [scene_wkb.num_vertices] = scene_wka.p[i]; \
- scene_wkb.colors [scene_wkb.num_vertices] = scene_wka.colors[i]; \
- scene_wkb.t [scene_wkb.num_vertices] = scene_wka.t[i]; \
- /*redundant; indices are set at sceneClipPlanesAndLumFade*/ \
- /*scene_wkb.indices[scene_wkb.num_vertices] = scene_wkb.num_vertices;*/ \
- scene_wkb.p_z [scene_wkb.num_vertices] = scene_wka.p_z[i]; \
- scene_wkb.n [scene_wkb.num_vertices] = scene_wka.n[i]; \
- scene_wkb.mids [scene_wkb.num_vertices] = midpoint; \
- ++scene_wkb.num_vertices; }
- //reminder, dot product is: "(a.x * b.x) + (a.y * b.y) + (a.z * b.z)"
- static inline bool isBackFace(Vec3 midpoint, Vec3 surface_normal){
- return ( (-midpoint.x*surface_normal.x) +
- (-midpoint.y*surface_normal.y) +
- (-midpoint.z*surface_normal.z) ) < 0.0f;
- }
- //wkb = backface_cull(wka)
- void sceneCullBackFaces(){
- scene_wkb.num_vertices = 0;
- for(unsigned i=0; i<scene_wka.num_vertices;){
- unsigned _i = i;
- Vec3 a(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]); ++_i;
- Vec3 b(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]); ++_i;
- Vec3 c(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]); ++_i;
- Vec3 u(b.x-a.x, b.y-a.y, b.z-a.z);
- Vec3 v(c.x-a.x, c.y-a.y, c.z-a.z);
- Vec3 midpoint;
- midpoint.x = (a.x + b.x + c.x) * 0.333333333f;
- midpoint.y = (a.y + b.y + c.y) * 0.333333333f;
- midpoint.z = (a.z + b.z + c.z) * 0.333333333f;
- Vec3 surface_normal;
- surface_normal.x = u.y*v.z - u.z*v.y;
- surface_normal.y = u.z*v.x - u.x*v.z;
- surface_normal.z = u.x*v.y - u.y*v.x;
- if(!isBackFace(midpoint, surface_normal)){
- CBF_ADD_VERT; ++i;
- CBF_ADD_VERT; ++i;
- CBF_ADD_VERT; ++i;
- } else {
- i += 3;
- }
- }
- }
- #define CPLF_ADD_VERT(z_) { \
- luminosity = 1.0f - ((z_-CLIP_NEAR)/(CLIP_FAR-CLIP_NEAR)); \
- color = (scene_wkb.colors[i].v&255) * luminosity; \
- color |= color<< 8; \
- color |= color<<16; \
- \
- scene_wka.p [scene_wka.num_vertices] = scene_wkb.p[i]; \
- scene_wka.colors [scene_wka.num_vertices].v = color; \
- scene_wka.t [scene_wka.num_vertices] = scene_wkb.t[i]; \
- scene_wka.indices[scene_wka.num_vertices] = scene_wka.num_vertices; \
- scene_wka.p_z [scene_wka.num_vertices] = scene_wkb.p_z[i]; \
- scene_wka.n [scene_wka.num_vertices] = scene_wkb.n[i]; \
- scene_wka.mids [scene_wka.num_vertices] = scene_wkb.mids[i]; \
- ++scene_wka.num_vertices; }
- //wka = plane_clip(wkb)
- //wka = apply_luminosity_fade(wka)
- void sceneClipPlanesAndLumFade(){
- #if PRECISE_CLIPPING == 0
- scene_wka.num_vertices = 0;
- for(unsigned i=0; i<scene_wkb.num_vertices;){
- unsigned _i = i;
- float za = scene_wkb.p_z[_i]; ++_i;
- float zb = scene_wkb.p_z[_i]; ++_i;
- float zc = scene_wkb.p_z[_i]; ++_i;
- #ifndef CLIP_NEAR
- #define CLIP_NEAR 1.0f
- #define CLIP_NEAR_WAS_UNDEF
- #endif
- //if triangle is out of bounds z-wise, don't append it to wka
- if(za < CLIP_NEAR || za >= CLIP_FAR ||
- zb < CLIP_NEAR || zb >= CLIP_FAR ||
- zc < CLIP_NEAR || zc >= CLIP_FAR )
- {
- i += 3;
- } else {
- float luminosity; unsigned color;
- CPLF_ADD_VERT(za); ++i;
- CPLF_ADD_VERT(zb); ++i;
- CPLF_ADD_VERT(zc); ++i;
- }
- #ifdef CLIP_NEAR_WAS_UNDEF
- #undef CLIP_NEAR
- #undef CLIP_NEAR_WAS_UNDEF
- #endif
- }
- #else
- scene_wka.setAll(scene_wkb);
- #endif
- }
- #define SP_ADD_VERT(_p) { \
- scene_wkb.p [scene_wkb.num_vertices].x = _p.x; \
- scene_wkb.p [scene_wkb.num_vertices].y = _p.y; \
- scene_wkb.colors [scene_wkb.num_vertices] = scene_wka.colors[i]; \
- scene_wkb.t [scene_wkb.num_vertices] = scene_wka.t[i]; \
- scene_wkb.indices[scene_wkb.num_vertices] = scene_wkb.num_vertices; \
- scene_wkb.p_z [scene_wkb.num_vertices] = _p.z; \
- scene_wkb.n [scene_wkb.num_vertices] = scene_wka.n[i]; \
- scene_wkb.mids [scene_wkb.num_vertices] = scene_wka.mids[i]; \
- ++scene_wkb.num_vertices; }
- #define SIMPLE_PROJECTION 0
- //wkb = project(wka) (also culls triangles that are off-screen)
- void sceneProject(float viewportMultiplierX, float viewportMultiplierY){
- #if SIMPLE_PROJECTION == 1
- scene_wkb.setAll(scene_wka);
- // /=z
- for(unsigned i=0; i<scene_wkb.num_vertices; ++i){
- scene_wkb.p[i].x /= scene_wkb.p_z[i];
- scene_wkb.p[i].y /= scene_wkb.p_z[i];
- }
- // move to screenspace
- for(unsigned i=0; i<scene_wkb.num_vertices; ++i){
- scene_wkb.p[i].x *= CNV_W/2; scene_wkb.p[i].x += CNV_W/2;
- scene_wkb.p[i].y *= -CNV_H/2; scene_wkb.p[i].y += CNV_H/2;
- }
- #else
- scene_wkb.num_vertices = 0;
- //for dividing via multiplying by the inverse of the divisor
- float v_x_inv = 1.0f/viewportMultiplierX;
- float v_y_inv = 1.0f/viewportMultiplierY;
- for(unsigned i=0; i<scene_wka.num_vertices;){
- unsigned _i = i;
- Vec3 a(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]); ++_i;
- Vec3 b(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]); ++_i;
- Vec3 c(scene_wka.p[_i].x, scene_wka.p[_i].y, scene_wka.p_z[_i]); ++_i;
- // (P*d)/z = P'
- // *= d (near plane)
- #ifdef CLIP_NEAR //if undefined, CLIP_NEAR is assumed to equal 1.0f
- a.x *= CLIP_NEAR, a.y *= CLIP_NEAR;
- b.x *= CLIP_NEAR, b.y *= CLIP_NEAR;
- c.x *= CLIP_NEAR, c.y *= CLIP_NEAR;
- #endif
- // /= z
- a.x /= a.z, a.y /= a.z;
- b.x /= b.z, b.y /= b.z;
- c.x /= c.z, c.y /= c.z;
- // (P'*C)/V
- // *C
- a.x *= CNV_W/2, a.y *= -CNV_H/2; //(-canvas_height, otherwise things will
- b.x *= CNV_W/2, b.y *= -CNV_H/2; //appear upside-down!)
- c.x *= CNV_W/2, c.y *= -CNV_H/2;
- // /V
- a.x *= v_x_inv, a.y *= v_y_inv; //remember, this is actually a division
- b.x *= v_x_inv, b.y *= v_y_inv;
- c.x *= v_x_inv, c.y *= v_y_inv;
- //push right and down into screen space
- a.x += CNV_W/2, a.y += CNV_H/2;
- b.x += CNV_W/2, b.y += CNV_H/2;
- c.x += CNV_W/2, c.y += CNV_H/2;
- //copy triangle to wkb, unless all 3 points are off-screen
- if( (a.x < 0 || a.x >= CNV_W || a.y < 0 || a.y >= CNV_H) &&
- (b.x < 0 || b.x >= CNV_W || b.y < 0 || b.y >= CNV_H) &&
- (c.x < 0 || c.x >= CNV_W || c.y < 0 || c.y >= CNV_H) )
- {
- i += 3;
- } else {
- SP_ADD_VERT(a); ++i;
- SP_ADD_VERT(b); ++i;
- SP_ADD_VERT(c); ++i;
- }
- }
- #endif
- }
- void sceneZSort(){
- //compiler complains if i try to capture scene_wkb directly
- GeometryBuffer wkb_copy = scene_wkb;
- std::sort(wkb_copy.indices_v, wkb_copy.indices_v+wkb_copy.num_vertices/3,
- [&wkb_copy](Vec3Int a, Vec3Int b){
- return wkb_copy.mids[b.x].z<wkb_copy.mids[a.x].z;
- });
- }
- void scenePS1Geometry(GeometryBuffer& buffer){
- #if PS1_SNAP > 0
- unsigned num_vertices = buffer.num_vertices;
- Vec2* xy = buffer.p;
- float* z = buffer.p_z;
- for(unsigned i=0; i<num_vertices; ++i){
- #define _PS1_SNAP (PS1_SNAP PS1_SNAP_MOD)
- #define VERT_SNAP(value) ( (float)((s64)((value)*_PS1_SNAP)) / _PS1_SNAP )
- xy[i].x = VERT_SNAP(xy[i].x);
- xy[i].y = VERT_SNAP(xy[i].y);
- z[i] = VERT_SNAP(z[i] );
- }
- #endif
- }
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\src\Text.cpp":
- #include <scene.hpp>
- char _fstr_failure[] = "(FSTR FAILED)";
- char _fstr[2][FSTR_LEN];
- int _fstr_which = 0;
- Text* text_p = nullptr;
- //assumes that font image uses accepted dimensions and formatting,
- //and that black is used as the transparent color
- Text::Text(const char* bmpPath){
- if(!file::exists(bmpPath)) throw fstr("font bitmap \"%s\" doesn't exist", bmpPath);
- SDL_Surface* _input = SDL_LoadBMP(bmpPath);
- if(!_input) throw SDL_GetError();
- SDL_Surface* input = SDL_ConvertSurfaceFormat(_input, SDL_PIXELFORMAT_ABGR8888, 0);
- SDL_FreeSurface(_input); //shouldn't overwrite sdl error
- if(!input) throw SDL_GetError();
- SDL_SetColorKey(input, SDL_TRUE, 0xff000000);
- w = (input->w/16)-1;
- h = (input->h/16)-1;
- if(!canvas) throw "canvas object doesn't exist";
- atlas = SDL_CreateTextureFromSurface(canvas->getRnd(), input);
- SDL_FreeSurface(input);
- if(!atlas) throw SDL_GetError();
- }
- SDL_Point Text::getTextSize(const char* text, float scale){
- if(!text) throw "string given to Text was nullptr";
- SDL_Point scaled_dimensions = { MAX((int)(w*scale),1), MAX((int)(h*scale),1) };
- SDL_Point size = { 0, scaled_dimensions.y*(*text!=0) };
- char chr;
- int max_width = 0;
- while( (chr=*(text++)) )
- if(chr == '\n'){
- if(max_width < size.x) max_width = size.x;
- size.x = 0;
- size.y += scaled_dimensions.y;
- } else {
- size.x += scaled_dimensions.x;
- }
- if(size.x < max_width) size.x = max_width;
- return size;
- }
- void Text::draw(int x, int y, const char* _text, unsigned maxLen, float scale){
- if(!_text) throw "string given to Text was nullptr";
- bool cnvWasTarget = canvas->isCnvTarget();
- SDL_Renderer* rnd = canvas->getRnd();
- SDL_Texture* cnv = canvas->getCnv();
- if(!cnvWasTarget && SDL_SetRenderTarget(rnd,cnv)<0)
- throw SDL_GetError();
- //if high bit of maxLen is set, ignore automatic origin rules
- if(!(maxLen&0x80000000)){
- SDL_Point textSize;
- bool getTextSize_called = false;
- if(x < 0){
- textSize = getTextSize(_text, scale);
- getTextSize_called = true;
- if(x == CENTER_TEXT) x = CNV_W/2 - textSize.x/2;
- else x = CNV_W - textSize.x + x + 1;
- }
- if(y < 0){
- if(!getTextSize_called)
- textSize = getTextSize(_text, scale);
- if(y == CENTER_TEXT) y = CNV_H/2 - textSize.y/2;
- else y = CNV_H - textSize.y + y + 1;
- }
- } else {
- maxLen &= 0x7fffffff;
- }
- SDL_Rect src = {0,0, w,h};
- SDL_Rect dst = {x,y, MAX((int)(w*scale), 1),
- MAX((int)(h*scale), 1)};
- int src_stride_w = src.w + 1;
- int src_stride_h = src.h + 1;
- const unsigned char* text = (unsigned char*)_text;
- unsigned char chr;
- if(!maxLen) --maxLen;
- while( (chr=*(text++)) && (maxLen--) )
- if(chr == '\n'){
- dst.x = x;
- dst.y += dst.h;
- } else {
- src.x = ( chr &15)*src_stride_w + 1;
- src.y = ((chr>>4)&15)*src_stride_h + 1;
- if(SDL_RenderCopy(rnd, atlas, &src, &dst)<0) throw SDL_GetError();
- dst.x += dst.w;
- }
- if(!cnvWasTarget && SDL_SetRenderTarget(rnd,nullptr)<0)
- throw SDL_GetError();
- }
- void Text::drawBox(int x, int y, const char* text, unsigned maxLen, float scale){
- SDL_Point textSize = getTextSize(text, scale);
- SDL_Rect dst = {x,y, textSize.x+3,textSize.y+3};
- if(dst.x == CENTER_TEXT) dst.x = CNV_W/2 - dst.w/2;
- else if(dst.x < 0) dst.x = CNV_W - dst.w + dst.x + 1;
- if(dst.y == CENTER_TEXT) dst.y = CNV_H/2 - dst.h/2;
- else if(dst.y < 0) dst.y = CNV_H - dst.h + dst.y + 1;
- #define B_C 0xc0
- #define BORDER_COLOR ABGR(B_C,B_C,B_C,255)
- canvas->renderFillRectBordered(dst, BORDER_COLOR, 0xff000000);
- draw(dst.x+2,dst.y+2, text, 0x80000000|maxLen, scale);
- }
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\include\common.hpp":
- #ifndef _UTILS_COMMON_HPP
- #define _UTILS_COMMON_HPP
- #include <SDL2/SDL.h>
- //#include <immintrin.h>
- #include <algorithm> //for std::sort
- #define INT_S32_MAX (0x7fffffff)
- #define INT_U64_MSb (0x8000000000000000)
- #define _pi (3.1415926535897932384626433f) //overkill for single-precision lol
- #define _2pi (_pi*2)
- #define _pi2 (_pi/2)
- #define _pi4 (_pi/4)
- #define _pi8 (_pi/8)
- #define MIN(_a, _b) ( ((_a)<(_b)) ? (_a) : (_b) )
- #define MAX(_a, _b) ( ((_a)>(_b)) ? (_a) : (_b) )
- #define MIN3(_a, _b, _c) MIN(MIN(_a, _b), _c)
- #define MAX3(_a, _b, _c) MAX(MAX(_a, _b), _c)
- #define CLAMP(_n, _mn, _mx) MIN(MAX(_n, _mn),_mx)
- #define SAFE_FREE(ptr) if(ptr){ memory::free(&ptr); ptr = nullptr; }
- #define SAFE_FREE_SIMD(ptr) if(ptr){ memory::freeSIMD(&ptr); ptr = nullptr; }
- #define SAFE_DELETE(ptr) if(ptr){ delete ptr; ptr = nullptr; }
- #ifdef _DEBUG
- #define Log(...) SDL_Log(__VA_ARGS__)
- #else
- #define Log(...)
- #endif /* _DEBUG */
- #define loghere Log("\"%s\": %3i",__FILE__,__LINE__);
- typedef Uint8 u8;
- typedef Uint16 u16;
- typedef Uint32 u32;
- typedef Uint64 u64;
- typedef Sint8 s8;
- typedef Sint16 s16;
- typedef Sint32 s32;
- typedef Sint64 s64;
- typedef float f32;
- typedef double f64;
- namespace shape {
- typedef SDL_Point point;
- typedef SDL_FPoint pointf;
- typedef SDL_Rect rect;
- typedef SDL_FRect rectf;
- };
- #endif /* _UTILS_COMMON_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\include\file.hpp":
- #ifndef _UTILS_FILE_HPP
- #define _UTILS_FILE_HPP
- #include "common.hpp"
- namespace file {
- bool exists(const char* filePath);
- s32 getSize(const char* filePath);
- };
- struct BinaryData { //16B
- union {
- void* const ptr;
- char* const data = nullptr;
- };
- const size_t data_len = 0;
- BinaryData(const char* filePath);
- BinaryData(const void* data, size_t dataSize){ loadFromMemory(data, dataSize); }
- ~BinaryData();
- //will (re)allocate dataSize bytes for _data, before copying data to _data
- //(if data is nullptr, this behaves as if you were realloc'ing _data)
- //(also, the actual num of bytes copied is equal to MIN(dataSize, data_len))
- void loadFromMemory(const void* data, size_t dataSize);
- };
- #endif /* _UTILS_FILEDATA_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\include\memory.hpp":
- #ifndef _UTILS_MEMORY_HPP
- #define _UTILS_MEMORY_HPP
- #include "common.hpp"
- namespace memory {
- void* alloc(size_t size);
- //this version of free is especially useful, because it's safe to pass nullptr to!
- //this rule goes for both ptr_p and *ptr_p
- #ifndef free
- #define free _free_real
- #endif /* free */
- void _free_real(void* ptr_p);
- //^^i would call this just free, but that seems to cause conflicts
- //if calling free from memory::free, resulting in recursion >:(
- #ifndef realloc
- #define realloc _realloc_real
- #endif /* realloc */
- void* _realloc_real(void* ptr_p, size_t newSize);
- //^^(for both free and realloc, a void** declared in function as void*,
- // so you don't need to explicitly cast it to void**)
- size_t getNumAllocations();
- void* allocSIMD(size_t size);
- void freeSIMD(void* ptr_p);
- void* reallocSIMD(void* ptr_p, size_t newSize);
- size_t getSIMDAlignment();
- struct wrapper {
- void* ptr = nullptr;
- inline wrapper(size_t size){ if(!(ptr=alloc(size))) throw "Failed to allocate memory"; }
- inline ~wrapper(){ _free_real(&ptr); }
- inline void* reallocate(size_t newSize){ return _realloc_real(&ptr, newSize); }
- };
- struct wrapperSIMD {
- void* ptr = nullptr;
- inline wrapperSIMD(size_t size){ if(!(ptr=allocSIMD(size))) throw "Failed to allocate SIMD memory"; }
- inline ~wrapperSIMD(){ freeSIMD(&ptr); }
- inline void* reallocate(size_t newSize){ return reallocSIMD(&ptr, newSize); }
- };
- void* set(void* dst, char v, size_t size);
- void* copy(void* dst, const void* src, size_t size);
- }; /* namespace memory */
- #endif /* _UTILS_MEMORY_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\include\scene.hpp":
- #ifndef _SCENE_HPP
- #define _SCENE_HPP
- #include <common.hpp>
- #include <file.hpp>
- #include <memory.hpp>
- #include <Text.hpp>
- #include <fast_obj.hpp>
- /*
- //fov (in degrees) to viewport dimensions, assuming near plane = 1
- //( v=tan(f/(360/pi)), f=atan(v*(360/pi)) )
- #define fx_360_pi (360.0/pi)
- #define FOV_TO_VIEWPORT(_fov ) (tan((_fov)/fx_360_pi))
- #define VIEWPORT_TO_FOV(_view) (atan(_view)*fx_360_pi)
- */
- #define WIN_W 512*2
- #define WIN_H 288*2
- #define CNV_DIV 2
- #ifdef _DEBUG
- #define WIN_TITLE "Not Asteroids (DEBUG BUILD)"
- #else
- #define WIN_TITLE "Not Asteroids"
- #endif
- #define TRAP_PROMPT "(press f11 to enable fullscreen)"
- #define UNTRAP_PROMPT "(press f11 to enable fullscreen; esc to free mouse)"
- #define CNV_W ((WIN_W)/(CNV_DIV))
- #define CNV_H ((WIN_H)/(CNV_DIV))
- //#define CLIP_NEAR 0.8f //if undefined, near plane is assumed to be 1.0f
- #define CLIP_FAR 768.0f//512.0f
- //will simplify vertex positions to 1/PS1_SNAP'th
- //(if 0, feature is disabled)
- #define PS1_SNAP 8
- #define PS1_SNAP_MOD
- #define cosf cosf
- #define sinf sinf
- //will make any texture coordinates wrap around to fit within the 0.0-1.0 range
- //(will turn 1.3 to 0.3, -0.3 to 0.7, and so on)
- #define UV_COORD_WRAPAROUND 1 //0&1 to disable and enable respectively
- //if 1, proper clip plane handling will be enabled, instead of triangles simply
- //disappearing the moment a triangle passes through a clip plane boundary
- #define PRECISE_CLIPPING 0 //(currently not implemented; keep this equal to 0)
- struct Vec2 {
- float x, y;
- inline Vec2(float _x, float _y) : x(_x), y(_y) {}
- inline Vec2() : x(0), y(0) {}
- };
- struct Vec3 {
- float x, y, z;
- inline Vec3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
- inline Vec3() : x(0), y(0), z(0) {}
- inline Vec3& operator*=(const float& m){ x*=m, y*=m, z*=m; return *this; }
- } __attribute__((packed));
- struct Vec3Int { int x, y, z; } __attribute__((packed));
- struct Vec4 { float x, y, z, w; };
- union ABGR {
- unsigned v;
- struct {
- unsigned char r;
- unsigned char g;
- unsigned char b;
- unsigned char a;
- };
- inline ABGR() : v(0) {}
- inline ABGR(unsigned _v) : v(_v) {}
- inline ABGR(char _r, char _g, char _b, char _a) : r(_r), g(_g), b(_b), a(_a) {}
- };
- struct Vertex { //40B; 3D vertex
- union {
- Vec3 p;
- struct { float px, py, pz; } __attribute__((packed));
- };
- ABGR color;
- union {
- Vec2 t;
- struct { float tx, ty; }; };
- union {
- Vec3 n;
- struct { float nx, ny, nz; } __attribute__((packed));
- };
- unsigned _padding32;
- };
- struct Triangle { Vertex a, b, c; };
- struct Location {
- //(transformations are applied in order of how they appear here)
- float yaw, pitch, roll;
- float scale;
- float x, y, z;
- } __attribute__((packed));
- class Canvas;
- struct GeometryBuffer { //fed into SDL_RenderGeometryRaw
- Vec2* p = nullptr; //vertex positions
- ABGR* colors = nullptr;
- Vec2* t = nullptr; //uv coords
- union {
- Vec3Int* indices_v;
- int* indices = nullptr;
- };
- //(z axis is separated, since SDL_RenderGeometryRaw doesn't use it)
- float* p_z = nullptr;
- Vec3* n = nullptr; //normals
- Vec3* mids = nullptr; //face midpoints
- size_t num_vertices = 0;
- void reallocAll(size_t n_v){
- if(0){ _oom_error: throw "failed to reallocate memory for GeometryBuffer"; }
- if(!memory::reallocSIMD(&p, n_v * sizeof(p[0] ))) goto _oom_error;
- if(!memory::reallocSIMD(&colors, n_v * sizeof(colors[0] ))) goto _oom_error;
- if(!memory::reallocSIMD(&t, n_v * sizeof(t[0] ))) goto _oom_error;
- if(!memory::reallocSIMD(&indices, n_v * sizeof(indices[0]))) goto _oom_error;
- if(!memory::reallocSIMD(&p_z, n_v * sizeof(p_z[0] ))) goto _oom_error;
- if(!memory::reallocSIMD(&n, n_v * sizeof(n[0] ))) goto _oom_error;
- if(!memory::reallocSIMD(&mids, n_v * sizeof(mids[0] ))) goto _oom_error;
- num_vertices = n_v;
- }
- void freeAll(){
- SAFE_FREE_SIMD(p );
- SAFE_FREE_SIMD(colors );
- SAFE_FREE_SIMD(t );
- SAFE_FREE_SIMD(indices);
- SAFE_FREE_SIMD(p_z );
- SAFE_FREE_SIMD(n );
- SAFE_FREE_SIMD(mids );
- num_vertices = 0;
- }
- //assumes both this and src have the same or larger allocated sizes,
- //otherwise this will probably break catastrophically
- void setAll(GeometryBuffer& src){
- memory::copy(p, src.p, src.num_vertices * sizeof(p[0] ));
- memory::copy(colors, src.colors, src.num_vertices * sizeof(colors[0] ));
- memory::copy(t, src.t, src.num_vertices * sizeof(t[0] ));
- memory::copy(indices, src.indices, src.num_vertices * sizeof(indices[0]));
- memory::copy(p_z, src.p_z, src.num_vertices * sizeof(p_z[0] ));
- memory::copy(n, src.n, src.num_vertices * sizeof(n[0] ));
- memory::copy(mids, src.mids, src.num_vertices * sizeof(mids[0] ));
- num_vertices = src.num_vertices;
- }
- };
- extern Canvas* canvas;
- extern SDL_Surface* geometrySrf;
- extern SDL_Texture* geometryTex;
- //pipeline goes as follows:
- //
- //wka = ori (deep copy)
- //transform meshes in wka (in order of operation):
- // rotate
- // scale
- // translate
- //wka = camera_rotate(wka):
- // translate
- // rotate
- // scale
- //
- //wkb = backface_cull(wka)
- //
- //wka = plane_clip(wkb)
- //wka = apply_luminosity_fade(wka)
- //
- //wkb = project(wka) (also culls triangles that are off-screen)
- //wkb = z_sort(wkb) (make sure to reset indices before doing this!)
- //render(wkb)
- extern GeometryBuffer scene_ori; //original state
- extern GeometryBuffer scene_wka; //work buffer a
- extern GeometryBuffer scene_wkb; //work buffer b
- //camera's position, rotation, and scale
- //(unlike meshes, the camera's scale is the inverse of the scene scale result,
- // meaning that the scene's scale is 1.0f/scene_camera.scale. For example,
- // a scene_camera.scale of 0.25f will grow the scene by 4x)
- extern Location scene_camera;
- class Canvas {
- SDL_Window* win = nullptr;
- SDL_Renderer* rnd = nullptr;
- SDL_Texture* cnv = nullptr;
- bool cnvIsTarget = false;
- public:
- Canvas(int winW, int winH, int cnvW, int cnvH, const char* title = nullptr);
- ~Canvas();
- inline SDL_Window* getWin(){ return win; };
- inline SDL_Renderer* getRnd(){ return rnd; };
- inline SDL_Texture* getCnv(){ return cnv; };
- inline bool isCnvTarget(){ return cnvIsTarget; }
- inline void clear(ABGR c = 0xff000000){
- if(!cnvIsTarget){
- if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
- cnvIsTarget = true;
- }
- SDL_SetRenderDrawColor(rnd, c.r, c.g, c.b, c.a);
- SDL_RenderClear(rnd);
- }
- inline void renderGeometry(const GeometryBuffer& buffer){
- if(!buffer.num_vertices) return;
- if(!cnvIsTarget){
- if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
- cnvIsTarget = true;
- }
- if(SDL_RenderGeometryRaw(rnd, geometryTex,
- (float*)buffer.p, sizeof(buffer.p[0]),
- (SDL_Color*)buffer.colors, sizeof(buffer.colors[0]),
- (float*)buffer.t, sizeof(buffer.t[0]),
- buffer.num_vertices,
- buffer.indices, buffer.num_vertices,
- sizeof(buffer.indices[0])) < 0)
- {
- throw SDL_GetError();
- }
- }
- inline void renderFillRect(const SDL_Rect* dst, ABGR c){
- if(!cnvIsTarget){
- if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
- cnvIsTarget = true;
- }
- if(SDL_SetRenderDrawColor(rnd, c.r, c.g, c.b, c.a)<0) throw SDL_GetError();
- if(SDL_RenderFillRect(rnd, dst)<0) throw SDL_GetError();
- }
- inline void renderFillRectBordered(SDL_Rect dst, ABGR c_bdr = 0xffffffff,
- ABGR c_bkg = 0xff000000)
- {
- if(!cnvIsTarget){
- if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
- cnvIsTarget = true;
- }
- if(SDL_SetRenderDrawColor(rnd, c_bkg.r, c_bkg.g, c_bkg.b, c_bkg.a)<0) throw SDL_GetError();
- if(SDL_RenderFillRect(rnd, &dst)<0) throw SDL_GetError();
- if(SDL_SetRenderDrawColor(rnd, c_bdr.r, c_bdr.g, c_bdr.b, c_bdr.a)<0) throw SDL_GetError();
- if(SDL_RenderDrawRect(rnd, &dst)<0) throw SDL_GetError();
- }
- inline void renderCopy(SDL_Texture& texture, const SDL_Rect* src, SDL_Rect* dst){
- if(!cnvIsTarget){
- if(SDL_SetRenderTarget(rnd, cnv)<0) throw SDL_GetError();
- cnvIsTarget = true;
- }
- if(SDL_RenderCopy(rnd, &texture, src, dst)<0) throw SDL_GetError();
- }
- inline void present(unsigned delayMS = 16){
- if(cnvIsTarget){
- if(SDL_SetRenderTarget(rnd, nullptr)<0) throw SDL_GetError();
- cnvIsTarget = false;
- }
- SDL_RenderCopy(rnd, cnv, nullptr, nullptr);
- SDL_RenderPresent(rnd);
- if(delayMS > 0) SDL_Delay(delayMS);
- }
- };
- struct MeshSimple {
- //every 3 verts makes a triangle (no quads nor n-gons)
- Vertex* verts;
- unsigned verts_len; // = faces_len * 3
- Location p;
- //index of the mesh's place within scene vertices
- unsigned first_index;
- unsigned _padding32;
- MeshSimple(const char* fileName);
- ~MeshSimple();
- #if defined(_DEBUG) && 1
- inline Vertex& vert(size_t i){
- if(i >= verts_len) throw "vert index out of bounds";
- return verts[i];
- }
- #else
- inline Vertex& vert(size_t i){ return verts[i]; }
- #endif /* defined(_DEBUG) */
- };
- void sceneRebuild(MeshSimple** meshes, int meshes_len);
- #define LOOP_END_MAX 0xffffffff
- //operates on scene_wka, while assuming that
- //the contents of scene_ori were just copied
- //if mesh == nullptr, rotate entirety of wka
- void rotateWka(Location p, unsigned loop_start, unsigned loop_end);
- void scaleWka(Location p, unsigned loop_start, unsigned loop_end);
- void translateWka(Location p, unsigned loop_start, unsigned loop_end);
- void sceneApplyTransform(MeshSimple* mesh);
- static inline void meshRotate(MeshSimple& mesh){
- rotateWka(mesh.p, mesh.first_index, mesh.first_index+mesh.verts_len); }
- static inline void meshScale(MeshSimple& mesh){
- scaleWka(mesh.p, mesh.first_index, mesh.first_index+mesh.verts_len); }
- static inline void meshTranslate(MeshSimple& mesh){
- translateWka(mesh.p, mesh.first_index, mesh.first_index+mesh.verts_len); }
- static inline void meshTransform(MeshSimple& mesh){
- sceneApplyTransform(&mesh); }
- static inline void cameraTransform(){
- sceneApplyTransform(nullptr); }
- //wkb = backface_cull(wka)
- void sceneCullBackFaces();
- //wka = plane_clip(wkb)
- //wka = apply_luminosity_fade(wka)
- void sceneClipPlanesAndLumFade();
- //wkb = project(wka) (also culls triangles that are off-screen)
- void sceneProject(float viewportMultiplierX, float viewportMultiplierY);
- //wkb = z_sort(wkb) (make sure to reset indices before doing this!)
- void sceneZSort();
- //create a vertex snap effect on wkb (optional)
- void scenePS1Geometry(GeometryBuffer& buffer);
- //maybe next time i could do an xor to determine which
- //work buffer is used each operation...
- static inline void sceneRender(float viewportMultiplierX = ((float)CNV_W)/((float)CNV_H),
- float viewportMultiplierY = 1.0f)
- {
- sceneCullBackFaces();
- sceneClipPlanesAndLumFade();
- #if PS1_SNAP > 0
- scenePS1Geometry(scene_wka); //(optional)
- #endif
- sceneProject(viewportMultiplierX, viewportMultiplierY);
- //Log("number of active triangles = %4u", (unsigned)(scene_wkb.num_vertices/3));
- sceneZSort();
- canvas->renderGeometry(scene_wkb);
- }
- #endif /* _SCENE_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"sdl2rnd\include\Text.hpp":
- #ifndef _TEXT_HPP
- #define _TEXT_HPP
- #include <SDL2/SDL.h>
- class Text {
- SDL_Texture* atlas = nullptr;
- int w, h; //width of each glyph
- public:
- Text(const char* bmpPath);
- inline ~Text(){ if(atlas){ SDL_DestroyTexture(atlas); atlas = nullptr; } }
- //returns the bounding box, in pixels
- SDL_Point getTextSize(const char* text, float scale = 1.0f);
- //set x and/or y to this to center the text on-screen on that axis
- #define CENTER_TEXT (-2147483647) //aka 0x80000001
- void draw(int x, int y, const char* text, unsigned maxLen = 0, float scale = 1.0f);
- //(x & y can also be other values <0, which will make the text start drawing at
- //CNV_W-text_width+x+1 & CNV_H-text_height+y+1 respectively)
- //(also, the high bit of maxLen must not be set, as that is used as a flag internally)
- //same rules apply, but the x & y are adjusted
- //to match a 2-pixel border around the text
- void drawBox(int x, int y, const char* text, unsigned maxLen = 0, float scale = 1.0f);
- };
- #define FSTR_LEN 4096
- extern char _fstr_failure[]; // = "(FSTR FAILED)"
- extern char _fstr[2][FSTR_LEN];
- extern int _fstr_which;
- //(could potentially cast result to const char* if necessary)
- #define fstr(...) ( \
- (snprintf(_fstr[(_fstr_which^=1)],FSTR_LEN,__VA_ARGS__)>=0) \
- ? _fstr[_fstr_which] : _fstr_failure \
- )
- extern Text* text_p;
- #define text(_x, _y, _maxLen, _text) text_p->draw (_x, _y, _text, _maxLen, 1.0f)
- #define text_box(_x, _y, _maxLen, _text) text_p->drawBox(_x, _y, _text, _maxLen, 1.0f)
- #define textf(_x, _y, ...) text_p->draw (_x, _y, fstr(__VA_ARGS__), 0, 1.0f)
- #define textf_box(_x, _y, ...) text_p->drawBox(_x, _y, fstr(__VA_ARGS__), 0, 1.0f)
- #endif /* _TEXT_HPP */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement