Compare commits
22 Commits
4e12eb575b
...
4ed84e6ac1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ed84e6ac1 | ||
|
|
f5424bf29d | ||
|
|
e504e9b3a0 | ||
|
|
b961a0b76d | ||
|
|
09edc16c47 | ||
|
|
5ab977ea35 | ||
|
|
f5f054eb4b | ||
|
|
0dee9aed40 | ||
|
|
30438a82ea | ||
|
|
7b3840c000 | ||
|
|
ee1b03cc08 | ||
|
|
9d1b6952be | ||
|
|
b854c55cb7 | ||
|
|
2fa06b8f4e | ||
|
|
1c12d5b946 | ||
|
|
d879b44021 | ||
|
|
a4d0a7c250 | ||
|
|
6ce41e854f | ||
|
|
9d1fb5949c | ||
|
|
5e1f9c4f3a | ||
|
|
45a7bfe32a | ||
|
|
6562ecc936 |
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.vs/
|
||||
CMakeFiles/
|
||||
out/
|
||||
CMakeCache.txt
|
||||
@@ -1,69 +1,52 @@
|
||||
# This CMakeList.txt currently only supports compilation of
|
||||
#a program on windows or linux, but only with the dependancies
|
||||
#for oclPixelGameEngine.h
|
||||
# a program on windows or linux, but only with the dependancies
|
||||
# for oclPixelGameEngine.h
|
||||
|
||||
# NOTE: THIS CMAKELIST WILL NOT INSTALL DEPENDANCIES, IT WILL JUST FIND THEM AND
|
||||
#COMPILE / LINK THEM RESPECTIVELY, YOU NEED TO INSTALL THEM YOURSELF
|
||||
# COMPILE / LINK THEM RESPECTIVELY, YOU NEED TO INSTALL THEM YOURSELF
|
||||
|
||||
# Any issues, submit an issue, or contact the author, "Ben (plane000)#8618" on Discord
|
||||
# Any problems? submit an issue, or contact the author, "Ben (plane000)#8618" on Discord
|
||||
|
||||
# Currently linked / compiled by default is:
|
||||
#Threads (pthread), OpenGL, GLX, libPNG, X11
|
||||
# Threads (pthread), OpenGL, GLX, libPNG, X11
|
||||
|
||||
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
project(oclPixelGameEngine) # You can change this with your project name!
|
||||
project(olcPixelGameEngine)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} CMakeFiles/) # Don't worry what this does, it just gives more compatability options with libraries!
|
||||
cmake_policy(SET CMP0037 OLD) # This just allows the / charicter in path names
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} CMakeFiles/)
|
||||
|
||||
set(ExecutableName output) # You can change this to whatever you wish the executable outputed to be, don't worry about a .exe, i'll do that!
|
||||
set(SourceDir src) # Change src/ to wherever your code is
|
||||
set(Executable output)
|
||||
set(SourceDir src) # Change src/ to your source directory
|
||||
|
||||
# You can uncomment these 2 lines if you wish to have some headers included
|
||||
# set(IncludeDir include/) # Change include/ to your include directory
|
||||
# include_directories(${IncludeDir})
|
||||
set(IncludeDir include/) # Change include/ to your include directory
|
||||
include_directories(${IncludeDir})
|
||||
|
||||
# Uncomment this if you have your source in a folder called src/
|
||||
# file(GLOB_RECURSE SourceFiles
|
||||
# ${SourceDir}/*.cpp
|
||||
# )
|
||||
file(GLOB_RECURSE SourceFiles
|
||||
${SourceDir}/*.cpp
|
||||
olcExampleProgram.cpp # Remove this
|
||||
)
|
||||
|
||||
# Comment this line if you wish to compile your own programs source code
|
||||
set(SourceFiles OneLoneCoder_PGE_SpriteTransforms.cpp)
|
||||
|
||||
# From this point on, you don't need to worry about what the code does, it just manages dependancies, linking and compilation
|
||||
#enjoy tinkering!
|
||||
|
||||
# Find thread package
|
||||
set(THREADS_PREFER_PTHREAD_FLAD ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# Find GL and GLX package
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
|
||||
if (UNIX)
|
||||
find_package(X11 REQUIRED)
|
||||
find_package(PNG REQUIRED)
|
||||
include_directories(${PNG_INCLUDE_DIR})
|
||||
|
||||
# Set platform spesific output names
|
||||
set(Executable ${ExecutableName}.o)
|
||||
endif (UNIX)
|
||||
if (WIN32)
|
||||
target_include_directories(${WinSDK})
|
||||
|
||||
# Set platform spesific output names
|
||||
set(Executable ${ExecutableName}.exe)
|
||||
if (WIN32)
|
||||
include_directories(${WinSDK})
|
||||
endif (WIN32)
|
||||
|
||||
add_executable(${Executable}
|
||||
${SourceFiles}
|
||||
# Add more directories, files or CMake variables here to have them compile too!
|
||||
)
|
||||
|
||||
target_link_libraries(${Executable}
|
||||
link_libraries(${Executable}
|
||||
Threads::Threads
|
||||
OpenGL::OpenGL
|
||||
OpenGL::GL
|
||||
|
||||
34
Contributions/README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# 3rd Party Contributions
|
||||
|
||||
These source code contributions enhance the functionality of the olcPixelGameEngine header file. They are not supported by OneLoneCoder.com or javidx9 so use them at your own risk! Though this is a nice community and to get listed here you have to be trusted...
|
||||
|
||||
## PixelGameEngine Extensions (PGEX)
|
||||
* Widens support for audio files into olcPGEX_Sound.h
|
||||
* https://github.com/gorbit99/olcPGEX_AudioConvert
|
||||
* Cross Platform Controller Support
|
||||
* https://github.com/gorbit99/olcPGEX_Gamepad
|
||||
* Sprite Animation, Sprite State Machine and Sprite Sheet Manipulation
|
||||
* https://github.com/matt-hayward/olcPGEX_AnimatedSprite
|
||||
* Additional colour constants
|
||||
* https://github.com/matt-hayward/olcPGEX_AdditionalColours
|
||||
|
||||
## MacOS Support
|
||||
* These will potentially be absorbed into main build
|
||||
* https://github.com/MumflrFumperdink/olcPGEMac
|
||||
|
||||
## Build Systems
|
||||
* CMake script
|
||||
* https://github.com/plane000/olcPixelGameEngine/blob/master/CMakeLists.txt
|
||||
|
||||
## Utilities
|
||||
* Additional fonts and font handling tools
|
||||
* https://github.com/gorbit99/OLC-Font
|
||||
* Convert olcConsoleGameEngine ".spr" files into olc::Sprite types
|
||||
* https://github.com/gorbit99/SprConverter
|
||||
|
||||
## Customisations
|
||||
* Version with SDL backend, and native controller support
|
||||
* https://github.com/Allersnj/olcPixelGameEngineSDL
|
||||
|
||||
## Cool Projects
|
||||
Have you made something using olcPixelGameEngine? Contact me to get a link to it here!
|
||||
313
Extensions/olcPGEX_Graphics2D.h
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
olcPGEX_Graphics2D.h
|
||||
|
||||
+-------------------------------------------------------------+
|
||||
| OneLoneCoder Pixel Game Engine Extension |
|
||||
| Advanced 2D Rendering - v0.5 |
|
||||
+-------------------------------------------------------------+
|
||||
|
||||
What is this?
|
||||
~~~~~~~~~~~~~
|
||||
This is an extension to the olcPixelGameEngine, which provides
|
||||
advanced olc::Sprite manipulation and drawing routines. To use
|
||||
it, simply include this header file.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 - 2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
/*
|
||||
Matrices stored as [Column][Row] (i.e. x, y)
|
||||
|
||||
|C0R0 C1R0 C2R0| | x | | x'|
|
||||
|C0R1 C1R1 C2R1| * | y | = | y'|
|
||||
|C0R2 C1R2 C2R2| |1.0| | - |
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef OLC_PGEX_GFX2D
|
||||
#define OLC_PGEX_GFX2D
|
||||
|
||||
#include <algorithm>
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
namespace olc
|
||||
{
|
||||
// Container class for Advanced 2D Drawing functions
|
||||
class GFX2D : public olc::PGEX
|
||||
{
|
||||
// A representation of an affine transform, used to rotate, scale, offset & shear space
|
||||
public:
|
||||
class Transform2D
|
||||
{
|
||||
public:
|
||||
Transform2D();
|
||||
|
||||
public:
|
||||
// Set this transformation to unity
|
||||
void Reset();
|
||||
// Append a rotation of fTheta radians to this transform
|
||||
void Rotate(float fTheta);
|
||||
// Append a translation (ox, oy) to this transform
|
||||
void Translate(float ox, float oy);
|
||||
// Append a scaling operation (sx, sy) to this transform
|
||||
void Scale(float sx, float sy);
|
||||
// Append a shear operation (sx, sy) to this transform
|
||||
void Shear(float sx, float sy);
|
||||
|
||||
void Perspective(float ox, float oy);
|
||||
// Calculate the Forward Transformation of the coordinate (in_x, in_y) -> (out_x, out_y)
|
||||
void Forward(float in_x, float in_y, float &out_x, float &out_y);
|
||||
// Calculate the Inverse Transformation of the coordinate (in_x, in_y) -> (out_x, out_y)
|
||||
void Backward(float in_x, float in_y, float &out_x, float &out_y);
|
||||
// Regenerate the Inverse Transformation
|
||||
void Invert();
|
||||
|
||||
private:
|
||||
void Multiply();
|
||||
float matrix[4][3][3];
|
||||
int nTargetMatrix;
|
||||
int nSourceMatrix;
|
||||
bool bDirty;
|
||||
};
|
||||
|
||||
public:
|
||||
// Draws a sprite with the transform applied
|
||||
static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#ifdef OLC_PGEX_GRAPHICS2D
|
||||
#undef OLC_PGEX_GRAPHICS2D
|
||||
|
||||
namespace olc
|
||||
{
|
||||
void GFX2D::DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform)
|
||||
{
|
||||
if (sprite == nullptr)
|
||||
return;
|
||||
|
||||
// Work out bounding rectangle of sprite
|
||||
float ex, ey;
|
||||
float sx, sy;
|
||||
float px, py;
|
||||
|
||||
transform.Forward(0.0f, 0.0f, sx, sy);
|
||||
px = sx; py = sy;
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
transform.Forward((float)sprite->width, (float)sprite->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
transform.Forward(0.0f, (float)sprite->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
transform.Forward((float)sprite->width, 0.0f, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
// Perform inversion of transform if required
|
||||
transform.Invert();
|
||||
|
||||
if (ex < sx)
|
||||
std::swap(ex, sx);
|
||||
if (ey < sy)
|
||||
std::swap(ey, sy);
|
||||
|
||||
// Iterate through render space, and sample Sprite from suitable texel location
|
||||
for (float i = sx; i < ex; i++)
|
||||
{
|
||||
for (float j = sy; j < ey; j++)
|
||||
{
|
||||
float ox, oy;
|
||||
transform.Backward(i, j, ox, oy);
|
||||
pge->Draw((int32_t)i, (int32_t)j, sprite->GetPixel((int32_t)(ox+0.5f), (int32_t)(oy+0.5f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
olc::GFX2D::Transform2D::Transform2D()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Reset()
|
||||
{
|
||||
nTargetMatrix = 0;
|
||||
nSourceMatrix = 1;
|
||||
bDirty = true;
|
||||
|
||||
// Columns Then Rows
|
||||
|
||||
// Matrices 0 & 1 are used as swaps in Transform accumulation
|
||||
matrix[0][0][0] = 1.0f; matrix[0][1][0] = 0.0f; matrix[0][2][0] = 0.0f;
|
||||
matrix[0][0][1] = 0.0f; matrix[0][1][1] = 1.0f; matrix[0][2][1] = 0.0f;
|
||||
matrix[0][0][2] = 0.0f; matrix[0][1][2] = 0.0f; matrix[0][2][2] = 1.0f;
|
||||
|
||||
matrix[1][0][0] = 1.0f; matrix[1][1][0] = 0.0f; matrix[1][2][0] = 0.0f;
|
||||
matrix[1][0][1] = 0.0f; matrix[1][1][1] = 1.0f; matrix[1][2][1] = 0.0f;
|
||||
matrix[1][0][2] = 0.0f; matrix[1][1][2] = 0.0f; matrix[1][2][2] = 1.0f;
|
||||
|
||||
// Matrix 2 is a cache matrix to hold the immediate transform operation
|
||||
// Matrix 3 is a cache matrix to hold the inverted transform
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Multiply()
|
||||
{
|
||||
for (int c = 0; c < 3; c++)
|
||||
{
|
||||
for (int r = 0; r < 3; r++)
|
||||
{
|
||||
matrix[nTargetMatrix][c][r] = matrix[2][0][r] * matrix[nSourceMatrix][c][0] +
|
||||
matrix[2][1][r] * matrix[nSourceMatrix][c][1] +
|
||||
matrix[2][2][r] * matrix[nSourceMatrix][c][2];
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(nTargetMatrix, nSourceMatrix);
|
||||
bDirty = true; // Any transform multiply dirties the inversion
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Rotate(float fTheta)
|
||||
{
|
||||
// Construct Rotation Matrix
|
||||
matrix[2][0][0] = cosf(fTheta); matrix[2][1][0] = sinf(fTheta); matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = -sinf(fTheta); matrix[2][1][1] = cosf(fTheta); matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Scale(float sx, float sy)
|
||||
{
|
||||
// Construct Scale Matrix
|
||||
matrix[2][0][0] = sx; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = 0.0f; matrix[2][1][1] = sy; matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Shear(float sx, float sy)
|
||||
{
|
||||
// Construct Shear Matrix
|
||||
matrix[2][0][0] = 1.0f; matrix[2][1][0] = sx; matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = sy; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Translate(float ox, float oy)
|
||||
{
|
||||
// Construct Translate Matrix
|
||||
matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = ox;
|
||||
matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = oy;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Perspective(float ox, float oy)
|
||||
{
|
||||
// Construct Translate Matrix
|
||||
matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = ox; matrix[2][1][2] = oy; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Forward(float in_x, float in_y, float &out_x, float &out_y)
|
||||
{
|
||||
out_x = in_x * matrix[nSourceMatrix][0][0] + in_y * matrix[nSourceMatrix][1][0] + matrix[nSourceMatrix][2][0];
|
||||
out_y = in_x * matrix[nSourceMatrix][0][1] + in_y * matrix[nSourceMatrix][1][1] + matrix[nSourceMatrix][2][1];
|
||||
float out_z = in_x * matrix[nSourceMatrix][0][2] + in_y * matrix[nSourceMatrix][1][2] + matrix[nSourceMatrix][2][2];
|
||||
if (out_z != 0)
|
||||
{
|
||||
out_x /= out_z;
|
||||
out_y /= out_z;
|
||||
}
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Backward(float in_x, float in_y, float &out_x, float &out_y)
|
||||
{
|
||||
out_x = in_x * matrix[3][0][0] + in_y * matrix[3][1][0] + matrix[3][2][0];
|
||||
out_y = in_x * matrix[3][0][1] + in_y * matrix[3][1][1] + matrix[3][2][1];
|
||||
float out_z = in_x * matrix[3][0][2] + in_y * matrix[3][1][2] + matrix[3][2][2];
|
||||
if (out_z != 0)
|
||||
{
|
||||
out_x /= out_z;
|
||||
out_y /= out_z;
|
||||
}
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Invert()
|
||||
{
|
||||
if (bDirty) // Obviously costly so only do if needed
|
||||
{
|
||||
float det = matrix[nSourceMatrix][0][0] * (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) -
|
||||
matrix[nSourceMatrix][1][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2]) +
|
||||
matrix[nSourceMatrix][2][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][0][2]);
|
||||
|
||||
float idet = 1.0f / det;
|
||||
matrix[3][0][0] = (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) * idet;
|
||||
matrix[3][1][0] = (matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][2]) * idet;
|
||||
matrix[3][2][0] = (matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][1] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][1]) * idet;
|
||||
matrix[3][0][1] = (matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2]) * idet;
|
||||
matrix[3][1][1] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][0][2]) * idet;
|
||||
matrix[3][2][1] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][1]) * idet;
|
||||
matrix[3][0][2] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][1]) * idet;
|
||||
matrix[3][1][2] = (matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][2]) * idet;
|
||||
matrix[3][2][2] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][1] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][0]) * idet;
|
||||
bDirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
1174
Extensions/olcPGEX_Graphics3D.h
Normal file
585
Extensions/olcPGEX_PopUpMenu.h
Normal file
@@ -0,0 +1,585 @@
|
||||
/*
|
||||
olcPGEX_PopUp.h
|
||||
|
||||
+-------------------------------------------------------------+
|
||||
| OneLoneCoder Pixel Game Engine Extension |
|
||||
| Retro PopUp Menu 1.0 |
|
||||
+-------------------------------------------------------------+
|
||||
|
||||
What is this?
|
||||
~~~~~~~~~~~~~
|
||||
This is an extension to the olcPixelGameEngine, which provides
|
||||
a quick and easy to use, flexible, skinnable context pop-up
|
||||
menu system.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 - 2020 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019, 2020
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
#define OLC_PGEX_POPUPMENU
|
||||
#include "olcPGEX_PopUpMenu.h"
|
||||
|
||||
NOTE: Requires a 9-patch sprite, by default each patch is
|
||||
8x8 pixels, patches are as follows:
|
||||
|
||||
| PANEL TL | PANEL T | PANEL TR | SCROLL UP | CURSOR TL | CURSOR TR |
|
||||
| PANEL L | PANEL M | PANEL R | SUBMENU | CURSOR BL | CURSOR BR |
|
||||
| PANEL BL | PANEL B | PANEL BR | SCROLL DOWN | UNUSED | UNUSED |
|
||||
|
||||
You can find an example sprite here:
|
||||
https://github.com/OneLoneCoder/olcPixelGameEngine/blob/master/Videos/RetroMenu.png
|
||||
|
||||
Constructing A Menu
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Declaration (presumably inside class)
|
||||
olc::popup::Menu m;
|
||||
|
||||
// Construction (root menu is a 1x5 table)
|
||||
m.SetTable(1, 5);
|
||||
|
||||
// Add first item to root menu (A 1x5 submenu)
|
||||
m["Menu1"].SetTable(1, 5);
|
||||
|
||||
// Add items to first item
|
||||
m["Menu1"]["Item1"];
|
||||
m["Menu1"]["Item2"];
|
||||
|
||||
// Add a 4x3 submenu
|
||||
m["Menu1"]["Item3"].SetTable(4, 3);
|
||||
m["Menu1"]["Item3"]["Option1"];
|
||||
m["Menu1"]["Item3"]["Option2"];
|
||||
|
||||
// Set properties of specific item
|
||||
m["Menu1"]["Item3"]["Option3"].Enable(false);
|
||||
m["Menu1"]["Item3"]["Option4"];
|
||||
m["Menu1"]["Item3"]["Option5"];
|
||||
m["Menu1"]["Item4"];
|
||||
|
||||
// Add second item to root menu
|
||||
m["Menu2"].SetTable(3, 3);
|
||||
m["Menu2"]["Item1"];
|
||||
m["Menu2"]["Item2"].SetID(1001).Enable(true);
|
||||
m["Menu2"]["Item3"];
|
||||
|
||||
// Construct the menu structure
|
||||
m.Build();
|
||||
|
||||
|
||||
Displaying a Menu
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Declaration of menu manager (presumably inside class)
|
||||
olc::popup::Manager man;
|
||||
|
||||
// Set the Menu object to the MenuManager (call once per pop)
|
||||
man.Open(&m);
|
||||
|
||||
// Draw Menu at position (30, 30), using "patch sprite"
|
||||
man.Draw(sprGFX, { 30,30 });
|
||||
|
||||
|
||||
Interacting with menu
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Send key events to menu
|
||||
if (GetKey(olc::Key::UP).bPressed) man.OnUp();
|
||||
if (GetKey(olc::Key::DOWN).bPressed) man.OnDown();
|
||||
if (GetKey(olc::Key::LEFT).bPressed) man.OnLeft();
|
||||
if (GetKey(olc::Key::RIGHT).bPressed) man.OnRight();
|
||||
if (GetKey(olc::Key::Z).bPressed) man.OnBack();
|
||||
|
||||
// "Confirm/Action" Key does something, if it returns non-null
|
||||
// then a menu item has been selected. The specific item will
|
||||
// be returned
|
||||
olc::popup::Menu* command = nullptr;
|
||||
if (GetKey(olc::Key::SPACE).bPressed) command = man.OnConfirm();
|
||||
if (command != nullptr)
|
||||
{
|
||||
std::string sLastAction =
|
||||
"Selected: " + command->GetName() +
|
||||
" ID: " + std::to_string(command->GetID());
|
||||
|
||||
// Optionally close menu?
|
||||
man.Close();
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
#ifndef OLC_PGEX_POPUPMENU_H
|
||||
#define OLC_PGEX_POPUPMENU_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace olc
|
||||
{
|
||||
namespace popup
|
||||
{
|
||||
constexpr int32_t nPatch = 8;
|
||||
|
||||
class Menu
|
||||
{
|
||||
public:
|
||||
Menu();
|
||||
Menu(const std::string n);
|
||||
|
||||
Menu& SetTable(int32_t nColumns, int32_t nRows);
|
||||
Menu& SetID(int32_t id);
|
||||
Menu& Enable(bool b);
|
||||
|
||||
int32_t GetID();
|
||||
std::string& GetName();
|
||||
bool Enabled();
|
||||
bool HasChildren();
|
||||
olc::vi2d GetSize();
|
||||
olc::vi2d& GetCursorPosition();
|
||||
Menu& operator[](const std::string& name);
|
||||
void Build();
|
||||
void DrawSelf(olc::PixelGameEngine& pge, olc::Sprite* sprGFX, olc::vi2d vScreenOffset);
|
||||
void ClampCursor();
|
||||
void OnUp();
|
||||
void OnDown();
|
||||
void OnLeft();
|
||||
void OnRight();
|
||||
Menu* OnConfirm();
|
||||
Menu* GetSelectedItem();
|
||||
|
||||
protected:
|
||||
int32_t nID = -1;
|
||||
olc::vi2d vCellTable = { 1, 0 };
|
||||
std::unordered_map<std::string, size_t> itemPointer;
|
||||
std::vector<olc::popup::Menu> items;
|
||||
olc::vi2d vSizeInPatches = { 0, 0 };
|
||||
olc::vi2d vCellSize = { 0, 0 };
|
||||
olc::vi2d vCellPadding = { 2, 0 };
|
||||
olc::vi2d vCellCursor = { 0, 0 };
|
||||
int32_t nCursorItem = 0;
|
||||
int32_t nTopVisibleRow = 0;
|
||||
int32_t nTotalRows = 0;
|
||||
const olc::vi2d vPatchSize = { nPatch, nPatch };
|
||||
std::string sName;
|
||||
olc::vi2d vCursorPos = { 0, 0 };
|
||||
bool bEnabled = true;
|
||||
};
|
||||
|
||||
class Manager : public olc::PGEX
|
||||
{
|
||||
public:
|
||||
Manager();
|
||||
void Open(Menu* mo);
|
||||
void Close();
|
||||
void OnUp();
|
||||
void OnDown();
|
||||
void OnLeft();
|
||||
void OnRight();
|
||||
void OnBack();
|
||||
Menu* OnConfirm();
|
||||
void Draw(olc::Sprite* sprGFX, olc::vi2d vScreenOffset);
|
||||
|
||||
private:
|
||||
std::list<Menu*> panels;
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef OLC_PGEX_POPUPMENU
|
||||
#undef OLC_PGEX_POPUPMENU
|
||||
|
||||
namespace olc
|
||||
{
|
||||
namespace popup
|
||||
{
|
||||
Menu::Menu()
|
||||
{
|
||||
}
|
||||
|
||||
Menu::Menu(const std::string n)
|
||||
{
|
||||
sName = n;
|
||||
}
|
||||
|
||||
|
||||
Menu& Menu::SetTable(int32_t nColumns, int32_t nRows)
|
||||
{
|
||||
vCellTable = { nColumns, nRows };
|
||||
return *this;
|
||||
}
|
||||
|
||||
Menu& Menu::SetID(int32_t id)
|
||||
{
|
||||
nID = id;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Menu& Menu::Enable(bool b)
|
||||
{
|
||||
bEnabled = b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int32_t Menu::GetID()
|
||||
{
|
||||
return nID;
|
||||
}
|
||||
|
||||
std::string& Menu::GetName()
|
||||
{
|
||||
return sName;
|
||||
}
|
||||
|
||||
bool Menu::Enabled()
|
||||
{
|
||||
return bEnabled;
|
||||
}
|
||||
|
||||
bool Menu::HasChildren()
|
||||
{
|
||||
return !items.empty();
|
||||
}
|
||||
|
||||
olc::vi2d Menu::GetSize()
|
||||
{
|
||||
return { int32_t(sName.size()), 1 };
|
||||
}
|
||||
|
||||
olc::vi2d& Menu::GetCursorPosition()
|
||||
{
|
||||
return vCursorPos;
|
||||
}
|
||||
|
||||
Menu& Menu::operator[](const std::string& name)
|
||||
{
|
||||
if (itemPointer.count(name) == 0)
|
||||
{
|
||||
itemPointer[name] = items.size();
|
||||
items.push_back(Menu(name));
|
||||
}
|
||||
|
||||
return items[itemPointer[name]];
|
||||
}
|
||||
|
||||
void Menu::Build()
|
||||
{
|
||||
// Recursively build all children, so they can determine their size, use
|
||||
// that size to indicate cell sizes if this object contains more than
|
||||
// one item
|
||||
for (auto& m : items)
|
||||
{
|
||||
if (m.HasChildren())
|
||||
{
|
||||
m.Build();
|
||||
}
|
||||
|
||||
// Longest child name determines cell width
|
||||
vCellSize.x = std::max(m.GetSize().x, vCellSize.x);
|
||||
vCellSize.y = std::max(m.GetSize().y, vCellSize.y);
|
||||
}
|
||||
|
||||
// Adjust size of this object (in patches) if it were rendered as a panel
|
||||
vSizeInPatches.x = vCellTable.x * vCellSize.x + (vCellTable.x - 1) * vCellPadding.x + 2;
|
||||
vSizeInPatches.y = vCellTable.y * vCellSize.y + (vCellTable.y - 1) * vCellPadding.y + 2;
|
||||
|
||||
// Calculate how many rows this item has to hold
|
||||
nTotalRows = (items.size() / vCellTable.x) + (((items.size() % vCellTable.x) > 0) ? 1 : 0);
|
||||
}
|
||||
|
||||
void Menu::DrawSelf(olc::PixelGameEngine& pge, olc::Sprite* sprGFX, olc::vi2d vScreenOffset)
|
||||
{
|
||||
// === Draw Panel
|
||||
|
||||
// Record current pixel mode user is using
|
||||
olc::Pixel::Mode currentPixelMode = pge.GetPixelMode();
|
||||
pge.SetPixelMode(olc::Pixel::MASK);
|
||||
|
||||
// Draw Panel & Border
|
||||
olc::vi2d vPatchPos = { 0,0 };
|
||||
for (vPatchPos.x = 0; vPatchPos.x < vSizeInPatches.x; vPatchPos.x++)
|
||||
{
|
||||
for (vPatchPos.y = 0; vPatchPos.y < vSizeInPatches.y; vPatchPos.y++)
|
||||
{
|
||||
// Determine position in screen space
|
||||
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
|
||||
// Calculate which patch is needed
|
||||
olc::vi2d vSourcePatch = { 0, 0 };
|
||||
if (vPatchPos.x > 0) vSourcePatch.x = 1;
|
||||
if (vPatchPos.x == vSizeInPatches.x - 1) vSourcePatch.x = 2;
|
||||
if (vPatchPos.y > 0) vSourcePatch.y = 1;
|
||||
if (vPatchPos.y == vSizeInPatches.y - 1) vSourcePatch.y = 2;
|
||||
|
||||
// Draw Actual Patch
|
||||
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
|
||||
}
|
||||
}
|
||||
|
||||
// === Draw Panel Contents
|
||||
olc::vi2d vCell = { 0,0 };
|
||||
vPatchPos = { 1,1 };
|
||||
|
||||
// Work out visible items
|
||||
int32_t nTopLeftItem = nTopVisibleRow * vCellTable.x;
|
||||
int32_t nBottomRightItem = vCellTable.y * vCellTable.x + nTopLeftItem;
|
||||
|
||||
// Clamp to size of child item vector
|
||||
nBottomRightItem = std::min(int32_t(items.size()), nBottomRightItem);
|
||||
int32_t nVisibleItems = nBottomRightItem - nTopLeftItem;
|
||||
|
||||
// Draw Scroll Markers (if required)
|
||||
if (nTopVisibleRow > 0)
|
||||
{
|
||||
vPatchPos = { vSizeInPatches.x - 2, 0 };
|
||||
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
olc::vi2d vSourcePatch = { 3, 0 };
|
||||
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
|
||||
}
|
||||
|
||||
if ((nTotalRows - nTopVisibleRow) > vCellTable.y)
|
||||
{
|
||||
vPatchPos = { vSizeInPatches.x - 2, vSizeInPatches.y - 1 };
|
||||
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
olc::vi2d vSourcePatch = { 3, 2 };
|
||||
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
|
||||
}
|
||||
|
||||
// Draw Visible Items
|
||||
for (int32_t i = 0; i < nVisibleItems; i++)
|
||||
{
|
||||
// Cell location
|
||||
vCell.x = i % vCellTable.x;
|
||||
vCell.y = i / vCellTable.x;
|
||||
|
||||
// Patch location (including border offset and padding)
|
||||
vPatchPos.x = vCell.x * (vCellSize.x + vCellPadding.x) + 1;
|
||||
vPatchPos.y = vCell.y * (vCellSize.y + vCellPadding.y) + 1;
|
||||
|
||||
// Actual screen location in pixels
|
||||
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
|
||||
// Display Item Header
|
||||
pge.DrawString(vScreenLocation, items[nTopLeftItem + i].sName, items[nTopLeftItem + i].bEnabled ? olc::WHITE : olc::DARK_GREY);
|
||||
|
||||
if (items[nTopLeftItem + i].HasChildren())
|
||||
{
|
||||
// Display Indicator that panel has a sub panel
|
||||
vPatchPos.x = vCell.x * (vCellSize.x + vCellPadding.x) + 1 + vCellSize.x;
|
||||
vPatchPos.y = vCell.y * (vCellSize.y + vCellPadding.y) + 1;
|
||||
olc::vi2d vSourcePatch = { 3, 1 };
|
||||
vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate cursor position in screen space in case system draws it
|
||||
vCursorPos.x = (vCellCursor.x * (vCellSize.x + vCellPadding.x)) * nPatch + vScreenOffset.x - nPatch;
|
||||
vCursorPos.y = ((vCellCursor.y - nTopVisibleRow) * (vCellSize.y + vCellPadding.y)) * nPatch + vScreenOffset.y + nPatch;
|
||||
}
|
||||
|
||||
void Menu::ClampCursor()
|
||||
{
|
||||
// Find item in children
|
||||
nCursorItem = vCellCursor.y * vCellTable.x + vCellCursor.x;
|
||||
|
||||
// Clamp Cursor
|
||||
if (nCursorItem >= int32_t(items.size()))
|
||||
{
|
||||
vCellCursor.y = (items.size() / vCellTable.x);
|
||||
vCellCursor.x = (items.size() % vCellTable.x) - 1;
|
||||
nCursorItem = items.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::OnUp()
|
||||
{
|
||||
vCellCursor.y--;
|
||||
if (vCellCursor.y < 0) vCellCursor.y = 0;
|
||||
|
||||
if (vCellCursor.y < nTopVisibleRow)
|
||||
{
|
||||
nTopVisibleRow--;
|
||||
if (nTopVisibleRow < 0) nTopVisibleRow = 0;
|
||||
}
|
||||
|
||||
ClampCursor();
|
||||
}
|
||||
|
||||
void Menu::OnDown()
|
||||
{
|
||||
vCellCursor.y++;
|
||||
if (vCellCursor.y == nTotalRows) vCellCursor.y = nTotalRows - 1;
|
||||
|
||||
if (vCellCursor.y > (nTopVisibleRow + vCellTable.y - 1))
|
||||
{
|
||||
nTopVisibleRow++;
|
||||
if (nTopVisibleRow > (nTotalRows - vCellTable.y))
|
||||
nTopVisibleRow = nTotalRows - vCellTable.y;
|
||||
}
|
||||
|
||||
ClampCursor();
|
||||
}
|
||||
|
||||
void Menu::OnLeft()
|
||||
{
|
||||
vCellCursor.x--;
|
||||
if (vCellCursor.x < 0) vCellCursor.x = 0;
|
||||
ClampCursor();
|
||||
}
|
||||
|
||||
void Menu::OnRight()
|
||||
{
|
||||
vCellCursor.x++;
|
||||
if (vCellCursor.x == vCellTable.x) vCellCursor.x = vCellTable.x - 1;
|
||||
ClampCursor();
|
||||
}
|
||||
|
||||
Menu* Menu::OnConfirm()
|
||||
{
|
||||
// Check if selected item has children
|
||||
if (items[nCursorItem].HasChildren())
|
||||
{
|
||||
return &items[nCursorItem];
|
||||
}
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
Menu* Menu::GetSelectedItem()
|
||||
{
|
||||
return &items[nCursorItem];
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
|
||||
Manager::Manager()
|
||||
{
|
||||
}
|
||||
|
||||
void Manager::Open(Menu* mo)
|
||||
{
|
||||
Close();
|
||||
panels.push_back(mo);
|
||||
}
|
||||
|
||||
void Manager::Close()
|
||||
{
|
||||
panels.clear();
|
||||
}
|
||||
|
||||
void Manager::OnUp()
|
||||
{
|
||||
if (!panels.empty()) panels.back()->OnUp();
|
||||
}
|
||||
|
||||
void Manager::OnDown()
|
||||
{
|
||||
if (!panels.empty()) panels.back()->OnDown();
|
||||
}
|
||||
|
||||
void Manager::OnLeft()
|
||||
{
|
||||
if (!panels.empty()) panels.back()->OnLeft();
|
||||
}
|
||||
|
||||
void Manager::OnRight()
|
||||
{
|
||||
if (!panels.empty()) panels.back()->OnRight();
|
||||
}
|
||||
|
||||
void Manager::OnBack()
|
||||
{
|
||||
if (!panels.empty()) panels.pop_back();
|
||||
}
|
||||
|
||||
Menu* Manager::OnConfirm()
|
||||
{
|
||||
if (panels.empty()) return nullptr;
|
||||
|
||||
Menu* next = panels.back()->OnConfirm();
|
||||
if (next == panels.back())
|
||||
{
|
||||
if (panels.back()->GetSelectedItem()->Enabled())
|
||||
return panels.back()->GetSelectedItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (next->Enabled())
|
||||
panels.push_back(next);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Manager::Draw(olc::Sprite* sprGFX, olc::vi2d vScreenOffset)
|
||||
{
|
||||
if (panels.empty()) return;
|
||||
|
||||
// Draw Visible Menu System
|
||||
for (auto& p : panels)
|
||||
{
|
||||
p->DrawSelf(*pge, sprGFX, vScreenOffset);
|
||||
vScreenOffset += {10, 10};
|
||||
}
|
||||
|
||||
// Draw Cursor
|
||||
olc::Pixel::Mode currentPixelMode = pge->GetPixelMode();
|
||||
pge->SetPixelMode(olc::Pixel::ALPHA);
|
||||
pge->DrawPartialSprite(panels.back()->GetCursorPosition(), sprGFX, olc::vi2d(4, 0) * nPatch, { nPatch * 2, nPatch * 2 });
|
||||
pge->SetPixelMode(currentPixelMode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
# License (OLC-3)
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
Copyright 2018-2020 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
||||
2362
LastVersion/olcPixelGameEngine.h
Normal file
36
README.md
@@ -1,12 +1,44 @@
|
||||
# olcPixelGameEngine
|
||||
The official distribution of olcPixelGameEngine, a tool used in javidx9's YouTube videos and projects
|
||||
Unofficial fork of the olcPixelGameEngine, maintained and updeted by me, a tool used in javidx9's YouTube videos and projects
|
||||
|
||||
**You only need the one file - olcPixelGameEngine.h - included in your project!**
|
||||
|
||||
Provides a fast, richly featured, cross platform pixel drawing and user interface framework for
|
||||
* The development of games
|
||||
* Visualisation of algorithms
|
||||
* Prototyping and experimentation
|
||||
* Education
|
||||
|
||||
olcPixelGameEngine is easily extended! for example:
|
||||
* 2D Affine transforms
|
||||
* 3D Software renderer
|
||||
* Controller input
|
||||
* Sound
|
||||
* Hardware interfaces
|
||||
|
||||
olcPixelGameEngine is easy to port! Runs on:
|
||||
* Windows (all)
|
||||
* Linux / Raspberry Pi / ChromeOS
|
||||
* MacOS (coming soon to official, but already available in "Contributors")
|
||||
* PSP & Switch (Not supported by OneLoneCoder)
|
||||
|
||||
olcPixelGameEngine has been reimplemented in other languages!
|
||||
* C#
|
||||
* Rust
|
||||
* Lua
|
||||
* Java
|
||||
|
||||
olcPixelGameEngine is actively maintained and developed!
|
||||
|
||||
olcPixelGameEngine is used by 100s, if not 1000s of programmers at all levels of ability!
|
||||
|
||||
|
||||
# Documentation
|
||||
Please see https://github.com/OneLoneCoder/olcPixelGameEngine/wiki
|
||||
|
||||
# License (OLC-3)
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
Copyright 2018, 2019, 2020 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
||||
BIN
Videos/CarCrimeCity/Part1/City_Roads1_mip0.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
670
Videos/CarCrimeCity/Part1/OneLoneCoder_CarCrimeCity1.cpp
Normal file
@@ -0,0 +1,670 @@
|
||||
/*
|
||||
BIG PROJECT - Top Down City Based Car Crime Game Part #1
|
||||
"Probably gonna regret starting this one..." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Instructions:
|
||||
~~~~~~~~~~~~~
|
||||
This is the source that accompanies part 1 of the video series which
|
||||
can be viewed via the link below. Here you can create and edit a city
|
||||
from a top down perspective ad navigate it with the car.
|
||||
|
||||
Using the mouse left click you can select cells. Using right click clears
|
||||
all the selected cells.
|
||||
|
||||
"E" - Lowers building height
|
||||
"T" - Raises building height
|
||||
"R" - Places road
|
||||
"Z, X" - Zoom
|
||||
"Up, Left, Right" - Control car
|
||||
"F5" - Save current city
|
||||
"F8" - Load existing city
|
||||
|
||||
A default city is provided for you - "example1.city", please ensure
|
||||
you have this file also.
|
||||
|
||||
Relevant Video: https://youtu.be/mD6b_hP17WI
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018
|
||||
*/
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
#include "olcPGEX_Graphics3D.h"
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <fstream>
|
||||
|
||||
// Override base class with your custom functionality
|
||||
class CarCrimeCity : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
CarCrimeCity()
|
||||
{
|
||||
sAppName = "Car Crime City";
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// Define the cell
|
||||
struct sCell
|
||||
{
|
||||
int nHeight = 0;
|
||||
int nWorldX = 0;
|
||||
int nWorldY = 0;
|
||||
bool bRoad = false;
|
||||
bool bBuilding = true;
|
||||
};
|
||||
|
||||
// Map variables
|
||||
int nMapWidth;
|
||||
int nMapHeight;
|
||||
sCell *pMap;
|
||||
|
||||
olc::Sprite *sprAll;
|
||||
olc::Sprite *sprGround;
|
||||
olc::Sprite *sprRoof;
|
||||
olc::Sprite *sprFrontage;
|
||||
olc::Sprite *sprWindows;
|
||||
olc::Sprite *sprRoad[12];
|
||||
olc::Sprite *sprCar;
|
||||
|
||||
float fCameraX = 0.0f;
|
||||
float fCameraY = 0.0f;
|
||||
float fCameraZ = -10.0f;
|
||||
|
||||
olc::GFX3D::mesh meshCube;
|
||||
olc::GFX3D::mesh meshFlat;
|
||||
olc::GFX3D::mesh meshWallsOut;
|
||||
|
||||
float fCarAngle = 0.0f;
|
||||
float fCarSpeed = 2.0f;
|
||||
olc::GFX3D::vec3d vecCarVel = { 0,0,0 };
|
||||
olc::GFX3D::vec3d vecCarPos = { 0,0,0 };
|
||||
|
||||
|
||||
int nMouseWorldX = 0;
|
||||
int nMouseWorldY = 0;
|
||||
int nOldMouseWorldX = 0;
|
||||
int nOldMouseWorldY = 0;
|
||||
|
||||
bool bMouseDown = false;
|
||||
std::unordered_set<sCell*> setSelectedCells;
|
||||
|
||||
olc::GFX3D::PipeLine pipeRender;
|
||||
olc::GFX3D::mat4x4 matProj;
|
||||
olc::GFX3D::vec3d vUp = { 0,1,0 };
|
||||
olc::GFX3D::vec3d vEye = { 0,0,-10 };
|
||||
olc::GFX3D::vec3d vLookDir = { 0,0,1 };
|
||||
|
||||
olc::GFX3D::vec3d viewWorldTopLeft, viewWorldBottomRight;
|
||||
|
||||
|
||||
void SaveCity(std::string sFilename)
|
||||
{
|
||||
std::ofstream file(sFilename, std::ios::out | std::ios::binary);
|
||||
file.write((char*)&nMapWidth, sizeof(int));
|
||||
file.write((char*)&nMapHeight, sizeof(int));
|
||||
for (int x = 0; x < nMapWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nMapHeight; y++)
|
||||
{
|
||||
file.write((char*)&pMap[y*nMapWidth + x], sizeof(sCell));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LoadCity(std::string sFilename)
|
||||
{
|
||||
std::ifstream file(sFilename, std::ios::in | std::ios::binary);
|
||||
file.read((char*)&nMapWidth, sizeof(int));
|
||||
file.read((char*)&nMapHeight, sizeof(int));
|
||||
delete[] pMap;
|
||||
pMap = new sCell[nMapWidth * nMapHeight];
|
||||
for (int x = 0; x < nMapWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nMapHeight; y++)
|
||||
{
|
||||
file.read((char*)&pMap[y*nMapWidth + x], sizeof(sCell));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
// Load Sprite Sheet
|
||||
sprAll = new olc::Sprite("City_Roads1_mip0.png");
|
||||
|
||||
// Here we break up the sprite sheet into individual textures. This is more
|
||||
// out of convenience than anything else, as it keeps the texture coordinates
|
||||
// easy to manipulate
|
||||
|
||||
// Building Lowest Floor
|
||||
sprFrontage = new olc::Sprite(32, 96);
|
||||
SetDrawTarget(sprFrontage);
|
||||
DrawPartialSprite(0, 0, sprAll, 288, 64, 32, 96);
|
||||
|
||||
// Building Windows
|
||||
sprWindows = new olc::Sprite(32, 96);
|
||||
SetDrawTarget(sprWindows);
|
||||
DrawPartialSprite(0, 0, sprAll, 320, 64, 32, 96);
|
||||
|
||||
// Plain Grass Field
|
||||
sprGround = new olc::Sprite(96, 96);
|
||||
SetDrawTarget(sprGround);
|
||||
DrawPartialSprite(0, 0, sprAll, 192, 0, 96, 96);
|
||||
|
||||
// Building Roof
|
||||
sprRoof = new olc::Sprite(96, 96);
|
||||
SetDrawTarget(sprRoof);
|
||||
DrawPartialSprite(0, 0, sprAll, 352, 64, 96, 96);
|
||||
|
||||
// There are 12 Road Textures, aranged in a 3x4 grid
|
||||
for (int r = 0; r < 12; r++)
|
||||
{
|
||||
sprRoad[r] = new olc::Sprite(96, 96);
|
||||
SetDrawTarget(sprRoad[r]);
|
||||
DrawPartialSprite(0, 0, sprAll, (r%3)*96, (r/3)*96, 96, 96);
|
||||
}
|
||||
|
||||
// Don't foregt to set the draw target back to being the main screen (been there... wasted 1.5 hours :| )
|
||||
SetDrawTarget(nullptr);
|
||||
|
||||
// The Yellow Car
|
||||
sprCar = new olc::Sprite("car_top.png");
|
||||
|
||||
|
||||
|
||||
// Define the city map, a 64x32 array of Cells. Initialise cells
|
||||
// to be just grass fields
|
||||
nMapWidth = 64;
|
||||
nMapHeight = 32;
|
||||
pMap = new sCell[nMapWidth * nMapHeight];
|
||||
for (int x = 0; x < nMapWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nMapHeight; y++)
|
||||
{
|
||||
pMap[y*nMapWidth + x].bRoad = false;
|
||||
pMap[y*nMapWidth + x].nHeight = 0;
|
||||
pMap[y*nMapWidth + x].nWorldX = x;
|
||||
pMap[y*nMapWidth + x].nWorldY = y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now we'll hand construct some meshes. These are DELIBERATELY simple and not optimised (see a later video)
|
||||
// Here the geometry is unit in size (1x1x1)
|
||||
|
||||
// A Full cube - Always useful for debugging
|
||||
meshCube.tris =
|
||||
{
|
||||
// SOUTH
|
||||
{ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, },
|
||||
{ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
|
||||
// EAST
|
||||
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, },
|
||||
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
|
||||
// NORTH
|
||||
{ 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, },
|
||||
{ 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
|
||||
// WEST
|
||||
{ 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, },
|
||||
{ 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
|
||||
// TOP
|
||||
{ 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, },
|
||||
{ 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
|
||||
// BOTTOM
|
||||
{ 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, },
|
||||
{ 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
|
||||
};
|
||||
|
||||
// A Flat quad
|
||||
meshFlat.tris =
|
||||
{
|
||||
{ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
{ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, },
|
||||
};
|
||||
|
||||
// The four outer walls of a cell
|
||||
meshWallsOut.tris =
|
||||
{
|
||||
// EAST
|
||||
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, },
|
||||
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, },
|
||||
|
||||
// WEST
|
||||
{ 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, },
|
||||
{ 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
|
||||
// TOP
|
||||
{ 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, },
|
||||
{ 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
|
||||
// BOTTOM
|
||||
{ 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, },
|
||||
{ 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, },
|
||||
};
|
||||
|
||||
|
||||
// Initialise the 3D Graphics PGE Extension. This is required
|
||||
// to setup internal buffers to the same size as the main output
|
||||
olc::GFX3D::ConfigureDisplay();
|
||||
|
||||
// Configure the rendering pipeline with projection and viewport properties
|
||||
pipeRender.SetProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f, 0.0f, 0.0f, ScreenWidth(), ScreenHeight());
|
||||
|
||||
// Also make a projection matrix, we might need this later
|
||||
matProj = olc::GFX3D::Math::Mat_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f);
|
||||
|
||||
LoadCity("example1.city");
|
||||
|
||||
// Ok, lets go!
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
// Directly manipulate camera
|
||||
//if (GetKey(olc::Key::W).bHeld) fCameraY -= 2.0f * fElapsedTime;
|
||||
//if (GetKey(olc::Key::S).bHeld) fCameraY += 2.0f * fElapsedTime;
|
||||
//if (GetKey(olc::Key::A).bHeld) fCameraX -= 2.0f * fElapsedTime;
|
||||
//if (GetKey(olc::Key::D).bHeld) fCameraX += 2.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::Z).bHeld) fCameraZ += 5.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::X).bHeld) fCameraZ -= 5.0f * fElapsedTime;
|
||||
|
||||
if (GetKey(olc::Key::F5).bReleased) SaveCity("example1.city");
|
||||
if (GetKey(olc::Key::F8).bReleased) LoadCity("example1.city");
|
||||
|
||||
// === Handle User Input for Editing ==
|
||||
|
||||
// If there are no selected cells, then only edit the cell under the current mouse cursor
|
||||
// otherwise iterate through the set of sleected cells and apply to all of them
|
||||
|
||||
// Check that cell exists in valid 2D map space
|
||||
if (nMouseWorldX >= 0 && nMouseWorldX < nMapWidth && nMouseWorldY >= 0 && nMouseWorldY < nMapHeight)
|
||||
{
|
||||
// Press "R" to toggle Road flag for selected cell(s)
|
||||
if (GetKey(olc::Key::R).bPressed)
|
||||
{
|
||||
if (!setSelectedCells.empty())
|
||||
{
|
||||
for (auto &cell : setSelectedCells)
|
||||
{
|
||||
cell->bRoad = !cell->bRoad;
|
||||
}
|
||||
}
|
||||
else
|
||||
pMap[nMouseWorldY*nMapWidth + nMouseWorldX].bRoad = !pMap[nMouseWorldY*nMapWidth + nMouseWorldX].bRoad;
|
||||
}
|
||||
|
||||
// Press "T" to increase height for selected cell(s)
|
||||
if (GetKey(olc::Key::T).bPressed)
|
||||
{
|
||||
if (!setSelectedCells.empty())
|
||||
{
|
||||
for (auto &cell : setSelectedCells)
|
||||
{
|
||||
cell->nHeight++;
|
||||
}
|
||||
}
|
||||
else
|
||||
pMap[nMouseWorldY*nMapWidth + nMouseWorldX].nHeight++;
|
||||
}
|
||||
|
||||
// Press "E" to decrease height for selected cell(s)
|
||||
if (GetKey(olc::Key::E).bPressed)
|
||||
{
|
||||
if (!setSelectedCells.empty())
|
||||
{
|
||||
for (auto &cell : setSelectedCells)
|
||||
{
|
||||
cell->nHeight--;
|
||||
}
|
||||
}
|
||||
else
|
||||
pMap[nMouseWorldY*nMapWidth + nMouseWorldX].nHeight--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// === Car User Input ===
|
||||
|
||||
if (GetKey(olc::Key::LEFT).bHeld) fCarAngle -= 4.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::RIGHT).bHeld) fCarAngle += 4.0f * fElapsedTime;
|
||||
|
||||
olc::GFX3D::vec3d a = { 1, 0, 0 };
|
||||
olc::GFX3D::mat4x4 m = olc::GFX3D::Math::Mat_MakeRotationZ(fCarAngle);
|
||||
vecCarVel = olc::GFX3D::Math::Mat_MultiplyVector(m, a);
|
||||
|
||||
if (GetKey(olc::Key::UP).bHeld)
|
||||
{
|
||||
vecCarPos.x += vecCarVel.x * fCarSpeed * fElapsedTime;
|
||||
vecCarPos.y += vecCarVel.y * fCarSpeed * fElapsedTime;
|
||||
}
|
||||
|
||||
// === Position Camera ===
|
||||
|
||||
// Our camera currently follows the car, and the car stays in the middle of
|
||||
// the screen. We need to know where the camera is before we can work with
|
||||
// on screen interactions
|
||||
fCameraY = vecCarPos.y;
|
||||
fCameraX = vecCarPos.x;
|
||||
vEye = { fCameraX,fCameraY,fCameraZ };
|
||||
olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir);
|
||||
|
||||
// Setup the camera properties for the pipeline - aka "view" transform
|
||||
pipeRender.SetCamera(vEye, vLookTarget, vUp);
|
||||
|
||||
|
||||
// === Calculate Mouse Position on Ground Plane ===
|
||||
|
||||
// Here we take the screen coordinate of the mouse, transform it into normalised space (-1 --> +1)
|
||||
// for both axes. Instead of inverting and multiplying by the projection matrix, we only need the
|
||||
// aspect ratio parameters, with which we'll scale the mouse coordinate. This new point is then
|
||||
// multiplied by the inverse of the look at matrix (camera view matrix) aka a point at matrix, to
|
||||
// transform the new point into world space.
|
||||
//
|
||||
// Now, the thing is, a 2D point is no good on its own, our world has depth. If we treat the 2D
|
||||
// point as a ray cast from (0, 0)->(mx, my), we can see where this ray intersects with a plane
|
||||
// at a specific depth.
|
||||
|
||||
// Create a point at matrix, if you recall, this is the inverse of the look at matrix
|
||||
// used by the camera
|
||||
olc::GFX3D::mat4x4 matView = olc::GFX3D::Math::Mat_PointAt(vEye, vLookTarget, vUp);
|
||||
|
||||
// Assume the origin of the mouse ray is the middle of the screen...
|
||||
olc::GFX3D::vec3d vecMouseOrigin = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
// ...and that a ray is cast to the mouse location from the origin. Here we translate
|
||||
// the mouse coordinates into viewport coordinates
|
||||
olc::GFX3D::vec3d vecMouseDir = {
|
||||
2.0f * ((GetMouseX() / (float)ScreenWidth()) - 0.5f) / matProj.m[0][0],
|
||||
2.0f * ((GetMouseY() / (float)ScreenHeight()) - 0.5f) / matProj.m[1][1],
|
||||
1.0f,
|
||||
0.0f };
|
||||
|
||||
// Now transform the origin point and ray direction by the inverse of the camera
|
||||
vecMouseOrigin = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseOrigin);
|
||||
vecMouseDir = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseDir);
|
||||
|
||||
// Extend the mouse ray to a large length
|
||||
vecMouseDir = olc::GFX3D::Math::Vec_Mul(vecMouseDir, 1000.0f);
|
||||
|
||||
// Offset the mouse ray by the mouse origin
|
||||
vecMouseDir = olc::GFX3D::Math::Vec_Add(vecMouseOrigin, vecMouseDir);
|
||||
|
||||
// All of our intersections for mouse checks occur in the ground plane (z=0), so
|
||||
// define a plane at that location
|
||||
olc::GFX3D::vec3d plane_p = { 0.0f, 0.0f, 0.0f };
|
||||
olc::GFX3D::vec3d plane_n = { 0.0f, 0.0f, 1.0f };
|
||||
|
||||
// Calculate Mouse Location in plane, by doing a line/plane intersection test
|
||||
float t = 0.0f;
|
||||
olc::GFX3D::vec3d mouse3d = olc::GFX3D::Math::Vec_IntersectPlane(plane_p, plane_n, vecMouseOrigin, vecMouseDir, t);
|
||||
|
||||
|
||||
|
||||
// === Now we have the mouse in 3D! Handle mouse user input ===
|
||||
|
||||
// Left click & left click drag selects cells by adding them to the set of selected cells
|
||||
// Here I make sure only to do this if the cell under the mouse has changed from the
|
||||
// previous frame, but the set will also reject duplicate cells being added
|
||||
if (GetMouse(0).bHeld && ((nMouseWorldX != nOldMouseWorldX) || (nMouseWorldY != nOldMouseWorldY)))
|
||||
setSelectedCells.emplace(&pMap[nMouseWorldY * nMapWidth + nMouseWorldX]);
|
||||
|
||||
// Single clicking cells also adds them
|
||||
if (GetMouse(0).bPressed)
|
||||
setSelectedCells.emplace(&pMap[nMouseWorldY * nMapWidth + nMouseWorldX]);
|
||||
|
||||
// If the user right clicks, the set of selected cells is emptied
|
||||
if (GetMouse(1).bReleased)
|
||||
setSelectedCells.clear();
|
||||
|
||||
// Cache the current mouse position to use during comparison in next frame
|
||||
nOldMouseWorldX = nMouseWorldX;
|
||||
nOldMouseWorldY = nMouseWorldY;
|
||||
|
||||
nMouseWorldX = (int)mouse3d.x;
|
||||
nMouseWorldY = (int)mouse3d.y;
|
||||
|
||||
|
||||
|
||||
|
||||
// === Rendering ===
|
||||
|
||||
// Right, now we're gonna render the scene!
|
||||
|
||||
// First Clear the screen and the depth buffer
|
||||
Clear(olc::BLUE);
|
||||
olc::GFX3D::ClearDepth();
|
||||
|
||||
// === Calculate Visible World ===
|
||||
|
||||
// Since we now have the transforms to convert screen space into ground plane space, we
|
||||
// can calculate the visible extents of the world, regardless of zoom level! The method is
|
||||
// exactly the same for the mouse, but we use fixed screen coordinates that represent the
|
||||
// top left, and bottom right of the screen
|
||||
|
||||
// Work out Top Left Ground Cell
|
||||
vecMouseDir = { -1.0f / matProj.m[0][0],-1.0f / matProj.m[1][1], 1.0f, 0.0f };
|
||||
vecMouseDir = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseDir);
|
||||
vecMouseDir = olc::GFX3D::Math::Vec_Mul(vecMouseDir, 1000.0f);
|
||||
vecMouseDir = olc::GFX3D::Math::Vec_Add(vecMouseOrigin, vecMouseDir);
|
||||
viewWorldTopLeft = olc::GFX3D::Math::Vec_IntersectPlane(plane_p, plane_n, vecMouseOrigin, vecMouseDir, t);
|
||||
|
||||
// Work out Bottom Right Ground Cell
|
||||
vecMouseDir = { 1.0f / matProj.m[0][0], 1.0f / matProj.m[1][1], 1.0f, 0.0f };
|
||||
vecMouseDir = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseDir);
|
||||
vecMouseDir = olc::GFX3D::Math::Vec_Mul(vecMouseDir, 1000.0f);
|
||||
vecMouseDir = olc::GFX3D::Math::Vec_Add(vecMouseOrigin, vecMouseDir);
|
||||
viewWorldBottomRight = olc::GFX3D::Math::Vec_IntersectPlane(plane_p, plane_n, vecMouseOrigin, vecMouseDir, t);
|
||||
|
||||
// Calculate visible tiles
|
||||
//int nStartX = 0;
|
||||
//int nEndX = nMapWidth;
|
||||
//int nStartY = 0;
|
||||
//int nEndY = nMapHeight;
|
||||
|
||||
int nStartX = std::max(0, (int)viewWorldTopLeft.x - 1);
|
||||
int nEndX = std::min(nMapWidth, (int)viewWorldBottomRight.x + 1);
|
||||
int nStartY = std::max(0, (int)viewWorldTopLeft.y - 1);
|
||||
int nEndY = std::min(nMapHeight, (int)viewWorldBottomRight.y + 1);
|
||||
|
||||
|
||||
// Iterate through all the cells we wish to draw. Each cell is 1x1 and elevates in the Z -Axis
|
||||
for (int x = nStartX; x < nEndX; x++)
|
||||
{
|
||||
for (int y = nStartY; y < nEndY; y++)
|
||||
{
|
||||
if (pMap[y*nMapWidth + x].bRoad)
|
||||
{
|
||||
// Cell is a road, look at neighbouring cells. If they are roads also,
|
||||
// then choose the appropriate texture that joins up correctly
|
||||
|
||||
int road = 0;
|
||||
auto r = [&](int i, int j)
|
||||
{
|
||||
return pMap[(y + j) * nMapWidth + (x + i)].bRoad;
|
||||
};
|
||||
|
||||
if (r(0, -1) && r(0, +1) && !r(-1, 0) && !r(+1, 0)) road = 0;
|
||||
if (!r(0, -1) && !r(0, +1) && r(-1, 0) && r(+1, 0)) road = 1;
|
||||
|
||||
if (!r(0, -1) && r(0, +1) && !r(-1, 0) && r(+1, 0)) road = 3;
|
||||
if (!r(0, -1) && r(0, +1) && r(-1, 0) && r(+1, 0)) road = 4;
|
||||
if (!r(0, -1) && r(0, +1) && r(-1, 0) && !r(+1, 0)) road = 5;
|
||||
|
||||
if (r(0, -1) && r(0, +1) && !r(-1, 0) && r(+1, 0)) road = 6;
|
||||
if (r(0, -1) && r(0, +1) && r(-1, 0) && r(+1, 0)) road = 7;
|
||||
if (r(0, -1) && r(0, +1) && r(-1, 0) && !r(+1, 0)) road = 8;
|
||||
|
||||
if (r(0, -1) && !r(0, +1) && !r(-1, 0) && r(+1, 0)) road = 9;
|
||||
if (r(0, -1) && !r(0, +1) && r(-1, 0) && r(+1, 0)) road = 10;
|
||||
if (r(0, -1) && !r(0, +1) && r(-1, 0) && !r(+1, 0)) road = 11;
|
||||
|
||||
// Create a translation transform to position the cell in the world
|
||||
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(x, y, 0.0f);
|
||||
pipeRender.SetTransform(matWorld);
|
||||
|
||||
// Set the appropriate texture to use
|
||||
pipeRender.SetTexture(sprRoad[road]);
|
||||
|
||||
// Draw a flat quad
|
||||
pipeRender.Render(meshFlat.tris);
|
||||
|
||||
}
|
||||
else // Not Road
|
||||
{
|
||||
// If the cell is not considered road, then draw it appropriately
|
||||
|
||||
if (pMap[y*nMapWidth + x].nHeight < 0)
|
||||
{
|
||||
// Cell is blank - for now ;-P
|
||||
}
|
||||
|
||||
if (pMap[y*nMapWidth + x].nHeight == 0)
|
||||
{
|
||||
// Cell is ground, draw a flat grass quad at height 0
|
||||
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(x, y, 0.0f);
|
||||
pipeRender.SetTransform(matWorld);
|
||||
pipeRender.SetTexture(sprGround);
|
||||
pipeRender.Render(meshFlat.tris);
|
||||
}
|
||||
|
||||
if (pMap[y*nMapWidth + x].nHeight > 0)
|
||||
{
|
||||
// Cell is Building, for now, we'll draw each storey as a seperate mesh
|
||||
int h, t;
|
||||
t = pMap[y*nMapWidth + x].nHeight;
|
||||
|
||||
for (h = 0; h < t; h++)
|
||||
{
|
||||
// Create a transform that positions the storey according to its height
|
||||
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(x, y, -(h + 1) * 0.2f);
|
||||
pipeRender.SetTransform(matWorld);
|
||||
|
||||
// Choose a texture, if its ground level, use the "street level front", otherwise use windows
|
||||
pipeRender.SetTexture(h == 0 ? sprFrontage : sprWindows);
|
||||
pipeRender.Render(meshWallsOut.tris);
|
||||
}
|
||||
|
||||
// Top the building off with a roof
|
||||
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(x, y, -(h) * 0.2f);
|
||||
pipeRender.SetTransform(matWorld);
|
||||
pipeRender.SetTexture(sprRoof);
|
||||
pipeRender.Render(meshFlat.tris);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw Selected Cells, iterate through the set of cells, and draw a wireframe quad at ground level
|
||||
// to indicate it is in the selection set
|
||||
for (auto &cell : setSelectedCells)
|
||||
{
|
||||
// Draw CursorCube
|
||||
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(cell->nWorldX, cell->nWorldY, 0.0f);
|
||||
pipeRender.SetTransform(matWorld);
|
||||
pipeRender.SetTexture(sprRoof);
|
||||
pipeRender.Render(meshFlat.tris, olc::GFX3D::RENDER_WIRE);
|
||||
}
|
||||
|
||||
// Draw Car, a few transforms required for this
|
||||
|
||||
// 1) Offset the car to the middle of the quad
|
||||
olc::GFX3D::mat4x4 matCarOffset = olc::GFX3D::Math::Mat_MakeTranslation(-0.5f, -0.5f, -0.0f);
|
||||
// 2) The quad is currently unit square, scale it to be more rectangular and smaller than the cells
|
||||
olc::GFX3D::mat4x4 matCarScale = olc::GFX3D::Math::Mat_MakeScale(0.4f, 0.2f, 1.0f);
|
||||
// 3) Combine into matrix
|
||||
olc::GFX3D::mat4x4 matCar = olc::GFX3D::Math::Mat_MultiplyMatrix(matCarOffset, matCarScale);
|
||||
// 4) Rotate the car around its offset origin, according to its angle
|
||||
olc::GFX3D::mat4x4 matCarRot = olc::GFX3D::Math::Mat_MakeRotationZ(fCarAngle);
|
||||
matCar = olc::GFX3D::Math::Mat_MultiplyMatrix(matCar, matCarRot);
|
||||
// 5) Translate the car into its position in the world. Give it a little elevation so its baove the ground
|
||||
olc::GFX3D::mat4x4 matCarTrans = olc::GFX3D::Math::Mat_MakeTranslation(vecCarPos.x, vecCarPos.y, -0.01f);
|
||||
matCar = olc::GFX3D::Math::Mat_MultiplyMatrix(matCar, matCarTrans);
|
||||
|
||||
// Set the car texture to the pipeline
|
||||
pipeRender.SetTexture(sprCar);
|
||||
// Apply "world" transform to pipeline
|
||||
pipeRender.SetTransform(matCar);
|
||||
|
||||
// The car has transparency, so enable it
|
||||
SetPixelMode(olc::Pixel::ALPHA);
|
||||
// Render the quad
|
||||
pipeRender.Render(meshFlat.tris);
|
||||
// Set transparency back to none to optimise drawing other pixels
|
||||
SetPixelMode(olc::Pixel::NORMAL);
|
||||
|
||||
|
||||
// Draw the current camera position for debug information
|
||||
//DrawString(10, 30, "CX: " + std::to_string(fCameraX) + " CY: " + std::to_string(fCameraY) + " CZ: " + std::to_string(fCameraZ));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
CarCrimeCity demo;
|
||||
if (demo.Construct(768, 480, 2, 2))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
BIN
Videos/CarCrimeCity/Part1/car_top.png
Normal file
|
After Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
BIN
Videos/CarCrimeCity/Part1/example1.city
Normal file
1174
Videos/CarCrimeCity/Part1/olcPGEX_Graphics3D.h
Normal file
2067
Videos/CarCrimeCity/Part1/olcPixelGameEngine.h
Normal file
256
Videos/CarCrimeCity/Part2/Lua533/include/lauxlib.h
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $
|
||||
** Auxiliary functions for building Lua libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef lauxlib_h
|
||||
#define lauxlib_h
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
|
||||
/* extra error code for 'luaL_load' */
|
||||
#define LUA_ERRFILE (LUA_ERRERR+1)
|
||||
|
||||
|
||||
typedef struct luaL_Reg {
|
||||
const char *name;
|
||||
lua_CFunction func;
|
||||
} luaL_Reg;
|
||||
|
||||
|
||||
#define LUAL_NUMSIZES (sizeof(lua_Integer)*16 + sizeof(lua_Number))
|
||||
|
||||
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver, size_t sz);
|
||||
#define luaL_checkversion(L) \
|
||||
luaL_checkversion_(L, LUA_VERSION_NUM, LUAL_NUMSIZES)
|
||||
|
||||
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
|
||||
LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
|
||||
LUALIB_API int (luaL_argerror) (lua_State *L, int arg, const char *extramsg);
|
||||
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int arg,
|
||||
size_t *l);
|
||||
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int arg,
|
||||
const char *def, size_t *l);
|
||||
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int arg);
|
||||
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int arg, lua_Number def);
|
||||
|
||||
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int arg);
|
||||
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int arg,
|
||||
lua_Integer def);
|
||||
|
||||
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
|
||||
LUALIB_API void (luaL_checktype) (lua_State *L, int arg, int t);
|
||||
LUALIB_API void (luaL_checkany) (lua_State *L, int arg);
|
||||
|
||||
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
|
||||
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
|
||||
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
|
||||
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
|
||||
|
||||
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
|
||||
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
|
||||
|
||||
LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
|
||||
const char *const lst[]);
|
||||
|
||||
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
|
||||
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
|
||||
|
||||
/* predefined references */
|
||||
#define LUA_NOREF (-2)
|
||||
#define LUA_REFNIL (-1)
|
||||
|
||||
LUALIB_API int (luaL_ref) (lua_State *L, int t);
|
||||
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
|
||||
|
||||
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
|
||||
const char *mode);
|
||||
|
||||
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
|
||||
|
||||
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
|
||||
const char *name, const char *mode);
|
||||
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
|
||||
|
||||
LUALIB_API lua_State *(luaL_newstate) (void);
|
||||
|
||||
LUALIB_API lua_Integer (luaL_len) (lua_State *L, int idx);
|
||||
|
||||
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
|
||||
const char *r);
|
||||
|
||||
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
|
||||
|
||||
LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
|
||||
|
||||
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
|
||||
const char *msg, int level);
|
||||
|
||||
LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
|
||||
lua_CFunction openf, int glb);
|
||||
|
||||
/*
|
||||
** ===============================================================
|
||||
** some useful macros
|
||||
** ===============================================================
|
||||
*/
|
||||
|
||||
|
||||
#define luaL_newlibtable(L,l) \
|
||||
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
|
||||
|
||||
#define luaL_newlib(L,l) \
|
||||
(luaL_checkversion(L), luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
|
||||
|
||||
#define luaL_argcheck(L, cond,arg,extramsg) \
|
||||
((void)((cond) || luaL_argerror(L, (arg), (extramsg))))
|
||||
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
|
||||
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
|
||||
|
||||
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
|
||||
|
||||
#define luaL_dofile(L, fn) \
|
||||
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||
|
||||
#define luaL_dostring(L, s) \
|
||||
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||
|
||||
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
|
||||
|
||||
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
|
||||
|
||||
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** Generic Buffer manipulation
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
typedef struct luaL_Buffer {
|
||||
char *b; /* buffer address */
|
||||
size_t size; /* buffer size */
|
||||
size_t n; /* number of characters in buffer */
|
||||
lua_State *L;
|
||||
char initb[LUAL_BUFFERSIZE]; /* initial buffer */
|
||||
} luaL_Buffer;
|
||||
|
||||
|
||||
#define luaL_addchar(B,c) \
|
||||
((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
|
||||
((B)->b[(B)->n++] = (c)))
|
||||
|
||||
#define luaL_addsize(B,s) ((B)->n += (s))
|
||||
|
||||
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
|
||||
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
|
||||
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
|
||||
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
|
||||
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
|
||||
LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
|
||||
LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
|
||||
|
||||
#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {======================================================
|
||||
** File handles for IO library
|
||||
** =======================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
|
||||
** initial structure 'luaL_Stream' (it may contain other fields
|
||||
** after that initial structure).
|
||||
*/
|
||||
|
||||
#define LUA_FILEHANDLE "FILE*"
|
||||
|
||||
|
||||
typedef struct luaL_Stream {
|
||||
FILE *f; /* stream (NULL for incompletely created streams) */
|
||||
lua_CFunction closef; /* to close stream (NULL for closed streams) */
|
||||
} luaL_Stream;
|
||||
|
||||
/* }====================================================== */
|
||||
|
||||
|
||||
|
||||
/* compatibility with old module system */
|
||||
#if defined(LUA_COMPAT_MODULE)
|
||||
|
||||
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
|
||||
int sizehint);
|
||||
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
|
||||
const luaL_Reg *l, int nup);
|
||||
|
||||
#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** "Abstraction Layer" for basic report of messages and errors
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/* print a string */
|
||||
#if !defined(lua_writestring)
|
||||
#define lua_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
|
||||
#endif
|
||||
|
||||
/* print a newline and flush the output */
|
||||
#if !defined(lua_writeline)
|
||||
#define lua_writeline() (lua_writestring("\n", 1), fflush(stdout))
|
||||
#endif
|
||||
|
||||
/* print an error message */
|
||||
#if !defined(lua_writestringerror)
|
||||
#define lua_writestringerror(s,p) \
|
||||
(fprintf(stderr, (s), (p)), fflush(stderr))
|
||||
#endif
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {============================================================
|
||||
** Compatibility with deprecated conversions
|
||||
** =============================================================
|
||||
*/
|
||||
#if defined(LUA_COMPAT_APIINTCASTS)
|
||||
|
||||
#define luaL_checkunsigned(L,a) ((lua_Unsigned)luaL_checkinteger(L,a))
|
||||
#define luaL_optunsigned(L,a,d) \
|
||||
((lua_Unsigned)luaL_optinteger(L,a,(lua_Integer)(d)))
|
||||
|
||||
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
|
||||
|
||||
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
|
||||
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
|
||||
|
||||
#endif
|
||||
/* }============================================================ */
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
486
Videos/CarCrimeCity/Part2/Lua533/include/lua.h
Normal file
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
|
||||
** Lua - A Scripting Language
|
||||
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
|
||||
** See Copyright Notice at the end of this file
|
||||
*/
|
||||
|
||||
|
||||
#ifndef lua_h
|
||||
#define lua_h
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
#include "luaconf.h"
|
||||
|
||||
|
||||
#define LUA_VERSION_MAJOR "5"
|
||||
#define LUA_VERSION_MINOR "3"
|
||||
#define LUA_VERSION_NUM 503
|
||||
#define LUA_VERSION_RELEASE "3"
|
||||
|
||||
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
||||
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
|
||||
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio"
|
||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
|
||||
|
||||
|
||||
/* mark for precompiled code ('<esc>Lua') */
|
||||
#define LUA_SIGNATURE "\x1bLua"
|
||||
|
||||
/* option for multiple returns in 'lua_pcall' and 'lua_call' */
|
||||
#define LUA_MULTRET (-1)
|
||||
|
||||
|
||||
/*
|
||||
** Pseudo-indices
|
||||
** (-LUAI_MAXSTACK is the minimum valid index; we keep some free empty
|
||||
** space after that to help overflow detection)
|
||||
*/
|
||||
#define LUA_REGISTRYINDEX (-LUAI_MAXSTACK - 1000)
|
||||
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
|
||||
|
||||
|
||||
/* thread status */
|
||||
#define LUA_OK 0
|
||||
#define LUA_YIELD 1
|
||||
#define LUA_ERRRUN 2
|
||||
#define LUA_ERRSYNTAX 3
|
||||
#define LUA_ERRMEM 4
|
||||
#define LUA_ERRGCMM 5
|
||||
#define LUA_ERRERR 6
|
||||
|
||||
|
||||
typedef struct lua_State lua_State;
|
||||
|
||||
|
||||
/*
|
||||
** basic types
|
||||
*/
|
||||
#define LUA_TNONE (-1)
|
||||
|
||||
#define LUA_TNIL 0
|
||||
#define LUA_TBOOLEAN 1
|
||||
#define LUA_TLIGHTUSERDATA 2
|
||||
#define LUA_TNUMBER 3
|
||||
#define LUA_TSTRING 4
|
||||
#define LUA_TTABLE 5
|
||||
#define LUA_TFUNCTION 6
|
||||
#define LUA_TUSERDATA 7
|
||||
#define LUA_TTHREAD 8
|
||||
|
||||
#define LUA_NUMTAGS 9
|
||||
|
||||
|
||||
|
||||
/* minimum Lua stack available to a C function */
|
||||
#define LUA_MINSTACK 20
|
||||
|
||||
|
||||
/* predefined values in the registry */
|
||||
#define LUA_RIDX_MAINTHREAD 1
|
||||
#define LUA_RIDX_GLOBALS 2
|
||||
#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
|
||||
|
||||
|
||||
/* type of numbers in Lua */
|
||||
typedef LUA_NUMBER lua_Number;
|
||||
|
||||
|
||||
/* type for integer functions */
|
||||
typedef LUA_INTEGER lua_Integer;
|
||||
|
||||
/* unsigned integer type */
|
||||
typedef LUA_UNSIGNED lua_Unsigned;
|
||||
|
||||
/* type for continuation-function contexts */
|
||||
typedef LUA_KCONTEXT lua_KContext;
|
||||
|
||||
|
||||
/*
|
||||
** Type for C functions registered with Lua
|
||||
*/
|
||||
typedef int (*lua_CFunction) (lua_State *L);
|
||||
|
||||
/*
|
||||
** Type for continuation functions
|
||||
*/
|
||||
typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
|
||||
|
||||
|
||||
/*
|
||||
** Type for functions that read/write blocks when loading/dumping Lua chunks
|
||||
*/
|
||||
typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
|
||||
|
||||
typedef int (*lua_Writer) (lua_State *L, const void *p, size_t sz, void *ud);
|
||||
|
||||
|
||||
/*
|
||||
** Type for memory-allocation functions
|
||||
*/
|
||||
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** generic extra include file
|
||||
*/
|
||||
#if defined(LUA_USER_H)
|
||||
#include LUA_USER_H
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** RCS ident string
|
||||
*/
|
||||
extern const char lua_ident[];
|
||||
|
||||
|
||||
/*
|
||||
** state manipulation
|
||||
*/
|
||||
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
|
||||
LUA_API void (lua_close) (lua_State *L);
|
||||
LUA_API lua_State *(lua_newthread) (lua_State *L);
|
||||
|
||||
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
|
||||
|
||||
|
||||
LUA_API const lua_Number *(lua_version) (lua_State *L);
|
||||
|
||||
|
||||
/*
|
||||
** basic stack manipulation
|
||||
*/
|
||||
LUA_API int (lua_absindex) (lua_State *L, int idx);
|
||||
LUA_API int (lua_gettop) (lua_State *L);
|
||||
LUA_API void (lua_settop) (lua_State *L, int idx);
|
||||
LUA_API void (lua_pushvalue) (lua_State *L, int idx);
|
||||
LUA_API void (lua_rotate) (lua_State *L, int idx, int n);
|
||||
LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
|
||||
LUA_API int (lua_checkstack) (lua_State *L, int n);
|
||||
|
||||
LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
|
||||
|
||||
|
||||
/*
|
||||
** access functions (stack -> C)
|
||||
*/
|
||||
|
||||
LUA_API int (lua_isnumber) (lua_State *L, int idx);
|
||||
LUA_API int (lua_isstring) (lua_State *L, int idx);
|
||||
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
|
||||
LUA_API int (lua_isinteger) (lua_State *L, int idx);
|
||||
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
|
||||
LUA_API int (lua_type) (lua_State *L, int idx);
|
||||
LUA_API const char *(lua_typename) (lua_State *L, int tp);
|
||||
|
||||
LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
|
||||
LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
|
||||
LUA_API int (lua_toboolean) (lua_State *L, int idx);
|
||||
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
|
||||
LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
|
||||
LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
|
||||
LUA_API void *(lua_touserdata) (lua_State *L, int idx);
|
||||
LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
|
||||
LUA_API const void *(lua_topointer) (lua_State *L, int idx);
|
||||
|
||||
|
||||
/*
|
||||
** Comparison and arithmetic functions
|
||||
*/
|
||||
|
||||
#define LUA_OPADD 0 /* ORDER TM, ORDER OP */
|
||||
#define LUA_OPSUB 1
|
||||
#define LUA_OPMUL 2
|
||||
#define LUA_OPMOD 3
|
||||
#define LUA_OPPOW 4
|
||||
#define LUA_OPDIV 5
|
||||
#define LUA_OPIDIV 6
|
||||
#define LUA_OPBAND 7
|
||||
#define LUA_OPBOR 8
|
||||
#define LUA_OPBXOR 9
|
||||
#define LUA_OPSHL 10
|
||||
#define LUA_OPSHR 11
|
||||
#define LUA_OPUNM 12
|
||||
#define LUA_OPBNOT 13
|
||||
|
||||
LUA_API void (lua_arith) (lua_State *L, int op);
|
||||
|
||||
#define LUA_OPEQ 0
|
||||
#define LUA_OPLT 1
|
||||
#define LUA_OPLE 2
|
||||
|
||||
LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
|
||||
LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
|
||||
|
||||
|
||||
/*
|
||||
** push functions (C -> stack)
|
||||
*/
|
||||
LUA_API void (lua_pushnil) (lua_State *L);
|
||||
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
|
||||
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
|
||||
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t len);
|
||||
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
|
||||
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
|
||||
va_list argp);
|
||||
LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
|
||||
LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
|
||||
LUA_API void (lua_pushboolean) (lua_State *L, int b);
|
||||
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
|
||||
LUA_API int (lua_pushthread) (lua_State *L);
|
||||
|
||||
|
||||
/*
|
||||
** get functions (Lua -> stack)
|
||||
*/
|
||||
LUA_API int (lua_getglobal) (lua_State *L, const char *name);
|
||||
LUA_API int (lua_gettable) (lua_State *L, int idx);
|
||||
LUA_API int (lua_getfield) (lua_State *L, int idx, const char *k);
|
||||
LUA_API int (lua_geti) (lua_State *L, int idx, lua_Integer n);
|
||||
LUA_API int (lua_rawget) (lua_State *L, int idx);
|
||||
LUA_API int (lua_rawgeti) (lua_State *L, int idx, lua_Integer n);
|
||||
LUA_API int (lua_rawgetp) (lua_State *L, int idx, const void *p);
|
||||
|
||||
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
|
||||
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
|
||||
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
|
||||
LUA_API int (lua_getuservalue) (lua_State *L, int idx);
|
||||
|
||||
|
||||
/*
|
||||
** set functions (stack -> Lua)
|
||||
*/
|
||||
LUA_API void (lua_setglobal) (lua_State *L, const char *name);
|
||||
LUA_API void (lua_settable) (lua_State *L, int idx);
|
||||
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
|
||||
LUA_API void (lua_seti) (lua_State *L, int idx, lua_Integer n);
|
||||
LUA_API void (lua_rawset) (lua_State *L, int idx);
|
||||
LUA_API void (lua_rawseti) (lua_State *L, int idx, lua_Integer n);
|
||||
LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
|
||||
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
|
||||
LUA_API void (lua_setuservalue) (lua_State *L, int idx);
|
||||
|
||||
|
||||
/*
|
||||
** 'load' and 'call' functions (load and run Lua code)
|
||||
*/
|
||||
LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults,
|
||||
lua_KContext ctx, lua_KFunction k);
|
||||
#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
|
||||
|
||||
LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
|
||||
lua_KContext ctx, lua_KFunction k);
|
||||
#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
|
||||
|
||||
LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
|
||||
const char *chunkname, const char *mode);
|
||||
|
||||
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data, int strip);
|
||||
|
||||
|
||||
/*
|
||||
** coroutine functions
|
||||
*/
|
||||
LUA_API int (lua_yieldk) (lua_State *L, int nresults, lua_KContext ctx,
|
||||
lua_KFunction k);
|
||||
LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg);
|
||||
LUA_API int (lua_status) (lua_State *L);
|
||||
LUA_API int (lua_isyieldable) (lua_State *L);
|
||||
|
||||
#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
|
||||
|
||||
|
||||
/*
|
||||
** garbage-collection function and options
|
||||
*/
|
||||
|
||||
#define LUA_GCSTOP 0
|
||||
#define LUA_GCRESTART 1
|
||||
#define LUA_GCCOLLECT 2
|
||||
#define LUA_GCCOUNT 3
|
||||
#define LUA_GCCOUNTB 4
|
||||
#define LUA_GCSTEP 5
|
||||
#define LUA_GCSETPAUSE 6
|
||||
#define LUA_GCSETSTEPMUL 7
|
||||
#define LUA_GCISRUNNING 9
|
||||
|
||||
LUA_API int (lua_gc) (lua_State *L, int what, int data);
|
||||
|
||||
|
||||
/*
|
||||
** miscellaneous functions
|
||||
*/
|
||||
|
||||
LUA_API int (lua_error) (lua_State *L);
|
||||
|
||||
LUA_API int (lua_next) (lua_State *L, int idx);
|
||||
|
||||
LUA_API void (lua_concat) (lua_State *L, int n);
|
||||
LUA_API void (lua_len) (lua_State *L, int idx);
|
||||
|
||||
LUA_API size_t (lua_stringtonumber) (lua_State *L, const char *s);
|
||||
|
||||
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
|
||||
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {==============================================================
|
||||
** some useful macros
|
||||
** ===============================================================
|
||||
*/
|
||||
|
||||
#define lua_getextraspace(L) ((void *)((char *)(L) - LUA_EXTRASPACE))
|
||||
|
||||
#define lua_tonumber(L,i) lua_tonumberx(L,(i),NULL)
|
||||
#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL)
|
||||
|
||||
#define lua_pop(L,n) lua_settop(L, -(n)-1)
|
||||
|
||||
#define lua_newtable(L) lua_createtable(L, 0, 0)
|
||||
|
||||
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
|
||||
|
||||
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
|
||||
|
||||
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
|
||||
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
|
||||
#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
|
||||
#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
|
||||
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
|
||||
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
|
||||
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
|
||||
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
|
||||
|
||||
#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
|
||||
|
||||
#define lua_pushglobaltable(L) \
|
||||
((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
|
||||
|
||||
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
|
||||
|
||||
|
||||
#define lua_insert(L,idx) lua_rotate(L, (idx), 1)
|
||||
|
||||
#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
|
||||
|
||||
#define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
|
||||
|
||||
/* }============================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {==============================================================
|
||||
** compatibility macros for unsigned conversions
|
||||
** ===============================================================
|
||||
*/
|
||||
#if defined(LUA_COMPAT_APIINTCASTS)
|
||||
|
||||
#define lua_pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
|
||||
#define lua_tounsignedx(L,i,is) ((lua_Unsigned)lua_tointegerx(L,i,is))
|
||||
#define lua_tounsigned(L,i) lua_tounsignedx(L,(i),NULL)
|
||||
|
||||
#endif
|
||||
/* }============================================================== */
|
||||
|
||||
/*
|
||||
** {======================================================================
|
||||
** Debug API
|
||||
** =======================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** Event codes
|
||||
*/
|
||||
#define LUA_HOOKCALL 0
|
||||
#define LUA_HOOKRET 1
|
||||
#define LUA_HOOKLINE 2
|
||||
#define LUA_HOOKCOUNT 3
|
||||
#define LUA_HOOKTAILCALL 4
|
||||
|
||||
|
||||
/*
|
||||
** Event masks
|
||||
*/
|
||||
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
|
||||
#define LUA_MASKRET (1 << LUA_HOOKRET)
|
||||
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
|
||||
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
|
||||
|
||||
typedef struct lua_Debug lua_Debug; /* activation record */
|
||||
|
||||
|
||||
/* Functions to be called by the debugger in specific events */
|
||||
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
|
||||
|
||||
|
||||
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
|
||||
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
|
||||
LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n);
|
||||
LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n);
|
||||
LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n);
|
||||
LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n);
|
||||
|
||||
LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
|
||||
LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
|
||||
int fidx2, int n2);
|
||||
|
||||
LUA_API void (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
|
||||
LUA_API lua_Hook (lua_gethook) (lua_State *L);
|
||||
LUA_API int (lua_gethookmask) (lua_State *L);
|
||||
LUA_API int (lua_gethookcount) (lua_State *L);
|
||||
|
||||
|
||||
struct lua_Debug {
|
||||
int event;
|
||||
const char *name; /* (n) */
|
||||
const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
|
||||
const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
|
||||
const char *source; /* (S) */
|
||||
int currentline; /* (l) */
|
||||
int linedefined; /* (S) */
|
||||
int lastlinedefined; /* (S) */
|
||||
unsigned char nups; /* (u) number of upvalues */
|
||||
unsigned char nparams;/* (u) number of parameters */
|
||||
char isvararg; /* (u) */
|
||||
char istailcall; /* (t) */
|
||||
char short_src[LUA_IDSIZE]; /* (S) */
|
||||
/* private part */
|
||||
struct CallInfo *i_ci; /* active function */
|
||||
};
|
||||
|
||||
/* }====================================================================== */
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#endif
|
||||
9
Videos/CarCrimeCity/Part2/Lua533/include/lua.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// lua.hpp
|
||||
// Lua header files for C++
|
||||
// <<extern "C">> not supplied automatically because Lua also compiles as C++
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lualib.h"
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
769
Videos/CarCrimeCity/Part2/Lua533/include/luaconf.h
Normal file
@@ -0,0 +1,769 @@
|
||||
/*
|
||||
** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
|
||||
** Configuration file for Lua
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef luaconf_h
|
||||
#define luaconf_h
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
/*
|
||||
** ===================================================================
|
||||
** Search for "@@" to find all configurable definitions.
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
** {====================================================================
|
||||
** System Configuration: macros to adapt (if needed) Lua to some
|
||||
** particular platform, for instance compiling it with 32-bit numbers or
|
||||
** restricting it to C89.
|
||||
** =====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUA_32BITS enables Lua with 32-bit integers and 32-bit floats. You
|
||||
** can also define LUA_32BITS in the make file, but changing here you
|
||||
** ensure that all software connected to Lua will be compiled with the
|
||||
** same configuration.
|
||||
*/
|
||||
/* #define LUA_32BITS */
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_USE_C89 controls the use of non-ISO-C89 features.
|
||||
** Define it if you want Lua to avoid the use of a few C99 features
|
||||
** or Windows-specific features on Windows.
|
||||
*/
|
||||
/* #define LUA_USE_C89 */
|
||||
|
||||
|
||||
/*
|
||||
** By default, Lua on Windows use (some) specific Windows features
|
||||
*/
|
||||
#if !defined(LUA_USE_C89) && defined(_WIN32) && !defined(_WIN32_WCE)
|
||||
#define LUA_USE_WINDOWS /* enable goodies for regular Windows */
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LUA_USE_WINDOWS)
|
||||
#define LUA_DL_DLL /* enable support for DLL */
|
||||
#define LUA_USE_C89 /* broadly, Windows is C89 */
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LUA_USE_LINUX)
|
||||
#define LUA_USE_POSIX
|
||||
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
|
||||
#define LUA_USE_READLINE /* needs some extra libraries */
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(LUA_USE_MACOSX)
|
||||
#define LUA_USE_POSIX
|
||||
#define LUA_USE_DLOPEN /* MacOS does not need -ldl */
|
||||
#define LUA_USE_READLINE /* needs an extra library: -lreadline */
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_C89_NUMBERS ensures that Lua uses the largest types available for
|
||||
** C89 ('long' and 'double'); Windows always has '__int64', so it does
|
||||
** not need to use this case.
|
||||
*/
|
||||
#if defined(LUA_USE_C89) && !defined(LUA_USE_WINDOWS)
|
||||
#define LUA_C89_NUMBERS
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@@ LUAI_BITSINT defines the (minimum) number of bits in an 'int'.
|
||||
*/
|
||||
/* avoid undefined shifts */
|
||||
#if ((INT_MAX >> 15) >> 15) >= 1
|
||||
#define LUAI_BITSINT 32
|
||||
#else
|
||||
/* 'int' always must have at least 16 bits */
|
||||
#define LUAI_BITSINT 16
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_INT_TYPE defines the type for Lua integers.
|
||||
@@ LUA_FLOAT_TYPE defines the type for Lua floats.
|
||||
** Lua should work fine with any mix of these options (if supported
|
||||
** by your C compiler). The usual configurations are 64-bit integers
|
||||
** and 'double' (the default), 32-bit integers and 'float' (for
|
||||
** restricted platforms), and 'long'/'double' (for C compilers not
|
||||
** compliant with C99, which may not have support for 'long long').
|
||||
*/
|
||||
|
||||
/* predefined options for LUA_INT_TYPE */
|
||||
#define LUA_INT_INT 1
|
||||
#define LUA_INT_LONG 2
|
||||
#define LUA_INT_LONGLONG 3
|
||||
|
||||
/* predefined options for LUA_FLOAT_TYPE */
|
||||
#define LUA_FLOAT_FLOAT 1
|
||||
#define LUA_FLOAT_DOUBLE 2
|
||||
#define LUA_FLOAT_LONGDOUBLE 3
|
||||
|
||||
#if defined(LUA_32BITS) /* { */
|
||||
/*
|
||||
** 32-bit integers and 'float'
|
||||
*/
|
||||
#if LUAI_BITSINT >= 32 /* use 'int' if big enough */
|
||||
#define LUA_INT_TYPE LUA_INT_INT
|
||||
#else /* otherwise use 'long' */
|
||||
#define LUA_INT_TYPE LUA_INT_LONG
|
||||
#endif
|
||||
#define LUA_FLOAT_TYPE LUA_FLOAT_FLOAT
|
||||
|
||||
#elif defined(LUA_C89_NUMBERS) /* }{ */
|
||||
/*
|
||||
** largest types available for C89 ('long' and 'double')
|
||||
*/
|
||||
#define LUA_INT_TYPE LUA_INT_LONG
|
||||
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
/*
|
||||
** default configuration for 64-bit Lua ('long long' and 'double')
|
||||
*/
|
||||
#if !defined(LUA_INT_TYPE)
|
||||
#define LUA_INT_TYPE LUA_INT_LONGLONG
|
||||
#endif
|
||||
|
||||
#if !defined(LUA_FLOAT_TYPE)
|
||||
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
|
||||
#endif
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Configuration for Paths.
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
|
||||
** Lua libraries.
|
||||
@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
|
||||
** C libraries.
|
||||
** CHANGE them if your machine has a non-conventional directory
|
||||
** hierarchy or if you want to install your libraries in
|
||||
** non-conventional directories.
|
||||
*/
|
||||
#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
|
||||
#if defined(_WIN32) /* { */
|
||||
/*
|
||||
** In Windows, any exclamation mark ('!') in the path is replaced by the
|
||||
** path of the directory of the executable file of the current process.
|
||||
*/
|
||||
#define LUA_LDIR "!\\lua\\"
|
||||
#define LUA_CDIR "!\\"
|
||||
#define LUA_SHRDIR "!\\..\\share\\lua\\" LUA_VDIR "\\"
|
||||
#define LUA_PATH_DEFAULT \
|
||||
LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
|
||||
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" \
|
||||
LUA_SHRDIR"?.lua;" LUA_SHRDIR"?\\init.lua;" \
|
||||
".\\?.lua;" ".\\?\\init.lua"
|
||||
#define LUA_CPATH_DEFAULT \
|
||||
LUA_CDIR"?.dll;" \
|
||||
LUA_CDIR"..\\lib\\lua\\" LUA_VDIR "\\?.dll;" \
|
||||
LUA_CDIR"loadall.dll;" ".\\?.dll;" \
|
||||
LUA_CDIR"?53.dll;" ".\\?53.dll"
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
#define LUA_ROOT "/usr/local/"
|
||||
#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR "/"
|
||||
#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR "/"
|
||||
#define LUA_PATH_DEFAULT \
|
||||
LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
|
||||
LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" \
|
||||
"./?.lua;" "./?/init.lua"
|
||||
#define LUA_CPATH_DEFAULT \
|
||||
LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so;" \
|
||||
LUA_CDIR"lib?53.so;" "./lib?53.so"
|
||||
#endif /* } */
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_DIRSEP is the directory separator (for submodules).
|
||||
** CHANGE it if your machine does not use "/" as the directory separator
|
||||
** and is not Windows. (On Windows Lua automatically uses "\".)
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
#define LUA_DIRSEP "\\"
|
||||
#else
|
||||
#define LUA_DIRSEP "/"
|
||||
#endif
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Marks for exported symbols in the C code
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUA_API is a mark for all core API functions.
|
||||
@@ LUALIB_API is a mark for all auxiliary library functions.
|
||||
@@ LUAMOD_API is a mark for all standard library opening functions.
|
||||
** CHANGE them if you need to define those functions in some special way.
|
||||
** For instance, if you want to create one Windows DLL with the core and
|
||||
** the libraries, you may want to use the following definition (define
|
||||
** LUA_BUILD_AS_DLL to get it).
|
||||
*/
|
||||
#if defined(LUA_BUILD_AS_DLL) /* { */
|
||||
|
||||
#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
|
||||
#define LUA_API __declspec(dllexport)
|
||||
#else /* }{ */
|
||||
#define LUA_API __declspec(dllimport)
|
||||
#endif /* } */
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
#define LUA_API extern
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
/* more often than not the libs go together with the core */
|
||||
#define LUALIB_API LUA_API
|
||||
#define LUAMOD_API LUALIB_API
|
||||
|
||||
|
||||
/*
|
||||
@@ LUAI_FUNC is a mark for all extern functions that are not to be
|
||||
** exported to outside modules.
|
||||
@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables
|
||||
** that are not to be exported to outside modules (LUAI_DDEF for
|
||||
** definitions and LUAI_DDEC for declarations).
|
||||
** CHANGE them if you need to mark them in some special way. Elf/gcc
|
||||
** (versions 3.2 and later) mark them as "hidden" to optimize access
|
||||
** when Lua is compiled as a shared library. Not all elf targets support
|
||||
** this attribute. Unfortunately, gcc does not offer a way to check
|
||||
** whether the target offers that support, and those without support
|
||||
** give a warning about it. To avoid these warnings, change to the
|
||||
** default definition.
|
||||
*/
|
||||
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
|
||||
defined(__ELF__) /* { */
|
||||
#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
|
||||
#else /* }{ */
|
||||
#define LUAI_FUNC extern
|
||||
#endif /* } */
|
||||
|
||||
#define LUAI_DDEC LUAI_FUNC
|
||||
#define LUAI_DDEF /* empty */
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Compatibility with previous versions
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_5_2 controls other macros for compatibility with Lua 5.2.
|
||||
@@ LUA_COMPAT_5_1 controls other macros for compatibility with Lua 5.1.
|
||||
** You can define it to get all options, or change specific options
|
||||
** to fit your specific needs.
|
||||
*/
|
||||
#if defined(LUA_COMPAT_5_2) /* { */
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_MATHLIB controls the presence of several deprecated
|
||||
** functions in the mathematical library.
|
||||
*/
|
||||
#define LUA_COMPAT_MATHLIB
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_BITLIB controls the presence of library 'bit32'.
|
||||
*/
|
||||
#define LUA_COMPAT_BITLIB
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_IPAIRS controls the effectiveness of the __ipairs metamethod.
|
||||
*/
|
||||
#define LUA_COMPAT_IPAIRS
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_APIINTCASTS controls the presence of macros for
|
||||
** manipulating other integer types (lua_pushunsigned, lua_tounsigned,
|
||||
** luaL_checkint, luaL_checklong, etc.)
|
||||
*/
|
||||
#define LUA_COMPAT_APIINTCASTS
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
#if defined(LUA_COMPAT_5_1) /* { */
|
||||
|
||||
/* Incompatibilities from 5.2 -> 5.3 */
|
||||
#define LUA_COMPAT_MATHLIB
|
||||
#define LUA_COMPAT_APIINTCASTS
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
|
||||
** You can replace it with 'table.unpack'.
|
||||
*/
|
||||
#define LUA_COMPAT_UNPACK
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'.
|
||||
** You can replace it with 'package.searchers'.
|
||||
*/
|
||||
#define LUA_COMPAT_LOADERS
|
||||
|
||||
/*
|
||||
@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall.
|
||||
** You can call your C function directly (with light C functions).
|
||||
*/
|
||||
#define lua_cpcall(L,f,u) \
|
||||
(lua_pushcfunction(L, (f)), \
|
||||
lua_pushlightuserdata(L,(u)), \
|
||||
lua_pcall(L,1,0,0))
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.
|
||||
** You can rewrite 'log10(x)' as 'log(x, 10)'.
|
||||
*/
|
||||
#define LUA_COMPAT_LOG10
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base
|
||||
** library. You can rewrite 'loadstring(s)' as 'load(s)'.
|
||||
*/
|
||||
#define LUA_COMPAT_LOADSTRING
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.
|
||||
*/
|
||||
#define LUA_COMPAT_MAXN
|
||||
|
||||
/*
|
||||
@@ The following macros supply trivial compatibility for some
|
||||
** changes in the API. The macros themselves document how to
|
||||
** change your code to avoid using them.
|
||||
*/
|
||||
#define lua_strlen(L,i) lua_rawlen(L, (i))
|
||||
|
||||
#define lua_objlen(L,i) lua_rawlen(L, (i))
|
||||
|
||||
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
|
||||
#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_MODULE controls compatibility with previous
|
||||
** module functions 'module' (Lua) and 'luaL_register' (C).
|
||||
*/
|
||||
#define LUA_COMPAT_MODULE
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_COMPAT_FLOATSTRING makes Lua format integral floats without a
|
||||
@@ a float mark ('.0').
|
||||
** This macro is not on by default even in compatibility mode,
|
||||
** because this is not really an incompatibility.
|
||||
*/
|
||||
/* #define LUA_COMPAT_FLOATSTRING */
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Configuration for Numbers.
|
||||
** Change these definitions if no predefined LUA_FLOAT_* / LUA_INT_*
|
||||
** satisfy your needs.
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUA_NUMBER is the floating-point type used by Lua.
|
||||
@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
|
||||
@@ over a floating number.
|
||||
@@ l_mathlim(x) corrects limit name 'x' to the proper float type
|
||||
** by prefixing it with one of FLT/DBL/LDBL.
|
||||
@@ LUA_NUMBER_FRMLEN is the length modifier for writing floats.
|
||||
@@ LUA_NUMBER_FMT is the format for writing floats.
|
||||
@@ lua_number2str converts a float to a string.
|
||||
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
|
||||
@@ l_floor takes the floor of a float.
|
||||
@@ lua_str2number converts a decimal numeric string to a number.
|
||||
*/
|
||||
|
||||
|
||||
/* The following definitions are good for most cases here */
|
||||
|
||||
#define l_floor(x) (l_mathop(floor)(x))
|
||||
|
||||
#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n))
|
||||
|
||||
/*
|
||||
@@ lua_numbertointeger converts a float number to an integer, or
|
||||
** returns 0 if float is not within the range of a lua_Integer.
|
||||
** (The range comparisons are tricky because of rounding. The tests
|
||||
** here assume a two-complement representation, where MININTEGER always
|
||||
** has an exact representation as a float; MAXINTEGER may not have one,
|
||||
** and therefore its conversion to float may have an ill-defined value.)
|
||||
*/
|
||||
#define lua_numbertointeger(n,p) \
|
||||
((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
|
||||
(n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
|
||||
(*(p) = (LUA_INTEGER)(n), 1))
|
||||
|
||||
|
||||
/* now the variable definitions */
|
||||
|
||||
#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
|
||||
|
||||
#define LUA_NUMBER float
|
||||
|
||||
#define l_mathlim(n) (FLT_##n)
|
||||
|
||||
#define LUAI_UACNUMBER double
|
||||
|
||||
#define LUA_NUMBER_FRMLEN ""
|
||||
#define LUA_NUMBER_FMT "%.7g"
|
||||
|
||||
#define l_mathop(op) op##f
|
||||
|
||||
#define lua_str2number(s,p) strtof((s), (p))
|
||||
|
||||
|
||||
#elif LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE /* }{ long double */
|
||||
|
||||
#define LUA_NUMBER long double
|
||||
|
||||
#define l_mathlim(n) (LDBL_##n)
|
||||
|
||||
#define LUAI_UACNUMBER long double
|
||||
|
||||
#define LUA_NUMBER_FRMLEN "L"
|
||||
#define LUA_NUMBER_FMT "%.19Lg"
|
||||
|
||||
#define l_mathop(op) op##l
|
||||
|
||||
#define lua_str2number(s,p) strtold((s), (p))
|
||||
|
||||
#elif LUA_FLOAT_TYPE == LUA_FLOAT_DOUBLE /* }{ double */
|
||||
|
||||
#define LUA_NUMBER double
|
||||
|
||||
#define l_mathlim(n) (DBL_##n)
|
||||
|
||||
#define LUAI_UACNUMBER double
|
||||
|
||||
#define LUA_NUMBER_FRMLEN ""
|
||||
#define LUA_NUMBER_FMT "%.14g"
|
||||
|
||||
#define l_mathop(op) op
|
||||
|
||||
#define lua_str2number(s,p) strtod((s), (p))
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
#error "numeric float type not defined"
|
||||
|
||||
#endif /* } */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_INTEGER is the integer type used by Lua.
|
||||
**
|
||||
@@ LUA_UNSIGNED is the unsigned version of LUA_INTEGER.
|
||||
**
|
||||
@@ LUAI_UACINT is the result of an 'usual argument conversion'
|
||||
@@ over a lUA_INTEGER.
|
||||
@@ LUA_INTEGER_FRMLEN is the length modifier for reading/writing integers.
|
||||
@@ LUA_INTEGER_FMT is the format for writing integers.
|
||||
@@ LUA_MAXINTEGER is the maximum value for a LUA_INTEGER.
|
||||
@@ LUA_MININTEGER is the minimum value for a LUA_INTEGER.
|
||||
@@ lua_integer2str converts an integer to a string.
|
||||
*/
|
||||
|
||||
|
||||
/* The following definitions are good for most cases here */
|
||||
|
||||
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
|
||||
#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n))
|
||||
|
||||
#define LUAI_UACINT LUA_INTEGER
|
||||
|
||||
/*
|
||||
** use LUAI_UACINT here to avoid problems with promotions (which
|
||||
** can turn a comparison between unsigneds into a signed comparison)
|
||||
*/
|
||||
#define LUA_UNSIGNED unsigned LUAI_UACINT
|
||||
|
||||
|
||||
/* now the variable definitions */
|
||||
|
||||
#if LUA_INT_TYPE == LUA_INT_INT /* { int */
|
||||
|
||||
#define LUA_INTEGER int
|
||||
#define LUA_INTEGER_FRMLEN ""
|
||||
|
||||
#define LUA_MAXINTEGER INT_MAX
|
||||
#define LUA_MININTEGER INT_MIN
|
||||
|
||||
#elif LUA_INT_TYPE == LUA_INT_LONG /* }{ long */
|
||||
|
||||
#define LUA_INTEGER long
|
||||
#define LUA_INTEGER_FRMLEN "l"
|
||||
|
||||
#define LUA_MAXINTEGER LONG_MAX
|
||||
#define LUA_MININTEGER LONG_MIN
|
||||
|
||||
#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
|
||||
|
||||
/* use presence of macro LLONG_MAX as proxy for C99 compliance */
|
||||
#if defined(LLONG_MAX) /* { */
|
||||
/* use ISO C99 stuff */
|
||||
|
||||
#define LUA_INTEGER long long
|
||||
#define LUA_INTEGER_FRMLEN "ll"
|
||||
|
||||
#define LUA_MAXINTEGER LLONG_MAX
|
||||
#define LUA_MININTEGER LLONG_MIN
|
||||
|
||||
#elif defined(LUA_USE_WINDOWS) /* }{ */
|
||||
/* in Windows, can use specific Windows types */
|
||||
|
||||
#define LUA_INTEGER __int64
|
||||
#define LUA_INTEGER_FRMLEN "I64"
|
||||
|
||||
#define LUA_MAXINTEGER _I64_MAX
|
||||
#define LUA_MININTEGER _I64_MIN
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
#error "Compiler does not support 'long long'. Use option '-DLUA_32BITS' \
|
||||
or '-DLUA_C89_NUMBERS' (see file 'luaconf.h' for details)"
|
||||
|
||||
#endif /* } */
|
||||
|
||||
#else /* }{ */
|
||||
|
||||
#error "numeric integer type not defined"
|
||||
|
||||
#endif /* } */
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Dependencies with C99 and other C details
|
||||
** ===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
|
||||
** (All uses in Lua have only one format item.)
|
||||
*/
|
||||
#if !defined(LUA_USE_C89)
|
||||
#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
|
||||
#else
|
||||
#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ lua_strx2number converts an hexadecimal numeric string to a number.
|
||||
** In C99, 'strtod' does that conversion. Otherwise, you can
|
||||
** leave 'lua_strx2number' undefined and Lua will provide its own
|
||||
** implementation.
|
||||
*/
|
||||
#if !defined(LUA_USE_C89)
|
||||
#define lua_strx2number(s,p) lua_str2number(s,p)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ lua_number2strx converts a float to an hexadecimal numeric string.
|
||||
** In C99, 'sprintf' (with format specifiers '%a'/'%A') does that.
|
||||
** Otherwise, you can leave 'lua_number2strx' undefined and Lua will
|
||||
** provide its own implementation.
|
||||
*/
|
||||
#if !defined(LUA_USE_C89)
|
||||
#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** 'strtof' and 'opf' variants for math functions are not valid in
|
||||
** C89. Otherwise, the macro 'HUGE_VALF' is a good proxy for testing the
|
||||
** availability of these variants. ('math.h' is already included in
|
||||
** all files that use these macros.)
|
||||
*/
|
||||
#if defined(LUA_USE_C89) || (defined(HUGE_VAL) && !defined(HUGE_VALF))
|
||||
#undef l_mathop /* variants not available */
|
||||
#undef lua_str2number
|
||||
#define l_mathop(op) (lua_Number)op /* no variant */
|
||||
#define lua_str2number(s,p) ((lua_Number)strtod((s), (p)))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_KCONTEXT is the type of the context ('ctx') for continuation
|
||||
** functions. It must be a numerical type; Lua will use 'intptr_t' if
|
||||
** available, otherwise it will use 'ptrdiff_t' (the nearest thing to
|
||||
** 'intptr_t' in C89)
|
||||
*/
|
||||
#define LUA_KCONTEXT ptrdiff_t
|
||||
|
||||
#if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
|
||||
__STDC_VERSION__ >= 199901L
|
||||
#include <stdint.h>
|
||||
#if defined(INTPTR_MAX) /* even in C99 this type is optional */
|
||||
#undef LUA_KCONTEXT
|
||||
#define LUA_KCONTEXT intptr_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ lua_getlocaledecpoint gets the locale "radix character" (decimal point).
|
||||
** Change that if you do not want to use C locales. (Code using this
|
||||
** macro must include header 'locale.h'.)
|
||||
*/
|
||||
#if !defined(lua_getlocaledecpoint)
|
||||
#define lua_getlocaledecpoint() (localeconv()->decimal_point[0])
|
||||
#endif
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Language Variations
|
||||
** =====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUA_NOCVTN2S/LUA_NOCVTS2N control how Lua performs some
|
||||
** coercions. Define LUA_NOCVTN2S to turn off automatic coercion from
|
||||
** numbers to strings. Define LUA_NOCVTS2N to turn off automatic
|
||||
** coercion from strings to numbers.
|
||||
*/
|
||||
/* #define LUA_NOCVTN2S */
|
||||
/* #define LUA_NOCVTS2N */
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_USE_APICHECK turns on several consistency checks on the C API.
|
||||
** Define it as a help when debugging C code.
|
||||
*/
|
||||
#if defined(LUA_USE_APICHECK)
|
||||
#include <assert.h>
|
||||
#define luai_apicheck(l,e) assert(e)
|
||||
#endif
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
** {==================================================================
|
||||
** Macros that affect the API and must be stable (that is, must be the
|
||||
** same when you compile Lua and when you compile code that links to
|
||||
** Lua). You probably do not want/need to change them.
|
||||
** =====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ LUAI_MAXSTACK limits the size of the Lua stack.
|
||||
** CHANGE it if you need a different limit. This limit is arbitrary;
|
||||
** its only purpose is to stop Lua from consuming unlimited stack
|
||||
** space (and to reserve some numbers for pseudo-indices).
|
||||
*/
|
||||
#if LUAI_BITSINT >= 32
|
||||
#define LUAI_MAXSTACK 1000000
|
||||
#else
|
||||
#define LUAI_MAXSTACK 15000
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_EXTRASPACE defines the size of a raw memory area associated with
|
||||
** a Lua state with very fast access.
|
||||
** CHANGE it if you need a different size.
|
||||
*/
|
||||
#define LUA_EXTRASPACE (sizeof(void *))
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_IDSIZE gives the maximum size for the description of the source
|
||||
@@ of a function in debug information.
|
||||
** CHANGE it if you want a different size.
|
||||
*/
|
||||
#define LUA_IDSIZE 60
|
||||
|
||||
|
||||
/*
|
||||
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
|
||||
** CHANGE it if it uses too much C-stack space. (For long double,
|
||||
** 'string.format("%.99f", 1e4932)' needs ~5030 bytes, so a
|
||||
** smaller buffer would force a memory allocation for each call to
|
||||
** 'string.format'.)
|
||||
*/
|
||||
#if defined(LUA_FLOAT_LONGDOUBLE)
|
||||
#define LUAL_BUFFERSIZE 8192
|
||||
#else
|
||||
#define LUAL_BUFFERSIZE ((int)(0x80 * sizeof(void*) * sizeof(lua_Integer)))
|
||||
#endif
|
||||
|
||||
/* }================================================================== */
|
||||
|
||||
|
||||
/*
|
||||
@@ LUA_QL describes how error messages quote program elements.
|
||||
** Lua does not use these macros anymore; they are here for
|
||||
** compatibility only.
|
||||
*/
|
||||
#define LUA_QL(x) "'" x "'"
|
||||
#define LUA_QS LUA_QL("%s")
|
||||
|
||||
|
||||
|
||||
|
||||
/* =================================================================== */
|
||||
|
||||
/*
|
||||
** Local configuration. You can use this space to add your redefinitions
|
||||
** without modifying the main part of the file.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
58
Videos/CarCrimeCity/Part2/Lua533/include/lualib.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
** $Id: lualib.h,v 1.44 2014/02/06 17:32:33 roberto Exp $
|
||||
** Lua standard libraries
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
||||
|
||||
#ifndef lualib_h
|
||||
#define lualib_h
|
||||
|
||||
#include "lua.h"
|
||||
|
||||
|
||||
|
||||
LUAMOD_API int (luaopen_base) (lua_State *L);
|
||||
|
||||
#define LUA_COLIBNAME "coroutine"
|
||||
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
|
||||
|
||||
#define LUA_TABLIBNAME "table"
|
||||
LUAMOD_API int (luaopen_table) (lua_State *L);
|
||||
|
||||
#define LUA_IOLIBNAME "io"
|
||||
LUAMOD_API int (luaopen_io) (lua_State *L);
|
||||
|
||||
#define LUA_OSLIBNAME "os"
|
||||
LUAMOD_API int (luaopen_os) (lua_State *L);
|
||||
|
||||
#define LUA_STRLIBNAME "string"
|
||||
LUAMOD_API int (luaopen_string) (lua_State *L);
|
||||
|
||||
#define LUA_UTF8LIBNAME "utf8"
|
||||
LUAMOD_API int (luaopen_utf8) (lua_State *L);
|
||||
|
||||
#define LUA_BITLIBNAME "bit32"
|
||||
LUAMOD_API int (luaopen_bit32) (lua_State *L);
|
||||
|
||||
#define LUA_MATHLIBNAME "math"
|
||||
LUAMOD_API int (luaopen_math) (lua_State *L);
|
||||
|
||||
#define LUA_DBLIBNAME "debug"
|
||||
LUAMOD_API int (luaopen_debug) (lua_State *L);
|
||||
|
||||
#define LUA_LOADLIBNAME "package"
|
||||
LUAMOD_API int (luaopen_package) (lua_State *L);
|
||||
|
||||
|
||||
/* open all previous libraries */
|
||||
LUALIB_API void (luaL_openlibs) (lua_State *L);
|
||||
|
||||
|
||||
|
||||
#if !defined(lua_assert)
|
||||
#define lua_assert(x) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
BIN
Videos/CarCrimeCity/Part2/Lua533/liblua53.a
Normal file
BIN
Videos/CarCrimeCity/Part2/Lua533/lua53.dll
Normal file
716
Videos/CarCrimeCity/Part2/assets/buildings/udxs_building1.obj
Normal file
@@ -0,0 +1,716 @@
|
||||
# Blender v2.79 (sub 0) OBJ File: 'olc_building0.blend'
|
||||
# www.blender.org
|
||||
mtllib olc_building0.mtl
|
||||
o Plane
|
||||
v 0.000000 0.000000 0.000000
|
||||
v 0.000000 -1.000000 0.000000
|
||||
v -1.000000 0.000000 0.000000
|
||||
v -1.000000 -1.000000 0.000000
|
||||
v -0.025000 -0.412671 -0.052133
|
||||
v -0.025000 -0.587329 -0.052133
|
||||
v -0.975000 -0.025000 -0.050000
|
||||
v -0.975000 -0.975000 -0.050000
|
||||
v -1.000000 0.000000 -0.050000
|
||||
v 0.000000 0.000000 -0.050000
|
||||
v 0.000000 -1.000000 -0.050000
|
||||
v -1.000000 -1.000000 -0.050000
|
||||
v -0.975000 -0.025000 -0.517611
|
||||
v -0.975000 -0.975000 -0.517611
|
||||
v -1.000000 0.000000 -0.527316
|
||||
v 0.000000 0.000000 -0.527316
|
||||
v 0.000000 -1.000000 -0.527316
|
||||
v -1.000000 -1.000000 -0.527316
|
||||
v -0.975000 -0.025000 -0.550000
|
||||
v -0.025000 -0.025000 -0.550000
|
||||
v -0.025000 -0.975000 -0.550000
|
||||
v -0.975000 -0.975000 -0.550000
|
||||
v -0.025000 -0.601364 -0.402078
|
||||
v -0.025000 -0.601364 -0.044706
|
||||
v -0.025000 -0.398636 -0.044706
|
||||
v -0.025000 -0.398636 -0.402078
|
||||
v -0.374620 -0.412671 -0.045097
|
||||
v -0.374620 -0.587329 -0.047815
|
||||
v -0.374620 -0.587329 -0.388044
|
||||
v -0.374620 -0.412671 -0.388044
|
||||
v -0.005099 -0.601364 -0.402078
|
||||
v -0.005099 -0.601364 -0.044706
|
||||
v -0.005099 -0.398636 -0.044706
|
||||
v -0.005099 -0.398636 -0.402078
|
||||
v -0.005099 -0.587329 -0.388044
|
||||
v -0.005099 -0.587329 -0.047815
|
||||
v -0.005099 -0.412671 -0.045097
|
||||
v -0.005099 -0.412671 -0.388044
|
||||
v -0.017305 -0.419472 -0.044438
|
||||
v -0.017305 -0.594130 -0.044438
|
||||
v -0.025000 -0.975000 -0.517611
|
||||
v -0.025000 -0.975000 -0.050000
|
||||
v -0.025000 -0.601364 -0.402078
|
||||
v -0.025000 -0.601364 -0.044706
|
||||
v -0.025000 -0.025000 -0.050000
|
||||
v -0.025000 -0.025000 -0.517611
|
||||
v -0.025000 -0.398636 -0.044706
|
||||
v -0.025000 -0.398636 -0.402078
|
||||
v -0.925000 -0.075000 -1.550000
|
||||
v -0.075000 -0.075000 -1.550000
|
||||
v -0.075000 -0.925000 -1.550000
|
||||
v -0.925000 -0.925000 -1.550000
|
||||
v -0.975000 -0.025000 -1.550000
|
||||
v -0.025000 -0.025000 -1.550000
|
||||
v -0.025000 -0.975000 -1.550000
|
||||
v -0.975000 -0.975000 -1.550000
|
||||
v -0.975000 -0.025000 -1.600000
|
||||
v -0.025000 -0.025000 -1.600000
|
||||
v -0.025000 -0.975000 -1.600000
|
||||
v -0.975000 -0.975000 -1.600000
|
||||
v -0.925000 -0.075000 -1.600000
|
||||
v -0.075000 -0.075000 -1.600000
|
||||
v -0.075000 -0.925000 -1.600000
|
||||
v -0.925000 -0.925000 -1.600000
|
||||
v 0.160449 -0.127295 -1.107365
|
||||
v 0.160449 -0.127295 -1.287365
|
||||
v -0.026426 -0.127295 -1.107365
|
||||
v -0.026426 -0.127295 -1.287365
|
||||
v 0.160449 -0.427295 -1.107365
|
||||
v 0.160449 -0.427295 -1.287365
|
||||
v -0.026426 -0.427295 -1.107365
|
||||
v -0.026426 -0.427295 -1.287365
|
||||
v -0.026426 -0.127295 -1.287365
|
||||
v -0.026426 -0.127295 -1.107365
|
||||
v 0.160449 -0.127295 -1.287365
|
||||
v 0.160449 -0.127295 -1.107365
|
||||
v 0.160449 -0.427295 -1.287365
|
||||
v 0.160449 -0.427295 -1.107365
|
||||
v 0.160449 -0.127295 -1.287365
|
||||
v 0.160449 -0.127295 -1.107365
|
||||
v -0.026426 -0.427295 -1.287365
|
||||
v -0.026426 -0.427295 -1.107365
|
||||
v 0.160449 -0.427295 -1.287365
|
||||
v 0.160449 -0.427295 -1.107365
|
||||
v -0.157753 -0.144986 -1.539514
|
||||
v -0.157753 -0.144986 -1.637282
|
||||
v -0.240677 -0.144986 -1.539514
|
||||
v -0.240677 -0.144986 -1.637282
|
||||
v -0.157753 -0.328413 -1.539514
|
||||
v -0.157753 -0.328413 -1.637282
|
||||
v -0.240677 -0.328413 -1.539514
|
||||
v -0.240677 -0.328413 -1.637282
|
||||
v -0.480538 -0.445573 -1.455033
|
||||
v -0.480538 -0.445573 -1.817243
|
||||
v -0.732419 -0.445573 -1.455033
|
||||
v -0.732419 -0.445573 -1.817243
|
||||
v -0.480538 -0.823959 -1.455033
|
||||
v -0.480538 -0.823959 -1.685969
|
||||
v -0.732419 -0.823959 -1.455033
|
||||
v -0.732419 -0.823959 -1.685969
|
||||
v -0.157753 -0.144986 -1.539514
|
||||
v -0.157753 -0.144986 -1.637282
|
||||
v -0.240677 -0.144986 -1.539514
|
||||
v -0.240677 -0.144986 -1.637282
|
||||
v -0.157753 -0.328413 -1.539514
|
||||
v -0.157753 -0.328413 -1.637282
|
||||
v -0.240677 -0.328413 -1.539514
|
||||
v -0.240677 -0.328413 -1.637282
|
||||
v -0.026426 -0.585532 -1.287365
|
||||
v -0.026426 -0.585532 -1.107365
|
||||
v 0.160449 -0.585532 -1.287365
|
||||
v 0.160449 -0.585532 -1.107365
|
||||
v 0.160449 -0.885532 -1.287365
|
||||
v 0.160449 -0.885532 -1.107365
|
||||
v 0.160449 -0.585532 -1.287365
|
||||
v 0.160449 -0.585532 -1.107365
|
||||
v -0.026426 -0.885532 -1.287365
|
||||
v -0.026426 -0.885532 -1.107365
|
||||
v 0.160449 -0.885532 -1.287365
|
||||
v 0.160449 -0.885532 -1.107365
|
||||
v 0.160449 -0.586497 -0.622366
|
||||
v 0.160449 -0.586497 -0.802366
|
||||
v -0.026426 -0.586497 -0.622366
|
||||
v -0.026426 -0.586497 -0.802366
|
||||
v 0.160449 -0.886497 -0.802366
|
||||
v 0.160449 -0.886497 -0.622366
|
||||
v 0.160449 -0.586497 -0.802366
|
||||
v 0.160449 -0.586497 -0.622366
|
||||
v -0.026426 -0.886497 -0.802366
|
||||
v -0.026426 -0.886497 -0.622366
|
||||
v 0.160449 -0.886497 -0.802366
|
||||
v 0.160449 -0.886497 -0.622366
|
||||
v 0.160449 -0.126028 -0.622366
|
||||
v 0.160449 -0.126028 -0.802366
|
||||
v -0.026426 -0.126028 -0.622366
|
||||
v -0.026426 -0.126028 -0.802366
|
||||
v 0.160449 -0.426028 -0.802366
|
||||
v 0.160449 -0.426028 -0.622366
|
||||
v 0.160449 -0.126028 -0.802366
|
||||
v 0.160449 -0.126028 -0.622366
|
||||
v -0.026426 -0.426028 -0.802366
|
||||
v -0.026426 -0.426028 -0.622366
|
||||
v 0.160449 -0.426028 -0.802366
|
||||
v 0.160449 -0.426028 -0.622366
|
||||
v -0.026426 -0.585532 -1.287365
|
||||
v -0.026426 -0.585532 -1.107365
|
||||
v 0.160449 -0.585532 -1.287365
|
||||
v 0.160449 -0.585532 -1.107365
|
||||
v 0.160449 -0.885532 -1.287365
|
||||
v 0.160449 -0.885532 -1.107365
|
||||
v 0.160449 -0.585532 -1.287365
|
||||
v 0.160449 -0.585532 -1.107365
|
||||
v -0.026426 -0.885532 -1.287365
|
||||
v -0.026426 -0.885532 -1.107365
|
||||
v 0.160449 -0.885532 -1.287365
|
||||
v 0.160449 -0.885532 -1.107365
|
||||
v 0.160449 -0.586497 -0.622366
|
||||
v 0.160449 -0.586497 -0.802366
|
||||
v -0.026426 -0.586497 -0.622366
|
||||
v -0.026426 -0.586497 -0.802366
|
||||
v 0.160449 -0.886497 -0.802366
|
||||
v 0.160449 -0.886497 -0.622366
|
||||
v 0.160449 -0.586497 -0.802366
|
||||
v 0.160449 -0.586497 -0.622366
|
||||
v -0.026426 -0.886497 -0.802366
|
||||
v -0.026426 -0.886497 -0.622366
|
||||
v 0.160449 -0.886497 -0.802366
|
||||
v 0.160449 -0.886497 -0.622366
|
||||
v 0.160449 -0.126028 -0.622366
|
||||
v 0.160449 -0.126028 -0.802366
|
||||
v -0.026426 -0.126028 -0.622366
|
||||
v -0.026426 -0.126028 -0.802366
|
||||
v 0.160449 -0.426028 -0.802366
|
||||
v 0.160449 -0.426028 -0.622366
|
||||
v 0.160449 -0.126028 -0.802366
|
||||
v 0.160449 -0.126028 -0.622366
|
||||
v -0.026426 -0.426028 -0.802366
|
||||
v -0.026426 -0.426028 -0.622366
|
||||
v 0.160449 -0.426028 -0.802366
|
||||
v 0.160449 -0.426028 -0.622366
|
||||
v 0.160449 -0.584850 -1.107365
|
||||
v -0.026426 -0.584850 -1.107365
|
||||
v 0.160449 -0.884850 -1.107365
|
||||
v -0.026426 -0.884850 -1.107365
|
||||
v 0.160449 -0.127295 -0.622373
|
||||
v -0.026426 -0.127295 -0.622373
|
||||
v 0.160449 -0.427295 -0.622373
|
||||
v -0.026426 -0.427295 -0.622373
|
||||
v 0.160449 -0.584850 -0.622373
|
||||
v -0.026426 -0.584850 -0.622373
|
||||
v 0.160449 -0.884850 -0.622373
|
||||
v -0.026426 -0.884850 -0.622373
|
||||
vt 0.014847 0.403582
|
||||
vt 0.153703 0.694145
|
||||
vt 0.014847 0.694145
|
||||
vt 0.034115 0.694145
|
||||
vt 0.048963 1.000000
|
||||
vt 0.034115 1.000000
|
||||
vt 0.047359 0.372997
|
||||
vt 0.032511 0.067142
|
||||
vt 0.047358 0.067142
|
||||
vt 0.048963 0.694145
|
||||
vt 0.063810 1.000000
|
||||
vt 0.048963 1.000000
|
||||
vt 0.019268 0.694145
|
||||
vt 0.034115 1.000000
|
||||
vt 0.019268 1.000000
|
||||
vt 0.710478 0.701791
|
||||
vt 1.000000 0.694145
|
||||
vt 0.992576 0.701791
|
||||
vt 1.000000 1.000000
|
||||
vt 0.992576 0.992353
|
||||
vt 0.703054 1.000000
|
||||
vt 0.710478 0.992354
|
||||
vt 0.703054 0.694145
|
||||
vt 1.000000 0.051849
|
||||
vt 0.717901 0.357704
|
||||
vt 0.717901 0.051849
|
||||
vt 0.047359 0.082435
|
||||
vt 0.186214 0.372997
|
||||
vt 0.047359 0.372997
|
||||
vt 0.186214 0.082435
|
||||
vt 0.325069 0.372997
|
||||
vt 0.186214 0.372997
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.703054 0.694145
|
||||
vt 0.413541 0.701796
|
||||
vt 0.406108 0.694145
|
||||
vt 0.703054 1.000000
|
||||
vt 0.695640 0.701796
|
||||
vt 0.406108 1.000000
|
||||
vt 0.695640 0.992358
|
||||
vt 0.413541 0.992358
|
||||
vt 0.004421 0.885721
|
||||
vt 0.002849 0.709438
|
||||
vt 0.004421 0.823716
|
||||
vt 0.118100 0.779467
|
||||
vt 0.115894 0.721754
|
||||
vt 0.118100 0.726047
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.119844 0.783760
|
||||
vt 0.124009 0.890693
|
||||
vt 0.124009 0.890693
|
||||
vt 0.509125 0.003716
|
||||
vt 0.515034 0.113020
|
||||
vt 0.509125 0.113020
|
||||
vt 0.616064 0.113020
|
||||
vt 0.717901 0.000000
|
||||
vt 0.717901 0.113020
|
||||
vt 1.000000 1.000000
|
||||
vt 1.000000 1.000000
|
||||
vt 0.119842 0.995708
|
||||
vt 0.124009 0.890696
|
||||
vt 0.124009 1.000000
|
||||
vt 0.067977 0.995708
|
||||
vt 0.063810 0.890696
|
||||
vt 0.067977 0.890815
|
||||
vt 0.063810 1.000000
|
||||
vt 0.515034 0.113020
|
||||
vt 0.616064 0.000000
|
||||
vt 0.616064 0.113020
|
||||
vt 0.118100 0.721754
|
||||
vt 0.124009 0.783760
|
||||
vt 0.118100 0.783760
|
||||
vt 0.509125 0.113020
|
||||
vt 0.503215 0.003716
|
||||
vt 0.509125 0.003716
|
||||
vt 0.115815 0.777387
|
||||
vt 0.115815 0.723967
|
||||
vt 0.431190 0.196713
|
||||
vt 0.465497 0.082435
|
||||
vt 0.465497 0.372997
|
||||
vt 0.465497 0.113020
|
||||
vt 0.717901 0.372997
|
||||
vt 0.465497 0.372997
|
||||
vt 0.717901 0.372997
|
||||
vt 0.435802 0.678852
|
||||
vt 0.435802 0.372997
|
||||
vt 1.000000 0.372997
|
||||
vt 0.717901 0.678852
|
||||
vt 0.717901 0.372997
|
||||
vt 0.435802 0.372997
|
||||
vt 0.153703 0.678852
|
||||
vt 0.153703 0.372997
|
||||
vt 0.717901 0.678852
|
||||
vt 0.435802 0.694145
|
||||
vt 0.017664 0.372997
|
||||
vt 0.002817 0.113020
|
||||
vt 0.017664 0.113020
|
||||
vt 1.000000 0.357704
|
||||
vt 0.717901 0.372997
|
||||
vt 0.032511 0.372997
|
||||
vt 0.017664 0.372997
|
||||
vt 0.138856 0.724730
|
||||
vt 0.406108 0.709437
|
||||
vt 0.391260 0.724730
|
||||
vt 0.406108 1.000000
|
||||
vt 0.391260 0.984707
|
||||
vt 0.124009 1.000000
|
||||
vt 0.138856 0.984707
|
||||
vt 0.124009 0.709438
|
||||
vt 0.014847 0.694145
|
||||
vt 0.000000 0.434168
|
||||
vt 0.014847 0.434168
|
||||
vt 1.000000 0.678852
|
||||
vt 0.717901 0.694145
|
||||
vt 0.435802 0.678852
|
||||
vt 0.153703 0.694145
|
||||
vt 0.004421 0.740023
|
||||
vt 0.019268 1.000000
|
||||
vt 0.004421 1.000000
|
||||
vt 0.316450 0.067652
|
||||
vt 0.252222 0.005787
|
||||
vt 0.316449 0.005787
|
||||
vt 0.483784 0.067652
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.005787
|
||||
vt 0.419557 0.067652
|
||||
vt 0.248111 0.067096
|
||||
vt 0.165675 0.015745
|
||||
vt 0.248111 0.015745
|
||||
vt 0.252222 0.005787
|
||||
vt 0.316450 0.067652
|
||||
vt 0.316449 0.005787
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.067652
|
||||
vt 0.419557 0.005787
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.067652
|
||||
vt 0.483784 0.005787
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.000000 0.000000
|
||||
vt 0.525322 0.836366
|
||||
vt 0.586878 0.919862
|
||||
vt 0.525322 0.919862
|
||||
vt 0.552285 0.749140
|
||||
vt 0.608723 0.836366
|
||||
vt 0.552285 0.836366
|
||||
vt 0.586878 0.894429
|
||||
vt 0.643316 0.836366
|
||||
vt 0.643316 0.894429
|
||||
vt 0.520203 0.749140
|
||||
vt 0.463765 0.836366
|
||||
vt 0.463765 0.749140
|
||||
vt 0.463765 0.836366
|
||||
vt 0.525322 0.928691
|
||||
vt 0.463765 0.928691
|
||||
vt 0.892836 0.808021
|
||||
vt 0.844939 0.752099
|
||||
vt 0.892836 0.752099
|
||||
vt 0.884262 0.808021
|
||||
vt 0.827791 0.912939
|
||||
vt 0.827791 0.808021
|
||||
vt 0.940733 0.808021
|
||||
vt 0.892836 0.752099
|
||||
vt 0.940733 0.752099
|
||||
vt 0.884262 0.912939
|
||||
vt 0.940733 0.808021
|
||||
vt 0.940733 0.912939
|
||||
vt 0.779894 0.808021
|
||||
vt 0.827791 0.912939
|
||||
vt 0.779894 0.912939
|
||||
vt 0.252222 0.005787
|
||||
vt 0.316450 0.067652
|
||||
vt 0.316449 0.005787
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.067652
|
||||
vt 0.419557 0.005787
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.067652
|
||||
vt 0.483784 0.005787
|
||||
vt 0.252222 0.005787
|
||||
vt 0.316450 0.067652
|
||||
vt 0.316449 0.005787
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.067652
|
||||
vt 0.419557 0.005787
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.067652
|
||||
vt 0.483784 0.005787
|
||||
vt 0.252222 0.005787
|
||||
vt 0.316450 0.067652
|
||||
vt 0.316449 0.005787
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.067652
|
||||
vt 0.419557 0.005787
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.067652
|
||||
vt 0.483784 0.005787
|
||||
vt 0.316450 0.067652
|
||||
vt 0.252222 0.005787
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.067652
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.067652
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.005787
|
||||
vt 0.316450 0.067652
|
||||
vt 0.252222 0.005787
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.067652
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.067652
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.005787
|
||||
vt 0.316450 0.067652
|
||||
vt 0.252222 0.005787
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.067652
|
||||
vt 0.316449 0.005787
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.067652
|
||||
vt 0.419557 0.005787
|
||||
vt 0.483784 0.005787
|
||||
vt 0.248111 0.067096
|
||||
vt 0.165675 0.015745
|
||||
vt 0.248111 0.015745
|
||||
vt 0.248111 0.067096
|
||||
vt 0.165675 0.015745
|
||||
vt 0.248111 0.015745
|
||||
vt 0.248111 0.067096
|
||||
vt 0.165675 0.015745
|
||||
vt 0.248111 0.015745
|
||||
vt 0.153703 0.403582
|
||||
vt 0.048963 0.694145
|
||||
vt 0.032511 0.372997
|
||||
vt 0.063810 0.694145
|
||||
vt 0.034115 0.694145
|
||||
vt 0.186214 0.082435
|
||||
vt 0.325069 0.082435
|
||||
vt 0.002849 1.000000
|
||||
vt 0.115894 0.783760
|
||||
vt 1.000000 1.000000
|
||||
vt 0.119840 0.890696
|
||||
vt 0.067976 0.890695
|
||||
vt 0.067979 0.783760
|
||||
vt 0.063810 0.890691
|
||||
vt 0.063810 0.890691
|
||||
vt 0.515034 0.003716
|
||||
vt 0.616064 0.000000
|
||||
vt 0.119842 0.891647
|
||||
vt 0.515034 0.000000
|
||||
vt 0.124009 0.721754
|
||||
vt 0.503215 0.113020
|
||||
vt 0.326641 0.372997
|
||||
vt 0.431190 0.258718
|
||||
vt 0.325069 0.258718
|
||||
vt 0.325069 0.196713
|
||||
vt 0.326641 0.082435
|
||||
vt 0.717901 0.113020
|
||||
vt 0.717901 0.694145
|
||||
vt 0.002817 0.372997
|
||||
vt 1.000000 0.372997
|
||||
vt 0.032511 0.113020
|
||||
vt 0.000000 0.694145
|
||||
vt 1.000000 0.694145
|
||||
vt 0.435802 0.694145
|
||||
vt 0.019268 0.740023
|
||||
vt 0.252222 0.067652
|
||||
vt 0.165675 0.067096
|
||||
vt 0.252222 0.067652
|
||||
vt 0.316450 0.067652
|
||||
vt 0.419557 0.067652
|
||||
vt 0.586878 0.836366
|
||||
vt 0.640804 0.749140
|
||||
vt 0.586878 0.836366
|
||||
vt 0.552285 0.836366
|
||||
vt 0.844939 0.808021
|
||||
vt 0.884262 0.912939
|
||||
vt 0.892836 0.808021
|
||||
vt 0.884262 0.808021
|
||||
vt 0.827791 0.808021
|
||||
vt 0.252222 0.067652
|
||||
vt 0.316450 0.067652
|
||||
vt 0.419557 0.067652
|
||||
vt 0.252222 0.067652
|
||||
vt 0.316450 0.067652
|
||||
vt 0.419557 0.067652
|
||||
vt 0.252222 0.067652
|
||||
vt 0.316450 0.067652
|
||||
vt 0.419557 0.067652
|
||||
vt 0.252222 0.067652
|
||||
vt 0.316450 0.067652
|
||||
vt 0.419557 0.067652
|
||||
vt 0.252222 0.067652
|
||||
vt 0.316450 0.067652
|
||||
vt 0.419557 0.067652
|
||||
vt 0.252222 0.067652
|
||||
vt 0.316450 0.067652
|
||||
vt 0.419557 0.067652
|
||||
vt 0.165675 0.067096
|
||||
vt 0.165675 0.067096
|
||||
vt 0.165675 0.067096
|
||||
vn 0.0000 -1.0000 0.0000
|
||||
vn -1.0000 0.0000 0.0000
|
||||
vn 1.0000 0.0000 0.0000
|
||||
vn 0.0000 1.0000 0.0000
|
||||
vn 0.0000 0.0000 -1.0000
|
||||
vn 0.0000 0.0000 1.0000
|
||||
vn 0.0000 0.6720 -0.7406
|
||||
vn 0.6720 0.0000 -0.7406
|
||||
vn 0.0000 -0.6720 -0.7406
|
||||
vn -0.6720 0.0000 -0.7406
|
||||
vn 0.7071 0.0000 -0.7071
|
||||
vn 0.0000 -0.3278 -0.9448
|
||||
vn -0.0178 0.4677 -0.8837
|
||||
vn -0.0123 0.0000 -0.9999
|
||||
vn -0.0201 0.0156 -0.9997
|
||||
vn -0.0109 -0.4677 -0.8838
|
||||
usemtl Material.001
|
||||
s off
|
||||
f 8/1/1 41/2/1 42/3/1
|
||||
f 3/4/2 12/5/2 4/6/2
|
||||
f 2/7/3 10/8/3 1/9/3
|
||||
f 4/10/1 11/11/1 2/12/1
|
||||
f 1/13/4 9/14/4 3/15/4
|
||||
f 7/16/5 10/17/5 45/18/5
|
||||
f 45/18/5 11/19/5 42/20/5
|
||||
f 42/20/5 12/21/5 8/22/5
|
||||
f 8/22/5 9/23/5 7/16/5
|
||||
f 22/24/1 55/25/1 21/26/1
|
||||
f 45/27/4 13/28/4 7/29/4
|
||||
f 7/30/2 14/31/2 8/32/2
|
||||
f 43/33/6 26/34/6 23/35/6
|
||||
f 16/36/7 19/37/7 15/38/7
|
||||
f 17/39/8 20/40/8 16/36/8
|
||||
f 18/41/9 21/42/9 17/39/9
|
||||
f 15/38/10 22/43/10 18/41/10
|
||||
f 47/44/2 42/45/2 44/46/2
|
||||
f 5/47/3 44/48/3 6/49/3
|
||||
f 48/50/6 25/51/6 26/34/6
|
||||
f 27/52/6 25/53/6 47/54/6
|
||||
f 25/55/4 34/56/4 26/57/4
|
||||
f 30/58/1 37/59/1 27/60/1
|
||||
f 44/61/6 23/35/6 24/62/6
|
||||
f 35/63/3 32/64/3 31/65/3
|
||||
f 38/66/3 33/67/3 37/68/3
|
||||
f 35/63/3 34/69/3 38/66/3
|
||||
f 28/70/4 35/71/4 29/72/4
|
||||
f 26/73/5 31/74/5 23/75/5
|
||||
f 23/76/1 32/77/1 24/78/1
|
||||
f 6/49/11 39/79/11 40/80/11
|
||||
f 43/81/3 41/82/3 46/83/3
|
||||
f 51/84/5 49/85/5 50/86/5
|
||||
f 20/87/4 53/88/4 19/89/4
|
||||
f 19/90/2 56/91/2 22/92/2
|
||||
f 21/93/3 54/94/3 20/95/3
|
||||
f 54/96/4 57/97/4 53/88/4
|
||||
f 52/98/3 61/99/3 49/100/3
|
||||
f 56/101/1 59/102/1 55/25/1
|
||||
f 49/100/1 62/103/1 50/104/1
|
||||
f 61/105/5 58/106/5 62/107/5
|
||||
f 62/107/5 59/108/5 63/109/5
|
||||
f 63/109/5 60/110/5 64/111/5
|
||||
f 64/111/5 57/112/5 61/105/5
|
||||
f 50/113/2 63/114/2 51/115/2
|
||||
f 53/116/2 60/117/2 56/91/2
|
||||
f 55/118/3 58/119/3 54/94/3
|
||||
f 51/120/4 64/121/4 52/122/4
|
||||
f 66/123/4 67/124/4 65/125/4
|
||||
f 72/126/1 69/127/1 71/128/1
|
||||
f 70/129/3 65/125/3 69/127/3
|
||||
f 65/130/5 71/131/5 67/132/5
|
||||
f 74/133/1 75/134/1 76/135/1
|
||||
f 80/136/2 77/137/2 78/138/2
|
||||
f 84/139/4 81/140/4 82/141/4
|
||||
f 86/142/4 87/143/4 85/144/4
|
||||
f 88/145/2 91/146/2 87/143/2
|
||||
f 92/147/1 89/148/1 91/146/1
|
||||
f 90/149/3 85/144/3 89/148/3
|
||||
f 88/145/5 90/149/5 92/147/5
|
||||
f 94/150/4 95/151/4 93/152/4
|
||||
f 95/153/2 100/154/2 99/155/2
|
||||
f 100/156/1 97/157/1 99/158/1
|
||||
f 98/159/3 93/160/3 97/161/3
|
||||
f 96/162/12 98/163/12 100/164/12
|
||||
f 102/165/4 103/166/4 101/167/4
|
||||
f 104/168/2 107/169/2 103/170/2
|
||||
f 108/171/1 105/172/1 107/173/1
|
||||
f 106/174/3 101/175/3 105/176/3
|
||||
f 104/177/5 106/178/5 108/179/5
|
||||
f 110/180/1 111/181/1 112/182/1
|
||||
f 116/183/2 113/184/2 114/185/2
|
||||
f 120/186/4 117/187/4 118/188/4
|
||||
f 123/189/1 122/190/1 121/191/1
|
||||
f 128/192/2 125/193/2 126/194/2
|
||||
f 132/195/4 129/196/4 130/197/4
|
||||
f 135/198/1 134/199/1 133/200/1
|
||||
f 140/201/2 137/202/2 138/203/2
|
||||
f 144/204/4 141/205/4 142/206/4
|
||||
f 147/207/4 146/208/4 148/209/4
|
||||
f 149/210/3 152/211/3 150/212/3
|
||||
f 153/213/1 156/214/1 154/215/1
|
||||
f 158/216/4 159/217/4 157/218/4
|
||||
f 161/219/3 164/220/3 162/221/3
|
||||
f 165/222/1 168/223/1 166/224/1
|
||||
f 170/225/4 171/226/4 169/227/4
|
||||
f 173/228/3 176/229/3 174/230/3
|
||||
f 177/231/1 180/232/1 178/233/1
|
||||
f 181/234/5 184/235/5 182/236/5
|
||||
f 185/237/5 188/238/5 186/239/5
|
||||
f 189/240/5 192/241/5 190/242/5
|
||||
f 8/1/1 14/243/1 41/2/1
|
||||
f 3/4/2 9/244/2 12/5/2
|
||||
f 2/7/3 11/245/3 10/8/3
|
||||
f 4/10/1 12/246/1 11/11/1
|
||||
f 1/13/4 10/247/4 9/14/4
|
||||
f 7/16/5 9/23/5 10/17/5
|
||||
f 45/18/5 10/17/5 11/19/5
|
||||
f 42/20/5 11/19/5 12/21/5
|
||||
f 8/22/5 12/21/5 9/23/5
|
||||
f 22/24/1 56/101/1 55/25/1
|
||||
f 45/27/4 46/248/4 13/28/4
|
||||
f 7/30/2 13/249/2 14/31/2
|
||||
f 43/33/6 48/50/6 26/34/6
|
||||
f 16/36/7 20/40/7 19/37/7
|
||||
f 17/39/8 21/42/8 20/40/8
|
||||
f 18/41/9 22/43/9 21/42/9
|
||||
f 15/38/10 19/37/10 22/43/10
|
||||
f 47/44/2 45/250/2 42/45/2
|
||||
f 5/47/3 47/251/3 44/48/3
|
||||
f 48/50/6 47/252/6 25/51/6
|
||||
f 47/54/13 5/253/13 27/52/13
|
||||
f 5/253/14 6/254/14 28/255/14
|
||||
f 44/256/6 24/257/6 28/255/6
|
||||
f 5/253/15 28/255/15 27/52/15
|
||||
f 6/254/16 44/256/16 28/255/16
|
||||
f 25/55/4 33/258/4 34/56/4
|
||||
f 30/58/1 38/259/1 37/59/1
|
||||
f 44/61/6 43/33/6 23/35/6
|
||||
f 35/63/3 36/260/3 32/64/3
|
||||
f 38/66/3 34/69/3 33/67/3
|
||||
f 35/63/3 31/65/3 34/69/3
|
||||
f 28/70/4 36/261/4 35/71/4
|
||||
f 26/73/5 34/262/5 31/74/5
|
||||
f 23/76/1 31/263/1 32/77/1
|
||||
f 6/49/11 5/47/11 39/79/11
|
||||
f 46/83/3 45/264/3 48/265/3
|
||||
f 45/264/3 47/266/3 48/265/3
|
||||
f 44/267/3 42/268/3 43/81/3
|
||||
f 42/268/3 41/82/3 43/81/3
|
||||
f 46/83/3 48/265/3 43/81/3
|
||||
f 51/84/5 52/269/5 49/85/5
|
||||
f 20/87/4 54/96/4 53/88/4
|
||||
f 19/90/2 53/116/2 56/91/2
|
||||
f 21/93/3 55/118/3 54/94/3
|
||||
f 54/96/4 58/270/4 57/97/4
|
||||
f 52/98/3 64/271/3 61/99/3
|
||||
f 56/101/1 60/272/1 59/102/1
|
||||
f 49/100/1 61/273/1 62/103/1
|
||||
f 61/105/5 57/112/5 58/106/5
|
||||
f 62/107/5 58/106/5 59/108/5
|
||||
f 63/109/5 59/108/5 60/110/5
|
||||
f 64/111/5 60/110/5 57/112/5
|
||||
f 50/113/2 62/274/2 63/114/2
|
||||
f 53/116/2 57/275/2 60/117/2
|
||||
f 55/118/3 59/276/3 58/119/3
|
||||
f 51/120/4 63/277/4 64/121/4
|
||||
f 66/123/4 68/278/4 67/124/4
|
||||
f 72/126/1 70/129/1 69/127/1
|
||||
f 70/129/3 66/123/3 65/125/3
|
||||
f 65/130/5 69/279/5 71/131/5
|
||||
f 74/133/1 73/280/1 75/134/1
|
||||
f 80/136/2 79/281/2 77/137/2
|
||||
f 84/139/4 83/282/4 81/140/4
|
||||
f 86/142/4 88/145/4 87/143/4
|
||||
f 88/145/2 92/147/2 91/146/2
|
||||
f 92/147/1 90/149/1 89/148/1
|
||||
f 90/149/3 86/142/3 85/144/3
|
||||
f 88/145/5 86/142/5 90/149/5
|
||||
f 94/150/4 96/283/4 95/151/4
|
||||
f 95/153/2 96/284/2 100/154/2
|
||||
f 100/156/1 98/285/1 97/157/1
|
||||
f 98/159/3 94/286/3 93/160/3
|
||||
f 96/162/12 94/150/12 98/163/12
|
||||
f 102/165/4 104/287/4 103/166/4
|
||||
f 104/168/2 108/288/2 107/169/2
|
||||
f 108/171/1 106/289/1 105/172/1
|
||||
f 106/174/3 102/290/3 101/175/3
|
||||
f 104/177/5 102/291/5 106/178/5
|
||||
f 110/180/1 109/292/1 111/181/1
|
||||
f 116/183/2 115/293/2 113/184/2
|
||||
f 120/186/4 119/294/4 117/187/4
|
||||
f 123/189/1 124/295/1 122/190/1
|
||||
f 128/192/2 127/296/2 125/193/2
|
||||
f 132/195/4 131/297/4 129/196/4
|
||||
f 135/198/1 136/298/1 134/199/1
|
||||
f 140/201/2 139/299/2 137/202/2
|
||||
f 144/204/4 143/300/4 141/205/4
|
||||
f 147/207/4 145/301/4 146/208/4
|
||||
f 149/210/3 151/302/3 152/211/3
|
||||
f 153/213/1 155/303/1 156/214/1
|
||||
f 158/216/4 160/304/4 159/217/4
|
||||
f 161/219/3 163/305/3 164/220/3
|
||||
f 165/222/1 167/306/1 168/223/1
|
||||
f 170/225/4 172/307/4 171/226/4
|
||||
f 173/228/3 175/308/3 176/229/3
|
||||
f 177/231/1 179/309/1 180/232/1
|
||||
f 181/234/5 183/310/5 184/235/5
|
||||
f 185/237/5 187/311/5 188/238/5
|
||||
f 189/240/5 191/312/5 192/241/5
|
||||
BIN
Videos/CarCrimeCity/Part2/assets/buildings/udxs_building1.png
Normal file
|
After Width: | Height: | Size: 494 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/buildings/unit_building.blend
Normal file
BIN
Videos/CarCrimeCity/Part2/assets/buildings/unit_building.blend1
Normal file
26
Videos/CarCrimeCity/Part2/assets/buildings/unit_building.obj
Normal file
@@ -0,0 +1,26 @@
|
||||
# Blender v2.79 (sub 0) OBJ File: 'unit_building.blend'
|
||||
# www.blender.org
|
||||
v 1.0000 1.000 -0.000
|
||||
v 1.0000 1.0 -0.50
|
||||
v 0.0000 1.00 -0.000
|
||||
v 0.0000 1.000 -0.5
|
||||
v 1.0 0.00 0.000
|
||||
v 1.0 0.00000 -0.5
|
||||
v -0.000081 0.004528 0.004407
|
||||
v -0.000081 0.000101 -0.495573
|
||||
vn 0.0002 1.0000 -0.0089
|
||||
vn -1.0000 0.0002 -0.0000
|
||||
vn -0.0002 -1.0000 0.0089
|
||||
vn 1.0000 -0.0002 0.0000
|
||||
vn -0.0000 -0.0089 -1.0000
|
||||
s off
|
||||
f 2//1 3//1 1//1
|
||||
f 4//2 7//2 3//2
|
||||
f 8//3 5//3 7//3
|
||||
f 6//4 1//4 5//4
|
||||
f 4//5 6//5 8//5
|
||||
f 2//1 4//1 3//1
|
||||
f 4//2 8//2 7//2
|
||||
f 8//3 6//3 5//3
|
||||
f 6//4 2//4 1//4
|
||||
f 4//5 2//5 6//5
|
||||
BIN
Videos/CarCrimeCity/Part2/assets/cities/example1.city
Normal file
50
Videos/CarCrimeCity/Part2/assets/config.lua
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
|
||||
-- Size of pixel
|
||||
PixelWidth = 2
|
||||
PixelHeight = 2
|
||||
|
||||
-- Size of display window in pixels
|
||||
ScreenWidth = 768
|
||||
ScreenHeight = 480
|
||||
--ScreenWidth = 384
|
||||
--ScreenHeight = 240
|
||||
|
||||
FullScreen = false
|
||||
|
||||
-- Default city parameters
|
||||
DefaultMapWidth = 64
|
||||
DefaultMapHeight = 32
|
||||
--DefaultCityFile = "assets/cities/example1.city"
|
||||
|
||||
|
||||
-- Textures used by various game systems
|
||||
Textures = {}
|
||||
Textures[1] = {"Grass", "assets/system/grass1.png"}
|
||||
Textures[2] = {"AllRoads", "assets/system/roads4.png"}
|
||||
Textures[3] = {"Water", "assets/system/water1.png"}
|
||||
Textures[4] = {"Clouds", "assets/system/clouds2.png"}
|
||||
Textures[5] = {"WaterSide", "assets/system/waterside1.png"}
|
||||
Textures[6] = {"Smoke", "assets/system/skidsmoke1.png"}
|
||||
|
||||
-- Buildings
|
||||
Buildings = {}
|
||||
Buildings[1] = {"javidx9", "UnitBuilding_1", "assets/buildings/unit_building.obj", "",
|
||||
0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0}
|
||||
Buildings[2] = {"UDXS", "Apartments_1", "assets/buildings/udxs_building1.obj", "assets/buildings/udxs_building1.png",
|
||||
0.0, 0.0, 0.0, 1.0, 1.0, 0.5, 1.0, 1.0, 0.0}
|
||||
|
||||
Vehicles = {}
|
||||
Vehicles[1] = {"JustinRM", "Sedan", "assets/vehicles/CarCrime_Sedan.obj", "assets/vehicles/CarTex_256.png",
|
||||
0.0, 0.0, 1.5708, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0}
|
||||
Vehicles[2] = {"JustinRM", "SUV", "assets/vehicles/CarCrime_SUV.obj", "assets/vehicles/CarTex_256.png",
|
||||
0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0}
|
||||
Vehicles[3] = {"JustinRM", "TruckCab", "assets/vehicles/CarCrime_Truck_Cab.obj", "assets/vehicles/CarTex_256.png",
|
||||
0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0}
|
||||
Vehicles[4] = {"JustinRM", "TruckTrailer", "assets/vehicles/CarCrime_Truck_Trailer.obj", "assets/vehicles/CarTex_256.png",
|
||||
0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0}
|
||||
Vehicles[5] = {"JustinRM", "UTE", "assets/vehicles/CarCrime_Ute.obj", "assets/vehicles/CarTex_256.png",
|
||||
0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0}
|
||||
Vehicles[6] = {"JustinRM", "Wagon", "assets/vehicles/CarCrime_Wahon.obj", "assets/vehicles/CarTex_256.png",
|
||||
0.0, 0.0, 0.0, 0.05, 0.05, 0.05, 0.0, 0.0, 0.0}
|
||||
|
||||
BIN
Videos/CarCrimeCity/Part2/assets/system/car_top.png
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/car_top3.png
Normal file
|
After Width: | Height: | Size: 284 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/ccctitle1.png
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/clouds1.png
Normal file
|
After Width: | Height: | Size: 482 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/clouds2.png
Normal file
|
After Width: | Height: | Size: 383 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/grass1.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/roads1.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/roads2.png
Normal file
|
After Width: | Height: | Size: 691 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/roads3.png
Normal file
|
After Width: | Height: | Size: 732 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/roads4.png
Normal file
|
After Width: | Height: | Size: 616 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/skidsmoke1.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/water1.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
Videos/CarCrimeCity/Part2/assets/system/waterside1.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
121
Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_SUV.obj
Normal file
@@ -0,0 +1,121 @@
|
||||
# Blender v2.69 (sub 0) OBJ File: 'Car002.blend'
|
||||
# www.blender.org
|
||||
v 0.600000 -0.400000 -1.700000
|
||||
v 0.600000 1.700000 -1.700000
|
||||
v -0.600000 -0.400000 -1.700000
|
||||
v -0.600000 1.700000 -1.700000
|
||||
v -0.800000 2.000000 -1.100000
|
||||
v 0.800000 2.000000 -1.100000
|
||||
v -0.800000 2.000000 -1.100000
|
||||
v 0.800000 2.000000 -1.100000
|
||||
v -0.800000 -1.000000 -0.950000
|
||||
v 0.800000 -1.000000 -0.950000
|
||||
v -0.800000 -2.000000 -0.900000
|
||||
v 0.800000 -2.000000 -0.900000
|
||||
v -0.800000 2.000000 -0.400000
|
||||
v 0.800000 2.000000 -0.400000
|
||||
v -0.800000 -2.000000 -0.400000
|
||||
v 0.800000 -2.000000 -0.400000
|
||||
v 0.800000 -2.000000 -0.400000
|
||||
v 0.800000 2.000000 -0.400000
|
||||
v 0.800000 -2.000000 -0.900000
|
||||
v 0.800000 2.000000 -1.100000
|
||||
v -0.800000 -2.000000 -0.900000
|
||||
v -0.800000 2.000000 -1.100000
|
||||
v -0.800000 -2.000000 -0.400000
|
||||
v -0.800000 2.000000 -0.400000
|
||||
v 0.780000 1.200000 -0.400000
|
||||
v 0.780000 1.500000 -0.400000
|
||||
v 0.780000 1.400000 0.000000
|
||||
v 0.780000 1.000000 0.000000
|
||||
v 0.780000 0.900000 -0.400000
|
||||
v 0.780000 -1.100000 -0.400000
|
||||
v 0.780000 -0.800000 -0.400000
|
||||
v 0.780000 -0.900000 0.000000
|
||||
v 0.780000 -1.300000 0.000000
|
||||
v 0.780000 -1.400000 -0.400000
|
||||
v -0.780000 -1.100000 -0.400000
|
||||
v -0.780000 -1.400000 -0.400000
|
||||
v -0.780000 -1.300000 0.000000
|
||||
v -0.780000 -0.900000 0.000000
|
||||
v -0.780000 -0.800000 -0.400000
|
||||
v -0.780000 1.200000 -0.400000
|
||||
v -0.780000 0.900000 -0.400000
|
||||
v -0.780000 1.000000 0.000000
|
||||
v -0.780000 1.400000 0.000000
|
||||
v -0.780000 1.500000 -0.400000
|
||||
vt 0.564792 0.689981
|
||||
vt 0.564792 0.953949
|
||||
vt 0.338554 0.953949
|
||||
vt 0.338554 0.689981
|
||||
vt 0.334296 0.692438
|
||||
vt 0.334296 0.954445
|
||||
vt 0.203294 0.986197
|
||||
vt 0.203294 0.656186
|
||||
vt 0.695616 0.984433
|
||||
vt 0.572654 0.959219
|
||||
vt 0.695616 0.657719
|
||||
vt 0.572795 0.683358
|
||||
vt 0.941945 0.999442
|
||||
vt 0.694306 0.999442
|
||||
vt 0.941945 0.647349
|
||||
vt 0.694306 0.647349
|
||||
vt 0.070499 0.643570
|
||||
vt 0.070499 0.998147
|
||||
vt 0.003817 0.998147
|
||||
vt 0.003817 0.643570
|
||||
vt 0.997239 0.998410
|
||||
vt 0.940308 0.998410
|
||||
vt 0.997239 0.647262
|
||||
vt 0.940308 0.647262
|
||||
vt 0.331416 0.690927
|
||||
vt 0.238667 0.577426
|
||||
vt 0.563274 0.690927
|
||||
vt 0.735343 0.574985
|
||||
vt 0.970266 0.522520
|
||||
vt 0.962942 0.572543
|
||||
vt 0.072079 0.572543
|
||||
vt 0.079403 0.522520
|
||||
vt 0.744362 0.446044
|
||||
vt 0.780351 0.385565
|
||||
vt 0.817830 0.446044
|
||||
vt 0.854309 0.385565
|
||||
vt 0.891299 0.446044
|
||||
vt 0.743883 0.446331
|
||||
vt 0.779872 0.385852
|
||||
vt 0.817351 0.446331
|
||||
vt 0.853830 0.385852
|
||||
vt 0.890820 0.446331
|
||||
s off
|
||||
f 1/1 3/2 4/3
|
||||
f 2/4 1/1 4/3
|
||||
f 2/5 4/6 5/7
|
||||
f 5/7 6/8 2/5
|
||||
f 9/9 3/10 10/11
|
||||
f 3/10 1/12 10/11
|
||||
f 11/13 9/14 12/15
|
||||
f 10/16 12/15 9/14
|
||||
f 8/17 7/18 13/19
|
||||
f 13/19 14/20 8/17
|
||||
f 15/21 11/22 16/23
|
||||
f 12/24 16/23 11/22
|
||||
f 2/25 6/26 1/27
|
||||
f 10/28 1/27 6/26
|
||||
f 4/25 3/27 5/26
|
||||
f 9/28 5/26 3/27
|
||||
f 17/29 19/30 20/31
|
||||
f 18/32 17/29 20/31
|
||||
f 21/30 23/29 24/32
|
||||
f 22/31 21/30 24/32
|
||||
f 26/33 27/34 25/35
|
||||
f 27/34 28/36 25/35
|
||||
f 28/36 29/37 25/35
|
||||
f 31/38 32/39 30/40
|
||||
f 32/39 33/41 30/40
|
||||
f 33/41 34/42 30/40
|
||||
f 36/42 37/41 35/40
|
||||
f 37/41 38/39 35/40
|
||||
f 38/39 39/38 35/40
|
||||
f 41/37 42/36 40/35
|
||||
f 42/36 43/34 40/35
|
||||
f 43/34 44/33 40/35
|
||||
127
Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Sedan.obj
Normal file
@@ -0,0 +1,127 @@
|
||||
# Blender v2.69 (sub 0) OBJ File: 'Car002.blend'
|
||||
# www.blender.org
|
||||
v 0.600000 -0.200000 -1.100000
|
||||
v 0.600000 1.000000 -1.100000
|
||||
v -0.600000 -0.200000 -1.100000
|
||||
v -0.600000 1.000000 -1.100000
|
||||
v -0.800000 1.400000 -0.700000
|
||||
v 0.800000 1.400000 -0.700000
|
||||
v -0.800000 2.000000 -0.700000
|
||||
v 0.800000 2.000000 -0.700000
|
||||
v -0.800000 -1.000000 -0.700000
|
||||
v 0.800000 -1.000000 -0.700000
|
||||
v -0.800000 -2.000000 -0.700000
|
||||
v 0.800000 -2.000000 -0.700000
|
||||
v -0.800000 2.000000 -0.300000
|
||||
v 0.800000 2.000000 -0.300000
|
||||
v -0.800000 -2.000000 -0.300000
|
||||
v 0.800000 -2.000000 -0.300000
|
||||
v 0.800000 -2.000000 -0.300000
|
||||
v 0.800000 2.000000 -0.300000
|
||||
v 0.800000 -2.000000 -0.700000
|
||||
v 0.800000 2.000000 -0.700000
|
||||
v -0.800000 -2.000000 -0.700000
|
||||
v -0.800000 2.000000 -0.700000
|
||||
v -0.800000 -2.000000 -0.300000
|
||||
v -0.800000 2.000000 -0.300000
|
||||
v 0.780000 1.200000 -0.300000
|
||||
v 0.780000 1.500000 -0.300000
|
||||
v 0.780000 1.400000 0.000000
|
||||
v 0.780000 1.000000 0.000000
|
||||
v 0.780000 0.900000 -0.300000
|
||||
v 0.780000 -1.100000 -0.300000
|
||||
v 0.780000 -0.800000 -0.300000
|
||||
v 0.780000 -0.900000 0.000000
|
||||
v 0.780000 -1.300000 0.000000
|
||||
v 0.780000 -1.400000 -0.300000
|
||||
v -0.780000 -1.100000 -0.300000
|
||||
v -0.780000 -1.400000 -0.300000
|
||||
v -0.780000 -1.300000 0.000000
|
||||
v -0.780000 -0.900000 0.000000
|
||||
v -0.780000 -0.800000 -0.300000
|
||||
v -0.780000 1.200000 -0.300000
|
||||
v -0.780000 0.900000 -0.300000
|
||||
v -0.780000 1.000000 0.000000
|
||||
v -0.780000 1.400000 0.000000
|
||||
v -0.780000 1.500000 -0.300000
|
||||
vt 0.564792 0.689981
|
||||
vt 0.564792 0.953949
|
||||
vt 0.338554 0.953949
|
||||
vt 0.338554 0.689981
|
||||
vt 0.334296 0.692438
|
||||
vt 0.334296 0.954445
|
||||
vt 0.203294 0.986197
|
||||
vt 0.203294 0.656186
|
||||
vt 0.203326 0.657931
|
||||
vt 0.203326 0.986286
|
||||
vt 0.080997 0.986286
|
||||
vt 0.080997 0.657931
|
||||
vt 0.695616 0.984433
|
||||
vt 0.572654 0.959219
|
||||
vt 0.695616 0.657719
|
||||
vt 0.572795 0.683358
|
||||
vt 0.941945 0.999442
|
||||
vt 0.694306 0.999442
|
||||
vt 0.941945 0.647349
|
||||
vt 0.694306 0.647349
|
||||
vt 0.070499 0.643570
|
||||
vt 0.070499 0.998147
|
||||
vt 0.003817 0.998147
|
||||
vt 0.003817 0.643570
|
||||
vt 0.997239 0.998410
|
||||
vt 0.940308 0.998410
|
||||
vt 0.997239 0.647262
|
||||
vt 0.940308 0.647262
|
||||
vt 0.331416 0.690927
|
||||
vt 0.238667 0.577426
|
||||
vt 0.563274 0.690927
|
||||
vt 0.735343 0.574985
|
||||
vt 0.970266 0.522520
|
||||
vt 0.962942 0.572543
|
||||
vt 0.072079 0.572543
|
||||
vt 0.079403 0.522520
|
||||
vt 0.744362 0.446044
|
||||
vt 0.780351 0.385565
|
||||
vt 0.817830 0.446044
|
||||
vt 0.854309 0.385565
|
||||
vt 0.891299 0.446044
|
||||
vt 0.743883 0.446331
|
||||
vt 0.779872 0.385852
|
||||
vt 0.817351 0.446331
|
||||
vt 0.853830 0.385852
|
||||
vt 0.890820 0.446331
|
||||
s off
|
||||
f 1/1 3/2 4/3
|
||||
f 2/4 1/1 4/3
|
||||
f 2/5 4/6 5/7
|
||||
f 5/7 6/8 2/5
|
||||
f 6/9 5/10 7/11
|
||||
f 7/11 8/12 6/9
|
||||
f 9/13 3/14 10/15
|
||||
f 3/14 1/16 10/15
|
||||
f 11/17 9/18 12/19
|
||||
f 10/20 12/19 9/18
|
||||
f 8/21 7/22 13/23
|
||||
f 13/23 14/24 8/21
|
||||
f 15/25 11/26 16/27
|
||||
f 12/28 16/27 11/26
|
||||
f 2/29 6/30 1/31
|
||||
f 10/32 1/31 6/30
|
||||
f 4/29 3/31 5/30
|
||||
f 9/32 5/30 3/31
|
||||
f 17/33 19/34 20/35
|
||||
f 18/36 17/33 20/35
|
||||
f 21/34 23/33 24/36
|
||||
f 22/35 21/34 24/36
|
||||
f 26/37 27/38 25/39
|
||||
f 27/38 28/40 25/39
|
||||
f 28/40 29/41 25/39
|
||||
f 31/42 32/43 30/44
|
||||
f 32/43 33/45 30/44
|
||||
f 33/45 34/46 30/44
|
||||
f 36/46 37/45 35/44
|
||||
f 37/45 38/43 35/44
|
||||
f 38/43 39/42 35/44
|
||||
f 41/41 42/40 40/39
|
||||
f 42/40 43/38 40/39
|
||||
f 43/38 44/37 40/39
|
||||
137
Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Truck_Cab.obj
Normal file
@@ -0,0 +1,137 @@
|
||||
# Blender v2.69 (sub 0) OBJ File: 'Car002.blend'
|
||||
# www.blender.org
|
||||
v 0.600000 -1.900000 -1.500000
|
||||
v 0.600000 -1.000000 -1.500000
|
||||
v -0.600000 -1.900000 -1.500000
|
||||
v -0.600000 -1.000000 -1.500000
|
||||
v -0.800000 -0.900000 -0.700000
|
||||
v 0.800000 -0.900000 -0.700000
|
||||
v -0.800000 0.600000 -0.700000
|
||||
v 0.800000 0.600000 -0.700000
|
||||
v -0.800000 -2.400000 -0.700000
|
||||
v 0.800000 -2.400000 -0.700000
|
||||
v -0.800000 -2.400000 -0.700000
|
||||
v 0.800000 -2.400000 -0.700000
|
||||
v -0.800000 0.600000 -0.300000
|
||||
v 0.800000 0.600000 -0.300000
|
||||
v -0.800000 -2.400000 -0.300000
|
||||
v 0.800000 -2.400000 -0.300000
|
||||
v 0.800000 -2.400000 -0.300000
|
||||
v 0.800000 0.600000 -0.300000
|
||||
v 0.800000 -2.400000 -0.700000
|
||||
v 0.800000 0.600000 -0.700000
|
||||
v -0.800000 -2.400000 -0.700000
|
||||
v -0.800000 0.600000 -0.700000
|
||||
v -0.800000 -2.400000 -0.300000
|
||||
v -0.800000 0.600000 -0.300000
|
||||
v 0.780000 0.100000 -0.300000
|
||||
v 0.780000 0.400000 -0.300000
|
||||
v 0.780000 0.300000 0.000000
|
||||
v 0.780000 -0.100000 0.000000
|
||||
v 0.780000 -0.200000 -0.300000
|
||||
v 0.780000 -1.900000 -0.300000
|
||||
v 0.780000 -1.600000 -0.300000
|
||||
v 0.780000 -1.700000 0.000000
|
||||
v 0.780000 -2.100000 0.000000
|
||||
v 0.780000 -2.200000 -0.300000
|
||||
v -0.780000 -1.900000 -0.300000
|
||||
v -0.780000 -2.200000 -0.300000
|
||||
v -0.780000 -2.100000 0.000000
|
||||
v -0.780000 -1.700000 0.000000
|
||||
v -0.780000 -1.600000 -0.300000
|
||||
v -0.780000 0.100000 -0.300000
|
||||
v -0.780000 -0.200000 -0.300000
|
||||
v -0.780000 -0.100000 0.000000
|
||||
v -0.780000 0.300000 0.000000
|
||||
v -0.780000 0.400000 -0.300000
|
||||
v 0.780000 -0.600000 -0.300000
|
||||
v 0.780000 -0.300000 -0.300000
|
||||
v 0.780000 -0.400000 0.000000
|
||||
v 0.780000 -0.800000 0.000000
|
||||
v 0.780000 -0.900000 -0.300000
|
||||
v -0.780000 -0.600000 -0.300000
|
||||
v -0.780000 -0.900000 -0.300000
|
||||
v -0.780000 -0.800000 0.000000
|
||||
v -0.780000 -0.400000 0.000000
|
||||
v -0.780000 -0.300000 -0.300000
|
||||
vt 0.564792 0.689981
|
||||
vt 0.564792 0.953949
|
||||
vt 0.338554 0.953949
|
||||
vt 0.338554 0.689981
|
||||
vt 0.334296 0.692438
|
||||
vt 0.334296 0.954445
|
||||
vt 0.203294 0.986197
|
||||
vt 0.203294 0.656186
|
||||
vt 0.695616 0.984433
|
||||
vt 0.572654 0.959219
|
||||
vt 0.695616 0.657719
|
||||
vt 0.572795 0.683358
|
||||
vt 0.070499 0.643570
|
||||
vt 0.070499 0.998147
|
||||
vt 0.003817 0.998147
|
||||
vt 0.003817 0.643570
|
||||
vt 0.997239 0.998410
|
||||
vt 0.940308 0.998410
|
||||
vt 0.997239 0.647262
|
||||
vt 0.940308 0.647262
|
||||
vt 0.471796 0.690927
|
||||
vt 0.487691 0.573764
|
||||
vt 0.563274 0.690927
|
||||
vt 0.735343 0.574985
|
||||
vt 0.970266 0.522520
|
||||
vt 0.962942 0.572543
|
||||
vt 0.072079 0.572543
|
||||
vt 0.079403 0.522520
|
||||
vt 0.744362 0.446044
|
||||
vt 0.780351 0.385565
|
||||
vt 0.817830 0.446044
|
||||
vt 0.854309 0.385565
|
||||
vt 0.891299 0.446044
|
||||
vt 0.743883 0.446331
|
||||
vt 0.779872 0.385852
|
||||
vt 0.817351 0.446331
|
||||
vt 0.853830 0.385852
|
||||
vt 0.890820 0.446331
|
||||
vt 0.122341 0.504785
|
||||
vt 0.003867 0.504785
|
||||
vt 0.122341 0.378413
|
||||
vt 0.003867 0.378413
|
||||
s off
|
||||
f 1/1 3/2 4/3
|
||||
f 2/4 1/1 4/3
|
||||
f 2/5 4/6 5/7
|
||||
f 5/7 6/8 2/5
|
||||
f 9/9 3/10 10/11
|
||||
f 3/10 1/12 10/11
|
||||
f 8/13 7/14 13/15
|
||||
f 13/15 14/16 8/13
|
||||
f 15/17 11/18 16/19
|
||||
f 12/20 16/19 11/18
|
||||
f 2/21 6/22 1/23
|
||||
f 10/24 1/23 6/22
|
||||
f 4/21 3/23 5/22
|
||||
f 9/24 5/22 3/23
|
||||
f 17/25 19/26 20/27
|
||||
f 18/28 17/25 20/27
|
||||
f 21/26 23/25 24/28
|
||||
f 22/27 21/26 24/28
|
||||
f 26/29 27/30 25/31
|
||||
f 27/30 28/32 25/31
|
||||
f 28/32 29/33 25/31
|
||||
f 31/34 32/35 30/36
|
||||
f 32/35 33/37 30/36
|
||||
f 33/37 34/38 30/36
|
||||
f 36/38 37/37 35/36
|
||||
f 37/37 38/35 35/36
|
||||
f 38/35 39/34 35/36
|
||||
f 41/33 42/32 40/31
|
||||
f 42/32 43/30 40/31
|
||||
f 43/30 44/29 40/31
|
||||
f 5/39 7/40 6/41
|
||||
f 7/40 8/42 6/41
|
||||
f 46/29 47/30 45/31
|
||||
f 47/30 48/32 45/31
|
||||
f 48/32 49/33 45/31
|
||||
f 51/33 52/32 50/31
|
||||
f 52/32 53/30 50/31
|
||||
f 53/30 54/29 50/31
|
||||
@@ -0,0 +1,106 @@
|
||||
# Blender v2.69 (sub 0) OBJ File: 'Car002.blend'
|
||||
# www.blender.org
|
||||
v -0.800000 2.900000 -0.700000
|
||||
v 0.800000 2.900000 -0.700000
|
||||
v -0.800000 1.200000 -0.700000
|
||||
v 0.800000 1.200000 -0.700000
|
||||
v -0.800000 2.900000 -0.300000
|
||||
v 0.800000 2.900000 -0.300000
|
||||
v -0.800000 1.200000 -0.300000
|
||||
v 0.800000 1.200000 -0.300000
|
||||
v 0.800000 1.200000 -0.300000
|
||||
v 0.800000 2.900000 -0.300000
|
||||
v 0.800000 1.200000 -0.700000
|
||||
v 0.800000 2.900000 -0.700000
|
||||
v -0.800000 1.200000 -0.700000
|
||||
v -0.800000 2.900000 -0.700000
|
||||
v -0.800000 1.200000 -0.300000
|
||||
v -0.800000 2.900000 -0.300000
|
||||
v 0.780000 2.400000 -0.300000
|
||||
v 0.780000 2.700000 -0.300000
|
||||
v 0.780000 2.600000 0.000000
|
||||
v 0.780000 2.200000 0.000000
|
||||
v 0.780000 2.100000 -0.300000
|
||||
v -0.780000 2.400000 -0.300000
|
||||
v -0.780000 2.100000 -0.300000
|
||||
v -0.780000 2.200000 0.000000
|
||||
v -0.780000 2.600000 0.000000
|
||||
v -0.780000 2.700000 -0.300000
|
||||
v 0.780000 1.700000 -0.300000
|
||||
v 0.780000 2.000000 -0.300000
|
||||
v 0.780000 1.900000 0.000000
|
||||
v 0.780000 1.500000 0.000000
|
||||
v 0.780000 1.400000 -0.300000
|
||||
v -0.780000 1.700000 -0.300000
|
||||
v -0.780000 1.400000 -0.300000
|
||||
v -0.780000 1.500000 0.000000
|
||||
v -0.780000 1.900000 0.000000
|
||||
v -0.780000 2.000000 -0.300000
|
||||
v 0.800000 -0.600000 -2.000000
|
||||
v 0.800000 2.900000 -2.000000
|
||||
v -0.800000 -0.600000 -2.000000
|
||||
v -0.800000 2.900000 -2.000000
|
||||
v 0.800000 -0.600000 -0.800000
|
||||
v 0.800000 2.900000 -0.800000
|
||||
v -0.800000 -0.600000 -0.800000
|
||||
v -0.800000 2.900000 -0.800000
|
||||
vt 0.070499 0.643570
|
||||
vt 0.070499 0.998147
|
||||
vt 0.003817 0.998147
|
||||
vt 0.003817 0.643570
|
||||
vt 0.997239 0.998410
|
||||
vt 0.940308 0.998410
|
||||
vt 0.997239 0.647262
|
||||
vt 0.940308 0.647262
|
||||
vt 0.970266 0.522520
|
||||
vt 0.962942 0.572543
|
||||
vt 0.072079 0.572543
|
||||
vt 0.079403 0.522520
|
||||
vt 0.744362 0.446044
|
||||
vt 0.780351 0.385565
|
||||
vt 0.817830 0.446044
|
||||
vt 0.854309 0.385565
|
||||
vt 0.891299 0.446044
|
||||
vt 0.880027 0.325855
|
||||
vt 0.591008 0.325855
|
||||
vt 0.880027 0.000323
|
||||
vt 0.589446 0.324644
|
||||
vt 0.001453 0.324644
|
||||
vt 0.589446 0.001209
|
||||
vt 0.584620 0.002788
|
||||
vt 0.584620 0.324497
|
||||
vt 0.001010 0.324497
|
||||
vt 0.001010 0.002788
|
||||
vt 0.591008 0.000323
|
||||
vt 0.001453 0.001209
|
||||
s off
|
||||
f 2/1 1/2 5/3
|
||||
f 5/3 6/4 2/1
|
||||
f 7/5 3/6 8/7
|
||||
f 4/8 8/7 3/6
|
||||
f 9/9 11/10 12/11
|
||||
f 10/12 9/9 12/11
|
||||
f 13/10 15/9 16/12
|
||||
f 14/11 13/10 16/12
|
||||
f 18/13 19/14 17/15
|
||||
f 19/14 20/16 17/15
|
||||
f 20/16 21/17 17/15
|
||||
f 23/17 24/16 22/15
|
||||
f 24/16 25/14 22/15
|
||||
f 25/14 26/13 22/15
|
||||
f 39/18 37/19 43/20
|
||||
f 37/21 38/22 41/23
|
||||
f 28/13 29/14 27/15
|
||||
f 29/14 30/16 27/15
|
||||
f 30/16 31/17 27/15
|
||||
f 33/17 34/16 32/15
|
||||
f 34/16 35/14 32/15
|
||||
f 35/14 36/13 32/15
|
||||
f 37/24 39/25 40/26
|
||||
f 38/27 37/24 40/26
|
||||
f 37/19 41/28 43/20
|
||||
f 40/18 44/20 42/28
|
||||
f 39/21 43/23 44/29
|
||||
f 38/22 42/29 41/23
|
||||
f 38/19 40/18 42/28
|
||||
f 40/22 39/21 44/29
|
||||
127
Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Ute.obj
Normal file
@@ -0,0 +1,127 @@
|
||||
# Blender v2.69 (sub 0) OBJ File: 'Car002.blend'
|
||||
# www.blender.org
|
||||
v 0.600000 -0.200000 -1.100000
|
||||
v 0.600000 0.200000 -1.100000
|
||||
v -0.600000 -0.200000 -1.100000
|
||||
v -0.600000 0.200000 -1.100000
|
||||
v -0.800000 0.300000 -0.700000
|
||||
v 0.800000 0.300000 -0.700000
|
||||
v -0.800000 2.000000 -0.700000
|
||||
v 0.800000 2.000000 -0.700000
|
||||
v -0.800000 -1.000000 -0.700000
|
||||
v 0.800000 -1.000000 -0.700000
|
||||
v -0.800000 -2.000000 -0.700000
|
||||
v 0.800000 -2.000000 -0.700000
|
||||
v -0.800000 2.000000 -0.300000
|
||||
v 0.800000 2.000000 -0.300000
|
||||
v -0.800000 -2.000000 -0.300000
|
||||
v 0.800000 -2.000000 -0.300000
|
||||
v 0.800000 -2.000000 -0.300000
|
||||
v 0.800000 2.000000 -0.300000
|
||||
v 0.800000 -2.000000 -0.700000
|
||||
v 0.800000 2.000000 -0.700000
|
||||
v -0.800000 -2.000000 -0.700000
|
||||
v -0.800000 2.000000 -0.700000
|
||||
v -0.800000 -2.000000 -0.300000
|
||||
v -0.800000 2.000000 -0.300000
|
||||
v 0.780000 1.200000 -0.300000
|
||||
v 0.780000 1.500000 -0.300000
|
||||
v 0.780000 1.400000 0.000000
|
||||
v 0.780000 1.000000 0.000000
|
||||
v 0.780000 0.900000 -0.300000
|
||||
v 0.780000 -1.100000 -0.300000
|
||||
v 0.780000 -0.800000 -0.300000
|
||||
v 0.780000 -0.900000 0.000000
|
||||
v 0.780000 -1.300000 0.000000
|
||||
v 0.780000 -1.400000 -0.300000
|
||||
v -0.780000 -1.100000 -0.300000
|
||||
v -0.780000 -1.400000 -0.300000
|
||||
v -0.780000 -1.300000 0.000000
|
||||
v -0.780000 -0.900000 0.000000
|
||||
v -0.780000 -0.800000 -0.300000
|
||||
v -0.780000 1.200000 -0.300000
|
||||
v -0.780000 0.900000 -0.300000
|
||||
v -0.780000 1.000000 0.000000
|
||||
v -0.780000 1.400000 0.000000
|
||||
v -0.780000 1.500000 -0.300000
|
||||
vt 0.564792 0.689981
|
||||
vt 0.564792 0.953949
|
||||
vt 0.338554 0.953949
|
||||
vt 0.338554 0.689981
|
||||
vt 0.334296 0.692438
|
||||
vt 0.334296 0.954445
|
||||
vt 0.203294 0.986197
|
||||
vt 0.203294 0.656186
|
||||
vt 0.695616 0.984433
|
||||
vt 0.572654 0.959219
|
||||
vt 0.695616 0.657719
|
||||
vt 0.572795 0.683358
|
||||
vt 0.941945 0.999442
|
||||
vt 0.694306 0.999442
|
||||
vt 0.941945 0.647349
|
||||
vt 0.694306 0.647349
|
||||
vt 0.070499 0.643570
|
||||
vt 0.070499 0.998147
|
||||
vt 0.003817 0.998147
|
||||
vt 0.003817 0.643570
|
||||
vt 0.997239 0.998410
|
||||
vt 0.940308 0.998410
|
||||
vt 0.997239 0.647262
|
||||
vt 0.940308 0.647262
|
||||
vt 0.471796 0.690927
|
||||
vt 0.487691 0.573764
|
||||
vt 0.563274 0.690927
|
||||
vt 0.735343 0.574985
|
||||
vt 0.970266 0.522520
|
||||
vt 0.962942 0.572543
|
||||
vt 0.072079 0.572543
|
||||
vt 0.079403 0.522520
|
||||
vt 0.744362 0.446044
|
||||
vt 0.780351 0.385565
|
||||
vt 0.817830 0.446044
|
||||
vt 0.854309 0.385565
|
||||
vt 0.891299 0.446044
|
||||
vt 0.743883 0.446331
|
||||
vt 0.779872 0.385852
|
||||
vt 0.817351 0.446331
|
||||
vt 0.853830 0.385852
|
||||
vt 0.890820 0.446331
|
||||
vt 0.122341 0.504785
|
||||
vt 0.003867 0.504785
|
||||
vt 0.122341 0.378413
|
||||
vt 0.003867 0.378413
|
||||
s off
|
||||
f 1/1 3/2 4/3
|
||||
f 2/4 1/1 4/3
|
||||
f 2/5 4/6 5/7
|
||||
f 5/7 6/8 2/5
|
||||
f 9/9 3/10 10/11
|
||||
f 3/10 1/12 10/11
|
||||
f 11/13 9/14 12/15
|
||||
f 10/16 12/15 9/14
|
||||
f 8/17 7/18 13/19
|
||||
f 13/19 14/20 8/17
|
||||
f 15/21 11/22 16/23
|
||||
f 12/24 16/23 11/22
|
||||
f 2/25 6/26 1/27
|
||||
f 10/28 1/27 6/26
|
||||
f 4/25 3/27 5/26
|
||||
f 9/28 5/26 3/27
|
||||
f 17/29 19/30 20/31
|
||||
f 18/32 17/29 20/31
|
||||
f 21/30 23/29 24/32
|
||||
f 22/31 21/30 24/32
|
||||
f 26/33 27/34 25/35
|
||||
f 27/34 28/36 25/35
|
||||
f 28/36 29/37 25/35
|
||||
f 31/38 32/39 30/40
|
||||
f 32/39 33/41 30/40
|
||||
f 33/41 34/42 30/40
|
||||
f 36/42 37/41 35/40
|
||||
f 37/41 38/39 35/40
|
||||
f 38/39 39/38 35/40
|
||||
f 41/37 42/36 40/35
|
||||
f 42/36 43/34 40/35
|
||||
f 43/34 44/33 40/35
|
||||
f 5/43 7/44 6/45
|
||||
f 7/44 8/46 6/45
|
||||
121
Videos/CarCrimeCity/Part2/assets/vehicles/CarCrime_Wagon.obj
Normal file
@@ -0,0 +1,121 @@
|
||||
# Blender v2.69 (sub 0) OBJ File: 'Car002.blend'
|
||||
# www.blender.org
|
||||
v 0.600000 -0.200000 -1.100000
|
||||
v 0.600000 1.600000 -1.100000
|
||||
v -0.600000 -0.200000 -1.100000
|
||||
v -0.600000 1.600000 -1.100000
|
||||
v -0.800000 2.000000 -0.700000
|
||||
v 0.800000 2.000000 -0.700000
|
||||
v -0.800000 2.000000 -0.700000
|
||||
v 0.800000 2.000000 -0.700000
|
||||
v -0.800000 -1.000000 -0.700000
|
||||
v 0.800000 -1.000000 -0.700000
|
||||
v -0.800000 -2.000000 -0.700000
|
||||
v 0.800000 -2.000000 -0.700000
|
||||
v -0.800000 2.000000 -0.300000
|
||||
v 0.800000 2.000000 -0.300000
|
||||
v -0.800000 -2.000000 -0.300000
|
||||
v 0.800000 -2.000000 -0.300000
|
||||
v 0.800000 -2.000000 -0.300000
|
||||
v 0.800000 2.000000 -0.300000
|
||||
v 0.800000 -2.000000 -0.700000
|
||||
v 0.800000 2.000000 -0.700000
|
||||
v -0.800000 -2.000000 -0.700000
|
||||
v -0.800000 2.000000 -0.700000
|
||||
v -0.800000 -2.000000 -0.300000
|
||||
v -0.800000 2.000000 -0.300000
|
||||
v 0.780000 1.200000 -0.300000
|
||||
v 0.780000 1.500000 -0.300000
|
||||
v 0.780000 1.400000 0.000000
|
||||
v 0.780000 1.000000 0.000000
|
||||
v 0.780000 0.900000 -0.300000
|
||||
v 0.780000 -1.100000 -0.300000
|
||||
v 0.780000 -0.800000 -0.300000
|
||||
v 0.780000 -0.900000 0.000000
|
||||
v 0.780000 -1.300000 0.000000
|
||||
v 0.780000 -1.400000 -0.300000
|
||||
v -0.780000 -1.100000 -0.300000
|
||||
v -0.780000 -1.400000 -0.300000
|
||||
v -0.780000 -1.300000 0.000000
|
||||
v -0.780000 -0.900000 0.000000
|
||||
v -0.780000 -0.800000 -0.300000
|
||||
v -0.780000 1.200000 -0.300000
|
||||
v -0.780000 0.900000 -0.300000
|
||||
v -0.780000 1.000000 0.000000
|
||||
v -0.780000 1.400000 0.000000
|
||||
v -0.780000 1.500000 -0.300000
|
||||
vt 0.564792 0.689981
|
||||
vt 0.564792 0.953949
|
||||
vt 0.338554 0.953949
|
||||
vt 0.338554 0.689981
|
||||
vt 0.334296 0.692438
|
||||
vt 0.334296 0.954445
|
||||
vt 0.203294 0.986197
|
||||
vt 0.203294 0.656186
|
||||
vt 0.695616 0.984433
|
||||
vt 0.572654 0.959219
|
||||
vt 0.695616 0.657719
|
||||
vt 0.572795 0.683358
|
||||
vt 0.941945 0.999442
|
||||
vt 0.694306 0.999442
|
||||
vt 0.941945 0.647349
|
||||
vt 0.694306 0.647349
|
||||
vt 0.070499 0.643570
|
||||
vt 0.070499 0.998147
|
||||
vt 0.003817 0.998147
|
||||
vt 0.003817 0.643570
|
||||
vt 0.997239 0.998410
|
||||
vt 0.940308 0.998410
|
||||
vt 0.997239 0.647262
|
||||
vt 0.940308 0.647262
|
||||
vt 0.331416 0.690927
|
||||
vt 0.238667 0.577426
|
||||
vt 0.563274 0.690927
|
||||
vt 0.735343 0.574985
|
||||
vt 0.970266 0.522520
|
||||
vt 0.962942 0.572543
|
||||
vt 0.072079 0.572543
|
||||
vt 0.079403 0.522520
|
||||
vt 0.744362 0.446044
|
||||
vt 0.780351 0.385565
|
||||
vt 0.817830 0.446044
|
||||
vt 0.854309 0.385565
|
||||
vt 0.891299 0.446044
|
||||
vt 0.743883 0.446331
|
||||
vt 0.779872 0.385852
|
||||
vt 0.817351 0.446331
|
||||
vt 0.853830 0.385852
|
||||
vt 0.890820 0.446331
|
||||
s off
|
||||
f 1/1 3/2 4/3
|
||||
f 2/4 1/1 4/3
|
||||
f 2/5 4/6 5/7
|
||||
f 5/7 6/8 2/5
|
||||
f 9/9 3/10 10/11
|
||||
f 3/10 1/12 10/11
|
||||
f 11/13 9/14 12/15
|
||||
f 10/16 12/15 9/14
|
||||
f 8/17 7/18 13/19
|
||||
f 13/19 14/20 8/17
|
||||
f 15/21 11/22 16/23
|
||||
f 12/24 16/23 11/22
|
||||
f 2/25 6/26 1/27
|
||||
f 10/28 1/27 6/26
|
||||
f 4/25 3/27 5/26
|
||||
f 9/28 5/26 3/27
|
||||
f 17/29 19/30 20/31
|
||||
f 18/32 17/29 20/31
|
||||
f 21/30 23/29 24/32
|
||||
f 22/31 21/30 24/32
|
||||
f 26/33 27/34 25/35
|
||||
f 27/34 28/36 25/35
|
||||
f 28/36 29/37 25/35
|
||||
f 31/38 32/39 30/40
|
||||
f 32/39 33/41 30/40
|
||||
f 33/41 34/42 30/40
|
||||
f 36/42 37/41 35/40
|
||||
f 37/41 38/39 35/40
|
||||
f 38/39 39/38 35/40
|
||||
f 41/37 42/36 40/35
|
||||
f 42/36 43/34 40/35
|
||||
f 43/34 44/33 40/35
|
||||
BIN
Videos/CarCrimeCity/Part2/assets/vehicles/CarTex_256.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
206
Videos/CarCrimeCity/Part2/cAutomata.cpp
Normal file
@@ -0,0 +1,206 @@
|
||||
#include "cAutomata.h"
|
||||
|
||||
|
||||
cAuto_Node::cAuto_Node()
|
||||
{
|
||||
pos = { 0,0 };
|
||||
}
|
||||
|
||||
cAuto_Node::cAuto_Node(const olc::vf2d &worldpos)
|
||||
{
|
||||
pos = worldpos;
|
||||
}
|
||||
|
||||
olc::vf2d cAuto_Track::GetPostion(float t, cAuto_Node *pStart)
|
||||
{
|
||||
// pStart indicates the node the automata first encounted this track
|
||||
if (node[0] == pStart)
|
||||
{
|
||||
return node[0]->pos + (node[1]->pos - node[0]->pos) * (t / fTrackLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
return node[1]->pos + (node[0]->pos - node[1]->pos) * (t / fTrackLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
cAuto_Body::cAuto_Body()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
cAuto_Body::~cAuto_Body()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void cAuto_Body::UpdateAuto(float fElapsedTime)
|
||||
{
|
||||
// Work out which node is the target destination
|
||||
cAuto_Node *pExitNode = pCurrentTrack->node[0];
|
||||
if (pExitNode == pTrackOriginNode)
|
||||
pExitNode = pCurrentTrack->node[1];
|
||||
|
||||
bool bAutomataCanMove = true;
|
||||
|
||||
float fDistanceToAutoInFront = 1.0f;
|
||||
|
||||
// First check if the vehicle overlaps with the one in front of it
|
||||
|
||||
// Get an iterator for this automata
|
||||
auto itThisAutomata = std::find(pCurrentTrack->listAutos.begin(), pCurrentTrack->listAutos.end(), this);
|
||||
|
||||
// If this automata is at the front of this track segment
|
||||
if (*itThisAutomata == pCurrentTrack->listAutos.front())
|
||||
{
|
||||
// Then check all the following track segments. Take the position of
|
||||
// each vehicle at the back of the track segments auto list
|
||||
for (auto &track : pExitNode->listTracks)
|
||||
{
|
||||
if (track != pCurrentTrack && !track->listAutos.empty())
|
||||
{
|
||||
// Get Auto at back
|
||||
float fDistanceFromTrackStartToAutoRear = track->listAutos.back()->fAutoPos - track->listAutos.back()->fAutoLength;
|
||||
|
||||
if ((*itThisAutomata)->fAutoPos < (pCurrentTrack->fTrackLength + fDistanceFromTrackStartToAutoRear - fAutoLength))
|
||||
{
|
||||
// Move Automata along track, as there is space
|
||||
//bAutomataCanMove = true;
|
||||
fDistanceToAutoInFront = (pCurrentTrack->fTrackLength + fDistanceFromTrackStartToAutoRear - 0.1f) - (*itThisAutomata)->fAutoPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No space, so do not move automata
|
||||
bAutomataCanMove = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Track in front was empty, node is clear to pass through so
|
||||
//bAutomataCanMove = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the automata in front
|
||||
auto itAutomataInFront = itThisAutomata;
|
||||
itAutomataInFront--;
|
||||
|
||||
// If the distance between the front of the automata in front and the fornt of this automata
|
||||
// is greater than the length of the automata in front, then there is space for this automata
|
||||
// to enter
|
||||
if (fabs((*itAutomataInFront)->fAutoPos - (*itThisAutomata)->fAutoPos) > ((*itAutomataInFront)->fAutoLength + 0.1f))
|
||||
{
|
||||
// Move Automata along track
|
||||
//bAutomataCanMove = true;
|
||||
fDistanceToAutoInFront = ((*itAutomataInFront)->fAutoPos - (*itAutomataInFront)->fAutoLength - 0.1f) - (*itThisAutomata)->fAutoPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No space, so do not move automata
|
||||
bAutomataCanMove = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (bAutomataCanMove)
|
||||
{
|
||||
if (fDistanceToAutoInFront > pCurrentTrack->fTrackLength) fDistanceToAutoInFront = pCurrentTrack->fTrackLength;
|
||||
fAutoPos += fElapsedTime * std::max(fDistanceToAutoInFront, 1.0f) * (fAutoLength < 0.1f ? 0.3f : 0.5f);
|
||||
}
|
||||
|
||||
|
||||
if (fAutoPos >= pCurrentTrack->fTrackLength)
|
||||
{
|
||||
// Automata has reached end of current track
|
||||
|
||||
// Check if it can transition beyond node
|
||||
if (!pExitNode->bBlock)
|
||||
{
|
||||
// It can, so reset position along track back to start
|
||||
fAutoPos -= pCurrentTrack->fTrackLength;
|
||||
|
||||
// Choose a track from the node not equal to this one, that has an unblocked exit node
|
||||
|
||||
// For now choose at random
|
||||
cAuto_Track *pNewTrack = nullptr;
|
||||
|
||||
if (pExitNode->listTracks.size() == 2)
|
||||
{
|
||||
// Automata is travelling along straight joined sections, one of the
|
||||
// tracks is the track its just come in on, the other is the exit, so
|
||||
// choose the exit.
|
||||
auto it = pExitNode->listTracks.begin();
|
||||
pNewTrack = (*it);
|
||||
if (pCurrentTrack == pNewTrack)
|
||||
{
|
||||
++it;
|
||||
pNewTrack = (*it);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Automata has reached a junction with several exits
|
||||
while (pNewTrack == nullptr)
|
||||
{
|
||||
int i = rand() % pExitNode->listTracks.size();
|
||||
int j = 0;
|
||||
for (auto it = pExitNode->listTracks.begin(); it != pExitNode->listTracks.end(); ++it)
|
||||
{
|
||||
cAuto_Track* track = (*it);
|
||||
|
||||
// Work out which node is the target destination
|
||||
cAuto_Node *pNewExitNode = track->node[0];
|
||||
if (pNewExitNode == pExitNode)
|
||||
pNewExitNode = track->node[1];
|
||||
|
||||
if (j == i && track != pCurrentTrack && !pNewExitNode->bBlock /*((*it)->cell != pCurrentTrack->cell)*/)
|
||||
{
|
||||
pNewTrack = track;
|
||||
break;
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Change to new track, the origin node of the next
|
||||
// track is the same as the exit node to the current track
|
||||
pTrackOriginNode = pExitNode;
|
||||
|
||||
// Remove the automata from the front of the queue
|
||||
// on the current track
|
||||
pCurrentTrack->listAutos.pop_front();
|
||||
|
||||
// Switch the automatas track link to the new track
|
||||
pCurrentTrack = pNewTrack;
|
||||
|
||||
// Push the automata onto the back of the new track queue
|
||||
pCurrentTrack->listAutos.push_back(this);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// It cant pass the node, so clamp automata at this location
|
||||
fAutoPos = pCurrentTrack->fTrackLength;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Automata is travelling
|
||||
vAutoPos = pCurrentTrack->GetPostion(fAutoPos, pTrackOriginNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
107
Videos/CarCrimeCity/Part2/cAutomata.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Top Down City Based Car Crime Game - Part #2
|
||||
"Colin, I hope you're shooting 600+ wherever you are buddy. RIP." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Instructions:
|
||||
~~~~~~~~~~~~~
|
||||
Scroll with middle mouse wheel, TAB toggle edit mode, R to place road
|
||||
P to place pavement, Q to place building, Arrow keys to drive car
|
||||
|
||||
Relevant Video: https://youtu.be/fIV6P1W-wuo
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
class cAuto_Track;
|
||||
class cAuto_Node;
|
||||
class cAuto_Body;
|
||||
class cCell;
|
||||
|
||||
class cAuto_Node
|
||||
{
|
||||
public:
|
||||
cAuto_Node();
|
||||
cAuto_Node(const olc::vf2d &worldpos);
|
||||
olc::vf2d pos;
|
||||
bool bBlock = false;
|
||||
std::list<cAuto_Track*> listTracks;
|
||||
};
|
||||
|
||||
class cAuto_Track
|
||||
{
|
||||
public:
|
||||
cAuto_Node* node[2]; // Two end nodes
|
||||
cCell* cell; // Pointer to host cell
|
||||
olc::vf2d GetPostion(float t, cAuto_Node *pstart);
|
||||
std::list<cAuto_Body*> listAutos;
|
||||
float fTrackLength = 1.0f;
|
||||
};
|
||||
|
||||
class cAuto_Body
|
||||
{
|
||||
public:
|
||||
cAuto_Body();
|
||||
~cAuto_Body();
|
||||
|
||||
public:
|
||||
void UpdateAuto(float fElapsedTime);
|
||||
|
||||
public:
|
||||
olc::vf2d vAutoPos = { 0.0f, 0.0f };
|
||||
float fAutoPos = 0.0f; // Location of automata along track
|
||||
float fAutoLength = 0.0f; // Physical length of automata
|
||||
cAuto_Track *pCurrentTrack = nullptr;
|
||||
cAuto_Node *pTrackOriginNode = nullptr;
|
||||
|
||||
};
|
||||
709
Videos/CarCrimeCity/Part2/cCarCrimeCity.cpp
Normal file
@@ -0,0 +1,709 @@
|
||||
#include "cCarCrimeCity.h"
|
||||
|
||||
cCarCrimeCity::cCarCrimeCity()
|
||||
{
|
||||
sAppName = "Car Crime City";
|
||||
}
|
||||
|
||||
cCarCrimeCity::~cCarCrimeCity()
|
||||
{
|
||||
}
|
||||
|
||||
bool cCarCrimeCity::OnUserCreate()
|
||||
{
|
||||
// Initialise PGEX 3D
|
||||
olc::GFX3D::ConfigureDisplay();
|
||||
|
||||
// Load fixed system assets, i.e. those need to simply do anything
|
||||
if (!LoadAssets()) return false;
|
||||
|
||||
// Create Default city
|
||||
pCity = new cCityMap(cGameSettings::nDefaultMapWidth, cGameSettings::nDefaultMapHeight, mapAssetTextures, mapAssetMeshes, mapAssetTransform);
|
||||
|
||||
// If a city map file has been specified, then load it
|
||||
if (!cGameSettings::sDefaultCityFile.empty())
|
||||
{
|
||||
if (!pCity->LoadCity(cGameSettings::sDefaultCityFile))
|
||||
{
|
||||
std::cout << "Failed to load '" << cGameSettings::sDefaultCityFile << "'" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cCarCrimeCity::LoadAssets()
|
||||
{
|
||||
// Game Settings should have loaded all the relevant file information
|
||||
// to start loading asset information. Game assets will be stored in
|
||||
// a map structure. Maps can have slightly longer access times, so each
|
||||
// in game object will have facility to extract required resources once
|
||||
// when it is created, meaning no map search during normal use
|
||||
|
||||
// System Meshes
|
||||
// A simple flat unit quad
|
||||
olc::GFX3D::mesh* meshQuad = new olc::GFX3D::mesh();
|
||||
meshQuad->tris =
|
||||
{
|
||||
{ 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
{ 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
};
|
||||
mapAssetMeshes["UnitQuad"] = meshQuad;
|
||||
|
||||
//// The four outer walls of a cell
|
||||
olc::GFX3D::mesh* meshWallsOut = new olc::GFX3D::mesh();
|
||||
meshWallsOut->tris =
|
||||
{
|
||||
// EAST
|
||||
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
{ 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
|
||||
// WEST
|
||||
{ 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
{ 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
|
||||
// TOP
|
||||
{ 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
{ 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.2f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
|
||||
// BOTTOM
|
||||
{ 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
{ 1.0f, 0.0f, 0.2f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::WHITE, olc::WHITE, olc::WHITE },
|
||||
};
|
||||
mapAssetMeshes["WallsOut"] = meshWallsOut;
|
||||
|
||||
|
||||
// System Textures
|
||||
for (auto &asset : cGameSettings::vecAssetTextures)
|
||||
{
|
||||
olc::Sprite *sprAsset = new olc::Sprite();
|
||||
if (sprAsset->LoadFromFile(asset.sFile))
|
||||
{
|
||||
mapAssetTextures[asset.sName] = sprAsset;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Failed to load " << asset.sName << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Break up roads sprite into individual sprites. Why? Its easier to maintain
|
||||
// the roads sprite as a single image, but easier to use if they are all individual.
|
||||
// Breaking it up manually in the image editing software is time consuming so just
|
||||
// do it here
|
||||
int nRoadTexSize = 256; // In pixels in base texture
|
||||
int nRoadTexOffset = 64; // There exists a 64 pixel offset from top left of source image
|
||||
for (int r = 0; r < 12; r++)
|
||||
{
|
||||
olc::Sprite* road = new olc::Sprite(nRoadTexSize, nRoadTexSize);
|
||||
SetDrawTarget(road);
|
||||
DrawPartialSprite(0, 0, mapAssetTextures["AllRoads"], ((r % 3) * nRoadTexSize) + nRoadTexOffset, ((r / 3) * nRoadTexSize) + nRoadTexOffset, nRoadTexSize, nRoadTexSize);
|
||||
switch (r)
|
||||
{
|
||||
case 0: mapAssetTextures["Road_V"] = road; break;
|
||||
case 1: mapAssetTextures["Road_H"] = road; break;
|
||||
case 2: mapAssetTextures["Pavement"] = road; break;
|
||||
case 3: mapAssetTextures["Road_C1"] = road; break;
|
||||
case 4: mapAssetTextures["Road_T1"] = road; break;
|
||||
case 5: mapAssetTextures["Road_C2"] = road; break;
|
||||
case 6: mapAssetTextures["Road_T2"] = road; break;
|
||||
case 7: mapAssetTextures["Road_X"] = road; break;
|
||||
case 8: mapAssetTextures["Road_T3"] = road; break;
|
||||
case 9: mapAssetTextures["Road_C3"] = road; break;
|
||||
case 10: mapAssetTextures["Road_T4"] = road; break;
|
||||
case 11: mapAssetTextures["Road_C4"] = road; break;
|
||||
}
|
||||
}
|
||||
SetDrawTarget(nullptr);
|
||||
|
||||
|
||||
// Load Buildings
|
||||
for (auto &asset : cGameSettings::vecAssetBuildings)
|
||||
{
|
||||
mapAssetMeshes[asset.sDescription] = new olc::GFX3D::mesh();
|
||||
mapAssetMeshes[asset.sDescription]->LoadOBJFile(asset.sModelOBJ);
|
||||
mapAssetTextures[asset.sDescription] = new olc::Sprite(asset.sModelPNG);
|
||||
|
||||
olc::GFX3D::mat4x4 matScale = olc::GFX3D::Math::Mat_MakeScale(asset.fScale[0], asset.fScale[1], asset.fScale[2]);
|
||||
olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation(asset.fTranslate[0], asset.fTranslate[1], asset.fTranslate[2]);
|
||||
olc::GFX3D::mat4x4 matRotateX = olc::GFX3D::Math::Mat_MakeRotationX(asset.fRotate[0]);
|
||||
olc::GFX3D::mat4x4 matRotateY = olc::GFX3D::Math::Mat_MakeRotationY(asset.fRotate[1]);
|
||||
olc::GFX3D::mat4x4 matRotateZ = olc::GFX3D::Math::Mat_MakeRotationZ(asset.fRotate[2]);
|
||||
olc::GFX3D::mat4x4 matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTranslate, matScale);
|
||||
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateX);
|
||||
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateY);
|
||||
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateZ);
|
||||
mapAssetTransform[asset.sDescription] = matTransform;
|
||||
}
|
||||
|
||||
// Load Vehicles
|
||||
for (auto &asset : cGameSettings::vecAssetVehicles)
|
||||
{
|
||||
mapAssetMeshes[asset.sDescription] = new olc::GFX3D::mesh();
|
||||
mapAssetMeshes[asset.sDescription]->LoadOBJFile(asset.sModelOBJ);
|
||||
mapAssetTextures[asset.sDescription] = new olc::Sprite(asset.sModelPNG);
|
||||
|
||||
olc::GFX3D::mat4x4 matScale = olc::GFX3D::Math::Mat_MakeScale(asset.fScale[0], asset.fScale[1], asset.fScale[2]);
|
||||
olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation(asset.fTranslate[0], asset.fTranslate[1], asset.fTranslate[2]);
|
||||
olc::GFX3D::mat4x4 matRotateX = olc::GFX3D::Math::Mat_MakeRotationX(asset.fRotate[0]);
|
||||
olc::GFX3D::mat4x4 matRotateY = olc::GFX3D::Math::Mat_MakeRotationY(asset.fRotate[1]);
|
||||
olc::GFX3D::mat4x4 matRotateZ = olc::GFX3D::Math::Mat_MakeRotationZ(asset.fRotate[2]);
|
||||
olc::GFX3D::mat4x4 matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTranslate, matScale);
|
||||
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateX);
|
||||
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateY);
|
||||
matTransform = olc::GFX3D::Math::Mat_MultiplyMatrix(matTransform, matRotateZ);
|
||||
mapAssetTransform[asset.sDescription] = matTransform;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cCarCrimeCity::SpawnPedestrian(int x, int y)
|
||||
{
|
||||
cCell* cell = pCity->Cell(x, y);
|
||||
|
||||
cAuto_Track *t = ((cCell_Road*)cell)->pSafePedestrianTrack;
|
||||
if (t == nullptr) return;
|
||||
|
||||
cAuto_Body *a = new cAuto_Body();
|
||||
a->fAutoLength = 0.05f;
|
||||
a->pCurrentTrack = t;
|
||||
a->pCurrentTrack->listAutos.push_back(a);
|
||||
a->pTrackOriginNode = t->node[0];
|
||||
a->UpdateAuto(0.0f);
|
||||
listAutomata.push_back(a);
|
||||
}
|
||||
|
||||
void cCarCrimeCity::SpawnVehicle(int x, int y)
|
||||
{
|
||||
cCell* cell = pCity->Cell(x, y);
|
||||
|
||||
cAuto_Track *t = ((cCell_Road*)cell)->pSafeCarTrack;
|
||||
if (t == nullptr) return;
|
||||
|
||||
cAuto_Body *a = new cAuto_Body();
|
||||
a->fAutoLength = 0.2f;
|
||||
a->pCurrentTrack = t;
|
||||
a->pCurrentTrack->listAutos.push_back(a);
|
||||
a->pTrackOriginNode = t->node[0];
|
||||
a->UpdateAuto(0.0f);
|
||||
listAutomata.push_back(a);
|
||||
}
|
||||
|
||||
void cCarCrimeCity::DoEditMode(float fElapsedTime)
|
||||
{
|
||||
// Get cell under mouse cursor
|
||||
cCell* mcell = pCity->Cell(nMouseX, nMouseY);
|
||||
bool bTempCellAdded = false;
|
||||
|
||||
// Left click and drag adds cells
|
||||
if (mcell != nullptr && GetMouse(0).bHeld)
|
||||
setSelectedCells.emplace(nMouseY * pCity->GetWidth() + nMouseX);
|
||||
|
||||
// Right click clears selection
|
||||
if (GetMouse(1).bReleased)
|
||||
setSelectedCells.clear();
|
||||
|
||||
if (setSelectedCells.empty())
|
||||
{
|
||||
// If nothing can be edited validly then just exit
|
||||
if (mcell == nullptr)
|
||||
return;
|
||||
|
||||
// else set is empty, so temporarily add current cell to it
|
||||
setSelectedCells.emplace(nMouseY * pCity->GetWidth() + nMouseX);
|
||||
bTempCellAdded = true;
|
||||
}
|
||||
|
||||
// If the map changes, we will need to update
|
||||
// the automata, and adjacency
|
||||
bool bMapChanged = false;
|
||||
|
||||
// Press "G" to apply grass
|
||||
if (GetKey(olc::Key::G).bPressed)
|
||||
{
|
||||
for (auto &c : setSelectedCells)
|
||||
{
|
||||
int x = c % pCity->GetWidth();
|
||||
int y = c / pCity->GetWidth();
|
||||
cCell* cell = pCity->Replace(x, y, new cCell_Plane(pCity, x, y, PLANE_GRASS));
|
||||
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
|
||||
}
|
||||
|
||||
bMapChanged = true;
|
||||
}
|
||||
|
||||
// Press "P" to apply Pavement
|
||||
if (GetKey(olc::Key::P).bPressed)
|
||||
{
|
||||
for (auto &c : setSelectedCells)
|
||||
{
|
||||
int x = c % pCity->GetWidth();
|
||||
int y = c / pCity->GetWidth();
|
||||
cCell* cell = pCity->Replace(x, y, new cCell_Plane(pCity, x, y, PLANE_ASPHALT));
|
||||
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
|
||||
}
|
||||
|
||||
bMapChanged = true;
|
||||
}
|
||||
|
||||
// Press "W" to apply Water
|
||||
if (GetKey(olc::Key::W).bPressed)
|
||||
{
|
||||
for (auto &c : setSelectedCells)
|
||||
{
|
||||
int x = c % pCity->GetWidth();
|
||||
int y = c / pCity->GetWidth();
|
||||
cCell* cell = pCity->Replace(x, y, new cCell_Water(pCity, x, y));
|
||||
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
|
||||
}
|
||||
|
||||
bMapChanged = true;
|
||||
}
|
||||
|
||||
// Press "R" to apply Roads
|
||||
if (GetKey(olc::Key::Q).bPressed)
|
||||
{
|
||||
for (auto &c : setSelectedCells)
|
||||
{
|
||||
int x = c % pCity->GetWidth();
|
||||
int y = c / pCity->GetWidth();
|
||||
cCell* cell = pCity->Replace(x, y, new cCell_Building("Apartments_1", pCity, x, y));
|
||||
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
|
||||
}
|
||||
|
||||
bMapChanged = true;
|
||||
}
|
||||
|
||||
|
||||
// Press "R" to apply Roads
|
||||
if (GetKey(olc::Key::R).bPressed)
|
||||
{
|
||||
for (auto &c : setSelectedCells)
|
||||
{
|
||||
int x = c % pCity->GetWidth();
|
||||
int y = c / pCity->GetWidth();
|
||||
cCell* cell = pCity->Replace(x, y, new cCell_Road(pCity, x, y));
|
||||
cell->LinkAssets(mapAssetTextures, mapAssetMeshes, mapAssetTransform);
|
||||
}
|
||||
|
||||
bMapChanged = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (GetKey(olc::Key::C).bPressed)
|
||||
{
|
||||
for (auto &c : setSelectedCells)
|
||||
{
|
||||
int x = c % pCity->GetWidth();
|
||||
int y = c / pCity->GetWidth();
|
||||
SpawnVehicle(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (GetKey(olc::Key::V).bPressed)
|
||||
{
|
||||
for (auto &c : setSelectedCells)
|
||||
{
|
||||
int x = c % pCity->GetWidth();
|
||||
int y = c / pCity->GetWidth();
|
||||
SpawnPedestrian(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
if (bMapChanged)
|
||||
{
|
||||
// The navigation nodes may have tracks attached to them, so get rid of them
|
||||
// all. Below we will reconstruct all tracks because city has changed
|
||||
pCity->RemoveAllTracks();
|
||||
|
||||
for (auto &a : listAutomata) delete a;
|
||||
listAutomata.clear();
|
||||
|
||||
for (int x = 0; x < pCity->GetWidth(); x++)
|
||||
{
|
||||
for (int y = 0; y < pCity->GetHeight(); y++)
|
||||
{
|
||||
cCell *c = pCity->Cell(x, y);
|
||||
|
||||
// Update adjacency information, i.e. those cells whose
|
||||
// state changes based on neighbouring cells
|
||||
c->CalculateAdjacency();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// To facilitate "edit under cursor" we added a temporary cell
|
||||
// which needs to be removed now
|
||||
if (bTempCellAdded)
|
||||
setSelectedCells.clear();
|
||||
}
|
||||
|
||||
olc::vf2d cCarCrimeCity::GetMouseOnGround(const olc::vf2d &vMouseScreen)
|
||||
{
|
||||
olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir);
|
||||
olc::GFX3D::mat4x4 matProj = olc::GFX3D::Math::Mat_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f);
|
||||
olc::GFX3D::mat4x4 matView = olc::GFX3D::Math::Mat_PointAt(vEye, vLookTarget, vUp);
|
||||
olc::GFX3D::vec3d vecMouseDir = {
|
||||
2.0f * ((vMouseScreen.x / (float)ScreenWidth()) - 0.5f) / matProj.m[0][0],
|
||||
2.0f * ((vMouseScreen.y / (float)ScreenHeight()) - 0.5f) / matProj.m[1][1],
|
||||
1.0f,
|
||||
0.0f };
|
||||
|
||||
olc::GFX3D::vec3d vecMouseOrigin = { 0.0f, 0.0f, 0.0f };
|
||||
vecMouseOrigin = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseOrigin);
|
||||
vecMouseDir = olc::GFX3D::Math::Mat_MultiplyVector(matView, vecMouseDir);
|
||||
vecMouseDir = olc::GFX3D::Math::Vec_Mul(vecMouseDir, 1000.0f);
|
||||
vecMouseDir = olc::GFX3D::Math::Vec_Add(vecMouseOrigin, vecMouseDir);
|
||||
|
||||
// Perform line/plane intersection to determine mouse position in world space
|
||||
olc::GFX3D::vec3d plane_p = { 0.0f, 0.0f, 0.0f };
|
||||
olc::GFX3D::vec3d plane_n = { 0.0f, 0.0f, 1.0f };
|
||||
float t = 0.0f;
|
||||
olc::GFX3D::vec3d mouse3d = olc::GFX3D::Math::Vec_IntersectPlane(plane_p, plane_n, vecMouseOrigin, vecMouseDir, t);
|
||||
return { mouse3d.x, mouse3d.y };
|
||||
}
|
||||
|
||||
bool cCarCrimeCity::OnUserUpdate(float fElapsedTime)
|
||||
{
|
||||
fGlobalTime += fElapsedTime;
|
||||
|
||||
if (GetKey(olc::Key::TAB).bReleased) bEditMode = !bEditMode;
|
||||
|
||||
if (bEditMode) // Use mouse to pan and zoom, and place objects
|
||||
{
|
||||
vEye = vCamera;
|
||||
olc::vf2d vMouseScreen = { (float)GetMouseX(), (float)GetMouseY() };
|
||||
olc::vf2d vMouseOnGroundBeforeZoom = GetMouseOnGround(vMouseScreen);
|
||||
|
||||
vOffset = { 0,0 };
|
||||
|
||||
if (IsFocused())
|
||||
{
|
||||
if (GetMouse(2).bPressed) { vStartPan = vMouseOnGroundBeforeZoom; }
|
||||
if (GetMouse(2).bHeld) { vOffset = (vStartPan - vMouseOnGroundBeforeZoom); };
|
||||
|
||||
if (GetMouseWheel() > 0)
|
||||
{
|
||||
vCamera.z *= 0.5f;
|
||||
}
|
||||
|
||||
if (GetMouseWheel() < 0)
|
||||
{
|
||||
vCamera.z *= 1.5f;
|
||||
}
|
||||
}
|
||||
|
||||
vEye = vCamera;
|
||||
olc::vf2d vMouseOnGroundAfterZoom = GetMouseOnGround(vMouseScreen);
|
||||
vOffset += (vMouseOnGroundBeforeZoom - vMouseOnGroundAfterZoom);
|
||||
vCamera.x += vOffset.x;
|
||||
vCamera.y += vOffset.y;
|
||||
vEye = vCamera;
|
||||
|
||||
// Get Integer versions of mouse coords in world space
|
||||
nMouseX = (int)vMouseOnGroundAfterZoom.x;
|
||||
nMouseY = (int)vMouseOnGroundAfterZoom.y;
|
||||
|
||||
DoEditMode(fElapsedTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not in edit mode, so camera follows player
|
||||
if (GetKey(olc::Key::LEFT).bHeld) fAngle += -2.5f * fElapsedTime;
|
||||
if (GetKey(olc::Key::RIGHT).bHeld) fAngle += 2.5f * fElapsedTime;
|
||||
if (GetKey(olc::Key::UP).bHeld)
|
||||
{
|
||||
carvel = { cos(fAngle), sin(fAngle) };
|
||||
carpos += carvel * 2.0f * fElapsedTime;
|
||||
}
|
||||
|
||||
vCamera.x = carpos.x;
|
||||
vCamera.y = carpos.y;
|
||||
vEye = vCamera;
|
||||
}
|
||||
|
||||
/*fAngle = 0.0f;
|
||||
if (GetKey(olc::Key::LEFT).bHeld) fAngle = -0.8f;
|
||||
if (GetKey(olc::Key::RIGHT).bHeld) fAngle = 0.8f;*/
|
||||
|
||||
|
||||
//car.UpdateDrive(fElapsedTime, 1.0f, GetKey(olc::Key::UP).bHeld, GetKey(olc::Key::SPACE).bHeld, GetKey(olc::Key::DOWN).bHeld, fAngle);
|
||||
|
||||
|
||||
//if (car.bSkidding && fmod(fGlobalTime, 0.05f) < 0.01f)
|
||||
//{
|
||||
// listDecalSmoke.push_front({ 0.1f, {car.vPosRear.x, car.vPosRear.y, -0.03f} });
|
||||
//}
|
||||
|
||||
|
||||
//// Update Decals
|
||||
//for (auto &d : listDecalSmoke)
|
||||
//{
|
||||
// d.fLifetime += fElapsedTime;
|
||||
//}
|
||||
|
||||
//listDecalSmoke.remove_if([](const sSmokeDecal &d) {return d.fLifetime > 2.0f; });
|
||||
|
||||
//if (!bEditMode)
|
||||
//{
|
||||
// vCamera.x = car.GetOrigin().x;
|
||||
// vCamera.y = car.GetOrigin().y;
|
||||
//}
|
||||
|
||||
|
||||
//float fTargetHeight = -1.0f;
|
||||
//int nCarX = vCamera.x;
|
||||
//int nCarY = vCamera.y;
|
||||
|
||||
std::vector<cGameObjectQuad> vecNeighbours;
|
||||
|
||||
//// Check surrounding cells height
|
||||
//for (int x = nCarX - 1; x < nCarX + 2; x++)
|
||||
// for (int y = nCarY - 1; y < nCarY + 2; y++)
|
||||
// {
|
||||
// if (pCity->Cell(x,y) && pCity->Cell(x, y)->bBuilding)
|
||||
// {
|
||||
// cGameObjectQuad ob(1.0f, 1.0f);
|
||||
// ob.pos = { (float)x + 0.5f, (float)y + 0.5f, 0.0f, 1.0f };
|
||||
// ob.TransformModelToWorld();
|
||||
// vecNeighbours.push_back(ob);
|
||||
// fTargetHeight = -2.0f;
|
||||
// }
|
||||
// }
|
||||
|
||||
//goCar->pos.x = car.GetOrigin().x;
|
||||
//goCar->pos.y = car.GetOrigin().y;
|
||||
//goCar->fAngle = car.GetRotation();
|
||||
//goCar->TransformModelToWorld();
|
||||
|
||||
//for (auto &ob : vecNeighbours)
|
||||
//{
|
||||
// if (goCar->StaticCollisionWith(ob, true))
|
||||
// {
|
||||
// goCar->TransformModelToWorld();
|
||||
// car.vPosRear.x += goCar->pos.x - car.GetOrigin().x;
|
||||
// car.vPosRear.y += goCar->pos.y - car.GetOrigin().y;
|
||||
// car.vPosFront.x += goCar->pos.x - car.GetOrigin().x;
|
||||
// car.vPosFront.y += goCar->pos.y - car.GetOrigin().y;
|
||||
// car.fSpeed = 0.0f;
|
||||
// }
|
||||
//}
|
||||
|
||||
//if(!bEditMode)
|
||||
// vCamera.z += (fTargetHeight - vCamera.z) * 10.0f * fElapsedTime;
|
||||
|
||||
|
||||
//car.UpdateTow(fElapsedTime, { mouse3d.x, mouse3d.y });
|
||||
|
||||
|
||||
|
||||
//for (int v = 1; v<vecTraffic.size(); v++)
|
||||
//{
|
||||
// //vecTraffic[v].UpdateTow(fElapsedTime * 10.0f, vecTraffic[v - 1].vPosRear);
|
||||
//}
|
||||
|
||||
// Calculate Visible ground plane dimensions
|
||||
viewWorldTopLeft = GetMouseOnGround(olc::vf2d( 0.0f, 0.0f ));
|
||||
viewWorldBottomRight = GetMouseOnGround(olc::vf2d((float)ScreenWidth(), (float)ScreenHeight()));
|
||||
|
||||
// Calculate visible world extents
|
||||
int nStartX = std::max(0, (int)viewWorldTopLeft.x - 1);
|
||||
int nEndX = std::min(pCity->GetWidth(), (int)viewWorldBottomRight.x + 1);
|
||||
int nStartY = std::max(0, (int)viewWorldTopLeft.y - 1);
|
||||
int nEndY = std::min(pCity->GetHeight(), (int)viewWorldBottomRight.y + 1);
|
||||
|
||||
// Only update automata for cells near player
|
||||
int nAutomStartX = std::max(0, (int)viewWorldTopLeft.x - 3);
|
||||
int nAutomEndX = std::min(pCity->GetWidth(), (int)viewWorldBottomRight.x + 3);
|
||||
int nAutomStartY = std::max(0, (int)viewWorldTopLeft.y - 3);
|
||||
int nAutomEndY = std::min(pCity->GetHeight(), (int)viewWorldBottomRight.y + 3);
|
||||
|
||||
int nLocalStartX = std::max(0, (int)vCamera.x - 3);
|
||||
int nLocalEndX = std::min(pCity->GetWidth(), (int)vCamera.x + 3);
|
||||
int nLocalStartY = std::max(0, (int)vCamera.y - 3);
|
||||
int nLocalEndY = std::min(pCity->GetHeight(), (int)vCamera.y + 3);
|
||||
|
||||
|
||||
// Update Cells
|
||||
for (int x = nStartX; x < nEndX; x++)
|
||||
{
|
||||
for (int y = nStartY; y < nEndY; y++)
|
||||
{
|
||||
pCity->Cell(x, y)->Update(fElapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
// Update Automata
|
||||
for (auto &a : listAutomata)
|
||||
{
|
||||
a->UpdateAuto(fElapsedTime);
|
||||
|
||||
// If automata is too far from camera, remove it
|
||||
if ((a->vAutoPos - olc::vf2d(vCamera.x, vCamera.y)).mag() > 5.0f)
|
||||
{
|
||||
// Despawn automata
|
||||
|
||||
// 1) Disconnect it from track
|
||||
a->pCurrentTrack->listAutos.remove(a);
|
||||
|
||||
// 2) Erase it from memory
|
||||
delete a; a = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove dead automata, their pointer has been set to nullptr in the list
|
||||
listAutomata.remove(nullptr);
|
||||
|
||||
// Maintain a certain level of automata in vicinty of player
|
||||
if (listAutomata.size() < 20)
|
||||
{
|
||||
bool bSpawnOK = false;
|
||||
int nSpawnAttempt = 20;
|
||||
while (!bSpawnOK && nSpawnAttempt > 0)
|
||||
{
|
||||
// Find random cell on edge of vicinty, which is out of view of the player
|
||||
float fRandomAngle = ((float)rand() / (float)RAND_MAX) * 2.0f * 3.14159f;
|
||||
int nRandomCellX = vCamera.x + cos(fRandomAngle) * 3.0f;
|
||||
int nRandomCellY = vCamera.y + sin(fRandomAngle) * 3.0f;
|
||||
|
||||
nSpawnAttempt--;
|
||||
|
||||
if (pCity->Cell(nRandomCellX, nRandomCellY) && pCity->Cell(nRandomCellX, nRandomCellY)->nCellType == CELL_ROAD)
|
||||
{
|
||||
bSpawnOK = true;
|
||||
|
||||
// Add random automata
|
||||
if (rand() % 100 < 50)
|
||||
{
|
||||
// Spawn Pedestrian
|
||||
SpawnPedestrian(nRandomCellX, nRandomCellY);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Spawn Vehicle
|
||||
SpawnVehicle(nRandomCellX, nRandomCellY);
|
||||
// TODO: Get % chance of vehicle spawn from lua script
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Render Scene
|
||||
Clear(olc::BLUE);
|
||||
olc::GFX3D::ClearDepth();
|
||||
|
||||
// Create rendering pipeline
|
||||
olc::GFX3D::PipeLine pipe;
|
||||
pipe.SetProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.1f, 1000.0f, 0.0f, 0.0f, (float)ScreenWidth(), (float)ScreenHeight());
|
||||
olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir);
|
||||
pipe.SetCamera(vEye, vLookTarget, vUp);
|
||||
|
||||
|
||||
// Add global illumination vector (sunlight)
|
||||
olc::GFX3D::vec3d lightdir = { 1.0f, 1.0f, -1.0f };
|
||||
pipe.SetLightSource(0, olc::GFX3D::LIGHT_AMBIENT, olc::Pixel(100,100,100), { 0,0,0 }, lightdir);
|
||||
pipe.SetLightSource(1, olc::GFX3D::LIGHT_DIRECTIONAL, olc::WHITE, { 0,0,0 }, lightdir);
|
||||
|
||||
|
||||
// RENDER CELL CONTENTS
|
||||
|
||||
// Render Base Objects (those without alpha components)
|
||||
for (int x = nStartX; x < nEndX; x++)
|
||||
{
|
||||
//omp_set_dynamic(0);
|
||||
//omp_set_num_threads(4);
|
||||
//#pragma omp parallel for
|
||||
for (int y = nStartY; y < nEndY; y++)
|
||||
{
|
||||
pCity->Cell(x, y)->DrawBase(this, pipe);
|
||||
}
|
||||
//#pragma omp barrier
|
||||
}
|
||||
|
||||
// Render Upper Objects (those with alpha components)
|
||||
for (int x = nStartX; x < nEndX; x++)
|
||||
{
|
||||
for (int y = nStartY; y < nEndY; y++)
|
||||
{
|
||||
pCity->Cell(x, y)->DrawAlpha(this, pipe);
|
||||
}
|
||||
}
|
||||
|
||||
if (bEditMode)
|
||||
{
|
||||
// Render additional per cell debug information
|
||||
for (int x = nStartX; x < nEndX; x++)
|
||||
{
|
||||
for (int y = nStartY; y < nEndY; y++)
|
||||
{
|
||||
pCity->Cell(x, y)->DrawDebug(this, pipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bEditMode)
|
||||
{
|
||||
// Draw Selections
|
||||
for (auto &c : setSelectedCells)
|
||||
{
|
||||
int x = c % pCity->GetWidth();
|
||||
int y = c / pCity->GetWidth();
|
||||
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)x, (float)y, 0.01f);
|
||||
pipe.SetTransform(matWorld);
|
||||
pipe.Render(mapAssetMeshes["UnitQuad"]->tris, olc::GFX3D::RENDER_WIRE);
|
||||
}
|
||||
}
|
||||
|
||||
// RENDER AUTOMATA
|
||||
|
||||
std::string test[] = { "Sedan", "SUV", "TruckCab", "TruckTrailer", "UTE", "Wagon" };
|
||||
int i = 0;
|
||||
for (auto &a : listAutomata)
|
||||
{
|
||||
olc::GFX3D::vec3d v = { a->vAutoPos.x, a->vAutoPos.y, 0.0f };
|
||||
|
||||
/*olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation(a->vAutoPos.x, a->vAutoPos.y, 0.01f);
|
||||
matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(mapAssetTransform[test[i]], matWorld);
|
||||
pipe.SetTransform(matWorld);
|
||||
pipe.SetTexture(mapAssetTextures[test[i]]);
|
||||
pipe.Render(mapAssetMeshes[test[i]]->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_LIGHTS);
|
||||
i++;
|
||||
i = i % 6;*/
|
||||
|
||||
pipe.RenderCircleXZ(v, a->fAutoLength < 0.1f ? 0.05f : 0.07f, a->fAutoLength < 0.1f ? olc::MAGENTA : olc::YELLOW);
|
||||
}
|
||||
|
||||
|
||||
// Draw Player Vehicle
|
||||
{
|
||||
olc::GFX3D::mat4x4 matRotateZ = olc::GFX3D::Math::Mat_MakeRotationZ(fAngle);
|
||||
olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation(carpos.x, carpos.y, 0.01f);
|
||||
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(mapAssetTransform["Sedan"], matRotateZ);
|
||||
matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(matWorld, matTranslate);
|
||||
pipe.SetTransform(matWorld);
|
||||
pipe.SetTexture(mapAssetTextures["Sedan"]);
|
||||
pipe.Render(mapAssetMeshes[test[i]]->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_LIGHTS);
|
||||
}
|
||||
|
||||
DrawString(10, 10, "Automata: " + std::to_string(listAutomata.size()), olc::WHITE);
|
||||
|
||||
|
||||
if (GetKey(olc::Key::ESCAPE).bPressed)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cCarCrimeCity::OnUserDestroy()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
289
Videos/CarCrimeCity/Part2/cCarCrimeCity.h
Normal file
@@ -0,0 +1,289 @@
|
||||
/*
|
||||
Top Down City Based Car Crime Game - Part #2
|
||||
"Colin, I hope you're shooting 600+ wherever you are buddy. RIP." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Instructions:
|
||||
~~~~~~~~~~~~~
|
||||
Scroll with middle mouse wheel, TAB toggle edit mode, R to place road
|
||||
P to place pavement, Q to place building, Arrow keys to drive car
|
||||
|
||||
Relevant Video: https://youtu.be/fIV6P1W-wuo
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "olcPixelGameEngine.h"
|
||||
#include "olcPGEX_Graphics3D.h"
|
||||
|
||||
#include "cGameSettings.h"
|
||||
#include "cCityMap.h"
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
struct sSmokeDecal
|
||||
{
|
||||
float fLifetime = 0.1f;
|
||||
olc::GFX3D::vec3d pos;
|
||||
};
|
||||
|
||||
class cCarCrimeCity : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
cCarCrimeCity();
|
||||
~cCarCrimeCity();
|
||||
|
||||
private:
|
||||
bool OnUserCreate() override;
|
||||
bool OnUserUpdate(float fElapsedTime) override;
|
||||
bool OnUserDestroy() override;
|
||||
|
||||
private:
|
||||
|
||||
class cGameObjectQuad
|
||||
{
|
||||
public:
|
||||
cGameObjectQuad(float w, float h)
|
||||
{
|
||||
fWidth = w;
|
||||
fHeight = h;
|
||||
fAngle = 0.0f;
|
||||
|
||||
// Construct Model Quad Geometry
|
||||
vecPointsModel = { {-fWidth / 2.0f, -fHeight / 2.0f, -0.01f, 1.0f},
|
||||
{-fWidth / 2.0f, +fHeight / 2.0f, -0.01f, 1.0f},
|
||||
{+fWidth / 2.0f, +fHeight / 2.0f, -0.01f, 1.0f},
|
||||
{+fWidth / 2.0f, -fHeight / 2.0f, -0.01f, 1.0f} };
|
||||
|
||||
vecPointsWorld.resize(vecPointsModel.size());
|
||||
TransformModelToWorld();
|
||||
}
|
||||
|
||||
void TransformModelToWorld()
|
||||
{
|
||||
for (size_t i = 0; i < vecPointsModel.size(); ++i)
|
||||
{
|
||||
vecPointsWorld[i] = {
|
||||
(vecPointsModel[i].x * cosf(fAngle)) - (vecPointsModel[i].y * sinf(fAngle)) + pos.x,
|
||||
(vecPointsModel[i].x * sinf(fAngle)) + (vecPointsModel[i].y * cosf(fAngle)) + pos.y,
|
||||
vecPointsModel[i].z,
|
||||
vecPointsModel[i].w
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<olc::GFX3D::triangle> GetTriangles()
|
||||
{
|
||||
// Return triangles based upon this quad
|
||||
return
|
||||
{
|
||||
{vecPointsWorld[0], vecPointsWorld[1], vecPointsWorld[2], 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::RED},
|
||||
{vecPointsWorld[0], vecPointsWorld[2], vecPointsWorld[3], 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::RED},
|
||||
};
|
||||
}
|
||||
|
||||
// Use rectangle edge intersections.
|
||||
bool StaticCollisionWith(cGameObjectQuad &r2, bool bResolveStatic = false)
|
||||
{
|
||||
struct vec2d { float x; float y; };
|
||||
|
||||
bool bCollision = false;
|
||||
|
||||
// Check diagonals of R1 against edges of R2
|
||||
for (size_t p = 0; p < vecPointsWorld.size(); p++)
|
||||
{
|
||||
vec2d line_r1s = { pos.x, pos.y };
|
||||
vec2d line_r1e = { vecPointsWorld[p].x, vecPointsWorld[p].y };
|
||||
|
||||
vec2d displacement = { 0,0 };
|
||||
|
||||
for (size_t q = 0; q < r2.vecPointsWorld.size(); q++)
|
||||
{
|
||||
vec2d line_r2s = { r2.vecPointsWorld[q].x, r2.vecPointsWorld[q].y };
|
||||
vec2d line_r2e = { r2.vecPointsWorld[(q + 1) % r2.vecPointsWorld.size()].x, r2.vecPointsWorld[(q + 1) % r2.vecPointsWorld.size()].y };
|
||||
|
||||
// Standard "off the shelf" line segment intersection
|
||||
float h = (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r1e.y) - (line_r1s.x - line_r1e.x) * (line_r2e.y - line_r2s.y);
|
||||
float t1 = ((line_r2s.y - line_r2e.y) * (line_r1s.x - line_r2s.x) + (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r2s.y)) / h;
|
||||
float t2 = ((line_r1s.y - line_r1e.y) * (line_r1s.x - line_r2s.x) + (line_r1e.x - line_r1s.x) * (line_r1s.y - line_r2s.y)) / h;
|
||||
|
||||
if (t1 >= 0.0f && t1 <= 1.0f && t2 >= 0.0f && t2 <= 1.0f)
|
||||
{
|
||||
if (bResolveStatic)
|
||||
{
|
||||
displacement.x += (1.0f - t1) * (line_r1e.x - line_r1s.x);
|
||||
displacement.y += (1.0f - t1) * (line_r1e.y - line_r1s.y);
|
||||
bCollision = true;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pos.x -= displacement.x;
|
||||
pos.y -= displacement.y;
|
||||
}
|
||||
|
||||
// Check diagonals of R2 against edges of R1
|
||||
for (size_t p = 0; p < r2.vecPointsWorld.size(); p++)
|
||||
{
|
||||
vec2d line_r1s = { r2.pos.x, r2.pos.y };
|
||||
vec2d line_r1e = { r2.vecPointsWorld[p].x, r2.vecPointsWorld[p].y };
|
||||
|
||||
vec2d displacement = { 0,0 };
|
||||
|
||||
for (size_t q = 0; q < vecPointsWorld.size(); q++)
|
||||
{
|
||||
vec2d line_r2s = { vecPointsWorld[q].x, vecPointsWorld[q].y };
|
||||
vec2d line_r2e = { vecPointsWorld[(q + 1) % vecPointsWorld.size()].x, vecPointsWorld[(q + 1) % vecPointsWorld.size()].y };
|
||||
|
||||
// Standard "off the shelf" line segment intersection
|
||||
float h = (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r1e.y) - (line_r1s.x - line_r1e.x) * (line_r2e.y - line_r2s.y);
|
||||
float t1 = ((line_r2s.y - line_r2e.y) * (line_r1s.x - line_r2s.x) + (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r2s.y)) / h;
|
||||
float t2 = ((line_r1s.y - line_r1e.y) * (line_r1s.x - line_r2s.x) + (line_r1e.x - line_r1s.x) * (line_r1s.y - line_r2s.y)) / h;
|
||||
|
||||
if (t1 >= 0.0f && t1 <= 1.0f && t2 >= 0.0f && t2 <= 1.0f)
|
||||
{
|
||||
if (bResolveStatic)
|
||||
{
|
||||
displacement.x += (1.0f - t1) * (line_r1e.x - line_r1s.x);
|
||||
displacement.y += (1.0f - t1) * (line_r1e.y - line_r1s.y);
|
||||
bCollision = true;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pos.x += displacement.x;
|
||||
pos.y += displacement.y;
|
||||
}
|
||||
|
||||
return bCollision;
|
||||
}
|
||||
|
||||
std::vector<olc::GFX3D::triangle> meshTris;
|
||||
std::vector<olc::GFX3D::vec3d> vecPointsModel;
|
||||
std::vector<olc::GFX3D::vec3d> vecPointsWorld;
|
||||
olc::GFX3D::vec3d pos;
|
||||
|
||||
float fWidth;
|
||||
float fHeight;
|
||||
float fOriginX;
|
||||
float fOriginY;
|
||||
float fAngle;
|
||||
};
|
||||
|
||||
bool LoadAssets();
|
||||
|
||||
std::map<std::string, olc::Sprite*> mapAssetTextures;
|
||||
std::map<std::string, olc::GFX3D::mesh*> mapAssetMeshes;
|
||||
std::map<std::string, olc::GFX3D::mat4x4> mapAssetTransform;
|
||||
|
||||
// Camera variables
|
||||
olc::GFX3D::vec3d vCamera = { 0.0f, 0.0f, -3.0f };
|
||||
olc::GFX3D::vec3d vUp = { 0.0f, 1.0f, 0.0f };
|
||||
olc::GFX3D::vec3d vEye = { 0.0f, 0.0f, -3.0f };
|
||||
olc::GFX3D::vec3d vLookDir = { 0.0f, 0.0f, 1.0f };
|
||||
|
||||
// Ray Casting Parameters
|
||||
olc::vf2d viewWorldTopLeft;
|
||||
olc::vf2d viewWorldBottomRight;
|
||||
|
||||
// Cloud movement variables
|
||||
float fCloudOffsetX = 0.0f;
|
||||
float fCloudOffsetY = 0.0f;
|
||||
|
||||
// Mouse Control
|
||||
olc::vf2d vOffset = { 0.0f, 0.0f };
|
||||
olc::vf2d vStartPan = { 0.0f, 0.0f };
|
||||
olc::vf2d vMouseOnGround = { 0.0f, 0.0f };
|
||||
float fScale = 1.0f;
|
||||
|
||||
olc::vf2d GetMouseOnGround(const olc::vf2d &vMouseScreen);
|
||||
|
||||
//cVehicle car;
|
||||
olc::vf2d carvel;
|
||||
olc::vf2d carpos;
|
||||
float fSpeed = 0.0f;
|
||||
float fAngle = 0.0f;
|
||||
|
||||
std::list<cAuto_Body*> listAutomata; // Holds all automata, note its a pointer because we use polymorphism
|
||||
|
||||
void SpawnPedestrian(int x, int y);
|
||||
void SpawnVehicle(int x, int y);
|
||||
|
||||
//cGameObjectQuad *goCar = nullptr;
|
||||
//cGameObjectQuad *goObstacle = nullptr;
|
||||
|
||||
//std::vector<cGameObjectQuad> vecObstacles;
|
||||
|
||||
cCityMap *pCity = nullptr;
|
||||
|
||||
float fGlobalTime = 0.0f;
|
||||
|
||||
// Editing Utilities
|
||||
bool bEditMode = true;
|
||||
int nMouseX = 0;
|
||||
int nMouseY = 0;
|
||||
|
||||
struct sCellLoc { int x, y; };
|
||||
std::unordered_set<int> setSelectedCells;
|
||||
|
||||
//std::list<sSmokeDecal> listDecalSmoke;
|
||||
|
||||
//int nTrafficState = 0;
|
||||
|
||||
void DoEditMode(float fElapsedTime);
|
||||
};
|
||||
|
||||
121
Videos/CarCrimeCity/Part2/cCell.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
#include "cCell.h"
|
||||
|
||||
#include "cCityMap.h"
|
||||
#include "olcPixelGameEngine.h"
|
||||
#include <map>
|
||||
|
||||
cCell::cCell()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
cCell::~cCell()
|
||||
{
|
||||
// Cells own a list of automata navigation tracks
|
||||
// but this will be destroyed when the cell is deleted
|
||||
}
|
||||
|
||||
cCell::cCell(cCityMap* map, int x, int y)
|
||||
{
|
||||
pMap = map;
|
||||
nWorldX = x;
|
||||
nWorldY = y;
|
||||
nCellType = CELL_BLANK;
|
||||
|
||||
// Connect internal nodes
|
||||
for (int i = 0; i < 49; i++)
|
||||
pNaviNodes[i] = pMap->GetAutoNodeBase(x, y) + i;
|
||||
|
||||
// Link cell into maps node pool
|
||||
if (y > 0)
|
||||
{
|
||||
for (int i = 0; i < 7; i++)
|
||||
pNaviNodes[i] = pMap->GetAutoNodeBase(x, y - 1) + 42 + i;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 7; i++)
|
||||
pNaviNodes[i] = nullptr;
|
||||
}
|
||||
|
||||
if (x > 0)
|
||||
{
|
||||
// Link West side
|
||||
for (int i = 0; i < 7; i++)
|
||||
pNaviNodes[i * 7] = pMap->GetAutoNodeBase(x - 1, y) + 6 + i * 7;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 7; i++)
|
||||
pNaviNodes[i * 7] = nullptr;
|
||||
}
|
||||
|
||||
// South Side
|
||||
if (y < pMap->GetHeight() - 1)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 7; i++)
|
||||
pNaviNodes[42 + i] = nullptr;
|
||||
}
|
||||
|
||||
// East Side
|
||||
if (x < pMap->GetWidth() - 1)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 7; i++)
|
||||
pNaviNodes[6 + i * 7] = nullptr;
|
||||
}
|
||||
|
||||
// Unused Nodes
|
||||
pNaviNodes[9] = nullptr;
|
||||
pNaviNodes[11] = nullptr;
|
||||
pNaviNodes[15] = nullptr;
|
||||
pNaviNodes[19] = nullptr;
|
||||
pNaviNodes[29] = nullptr;
|
||||
pNaviNodes[33] = nullptr;
|
||||
pNaviNodes[37] = nullptr;
|
||||
pNaviNodes[39] = nullptr;
|
||||
pNaviNodes[0] = nullptr;
|
||||
pNaviNodes[6] = nullptr;
|
||||
pNaviNodes[42] = nullptr;
|
||||
pNaviNodes[48] = nullptr;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool cCell::LinkAssets(std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell::Update(float fElapsedTime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell::DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell::DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell::DrawDebug(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe)
|
||||
{
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void cCell::CalculateAdjacency()
|
||||
{
|
||||
|
||||
}
|
||||
60
Videos/CarCrimeCity/Part2/cCell.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "olcPixelGameEngine.h"
|
||||
#include "olcPGEX_Graphics3D.h"
|
||||
|
||||
#include "cAutomata.h"
|
||||
|
||||
|
||||
class cCityMap;
|
||||
|
||||
enum CellType
|
||||
{
|
||||
CELL_BLANK,
|
||||
CELL_GRASS,
|
||||
CELL_CONCRETE,
|
||||
CELL_WATER,
|
||||
CELL_BUILDING,
|
||||
CELL_ROAD,
|
||||
CELL_PAVEMENT,
|
||||
};
|
||||
|
||||
class cCell
|
||||
{
|
||||
public:
|
||||
cCell();
|
||||
cCell(cCityMap* map, int x, int y);
|
||||
~cCell();
|
||||
|
||||
protected:
|
||||
cCityMap* pMap = nullptr;
|
||||
|
||||
public:
|
||||
int nWorldX = 0;
|
||||
int nWorldY = 0;
|
||||
bool bSolid = false;
|
||||
CellType nCellType = CELL_BLANK;
|
||||
|
||||
// This cell may actuall be occupied by a multi-cell body
|
||||
// so this pointer points to the host cell that contains
|
||||
// that body
|
||||
cCell* pHostCell = nullptr;
|
||||
|
||||
// Each cell links to 20 automata transport nodes, 5 on each side
|
||||
cAuto_Node* pNaviNodes[49];
|
||||
|
||||
// Each cell can have a number of automata transport tracks, it owns them
|
||||
// These connect nodes together as determined by the cell
|
||||
std::list<cAuto_Track> listTracks;
|
||||
|
||||
public:
|
||||
virtual void CalculateAdjacency();
|
||||
virtual bool LinkAssets(std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms);
|
||||
virtual bool Update(float fElapsedTime);
|
||||
virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
virtual bool DrawDebug(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
};
|
||||
|
||||
53
Videos/CarCrimeCity/Part2/cCell_Building.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "cCell_Building.h"
|
||||
|
||||
|
||||
|
||||
cCell_Building::cCell_Building(const std::string &name, cCityMap* map, int x, int y) : cCell(map, x, y)
|
||||
{
|
||||
sName = name;
|
||||
}
|
||||
|
||||
|
||||
cCell_Building::~cCell_Building()
|
||||
{
|
||||
}
|
||||
|
||||
void cCell_Building::CalculateAdjacency()
|
||||
{
|
||||
}
|
||||
|
||||
bool cCell_Building::LinkAssets(std::map<std::string, olc::Sprite*>& mapTextures, std::map<std::string, olc::GFX3D::mesh*>& mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms)
|
||||
{
|
||||
texture = mapTextures[sName];
|
||||
mesh = mapMesh[sName];
|
||||
transform = mapTransforms[sName];
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Building::Update(float fElapsedTime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Building::DrawBase(olc::PixelGameEngine * pge, olc::GFX3D::PipeLine & pipe)
|
||||
{
|
||||
olc::GFX3D::mat4x4 matTranslate = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.0f);
|
||||
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MultiplyMatrix(transform, matTranslate);
|
||||
pipe.SetTransform(matWorld);
|
||||
if (texture != nullptr)
|
||||
{
|
||||
pipe.SetTexture(texture);
|
||||
pipe.Render(mesh->tris,olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_LIGHTS);
|
||||
}
|
||||
else
|
||||
{
|
||||
pipe.Render(mesh->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_FLAT | olc::GFX3D::RENDER_LIGHTS);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Building::DrawAlpha(olc::PixelGameEngine * pge, olc::GFX3D::PipeLine & pipe)
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
25
Videos/CarCrimeCity/Part2/cCell_Building.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "cCell.h"
|
||||
#include "olcPGEX_Graphics3D.h"
|
||||
|
||||
|
||||
class cCell_Building : public cCell
|
||||
{
|
||||
public:
|
||||
cCell_Building(const std::string &name, cCityMap* map, int x, int y);
|
||||
~cCell_Building();
|
||||
|
||||
private:
|
||||
std::string sName;
|
||||
olc::Sprite* texture = nullptr;
|
||||
olc::GFX3D::mesh* mesh = nullptr;
|
||||
olc::GFX3D::mat4x4 transform;
|
||||
|
||||
public:
|
||||
virtual void CalculateAdjacency();
|
||||
virtual bool LinkAssets(std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms);
|
||||
virtual bool Update(float fElapsedTime);
|
||||
virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
};
|
||||
|
||||
49
Videos/CarCrimeCity/Part2/cCell_Plane.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "cCell_Plane.h"
|
||||
|
||||
|
||||
|
||||
cCell_Plane::cCell_Plane(cCityMap* map, int x, int y, CELL_PLANE type) : cCell(map, x, y)
|
||||
{
|
||||
bSolid = false;
|
||||
nType = type;
|
||||
if (nType == PLANE_GRASS) nCellType = CELL_GRASS;
|
||||
if (nType == PLANE_ASPHALT) nCellType = CELL_PAVEMENT;
|
||||
}
|
||||
|
||||
|
||||
cCell_Plane::~cCell_Plane()
|
||||
{
|
||||
}
|
||||
|
||||
bool cCell_Plane::LinkAssets(std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms)
|
||||
{
|
||||
sprGrass = mapTextures["Grass"];
|
||||
sprPavement = mapTextures["Pavement"];
|
||||
meshUnitQuad = mapMesh["UnitQuad"];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cCell_Plane::Update(float fElapsedTime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Plane::DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe)
|
||||
{
|
||||
olc::GFX3D::mat4x4 matWorld;
|
||||
matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.0f);
|
||||
pipe.SetTransform(matWorld);
|
||||
|
||||
if(nType == PLANE_GRASS)
|
||||
pipe.SetTexture(sprGrass);
|
||||
else
|
||||
pipe.SetTexture(sprPavement);
|
||||
|
||||
pipe.Render(meshUnitQuad->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Plane::DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
34
Videos/CarCrimeCity/Part2/cCell_Plane.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "cCell.h"
|
||||
#include "olcPixelGameEngine.h"
|
||||
#include "olcPGEX_Graphics3D.h"
|
||||
#include <map>
|
||||
|
||||
|
||||
enum CELL_PLANE
|
||||
{
|
||||
PLANE_GRASS,
|
||||
PLANE_ASPHALT
|
||||
};
|
||||
|
||||
class cCell_Plane : public cCell
|
||||
{
|
||||
public:
|
||||
cCell_Plane(cCityMap* map, int x, int y, CELL_PLANE type);
|
||||
~cCell_Plane();
|
||||
|
||||
protected:
|
||||
CELL_PLANE nType = PLANE_GRASS;
|
||||
|
||||
private:
|
||||
olc::GFX3D::mesh* meshUnitQuad = nullptr;
|
||||
olc::Sprite* sprGrass = nullptr;
|
||||
olc::Sprite* sprPavement = nullptr;
|
||||
|
||||
public:
|
||||
virtual bool LinkAssets(std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms);
|
||||
virtual bool Update(float fElapsedTime);
|
||||
virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
};
|
||||
|
||||
812
Videos/CarCrimeCity/Part2/cCell_Road.cpp
Normal file
@@ -0,0 +1,812 @@
|
||||
#include "cCell_Road.h"
|
||||
#include "cCityMap.h"
|
||||
|
||||
|
||||
cCell_Road::cCell_Road(cCityMap* map, int x, int y) : cCell(map, x, y)
|
||||
{
|
||||
bSolid = false;
|
||||
nCellType = CELL_ROAD;
|
||||
}
|
||||
|
||||
cCell_Road::~cCell_Road()
|
||||
{
|
||||
}
|
||||
|
||||
void cCell_Road::CalculateAdjacency()
|
||||
{
|
||||
|
||||
// Calculate suitable road junction type
|
||||
auto r = [&](int i, int j)
|
||||
{
|
||||
return (pMap->Cell(nWorldX + i, nWorldY + j) != nullptr && pMap->Cell(nWorldX + i, nWorldY + j)->nCellType == CELL_ROAD);
|
||||
};
|
||||
|
||||
if (r(0, -1) && r(0, +1) && !r(-1, 0) && !r(+1, 0)) nRoadType = ROAD_V;
|
||||
if (!r(0, -1) && !r(0, +1) && r(-1, 0) && r(+1, 0)) nRoadType =ROAD_H;
|
||||
if (!r(0, -1) && r(0, +1) && !r(-1, 0) && r(+1, 0)) nRoadType = ROAD_C1;
|
||||
if (!r(0, -1) && r(0, +1) && r(-1, 0) && r(+1, 0)) nRoadType =ROAD_T1;
|
||||
if (!r(0, -1) && r(0, +1) && r(-1, 0) && !r(+1, 0)) nRoadType = ROAD_C2;
|
||||
if (r(0, -1) && r(0, +1) && !r(-1, 0) && r(+1, 0)) nRoadType = ROAD_T2;
|
||||
if (r(0, -1) && r(0, +1) && r(-1, 0) && r(+1, 0)) nRoadType = ROAD_X;
|
||||
if (r(0, -1) && r(0, +1) && r(-1, 0) && !r(+1, 0)) nRoadType = ROAD_T3;
|
||||
if (r(0, -1) && !r(0, +1) && !r(-1, 0) && r(+1, 0)) nRoadType = ROAD_C3;
|
||||
if (r(0, -1) && !r(0, +1) && r(-1, 0) && r(+1, 0)) nRoadType = ROAD_T4;
|
||||
if (r(0, -1) && !r(0, +1) && r(-1, 0) && !r(+1, 0)) nRoadType = ROAD_C4;
|
||||
|
||||
// Add navigation tracks based on type
|
||||
|
||||
auto AddTrack = [&](int n1, int n2) -> cAuto_Track*
|
||||
{
|
||||
if (pNaviNodes[n1] == nullptr || pNaviNodes[n2] == nullptr)
|
||||
{
|
||||
// Can't add track
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nodes exist so add track
|
||||
cAuto_Track t;
|
||||
t.node[0] = pNaviNodes[n1];
|
||||
t.node[1] = pNaviNodes[n2];
|
||||
t.cell = this;
|
||||
t.fTrackLength = (pNaviNodes[n1]->pos - pNaviNodes[n2]->pos).mag();
|
||||
listTracks.push_back(t);
|
||||
|
||||
// Add pointers to track to start and end nodes
|
||||
pNaviNodes[n1]->listTracks.push_back(&listTracks.back());
|
||||
pNaviNodes[n2]->listTracks.push_back(&listTracks.back());
|
||||
|
||||
return &listTracks.back();
|
||||
}
|
||||
};
|
||||
|
||||
// Ensure list of tracks for this cell is clear
|
||||
listTracks.clear();
|
||||
|
||||
// Add tracks depending on junction type
|
||||
pSafePedestrianTrack = nullptr;
|
||||
pSafeCarTrack = nullptr;
|
||||
pSafeChaseTrack = nullptr;
|
||||
|
||||
// Add Pedestrian Tracks
|
||||
switch (nRoadType)
|
||||
{
|
||||
case ROAD_H: pSafePedestrianTrack = AddTrack(7, 13); AddTrack(41, 35); break;
|
||||
case ROAD_V: pSafePedestrianTrack = AddTrack(1, 43); AddTrack(5, 47); break;
|
||||
|
||||
case ROAD_C1: pSafePedestrianTrack = AddTrack(43, 8); AddTrack(8, 13); AddTrack(47, 40); AddTrack(40, 41); break;
|
||||
case ROAD_C2: AddTrack(7, 12); AddTrack(12, 47); pSafePedestrianTrack = AddTrack(35, 36); AddTrack(36, 43); break;
|
||||
case ROAD_C3: AddTrack(1, 36); pSafePedestrianTrack = AddTrack(36, 41); AddTrack(5, 12); AddTrack(12, 13); break;
|
||||
case ROAD_C4: AddTrack(35, 40); AddTrack(40, 5); pSafePedestrianTrack = AddTrack(7, 8); AddTrack(8, 1); break;
|
||||
|
||||
case ROAD_T1: pSafePedestrianTrack = AddTrack(7, 8); AddTrack(8, 12); AddTrack(12, 13); AddTrack(35, 36); AddTrack(36, 38); AddTrack(38, 40); AddTrack(40, 41); AddTrack(8, 22); AddTrack(22, 36); AddTrack(36, 43); AddTrack(12, 26); AddTrack(26, 40); AddTrack(40, 47); break;
|
||||
case ROAD_T2: pSafePedestrianTrack = AddTrack(1, 8); AddTrack(8, 36); AddTrack(36, 43); AddTrack(5, 12); AddTrack(12, 26); AddTrack(26, 40); AddTrack(40, 47); AddTrack(8, 10); AddTrack(10, 12); AddTrack(12, 13); AddTrack(36, 38), AddTrack(38, 40); AddTrack(40, 41); break;
|
||||
case ROAD_T3: pSafePedestrianTrack = AddTrack(5, 12); AddTrack(12, 40); AddTrack(40, 47); AddTrack(1, 8); AddTrack(8, 22); AddTrack(22, 36); AddTrack(36, 43); AddTrack(12, 10); AddTrack(10, 8); AddTrack(8, 7); AddTrack(40, 38); AddTrack(38, 36); AddTrack(36, 35); break;
|
||||
case ROAD_T4: pSafePedestrianTrack = AddTrack(35, 36); AddTrack(36, 40); AddTrack(40, 41); AddTrack(7, 8); AddTrack(8, 10); AddTrack(10, 12); AddTrack(12, 13); AddTrack(36, 22); AddTrack(22, 8); AddTrack(8, 1); AddTrack(40, 26); AddTrack(26, 12); AddTrack(12, 5); break;
|
||||
|
||||
case ROAD_X: AddTrack(35, 36); AddTrack(36, 38); AddTrack(38, 40); AddTrack(40, 41); AddTrack(7, 8); AddTrack(8, 10); AddTrack(10, 12); AddTrack(12, 13); AddTrack(36, 22); AddTrack(22, 8); AddTrack(8, 1); AddTrack(40, 26); AddTrack(26, 12); AddTrack(12, 5); pSafePedestrianTrack = AddTrack(36, 43); AddTrack(40, 47); break;
|
||||
}
|
||||
|
||||
|
||||
// Add Chase Tracks
|
||||
switch (nRoadType)
|
||||
{
|
||||
case ROAD_H: AddTrack(21, 27); break;
|
||||
case ROAD_V: AddTrack(3, 45); break;
|
||||
|
||||
case ROAD_C1: AddTrack(45, 24); AddTrack(24, 27); break;
|
||||
case ROAD_C2: AddTrack(21, 24); AddTrack(24, 45); break;
|
||||
case ROAD_C3: AddTrack(3, 24); AddTrack(24, 27); break;
|
||||
case ROAD_C4: AddTrack(21, 24); AddTrack(24, 3); break;
|
||||
|
||||
case ROAD_T1: AddTrack(21, 24); AddTrack(24, 27); AddTrack(24, 45); break;
|
||||
case ROAD_T2: AddTrack(3, 24); AddTrack(24, 45); AddTrack(24, 27); break;
|
||||
case ROAD_T3: AddTrack(3, 24); AddTrack(24, 45); AddTrack(24, 21); break;
|
||||
case ROAD_T4: AddTrack(21, 24); AddTrack(24, 27); AddTrack(24, 3); break;
|
||||
|
||||
case ROAD_X: AddTrack(3, 24); AddTrack(27, 24); AddTrack(45, 24); AddTrack(21, 24); break;
|
||||
}
|
||||
|
||||
|
||||
//// Road traffic tracks
|
||||
switch (nRoadType)
|
||||
{
|
||||
case ROAD_H: pSafeCarTrack = AddTrack(14, 20); AddTrack(28, 34); break;
|
||||
case ROAD_V: AddTrack(2, 44); pSafeCarTrack = AddTrack(4, 46); break;
|
||||
|
||||
case ROAD_C1: pSafeCarTrack = AddTrack(44, 16); AddTrack(16, 20); AddTrack(46, 32); AddTrack(32, 34); break;
|
||||
case ROAD_C2: pSafeCarTrack = AddTrack(14, 18); AddTrack(18, 46); AddTrack(28, 30); AddTrack(30, 44); break;
|
||||
case ROAD_C3: AddTrack(2, 30); AddTrack(30, 34); pSafeCarTrack = AddTrack(4, 18); AddTrack(18, 20); break;
|
||||
case ROAD_C4: AddTrack(2, 16); AddTrack(16, 14); pSafeCarTrack = AddTrack(4, 32); AddTrack(32, 28); break;
|
||||
|
||||
|
||||
case ROAD_T1: AddTrack(14, 16); AddTrack(16, 18); AddTrack(18, 20); AddTrack(28, 30); AddTrack(30, 32); AddTrack(32, 34);
|
||||
AddTrack(16, 30); AddTrack(30, 44); AddTrack(18, 32); AddTrack(32, 46); break;
|
||||
|
||||
case ROAD_T4: AddTrack(14, 16); AddTrack(16, 18); AddTrack(18, 20); AddTrack(28, 30); AddTrack(30, 32); AddTrack(32, 34);
|
||||
AddTrack(16, 30); AddTrack(16, 2); AddTrack(18, 32); AddTrack(18, 4); break;
|
||||
|
||||
case ROAD_T2: AddTrack(2, 16); AddTrack(16, 30); AddTrack(30, 44); AddTrack(4, 18); AddTrack(18, 32); AddTrack(32, 46);
|
||||
AddTrack(16, 18); AddTrack(18, 20); AddTrack(30, 32); AddTrack(32, 34); break;
|
||||
|
||||
case ROAD_T3: AddTrack(2, 16); AddTrack(16, 30); AddTrack(30, 44); AddTrack(4, 18); AddTrack(18, 32); AddTrack(32, 46);
|
||||
AddTrack(14, 16); AddTrack(16, 18); AddTrack(28, 30); AddTrack(30, 32); break;
|
||||
|
||||
case ROAD_X:
|
||||
AddTrack(2, 16); AddTrack(16, 30); AddTrack(30, 44); AddTrack(4, 18); AddTrack(18, 32); AddTrack(32, 46);
|
||||
AddTrack(14, 16); AddTrack(16, 18); AddTrack(18, 20); AddTrack(28, 30); AddTrack(30, 32); AddTrack(32, 34); break;
|
||||
}
|
||||
|
||||
|
||||
// Stop Patterns, here we go, loads of data... :(
|
||||
|
||||
// .PO.OP.
|
||||
// PP.P.PP
|
||||
// O.O.O.O
|
||||
// .P...P.
|
||||
// O.O.O.O
|
||||
// PP.P.PP
|
||||
// .PO.OP.
|
||||
|
||||
// .PO.OP.
|
||||
// PP.P.PP
|
||||
// O.X.X.O
|
||||
// .P...P.
|
||||
// O.X.X.O
|
||||
// PP.P.PP
|
||||
// .PO.OP.
|
||||
|
||||
// .PO.OP.
|
||||
// PP.X.PP
|
||||
// O.X.X.O
|
||||
// .X...X.
|
||||
// O.X.X.O
|
||||
// PP.X.PP
|
||||
// .PO.OP.
|
||||
|
||||
auto stopmap = [&](const std::string &s)
|
||||
{
|
||||
StopPattern p;
|
||||
for (size_t i = 0; i < s.size(); i++)
|
||||
p.bStop[i] = (s[i] == 'X');
|
||||
return p;
|
||||
};
|
||||
|
||||
switch (nRoadType)
|
||||
{
|
||||
case ROAD_H:
|
||||
case ROAD_V:
|
||||
case ROAD_C1:
|
||||
case ROAD_C2:
|
||||
case ROAD_C3:
|
||||
case ROAD_C4:
|
||||
// Allow all
|
||||
/*vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.OP."
|
||||
"PP.P.PP"
|
||||
"O.O.O.O"
|
||||
".P...P."
|
||||
"O.O.O.O"
|
||||
"PP.P.PP"
|
||||
".PO.OP."));*/
|
||||
break;
|
||||
|
||||
case ROAD_X:
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
// Allow West Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"O.O.O.O"
|
||||
".X...X."
|
||||
"X.X.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Drain West Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.O.O"
|
||||
".X...X."
|
||||
"X.X.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Allow North Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.OP."
|
||||
"PP.X.PP"
|
||||
"X.X.O.O"
|
||||
".X...X."
|
||||
"O.O.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Drain North Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.O.O"
|
||||
".X...X."
|
||||
"O.O.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
// Allow EAST Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.X.X"
|
||||
".X...X."
|
||||
"O.O.O.O"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Drain East Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.X.X"
|
||||
".X...X."
|
||||
"O.O.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Allow SOUTH Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.O.O"
|
||||
".X...X."
|
||||
"O.O.X.X"
|
||||
"PP.X.PP"
|
||||
".PO.XP."));
|
||||
// Drain SOUTH Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.O.O"
|
||||
".X...X."
|
||||
"O.O.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
|
||||
break;
|
||||
|
||||
case ROAD_T1:
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
// Allow West Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"O.O.O.O"
|
||||
".X...X."
|
||||
"X.X.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Drain West Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.O.O.O"
|
||||
".X...X."
|
||||
"X.X.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
// Allow EAST Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"O.O.O.O"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Drain East Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"O.O.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Allow SOUTH Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.O.O.O"
|
||||
".X...X."
|
||||
"O.O.X.X"
|
||||
"PP.X.PP"
|
||||
".PO.XP."));
|
||||
// Drain SOUTH Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.O.O.O"
|
||||
".X...X."
|
||||
"O.O.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
break;
|
||||
|
||||
case ROAD_T2:
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.X.X"
|
||||
".P...X."
|
||||
"X.X.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
// Allow North Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.OP."
|
||||
"PP.X.PP"
|
||||
"X.X.O.O"
|
||||
".P...X."
|
||||
"X.X.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Drain North Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.O.O"
|
||||
".P...X."
|
||||
"X.X.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
// Allow EAST Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.X.X"
|
||||
".P...X."
|
||||
"X.O.O.O"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Drain East Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.X.X"
|
||||
".P...X."
|
||||
"X.O.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Allow SOUTH Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.O.O"
|
||||
".P...X."
|
||||
"X.O.X.X"
|
||||
"PP.X.PP"
|
||||
".PO.XP."));
|
||||
// Drain SOUTH Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.O.O"
|
||||
".P...X."
|
||||
"X.O.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
break;
|
||||
case ROAD_T3:
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.X.X"
|
||||
".X...P."
|
||||
"X.X.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
// Allow West Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"O.O.O.X"
|
||||
".X...P."
|
||||
"X.X.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Drain West Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.O.X"
|
||||
".X...P."
|
||||
"X.X.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
// Allow North Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.OP."
|
||||
"PP.X.PP"
|
||||
"X.X.O.X"
|
||||
".X...P."
|
||||
"O.O.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
// Drain North Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.O.X"
|
||||
".X...P."
|
||||
"O.O.O.X"
|
||||
"PP.X.PP"
|
||||
".PX.OP."));
|
||||
|
||||
// Allow SOUTH Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.X.X"
|
||||
".X...P."
|
||||
"O.O.X.X"
|
||||
"PP.X.PP"
|
||||
".PO.XP."));
|
||||
// Drain SOUTH Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.X.X"
|
||||
".X...P."
|
||||
"O.O.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
break;
|
||||
|
||||
case ROAD_T4:
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Allow West Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"O.O.O.O"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain West Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.O.O"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Allow North Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.OP."
|
||||
"PP.X.PP"
|
||||
"X.X.O.O"
|
||||
".X...X."
|
||||
"O.O.O.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain North Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.O.O"
|
||||
".X...X."
|
||||
"O.O.O.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Allow Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.P.PP"
|
||||
"X.X.X.X"
|
||||
".P...P."
|
||||
"X.X.X.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain Pedestrians
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PX.XP."
|
||||
"PP.X.PP"
|
||||
"X.X.X.X"
|
||||
".X...X."
|
||||
"X.X.X.X"
|
||||
"PP.X.PP"
|
||||
".PX.XP."));
|
||||
// Allow EAST Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.X.X"
|
||||
".X...X."
|
||||
"O.O.O.O"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
// Drain East Traffic
|
||||
vStopPattern.push_back(
|
||||
stopmap(
|
||||
".PO.XP."
|
||||
"PP.X.PP"
|
||||
"X.O.X.X"
|
||||
".X...X."
|
||||
"O.O.O.X"
|
||||
"PP.P.PP"
|
||||
".PX.XP."));
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool cCell_Road::LinkAssets(std::map<std::string, olc::Sprite*>& mapTextures, std::map<std::string, olc::GFX3D::mesh*>& mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms)
|
||||
{
|
||||
meshUnitQuad = mapMesh["UnitQuad"];
|
||||
sprRoadTex[ROAD_V] = mapTextures["Road_V"];
|
||||
sprRoadTex[ROAD_H] = mapTextures["Road_H"];
|
||||
sprRoadTex[ROAD_C1] = mapTextures["Road_C1"];
|
||||
sprRoadTex[ROAD_T1] = mapTextures["Road_T1"];
|
||||
sprRoadTex[ROAD_C2] = mapTextures["Road_C2"];
|
||||
sprRoadTex[ROAD_T2] = mapTextures["Road_T2"];
|
||||
sprRoadTex[ROAD_X] = mapTextures["Road_X"];
|
||||
sprRoadTex[ROAD_T3] = mapTextures["Road_T3"];
|
||||
sprRoadTex[ROAD_C3] = mapTextures["Road_C3"];
|
||||
sprRoadTex[ROAD_T4] = mapTextures["Road_T4"];
|
||||
sprRoadTex[ROAD_C4] = mapTextures["Road_C4"];
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Road::Update(float fElapsedTime)
|
||||
{
|
||||
if (vStopPattern.empty())
|
||||
return false;
|
||||
|
||||
fStopPatternTimer += fElapsedTime;
|
||||
if (fStopPatternTimer >= 5.0f)
|
||||
{
|
||||
fStopPatternTimer -= 5.0f;
|
||||
nCurrentStopPattern++;
|
||||
nCurrentStopPattern %= vStopPattern.size();
|
||||
for (int i = 0; i < 49; i++)
|
||||
if(pNaviNodes[i] != nullptr)
|
||||
pNaviNodes[i]->bBlock = vStopPattern[nCurrentStopPattern].bStop[i];
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Road::DrawBase(olc::PixelGameEngine* pge, olc::GFX3D::PipeLine & pipe)
|
||||
{
|
||||
olc::GFX3D::mat4x4 matWorld;
|
||||
matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.0f);
|
||||
pipe.SetTransform(matWorld);
|
||||
pipe.SetTexture(sprRoadTex[nRoadType]);
|
||||
pipe.Render(meshUnitQuad->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Road::DrawAlpha(olc::PixelGameEngine* pge, olc::GFX3D::PipeLine & pipe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Road::DrawDebug(olc::PixelGameEngine* pge, olc::GFX3D::PipeLine & pipe)
|
||||
{
|
||||
|
||||
|
||||
|
||||
// Draw Automata navigation tracks
|
||||
for (auto &track : listTracks)
|
||||
{
|
||||
olc::GFX3D::vec3d p1 = { track.node[0]->pos.x, track.node[0]->pos.y, 0.0f };
|
||||
olc::GFX3D::vec3d p2 = { track.node[1]->pos.x, track.node[1]->pos.y, 0.0f };
|
||||
pipe.RenderLine(p1, p2, olc::CYAN);
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < 49; i++)
|
||||
{
|
||||
if (pNaviNodes[i] != nullptr)
|
||||
{
|
||||
olc::GFX3D::vec3d p1 = { pNaviNodes[i]->pos.x, pNaviNodes[i]->pos.y, 0.01f };
|
||||
pipe.RenderCircleXZ(p1, 0.03f, pNaviNodes[i]->bBlock ? olc::RED : olc::GREEN);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
54
Videos/CarCrimeCity/Part2/cCell_Road.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include "cCell.h"
|
||||
|
||||
enum RoadType
|
||||
{
|
||||
ROAD_H,
|
||||
ROAD_V,
|
||||
ROAD_C1,
|
||||
ROAD_C2,
|
||||
ROAD_C3,
|
||||
ROAD_C4,
|
||||
ROAD_T1,
|
||||
ROAD_T2,
|
||||
ROAD_T3,
|
||||
ROAD_T4,
|
||||
ROAD_X,
|
||||
};
|
||||
|
||||
|
||||
class cCell_Road : public cCell
|
||||
{
|
||||
public:
|
||||
cCell_Road(cCityMap* map, int x, int y);
|
||||
~cCell_Road();
|
||||
|
||||
private:
|
||||
struct StopPattern
|
||||
{
|
||||
bool bStop[49];
|
||||
};
|
||||
|
||||
private:
|
||||
bool bNeighboursAreRoads[4];
|
||||
|
||||
olc::GFX3D::mesh *meshUnitQuad = nullptr;
|
||||
olc::Sprite* sprRoadTex[11];
|
||||
|
||||
std::vector<StopPattern> vStopPattern;
|
||||
int nCurrentStopPattern = 0;
|
||||
float fStopPatternTimer = 0.0f;
|
||||
public:
|
||||
RoadType nRoadType = ROAD_X;
|
||||
cAuto_Track* pSafeCarTrack = nullptr;
|
||||
cAuto_Track* pSafePedestrianTrack = nullptr;
|
||||
cAuto_Track* pSafeChaseTrack = nullptr;
|
||||
|
||||
virtual void CalculateAdjacency();
|
||||
virtual bool LinkAssets(std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms);
|
||||
virtual bool Update(float fElapsedTime);
|
||||
virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
virtual bool DrawDebug(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
};
|
||||
|
||||
91
Videos/CarCrimeCity/Part2/cCell_Water.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
#include "cCell_Water.h"
|
||||
#include "cCityMap.h"
|
||||
|
||||
|
||||
cCell_Water::cCell_Water(cCityMap* map, int x, int y) : cCell(map, x, y)
|
||||
{
|
||||
nCellType = CELL_WATER;
|
||||
bNeighboursAreWater[0] = false;
|
||||
bNeighboursAreWater[1] = false;
|
||||
bNeighboursAreWater[2] = false;
|
||||
bNeighboursAreWater[3] = false;
|
||||
}
|
||||
|
||||
|
||||
cCell_Water::~cCell_Water()
|
||||
{
|
||||
}
|
||||
|
||||
bool cCell_Water::LinkAssets(std::map<std::string, olc::Sprite*>& mapTextures, std::map<std::string, olc::GFX3D::mesh*>& mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms)
|
||||
{
|
||||
meshUnitQuad = mapMesh["UnitQuad"];
|
||||
meshWalls = mapMesh["WallsOut"];
|
||||
sprWater = mapTextures["Water"];
|
||||
sprSides = mapTextures["WaterSide"];
|
||||
sprClouds = mapTextures["Clouds"];
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Water::Update(float fElapsedTime)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Water::DrawBase(olc::PixelGameEngine * pge, olc::GFX3D::PipeLine & pipe)
|
||||
{
|
||||
olc::GFX3D::mat4x4 matWorld;
|
||||
matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.0f);
|
||||
pipe.SetTransform(matWorld);
|
||||
pipe.SetTexture(sprSides);
|
||||
if (!bNeighboursAreWater[1]) pipe.Render(meshWalls->tris, olc::GFX3D::RENDER_LIGHTS | olc::GFX3D::RENDER_CULL_CCW | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_DEPTH, 0, 2);
|
||||
if (!bNeighboursAreWater[3]) pipe.Render(meshWalls->tris, olc::GFX3D::RENDER_LIGHTS | olc::GFX3D::RENDER_CULL_CCW | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_DEPTH, 2, 2);
|
||||
if (!bNeighboursAreWater[2]) pipe.Render(meshWalls->tris, olc::GFX3D::RENDER_LIGHTS | olc::GFX3D::RENDER_CULL_CCW | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_DEPTH, 4, 2);
|
||||
if (!bNeighboursAreWater[0]) pipe.Render(meshWalls->tris, olc::GFX3D::RENDER_LIGHTS | olc::GFX3D::RENDER_CULL_CCW | olc::GFX3D::RENDER_TEXTURED | olc::GFX3D::RENDER_DEPTH, 6, 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cCell_Water::DrawAlpha(olc::PixelGameEngine * pge, olc::GFX3D::PipeLine & pipe)
|
||||
{
|
||||
auto renderWater = [&](const int x, const int y, const olc::Pixel& pSource, const olc::Pixel& pDest)
|
||||
{
|
||||
float a = (float)(pSource.a / 255.0f) * 0.6f;
|
||||
float c = 1.0f - a;
|
||||
float r = a * (float)pSource.r + c * (float)pDest.r;
|
||||
float g = a * (float)pSource.g + c * (float)pDest.g;
|
||||
float b = a * (float)pSource.b + c * (float)pDest.b;
|
||||
|
||||
a = 0.4f;
|
||||
c = 1.0f - a;
|
||||
olc::Pixel sky = sprClouds->GetPixel(x, y);
|
||||
float sr = a * (float)sky.r + c * r;
|
||||
float sg = a * (float)sky.g + c * g;
|
||||
float sb = a * (float)sky.b + c * b;
|
||||
|
||||
return olc::Pixel((uint8_t)sr, (uint8_t)sg, (uint8_t)sb);
|
||||
};
|
||||
|
||||
pge->SetPixelMode(renderWater);
|
||||
olc::GFX3D::mat4x4 matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)nWorldX, (float)nWorldY, 0.07f);
|
||||
pipe.SetTransform(matWorld);
|
||||
pipe.SetTexture(sprWater);
|
||||
pipe.Render(meshUnitQuad->tris, olc::GFX3D::RENDER_CULL_CW | olc::GFX3D::RENDER_DEPTH | olc::GFX3D::RENDER_TEXTURED);
|
||||
pge->SetPixelMode(olc::Pixel::NORMAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void cCell_Water::CalculateAdjacency()
|
||||
{
|
||||
auto r = [&](int i, int j)
|
||||
{
|
||||
if (pMap->Cell(nWorldX + i, nWorldY + j) != nullptr)
|
||||
return pMap->Cell(nWorldX + i, nWorldY + j)->nCellType == CELL_WATER;
|
||||
else
|
||||
return false;
|
||||
};
|
||||
|
||||
bNeighboursAreWater[0] = r(0, -1);
|
||||
bNeighboursAreWater[1] = r(+1, 0);
|
||||
bNeighboursAreWater[2] = r(0, +1);
|
||||
bNeighboursAreWater[3] = r(-1, 0);
|
||||
}
|
||||
25
Videos/CarCrimeCity/Part2/cCell_Water.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "cCell.h"
|
||||
class cCell_Water : public cCell
|
||||
{
|
||||
public:
|
||||
cCell_Water(cCityMap* map, int x, int y);
|
||||
~cCell_Water();
|
||||
|
||||
private:
|
||||
olc::GFX3D::mesh* meshUnitQuad = nullptr;
|
||||
olc::GFX3D::mesh* meshWalls = nullptr;
|
||||
olc::Sprite* sprWater = nullptr;
|
||||
olc::Sprite* sprSides = nullptr;
|
||||
olc::Sprite* sprClouds = nullptr;
|
||||
|
||||
bool bNeighboursAreWater[4];
|
||||
|
||||
public:
|
||||
virtual void CalculateAdjacency();
|
||||
virtual bool LinkAssets(std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms);
|
||||
virtual bool Update(float fElapsedTime);
|
||||
virtual bool DrawBase(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
virtual bool DrawAlpha(olc::PixelGameEngine *pge, olc::GFX3D::PipeLine &pipe);
|
||||
};
|
||||
|
||||
202
Videos/CarCrimeCity/Part2/cCityMap.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
#include "cCityMap.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
|
||||
|
||||
cCityMap::cCityMap(int w, int h, std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms)
|
||||
{
|
||||
CreateCity(w, h, mapTextures, mapMesh, mapTransforms);
|
||||
}
|
||||
|
||||
cCityMap::~cCityMap()
|
||||
{
|
||||
ReleaseCity();
|
||||
}
|
||||
|
||||
int cCityMap::GetWidth()
|
||||
{
|
||||
return nWidth;
|
||||
}
|
||||
|
||||
int cCityMap::GetHeight()
|
||||
{
|
||||
return nHeight;
|
||||
}
|
||||
|
||||
cCell* cCityMap::Cell(int x, int y)
|
||||
{
|
||||
if (x >= 0 && x < nWidth && y >= 0 && y < nHeight)
|
||||
return pCells[y*nWidth + x];
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cCell* cCityMap::Replace(int x, int y, cCell* cell)
|
||||
{
|
||||
if (cell == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (pCells[y * nWidth + x] != nullptr)
|
||||
delete pCells[y * nWidth + x];
|
||||
|
||||
pCells[y * nWidth + x] = cell;
|
||||
return cell;
|
||||
}
|
||||
|
||||
void cCityMap::CreateCity(int w, int h, std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms)
|
||||
{
|
||||
ReleaseCity();
|
||||
nWidth = w;
|
||||
nHeight = h;
|
||||
pCells = new cCell*[nHeight * nWidth];
|
||||
|
||||
// Create Navigation Node Pool, assumes 5 nodes on east and south
|
||||
// side of each cell. The City owns these nodes, and cells in the
|
||||
// city borrow them and link to them as required
|
||||
pNodes = new cAuto_Node[nHeight * nWidth * 49];
|
||||
|
||||
// The cell has 49 nodes, though some are simply unused. This is less memory
|
||||
// efficient certainly, but makes code more intuitive and easier to write
|
||||
|
||||
for (int x = 0; x < nWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nHeight; y++)
|
||||
{
|
||||
// Nodes sit between cells, therefore each create nodes along
|
||||
// the east and southern sides of the cell. This assumes that
|
||||
// navigation along the top and left boundaries of the map
|
||||
// will not occur. And it shouldnt, as its water
|
||||
|
||||
int idx = (y * nWidth + x) * 49;
|
||||
|
||||
for (int dx = 0; dx < 7; dx++)
|
||||
{
|
||||
float off_x = 0.0f;
|
||||
switch (dx)
|
||||
{
|
||||
case 0: off_x = 0.000f; break;
|
||||
case 1: off_x = 0.083f; break;
|
||||
case 2: off_x = 0.333f; break;
|
||||
case 3: off_x = 0.500f; break;
|
||||
case 4: off_x = 0.667f; break;
|
||||
case 5: off_x = 0.917f; break;
|
||||
case 6: off_x = 1.000f; break;
|
||||
}
|
||||
|
||||
|
||||
for (int dy = 0; dy < 7; dy++)
|
||||
{
|
||||
float off_y = 0.0f;
|
||||
switch (dy)
|
||||
{
|
||||
case 0: off_y = 0.000f; break;
|
||||
case 1: off_y = 0.083f; break;
|
||||
case 2: off_y = 0.333f; break;
|
||||
case 3: off_y = 0.500f; break;
|
||||
case 4: off_y = 0.667f; break;
|
||||
case 5: off_y = 0.917f; break;
|
||||
case 6: off_y = 1.000f; break;
|
||||
}
|
||||
|
||||
pNodes[idx + dy * 7 + dx].pos = { (float)x + off_x, (float)y + off_y };
|
||||
pNodes[idx + dy * 7 + dx].bBlock = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Now create default Cell
|
||||
for (int x = 0; x < nWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nHeight; y++)
|
||||
{
|
||||
// Default city, everything is grass
|
||||
pCells[y * nWidth + x] = new cCell_Plane(this, x, y, PLANE_GRASS);
|
||||
|
||||
// Give the cell the opportunity to locally reference the resources it needs
|
||||
pCells[y * nWidth + x]->LinkAssets(mapTextures, mapMesh, mapTransforms);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cAuto_Node* cCityMap::GetAutoNodeBase(int x, int y)
|
||||
{
|
||||
return pNodes + (y * nWidth + x) * 49;
|
||||
}
|
||||
|
||||
void cCityMap::RemoveAllTracks()
|
||||
{
|
||||
for (int i = 0; i < nWidth * nHeight * 49; i++)
|
||||
{
|
||||
pNodes[i].listTracks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void cCityMap::ReleaseCity()
|
||||
{
|
||||
for (int x = 0; x < nWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nHeight; y++)
|
||||
{
|
||||
// Erase any tracks attached to nodes
|
||||
for(int i=0; i<49; i++)
|
||||
Cell(x, y)->pNaviNodes[i]->listTracks.clear();
|
||||
|
||||
// Release individual cell objects
|
||||
delete pCells[y * nWidth + x];
|
||||
}
|
||||
}
|
||||
|
||||
// Release array of cell pointers
|
||||
if (pCells != nullptr) delete pCells;
|
||||
|
||||
// Release array of automata navigation nodes
|
||||
if (pNodes != nullptr) delete pNodes;
|
||||
|
||||
nWidth = 0;
|
||||
nHeight = 0;
|
||||
}
|
||||
|
||||
|
||||
bool cCityMap::SaveCity(std::string sFilename)
|
||||
{
|
||||
/*std::ofstream file(sFilename, std::ios::out | std::ios::binary);
|
||||
if (!file.is_open()) return false;
|
||||
|
||||
file.write((char*)&m_nWidth, sizeof(int));
|
||||
file.write((char*)&m_nHeight, sizeof(int));
|
||||
|
||||
for (int x = 0; x < m_nWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < m_nHeight; y++)
|
||||
{
|
||||
file.write((char*)Cell(x, y), sizeof(cCityCell));
|
||||
}
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cCityMap::LoadCity(std::string sFilename)
|
||||
{
|
||||
/*std::ifstream file(sFilename, std::ios::in | std::ios::binary);
|
||||
if (!file.is_open()) return false;
|
||||
|
||||
int w, h;
|
||||
file.read((char*)&w, sizeof(int));
|
||||
file.read((char*)&h, sizeof(int));
|
||||
CreateCity(w, h);
|
||||
|
||||
for (int x = 0; x < m_nWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < m_nHeight; y++)
|
||||
{
|
||||
file.read((char*)Cell(x, y), sizeof(cCityCell));
|
||||
}
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
63
Videos/CarCrimeCity/Part2/cCityMap.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "olcPixelGameEngine.h"
|
||||
#include "olcPGEX_Graphics3D.h"
|
||||
#include "cCell.h"
|
||||
#include "cCell_Plane.h"
|
||||
#include "cCell_Water.h"
|
||||
#include "cCell_Road.h"
|
||||
#include "cCell_Building.h"
|
||||
|
||||
/*
|
||||
This class holds the definition of a map. The map data is actually
|
||||
stored within this clap, as well as accessors to access the individual
|
||||
map cells
|
||||
*/
|
||||
class cCityMap
|
||||
{
|
||||
public:
|
||||
// Construct a "blank" city w units wide by h units high
|
||||
cCityMap(int w, int h, std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms);
|
||||
|
||||
// Cleans up city, like Batman
|
||||
~cCityMap();
|
||||
|
||||
public:
|
||||
// Save the current city to a file, this will overwrite an existing
|
||||
// city file without warning. Returns true if successful
|
||||
bool SaveCity(std::string sFilename);
|
||||
|
||||
// Load a city from file and replace current city with it, retuns
|
||||
// true if successful
|
||||
bool LoadCity(std::string sFilename);
|
||||
|
||||
public:
|
||||
// Return width of city in cells
|
||||
int GetWidth();
|
||||
// Return height of city in cells
|
||||
int GetHeight();
|
||||
// Return a specific cell reference if inside city limits, or nullptr
|
||||
cCell* Cell(int x, int y);
|
||||
// Replace a specific cell
|
||||
cCell* Replace(int x, int y, cCell* cell);
|
||||
|
||||
cAuto_Node* GetAutoNodeBase(int x, int y);
|
||||
|
||||
void RemoveAllTracks();
|
||||
|
||||
private:
|
||||
int nWidth = 0;
|
||||
int nHeight = 0;
|
||||
cCell **pCells = nullptr;
|
||||
cAuto_Node *pNodes = nullptr;
|
||||
|
||||
private:
|
||||
// Creates a "default" city of specified size
|
||||
void CreateCity(int w, int h, std::map<std::string, olc::Sprite*> &mapTextures, std::map<std::string, olc::GFX3D::mesh*> &mapMesh, std::map<std::string, olc::GFX3D::mat4x4> &mapTransforms);
|
||||
// Destroy city
|
||||
void ReleaseCity();
|
||||
};
|
||||
|
||||
156
Videos/CarCrimeCity/Part2/cGameSettings.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "cGameSettings.h"
|
||||
|
||||
|
||||
|
||||
cGameSettings::cGameSettings()
|
||||
{
|
||||
}
|
||||
|
||||
cGameSettings::~cGameSettings()
|
||||
{
|
||||
}
|
||||
|
||||
bool cGameSettings::LoadConfigFile(std::string sFile)
|
||||
{
|
||||
lua_State *L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
|
||||
// Load game settings file
|
||||
int r = luaL_loadfile(L, sFile.c_str());
|
||||
if (r != LUA_OK)
|
||||
{
|
||||
std::string errormsg = lua_tostring(L, -1);
|
||||
std::cout << errormsg << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Execute it
|
||||
int i = lua_pcall(L, 0, LUA_MULTRET, 0);
|
||||
if (i != LUA_OK)
|
||||
{
|
||||
std::string errormsg = lua_tostring(L, -1);
|
||||
std::cout << errormsg << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
lua_getglobal(L, "PixelWidth");
|
||||
if (lua_isinteger(L, -1)) cGameSettings::nPixelWidth = (int)lua_tointeger(L, -1);
|
||||
|
||||
lua_getglobal(L, "PixelHeight");
|
||||
if (lua_isinteger(L, -1)) cGameSettings::nPixelHeight = (int)lua_tointeger(L, -1);
|
||||
|
||||
lua_getglobal(L, "ScreenWidth");
|
||||
if (lua_isinteger(L, -1)) cGameSettings::nScreenWidth = (int)lua_tointeger(L, -1);
|
||||
|
||||
lua_getglobal(L, "ScreenHeight");
|
||||
if (lua_isinteger(L, -1)) cGameSettings::nScreenHeight = (int)lua_tointeger(L, -1);
|
||||
|
||||
lua_getglobal(L, "DefaultMapWidth");
|
||||
if (lua_isinteger(L, -1)) cGameSettings::nDefaultMapWidth = (int)lua_tointeger(L, -1);
|
||||
|
||||
lua_getglobal(L, "DefaultMapHeight");
|
||||
if (lua_isinteger(L, -1)) cGameSettings::nDefaultMapHeight = (int)lua_tointeger(L, -1);
|
||||
|
||||
lua_getglobal(L, "DefaultCityFile");
|
||||
if (lua_isstring(L, -1)) cGameSettings::sDefaultCityFile = lua_tostring(L, -1);
|
||||
|
||||
lua_getglobal(L, "FullScreen");
|
||||
if (lua_isboolean(L, -1)) cGameSettings::bFullScreen = lua_toboolean(L, -1);
|
||||
|
||||
|
||||
//// Load System Texture files
|
||||
|
||||
// Load Texture Assets
|
||||
lua_getglobal(L, "Textures"); // -1 Table "Teams"
|
||||
if (lua_istable(L, -1))
|
||||
{
|
||||
lua_pushnil(L); // -2 Key Nil : -1 Table "Teams"
|
||||
|
||||
while (lua_next(L, -2) != 0) // -1 Table : -2 Key "TeamName" : -3 Table "Teams"
|
||||
{
|
||||
sAssetTexture texture;
|
||||
int stage = 0;
|
||||
if (lua_istable(L, -1))
|
||||
{
|
||||
lua_gettable(L, -1); // -1 Table : -2 Table Value : -3 Key "TeamName" : -4 Table "Teams"
|
||||
lua_pushnil(L); // -1 Key Nil : -2 Table : -3 Table Value : -4 Key "TeamName" : -5 Table "Teams"
|
||||
while (lua_next(L, -2) != 0) // -1 Value "BotFile" : -2 Key Nil : -3 Table : -4 Table Value : -5 Key "TeamName" : -6 Table "Teams"
|
||||
{
|
||||
if (stage == 0) texture.sName = lua_tostring(L, -1);
|
||||
if (stage == 1) texture.sFile = lua_tostring(L, -1);
|
||||
lua_pop(L, 1); // -1 Key Nil : -2 Table : -3 Table Value : -4 Key "TeamName" : -5 Table "Teams"
|
||||
stage++;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1); // -1 Table : -2 Table Value : -3 Key "TeamName" : -4 Table "Teams"
|
||||
vecAssetTextures.push_back(texture);
|
||||
}
|
||||
}
|
||||
|
||||
auto GroupLoadAssets = [L](const std::string &group, std::vector<sAssetModel> &vec)
|
||||
{
|
||||
lua_getglobal(L, group.c_str());
|
||||
if (lua_istable(L, -1))
|
||||
{
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0)
|
||||
{
|
||||
sAssetModel model;
|
||||
int stage = 0;
|
||||
if (lua_istable(L, -1))
|
||||
{
|
||||
lua_gettable(L, -1);
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, -2) != 0)
|
||||
{
|
||||
if (stage == 0) model.sCreator = lua_tostring(L, -1);
|
||||
if (stage == 1) model.sDescription = lua_tostring(L, -1);
|
||||
if (stage == 2) model.sModelOBJ = lua_tostring(L, -1);
|
||||
if (stage == 3) model.sModelPNG = lua_tostring(L, -1);
|
||||
|
||||
if (stage == 4) model.fRotate[0] = (float)lua_tonumber(L, -1);
|
||||
if (stage == 5) model.fRotate[1] = (float)lua_tonumber(L, -1);
|
||||
if (stage == 6) model.fRotate[2] = (float)lua_tonumber(L, -1);
|
||||
|
||||
if (stage == 7) model.fScale[0] = (float)lua_tonumber(L, -1);
|
||||
if (stage == 8) model.fScale[1] = (float)lua_tonumber(L, -1);
|
||||
if (stage == 9) model.fScale[2] = (float)lua_tonumber(L, -1);
|
||||
|
||||
if (stage == 10) model.fTranslate[0] = (float)lua_tonumber(L, -1);
|
||||
if (stage == 11) model.fTranslate[1] = (float)lua_tonumber(L, -1);
|
||||
if (stage == 12) model.fTranslate[2] = (float)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
stage++;
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
vec.push_back(model);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Load Building Assets
|
||||
GroupLoadAssets("Buildings", vecAssetBuildings);
|
||||
|
||||
// Load Vehicle Assets
|
||||
GroupLoadAssets("Vehicles", vecAssetVehicles);
|
||||
|
||||
|
||||
lua_close(L);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int cGameSettings::nScreenWidth = 768;
|
||||
int cGameSettings::nScreenHeight = 480;
|
||||
int cGameSettings::nPixelWidth = 2;
|
||||
int cGameSettings::nPixelHeight = 2;
|
||||
bool cGameSettings::bFullScreen = false;
|
||||
|
||||
int cGameSettings::nDefaultMapWidth = 64;
|
||||
int cGameSettings::nDefaultMapHeight = 32;
|
||||
std::string cGameSettings::sDefaultCityFile = "";
|
||||
|
||||
std::vector<sAssetTexture> cGameSettings::vecAssetTextures;
|
||||
std::vector<sAssetModel> cGameSettings::vecAssetBuildings;
|
||||
std::vector<sAssetModel> cGameSettings::vecAssetVehicles;
|
||||
65
Videos/CarCrimeCity/Part2/cGameSettings.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "lua533/include/lua.h"
|
||||
#include "lua533/include/lauxlib.h"
|
||||
#include "lua533/include/lualib.h"
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "lua533/liblua53.a")
|
||||
#endif
|
||||
|
||||
/*
|
||||
This is a singleton that stores all the games configuration settings.
|
||||
These settings are loaded on game start up and are to be considered
|
||||
read-only.
|
||||
*/
|
||||
|
||||
struct sAssetModel
|
||||
{
|
||||
std::string sCreator;
|
||||
std::string sDescription;
|
||||
std::string sModelOBJ;
|
||||
std::string sModelPNG;
|
||||
float fRotate[3];
|
||||
float fScale[3];
|
||||
float fTranslate[3];
|
||||
};
|
||||
|
||||
struct sAssetTexture
|
||||
{
|
||||
std::string sName;
|
||||
std::string sFile;
|
||||
};
|
||||
|
||||
class cGameSettings
|
||||
{
|
||||
public:
|
||||
cGameSettings();
|
||||
~cGameSettings();
|
||||
|
||||
public:
|
||||
bool LoadConfigFile(std::string sFile);
|
||||
|
||||
public:
|
||||
static int nScreenWidth;
|
||||
static int nScreenHeight;
|
||||
static int nPixelWidth;
|
||||
static int nPixelHeight;
|
||||
static bool bFullScreen;
|
||||
|
||||
static int nDefaultMapWidth;
|
||||
static int nDefaultMapHeight;
|
||||
static std::string sDefaultCityFile;
|
||||
|
||||
static std::vector<sAssetTexture> vecAssetTextures;
|
||||
static std::vector<sAssetModel> vecAssetBuildings;
|
||||
static std::vector<sAssetModel> vecAssetVehicles;
|
||||
};
|
||||
|
||||
BIN
Videos/CarCrimeCity/Part2/lua53.dll
Normal file
367
Videos/CarCrimeCity/Part2/main.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
/*
|
||||
Top Down City Based Car Crime Game - Part #2
|
||||
"Colin, I hope you're shooting 600+ wherever you are buddy. RIP." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Instructions:
|
||||
~~~~~~~~~~~~~
|
||||
Scroll with middle mouse wheel, TAB toggle edit mode, R to place road
|
||||
P to place pavement, Q to place building, Arrow keys to drive car
|
||||
|
||||
Relevant Video: https://youtu.be/fIV6P1W-wuo
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
|
||||
#include "cGameSettings.h"
|
||||
#include "cCarCrimeCity.h"
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// Load the settings singleton
|
||||
cGameSettings config;
|
||||
if (!config.LoadConfigFile("assets/config.lua"))
|
||||
{
|
||||
std::cout << "Failed to load '/assets/config.lua'" << std::endl;
|
||||
std::cout << " -> Using default configuration" << std::endl;
|
||||
}
|
||||
|
||||
// Start the PixelGameEngine
|
||||
cCarCrimeCity game;
|
||||
if (game.Construct(config.nScreenWidth, config.nScreenHeight, config.nPixelWidth, config.nPixelHeight, config.bFullScreen))
|
||||
game.Start();
|
||||
|
||||
// Exit!
|
||||
return 0;
|
||||
}
|
||||
|
||||
//#define OLC_PGE_APPLICATION
|
||||
//#include "olcPixelGameEngine.h"
|
||||
//
|
||||
//#define OLC_PGEX_GRAPHICS3D
|
||||
//#include "olcPGEX_Graphics3D.h"
|
||||
//
|
||||
//
|
||||
//
|
||||
//enum CELLTYPE
|
||||
//{
|
||||
// CELL_BLANK = 0,
|
||||
// CELL_GRASS = 1,
|
||||
// CELL_CONCRETE = 2,
|
||||
// CELL_WATER = 3,
|
||||
// CELL_BUILDING = 4,
|
||||
// CELL_ROAD_H = 5,
|
||||
// CELL_ROAD_V = 6,
|
||||
// CELL_ROAD_C1 = 7,
|
||||
// CELL_ROAD_C2 = 8,
|
||||
// CELL_ROAD_C3 = 9,
|
||||
// CELL_ROAD_C4 = 10,
|
||||
// CELL_ROAD_T1 = 11,
|
||||
// CELL_ROAD_T2 = 12,
|
||||
// CELL_ROAD_T3 = 13,
|
||||
// CELL_ROAD_T4 = 14,
|
||||
// CELL_ROAD_X = 15,
|
||||
//};
|
||||
//
|
||||
//struct cCityCell
|
||||
//{
|
||||
// int nType = 5;// CELL_GRASS;
|
||||
//};
|
||||
//
|
||||
//class cCityMap
|
||||
//{
|
||||
//public:
|
||||
// // Construct a "blank" city w units wide by h units high
|
||||
// cCityMap(int w, int h);
|
||||
//
|
||||
// // Cleans up city, like Batman
|
||||
// ~cCityMap();
|
||||
//
|
||||
//
|
||||
//public:
|
||||
// // Return width of city in cells
|
||||
// int GetWidth();
|
||||
// // Return height of city in cells
|
||||
// int GetHeight();
|
||||
// // Return a specific cell reference if inside city limits, or nullptr
|
||||
// cCityCell* Cell(int x, int y);
|
||||
//
|
||||
//private:
|
||||
// int m_nWidth = 0;
|
||||
// int m_nHeight = 0;
|
||||
// cCityCell *m_pCells = nullptr;
|
||||
//
|
||||
//private:
|
||||
// // Creates a "default" city of specified size
|
||||
// void CreateCity(int w, int h);
|
||||
// // Destroy city
|
||||
// void ReleaseCity();
|
||||
//};
|
||||
//
|
||||
//cCityMap::cCityMap(int w, int h)
|
||||
//{
|
||||
// CreateCity(w, h);
|
||||
//}
|
||||
//
|
||||
//cCityMap::~cCityMap()
|
||||
//{
|
||||
// //ReleaseCity();
|
||||
//}
|
||||
//
|
||||
//int cCityMap::GetWidth()
|
||||
//{
|
||||
// return m_nWidth;
|
||||
//}
|
||||
//
|
||||
//int cCityMap::GetHeight()
|
||||
//{
|
||||
// return m_nHeight;
|
||||
//}
|
||||
//
|
||||
//cCityCell* cCityMap::Cell(int x, int y)
|
||||
//{
|
||||
// if (x >= 0 && x < m_nWidth && y >= 0 && y < m_nHeight)
|
||||
// return &m_pCells[y*m_nWidth + x];
|
||||
// else
|
||||
// return nullptr;
|
||||
//}
|
||||
//
|
||||
//void cCityMap::CreateCity(int w, int h)
|
||||
//{
|
||||
// //ReleaseCity();
|
||||
// m_nWidth = w;
|
||||
// m_nHeight = h;
|
||||
// m_pCells = new cCityCell[m_nHeight * m_nWidth];
|
||||
//
|
||||
// for (int x = 0; x < m_nWidth; x++)
|
||||
// {
|
||||
// for (int y = 0; y < m_nHeight; y++)
|
||||
// {
|
||||
// //m_pCells[y*m_nWidth + x] = new cCityCell();
|
||||
// //Cell(x, y)->bRoad = false;
|
||||
// //Cell(x, y)->nHeight = 0;
|
||||
// //Cell(x, y)->nWorldX = x;
|
||||
// //Cell(x, y)->nWorldY = y;
|
||||
// Cell(x, y)->nType = CELL_GRASS;
|
||||
// //Cell(x, y)->bBuilding = false;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void cCityMap::ReleaseCity()
|
||||
//{
|
||||
// if (m_pCells != nullptr) delete m_pCells;
|
||||
// m_nWidth = 0;
|
||||
// m_nHeight = 0;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//class cCarCrimeCity : public olc::PixelGameEngine
|
||||
//{
|
||||
//public:
|
||||
// cCarCrimeCity()
|
||||
// {
|
||||
// sAppName = "Car Crime City";
|
||||
// }
|
||||
//
|
||||
// ~cCarCrimeCity()
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// bool OnUserCreate()
|
||||
// {
|
||||
// // Initialise PGEX 3D
|
||||
// olc::GFX3D::ConfigureDisplay();
|
||||
//
|
||||
// // Create Default city
|
||||
// pCity = new cCityMap(64, 32);// cGameSettings::nDefaultMapWidth, cGameSettings::nDefaultMapHeight);
|
||||
//
|
||||
//
|
||||
// // A simple flat unit quad
|
||||
// meshQuad.tris =
|
||||
// {
|
||||
// { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, olc::RED },
|
||||
// { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, olc::RED},
|
||||
// };
|
||||
//
|
||||
//
|
||||
// sprOld = new olc::Sprite("assets/system/grass1.png");
|
||||
//
|
||||
//
|
||||
//
|
||||
// SetDrawTarget(nullptr);
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// bool OnUserUpdate(float fElapsedTime)
|
||||
// {
|
||||
// // User Input
|
||||
// if (GetKey(olc::Key::W).bHeld) vCamera.y -= 2.0f * fElapsedTime;
|
||||
// if (GetKey(olc::Key::S).bHeld) vCamera.y += 2.0f * fElapsedTime;
|
||||
// if (GetKey(olc::Key::A).bHeld) vCamera.x -= 2.0f * fElapsedTime;
|
||||
// if (GetKey(olc::Key::D).bHeld) vCamera.x += 2.0f * fElapsedTime;
|
||||
// if (GetKey(olc::Key::Z).bHeld) vCamera.z += 10.0f * fElapsedTime;
|
||||
// if (GetKey(olc::Key::X).bHeld) vCamera.z -= 10.0f * fElapsedTime;
|
||||
//
|
||||
//
|
||||
// vEye = vCamera;
|
||||
//
|
||||
// // Perform Ray casting to calculate visible world extents and mouse position
|
||||
// olc::GFX3D::vec3d vLookTarget = olc::GFX3D::Math::Vec_Add(vEye, vLookDir);
|
||||
// olc::GFX3D::mat4x4 matProj = olc::GFX3D::Math::Mat_MakeProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.5f, 1000.0f);
|
||||
// olc::GFX3D::mat4x4 matView = olc::GFX3D::Math::Mat_PointAt(vEye, vLookTarget, vUp);
|
||||
//
|
||||
//
|
||||
//
|
||||
// // Render Scene
|
||||
// Clear(olc::BLUE);
|
||||
// olc::GFX3D::ClearDepth();
|
||||
//
|
||||
// // Create rendering pipeline
|
||||
// olc::GFX3D::PipeLine pipe;
|
||||
// pipe.SetProjection(90.0f, (float)ScreenHeight() / (float)ScreenWidth(), 0.5f, 1000.0f, 0.0f, 0.0f, (float)ScreenWidth(), (float)ScreenHeight());
|
||||
// pipe.SetCamera(vEye, vLookTarget, vUp);
|
||||
//
|
||||
//
|
||||
//
|
||||
// int nStartX = 0;
|
||||
// int nEndX = pCity->GetWidth();
|
||||
// int nStartY = 0;
|
||||
// int nEndY = pCity->GetHeight();
|
||||
//
|
||||
// // Render Ground, Roads, Walls & Buildings
|
||||
// for (int x = nStartX; x < nEndX; x++)
|
||||
// {
|
||||
// if (x == 15)
|
||||
// int k = 7;
|
||||
//
|
||||
// for (int y = nStartY; y < nEndY; y++)
|
||||
// {
|
||||
//
|
||||
//
|
||||
// switch (pCity->Cell(x, y)->nType)
|
||||
// {
|
||||
// case CELL_GRASS:
|
||||
// {
|
||||
// olc::GFX3D::mat4x4 matWorld;
|
||||
// matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)x, (float)y, 0.0f);
|
||||
// pipe.SetTransform(matWorld);
|
||||
// pipe.SetTexture(sprOld);
|
||||
// //pipe.SetTexture(vecSpriteSystem[0]);
|
||||
// //pipe.Render(vecMeshSystem[0].tris);
|
||||
// pipe.Render(meshQuad.tris);
|
||||
// //pipe.Render(vecMeshSystem[0].tris, olc::GFX3D::RENDER_FLAT);
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// default:
|
||||
// {
|
||||
// olc::GFX3D::mat4x4 matWorld;
|
||||
// matWorld = olc::GFX3D::Math::Mat_MakeTranslation((float)x, (float)y, 0.0f);
|
||||
// pipe.SetTransform(matWorld);
|
||||
// pipe.Render(meshQuad.tris, olc::GFX3D::RENDER_WIRE);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
//
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// bool OnUserDestroy()
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
//
|
||||
//private:
|
||||
// olc::GFX3D::vec3d vCamera = { 0.0f, 0.0f, -10.0f };
|
||||
// olc::GFX3D::vec3d vUp = { 0.0f, 1.0f, 0.0f };
|
||||
// olc::GFX3D::vec3d vEye = { 0.0f, 0.0f, -10.0f };
|
||||
// olc::GFX3D::vec3d vLookDir = { 0.0f, 0.0f, 1.0f };
|
||||
//
|
||||
//
|
||||
//
|
||||
// olc::Sprite *sprOld = nullptr;
|
||||
// olc::GFX3D::mesh meshQuad;
|
||||
//
|
||||
// cCityMap *pCity = nullptr;
|
||||
//
|
||||
//
|
||||
//
|
||||
//};
|
||||
//
|
||||
//int main()
|
||||
//{
|
||||
// // Load the settings singleton
|
||||
// /*cGameSettings config;
|
||||
// if (!config.LoadConfigFile("assets/config.lua"))
|
||||
// {
|
||||
// std::cout << "Failed to load '/assets/config.lua'" << std::endl;
|
||||
// std::cout << " -> Using default configuration" << std::endl;
|
||||
// }*/
|
||||
//
|
||||
// // Start the PixelGameEngine
|
||||
// cCarCrimeCity game;
|
||||
// if (game.Construct(256, 240, 4, 4))// config.nScreenWidth, config.nScreenHeight, config.nPixelWidth, config.nPixelHeight))
|
||||
// game.Start();
|
||||
//
|
||||
// // Exit!
|
||||
// return 0;
|
||||
//}
|
||||
1725
Videos/CarCrimeCity/Part2/olcPGEX_Graphics3D.h
Normal file
5
Videos/CarCrimeCity/Part2/olcPixelGameEngine.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#define OLC_PGEX_GRAPHICS3D
|
||||
#include "olcPGEX_Graphics3D.h"
|
||||
2317
Videos/CarCrimeCity/Part2/olcPixelGameEngine.h
Normal file
BIN
Videos/DemoBinaries/OLC_8BitsImProc.zip
Normal file
504
Videos/OneLoneCoder_PGE_8BitsImProc.cpp
Normal file
@@ -0,0 +1,504 @@
|
||||
/*
|
||||
8-Bits Of Image Processing You Should Know
|
||||
"Colin, at least you'll always get 700s now..." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Instructions:
|
||||
~~~~~~~~~~~~~
|
||||
Choose algorithm 1-8, instructions on screen
|
||||
|
||||
|
||||
Relevant Video: https://youtu.be/mRM5Js3VLCk
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#include "escapi.h"
|
||||
|
||||
int nFrameWidth = 320;
|
||||
int nFrameHeight = 240;
|
||||
|
||||
struct frame
|
||||
{
|
||||
float *pixels = nullptr;
|
||||
|
||||
frame()
|
||||
{
|
||||
pixels = new float[nFrameWidth * nFrameHeight];
|
||||
}
|
||||
|
||||
~frame()
|
||||
{
|
||||
delete[] pixels;
|
||||
}
|
||||
|
||||
|
||||
float get(int x, int y)
|
||||
{
|
||||
if (x >= 0 && x < nFrameWidth && y >= 0 && y < nFrameHeight)
|
||||
{
|
||||
return pixels[y*nFrameWidth + x];
|
||||
}
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void set(int x, int y, float p)
|
||||
{
|
||||
if (x >= 0 && x < nFrameWidth && y >= 0 && y < nFrameHeight)
|
||||
{
|
||||
pixels[y*nFrameWidth + x] = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void operator=(const frame &f)
|
||||
{
|
||||
memcpy(this->pixels, f.pixels, nFrameWidth * nFrameHeight * sizeof(float));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class WIP_ImageProcessing : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
WIP_ImageProcessing()
|
||||
{
|
||||
sAppName = "WIP_ImageProcessing";
|
||||
}
|
||||
|
||||
union RGBint
|
||||
{
|
||||
int rgb;
|
||||
unsigned char c[4];
|
||||
};
|
||||
|
||||
int nCameras = 0;
|
||||
SimpleCapParams capture;
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
// Initialise webcam to screen dimensions
|
||||
nCameras = setupESCAPI();
|
||||
if (nCameras == 0) return false;
|
||||
capture.mWidth = nFrameWidth;
|
||||
capture.mHeight = nFrameHeight;
|
||||
capture.mTargetBuf = new int[nFrameWidth * nFrameHeight];
|
||||
if (initCapture(0, &capture) == 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrawFrame(frame &f, int x, int y)
|
||||
{
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
int c = (int)std::min(std::max(0.0f, f.pixels[j*nFrameWidth + i] * 255.0f), 255.0f);
|
||||
Draw(x + i, y + j, olc::Pixel(c, c, c));
|
||||
}
|
||||
}
|
||||
|
||||
enum ALGORITHM
|
||||
{
|
||||
THRESHOLD, MOTION, LOWPASS, CONVOLUTION,
|
||||
SOBEL, MORPHO, MEDIAN, ADAPTIVE,
|
||||
};
|
||||
|
||||
enum MORPHOP
|
||||
{
|
||||
DILATION,
|
||||
EROSION,
|
||||
EDGE
|
||||
};
|
||||
|
||||
frame input, output, prev_input, activity, threshold;
|
||||
|
||||
// Algorithm Currently Running
|
||||
ALGORITHM algo = THRESHOLD;
|
||||
MORPHOP morph = DILATION;
|
||||
int nMorphCount = 1;
|
||||
|
||||
float fThresholdValue = 0.5f;
|
||||
float fLowPassRC = 0.1f;
|
||||
float fAdaptiveBias = 1.1f;
|
||||
|
||||
float *pConvoKernel = kernel_blur;
|
||||
|
||||
float kernel_blur[9] =
|
||||
{
|
||||
0.0f, 0.125, 0.0f,
|
||||
0.125f, 0.5f, 0.125f,
|
||||
0.0f, 0.125f, 0.0f,
|
||||
};
|
||||
|
||||
float kernel_sharpen[9] =
|
||||
{
|
||||
0.0f, -1.0f, 0.0f,
|
||||
-1.0f, 5.0f, -1.0f,
|
||||
0.0f, -1.0f, 0.0f,
|
||||
};
|
||||
|
||||
float kernel_sobel_v[9] =
|
||||
{
|
||||
-1.0f, 0.0f, +1.0f,
|
||||
-2.0f, 0.0f, +2.0f,
|
||||
-1.0f, 0.0f, +1.0f,
|
||||
};
|
||||
|
||||
float kernel_sobel_h[9] =
|
||||
{
|
||||
-1.0f, -2.0f, -1.0f,
|
||||
0.0f, 0.0f, 0.0f,
|
||||
+1.0f, +2.0f, +1.0f,
|
||||
};
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
// CAPTURING WEBCAM IMAGE
|
||||
prev_input = input;
|
||||
doCapture(0); while (isCaptureDone(0) == 0) {}
|
||||
for (int y = 0; y < capture.mHeight; y++)
|
||||
for (int x = 0; x < capture.mWidth; x++)
|
||||
{
|
||||
RGBint col;
|
||||
int id = y * capture.mWidth + x;
|
||||
col.rgb = capture.mTargetBuf[id];
|
||||
input.pixels[y*nFrameWidth + x] = (float)col.c[1] / 255.0f;
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::K1).bReleased) algo = THRESHOLD;
|
||||
if (GetKey(olc::Key::K2).bReleased) algo = MOTION;
|
||||
if (GetKey(olc::Key::K3).bReleased) algo = LOWPASS;
|
||||
if (GetKey(olc::Key::K4).bReleased) algo = CONVOLUTION;
|
||||
if (GetKey(olc::Key::K5).bReleased) algo = SOBEL;
|
||||
if (GetKey(olc::Key::K6).bReleased) algo = MORPHO;
|
||||
if (GetKey(olc::Key::K7).bReleased) algo = MEDIAN;
|
||||
if (GetKey(olc::Key::K8).bReleased) algo = ADAPTIVE;
|
||||
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case THRESHOLD:
|
||||
|
||||
// Respond to user input
|
||||
if (GetKey(olc::Key::Z).bHeld) fThresholdValue -= 0.1f * fElapsedTime;
|
||||
if (GetKey(olc::Key::X).bHeld) fThresholdValue += 0.1f * fElapsedTime;
|
||||
if (fThresholdValue > 1.0f) fThresholdValue = 1.0f;
|
||||
if (fThresholdValue < 0.0f) fThresholdValue = 0.0f;
|
||||
|
||||
// Perform threshold per pixel
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
output.set(i, j, input.get(i, j) >= fThresholdValue ? 1.0f : 0.0f);
|
||||
break;
|
||||
|
||||
case MOTION:
|
||||
|
||||
// Returns the absolute difference between successive frames per pixel
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
output.set(i, j, fabs(input.get(i, j) - prev_input.get(i, j)));
|
||||
break;
|
||||
|
||||
|
||||
case LOWPASS:
|
||||
|
||||
// Respond to user input
|
||||
if (GetKey(olc::Key::Z).bHeld) fLowPassRC -= 0.1f * fElapsedTime;
|
||||
if (GetKey(olc::Key::X).bHeld) fLowPassRC += 0.1f * fElapsedTime;
|
||||
if (fLowPassRC > 1.0f) fLowPassRC = 1.0f;
|
||||
if (fLowPassRC < 0.0f) fLowPassRC = 0.0f;
|
||||
|
||||
// Pass each pixel through a temporal RC filter
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
float dPixel = input.get(i, j) - output.get(i, j);
|
||||
dPixel *= fLowPassRC;
|
||||
output.set(i, j, dPixel + output.get(i, j));
|
||||
}
|
||||
break;
|
||||
|
||||
case CONVOLUTION:
|
||||
// Respond to user input
|
||||
if (GetKey(olc::Key::Z).bHeld) pConvoKernel = kernel_blur;
|
||||
if (GetKey(olc::Key::X).bHeld) pConvoKernel = kernel_sharpen;
|
||||
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
float fSum = 0.0f;
|
||||
for (int n = -1; n < +2; n++)
|
||||
for (int m = -1; m < +2; m++)
|
||||
fSum += input.get(i + n, j + m) * pConvoKernel[(m + 1) * 3 + (n + 1)];
|
||||
|
||||
output.set(i, j, fSum);
|
||||
}
|
||||
break;
|
||||
|
||||
case SOBEL:
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
float fKernelSumH = 0.0f;
|
||||
float fKernelSumV = 0.0f;
|
||||
|
||||
for (int n = -1; n < +2; n++)
|
||||
for (int m = -1; m < +2; m++)
|
||||
{
|
||||
fKernelSumH += input.get(i + n, j + m) * kernel_sobel_h[(m + 1) * 3 + (n + 1)];
|
||||
fKernelSumV += input.get(i + n, j + m) * kernel_sobel_v[(m + 1) * 3 + (n + 1)];
|
||||
}
|
||||
|
||||
output.set(i, j, fabs((fKernelSumH + fKernelSumV) / 2.0f));
|
||||
}
|
||||
break;
|
||||
|
||||
case MORPHO:
|
||||
|
||||
// Respond to user input
|
||||
if (GetKey(olc::Key::Z).bHeld) morph = DILATION;
|
||||
if (GetKey(olc::Key::X).bHeld) morph = EROSION;
|
||||
if (GetKey(olc::Key::C).bHeld) morph = EDGE;
|
||||
|
||||
if (GetKey(olc::Key::A).bReleased) nMorphCount--;
|
||||
if (GetKey(olc::Key::S).bReleased) nMorphCount++;
|
||||
if (nMorphCount > 10.0f) nMorphCount = 10.0f;
|
||||
if (nMorphCount < 1.0f) nMorphCount = 1.0f;
|
||||
|
||||
// Threshold First to binarise image
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
activity.set(i, j, input.get(i, j) > fThresholdValue ? 1.0f : 0.0f);
|
||||
}
|
||||
|
||||
threshold = activity;
|
||||
|
||||
switch (morph)
|
||||
{
|
||||
case DILATION:
|
||||
for (int n = 0; n < nMorphCount; n++)
|
||||
{
|
||||
output = activity;
|
||||
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
if (activity.get(i, j) == 1.0f)
|
||||
{
|
||||
output.set(i, j, 1.0f);
|
||||
output.set(i - 1, j, 1.0f);
|
||||
output.set(i + 1, j, 1.0f);
|
||||
output.set(i, j - 1, 1.0f);
|
||||
output.set(i, j + 1, 1.0f);
|
||||
output.set(i - 1, j - 1, 1.0f);
|
||||
output.set(i + 1, j + 1, 1.0f);
|
||||
output.set(i + 1, j - 1, 1.0f);
|
||||
output.set(i - 1, j + 1, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
activity = output;
|
||||
}
|
||||
break;
|
||||
|
||||
case EROSION:
|
||||
for (int n = 0; n < nMorphCount; n++)
|
||||
{
|
||||
output = activity;
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
|
||||
float sum = activity.get(i - 1, j) + activity.get(i + 1, j) + activity.get(i, j - 1) + activity.get(i, j + 1) +
|
||||
activity.get(i - 1, j - 1) + activity.get(i + 1, j + 1) + activity.get(i + 1, j - 1) + activity.get(i - 1, j + 1);
|
||||
|
||||
if (activity.get(i, j) == 1.0f && sum < 8.0f)
|
||||
{
|
||||
output.set(i, j, 0.0f);
|
||||
}
|
||||
}
|
||||
activity = output;
|
||||
}
|
||||
break;
|
||||
|
||||
case EDGE:
|
||||
output = activity;
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
|
||||
float sum = activity.get(i - 1, j) + activity.get(i + 1, j) + activity.get(i, j - 1) + activity.get(i, j + 1) +
|
||||
activity.get(i - 1, j - 1) + activity.get(i + 1, j + 1) + activity.get(i + 1, j - 1) + activity.get(i - 1, j + 1);
|
||||
|
||||
if (activity.get(i, j) == 1.0f && sum == 8.0f)
|
||||
{
|
||||
output.set(i, j, 0.0f);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case MEDIAN:
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
std::vector<float> v;
|
||||
|
||||
for (int n = -2; n < +3; n++)
|
||||
for (int m = -2; m < +3; m++)
|
||||
v.push_back(input.get(i + n, j + m));
|
||||
|
||||
std::sort(v.begin(), v.end(), std::greater<float>());
|
||||
output.set(i, j, v[12]);
|
||||
}
|
||||
break;
|
||||
|
||||
case ADAPTIVE:
|
||||
// Respond to user input
|
||||
if (GetKey(olc::Key::Z).bHeld) fAdaptiveBias -= 0.1f * fElapsedTime;
|
||||
if (GetKey(olc::Key::X).bHeld) fAdaptiveBias += 0.1f * fElapsedTime;
|
||||
if (fAdaptiveBias > 1.5f) fAdaptiveBias = 1.5f;
|
||||
if (fAdaptiveBias < 0.5f) fAdaptiveBias = 0.5f;
|
||||
|
||||
|
||||
for (int i = 0; i < nFrameWidth; i++)
|
||||
for (int j = 0; j < nFrameHeight; j++)
|
||||
{
|
||||
float fRegionSum = 0.0f;
|
||||
|
||||
for (int n = -2; n < +3; n++)
|
||||
for (int m = -2; m < +3; m++)
|
||||
fRegionSum += input.get(i + n, j + m);
|
||||
|
||||
fRegionSum /= 25.0f;
|
||||
output.set(i, j, input.get(i, j) > (fRegionSum * fAdaptiveBias) ? 1.0f : 0.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// DRAW STUFF ONLY HERE
|
||||
Clear(olc::DARK_BLUE);
|
||||
DrawFrame(algo == MORPHO ? threshold : input, 10, 10);
|
||||
DrawFrame(output, 340, 10);
|
||||
|
||||
DrawString(150, 255, "INPUT");
|
||||
DrawString(480, 255, "OUTPUT");
|
||||
|
||||
DrawString(10, 275, "1) Threshold");
|
||||
DrawString(10, 285, "2) Absolute Motion");
|
||||
DrawString(10, 295, "3) Low-Pass Temporal Filtering");
|
||||
DrawString(10, 305, "4) Convolution (Blurring/Sharpening)");
|
||||
DrawString(10, 315, "5) Sobel Edge Detection");
|
||||
DrawString(10, 325, "6) Binary Morphological Operations (Erosion/Dilation)");
|
||||
DrawString(10, 335, "7) Median Filter");
|
||||
DrawString(10, 345, "8) Adaptive Threshold");
|
||||
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
case THRESHOLD:
|
||||
DrawString(10, 375, "Change threshold value with Z and X keys");
|
||||
DrawString(10, 385, "Current value = " + std::to_string(fThresholdValue));
|
||||
break;
|
||||
|
||||
case LOWPASS:
|
||||
DrawString(10, 375, "Change RC constant value with Z and X keys");
|
||||
DrawString(10, 385, "Current value = " + std::to_string(fLowPassRC));
|
||||
break;
|
||||
|
||||
case CONVOLUTION:
|
||||
DrawString(10, 375, "Change convolution kernel with Z and X keys");
|
||||
DrawString(10, 385, "Current kernel = " + std::string((pConvoKernel == kernel_blur) ? "Blur" : "Sharpen"));
|
||||
break;
|
||||
|
||||
case MORPHO:
|
||||
DrawString(10, 375, "Change operation with Z and X and C keys");
|
||||
if (morph == DILATION) DrawString(10, 385, "Current operation = DILATION");
|
||||
if (morph == EROSION) DrawString(10, 385, "Current operation = EROSION");
|
||||
if (morph == EDGE) DrawString(10, 385, "Current operation = EDGE");
|
||||
DrawString(10, 395, "Change Iterations with A and S keys");
|
||||
DrawString(10, 405, "Current iteration count = " + std::to_string(nMorphCount));
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case ADAPTIVE:
|
||||
DrawString(10, 375, "Change adaptive threshold bias with Z and X keys");
|
||||
DrawString(10, 385, "Current value = " + std::to_string(fAdaptiveBias));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::ESCAPE).bPressed) return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
WIP_ImageProcessing demo;
|
||||
if (demo.Construct(670, 460, 2, 2))
|
||||
demo.Start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
431
Videos/OneLoneCoder_PGE_DungeonWarping.cpp
Normal file
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
Dungeon Warping via Orthographic Projections
|
||||
"For my Mother-In-Law, you will be missed..." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2020 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Relevant Video: https://youtu.be/Ql5VZGkL23o
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Community Blog: https://community.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018, 2019, 2020
|
||||
*/
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
/*
|
||||
|
||||
NOTE! This program requires a tile spritesheet NOT
|
||||
provided in this github. You only need a few tiles,
|
||||
see video for details.
|
||||
|
||||
*/
|
||||
|
||||
class olcDungeon : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
olcDungeon()
|
||||
{
|
||||
sAppName = "Dungeon Explorer";
|
||||
}
|
||||
|
||||
struct Renderable
|
||||
{
|
||||
Renderable() {}
|
||||
|
||||
void Load(const std::string& sFile)
|
||||
{
|
||||
sprite = new olc::Sprite(sFile);
|
||||
decal = new olc::Decal(sprite);
|
||||
}
|
||||
|
||||
~Renderable()
|
||||
{
|
||||
delete decal;
|
||||
delete sprite;
|
||||
}
|
||||
|
||||
olc::Sprite* sprite = nullptr;
|
||||
olc::Decal* decal = nullptr;
|
||||
};
|
||||
|
||||
struct vec3d
|
||||
{
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
struct sQuad
|
||||
{
|
||||
vec3d points[4];
|
||||
olc::vf2d tile;
|
||||
};
|
||||
|
||||
struct sCell
|
||||
{
|
||||
bool wall = false;
|
||||
olc::vi2d id[6]{ };
|
||||
};
|
||||
|
||||
class World
|
||||
{
|
||||
public:
|
||||
World()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Create(int w, int h)
|
||||
{
|
||||
size = { w, h };
|
||||
vCells.resize(w * h);
|
||||
}
|
||||
|
||||
sCell& GetCell(const olc::vi2d& v)
|
||||
{
|
||||
if (v.x >= 0 && v.x < size.x && v.y >= 0 && v.y < size.y)
|
||||
return vCells[v.y * size.x + v.x];
|
||||
else
|
||||
return NullCell;
|
||||
}
|
||||
|
||||
public:
|
||||
olc::vi2d size;
|
||||
|
||||
private:
|
||||
std::vector<sCell> vCells;
|
||||
sCell NullCell;
|
||||
};
|
||||
|
||||
World world;
|
||||
Renderable rendSelect;
|
||||
Renderable rendAllWalls;
|
||||
|
||||
olc::vf2d vCameraPos = { 0.0f, 0.0f };
|
||||
float fCameraAngle = 0.0f;
|
||||
float fCameraAngleTarget = fCameraAngle;
|
||||
float fCameraPitch = 5.5f;
|
||||
float fCameraZoom = 16.0f;
|
||||
|
||||
bool bVisible[6];
|
||||
|
||||
olc::vi2d vCursor = { 0, 0 };
|
||||
olc::vi2d vTileCursor = { 0,0 };
|
||||
olc::vi2d vTileSize = { 32, 32 };
|
||||
|
||||
enum Face
|
||||
{
|
||||
Floor = 0,
|
||||
North = 1,
|
||||
East = 2,
|
||||
South = 3,
|
||||
West = 4,
|
||||
Top = 5
|
||||
};
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
rendSelect.Load("./gfx/dng_select.png");
|
||||
rendAllWalls.Load("./gfx/oldDungeon.png");
|
||||
|
||||
world.Create(64, 64);
|
||||
|
||||
for (int y=0; y<world.size.y; y++)
|
||||
for(int x=0; x<world.size.x; x++)
|
||||
{
|
||||
world.GetCell({ x, y }).wall = false;
|
||||
world.GetCell({ x, y }).id[Face::Floor] = olc::vi2d{ 3, 0 } * vTileSize;
|
||||
world.GetCell({ x, y }).id[Face::Top] = olc::vi2d{ 1, 0 } * vTileSize;
|
||||
world.GetCell({ x, y }).id[Face::North] = olc::vi2d{ 0, 6 } * vTileSize;
|
||||
world.GetCell({ x, y }).id[Face::South] = olc::vi2d{ 0, 6 } * vTileSize;
|
||||
world.GetCell({ x, y }).id[Face::West] = olc::vi2d{ 0, 6 } * vTileSize;
|
||||
world.GetCell({ x, y }).id[Face::East] = olc::vi2d{ 0, 6 } * vTileSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::array<vec3d, 8> CreateCube(const olc::vi2d& vCell, const float fAngle, const float fPitch, const float fScale, const vec3d& vCamera)
|
||||
{
|
||||
// Unit Cube
|
||||
std::array<vec3d, 8> unitCube, rotCube, worldCube, projCube;
|
||||
unitCube[0] = { 0.0f, 0.0f, 0.0f };
|
||||
unitCube[1] = { fScale, 0.0f, 0.0f };
|
||||
unitCube[2] = { fScale, -fScale, 0.0f };
|
||||
unitCube[3] = { 0.0f, -fScale, 0.0f };
|
||||
unitCube[4] = { 0.0f, 0.0f, fScale };
|
||||
unitCube[5] = { fScale, 0.0f, fScale };
|
||||
unitCube[6] = { fScale, -fScale, fScale };
|
||||
unitCube[7] = { 0.0f, -fScale, fScale };
|
||||
|
||||
// Translate Cube in X-Z Plane
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
unitCube[i].x += (vCell.x * fScale - vCamera.x);
|
||||
unitCube[i].y += -vCamera.y;
|
||||
unitCube[i].z += (vCell.y * fScale - vCamera.z);
|
||||
}
|
||||
|
||||
// Rotate Cube in Y-Axis around origin
|
||||
float s = sin(fAngle);
|
||||
float c = cos(fAngle);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
rotCube[i].x = unitCube[i].x * c + unitCube[i].z * s;
|
||||
rotCube[i].y = unitCube[i].y;
|
||||
rotCube[i].z = unitCube[i].x * -s + unitCube[i].z * c;
|
||||
}
|
||||
|
||||
// Rotate Cube in X-Axis around origin (tilt slighly overhead)
|
||||
s = sin(fPitch);
|
||||
c = cos(fPitch);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
worldCube[i].x = rotCube[i].x;
|
||||
worldCube[i].y = rotCube[i].y * c - rotCube[i].z * s;
|
||||
worldCube[i].z = rotCube[i].y * s + rotCube[i].z * c;
|
||||
}
|
||||
|
||||
// Project Cube Orthographically - Unit Cube Viewport
|
||||
//float fLeft = -ScreenWidth() * 0.5f;
|
||||
//float fRight = ScreenWidth() * 0.5f;
|
||||
//float fTop = ScreenHeight() * 0.5f;
|
||||
//float fBottom = -ScreenHeight() * 0.5f;
|
||||
//float fNear = 0.1f;
|
||||
//float fFar = 100.0f;*/
|
||||
//for (int i = 0; i < 8; i++)
|
||||
//{
|
||||
// projCube[i].x = (2.0f / (fRight - fLeft)) * worldCube[i].x - ((fRight + fLeft) / (fRight - fLeft));
|
||||
// projCube[i].y = (2.0f / (fTop - fBottom)) * worldCube[i].y - ((fTop + fBottom) / (fTop - fBottom));
|
||||
// projCube[i].z = (2.0f / (fFar - fNear)) * worldCube[i].z - ((fFar + fNear) / (fFar - fNear));
|
||||
// projCube[i].x *= -fRight;
|
||||
// projCube[i].y *= -fTop;
|
||||
// projCube[i].x += fRight;
|
||||
// projCube[i].y += fTop;
|
||||
//}
|
||||
|
||||
// Project Cube Orthographically - Full Screen Centered
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
projCube[i].x = worldCube[i].x + ScreenWidth() * 0.5f;
|
||||
projCube[i].y = worldCube[i].y + ScreenHeight() * 0.5f;
|
||||
projCube[i].z = worldCube[i].z;
|
||||
}
|
||||
|
||||
return projCube;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CalculateVisibleFaces(std::array<vec3d, 8>& cube)
|
||||
{
|
||||
auto CheckNormal = [&](int v1, int v2, int v3)
|
||||
{
|
||||
olc::vf2d a = { cube[v1].x, cube[v1].y };
|
||||
olc::vf2d b = { cube[v2].x, cube[v2].y };
|
||||
olc::vf2d c = { cube[v3].x, cube[v3].y };
|
||||
return (b - a).cross(c - a) > 0;
|
||||
};
|
||||
|
||||
bVisible[Face::Floor] = CheckNormal(4, 0, 1);
|
||||
bVisible[Face::South] = CheckNormal(3, 0, 1);
|
||||
bVisible[Face::North] = CheckNormal(6, 5, 4);
|
||||
bVisible[Face::East] = CheckNormal(7, 4, 0);
|
||||
bVisible[Face::West] = CheckNormal(2, 1, 5);
|
||||
bVisible[Face::Top] = CheckNormal(7, 3, 2);
|
||||
}
|
||||
|
||||
void GetFaceQuads(const olc::vi2d& vCell, const float fAngle, const float fPitch, const float fScale, const vec3d& vCamera, std::vector<sQuad> &render)
|
||||
{
|
||||
std::array<vec3d, 8> projCube = CreateCube(vCell, fAngle, fPitch, fScale, vCamera);
|
||||
|
||||
auto& cell = world.GetCell(vCell);
|
||||
|
||||
auto MakeFace = [&](int v1, int v2, int v3, int v4, Face f)
|
||||
{
|
||||
render.push_back({ projCube[v1], projCube[v2], projCube[v3], projCube[v4], cell.id[f] });
|
||||
};
|
||||
|
||||
if (!cell.wall)
|
||||
{
|
||||
if(bVisible[Face::Floor]) MakeFace(4, 0, 1, 5, Face::Floor);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bVisible[Face::South]) MakeFace(3, 0, 1, 2, Face::South);
|
||||
if (bVisible[Face::North]) MakeFace(6, 5, 4, 7, Face::North);
|
||||
if (bVisible[Face::East]) MakeFace(7, 4, 0, 3, Face::East);
|
||||
if (bVisible[Face::West]) MakeFace(2, 1, 5, 6, Face::West);
|
||||
if (bVisible[Face::Top]) MakeFace(7, 3, 2, 6, Face::Top);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
// Grab mouse for convenience
|
||||
olc::vi2d vMouse = { GetMouseX(), GetMouseY() };
|
||||
|
||||
// Edit mode - Selection from tile sprite sheet
|
||||
if (GetKey(olc::Key::TAB).bHeld)
|
||||
{
|
||||
DrawSprite({ 0, 0 }, rendAllWalls.sprite);
|
||||
DrawRect(vTileCursor * vTileSize, vTileSize);
|
||||
if (GetMouse(0).bPressed) vTileCursor = vMouse / vTileSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
// WS keys to tilt camera
|
||||
if (GetKey(olc::Key::W).bHeld) fCameraPitch += 1.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::S).bHeld) fCameraPitch -= 1.0f * fElapsedTime;
|
||||
|
||||
// DA Keys to manually rotate camera
|
||||
if (GetKey(olc::Key::D).bHeld) fCameraAngleTarget += 1.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::A).bHeld) fCameraAngleTarget -= 1.0f * fElapsedTime;
|
||||
|
||||
// QZ Keys to zoom in or out
|
||||
if (GetKey(olc::Key::Q).bHeld) fCameraZoom += 5.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::Z).bHeld) fCameraZoom -= 5.0f * fElapsedTime;
|
||||
|
||||
// Numpad keys used to rotate camera to fixed angles
|
||||
if (GetKey(olc::Key::NP2).bPressed) fCameraAngleTarget = 3.14159f * 0.0f;
|
||||
if (GetKey(olc::Key::NP1).bPressed) fCameraAngleTarget = 3.14159f * 0.25f;
|
||||
if (GetKey(olc::Key::NP4).bPressed) fCameraAngleTarget = 3.14159f * 0.5f;
|
||||
if (GetKey(olc::Key::NP7).bPressed) fCameraAngleTarget = 3.14159f * 0.75f;
|
||||
if (GetKey(olc::Key::NP8).bPressed) fCameraAngleTarget = 3.14159f * 1.0f;
|
||||
if (GetKey(olc::Key::NP9).bPressed) fCameraAngleTarget = 3.14159f * 1.25f;
|
||||
if (GetKey(olc::Key::NP6).bPressed) fCameraAngleTarget = 3.14159f * 1.5f;
|
||||
if (GetKey(olc::Key::NP3).bPressed) fCameraAngleTarget = 3.14159f * 1.75f;
|
||||
|
||||
// Numeric keys apply selected tile to specific face
|
||||
if (GetKey(olc::Key::K1).bPressed) world.GetCell(vCursor).id[Face::North] = vTileCursor * vTileSize;
|
||||
if (GetKey(olc::Key::K2).bPressed) world.GetCell(vCursor).id[Face::East] = vTileCursor * vTileSize;
|
||||
if (GetKey(olc::Key::K3).bPressed) world.GetCell(vCursor).id[Face::South] = vTileCursor * vTileSize;
|
||||
if (GetKey(olc::Key::K4).bPressed) world.GetCell(vCursor).id[Face::West] = vTileCursor * vTileSize;
|
||||
if (GetKey(olc::Key::K5).bPressed) world.GetCell(vCursor).id[Face::Floor] = vTileCursor * vTileSize;
|
||||
if (GetKey(olc::Key::K6).bPressed) world.GetCell(vCursor).id[Face::Top] = vTileCursor * vTileSize;
|
||||
|
||||
// Smooth camera
|
||||
fCameraAngle += (fCameraAngleTarget - fCameraAngle) * 10.0f * fElapsedTime;
|
||||
|
||||
// Arrow keys to move the selection cursor around map (boundary checked)
|
||||
if (GetKey(olc::Key::LEFT).bPressed) vCursor.x--;
|
||||
if (GetKey(olc::Key::RIGHT).bPressed) vCursor.x++;
|
||||
if (GetKey(olc::Key::UP).bPressed) vCursor.y--;
|
||||
if (GetKey(olc::Key::DOWN).bPressed) vCursor.y++;
|
||||
if (vCursor.x < 0) vCursor.x = 0;
|
||||
if (vCursor.y < 0) vCursor.y = 0;
|
||||
if (vCursor.x >= world.size.x) vCursor.x = world.size.x - 1;
|
||||
if (vCursor.y >= world.size.y) vCursor.y = world.size.y - 1;
|
||||
|
||||
// Place block with space
|
||||
if (GetKey(olc::Key::SPACE).bPressed)
|
||||
{
|
||||
world.GetCell(vCursor).wall = !world.GetCell(vCursor).wall;
|
||||
}
|
||||
|
||||
// Position camera in world
|
||||
vCameraPos = { vCursor.x + 0.5f, vCursor.y + 0.5f };
|
||||
vCameraPos *= fCameraZoom;
|
||||
|
||||
// Rendering
|
||||
|
||||
// 1) Create dummy cube to extract visible face information
|
||||
// Cull faces that cannot be seen
|
||||
std::array<vec3d, 8> cullCube = CreateCube({ 0, 0 }, fCameraAngle, fCameraPitch, fCameraZoom, { vCameraPos.x, 0.0f, vCameraPos.y });
|
||||
CalculateVisibleFaces(cullCube);
|
||||
|
||||
// 2) Get all visible sides of all visible "tile cubes"
|
||||
std::vector<sQuad> vQuads;
|
||||
for(int y = 0; y<world.size.y; y++)
|
||||
for(int x=0; x<world.size.x; x++)
|
||||
GetFaceQuads({ x, y }, fCameraAngle, fCameraPitch, fCameraZoom, { vCameraPos.x, 0.0f, vCameraPos.y }, vQuads);
|
||||
|
||||
// 3) Sort in order of depth, from farthest away to closest
|
||||
std::sort(vQuads.begin(), vQuads.end(), [](const sQuad& q1, const sQuad& q2)
|
||||
{
|
||||
float z1 = (q1.points[0].z + q1.points[1].z + q1.points[2].z + q1.points[3].z) * 0.25f;
|
||||
float z2 = (q2.points[0].z + q2.points[1].z + q2.points[2].z + q2.points[3].z) * 0.25f;
|
||||
return z1 < z2;
|
||||
});
|
||||
|
||||
// 4) Iterate through all "tile cubes" and draw their visible faces
|
||||
Clear(olc::BLACK);
|
||||
for (auto& q : vQuads)
|
||||
DrawPartialWarpedDecal
|
||||
(
|
||||
rendAllWalls.decal,
|
||||
{ {q.points[0].x, q.points[0].y}, {q.points[1].x, q.points[1].y}, {q.points[2].x, q.points[2].y}, {q.points[3].x, q.points[3].y} },
|
||||
q.tile,
|
||||
vTileSize
|
||||
);
|
||||
|
||||
// 5) Draw current tile selection
|
||||
DrawPartialDecal({ 10,10 }, rendAllWalls.decal, vTileCursor * vTileSize, vTileSize);
|
||||
|
||||
// 6) Draw selection "tile cube"
|
||||
vQuads.clear();
|
||||
GetFaceQuads(vCursor, fCameraAngle, fCameraPitch, fCameraZoom, { vCameraPos.x, 0.0f, vCameraPos.y }, vQuads);
|
||||
for (auto& q : vQuads)
|
||||
DrawWarpedDecal(rendSelect.decal, { {q.points[0].x, q.points[0].y}, {q.points[1].x, q.points[1].y}, {q.points[2].x, q.points[2].y}, {q.points[3].x, q.points[3].y} });
|
||||
|
||||
// 7) Draw some debug info
|
||||
DrawStringDecal({ 0,0 }, "Cursor: " + std::to_string(vCursor.x) + ", " + std::to_string(vCursor.y), olc::YELLOW, { 0.5f, 0.5f });
|
||||
DrawStringDecal({ 0,8 }, "Angle: " + std::to_string(fCameraAngle) + ", " + std::to_string(fCameraPitch), olc::YELLOW, { 0.5f, 0.5f });
|
||||
|
||||
// Graceful exit if user is in full screen mode
|
||||
return !GetKey(olc::Key::ESCAPE).bPressed;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
olcDungeon demo;
|
||||
if (demo.Construct(640, 480, 2, 2, false))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,184 +1,189 @@
|
||||
/*
|
||||
OneLoneCoder_PGE_ExtensionTestGFX2D.cpp
|
||||
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018
|
||||
*/
|
||||
|
||||
// Include the olcPixelGameEngine
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
// To use an extension, just include it
|
||||
#include "olcPGEX_Graphics2D.h"
|
||||
|
||||
class TestExtension : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
TestExtension()
|
||||
{
|
||||
sAppName = "Testing Graphics2D";
|
||||
}
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
listEvents.push_back("");
|
||||
|
||||
spr = new olc::Sprite("logo_long.png");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::list<std::string> listEvents;
|
||||
float fTotalTime = 0.0f;
|
||||
olc::Sprite *spr;
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
// Clear Screen
|
||||
SetPixelMode(olc::Pixel::NORMAL);
|
||||
Clear(olc::BLUE);
|
||||
|
||||
// Draw Primitives
|
||||
DrawCircle(32, 32, 30); // Circle
|
||||
DrawCircle(96, 32, 30); // Circle
|
||||
|
||||
|
||||
float mx = GetMouseX();
|
||||
float my = GetMouseY();
|
||||
|
||||
float px1 = mx - 32, px2 = mx - 96;
|
||||
float py1 = my - 32, py2 = my - 32;
|
||||
float pr1 = 1.0f / sqrtf(px1*px1 + py1*py1);
|
||||
float pr2 = 1.0f / sqrtf(px2*px2 + py2*py2);
|
||||
px1 = 22.0f * (px1 * pr1) + 32.0f;
|
||||
py1 = 22.0f * (py1 * pr1) + 32.0f;
|
||||
px2 = 22.0f * (px2 * pr2) + 96.0f;
|
||||
py2 = 22.0f * (py2 * pr2) + 32.0f;
|
||||
FillCircle(px1, py1, 8, olc::CYAN);
|
||||
FillCircle(px2, py2, 8, olc::CYAN);
|
||||
|
||||
DrawLine(10, 70, 54, 70); // Lines
|
||||
DrawLine(54, 70, 70, 54);
|
||||
|
||||
DrawRect(10, 80, 54, 30);
|
||||
FillRect(10, 80, 54, 30);
|
||||
|
||||
// Multiline Text
|
||||
std::string mpos = "Your Mouse Position is:\nX=" + std::to_string(mx) + "\nY=" + std::to_string(my);
|
||||
DrawString(10, 130, mpos);
|
||||
|
||||
auto AddEvent = [&](std::string s)
|
||||
{
|
||||
listEvents.push_back(s);
|
||||
listEvents.pop_front();
|
||||
};
|
||||
|
||||
if (GetMouse(0).bPressed) AddEvent("Mouse Button 0 Down");
|
||||
if (GetMouse(0).bReleased) AddEvent("Mouse Button 0 Up");
|
||||
if (GetMouse(1).bPressed) AddEvent("Mouse Button 1 Down");
|
||||
if (GetMouse(1).bReleased) AddEvent("Mouse Button 1 Up");
|
||||
if (GetMouse(2).bPressed) AddEvent("Mouse Button 2 Down");
|
||||
if (GetMouse(2).bReleased) AddEvent("Mouse Button 2 Up");
|
||||
|
||||
|
||||
// Draw Event Log
|
||||
int nLog = 0;
|
||||
for (auto &s : listEvents)
|
||||
{
|
||||
DrawString(200, nLog * 8 + 20, s, olc::Pixel(nLog * 16, nLog * 16, nLog * 16));
|
||||
nLog++;
|
||||
}
|
||||
|
||||
|
||||
// Test Text scaling and colours
|
||||
DrawString(0, 360, "Text Scale = 1", olc::WHITE, 1);
|
||||
DrawString(0, 368, "Text Scale = 2", olc::BLUE, 2);
|
||||
DrawString(0, 384, "Text Scale = 3", olc::RED, 3);
|
||||
DrawString(0, 408, "Text Scale = 4", olc::YELLOW, 4);
|
||||
DrawString(0, 440, "Text Scale = 5", olc::GREEN, 5);
|
||||
|
||||
fTotalTime += fElapsedTime;
|
||||
|
||||
float fAngle = fTotalTime;
|
||||
|
||||
// Draw Sprite using extension, first create a transformation stack
|
||||
olc::GFX2D::Transform2D t1;
|
||||
|
||||
// Traslate sprite so center of image is at 0,0
|
||||
t1.Translate(-250, -35);
|
||||
// Scale the sprite
|
||||
t1.Scale(1 * sinf(fAngle) + 1, 1 * sinf(fAngle) + 1);
|
||||
// Rotate it
|
||||
t1.Rotate(fAngle*2.0f);
|
||||
// Translate to 0,100
|
||||
t1.Translate(0, 100);
|
||||
// Rotate different speed
|
||||
t1.Rotate(fAngle / 3);
|
||||
// Translate to centre of screen
|
||||
t1.Translate(320, 240);
|
||||
|
||||
SetPixelMode(olc::Pixel::ALPHA);
|
||||
|
||||
// Use extension to draw sprite with transform applied
|
||||
olc::GFX2D::DrawSprite(spr, t1);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
TestExtension demo;
|
||||
if (demo.Construct(640, 480, 2, 2))
|
||||
demo.Start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
OneLoneCoder_PGE_ExtensionTestGFX2D.cpp
|
||||
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018
|
||||
*/
|
||||
|
||||
// Include the olcPixelGameEngine
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
// To use an extension, just include it
|
||||
#define OLC_PGE_GRAPHICS2D
|
||||
#include "olcPGEX_Graphics2D.h"
|
||||
|
||||
class TestExtension : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
TestExtension()
|
||||
{
|
||||
sAppName = "Testing Graphics2D";
|
||||
}
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
listEvents.push_back("");
|
||||
|
||||
spr = new olc::Sprite("new_piskel.png");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::list<std::string> listEvents;
|
||||
float fTotalTime = 0.0f;
|
||||
olc::Sprite *spr;
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
// Clear Screen
|
||||
SetPixelMode(olc::Pixel::NORMAL);
|
||||
Clear(olc::BLUE);
|
||||
|
||||
// Draw Primitives
|
||||
DrawCircle(32, 32, 30); // Circle
|
||||
DrawCircle(96, 32, 30); // Circle
|
||||
|
||||
|
||||
float mx = (float)GetMouseX();
|
||||
float my = (float)GetMouseY();
|
||||
|
||||
float px1 = mx - 32, px2 = mx - 96;
|
||||
float py1 = my - 32, py2 = my - 32;
|
||||
float pr1 = 1.0f / sqrtf(px1*px1 + py1*py1);
|
||||
float pr2 = 1.0f / sqrtf(px2*px2 + py2*py2);
|
||||
px1 = 22.0f * (px1 * pr1) + 32.0f;
|
||||
py1 = 22.0f * (py1 * pr1) + 32.0f;
|
||||
px2 = 22.0f * (px2 * pr2) + 96.0f;
|
||||
py2 = 22.0f * (py2 * pr2) + 32.0f;
|
||||
FillCircle((int32_t)px1, (int32_t)py1, 8, olc::CYAN);
|
||||
FillCircle((int32_t)px2, (int32_t)py2, 8, olc::CYAN);
|
||||
|
||||
DrawLine(10, 70, 54, 70); // Lines
|
||||
DrawLine(54, 70, 70, 54);
|
||||
|
||||
DrawRect(10, 80, 54, 30);
|
||||
FillRect(10, 80, 54, 30);
|
||||
|
||||
// Multiline Text
|
||||
std::string mpos = "Your Mouse Position is:\nX=" + std::to_string(mx) + "\nY=" + std::to_string(my);
|
||||
DrawString(10, 130, mpos);
|
||||
|
||||
auto AddEvent = [&](std::string s)
|
||||
{
|
||||
listEvents.push_back(s);
|
||||
listEvents.pop_front();
|
||||
};
|
||||
|
||||
if (GetMouse(0).bPressed) AddEvent("Mouse Button 0 Down");
|
||||
if (GetMouse(0).bReleased) AddEvent("Mouse Button 0 Up");
|
||||
if (GetMouse(1).bPressed) AddEvent("Mouse Button 1 Down");
|
||||
if (GetMouse(1).bReleased) AddEvent("Mouse Button 1 Up");
|
||||
if (GetMouse(2).bPressed) AddEvent("Mouse Button 2 Down");
|
||||
if (GetMouse(2).bReleased) AddEvent("Mouse Button 2 Up");
|
||||
|
||||
|
||||
// Draw Event Log
|
||||
int nLog = 0;
|
||||
for (auto &s : listEvents)
|
||||
{
|
||||
DrawString(200, nLog * 8 + 20, s, olc::Pixel(nLog * 16, nLog * 16, nLog * 16));
|
||||
nLog++;
|
||||
}
|
||||
|
||||
std::string notes = "CDEFGAB";
|
||||
|
||||
|
||||
// Test Text scaling and colours
|
||||
DrawString(0, 360, "Text Scale = 1", olc::WHITE, 1);
|
||||
DrawString(0, 368, "Text Scale = 2", olc::BLUE, 2);
|
||||
DrawString(0, 384, "Text Scale = 3", olc::RED, 3);
|
||||
DrawString(0, 408, "Text Scale = 4", olc::YELLOW, 4);
|
||||
DrawString(0, 440, "Text Scale = 5", olc::GREEN, 5);
|
||||
|
||||
fTotalTime += fElapsedTime;
|
||||
|
||||
float fAngle = fTotalTime;
|
||||
|
||||
// Draw Sprite using extension, first create a transformation stack
|
||||
olc::GFX2D::Transform2D t1;
|
||||
|
||||
// Traslate sprite so center of image is at 0,0
|
||||
t1.Translate(-250, -35);
|
||||
// Scale the sprite
|
||||
t1.Scale(1 * sinf(fAngle) + 1, 1 * sinf(fAngle) + 1);
|
||||
// Rotate it
|
||||
t1.Rotate(fAngle*2.0f);
|
||||
// Translate to 0,100
|
||||
t1.Translate(0, 100);
|
||||
// Rotate different speed
|
||||
t1.Rotate(fAngle / 3);
|
||||
// Translate to centre of screen
|
||||
t1.Translate(320, 240);
|
||||
|
||||
SetPixelMode(olc::Pixel::ALPHA);
|
||||
|
||||
// Use extension to draw sprite with transform applied
|
||||
olc::GFX2D::DrawSprite(spr, t1);
|
||||
|
||||
DrawSprite((int32_t)mx, (int32_t)my, spr, 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
TestExtension demo;
|
||||
if (demo.Construct(640, 480, 2, 2))
|
||||
demo.Start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
214
Videos/OneLoneCoder_PGE_IsometricTiles.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
Coding Quickie: Isometric Tiles
|
||||
"Owww... My insides hurt :(" - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Relevant Video: https://youtu.be/ukkbNKTgf5U
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
// Override base class with your custom functionality
|
||||
class IsometricDemo : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
IsometricDemo()
|
||||
{
|
||||
sAppName = "Coding Quickie: Isometric Tiles";
|
||||
}
|
||||
|
||||
private:
|
||||
// Number of tiles in world
|
||||
olc::vi2d vWorldSize = { 14, 10 };
|
||||
|
||||
// Size of single tile graphic
|
||||
olc::vi2d vTileSize = { 40, 20 };
|
||||
|
||||
// Where to place tile (0,0) on screen (in tile size steps)
|
||||
olc::vi2d vOrigin = { 5, 1 };
|
||||
|
||||
// Sprite that holds all imagery
|
||||
olc::Sprite *sprIsom = nullptr;
|
||||
|
||||
// Pointer to create 2D world array
|
||||
int *pWorld = nullptr;
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
// Load sprites used in demonstration
|
||||
sprIsom = new olc::Sprite("isometric_demo.png");
|
||||
|
||||
// Create empty world
|
||||
pWorld = new int[vWorldSize.x * vWorldSize.y]{ 0 };
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
Clear(olc::WHITE);
|
||||
|
||||
// Get Mouse in world
|
||||
olc::vi2d vMouse = { GetMouseX(), GetMouseY() };
|
||||
|
||||
// Work out active cell
|
||||
olc::vi2d vCell = { vMouse.x / vTileSize.x, vMouse.y / vTileSize.y };
|
||||
|
||||
// Work out mouse offset into cell
|
||||
olc::vi2d vOffset = { vMouse.x % vTileSize.x, vMouse.y % vTileSize.y };
|
||||
|
||||
// Sample into cell offset colour
|
||||
olc::Pixel col = sprIsom->GetPixel(3 * vTileSize.x + vOffset.x, vOffset.y);
|
||||
|
||||
// Work out selected cell by transforming screen cell
|
||||
olc::vi2d vSelected =
|
||||
{
|
||||
(vCell.y - vOrigin.y) + (vCell.x - vOrigin.x),
|
||||
(vCell.y - vOrigin.y) - (vCell.x - vOrigin.x)
|
||||
};
|
||||
|
||||
// "Bodge" selected cell by sampling corners
|
||||
if (col == olc::RED) vSelected += {-1, +0};
|
||||
if (col == olc::BLUE) vSelected += {+0, -1};
|
||||
if (col == olc::GREEN) vSelected += {+0, +1};
|
||||
if (col == olc::YELLOW) vSelected += {+1, +0};
|
||||
|
||||
// Handle mouse click to toggle if a tile is visible or not
|
||||
if (GetMouse(0).bPressed)
|
||||
{
|
||||
// Guard array boundary
|
||||
if (vSelected.x >= 0 && vSelected.x < vWorldSize.x && vSelected.y >= 0 && vSelected.y < vWorldSize.y)
|
||||
++pWorld[vSelected.y * vWorldSize.x + vSelected.x] %= 6;
|
||||
}
|
||||
|
||||
// Labmda function to convert "world" coordinate into screen space
|
||||
auto ToScreen = [&](int x, int y)
|
||||
{
|
||||
return olc::vi2d
|
||||
{
|
||||
(vOrigin.x * vTileSize.x) + (x - y) * (vTileSize.x / 2),
|
||||
(vOrigin.y * vTileSize.y) + (x + y) * (vTileSize.y / 2)
|
||||
};
|
||||
};
|
||||
|
||||
// Draw World - has binary transparancy so enable masking
|
||||
SetPixelMode(olc::Pixel::MASK);
|
||||
|
||||
// (0,0) is at top, defined by vOrigin, so draw from top to bottom
|
||||
// to ensure tiles closest to camera are drawn last
|
||||
for (int y = 0; y < vWorldSize.y; y++)
|
||||
{
|
||||
for (int x = 0; x < vWorldSize.x; x++)
|
||||
{
|
||||
// Convert cell coordinate to world space
|
||||
olc::vi2d vWorld = ToScreen(x, y);
|
||||
|
||||
switch(pWorld[y*vWorldSize.x + x])
|
||||
{
|
||||
case 0:
|
||||
// Invisble Tile
|
||||
DrawPartialSprite(vWorld.x, vWorld.y, sprIsom, 1 * vTileSize.x, 0, vTileSize.x, vTileSize.y);
|
||||
break;
|
||||
case 1:
|
||||
// Visible Tile
|
||||
DrawPartialSprite(vWorld.x, vWorld.y, sprIsom, 2 * vTileSize.x, 0, vTileSize.x, vTileSize.y);
|
||||
break;
|
||||
case 2:
|
||||
// Tree
|
||||
DrawPartialSprite(vWorld.x, vWorld.y - vTileSize.y, sprIsom, 0 * vTileSize.x, 1 * vTileSize.y, vTileSize.x, vTileSize.y * 2);
|
||||
break;
|
||||
case 3:
|
||||
// Spooky Tree
|
||||
DrawPartialSprite(vWorld.x, vWorld.y - vTileSize.y, sprIsom, 1 * vTileSize.x, 1 * vTileSize.y, vTileSize.x, vTileSize.y * 2);
|
||||
break;
|
||||
case 4:
|
||||
// Beach
|
||||
DrawPartialSprite(vWorld.x, vWorld.y - vTileSize.y, sprIsom, 2 * vTileSize.x, 1 * vTileSize.y, vTileSize.x, vTileSize.y * 2);
|
||||
break;
|
||||
case 5:
|
||||
// Water
|
||||
DrawPartialSprite(vWorld.x, vWorld.y - vTileSize.y, sprIsom, 3 * vTileSize.x, 1 * vTileSize.y, vTileSize.x, vTileSize.y * 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw Selected Cell - Has varying alpha components
|
||||
SetPixelMode(olc::Pixel::ALPHA);
|
||||
|
||||
// Convert selected cell coordinate to world space
|
||||
olc::vi2d vSelectedWorld = ToScreen(vSelected.x, vSelected.y);
|
||||
|
||||
// Draw "highlight" tile
|
||||
DrawPartialSprite(vSelectedWorld.x, vSelectedWorld.y, sprIsom, 0 * vTileSize.x, 0, vTileSize.x, vTileSize.y);
|
||||
|
||||
// Go back to normal drawing with no expected transparency
|
||||
SetPixelMode(olc::Pixel::NORMAL);
|
||||
|
||||
// Draw Hovered Cell Boundary
|
||||
//DrawRect(vCell.x * vTileSize.x, vCell.y * vTileSize.y, vTileSize.x, vTileSize.y, olc::RED);
|
||||
|
||||
// Draw Debug Info
|
||||
DrawString(4, 4, "Mouse : " + std::to_string(vMouse.x) + ", " + std::to_string(vMouse.y), olc::BLACK);
|
||||
DrawString(4, 14, "Cell : " + std::to_string(vCell.x) + ", " + std::to_string(vCell.y), olc::BLACK);
|
||||
DrawString(4, 24, "Selected: " + std::to_string(vSelected.x) + ", " + std::to_string(vSelected.y), olc::BLACK);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
IsometricDemo demo;
|
||||
if (demo.Construct(512, 480, 2, 2))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
626
Videos/OneLoneCoder_PGE_MIDI.cpp
Normal file
@@ -0,0 +1,626 @@
|
||||
/*
|
||||
Programming MIDI: Parsing, Displaying (& Playing) MIDI Files
|
||||
"Better get these done before im virused..." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2020 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Relevant Video: https://youtu.be/040BKtnDdg0
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Community: https://community.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018, 2019, 2020
|
||||
*/
|
||||
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <array>
|
||||
|
||||
//#pragma comment(lib, "winmm.lib")
|
||||
|
||||
|
||||
struct MidiEvent
|
||||
{
|
||||
enum class Type
|
||||
{
|
||||
NoteOff,
|
||||
NoteOn,
|
||||
Other
|
||||
} event;
|
||||
|
||||
uint8_t nKey = 0;
|
||||
uint8_t nVelocity = 0;
|
||||
uint32_t nDeltaTick = 0;
|
||||
};
|
||||
|
||||
|
||||
struct MidiNote
|
||||
{
|
||||
uint8_t nKey = 0;
|
||||
uint8_t nVelocity = 0;
|
||||
uint32_t nStartTime = 0;
|
||||
uint32_t nDuration = 0;
|
||||
};
|
||||
|
||||
struct MidiTrack
|
||||
{
|
||||
std::string sName;
|
||||
std::string sInstrument;
|
||||
std::vector<MidiEvent> vecEvents;
|
||||
std::vector<MidiNote> vecNotes;
|
||||
uint8_t nMaxNote = 64;
|
||||
uint8_t nMinNote = 64;
|
||||
};
|
||||
|
||||
|
||||
class MidiFile
|
||||
{
|
||||
public:
|
||||
enum EventName : uint8_t
|
||||
{
|
||||
VoiceNoteOff = 0x80,
|
||||
VoiceNoteOn = 0x90,
|
||||
VoiceAftertouch = 0xA0,
|
||||
VoiceControlChange = 0xB0,
|
||||
VoiceProgramChange = 0xC0,
|
||||
VoiceChannelPressure = 0xD0,
|
||||
VoicePitchBend = 0xE0,
|
||||
SystemExclusive = 0xF0,
|
||||
};
|
||||
|
||||
enum MetaEventName : uint8_t
|
||||
{
|
||||
MetaSequence = 0x00,
|
||||
MetaText = 0x01,
|
||||
MetaCopyright = 0x02,
|
||||
MetaTrackName = 0x03,
|
||||
MetaInstrumentName = 0x04,
|
||||
MetaLyrics = 0x05,
|
||||
MetaMarker = 0x06,
|
||||
MetaCuePoint = 0x07,
|
||||
MetaChannelPrefix = 0x20,
|
||||
MetaEndOfTrack = 0x2F,
|
||||
MetaSetTempo = 0x51,
|
||||
MetaSMPTEOffset = 0x54,
|
||||
MetaTimeSignature = 0x58,
|
||||
MetaKeySignature = 0x59,
|
||||
MetaSequencerSpecific = 0x7F,
|
||||
};
|
||||
|
||||
public:
|
||||
MidiFile()
|
||||
{
|
||||
}
|
||||
|
||||
MidiFile(const std::string& sFileName)
|
||||
{
|
||||
ParseFile(sFileName);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ParseFile(const std::string& sFileName)
|
||||
{
|
||||
// Open the MIDI File as a stream
|
||||
std::ifstream ifs;
|
||||
ifs.open(sFileName, std::fstream::in | std::ios::binary);
|
||||
if (!ifs.is_open())
|
||||
return false;
|
||||
|
||||
|
||||
// Helper Utilities ====================
|
||||
|
||||
// Swaps byte order of 32-bit integer
|
||||
auto Swap32 = [](uint32_t n)
|
||||
{
|
||||
return (((n >> 24) & 0xff) | ((n << 8) & 0xff0000) | ((n >> 8) & 0xff00) | ((n << 24) & 0xff000000));
|
||||
};
|
||||
|
||||
// Swaps byte order of 16-bit integer
|
||||
auto Swap16 = [](uint16_t n)
|
||||
{
|
||||
return ((n >> 8) | (n << 8));
|
||||
};
|
||||
|
||||
// Reads nLength bytes form file stream, and constructs a text string
|
||||
auto ReadString = [&ifs](uint32_t nLength)
|
||||
{
|
||||
std::string s;
|
||||
for (uint32_t i = 0; i < nLength; i++) s += ifs.get();
|
||||
return s;
|
||||
};
|
||||
|
||||
// Reads a compressed MIDI value. This can be up to 32 bits long. Essentially if the first byte, first
|
||||
// bit is set to 1, that indicates that the next byte is required to construct the full word. Only
|
||||
// the bottom 7 bits of each byte are used to construct the final word value. Each successive byte
|
||||
// that has MSB set, indicates a further byte needs to be read.
|
||||
auto ReadValue = [&ifs]()
|
||||
{
|
||||
uint32_t nValue = 0;
|
||||
uint8_t nByte = 0;
|
||||
|
||||
// Read byte
|
||||
nValue = ifs.get();
|
||||
|
||||
// Check MSB, if set, more bytes need reading
|
||||
if (nValue & 0x80)
|
||||
{
|
||||
// Extract bottom 7 bits of read byte
|
||||
nValue &= 0x7F;
|
||||
do
|
||||
{
|
||||
// Read next byte
|
||||
nByte = ifs.get();
|
||||
|
||||
// Construct value by setting bottom 7 bits, then shifting 7 bits
|
||||
nValue = (nValue << 7) | (nByte & 0x7F);
|
||||
}
|
||||
while (nByte & 0x80); // Loop whilst read byte MSB is 1
|
||||
}
|
||||
|
||||
// Return final construction (always 32-bit unsigned integer internally)
|
||||
return nValue;
|
||||
};
|
||||
|
||||
uint32_t n32 = 0;
|
||||
uint16_t n16 = 0;
|
||||
|
||||
// Read MIDI Header (Fixed Size)
|
||||
ifs.read((char*)&n32, sizeof(uint32_t));
|
||||
uint32_t nFileID = Swap32(n32);
|
||||
ifs.read((char*)&n32, sizeof(uint32_t));
|
||||
uint32_t nHeaderLength = Swap32(n32);
|
||||
ifs.read((char*)&n16, sizeof(uint16_t));
|
||||
uint16_t nFormat = Swap16(n16);
|
||||
ifs.read((char*)&n16, sizeof(uint16_t));
|
||||
uint16_t nTrackChunks = Swap16(n16);
|
||||
ifs.read((char*)&n16, sizeof(uint16_t));
|
||||
uint16_t nDivision = Swap16(n16);
|
||||
|
||||
for (uint16_t nChunk = 0; nChunk < nTrackChunks; nChunk++)
|
||||
{
|
||||
std::cout << "===== NEW TRACK" << std::endl;
|
||||
// Read Track Header
|
||||
ifs.read((char*)&n32, sizeof(uint32_t));
|
||||
uint32_t nTrackID = Swap32(n32);
|
||||
ifs.read((char*)&n32, sizeof(uint32_t));
|
||||
uint32_t nTrackLength = Swap32(n32);
|
||||
|
||||
bool bEndOfTrack = false;
|
||||
|
||||
vecTracks.push_back(MidiTrack());
|
||||
|
||||
uint32_t nWallTime = 0;
|
||||
|
||||
uint8_t nPreviousStatus = 0;
|
||||
|
||||
while (!ifs.eof() && !bEndOfTrack)
|
||||
{
|
||||
// Fundamentally all MIDI Events contain a timecode, and a status byte*
|
||||
uint32_t nStatusTimeDelta = 0;
|
||||
uint8_t nStatus = 0;
|
||||
|
||||
|
||||
// Read Timecode from MIDI stream. This could be variable in length
|
||||
// and is the delta in "ticks" from the previous event. Of course this value
|
||||
// could be 0 if two events happen simultaneously.
|
||||
nStatusTimeDelta = ReadValue();
|
||||
|
||||
// Read first byte of message, this could be the status byte, or it could not...
|
||||
nStatus = ifs.get();
|
||||
|
||||
// All MIDI Status events have the MSB set. The data within a standard MIDI event
|
||||
// does not. A crude yet utilised form of compression is to omit sending status
|
||||
// bytes if the following sequence of events all refer to the same MIDI Status.
|
||||
// This is called MIDI Running Status, and is essential to succesful decoding of
|
||||
// MIDI streams and files.
|
||||
//
|
||||
// If the MSB of the read byte was not set, and on the whole we were expecting a
|
||||
// status byte, then Running Status is in effect, so we refer to the previous
|
||||
// confirmed status byte.
|
||||
if (nStatus < 0x80)
|
||||
{
|
||||
// MIDI Running Status is happening, so refer to previous valid MIDI Status byte
|
||||
nStatus = nPreviousStatus;
|
||||
|
||||
// We had to read the byte to assess if MIDI Running Status is in effect. But!
|
||||
// that read removed the byte form the stream, and that will desync all of the
|
||||
// following code because normally we would have read a status byte, but instead
|
||||
// we have read the data contained within a MIDI message. The simple solution is
|
||||
// to put the byte back :P
|
||||
ifs.seekg(-1, std::ios_base::cur);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ((nStatus & 0xF0) == EventName::VoiceNoteOff)
|
||||
{
|
||||
nPreviousStatus = nStatus;
|
||||
uint8_t nChannel = nStatus & 0x0F;
|
||||
uint8_t nNoteID = ifs.get();
|
||||
uint8_t nNoteVelocity = ifs.get();
|
||||
vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::NoteOff, nNoteID, nNoteVelocity, nStatusTimeDelta });
|
||||
}
|
||||
|
||||
else if ((nStatus & 0xF0) == EventName::VoiceNoteOn)
|
||||
{
|
||||
nPreviousStatus = nStatus;
|
||||
uint8_t nChannel = nStatus & 0x0F;
|
||||
uint8_t nNoteID = ifs.get();
|
||||
uint8_t nNoteVelocity = ifs.get();
|
||||
if(nNoteVelocity == 0)
|
||||
vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::NoteOff, nNoteID, nNoteVelocity, nStatusTimeDelta });
|
||||
else
|
||||
vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::NoteOn, nNoteID, nNoteVelocity, nStatusTimeDelta });
|
||||
}
|
||||
|
||||
else if ((nStatus & 0xF0) == EventName::VoiceAftertouch)
|
||||
{
|
||||
nPreviousStatus = nStatus;
|
||||
uint8_t nChannel = nStatus & 0x0F;
|
||||
uint8_t nNoteID = ifs.get();
|
||||
uint8_t nNoteVelocity = ifs.get();
|
||||
vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other });
|
||||
}
|
||||
|
||||
else if ((nStatus & 0xF0) == EventName::VoiceControlChange)
|
||||
{
|
||||
nPreviousStatus = nStatus;
|
||||
uint8_t nChannel = nStatus & 0x0F;
|
||||
uint8_t nControlID = ifs.get();
|
||||
uint8_t nControlValue = ifs.get();
|
||||
vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other });
|
||||
}
|
||||
|
||||
else if ((nStatus & 0xF0) == EventName::VoiceProgramChange)
|
||||
{
|
||||
nPreviousStatus = nStatus;
|
||||
uint8_t nChannel = nStatus & 0x0F;
|
||||
uint8_t nProgramID = ifs.get();
|
||||
vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other });
|
||||
}
|
||||
|
||||
else if ((nStatus & 0xF0) == EventName::VoiceChannelPressure)
|
||||
{
|
||||
nPreviousStatus = nStatus;
|
||||
uint8_t nChannel = nStatus & 0x0F;
|
||||
uint8_t nChannelPressure = ifs.get();
|
||||
vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other });
|
||||
}
|
||||
|
||||
else if ((nStatus & 0xF0) == EventName::VoicePitchBend)
|
||||
{
|
||||
nPreviousStatus = nStatus;
|
||||
uint8_t nChannel = nStatus & 0x0F;
|
||||
uint8_t nLS7B = ifs.get();
|
||||
uint8_t nMS7B = ifs.get();
|
||||
vecTracks[nChunk].vecEvents.push_back({ MidiEvent::Type::Other });
|
||||
|
||||
}
|
||||
|
||||
else if ((nStatus & 0xF0) == EventName::SystemExclusive)
|
||||
{
|
||||
nPreviousStatus = 0;
|
||||
|
||||
if (nStatus == 0xFF)
|
||||
{
|
||||
// Meta Message
|
||||
uint8_t nType = ifs.get();
|
||||
uint8_t nLength = ReadValue();
|
||||
|
||||
switch (nType)
|
||||
{
|
||||
case MetaSequence:
|
||||
std::cout << "Sequence Number: " << ifs.get() << ifs.get() << std::endl;
|
||||
break;
|
||||
case MetaText:
|
||||
std::cout << "Text: " << ReadString(nLength) << std::endl;
|
||||
break;
|
||||
case MetaCopyright:
|
||||
std::cout << "Copyright: " << ReadString(nLength) << std::endl;
|
||||
break;
|
||||
case MetaTrackName:
|
||||
vecTracks[nChunk].sName = ReadString(nLength);
|
||||
std::cout << "Track Name: " << vecTracks[nChunk].sName << std::endl;
|
||||
break;
|
||||
case MetaInstrumentName:
|
||||
vecTracks[nChunk].sInstrument = ReadString(nLength);
|
||||
std::cout << "Instrument Name: " << vecTracks[nChunk].sInstrument << std::endl;
|
||||
break;
|
||||
case MetaLyrics:
|
||||
std::cout << "Lyrics: " << ReadString(nLength) << std::endl;
|
||||
break;
|
||||
case MetaMarker:
|
||||
std::cout << "Marker: " << ReadString(nLength) << std::endl;
|
||||
break;
|
||||
case MetaCuePoint:
|
||||
std::cout << "Cue: " << ReadString(nLength) << std::endl;
|
||||
break;
|
||||
case MetaChannelPrefix:
|
||||
std::cout << "Prefix: " << ifs.get() << std::endl;
|
||||
break;
|
||||
case MetaEndOfTrack:
|
||||
bEndOfTrack = true;
|
||||
break;
|
||||
case MetaSetTempo:
|
||||
// Tempo is in microseconds per quarter note
|
||||
if (m_nTempo == 0)
|
||||
{
|
||||
(m_nTempo |= (ifs.get() << 16));
|
||||
(m_nTempo |= (ifs.get() << 8));
|
||||
(m_nTempo |= (ifs.get() << 0));
|
||||
m_nBPM = (60000000 / m_nTempo);
|
||||
std::cout << "Tempo: " << m_nTempo << " (" << m_nBPM << "bpm)" << std::endl;
|
||||
}
|
||||
break;
|
||||
case MetaSMPTEOffset:
|
||||
std::cout << "SMPTE: H:" << ifs.get() << " M:" << ifs.get() << " S:" << ifs.get() << " FR:" << ifs.get() << " FF:" << ifs.get() << std::endl;
|
||||
break;
|
||||
case MetaTimeSignature:
|
||||
std::cout << "Time Signature: " << ifs.get() << "/" << (2 << ifs.get()) << std::endl;
|
||||
std::cout << "ClocksPerTick: " << ifs.get() << std::endl;
|
||||
|
||||
// A MIDI "Beat" is 24 ticks, so specify how many 32nd notes constitute a beat
|
||||
std::cout << "32per24Clocks: " << ifs.get() << std::endl;
|
||||
break;
|
||||
case MetaKeySignature:
|
||||
std::cout << "Key Signature: " << ifs.get() << std::endl;
|
||||
std::cout << "Minor Key: " << ifs.get() << std::endl;
|
||||
break;
|
||||
case MetaSequencerSpecific:
|
||||
std::cout << "Sequencer Specific: " << ReadString(nLength) << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "Unrecognised MetaEvent: " << nType << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (nStatus == 0xF0)
|
||||
{
|
||||
// System Exclusive Message Begin
|
||||
std::cout << "System Exclusive Begin: " << ReadString(ReadValue()) << std::endl;
|
||||
}
|
||||
|
||||
if (nStatus == 0xF7)
|
||||
{
|
||||
// System Exclusive Message Begin
|
||||
std::cout << "System Exclusive End: " << ReadString(ReadValue()) << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unrecognised Status Byte: " << nStatus << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Convert Time Events to Notes
|
||||
for (auto& track : vecTracks)
|
||||
{
|
||||
uint32_t nWallTime = 0;
|
||||
|
||||
std::list<MidiNote> listNotesBeingProcessed;
|
||||
|
||||
for (auto& event : track.vecEvents)
|
||||
{
|
||||
nWallTime += event.nDeltaTick;
|
||||
|
||||
if (event.event == MidiEvent::Type::NoteOn)
|
||||
{
|
||||
// New Note
|
||||
listNotesBeingProcessed.push_back({ event.nKey, event.nVelocity, nWallTime, 0 });
|
||||
}
|
||||
|
||||
if (event.event == MidiEvent::Type::NoteOff)
|
||||
{
|
||||
auto note = std::find_if(listNotesBeingProcessed.begin(), listNotesBeingProcessed.end(), [&](const MidiNote& n) { return n.nKey == event.nKey; });
|
||||
if (note != listNotesBeingProcessed.end())
|
||||
{
|
||||
note->nDuration = nWallTime - note->nStartTime;
|
||||
track.vecNotes.push_back(*note);
|
||||
track.nMinNote = std::min(track.nMinNote, note->nKey);
|
||||
track.nMaxNote = std::max(track.nMaxNote, note->nKey);
|
||||
listNotesBeingProcessed.erase(note);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<MidiTrack> vecTracks;
|
||||
uint32_t m_nTempo = 0;
|
||||
uint32_t m_nBPM = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class olcMIDIViewer : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
olcMIDIViewer()
|
||||
{
|
||||
sAppName = "MIDI File Viewer";
|
||||
}
|
||||
|
||||
|
||||
MidiFile midi;
|
||||
|
||||
//HMIDIOUT hInstrument;
|
||||
size_t nCurrentNote[16]{ 0 };
|
||||
|
||||
double dSongTime = 0.0;
|
||||
double dRunTime = 0.0;
|
||||
uint32_t nMidiClock = 0;
|
||||
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
|
||||
midi.ParseFile("ff7_battle.mid");
|
||||
|
||||
/*
|
||||
int nMidiDevices = midiOutGetNumDevs();
|
||||
if (nMidiDevices > 0)
|
||||
{
|
||||
if (midiOutOpen(&hInstrument, 2, NULL, 0, NULL) == MMSYSERR_NOERROR)
|
||||
{
|
||||
std::cout << "Opened midi" << std::endl;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float nTrackOffset = 1000;
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
Clear(olc::BLACK);
|
||||
uint32_t nTimePerColumn = 50;
|
||||
uint32_t nNoteHeight = 2;
|
||||
uint32_t nOffsetY = 0;
|
||||
|
||||
if (GetKey(olc::Key::LEFT).bHeld) nTrackOffset -= 10000.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::RIGHT).bHeld) nTrackOffset += 10000.0f * fElapsedTime;
|
||||
|
||||
|
||||
for (auto& track : midi.vecTracks)
|
||||
{
|
||||
if (!track.vecNotes.empty())
|
||||
{
|
||||
uint32_t nNoteRange = track.nMaxNote - track.nMinNote;
|
||||
|
||||
FillRect(0, nOffsetY, ScreenWidth(), (nNoteRange + 1) * nNoteHeight, olc::DARK_GREY);
|
||||
DrawString(1, nOffsetY + 1, track.sName);
|
||||
|
||||
for (auto& note : track.vecNotes)
|
||||
{
|
||||
FillRect((note.nStartTime - nTrackOffset) / nTimePerColumn, (nNoteRange - (note.nKey - track.nMinNote)) * nNoteHeight + nOffsetY, note.nDuration / nTimePerColumn, nNoteHeight, olc::WHITE);
|
||||
}
|
||||
|
||||
nOffsetY += (nNoteRange + 1) * nNoteHeight + 4;
|
||||
}
|
||||
}
|
||||
|
||||
// BELOW - ABSOLUTELY HORRIBLE BODGE TO PLAY SOUND
|
||||
// DO NOT USE THIS CODE...
|
||||
|
||||
/*
|
||||
dRunTime += fElapsedTime;
|
||||
uint32_t nTempo = 4;
|
||||
int nTrack = 1;
|
||||
while (dRunTime >= 1.0 / double(midi.m_nBPM * 8))
|
||||
{
|
||||
dRunTime -= 1.0 / double(midi.m_nBPM * 8);
|
||||
|
||||
// Single MIDI Clock
|
||||
nMidiClock++;
|
||||
|
||||
int i = 0;
|
||||
int nTrack = 1;
|
||||
//for (nTrack = 1; nTrack < 3; nTrack++)
|
||||
{
|
||||
if (nCurrentNote[nTrack] < midi.vecTracks[nTrack].vecEvents.size())
|
||||
{
|
||||
if (midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nDeltaTick == 0)
|
||||
{
|
||||
uint32_t nStatus = 0;
|
||||
uint32_t nNote = midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nKey;
|
||||
uint32_t nVelocity = midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nVelocity;
|
||||
|
||||
if (midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].event == MidiEvent::Type::NoteOn)
|
||||
nStatus = 0x90;
|
||||
else
|
||||
nStatus = 0x80;
|
||||
|
||||
midiOutShortMsg(hInstrument, (nVelocity << 16) | (nNote << 8) | nStatus);
|
||||
nCurrentNote[nTrack]++;
|
||||
}
|
||||
else
|
||||
midi.vecTracks[nTrack].vecEvents[nCurrentNote[nTrack]].nDeltaTick--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::SPACE).bPressed)
|
||||
{
|
||||
midiOutShortMsg(hInstrument, 0x00403C90);
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::SPACE).bReleased)
|
||||
{
|
||||
midiOutShortMsg(hInstrument, 0x00003C80);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
olcMIDIViewer demo;
|
||||
if (demo.Construct(1280, 960, 1, 1))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,426 +1,426 @@
|
||||
/*
|
||||
OneLoneCoder.com - Path Finding #2 - Wave Propagation & Potential Fields
|
||||
"...never get lost again, so long as you know where you are" - @Javidx9
|
||||
|
||||
|
||||
Background
|
||||
~~~~~~~~~~
|
||||
A nice follow up alternative to the A* Algorithm. Wave propagation is less
|
||||
applicable to multiple objects with multiple destinations, but fantatsic
|
||||
for multiple objects all reaching the same destination.
|
||||
|
||||
WARNING! This code is NOT OPTIMAL!! It is however very robust. There
|
||||
are many ways to optimise this further.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Relevant Videos
|
||||
~~~~~~~~~~~~~~~
|
||||
Part #1 https://youtu.be/icZj67PTFhc
|
||||
Part #2 https://youtu.be/0ihciMKlcP8
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018
|
||||
*/
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
|
||||
// Override base class with your custom functionality
|
||||
class PathFinding_FlowFields : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
PathFinding_FlowFields()
|
||||
{
|
||||
sAppName = "PathFinding - Flow Fields";
|
||||
}
|
||||
|
||||
private:
|
||||
int nMapWidth;
|
||||
int nMapHeight;
|
||||
int nCellSize;
|
||||
int nBorderWidth;
|
||||
|
||||
bool *bObstacleMap;
|
||||
|
||||
int *nFlowFieldZ;
|
||||
float *fFlowFieldY;
|
||||
float *fFlowFieldX;
|
||||
|
||||
int nStartX;
|
||||
int nStartY;
|
||||
int nEndX;
|
||||
int nEndY;
|
||||
|
||||
int nWave = 1;
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
nBorderWidth = 4;
|
||||
nCellSize = 32;
|
||||
nMapWidth = ScreenWidth() / nCellSize;
|
||||
nMapHeight = ScreenHeight() / nCellSize;
|
||||
bObstacleMap = new bool[nMapWidth * nMapHeight]{ false };
|
||||
nFlowFieldZ = new int[nMapWidth * nMapHeight]{ 0 };
|
||||
fFlowFieldX = new float[nMapWidth * nMapHeight]{ 0 };
|
||||
fFlowFieldY = new float[nMapWidth * nMapHeight]{ 0 };
|
||||
|
||||
nStartX = 3;
|
||||
nStartY = 7;
|
||||
nEndX = 12;
|
||||
nEndY = 7;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
// Little convenience lambda 2D -> 1D
|
||||
auto p = [&](int x, int y) { return y * nMapWidth + x; };
|
||||
|
||||
// User Input
|
||||
int nSelectedCellX = GetMouseX() / nCellSize;
|
||||
int nSelectedCellY = GetMouseY() / nCellSize;
|
||||
|
||||
if (GetMouse(0).bReleased)
|
||||
{
|
||||
// Toggle Obstacle if mouse left clicked
|
||||
bObstacleMap[p(nSelectedCellX, nSelectedCellY)] =
|
||||
!bObstacleMap[p(nSelectedCellX, nSelectedCellY)];
|
||||
}
|
||||
|
||||
if (GetMouse(1).bReleased)
|
||||
{
|
||||
nStartX = nSelectedCellX;
|
||||
nStartY = nSelectedCellY;
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::Q).bReleased)
|
||||
{
|
||||
nWave++;
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::A).bReleased)
|
||||
{
|
||||
nWave--;
|
||||
if (nWave == 0)
|
||||
nWave = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 1) Prepare flow field, add a boundary, and add obstacles
|
||||
// by setting the flow Field Height (Z) to -1
|
||||
for (int x = 0; x < nMapWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nMapHeight; y++)
|
||||
{
|
||||
// Set border or obstacles
|
||||
if (x == 0 || y == 0 || x == (nMapWidth - 1) || y == (nMapHeight - 1) || bObstacleMap[p(x, y)])
|
||||
{
|
||||
nFlowFieldZ[p(x, y)] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nFlowFieldZ[p(x, y)] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Propagate a wave (i.e. flood-fill) from target location. Here I use
|
||||
// a tuple, of {x, y, distance} - though you could use a struct or
|
||||
// similar.
|
||||
std::list<std::tuple<int, int, int>> nodes;
|
||||
|
||||
// Add the first discovered node - the target location, with a distance of 1
|
||||
nodes.push_back({ nEndX, nEndY, 1 });
|
||||
|
||||
while (!nodes.empty())
|
||||
{
|
||||
// Each iteration through the discovered nodes may create newly discovered
|
||||
// nodes, so I maintain a second list. It's important not to contaminate
|
||||
// the list being iterated through.
|
||||
std::list<std::tuple<int, int, int>> new_nodes;
|
||||
|
||||
// Now iterate through each discovered node. If it has neighbouring nodes
|
||||
// that are empty space and undiscovered, add those locations to the
|
||||
// new nodes list
|
||||
for (auto &n : nodes)
|
||||
{
|
||||
int x = std::get<0>(n); // Map X-Coordinate
|
||||
int y = std::get<1>(n); // Map Y-Coordinate
|
||||
int d = std::get<2>(n); // Distance From Target Location
|
||||
|
||||
// Set distance count for this node. NOte that when we add nodes we add 1
|
||||
// to this distance. This emulates propagating a wave across the map, where
|
||||
// the front of that wave increments each iteration. In this way, we can
|
||||
// propagate distance information 'away from target location'
|
||||
nFlowFieldZ[p(x, y)] = d;
|
||||
|
||||
// Add neigbour nodes if unmarked, i.e their "height" is 0. Any discovered
|
||||
// node or obstacle will be non-zero
|
||||
|
||||
// Check East
|
||||
if ((x + 1) < nMapWidth && nFlowFieldZ[p(x + 1, y)] == 0)
|
||||
new_nodes.push_back({ x + 1, y, d + 1 });
|
||||
|
||||
// Check West
|
||||
if ((x - 1) >= 0 && nFlowFieldZ[p(x - 1, y)] == 0)
|
||||
new_nodes.push_back({ x - 1, y, d + 1 });
|
||||
|
||||
// Check South
|
||||
if ((y + 1) < nMapHeight && nFlowFieldZ[p(x, y + 1)] == 0)
|
||||
new_nodes.push_back({ x, y + 1, d + 1 });
|
||||
|
||||
// Check North
|
||||
if ((y - 1) >= 0 && nFlowFieldZ[p(x, y - 1)] == 0)
|
||||
new_nodes.push_back({ x, y - 1, d + 1 });
|
||||
}
|
||||
|
||||
// We will now have potentially multiple nodes for a single location. This means our
|
||||
// algorithm will never complete! So we must remove duplicates form our new node list.
|
||||
// Im doing this with some clever code - but it is not performant(!) - it is merely
|
||||
// convenient. I'd suggest doing away with overhead structures like linked lists and sorts
|
||||
// if you are aiming for fastest path finding.
|
||||
|
||||
// Sort the nodes - This will stack up nodes that are similar: A, B, B, B, B, C, D, D, E, F, F
|
||||
new_nodes.sort([&](const std::tuple<int, int, int> &n1, const std::tuple<int, int, int> &n2)
|
||||
{
|
||||
// In this instance I dont care how the values are sorted, so long as nodes that
|
||||
// represent the same location are adjacent in the list. I can use the p() lambda
|
||||
// to generate a unique 1D value for a 2D coordinate, so I'll sort by that.
|
||||
return p(std::get<0>(n1), std::get<1>(n1)) < p(std::get<0>(n2), std::get<1>(n2));
|
||||
});
|
||||
|
||||
// Use "unique" function to remove adjacent duplicates : A, B, -, -, -, C, D, -, E, F -
|
||||
// and also erase them : A, B, C, D, E, F
|
||||
new_nodes.unique([&](const std::tuple<int, int, int> &n1, const std::tuple<int, int, int> &n2)
|
||||
{
|
||||
return p(std::get<0>(n1), std::get<1>(n1)) == p(std::get<0>(n2), std::get<1>(n2));
|
||||
});
|
||||
|
||||
// We've now processed all the discoverd nodes, so clear the list, and add the newly
|
||||
// discovered nodes for processing on the next iteration
|
||||
nodes.clear();
|
||||
nodes.insert(nodes.begin(), new_nodes.begin(), new_nodes.end());
|
||||
|
||||
// When there are no more newly discovered nodes, we have "flood filled" the entire
|
||||
// map. The propagation phase of the algorithm is complete
|
||||
}
|
||||
|
||||
|
||||
// 3) Create Path. Starting a start location, create a path of nodes until you reach target
|
||||
// location. At each node find the neighbour with the lowest "distance" score.
|
||||
std::list<std::pair<int, int>> path;
|
||||
path.push_back({ nStartX, nStartY });
|
||||
int nLocX = nStartX;
|
||||
int nLocY = nStartY;
|
||||
bool bNoPath = false;
|
||||
|
||||
while (!(nLocX == nEndX && nLocY == nEndY) && !bNoPath)
|
||||
{
|
||||
std::list<std::tuple<int, int, int>> listNeighbours;
|
||||
|
||||
// 4-Way Connectivity
|
||||
if ((nLocY - 1) >= 0 && nFlowFieldZ[p(nLocX, nLocY - 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX, nLocY - 1, nFlowFieldZ[p(nLocX, nLocY - 1)] });
|
||||
|
||||
if ((nLocX + 1) < nMapWidth && nFlowFieldZ[p(nLocX + 1, nLocY)] > 0)
|
||||
listNeighbours.push_back({ nLocX + 1, nLocY, nFlowFieldZ[p(nLocX + 1, nLocY)] });
|
||||
|
||||
if ((nLocY + 1) < nMapHeight && nFlowFieldZ[p(nLocX, nLocY + 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX, nLocY + 1, nFlowFieldZ[p(nLocX, nLocY + 1)] });
|
||||
|
||||
if ((nLocX - 1) >= 0 && nFlowFieldZ[p(nLocX - 1, nLocY)] > 0)
|
||||
listNeighbours.push_back({ nLocX - 1, nLocY, nFlowFieldZ[p(nLocX - 1, nLocY)] });
|
||||
|
||||
// 8-Way Connectivity
|
||||
if ((nLocY - 1) >= 0 && (nLocX - 1) >= 0 && nFlowFieldZ[p(nLocX - 1, nLocY - 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX - 1, nLocY - 1, nFlowFieldZ[p(nLocX - 1, nLocY - 1)] });
|
||||
|
||||
if ((nLocY - 1) >= 0 && (nLocX + 1) < nMapWidth && nFlowFieldZ[p(nLocX + 1, nLocY - 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX + 1, nLocY - 1, nFlowFieldZ[p(nLocX + 1, nLocY - 1)] });
|
||||
|
||||
if ((nLocY + 1) < nMapHeight && (nLocX - 1) >= 0 && nFlowFieldZ[p(nLocX - 1, nLocY + 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX - 1, nLocY + 1, nFlowFieldZ[p(nLocX - 1, nLocY + 1)] });
|
||||
|
||||
if ((nLocY + 1) < nMapHeight && (nLocX + 1) < nMapWidth && nFlowFieldZ[p(nLocX + 1, nLocY + 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX + 1, nLocY + 1, nFlowFieldZ[p(nLocX + 1, nLocY + 1)] });
|
||||
|
||||
// Sprt neigbours based on height, so lowest neighbour is at front
|
||||
// of list
|
||||
listNeighbours.sort([&](const std::tuple<int, int, int> &n1, const std::tuple<int, int, int> &n2)
|
||||
{
|
||||
return std::get<2>(n1) < std::get<2>(n2); // Compare distances
|
||||
});
|
||||
|
||||
if (listNeighbours.empty()) // Neighbour is invalid or no possible path
|
||||
bNoPath = true;
|
||||
else
|
||||
{
|
||||
nLocX = std::get<0>(listNeighbours.front());
|
||||
nLocY = std::get<1>(listNeighbours.front());
|
||||
path.push_back({ nLocX, nLocY });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 4) Create Flow "Field"
|
||||
for (int x = 1; x < nMapWidth - 1; x++)
|
||||
{
|
||||
for (int y = 1; y < nMapHeight - 1; y++)
|
||||
{
|
||||
float vx = 0.0f;
|
||||
float vy = 0.0f;
|
||||
|
||||
vy -= (float)((nFlowFieldZ[p(x, y + 1)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x, y + 1)]) - nFlowFieldZ[p(x, y)]);
|
||||
vx -= (float)((nFlowFieldZ[p(x + 1, y)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x + 1, y)]) - nFlowFieldZ[p(x, y)]);
|
||||
vy += (float)((nFlowFieldZ[p(x, y - 1)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x, y - 1)]) - nFlowFieldZ[p(x, y)]);
|
||||
vx += (float)((nFlowFieldZ[p(x - 1, y)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x - 1, y)]) - nFlowFieldZ[p(x, y)]);
|
||||
|
||||
float r = 1.0f / sqrtf(vx*vx + vy * vy);
|
||||
fFlowFieldX[p(x, y)] = vx * r;
|
||||
fFlowFieldY[p(x, y)] = vy * r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Draw Map
|
||||
Clear(olc::BLACK);
|
||||
|
||||
for (int x = 0; x < nMapWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nMapHeight; y++)
|
||||
{
|
||||
olc::Pixel colour = olc::BLUE;
|
||||
|
||||
if (bObstacleMap[p(x, y)])
|
||||
colour = olc::GREY;
|
||||
|
||||
if (nWave == nFlowFieldZ[p(x, y)])
|
||||
colour = olc::DARK_CYAN;
|
||||
|
||||
if (x == nStartX && y == nStartY)
|
||||
colour = olc::GREEN;
|
||||
|
||||
if (x == nEndX && y == nEndY)
|
||||
colour = olc::RED;
|
||||
|
||||
// Draw Base
|
||||
FillRect(x * nCellSize, y * nCellSize, nCellSize - nBorderWidth, nCellSize - nBorderWidth, colour);
|
||||
|
||||
// Draw "potential" or "distance" or "height" :D
|
||||
//DrawString(x * nCellSize, y * nCellSize, std::to_string(nFlowFieldZ[p(x, y)]), olc::WHITE);
|
||||
|
||||
if (nFlowFieldZ[p(x, y)] > 0)
|
||||
{
|
||||
float ax[4], ay[4];
|
||||
float fAngle = atan2f(fFlowFieldY[p(x, y)], fFlowFieldX[p(x, y)]);
|
||||
float fRadius = (float)(nCellSize - nBorderWidth) / 2.0f;
|
||||
int fOffsetX = x * nCellSize + ((nCellSize - nBorderWidth) / 2);
|
||||
int fOffsetY = y * nCellSize + ((nCellSize - nBorderWidth) / 2);
|
||||
ax[0] = cosf(fAngle) * fRadius + fOffsetX;
|
||||
ay[0] = sinf(fAngle) * fRadius + fOffsetY;
|
||||
ax[1] = cosf(fAngle) * -fRadius + fOffsetX;
|
||||
ay[1] = sinf(fAngle) * -fRadius + fOffsetY;
|
||||
ax[2] = cosf(fAngle + 0.1f) * fRadius * 0.7f + fOffsetX;
|
||||
ay[2] = sinf(fAngle + 0.1f) * fRadius * 0.7f + fOffsetY;
|
||||
ax[3] = cosf(fAngle - 0.1f) * fRadius * 0.7f + fOffsetX;
|
||||
ay[3] = sinf(fAngle - 0.1f) * fRadius * 0.7f + fOffsetY;
|
||||
|
||||
DrawLine(ax[0], ay[0], ax[1], ay[1], olc::CYAN);
|
||||
DrawLine(ax[0], ay[0], ax[2], ay[2], olc::CYAN);
|
||||
DrawLine(ax[0], ay[0], ax[3], ay[3], olc::CYAN);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool bFirstPoint = true;
|
||||
int ox, oy;
|
||||
for (auto &a : path)
|
||||
{
|
||||
if (bFirstPoint)
|
||||
{
|
||||
ox = a.first;
|
||||
oy = a.second;
|
||||
bFirstPoint = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawLine(
|
||||
ox * nCellSize + ((nCellSize - nBorderWidth) / 2),
|
||||
oy * nCellSize + ((nCellSize - nBorderWidth) / 2),
|
||||
a.first * nCellSize + ((nCellSize - nBorderWidth) / 2),
|
||||
a.second * nCellSize + ((nCellSize - nBorderWidth) / 2), olc::YELLOW);
|
||||
|
||||
ox = a.first;
|
||||
oy = a.second;
|
||||
|
||||
FillCircle(ox * nCellSize + ((nCellSize - nBorderWidth) / 2), oy * nCellSize + ((nCellSize - nBorderWidth) / 2), 10, olc::YELLOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
PathFinding_FlowFields demo;
|
||||
if (demo.Construct(512, 480, 2, 2))
|
||||
demo.Start();
|
||||
return 0;
|
||||
/*
|
||||
OneLoneCoder.com - Path Finding #2 - Wave Propagation & Potential Fields
|
||||
"...never get lost again, so long as you know where you are" - @Javidx9
|
||||
|
||||
|
||||
Background
|
||||
~~~~~~~~~~
|
||||
A nice follow up alternative to the A* Algorithm. Wave propagation is less
|
||||
applicable to multiple objects with multiple destinations, but fantatsic
|
||||
for multiple objects all reaching the same destination.
|
||||
|
||||
WARNING! This code is NOT OPTIMAL!! It is however very robust. There
|
||||
are many ways to optimise this further.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Relevant Videos
|
||||
~~~~~~~~~~~~~~~
|
||||
Part #1 https://youtu.be/icZj67PTFhc
|
||||
Part #2 https://youtu.be/0ihciMKlcP8
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018
|
||||
*/
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
|
||||
// Override base class with your custom functionality
|
||||
class PathFinding_FlowFields : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
PathFinding_FlowFields()
|
||||
{
|
||||
sAppName = "PathFinding - Flow Fields";
|
||||
}
|
||||
|
||||
private:
|
||||
int nMapWidth;
|
||||
int nMapHeight;
|
||||
int nCellSize;
|
||||
int nBorderWidth;
|
||||
|
||||
bool *bObstacleMap;
|
||||
|
||||
int *nFlowFieldZ;
|
||||
float *fFlowFieldY;
|
||||
float *fFlowFieldX;
|
||||
|
||||
int nStartX;
|
||||
int nStartY;
|
||||
int nEndX;
|
||||
int nEndY;
|
||||
|
||||
int nWave = 1;
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
nBorderWidth = 4;
|
||||
nCellSize = 32;
|
||||
nMapWidth = ScreenWidth() / nCellSize;
|
||||
nMapHeight = ScreenHeight() / nCellSize;
|
||||
bObstacleMap = new bool[nMapWidth * nMapHeight]{ false };
|
||||
nFlowFieldZ = new int[nMapWidth * nMapHeight]{ 0 };
|
||||
fFlowFieldX = new float[nMapWidth * nMapHeight]{ 0 };
|
||||
fFlowFieldY = new float[nMapWidth * nMapHeight]{ 0 };
|
||||
|
||||
nStartX = 3;
|
||||
nStartY = 7;
|
||||
nEndX = 12;
|
||||
nEndY = 7;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
// Little convenience lambda 2D -> 1D
|
||||
auto p = [&](int x, int y) { return y * nMapWidth + x; };
|
||||
|
||||
// User Input
|
||||
int nSelectedCellX = GetMouseX() / nCellSize;
|
||||
int nSelectedCellY = GetMouseY() / nCellSize;
|
||||
|
||||
if (GetMouse(0).bReleased)
|
||||
{
|
||||
// Toggle Obstacle if mouse left clicked
|
||||
bObstacleMap[p(nSelectedCellX, nSelectedCellY)] =
|
||||
!bObstacleMap[p(nSelectedCellX, nSelectedCellY)];
|
||||
}
|
||||
|
||||
if (GetMouse(1).bReleased)
|
||||
{
|
||||
nStartX = nSelectedCellX;
|
||||
nStartY = nSelectedCellY;
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::Q).bReleased)
|
||||
{
|
||||
nWave++;
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::A).bReleased)
|
||||
{
|
||||
nWave--;
|
||||
if (nWave == 0)
|
||||
nWave = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 1) Prepare flow field, add a boundary, and add obstacles
|
||||
// by setting the flow Field Height (Z) to -1
|
||||
for (int x = 0; x < nMapWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nMapHeight; y++)
|
||||
{
|
||||
// Set border or obstacles
|
||||
if (x == 0 || y == 0 || x == (nMapWidth - 1) || y == (nMapHeight - 1) || bObstacleMap[p(x, y)])
|
||||
{
|
||||
nFlowFieldZ[p(x, y)] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nFlowFieldZ[p(x, y)] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Propagate a wave (i.e. flood-fill) from target location. Here I use
|
||||
// a tuple, of {x, y, distance} - though you could use a struct or
|
||||
// similar.
|
||||
std::list<std::tuple<int, int, int>> nodes;
|
||||
|
||||
// Add the first discovered node - the target location, with a distance of 1
|
||||
nodes.push_back({ nEndX, nEndY, 1 });
|
||||
|
||||
while (!nodes.empty())
|
||||
{
|
||||
// Each iteration through the discovered nodes may create newly discovered
|
||||
// nodes, so I maintain a second list. It's important not to contaminate
|
||||
// the list being iterated through.
|
||||
std::list<std::tuple<int, int, int>> new_nodes;
|
||||
|
||||
// Now iterate through each discovered node. If it has neighbouring nodes
|
||||
// that are empty space and undiscovered, add those locations to the
|
||||
// new nodes list
|
||||
for (auto &n : nodes)
|
||||
{
|
||||
int x = std::get<0>(n); // Map X-Coordinate
|
||||
int y = std::get<1>(n); // Map Y-Coordinate
|
||||
int d = std::get<2>(n); // Distance From Target Location
|
||||
|
||||
// Set distance count for this node. NOte that when we add nodes we add 1
|
||||
// to this distance. This emulates propagating a wave across the map, where
|
||||
// the front of that wave increments each iteration. In this way, we can
|
||||
// propagate distance information 'away from target location'
|
||||
nFlowFieldZ[p(x, y)] = d;
|
||||
|
||||
// Add neigbour nodes if unmarked, i.e their "height" is 0. Any discovered
|
||||
// node or obstacle will be non-zero
|
||||
|
||||
// Check East
|
||||
if ((x + 1) < nMapWidth && nFlowFieldZ[p(x + 1, y)] == 0)
|
||||
new_nodes.push_back({ x + 1, y, d + 1 });
|
||||
|
||||
// Check West
|
||||
if ((x - 1) >= 0 && nFlowFieldZ[p(x - 1, y)] == 0)
|
||||
new_nodes.push_back({ x - 1, y, d + 1 });
|
||||
|
||||
// Check South
|
||||
if ((y + 1) < nMapHeight && nFlowFieldZ[p(x, y + 1)] == 0)
|
||||
new_nodes.push_back({ x, y + 1, d + 1 });
|
||||
|
||||
// Check North
|
||||
if ((y - 1) >= 0 && nFlowFieldZ[p(x, y - 1)] == 0)
|
||||
new_nodes.push_back({ x, y - 1, d + 1 });
|
||||
}
|
||||
|
||||
// We will now have potentially multiple nodes for a single location. This means our
|
||||
// algorithm will never complete! So we must remove duplicates form our new node list.
|
||||
// Im doing this with some clever code - but it is not performant(!) - it is merely
|
||||
// convenient. I'd suggest doing away with overhead structures like linked lists and sorts
|
||||
// if you are aiming for fastest path finding.
|
||||
|
||||
// Sort the nodes - This will stack up nodes that are similar: A, B, B, B, B, C, D, D, E, F, F
|
||||
new_nodes.sort([&](const std::tuple<int, int, int> &n1, const std::tuple<int, int, int> &n2)
|
||||
{
|
||||
// In this instance I dont care how the values are sorted, so long as nodes that
|
||||
// represent the same location are adjacent in the list. I can use the p() lambda
|
||||
// to generate a unique 1D value for a 2D coordinate, so I'll sort by that.
|
||||
return p(std::get<0>(n1), std::get<1>(n1)) < p(std::get<0>(n2), std::get<1>(n2));
|
||||
});
|
||||
|
||||
// Use "unique" function to remove adjacent duplicates : A, B, -, -, -, C, D, -, E, F -
|
||||
// and also erase them : A, B, C, D, E, F
|
||||
new_nodes.unique([&](const std::tuple<int, int, int> &n1, const std::tuple<int, int, int> &n2)
|
||||
{
|
||||
return p(std::get<0>(n1), std::get<1>(n1)) == p(std::get<0>(n2), std::get<1>(n2));
|
||||
});
|
||||
|
||||
// We've now processed all the discoverd nodes, so clear the list, and add the newly
|
||||
// discovered nodes for processing on the next iteration
|
||||
nodes.clear();
|
||||
nodes.insert(nodes.begin(), new_nodes.begin(), new_nodes.end());
|
||||
|
||||
// When there are no more newly discovered nodes, we have "flood filled" the entire
|
||||
// map. The propagation phase of the algorithm is complete
|
||||
}
|
||||
|
||||
|
||||
// 3) Create Path. Starting a start location, create a path of nodes until you reach target
|
||||
// location. At each node find the neighbour with the lowest "distance" score.
|
||||
std::list<std::pair<int, int>> path;
|
||||
path.push_back({ nStartX, nStartY });
|
||||
int nLocX = nStartX;
|
||||
int nLocY = nStartY;
|
||||
bool bNoPath = false;
|
||||
|
||||
while (!(nLocX == nEndX && nLocY == nEndY) && !bNoPath)
|
||||
{
|
||||
std::list<std::tuple<int, int, int>> listNeighbours;
|
||||
|
||||
// 4-Way Connectivity
|
||||
if ((nLocY - 1) >= 0 && nFlowFieldZ[p(nLocX, nLocY - 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX, nLocY - 1, nFlowFieldZ[p(nLocX, nLocY - 1)] });
|
||||
|
||||
if ((nLocX + 1) < nMapWidth && nFlowFieldZ[p(nLocX + 1, nLocY)] > 0)
|
||||
listNeighbours.push_back({ nLocX + 1, nLocY, nFlowFieldZ[p(nLocX + 1, nLocY)] });
|
||||
|
||||
if ((nLocY + 1) < nMapHeight && nFlowFieldZ[p(nLocX, nLocY + 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX, nLocY + 1, nFlowFieldZ[p(nLocX, nLocY + 1)] });
|
||||
|
||||
if ((nLocX - 1) >= 0 && nFlowFieldZ[p(nLocX - 1, nLocY)] > 0)
|
||||
listNeighbours.push_back({ nLocX - 1, nLocY, nFlowFieldZ[p(nLocX - 1, nLocY)] });
|
||||
|
||||
// 8-Way Connectivity
|
||||
if ((nLocY - 1) >= 0 && (nLocX - 1) >= 0 && nFlowFieldZ[p(nLocX - 1, nLocY - 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX - 1, nLocY - 1, nFlowFieldZ[p(nLocX - 1, nLocY - 1)] });
|
||||
|
||||
if ((nLocY - 1) >= 0 && (nLocX + 1) < nMapWidth && nFlowFieldZ[p(nLocX + 1, nLocY - 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX + 1, nLocY - 1, nFlowFieldZ[p(nLocX + 1, nLocY - 1)] });
|
||||
|
||||
if ((nLocY + 1) < nMapHeight && (nLocX - 1) >= 0 && nFlowFieldZ[p(nLocX - 1, nLocY + 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX - 1, nLocY + 1, nFlowFieldZ[p(nLocX - 1, nLocY + 1)] });
|
||||
|
||||
if ((nLocY + 1) < nMapHeight && (nLocX + 1) < nMapWidth && nFlowFieldZ[p(nLocX + 1, nLocY + 1)] > 0)
|
||||
listNeighbours.push_back({ nLocX + 1, nLocY + 1, nFlowFieldZ[p(nLocX + 1, nLocY + 1)] });
|
||||
|
||||
// Sprt neigbours based on height, so lowest neighbour is at front
|
||||
// of list
|
||||
listNeighbours.sort([&](const std::tuple<int, int, int> &n1, const std::tuple<int, int, int> &n2)
|
||||
{
|
||||
return std::get<2>(n1) < std::get<2>(n2); // Compare distances
|
||||
});
|
||||
|
||||
if (listNeighbours.empty()) // Neighbour is invalid or no possible path
|
||||
bNoPath = true;
|
||||
else
|
||||
{
|
||||
nLocX = std::get<0>(listNeighbours.front());
|
||||
nLocY = std::get<1>(listNeighbours.front());
|
||||
path.push_back({ nLocX, nLocY });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 4) Create Flow "Field"
|
||||
for (int x = 1; x < nMapWidth - 1; x++)
|
||||
{
|
||||
for (int y = 1; y < nMapHeight - 1; y++)
|
||||
{
|
||||
float vx = 0.0f;
|
||||
float vy = 0.0f;
|
||||
|
||||
vy -= (float)((nFlowFieldZ[p(x, y + 1)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x, y + 1)]) - nFlowFieldZ[p(x, y)]);
|
||||
vx -= (float)((nFlowFieldZ[p(x + 1, y)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x + 1, y)]) - nFlowFieldZ[p(x, y)]);
|
||||
vy += (float)((nFlowFieldZ[p(x, y - 1)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x, y - 1)]) - nFlowFieldZ[p(x, y)]);
|
||||
vx += (float)((nFlowFieldZ[p(x - 1, y)] <= 0 ? nFlowFieldZ[p(x, y)] : nFlowFieldZ[p(x - 1, y)]) - nFlowFieldZ[p(x, y)]);
|
||||
|
||||
float r = 1.0f / sqrtf(vx*vx + vy * vy);
|
||||
fFlowFieldX[p(x, y)] = vx * r;
|
||||
fFlowFieldY[p(x, y)] = vy * r;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Draw Map
|
||||
Clear(olc::BLACK);
|
||||
|
||||
for (int x = 0; x < nMapWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < nMapHeight; y++)
|
||||
{
|
||||
olc::Pixel colour = olc::BLUE;
|
||||
|
||||
if (bObstacleMap[p(x, y)])
|
||||
colour = olc::GREY;
|
||||
|
||||
if (nWave == nFlowFieldZ[p(x, y)])
|
||||
colour = olc::DARK_CYAN;
|
||||
|
||||
if (x == nStartX && y == nStartY)
|
||||
colour = olc::GREEN;
|
||||
|
||||
if (x == nEndX && y == nEndY)
|
||||
colour = olc::RED;
|
||||
|
||||
// Draw Base
|
||||
FillRect(x * nCellSize, y * nCellSize, nCellSize - nBorderWidth, nCellSize - nBorderWidth, colour);
|
||||
|
||||
// Draw "potential" or "distance" or "height" :D
|
||||
//DrawString(x * nCellSize, y * nCellSize, std::to_string(nFlowFieldZ[p(x, y)]), olc::WHITE);
|
||||
|
||||
if (nFlowFieldZ[p(x, y)] > 0)
|
||||
{
|
||||
float ax[4], ay[4];
|
||||
float fAngle = atan2f(fFlowFieldY[p(x, y)], fFlowFieldX[p(x, y)]);
|
||||
float fRadius = (float)(nCellSize - nBorderWidth) / 2.0f;
|
||||
int fOffsetX = x * nCellSize + ((nCellSize - nBorderWidth) / 2);
|
||||
int fOffsetY = y * nCellSize + ((nCellSize - nBorderWidth) / 2);
|
||||
ax[0] = cosf(fAngle) * fRadius + fOffsetX;
|
||||
ay[0] = sinf(fAngle) * fRadius + fOffsetY;
|
||||
ax[1] = cosf(fAngle) * -fRadius + fOffsetX;
|
||||
ay[1] = sinf(fAngle) * -fRadius + fOffsetY;
|
||||
ax[2] = cosf(fAngle + 0.1f) * fRadius * 0.7f + fOffsetX;
|
||||
ay[2] = sinf(fAngle + 0.1f) * fRadius * 0.7f + fOffsetY;
|
||||
ax[3] = cosf(fAngle - 0.1f) * fRadius * 0.7f + fOffsetX;
|
||||
ay[3] = sinf(fAngle - 0.1f) * fRadius * 0.7f + fOffsetY;
|
||||
|
||||
DrawLine(ax[0], ay[0], ax[1], ay[1], olc::CYAN);
|
||||
DrawLine(ax[0], ay[0], ax[2], ay[2], olc::CYAN);
|
||||
DrawLine(ax[0], ay[0], ax[3], ay[3], olc::CYAN);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool bFirstPoint = true;
|
||||
int ox, oy;
|
||||
for (auto &a : path)
|
||||
{
|
||||
if (bFirstPoint)
|
||||
{
|
||||
ox = a.first;
|
||||
oy = a.second;
|
||||
bFirstPoint = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawLine(
|
||||
ox * nCellSize + ((nCellSize - nBorderWidth) / 2),
|
||||
oy * nCellSize + ((nCellSize - nBorderWidth) / 2),
|
||||
a.first * nCellSize + ((nCellSize - nBorderWidth) / 2),
|
||||
a.second * nCellSize + ((nCellSize - nBorderWidth) / 2), olc::YELLOW);
|
||||
|
||||
ox = a.first;
|
||||
oy = a.second;
|
||||
|
||||
FillCircle(ox * nCellSize + ((nCellSize - nBorderWidth) / 2), oy * nCellSize + ((nCellSize - nBorderWidth) / 2), 10, olc::YELLOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
PathFinding_FlowFields demo;
|
||||
if (demo.Construct(512, 480, 2, 2))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
434
Videos/OneLoneCoder_PGE_PolygonCollisions1.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
Convex Polygon Collision Detection
|
||||
"Don't you dare try concave ones..." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Instructions:
|
||||
~~~~~~~~~~~~~
|
||||
Use arrow keys to control pentagon
|
||||
Use WASD to control triangle
|
||||
F1..F4 selects algorithm
|
||||
|
||||
Relevant Video: https://youtu.be/7Ik2vowGcU0
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
// Override base class with your custom functionality
|
||||
class PolygonCollisions : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
PolygonCollisions()
|
||||
{
|
||||
sAppName = "Polygon Collisions";
|
||||
}
|
||||
|
||||
struct vec2d
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
struct polygon
|
||||
{
|
||||
std::vector<vec2d> p; // Transformed Points
|
||||
vec2d pos; // Position of shape
|
||||
float angle; // Direction of shape
|
||||
std::vector<vec2d> o; // "Model" of shape
|
||||
bool overlap = false; // Flag to indicate if overlap has occurred
|
||||
};
|
||||
|
||||
std::vector<polygon> vecShapes;
|
||||
|
||||
int nMode = 0;
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
// Create Pentagon
|
||||
polygon s1;
|
||||
float fTheta = 3.14159f * 2.0f / 5.0f;
|
||||
s1.pos = { 100, 100 };
|
||||
s1.angle = 0.0f;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
s1.o.push_back({ 30.0f * cosf(fTheta * i), 30.0f * sinf(fTheta * i) });
|
||||
s1.p.push_back({ 30.0f * cosf(fTheta * i), 30.0f * sinf(fTheta * i) });
|
||||
}
|
||||
|
||||
// Create Triangle
|
||||
polygon s2;
|
||||
fTheta = 3.14159f * 2.0f / 3.0f;
|
||||
s2.pos = { 200, 150 };
|
||||
s2.angle = 0.0f;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
s2.o.push_back({ 20.0f * cosf(fTheta * i), 20.0f * sinf(fTheta * i) });
|
||||
s2.p.push_back({ 20.0f * cosf(fTheta * i), 20.0f * sinf(fTheta * i) });
|
||||
}
|
||||
|
||||
// Create Quad
|
||||
polygon s3;
|
||||
s3.pos = { 50, 200 };
|
||||
s3.angle = 0.0f;
|
||||
s3.o.push_back({ -30, -30 });
|
||||
s3.o.push_back({ -30, +30 });
|
||||
s3.o.push_back({ +30, +30 });
|
||||
s3.o.push_back({ +30, -30 });
|
||||
s3.p.resize(4);
|
||||
|
||||
|
||||
vecShapes.push_back(s1);
|
||||
vecShapes.push_back(s2);
|
||||
vecShapes.push_back(s3);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ShapeOverlap_SAT(polygon &r1, polygon &r2)
|
||||
{
|
||||
polygon *poly1 = &r1;
|
||||
polygon *poly2 = &r2;
|
||||
|
||||
for (int shape = 0; shape < 2; shape++)
|
||||
{
|
||||
if (shape == 1)
|
||||
{
|
||||
poly1 = &r2;
|
||||
poly2 = &r1;
|
||||
}
|
||||
|
||||
for (int a = 0; a < poly1->p.size(); a++)
|
||||
{
|
||||
int b = (a + 1) % poly1->p.size();
|
||||
vec2d axisProj = { -(poly1->p[b].y - poly1->p[a].y), poly1->p[b].x - poly1->p[a].x };
|
||||
float d = sqrtf(axisProj.x * axisProj.x + axisProj.y * axisProj.y);
|
||||
axisProj = { axisProj.x / d, axisProj.y / d };
|
||||
|
||||
// Work out min and max 1D points for r1
|
||||
float min_r1 = INFINITY, max_r1 = -INFINITY;
|
||||
for (int p = 0; p < poly1->p.size(); p++)
|
||||
{
|
||||
float q = (poly1->p[p].x * axisProj.x + poly1->p[p].y * axisProj.y);
|
||||
min_r1 = std::min(min_r1, q);
|
||||
max_r1 = std::max(max_r1, q);
|
||||
}
|
||||
|
||||
// Work out min and max 1D points for r2
|
||||
float min_r2 = INFINITY, max_r2 = -INFINITY;
|
||||
for (int p = 0; p < poly2->p.size(); p++)
|
||||
{
|
||||
float q = (poly2->p[p].x * axisProj.x + poly2->p[p].y * axisProj.y);
|
||||
min_r2 = std::min(min_r2, q);
|
||||
max_r2 = std::max(max_r2, q);
|
||||
}
|
||||
|
||||
if (!(max_r2 >= min_r1 && max_r1 >= min_r2))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShapeOverlap_SAT_STATIC(polygon &r1, polygon &r2)
|
||||
{
|
||||
polygon *poly1 = &r1;
|
||||
polygon *poly2 = &r2;
|
||||
|
||||
float overlap = INFINITY;
|
||||
|
||||
for (int shape = 0; shape < 2; shape++)
|
||||
{
|
||||
if (shape == 1)
|
||||
{
|
||||
poly1 = &r2;
|
||||
poly2 = &r1;
|
||||
}
|
||||
|
||||
for (int a = 0; a < poly1->p.size(); a++)
|
||||
{
|
||||
int b = (a + 1) % poly1->p.size();
|
||||
vec2d axisProj = { -(poly1->p[b].y - poly1->p[a].y), poly1->p[b].x - poly1->p[a].x };
|
||||
|
||||
// Optional normalisation of projection axis enhances stability slightly
|
||||
//float d = sqrtf(axisProj.x * axisProj.x + axisProj.y * axisProj.y);
|
||||
//axisProj = { axisProj.x / d, axisProj.y / d };
|
||||
|
||||
// Work out min and max 1D points for r1
|
||||
float min_r1 = INFINITY, max_r1 = -INFINITY;
|
||||
for (int p = 0; p < poly1->p.size(); p++)
|
||||
{
|
||||
float q = (poly1->p[p].x * axisProj.x + poly1->p[p].y * axisProj.y);
|
||||
min_r1 = std::min(min_r1, q);
|
||||
max_r1 = std::max(max_r1, q);
|
||||
}
|
||||
|
||||
// Work out min and max 1D points for r2
|
||||
float min_r2 = INFINITY, max_r2 = -INFINITY;
|
||||
for (int p = 0; p < poly2->p.size(); p++)
|
||||
{
|
||||
float q = (poly2->p[p].x * axisProj.x + poly2->p[p].y * axisProj.y);
|
||||
min_r2 = std::min(min_r2, q);
|
||||
max_r2 = std::max(max_r2, q);
|
||||
}
|
||||
|
||||
// Calculate actual overlap along projected axis, and store the minimum
|
||||
overlap = std::min(std::min(max_r1, max_r2) - std::max(min_r1, min_r2), overlap);
|
||||
|
||||
if (!(max_r2 >= min_r1 && max_r1 >= min_r2))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we got here, the objects have collided, we will displace r1
|
||||
// by overlap along the vector between the two object centers
|
||||
vec2d d = { r2.pos.x - r1.pos.x, r2.pos.y - r1.pos.y };
|
||||
float s = sqrtf(d.x*d.x + d.y*d.y);
|
||||
r1.pos.x -= overlap * d.x / s;
|
||||
r1.pos.y -= overlap * d.y / s;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use edge/diagonal intersections.
|
||||
bool ShapeOverlap_DIAGS(polygon &r1, polygon &r2)
|
||||
{
|
||||
polygon *poly1 = &r1;
|
||||
polygon *poly2 = &r2;
|
||||
|
||||
for (int shape = 0; shape < 2; shape++)
|
||||
{
|
||||
if (shape == 1)
|
||||
{
|
||||
poly1 = &r2;
|
||||
poly2 = &r1;
|
||||
}
|
||||
|
||||
// Check diagonals of polygon...
|
||||
for (int p = 0; p < poly1->p.size(); p++)
|
||||
{
|
||||
vec2d line_r1s = poly1->pos;
|
||||
vec2d line_r1e = poly1->p[p];
|
||||
|
||||
// ...against edges of the other
|
||||
for (int q = 0; q < poly2->p.size(); q++)
|
||||
{
|
||||
vec2d line_r2s = poly2->p[q];
|
||||
vec2d line_r2e = poly2->p[(q + 1) % poly2->p.size()];
|
||||
|
||||
// Standard "off the shelf" line segment intersection
|
||||
float h = (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r1e.y) - (line_r1s.x - line_r1e.x) * (line_r2e.y - line_r2s.y);
|
||||
float t1 = ((line_r2s.y - line_r2e.y) * (line_r1s.x - line_r2s.x) + (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r2s.y)) / h;
|
||||
float t2 = ((line_r1s.y - line_r1e.y) * (line_r1s.x - line_r2s.x) + (line_r1e.x - line_r1s.x) * (line_r1s.y - line_r2s.y)) / h;
|
||||
|
||||
if (t1 >= 0.0f && t1 < 1.0f && t2 >= 0.0f && t2 < 1.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use edge/diagonal intersections.
|
||||
bool ShapeOverlap_DIAGS_STATIC(polygon &r1, polygon &r2)
|
||||
{
|
||||
polygon *poly1 = &r1;
|
||||
polygon *poly2 = &r2;
|
||||
|
||||
for (int shape = 0; shape < 2; shape++)
|
||||
{
|
||||
if (shape == 1)
|
||||
{
|
||||
poly1 = &r2;
|
||||
poly2 = &r1;
|
||||
}
|
||||
|
||||
// Check diagonals of this polygon...
|
||||
for (int p = 0; p < poly1->p.size(); p++)
|
||||
{
|
||||
vec2d line_r1s = poly1->pos;
|
||||
vec2d line_r1e = poly1->p[p];
|
||||
|
||||
vec2d displacement = { 0,0 };
|
||||
|
||||
// ...against edges of this polygon
|
||||
for (int q = 0; q < poly2->p.size(); q++)
|
||||
{
|
||||
vec2d line_r2s = poly2->p[q];
|
||||
vec2d line_r2e = poly2->p[(q + 1) % poly2->p.size()];
|
||||
|
||||
// Standard "off the shelf" line segment intersection
|
||||
float h = (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r1e.y) - (line_r1s.x - line_r1e.x) * (line_r2e.y - line_r2s.y);
|
||||
float t1 = ((line_r2s.y - line_r2e.y) * (line_r1s.x - line_r2s.x) + (line_r2e.x - line_r2s.x) * (line_r1s.y - line_r2s.y)) / h;
|
||||
float t2 = ((line_r1s.y - line_r1e.y) * (line_r1s.x - line_r2s.x) + (line_r1e.x - line_r1s.x) * (line_r1s.y - line_r2s.y)) / h;
|
||||
|
||||
if (t1 >= 0.0f && t1 < 1.0f && t2 >= 0.0f && t2 < 1.0f)
|
||||
{
|
||||
displacement.x += (1.0f - t1) * (line_r1e.x - line_r1s.x);
|
||||
displacement.y += (1.0f - t1) * (line_r1e.y - line_r1s.y);
|
||||
}
|
||||
}
|
||||
|
||||
r1.pos.x += displacement.x * (shape == 0 ? -1 : +1);
|
||||
r1.pos.y += displacement.y * (shape == 0 ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
// Cant overlap if static collision is resolved
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
if (GetKey(olc::Key::F1).bReleased) nMode = 0;
|
||||
if (GetKey(olc::Key::F2).bReleased) nMode = 1;
|
||||
if (GetKey(olc::Key::F3).bReleased) nMode = 2;
|
||||
if (GetKey(olc::Key::F4).bReleased) nMode = 3;
|
||||
|
||||
// Shape 1
|
||||
if (GetKey(olc::Key::LEFT).bHeld) vecShapes[0].angle -= 2.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::RIGHT).bHeld) vecShapes[0].angle += 2.0f * fElapsedTime;
|
||||
|
||||
if (GetKey(olc::Key::UP).bHeld)
|
||||
{
|
||||
vecShapes[0].pos.x += cosf(vecShapes[0].angle) * 60.0f * fElapsedTime;
|
||||
vecShapes[0].pos.y += sinf(vecShapes[0].angle) * 60.0f * fElapsedTime;
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::DOWN).bHeld)
|
||||
{
|
||||
vecShapes[0].pos.x -= cosf(vecShapes[0].angle) * 60.0f * fElapsedTime;
|
||||
vecShapes[0].pos.y -= sinf(vecShapes[0].angle) * 60.0f * fElapsedTime;
|
||||
}
|
||||
|
||||
// Shape 2
|
||||
if (GetKey(olc::Key::A).bHeld) vecShapes[1].angle -= 2.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::D).bHeld) vecShapes[1].angle += 2.0f * fElapsedTime;
|
||||
|
||||
if (GetKey(olc::Key::W).bHeld)
|
||||
{
|
||||
vecShapes[1].pos.x += cosf(vecShapes[1].angle) * 60.0f * fElapsedTime;
|
||||
vecShapes[1].pos.y += sinf(vecShapes[1].angle) * 60.0f * fElapsedTime;
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::S).bHeld)
|
||||
{
|
||||
vecShapes[1].pos.x -= cosf(vecShapes[1].angle) * 60.0f * fElapsedTime;
|
||||
vecShapes[1].pos.y -= sinf(vecShapes[1].angle) * 60.0f * fElapsedTime;
|
||||
}
|
||||
|
||||
// Update Shapes and reset flags
|
||||
for (auto &r : vecShapes)
|
||||
{
|
||||
for (int i = 0; i < r.o.size(); i++)
|
||||
r.p[i] =
|
||||
{ // 2D Rotation Transform + 2D Translation
|
||||
(r.o[i].x * cosf(r.angle)) - (r.o[i].y * sinf(r.angle)) + r.pos.x,
|
||||
(r.o[i].x * sinf(r.angle)) + (r.o[i].y * cosf(r.angle)) + r.pos.y,
|
||||
};
|
||||
|
||||
r.overlap = false;
|
||||
}
|
||||
|
||||
// Check for overlap
|
||||
for (int m = 0; m < vecShapes.size(); m++)
|
||||
for (int n = m + 1; n < vecShapes.size(); n++)
|
||||
{
|
||||
switch (nMode)
|
||||
{
|
||||
case 0: vecShapes[m].overlap |= ShapeOverlap_SAT(vecShapes[m], vecShapes[n]); break;
|
||||
case 1: vecShapes[m].overlap |= ShapeOverlap_SAT_STATIC(vecShapes[m], vecShapes[n]); break;
|
||||
case 2: vecShapes[m].overlap |= ShapeOverlap_DIAGS(vecShapes[m], vecShapes[n]); break;
|
||||
case 3: vecShapes[m].overlap |= ShapeOverlap_DIAGS_STATIC(vecShapes[m], vecShapes[n]); break;
|
||||
}
|
||||
}
|
||||
|
||||
// === Render Display ===
|
||||
Clear(olc::BLUE);
|
||||
|
||||
// Draw Shapes
|
||||
for (auto &r : vecShapes)
|
||||
{
|
||||
// Draw Boundary
|
||||
for (int i = 0; i < r.p.size(); i++)
|
||||
DrawLine(r.p[i].x, r.p[i].y, r.p[(i + 1) % r.p.size()].x, r.p[(i + 1) % r.p.size()].y, (r.overlap ? olc::RED : olc::WHITE));
|
||||
|
||||
// Draw Direction
|
||||
DrawLine(r.p[0].x, r.p[0].y, r.pos.x, r.pos.y, (r.overlap ? olc::RED : olc::WHITE));
|
||||
}
|
||||
|
||||
// Draw HUD
|
||||
DrawString(8, 10, "F1: SAT", (nMode == 0 ? olc::RED : olc::YELLOW));
|
||||
DrawString(8, 20, "F2: SAT/STATIC", (nMode == 1 ? olc::RED : olc::YELLOW));
|
||||
DrawString(8, 30, "F3: DIAG", (nMode == 2 ? olc::RED : olc::YELLOW));
|
||||
DrawString(8, 40, "F4: DIAG/STATIC", (nMode == 3 ? olc::RED : olc::YELLOW));
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
PolygonCollisions demo;
|
||||
if (demo.Construct(256, 240, 4, 4))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
542
Videos/OneLoneCoder_PGE_Polymorphism.cpp
Normal file
@@ -0,0 +1,542 @@
|
||||
/*
|
||||
OLC::CAD - A practical example of Polymorphism
|
||||
"Damn Gorbette, you made us giggle..." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Instructions:
|
||||
~~~~~~~~~~~~~
|
||||
Press & Hold middle mouse mutton to PAN
|
||||
Use Scroll wheel (or Q & A) to zoom in & out
|
||||
Press L to start drawing a line
|
||||
Press C to start drawing a circle
|
||||
Press B to start drawing a box
|
||||
Press S to start drawing a curve
|
||||
Press M to move node under cursor
|
||||
|
||||
Relevant Video: https://youtu.be/kxKKHKSMGIg
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
// Forward declare shape, since we use it in sNode
|
||||
struct sShape;
|
||||
|
||||
// Define a node
|
||||
struct sNode
|
||||
{
|
||||
sShape *parent;
|
||||
olc::vf2d pos;
|
||||
};
|
||||
|
||||
// Our BASE class, defines the interface for all shapes
|
||||
struct sShape
|
||||
{
|
||||
// Shapes are defined by the placment of nodes
|
||||
std::vector<sNode> vecNodes;
|
||||
uint32_t nMaxNodes = 0;
|
||||
|
||||
// The colour of the shape
|
||||
olc::Pixel col = olc::GREEN;
|
||||
|
||||
// All shapes share word to screen transformation
|
||||
// coefficients, so share them staically
|
||||
static float fWorldScale;
|
||||
static olc::vf2d vWorldOffset;
|
||||
|
||||
// Convert coordinates from World Space --> Screen Space
|
||||
void WorldToScreen(const olc::vf2d &v, int &nScreenX, int &nScreenY)
|
||||
{
|
||||
nScreenX = (int)((v.x - vWorldOffset.x) * fWorldScale);
|
||||
nScreenY = (int)((v.y - vWorldOffset.y) * fWorldScale);
|
||||
}
|
||||
|
||||
// This is a PURE function, which makes this class abstract. A sub-class
|
||||
// of this class must provide an implementation of this function by
|
||||
// overriding it
|
||||
virtual void DrawYourself(olc::PixelGameEngine *pge) = 0;
|
||||
|
||||
// Shapes are defined by nodes, the shape is responsible
|
||||
// for issuing nodes that get placed by the user. The shape may
|
||||
// change depending on how many nodes have been placed. Once the
|
||||
// maximum number of nodes for a shape have been placed, it returns
|
||||
// nullptr
|
||||
sNode* GetNextNode(const olc::vf2d &p)
|
||||
{
|
||||
if (vecNodes.size() == nMaxNodes)
|
||||
return nullptr; // Shape is complete so no new nodes to be issued
|
||||
|
||||
// else create new node and add to shapes node vector
|
||||
sNode n;
|
||||
n.parent = this;
|
||||
n.pos = p;
|
||||
vecNodes.push_back(n);
|
||||
|
||||
// Beware! - This normally is bad! But see sub classes
|
||||
return &vecNodes[vecNodes.size() - 1];
|
||||
}
|
||||
|
||||
// Test to see if supplied coordinate exists at same location
|
||||
// as any of the nodes for this shape. Return a pointer to that
|
||||
// node if it does
|
||||
sNode* HitNode(olc::vf2d &p)
|
||||
{
|
||||
for (auto &n : vecNodes)
|
||||
{
|
||||
if ((p - n.pos).mag() < 0.01f)
|
||||
return &n;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Draw all of the nodes that define this shape so far
|
||||
void DrawNodes(olc::PixelGameEngine *pge)
|
||||
{
|
||||
for (auto &n : vecNodes)
|
||||
{
|
||||
int sx, sy;
|
||||
WorldToScreen(n.pos, sx, sy);
|
||||
pge->FillCircle(sx, sy, 2, olc::RED);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// We must provide an implementation of our static variables
|
||||
float sShape::fWorldScale = 1.0f;
|
||||
olc::vf2d sShape::vWorldOffset = { 0,0 };
|
||||
|
||||
|
||||
|
||||
// LINE sub class, inherits from sShape
|
||||
struct sLine : public sShape
|
||||
{
|
||||
sLine()
|
||||
{
|
||||
nMaxNodes = 2;
|
||||
vecNodes.reserve(nMaxNodes); // We're gonna be getting pointers to vector elements
|
||||
// though we have defined already how much capacity our vector will have. This makes
|
||||
// it safe to do this as we know the vector will not be maniupulated as we add nodes
|
||||
// to it. Is this bad practice? Possibly, but as with all thing programming, if you
|
||||
// know what you are doing, it's ok :D
|
||||
}
|
||||
|
||||
// Implements custom DrawYourself Function, meaning the shape
|
||||
// is no longer abstract
|
||||
void DrawYourself(olc::PixelGameEngine *pge) override
|
||||
{
|
||||
int sx, sy, ex, ey;
|
||||
WorldToScreen(vecNodes[0].pos, sx, sy);
|
||||
WorldToScreen(vecNodes[1].pos, ex, ey);
|
||||
pge->DrawLine(sx, sy, ex, ey, col);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// BOX
|
||||
struct sBox : public sShape
|
||||
{
|
||||
sBox()
|
||||
{
|
||||
nMaxNodes = 2;
|
||||
vecNodes.reserve(nMaxNodes);
|
||||
}
|
||||
|
||||
void DrawYourself(olc::PixelGameEngine *pge) override
|
||||
{
|
||||
int sx, sy, ex, ey;
|
||||
WorldToScreen(vecNodes[0].pos, sx, sy);
|
||||
WorldToScreen(vecNodes[1].pos, ex, ey);
|
||||
pge->DrawRect(sx, sy, ex - sx, ey - sy, col);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// CIRCLE
|
||||
struct sCircle : public sShape
|
||||
{
|
||||
sCircle()
|
||||
{
|
||||
nMaxNodes = 2;
|
||||
vecNodes.reserve(nMaxNodes);
|
||||
}
|
||||
|
||||
void DrawYourself(olc::PixelGameEngine *pge) override
|
||||
{
|
||||
float fRadius = (vecNodes[0].pos - vecNodes[1].pos).mag();
|
||||
int sx, sy, ex, ey;
|
||||
WorldToScreen(vecNodes[0].pos, sx, sy);
|
||||
WorldToScreen(vecNodes[1].pos, ex, ey);
|
||||
pge->DrawLine(sx, sy, ex, ey, col, 0xFF00FF00);
|
||||
|
||||
// Note the radius is also scaled so it is drawn appropriately
|
||||
pge->DrawCircle(sx, sy, (int32_t)(fRadius * fWorldScale), col);
|
||||
}
|
||||
};
|
||||
|
||||
// BEZIER SPLINE - requires 3 nodes to be defined fully
|
||||
struct sCurve : public sShape
|
||||
{
|
||||
sCurve()
|
||||
{
|
||||
nMaxNodes = 3;
|
||||
vecNodes.reserve(nMaxNodes);
|
||||
}
|
||||
|
||||
void DrawYourself(olc::PixelGameEngine *pge) override
|
||||
{
|
||||
int sx, sy, ex, ey;
|
||||
|
||||
if (vecNodes.size() < 3)
|
||||
{
|
||||
// Can only draw line from first to second
|
||||
WorldToScreen(vecNodes[0].pos, sx, sy);
|
||||
WorldToScreen(vecNodes[1].pos, ex, ey);
|
||||
pge->DrawLine(sx, sy, ex, ey, col, 0xFF00FF00);
|
||||
}
|
||||
|
||||
if (vecNodes.size() == 3)
|
||||
{
|
||||
// Can draw line from first to second
|
||||
WorldToScreen(vecNodes[0].pos, sx, sy);
|
||||
WorldToScreen(vecNodes[1].pos, ex, ey);
|
||||
pge->DrawLine(sx, sy, ex, ey, col, 0xFF00FF00);
|
||||
|
||||
// Can draw second structural line
|
||||
WorldToScreen(vecNodes[1].pos, sx, sy);
|
||||
WorldToScreen(vecNodes[2].pos, ex, ey);
|
||||
pge->DrawLine(sx, sy, ex, ey, col, 0xFF00FF00);
|
||||
|
||||
// And bezier curve
|
||||
olc::vf2d op = vecNodes[0].pos;
|
||||
olc::vf2d np = op;
|
||||
for (float t = 0; t < 1.0f; t += 0.01f)
|
||||
{
|
||||
np = (1 - t)*(1 - t)*vecNodes[0].pos + 2 * (1 - t)*t*vecNodes[1].pos + t * t * vecNodes[2].pos;
|
||||
WorldToScreen(op, sx, sy);
|
||||
WorldToScreen(np, ex, ey);
|
||||
pge->DrawLine(sx, sy, ex, ey, col);
|
||||
op = np;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// APPLICATION STARTS HERE
|
||||
|
||||
class Polymorphism : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
Polymorphism()
|
||||
{
|
||||
sAppName = "Polymorphism";
|
||||
}
|
||||
|
||||
private:
|
||||
// Pan & Zoom variables
|
||||
olc::vf2d vOffset = { 0.0f, 0.0f };
|
||||
olc::vf2d vStartPan = { 0.0f, 0.0f };
|
||||
float fScale = 10.0f;
|
||||
float fGrid = 1.0f;
|
||||
|
||||
// Convert coordinates from World Space --> Screen Space
|
||||
void WorldToScreen(const olc::vf2d &v, int &nScreenX, int &nScreenY)
|
||||
{
|
||||
nScreenX = (int)((v.x - vOffset.x) * fScale);
|
||||
nScreenY = (int)((v.y - vOffset.y) * fScale);
|
||||
}
|
||||
|
||||
// Convert coordinates from Screen Space --> World Space
|
||||
void ScreenToWorld(int nScreenX, int nScreenY, olc::vf2d &v)
|
||||
{
|
||||
v.x = (float)(nScreenX) / fScale + vOffset.x;
|
||||
v.y = (float)(nScreenY) / fScale + vOffset.y;
|
||||
}
|
||||
|
||||
|
||||
// A pointer to a shape that is currently being defined
|
||||
// by the placment of nodes
|
||||
sShape* tempShape = nullptr;
|
||||
|
||||
// A list of pointers to all shapes which have been drawn
|
||||
// so far
|
||||
std::list<sShape*> listShapes;
|
||||
|
||||
// A pointer to a node that is currently selected. Selected
|
||||
// nodes follow the mouse cursor
|
||||
sNode *selectedNode = nullptr;
|
||||
|
||||
// "Snapped" mouse location
|
||||
olc::vf2d vCursor = { 0, 0 };
|
||||
|
||||
// NOTE! No direct instances of lines, circles, boxes or curves,
|
||||
// the application is only aware of the existence of shapes!
|
||||
// THIS IS THE POWER OF POLYMORPHISM!
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
// Configure world space (0,0) to be middle of screen space
|
||||
vOffset = { (float)(-ScreenWidth() / 2) / fScale, (float)(-ScreenHeight() / 2) / fScale };
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
// Get mouse location this frame
|
||||
olc::vf2d vMouse = { (float)GetMouseX(), (float)GetMouseY() };
|
||||
|
||||
|
||||
// Handle Pan & Zoom
|
||||
if (GetMouse(2).bPressed)
|
||||
{
|
||||
vStartPan = vMouse;
|
||||
}
|
||||
|
||||
if (GetMouse(2).bHeld)
|
||||
{
|
||||
vOffset -= (vMouse - vStartPan) / fScale;
|
||||
vStartPan = vMouse;
|
||||
}
|
||||
|
||||
olc::vf2d vMouseBeforeZoom;
|
||||
ScreenToWorld((int)vMouse.x, (int)vMouse.y, vMouseBeforeZoom);
|
||||
|
||||
if (GetKey(olc::Key::Q).bHeld || GetMouseWheel() > 0)
|
||||
{
|
||||
fScale *= 1.1f;
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::A).bHeld || GetMouseWheel() < 0)
|
||||
{
|
||||
fScale *= 0.9f;
|
||||
}
|
||||
|
||||
olc::vf2d vMouseAfterZoom;
|
||||
ScreenToWorld((int)vMouse.x, (int)vMouse.y, vMouseAfterZoom);
|
||||
vOffset += (vMouseBeforeZoom - vMouseAfterZoom);
|
||||
|
||||
|
||||
// Snap mouse cursor to nearest grid interval
|
||||
vCursor.x = floorf((vMouseAfterZoom.x + 0.5f) * fGrid);
|
||||
vCursor.y = floorf((vMouseAfterZoom.y + 0.5f) * fGrid);
|
||||
|
||||
|
||||
if (GetKey(olc::Key::L).bPressed)
|
||||
{
|
||||
tempShape = new sLine();
|
||||
|
||||
// Place first node at location of keypress
|
||||
selectedNode = tempShape->GetNextNode(vCursor);
|
||||
|
||||
// Get Second node
|
||||
selectedNode = tempShape->GetNextNode(vCursor);
|
||||
}
|
||||
|
||||
|
||||
if (GetKey(olc::Key::B).bPressed)
|
||||
{
|
||||
tempShape = new sBox();
|
||||
|
||||
// Place first node at location of keypress
|
||||
selectedNode = tempShape->GetNextNode(vCursor);
|
||||
|
||||
// Get Second node
|
||||
selectedNode = tempShape->GetNextNode(vCursor);
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::C).bPressed)
|
||||
{
|
||||
// Create new shape as a temporary
|
||||
tempShape = new sCircle();
|
||||
|
||||
// Place first node at location of keypress
|
||||
selectedNode = tempShape->GetNextNode(vCursor);
|
||||
|
||||
// Get Second node
|
||||
selectedNode = tempShape->GetNextNode(vCursor);
|
||||
}
|
||||
|
||||
if (GetKey(olc::Key::S).bPressed)
|
||||
{
|
||||
// Create new shape as a temporary
|
||||
tempShape = new sCurve();
|
||||
|
||||
// Place first node at location of keypress
|
||||
selectedNode = tempShape->GetNextNode(vCursor);
|
||||
|
||||
// Get Second node
|
||||
selectedNode = tempShape->GetNextNode(vCursor);
|
||||
}
|
||||
|
||||
// Search for any node that exists under the cursor, if one
|
||||
// is found then select it
|
||||
if (GetKey(olc::Key::M).bPressed)
|
||||
{
|
||||
selectedNode = nullptr;
|
||||
for (auto &shape : listShapes)
|
||||
{
|
||||
selectedNode = shape->HitNode(vCursor);
|
||||
if (selectedNode != nullptr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If a node is selected, make it follow the mouse cursor
|
||||
// by updating its position
|
||||
if (selectedNode != nullptr)
|
||||
{
|
||||
selectedNode->pos = vCursor;
|
||||
}
|
||||
|
||||
|
||||
// As the user left clicks to place nodes, the shape can grow
|
||||
// until it requires no more nodes, at which point it is completed
|
||||
// and added to the list of completed shapes.
|
||||
if (GetMouse(0).bReleased)
|
||||
{
|
||||
if (tempShape != nullptr)
|
||||
{
|
||||
selectedNode = tempShape->GetNextNode(vCursor);
|
||||
if (selectedNode == nullptr)
|
||||
{
|
||||
tempShape->col = olc::WHITE;
|
||||
listShapes.push_back(tempShape);
|
||||
tempShape = nullptr; // Thanks @howlevergreen /Disord
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedNode = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Clear Screen
|
||||
Clear(olc::VERY_DARK_BLUE);
|
||||
|
||||
int sx, sy;
|
||||
int ex, ey;
|
||||
|
||||
// Get visible world
|
||||
olc::vf2d vWorldTopLeft, vWorldBottomRight;
|
||||
ScreenToWorld(0, 0, vWorldTopLeft);
|
||||
ScreenToWorld(ScreenWidth(), ScreenHeight(), vWorldBottomRight);
|
||||
|
||||
// Get values just beyond screen boundaries
|
||||
vWorldTopLeft.x = floor(vWorldTopLeft.x);
|
||||
vWorldTopLeft.y = floor(vWorldTopLeft.y);
|
||||
vWorldBottomRight.x = ceil(vWorldBottomRight.x);
|
||||
vWorldBottomRight.y = ceil(vWorldBottomRight.y);
|
||||
|
||||
// Draw Grid dots
|
||||
for (float x = vWorldTopLeft.x; x < vWorldBottomRight.x; x += fGrid)
|
||||
{
|
||||
for (float y = vWorldTopLeft.y; y < vWorldBottomRight.y; y += fGrid)
|
||||
{
|
||||
WorldToScreen({ x, y }, sx, sy);
|
||||
Draw(sx, sy, olc::BLUE);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw World Axis
|
||||
WorldToScreen({ 0,vWorldTopLeft.y }, sx, sy);
|
||||
WorldToScreen({ 0,vWorldBottomRight.y }, ex, ey);
|
||||
DrawLine(sx, sy, ex, ey, olc::GREY, 0xF0F0F0F0);
|
||||
WorldToScreen({ vWorldTopLeft.x,0 }, sx, sy);
|
||||
WorldToScreen({ vWorldBottomRight.x,0 }, ex, ey);
|
||||
DrawLine(sx, sy, ex, ey, olc::GREY, 0xF0F0F0F0);
|
||||
|
||||
// Update shape translation coefficients
|
||||
sShape::fWorldScale = fScale;
|
||||
sShape::vWorldOffset = vOffset;
|
||||
|
||||
// Draw All Existing Shapes
|
||||
for (auto &shape : listShapes)
|
||||
{
|
||||
shape->DrawYourself(this);
|
||||
shape->DrawNodes(this);
|
||||
}
|
||||
|
||||
// Draw shape currently being defined
|
||||
if (tempShape != nullptr)
|
||||
{
|
||||
tempShape->DrawYourself(this);
|
||||
tempShape->DrawNodes(this);
|
||||
}
|
||||
|
||||
// Draw "Snapped" Cursor
|
||||
WorldToScreen(vCursor, sx, sy);
|
||||
DrawCircle(sx, sy, 3, olc::YELLOW);
|
||||
|
||||
// Draw Cursor Position
|
||||
DrawString(10, 10, "X=" + std::to_string(vCursor.x) + ", Y=" + std::to_string(vCursor.x), olc::YELLOW, 2);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
Polymorphism demo;
|
||||
if (demo.Construct(800, 480, 1, 1, false))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
372
Videos/OneLoneCoder_PGE_ProcGen_Universe.cpp
Normal file
@@ -0,0 +1,372 @@
|
||||
/*
|
||||
Procedural Generation: Programming The Universe
|
||||
"Here we go again! Year 4 begins now..." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2020 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Relevant Video: https://youtu.be/ZZY9YE7rZJw
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018, 2019, 2020
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
constexpr uint32_t g_starColours[8] =
|
||||
{
|
||||
0xFFFFFFFF, 0xFFD9FFFF, 0xFFA3FFFF, 0xFFFFC8C8,
|
||||
0xFFFFCB9D, 0xFF9F9FFF, 0xFF415EFF, 0xFF28199D
|
||||
};
|
||||
|
||||
|
||||
struct sPlanet
|
||||
{
|
||||
double distance = 0.0;
|
||||
double diameter = 0.0;
|
||||
double foliage = 0.0;
|
||||
double minerals = 0.0;
|
||||
double water = 0.0;
|
||||
double gases = 0.0;
|
||||
double temperature = 0.0;
|
||||
double population = 0.0;
|
||||
bool ring = false;
|
||||
std::vector<double> vMoons;
|
||||
};
|
||||
|
||||
class cStarSystem
|
||||
{
|
||||
public:
|
||||
cStarSystem(uint32_t x, uint32_t y, bool bGenerateFullSystem = false)
|
||||
{
|
||||
// Set seed based on location of star system
|
||||
nProcGen = (x & 0xFFFF) << 16 | (y & 0xFFFF);
|
||||
|
||||
// Not all locations contain a system
|
||||
starExists = (rndInt(0, 20) == 1);
|
||||
if (!starExists) return;
|
||||
|
||||
// Generate Star
|
||||
starDiameter = rndDouble(10.0, 40.0);
|
||||
starColour.n = g_starColours[rndInt(0, 8)];
|
||||
|
||||
// When viewing the galaxy map, we only care about the star
|
||||
// so abort early
|
||||
if (!bGenerateFullSystem) return;
|
||||
|
||||
// If we are viewing the system map, we need to generate the
|
||||
// full system
|
||||
|
||||
// Generate Planets
|
||||
double dDistanceFromStar = rndDouble(60.0, 200.0);
|
||||
int nPlanets = rndInt(0, 10);
|
||||
for (int i = 0; i < nPlanets; i++)
|
||||
{
|
||||
sPlanet p;
|
||||
p.distance = dDistanceFromStar;
|
||||
dDistanceFromStar += rndDouble(20.0, 200.0);
|
||||
p.diameter = rndDouble(4.0, 20.0);
|
||||
|
||||
// Could make temeprature a function of distance from star
|
||||
p.temperature = rndDouble(-200.0, 300.0);
|
||||
|
||||
// Composition of planet
|
||||
p.foliage = rndDouble(0.0, 1.0);
|
||||
p.minerals = rndDouble(0.0, 1.0);
|
||||
p.gases = rndDouble(0.0, 1.0);
|
||||
p.water = rndDouble(0.0, 1.0);
|
||||
|
||||
// Normalise to 100%
|
||||
double dSum = 1.0 / (p.foliage + p.minerals + p.gases + p.water);
|
||||
p.foliage *= dSum;
|
||||
p.minerals *= dSum;
|
||||
p.gases *= dSum;
|
||||
p.water *= dSum;
|
||||
|
||||
// Population could be a function of other habitat encouraging
|
||||
// properties, such as temperature and water
|
||||
p.population = std::max(rndInt(-5000000, 20000000), 0);
|
||||
|
||||
// 10% of planets have a ring
|
||||
p.ring = rndInt(0, 10) == 1;
|
||||
|
||||
// Satellites (Moons)
|
||||
int nMoons = std::max(rndInt(-5, 5), 0);
|
||||
for (int n = 0; n < nMoons; n++)
|
||||
{
|
||||
// A moon is just a diameter for now, but it could be
|
||||
// whatever you want!
|
||||
p.vMoons.push_back(rndDouble(1.0, 5.0));
|
||||
}
|
||||
|
||||
// Add planet to vector
|
||||
vPlanets.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
~cStarSystem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<sPlanet> vPlanets;
|
||||
|
||||
public:
|
||||
bool starExists = false;
|
||||
double starDiameter = 0.0f;
|
||||
olc::Pixel starColour = olc::WHITE;
|
||||
|
||||
private:
|
||||
uint32_t nProcGen = 0;
|
||||
|
||||
double rndDouble(double min, double max)
|
||||
{
|
||||
return ((double)rnd() / (double)(0x7FFFFFFF)) * (max - min) + min;
|
||||
}
|
||||
|
||||
int rndInt(int min, int max)
|
||||
{
|
||||
return (rnd() % (max - min)) + min;
|
||||
}
|
||||
|
||||
uint32_t rnd()
|
||||
{
|
||||
nProcGen += 0xe120fc15;
|
||||
uint64_t tmp;
|
||||
tmp = (uint64_t)nProcGen * 0x4a39b70d;
|
||||
uint32_t m1 = (tmp >> 32) ^ tmp;
|
||||
tmp = (uint64_t)m1 * 0x12fad5c9;
|
||||
uint32_t m2 = (tmp >> 32) ^ tmp;
|
||||
return m2;
|
||||
}
|
||||
};
|
||||
|
||||
class olcGalaxy : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
olcGalaxy()
|
||||
{
|
||||
sAppName = "olcGalaxy";
|
||||
}
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
olc::vf2d vGalaxyOffset = { 0,0 };
|
||||
bool bStarSelected = false;
|
||||
uint32_t nSelectedStarSeed1 = 0;
|
||||
uint32_t nSelectedStarSeed2 = 0;
|
||||
|
||||
|
||||
/*uint32_t nLehmer = 0;
|
||||
uint32_t Lehmer32()
|
||||
{
|
||||
nLehmer += 0xe120fc15;
|
||||
uint64_t tmp;
|
||||
tmp = (uint64_t)nLehmer * 0x4a39b70d;
|
||||
uint32_t m1 = (tmp >> 32) ^ tmp;
|
||||
tmp = (uint64_t)m1 * 0x12fad5c9;
|
||||
uint32_t m2 = (tmp >> 32) ^ tmp;
|
||||
return m2;
|
||||
}*/
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
if (fElapsedTime <= 0.0001f) return true;
|
||||
Clear(olc::BLACK);
|
||||
|
||||
//if (GetKey(olc::SPACE).bReleased)
|
||||
//{
|
||||
|
||||
// //srand(1000);
|
||||
|
||||
// std::random_device rd;
|
||||
// std::mt19937 mt(1000);
|
||||
// std::uniform_int_distribution<int> dist(0, 256);
|
||||
|
||||
// auto tp1 = std::chrono::system_clock::now();
|
||||
// // Ranomness Tests
|
||||
// for (int x = 0; x < ScreenWidth(); x++)
|
||||
// {
|
||||
// for (int y = 0; y < ScreenHeight(); y++)
|
||||
// {
|
||||
// bool bIsStar = false;
|
||||
// int nSeed = y << 16 | x;
|
||||
//
|
||||
// // Standard C++ rand()
|
||||
// //srand(nSeed);
|
||||
// //bIsStar = rand() % 256 < 32;
|
||||
|
||||
// // std::random
|
||||
// //mt.seed(nSeed);
|
||||
// //bIsStar = dist(mt) < 32;
|
||||
|
||||
// // Lehmer32
|
||||
// nLehmer = nSeed;
|
||||
// bIsStar = Lehmer32() % 256 < 32;
|
||||
|
||||
// Draw(x, y, bIsStar ? olc::WHITE : olc::BLACK);
|
||||
// }
|
||||
// }
|
||||
// auto tp2 = std::chrono::system_clock::now();
|
||||
// std::chrono::duration<float> elapsedTime = tp2 - tp1;
|
||||
// DrawString(3, 3, "Time: " + std::to_string(elapsedTime.count()), olc::RED, 2);
|
||||
//}
|
||||
|
||||
|
||||
//return true;
|
||||
|
||||
|
||||
if (GetKey(olc::W).bHeld) vGalaxyOffset.y -= 50.0f * fElapsedTime;
|
||||
if (GetKey(olc::S).bHeld) vGalaxyOffset.y += 50.0f * fElapsedTime;
|
||||
if (GetKey(olc::A).bHeld) vGalaxyOffset.x -= 50.0f * fElapsedTime;
|
||||
if (GetKey(olc::D).bHeld) vGalaxyOffset.x += 50.0f * fElapsedTime;
|
||||
|
||||
int nSectorsX = ScreenWidth() / 16;
|
||||
int nSectorsY = ScreenHeight() / 16;
|
||||
|
||||
olc::vi2d mouse = { GetMouseX() / 16, GetMouseY() / 16 };
|
||||
olc::vi2d galaxy_mouse = mouse + vGalaxyOffset;
|
||||
olc::vi2d screen_sector = { 0,0 };
|
||||
|
||||
for (screen_sector.x = 0; screen_sector.x < nSectorsX; screen_sector.x++)
|
||||
for (screen_sector.y = 0; screen_sector.y < nSectorsY; screen_sector.y++)
|
||||
{
|
||||
uint32_t seed1 = (uint32_t)vGalaxyOffset.x + (uint32_t)screen_sector.x;
|
||||
uint32_t seed2 = (uint32_t)vGalaxyOffset.y + (uint32_t)screen_sector.y;
|
||||
|
||||
cStarSystem star(seed1, seed2);
|
||||
if (star.starExists)
|
||||
{
|
||||
FillCircle(screen_sector.x * 16 + 8, screen_sector.y * 16 + 8,
|
||||
(int)star.starDiameter / 8, star.starColour);
|
||||
|
||||
// For convenience highlight hovered star
|
||||
if (mouse.x == screen_sector.x && mouse.y == screen_sector.y)
|
||||
{
|
||||
DrawCircle(screen_sector.x * 16 + 8, screen_sector.y * 16 + 8, 12, olc::YELLOW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Mouse Click
|
||||
if (GetMouse(0).bPressed)
|
||||
{
|
||||
uint32_t seed1 = (uint32_t)vGalaxyOffset.x + (uint32_t)mouse.x;
|
||||
uint32_t seed2 = (uint32_t)vGalaxyOffset.y + (uint32_t)mouse.y;
|
||||
|
||||
cStarSystem star(seed1, seed2);
|
||||
if (star.starExists)
|
||||
{
|
||||
bStarSelected = true;
|
||||
nSelectedStarSeed1 = seed1;
|
||||
nSelectedStarSeed2 = seed2;
|
||||
}
|
||||
else
|
||||
bStarSelected = false;
|
||||
}
|
||||
|
||||
// Draw Details of selected star system
|
||||
if (bStarSelected)
|
||||
{
|
||||
// Generate full star system
|
||||
cStarSystem star(nSelectedStarSeed1, nSelectedStarSeed2, true);
|
||||
|
||||
// Draw Window
|
||||
FillRect(8, 240, 496, 232, olc::DARK_BLUE);
|
||||
DrawRect(8, 240, 496, 232, olc::WHITE);
|
||||
|
||||
// Draw Star
|
||||
olc::vi2d vBody = { 14, 356 };
|
||||
|
||||
vBody.x += star.starDiameter * 1.375;
|
||||
FillCircle(vBody, (int)(star.starDiameter * 1.375), star.starColour);
|
||||
vBody.x += (star.starDiameter * 1.375) + 8;
|
||||
|
||||
|
||||
|
||||
// Draw Planets
|
||||
for (auto& planet : star.vPlanets)
|
||||
{
|
||||
if (vBody.x + planet.diameter >= 496) break;
|
||||
|
||||
vBody.x += planet.diameter;
|
||||
FillCircle(vBody, (int)(planet.diameter * 1.0), olc::RED);
|
||||
|
||||
olc::vi2d vMoon = vBody;
|
||||
vMoon.y += planet.diameter + 10;
|
||||
|
||||
// Draw Moons
|
||||
for (auto& moon : planet.vMoons)
|
||||
{
|
||||
vMoon.y += moon;
|
||||
FillCircle(vMoon, (int)(moon * 1.0), olc::GREY);
|
||||
vMoon.y += moon + 10;
|
||||
}
|
||||
|
||||
vBody.x += planet.diameter + 8;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
olcGalaxy demo;
|
||||
if (demo.Construct(512, 480, 2, 2, false, false))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
482
Videos/OneLoneCoder_PGE_RetroMenu.cpp
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
Easy To Use "Retro Pop-Up Menu System"
|
||||
"There's a storm comin'......" - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2020 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Relevant Video: https://youtu.be/jde1Jq5dF0E
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Community Blog: https://community.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018, 2019, 2020
|
||||
*/
|
||||
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
constexpr int32_t nPatch = 8;
|
||||
|
||||
|
||||
class menuobject
|
||||
{
|
||||
public:
|
||||
menuobject()
|
||||
{ sName = "root"; }
|
||||
|
||||
menuobject(const std::string& name)
|
||||
{ sName = name; }
|
||||
|
||||
menuobject& SetTable(int nColumns, int nRows)
|
||||
{ vCellTable = { nColumns, nRows }; return *this; }
|
||||
|
||||
menuobject& SetID(int32_t id)
|
||||
{ nID = id; return *this; }
|
||||
|
||||
int32_t GetID()
|
||||
{ return nID; }
|
||||
|
||||
std::string& GetName()
|
||||
{ return sName; }
|
||||
|
||||
menuobject& Enable(bool b)
|
||||
{ bEnabled = b; return *this; }
|
||||
|
||||
bool Enabled()
|
||||
{ return bEnabled; }
|
||||
|
||||
bool HasChildren()
|
||||
{ return !items.empty(); }
|
||||
|
||||
// For now, cells are simply one line strings
|
||||
olc::vi2d GetSize()
|
||||
{ return { int32_t(sName.size()), 1 }; }
|
||||
|
||||
olc::vi2d& GetCursorPosition()
|
||||
{ return vCursorPos; }
|
||||
|
||||
menuobject& operator[](const std::string& name)
|
||||
{
|
||||
if (itemPointer.count(name) == 0)
|
||||
{
|
||||
itemPointer[name] = items.size();
|
||||
items.push_back(menuobject(name));
|
||||
}
|
||||
|
||||
return items[itemPointer[name]];
|
||||
}
|
||||
|
||||
void Build()
|
||||
{
|
||||
// Recursively build all children, so they can determine their size, use
|
||||
// that size to indicate cell sizes if this object contains more than
|
||||
// one item
|
||||
for (auto& m : items)
|
||||
{
|
||||
if (m.HasChildren())
|
||||
{
|
||||
m.Build();
|
||||
}
|
||||
|
||||
// Longest child name determines cell width
|
||||
vCellSize.x = std::max(m.GetSize().x, vCellSize.x);
|
||||
vCellSize.y = std::max(m.GetSize().y, vCellSize.y);
|
||||
}
|
||||
|
||||
// Adjust size of this object (in patches) if it were rendered as a panel
|
||||
vSizeInPatches.x = vCellTable.x * vCellSize.x + (vCellTable.x - 1) * vCellPadding.x + 2;
|
||||
vSizeInPatches.y = vCellTable.y * vCellSize.y + (vCellTable.y - 1) * vCellPadding.y + 2;
|
||||
|
||||
// Calculate how many rows this item has to hold
|
||||
nTotalRows = (items.size() / vCellTable.x) + (((items.size() % vCellTable.x) > 0) ? 1 : 0);
|
||||
}
|
||||
|
||||
void DrawSelf(olc::PixelGameEngine& pge, olc::Sprite* sprGFX, olc::vi2d vScreenOffset)
|
||||
{
|
||||
// === Draw Panel
|
||||
|
||||
// Record current pixel mode user is using
|
||||
olc::Pixel::Mode currentPixelMode = pge.GetPixelMode();
|
||||
pge.SetPixelMode(olc::Pixel::MASK);
|
||||
|
||||
// Draw Panel & Border
|
||||
olc::vi2d vPatchPos = { 0,0 };
|
||||
for (vPatchPos.x = 0; vPatchPos.x < vSizeInPatches.x; vPatchPos.x++)
|
||||
{
|
||||
for (vPatchPos.y = 0; vPatchPos.y < vSizeInPatches.y; vPatchPos.y++)
|
||||
{
|
||||
// Determine position in screen space
|
||||
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
|
||||
// Calculate which patch is needed
|
||||
olc::vi2d vSourcePatch = { 0, 0 };
|
||||
if (vPatchPos.x > 0) vSourcePatch.x = 1;
|
||||
if (vPatchPos.x == vSizeInPatches.x - 1) vSourcePatch.x = 2;
|
||||
if (vPatchPos.y > 0) vSourcePatch.y = 1;
|
||||
if (vPatchPos.y == vSizeInPatches.y - 1) vSourcePatch.y = 2;
|
||||
|
||||
// Draw Actual Patch
|
||||
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
|
||||
}
|
||||
}
|
||||
|
||||
// === Draw Panel Contents
|
||||
olc::vi2d vCell = { 0,0 };
|
||||
vPatchPos = { 1,1 };
|
||||
|
||||
// Work out visible items
|
||||
int32_t nTopLeftItem = nTopVisibleRow * vCellTable.x;
|
||||
int32_t nBottomRightItem = vCellTable.y * vCellTable.x + nTopLeftItem;
|
||||
|
||||
// Clamp to size of child item vector
|
||||
nBottomRightItem = std::min(int32_t(items.size()), nBottomRightItem);
|
||||
int32_t nVisibleItems = nBottomRightItem - nTopLeftItem;
|
||||
|
||||
// Draw Scroll Markers (if required)
|
||||
if (nTopVisibleRow > 0)
|
||||
{
|
||||
vPatchPos = { vSizeInPatches.x - 2, 0 };
|
||||
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
olc::vi2d vSourcePatch = { 3, 0 };
|
||||
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
|
||||
}
|
||||
|
||||
if ((nTotalRows - nTopVisibleRow) > vCellTable.y)
|
||||
{
|
||||
vPatchPos = { vSizeInPatches.x - 2, vSizeInPatches.y - 1 };
|
||||
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
olc::vi2d vSourcePatch = { 3, 2 };
|
||||
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
|
||||
}
|
||||
|
||||
// Draw Visible Items
|
||||
for (int32_t i = 0; i < nVisibleItems; i++)
|
||||
{
|
||||
// Cell location
|
||||
vCell.x = i % vCellTable.x;
|
||||
vCell.y = i / vCellTable.x;
|
||||
|
||||
// Patch location (including border offset and padding)
|
||||
vPatchPos.x = vCell.x * (vCellSize.x + vCellPadding.x) + 1;
|
||||
vPatchPos.y = vCell.y * (vCellSize.y + vCellPadding.y) + 1;
|
||||
|
||||
// Actual screen location in pixels
|
||||
olc::vi2d vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
|
||||
// Display Item Header
|
||||
pge.DrawString(vScreenLocation, items[nTopLeftItem + i].sName, items[nTopLeftItem + i].bEnabled ? olc::WHITE : olc::DARK_GREY);
|
||||
|
||||
if (items[nTopLeftItem + i].HasChildren())
|
||||
{
|
||||
// Display Indicator that panel has a sub panel
|
||||
vPatchPos.x = vCell.x * (vCellSize.x + vCellPadding.x) + 1 + vCellSize.x;
|
||||
vPatchPos.y = vCell.y * (vCellSize.y + vCellPadding.y) + 1;
|
||||
olc::vi2d vSourcePatch = { 3, 1 };
|
||||
vScreenLocation = vPatchPos * nPatch + vScreenOffset;
|
||||
pge.DrawPartialSprite(vScreenLocation, sprGFX, vSourcePatch * nPatch, vPatchSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate cursor position in screen space in case system draws it
|
||||
vCursorPos.x = (vCellCursor.x * (vCellSize.x + vCellPadding.x)) * nPatch + vScreenOffset.x - nPatch;
|
||||
vCursorPos.y = ((vCellCursor.y - nTopVisibleRow) * (vCellSize.y + vCellPadding.y)) * nPatch + vScreenOffset.y + nPatch;
|
||||
}
|
||||
|
||||
void ClampCursor()
|
||||
{
|
||||
// Find item in children
|
||||
nCursorItem = vCellCursor.y * vCellTable.x + vCellCursor.x;
|
||||
|
||||
// Clamp Cursor
|
||||
if (nCursorItem >= int32_t(items.size()))
|
||||
{
|
||||
vCellCursor.y = (items.size() / vCellTable.x);
|
||||
vCellCursor.x = (items.size() % vCellTable.x) - 1;
|
||||
nCursorItem = items.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void OnUp()
|
||||
{
|
||||
vCellCursor.y--;
|
||||
if (vCellCursor.y < 0) vCellCursor.y = 0;
|
||||
|
||||
if (vCellCursor.y < nTopVisibleRow)
|
||||
{
|
||||
nTopVisibleRow--;
|
||||
if (nTopVisibleRow < 0) nTopVisibleRow = 0;
|
||||
}
|
||||
|
||||
ClampCursor();
|
||||
}
|
||||
|
||||
void OnDown()
|
||||
{
|
||||
vCellCursor.y++;
|
||||
if (vCellCursor.y == nTotalRows) vCellCursor.y = nTotalRows - 1;
|
||||
|
||||
if (vCellCursor.y > (nTopVisibleRow + vCellTable.y - 1))
|
||||
{
|
||||
nTopVisibleRow++;
|
||||
if (nTopVisibleRow > (nTotalRows - vCellTable.y))
|
||||
nTopVisibleRow = nTotalRows - vCellTable.y;
|
||||
}
|
||||
|
||||
ClampCursor();
|
||||
}
|
||||
|
||||
void OnLeft()
|
||||
{
|
||||
vCellCursor.x--;
|
||||
if (vCellCursor.x < 0) vCellCursor.x = 0;
|
||||
ClampCursor();
|
||||
}
|
||||
|
||||
void OnRight()
|
||||
{
|
||||
vCellCursor.x++;
|
||||
if (vCellCursor.x == vCellTable.x) vCellCursor.x = vCellTable.x - 1;
|
||||
ClampCursor();
|
||||
}
|
||||
|
||||
menuobject* OnConfirm()
|
||||
{
|
||||
// Check if selected item has children
|
||||
if (items[nCursorItem].HasChildren())
|
||||
{
|
||||
return &items[nCursorItem];
|
||||
}
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
menuobject* GetSelectedItem()
|
||||
{
|
||||
return &items[nCursorItem];
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
int32_t nID = -1;
|
||||
olc::vi2d vCellTable = { 1, 0 };
|
||||
std::unordered_map<std::string, size_t> itemPointer;
|
||||
std::vector<menuobject> items;
|
||||
olc::vi2d vSizeInPatches = { 0, 0 };
|
||||
olc::vi2d vCellSize = { 0, 0 };
|
||||
olc::vi2d vCellPadding = { 2, 0 };
|
||||
olc::vi2d vCellCursor = { 0, 0 };
|
||||
int32_t nCursorItem = 0;
|
||||
int32_t nTopVisibleRow = 0;
|
||||
int32_t nTotalRows = 0;
|
||||
const olc::vi2d vPatchSize = { nPatch, nPatch };
|
||||
std::string sName;
|
||||
olc::vi2d vCursorPos = { 0, 0 };
|
||||
bool bEnabled = true;
|
||||
};
|
||||
|
||||
|
||||
class menumanager
|
||||
{
|
||||
public:
|
||||
menumanager() { }
|
||||
|
||||
void Open(menuobject* mo) { Close(); panels.push_back(mo); }
|
||||
void Close() { panels.clear(); }
|
||||
|
||||
void OnUp() { if (!panels.empty()) panels.back()->OnUp(); }
|
||||
void OnDown() { if (!panels.empty()) panels.back()->OnDown(); }
|
||||
void OnLeft() { if (!panels.empty()) panels.back()->OnLeft(); }
|
||||
void OnRight() { if (!panels.empty()) panels.back()->OnRight(); }
|
||||
void OnBack() { if (!panels.empty()) panels.pop_back(); }
|
||||
|
||||
menuobject* OnConfirm()
|
||||
{
|
||||
if (panels.empty()) return nullptr;
|
||||
|
||||
menuobject* next = panels.back()->OnConfirm();
|
||||
if (next == panels.back())
|
||||
{
|
||||
if(panels.back()->GetSelectedItem()->Enabled())
|
||||
return panels.back()->GetSelectedItem();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(next->Enabled())
|
||||
panels.push_back(next);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Draw(olc::PixelGameEngine& pge, olc::Sprite* sprGFX, olc::vi2d vScreenOffset)
|
||||
{
|
||||
if (panels.empty()) return;
|
||||
|
||||
// Draw Visible Menu System
|
||||
for (auto& p : panels)
|
||||
{
|
||||
p->DrawSelf(pge, sprGFX, vScreenOffset);
|
||||
vScreenOffset += {10, 10};
|
||||
}
|
||||
|
||||
// Draw Cursor
|
||||
olc::Pixel::Mode currentPixelMode = pge.GetPixelMode();
|
||||
pge.SetPixelMode(olc::Pixel::ALPHA);
|
||||
pge.DrawPartialSprite(panels.back()->GetCursorPosition(), sprGFX, olc::vi2d(4, 0) * nPatch, { nPatch * 2, nPatch * 2 });
|
||||
pge.SetPixelMode(currentPixelMode);
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<menuobject*> panels;
|
||||
};
|
||||
|
||||
// Override base class with your custom functionality
|
||||
class olcRetroPopUpMenu : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
olcRetroPopUpMenu()
|
||||
{
|
||||
sAppName = "Retro Pop-Up Menu";
|
||||
}
|
||||
|
||||
olc::Sprite* sprGFX = nullptr;
|
||||
|
||||
menuobject mo;
|
||||
menumanager mm;
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
sprGFX = new olc::Sprite("./RetroMenu.png");
|
||||
|
||||
mo["main"].SetTable(1, 4);
|
||||
mo["main"]["Attack"].SetID(101);
|
||||
|
||||
mo["main"]["Magic"].SetTable(1, 2);
|
||||
|
||||
mo["main"]["Magic"]["White"].SetTable(3, 6);
|
||||
auto& menuWhiteMagic = mo["main"]["Magic"]["White"];
|
||||
menuWhiteMagic["Cure"].SetID(401);
|
||||
menuWhiteMagic["Cura"].SetID(402);
|
||||
menuWhiteMagic["Curaga"].SetID(403);
|
||||
menuWhiteMagic["Esuna"].SetID(404);
|
||||
|
||||
mo["main"]["Magic"]["Black"].SetTable(3, 4);
|
||||
auto& menuBlackMagic = mo["main"]["Magic"]["Black"];
|
||||
menuBlackMagic["Fire"].SetID(201);
|
||||
menuBlackMagic["Fira"].SetID(202);
|
||||
menuBlackMagic["Firaga"].SetID(203);
|
||||
menuBlackMagic["Blizzard"].SetID(204);
|
||||
menuBlackMagic["Blizzara"].SetID(205).Enable(false);
|
||||
menuBlackMagic["Blizzaga"].SetID(206).Enable(false);
|
||||
menuBlackMagic["Thunder"].SetID(207);
|
||||
menuBlackMagic["Thundara"].SetID(208);
|
||||
menuBlackMagic["Thundaga"].SetID(209);
|
||||
menuBlackMagic["Quake"].SetID(210);
|
||||
menuBlackMagic["Quake2"].SetID(211);
|
||||
menuBlackMagic["Quake3"].SetID(212);
|
||||
menuBlackMagic["Bio"].SetID(213);
|
||||
menuBlackMagic["Bio1"].SetID(214);
|
||||
menuBlackMagic["Bio2"].SetID(215);
|
||||
menuBlackMagic["Demi"].SetID(216);
|
||||
menuBlackMagic["Demi1"].SetID(217);
|
||||
menuBlackMagic["Demi2"].SetID(218);
|
||||
|
||||
mo["main"]["Defend"].SetID(102);
|
||||
|
||||
mo["main"]["Items"].SetTable(2, 4).Enable(false);
|
||||
mo["main"]["Items"]["Potion"].SetID(301);
|
||||
mo["main"]["Items"]["Ether"].SetID(302);
|
||||
mo["main"]["Items"]["Elixir"].SetID(303);
|
||||
|
||||
mo["main"]["Escape"].SetID(103);
|
||||
|
||||
mo.Build();
|
||||
|
||||
mm.Open(&mo["main"]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
menuobject* command = nullptr;
|
||||
|
||||
if (GetKey(olc::Key::M).bPressed) mm.Open(&mo["main"]);
|
||||
|
||||
if (GetKey(olc::Key::UP).bPressed) mm.OnUp();
|
||||
if (GetKey(olc::Key::DOWN).bPressed) mm.OnDown();
|
||||
if (GetKey(olc::Key::LEFT).bPressed) mm.OnLeft();
|
||||
if (GetKey(olc::Key::RIGHT).bPressed) mm.OnRight();
|
||||
if (GetKey(olc::Key::SPACE).bPressed) command = mm.OnConfirm();
|
||||
if (GetKey(olc::Key::Z).bPressed) mm.OnBack();
|
||||
|
||||
if (command != nullptr)
|
||||
{
|
||||
sLastAction = "Selected: " + command->GetName() + " ID: " + std::to_string(command->GetID());
|
||||
mm.Close();
|
||||
}
|
||||
|
||||
Clear(olc::BLACK);
|
||||
mm.Draw(*this, sprGFX, { 30,30 });
|
||||
DrawString(10, 200, sLastAction);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string sLastAction;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
olcRetroPopUpMenu demo;
|
||||
if (demo.Construct(384, 240, 4, 4))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
272
Videos/OneLoneCoder_PGE_RobotArm1.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
Programming a robotic arm
|
||||
"I told you, put down the screwdriver..." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Instructions:
|
||||
~~~~~~~~~~~~~
|
||||
Without a robot arm and an mbed there is not much you can do!
|
||||
Also requires a 3rd Party PGEX UI by ZleapingBear:
|
||||
https://youtu.be/bfiSjC__MCI
|
||||
|
||||
|
||||
Relevant Video: https://youtu.be/ekdQ-aAB36Y
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
#include "olcPGEX_UI.h"
|
||||
|
||||
class RobotArm1 : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
RobotArm1()
|
||||
{
|
||||
sAppName = "Robot Arm 1";
|
||||
}
|
||||
|
||||
olc::UI_CONTAINER gui;
|
||||
float fJointAngle[6];
|
||||
float fAccumulatedTime = 0.0f;
|
||||
HANDLE hCom = nullptr;
|
||||
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
gui.addSlider(10, 20, 180);
|
||||
gui.addSlider(10, 60, 180);
|
||||
gui.addSlider(10, 100, 180);
|
||||
gui.addSlider(10, 140, 180);
|
||||
gui.addSlider(10, 180, 180);
|
||||
gui.addSlider(10, 220, 180);
|
||||
gui.setValue(0, 50);
|
||||
gui.setValue(1, 50);
|
||||
gui.setValue(2, 50);
|
||||
gui.setValue(3, 50);
|
||||
gui.setValue(4, 50);
|
||||
gui.setValue(5, 50);
|
||||
|
||||
// Open COM Port
|
||||
hCom = CreateFile("COM3", GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hCom == nullptr) return false;
|
||||
|
||||
// Configure Protocol: 9600bps, 8N1
|
||||
DCB dcb = { 0 };
|
||||
GetCommState(hCom, &dcb);
|
||||
dcb.BaudRate = CBR_9600;
|
||||
dcb.ByteSize = 8;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
dcb.Parity = NOPARITY;
|
||||
SetCommState(hCom, &dcb);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserDestroy() override
|
||||
{
|
||||
if (hCom != nullptr) CloseHandle(hCom);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
gui.Update(fElapsedTime);
|
||||
Clear(olc::GREEN);
|
||||
gui.drawUIObjects();
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
fJointAngle[i] = (gui.getSliderFloat(i) / 100.0f) * 180.0f - 90.0f;
|
||||
|
||||
unsigned char command[12];
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
command[i * 2 + 0] = i;
|
||||
command[i * 2 + 1] = (int)(128 + fJointAngle[i]);
|
||||
}
|
||||
|
||||
fAccumulatedTime += fElapsedTime;
|
||||
if (fAccumulatedTime > 0.05f)
|
||||
{
|
||||
fAccumulatedTime -= 0.05f;
|
||||
DWORD bw = 0;
|
||||
WriteFile(hCom, command, 12, &bw, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
RobotArm1 demo;
|
||||
if (demo.Construct(400, 400, 2, 2))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Below here is the source code compiled on MBED LPC1768, using the BufferedSerial Library
|
||||
|
||||
/*
|
||||
|
||||
#include "mbed.h"
|
||||
#include "BufferedSerial.h"
|
||||
|
||||
PwmOut pin26(p26);
|
||||
PwmOut pin25(p25);
|
||||
PwmOut pin24(p24);
|
||||
PwmOut pin23(p23);
|
||||
PwmOut pin22(p22);
|
||||
PwmOut pin21(p21);
|
||||
|
||||
BufferedSerial uart(p9, p10);
|
||||
|
||||
|
||||
class Joint
|
||||
{
|
||||
private:
|
||||
static const float fDutyMin = 0.03f; // -90
|
||||
static const float fDutyMax = 0.11f; // +90
|
||||
static const float fDutyRange = fDutyMax - fDutyMin;
|
||||
|
||||
float fTarget;
|
||||
float fPosition;
|
||||
float fJointMax;
|
||||
float fJointMin;
|
||||
|
||||
public:
|
||||
Joint(float fMin = -90.0f, float fMax = 90.0f, float fDefaultPos = 0.0f)
|
||||
{
|
||||
fJointMin = fMin;
|
||||
fJointMax = fMax;
|
||||
fPosition = 0.0f;
|
||||
SetTarget(fDefaultPos);
|
||||
}
|
||||
|
||||
void SetTarget(float fAngle)
|
||||
{
|
||||
fTarget = fAngle;
|
||||
if(fTarget < fJointMin) fTarget = fJointMin;
|
||||
if(fTarget > fJointMax) fTarget = fJointMax;
|
||||
}
|
||||
|
||||
void UpdatePosition()
|
||||
{
|
||||
fPosition = fTarget;
|
||||
}
|
||||
|
||||
float GetTarget()
|
||||
{
|
||||
return fTarget;
|
||||
}
|
||||
|
||||
float GetDutyCycle()
|
||||
{
|
||||
float fDutyCycle = fPosition / (fJointMax - fJointMin);
|
||||
fDutyCycle = (fDutyCycle * fDutyRange) + fDutyMin + (fDutyRange * 0.5f);
|
||||
return fDutyCycle;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// Servos (MG996R) operate on 20ms period, so set
|
||||
// PWM period for each pin
|
||||
pin26.period(0.02f);
|
||||
pin25.period(0.02f);
|
||||
pin24.period(0.02f);
|
||||
pin23.period(0.02f);
|
||||
pin22.period(0.02f);
|
||||
pin21.period(0.02f);
|
||||
|
||||
Joint joint[6];
|
||||
|
||||
joint[0].SetTarget(0.0f);
|
||||
joint[1].SetTarget(0.0f);
|
||||
joint[2].SetTarget(0.0f);
|
||||
joint[3].SetTarget(-25.0f);
|
||||
joint[4].SetTarget(-20.0f);
|
||||
joint[5].SetTarget(-15.0f);
|
||||
|
||||
int nTargetJoint = 0;
|
||||
|
||||
while(1)
|
||||
{
|
||||
// Read from UART
|
||||
if(uart.readable())
|
||||
{
|
||||
unsigned char c = (unsigned char)uart.getc();
|
||||
|
||||
if(c < 10)
|
||||
nTargetJoint = c;
|
||||
else
|
||||
joint[nTargetJoint].SetTarget((float)c - 128);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Write Duty Cycles
|
||||
// Update each joints position
|
||||
for(int i=0; i<6; i++)
|
||||
joint[i].UpdatePosition();
|
||||
|
||||
// Set PWM values for each joint
|
||||
pin26.write(joint[0].GetDutyCycle());
|
||||
pin25.write(joint[1].GetDutyCycle());
|
||||
pin24.write(joint[2].GetDutyCycle());
|
||||
pin23.write(joint[3].GetDutyCycle());
|
||||
pin22.write(joint[4].GetDutyCycle());
|
||||
pin21.write(joint[5].GetDutyCycle());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
484
Videos/OneLoneCoder_PGE_ShootEmUp.cpp
Normal file
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
Live 100K Code Party! Code-It-Yourself: SHMUP
|
||||
"It's done... 2019 is done..." - javidx9
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018-2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Relevant Video: https://youtu.be/CqDfZEX0Yhc
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
https://www.youtube.com/javidx9extra
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Community Blog: http://community.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
// IMPORTANT!! Requires sprites not provided in repo!
|
||||
// Sprites are 48x48 pixels.
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
|
||||
class Example : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
Example()
|
||||
{
|
||||
sAppName = "100K Live Special - SHMUP";
|
||||
}
|
||||
|
||||
olc::Sprite* sprPlayer = nullptr;
|
||||
olc::Sprite* sprEnemy[3];
|
||||
|
||||
olc::vf2d vPlayerPos;
|
||||
float fPlayerSpeed = 100.0f;
|
||||
float fScrollSpeed = 60.0f;
|
||||
float fPlayerShipRad = 24 * 24;
|
||||
float fPlayerHealth = 1000.0f;
|
||||
float fPlayerGunTemp = 0.0f;
|
||||
float fPlayerGunReload = 0.2f;
|
||||
float fPlayerGunReloadTime = 0.0f;
|
||||
|
||||
double dWorldPos = 0.0f;
|
||||
|
||||
std::array<olc::vf2d, 1000> aryStars;
|
||||
|
||||
struct sBullet
|
||||
{
|
||||
olc::vf2d pos;
|
||||
olc::vf2d vel;
|
||||
bool remove = false;
|
||||
};
|
||||
|
||||
struct sEnemy;
|
||||
|
||||
struct sEnemyDefinition
|
||||
{
|
||||
double dTriggerTime;
|
||||
uint32_t nSpriteID = 0;
|
||||
float fHealth = 0.0f;
|
||||
std::function<void(sEnemy&, float, float)> funcMove;
|
||||
std::function<void(sEnemy&, float, float, std::list<sBullet>& bullets)> funcFire;
|
||||
float offset = 0.0f;
|
||||
};
|
||||
|
||||
struct sEnemy
|
||||
{
|
||||
olc::vf2d pos;
|
||||
sEnemyDefinition def;
|
||||
|
||||
std::array<float, 4> dataMove{ 0 };
|
||||
std::array<float, 4> dataFire{ 0 };
|
||||
|
||||
void Update(float fElapsedTime, float fScrollSpeed, std::list<sBullet>& bullets)
|
||||
{
|
||||
def.funcMove(*this, fElapsedTime, fScrollSpeed);
|
||||
def.funcFire(*this, fElapsedTime, fScrollSpeed, bullets);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
olc::vf2d GetMiddle(const olc::Sprite *s)
|
||||
{
|
||||
return { (float)s->width / 2.0f, (float)s->height / 2.0f };
|
||||
}
|
||||
|
||||
|
||||
std::list<sEnemyDefinition> listSpawns;
|
||||
std::list<sEnemy> listEnemies;
|
||||
std::list<sBullet> listEnemyBullets;
|
||||
std::list<sBullet> listPlayerBullets;
|
||||
std::list<olc::vf2d> listStars;
|
||||
std::list<sBullet> listFragments;
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
// Load resources
|
||||
sprPlayer = new olc::Sprite("gfx//100k_player.png");
|
||||
sprEnemy[0] = new olc::Sprite("gfx//100k_enemy1.png");
|
||||
sprEnemy[1] = new olc::Sprite("gfx//100k_enemy2.png");
|
||||
sprEnemy[2] = new olc::Sprite("gfx//100k_enemy3.png");
|
||||
|
||||
// Generate Star Map
|
||||
for (auto& s : aryStars) s = { (float)(rand() % ScreenWidth()), (float)(rand() % ScreenHeight()) };
|
||||
|
||||
// MOVEMENT PATTERN FUNCTIONS
|
||||
auto Move_None = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed)
|
||||
{
|
||||
e.pos.y += fScrollSpeed * fElapsedTime;
|
||||
};
|
||||
|
||||
auto Move_StraightFast = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed)
|
||||
{
|
||||
e.pos.y += 3.0f * fScrollSpeed * fElapsedTime;
|
||||
};
|
||||
|
||||
auto Move_StraightSlow = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed)
|
||||
{
|
||||
e.pos.y += 0.5f * fScrollSpeed * fElapsedTime;
|
||||
};
|
||||
|
||||
auto Move_SinusoidNarrow = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed)
|
||||
{
|
||||
e.dataMove[0] += fElapsedTime;
|
||||
e.pos.y += 0.5f * fScrollSpeed * fElapsedTime;
|
||||
e.pos.x += 50.0f * cosf(e.dataMove[0]) * fElapsedTime;
|
||||
};
|
||||
|
||||
auto Move_SinusoidWide = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed)
|
||||
{
|
||||
e.dataMove[0] += fElapsedTime;
|
||||
e.pos.y += 0.5f * fScrollSpeed * fElapsedTime;
|
||||
e.pos.x += 150.0f * cosf(e.dataMove[0]) * fElapsedTime;
|
||||
};
|
||||
|
||||
// FIRING PATTERN FUNCTIONS
|
||||
auto Fire_None = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list<sBullet>& bullets)
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
auto Fire_StraightDelay2 = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list<sBullet>& bullets)
|
||||
{
|
||||
constexpr float fDelay = 0.2f;
|
||||
e.dataFire[0] += fElapsedTime;
|
||||
if (e.dataFire[0] >= fDelay)
|
||||
{
|
||||
e.dataFire[0] -= fDelay;
|
||||
sBullet b;
|
||||
b.pos = e.pos + olc::vf2d((float)sprEnemy[e.def.nSpriteID]->width / 2.0f, (float)sprEnemy[e.def.nSpriteID]->height);
|
||||
b.vel = { 0.0f, 180.0f };
|
||||
bullets.push_back(b);
|
||||
}
|
||||
};
|
||||
|
||||
auto Fire_CirclePulse2 = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list<sBullet>& bullets)
|
||||
{
|
||||
constexpr float fDelay = 0.2f;
|
||||
constexpr int nBullets = 10;
|
||||
constexpr float fTheta = 2.0f * 3.14159f / (float)nBullets;
|
||||
e.dataFire[0] += fElapsedTime;
|
||||
if (e.dataFire[0] >= fDelay)
|
||||
{
|
||||
e.dataFire[0] -= fDelay;
|
||||
for (int i = 0; i < nBullets; i++)
|
||||
{
|
||||
sBullet b;
|
||||
b.pos = e.pos + GetMiddle(sprEnemy[e.def.nSpriteID]);
|
||||
b.vel = { 180.0f * cosf(fTheta * i), 180.0f * sinf(fTheta * i)};
|
||||
bullets.push_back(b);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto Fire_DeathSpiral = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list<sBullet>& bullets)
|
||||
{
|
||||
constexpr float fDelay = 0.01f;
|
||||
e.dataFire[0] += fElapsedTime;
|
||||
if (e.dataFire[0] >= fDelay)
|
||||
{
|
||||
e.dataFire[1] += 0.1f;
|
||||
e.dataFire[0] -= fDelay;
|
||||
sBullet b;
|
||||
b.pos = e.pos + GetMiddle(sprEnemy[e.def.nSpriteID]);
|
||||
b.vel = { 180.0f * cosf(e.dataFire[1]), 180.0f * sinf(e.dataFire[1]) };
|
||||
bullets.push_back(b);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
auto Fire_DeathSpiralCircle = [&](sEnemy& e, float fElapsedTime, float fScrollSpeed, std::list<sBullet>& bullets)
|
||||
{
|
||||
constexpr float fDelay = 0.2f;
|
||||
constexpr int nBullets = 100;
|
||||
constexpr float fTheta = 2.0f * 3.14159f / (float)nBullets;
|
||||
e.dataFire[0] += fElapsedTime;
|
||||
if (e.dataFire[0] >= fDelay)
|
||||
{
|
||||
e.dataFire[0] -= fDelay;
|
||||
e.dataFire[1] += 0.1f;
|
||||
for (int i = 0; i < nBullets; i++)
|
||||
{
|
||||
sBullet b;
|
||||
b.pos = e.pos + GetMiddle(sprEnemy[e.def.nSpriteID]);
|
||||
b.vel = { 180.0f * cosf(fTheta * i + e.dataFire[1]), 180.0f * sinf(fTheta * i + e.dataFire[1]) };
|
||||
bullets.push_back(b);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Construct level
|
||||
listSpawns =
|
||||
{
|
||||
{100.0, 0, 3.0f, Move_None, Fire_CirclePulse2, 0.25f},
|
||||
{100.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.75f},
|
||||
{120.0, 1, 3.0f, Move_SinusoidNarrow, Fire_CirclePulse2, 0.50f},
|
||||
|
||||
{200.0, 2, 3.0f, Move_SinusoidWide, Fire_CirclePulse2, 0.30f},
|
||||
{200.0, 2, 3.0f, Move_SinusoidWide, Fire_CirclePulse2, 0.70f},
|
||||
|
||||
{500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.2f},
|
||||
{500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.4f},
|
||||
{500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.6f},
|
||||
{500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.8f},
|
||||
|
||||
{550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.1f},
|
||||
{550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.3f},
|
||||
{550.0, 0, 3.0f, Move_StraightSlow, Fire_DeathSpiralCircle, 0.5f},
|
||||
{550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.7f},
|
||||
{550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.9f},
|
||||
|
||||
{600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.2f},
|
||||
{600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.4f},
|
||||
{600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.6f},
|
||||
{600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.8f},
|
||||
|
||||
{1100.0, 0, 3.0f, Move_None, Fire_CirclePulse2, 0.25f},
|
||||
{1100.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.75f},
|
||||
{1120.0, 1, 3.0f, Move_SinusoidNarrow, Fire_CirclePulse2, 0.50f},
|
||||
|
||||
{1200.0, 2, 3.0f, Move_SinusoidWide, Fire_CirclePulse2, 0.30f},
|
||||
{1200.0, 2, 3.0f, Move_SinusoidWide, Fire_CirclePulse2, 0.70f},
|
||||
|
||||
{1500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.2f},
|
||||
{1500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.4f},
|
||||
{1500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.6f},
|
||||
{1500.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.8f},
|
||||
|
||||
{1550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.1f},
|
||||
{1550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.3f},
|
||||
{1550.0, 0, 3.0f, Move_StraightSlow, Fire_DeathSpiralCircle, 0.5f},
|
||||
{1550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.7f},
|
||||
{1550.0, 0, 3.0f, Move_StraightFast, Fire_DeathSpiral, 0.9f},
|
||||
|
||||
{1600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.2f},
|
||||
{1600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.4f},
|
||||
{1600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.6f},
|
||||
{1600.0, 0, 3.0f, Move_StraightFast, Fire_StraightDelay2, 0.8f},
|
||||
};
|
||||
|
||||
|
||||
vPlayerPos = { (float)ScreenWidth() / 2, (float)ScreenHeight() / 2 };
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
// AutoScroll World
|
||||
dWorldPos += fScrollSpeed * fElapsedTime;
|
||||
|
||||
// Scroll Player Object
|
||||
vPlayerPos.y += fScrollSpeed * fElapsedTime;
|
||||
|
||||
// Handle Player Input
|
||||
if (GetKey(olc::W).bHeld) vPlayerPos.y -= (fPlayerSpeed + fScrollSpeed) * fElapsedTime;
|
||||
if (GetKey(olc::S).bHeld) vPlayerPos.y += (fPlayerSpeed - fScrollSpeed) * fElapsedTime;
|
||||
if (GetKey(olc::A).bHeld) vPlayerPos.x -= fPlayerSpeed * fElapsedTime * 2.0f;
|
||||
if (GetKey(olc::D).bHeld) vPlayerPos.x += fPlayerSpeed * fElapsedTime * 2.0f;
|
||||
|
||||
// Clamp Player to screen
|
||||
if (vPlayerPos.x <= 0) vPlayerPos.x = 0;
|
||||
if (vPlayerPos.x + (float)sprPlayer->width >= ScreenWidth()) vPlayerPos.x = (float)ScreenWidth() - sprPlayer->width;
|
||||
if (vPlayerPos.y <= 0) vPlayerPos.y = 0;
|
||||
if (vPlayerPos.y + (float)sprPlayer->height >= ScreenHeight()) vPlayerPos.y = (float)ScreenHeight() - sprPlayer->height;
|
||||
|
||||
// Player Weapon Fire
|
||||
bool bCanFire = false;
|
||||
fPlayerGunReloadTime -= fElapsedTime;
|
||||
if (fPlayerGunReloadTime <= 0.0f)
|
||||
{
|
||||
bCanFire = true;
|
||||
}
|
||||
|
||||
fPlayerGunTemp -= fElapsedTime * 10.0f;
|
||||
if (fPlayerGunTemp < 0) fPlayerGunTemp = 0;
|
||||
if (GetMouse(0).bHeld)
|
||||
{
|
||||
if (bCanFire && fPlayerGunTemp < 80.0f)
|
||||
{
|
||||
fPlayerGunReloadTime = fPlayerGunReload;
|
||||
fPlayerGunTemp += 5.0f;
|
||||
if (fPlayerGunTemp > 100.0f) fPlayerGunTemp = 100.0f;
|
||||
listPlayerBullets.push_back({vPlayerPos + olc::vf2d((float)sprPlayer->width / 2.0f, 0.0f), {0.0f, -200.0f} });
|
||||
}
|
||||
}
|
||||
|
||||
// Update Player Bullets
|
||||
for (auto& b : listPlayerBullets)
|
||||
{
|
||||
// Position Bullet
|
||||
b.pos += (b.vel + olc::vf2d(0.0f, fScrollSpeed)) * fElapsedTime;
|
||||
|
||||
// Check Enemies Vs Player Bullets
|
||||
for (auto& e : listEnemies)
|
||||
{
|
||||
if ((b.pos - (e.pos + olc::vf2d(24.0f, 24.0f))).mag2() < fPlayerShipRad)
|
||||
{
|
||||
// Enemy has been hit
|
||||
b.remove = true;
|
||||
e.def.fHealth -= 1.0f;
|
||||
|
||||
// Trigger explosion
|
||||
if (e.def.fHealth <= 0)
|
||||
{
|
||||
for (int i = 0; i < 500; i++)
|
||||
{
|
||||
float angle = ((float)rand() / (float)RAND_MAX) * 2.0f * 3.14159f;
|
||||
float speed = ((float)rand() / (float)RAND_MAX) * 200.0f + 50.0f;
|
||||
listFragments.push_back({
|
||||
e.pos + GetMiddle(sprEnemy[e.def.nSpriteID]),
|
||||
{ cosf(angle)*speed, sinf(angle)*speed }});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Perform spawn check
|
||||
while(!listSpawns.empty() && dWorldPos >= listSpawns.front().dTriggerTime)
|
||||
{
|
||||
sEnemy e;
|
||||
e.def = listSpawns.front();
|
||||
e.pos =
|
||||
{
|
||||
listSpawns.front().offset * (float)(ScreenWidth() - sprEnemy[e.def.nSpriteID]->width),
|
||||
0.0f - sprEnemy[e.def.nSpriteID]->height
|
||||
};
|
||||
listSpawns.pop_front();
|
||||
listEnemies.push_back(e);
|
||||
}
|
||||
|
||||
// Update Enemies
|
||||
for (auto& e : listEnemies) e.Update(fElapsedTime, fScrollSpeed, listEnemyBullets);
|
||||
|
||||
// Update Enemy Bullets
|
||||
for (auto& b : listEnemyBullets)
|
||||
{
|
||||
// Position Bullet
|
||||
b.pos += (b.vel + olc::vf2d(0.0f, fScrollSpeed)) * fElapsedTime;
|
||||
|
||||
// Check Player Vs Enemy Bullets
|
||||
if ((b.pos - (vPlayerPos + olc::vf2d(24.0f, 24.0f))).mag2() < fPlayerShipRad)
|
||||
{
|
||||
b.remove = true;
|
||||
fPlayerHealth -= 10.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Update Fragments
|
||||
for(auto& f : listFragments) f.pos += (f.vel + olc::vf2d(0.0f, fScrollSpeed)) * fElapsedTime;
|
||||
|
||||
// Remove Offscreen Enemies
|
||||
listEnemies.remove_if([&](const sEnemy& e) {return (e.pos.y >= (float)ScreenHeight()) || e.def.fHealth <= 0.0f; });
|
||||
|
||||
// Remove finished enemy bullets
|
||||
listEnemyBullets.remove_if([&](const sBullet& b) {return b.pos.x<0 || b.pos.x>ScreenWidth() || b.pos.y <0 || b.pos.y>ScreenHeight() || b.remove; });
|
||||
|
||||
// Remove finished player bullets
|
||||
listPlayerBullets.remove_if([&](const sBullet& b) {return b.pos.x<0 || b.pos.x>ScreenWidth() || b.pos.y <0 || b.pos.y>ScreenHeight() || b.remove; });
|
||||
|
||||
// Remove finished fragments
|
||||
listFragments.remove_if([&](const sBullet& b) {return b.pos.x<0 || b.pos.x>ScreenWidth() || b.pos.y <0 || b.pos.y>ScreenHeight() || b.remove; });
|
||||
|
||||
// GRAPHICS
|
||||
Clear(olc::BLACK);
|
||||
|
||||
// Update & Draw Stars
|
||||
for (size_t i=0; i<aryStars.size(); i++)
|
||||
{
|
||||
auto& s = aryStars[i];
|
||||
s.y += fScrollSpeed * fElapsedTime * ((i<aryStars.size() >> 2) ? 0.8f : 1.0f);
|
||||
if (s.y >= (float)ScreenHeight())
|
||||
s = { (float)(rand() % ScreenWidth()), 0.0f };
|
||||
|
||||
Draw(s, (i < aryStars.size() >> 2) ? olc::DARK_GREY : olc::WHITE);
|
||||
}
|
||||
|
||||
SetPixelMode(olc::Pixel::MASK);
|
||||
|
||||
// Draw Enemies
|
||||
for (auto& e : listEnemies) DrawSprite(e.pos, sprEnemy[e.def.nSpriteID]);
|
||||
|
||||
// Draw Player
|
||||
DrawSprite(vPlayerPos, sprPlayer);
|
||||
|
||||
SetPixelMode(olc::Pixel::NORMAL);
|
||||
|
||||
// Draw Enemy Bullets
|
||||
for (auto& b : listEnemyBullets) FillCircle(b.pos, 3, olc::RED);
|
||||
|
||||
// Draw Player Bullets
|
||||
for (auto& b : listPlayerBullets) FillCircle(b.pos, 3, olc::CYAN);
|
||||
|
||||
// Draw Fragments
|
||||
for (auto& b : listFragments) Draw(b.pos, olc::YELLOW);
|
||||
|
||||
// Draw Player Health Bar
|
||||
DrawString(4, 4, "HEALTH:");
|
||||
FillRect(60, 4, (fPlayerHealth / 1000.0f * 576.0f), 8, olc::GREEN);
|
||||
|
||||
DrawString(4, 14, "WEAPON:");
|
||||
FillRect(60, 14, (fPlayerGunTemp / 100.0f * 576.0f), 8, olc::YELLOW);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
Example demo;
|
||||
if (demo.Construct(640, 480, 2, 2))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
@@ -1,269 +1,272 @@
|
||||
/*
|
||||
Simple example code for olcPGEX_Sound.h - Mind your speakers!
|
||||
|
||||
You will need SampleA.wav, SampleB.wav and SampleC.wav for this demo.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Homepage: https://www.onelonecoder.com
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018
|
||||
*/
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
#include "olcPGEX_Sound.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
class SoundTest : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
SoundTest()
|
||||
{
|
||||
sAppName = "Sound Test";
|
||||
}
|
||||
|
||||
private:
|
||||
int sndSampleA;
|
||||
int sndSampleB;
|
||||
int sndSampleC;
|
||||
bool bToggle = false;
|
||||
static bool bSynthPlaying;
|
||||
static float fSynthFrequency;
|
||||
static float fFilterVolume;
|
||||
|
||||
const olc::Key keys[12] = { olc::Key::Z, olc::Key::S, olc::Key::X, olc::Key::D, olc::Key::C,
|
||||
olc::Key::V, olc::Key::G, olc::Key::B, olc::Key::H, olc::Key::N, olc::Key::J, olc::Key::M};
|
||||
|
||||
static float fPreviousSamples[128];
|
||||
static int nSamplePos;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// This is an optional function that allows the user to generate or synthesize sounds
|
||||
// in a custom way, it is fed into the output mixer bu the extension
|
||||
static float MyCustomSynthFunction(int nChannel, float fGlobalTime, float fTimeStep)
|
||||
{
|
||||
// Just generate a sine wave of the appropriate frequency
|
||||
if (bSynthPlaying)
|
||||
return sin(fSynthFrequency * 2.0f * 3.14159f * fGlobalTime);
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// This is an optional function that allows the user to filter the output from
|
||||
// the internal mixer of the extension. Here you could add effects or just
|
||||
// control volume. I also like to use it to extract information about
|
||||
// the currently playing output waveform
|
||||
static float MyCustomFilterFunction(int nChannel, float fGlobalTime, float fSample)
|
||||
{
|
||||
// Fundamentally just control volume
|
||||
float fOutput = fSample * fFilterVolume;
|
||||
|
||||
// But also add sample to list of previous samples for visualisation
|
||||
fPreviousSamples[nSamplePos] = fOutput;
|
||||
nSamplePos++;
|
||||
nSamplePos %= 128;
|
||||
|
||||
return fOutput;
|
||||
}
|
||||
|
||||
|
||||
bool OnUserCreate()
|
||||
{
|
||||
olc::SOUND::InitialiseAudio();
|
||||
sndSampleA = olc::SOUND::LoadAudioSample("SampleA.wav");
|
||||
sndSampleB = olc::SOUND::LoadAudioSample("SampleB.wav");
|
||||
sndSampleC = olc::SOUND::LoadAudioSample("SampleC.wav");
|
||||
|
||||
// Give the sound engine a hook to a custom generation function
|
||||
olc::SOUND::SetUserSynthFunction(MyCustomSynthFunction);
|
||||
|
||||
// Give the sound engine a hook to a custom filtering function
|
||||
olc::SOUND::SetUserFilterFunction(MyCustomFilterFunction);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime)
|
||||
{
|
||||
//olc::SOUND::PlaySample(sndTest);
|
||||
|
||||
auto PointInRect = [&](int x, int y, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
return x >= rx && x < (rx + rw) && y >= ry && y < (ry + rh);
|
||||
};
|
||||
|
||||
int nMouseX = GetMouseX();
|
||||
int nMouseY = GetMouseY();
|
||||
|
||||
if(GetMouse(0).bPressed && PointInRect(nMouseX, nMouseY, 16, 16, 128, 24))
|
||||
olc::SOUND::PlaySample(sndSampleA); // Plays the sample once
|
||||
|
||||
if (GetMouse(0).bPressed && PointInRect(nMouseX, nMouseY, 16, 48, 128, 24))
|
||||
olc::SOUND::PlaySample(sndSampleB);
|
||||
|
||||
if (GetMouse(0).bPressed && PointInRect(nMouseX, nMouseY, 16, 80, 128, 24))
|
||||
{
|
||||
bToggle = !bToggle;
|
||||
if (bToggle)
|
||||
{
|
||||
olc::SOUND::PlaySample(sndSampleC, true); // Plays the sample in looping mode
|
||||
}
|
||||
else
|
||||
{
|
||||
olc::SOUND::StopSample(sndSampleC);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetMouse(0).bHeld && PointInRect(nMouseX, nMouseY, 160, 16, 90, 24))
|
||||
fFilterVolume += 2.0f * fElapsedTime;
|
||||
|
||||
if (GetMouse(0).bHeld && PointInRect(nMouseX, nMouseY, 160, 48, 90, 24))
|
||||
fFilterVolume -= 2.0f * fElapsedTime;
|
||||
|
||||
if (fFilterVolume < 0.0f) fFilterVolume = 0.0f;
|
||||
if (fFilterVolume > 1.0f) fFilterVolume = 1.0f;
|
||||
|
||||
// Detect keyboard - very simple synthesizer
|
||||
if (IsFocused())
|
||||
{
|
||||
bool bKeyIsPressed = false;
|
||||
float fFrequency = 0.0f;
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
if (GetKey(keys[i]).bHeld)
|
||||
{
|
||||
bKeyIsPressed = true;
|
||||
float fOctaveBaseFrequency = 220.0f;
|
||||
float f12thRootOf2 = pow(2.0f, 1.0f / 12.0f);
|
||||
fFrequency = fOctaveBaseFrequency * powf(f12thRootOf2, (float)i);
|
||||
}
|
||||
}
|
||||
|
||||
fSynthFrequency = fFrequency;
|
||||
bSynthPlaying = bKeyIsPressed;
|
||||
}
|
||||
|
||||
|
||||
// Draw Buttons
|
||||
Clear(olc::BLUE);
|
||||
|
||||
DrawRect(16, 16, 128, 24);
|
||||
DrawString(20, 20, "Play Sample A");
|
||||
|
||||
DrawRect(16, 48, 128, 24);
|
||||
DrawString(20, 52, "Play Sample B");
|
||||
|
||||
DrawRect(16, 80, 128, 24);
|
||||
DrawString(20, 84, (bToggle ? "Stop Sample C" : "Loop Sample C"));
|
||||
|
||||
|
||||
DrawRect(160, 16, 90, 24);
|
||||
DrawString(164, 20, "Volume +");
|
||||
|
||||
DrawRect(160, 48, 90, 24);
|
||||
DrawString(164, 52, "Volume -");
|
||||
|
||||
|
||||
DrawString(164, 80, "Volume: " + std::to_string((int)(fFilterVolume * 10.0f)));
|
||||
|
||||
// Draw Keyboard
|
||||
|
||||
// White Keys
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
FillRect(i * 16 + 8, 160, 16, 64);
|
||||
DrawRect(i * 16 + 8, 160, 16, 64, olc::BLACK);
|
||||
DrawString(i * 16 + 12, 212, std::string(1, "ZXCVBNM"[i]), olc::BLACK);
|
||||
}
|
||||
|
||||
// Black Keys
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (i != 2)
|
||||
{
|
||||
FillRect(i * 16 + 18, 160, 12, 32, olc::BLACK);
|
||||
DrawString(i * 16 + 20, 180, std::string(1, "SDFGHJ"[i]), olc::WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw visualisation
|
||||
int nStartPos = (nSamplePos + 127) % 128;
|
||||
|
||||
for (int i = 127; i >= 0; i--)
|
||||
{
|
||||
float fSample = fPreviousSamples[(nSamplePos + i) % 128];
|
||||
DrawLine(124 + i, 210, 124 + i, 210 + (int)(fSample * 20.0f), olc::RED);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Note we must shut down the sound system too!!
|
||||
bool OnUserDestroy()
|
||||
{
|
||||
olc::SOUND::DestroyAudio();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bool SoundTest::bSynthPlaying = false;
|
||||
float SoundTest::fSynthFrequency = 0.0f;
|
||||
float SoundTest::fFilterVolume = 1.0f;
|
||||
int SoundTest::nSamplePos = 0;
|
||||
float SoundTest::fPreviousSamples[128];
|
||||
|
||||
int main()
|
||||
{
|
||||
SoundTest demo;
|
||||
if(demo.Construct(256, 240, 4, 4))
|
||||
demo.Start();
|
||||
|
||||
return 0;
|
||||
/*
|
||||
Simple example code for olcPGEX_Sound.h - Mind your speakers!
|
||||
|
||||
You will need SampleA.wav, SampleB.wav and SampleC.wav for this demo.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Homepage: https://www.onelonecoder.com
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018
|
||||
*/
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#define OLC_PGEX_SOUND
|
||||
#include "olcPGEX_Sound.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
class SoundTest : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
SoundTest()
|
||||
{
|
||||
sAppName = "Sound Test";
|
||||
}
|
||||
|
||||
private:
|
||||
int sndSampleA;
|
||||
int sndSampleB;
|
||||
int sndSampleC;
|
||||
bool bToggle = false;
|
||||
static bool bSynthPlaying;
|
||||
static float fSynthFrequency;
|
||||
static float fFilterVolume;
|
||||
|
||||
const olc::Key keys[12] = { olc::Key::Z, olc::Key::S, olc::Key::X, olc::Key::D, olc::Key::C,
|
||||
olc::Key::V, olc::Key::G, olc::Key::B, olc::Key::H, olc::Key::N, olc::Key::J, olc::Key::M};
|
||||
|
||||
static float fPreviousSamples[128];
|
||||
static int nSamplePos;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
// This is an optional function that allows the user to generate or synthesize sounds
|
||||
// in a custom way, it is fed into the output mixer bu the extension
|
||||
static float MyCustomSynthFunction(int nChannel, float fGlobalTime, float fTimeStep)
|
||||
{
|
||||
// Just generate a sine wave of the appropriate frequency
|
||||
if (bSynthPlaying)
|
||||
return sin(fSynthFrequency * 2.0f * 3.14159f * fGlobalTime);
|
||||
else
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// This is an optional function that allows the user to filter the output from
|
||||
// the internal mixer of the extension. Here you could add effects or just
|
||||
// control volume. I also like to use it to extract information about
|
||||
// the currently playing output waveform
|
||||
static float MyCustomFilterFunction(int nChannel, float fGlobalTime, float fSample)
|
||||
{
|
||||
// Fundamentally just control volume
|
||||
float fOutput = fSample * fFilterVolume;
|
||||
|
||||
// But also add sample to list of previous samples for visualisation
|
||||
fPreviousSamples[nSamplePos] = fOutput;
|
||||
nSamplePos++;
|
||||
nSamplePos %= 128;
|
||||
|
||||
return fOutput;
|
||||
}
|
||||
|
||||
|
||||
bool OnUserCreate()
|
||||
{
|
||||
olc::SOUND::InitialiseAudio(44100, 1, 8, 512);
|
||||
|
||||
sndSampleA = olc::SOUND::LoadAudioSample("SampleA.wav");
|
||||
sndSampleB = olc::SOUND::LoadAudioSample("SampleB.wav");
|
||||
sndSampleC = olc::SOUND::LoadAudioSample("SampleC.wav");
|
||||
|
||||
// Give the sound engine a hook to a custom generation function
|
||||
olc::SOUND::SetUserSynthFunction(MyCustomSynthFunction);
|
||||
|
||||
// Give the sound engine a hook to a custom filtering function
|
||||
olc::SOUND::SetUserFilterFunction(MyCustomFilterFunction);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime)
|
||||
{
|
||||
//olc::SOUND::PlaySample(sndTest);
|
||||
|
||||
auto PointInRect = [&](int x, int y, int rx, int ry, int rw, int rh)
|
||||
{
|
||||
return x >= rx && x < (rx + rw) && y >= ry && y < (ry + rh);
|
||||
};
|
||||
|
||||
int nMouseX = GetMouseX();
|
||||
int nMouseY = GetMouseY();
|
||||
|
||||
if(GetMouse(0).bPressed && PointInRect(nMouseX, nMouseY, 16, 16, 128, 24))
|
||||
olc::SOUND::PlaySample(sndSampleA); // Plays the sample once
|
||||
|
||||
if (GetMouse(0).bPressed && PointInRect(nMouseX, nMouseY, 16, 48, 128, 24))
|
||||
olc::SOUND::PlaySample(sndSampleB);
|
||||
|
||||
if (GetMouse(0).bPressed && PointInRect(nMouseX, nMouseY, 16, 80, 128, 24))
|
||||
{
|
||||
bToggle = !bToggle;
|
||||
if (bToggle)
|
||||
{
|
||||
olc::SOUND::PlaySample(sndSampleC, true); // Plays the sample in looping mode
|
||||
}
|
||||
else
|
||||
{
|
||||
olc::SOUND::StopSample(sndSampleC);
|
||||
}
|
||||
}
|
||||
|
||||
if (GetMouse(0).bHeld && PointInRect(nMouseX, nMouseY, 160, 16, 90, 24))
|
||||
fFilterVolume += 2.0f * fElapsedTime;
|
||||
|
||||
if (GetMouse(0).bHeld && PointInRect(nMouseX, nMouseY, 160, 48, 90, 24))
|
||||
fFilterVolume -= 2.0f * fElapsedTime;
|
||||
|
||||
if (fFilterVolume < 0.0f) fFilterVolume = 0.0f;
|
||||
if (fFilterVolume > 1.0f) fFilterVolume = 1.0f;
|
||||
|
||||
// Detect keyboard - very simple synthesizer
|
||||
if (IsFocused())
|
||||
{
|
||||
bool bKeyIsPressed = false;
|
||||
float fFrequency = 0.0f;
|
||||
for (int i = 0; i < 12; i++)
|
||||
{
|
||||
if (GetKey(keys[i]).bHeld)
|
||||
{
|
||||
bKeyIsPressed = true;
|
||||
float fOctaveBaseFrequency = 220.0f;
|
||||
float f12thRootOf2 = pow(2.0f, 1.0f / 12.0f);
|
||||
fFrequency = fOctaveBaseFrequency * powf(f12thRootOf2, (float)i);
|
||||
}
|
||||
}
|
||||
|
||||
fSynthFrequency = fFrequency;
|
||||
bSynthPlaying = bKeyIsPressed;
|
||||
}
|
||||
|
||||
|
||||
// Draw Buttons
|
||||
Clear(olc::BLUE);
|
||||
|
||||
DrawRect(16, 16, 128, 24);
|
||||
DrawString(20, 20, "Play Sample A");
|
||||
|
||||
DrawRect(16, 48, 128, 24);
|
||||
DrawString(20, 52, "Play Sample B");
|
||||
|
||||
DrawRect(16, 80, 128, 24);
|
||||
DrawString(20, 84, (bToggle ? "Stop Sample C" : "Loop Sample C"));
|
||||
|
||||
|
||||
DrawRect(160, 16, 90, 24);
|
||||
DrawString(164, 20, "Volume +");
|
||||
|
||||
DrawRect(160, 48, 90, 24);
|
||||
DrawString(164, 52, "Volume -");
|
||||
|
||||
|
||||
DrawString(164, 80, "Volume: " + std::to_string((int)(fFilterVolume * 10.0f)));
|
||||
|
||||
// Draw Keyboard
|
||||
|
||||
// White Keys
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
FillRect(i * 16 + 8, 160, 16, 64);
|
||||
DrawRect(i * 16 + 8, 160, 16, 64, olc::BLACK);
|
||||
DrawString(i * 16 + 12, 212, std::string(1, "ZXCVBNM"[i]), olc::BLACK);
|
||||
}
|
||||
|
||||
// Black Keys
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
if (i != 2)
|
||||
{
|
||||
FillRect(i * 16 + 18, 160, 12, 32, olc::BLACK);
|
||||
DrawString(i * 16 + 20, 180, std::string(1, "SDFGHJ"[i]), olc::WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw visualisation
|
||||
int nStartPos = (nSamplePos + 127) % 128;
|
||||
|
||||
for (int i = 127; i >= 0; i--)
|
||||
{
|
||||
float fSample = fPreviousSamples[(nSamplePos + i) % 128];
|
||||
DrawLine(124 + i, 210, 124 + i, 210 + (int)(fSample * 20.0f), olc::RED);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Note we must shut down the sound system too!!
|
||||
bool OnUserDestroy()
|
||||
{
|
||||
olc::SOUND::DestroyAudio();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bool SoundTest::bSynthPlaying = false;
|
||||
float SoundTest::fSynthFrequency = 0.0f;
|
||||
float SoundTest::fFilterVolume = 1.0f;
|
||||
int SoundTest::nSamplePos = 0;
|
||||
float SoundTest::fPreviousSamples[128];
|
||||
|
||||
int main()
|
||||
{
|
||||
SoundTest demo;
|
||||
if(demo.Construct(256, 240, 4, 4))
|
||||
demo.Start();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,257 +1,257 @@
|
||||
/*
|
||||
OneLoneCoder.com - 2D Sprite Affine Transformations
|
||||
"No more 90 degree movements" - @Javidx9
|
||||
|
||||
|
||||
Background
|
||||
~~~~~~~~~~
|
||||
The sophistication of 2D engines is enhanced when the programmer is
|
||||
able to rotate and scale sprites in a convenient manner. This program
|
||||
shows the basics of how affine transformations accomplish this.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Relevant Videos
|
||||
~~~~~~~~~~~~~~~
|
||||
https://youtu.be/zxwLN2blwbQ
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018
|
||||
*/
|
||||
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#include <algorithm>
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
|
||||
class SpriteTransforms : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
SpriteTransforms()
|
||||
{
|
||||
sAppName = "Sprite Transforms";
|
||||
}
|
||||
|
||||
private:
|
||||
olc::Sprite *sprCar;
|
||||
|
||||
struct matrix3x3
|
||||
{
|
||||
float m[3][3];
|
||||
};
|
||||
|
||||
void Identity(matrix3x3 &mat)
|
||||
{
|
||||
mat.m[0][0] = 1.0f; mat.m[1][0] = 0.0f; mat.m[2][0] = 0.0f;
|
||||
mat.m[0][1] = 0.0f; mat.m[1][1] = 1.0f; mat.m[2][1] = 0.0f;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void Translate(matrix3x3 &mat, float ox, float oy)
|
||||
{
|
||||
mat.m[0][0] = 1.0f; mat.m[1][0] = 0.0f; mat.m[2][0] = ox;
|
||||
mat.m[0][1] = 0.0f; mat.m[1][1] = 1.0f; mat.m[2][1] = oy;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void Rotate(matrix3x3 &mat, float fTheta)
|
||||
{
|
||||
mat.m[0][0] = cosf(fTheta); mat.m[1][0] = sinf(fTheta); mat.m[2][0] = 0.0f;
|
||||
mat.m[0][1] = -sinf(fTheta); mat.m[1][1] = cosf(fTheta); mat.m[2][1] = 0.0f;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void Scale(matrix3x3 &mat, float sx, float sy)
|
||||
{
|
||||
mat.m[0][0] = sx; mat.m[1][0] = 0.0f; mat.m[2][0] = 0.0f;
|
||||
mat.m[0][1] = 0.0f; mat.m[1][1] = sy; mat.m[2][1] = 0.0f;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void Shear(matrix3x3 &mat, float sx, float sy)
|
||||
{
|
||||
mat.m[0][0] = 1.0f; mat.m[1][0] = sx; mat.m[2][0] = 0.0f;
|
||||
mat.m[0][1] = sy; mat.m[1][1] = 1.0f; mat.m[2][1] = 0.0f;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void MatrixMultiply(matrix3x3 &matResult, matrix3x3 &matA, matrix3x3 &matB)
|
||||
{
|
||||
for (int c = 0; c < 3; c++)
|
||||
{
|
||||
for (int r = 0; r < 3; r++)
|
||||
{
|
||||
matResult.m[c][r] = matA.m[0][r] * matB.m[c][0] +
|
||||
matA.m[1][r] * matB.m[c][1] +
|
||||
matA.m[2][r] * matB.m[c][2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Forward(matrix3x3 &mat, float in_x, float in_y, float &out_x, float &out_y)
|
||||
{
|
||||
out_x = in_x * mat.m[0][0] + in_y * mat.m[1][0] + mat.m[2][0];
|
||||
out_y = in_x * mat.m[0][1] + in_y * mat.m[1][1] + mat.m[2][1];
|
||||
}
|
||||
|
||||
void Invert(matrix3x3 &matIn, matrix3x3 &matOut)
|
||||
{
|
||||
float det = matIn.m[0][0] * (matIn.m[1][1] * matIn.m[2][2] - matIn.m[1][2] * matIn.m[2][1]) -
|
||||
matIn.m[1][0] * (matIn.m[0][1] * matIn.m[2][2] - matIn.m[2][1] * matIn.m[0][2]) +
|
||||
matIn.m[2][0] * (matIn.m[0][1] * matIn.m[1][2] - matIn.m[1][1] * matIn.m[0][2]);
|
||||
|
||||
float idet = 1.0f / det;
|
||||
matOut.m[0][0] = (matIn.m[1][1] * matIn.m[2][2] - matIn.m[1][2] * matIn.m[2][1]) * idet;
|
||||
matOut.m[1][0] = (matIn.m[2][0] * matIn.m[1][2] - matIn.m[1][0] * matIn.m[2][2]) * idet;
|
||||
matOut.m[2][0] = (matIn.m[1][0] * matIn.m[2][1] - matIn.m[2][0] * matIn.m[1][1]) * idet;
|
||||
matOut.m[0][1] = (matIn.m[2][1] * matIn.m[0][2] - matIn.m[0][1] * matIn.m[2][2]) * idet;
|
||||
matOut.m[1][1] = (matIn.m[0][0] * matIn.m[2][2] - matIn.m[2][0] * matIn.m[0][2]) * idet;
|
||||
matOut.m[2][1] = (matIn.m[0][1] * matIn.m[2][0] - matIn.m[0][0] * matIn.m[2][1]) * idet;
|
||||
matOut.m[0][2] = (matIn.m[0][1] * matIn.m[1][2] - matIn.m[0][2] * matIn.m[1][1]) * idet;
|
||||
matOut.m[1][2] = (matIn.m[0][2] * matIn.m[1][0] - matIn.m[0][0] * matIn.m[1][2]) * idet;
|
||||
matOut.m[2][2] = (matIn.m[0][0] * matIn.m[1][1] - matIn.m[0][1] * matIn.m[1][0]) * idet;
|
||||
}
|
||||
|
||||
|
||||
float fRotate = 0.0f;
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
sprCar = new olc::Sprite("car_top1.png");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
|
||||
if (GetKey(olc::Key::Z).bHeld) fRotate -= 2.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::X).bHeld) fRotate += 2.0f * fElapsedTime;
|
||||
|
||||
|
||||
Clear(olc::DARK_CYAN);
|
||||
|
||||
SetPixelMode(olc::Pixel::ALPHA);
|
||||
//DrawSprite(0, 0, sprCar, 3);
|
||||
|
||||
|
||||
matrix3x3 matFinal, matA, matB, matC, matFinalInv;
|
||||
Translate(matA, -100, -50);
|
||||
Rotate(matB, fRotate);
|
||||
MatrixMultiply(matC, matB, matA);
|
||||
|
||||
Translate(matA, (float)ScreenWidth()/2, (float)ScreenHeight()/2);
|
||||
MatrixMultiply(matFinal, matA, matC);
|
||||
|
||||
Invert(matFinal, matFinalInv);
|
||||
|
||||
// Draws the dumb way, but leaves gaps
|
||||
/*for (int x = 0; x < sprCar->width; x++)
|
||||
{
|
||||
for (int y = 0; y < sprCar->height; y++)
|
||||
{
|
||||
olc::Pixel p = sprCar->GetPixel(x, y);
|
||||
|
||||
float nx, ny;
|
||||
Forward(matFinal, (float)x, (float)y, nx, ny);
|
||||
Draw(nx, ny, p);
|
||||
}
|
||||
}*/
|
||||
|
||||
// Work out bounding box of sprite post-transformation
|
||||
// by passing through sprite corner locations into
|
||||
// transformation matrix
|
||||
float ex, ey;
|
||||
float sx, sy;
|
||||
float px, py;
|
||||
|
||||
Forward(matFinal, 0.0f, 0.0f, px, py);
|
||||
sx = px; sy = py;
|
||||
ex = px; ey = py;
|
||||
|
||||
Forward(matFinal, (float)sprCar->width, (float)sprCar->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
Forward(matFinal, 0.0f, (float)sprCar->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
Forward(matFinal, (float)sprCar->width, 0.0f, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
// Use transformed corner locations in screen space to establish
|
||||
// region of pixels to fill, using inverse transform to sample
|
||||
// sprite at suitable locations.
|
||||
for (int x = sx; x < ex; x++)
|
||||
{
|
||||
for (int y = sy; y < ey; y++)
|
||||
{
|
||||
float nx, ny;
|
||||
Forward(matFinalInv, (float)x, (float)y, nx, ny);
|
||||
olc::Pixel p = sprCar->GetPixel((int32_t)(nx + 0.5f), (int32_t)(ny + 0.5f));
|
||||
Draw(x, y, p);
|
||||
}
|
||||
}
|
||||
|
||||
SetPixelMode(olc::Pixel::NORMAL);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
SpriteTransforms demo;
|
||||
if (demo.Construct(256, 240, 4, 4))
|
||||
demo.Start();
|
||||
return 0;
|
||||
/*
|
||||
OneLoneCoder.com - 2D Sprite Affine Transformations
|
||||
"No more 90 degree movements" - @Javidx9
|
||||
|
||||
|
||||
Background
|
||||
~~~~~~~~~~
|
||||
The sophistication of 2D engines is enhanced when the programmer is
|
||||
able to rotate and scale sprites in a convenient manner. This program
|
||||
shows the basics of how affine transformations accomplish this.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Relevant Videos
|
||||
~~~~~~~~~~~~~~~
|
||||
https://youtu.be/zxwLN2blwbQ
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2018
|
||||
*/
|
||||
|
||||
|
||||
#define OLC_PGE_APPLICATION
|
||||
#include "olcPixelGameEngine.h"
|
||||
|
||||
#include <algorithm>
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
|
||||
class SpriteTransforms : public olc::PixelGameEngine
|
||||
{
|
||||
public:
|
||||
SpriteTransforms()
|
||||
{
|
||||
sAppName = "Sprite Transforms";
|
||||
}
|
||||
|
||||
private:
|
||||
olc::Sprite *sprCar;
|
||||
|
||||
struct matrix3x3
|
||||
{
|
||||
float m[3][3];
|
||||
};
|
||||
|
||||
void Identity(matrix3x3 &mat)
|
||||
{
|
||||
mat.m[0][0] = 1.0f; mat.m[1][0] = 0.0f; mat.m[2][0] = 0.0f;
|
||||
mat.m[0][1] = 0.0f; mat.m[1][1] = 1.0f; mat.m[2][1] = 0.0f;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void Translate(matrix3x3 &mat, float ox, float oy)
|
||||
{
|
||||
mat.m[0][0] = 1.0f; mat.m[1][0] = 0.0f; mat.m[2][0] = ox;
|
||||
mat.m[0][1] = 0.0f; mat.m[1][1] = 1.0f; mat.m[2][1] = oy;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void Rotate(matrix3x3 &mat, float fTheta)
|
||||
{
|
||||
mat.m[0][0] = cosf(fTheta); mat.m[1][0] = sinf(fTheta); mat.m[2][0] = 0.0f;
|
||||
mat.m[0][1] = -sinf(fTheta); mat.m[1][1] = cosf(fTheta); mat.m[2][1] = 0.0f;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void Scale(matrix3x3 &mat, float sx, float sy)
|
||||
{
|
||||
mat.m[0][0] = sx; mat.m[1][0] = 0.0f; mat.m[2][0] = 0.0f;
|
||||
mat.m[0][1] = 0.0f; mat.m[1][1] = sy; mat.m[2][1] = 0.0f;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void Shear(matrix3x3 &mat, float sx, float sy)
|
||||
{
|
||||
mat.m[0][0] = 1.0f; mat.m[1][0] = sx; mat.m[2][0] = 0.0f;
|
||||
mat.m[0][1] = sy; mat.m[1][1] = 1.0f; mat.m[2][1] = 0.0f;
|
||||
mat.m[0][2] = 0.0f; mat.m[1][2] = 0.0f; mat.m[2][2] = 1.0f;
|
||||
}
|
||||
|
||||
void MatrixMultiply(matrix3x3 &matResult, matrix3x3 &matA, matrix3x3 &matB)
|
||||
{
|
||||
for (int c = 0; c < 3; c++)
|
||||
{
|
||||
for (int r = 0; r < 3; r++)
|
||||
{
|
||||
matResult.m[c][r] = matA.m[0][r] * matB.m[c][0] +
|
||||
matA.m[1][r] * matB.m[c][1] +
|
||||
matA.m[2][r] * matB.m[c][2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Forward(matrix3x3 &mat, float in_x, float in_y, float &out_x, float &out_y)
|
||||
{
|
||||
out_x = in_x * mat.m[0][0] + in_y * mat.m[1][0] + mat.m[2][0];
|
||||
out_y = in_x * mat.m[0][1] + in_y * mat.m[1][1] + mat.m[2][1];
|
||||
}
|
||||
|
||||
void Invert(matrix3x3 &matIn, matrix3x3 &matOut)
|
||||
{
|
||||
float det = matIn.m[0][0] * (matIn.m[1][1] * matIn.m[2][2] - matIn.m[1][2] * matIn.m[2][1]) -
|
||||
matIn.m[1][0] * (matIn.m[0][1] * matIn.m[2][2] - matIn.m[2][1] * matIn.m[0][2]) +
|
||||
matIn.m[2][0] * (matIn.m[0][1] * matIn.m[1][2] - matIn.m[1][1] * matIn.m[0][2]);
|
||||
|
||||
float idet = 1.0f / det;
|
||||
matOut.m[0][0] = (matIn.m[1][1] * matIn.m[2][2] - matIn.m[1][2] * matIn.m[2][1]) * idet;
|
||||
matOut.m[1][0] = (matIn.m[2][0] * matIn.m[1][2] - matIn.m[1][0] * matIn.m[2][2]) * idet;
|
||||
matOut.m[2][0] = (matIn.m[1][0] * matIn.m[2][1] - matIn.m[2][0] * matIn.m[1][1]) * idet;
|
||||
matOut.m[0][1] = (matIn.m[2][1] * matIn.m[0][2] - matIn.m[0][1] * matIn.m[2][2]) * idet;
|
||||
matOut.m[1][1] = (matIn.m[0][0] * matIn.m[2][2] - matIn.m[2][0] * matIn.m[0][2]) * idet;
|
||||
matOut.m[2][1] = (matIn.m[0][1] * matIn.m[2][0] - matIn.m[0][0] * matIn.m[2][1]) * idet;
|
||||
matOut.m[0][2] = (matIn.m[0][1] * matIn.m[1][2] - matIn.m[0][2] * matIn.m[1][1]) * idet;
|
||||
matOut.m[1][2] = (matIn.m[0][2] * matIn.m[1][0] - matIn.m[0][0] * matIn.m[1][2]) * idet;
|
||||
matOut.m[2][2] = (matIn.m[0][0] * matIn.m[1][1] - matIn.m[0][1] * matIn.m[1][0]) * idet;
|
||||
}
|
||||
|
||||
|
||||
float fRotate = 0.0f;
|
||||
|
||||
public:
|
||||
bool OnUserCreate() override
|
||||
{
|
||||
sprCar = new olc::Sprite("car_top1.png");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OnUserUpdate(float fElapsedTime) override
|
||||
{
|
||||
|
||||
if (GetKey(olc::Key::Z).bHeld) fRotate -= 2.0f * fElapsedTime;
|
||||
if (GetKey(olc::Key::X).bHeld) fRotate += 2.0f * fElapsedTime;
|
||||
|
||||
|
||||
Clear(olc::DARK_CYAN);
|
||||
|
||||
SetPixelMode(olc::Pixel::ALPHA);
|
||||
//DrawSprite(0, 0, sprCar, 3);
|
||||
|
||||
|
||||
matrix3x3 matFinal, matA, matB, matC, matFinalInv;
|
||||
Translate(matA, -100, -50);
|
||||
Rotate(matB, fRotate);
|
||||
MatrixMultiply(matC, matB, matA);
|
||||
|
||||
Translate(matA, (float)ScreenWidth()/2, (float)ScreenHeight()/2);
|
||||
MatrixMultiply(matFinal, matA, matC);
|
||||
|
||||
Invert(matFinal, matFinalInv);
|
||||
|
||||
// Draws the dumb way, but leaves gaps
|
||||
/*for (int x = 0; x < sprCar->width; x++)
|
||||
{
|
||||
for (int y = 0; y < sprCar->height; y++)
|
||||
{
|
||||
olc::Pixel p = sprCar->GetPixel(x, y);
|
||||
|
||||
float nx, ny;
|
||||
Forward(matFinal, (float)x, (float)y, nx, ny);
|
||||
Draw(nx, ny, p);
|
||||
}
|
||||
}*/
|
||||
|
||||
// Work out bounding box of sprite post-transformation
|
||||
// by passing through sprite corner locations into
|
||||
// transformation matrix
|
||||
float ex, ey;
|
||||
float sx, sy;
|
||||
float px, py;
|
||||
|
||||
Forward(matFinal, 0.0f, 0.0f, px, py);
|
||||
sx = px; sy = py;
|
||||
ex = px; ey = py;
|
||||
|
||||
Forward(matFinal, (float)sprCar->width, (float)sprCar->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
Forward(matFinal, 0.0f, (float)sprCar->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
Forward(matFinal, (float)sprCar->width, 0.0f, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
// Use transformed corner locations in screen space to establish
|
||||
// region of pixels to fill, using inverse transform to sample
|
||||
// sprite at suitable locations.
|
||||
for (int x = sx; x < ex; x++)
|
||||
{
|
||||
for (int y = sy; y < ey; y++)
|
||||
{
|
||||
float nx, ny;
|
||||
Forward(matFinalInv, (float)x, (float)y, nx, ny);
|
||||
olc::Pixel p = sprCar->GetPixel((int32_t)(nx + 0.5f), (int32_t)(ny + 0.5f));
|
||||
Draw(x, y, p);
|
||||
}
|
||||
}
|
||||
|
||||
SetPixelMode(olc::Pixel::NORMAL);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
SpriteTransforms demo;
|
||||
if (demo.Construct(256, 240, 4, 4))
|
||||
demo.Start();
|
||||
return 0;
|
||||
}
|
||||
BIN
Videos/OneLoneCoder_PGE_olcEngine3D.cpp
Normal file
BIN
Videos/RetroMenu.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
1509
Videos/SavingSedit/OneLoneCoder_PGE_SavingSedit.cpp
Normal file
224
Videos/SavingSedit/Zix_PGE_Controller.h
Normal file
@@ -0,0 +1,224 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <xinput.h>
|
||||
|
||||
typedef DWORD(WINAPI XInputGetState_t)(DWORD dwUserIndex, XINPUT_STATE* pState);
|
||||
static XInputGetState_t* XInputStateGet;
|
||||
|
||||
typedef DWORD(WINAPI XInputSetState_t)(DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
|
||||
static XInputSetState_t* XInputStateSet;
|
||||
#endif
|
||||
|
||||
#define C_BUTTON_COUNT 14
|
||||
enum CButton
|
||||
{
|
||||
UP,
|
||||
DOWN,
|
||||
LEFT,
|
||||
RIGHT,
|
||||
START,
|
||||
BACK,
|
||||
A,
|
||||
B,
|
||||
X,
|
||||
Y,
|
||||
LEFT_SHOULDER,
|
||||
RIGHT_SHOULDER,
|
||||
LEFT_THUMB,
|
||||
RIGHT_THUMB
|
||||
};
|
||||
|
||||
struct CBState
|
||||
{
|
||||
bool bPressed = false;
|
||||
bool bReleased = false;
|
||||
bool bHeld = false;
|
||||
};
|
||||
|
||||
class ControllerManager
|
||||
{
|
||||
private:
|
||||
bool buttonState[C_BUTTON_COUNT];
|
||||
bool lastButtonState[C_BUTTON_COUNT];
|
||||
|
||||
// Trigger values are in the range of 0 to 1, where 0 is fully
|
||||
// released and 1 is fully pressed.
|
||||
float triggerLeft = 0;
|
||||
float triggerRight = 0;
|
||||
|
||||
// Stick values are in the range of -1 to 1. For X values, -1 is
|
||||
// all the way to the left while +1 is all the way to the right.
|
||||
float leftStickX = 0;
|
||||
float leftStickY = 0;
|
||||
float rightStickX = 0;
|
||||
float rightStickY = 0;
|
||||
|
||||
// Whether or not the controller is plugged in.
|
||||
bool pluggedIn = true;
|
||||
|
||||
bool vibrating = false;
|
||||
float vibrateTime = 0;
|
||||
float vibrateCounter = 0;
|
||||
|
||||
public:
|
||||
bool Initialize();
|
||||
void Update(float dt);
|
||||
|
||||
void Vibrate(short amt, int timeMs);
|
||||
|
||||
CBState GetButton(CButton button);
|
||||
|
||||
float GetLeftTrigger() { return triggerLeft; }
|
||||
float GetRightTrigger() { return triggerRight; }
|
||||
|
||||
float GetLeftStickX() { return leftStickX; }
|
||||
float GetLeftStickY() { return leftStickY; }
|
||||
|
||||
float GetRightStickX() { return rightStickX; }
|
||||
float GetRightStickY() { return rightStickY; }
|
||||
|
||||
bool IsVibrating() { return vibrating; }
|
||||
bool IsPluggedIn() { return pluggedIn; }
|
||||
|
||||
private:
|
||||
float NormalizeStickValue(short value);
|
||||
};
|
||||
|
||||
bool ControllerManager::Initialize()
|
||||
{
|
||||
#ifdef WIN32
|
||||
// TODO: Should we check for version 9.1.0 if we fail to find 1.4?
|
||||
HMODULE lib = LoadLibraryA("xinput1_4.dll");
|
||||
|
||||
if (!lib) return false;
|
||||
|
||||
XInputStateGet = (XInputGetState_t*)GetProcAddress(lib, "XInputGetState");
|
||||
XInputStateSet = (XInputSetState_t*)GetProcAddress(lib, "XInputSetState");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float ControllerManager::NormalizeStickValue(short value)
|
||||
{
|
||||
// The value we are given is in the range -32768 to 32767 with some deadzone around zero.
|
||||
// We will assume all values in this dead zone to be a reading of zero (the stick is not moved).
|
||||
if (value > -7000 && value < 7000) return 0;
|
||||
|
||||
// Otherwise, we are going to normalize the value.
|
||||
return ((value + 32768.0f) / (32768.0f + 32767.0f) * 2) - 1;
|
||||
}
|
||||
|
||||
void ControllerManager::Vibrate(short amt, int timeMs)
|
||||
{
|
||||
// If we are already vibrating, just ignore this, unless they say zero, in which case we will let them stop it.
|
||||
if (vibrating && amt != 0) return;
|
||||
|
||||
// Only start the timer if we are actually vibrating.
|
||||
if (amt != 0)
|
||||
{
|
||||
vibrateTime = timeMs / 1000.0f;
|
||||
vibrating = true;
|
||||
}
|
||||
#ifdef WIN32
|
||||
XINPUT_VIBRATION info =
|
||||
{
|
||||
amt,
|
||||
amt
|
||||
};
|
||||
XInputStateSet(0, &info);
|
||||
#endif
|
||||
}
|
||||
|
||||
CBState ControllerManager::GetButton(CButton button)
|
||||
{
|
||||
return
|
||||
{
|
||||
!lastButtonState[button] && buttonState[button],
|
||||
lastButtonState[button] && !buttonState[button],
|
||||
lastButtonState[button] && buttonState[button]
|
||||
};
|
||||
}
|
||||
|
||||
void ControllerManager::Update(float dt)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (vibrating)
|
||||
{
|
||||
vibrateCounter += dt;
|
||||
if (vibrateCounter >= vibrateTime)
|
||||
{
|
||||
XINPUT_VIBRATION info =
|
||||
{
|
||||
0, 0
|
||||
};
|
||||
XInputStateSet(0, &info);
|
||||
|
||||
vibrating = false;
|
||||
vibrateCounter = 0;
|
||||
vibrateTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < C_BUTTON_COUNT; i++)
|
||||
{
|
||||
lastButtonState[i] = buttonState[i];
|
||||
}
|
||||
|
||||
XINPUT_STATE state;
|
||||
|
||||
// Try and get the first controller. For now we will only support a single one.
|
||||
DWORD res = XInputStateGet(0, &state);
|
||||
|
||||
// If the controller is plugged in, handle input.
|
||||
if (res == ERROR_SUCCESS)
|
||||
{
|
||||
XINPUT_GAMEPAD* pad = &state.Gamepad;
|
||||
|
||||
buttonState[UP] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_UP);
|
||||
buttonState[DOWN] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN);
|
||||
buttonState[LEFT] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT);
|
||||
buttonState[RIGHT] = (pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT);
|
||||
buttonState[START] = (pad->wButtons & XINPUT_GAMEPAD_START);
|
||||
buttonState[BACK] = (pad->wButtons & XINPUT_GAMEPAD_BACK);
|
||||
buttonState[LEFT_SHOULDER] = (pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER);
|
||||
buttonState[RIGHT_SHOULDER] = (pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER);
|
||||
buttonState[LEFT_THUMB] = (pad->wButtons & XINPUT_GAMEPAD_LEFT_THUMB);
|
||||
buttonState[RIGHT_THUMB] = (pad->wButtons & XINPUT_GAMEPAD_RIGHT_THUMB);
|
||||
buttonState[A] = (pad->wButtons & XINPUT_GAMEPAD_A);
|
||||
buttonState[B] = (pad->wButtons & XINPUT_GAMEPAD_B);
|
||||
buttonState[X] = (pad->wButtons & XINPUT_GAMEPAD_X);
|
||||
buttonState[Y] = (pad->wButtons & XINPUT_GAMEPAD_Y);
|
||||
|
||||
triggerLeft = pad->bLeftTrigger / 255.0f;
|
||||
triggerRight = pad->bRightTrigger / 255.0f;
|
||||
leftStickX = NormalizeStickValue(pad->sThumbLX);
|
||||
leftStickY = NormalizeStickValue(pad->sThumbLY);
|
||||
rightStickX = NormalizeStickValue(pad->sThumbRX);
|
||||
rightStickY = NormalizeStickValue(pad->sThumbRY);
|
||||
|
||||
if (!pluggedIn)
|
||||
{
|
||||
pluggedIn = true;
|
||||
// Send callback.
|
||||
// printf("Plugged in.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pluggedIn)
|
||||
{
|
||||
pluggedIn = false;
|
||||
// Send callback.
|
||||
// printf("Unplugged.\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < C_BUTTON_COUNT; i++)
|
||||
{
|
||||
lastButtonState[i] = buttonState[i] = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
42
Videos/SavingSedit/licence.txt
Normal file
@@ -0,0 +1,42 @@
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 - 2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Homepage: https://www.onelonecoder.com
|
||||
Patreon: https://www.patreon.com/javidx9
|
||||
313
Videos/SavingSedit/olcPGEX_Graphics2D.h
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
olcPGEX_Graphics2D.h
|
||||
|
||||
+-------------------------------------------------------------+
|
||||
| OneLoneCoder Pixel Game Engine Extension |
|
||||
| Advanced 2D Rendering - v0.4 |
|
||||
+-------------------------------------------------------------+
|
||||
|
||||
What is this?
|
||||
~~~~~~~~~~~~~
|
||||
This is an extension to the olcPixelGameEngine, which provides
|
||||
advanced olc::Sprite manipulation and drawing routines. To use
|
||||
it, simply include this header file.
|
||||
|
||||
License (OLC-3)
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Copyright 2018 - 2019 OneLoneCoder.com
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions or derivations of source code must retain the above
|
||||
copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions or derivative works in binary form must reproduce
|
||||
the above copyright notice. This list of conditions and the following
|
||||
disclaimer must be reproduced in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
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
|
||||
HOLDER 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.
|
||||
|
||||
Links
|
||||
~~~~~
|
||||
YouTube: https://www.youtube.com/javidx9
|
||||
Discord: https://discord.gg/WhwHUMV
|
||||
Twitter: https://www.twitter.com/javidx9
|
||||
Twitch: https://www.twitch.tv/javidx9
|
||||
GitHub: https://www.github.com/onelonecoder
|
||||
Homepage: https://www.onelonecoder.com
|
||||
|
||||
Author
|
||||
~~~~~~
|
||||
David Barr, aka javidx9, ©OneLoneCoder 2019
|
||||
*/
|
||||
|
||||
/*
|
||||
Matrices stored as [Column][Row] (i.e. x, y)
|
||||
|
||||
|C0R0 C1R0 C2R0| | x | | x'|
|
||||
|C0R1 C1R1 C2R1| * | y | = | y'|
|
||||
|C0R2 C1R2 C2R2| |1.0| | - |
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef OLC_PGEX_GFX2D
|
||||
#define OLC_PGEX_GFX2D
|
||||
|
||||
#include <algorithm>
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
namespace olc
|
||||
{
|
||||
// Container class for Advanced 2D Drawing functions
|
||||
class GFX2D : public olc::PGEX
|
||||
{
|
||||
// A representation of an affine transform, used to rotate, scale, offset & shear space
|
||||
public:
|
||||
class Transform2D
|
||||
{
|
||||
public:
|
||||
Transform2D();
|
||||
|
||||
public:
|
||||
// Set this transformation to unity
|
||||
void Reset();
|
||||
// Append a rotation of fTheta radians to this transform
|
||||
void Rotate(float fTheta);
|
||||
// Append a translation (ox, oy) to this transform
|
||||
void Translate(float ox, float oy);
|
||||
// Append a scaling operation (sx, sy) to this transform
|
||||
void Scale(float sx, float sy);
|
||||
// Append a shear operation (sx, sy) to this transform
|
||||
void Shear(float sx, float sy);
|
||||
|
||||
void Perspective(float ox, float oy);
|
||||
// Calculate the Forward Transformation of the coordinate (in_x, in_y) -> (out_x, out_y)
|
||||
void Forward(float in_x, float in_y, float &out_x, float &out_y);
|
||||
// Calculate the Inverse Transformation of the coordinate (in_x, in_y) -> (out_x, out_y)
|
||||
void Backward(float in_x, float in_y, float &out_x, float &out_y);
|
||||
// Regenerate the Inverse Transformation
|
||||
void Invert();
|
||||
|
||||
private:
|
||||
void Multiply();
|
||||
float matrix[4][3][3];
|
||||
int nTargetMatrix;
|
||||
int nSourceMatrix;
|
||||
bool bDirty;
|
||||
};
|
||||
|
||||
public:
|
||||
// Draws a sprite with the transform applied
|
||||
static void DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#ifdef OLC_PGE_GRAPHICS2D
|
||||
#undef OLC_PGE_GRAPHICS2D
|
||||
|
||||
namespace olc
|
||||
{
|
||||
void GFX2D::DrawSprite(olc::Sprite *sprite, olc::GFX2D::Transform2D &transform)
|
||||
{
|
||||
if (sprite == nullptr)
|
||||
return;
|
||||
|
||||
// Work out bounding rectangle of sprite
|
||||
float ex, ey;
|
||||
float sx, sy;
|
||||
float px, py;
|
||||
|
||||
transform.Forward(0.0f, 0.0f, sx, sy);
|
||||
px = sx; py = sy;
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
transform.Forward((float)sprite->width, (float)sprite->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
transform.Forward(0.0f, (float)sprite->height, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
transform.Forward((float)sprite->width, 0.0f, px, py);
|
||||
sx = std::min(sx, px); sy = std::min(sy, py);
|
||||
ex = std::max(ex, px); ey = std::max(ey, py);
|
||||
|
||||
// Perform inversion of transform if required
|
||||
transform.Invert();
|
||||
|
||||
if (ex < sx)
|
||||
std::swap(ex, sx);
|
||||
if (ey < sy)
|
||||
std::swap(ey, sy);
|
||||
|
||||
// Iterate through render space, and sample Sprite from suitable texel location
|
||||
for (float i = sx; i < ex; i++)
|
||||
{
|
||||
for (float j = sy; j < ey; j++)
|
||||
{
|
||||
float ox, oy;
|
||||
transform.Backward(i, j, ox, oy);
|
||||
pge->Draw((int32_t)i, (int32_t)j, sprite->GetPixel((int32_t)(ox+0.5f), (int32_t)(oy+0.5f)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
olc::GFX2D::Transform2D::Transform2D()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Reset()
|
||||
{
|
||||
nTargetMatrix = 0;
|
||||
nSourceMatrix = 1;
|
||||
bDirty = true;
|
||||
|
||||
// Columns Then Rows
|
||||
|
||||
// Matrices 0 & 1 are used as swaps in Transform accumulation
|
||||
matrix[0][0][0] = 1.0f; matrix[0][1][0] = 0.0f; matrix[0][2][0] = 0.0f;
|
||||
matrix[0][0][1] = 0.0f; matrix[0][1][1] = 1.0f; matrix[0][2][1] = 0.0f;
|
||||
matrix[0][0][2] = 0.0f; matrix[0][1][2] = 0.0f; matrix[0][2][2] = 1.0f;
|
||||
|
||||
matrix[1][0][0] = 1.0f; matrix[1][1][0] = 0.0f; matrix[1][2][0] = 0.0f;
|
||||
matrix[1][0][1] = 0.0f; matrix[1][1][1] = 1.0f; matrix[1][2][1] = 0.0f;
|
||||
matrix[1][0][2] = 0.0f; matrix[1][1][2] = 0.0f; matrix[1][2][2] = 1.0f;
|
||||
|
||||
// Matrix 2 is a cache matrix to hold the immediate transform operation
|
||||
// Matrix 3 is a cache matrix to hold the inverted transform
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Multiply()
|
||||
{
|
||||
for (int c = 0; c < 3; c++)
|
||||
{
|
||||
for (int r = 0; r < 3; r++)
|
||||
{
|
||||
matrix[nTargetMatrix][c][r] = matrix[2][0][r] * matrix[nSourceMatrix][c][0] +
|
||||
matrix[2][1][r] * matrix[nSourceMatrix][c][1] +
|
||||
matrix[2][2][r] * matrix[nSourceMatrix][c][2];
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(nTargetMatrix, nSourceMatrix);
|
||||
bDirty = true; // Any transform multiply dirties the inversion
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Rotate(float fTheta)
|
||||
{
|
||||
// Construct Rotation Matrix
|
||||
matrix[2][0][0] = cosf(fTheta); matrix[2][1][0] = sinf(fTheta); matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = -sinf(fTheta); matrix[2][1][1] = cosf(fTheta); matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Scale(float sx, float sy)
|
||||
{
|
||||
// Construct Scale Matrix
|
||||
matrix[2][0][0] = sx; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = 0.0f; matrix[2][1][1] = sy; matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Shear(float sx, float sy)
|
||||
{
|
||||
// Construct Shear Matrix
|
||||
matrix[2][0][0] = 1.0f; matrix[2][1][0] = sx; matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = sy; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Translate(float ox, float oy)
|
||||
{
|
||||
// Construct Translate Matrix
|
||||
matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = ox;
|
||||
matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = oy;
|
||||
matrix[2][0][2] = 0.0f; matrix[2][1][2] = 0.0f; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Perspective(float ox, float oy)
|
||||
{
|
||||
// Construct Translate Matrix
|
||||
matrix[2][0][0] = 1.0f; matrix[2][1][0] = 0.0f; matrix[2][2][0] = 0.0f;
|
||||
matrix[2][0][1] = 0.0f; matrix[2][1][1] = 1.0f; matrix[2][2][1] = 0.0f;
|
||||
matrix[2][0][2] = ox; matrix[2][1][2] = oy; matrix[2][2][2] = 1.0f;
|
||||
Multiply();
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Forward(float in_x, float in_y, float &out_x, float &out_y)
|
||||
{
|
||||
out_x = in_x * matrix[nSourceMatrix][0][0] + in_y * matrix[nSourceMatrix][1][0] + matrix[nSourceMatrix][2][0];
|
||||
out_y = in_x * matrix[nSourceMatrix][0][1] + in_y * matrix[nSourceMatrix][1][1] + matrix[nSourceMatrix][2][1];
|
||||
float out_z = in_x * matrix[nSourceMatrix][0][2] + in_y * matrix[nSourceMatrix][1][2] + matrix[nSourceMatrix][2][2];
|
||||
if (out_z != 0)
|
||||
{
|
||||
out_x /= out_z;
|
||||
out_y /= out_z;
|
||||
}
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Backward(float in_x, float in_y, float &out_x, float &out_y)
|
||||
{
|
||||
out_x = in_x * matrix[3][0][0] + in_y * matrix[3][1][0] + matrix[3][2][0];
|
||||
out_y = in_x * matrix[3][0][1] + in_y * matrix[3][1][1] + matrix[3][2][1];
|
||||
float out_z = in_x * matrix[3][0][2] + in_y * matrix[3][1][2] + matrix[3][2][2];
|
||||
if (out_z != 0)
|
||||
{
|
||||
out_x /= out_z;
|
||||
out_y /= out_z;
|
||||
}
|
||||
}
|
||||
|
||||
void olc::GFX2D::Transform2D::Invert()
|
||||
{
|
||||
if (bDirty) // Obviously costly so only do if needed
|
||||
{
|
||||
float det = matrix[nSourceMatrix][0][0] * (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) -
|
||||
matrix[nSourceMatrix][1][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2]) +
|
||||
matrix[nSourceMatrix][2][0] * (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][0][2]);
|
||||
|
||||
float idet = 1.0f / det;
|
||||
matrix[3][0][0] = (matrix[nSourceMatrix][1][1] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][1][2] * matrix[nSourceMatrix][2][1]) * idet;
|
||||
matrix[3][1][0] = (matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][2]) * idet;
|
||||
matrix[3][2][0] = (matrix[nSourceMatrix][1][0] * matrix[nSourceMatrix][2][1] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][1][1]) * idet;
|
||||
matrix[3][0][1] = (matrix[nSourceMatrix][2][1] * matrix[nSourceMatrix][0][2] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][2]) * idet;
|
||||
matrix[3][1][1] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][2] - matrix[nSourceMatrix][2][0] * matrix[nSourceMatrix][0][2]) * idet;
|
||||
matrix[3][2][1] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][2][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][2][1]) * idet;
|
||||
matrix[3][0][2] = (matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][2] - matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][1]) * idet;
|
||||
matrix[3][1][2] = (matrix[nSourceMatrix][0][2] * matrix[nSourceMatrix][1][0] - matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][2]) * idet;
|
||||
matrix[3][2][2] = (matrix[nSourceMatrix][0][0] * matrix[nSourceMatrix][1][1] - matrix[nSourceMatrix][0][1] * matrix[nSourceMatrix][1][0]) * idet;
|
||||
bDirty = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||