Compare commits

...

59 Commits

Author SHA1 Message Date
c00f05aafd feat(renderer): smooth shadow sun direction transitions using quantized directions and slerp 2026-06-17 22:09:50 +08:00
dc1ef70231 fix(texture): set texture wrap mode to clamp to edge 2026-06-17 21:13:23 +08:00
e224110452 feat(renderer): add runtime shader and shadow mode controls
Introduce user-controllable shader on/off, shadow mode (rotated Poisson disk, 3x3 grid, or off), light cull face, and discard transparent in depth pass. Expose all settings in new dev panel "shader" tab. Move ambient strength slider to the new tab.
2026-06-17 20:16:20 +08:00
74b0aebc9f chore(world): add missing <numbers> include 2026-06-17 19:16:02 +08:00
be425a705c feat(dev-panel): add tick freeze toggle and fix TickType sign
Add checkbox to freeze tick advancement in dev panel.
Change TickType from unsigned long long to signed long long to prevent underflow.
2026-06-17 19:15:16 +08:00
31bf337f6f perf(shadow): increase depth map resolution and refine PCF sampling 2026-06-17 15:23:38 +08:00
662f10047a feat(renderer): add shadow mapping with PCF soft shadows
Introduce shadow mapping using a dedicated depth framebuffer and shader. The block fragment shader now performs percentage-closer filtering (PCF) with Poisson disk sampling and random rotation for soft shadows. The vertex shader outputs light-space coordinates. A new depth shader pair handles rendering from the light's perspective, discarding transparent fragments. The renderer sets up the light projection based on the camera position and sun direction, and applies the shadow factor to diffuse lighting. Day/night cycle can now be toggled off in the world server thread.
2026-06-16 22:27:08 +08:00
943c6f1f46 fix(game_time): use unsigned tick type and enforce positive tick speed 2026-06-16 18:51:47 +08:00
7ede49da72 feat(renderer): make ambient strength adjustable via dev panel 2026-06-16 18:44:59 +08:00
a4f92e3659 feat(world): add day/night cycle with server tick system 2026-06-16 16:17:47 +08:00
f43ef64691 feat(rendering): add basic diffuse and ambient lighting to block rendering 2026-06-16 13:53:47 +08:00
zhenyan121
f4114c2699 refactor: world generation (#17)
* refactor: use TBB for concurrent hash maps and parallelize chunk processing

* fix: tbb link fail

* refactor(chunk): remove biome check for caves in rivers and oceans

* refactor(random): replace std distributions with custom implementations

Avoid overhead and platform-dependent behavior of `<random>` distributions by using direct engine operations and integer arithmetic. This ensures deterministic, cross-platform results and improves performance.

* refactor(generation): use chunk seed for cave and river paths

- Use per-chunk seed instead of global path_id for cave and river generation.
- Remove unused m_sum variables and m_path_id members.
- Clamp river yaw within 10 degrees of initial direction.
- Fix river radius interpolation (use t instead of 1-t).
- Lower sea level from 64 to 63.
2026-06-14 11:36:37 +08:00
zhenyan121
932463663f feat: ocean (#16)
* feat(gameplay): add Ocean biome with water generation and heightmap adjustments

- Introduce Ocean biome enum, builder, and detection logic.
- Add ocean water building to all existing biomes and modify heightmap thresholds for low mountainous areas.
- Skip cave and river generation in Ocean (and River) biomes; avoid carving water blocks.
- Comment out border blending call and update block fill logic.

* fix(gameplay): re-enable border blending and protect water in cave gen

* refactor(generation): move ocean water build to later phase

* feat(block): add is_transitional property and refine border blending

* fix(block): set stone block as transitional

* fix(world): generate temporary chunks for surface blend neighbor data

* fix(gameplay): simplify block fill logic in blend_surface_blocks_borders

* refactor(tree): remove debug logging and unused include
2026-06-12 19:42:59 +08:00
zhenyan121
bac3df801b refactor: chunk render (#15)
* refactor(renderer): centralize VAO setup and rename init_underwater

* refactor(gameplay): replace VBO with VAO for vertex data

* fix(renderer): move depth test enable to world rendering

The `glEnable(GL_DEPTH_TEST)` call was incorrectly placed in the general `render()` function, affecting UI and text rendering. Moved it to the start of the world rendering loop to ensure depth testing is only active during 3D world pass.
2026-06-11 14:58:39 +08:00
zhenyan121
d0bc8d627f refactor: transparent render (#14)
* fix(renderer): defer uniform location retrieval and add view matrix in outline rendering

* refactor(gameplay): encapsulate per-type vertex data into VertexData struct

* feat(rendering): separate transparent blocks into discard and blend modes

* feat(renderer): implement order-independent transparency

* fix(shaders): reduce alpha discard threshold to 0.8
2026-06-11 12:21:19 +08:00
zhenyan121
2906106597 feat: water rendering (#13)
* refactor: update water texture

* feat(gameplay): implement transparent block rendering with depth sorting

* fix(world): use camera pos for distance calculations, make water passable

* refactor(player): use ivec3 for block pass check

* feat(camera): add underwater detection

* feat(renderer): add underwater effect with framebuffer post-processing

* feat(block): add gas property and refactor solid block check

* fix(assets): set leaf block transparency to false

* fix(block): set leaf as transparent
2026-05-30 15:11:40 +08:00
zhenyan121
a0139dd315 fix: msvc build fail (#12) 2026-05-28 21:55:44 +08:00
zhenyan121
5901ab7cd9 feat: grass (#11)
* feat: add grass texture and update grass_block texture

* feat: add block data

* feat: add blocks_tool

* feat: add sync info and change function in blocks_tools

* feat: add check and new function

* refactor: make block texture loading data-driven

* feat: add rendering for grass

* feat: passable grass

* feat: random grass place

* fix: memory leak in TextureManager::load_cross_plane_texture
2026-05-28 21:34:36 +08:00
zhenyan121
bbf8b4e969 refactor: river (#10)
* fix: correct snowy grass block texture

* refactor: river generation

* fix: water placement error due to interpolation

* perf: improve river naturalness

* feat: add river tab item

* fix: path truncation
2026-05-23 14:29:41 +08:00
zhenyan121
a54e87dbc6 refactor: terrain generation (#9)
* feat: add BlockType

* refactor: use fBM for heightmap generation

* feat: improve mountain realism

* refactor: adjust mountain spawn probability

* feat: add biome boundary blending

* refactor: remove resolve_biome_adjacency_conflict function

* feat: add snowy plain

* perf: speed up world generation

* refactor: lower overall terrain height
2026-05-23 10:33:52 +08:00
zhenyan121
1a26474a05 feat: add cave (#8)
* feat: add cave generate

* fix: incorrect blocks on cave surface

* fix: non-deterministic cave generator

* refactor: move all chunk generation to dedicated generation thread

* refactor: remove inital cave

* feat: add cave parameter adjustment

* refactor: adjust cave probability
2026-05-09 20:13:55 +08:00
zhenyan121
d986e03f9c fix: windows build fail (#7) 2026-05-03 19:45:14 +08:00
zhenyan121
9d200f31be refactor: chunk interpolate (#6)
* refactor: rewrite blend_heightmap_boundaries

* refactor: init_world

* fix: unnatural biome boundary transition
2026-05-03 16:02:01 +08:00
zhenyan121
a02bfad639 refactor: biome build (#5)
* refactor: rename Biome to BiomeType

* feat: add biome builder
2026-05-02 13:40:46 +08:00
zhenyan121
a63dfa7f47 feat: add river biome (#4)
* feat: add river biome

* fix: duplicate mountain terrain generation

* fix: safe_int_to_biome not include river
2026-05-01 19:18:46 +08:00
zhenyan121
d4d761b2aa Potential fix for code scanning alert no. 1: Workflow does not contain permissions (#3)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-04-30 12:08:12 +08:00
zhenyan121
315c60e4a6 feat: block switching (#2)
* feat: add item tab item in dev panel

* feat: add block switching via mouse wheel
2026-04-30 11:53:35 +08:00
zhenyan121
9a8e76d25f refactor: set forest base y to 62 (#1) 2026-04-28 21:58:35 +08:00
14c942333c ci: upgrade clang image tag to latest 2026-04-28 12:46:01 +08:00
b88bc30756 ci: add find in include directory 2026-04-28 12:13:10 +08:00
a526d37f97 ci: use Docker instead of directly installing clang-format 2026-04-28 12:06:55 +08:00
fb86836e19 ci: upgrade clang-format version in CI 2026-04-28 09:38:22 +08:00
f2f00ce658 ci: add automated code style checking 2026-04-28 09:33:07 +08:00
611a795481 chore: add clang-format and pre-commit configuration 2026-04-28 09:22:55 +08:00
dc3be5a4bc refactor: adjust mountain frequency 2026-04-27 15:26:49 +08:00
932c11a646 fix: chunk conflict resolution not taking effort 2026-04-27 09:30:45 +08:00
5b2f06b3ec feat: add about tab item 2026-04-26 21:14:13 +08:00
bd5665c935 fix: can't find iota 2026-04-26 17:34:11 +08:00
59ab47d317 feat: add anisotropic filtering control 2026-04-26 17:29:58 +08:00
e34a20599d feat: add tp in devpanel 2026-04-26 14:26:39 +08:00
c5a78185ba feat: add ChunkGenerator 2026-04-26 14:10:09 +08:00
a3eb19e58f feat: smooth biome block transition 2026-04-26 11:35:16 +08:00
9402847e89 feat: add biome parameter adjustment 2026-04-25 22:23:24 +08:00
a95ad796ce feat: add world and player tab item 2026-04-25 18:36:13 +08:00
8b5717a655 refactor: extract constants into separate constants.hpp file 2026-04-25 16:25:47 +08:00
055c4d687b fix: load path failure
Co-authored-by: Copilot <copilot@github.com>
2026-04-25 14:33:43 +08:00
4ca2133ff3 feat: add DevPanel 2026-04-25 14:24:50 +08:00
ada0603a2f build: enable Freetype support 2026-04-25 13:42:14 +08:00
dc3926e47f chore: add imgui library 2026-04-24 21:25:01 +08:00
3e27ab675c fix: fullscreen resolution error on Windows 2026-04-24 18:01:17 +08:00
106cc3d398 feat: add Config class 2026-04-24 17:08:06 +08:00
2409734e89 chore: add toml++ library 2026-04-24 10:21:26 +08:00
8f8e2c1bd5 chore: remove dead code 2026-04-23 21:09:03 +08:00
2707748843 refactor: increase BLEND_RADIUS to 12 2026-04-23 15:40:40 +08:00
e90b0ce2f4 refactor: chunk generation logic 2026-04-23 15:19:34 +08:00
c7a0aff0c1 chore: add .clangd configuration 2026-04-21 22:53:34 +08:00
c2321a0a6e refactor: warp everything in Cubed namespace 2026-04-20 22:18:02 +08:00
6c74f4582c docs: add build guide 2026-04-19 18:01:09 +08:00
553955841b fix: missing face culling for old chunks during generation 2026-04-19 17:49:08 +08:00
170 changed files with 69277 additions and 2215 deletions

321
.clang-format Normal file
View File

@@ -0,0 +1,321 @@
---
Language: Cpp
AlignAfterOpenBracket: true
AccessModifierOffset: -4
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: true
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
AlignPPAndNotPP: true
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowBreakBeforeNoexceptSpecifier: Never
AllowBreakBeforeQtProperty: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AllowShortNamespacesOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AttributeMacros:
- __capability
BinPackArguments: true
BinPackLongBracedList: true
BinPackParameters: BinPack
BitFieldColonSpacing: Both
BracedInitializerIndentWidth: -1
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterExternBlock: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterOpenBracketBracedList: false
BreakAfterOpenBracketFunction: false
BreakAfterOpenBracketIf: false
BreakAfterOpenBracketLoop: false
BreakAfterOpenBracketSwitch: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeCloseBracketBracedList: false
BreakBeforeCloseBracketFunction: false
BreakBeforeCloseBracketIf: false
BreakBeforeCloseBracketLoop: false
BreakBeforeCloseBracketSwitch: false
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Attach
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTemplateCloser: false
BreakBeforeTernaryOperators: true
BreakBinaryOperations: Never
BreakConstructorInitializers: BeforeColon
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
BreakTemplateDeclarations: MultiLine
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: AlignFirstComment
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
EnumTrailingComma: Leave
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigitsInsert: 0
BinaryMaxDigitsRemove: 0
Decimal: 0
DecimalMinDigitsInsert: 0
DecimalMaxDigitsRemove: 0
Hex: 0
HexMinDigitsInsert: 0
HexMaxDigitsRemove: 0
BinaryMinDigits: 0
DecimalMinDigits: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: true
AtStartOfFile: true
KeepFormFeed: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ''
MacroBlockEnd: ''
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
NumericLiteralCase:
ExponentLetter: Leave
HexDigit: Leave
Prefix: Leave
Suffix: Leave
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
OneLineFormatOffRegex: ''
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakBeforeMemberAccess: 150
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
PPIndentWidth: -1
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: Always
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes:
Enabled: true
IgnoreCase: false
IgnoreExtension: false
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterOperatorKeyword: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterNot: false
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBraces: Never
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TableGenBreakInsideDAGArg: DontBreak
TabWidth: 8
UseTab: Never
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
...

3
.clang-format-ignore Normal file
View File

@@ -0,0 +1,3 @@
third_party/
build/
vendor/

2
.clangd Normal file
View File

@@ -0,0 +1,2 @@
CompileFlags:
Add: [-Wall, -Wextra, -Wpedantic, -Wno-unused-parameter]

17
.github/workflows/format-check.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
# .github/workflows/format-check.yml
name: Code Format Check
on: [push, pull_request]
permissions:
contents: read
jobs:
formatting:
runs-on: ubuntu-latest
container: silkeh/clang:latest
steps:
- uses: actions/checkout@v4
- name: Run clang-format
run: |
find src include -name '*.cpp' -o -name '*.h' -print0 | xargs -0 clang-format --dry-run --Werror

4
.gitignore vendored
View File

@@ -39,4 +39,6 @@ CMakeError.log
*.swp *.swp
*.swo *.swo
*~ *~
.DS_Store .DS_Store
assets/config.toml
.venv/

8
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,8 @@
repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: "v22.1.4"
hooks:
- id: clang-format
args: ["--style=file"]
types_or: ["c++", "c"]
exclude: '^third_party/.*$'

1
.python-version Normal file
View File

@@ -0,0 +1 @@
3.14

View File

@@ -58,6 +58,21 @@ if (WIN32)
if(TARGET freetype) if(TARGET freetype)
add_library(Freetype::Freetype ALIAS freetype) add_library(Freetype::Freetype ALIAS freetype)
endif() endif()
set(_BUILD_SHARED_LIBS_SAVED ${BUILD_SHARED_LIBS})
set(BUILD_SHARED_LIBS ON)
FetchContent_Declare(
onetbb
GIT_REPOSITORY https://github.com/uxlfoundation/oneTBB.git
GIT_TAG v2023.0.0
)
set(BUILD_TESTING OFF CACHE BOOL "Build tests" FORCE)
set(TBB_TEST OFF CACHE BOOL "Build TBB tests" FORCE)
FetchContent_MakeAvailable(onetbb)
set(BUILD_SHARED_LIBS ${_BUILD_SHARED_LIBS_SAVED})
unset(_BUILD_SHARED_LIBS_SAVED)
endif() endif()
FetchContent_Declare( FetchContent_Declare(
@@ -74,6 +89,14 @@ FetchContent_Declare(
) )
FetchContent_MakeAvailable(soil2) FetchContent_MakeAvailable(soil2)
FetchContent_Declare(
tomlplusplus
GIT_REPOSITORY https://github.com/marzer/tomlplusplus.git
GIT_TAG v3.4.0
)
FetchContent_MakeAvailable(tomlplusplus)
add_subdirectory(third_party/imgui)
set(INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) set(INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
@@ -82,8 +105,11 @@ add_executable(${PROJECT_NAME}
src/app.cpp src/app.cpp
src/debug_collector.cpp src/debug_collector.cpp
src/camera.cpp src/camera.cpp
src/config.cpp
src/dev_panel.cpp
src/gameplay/biome.cpp src/gameplay/biome.cpp
src/gameplay/chunk.cpp src/gameplay/chunk.cpp
src/gameplay/chunk_generator.cpp
src/gameplay/player.cpp src/gameplay/player.cpp
src/gameplay/tree.cpp src/gameplay/tree.cpp
src/gameplay/world.cpp src/gameplay/world.cpp
@@ -96,24 +122,37 @@ add_executable(${PROJECT_NAME}
src/tools/math_tools.cpp src/tools/math_tools.cpp
src/tools/shader_tools.cpp src/tools/shader_tools.cpp
src/tools/font.cpp src/tools/font.cpp
src/tools/log.cpp
src/tools/perlin_noise.cpp src/tools/perlin_noise.cpp
src/ui/text.cpp src/ui/text.cpp
src/window.cpp src/window.cpp
src/gameplay/builders/biome_builder.cpp
src/gameplay/builders/plain_builder.cpp
src/gameplay/builders/mountain_builder.cpp
src/gameplay/builders/river_builder.cpp
src/gameplay/builders/desert_builder.cpp
src/gameplay/builders/forest_builder.cpp
src/gameplay/cave_carver.cpp
src/gameplay/cave_path.cpp
src/gameplay/builders/snowy_plain_builder.cpp
src/gameplay/river_worm.cpp
src/gameplay/river_path.cpp
src/block.cpp
src/gameplay/vertex_data.cpp
src/gameplay/builders/ocean_builder.cpp
) )
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "Building with AddressSanitizer enabled for target: ${PROJECT_NAME}") message(STATUS "Building with AddressSanitizer enabled for target: ${PROJECT_NAME}")
target_compile_options(${PROJECT_NAME} PRIVATE target_compile_options(${PROJECT_NAME} PRIVATE
-fsanitize=address #-fsanitize=address
#-fsanitize=thread #-fsanitize=thread
-fno-omit-frame-pointer -fno-omit-frame-pointer
-g -g
) )
target_link_options(${PROJECT_NAME} PRIVATE target_link_options(${PROJECT_NAME} PRIVATE
-fsanitize=address #-fsanitize=address
#-fsanitize=thread #-fsanitize=thread
) )
@@ -137,10 +176,13 @@ target_link_libraries(${PROJECT_NAME}
OpenGL::GL OpenGL::GL
soil2 soil2
Freetype::Freetype Freetype::Freetype
tomlplusplus::tomlplusplus
imgui
tbb
) )
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
target_link_libraries(${PROJECT_NAME} PRIVATE tbb) # target_link_libraries(${PROJECT_NAME} PRIVATE tbb)
endif() endif()
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
@@ -160,3 +202,19 @@ if (UNIX AND NOT APPLE)
target_compile_options(${PROJECT_NAME} PRIVATE ${EGL_CFLAGS_OTHER} ${Wayland_CFLAGS_OTHER}) target_compile_options(${PROJECT_NAME} PRIVATE ${EGL_CFLAGS_OTHER} ${Wayland_CFLAGS_OTHER})
endif() endif()
if (WIN32)
foreach(TBB_LIB IN ITEMS tbb tbbmalloc tbbmalloc_proxy)
if(TARGET ${TBB_LIB})
add_custom_command(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:${TBB_LIB}>
$<TARGET_FILE_DIR:${PROJECT_NAME}>
COMMENT "Copying ${TBB_LIB}.dll"
)
else()
message(STATUS "Target ${TBB_LIB} not found, skipping copy")
endif()
endforeach()
endif()

View File

@@ -1,2 +1,21 @@
## What's it ## What's it
A cube game like Minecraft, using C++ and OpenGL. A cube game like Minecraft, using C++ and OpenGL.
## Build Guide
### Prerequisites
- **CMake** (>= 3.24)
- **C++ 23** compatible compiler
### Step
1. Clone the repository
```bash
git clone https://github.com/zhenyan121/Cubed.git && cd Cubed
```
2. Configure with CMake
```bash
mkdir build && cd build
cmake -G "Ninja" ..
```
3. Build the project
```bash
ninja
```

View File

@@ -0,0 +1,10 @@
id = 0
is_blend = false
is_cross_plane = false
is_discard = true
is_gas = true
is_liquid = false
is_passable = true
is_transitional = false
is_transparent = true
name = 'air'

View File

@@ -0,0 +1,10 @@
id = 2
is_blend = false
is_cross_plane = false
is_discard = false
is_gas = false
is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'dirt'

View File

@@ -0,0 +1,10 @@
id = 9
is_blend = false
is_cross_plane = true
is_discard = true
is_gas = false
is_liquid = false
is_passable = true
is_transitional = false
is_transparent = true
name = 'grass'

View File

@@ -0,0 +1,10 @@
id = 1
is_blend = false
is_cross_plane = false
is_discard = false
is_gas = false
is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'grass_block'

View File

@@ -0,0 +1,10 @@
id = 6
is_blend = false
is_cross_plane = false
is_discard = true
is_gas = false
is_liquid = false
is_passable = false
is_transitional = false
is_transparent = true
name = 'leaf'

View File

@@ -0,0 +1,10 @@
id = 5
is_blend = false
is_cross_plane = false
is_discard = false
is_gas = false
is_liquid = false
is_passable = false
is_transitional = false
is_transparent = false
name = 'log'

View File

@@ -0,0 +1,10 @@
id = 4
is_blend = false
is_cross_plane = false
is_discard = false
is_gas = false
is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'sand'

View File

@@ -0,0 +1,10 @@
id = 8
is_blend = false
is_cross_plane = false
is_discard = false
is_gas = false
is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'snowy_grass_block'

View File

@@ -0,0 +1,10 @@
id = 3
is_blend = false
is_cross_plane = false
is_discard = false
is_gas = false
is_liquid = false
is_passable = false
is_transitional = true
is_transparent = false
name = 'stone'

View File

@@ -0,0 +1,10 @@
name = "template"
id = 0
is_liquid = false
is_gas = false
is_passable = false
is_cross_plane = false
is_transparent = false
is_discard = false
is_blend = false
is_transitional = false

View File

@@ -0,0 +1,10 @@
id = 7
is_blend = true
is_cross_plane = false
is_discard = false
is_gas = false
is_liquid = true
is_passable = true
is_transitional = false
is_transparent = true
name = 'water'

View File

@@ -0,0 +1,28 @@
#version 460
layout (location = 0) out vec4 accum;
layout (location = 1) out float reveal;
in vec2 tc;
flat in int tex_layer;
in float v_depth;
layout (binding = 0) uniform sampler2DArray samp;
float weight(float z, float a) {
float intermediate = 0.03 / (1e-5 + pow(z / 200.0, 4.0));
return a * clamp(intermediate, 1e-2, 3e2);
}
void main() {
vec4 color = texture(samp, vec3(tc, tex_layer));
float alpha = color.a;
if (alpha < 1e-4) discard;
float w = weight(v_depth, alpha);
accum = vec4(color.rgb * alpha * w, alpha * w);
reveal = alpha;
}

View File

@@ -0,0 +1,21 @@
#version 460
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in float layer;
out vec2 tc;
flat out int tex_layer;
out float v_depth;
uniform mat4 mv_matrix;
uniform mat4 proj_matrix;
void main(void) {
vec4 view_pos = mv_matrix * vec4(pos, 1.0);
gl_Position = proj_matrix * view_pos;
tc = texCoord;
tex_layer = int(layer);
v_depth = -view_pos.z;
}

View File

@@ -0,0 +1,19 @@
#version 460
uniform sampler2D u_accumTex;
uniform sampler2D u_revealTex;
in vec2 TexCoord;
out vec4 FragColor;
void main() {
vec4 a = texture(u_accumTex, TexCoord);
float r = texture(u_revealTex, TexCoord).r;
if (a.a < 1e-4) discard;
vec3 color = a.rgb / max(a.a, 1e-5);
float transmittance = r;
float opacity = 1.0 - transmittance;
FragColor = vec4(color * opacity, opacity);
}

View File

@@ -0,0 +1,11 @@
#version 460
layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 texCoord;
out vec2 TexCoord;
void main() {
gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
TexCoord = texCoord;
}

View File

@@ -1,15 +1,125 @@
#version 460 #version 460
in vec2 tc; in vec2 tc;
in vec3 normal;
in vec3 vert_pos;
in vec4 FragPosLightSpace;
flat in int tex_layer; flat in int tex_layer;
out vec4 color; out vec4 color;
layout (binding = 0) uniform sampler2D shadowMap;
layout (binding = 1) uniform sampler2DArray samp;
uniform float ambientStrength;
uniform vec3 sunlightColor;
uniform vec3 sunlightDir;
uniform bool shader_on;
uniform int shadowMode;
const vec2 poissonDisk[8] = vec2[](
vec2( 0.1440, 0.7659), vec2(-0.5761, 0.4479),
vec2(-0.3220, -0.6058), vec2( 0.5693, -0.4048),
vec2(-0.1276, 0.1657), vec2(-0.0649, -0.0165),
vec2( 0.2773, -0.0305), vec2(-0.1134, -0.2122)
);
float random(vec3 seed) {
return fract(sin(dot(seed, vec3(12.9898,78.233,45.5432))) * 43758.5453);
}
float ShadowCalculation(vec4 fragPosLightSpace, vec3 norm, vec3 lightDir)
{
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
projCoords = projCoords * 0.5 + 0.5;
if (projCoords.x < 0.0 || projCoords.x > 1.0 ||
projCoords.y < 0.0 || projCoords.y > 1.0 ||
projCoords.z < 0.0 || projCoords.z > 1.0) {
return 0.0;
}
float currentDepth = projCoords.z;
vec2 texelSize = 1.0 / vec2(textureSize(shadowMap, 0));
float shadow = 0.0;
float bias =
max(
0.0003,
0.001 * (1.0 - dot(norm, lightDir))
);
if (shadowMode == 0) {
vec3 seed = vert_pos * 37.0 + sin(vert_pos * 91.7) * 13.0;
float angle = random(seed) * 6.2831853;; // 2*PI
float s = sin(angle), c = cos(angle);
mat2 rot = mat2(c, -s, s, c);
float radius = 0.7;
const int samples = 8;
for (int i = 0; i < samples; ++i) {
vec2 offset = rot * poissonDisk[i] * radius * texelSize;
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
}
shadow /= float(samples);
} else if (shadowMode == 1) {
for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
vec2 offset = vec2(x, y) * texelSize;
float pcfDepth = texture(shadowMap, projCoords.xy + offset).r;
shadow += (currentDepth - bias > pcfDepth ? 1.0 : 0.0);
}
}
shadow /= 9.0;
} else if (shadowMode == 2) {
// pcf off
float pcfDepth =
texture(shadowMap, projCoords.xy).r;
shadow =
currentDepth - bias > pcfDepth
? 1.0
: 0.0;
} else {
float pcfDepth =
texture(shadowMap, projCoords.xy).r;
shadow =
currentDepth - bias > pcfDepth
? 1.0
: 0.0;
}
return shadow;
}
layout (binding = 0) uniform sampler2DArray samp;
void main(void) { void main(void) {
color = texture(samp, vec3(tc, tex_layer)); vec4 objectColor = texture(samp, vec3(tc, tex_layer));
if (color.a < 0.5) {
if (objectColor.a < 0.8) {
discard; discard;
} }
if (!shader_on) {
color = objectColor;
return;
}
vec3 lightDir = normalize(-sunlightDir);
vec3 ambient = ambientStrength * sunlightColor;
vec3 norm = normalize(normal);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * sunlightColor;
float shadow = ShadowCalculation(FragPosLightSpace, norm, lightDir);
color = vec4((ambient + (1.0 - shadow) * (diffuse)) * objectColor.rgb, objectColor.a);
//color = varyingColor; //color = varyingColor;
} }

View File

@@ -3,8 +3,12 @@
layout (location = 0) in vec3 pos; layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord; layout (location = 1) in vec2 texCoord;
layout (location = 2) in float layer; layout (location = 2) in float layer;
layout (location = 3) in vec3 aNormal;
out vec2 tc; out vec2 tc;
out vec3 normal;
out vec3 vert_pos;
flat out int tex_layer; flat out int tex_layer;
out vec4 FragPosLightSpace;
mat4 buildRotateX(float rad); mat4 buildRotateX(float rad);
mat4 buildRotateY(float rad); mat4 buildRotateY(float rad);
@@ -13,13 +17,21 @@ mat4 buildTranslate(float x, float y, float z);
uniform mat4 mv_matrix; uniform mat4 mv_matrix;
uniform mat4 proj_matrix; uniform mat4 proj_matrix;
uniform mat4 norm_matrix;
uniform mat4 lightSpaceMatrix;
void main(void) { void main(void) {
gl_Position = proj_matrix * mv_matrix * vec4(pos, 1.0); vec4 viewPos = mv_matrix * vec4(pos, 1.0);
vert_pos = pos;
tc = texCoord; tc = texCoord;
tex_layer = int(layer); tex_layer = int(layer);
normal = mat3(norm_matrix) * aNormal;
FragPosLightSpace = lightSpaceMatrix * vec4(pos, 1.0);
gl_Position = proj_matrix * viewPos;
} }
mat4 buildTranslate(float x, float y, float z) { mat4 buildTranslate(float x, float y, float z) {

View File

@@ -0,0 +1,16 @@
#version 460
in vec2 tc;
flat in int tex_layer;
layout (binding = 1) uniform sampler2DArray samp;
uniform bool is_discard_tranparent;
void main() {
if (is_discard_tranparent) {
vec4 texColor = texture(samp, vec3(tc, tex_layer));
if (texColor.a < 0.8)
discard;
}
//gl_FragDepth = gl_FragCoord.z;
}

View File

@@ -0,0 +1,12 @@
#version 460
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in float layer;
uniform mat4 lightSpaceMatrix;
out vec2 tc;
flat out int tex_layer;
void main() {
tc = texCoord;
tex_layer = int(layer);
gl_Position = lightSpaceMatrix * vec4(pos, 1.0);
}

View File

@@ -2,8 +2,10 @@
out vec4 frag_color; out vec4 frag_color;
uniform vec3 color;
void main(void) { void main(void) {
frag_color = vec4(0.529, 0.808, 0.922, 1.0); frag_color = vec4(color, 1.0);
} }

View File

@@ -0,0 +1,35 @@
#version 460
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D u_sceneTexture;
uniform float u_time;
uniform bool u_underwater;
uniform vec3 u_waterColor;
uniform float u_fogDensity;
void main() {
vec4 original = texture(u_sceneTexture, TexCoord);
if (!u_underwater) {
FragColor = original;
return;
}
vec2 distoredUV = TexCoord;
float strength = 0.003;
distoredUV.x += sin(TexCoord.y * 15.0 + u_time * 5.0) * strength;
distoredUV.y += cos(TexCoord.x * 15.0 + u_time * 4.3) * strength;
distoredUV = clamp(distoredUV, 0.001, 0.999);
vec4 distorted = texture(u_sceneTexture, distoredUV);
float caustic = 0.9 + 0.1 * sin(TexCoord.x * 20.0 + u_time) * cos(TexCoord.y * 20.0 + u_time * 1.2);
vec3 causticLight = vec3(caustic, caustic * 0.95, caustic * 0.9);
//vec3 causticLight = vec3(1.0);
float fogFactor = clamp(1.0 - (TexCoord.y * u_fogDensity * 10.0), 0.0, 1.0);
vec3 mixed = mix(u_waterColor, distorted.rgb * causticLight, fogFactor);
FragColor = vec4(mixed, 1.0);
}

View File

@@ -0,0 +1,11 @@
#version 460
layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 texCoord;
out vec2 TexCoord;
void main() {
gl_Position = vec4(pos.x, pos.y, 0.0, 1.0);
TexCoord = texCoord;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 563 B

After

Width:  |  Height:  |  Size: 555 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 399 B

After

Width:  |  Height:  |  Size: 381 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 882 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 499 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 890 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

View File

@@ -1,19 +1,20 @@
#pragma once #pragma once
#include <glm/glm.hpp> #include <glm/glm.hpp>
namespace Cubed {
struct AABB { struct AABB {
glm::vec3 min{0.0f, 0.0f, 0.0f}; glm::vec3 min{0.0f, 0.0f, 0.0f};
glm::vec3 max{0.0f, 0.0f, 0.0f}; glm::vec3 max{0.0f, 0.0f, 0.0f};
AABB(glm::vec3 min_point, glm::vec3 max_point): AABB(glm::vec3 min_point, glm::vec3 max_point)
min(min_point), : min(min_point), max(max_point) {}
max(max_point)
{
}
bool intersects(const AABB& other) const { bool intersects(const AABB& other) const {
return (min.x <= other.max.x && max.x >= other.min.x) && return (min.x <= other.max.x && max.x >= other.min.x) &&
(min.y <= other.max.y && max.y >= other.min.y) && (min.y <= other.max.y && max.y >= other.min.y) &&
(min.z <= other.max.z && max.z >= other.min.z); (min.z <= other.max.z && max.z >= other.min.z);
} }
}; };
} // namespace Cubed

View File

@@ -1,52 +1,68 @@
#pragma once #pragma once
#define GLFW_INCLUDE_NONE
#include <Cubed/camera.hpp> #include "Cubed/camera.hpp"
#include <Cubed/gameplay/world.hpp> #include "Cubed/dev_panel.hpp"
#include <Cubed/input.hpp> #include "Cubed/gameplay/world.hpp"
#include <Cubed/renderer.hpp> #include "Cubed/renderer.hpp"
#include <Cubed/texture_manager.hpp> #include "Cubed/texture_manager.hpp"
#include <Cubed/window.hpp> #include "Cubed/window.hpp"
namespace Cubed { namespace Cubed {
class App { class App {
public: public:
App(); App();
~App(); ~App();
static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos); static void cursor_position_callback(GLFWwindow* window, double xpos,
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods); double ypos);
static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods); static void key_callback(GLFWwindow* window, int key, int scancode,
int action, int mods);
static void mouse_button_callback(GLFWwindow* window, int button,
int action, int mods);
static void window_focus_callback(GLFWwindow* window, int focused); static void window_focus_callback(GLFWwindow* window, int focused);
static void window_reshape_callback(GLFWwindow* window, int new_width, int new_height); static void window_reshape_callback(GLFWwindow* window, int new_width,
static void mouse_scroll_callback(GLFWwindow* window, double xoffset, double yoffset); int new_height);
static void mouse_scroll_callback(GLFWwindow* window, double xoffset,
double yoffset);
static void cursor_enter_callback(GLFWwindow* window, int entered);
static void char_callback(GLFWwindow* window, unsigned int ch);
static int start_cubed_application(int argc, char** argv); static int start_cubed_application(int argc, char** argv);
static unsigned int seed(); static unsigned int seed();
static float delte_time(); static float delte_time();
static float get_fps(); static float get_fps();
Camera& camera();
DevPanel& dev_panel();
Renderer& renderer();
TextureManager& texture_manager();
Window& window();
World& world();
private: private:
Camera m_camera; Camera m_camera;
TextureManager m_texture_manager; TextureManager m_texture_manager;
World m_world; World m_world;
Renderer m_renderer{m_camera, m_world, m_texture_manager}; DevPanel m_dev_panel{*this};
Renderer m_renderer{m_camera, m_world, m_texture_manager, m_dev_panel};
Window m_window{m_renderer}; Window m_window{m_renderer};
inline static double last_time = glfwGetTime(); inline static double last_time = glfwGetTime();
inline static double current_time = glfwGetTime(); inline static double current_time = glfwGetTime();
inline static double delta_time = 0.0f; inline static double delta_time = 0.0f;
inline static double fps_time_count = 0.0f; inline static double fps_time_count = 0.0f;
inline static int frame_count = 0; inline static int frame_count = 0;
inline static int fps = 0; inline static int fps = 0;
void init(); void init();
auto init_camera(); auto init_camera();
auto init_texture(); auto init_texture();
auto init_world(); auto init_world();
void render(); void render();
void run(); void run();
void update(); void update();
}; };
} } // namespace Cubed

View File

@@ -1,35 +1,38 @@
#pragma once #pragma once
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <glad/glad.h>
#include <GLFW/glfw3.h> namespace Cubed {
class Player; class Player;
class Camera { class Camera {
private: private:
bool m_firse_mouse = true; bool m_firse_mouse = true;
Player* m_player; Player* m_player;
float m_last_mouse_x, m_last_mouse_y; float m_last_mouse_x, m_last_mouse_y;
glm::vec3 m_camera_pos; glm::vec3 m_camera_pos;
bool m_under_water = false;
public: public:
Camera(); Camera();
void update_move_camera(); void update_move_camera();
void camera_init(Player* player); void camera_init(Player* player);
void hot_reload();
void reset_camera(); void reset_camera();
void update_cursor_position_camera(double xpos, double ypos); void update_cursor_position_camera(double xpos, double ypos);
const glm::mat4 get_camera_lookat() const; const glm::mat4 get_camera_lookat() const;
const glm::vec3& get_camera_pos() const; const glm::vec3& get_camera_pos() const;
bool is_under_water() const;
glm::vec3 get_camera_front() const;
}; };
} // namespace Cubed

View File

@@ -1,150 +1,107 @@
#pragma once #pragma once
constexpr int WORLD_SIZE_Y = 256; #include "Cubed/tools/cubed_assert.hpp"
constexpr int MAX_BLOCK_NUM = 7;
constexpr int MAX_UI_NUM = 1;
constexpr int CHUCK_SIZE = 16; #include <toml++/toml.hpp>
constexpr int DISTANCE = 24;
constexpr int MAX_BLOCK_STATUS = 1;
constexpr int MAX_CHARACTER = 128;
constexpr float NORMAL_FOV = 70.0f;
constexpr int MAX_BIOME_SUM = 4; namespace Cubed {
constexpr float VERTICES_POS[6][6][3] = { template <typename T>
// ===== front (z = +1) ===== concept TomlValueType =
0.0f, 0.0f, 1.0f, // bottom left std::same_as<T, int> || std::same_as<T, bool> || std::same_as<T, double> ||
0.0f, 1.0f, 1.0f, // top left std::same_as<T, const char*> || std::same_as<T, toml::date> ||
1.0f, 1.0f, 1.0f, // top right std::same_as<T, toml::time> || std::same_as<T, toml::date_time> ||
1.0f, 1.0f, 1.0f, // top right std::same_as<T, std::string>;
1.0f, 0.0f, 1.0f, // bottom right
0.0f, 0.0f, 1.0f, // bottom left
// ===== right (x = +1) =====
1.0f, 0.0f, 1.0f, // bottom front
1.0f, 0.0f, 0.0f, // bottom back
1.0f, 1.0f, 0.0f, // top back
1.0f, 1.0f, 0.0f, // top back
1.0f, 1.0f, 1.0f, // top front
1.0f, 0.0f, 1.0f, // bottom front
// ===== back (z = -1) =====
0.0f, 0.0f, 0.0f, // bottom left
1.0f, 0.0f, 0.0f, // bottom right
1.0f, 1.0f, 0.0f, // top right
1.0f, 1.0f, 0.0f, // top right
0.0f, 1.0f, 0.0f, // top left
0.0f, 0.0f, 0.0f, // bottom left
// ===== left (x = -1) =====
0.0f, 0.0f, 0.0f, // bottom back
0.0f, 0.0f, 1.0f, // bottom front
0.0f, 1.0f, 1.0f, // top front
0.0f, 1.0f, 1.0f, // top front
0.0f, 1.0f, 0.0f, // top back
0.0f, 0.0f, 0.0f, // bottom back
// ===== top (y = +1) =====
0.0f, 1.0f, 0.0f, // back left
1.0f, 1.0f, 0.0f, // back right
1.0f, 1.0f, 1.0f, // front right
1.0f, 1.0f, 1.0f, // front right
0.0f, 1.0f, 1.0f, // front left
0.0f, 1.0f, 0.0f, // back left
// ===== bottom (y = -1) =====
0.0f, 0.0f, 1.0f, // front left
1.0f, 0.0f, 1.0f, // front right
1.0f, 0.0f, 0.0f, // back right
1.0f, 0.0f, 0.0f, // back right
0.0f, 0.0f, 0.0f, // back left
0.0f, 0.0f, 1.0f // front left
};
constexpr float TEX_COORDS[6][6][2] = { class Config {
// ===== front (z = +1) ===== public:
0.0f, 1.0f, // bottom left Config();
0.0f, 0.0f, // top left ~Config();
1.0f, 0.0f, // top right
1.0f, 0.0f, // top right static Config& get();
1.0f, 1.0f, // bottom right
0.0f, 1.0f, // bottom left toml::table& table();
// ===== right (x = +1) =====
0.0f, 1.0f, // bottom front void load_or_create_config();
1.0f, 1.0f, // bottom back void save_to_file();
1.0f, 0.0f, // top back
1.0f, 0.0f, // top back template <TomlValueType T> T get(std::string_view key) const {
0.0f, 0.0f, // top front size_t cur = 0;
0.0f, 1.0f, // bottom front auto pos = key.find('.');
// ===== back (z = -1) ===== const toml::table* table = &m_tbl;
1.0f, 1.0f, // bottom left while (pos != std::string_view::npos) {
0.0f, 1.0f, // bottom right std::string_view s = key.substr(cur, pos - cur);
0.0f, 0.0f, // top right if (s.empty()) {
0.0f, 0.0f, // top right Logger::error("Empty key/table name in path '{}'", key);
1.0f, 0.0f, // top left ASSERT(false);
1.0f, 1.0f, // bottom left std::abort();
// ===== left (x = -1) ===== }
1.0f, 1.0f, // bottom back cur = pos + 1;
0.0f, 1.0f, // bottom front pos = key.find('.', cur);
0.0f, 0.0f, // top front if (auto* next = (*table)[s].as_table()) {
0.0f, 0.0f, // top front table = next;
1.0f, 0.0f, // top back } else {
1.0f, 1.0f, // bottom back Logger::error("Can't find table {}", s);
// ===== top (y = +1) ===== ASSERT(false);
0.0f, 0.0f, // back left std::abort();
1.0f, 0.0f, // back right }
1.0f, 1.0f, // front right }
1.0f, 1.0f, // front right std::string_view n_key = key.substr(cur);
0.0f, 1.0f, // front left if (n_key.empty()) {
0.0f, 0.0f, // back left Logger::error("Trailing dot in path '{}'", key);
// ===== bottom (y = -1) ===== ASSERT(false);
0.0f, 0.0f, // front left std::abort();
1.0f, 0.0f, // front right }
1.0f, 1.0f, // back right auto opt = (*table)[n_key].value<T>();
1.0f, 1.0f, // back right if (opt) {
0.0f, 1.0f, // back left return *opt;
0.0f, 0.0f, // front left } else {
Logger::error("Can't find key {}", n_key);
ASSERT(false);
std::abort();
}
}
template <typename T> void set(std::string_view key, T&& val) {
if constexpr (!TomlValueType<std::decay_t<T>>) {
static_assert(false, "Type Not Support");
}
size_t cur = 0;
auto pos = key.find('.');
toml::table* table = &m_tbl;
while (pos != std::string_view::npos) {
std::string_view s = key.substr(cur, pos - cur);
if (s.empty()) {
Logger::error("Empty key/table name in path '{}'", key);
ASSERT(false);
std::abort();
}
cur = pos + 1;
pos = key.find('.', cur);
if (auto* next = (*table)[s].as_table()) {
table = next;
} else {
auto [it, inserted] = table->insert_or_assign(s, toml::table{});
table = it->second.as_table();
}
}
std::string_view n_key = key.substr(cur);
if (n_key.empty()) {
Logger::error("Trailing dot in path '{}'", key);
ASSERT(false);
std::abort();
}
table->insert_or_assign(n_key, std::forward<T>(val));
}
template <typename T> void set_and_save(std::string_view key, T&& val) {
set(key, std::forward(val));
save_to_file();
}
toml::node_view<toml::node> val_view(std::string_view key);
private:
toml::table m_tbl;
constexpr static inline std::string_view CONGIF_PATH =
ASSETS_PATH "config.toml";
void create_config();
}; };
constexpr float CUBE_VER[24] = { } // namespace Cubed
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
1.0, 1.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0,
1.0, 1.0, 1.0,
0.0, 1.0, 1.0
};
constexpr int OUTLINE_CUBE_INDICES[24] = {
0,1, 1,2, 2,3, 3,0,
4,5, 5,6, 6,7, 7,4,
0,4, 1,5, 2,6, 3,7
};
constexpr float SQUARE_VERTICES[6][2] = {
-0.5f, -0.5f, // bottom left
-0.5f, 0.5f, // top left
0.5f, 0.5f, // top right
0.5f, 0.5f, // top right
0.5f, -0.5f, // bottom right
-0.5f, -0.5f // bottom left
};
constexpr float SQUARE_TEXTURE_POS[6][2] = {
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
};
struct Vertex {
float x = 0.0f, y = 0.0f, z = 0.0f;
float s = 0.0f, t = 0.0f;
float layer = 0.0f;
};
struct Vertex2D {
float x = 0.0f, y = 0.0f;
float s = 0.0f, t = 0.0f;
float layer = 0.0f;
};

View File

@@ -0,0 +1,35 @@
#pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include <array>
namespace Cubed {
constexpr int WORLD_SIZE_Y = 256;
constexpr int CHUNK_SIZE = 16;
constexpr int SEA_LEVEL = 63;
constexpr int MAX_UI_NUM = 1;
constexpr int MAX_BLOCK_STATUS = 1;
constexpr int MAX_BIOME_SUM = 4;
constexpr int MAX_CHARACTER = 128;
constexpr int PRE_LOAD_DISTANCE = 24;
constexpr int MAX_DISTANCE = 128;
constexpr int CROSS_PLANE_DISTANCE = 8;
constexpr float DEFAULT_FOV = 70.0f;
constexpr float DEFAULT_MAX_WALK_SPEED = 4.5f;
constexpr float DEFAULT_MAX_RUN_SPEED = 7.0f;
constexpr float DEFAULT_ACCELERATION = 10.0f;
constexpr float DEFAULT_DECELERATION = 15.0f;
constexpr float DEFAULT_G = 22.5f;
constexpr int SIZE_X = CHUNK_SIZE;
constexpr int SIZE_Y = WORLD_SIZE_Y;
constexpr int SIZE_Z = CHUNK_SIZE;
constexpr ChunkPos CHUNK_DIR[]{{1, 0}, {-1, 0}, {0, 1}, {0, -1},
{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
using HeightMapArray = std::array<std::array<int, CHUNK_SIZE>, CHUNK_SIZE>;
} // namespace Cubed

View File

@@ -1,14 +1,16 @@
#pragma once #pragma once
#include <Cubed/ui/text.hpp> #include "Cubed/ui/text.hpp"
#include <unordered_map> #include <unordered_map>
namespace Cubed {
class DebugCollector { class DebugCollector {
public: public:
static DebugCollector& get(); static DebugCollector& get();
DebugCollector(); DebugCollector();
std::unordered_map<std::size_t, Text>& all_texts(); std::unordered_map<std::size_t, Text>& all_texts();
Text& text(std::string_view name); Text& text(std::string_view name);
@@ -17,4 +19,6 @@ public:
private: private:
std::unordered_map<std::size_t, Text> m_texts; std::unordered_map<std::size_t, Text> m_texts;
}; };
} // namespace Cubed

View File

@@ -0,0 +1,65 @@
#pragma once
#include <toml++/toml.hpp>
namespace Cubed {
class App;
class Player;
class DevPanel {
struct ConfigView {
float fov = 70.0f;
bool fullscreen = false;
bool v_sync = true;
float mouse_sensitivity = 0.15f;
int width = 800;
int height = 600;
int rendering_distance = 24;
int aniso = 1;
int max_aniso = 1;
bool is_enable_aniso = false;
bool is_support_aniso = true;
bool is_reload = true;
};
struct PlayerProfile {
int game_mode = 0;
int gait = 0;
float pos[3] = {0.0f, 0.0f, 0.0f};
};
struct TextEditing {
bool perlin_seed = false;
};
public:
DevPanel(App& app);
void init();
void render();
private:
App& m_app;
ConfigView m_config;
Player* m_player;
PlayerProfile m_player_profile;
TextEditing m_text_editing;
bool m_need_save_config = false;
bool m_gen_thread_running = true;
int m_theme = 0;
int m_pre_set_day_tick = 0;
int m_pre_set_tick_speed = 1;
bool m_tick_frezze = false;
void show_about_table_bar();
void show_biome_table_bar();
void show_time_table_bar();
void show_cave_table_bar();
void show_river_table_bar();
void show_settings_tab_item();
void show_world_tab_item();
void show_player_tab_item();
void show_items_tab_item();
void show_shader_tab_item();
void update_config_view();
void update_player_profile();
};
} // namespace Cubed

View File

@@ -1,19 +1,28 @@
#pragma once #pragma once
#include <array> #include <array>
#include <string> #include <string>
#include <vector>
constexpr float BIOME_NOISE_FREQUENCY = 0.003f; namespace Cubed {
constexpr float PLAIN_FREQ = 0.4f; constexpr float BIOME_NOISE_FREQUENCY = 0.06f;
constexpr float FOREST_FREQ = 1.2f; constexpr float HEIGHTMAP_NOISE_FREQUENCY = 0.001f;
constexpr float DESERT_FREQ = 1.2f; constexpr float MOUNTAINOUS_NOISE_FREQUENCY = 0.003f;
constexpr float MOUNTAIN_FREQ = 2.0f; enum class BiomeType {
enum class Biome {
PLAIN = 0, PLAIN = 0,
FOREST, FOREST,
DESERT, DESERT,
MOUNTAIN MOUNTAIN,
RIVER,
SNOWY_PLAIN,
OCEAN,
NONE
};
struct BiomeConditions {
float temp = 0.0f;
float humid = 0.0f;
float mountainous = 0.0f;
}; };
struct BiomeHeightRange { struct BiomeHeightRange {
@@ -21,10 +30,51 @@ struct BiomeHeightRange {
int amplitude; int amplitude;
}; };
std::string get_biome_str(Biome biome); struct BiomeNonAdjacent {
Biome get_biome_from_noise(float temp, float humid); BiomeType first;
std::array<float, 3> get_noise_frequencies_for_biome(Biome biome); std::vector<BiomeType> second;
BiomeHeightRange get_biome_height_range(Biome biome); BiomeType replace;
Biome safe_int_to_biome(int x); };
int get_interpolated_height(float world_x, float world_z, float temp, float humid);
static inline const std::vector<BiomeNonAdjacent> NON_ADJACENT{
{{BiomeType::PLAIN, {BiomeType::DESERT}, BiomeType::RIVER},
{BiomeType::FOREST, {BiomeType::DESERT}, BiomeType::RIVER},
{BiomeType::DESERT, {BiomeType::FOREST}, BiomeType::RIVER},
{BiomeType::MOUNTAIN, {BiomeType::NONE}, BiomeType::RIVER}}};
struct BaseBiomeParams {
BiomeType biome;
std::pair<float, float> temp;
std::pair<float, float> humid;
std::array<float, 3> frequencies;
BiomeHeightRange height_range;
};
struct PlainParams : public BaseBiomeParams {};
struct ForestParams : public BaseBiomeParams {
float tree_frequency;
};
struct DesertParams : public BaseBiomeParams {};
struct MountainParams : public BaseBiomeParams {};
struct RiverParams : public BaseBiomeParams {};
std::string get_biome_str(BiomeType biome);
// std::array<float, 3> get_noise_frequencies_for_biome(BiomeType biome);
// BiomeHeightRange get_biome_height_range(BiomeType biome);
BiomeType safe_int_to_biome(int x);
int get_interpolated_height(float world_x, float world_z, float temp,
float humid);
BiomeType determine_biome(const BiomeConditions& conditions);
PlainParams& plain_params();
ForestParams& forest_params();
DesertParams& desert_params();
MountainParams& mountain_params();
RiverParams& river_params();
} // namespace Cubed

View File

@@ -1,21 +1,21 @@
#pragma once #pragma once
#include <glad/glad.h> #include <glad/glad.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <array>
#include <string> #include <string>
#include <vector> #include <vector>
#include <Cubed/config.hpp> namespace Cubed {
#include <Cubed/tools/cubed_assert.hpp>
using BlockType = uint8_t;
struct BlockTexture { struct BlockTexture {
std::string name; std::string name;
unsigned id; unsigned id;
std::vector<GLuint> texture; std::vector<GLuint> texture;
}; };
struct Block : public BlockTexture{ struct Block : public BlockTexture {};
};
struct BlockRenderData { struct BlockRenderData {
std::vector<bool> draw_face; std::vector<bool> draw_face;
@@ -23,12 +23,8 @@ struct BlockRenderData {
BlockRenderData() = default; BlockRenderData() = default;
BlockRenderData(const BlockRenderData&) = default; BlockRenderData(const BlockRenderData&) = default;
BlockRenderData& operator=(const BlockRenderData&) = default; BlockRenderData& operator=(const BlockRenderData&) = default;
BlockRenderData(BlockRenderData&& data) : BlockRenderData(BlockRenderData&& data)
draw_face(std::move(data.draw_face)), : draw_face(std::move(data.draw_face)), block_id(data.block_id) {}
block_id(data.block_id)
{
}
BlockRenderData& operator=(BlockRenderData&& data) { BlockRenderData& operator=(BlockRenderData&& data) {
draw_face = std::move(data.draw_face); draw_face = std::move(data.draw_face);
block_id = data.block_id; block_id = data.block_id;
@@ -41,27 +37,55 @@ struct LookBlock {
glm::ivec3 normal; glm::ivec3 normal;
}; };
constexpr std::array<std::string_view, MAX_BLOCK_NUM> BLOCK_REISTER{ struct BlockData {
"air", std::string name;
"grass_block", BlockType id = 0;
"dirt",
"stone", bool is_liquid = false;
"sand", bool is_gas = false;
"log",
"leaf" bool is_passable = false;
bool is_cross_plane = false;
bool is_transparent = false;
bool is_discard = false;
bool is_blend = false;
bool is_transitional = false;
BlockData(BlockType b_id, std::string_view b_name, bool liquid,
bool passable, bool cross_plane, bool transparent, bool gas,
bool discard, bool blend, bool transitional)
: name(b_name), id(b_id), is_liquid(liquid), is_gas(gas),
is_passable(passable), is_cross_plane(cross_plane),
is_transparent(transparent), is_discard(discard), is_blend(blend),
is_transitional(transitional) {}
}; };
const std::array<bool, MAX_BLOCK_NUM> TRANSPARENT_MAP { class BlockManager {
true,
false, public:
false, static const std::vector<BlockData>& datas();
false, static void init();
false, static unsigned sums();
false, static unsigned cross_plane_sum();
true static const std::string& name_form_id(BlockType id);
static bool is_gas(BlockType id);
static bool is_liquid(BlockType id);
static bool is_cross_plane(BlockType id);
static bool is_transparent(BlockType id);
static bool is_passable(BlockType id);
static bool is_discard(BlockType id);
static bool is_blend(BlockType id);
static bool is_transitional(BlockType id);
static BlockType cross_plane_index(BlockType id);
private:
static void set_up_cross_plane_map();
static inline std::vector<BlockData> m_datas;
static inline bool is_init = false;
static inline std::unordered_map<BlockType, BlockType> m_cross_plane_map;
}; };
inline bool is_in_transparent_map(unsigned id) { } // namespace Cubed
CUBED_ASSERT_MSG(id < MAX_BLOCK_NUM, "ID is invaild");
return TRANSPARENT_MAP[id];
};

View File

@@ -0,0 +1,18 @@
#pragma once
namespace Cubed {
class ChunkGenerator;
class BiomeBuilder {
public:
BiomeBuilder() = default;
virtual ~BiomeBuilder() = default;
virtual ChunkGenerator& get_chunk_generator() = 0;
virtual void build_biome() = 0;
virtual void build_vegetation() = 0;
void ocean_water_build();
protected:
void build_bottom();
void place_grass();
};
} // namespace Cubed

View File

@@ -0,0 +1,21 @@
#pragma once
#include "Cubed/gameplay/builders/biome_builder.hpp"
namespace Cubed {
class ChunkGenerator;
class DesertBuilder : public BiomeBuilder {
public:
DesertBuilder(ChunkGenerator& chunk_generator);
void build_biome() override;
ChunkGenerator& get_chunk_generator() override;
void build_vegetation() override;
private:
ChunkGenerator& m_chunk_generator;
void build_blocks();
};
} // namespace Cubed

View File

@@ -0,0 +1,21 @@
#pragma once
#include "Cubed/gameplay/builders/biome_builder.hpp"
namespace Cubed {
class ChunkGenerator;
class ForestBuilder : public BiomeBuilder {
public:
ForestBuilder(ChunkGenerator& chunk_generator);
void build_biome() override;
ChunkGenerator& get_chunk_generator() override;
void build_vegetation() override;
private:
ChunkGenerator& m_chunk_generator;
void build_blocks();
};
} // namespace Cubed

View File

@@ -0,0 +1,21 @@
#pragma once
#include "Cubed/gameplay/builders/biome_builder.hpp"
namespace Cubed {
class ChunkGenerator;
class MountainBuilder : public BiomeBuilder {
public:
MountainBuilder(ChunkGenerator& chunk_generator);
void build_biome() override;
ChunkGenerator& get_chunk_generator() override;
void build_vegetation() override;
private:
ChunkGenerator& m_chunk_generator;
void build_blocks();
};
} // namespace Cubed

View File

@@ -0,0 +1,23 @@
#pragma once
#pragma once
#include "Cubed/gameplay/builders/biome_builder.hpp"
namespace Cubed {
class ChunkGenerator;
class OceanBuilder : public BiomeBuilder {
public:
OceanBuilder(ChunkGenerator& chunk_generator);
void build_biome() override;
ChunkGenerator& get_chunk_generator() override;
void build_vegetation() override;
private:
ChunkGenerator& m_chunk_generator;
void build_blocks();
};
} // namespace Cubed

View File

@@ -0,0 +1,21 @@
#pragma once
#include "Cubed/gameplay/builders/biome_builder.hpp"
namespace Cubed {
class ChunkGenerator;
class PlainBuilder : public BiomeBuilder {
public:
PlainBuilder(ChunkGenerator& chunk_generator);
void build_biome() override;
ChunkGenerator& get_chunk_generator() override;
void build_vegetation() override;
private:
ChunkGenerator& m_chunk_generator;
void build_blocks();
};
} // namespace Cubed

View File

@@ -0,0 +1,21 @@
#pragma once
#include "Cubed/gameplay/builders/biome_builder.hpp"
namespace Cubed {
class ChunkGenerator;
class RiverBuilder : public BiomeBuilder {
public:
RiverBuilder(ChunkGenerator& chunk_generator);
void build_biome() override;
ChunkGenerator& get_chunk_generator() override;
void build_vegetation() override;
private:
ChunkGenerator& m_chunk_generator;
void build_blocks();
};
} // namespace Cubed

View File

@@ -0,0 +1,21 @@
#pragma once
#include "Cubed/gameplay/builders/biome_builder.hpp"
namespace Cubed {
class ChunkGenerator;
class SnowyPlainBuilder : public BiomeBuilder {
public:
SnowyPlainBuilder(ChunkGenerator& chunk_generator);
void build_biome() override;
ChunkGenerator& get_chunk_generator() override;
void build_vegetation() override;
private:
ChunkGenerator& m_chunk_generator;
void build_blocks();
};
} // namespace Cubed

View File

@@ -0,0 +1,27 @@
#pragma once
#include "Cubed/gameplay/cave_path.hpp"
#include <tbb/concurrent_hash_map.h>
namespace Cubed {
class CaveCarver {
using CaveHashMap = tbb::concurrent_hash_map<unsigned, CavePath>;
public:
CaveCarver();
CaveHashMap& paths();
void init(unsigned world_seed);
void reload(unsigned world_seed);
void add_path(const glm::vec3& pos, unsigned chunk_seed);
void try_to_add_path(const ChunkPos& pos, unsigned chunk_seed);
void cleanup_finished_caves();
int cave_sum() const;
float& cave_probability();
private:
CaveHashMap m_paths;
unsigned m_seed = 0;
Random m_random;
float m_cave_probability = 0.035f;
};
} // namespace Cubed

View File

@@ -0,0 +1,54 @@
#pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/path_point.hpp"
#include "Cubed/tools/cubed_random.hpp"
#include <glm/glm.hpp>
#include <tbb/concurrent_hash_map.h>
namespace Cubed {
class CavePath {
using ChunkPosSet =
tbb::concurrent_hash_map<ChunkPos, bool, ChunkPos::TBBHash>;
public:
CavePath(unsigned int chunk_seed, unsigned world_seed,
const glm::vec3& start_pos);
const std::vector<PathPoint>& points() const;
void clear_chunk(const ChunkPos& pos);
bool is_finished() const;
static float& radius_xz_min();
static float& radius_xz_max();
static float& radius_y_min();
static float& radius_y_max();
static float& delta_angle_min();
static float& delta_angle_max();
static int& step_min();
static int& step_max();
private:
static inline float m_radius_xz_min = 5.0f;
static inline float m_radius_xz_max = 15.0f;
static inline float m_radius_y_min = 4.0f;
static inline float m_radius_y_max = 10.0f;
static inline float m_delta_angle_min = -5.0f;
static inline float m_delta_angle_max = 5.0f;
static inline int m_step_min = 10;
static inline int m_step_max = 400;
unsigned int m_seed = 0;
float m_yaw = 0.0f;
float m_pitch = 0.0f;
int m_step = 0;
float m_step_len = 1.0f;
PathPoint m_start_path_point{{0.0f, 0.0f, 0.0f}, 0.0f, 0.0f};
Random m_random;
std::vector<PathPoint> m_points;
ChunkPosSet m_pending_chunks;
void collect_path_points();
void precompute_chunk_coverage();
};
} // namespace Cubed

View File

@@ -1,68 +1,134 @@
#pragma once #pragma once
#include <atomic> #include "Cubed/gameplay/biome.hpp"
#include <cstdint> #include "Cubed/gameplay/block.hpp"
#include "Cubed/gameplay/chunk_generator.hpp"
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/vertex_data.hpp"
#include <Cubed/config.hpp> #include <atomic>
#include <Cubed/gameplay/biome.hpp> #include <mutex>
#include <Cubed/gameplay/chunk_pos.hpp> namespace Cubed {
#include <Cubed/gameplay/block.hpp>
class World; class World;
// if want to use, do init_chunk(), gen_vertex_data() and // if want to use, do init_chunk(), gen_vertex_data() and
class Chunk { class Chunk {
private: private:
std::atomic<bool> m_dirty {false}; using OptionalBlockVectorArray =
std::array<std::optional<std::vector<BlockType>>, 4>;
static constexpr int SIZE_X = CHUCK_SIZE; static constexpr int SIZE_X = CHUNK_SIZE;
static constexpr int SIZE_Y = WORLD_SIZE_Y; static constexpr int SIZE_Y = WORLD_SIZE_Y;
static constexpr int SIZE_Z = CHUCK_SIZE; static constexpr int SIZE_Z = CHUNK_SIZE;
static constexpr int VERTEX_DATA_SUM = 4;
Biome m_biome = Biome::PLAIN; std::atomic<bool> m_dirty{false};
std::atomic<bool> m_need_upload{true};
std::atomic<bool> m_is_on_gen_vertex_data{false};
std::atomic<BiomeType> m_biome = BiomeType::PLAIN;
std::mutex m_vertexs_data_mutex;
std::unique_ptr<ChunkGenerator> m_generator;
ChunkPos m_chunk_pos; ChunkPos m_chunk_pos;
World& m_world; World& m_world;
HeightMapArray m_heightmap;
// the index is a array of block id // the index is a array of block id
std::vector<uint8_t> m_blocks; std::vector<BlockType> m_blocks;
GLuint m_vbo = 0;
std::vector<Vertex> m_vertexs_data; /*
0 - normal
1 - cross_plane
2 - normal_discard
3 - transparent and blend
*/
std::vector<VertexData> m_vertex_data;
float frequency = 0.01f; float frequency = 0.01f;
float height = 80; float height = 80;
unsigned m_seed = 0;
BiomeConditions m_conditions;
void clear_dirty(); void clear_dirty();
void gen_vertices(const OptionalBlockVectorArray& neighbor_block);
void resolve_biome(); void gen_cross_plane_vertices(int world_x, int world_y, int world_z,
void resolve_blocks(); BlockType id);
public: public:
Chunk(World& world, ChunkPos chunk_pos); Chunk(World& world, ChunkPos chunk_pos);
~Chunk(); ~Chunk();
Chunk(const Chunk&) = delete; Chunk(const Chunk&) = delete;
Chunk& operator=(const Chunk&) = delete; Chunk& operator=(const Chunk&) = delete;
Chunk(Chunk&&); Chunk(Chunk&&) noexcept;
Chunk& operator=(Chunk&&); Chunk& operator=(Chunk&&) noexcept;
Biome get_biome() const; static std::tuple<int, int, int> world_to_block(int world_x, int world_y,
int world_z, int chunk_x,
const std::vector<uint8_t>& get_chunk_blocks() const; int chunk_z);
static std::tuple<int, int, int> world_to_block(const glm::ivec3& block_pos,
static int get_index(int x, int y, int z); ChunkPos chunk_pos);
static int get_index(const glm::vec3& pos); static std::tuple<int, int, int> block_to_world(int x, int y, int z,
void init_chunk(); int chunk_x, int chunk_z);
//void gen_vertex_data(); static std::tuple<int, int, int> block_to_world(const glm::ivec3& block_pos,
// 0 : (1, 0) ChunkPos chunk_pos);
// 1 : (-1, 0) BiomeType get_biome() const;
// 2 : (0, 1) ChunkPos get_chunk_pos() const;
// 3 : (0, -1) const std::vector<BlockType>& get_chunk_blocks() const;
void gen_vertex_data(const std::array<const std::vector<uint8_t>*, 4>& neighbor_block); HeightMapArray get_heightmap() const;
static int index(int x, int y, int z);
static int index(const glm::vec3& pos);
// Init Chunk
// Determine biome from temperature and humidity noise
void gen_phase_one();
// Resolve biome adjacency conflicts with neighbor chunks
void gen_phase_two(const std::array<const Chunk*, 8>& adj_chunks);
// Generate heightmap using biome-specific noise
void gen_phase_three();
// Blend heightmap with neighbors for smooth transitions
void gen_phase_four(
const std::array<std::optional<HeightMapArray>, 8>& neighbor_heightmap,
const std::array<BiomeType, 8>& neighbor_biome);
// Generate terrain blocks from heightmap and biome
void gen_phase_five();
// Blend surface blocks at chunk borders with neighbors
void gen_phase_six(const std::array<std::optional<std::vector<BlockType>>,
4>& neighbor_block);
// Generate biome-specific vegetation/structures
void gen_phase_seven();
// void gen_vertex_data();
// 0 : (1, 0)
// 1 : (-1, 0)
// 2 : (0, 1)
// 3 : (0, -1)
void gen_vertex_data(const OptionalBlockVectorArray& neighbor_block);
void upload_to_gpu(); void upload_to_gpu();
GLuint get_vbo() const; GLuint get_normal_vao() const;
const std::vector<Vertex>& get_vertex_data() const; size_t get_normal_vertices_sum() const;
GLuint get_cross_vao() const;
size_t get_cross_vertices_sum() const;
GLuint get_normal_discard_vao() const;
size_t get_normal_discard_vertices_sum() const;
GLuint get_normal_blend_vao() const;
size_t get_normal_blend_vertices_sum() const;
bool is_dirty() const; bool is_dirty() const;
void mark_dirty(); void mark_dirty();
bool is_need_upload() const;
void need_upload();
void set_chunk_block(int index, unsigned id); void set_chunk_block(int index, unsigned id);
}; ChunkPos chunk_pos() const;
BiomeType biome() const;
void biome(BiomeType b);
HeightMapArray& heightmap();
std::vector<BlockType>& blocks();
World& world();
unsigned seed() const;
BiomeConditions& conditions();
};
} // namespace Cubed

View File

@@ -0,0 +1,70 @@
#pragma once
#include "Cubed/constants.hpp"
#include "Cubed/gameplay/biome.hpp"
#include "Cubed/gameplay/block.hpp"
#include "Cubed/gameplay/builders/biome_builder.hpp"
#include "Cubed/gameplay/path_point.hpp"
#include "Cubed/tools/cubed_random.hpp"
#include <atomic>
#include <memory>
#include <optional>
namespace Cubed {
class Chunk;
class ChunkGenerator {
public:
ChunkGenerator(Chunk& chunk);
static void init();
static void reload();
static const unsigned& seed();
static void seed(unsigned s);
unsigned chunk_seed() const;
// Generate Biome
void assign_chunk_biome();
// Adjust Biome
void resolve_biome_adjacency_conflict(
const std::array<const Chunk*, 8>& adj_chunks);
// Generate Heightmap
void generate_heightmap();
// Adjust Height
void blend_heightmap_boundaries(
const std::array<std::optional<HeightMapArray>, 8>& neighbor_heightmap,
const std::array<BiomeType, 8>& neighbor_biome);
// Generate Block
void generate_terrain_blocks();
// Adjust Block;
void blend_surface_blocks_borders(
const std::array<std::optional<std::vector<BlockType>>, 4>&
neighbor_block);
// Generate Structure
void generate_vegetation();
BiomeType get_biome_at(float world_x, float world_z);
Chunk& chunk();
Random& random();
const std::array<BiomeType, 8>& neighbor_biome() const;
void ocean_build();
void generate_cave();
void generate_river();
private:
static inline std::atomic<bool> is_init{false};
static inline unsigned m_generator_seed{0};
static inline std::atomic<bool> is_seed_change{false};
Chunk& m_chunk;
Random m_random;
std::unique_ptr<BiomeBuilder> m_biome_builder{nullptr};
bool is_cur_chunk_ins = false;
std::array<BiomeType, 8> m_neighbor_biome;
unsigned m_chunk_seed = 0;
void make_biome_builder();
void
carve_worm(const std::vector<PathPoint>& points, const ChunkPos& chunk_pos,
std::function<void(int /*x*/, int /*y*/, int /*z*/)> on_hit);
};
} // namespace Cubed

View File

@@ -1,23 +1,30 @@
#pragma once #pragma once
#include <functional> #include <functional>
namespace Cubed {
#include <Cubed/tools/log.hpp>
#include <Cubed/tools/cubed_assert.hpp>
struct ChunkPos { struct ChunkPos {
int x; int x;
int z; int z;
bool operator==(const ChunkPos&) const = default; bool operator==(const ChunkPos&) const = default;
struct Hash { struct Hash {
std::size_t operator()(const ChunkPos& pos) const{ std::size_t operator()(const ChunkPos& pos) const {
std::size_t h1 = std::hash<int>{}(pos.x); std::size_t h1 = std::hash<int>{}(pos.x);
std::size_t h2 = std::hash<int>{}(pos.z); std::size_t h2 = std::hash<int>{}(pos.z);
return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2)); return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
} }
}; };
struct TBBHash {
ChunkPos operator+(const ChunkPos& pos) const{ std::size_t hash(const ChunkPos& p) const {
return ChunkPos::Hash{}(p);
}
bool equal(const ChunkPos& a, const ChunkPos& b) const {
return a == b;
}
};
ChunkPos operator+(const ChunkPos& pos) const {
return ChunkPos{x + pos.x, z + pos.z}; return ChunkPos{x + pos.x, z + pos.z};
} }
@@ -28,3 +35,4 @@ struct ChunkPos {
}; };
}; };
} // namespace Cubed

View File

@@ -2,18 +2,20 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
enum class GameMode {
CREATIVE, namespace Cubed {
SPECTATOR
}; enum class GameMode { CREATIVE = 0, SPECTATOR };
inline std::string to_str(GameMode mode) { inline std::string to_str(GameMode mode) {
using enum GameMode; using enum GameMode;
switch (mode) { switch (mode) {
case CREATIVE: case CREATIVE:
return {"Creative"}; return {"Creative"};
case SPECTATOR: case SPECTATOR:
return {"Spective"}; return {"Spective"};
} }
throw std::invalid_argument{"GameMode is invaild"}; throw std::invalid_argument{"GameMode is invaild"};
} }
} // namespace Cubed

View File

@@ -0,0 +1,10 @@
#pragma once
// Prevent unsigned underflow issues in subtraction
using TickType = long long;
constexpr int DEFAULT_PER_TICK_TIME = 50;
constexpr TickType DAY_TIME = 24000;
constexpr TickType PER_HOUR = 1000;

View File

@@ -0,0 +1,36 @@
#pragma once
#include <glm/glm.hpp>
struct PathPoint {
glm::vec3 pos;
glm::vec3 tangent{0.0f, 0.0f, 1.0f};
float rad_xz;
float rad_y;
PathPoint(const glm::vec3& p, float rx, float ry)
: pos(p), rad_xz(rx), rad_y(ry) {}
bool contains(const glm::vec3& other_pos) const {
glm::vec3 to_point = other_pos - pos;
glm::vec3 world_up(0.0f, 1.0f, 0.0f);
glm::vec3 right = glm::normalize(glm::cross(tangent, world_up));
if (glm::length(right) < 0.001f) {
glm::vec3 alt_up(1.0f, 0.0f, 0.0f);
right = glm::normalize(glm::cross(tangent, alt_up));
}
glm::vec3 up = glm::normalize(glm::cross(right, tangent));
float horizontal_dist = glm::dot(to_point, right);
float vertical_dist = glm::dot(to_point, up);
float a = rad_xz;
float b = rad_y;
if (a <= 0.0f || b <= 0.0f)
return false;
float check = (horizontal_dist * horizontal_dist) / (a * a) +
(vertical_dist * vertical_dist) / (b * b);
return check <= 1.0f;
}
};

View File

@@ -1,67 +1,70 @@
#pragma once #pragma once
#include "Cubed/AABB.hpp"
#include "Cubed/constants.hpp"
#include "Cubed/gameplay/block.hpp"
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/game_mode.hpp"
#include "Cubed/input.hpp"
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <Cubed/AABB.hpp>
#include <Cubed/config.hpp>
#include <Cubed/gameplay/block.hpp>
#include <Cubed/gameplay/chunk_pos.hpp>
#include <Cubed/gameplay/game_mode.hpp>
#include <Cubed/input.hpp>
#include <optional> #include <optional>
#include <string> #include <string>
enum class Gait{ namespace Cubed {
WALK,
RUN enum class Gait { WALK = 0, RUN };
};
class World; class World;
class Player { class Player {
private: private:
using enum GameMode; using enum GameMode;
constexpr static float WALK_SPEED = 4.5f; float m_max_walk_speed = DEFAULT_MAX_WALK_SPEED;
constexpr static float RUN_SPEED = 7.0f; float m_max_run_speed = DEFAULT_MAX_RUN_SPEED;
constexpr static float ACCELERATION = 10.0f; float m_acceleration = DEFAULT_ACCELERATION;
constexpr static float DECELERATION = 15.0f; float m_deceleration = DEFAULT_DECELERATION;
constexpr static float G = 22.5f; float m_g = DEFAULT_G;
constexpr static float MAX_SPACE_ON_TIME = 0.3f;
constexpr static float MAX_SPACE_ON_TIME = 0.3f;
float m_yaw = 0.0f; float m_yaw = 0.0f;
float m_pitch = 0.0f; float m_pitch = 0.0f;
float m_sensitivity = 0.15f; float m_sensitivity = 0.15f;
float max_speed = WALK_SPEED; float m_max_speed = m_max_walk_speed;
float y_speed = 0.0f; float m_y_speed = 0.0f;
bool can_up = true; bool can_up = true;
float space_on_time = 0.0f; float space_on_time = 0.0f;
bool space_on = false; bool space_on = false;
bool is_fly = false; bool is_fly = false;
float speed = 0;
glm::vec3 direction = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 move_distance {0.0f, 0.0f, 0.0f};
// player is tow block tall, the pos is the lower pos
glm::vec3 m_player_pos {0.0f, 120.0f, 0.0f};
ChunkPos m_player_chunk_pos {0, 0};
glm::vec3 m_front {0, 0, -1}; float m_xz_speed = 0.0f;
glm::vec3 m_right {0, 0, 0};
glm::vec3 m_size {0.6f, 1.8f, 0.6f}; unsigned m_place_block = 1;
glm::vec3 direction = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 move_distance{0.0f, 0.0f, 0.0f};
// player is tow block tall, the pos is the lower pos
glm::vec3 m_player_pos{0.0f, 255.0f, 0.0f};
ChunkPos m_player_chunk_pos{0, 0};
glm::vec3 m_front{0, 0, -1};
glm::vec3 m_right{0, 0, 0};
glm::vec3 m_size{0.6f, 1.8f, 0.6f};
Gait m_gait = Gait::WALK; Gait m_gait = Gait::WALK;
MoveState m_move_state {}; MoveState m_move_state{};
GameMode m_game_mode = CREATIVE; GameMode m_game_mode = CREATIVE;
std::optional<LookBlock> m_look_block = std::nullopt; std::optional<LookBlock> m_look_block = std::nullopt;
std::string m_name {}; std::string m_name{};
World& m_world; World& m_world;
bool ray_cast(const glm::vec3& start, const glm::vec3& dir, glm::ivec3& block_pos, glm::vec3& normal, float distance = 4.0f); bool ray_cast(const glm::vec3& start, const glm::vec3& dir,
glm::ivec3& block_pos, glm::vec3& normal,
float distance = 4.0f);
void check_player_chunk_transition(); void check_player_chunk_transition();
void update_direction(); void update_direction();
@@ -80,12 +83,28 @@ public:
const std::optional<LookBlock>& get_look_block_pos() const; const std::optional<LookBlock>& get_look_block_pos() const;
const glm::vec3& get_player_pos() const; const glm::vec3& get_player_pos() const;
const MoveState& get_move_state() const; const MoveState& get_move_state() const;
void change_mode(GameMode mode); void change_mode(GameMode mode);
void hot_reload();
void set_player_pos(const glm::vec3& pos); void set_player_pos(const glm::vec3& pos);
void set_place_block(unsigned id);
void update(float delta_time); void update(float delta_time);
void update_front_vec(float offset_x, float offset_y); void update_front_vec(float offset_x, float offset_y);
void update_player_move_state(int key, int action); void update_player_move_state(int key, int action);
void update_scroll(double yoffset); void update_scroll(double yoffset);
}; float& max_walk_speed();
float& max_run_speed();
float& max_speed();
float& acceleration();
float& deceleration();
float& g();
unsigned place_block() const;
Gait& gait();
GameMode& game_mode();
const World& get_world() const;
};
} // namespace Cubed

View File

@@ -0,0 +1,55 @@
#pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/path_point.hpp"
#include "Cubed/tools/cubed_random.hpp"
#include <glm/glm.hpp>
#include <tbb/concurrent_hash_map.h>
namespace Cubed {
class RiverPath {
using ChunkPosSet =
tbb::concurrent_hash_map<ChunkPos, bool, ChunkPos::TBBHash>;
public:
RiverPath(unsigned int chunk_seed, unsigned world_seed,
const glm::vec3& start_pos);
const std::vector<PathPoint>& points() const;
void clear_chunk(const ChunkPos& pos);
bool is_finished() const;
static float& radius_xz_min();
static float& radius_xz_max();
static float& radius_y_min();
static float& radius_y_max();
static float& delta_angle_min();
static float& delta_angle_max();
static int& step_min();
static int& step_max();
private:
static inline float m_radius_xz_min = 5.0f;
static inline float m_radius_xz_max = 10.0f;
static inline float m_radius_y_min = 4.0f;
static inline float m_radius_y_max = 8.0f;
static inline float m_delta_angle_min = -3.0f;
static inline float m_delta_angle_max = 3.0f;
static inline int m_step_min = 200;
static inline int m_step_max = 400;
unsigned int m_seed = 0;
float m_yaw = 0.0f;
float m_initial_yaw = 0.0f;
float m_pitch = 0.0f;
int m_step = 0;
float m_step_len = 1.0f;
PathPoint m_start_path_point{{0.0f, 0.0f, 0.0f}, 0.0f, 0.0f};
Random m_random;
std::vector<PathPoint> m_points;
ChunkPosSet m_pending_chunks;
void collect_path_points();
void precompute_chunk_coverage();
};
} // namespace Cubed

View File

@@ -0,0 +1,32 @@
#pragma once
#include "Cubed/gameplay/chunk_pos.hpp"
#include "Cubed/gameplay/river.path.hpp"
#include "Cubed/tools/cubed_random.hpp"
#include <glm/glm.hpp>
#include <tbb/concurrent_hash_map.h>
namespace Cubed {
class RiverWorm {
using RiverHashMap = tbb::concurrent_hash_map<unsigned, RiverPath>;
public:
RiverWorm();
RiverHashMap& paths();
void init(unsigned world_seed);
void reload(unsigned world_seed);
void add_path(const glm::vec3& pos, unsigned chunk_seed);
void try_to_add_path(const ChunkPos& pos, unsigned chunk_seed);
void cleanup_finished_rivers();
int river_sum() const;
float& river_probability();
private:
RiverHashMap m_paths;
unsigned m_seed = 0;
Random m_random;
float m_probability = 0.01f;
};
}; // namespace Cubed

View File

@@ -2,6 +2,8 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
namespace Cubed {
class Chunk; class Chunk;
struct TreeStructNode { struct TreeStructNode {
@@ -9,4 +11,6 @@ struct TreeStructNode {
unsigned id = 0; unsigned id = 0;
}; };
bool build_tree(Chunk& chunk, const glm::ivec3& pos); bool build_tree(Chunk& chunk, const glm::ivec3& pos);
} // namespace Cubed

View File

@@ -0,0 +1,25 @@
#pragma once
#include "Cubed/primitive_data.hpp"
#include <atomic>
#include <glad/glad.h>
#include <vector>
namespace Cubed {
class World;
struct VertexData {
std::vector<Vertex3D> m_vertices;
GLuint m_vbo = 0;
GLuint m_vao = 0;
std::atomic<std::size_t> m_sum{0};
World& m_world;
VertexData(World& world);
~VertexData();
VertexData(const VertexData&) = delete;
VertexData(VertexData&&) noexcept;
VertexData& operator=(const VertexData&) = delete;
VertexData& operator=(VertexData&&) noexcept;
void upload();
void update_sum();
};
} // namespace Cubed

View File

@@ -1,78 +1,157 @@
#pragma once #pragma once
#include "Cubed/AABB.hpp"
#include "Cubed/gameplay/cave_carver.hpp"
#include "Cubed/gameplay/chunk.hpp"
#include "Cubed/gameplay/game_time.hpp"
#include "Cubed/gameplay/river_worm.hpp"
#include <atomic> #include <atomic>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <thread>
#include <optional> #include <optional>
#include <thread>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <Cubed/AABB.hpp> namespace Cubed {
#include <Cubed/gameplay/chunk.hpp>
struct ChunkRenderSnapshot { struct ChunkRenderSnapshot {
GLuint vbo; GLuint normal_vao;
size_t vertex_count; size_t normal_vertices_count;
GLuint cross_vao;
size_t cross_vertices_count;
GLuint normal_discard_vao;
size_t normal_discard_vertices_count;
GLuint normal_blend_vao;
size_t normal_blend_vertices_count;
glm::vec3 center; glm::vec3 center;
glm::vec3 half_extents; glm::vec3 half_extents;
}; };
class Player; class Player;
class TextureManager;
class World { class World {
private: private:
using OptionalBlockVectorArray =
std::array<std::optional<std::vector<BlockType>>, 4>;
using ChunkPtrUpdateList = std::vector<std::pair<ChunkPos, Chunk*>>;
using ChunkPairVector = std::vector<std::pair<ChunkPos, Chunk>>;
using ConstChunkMap =
std::unordered_map<ChunkPos, const Chunk*, ChunkPos::Hash>;
using ChunkPosSet = std::unordered_set<ChunkPos, ChunkPos::Hash>;
using ChunkHashMap = std::unordered_map<ChunkPos, Chunk, ChunkPos::Hash>;
glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f}; glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f};
std::unordered_map<ChunkPos , Chunk, ChunkPos::Hash> m_chunks; ChunkHashMap m_chunks;
std::unordered_map<std::size_t, Player> m_players; std::unordered_map<std::size_t, Player> m_players;
std::vector<glm::vec4> m_planes; std::vector<glm::vec4> m_planes;
std::thread m_gen_thread; std::thread m_gen_thread;
std::thread m_server_thread;
std::stop_source m_server_stop_source;
std::atomic<int> m_per_tick_time = DEFAULT_PER_TICK_TIME; // ms
std::atomic<TickType> m_day_tick = 6000;
mutable std::mutex m_chunks_mutex; mutable std::mutex m_chunks_mutex;
std::mutex m_gen_signal_mutex; std::mutex m_gen_signal_mutex;
std::mutex m_new_chunk_queue_mutex; std::mutex m_new_chunk_queue_mutex;
std::mutex m_delete_vbo_mutex; std::mutex m_delete_vbo_mutex;
std::mutex m_delete_vao_mutex;
std::mutex m_gen_player_pos_mutex; std::mutex m_gen_player_pos_mutex;
std::vector<GLuint> m_pending_delete_vbo; std::vector<GLuint> m_pending_delete_vbo;
std::vector<GLuint> m_pending_delete_vao;
std::condition_variable m_gen_cv; std::condition_variable m_gen_cv;
std::atomic<bool> m_gen_running{false}; std::atomic<bool> m_gen_running{false};
std::atomic<bool> m_need_gen_chunk{false}; std::atomic<bool> m_need_gen_chunk{false};
std::atomic<bool> m_is_rebuilding{false};
std::atomic<bool> m_chunk_gen_finished{false};
std::atomic<bool> m_could_gen{true};
std::atomic<bool> m_tick_running{true};
std::atomic<int> m_rendering_distance{24};
std::atomic<float> m_chunk_gen_fraction{0.0f};
std::atomic<TickType> m_game_ticks{0};
std::vector<ChunkPos> m_dirty_queue; std::vector<ChunkPos> m_dirty_queue;
std::vector<ChunkRenderSnapshot> m_render_snapshots; std::vector<ChunkRenderSnapshot> m_render_snapshots;
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk; std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk;
std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk_queue; std::vector<std::pair<ChunkPos, Chunk>> m_new_chunk_queue;
void gen_chunks_internal(); CaveCarver m_cave_carcer;
RiverWorm m_river_worm;
void init_chunks();
void start_gen_thread(); void gen_chunks_internal();
void stop_gen_thread(); void sync_player_pos(glm::vec3& player_pos);
void
compute_required_chunks(ChunkPosSet& required_chunks,
ChunkPairVector& temp_neighbor,
std::vector<ChunkPos>& need_gen_temp_chunks_pos);
void sync_and_collect_missing_chunks(std::vector<ChunkPos>&,
const ChunkPosSet&);
void
build_neighbor_context_for_new_chunks(ConstChunkMap& new_chunks_neighbor,
ChunkPtrUpdateList& affected_neighbor,
const ChunkPairVector& new_chunks);
void build_neighbor_context_for_affected_neighbors(ChunkPtrUpdateList&,
ConstChunkMap&);
public: public:
World(); World();
~World(); ~World();
bool can_move(const AABB& player_box) const; bool can_move(const AABB& player_box) const;
//const BlockRenderData& get_block_render_data(int x, int y ,int z); // const BlockRenderData& get_block_render_data(int x, int y ,int z);
const std::optional<LookBlock>& get_look_block_pos(const std::string& name) const; const std::optional<LookBlock>&
get_look_block_pos(const std::string& name) const;
const Chunk* get_chunk(const ChunkPos& pos) const; const Chunk* get_chunk(const ChunkPos& pos) const;
Player& get_player(const std::string& name); Player& get_player(const std::string& name);
void init_world(); void init_world();
bool is_aabb_in_frustum(const glm::vec3& center, const glm::vec3& half_extents);
int get_block(const glm::ivec3& block_pos) const; int get_block(const glm::ivec3& block_pos) const;
bool is_block(const glm::ivec3& block_pos) const; bool is_solid(const glm::ivec3& block_pos) const;
bool can_pass_block(const glm::ivec3& block_pos) const;
BlockType get_block_tpye(const glm::ivec3& block_pos) const;
static ChunkPos chunk_pos(int world_x, int world_z); static ChunkPos chunk_pos(int world_x, int world_z);
void need_gen(); void need_gen();
void render(const glm::mat4& mvp_matrix);
void set_block(const glm::ivec3& pos, unsigned id); void set_block(const glm::ivec3& pos, unsigned id);
void update(float delta_time); void update(float delta_time);
void push_delete_vbo(GLuint vbo);
}; void push_delete_vbo(GLuint vbo);
void push_delete_vao(GLuint vao);
void hot_reload();
void rebuild_world();
float chunk_gen_fraction() const;
int rendering_distance() const;
void rendering_distance(int rendering_distance);
void start_gen_thread();
void start_server_thread();
void stop_gen_thread();
void stop_server_thread();
void serever_run(std::stop_token stoken);
CaveCarver& cave_carcer();
RiverWorm& river_worm();
std::vector<glm::vec4>& planes();
std::vector<ChunkRenderSnapshot>& render_snapshots();
glm::vec3 sunlight_dir() const;
TickType game_tick() const;
TickType day_tick() const;
void day_tick(TickType tick);
int per_tick_time() const;
void per_tick_time(int ms);
bool is_tick_running() const;
void tick_running(bool run);
};
} // namespace Cubed

View File

@@ -2,6 +2,8 @@
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
namespace Cubed {
struct MoveState { struct MoveState {
bool forward = false; bool forward = false;
bool back = false; bool back = false;
@@ -27,7 +29,8 @@ struct InputState {
}; };
namespace Input { namespace Input {
InputState& get_input_state(); InputState& get_input_state();
}
}
} // namespace Cubed

View File

@@ -1,14 +1,26 @@
#pragma once #pragma once
#include <string> // #include <string>
#include <unordered_map> // #include <unordered_map>
// #include <vector>
namespace Cubed {
class MapTable { class MapTable {
private: private:
static std::unordered_map<unsigned, std::string> id_to_name_map; /*
static std::unordered_map<size_t, unsigned> name_to_id_map; static inline std::unordered_map<unsigned, std::string> id_to_name_map;
static inline std::unordered_map<size_t, unsigned> name_to_id_map;
static inline std::vector<std::string> item_id_to_name;
*/
public: public:
// please using reference // please using reference
static const std::string& get_name_from_id(unsigned id); /*
static const unsigned get_id_from_name(const std::string& name); static std::string_view get_name_from_id(unsigned id);
static void init_map(); static unsigned get_id_from_name(const std::string& name);
static std::string_view item_name(unsigned id);
static const std::vector<std::string>& item_map();
*/
static void init_map();
}; };
} // namespace Cubed

View File

@@ -0,0 +1,235 @@
#pragma once
namespace Cubed {
#pragma region NORMAL_BLOCK
constexpr float VERTICES_POS[6][6][3] = {
// ===== front (z = +1) =====
{{0.0f, 0.0f, 1.0f}, // bottom left
{0.0f, 1.0f, 1.0f}, // top left
{1.0f, 1.0f, 1.0f}, // top right
{1.0f, 1.0f, 1.0f}, // top right
{1.0f, 0.0f, 1.0f}, // bottom right
{0.0f, 0.0f, 1.0f}}, // bottom left
// ===== right (x = +1) =====
{{1.0f, 0.0f, 1.0f}, // bottom front
{1.0f, 0.0f, 0.0f}, // bottom back
{1.0f, 1.0f, 0.0f}, // top back
{1.0f, 1.0f, 0.0f}, // top back
{1.0f, 1.0f, 1.0f}, // top front
{1.0f, 0.0f, 1.0f}}, // bottom front
// ===== back (z = -1) =====
{{0.0f, 0.0f, 0.0f}, // bottom left
{1.0f, 0.0f, 0.0f}, // bottom right
{1.0f, 1.0f, 0.0f}, // top right
{1.0f, 1.0f, 0.0f}, // top right
{0.0f, 1.0f, 0.0f}, // top left
{0.0f, 0.0f, 0.0f}}, // bottom left
// ===== left (x = -1) =====
{{0.0f, 0.0f, 0.0f}, // bottom back
{0.0f, 0.0f, 1.0f}, // bottom front
{0.0f, 1.0f, 1.0f}, // top front
{0.0f, 1.0f, 1.0f}, // top front
{0.0f, 1.0f, 0.0f}, // top back
{0.0f, 0.0f, 0.0f}}, // bottom back
// ===== top (y = +1) =====
{{0.0f, 1.0f, 0.0f}, // back left
{1.0f, 1.0f, 0.0f}, // back right
{1.0f, 1.0f, 1.0f}, // front right
{1.0f, 1.0f, 1.0f}, // front right
{0.0f, 1.0f, 1.0f}, // front left
{0.0f, 1.0f, 0.0f}}, // back left
// ===== bottom (y = -1) =====
{{0.0f, 0.0f, 1.0f}, // front left
{1.0f, 0.0f, 1.0f}, // front right
{1.0f, 0.0f, 0.0f}, // back right
{1.0f, 0.0f, 0.0f}, // back right
{0.0f, 0.0f, 0.0f}, // back left
{0.0f, 0.0f, 1.0f}} // front left
};
constexpr float TEX_COORDS[6][6][2] = {
// ===== front (z = +1) =====
{{0.0f, 1.0f}, // bottom left
{0.0f, 0.0f}, // top left
{1.0f, 0.0f}, // top right
{1.0f, 0.0f}, // top right
{1.0f, 1.0f}, // bottom right
{0.0f, 1.0f}}, // bottom left
// ===== right (x = +1) =====
{{0.0f, 1.0f}, // bottom front
{1.0f, 1.0f}, // bottom back
{1.0f, 0.0f}, // top back
{1.0f, 0.0f}, // top back
{0.0f, 0.0f}, // top front
{0.0f, 1.0f}}, // bottom front
// ===== back (z = -1) =====
{{1.0f, 1.0f}, // bottom left
{0.0f, 1.0f}, // bottom right
{0.0f, 0.0f}, // top right
{0.0f, 0.0f}, // top right
{1.0f, 0.0f}, // top left
{1.0f, 1.0f}}, // bottom left
// ===== left (x = -1) =====
{{1.0f, 1.0f}, // bottom back
{0.0f, 1.0f}, // bottom front
{0.0f, 0.0f}, // top front
{0.0f, 0.0f}, // top front
{1.0f, 0.0f}, // top back
{1.0f, 1.0f}}, // bottom back
// ===== top (y = +1) =====
{{0.0f, 0.0f}, // back left
{1.0f, 0.0f}, // back right
{1.0f, 1.0f}, // front right
{1.0f, 1.0f}, // front right
{0.0f, 1.0f}, // front left
{0.0f, 0.0f}}, // back left
// ===== bottom (y = -1) =====
{{0.0f, 0.0f}, // front left
{1.0f, 0.0f}, // front right
{1.0f, 1.0f}, // back right
{1.0f, 1.0f}, // back right
{0.0f, 1.0f}, // back left
{0.0f, 0.0f}} // front left
};
constexpr float NORMALS[6][6][3] = {
// ===== front (z = +1) =====
{{0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f}},
// ===== right (x = +1) =====
{{1.0f, 0.0f, 0.0f},
{1.0f, 0.0f, 0.0f},
{1.0f, 0.0f, 0.0f},
{1.0f, 0.0f, 0.0f},
{1.0f, 0.0f, 0.0f},
{1.0f, 0.0f, 0.0f}},
// ===== back (z = -1) =====
{{0.0f, 0.0f, -1.0f},
{0.0f, 0.0f, -1.0f},
{0.0f, 0.0f, -1.0f},
{0.0f, 0.0f, -1.0f},
{0.0f, 0.0f, -1.0f},
{0.0f, 0.0f, -1.0f}},
// ===== left (x = -1) =====
{{-1.0f, 0.0f, 0.0f},
{-1.0f, 0.0f, 0.0f},
{-1.0f, 0.0f, 0.0f},
{-1.0f, 0.0f, 0.0f},
{-1.0f, 0.0f, 0.0f},
{-1.0f, 0.0f, 0.0f}},
// ===== top (y = +1) =====
{{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f}},
// ===== bottom (y = -1) =====
{{0.0f, -1.0f, 0.0f},
{0.0f, -1.0f, 0.0f},
{0.0f, -1.0f, 0.0f},
{0.0f, -1.0f, 0.0f},
{0.0f, -1.0f, 0.0f},
{0.0f, -1.0f, 0.0f}}};
#pragma endregion
constexpr float CUBE_VER[24] = {0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0,
0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0,
0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0};
constexpr int OUTLINE_CUBE_INDICES[24] = {0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6,
6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7};
constexpr float SQUARE_VERTICES[6][2] = {
{-0.5f, -0.5f}, // bottom left
{-0.5f, 0.5f}, // top left
{0.5f, 0.5f}, // top right
{0.5f, 0.5f}, // top right
{0.5f, -0.5f}, // bottom right
{-0.5f, -0.5f} // bottom left
};
constexpr float SQUARE_TEXTURE_POS[6][2] = {
{0.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f},
{1.0f, 1.0f}, {1.0f, 0.0f}, {0.0f, 0.0f},
};
#pragma region CROSS_PLANE
constexpr float CROSS_VERTICES_POS[2][6][3] = {
// ===== Plane 1: bottom-front-left to top-back-right =====
{{0.0f, 0.0f, 0.0f}, // bottom front left
{0.0f, 1.0f, 0.0f}, // top front left
{1.0f, 1.0f, 1.0f}, // top back right
{1.0f, 1.0f, 1.0f}, // top back right
{1.0f, 0.0f, 1.0f}, // bottom back right
{0.0f, 0.0f, 0.0f}}, // bottom front left
// ===== Plane 2: bottom-front-right to top-back-left =====
{{1.0f, 0.0f, 0.0f}, // bottom front right
{1.0f, 1.0f, 0.0f}, // top front right
{0.0f, 1.0f, 1.0f}, // top back left
{0.0f, 1.0f, 1.0f}, // top back left
{0.0f, 0.0f, 1.0f}, // bottom back left
{1.0f, 0.0f, 0.0f}}, // bottom front right
};
constexpr float CROSS_TEX_COORDS[2][6][2] = {
// ===== Plane 1: bottom-front-left to top-back-right =====
{{0.0f, 1.0f}, // bottom left
{0.0f, 0.0f}, // top left
{1.0f, 0.0f}, // top right
{1.0f, 0.0f}, // top right
{1.0f, 1.0f}, // bottom right
{0.0f, 1.0f}}, // bottom left
// ===== Plane 2: bottom-front-right to top-back-left =====
{{0.0f, 1.0f}, // bottom left
{0.0f, 0.0f}, // top left
{1.0f, 0.0f}, // top right
{1.0f, 0.0f}, // top right
{1.0f, 1.0f}, // bottom right
{0.0f, 1.0f}}, // bottom left
};
constexpr float CROSS_NORMALS[2][6][3] = {
// ===== Plane 1: upward =====
{{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f}},
// ===== Plane 2: upward =====
{{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f},
{0.0f, 1.0f, 0.0f}}};
#pragma endregion
constexpr float QUAD_VERTICES[] = {
// postion // texcoorlds
-1.0f, 1.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f};
struct Vertex3D {
float x = 0.0f, y = 0.0f, z = 0.0f;
float s = 0.0f, t = 0.0f;
float layer = 0.0f;
float nx = 0.0f, ny = 0.0f, nz = 0.0f;
};
struct Vertex2D {
float x = 0.0f, y = 0.0f;
float s = 0.0f, t = 0.0f;
float layer = 0.0f;
};
} // namespace Cubed

View File

@@ -1,57 +1,131 @@
#pragma once #pragma once
#include <Cubed/config.hpp> #include "Cubed/constants.hpp"
#include <Cubed/shader.hpp> #include "Cubed/primitive_data.hpp"
#include <Cubed/ui/text.hpp> #include "Cubed/shader.hpp"
#include "Cubed/ui/text.hpp"
#include <glad/glad.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <vector> #include <vector>
namespace Cubed {
class Camera; class Camera;
class TextureManager; class TextureManager;
class World; class World;
class DevPanel;
class Renderer { class Renderer {
public: public:
constexpr static int NUM_VAO = 5; constexpr static int NUM_VAO = 7;
Renderer(const Camera& camera, World& world, const TextureManager& texture_manager); Renderer(const Camera& camera, World& world,
const TextureManager& texture_manager, DevPanel& dev_panel);
~Renderer(); ~Renderer();
void hot_reload();
void init(); void init();
const Shader& get_shader(const std::string& name) const; const Shader& get_shader(const std::string& name) const;
void render(); void render();
void update(float delta_time);
void update_fov(float fov); void update_fov(float fov);
void update_proj_matrix(float aspect, float width, float height); void update_proj_matrix(float aspect, float width, float height);
void updata_framebuffer(int width, int height);
float& ambient_strength();
bool& discard_transparent();
bool& shader_on();
int& shadow_mode();
int& light_cull_face();
private: private:
static constexpr glm::vec3 SUNLIGHT_COLOR{1.0f, 1.0f, 1.0f};
static constexpr glm::vec3 SUN_COLOR{1.00f, 0.95f, 0.80f};
static constexpr glm::vec3 MOON_COLOR{0.75f, 0.80f, 1.00f};
static constexpr glm::vec3 SKY_COLOR{0.529, 0.808, 0.922};
static constexpr float FAR_PLANE = 1000.0f;
static constexpr float NEAR_PLANE = 0.1f;
static constexpr float SUN_SIZE = 50.0f;
static constexpr float MOON_SIZE = 50.0f;
static constexpr float DEPTH_MAP_SIZE = 4096.0f;
static constexpr float ANGLE_STEP_DEG = 0.5f;
float m_ambient_strength = 0.1f;
const Camera& m_camera; const Camera& m_camera;
DevPanel& m_dev_panel;
const TextureManager& m_texture_manager; const TextureManager& m_texture_manager;
World& m_world; World& m_world;
bool m_discard_tranparent = true;
bool m_shader_on = true;
int m_shadow_mode = 0;
int m_light_cull_face = 0;
float m_aspect = 0.0f; float m_aspect = 0.0f;
float m_fov = NORMAL_FOV; float m_fov = DEFAULT_FOV;
glm::mat4 m_p_mat, m_v_mat, m_m_mat, m_mv_mat, m_mvp_mat;
GLuint m_mv_loc;
GLuint m_proj_loc;
GLuint m_sky_vbo; float m_delta_time = 0.0f;
GLuint m_text_vbo;
GLuint m_outline_indices_vbo; float m_width = 0.0f;
GLuint m_outline_vbo; float m_height = 0.0f;
GLuint m_ui_vbo;
glm::mat4 m_p_mat, m_v_mat, m_m_mat, m_mv_mat, m_mvp_mat, m_norm_mat;
GLuint m_mv_loc = 0;
GLuint m_proj_loc = 0;
GLuint m_sky_vbo = 0;
GLuint m_text_vbo = 0;
GLuint m_outline_indices_vbo = 0;
GLuint m_outline_vbo = 0;
GLuint m_ui_vbo = 0;
GLuint m_fbo = 0;
GLuint m_screen_texture = 0;
GLuint m_depth_render_buffer = 0;
GLuint m_oit_fbo = 0;
GLuint m_accum_texture = 0;
GLuint m_reveal_texture = 0;
GLuint m_oit_depth_render_buffer = 0;
GLuint m_depth_map_fbo = 0;
GLuint m_depth_map_texture = 0;
GLuint m_quad_vbo = 0;
glm::mat4 m_ui_proj; glm::mat4 m_ui_proj;
glm::mat4 m_ui_m_matrix; glm::mat4 m_ui_m_matrix;
std::unordered_map<std::size_t, Shader> m_shaders; std::unordered_map<std::size_t, Shader> m_shaders;
glm::vec3 m_blend_from_sundir;
glm::vec3 m_blend_to_sundir;
float m_blend_t = 1.0f;
bool m_blend_initialized = false;
static constexpr float BLEND_DURATION = 0.15f;
/*
0 - quad vao
1 - sky vao
2 - outline vao
3 - ui vao
4 - text vao
*/
std::vector<GLuint> m_vao; std::vector<GLuint> m_vao;
std::vector<Vertex2D> m_ui; std::vector<Vertex2D> m_ui;
void init_quad();
void init_text(); void init_text();
void render_outline(); void render_outline();
void render_sky(); void render_sky();
void render_text(); void render_text();
void render_ui(); void render_ui();
void render_world(); void render_world();
}; void render_underwater();
void render_dev_panel();
glm::vec3 quantize_sun_direction(const glm::vec3& sundir,
float angle_step_deg) const;
glm::vec3 get_smoothed_shadow_sundir(const glm::vec3& raw_shadow_sundir,
float dt);
};
} // namespace Cubed

View File

@@ -1,18 +1,22 @@
#pragma once #pragma once
#include <glad/glad.h> #include <glad/glad.h>
#include <string> #include <string>
#include <unordered_map>
namespace Cubed {
class Shader { class Shader {
public: public:
Shader(); Shader();
Shader(const std::string& name, const std::string& v_shader_path, const std::string& f_shader_path); Shader(const std::string& name, const std::string& v_shader_path,
const std::string& f_shader_path);
~Shader(); ~Shader();
Shader(const Shader&) = delete; Shader(const Shader&) = delete;
Shader& operator=(const Shader&) = delete; Shader& operator=(const Shader&) = delete;
Shader(Shader&& shader) noexcept; Shader(Shader&& shader) noexcept;
Shader& operator=(Shader&& shader) noexcept; Shader& operator=(Shader&& shader) noexcept;
void create(const std::string& name, const std::string& v_shader_path, const std::string& f_shader_path); void create(const std::string& name, const std::string& v_shader_path,
const std::string& f_shader_path);
std::size_t hash() const; std::size_t hash() const;
GLuint loc(const std::string& loc) const; GLuint loc(const std::string& loc) const;
const std::string& name() const; const std::string& name() const;
@@ -22,5 +26,7 @@ private:
GLuint m_program = 0; GLuint m_program = 0;
std::size_t m_hash = 0; std::size_t m_hash = 0;
std::string m_name = "-1"; std::string m_name = "-1";
mutable std::unordered_map<std::string, GLint> m_uniform_cache;
}; };
} // namespace Cubed

View File

@@ -1,31 +1,48 @@
#pragma once #pragma once
#include <glad/glad.h> #include "Cubed/gameplay/block.hpp"
#include <Cubed/gameplay/block.hpp>
#include <Cubed/tools/shader_tools.hpp>
#include <glad/glad.h>
namespace Cubed {
class TextureManager { class TextureManager {
private: private:
bool m_need_reload = false; bool m_need_reload = false;
GLuint m_block_status_array; GLuint m_block_status_array = 0;
GLuint m_texture_array; GLuint m_texture_array = 0;
GLuint m_ui_array; GLuint m_cross_plane_array = 0;
GLuint m_ui_array = 0;
GLfloat m_max_aniso = 0.0f;
int m_aniso = 1;
std::vector<GLuint> m_item_textures;
void load_block_status(unsigned status_id); void load_block_status(unsigned status_id);
void load_block_texture(unsigned block_id); void load_block_texture(unsigned block_id);
void load_block_item_texture(unsigned id);
void load_cross_plane_texture(unsigned id);
void load_ui_texture(unsigned id); void load_ui_texture(unsigned id);
void init_item();
void init_block();
void init_ui();
void init_block_status();
public: public:
TextureManager(); TextureManager();
~TextureManager(); ~TextureManager();
void delet_texture(); void delet_texture();
GLuint get_block_status_array() const; GLuint get_block_status_array() const;
GLuint get_texture_array() const; GLuint get_texture_array() const;
GLuint get_cross_plane_array() const;
GLuint get_ui_array() const; GLuint get_ui_array() const;
const std::vector<GLuint>& item_textures() const;
// Must call after MapTable::init_map() and glfwMakeContextCurrent(window); // Must call after MapTable::init_map() and glfwMakeContextCurrent(window);
void init_texture(); void init_texture();
void hot_reload(); void hot_reload();
void need_reload(); void need_reload();
void update(); void update();
int max_aniso() const;
}; };
} // namespace Cubed

View File

@@ -1,36 +1,39 @@
#pragma once #pragma once
#include <Cubed/tools/log.hpp> #include "Cubed/tools/log.hpp"
namespace Assert {
inline void msg(const char* condition, const char* file,
int line, const char* func,
std::string_view message = ""
) {
Logger::error("Assertion failed: {} at {}: {} in function {}",
condition, file, line, func);
if (message.size()) {
Logger::error("Message: {}", message);
}
std::abort();
namespace Cubed {
namespace Assert {
inline void msg(const char* condition, const char* file, int line,
const char* func, std::string_view message = "") {
Logger::error("Assertion failed: {} at {}: {} in function {}", condition,
file, line, func);
if (message.size()) {
Logger::error("Message: {}", message);
} }
std::abort();
} }
} // namespace Assert
#ifdef DEBUG_MODE #ifdef DEBUG_MODE
#define CUBED_ASSERT(cond) \ #define ASSERT(cond) \
do { \ do { \
if (!(cond)) { \ if (!(cond)) { \
::Assert::msg(#cond, __FILE__, __LINE__, __func__); \ ::Cubed::Assert::msg(#cond, __FILE__, __LINE__, __func__); \
} \ } \
} while (0) } while (0)
#define CUBED_ASSERT_MSG(cond, message) \ #define ASSERT_MSG(cond, message) \
do { \ do { \
if (!(cond)) { \ if (!(cond)) { \
::Assert::msg(#cond, __FILE__, __LINE__, __func__, message); \ ::Cubed::Assert::msg(#cond, __FILE__, __LINE__, __func__, \
} \ message); \
} \
} while (0) } while (0)
#else #else
#define CUBED_ASSERT(cond) ((void)0) #define ASSERT(cond) ((void)0)
#define CUBED_ASSERT_MSG(cond, message) ((void)0) #define ASSERT_MSG(cond, message) ((void)0)
#endif #endif
} // namespace Cubed

View File

@@ -1,8 +1,44 @@
#pragma once #pragma once
#include <cstdint>
#include <string_view> #include <string_view>
namespace Cubed {
namespace HASH { namespace HASH {
inline std::size_t str(std::string_view value) { inline std::size_t str(std::string_view value) {
return std::hash<std::string_view>{}(value); return std::hash<std::string_view>{}(value);
} }
inline uint32_t combine_32(uint32_t seed, uint32_t v) {
} seed ^= v + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
}
inline uint32_t chunk_seed_hash(int32_t a, int32_t b, uint32_t fixed_seed) {
uint32_t seed =
combine_32(combine_32(fixed_seed, (uint32_t)a), (uint32_t)b);
return seed;
}
/*
inline uint32_t chunk_seed_hash(int32_t a, int32_t b, uint32_t fixed_seed) {
uint32_t h = fixed_seed;
h ^= (uint32_t)a * 0xcc9e2d51u;
h = (h << 15) | (h >> 17); // rotl 15
h *= 0x1b873593u;
h ^= (uint32_t)b * 0xcc9e2d51u;
h = (h << 15) | (h >> 17); // rotl 15
h *= 0x1b873593u;
// Finalizationavalanche
h ^= h >> 16;
h *= 0x85ebca6bu;
h ^= h >> 13;
h *= 0xc2b2ae35u;
h ^= h >> 16;
return h;
}
*/
} // namespace HASH
} // namespace Cubed

View File

@@ -4,19 +4,19 @@ namespace Cubed {
class Random { class Random {
public: public:
static unsigned get_base_seed(); Random();
static unsigned get_thread_seed(); Random(unsigned seed);
static Random& get();
bool random_bool(double probability); bool random_bool(double probability);
std::mt19937& engine(); std::mt19937& engine();
unsigned seed(); unsigned seed();
void init(unsigned seed);
int random_int(int min, int max);
float random_float(float min, float max);
private: private:
Random();
unsigned int m_seed = 0; unsigned int m_seed = 0;
std::mt19937 m_engine; std::mt19937 m_engine;
}; };
} // namespace Cubed
}

View File

@@ -2,13 +2,14 @@
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include "Cubed/primitive_data.hpp"
#include <glad/glad.h> #include <glad/glad.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <Cubed/config.hpp> namespace Cubed {
struct Character { struct Character {
glm::vec2 uv_min; glm::vec2 uv_min;
@@ -25,8 +26,12 @@ public:
Font(); Font();
~Font(); ~Font();
static std::vector<Vertex2D> vertices(const std::string& text, float x = 0.0f, float y = 0.0f, float scale = 1.0f); static std::vector<Vertex2D> vertices(const std::string& text,
float x = 0.0f, float y = 0.0f,
float scale = 1.0f);
static GLuint text_texture(); static GLuint text_texture();
static const std::string& font_path();
private: private:
FT_Library m_ft; FT_Library m_ft;
FT_Face m_face; FT_Face m_face;
@@ -35,10 +40,12 @@ private:
float m_texture_height = 64; float m_texture_height = 64;
static inline GLuint m_text_texture; static inline GLuint m_text_texture;
static inline std::string m_font_path{ASSETS_PATH
"fonts/IBMPlexSans-Regular.ttf"};
std::unordered_map<char8_t, Character> m_characters; std::unordered_map<char8_t, Character> m_characters;
void load_character(char8_t c); void load_character(char8_t c);
void setup_font_character(); void setup_font_character();
};
} // namespace Cubed
};

Some files were not shown because too many files have changed in this diff Show More