First build that actually works. SDL_main errors before but didn't figure out the cause.
This commit is contained in:
commit
6b181382bd
21 changed files with 2853 additions and 0 deletions
29
.gitignore
vendored
Normal file
29
.gitignore
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
# ---> Vim
|
||||
# Swap
|
||||
[._]*.s[a-v][a-z]
|
||||
!*.svg # comment out if you don't need vector files
|
||||
[._]*.sw[a-p]
|
||||
[._]s[a-rt-v][a-z]
|
||||
[._]ss[a-gi-z]
|
||||
[._]sw[a-p]
|
||||
|
||||
# Session
|
||||
Session.vim
|
||||
Sessionx.vim
|
||||
|
||||
# Temporary
|
||||
.netrwhist
|
||||
*~
|
||||
# Auto-generated tag files
|
||||
tags
|
||||
# Persistent undo
|
||||
[._]*.un~
|
||||
|
||||
subprojects
|
||||
builddir
|
||||
ttassets
|
||||
backup
|
||||
*.exe
|
||||
*.dll
|
||||
*.world
|
||||
coverage
|
1
.vimrc_proj
Normal file
1
.vimrc_proj
Normal file
|
@ -0,0 +1 @@
|
|||
set makeprg=meson\ compile\ -C\ .
|
26
Makefile
Normal file
26
Makefile
Normal file
|
@ -0,0 +1,26 @@
|
|||
all: build test
|
||||
|
||||
reset:
|
||||
powershell -executionpolicy bypass .\scripts\reset_build.ps1
|
||||
|
||||
%.cpp : %.rl
|
||||
ragel -o $@ $<
|
||||
|
||||
build:
|
||||
meson compile -j 10 -C builddir
|
||||
|
||||
test: build
|
||||
./builddir/runtests
|
||||
|
||||
run: build test
|
||||
powershell "cp ./builddir/lodecaster.exe ."
|
||||
./lodecaster
|
||||
|
||||
clean:
|
||||
meson compile --clean -C builddir
|
||||
|
||||
debug_test: build
|
||||
gdb --nx -x .gdbinit --ex run --args builddir/runtests.exe
|
||||
|
||||
cover:
|
||||
gcovr --html coverage/index.html --gcov-ignore-errors=no_working_dir_found --exclude "scratchpad.*" --exclude "subprojects.*" --html-nested coverage/
|
BIN
charset.png
Normal file
BIN
charset.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
34
main.cpp
Normal file
34
main.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Copyright (c) 2004, Lode Vandevenne
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include "quickcg.h"
|
||||
using namespace QuickCG;
|
||||
using namespace std;
|
||||
|
||||
//place the example code below here:
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
screen(256, 256, 0, "Small Test Script");
|
||||
for (int x = 0; x < w; x++)
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
pset(x, y, ColorRGBA(x, y, 128, 255));
|
||||
}
|
||||
print("Hello, world!", 8, 8);
|
||||
|
||||
std::string test;
|
||||
test.resize(20);
|
||||
|
||||
redraw();
|
||||
sleep();
|
||||
|
||||
return 0;
|
||||
}
|
27
meson.build
Normal file
27
meson.build
Normal file
|
@ -0,0 +1,27 @@
|
|||
project('lodecaster', 'cpp',
|
||||
default_options: ['cpp_std=c++20'])
|
||||
|
||||
catch2 = dependency('catch2-with-main')
|
||||
fmt = dependency('fmt')
|
||||
json = dependency('nlohmann_json')
|
||||
sdl2 = dependency('sdl2')
|
||||
sdl2_main = dependency('sdl2main')
|
||||
|
||||
dependencies = [
|
||||
sdl2, sdl2_main,
|
||||
fmt, json
|
||||
]
|
||||
|
||||
executable('runtests', [
|
||||
'quickcg.cpp',
|
||||
'main.cpp',
|
||||
],
|
||||
win_subsystem: 'windows',
|
||||
dependencies: dependencies)
|
||||
|
||||
executable('lodecaster', [
|
||||
'quickcg.cpp',
|
||||
'raycaster_flat.cpp',
|
||||
],
|
||||
win_subsystem: 'windows',
|
||||
dependencies: dependencies)
|
2005
quickcg.cpp
Normal file
2005
quickcg.cpp
Normal file
File diff suppressed because it is too large
Load diff
334
quickcg.h
Normal file
334
quickcg.h
Normal file
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
QuickCG SDL2 20190709
|
||||
|
||||
Copyright (c) 2004-2007, Lode Vandevenne
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
QuickCG is an SDL 2.0 codebase that wraps some of the SDL 2.0 functionality.
|
||||
It's used by Lode's Computer Graphics Tutorial to work with simple function calls
|
||||
to demonstrate graphical programs. It may or may not be of industrial strength
|
||||
for games, though I've actually used it for some.
|
||||
|
||||
QuickCG can handle some things that standard C++ does not but that are useful, such as:
|
||||
-drawing graphics
|
||||
-a bitmap font
|
||||
-simplified saving and loading of files
|
||||
-reading keyboard and mouse input
|
||||
-playing sound
|
||||
-color models
|
||||
-loading images
|
||||
|
||||
Contact info:
|
||||
My email address is (puzzle the account and domain together with an @ symbol):
|
||||
Domain: gmail dot com.
|
||||
Account: lode dot vandevenne.
|
||||
*/
|
||||
|
||||
#ifndef _quickcg_h_included
|
||||
#define _quickcg_h_included
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <algorithm> //std::min and std::max
|
||||
|
||||
namespace QuickCG
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//useful templates//////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//don't know why, but the standard C++ abs sometimes gives cryptic errors? if so use this :D
|
||||
template<typename T>
|
||||
const T template_abs(const T &a)
|
||||
{
|
||||
return (a < 0) ? -a : a;
|
||||
}
|
||||
|
||||
//usage: std::string str = valtostr(25454.91654654f);
|
||||
template<typename T>
|
||||
std::string valtostr(const T& val)
|
||||
{
|
||||
std::ostringstream sstream;
|
||||
sstream << val;
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
//usage: double val = strtoval<double>("465498.654");
|
||||
template<typename T>
|
||||
T strtoval(const std::string& s)
|
||||
{
|
||||
std::istringstream sstream(s);
|
||||
T val;
|
||||
sstream >> val;
|
||||
return val;
|
||||
}
|
||||
|
||||
//length is decimal precision of the floating point number
|
||||
template<typename T>
|
||||
std::string valtostr(const T& val, int length, bool fixed = true)
|
||||
{
|
||||
std::ostringstream sstream;
|
||||
if(fixed) sstream << std::fixed;
|
||||
sstream << std::setprecision(length) << val;
|
||||
return sstream.str();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//COLOR STRUCTS/////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct ColorRGBA8bit;
|
||||
//a color with 4 components: r, g, b and a
|
||||
struct ColorRGBA
|
||||
{
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
int a;
|
||||
|
||||
ColorRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
ColorRGBA(const ColorRGBA8bit& color);
|
||||
ColorRGBA();
|
||||
};
|
||||
|
||||
ColorRGBA operator+(const ColorRGBA& color, const ColorRGBA& color2);
|
||||
ColorRGBA operator-(const ColorRGBA& color, const ColorRGBA& color2);
|
||||
ColorRGBA operator*(const ColorRGBA& color, int a);
|
||||
ColorRGBA operator*(int a, const ColorRGBA& color);
|
||||
ColorRGBA operator/(const ColorRGBA& color, int a);
|
||||
ColorRGBA overlay(const ColorRGBA& color, const ColorRGBA& color2);
|
||||
bool operator==(const ColorRGBA& color, const ColorRGBA& color2);
|
||||
bool operator!=(const ColorRGBA& color, const ColorRGBA& color2);
|
||||
|
||||
static const ColorRGBA RGB_Black ( 0, 0, 0, 255);
|
||||
static const ColorRGBA RGB_Red (255, 0, 0, 255);
|
||||
static const ColorRGBA RGB_Green ( 0, 255, 0, 255);
|
||||
static const ColorRGBA RGB_Blue ( 0, 0, 255, 255);
|
||||
static const ColorRGBA RGB_Cyan ( 0, 255, 255, 255);
|
||||
static const ColorRGBA RGB_Magenta (255, 0, 255, 255);
|
||||
static const ColorRGBA RGB_Yellow (255, 255, 0, 255);
|
||||
static const ColorRGBA RGB_White (255, 255, 255, 255);
|
||||
static const ColorRGBA RGB_Gray (128, 128, 128, 255);
|
||||
static const ColorRGBA RGB_Grey (192, 192, 192, 255);
|
||||
static const ColorRGBA RGB_Maroon (128, 0, 0, 255);
|
||||
static const ColorRGBA RGB_Darkgreen( 0, 128, 0, 255);
|
||||
static const ColorRGBA RGB_Navy ( 0, 0, 128, 255);
|
||||
static const ColorRGBA RGB_Teal ( 0, 128, 128, 255);
|
||||
static const ColorRGBA RGB_Purple (128, 0, 128, 255);
|
||||
static const ColorRGBA RGB_Olive (128, 128, 0, 255);
|
||||
|
||||
//a color with 4 components: r, g, b and a
|
||||
struct ColorRGBA8bit
|
||||
{
|
||||
Uint8 r;
|
||||
Uint8 g;
|
||||
Uint8 b;
|
||||
Uint8 a;
|
||||
|
||||
ColorRGBA8bit(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
|
||||
ColorRGBA8bit(const ColorRGBA& color);
|
||||
ColorRGBA8bit();
|
||||
};
|
||||
|
||||
//a color with 3 components: h, s and l
|
||||
struct ColorHSL
|
||||
{
|
||||
int h;
|
||||
int s;
|
||||
int l;
|
||||
int a;
|
||||
|
||||
ColorHSL(Uint8 h, Uint8 s, Uint8 l, Uint8 a);
|
||||
ColorHSL();
|
||||
};
|
||||
|
||||
//a color with 3 components: h, s and v
|
||||
struct ColorHSV
|
||||
{
|
||||
int h;
|
||||
int s;
|
||||
int v;
|
||||
int a;
|
||||
|
||||
ColorHSV(Uint8 h, Uint8 s, Uint8 v, Uint8 a);
|
||||
ColorHSV();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//GLOBAL VARIABLES//////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern int w;
|
||||
extern int h;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//KEYBOARD FUNCTIONS////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool keyDown(int key); //this checks if the key is held down, returns true all the time until the key is up
|
||||
bool keyPressed(int key); //this checks if the key is *just* pressed, returns true only once until the key is up again
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//BASIC SCREEN FUNCTIONS////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void screen(int width = 640, int height = 400, bool fullscreen = 0, const std::string& text = " ");
|
||||
void lock();
|
||||
void unlock();
|
||||
void redraw();
|
||||
void cls(const ColorRGBA& color = RGB_Black);
|
||||
void pset(int x, int y, const ColorRGBA& color);
|
||||
ColorRGBA pget(int x, int y);
|
||||
void drawBuffer(Uint32* buffer);
|
||||
bool onScreen(int x, int y);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//NON GRAPHICAL FUNCTIONS///////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void sleep();
|
||||
void sleep(double seconds);
|
||||
void waitFrame(double oldTime, double frameDuration); //in seconds
|
||||
bool done(bool quit_if_esc = true, bool delay = true);
|
||||
void end();
|
||||
void readKeys();
|
||||
void getMouseState(int& mouseX, int& mouseY);
|
||||
void getMouseState(int& mouseX, int& mouseY, bool& LMB, bool& RMB);
|
||||
unsigned long getTicks(); //ticks in milliseconds
|
||||
inline double getTime() { return getTicks() / 1000.0; } //time in seconds
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//2D SHAPES/////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool horLine(int y, int x1, int x2, const ColorRGBA& color);
|
||||
bool verLine(int x, int y1, int y2, const ColorRGBA& color);
|
||||
bool drawLine(int x1, int y1, int x2, int y2, const ColorRGBA& color);
|
||||
bool drawCircle(int xc, int yc, int radius, const ColorRGBA& color);
|
||||
bool drawDisk(int xc, int yc, int radius, const ColorRGBA& color);
|
||||
bool drawRect(int x1, int y1, int x2, int y2, const ColorRGBA& color);
|
||||
bool clipLine(int x1,int y1,int x2, int y2, int & x3, int & y3, int & x4, int & y4);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//COLOR CONVERSIONS/////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
ColorHSL RGBtoHSL(const ColorRGBA& ColorRGBA);
|
||||
ColorRGBA HSLtoRGB(const ColorHSL& colorHSL);
|
||||
ColorHSV RGBtoHSV(const ColorRGBA& ColorRGBA);
|
||||
ColorRGBA HSVtoRGB(const ColorHSV& colorHSV);
|
||||
Uint32 RGBtoINT(const ColorRGBA& ColorRGBA);
|
||||
ColorRGBA INTtoRGB(Uint32 colorINT);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//FILE FUNCTIONS////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void loadFile(std::vector<unsigned char>& buffer, const std::string& filename);
|
||||
void saveFile(const std::vector<unsigned char>& buffer, const std::string& filename);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//IMAGE FUNCTIONS///////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int loadImage(std::vector<ColorRGBA>& out, unsigned long& w, unsigned long& h, const std::string& filename);
|
||||
int loadImage(std::vector<Uint32>& out, unsigned long& w, unsigned long& h, const std::string& filename);
|
||||
int decodePNG(std::vector<unsigned char>& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true);
|
||||
int decodePNG(std::vector<unsigned char>& out_image_32bit, unsigned long& image_width, unsigned long& image_height, const std::vector<unsigned char>& in_png);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//TEXT FUNCTIONS////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
extern bool font[256][8][8];
|
||||
void drawLetter(unsigned char n, int x, int y, const ColorRGBA& color = RGB_White, bool bg = 0, const ColorRGBA& color2 = RGB_Black);
|
||||
int printString(const std::string& text, int x = 0, int y = 0, const ColorRGBA& color = RGB_White, bool bg = 0, const ColorRGBA& color2 = RGB_Black, int forceLength = 0);
|
||||
|
||||
//print something (string, int, float, ...)
|
||||
template<typename T>
|
||||
int print(const T& val, int x = 0, int y = 0, const ColorRGBA& color = RGB_White, bool bg = 0, const ColorRGBA& color2 = RGB_Black, int forceLength = 0)
|
||||
{
|
||||
std::string text = valtostr(val);
|
||||
return printString(text, x, y, color, bg, color2, forceLength);
|
||||
}
|
||||
|
||||
//print some floating point number, this one allows printing floating point numbers with limited length
|
||||
template<typename T>
|
||||
int fprint(const T& val, int length, int x = 0, int y = 0, const ColorRGBA& color = RGB_White, bool bg = 0, const ColorRGBA& color2 = RGB_Black, int forceLength = 0)
|
||||
{
|
||||
std::string text = valtostr(val, length, true);
|
||||
return printString(text, x, y, color, bg, color2, forceLength);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//TEXT INPUT FUNCTIONS//////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
Uint8 getInputCharacter();
|
||||
void getInputString(std::string& text, const std::string& message = "", bool clear = false, int x = 0, int y = 0, const ColorRGBA& color = RGB_White, bool bg = 0, const ColorRGBA& color2 = RGB_Black);
|
||||
|
||||
template<typename T>
|
||||
T getInput(const std::string& message = "", bool clear = false, int x = 0, int y = 0, const ColorRGBA& color = RGB_White, bool bg = 0, const ColorRGBA& color2 = RGB_Black)
|
||||
{
|
||||
std::string text;
|
||||
getInputString(text, message, clear, x, y, color, bg, color2);
|
||||
return strtoval<T>(text);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//SOUNDCARD FUNCTIONS///////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int audioOpen(int samplerate, int framesize); //always 16-bit mono sound for now; returns 0 if no error happened
|
||||
void audioClose();
|
||||
int audioReOpen(); //closes and opens again with same parameters
|
||||
|
||||
/*
|
||||
push samples to the soundcard, making sure not to cause shortage or overflow
|
||||
pos and end are the range in the samples vector that you want to push to the audio card
|
||||
*/
|
||||
void audioPushSamples(const std::vector<double>& samples, size_t pos, size_t end);
|
||||
|
||||
size_t audioSamplesShortage(); //returns value > 0 if the soundcard is consuming more samples than you're producing
|
||||
size_t audioSamplesOverflow(); //returns value > 0 if you're producing more samples than the soundard is consuming - so take it easy a bit
|
||||
void audioSetBufferSamplesRange(size_t min_samples, size_t max_samples); //set shortage and overflow values. E.g. 4096 and 8192.
|
||||
|
||||
/*
|
||||
This plays the sound starting at this time, until it's done
|
||||
The difference with audioPushSamples is:
|
||||
audioPlay allows playing multiple sounds at the same time: it doesn't push at the end,
|
||||
but elementwise-adds or pushes back samples if needed.
|
||||
The duration depends on samplerate, make sure the samples in the vector have the correct samplerate.
|
||||
*/
|
||||
void audioPlay(const std::vector<double>& samples);
|
||||
|
||||
void audioSetMode(int mode); //0: silent, 1: full (no volume calculations ==> faster), 2: volume-controlled (= default value)
|
||||
void audioSetVolume(double volume); //multiplier used if mode is 2 (volume-controlled). Default value is 1.0.
|
||||
|
||||
} //end of namespace QuickCG
|
||||
|
||||
#endif
|
||||
|
||||
|
242
raycaster_flat.cpp
Normal file
242
raycaster_flat.cpp
Normal file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
Copyright (c) 2004-2021, Lode Vandevenne
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include "quickcg.h"
|
||||
using namespace QuickCG;
|
||||
|
||||
/*
|
||||
g++ *.cpp -lSDL -O3 -W -Wall -ansi -pedantic
|
||||
g++ *.cpp -lSDL
|
||||
*/
|
||||
|
||||
//place the example code below here:
|
||||
|
||||
#define screenWidth 640
|
||||
#define screenHeight 480
|
||||
#define mapWidth 24
|
||||
#define mapHeight 24
|
||||
|
||||
int worldMap[mapWidth][mapHeight]=
|
||||
{
|
||||
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,2,2,2,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
|
||||
{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,3,0,0,0,3,0,0,0,1},
|
||||
{1,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,2,2,0,2,2,0,0,0,0,3,0,3,0,3,0,0,0,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,4,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,4,0,4,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,4,0,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,4,4,4,4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
|
||||
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
|
||||
};
|
||||
|
||||
int main(int /*argc*/, char */*argv*/[])
|
||||
{
|
||||
double posX = 22, posY = 12; //x and y start position
|
||||
double dirX = -1, dirY = 0; //initial direction vector
|
||||
double planeX = 0, planeY = 0.66; //the 2d raycaster version of camera plane
|
||||
|
||||
double time = 0; //time of current frame
|
||||
double oldTime = 0; //time of previous frame
|
||||
|
||||
screen(screenWidth, screenHeight, 0, "Raycaster");
|
||||
while(!done())
|
||||
{
|
||||
for(int x = 0; x < w; x++)
|
||||
{
|
||||
//calculate ray position and direction
|
||||
double cameraX = 2 * x / (double)w - 1; //x-coordinate in camera space
|
||||
double rayDirX = dirX + planeX * cameraX;
|
||||
double rayDirY = dirY + planeY * cameraX;
|
||||
//which box of the map we're in
|
||||
int mapX = int(posX);
|
||||
int mapY = int(posY);
|
||||
|
||||
//length of ray from current position to next x or y-side
|
||||
double sideDistX;
|
||||
double sideDistY;
|
||||
|
||||
//length of ray from one x or y-side to next x or y-side
|
||||
//these are derived as:
|
||||
//deltaDistX = sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX))
|
||||
//deltaDistY = sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY))
|
||||
//which can be simplified to abs(|rayDir| / rayDirX) and abs(|rayDir| / rayDirY)
|
||||
//where |rayDir| is the length of the vector (rayDirX, rayDirY). Its length,
|
||||
//unlike (dirX, dirY) is not 1, however this does not matter, only the
|
||||
//ratio between deltaDistX and deltaDistY matters, due to the way the DDA
|
||||
//stepping further below works. So the values can be computed as below.
|
||||
// Division through zero is prevented, even though technically that's not
|
||||
// needed in C++ with IEEE 754 floating point values.
|
||||
double deltaDistX = (rayDirX == 0) ? 1e30 : std::abs(1 / rayDirX);
|
||||
double deltaDistY = (rayDirY == 0) ? 1e30 : std::abs(1 / rayDirY);
|
||||
|
||||
double perpWallDist;
|
||||
|
||||
//what direction to step in x or y-direction (either +1 or -1)
|
||||
int stepX;
|
||||
int stepY;
|
||||
|
||||
int hit = 0; //was there a wall hit?
|
||||
int side; //was a NS or a EW wall hit?
|
||||
//calculate step and initial sideDist
|
||||
if(rayDirX < 0)
|
||||
{
|
||||
stepX = -1;
|
||||
sideDistX = (posX - mapX) * deltaDistX;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepX = 1;
|
||||
sideDistX = (mapX + 1.0 - posX) * deltaDistX;
|
||||
}
|
||||
if(rayDirY < 0)
|
||||
{
|
||||
stepY = -1;
|
||||
sideDistY = (posY - mapY) * deltaDistY;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepY = 1;
|
||||
sideDistY = (mapY + 1.0 - posY) * deltaDistY;
|
||||
}
|
||||
//perform DDA
|
||||
while(hit == 0)
|
||||
{
|
||||
//jump to next map square, either in x-direction, or in y-direction
|
||||
if(sideDistX < sideDistY)
|
||||
{
|
||||
sideDistX += deltaDistX;
|
||||
mapX += stepX;
|
||||
side = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sideDistY += deltaDistY;
|
||||
mapY += stepY;
|
||||
side = 1;
|
||||
}
|
||||
//Check if ray has hit a wall
|
||||
if(worldMap[mapX][mapY] > 0) hit = 1;
|
||||
}
|
||||
//Calculate distance projected on camera direction. This is the shortest distance from the point where the wall is
|
||||
//hit to the camera plane. Euclidean to center camera point would give fisheye effect!
|
||||
//This can be computed as (mapX - posX + (1 - stepX) / 2) / rayDirX for side == 0, or same formula with Y
|
||||
//for size == 1, but can be simplified to the code below thanks to how sideDist and deltaDist are computed:
|
||||
//because they were left scaled to |rayDir|. sideDist is the entire length of the ray above after the multiple
|
||||
//steps, but we subtract deltaDist once because one step more into the wall was taken above.
|
||||
if(side == 0) perpWallDist = (sideDistX - deltaDistX);
|
||||
else perpWallDist = (sideDistY - deltaDistY);
|
||||
|
||||
//Calculate height of line to draw on screen
|
||||
int lineHeight = (int)(h / perpWallDist);
|
||||
|
||||
//calculate lowest and highest pixel to fill in current stripe
|
||||
int drawStart = -lineHeight / 2 + h / 2;
|
||||
if(drawStart < 0) drawStart = 0;
|
||||
int drawEnd = lineHeight / 2 + h / 2;
|
||||
if(drawEnd >= h) drawEnd = h - 1;
|
||||
|
||||
//choose wall color
|
||||
ColorRGB color;
|
||||
switch(worldMap[mapX][mapY])
|
||||
{
|
||||
case 1: color = RGB_Red; break; //red
|
||||
case 2: color = RGB_Green; break; //green
|
||||
case 3: color = RGB_Blue; break; //blue
|
||||
case 4: color = RGB_White; break; //white
|
||||
default: color = RGB_Yellow; break; //yellow
|
||||
}
|
||||
|
||||
//give x and y sides different brightness
|
||||
if(side == 1) {color = color / 2;}
|
||||
|
||||
//draw the pixels of the stripe as a vertical line
|
||||
verLine(x, drawStart, drawEnd, color);
|
||||
}
|
||||
//timing for input and FPS counter
|
||||
oldTime = time;
|
||||
time = getTicks();
|
||||
double frameTime = (time - oldTime) / 1000.0; //frameTime is the time this frame has taken, in seconds
|
||||
print(1.0 / frameTime); //FPS counter
|
||||
redraw();
|
||||
cls();
|
||||
|
||||
//speed modifiers
|
||||
double moveSpeed = frameTime * 5.0; //the constant value is in squares/second
|
||||
double rotSpeed = frameTime * 3.0; //the constant value is in radians/second
|
||||
readKeys();
|
||||
//move forward if no wall in front of you
|
||||
if(keyDown(SDLK_UP))
|
||||
{
|
||||
if(worldMap[int(posX + dirX * moveSpeed)][int(posY)] == false) posX += dirX * moveSpeed;
|
||||
if(worldMap[int(posX)][int(posY + dirY * moveSpeed)] == false) posY += dirY * moveSpeed;
|
||||
}
|
||||
//move backwards if no wall behind you
|
||||
if(keyDown(SDLK_DOWN))
|
||||
{
|
||||
if(worldMap[int(posX - dirX * moveSpeed)][int(posY)] == false) posX -= dirX * moveSpeed;
|
||||
if(worldMap[int(posX)][int(posY - dirY * moveSpeed)] == false) posY -= dirY * moveSpeed;
|
||||
}
|
||||
//rotate to the right
|
||||
if(keyDown(SDLK_RIGHT))
|
||||
{
|
||||
//both camera direction and camera plane must be rotated
|
||||
double oldDirX = dirX;
|
||||
dirX = dirX * cos(-rotSpeed) - dirY * sin(-rotSpeed);
|
||||
dirY = oldDirX * sin(-rotSpeed) + dirY * cos(-rotSpeed);
|
||||
double oldPlaneX = planeX;
|
||||
planeX = planeX * cos(-rotSpeed) - planeY * sin(-rotSpeed);
|
||||
planeY = oldPlaneX * sin(-rotSpeed) + planeY * cos(-rotSpeed);
|
||||
}
|
||||
//rotate to the left
|
||||
if(keyDown(SDLK_LEFT))
|
||||
{
|
||||
//both camera direction and camera plane must be rotated
|
||||
double oldDirX = dirX;
|
||||
dirX = dirX * cos(rotSpeed) - dirY * sin(rotSpeed);
|
||||
dirY = oldDirX * sin(rotSpeed) + dirY * cos(rotSpeed);
|
||||
double oldPlaneX = planeX;
|
||||
planeX = planeX * cos(rotSpeed) - planeY * sin(rotSpeed);
|
||||
planeY = oldPlaneX * sin(rotSpeed) + planeY * cos(rotSpeed);
|
||||
}
|
||||
}
|
||||
}
|
7
scripts/coverage_reset.ps1
Normal file
7
scripts/coverage_reset.ps1
Normal file
|
@ -0,0 +1,7 @@
|
|||
mv .\subprojects\packagecache .
|
||||
rm -recurse -force .\subprojects\,.\builddir\
|
||||
mkdir subprojects
|
||||
mv .\packagecache .\subprojects\
|
||||
mkdir builddir
|
||||
cp wraps\*.wrap subprojects\
|
||||
meson setup --default-library=static --prefer-static -Db_coverage=true builddir
|
11
scripts/coverage_reset.sh
Normal file
11
scripts/coverage_reset.sh
Normal file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
mv -f ./subprojects/packagecache .
|
||||
rm -rf subprojects builddir
|
||||
mkdir subprojects
|
||||
mv packagecache ./subprojects/
|
||||
mkdir builddir
|
||||
cp wraps/*.wrap subprojects/
|
||||
# on OSX you can't do this with static
|
||||
meson setup -Db_coverage=true builddir
|
7
scripts/reset_build.ps1
Normal file
7
scripts/reset_build.ps1
Normal file
|
@ -0,0 +1,7 @@
|
|||
mv .\subprojects\packagecache .
|
||||
rm -recurse -force .\subprojects\,.\builddir\
|
||||
mkdir subprojects
|
||||
mv .\packagecache .\subprojects\
|
||||
mkdir builddir
|
||||
cp wraps\*.wrap subprojects\
|
||||
meson setup --default-library=static --prefer-static builddir
|
11
scripts/reset_build.sh
Normal file
11
scripts/reset_build.sh
Normal file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
mv -f ./subprojects/packagecache .
|
||||
rm -rf subprojects builddir
|
||||
mkdir subprojects
|
||||
mv packagecache ./subprojects/
|
||||
mkdir builddir
|
||||
cp wraps/*.wrap subprojects/
|
||||
# on OSX you can't do this with static
|
||||
meson setup builddir
|
36
sdlprog.cpp
Normal file
36
sdlprog.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include "SDL.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Surface *surface;
|
||||
SDL_Event event;
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s", SDL_GetError());
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (SDL_CreateWindowAndRenderer(320, 240, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window and renderer: %s", SDL_GetError());
|
||||
return 3;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
SDL_PollEvent(&event);
|
||||
if (event.type == SDL_QUIT) {
|
||||
break;
|
||||
}
|
||||
SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0x00);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
return 0;
|
||||
}
|
9
tests/base.cpp
Normal file
9
tests/base.cpp
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <fmt/core.h>
|
||||
#include <string>
|
||||
|
||||
using namespace fmt;
|
||||
|
||||
TEST_CASE("base test", "[base]") {
|
||||
REQUIRE(1 == 1);
|
||||
}
|
11
wraps/catch2.wrap
Normal file
11
wraps/catch2.wrap
Normal file
|
@ -0,0 +1,11 @@
|
|||
[wrap-file]
|
||||
directory = Catch2-3.7.1
|
||||
source_url = https://github.com/catchorg/Catch2/archive/v3.7.1.tar.gz
|
||||
source_filename = Catch2-3.7.1.tar.gz
|
||||
source_hash = c991b247a1a0d7bb9c39aa35faf0fe9e19764213f28ffba3109388e62ee0269c
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/catch2_3.7.1-1/Catch2-3.7.1.tar.gz
|
||||
wrapdb_version = 3.7.1-1
|
||||
|
||||
[provide]
|
||||
catch2 = catch2_dep
|
||||
catch2-with-main = catch2_with_main_dep
|
13
wraps/fmt.wrap
Normal file
13
wraps/fmt.wrap
Normal file
|
@ -0,0 +1,13 @@
|
|||
[wrap-file]
|
||||
directory = fmt-11.0.2
|
||||
source_url = https://github.com/fmtlib/fmt/archive/11.0.2.tar.gz
|
||||
source_filename = fmt-11.0.2.tar.gz
|
||||
source_hash = 6cb1e6d37bdcb756dbbe59be438790db409cdb4868c66e888d5df9f13f7c027f
|
||||
patch_filename = fmt_11.0.2-1_patch.zip
|
||||
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_11.0.2-1/get_patch
|
||||
patch_hash = 90c9e3b8e8f29713d40ca949f6f93ad115d78d7fb921064112bc6179e6427c5e
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/fmt_11.0.2-1/fmt-11.0.2.tar.gz
|
||||
wrapdb_version = 11.0.2-1
|
||||
|
||||
[provide]
|
||||
fmt = fmt_dep
|
11
wraps/freetype2.wrap
Normal file
11
wraps/freetype2.wrap
Normal file
|
@ -0,0 +1,11 @@
|
|||
[wrap-file]
|
||||
directory = freetype-2.13.3
|
||||
source_url = https://download.savannah.gnu.org/releases/freetype/freetype-2.13.3.tar.xz
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/freetype2_2.13.3-1/freetype-2.13.3.tar.xz
|
||||
source_filename = freetype-2.13.3.tar.xz
|
||||
source_hash = 0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289
|
||||
wrapdb_version = 2.13.3-1
|
||||
|
||||
[provide]
|
||||
freetype2 = freetype_dep
|
||||
freetype = freetype_dep
|
13
wraps/libpng.wrap
Normal file
13
wraps/libpng.wrap
Normal file
|
@ -0,0 +1,13 @@
|
|||
[wrap-file]
|
||||
directory = libpng-1.6.44
|
||||
source_url = https://github.com/glennrp/libpng/archive/v1.6.44.tar.gz
|
||||
source_filename = libpng-1.6.44.tar.gz
|
||||
source_hash = 0ef5b633d0c65f780c4fced27ff832998e71478c13b45dfb6e94f23a82f64f7c
|
||||
patch_filename = libpng_1.6.44-1_patch.zip
|
||||
patch_url = https://wrapdb.mesonbuild.com/v2/libpng_1.6.44-1/get_patch
|
||||
patch_hash = 394b07614c45fbd1beac8b660386216a490fe12f841a1a445799b676c9c892fb
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/libpng_1.6.44-1/libpng-1.6.44.tar.gz
|
||||
wrapdb_version = 1.6.44-1
|
||||
|
||||
[provide]
|
||||
libpng = libpng_dep
|
11
wraps/nlohmann_json.wrap
Normal file
11
wraps/nlohmann_json.wrap
Normal file
|
@ -0,0 +1,11 @@
|
|||
[wrap-file]
|
||||
directory = nlohmann_json-3.11.3
|
||||
lead_directory_missing = true
|
||||
source_url = https://github.com/nlohmann/json/releases/download/v3.11.3/include.zip
|
||||
source_filename = nlohmann_json-3.11.3.zip
|
||||
source_hash = a22461d13119ac5c78f205d3df1db13403e58ce1bb1794edc9313677313f4a9d
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/nlohmann_json_3.11.3-1/nlohmann_json-3.11.3.zip
|
||||
wrapdb_version = 3.11.3-1
|
||||
|
||||
[provide]
|
||||
nlohmann_json = nlohmann_json_dep
|
15
wraps/sdl2.wrap
Normal file
15
wraps/sdl2.wrap
Normal file
|
@ -0,0 +1,15 @@
|
|||
[wrap-file]
|
||||
directory = SDL2-2.30.6
|
||||
source_url = https://github.com/libsdl-org/SDL/releases/download/release-2.30.6/SDL2-2.30.6.tar.gz
|
||||
source_filename = SDL2-2.30.6.tar.gz
|
||||
source_hash = c6ef64ca18a19d13df6eb22df9aff19fb0db65610a74cc81dae33a82235cacd4
|
||||
patch_filename = sdl2_2.30.6-2_patch.zip
|
||||
patch_url = https://wrapdb.mesonbuild.com/v2/sdl2_2.30.6-2/get_patch
|
||||
patch_hash = aa9f6a4947b07510c2ea84fb457e965bebe5a5deeb9f5059fbcf10dfe6b76d1f
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/sdl2_2.30.6-2/SDL2-2.30.6.tar.gz
|
||||
wrapdb_version = 2.30.6-2
|
||||
|
||||
[provide]
|
||||
sdl2 = sdl2_dep
|
||||
sdl2main = sdl2main_dep
|
||||
sdl2_test = sdl2_test_dep
|
Loading…
Add table
Add a link
Reference in a new issue