first commit
15
content/editor/entities.lua
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
game_object = {
|
||||||
|
{ PROPERTY_STRING, "name", "Name of the object." } ,
|
||||||
|
{ PROPERTY_STRING_NOT_EDITABLE, "classname", "Clasname." },
|
||||||
|
{ PROPERTY_VEC3, "position", "World position." },
|
||||||
|
{ PROPERTY_VEC3, "rotation", "World rotation." },
|
||||||
|
{ PROPERTY_VEC3, "scale", "World scale." },
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
editor_entities = {
|
||||||
|
|
||||||
|
{ game_object, "game_object" },
|
||||||
|
|
||||||
|
}
|
24
content/levels/playertest.txt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
BeginEntity test_entity
|
||||||
|
ClassName Player
|
||||||
|
Position 0.0 0.0 0.0
|
||||||
|
Rotation 0.0 0.0 0.0
|
||||||
|
EndEntity
|
||||||
|
|
||||||
|
# Water
|
||||||
|
BeginEntity water_test
|
||||||
|
ClassName GameObject
|
||||||
|
Tag Water
|
||||||
|
Position 0.0 -0.1 0.0
|
||||||
|
Rotation 0.0 0.0 0.0
|
||||||
|
Visual content/test/water_test.obj
|
||||||
|
EndEntity
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Enemies ...
|
||||||
|
|
||||||
|
BeginEntity test_enemy
|
||||||
|
ClassName GameObject
|
||||||
|
Position -2.70 0.00 3.28
|
||||||
|
Rotation 0.0 0.0 0.0
|
||||||
|
Visual content/test/ship.obj
|
||||||
|
EndEntity
|
10
content/shaders/debug_draw.ps
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec3 v_color;
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fragColor = vec4(v_color, 1.0);
|
||||||
|
}
|
15
content/shaders/debug_draw.vs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 position;
|
||||||
|
layout (location = 1) in vec3 color;
|
||||||
|
|
||||||
|
out vec3 v_color;
|
||||||
|
|
||||||
|
uniform mat4 u_modelViewProjection;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = u_modelViewProjection * vec4(position, 1.0f);
|
||||||
|
|
||||||
|
v_color = color;
|
||||||
|
}
|
15
content/shaders/lit_generic.ps
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#version 120
|
||||||
|
|
||||||
|
varying vec3 v_position;
|
||||||
|
varying vec3 v_normal;
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
varying vec3 v_finalColor;
|
||||||
|
|
||||||
|
uniform sampler2D u_albedoTexture;
|
||||||
|
uniform vec4 u_customColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
//gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
|
gl_FragColor = u_customColor * vec4(v_finalColor, 1.0) * texture2D(u_albedoTexture, v_texcoord);
|
||||||
|
//gl_FragColor = vec4( v_normal, 1.0 );
|
||||||
|
}
|
46
content/shaders/lit_generic.vs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#version 120
|
||||||
|
|
||||||
|
attribute vec3 a_position;
|
||||||
|
attribute vec3 a_normal;
|
||||||
|
attribute vec2 a_texcoord;
|
||||||
|
|
||||||
|
varying vec3 v_position;
|
||||||
|
varying vec3 v_normal;
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
varying vec3 v_finalColor;
|
||||||
|
|
||||||
|
uniform mat4 u_modelMatrix;
|
||||||
|
uniform mat4 u_viewMatrix;
|
||||||
|
uniform mat4 u_projectionMatrix;
|
||||||
|
uniform mat4 u_modelViewProjection;
|
||||||
|
|
||||||
|
vec3 CalcOmniLight()
|
||||||
|
{
|
||||||
|
vec3 lightPos = vec3(0.1, 2.1, 0.1);
|
||||||
|
float d = distance(lightPos, v_position);
|
||||||
|
vec3 L = normalize(lightPos-v_position);
|
||||||
|
vec3 N = normalize(v_normal);
|
||||||
|
vec3 col = vec3( max(0, dot(N, L) / d) );
|
||||||
|
col = col * 0.8 + 0.2;
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 CalcDirLight()
|
||||||
|
{
|
||||||
|
vec3 lightPos = vec3(5.0, 10.0, 1.0);
|
||||||
|
//lightPos = -lightPos;
|
||||||
|
|
||||||
|
vec3 L = normalize(lightPos);
|
||||||
|
vec3 N = normalize(v_normal);
|
||||||
|
vec3 col = vec3( max(0, dot(N, L)) );
|
||||||
|
col = col * 0.8 + 0.2;
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
v_position = vec3( u_modelMatrix * vec4(a_position, 1.0) );
|
||||||
|
v_normal = vec3( mat3(u_modelMatrix) * a_normal );
|
||||||
|
v_texcoord = a_texcoord;
|
||||||
|
v_finalColor = CalcDirLight();
|
||||||
|
gl_Position = u_modelViewProjection * vec4(a_position, 1);
|
||||||
|
}
|
15
content/shaders/lit_generic_texcoordgen.ps
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#version 120
|
||||||
|
|
||||||
|
varying vec3 v_position;
|
||||||
|
varying vec3 v_normal;
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
varying vec3 v_finalColor;
|
||||||
|
|
||||||
|
uniform sampler2D u_albedoTexture;
|
||||||
|
uniform vec4 u_customColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
//gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
|
gl_FragColor = u_customColor * vec4(v_finalColor, 1.0) * texture2D(u_albedoTexture, v_texcoord);
|
||||||
|
//gl_FragColor = vec4( v_normal, 1.0 );
|
||||||
|
}
|
8
content/shaders/ui_base.ps
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#version 120
|
||||||
|
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
varying vec4 v_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = v_color;
|
||||||
|
}
|
16
content/shaders/ui_base.vs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#version 120
|
||||||
|
|
||||||
|
attribute vec2 a_position;
|
||||||
|
attribute vec2 a_texcoord;
|
||||||
|
attribute vec4 a_color;
|
||||||
|
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
varying vec4 v_color;
|
||||||
|
|
||||||
|
uniform mat4 u_projectionMatrix;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
v_texcoord = a_texcoord;
|
||||||
|
v_color = a_color;
|
||||||
|
gl_Position = u_projectionMatrix * vec4(a_position.xy,0,1);
|
||||||
|
}
|
11
content/shaders/ui_tex.ps
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#version 120
|
||||||
|
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
varying vec4 v_color;
|
||||||
|
|
||||||
|
uniform sampler2D u_texture;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 tex = texture2D( u_texture, v_texcoord );
|
||||||
|
gl_FragColor = v_color * tex;
|
||||||
|
}
|
BIN
content/test/ship.blend
Normal file
BIN
content/test/ship.blend1
Normal file
13
content/test/ship.mtl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Blender 4.0.2 MTL File: 'ship.blend'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.001
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
#map_Kd content/test/uvgrid.png
|
||||||
|
map_Kd content/test/tetrad.png
|
478
content/test/ship.obj
Normal file
@ -0,0 +1,478 @@
|
|||||||
|
# Blender 4.0.2
|
||||||
|
# www.blender.org
|
||||||
|
mtllib ship.mtl
|
||||||
|
o ship
|
||||||
|
v -0.206022 0.561873 -0.011206
|
||||||
|
v -0.119716 0.560522 0.008077
|
||||||
|
v -0.004751 0.563370 -0.023105
|
||||||
|
v 0.055282 0.559558 -0.007712
|
||||||
|
v 0.145744 0.561427 0.010017
|
||||||
|
v 0.213930 0.562807 -0.008303
|
||||||
|
v -0.161451 0.562805 0.002926
|
||||||
|
v 0.003766 0.534670 -0.026896
|
||||||
|
v -0.203839 0.511860 -0.018421
|
||||||
|
v -0.162010 0.485302 -0.011563
|
||||||
|
v 0.213836 0.478134 -0.020207
|
||||||
|
v -0.045692 0.468001 -0.022078
|
||||||
|
v 0.082312 0.521381 -0.023491
|
||||||
|
v 0.044539 0.402209 -0.003451
|
||||||
|
v -0.205619 0.398058 0.004964
|
||||||
|
v -0.169031 0.381641 0.021240
|
||||||
|
v -0.068870 0.339942 0.010303
|
||||||
|
v 0.009781 0.363531 -0.014819
|
||||||
|
v 0.096103 0.397493 0.019756
|
||||||
|
v 0.217964 0.399421 0.006125
|
||||||
|
v -0.204553 0.325254 0.003283
|
||||||
|
v -0.156494 0.281751 0.003940
|
||||||
|
v 0.020743 0.317356 -0.021851
|
||||||
|
v 0.129477 0.339985 0.026030
|
||||||
|
v 0.220711 0.306984 0.005506
|
||||||
|
v -0.076777 0.258270 -0.021832
|
||||||
|
v -0.029258 0.288322 -0.010229
|
||||||
|
v 0.066269 0.241267 -0.016551
|
||||||
|
v 0.146799 0.185187 -0.011010
|
||||||
|
v -0.154116 0.185233 -0.016433
|
||||||
|
v -0.031760 0.211335 -0.023012
|
||||||
|
v 0.004891 0.201931 -0.031796
|
||||||
|
v 0.212805 0.190185 -0.016808
|
||||||
|
v -0.204504 0.199190 -0.017579
|
||||||
|
v -0.095264 0.184441 -0.020341
|
||||||
|
v 0.046662 0.144795 -0.003573
|
||||||
|
v -0.204608 0.144531 -0.017393
|
||||||
|
v -0.156809 0.146968 0.008014
|
||||||
|
v -0.079562 0.145971 -0.007068
|
||||||
|
v -0.036451 0.146321 0.007217
|
||||||
|
v 0.004779 0.135828 -0.015514
|
||||||
|
v 0.172277 0.145146 0.007740
|
||||||
|
v 0.214538 0.144846 0.002540
|
||||||
|
v -0.167417 0.048338 0.229981
|
||||||
|
v -0.169698 0.120416 0.169698
|
||||||
|
v -0.176530 0.046931 -0.176530
|
||||||
|
v 0.176530 0.046931 0.176530
|
||||||
|
v 0.169698 0.120416 0.169698
|
||||||
|
v 0.167417 0.048338 -0.229981
|
||||||
|
v 0.149213 0.119405 -0.270229
|
||||||
|
v 0.146055 0.120416 0.270657
|
||||||
|
v -0.149213 0.119405 0.270229
|
||||||
|
v -0.146055 0.120416 -0.270657
|
||||||
|
v -0.149420 0.054673 -0.264796
|
||||||
|
v 0.149420 0.054673 0.264796
|
||||||
|
v -0.002886 0.116702 0.423249
|
||||||
|
v 0.000000 0.120416 -0.416631
|
||||||
|
v 0.000000 0.046931 -0.416631
|
||||||
|
v -0.169698 0.120416 -0.169698
|
||||||
|
v 0.169698 0.120416 -0.169698
|
||||||
|
v 0.137782 0.120416 -0.244473
|
||||||
|
v 0.134751 0.120416 0.249709
|
||||||
|
v -0.134751 0.120416 -0.249709
|
||||||
|
v -0.137782 0.120416 0.244473
|
||||||
|
v 0.000000 0.116627 0.384384
|
||||||
|
v 0.000000 0.116627 -0.384384
|
||||||
|
v 0.148794 0.101470 -0.232115
|
||||||
|
v -0.148794 0.101470 0.232115
|
||||||
|
v 0.154047 0.101470 0.222255
|
||||||
|
v -0.154047 0.101470 -0.222255
|
||||||
|
v -0.066114 -0.165458 -0.222948
|
||||||
|
v -0.068212 -0.165409 0.217791
|
||||||
|
v 0.068212 -0.165409 -0.217791
|
||||||
|
v 0.066114 -0.165458 0.222948
|
||||||
|
v -0.003313 -0.164842 0.347649
|
||||||
|
v 0.003313 -0.164842 -0.347649
|
||||||
|
v -0.008288 0.574476 -0.002763
|
||||||
|
v -0.008288 0.091646 0.002763
|
||||||
|
v 0.008288 0.091646 -0.002763
|
||||||
|
v 0.008288 0.574476 0.002763
|
||||||
|
v -0.299244 0.509855 -0.002763
|
||||||
|
v 0.299244 0.509855 0.002763
|
||||||
|
v 0.299244 0.526432 -0.002763
|
||||||
|
v -0.299244 0.526432 0.002763
|
||||||
|
v -0.299244 0.185914 -0.002763
|
||||||
|
v 0.299244 0.185914 0.002763
|
||||||
|
v 0.299244 0.202490 -0.002763
|
||||||
|
v -0.299244 0.202490 0.002763
|
||||||
|
vn 0.2960 0.1490 -0.9435
|
||||||
|
vn 0.1042 0.2427 -0.9645
|
||||||
|
vn 0.2031 0.0498 -0.9779
|
||||||
|
vn 0.1526 0.4199 -0.8946
|
||||||
|
vn 0.0654 0.1817 -0.9812
|
||||||
|
vn 0.0049 0.0973 -0.9952
|
||||||
|
vn 0.0234 -0.0659 -0.9976
|
||||||
|
vn 0.2961 -0.1736 -0.9392
|
||||||
|
vn 0.4145 -0.2013 -0.8875
|
||||||
|
vn 0.0536 0.0203 -0.9984
|
||||||
|
vn 0.1127 -0.0811 -0.9903
|
||||||
|
vn 0.2245 0.1521 -0.9625
|
||||||
|
vn -0.0913 0.1252 -0.9879
|
||||||
|
vn -0.1088 -0.0643 -0.9920
|
||||||
|
vn -0.1416 -0.1919 -0.9711
|
||||||
|
vn 0.0753 0.0706 -0.9947
|
||||||
|
vn 0.2214 -0.2971 -0.9288
|
||||||
|
vn -0.1656 0.1289 -0.9777
|
||||||
|
vn 0.1741 0.0710 -0.9822
|
||||||
|
vn 0.0013 0.1961 -0.9806
|
||||||
|
vn 0.0693 0.1131 -0.9912
|
||||||
|
vn -0.2896 0.0434 -0.9562
|
||||||
|
vn -0.0926 0.1833 -0.9787
|
||||||
|
vn 0.0158 -0.1219 -0.9924
|
||||||
|
vn -0.0801 -0.1775 -0.9809
|
||||||
|
vn -0.0108 -0.0845 -0.9964
|
||||||
|
vn -0.0855 -0.0924 -0.9920
|
||||||
|
vn 0.1983 -0.2123 -0.9569
|
||||||
|
vn 0.1618 -0.5128 -0.8431
|
||||||
|
vn 0.0552 -0.1308 -0.9899
|
||||||
|
vn 0.0491 -0.3777 -0.9246
|
||||||
|
vn -0.1157 -0.2374 -0.9645
|
||||||
|
vn -0.0945 -0.1010 -0.9904
|
||||||
|
vn -0.0217 -0.4108 -0.9115
|
||||||
|
vn -0.1150 -0.3936 -0.9121
|
||||||
|
vn 0.5507 -0.3000 -0.7789
|
||||||
|
vn 0.9705 0.1358 -0.1991
|
||||||
|
vn -0.0000 1.0000 -0.0000
|
||||||
|
vn -0.9705 0.1358 0.1991
|
||||||
|
vn -0.5507 -0.3000 0.7789
|
||||||
|
vn -0.8038 -0.3896 -0.4495
|
||||||
|
vn -0.7124 0.0428 0.7004
|
||||||
|
vn 0.8641 -0.3331 0.3774
|
||||||
|
vn 0.7157 -0.0256 0.6979
|
||||||
|
vn 0.7124 0.0428 -0.7004
|
||||||
|
vn -0.8641 -0.3331 -0.3774
|
||||||
|
vn -0.0031 0.9954 -0.0960
|
||||||
|
vn 0.0031 0.9954 0.0960
|
||||||
|
vn 0.8860 -0.2683 -0.3782
|
||||||
|
vn -0.8860 -0.2683 0.3782
|
||||||
|
vn 0.8038 -0.3896 0.4495
|
||||||
|
vn 0.0708 0.9051 -0.4193
|
||||||
|
vn -0.0546 0.1148 -0.9919
|
||||||
|
vn -0.1125 0.7364 -0.6671
|
||||||
|
vn 0.0035 0.3344 -0.9424
|
||||||
|
vn 0.0104 -0.1386 -0.9903
|
||||||
|
vn 0.0321 0.0517 -0.9981
|
||||||
|
vn 0.2213 -0.2523 -0.9420
|
||||||
|
vn -0.0870 -0.3704 -0.9248
|
||||||
|
vn -0.9957 0.0926 -0.0000
|
||||||
|
vn 0.9957 0.0926 -0.0000
|
||||||
|
vn 0.0183 0.9998 -0.0099
|
||||||
|
vn -0.1072 0.9874 0.1160
|
||||||
|
vn 0.9732 0.0295 0.2279
|
||||||
|
vn -0.9732 0.0295 -0.2279
|
||||||
|
vn 0.8866 -0.1307 -0.4437
|
||||||
|
vn -0.0183 0.9998 0.0099
|
||||||
|
vn -0.7069 -0.0000 -0.7073
|
||||||
|
vn -0.6844 0.7291 0.0079
|
||||||
|
vn 0.8713 -0.3871 0.3016
|
||||||
|
vn 0.7004 -0.0000 -0.7138
|
||||||
|
vn 0.6683 -0.1939 0.7182
|
||||||
|
vn 0.0190 0.9998 -0.0005
|
||||||
|
vn 0.0450 0.9988 -0.0192
|
||||||
|
vn -0.0450 0.9988 0.0192
|
||||||
|
vn 0.6844 0.7291 -0.0079
|
||||||
|
vn 0.6820 0.2827 0.6745
|
||||||
|
vn -0.6820 0.2827 -0.6745
|
||||||
|
vn -0.0004 -1.0000 -0.0001
|
||||||
|
vn 0.8876 -0.4605 0.0042
|
||||||
|
vn -0.0005 -1.0000 0.0046
|
||||||
|
vn 0.0005 -1.0000 -0.0046
|
||||||
|
vn -0.6993 -0.2313 -0.6764
|
||||||
|
vn -0.8876 -0.4605 -0.0042
|
||||||
|
vn -0.8713 -0.3871 -0.3016
|
||||||
|
vn -0.8472 -0.3191 0.4248
|
||||||
|
vn -0.3162 0.0109 -0.9486
|
||||||
|
vn 0.3162 0.0109 0.9486
|
||||||
|
vn -0.0088 -0.3162 -0.9486
|
||||||
|
vn -0.0088 0.3162 0.9486
|
||||||
|
vn -0.9997 -0.0129 0.0225
|
||||||
|
vn 0.9997 -0.0129 -0.0225
|
||||||
|
vn 0.1159 0.9865 0.1159
|
||||||
|
vn 0.0085 0.9993 -0.0354
|
||||||
|
vn 0.9524 0.1148 0.2824
|
||||||
|
vn -0.9524 0.1148 -0.2824
|
||||||
|
vn 0.7382 -0.3193 -0.5943
|
||||||
|
vn -0.0291 0.9996 -0.0041
|
||||||
|
vn -0.7132 -0.0259 -0.7005
|
||||||
|
vn -0.7710 0.6369 -0.0000
|
||||||
|
vn -0.0085 0.9993 0.0354
|
||||||
|
vn 0.7710 0.6369 -0.0000
|
||||||
|
vn 0.0004 -1.0000 0.0001
|
||||||
|
vn 0.9064 -0.4219 -0.0218
|
||||||
|
vn -0.9064 -0.4219 0.0218
|
||||||
|
vn -0.7124 -0.1810 0.6780
|
||||||
|
vn 0.3162 -0.0109 -0.9486
|
||||||
|
vn -0.3162 -0.0109 0.9486
|
||||||
|
vn 0.0088 0.3162 -0.9486
|
||||||
|
vn 0.0088 -0.3162 0.9486
|
||||||
|
vt 0.249493 0.888699
|
||||||
|
vt 0.300679 0.888352
|
||||||
|
vt 0.252663 0.828817
|
||||||
|
vt 0.564031 0.887391
|
||||||
|
vt 0.604969 0.823879
|
||||||
|
vt 0.501539 0.840125
|
||||||
|
vt 0.305402 0.774472
|
||||||
|
vt 0.250800 0.691603
|
||||||
|
vt 0.555279 0.692751
|
||||||
|
vt 0.502804 0.650588
|
||||||
|
vt 0.298686 0.672311
|
||||||
|
vt 0.250764 0.604810
|
||||||
|
vt 0.468563 0.568169
|
||||||
|
vt 0.443762 0.782837
|
||||||
|
vt 0.758306 0.691625
|
||||||
|
vt 0.655221 0.628090
|
||||||
|
vt 0.614851 0.694249
|
||||||
|
vt 0.762260 0.582675
|
||||||
|
vt 0.587125 0.509568
|
||||||
|
vt 0.309337 0.543049
|
||||||
|
vt 0.251234 0.453628
|
||||||
|
vt 0.408695 0.616702
|
||||||
|
vt 0.402239 0.524216
|
||||||
|
vt 0.642557 0.450784
|
||||||
|
vt 0.379100 0.438470
|
||||||
|
vt 0.502499 0.456641
|
||||||
|
vt 0.452134 0.468589
|
||||||
|
vt 0.553067 0.388907
|
||||||
|
vt 0.308797 0.392191
|
||||||
|
vt 0.302135 0.439353
|
||||||
|
vt 0.401258 0.389574
|
||||||
|
vt 0.502475 0.377401
|
||||||
|
vt 0.752623 0.441086
|
||||||
|
vt 0.703496 0.388274
|
||||||
|
vt 0.754208 0.388223
|
||||||
|
vt 0.768893 0.270715
|
||||||
|
vt 0.754316 0.015814
|
||||||
|
vt 0.813716 0.356142
|
||||||
|
vt 0.706982 0.358905
|
||||||
|
vt 0.293085 0.698783
|
||||||
|
vt 0.338306 0.791985
|
||||||
|
vt 0.325015 0.816889
|
||||||
|
vt 0.221363 0.270715
|
||||||
|
vt 0.176540 0.356142
|
||||||
|
vt 0.283275 0.358905
|
||||||
|
vt 0.235941 0.015814
|
||||||
|
vt 0.810847 0.270715
|
||||||
|
vt 0.916090 0.015814
|
||||||
|
vt 0.762219 0.015814
|
||||||
|
vt 0.700395 0.291473
|
||||||
|
vt 0.655175 0.198272
|
||||||
|
vt 0.668466 0.173368
|
||||||
|
vt 0.496740 0.354358
|
||||||
|
vt 0.591654 0.336168
|
||||||
|
vt 0.591654 0.358905
|
||||||
|
vt 0.690585 0.358905
|
||||||
|
vt 0.757323 0.336168
|
||||||
|
vt 0.791985 0.358905
|
||||||
|
vt 0.599616 0.358905
|
||||||
|
vt 0.496740 0.354447
|
||||||
|
vt 0.599616 0.270715
|
||||||
|
vt 0.401827 0.336168
|
||||||
|
vt 0.401827 0.358905
|
||||||
|
vt 0.299672 0.358905
|
||||||
|
vt 0.232934 0.336168
|
||||||
|
vt 0.198272 0.358905
|
||||||
|
vt 0.669690 0.232934
|
||||||
|
vt 0.329763 0.221671
|
||||||
|
vt 0.496740 0.033828
|
||||||
|
vt 0.323790 0.757323
|
||||||
|
vt 0.663718 0.768586
|
||||||
|
vt 0.496740 0.956429
|
||||||
|
vt 0.203684 0.358905
|
||||||
|
vt 0.221671 0.336168
|
||||||
|
vt 0.786573 0.358905
|
||||||
|
vt 0.768586 0.336168
|
||||||
|
vt 0.179409 0.270715
|
||||||
|
vt 0.074167 0.015814
|
||||||
|
vt 0.228038 0.015814
|
||||||
|
vt 0.353089 0.887169
|
||||||
|
vt 0.491410 0.889914
|
||||||
|
vt 0.671747 0.882793
|
||||||
|
vt 0.753450 0.889732
|
||||||
|
vt 0.751248 0.782506
|
||||||
|
vt 0.521490 0.588413
|
||||||
|
vt 0.251190 0.387845
|
||||||
|
vt 0.452996 0.389993
|
||||||
|
vt 0.706982 0.270715
|
||||||
|
vt 0.283275 0.270715
|
||||||
|
vt 0.673508 0.811023
|
||||||
|
vt 0.496740 0.995128
|
||||||
|
vt 0.173368 0.358905
|
||||||
|
vt 0.816889 0.358905
|
||||||
|
vt 0.995128 0.270715
|
||||||
|
vt 0.496740 0.270715
|
||||||
|
vt 0.393864 0.358905
|
||||||
|
vt 0.496740 0.358905
|
||||||
|
vt 0.599616 0.356142
|
||||||
|
vt -0.004872 0.270715
|
||||||
|
vt 0.319973 0.179234
|
||||||
|
vt 0.496740 -0.004872
|
||||||
|
vt 0.700395 0.698783
|
||||||
|
vt 0.659826 0.786573
|
||||||
|
vt 0.293085 0.291473
|
||||||
|
vt 0.333655 0.203684
|
||||||
|
vt 0.424218 0.235941
|
||||||
|
vt 0.569262 0.754316
|
||||||
|
vt 0.572861 0.228038
|
||||||
|
vt 0.500066 0.074167
|
||||||
|
vt 0.420620 0.762219
|
||||||
|
vt 0.493415 0.916090
|
||||||
|
vt 0.486794 0.324378
|
||||||
|
vt 0.491813 0.903823
|
||||||
|
vt 0.498444 0.324378
|
||||||
|
vt 0.506687 0.324378
|
||||||
|
vt 0.498444 0.903823
|
||||||
|
vt 0.491813 0.324378
|
||||||
|
vt 0.855863 0.826272
|
||||||
|
vt 0.137617 0.846165
|
||||||
|
vt 0.855863 0.846165
|
||||||
|
vt 0.137617 0.826272
|
||||||
|
vt 0.855863 0.437509
|
||||||
|
vt 0.137617 0.457403
|
||||||
|
vt 0.855863 0.457402
|
||||||
|
vt 0.137617 0.437509
|
||||||
|
vt 0.393864 0.270715
|
||||||
|
vt 0.486794 0.903823
|
||||||
|
vt 0.506687 0.903823
|
||||||
|
s 1
|
||||||
|
usemtl Material.001
|
||||||
|
f 1/1/1 7/2/2 9/3/3
|
||||||
|
f 4/4/4 13/5/5 8/6/6
|
||||||
|
f 10/7/7 15/8/8 9/3/3
|
||||||
|
f 14/9/9 18/10/10 13/5/5
|
||||||
|
f 15/8/8 16/11/11 21/12/12
|
||||||
|
f 18/10/10 27/13/13 12/14/14
|
||||||
|
f 20/15/15 24/16/16 19/17/17
|
||||||
|
f 20/15/15 25/18/18 24/16/16
|
||||||
|
f 24/16/16 28/19/19 19/17/17
|
||||||
|
f 21/12/12 22/20/20 34/21/21
|
||||||
|
f 17/22/22 26/23/23 22/20/20
|
||||||
|
f 17/22/22 27/13/13 26/23/23
|
||||||
|
f 25/18/18 29/24/24 24/16/16
|
||||||
|
f 22/20/20 26/23/23 35/25/25
|
||||||
|
f 27/13/13 28/19/19 32/26/26
|
||||||
|
f 31/27/27 35/25/25 26/23/23
|
||||||
|
f 28/19/19 29/24/24 36/28/28
|
||||||
|
f 35/25/25 38/29/29 30/30/30
|
||||||
|
f 35/25/25 39/31/31 38/29/29
|
||||||
|
f 32/26/26 36/28/28 41/32/32
|
||||||
|
f 33/33/33 42/34/34 29/24/24
|
||||||
|
f 33/33/33 43/35/35 42/34/34
|
||||||
|
s 0
|
||||||
|
f 49/36/36 73/37/36 50/38/36
|
||||||
|
f 49/36/37 50/38/37 60/39/37
|
||||||
|
f 59/40/38 63/41/38 53/42/38
|
||||||
|
f 44/43/39 52/44/39 45/45/39
|
||||||
|
f 44/43/40 72/46/40 52/44/40
|
||||||
|
f 54/47/41 76/48/41 71/49/41
|
||||||
|
f 48/50/38 62/51/38 51/52/38
|
||||||
|
f 66/53/42 67/54/42 61/55/42
|
||||||
|
f 59/56/43 70/57/43 63/58/43
|
||||||
|
f 51/59/44 56/60/44 55/61/44
|
||||||
|
f 65/53/45 68/62/45 64/63/45
|
||||||
|
f 48/64/46 69/65/46 62/66/46
|
||||||
|
f 69/67/47 68/68/47 65/69/47
|
||||||
|
f 70/70/48 67/71/48 66/72/48
|
||||||
|
f 64/73/49 68/74/49 45/64/49
|
||||||
|
f 61/75/50 67/76/50 60/56/50
|
||||||
|
f 55/77/51 75/78/51 74/79/51
|
||||||
|
s 1
|
||||||
|
f 2/80/52 8/6/6 7/2/2
|
||||||
|
f 2/80/52 3/81/53 8/6/6
|
||||||
|
f 3/81/53 4/4/4 8/6/6
|
||||||
|
f 4/4/4 5/82/54 13/5/5
|
||||||
|
f 5/82/54 6/83/55 13/5/5
|
||||||
|
f 9/3/3 7/2/2 10/7/7
|
||||||
|
f 16/11/11 12/14/14 17/22/22
|
||||||
|
f 8/6/6 13/5/5 12/14/14
|
||||||
|
f 13/5/5 6/83/55 11/84/56
|
||||||
|
f 13/5/5 11/84/56 14/9/9
|
||||||
|
f 10/7/7 16/11/11 15/8/8
|
||||||
|
f 23/85/57 19/17/17 28/19/19
|
||||||
|
f 13/5/5 18/10/10 12/14/14
|
||||||
|
f 14/9/9 11/84/56 19/17/17
|
||||||
|
f 11/84/56 20/15/15 19/17/17
|
||||||
|
f 17/22/22 12/14/14 27/13/13
|
||||||
|
f 21/12/12 16/11/11 22/20/20
|
||||||
|
f 16/11/11 17/22/22 22/20/20
|
||||||
|
f 18/10/10 23/85/57 27/13/13
|
||||||
|
f 18/10/10 14/9/9 23/85/57
|
||||||
|
f 37/86/58 30/30/30 38/29/29
|
||||||
|
f 23/85/57 28/19/19 27/13/13
|
||||||
|
f 24/16/16 29/24/24 28/19/19
|
||||||
|
f 22/20/20 30/30/30 34/21/21
|
||||||
|
f 22/20/20 35/25/25 30/30/30
|
||||||
|
f 26/23/23 27/13/13 31/27/27
|
||||||
|
f 27/13/13 32/26/26 31/27/27
|
||||||
|
f 29/24/24 25/18/18 33/33/33
|
||||||
|
f 32/26/26 28/19/19 36/28/28
|
||||||
|
f 39/31/31 31/27/27 40/87/59
|
||||||
|
f 40/87/59 32/26/26 41/32/32
|
||||||
|
s 0
|
||||||
|
f 46/88/60 45/45/60 59/39/60
|
||||||
|
s 1
|
||||||
|
f 29/24/24 42/34/34 36/28/28
|
||||||
|
s 0
|
||||||
|
f 47/89/61 60/39/61 48/45/61
|
||||||
|
f 66/72/62 53/42/62 63/41/62
|
||||||
|
f 66/72/63 50/90/63 57/91/63
|
||||||
|
f 55/77/64 48/45/64 51/92/64
|
||||||
|
f 54/47/65 59/39/65 53/93/65
|
||||||
|
f 58/94/66 73/37/66 76/48/66
|
||||||
|
f 65/69/67 51/52/67 62/51/67
|
||||||
|
s 1
|
||||||
|
f 7/2/2 12/14/14 10/7/7
|
||||||
|
s 0
|
||||||
|
f 58/95/68 53/96/68 57/97/68
|
||||||
|
f 69/65/69 60/56/69 67/76/69
|
||||||
|
f 47/89/70 55/77/70 74/79/70
|
||||||
|
f 50/98/71 58/95/71 57/97/71
|
||||||
|
f 55/77/72 56/99/72 75/78/72
|
||||||
|
f 65/69/73 52/100/73 56/101/73
|
||||||
|
f 60/102/74 50/90/74 61/103/74
|
||||||
|
f 45/104/75 52/100/75 64/105/75
|
||||||
|
f 69/67/38 70/70/38 68/68/38
|
||||||
|
f 70/57/76 45/64/76 68/74/76
|
||||||
|
f 63/63/77 70/62/77 66/53/77
|
||||||
|
f 62/55/78 69/54/78 65/53/78
|
||||||
|
f 72/106/79 73/107/79 74/108/79
|
||||||
|
f 73/37/80 47/89/80 74/79/80
|
||||||
|
f 74/108/81 75/109/81 72/106/81
|
||||||
|
f 71/110/82 76/111/82 73/107/82
|
||||||
|
f 54/47/83 58/94/83 76/48/83
|
||||||
|
f 72/46/84 46/88/84 71/49/84
|
||||||
|
f 46/88/85 54/47/85 71/49/85
|
||||||
|
f 75/78/86 52/44/86 72/46/86
|
||||||
|
f 78/112/87 80/113/87 79/114/87
|
||||||
|
f 79/115/88 77/116/88 78/117/88
|
||||||
|
f 82/118/89 84/119/89 83/120/89
|
||||||
|
f 83/120/90 81/121/90 82/118/90
|
||||||
|
f 86/122/89 88/123/89 87/124/89
|
||||||
|
f 87/124/90 85/125/90 86/122/90
|
||||||
|
s 1
|
||||||
|
f 16/11/11 10/7/7 12/14/14
|
||||||
|
f 23/85/57 14/9/9 19/17/17
|
||||||
|
f 37/86/58 34/21/21 30/30/30
|
||||||
|
f 39/31/31 35/25/25 31/27/27
|
||||||
|
f 40/87/59 31/27/27 32/26/26
|
||||||
|
s 0
|
||||||
|
f 46/88/91 44/43/91 45/45/91
|
||||||
|
f 47/89/92 49/36/92 60/39/92
|
||||||
|
f 66/72/93 57/91/93 53/42/93
|
||||||
|
f 66/72/94 61/103/94 50/90/94
|
||||||
|
f 55/77/95 47/89/95 48/45/95
|
||||||
|
f 54/47/96 46/88/96 59/39/96
|
||||||
|
f 58/94/97 50/38/97 73/37/97
|
||||||
|
f 65/69/98 56/101/98 51/52/98
|
||||||
|
s 1
|
||||||
|
f 7/2/2 8/6/6 12/14/14
|
||||||
|
s 0
|
||||||
|
f 58/95/99 54/126/99 53/96/99
|
||||||
|
f 69/65/100 48/64/100 60/56/100
|
||||||
|
f 65/69/101 64/105/101 52/100/101
|
||||||
|
f 69/67/38 67/71/38 70/70/38
|
||||||
|
f 70/57/102 59/56/102 45/64/102
|
||||||
|
f 72/106/103 71/110/103 73/107/103
|
||||||
|
f 73/37/104 49/36/104 47/89/104
|
||||||
|
f 72/46/105 44/43/105 46/88/105
|
||||||
|
f 75/78/106 56/99/106 52/44/106
|
||||||
|
f 78/112/107 77/127/107 80/113/107
|
||||||
|
f 79/115/108 80/128/108 77/116/108
|
||||||
|
f 82/118/109 81/121/109 84/119/109
|
||||||
|
f 83/120/110 84/119/110 81/121/110
|
||||||
|
f 86/122/109 85/125/109 88/123/109
|
||||||
|
f 87/124/110 88/123/110 85/125/110
|
BIN
content/test/ship_back2.blend
Normal file
BIN
content/test/ship_backup.blend
Normal file
14
content/test/ship_weapon.mtl
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Blender 3.6.7 MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.001
|
||||||
|
Ns 360.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Kd 0.800000 0.800000 0.800000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.000000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd content/test/uvgrid.png
|
||||||
|
|
222
content/test/ship_weapon.obj
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
# Blender 3.6.7
|
||||||
|
# www.blender.org
|
||||||
|
mtllib ship_weapon.mtl
|
||||||
|
o Circle
|
||||||
|
v -0.001998 0.003339 -0.279058
|
||||||
|
v -0.060548 0.003339 -0.273291
|
||||||
|
v -0.116848 0.003339 -0.256213
|
||||||
|
v -0.168735 0.003339 -0.228479
|
||||||
|
v -0.214213 0.003339 -0.191155
|
||||||
|
v -0.251537 0.003339 -0.145676
|
||||||
|
v -0.279271 0.003339 -0.093790
|
||||||
|
v -0.296349 0.003339 -0.037490
|
||||||
|
v -0.302116 0.003339 0.021060
|
||||||
|
v -0.296349 0.003339 0.079610
|
||||||
|
v -0.279271 0.003339 0.135910
|
||||||
|
v -0.251537 0.003339 0.187796
|
||||||
|
v -0.214213 0.003339 0.233275
|
||||||
|
v -0.168735 0.003339 0.270599
|
||||||
|
v -0.116848 0.003339 0.298332
|
||||||
|
v -0.060548 0.003339 0.315411
|
||||||
|
v -0.001998 0.003339 0.321178
|
||||||
|
v 0.056552 0.003339 0.315411
|
||||||
|
v 0.112852 0.003339 0.298332
|
||||||
|
v 0.164738 0.003339 0.270599
|
||||||
|
v 0.210217 0.003339 0.233275
|
||||||
|
v 0.247541 0.003339 0.187796
|
||||||
|
v 0.275274 0.003339 0.135910
|
||||||
|
v 0.292353 0.003339 0.079610
|
||||||
|
v 0.298119 0.003339 0.021060
|
||||||
|
v 0.292353 0.003339 -0.037490
|
||||||
|
v 0.275274 0.003339 -0.093790
|
||||||
|
v 0.247541 0.003339 -0.145676
|
||||||
|
v 0.210217 0.003339 -0.191155
|
||||||
|
v 0.164738 0.003339 -0.228479
|
||||||
|
v 0.112852 0.003339 -0.256213
|
||||||
|
v 0.056552 0.003339 -0.273291
|
||||||
|
v -0.005752 0.003339 -0.035452
|
||||||
|
v -0.058510 0.003339 0.024814
|
||||||
|
v 0.001756 0.003339 0.077572
|
||||||
|
v 0.046705 0.003339 0.017645
|
||||||
|
v 0.001756 0.088887 -0.035452
|
||||||
|
v -0.050701 0.088887 0.017645
|
||||||
|
v -0.005752 0.088887 0.077572
|
||||||
|
v 0.054514 0.088887 0.024814
|
||||||
|
v -0.032392 0.125403 0.093038
|
||||||
|
v -0.032392 0.240710 0.093038
|
||||||
|
v -0.032392 0.125403 -0.346358
|
||||||
|
v -0.032392 0.240710 -0.346358
|
||||||
|
v 0.051930 0.125403 0.093038
|
||||||
|
v 0.051930 0.240710 0.093038
|
||||||
|
v 0.051930 0.125403 -0.346358
|
||||||
|
v 0.051930 0.240710 -0.346358
|
||||||
|
v -0.023528 0.055092 0.045175
|
||||||
|
v -0.023528 0.170399 0.045175
|
||||||
|
v -0.023528 0.055092 -0.002624
|
||||||
|
v -0.023528 0.170399 -0.002624
|
||||||
|
v 0.023972 0.055092 0.045175
|
||||||
|
v 0.023972 0.170399 0.045175
|
||||||
|
v 0.023972 0.055092 -0.002624
|
||||||
|
v 0.023972 0.170399 -0.002624
|
||||||
|
vn 0.7940 -0.1224 0.5955
|
||||||
|
vn -0.0000 1.0000 -0.0000
|
||||||
|
vn -0.6576 -0.0577 0.7512
|
||||||
|
vn 0.7100 -0.0623 -0.7014
|
||||||
|
vn -0.7523 0.0135 -0.6586
|
||||||
|
vn -0.7940 0.1224 0.5955
|
||||||
|
vn 0.7523 -0.0135 -0.6586
|
||||||
|
vn -0.7100 0.0623 -0.7014
|
||||||
|
vn 0.6576 0.0577 0.7512
|
||||||
|
vn -1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 -0.0000 -1.0000
|
||||||
|
vn 1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 -0.0000 1.0000
|
||||||
|
vn -0.0000 -1.0000 -0.0000
|
||||||
|
vt 0.480149 0.438877
|
||||||
|
vt 0.469410 0.567032
|
||||||
|
vt 0.390375 0.438877
|
||||||
|
vt 0.492575 0.559691
|
||||||
|
vt 0.410487 0.915985
|
||||||
|
vt 0.326147 0.890401
|
||||||
|
vt 0.248419 0.848854
|
||||||
|
vt 0.413540 0.469410
|
||||||
|
vt 0.124377 0.724813
|
||||||
|
vt 0.082831 0.647084
|
||||||
|
vt 0.057246 0.562744
|
||||||
|
vt 0.048608 0.475033
|
||||||
|
vt 0.057246 0.387323
|
||||||
|
vt 0.082831 0.302983
|
||||||
|
vt 0.124377 0.225254
|
||||||
|
vt 0.503821 0.390375
|
||||||
|
vt 0.248419 0.101213
|
||||||
|
vt 0.326147 0.059666
|
||||||
|
vt 0.410487 0.034082
|
||||||
|
vt 0.498198 0.025443
|
||||||
|
vt 0.670249 0.059666
|
||||||
|
vt 0.747977 0.101213
|
||||||
|
vt 0.571158 0.480149
|
||||||
|
vt 0.872019 0.225254
|
||||||
|
vt 0.913566 0.302983
|
||||||
|
vt 0.939150 0.387323
|
||||||
|
vt 0.947789 0.475033
|
||||||
|
vt 0.913566 0.647084
|
||||||
|
vt 0.872019 0.724813
|
||||||
|
vt 0.747977 0.848854
|
||||||
|
vt 0.670249 0.890401
|
||||||
|
vt 0.585909 0.915985
|
||||||
|
vt 0.498198 0.924624
|
||||||
|
vt 0.503821 0.438877
|
||||||
|
vt 0.492575 0.567032
|
||||||
|
vt 0.413540 0.438877
|
||||||
|
vt 0.559691 0.438877
|
||||||
|
vt 0.559691 0.567032
|
||||||
|
vt 0.469410 0.438877
|
||||||
|
vt 0.480149 0.567032
|
||||||
|
vt 0.180290 0.792942
|
||||||
|
vt 0.180290 0.157125
|
||||||
|
vt 0.816107 0.157125
|
||||||
|
vt 0.585909 0.034082
|
||||||
|
vt 0.939150 0.562744
|
||||||
|
vt 0.816107 0.792942
|
||||||
|
vt 0.582856 0.469410
|
||||||
|
vt 0.425239 0.480149
|
||||||
|
vt 0.492575 0.390375
|
||||||
|
vt 0.390375 0.567032
|
||||||
|
vt 0.582856 0.567032
|
||||||
|
vt 0.367207 0.794470
|
||||||
|
vt 1.025443 0.621735
|
||||||
|
vt 0.367207 0.621735
|
||||||
|
vt 0.452666 0.794470
|
||||||
|
vt 0.578985 0.621735
|
||||||
|
vt 0.452666 0.621735
|
||||||
|
vt 1.025443 0.794470
|
||||||
|
vt 0.578985 0.794470
|
||||||
|
vt 0.578985 1.025443
|
||||||
|
vt 0.452666 0.367207
|
||||||
|
vt 0.452666 1.025443
|
||||||
|
vt 0.578985 0.367207
|
||||||
|
vt 0.438908 0.689140
|
||||||
|
vt 0.510512 0.516405
|
||||||
|
vt 0.438908 0.516405
|
||||||
|
vt 0.465945 0.689140
|
||||||
|
vt 0.537102 0.516405
|
||||||
|
vt 0.465945 0.516405
|
||||||
|
vt 0.510512 0.689140
|
||||||
|
vt 0.537102 0.689140
|
||||||
|
vt 0.537102 0.510512
|
||||||
|
vt 0.465945 0.438908
|
||||||
|
vt 0.465945 0.510512
|
||||||
|
vt 0.537102 0.438908
|
||||||
|
vt 0.503821 0.559691
|
||||||
|
s 0
|
||||||
|
usemtl Material.001
|
||||||
|
f 36/1/1 40/2/1 35/3/1
|
||||||
|
f 33/4/2 2/5/2 3/6/2
|
||||||
|
f 33/4/2 3/6/2 4/7/2
|
||||||
|
f 34/8/2 6/9/2 7/10/2
|
||||||
|
f 34/8/2 8/11/2 9/12/2
|
||||||
|
f 34/8/2 10/13/2 11/14/2
|
||||||
|
f 34/8/2 11/14/2 12/15/2
|
||||||
|
f 35/16/2 14/17/2 15/18/2
|
||||||
|
f 35/16/2 16/19/2 17/20/2
|
||||||
|
f 35/16/2 19/21/2 20/22/2
|
||||||
|
f 36/23/2 22/24/2 23/25/2
|
||||||
|
f 36/23/2 24/26/2 25/27/2
|
||||||
|
f 36/23/2 27/28/2 28/29/2
|
||||||
|
f 33/4/2 30/30/2 31/31/2
|
||||||
|
f 33/4/2 32/32/2 1/33/2
|
||||||
|
f 35/34/3 39/35/3 34/36/3
|
||||||
|
f 33/37/4 37/38/4 36/1/4
|
||||||
|
f 34/39/5 38/40/5 33/37/5
|
||||||
|
f 33/4/2 1/33/2 2/5/2
|
||||||
|
f 33/4/2 4/7/2 5/41/2
|
||||||
|
f 13/42/2 35/16/2 34/8/2
|
||||||
|
f 34/8/2 7/10/2 8/11/2
|
||||||
|
f 34/8/2 9/12/2 10/13/2
|
||||||
|
f 34/8/2 12/15/2 13/42/2
|
||||||
|
f 22/24/2 35/16/2 21/43/2
|
||||||
|
f 35/16/2 15/18/2 16/19/2
|
||||||
|
f 35/16/2 17/20/2 18/44/2
|
||||||
|
f 35/16/2 18/44/2 19/21/2
|
||||||
|
f 35/16/2 20/22/2 21/43/2
|
||||||
|
f 26/45/2 36/23/2 25/27/2
|
||||||
|
f 36/23/2 23/25/2 24/26/2
|
||||||
|
f 29/46/2 33/4/2 36/23/2
|
||||||
|
f 36/23/2 26/45/2 27/28/2
|
||||||
|
f 36/23/2 28/29/2 29/46/2
|
||||||
|
f 33/4/2 31/31/2 32/32/2
|
||||||
|
f 40/47/2 38/48/2 39/49/2
|
||||||
|
f 34/39/6 39/50/6 38/40/6
|
||||||
|
f 36/1/7 37/38/7 40/2/7
|
||||||
|
f 5/41/2 34/8/2 33/4/2
|
||||||
|
f 33/37/8 38/40/8 37/38/8
|
||||||
|
f 35/34/9 40/51/9 39/35/9
|
||||||
|
f 42/52/10 43/53/10 41/54/10
|
||||||
|
f 44/55/11 47/56/11 43/57/11
|
||||||
|
f 48/58/12 45/54/12 47/53/12
|
||||||
|
f 46/59/13 41/57/13 45/56/13
|
||||||
|
f 47/60/14 41/61/14 43/62/14
|
||||||
|
f 44/62/2 46/63/2 48/60/2
|
||||||
|
f 50/64/10 51/65/10 49/66/10
|
||||||
|
f 52/67/11 55/68/11 51/69/11
|
||||||
|
f 56/70/12 53/66/12 55/65/12
|
||||||
|
f 54/71/13 49/69/13 53/68/13
|
||||||
|
f 55/72/14 49/73/14 51/74/14
|
||||||
|
f 52/74/2 54/75/2 56/72/2
|
||||||
|
f 13/42/2 14/17/2 35/16/2
|
||||||
|
f 22/24/2 36/23/2 35/16/2
|
||||||
|
f 29/46/2 30/30/2 33/4/2
|
||||||
|
f 40/47/2 37/76/2 38/48/2
|
||||||
|
f 5/41/2 6/9/2 34/8/2
|
||||||
|
f 42/52/10 44/58/10 43/53/10
|
||||||
|
f 44/55/11 48/59/11 47/56/11
|
||||||
|
f 48/58/12 46/52/12 45/54/12
|
||||||
|
f 46/59/13 42/55/13 41/57/13
|
||||||
|
f 47/60/14 45/63/14 41/61/14
|
||||||
|
f 44/62/2 42/61/2 46/63/2
|
||||||
|
f 50/64/10 52/70/10 51/65/10
|
||||||
|
f 52/67/11 56/71/11 55/68/11
|
||||||
|
f 56/70/12 54/64/12 53/66/12
|
||||||
|
f 54/71/13 50/67/13 49/69/13
|
||||||
|
f 55/72/14 53/75/14 49/73/14
|
||||||
|
f 52/74/2 50/73/2 54/75/2
|
13
content/test/test.mtl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Blender 4.0.2 MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.001
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd content/textures/test/diamond-inlay-tile1_albedo.png
|
||||||
|
map_Kn content/textures/test/diamond-inlay-tile1_normal-ogl.png
|
53
content/test/test.obj
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Blender 4.0.2
|
||||||
|
# www.blender.org
|
||||||
|
mtllib test.mtl
|
||||||
|
o Plane
|
||||||
|
v -5.000000 0.000000 5.000000
|
||||||
|
v 5.000000 0.000000 5.000000
|
||||||
|
v -5.000000 0.000000 -5.000000
|
||||||
|
v 5.000000 0.000000 -5.000000
|
||||||
|
v 2.368457 0.000000 -3.631543
|
||||||
|
v 2.368457 0.000000 -2.368457
|
||||||
|
v 3.631543 0.000000 -2.368457
|
||||||
|
v 3.631543 0.000000 -3.631543
|
||||||
|
v 2.368457 4.000000 -3.631543
|
||||||
|
v 2.368457 4.000000 -2.368457
|
||||||
|
v 3.631543 4.000000 -2.368457
|
||||||
|
v 3.631543 4.000000 -3.631543
|
||||||
|
vn 1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 1.0000 -0.0000
|
||||||
|
vn -1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 -0.0000 -1.0000
|
||||||
|
vn -0.0000 -0.0000 1.0000
|
||||||
|
vt 1.642477 0.813162
|
||||||
|
vt 1.245911 2.069025
|
||||||
|
vt 1.245911 0.813162
|
||||||
|
vt 1.245911 1.242810
|
||||||
|
vt -1.067532 2.069025
|
||||||
|
vt -1.067532 -1.070632
|
||||||
|
vt 2.072125 -1.070632
|
||||||
|
vt 1.642477 1.242810
|
||||||
|
vt 2.072125 2.069025
|
||||||
|
vt 1.642477 1.639376
|
||||||
|
vt 1.245911 1.639376
|
||||||
|
vt 1.642477 2.069025
|
||||||
|
s 0
|
||||||
|
usemtl Material.001
|
||||||
|
f 8/1/1 11/2/1 7/3/1
|
||||||
|
f 6/4/2 3/5/2 1/6/2
|
||||||
|
f 6/4/2 2/7/2 7/8/2
|
||||||
|
f 7/8/2 4/9/2 8/10/2
|
||||||
|
f 5/11/2 4/9/2 3/5/2
|
||||||
|
f 11/8/2 9/11/2 10/4/2
|
||||||
|
f 6/3/3 9/12/3 5/1/3
|
||||||
|
f 5/3/4 12/12/4 8/1/4
|
||||||
|
f 7/1/5 10/2/5 6/3/5
|
||||||
|
f 8/1/1 12/12/1 11/2/1
|
||||||
|
f 6/4/2 5/11/2 3/5/2
|
||||||
|
f 6/4/2 1/6/2 2/7/2
|
||||||
|
f 7/8/2 2/7/2 4/9/2
|
||||||
|
f 5/11/2 8/10/2 4/9/2
|
||||||
|
f 11/8/2 12/10/2 9/11/2
|
||||||
|
f 6/3/3 10/2/3 9/12/3
|
||||||
|
f 5/3/4 9/2/4 12/12/4
|
||||||
|
f 7/1/5 11/12/5 10/2/5
|
BIN
content/test/tetrad — копия.png
Normal file
After Width: | Height: | Size: 1.6 MiB |
BIN
content/test/tetrad.png
Normal file
After Width: | Height: | Size: 1.7 MiB |
BIN
content/test/uvgrid.png
Normal file
After Width: | Height: | Size: 3.0 MiB |
12
content/test/water_test.mtl
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# Blender 3.6.7 MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.001
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.450000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd content/textures/env/env_water.png
|
1097
content/test/water_test.obj
Normal file
BIN
content/textures/env/env_water.png
vendored
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
content/textures/font/font_arial_18.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
BIN
content/textures/font/font_system.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
content/textures/system/notex.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
content/textures/ui/ui_btn_newgame.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
content/textures/ui/ui_btn_quit.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
content/textures/ui/ui_button_template.pdn
Normal file
BIN
content/textures/ui/ui_cursor.png
Normal file
After Width: | Height: | Size: 217 B |
1475
content/textures/ui/ui_main_bg.pdn
Normal file
BIN
content/textures/ui/ui_main_bg.png
Normal file
After Width: | Height: | Size: 1.0 MiB |
BIN
content/textures/ui/ui_msg_nopoints.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
content/textures/ui/ui_new_unit.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
1
gen_vs2022.bat
Normal file
@ -0,0 +1 @@
|
|||||||
|
tools\premake5.exe vs2022
|
158
premake5.lua
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
solution "game"
|
||||||
|
configurations {
|
||||||
|
"Debug",
|
||||||
|
"Release"
|
||||||
|
}
|
||||||
|
|
||||||
|
platforms {
|
||||||
|
"x32",
|
||||||
|
"x64",
|
||||||
|
}
|
||||||
|
|
||||||
|
language "C++"
|
||||||
|
location "build"
|
||||||
|
targetdir "bin"
|
||||||
|
characterset "MBCS"
|
||||||
|
rtti "Off"
|
||||||
|
|
||||||
|
filter "x64"
|
||||||
|
targetdir "bin_x64"
|
||||||
|
|
||||||
|
filter "windows"
|
||||||
|
defines { "_WIN32", "WIN32", "WINDOWS" }
|
||||||
|
|
||||||
|
filter "Debug"
|
||||||
|
defines { "DEBUG", "_DEBUG" }
|
||||||
|
targetsuffix "_d"
|
||||||
|
flags { "Symbols" }
|
||||||
|
|
||||||
|
filter "Release"
|
||||||
|
defines { "NDEBUG" }
|
||||||
|
flags { "Symbols", "OptimizeSpeed", "No64BitChecks" }
|
||||||
|
|
||||||
|
--filter {}
|
||||||
|
|
||||||
|
|
||||||
|
PROJ_DIR = path.getabsolute(".")
|
||||||
|
LIB_DIR = path.getabsolute("thirdparty")
|
||||||
|
STB_DIR = path.join(LIB_DIR, "stb")
|
||||||
|
MINIAUDIO_DIR = path.join(LIB_DIR, "miniaudio")
|
||||||
|
GLAD_DIR = path.join(LIB_DIR, "glad")
|
||||||
|
GLM_DIR = path.join(LIB_DIR, "glm")
|
||||||
|
MINILUA_DIR = path.join(LIB_DIR, "minilua")
|
||||||
|
ODE_DIR = path.join(LIB_DIR, "ode-0.16.5")
|
||||||
|
|
||||||
|
-- Open Dynamics Engine
|
||||||
|
project "ode"
|
||||||
|
kind "StaticLib"
|
||||||
|
|
||||||
|
defines { "dIDEDOUBLE", "CCD_IDEDOUBLE", "_OU_FEATURE_SET=_OU_FEATURE_SET_TLS" }
|
||||||
|
|
||||||
|
filter { "Release*" }
|
||||||
|
defines { "NDEBUG", "dNODEBUG" }
|
||||||
|
flags { "OptimizeSpeed", "NoFramePointer" }
|
||||||
|
|
||||||
|
-- disable Visual Studio security warnings
|
||||||
|
filter { "vs*" }
|
||||||
|
defines { "_CRT_SECURE_NO_DEPRECATE", "_SCL_SECURE_NO_WARNINGS" }
|
||||||
|
|
||||||
|
-- enable M_* macros from math.h
|
||||||
|
filter { "vs*" }
|
||||||
|
defines { "_USE_MATH_DEFINES" }
|
||||||
|
|
||||||
|
filter {}
|
||||||
|
|
||||||
|
includedirs {
|
||||||
|
path.join(ODE_DIR, "OPCODE"),
|
||||||
|
path.join(ODE_DIR, "include"),
|
||||||
|
path.join(ODE_DIR, "build"),
|
||||||
|
path.join(ODE_DIR, "ou/include"),
|
||||||
|
path.join(ODE_DIR, "ou/src"),
|
||||||
|
path.join(ODE_DIR, "ode/src"),
|
||||||
|
path.join(ODE_DIR, "ode/src/joints"),
|
||||||
|
}
|
||||||
|
|
||||||
|
files {
|
||||||
|
-- ode sources
|
||||||
|
path.join(ODE_DIR, "include/ode/*.h"),
|
||||||
|
path.join(ODE_DIR, "ode/src/joints/*.h"),
|
||||||
|
path.join(ODE_DIR, "ode/src/joints/*.cpp"),
|
||||||
|
path.join(ODE_DIR, "ode/src/*.h"),
|
||||||
|
path.join(ODE_DIR, "ode/src/*.c"),
|
||||||
|
path.join(ODE_DIR, "ode/src/*.cpp"),
|
||||||
|
|
||||||
|
-- ou library
|
||||||
|
path.join(ODE_DIR, "ou/include/**.h"),
|
||||||
|
path.join(ODE_DIR, "ou/src/**.h"),
|
||||||
|
path.join(ODE_DIR, "ou/src/**.cpp"),
|
||||||
|
|
||||||
|
-- OPCODE
|
||||||
|
path.join(ODE_DIR, "OPCODE/*.h"),
|
||||||
|
path.join(ODE_DIR, "OPCODE/*.cpp"),
|
||||||
|
path.join(ODE_DIR, "OPCODE/Ice/*.h"),
|
||||||
|
path.join(ODE_DIR, "OPCODE/Ice/*.cpp")
|
||||||
|
}
|
||||||
|
|
||||||
|
excludes {
|
||||||
|
path.join(ODE_DIR, "ode/src/collision_std.cpp"),
|
||||||
|
path.join(ODE_DIR, "ode/src/collision_libccd.cpp"),
|
||||||
|
path.join(ODE_DIR, "ode/src/collision_libccd.h")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Game
|
||||||
|
project "game"
|
||||||
|
kind "ConsoleApp"
|
||||||
|
|
||||||
|
includedirs {
|
||||||
|
path.join(PROJ_DIR, "src"),
|
||||||
|
path.join(PROJ_DIR, "src/engine"),
|
||||||
|
LIB_DIR,
|
||||||
|
STB_DIR,
|
||||||
|
MINIAUDIO_DIR,
|
||||||
|
GLM_DIR,
|
||||||
|
MINILUA_DIR,
|
||||||
|
path.join(ODE_DIR, "include"),
|
||||||
|
path.join(ODE_DIR, "build"),
|
||||||
|
path.join(GLAD_DIR, "include")
|
||||||
|
}
|
||||||
|
|
||||||
|
files {
|
||||||
|
-- GLAD
|
||||||
|
path.join(GLAD_DIR, "src/*.c"),
|
||||||
|
|
||||||
|
-----------------------------------------
|
||||||
|
-- Engine
|
||||||
|
|
||||||
|
path.join(PROJ_DIR, "src/engine/utils/*.cpp"),
|
||||||
|
path.join(PROJ_DIR, "src/engine/utils/*.h"),
|
||||||
|
|
||||||
|
path.join(PROJ_DIR, "src/engine/filesystem/*.cpp"),
|
||||||
|
path.join(PROJ_DIR, "src/engine/filesystem/*.h"),
|
||||||
|
|
||||||
|
path.join(PROJ_DIR, "src/engine/input/*.cpp"),
|
||||||
|
path.join(PROJ_DIR, "src/engine/input/*.h"),
|
||||||
|
|
||||||
|
path.join(PROJ_DIR, "src/engine/render/*.cpp"),
|
||||||
|
path.join(PROJ_DIR, "src/engine/render/*.h"),
|
||||||
|
|
||||||
|
path.join(PROJ_DIR, "src/engine/sound/*.cpp"),
|
||||||
|
path.join(PROJ_DIR, "src/engine/sound/*.h"),
|
||||||
|
|
||||||
|
path.join(PROJ_DIR, "src/engine/physics/*.cpp"),
|
||||||
|
path.join(PROJ_DIR, "src/engine/physics/*.h"),
|
||||||
|
|
||||||
|
-----------------------------------------
|
||||||
|
-- Game
|
||||||
|
|
||||||
|
path.join(PROJ_DIR, "src/game/*.c"),
|
||||||
|
path.join(PROJ_DIR, "src/game/*.cpp"),
|
||||||
|
path.join(PROJ_DIR, "src/game/*.h"),
|
||||||
|
|
||||||
|
-----------------------------------------
|
||||||
|
-- Main
|
||||||
|
path.join(PROJ_DIR, "src/main/*.cpp"),
|
||||||
|
path.join(PROJ_DIR, "src/main/*.h"),
|
||||||
|
}
|
||||||
|
|
||||||
|
links { "ode" }
|
57
src/engine/filesystem/file.cpp
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "filesystem/file.h"
|
||||||
|
|
||||||
|
static const char* s_stdioOpeningMode[] = { "rb", "wb" };
|
||||||
|
static int s_stdioSeekDir[] = { SEEK_SET, SEEK_CUR, SEEK_END };
|
||||||
|
|
||||||
|
File::File(const char* path, FileAccess access)
|
||||||
|
{
|
||||||
|
m_filehandle = fopen(path, s_stdioOpeningMode[(int)access]);
|
||||||
|
assert(m_filehandle && "Unable to open file");
|
||||||
|
}
|
||||||
|
|
||||||
|
File::~File()
|
||||||
|
{
|
||||||
|
if (m_filehandle)
|
||||||
|
{
|
||||||
|
fclose(m_filehandle);
|
||||||
|
m_filehandle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::seek(SeekDir seekdir, long offset)
|
||||||
|
{
|
||||||
|
fseek(m_filehandle, offset, s_stdioSeekDir[(int)seekdir]);
|
||||||
|
}
|
||||||
|
|
||||||
|
long File::tell()
|
||||||
|
{
|
||||||
|
return ftell(m_filehandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::eof()
|
||||||
|
{
|
||||||
|
return feof(m_filehandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t File::read(void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
return fread(buffer, 1, size, m_filehandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t File::write(void const* buffer, size_t size)
|
||||||
|
{
|
||||||
|
return fwrite(buffer, size, 1, m_filehandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::readStringBuffer(char* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
seek(SeekDir::End, 0);
|
||||||
|
size_t length = tell();
|
||||||
|
seek(SeekDir::Begin, 0);
|
||||||
|
|
||||||
|
assert(length <= bufferSize);
|
||||||
|
|
||||||
|
read(buffer, length);
|
||||||
|
buffer[length] = '\0';
|
||||||
|
}
|
28
src/engine/filesystem/file.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef FILE_H
|
||||||
|
#define FILE_H
|
||||||
|
|
||||||
|
#include "filesystem/filecommon.h"
|
||||||
|
|
||||||
|
class File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
File(const char* path, FileAccess access);
|
||||||
|
~File();
|
||||||
|
|
||||||
|
FILE* getHandle() { return m_filehandle; }
|
||||||
|
|
||||||
|
void seek(SeekDir seekdir, long offset);
|
||||||
|
long tell();
|
||||||
|
bool eof();
|
||||||
|
|
||||||
|
size_t read(void* buffer, size_t size);
|
||||||
|
size_t write(void const* buffer, size_t size);
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
void readStringBuffer(char* buffer, size_t bufferSize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE* m_filehandle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
21
src/engine/filesystem/filecommon.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef FILECOMMON_H
|
||||||
|
#define FILECOMMON_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static const int kMaxPathLength = 260;
|
||||||
|
|
||||||
|
enum class FileAccess
|
||||||
|
{
|
||||||
|
Read,
|
||||||
|
Write
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SeekDir
|
||||||
|
{
|
||||||
|
Begin,
|
||||||
|
Current,
|
||||||
|
End
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !FILECOMMON_H
|
316
src/engine/filesystem/filemanager.cpp
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "filesystem/stream.h"
|
||||||
|
#include "filesystem/filemanager.h"
|
||||||
|
|
||||||
|
void RecursiveSearch(const std::string& path, std::vector<std::string>& files);
|
||||||
|
void osResolvePath(char* path);
|
||||||
|
|
||||||
|
FileManager* g_fileManager;
|
||||||
|
|
||||||
|
FileManager::FileManager()
|
||||||
|
{
|
||||||
|
static char currentDirectory[kMaxPathLength];
|
||||||
|
GetCurrentDirectoryA(kMaxPathLength, currentDirectory);
|
||||||
|
strcat(currentDirectory, "/");
|
||||||
|
|
||||||
|
osResolvePath(currentDirectory);
|
||||||
|
|
||||||
|
m_defaultPath = currentDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileManager::~FileManager()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::SetDefaultPath(const char* path)
|
||||||
|
{
|
||||||
|
m_defaultPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileManager::FileExist(const char* filename)
|
||||||
|
{
|
||||||
|
#if defined(WIN32) || defined(_WIN32)
|
||||||
|
char pathBuffer[kMaxPathLength];
|
||||||
|
if (!strstr(filename, m_defaultPath))
|
||||||
|
sprintf(pathBuffer, "%s%s", m_defaultPath, filename);
|
||||||
|
else
|
||||||
|
strcpy(pathBuffer, filename);
|
||||||
|
|
||||||
|
osResolvePath(pathBuffer);
|
||||||
|
|
||||||
|
DWORD dwAttrib = GetFileAttributes(pathBuffer);
|
||||||
|
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||||
|
#else
|
||||||
|
FILE* file;
|
||||||
|
|
||||||
|
if ((file = fopen(filename, "r")) != NULL)
|
||||||
|
{
|
||||||
|
fclose(file);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
File* FileManager::OpenFile(const char* path, FileAccess access)
|
||||||
|
{
|
||||||
|
char pathBuffer[kMaxPathLength];
|
||||||
|
if (!strstr(path, m_defaultPath))
|
||||||
|
sprintf(pathBuffer, "%s%s", m_defaultPath, path);
|
||||||
|
else
|
||||||
|
strcpy(pathBuffer, path);
|
||||||
|
|
||||||
|
osResolvePath(pathBuffer);
|
||||||
|
|
||||||
|
return new File(pathBuffer, access);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::CloseFile(File*& file)
|
||||||
|
{
|
||||||
|
if (file)
|
||||||
|
{
|
||||||
|
delete file;
|
||||||
|
file = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamBase* FileManager::OpenStream(const char* fname, FileAccess access)
|
||||||
|
{
|
||||||
|
char pathBuffer[kMaxPathLength];
|
||||||
|
if (!strstr(fname, m_defaultPath))
|
||||||
|
sprintf(pathBuffer, "%s%s", m_defaultPath, fname);
|
||||||
|
else
|
||||||
|
strcpy(pathBuffer, fname);
|
||||||
|
|
||||||
|
osResolvePath(pathBuffer);
|
||||||
|
|
||||||
|
if (!g_fileManager->FileExist( pathBuffer ))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
File* file = new File(pathBuffer, access);
|
||||||
|
return createFileStream(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if _WIN32
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <io.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
void GetFileListFromFolder(const char* path, const char* findingPattern, std::vector<std::string>& filesList)
|
||||||
|
{
|
||||||
|
struct _finddata_t c_file;
|
||||||
|
intptr_t hFile;
|
||||||
|
|
||||||
|
char pathfind[kMaxPathLength];
|
||||||
|
sprintf(pathfind, "%s/%s", path, findingPattern);
|
||||||
|
osResolvePath(pathfind);
|
||||||
|
|
||||||
|
if ((hFile = _findfirst(pathfind, &c_file)) != -1L) {
|
||||||
|
do {
|
||||||
|
char buffer[kMaxPathLength];
|
||||||
|
sprintf(buffer, "%s/%s", path, c_file.name);
|
||||||
|
filesList.push_back(buffer);
|
||||||
|
} while (_findnext(hFile, &c_file) == 0);
|
||||||
|
_findclose(hFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void osResolvePath(char* path)
|
||||||
|
{
|
||||||
|
assert(path);
|
||||||
|
|
||||||
|
size_t length = strlen(path);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)length; i++) {
|
||||||
|
if (path[i] == '/')
|
||||||
|
path[i] = '\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool osDirectoryIsExist(const char* path)
|
||||||
|
{
|
||||||
|
DWORD ftyp = GetFileAttributesA(path);
|
||||||
|
if (ftyp == INVALID_FILE_ATTRIBUTES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void osCreateDirectory(const char* path)
|
||||||
|
{
|
||||||
|
CreateDirectoryA(path, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecursiveSearch(const std::string& path, std::vector<std::string>& files)
|
||||||
|
{
|
||||||
|
struct _finddata_t c_file;
|
||||||
|
intptr_t hFile;
|
||||||
|
|
||||||
|
std::string bufferPath;
|
||||||
|
bufferPath += path;
|
||||||
|
bufferPath += "/";
|
||||||
|
bufferPath += "*.*";
|
||||||
|
|
||||||
|
if ((hFile = _findfirst(bufferPath.c_str(), &c_file)) != -1L)
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
if (strcmp(c_file.name, ".") == 0 ||
|
||||||
|
strcmp(c_file.name, "..") == 0 ||
|
||||||
|
strcmp(c_file.name, ".git") == 0 ||
|
||||||
|
strcmp(c_file.name, ".gitignore") == 0 ||
|
||||||
|
strcmp(c_file.name, ".gitignore") == 0 ||
|
||||||
|
strcmp(c_file.name, ".vs") == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (c_file.attrib & _A_SUBDIR)
|
||||||
|
{
|
||||||
|
std::string nextPath;
|
||||||
|
nextPath += path;
|
||||||
|
nextPath += "/";
|
||||||
|
nextPath += c_file.name;
|
||||||
|
|
||||||
|
RecursiveSearch(nextPath, files);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string filepath;
|
||||||
|
filepath += path;
|
||||||
|
filepath += "/";
|
||||||
|
filepath += c_file.name;
|
||||||
|
files.push_back(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (_findnext(hFile, &c_file) == 0);
|
||||||
|
_findclose(hFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
|
bool match(const char* pattern, const char* str, int p = 0, int c = 0)
|
||||||
|
{
|
||||||
|
if (pattern[p] == '\0')
|
||||||
|
{
|
||||||
|
return str[c] == '\0';
|
||||||
|
}
|
||||||
|
else if (pattern[p] == '*')
|
||||||
|
{
|
||||||
|
for (; str[c] != '\0'; c++)
|
||||||
|
{
|
||||||
|
if (match(pattern, str, p + 1, c))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return match(pattern, str, p + 1, c);
|
||||||
|
}
|
||||||
|
else if (pattern[p] != '?' && pattern[p] != str[c])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return match(pattern, str, p + 1, c + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetFileListFromFolder(const char* path, const char* findingPattern, std::vector<std::string>& filesList)
|
||||||
|
{
|
||||||
|
DIR* dir;
|
||||||
|
dirent* ent;
|
||||||
|
|
||||||
|
if ((dir = opendir(path)) != NULL)
|
||||||
|
{
|
||||||
|
while ((ent = readdir(dir)) != NULL)
|
||||||
|
{
|
||||||
|
if (match(findingPattern, ent->d_name))
|
||||||
|
{
|
||||||
|
char buffer[kMaxPathLength];
|
||||||
|
snprintf(buffer, kMaxPathLength, "%s/%s", path, ent->d_name);
|
||||||
|
filesList.push_back(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace fs
|
||||||
|
{
|
||||||
|
std::string getFileExtension(const std::string& filename)
|
||||||
|
{
|
||||||
|
size_t whereIsDot = filename.find_last_of('.');
|
||||||
|
if (whereIsDot != std::string::npos) {
|
||||||
|
return filename.substr(whereIsDot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getFilePath(const std::string& filename)
|
||||||
|
{
|
||||||
|
size_t lastindex = filename.find_last_of("/");
|
||||||
|
if (lastindex == std::string::npos) {
|
||||||
|
lastindex = filename.find_last_of("\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastindex != std::string::npos) {
|
||||||
|
|
||||||
|
return filename.substr(0, lastindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getFileNameWithoutExtension(const std::string& filename)
|
||||||
|
{
|
||||||
|
size_t lastindex = filename.find_last_of(".");
|
||||||
|
if (lastindex != std::string::npos) {
|
||||||
|
return filename.substr(0, lastindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getFilenameWithoutPath(const std::string& filename)
|
||||||
|
{
|
||||||
|
size_t whereIsSlash = filename.find_last_of('/');
|
||||||
|
if (whereIsSlash == std::string::npos) {
|
||||||
|
whereIsSlash = filename.find_last_of('\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (whereIsSlash == std::string::npos) {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string string = filename.substr(whereIsSlash + 1);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getFilenameWithoutPathAndExtension(const std::string& filename)
|
||||||
|
{
|
||||||
|
size_t whereIsDot = filename.find_last_of('.');
|
||||||
|
size_t whereIsSlash = filename.find_last_of('/');
|
||||||
|
if (whereIsSlash == std::string::npos) {
|
||||||
|
whereIsSlash = filename.find_last_of('\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (whereIsDot == std::string::npos && whereIsSlash == std::string::npos) {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string string = filename.substr(whereIsSlash + 1);
|
||||||
|
whereIsDot = string.find_last_of('.');
|
||||||
|
string = string.substr(0, whereIsDot);
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
}
|
51
src/engine/filesystem/filemanager.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef FILEMANAGER_H
|
||||||
|
#define FILEMANAGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "filesystem/file.h"
|
||||||
|
|
||||||
|
class StreamBase;
|
||||||
|
|
||||||
|
class FileManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileManager();
|
||||||
|
~FileManager();
|
||||||
|
|
||||||
|
void SetDefaultPath(const char* path);
|
||||||
|
const char* GetDefaultPath() { return m_defaultPath; }
|
||||||
|
|
||||||
|
bool FileExist(const char* filename);
|
||||||
|
|
||||||
|
File* OpenFile(const char* path, FileAccess access);
|
||||||
|
void CloseFile(File*& file);
|
||||||
|
|
||||||
|
StreamBase* OpenStream(const char* fname, FileAccess access);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* m_defaultPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern FileManager* g_fileManager;
|
||||||
|
|
||||||
|
void GetFileListFromFolder(const char* path, const char* findingPattern, std::vector<std::string>& filesList);
|
||||||
|
|
||||||
|
void osResolvePath(char* path);
|
||||||
|
bool osDirectoryIsExist(const char* path);
|
||||||
|
void osCreateDirectory(const char* path);
|
||||||
|
|
||||||
|
// Filename helper
|
||||||
|
|
||||||
|
namespace fs
|
||||||
|
{
|
||||||
|
std::string getFileExtension(const std::string& filename);
|
||||||
|
std::string getFilePath(const std::string& filename);
|
||||||
|
std::string getFileNameWithoutExtension(const std::string& filename);
|
||||||
|
std::string getFilenameWithoutPath(const std::string& filename);
|
||||||
|
std::string getFilenameWithoutPathAndExtension(const std::string& filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // !FILEMANAGER_H
|
61
src/engine/filesystem/stream.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "filesystem/stream.h"
|
||||||
|
#include "filesystem/filemanager.h"
|
||||||
|
|
||||||
|
class FileStream : public StreamBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileStream(File* file);
|
||||||
|
~FileStream();
|
||||||
|
|
||||||
|
size_t readBuffer(void* buffer, size_t size);
|
||||||
|
size_t writeBuffer(void* buffer, size_t size);
|
||||||
|
void seek(SeekDir way, long offset);
|
||||||
|
size_t tell();
|
||||||
|
bool eof();
|
||||||
|
|
||||||
|
private:
|
||||||
|
File* m_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
FileStream::FileStream(File* file)
|
||||||
|
{
|
||||||
|
assert(file && "Cannot open file stream with nullptr file handle.");
|
||||||
|
m_file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileStream::~FileStream()
|
||||||
|
{
|
||||||
|
if (m_file)
|
||||||
|
g_fileManager->CloseFile(m_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileStream::readBuffer(void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
return m_file->read(buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileStream::writeBuffer(void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
return m_file->write(buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileStream::seek(SeekDir way, long offset)
|
||||||
|
{
|
||||||
|
m_file->seek(way, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileStream::tell()
|
||||||
|
{
|
||||||
|
return m_file->tell();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileStream::eof()
|
||||||
|
{
|
||||||
|
return m_file->eof();;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamBase* createFileStream(File* file)
|
||||||
|
{
|
||||||
|
return new FileStream(file);
|
||||||
|
}
|
21
src/engine/filesystem/stream.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef STREAM_H
|
||||||
|
#define STREAM_H
|
||||||
|
|
||||||
|
#include "filesystem/filecommon.h"
|
||||||
|
|
||||||
|
class StreamBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~StreamBase() {}
|
||||||
|
|
||||||
|
virtual size_t readBuffer(void* buffer, size_t size) = 0;
|
||||||
|
virtual size_t writeBuffer(void* buffer, size_t size) = 0;
|
||||||
|
virtual void seek(SeekDir way, long offset) = 0;
|
||||||
|
virtual size_t tell() = 0;
|
||||||
|
virtual bool eof() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class File;
|
||||||
|
StreamBase* createFileStream(File* file);
|
||||||
|
|
||||||
|
#endif // !STREAM_H
|
182
src/engine/input/input_system.cpp
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "utils/maths.h"
|
||||||
|
#include "input/input_system.h"
|
||||||
|
|
||||||
|
const int kMaxKeyboardKeys = 460;
|
||||||
|
const int kMaxMouseButtons = mouseButton_LastNamed + 1; //5;
|
||||||
|
const float kKeyThreshold = 0.2f;
|
||||||
|
|
||||||
|
IInputSystem* g_inputSystem = nullptr;
|
||||||
|
|
||||||
|
class InputSystem : public IInputSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InputSystem();
|
||||||
|
~InputSystem();
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
size_t GetMaxScancode() const;
|
||||||
|
size_t GetMaxMouseButton() const;
|
||||||
|
|
||||||
|
char TranslateScancode(scanCode_t scancode) const;
|
||||||
|
|
||||||
|
void OnKeyDown(scanCode_t scancode);
|
||||||
|
void OnKeyUp(scanCode_t scancode);
|
||||||
|
void OnMouseKeyDown(mouseButton_t mousebutton);
|
||||||
|
void OnMouseKeyUp(mouseButton_t mousebutton);
|
||||||
|
void OnMouseMove(int32_t x, int32_t y);
|
||||||
|
void OnMouseWheel(int32_t x, int32_t y);
|
||||||
|
|
||||||
|
bool IsKeyPressed(scanCode_t scancode) const;
|
||||||
|
bool IsMouseButtonPressed(mouseButton_t mousebutton) const;
|
||||||
|
|
||||||
|
void GetMousePosition(int32_t* x, int32_t* y) const;
|
||||||
|
void GetMouseWheelPosition(int32_t* x, int32_t* y) const;
|
||||||
|
|
||||||
|
const char* ActionToString(Action action) const;
|
||||||
|
void BindKey(Action action, scanCode_t scancode);
|
||||||
|
bool IsActionActive(Action action) const;
|
||||||
|
void UnBindKey(Action action);
|
||||||
|
void UnBindAll();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_keyboardKeys[kMaxKeyboardKeys];
|
||||||
|
bool m_mouseButtons[kMaxMouseButtons];
|
||||||
|
Point2 m_mousePosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
InputSystem::InputSystem()
|
||||||
|
{
|
||||||
|
memset( m_keyboardKeys, 0, sizeof( m_keyboardKeys ) );
|
||||||
|
memset( m_mouseButtons, 0, sizeof( m_mouseButtons ) );
|
||||||
|
memset( &m_mousePosition, 0, sizeof( m_mousePosition ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
InputSystem::~InputSystem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::Init()
|
||||||
|
{
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::Shutdown()
|
||||||
|
{
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::Update()
|
||||||
|
{
|
||||||
|
// TODO: Reset all pressed keys ...
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t InputSystem::GetMaxScancode() const
|
||||||
|
{
|
||||||
|
return kMaxKeyboardKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t InputSystem::GetMaxMouseButton() const
|
||||||
|
{
|
||||||
|
return kMaxMouseButtons;
|
||||||
|
}
|
||||||
|
|
||||||
|
char InputSystem::TranslateScancode(scanCode_t scancode) const
|
||||||
|
{
|
||||||
|
assert(0 && "Not implemented");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::OnKeyDown(scanCode_t scancode)
|
||||||
|
{
|
||||||
|
assert(scancode <= kMaxKeyboardKeys);
|
||||||
|
m_keyboardKeys[scancode] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::OnKeyUp(scanCode_t scancode)
|
||||||
|
{
|
||||||
|
assert(scancode <= kMaxKeyboardKeys);
|
||||||
|
m_keyboardKeys[scancode] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::OnMouseKeyDown(mouseButton_t mousebutton)
|
||||||
|
{
|
||||||
|
assert(mousebutton <= kMaxMouseButtons);
|
||||||
|
m_mouseButtons[mousebutton] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::OnMouseKeyUp(mouseButton_t mousebutton)
|
||||||
|
{
|
||||||
|
assert(mousebutton <= kMaxMouseButtons);
|
||||||
|
m_mouseButtons[mousebutton] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::OnMouseMove(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
m_mousePosition.x = (int)x;
|
||||||
|
m_mousePosition.y = (int)y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::OnMouseWheel(int32_t x, int32_t y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputSystem::IsKeyPressed(scanCode_t scancode) const
|
||||||
|
{
|
||||||
|
assert(scancode <= KEY_MAX);
|
||||||
|
return m_keyboardKeys[scancode];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputSystem::IsMouseButtonPressed(mouseButton_t mousebutton) const
|
||||||
|
{
|
||||||
|
assert(mousebutton <= kMaxMouseButtons);
|
||||||
|
return m_mouseButtons[mousebutton];
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::GetMousePosition(int32_t* x, int32_t* y) const
|
||||||
|
{
|
||||||
|
if (x) *x = (int32_t)m_mousePosition.x;
|
||||||
|
if (y) *y = (int32_t)m_mousePosition.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::GetMouseWheelPosition(int32_t* x, int32_t* y) const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* InputSystem::ActionToString(Action action) const
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::BindKey(Action action, scanCode_t scancode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputSystem::IsActionActive(Action action) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::UnBindKey(Action action)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputSystem::UnBindAll()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IInputSystem* CreateInputSystem(void* wndHandle)
|
||||||
|
{
|
||||||
|
return new InputSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DestroyInputSystem(IInputSystem* pInstance)
|
||||||
|
{
|
||||||
|
InputSystem* pInput = (InputSystem*)pInstance;
|
||||||
|
delete pInput;
|
||||||
|
}
|
198
src/engine/input/input_system.h
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
#ifndef INPUT_SYSTEM_H
|
||||||
|
#define INPUT_SYSTEM_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum KeyboardKeys
|
||||||
|
{
|
||||||
|
KEY_UNKNOWN = 0,
|
||||||
|
KEY_SPACE = 32,
|
||||||
|
KEY_APOSTROPHE = 39, /* ' */
|
||||||
|
KEY_COMMA = 44, /* , */
|
||||||
|
KEY_MINUS = 45, /* - */
|
||||||
|
KEY_PERIOD = 46, /* . */
|
||||||
|
KEY_SLASH = 47, /* / */
|
||||||
|
KEY_0 = 48,
|
||||||
|
KEY_1 = 49,
|
||||||
|
KEY_2 = 50,
|
||||||
|
KEY_3 = 51,
|
||||||
|
KEY_4 = 52,
|
||||||
|
KEY_5 = 53,
|
||||||
|
KEY_6 = 54,
|
||||||
|
KEY_7 = 55,
|
||||||
|
KEY_8 = 56,
|
||||||
|
KEY_9 = 57,
|
||||||
|
KEY_SEMICOLON = 59, /* ; */
|
||||||
|
KEY_EQUAL = 61, /* = */
|
||||||
|
KEY_A = 65,
|
||||||
|
KEY_B = 66,
|
||||||
|
KEY_C = 67,
|
||||||
|
KEY_D = 68,
|
||||||
|
KEY_E = 69,
|
||||||
|
KEY_F = 70,
|
||||||
|
KEY_G = 71,
|
||||||
|
KEY_H = 72,
|
||||||
|
KEY_I = 73,
|
||||||
|
KEY_J = 74,
|
||||||
|
KEY_K = 75,
|
||||||
|
KEY_L = 76,
|
||||||
|
KEY_M = 77,
|
||||||
|
KEY_N = 78,
|
||||||
|
KEY_O = 79,
|
||||||
|
KEY_P = 80,
|
||||||
|
KEY_Q = 81,
|
||||||
|
KEY_R = 82,
|
||||||
|
KEY_S = 83,
|
||||||
|
KEY_T = 84,
|
||||||
|
KEY_U = 85,
|
||||||
|
KEY_V = 86,
|
||||||
|
KEY_W = 87,
|
||||||
|
KEY_X = 88,
|
||||||
|
KEY_Y = 89,
|
||||||
|
KEY_Z = 90,
|
||||||
|
KEY_LEFT_BRACKET = 91, /* [ */
|
||||||
|
KEY_BACKSLASH = 92, /* \ */
|
||||||
|
KEY_RIGHT_BRACKET = 93, /* ] */
|
||||||
|
KEY_GRAVE_ACCENT = 96, /* ` */
|
||||||
|
KEY_WORLD_1 = 161, /* non-US #1 */
|
||||||
|
KEY_WORLD_2 = 162, /* non-US #2 */
|
||||||
|
KEY_ESCAPE = 256,
|
||||||
|
KEY_ENTER = 257,
|
||||||
|
KEY_TAB = 258,
|
||||||
|
KEY_BACKSPACE = 259,
|
||||||
|
KEY_INSERT = 260,
|
||||||
|
KEY_DELETE = 261,
|
||||||
|
KEY_RIGHT = 262,
|
||||||
|
KEY_LEFT = 263,
|
||||||
|
KEY_DOWN = 264,
|
||||||
|
KEY_UP = 265,
|
||||||
|
KEY_PAGE_UP = 266,
|
||||||
|
KEY_PAGE_DOWN = 267,
|
||||||
|
KEY_HOME = 268,
|
||||||
|
KEY_END = 269,
|
||||||
|
KEY_CAPS_LOCK = 280,
|
||||||
|
KEY_SCROLL_LOCK = 281,
|
||||||
|
KEY_NUM_LOCK = 282,
|
||||||
|
KEY_PRINT_SCREEN = 283,
|
||||||
|
KEY_PAUSE = 284,
|
||||||
|
KEY_F1 = 290,
|
||||||
|
KEY_F2 = 291,
|
||||||
|
KEY_F3 = 292,
|
||||||
|
KEY_F4 = 293,
|
||||||
|
KEY_F5 = 294,
|
||||||
|
KEY_F6 = 295,
|
||||||
|
KEY_F7 = 296,
|
||||||
|
KEY_F8 = 297,
|
||||||
|
KEY_F9 = 298,
|
||||||
|
KEY_F10 = 299,
|
||||||
|
KEY_F11 = 300,
|
||||||
|
KEY_F12 = 301,
|
||||||
|
KEY_F13 = 302,
|
||||||
|
KEY_F14 = 303,
|
||||||
|
KEY_F15 = 304,
|
||||||
|
KEY_F16 = 305,
|
||||||
|
KEY_F17 = 306,
|
||||||
|
KEY_F18 = 307,
|
||||||
|
KEY_F19 = 308,
|
||||||
|
KEY_F20 = 309,
|
||||||
|
KEY_F21 = 310,
|
||||||
|
KEY_F22 = 311,
|
||||||
|
KEY_F23 = 312,
|
||||||
|
KEY_F24 = 313,
|
||||||
|
KEY_F25 = 314,
|
||||||
|
KEY_KP_0 = 320,
|
||||||
|
KEY_KP_1 = 321,
|
||||||
|
KEY_KP_2 = 322,
|
||||||
|
KEY_KP_3 = 323,
|
||||||
|
KEY_KP_4 = 324,
|
||||||
|
KEY_KP_5 = 325,
|
||||||
|
KEY_KP_6 = 326,
|
||||||
|
KEY_KP_7 = 327,
|
||||||
|
KEY_KP_8 = 328,
|
||||||
|
KEY_KP_9 = 329,
|
||||||
|
KEY_KP_DECIMAL = 330,
|
||||||
|
KEY_KP_DIVIDE = 331,
|
||||||
|
KEY_KP_MULTIPLY = 332,
|
||||||
|
KEY_KP_SUBTRACT = 333,
|
||||||
|
KEY_KP_ADD = 334,
|
||||||
|
KEY_KP_ENTER = 335,
|
||||||
|
KEY_KP_EQUAL = 336,
|
||||||
|
KEY_LEFT_SHIFT = 340,
|
||||||
|
KEY_LEFT_CONTROL = 341,
|
||||||
|
KEY_LEFT_ALT = 342,
|
||||||
|
KEY_LEFT_SUPER = 343,
|
||||||
|
KEY_RIGHT_SHIFT = 344,
|
||||||
|
KEY_RIGHT_CONTROL = 345,
|
||||||
|
KEY_RIGHT_ALT = 346,
|
||||||
|
KEY_RIGHT_SUPER = 347,
|
||||||
|
KEY_MENU = 348,
|
||||||
|
|
||||||
|
KEY_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef KeyboardKeys scanCode_t;
|
||||||
|
typedef uint8_t mouseButton_t;
|
||||||
|
|
||||||
|
enum mouseButton_
|
||||||
|
{
|
||||||
|
mouseButton_Left = 1,
|
||||||
|
mouseButton_Middle ,
|
||||||
|
mouseButton_Right ,
|
||||||
|
|
||||||
|
mouseButton_LastNamed = mouseButton_Right
|
||||||
|
};
|
||||||
|
#define GetNamelessMouseButtonIndex(buttonNum) mouseButton_t(mouseButton_LastNamed + buttonNum)
|
||||||
|
|
||||||
|
enum Action_
|
||||||
|
{
|
||||||
|
Action_Forward,
|
||||||
|
Action_Backward,
|
||||||
|
Action_Left,
|
||||||
|
Action_Right,
|
||||||
|
Action_Fire,
|
||||||
|
Action_Use,
|
||||||
|
Action_Max
|
||||||
|
};
|
||||||
|
typedef uint32_t Action;
|
||||||
|
|
||||||
|
class IInputSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IInputSystem() {}
|
||||||
|
|
||||||
|
virtual void Init() = 0;
|
||||||
|
virtual void Shutdown() = 0;
|
||||||
|
virtual void Update() = 0;
|
||||||
|
|
||||||
|
virtual size_t GetMaxScancode () const = 0;
|
||||||
|
virtual size_t GetMaxMouseButton() const = 0;
|
||||||
|
|
||||||
|
virtual char TranslateScancode(scanCode_t scancode) const = 0;
|
||||||
|
|
||||||
|
virtual void OnKeyDown (scanCode_t scancode) = 0;
|
||||||
|
virtual void OnKeyUp (scanCode_t scancode) = 0;
|
||||||
|
virtual void OnMouseKeyDown (mouseButton_t mousebutton) = 0;
|
||||||
|
virtual void OnMouseKeyUp (mouseButton_t mousebutton) = 0;
|
||||||
|
virtual void OnMouseMove (int32_t x, int32_t y) = 0;
|
||||||
|
virtual void OnMouseWheel (int32_t x, int32_t y) = 0;
|
||||||
|
|
||||||
|
virtual bool IsKeyPressed (scanCode_t scancode) const = 0;
|
||||||
|
virtual bool IsMouseButtonPressed (mouseButton_t mousebutton) const = 0;
|
||||||
|
|
||||||
|
virtual void GetMousePosition (int32_t* x, int32_t* y) const = 0;
|
||||||
|
virtual void GetMouseWheelPosition (int32_t* x, int32_t* y) const = 0;
|
||||||
|
|
||||||
|
virtual const char* ActionToString (Action action) const = 0;
|
||||||
|
virtual void BindKey (Action action, scanCode_t scancode) = 0;
|
||||||
|
virtual bool IsActionActive (Action action) const = 0;
|
||||||
|
virtual void UnBindKey (Action action) = 0;
|
||||||
|
virtual void UnBindAll () = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern IInputSystem* g_inputSystem;
|
||||||
|
|
||||||
|
IInputSystem* CreateInputSystem(void* wndHandle);
|
||||||
|
void DestroyInputSystem(IInputSystem* pInstance);
|
||||||
|
|
||||||
|
#endif // !INPUT_SYSTEM_H
|
158
src/engine/physics/physics_object.cpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#include "utils/maths.h"
|
||||||
|
#include "physics_object.h"
|
||||||
|
#include "physics_world.h"
|
||||||
|
#include "physics_render.h"
|
||||||
|
#include "game/game_object.h"
|
||||||
|
|
||||||
|
#include <ode/collision_trimesh.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
PhysicsObject::PhysicsObject() :
|
||||||
|
m_pCollisionShape(nullptr), m_pRigidBody(nullptr), m_pTriMesh(nullptr),
|
||||||
|
m_pEntity(nullptr),
|
||||||
|
m_Friction(0.5f), m_Gravity(0.0f), m_LinearVelocity(0.0f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsObject::~PhysicsObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::CreateTriMesh(const Vec3* vertices, const int verticesCount, const uint32_t* indices, const int indicesCount)
|
||||||
|
{
|
||||||
|
m_pRigidBody = dBodyCreate(g_PhysicsWorld->GetWorld());
|
||||||
|
dBodySetPosition(m_pRigidBody, 0, 0, 0);
|
||||||
|
|
||||||
|
dMass m;
|
||||||
|
dMassSetBox(&m, 1, 10.0f, 10.0f, 10.0f);
|
||||||
|
dBodySetMass(m_pRigidBody, &m);
|
||||||
|
|
||||||
|
// create triangle mesh
|
||||||
|
m_pTriMesh = dGeomTriMeshDataCreate();
|
||||||
|
|
||||||
|
// collect data
|
||||||
|
std::vector<dReal> odevertices;
|
||||||
|
int j = 0;
|
||||||
|
for (int i = 0; i < verticesCount; i++)
|
||||||
|
{
|
||||||
|
if (j > 2)
|
||||||
|
j = 0;
|
||||||
|
|
||||||
|
if (j == 0)
|
||||||
|
odevertices.push_back(vertices[i].x);
|
||||||
|
if (j == 1)
|
||||||
|
odevertices.push_back(vertices[i].x);
|
||||||
|
if (j == 2)
|
||||||
|
odevertices.push_back(vertices[i].x);
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
dGeomTriMeshDataBuildSimple(m_pTriMesh, odevertices.data(), odevertices.size(), (const dTriIndex*)indices, indicesCount);
|
||||||
|
m_pCollisionShape = dCreateTriMesh(g_PhysicsWorld->GetSpace(), m_pTriMesh, NULL, NULL, NULL);
|
||||||
|
dGeomSetBody(m_pCollisionShape, m_pRigidBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::CreatePlayer()
|
||||||
|
{
|
||||||
|
m_pRigidBody = dBodyCreate(g_PhysicsWorld->GetWorld());
|
||||||
|
dBodySetPosition(m_pRigidBody, 0, 0, 0);
|
||||||
|
dBodySetKinematic(m_pRigidBody);
|
||||||
|
dBodySetAutoDisableFlag(m_pRigidBody, 0); // disable body sleeping
|
||||||
|
|
||||||
|
dMass m;
|
||||||
|
dMassSetBox(&m, 1, 10.0f, 10.0f, 10.0f);
|
||||||
|
dBodySetMass(m_pRigidBody, &m);
|
||||||
|
|
||||||
|
m_pCollisionShape = dCreateBox(g_PhysicsWorld->GetSpace(), 0.5f, 0.5f, 0.5f);
|
||||||
|
dGeomSetBody(m_pCollisionShape, m_pRigidBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::CreateSimpleBox()
|
||||||
|
{
|
||||||
|
m_pRigidBody = dBodyCreate(g_PhysicsWorld->GetWorld());
|
||||||
|
dBodySetPosition(m_pRigidBody, 0, 0, 0);
|
||||||
|
|
||||||
|
dMass m;
|
||||||
|
dMassSetBox(&m, 1, 10.0f, 10.0f, 10.0f);
|
||||||
|
dBodySetMass(m_pRigidBody, &m);
|
||||||
|
|
||||||
|
m_pCollisionShape = dCreateBox(g_PhysicsWorld->GetSpace(), 0.5f, 0.5f, 0.5f);
|
||||||
|
dGeomSetBody(m_pCollisionShape, m_pRigidBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::CreateSimpleBox_Kinematic()
|
||||||
|
{
|
||||||
|
m_pRigidBody = dBodyCreate(g_PhysicsWorld->GetWorld());
|
||||||
|
dBodySetPosition(m_pRigidBody, 0, 0, 0);
|
||||||
|
dBodySetKinematic(m_pRigidBody);
|
||||||
|
|
||||||
|
dMass m;
|
||||||
|
dMassSetBox(&m, 1, 10.0f, 10.0f, 10.0f);
|
||||||
|
dBodySetMass(m_pRigidBody, &m);
|
||||||
|
|
||||||
|
m_pCollisionShape = dCreateBox(g_PhysicsWorld->GetSpace(), 0.5f, 0.5f, 0.5f);
|
||||||
|
dGeomSetBody(m_pCollisionShape, m_pRigidBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::Destroy()
|
||||||
|
{
|
||||||
|
g_PhysicsWorld->RemoveObject(this);
|
||||||
|
|
||||||
|
dGeomTriMeshDataDestroy(m_pTriMesh);
|
||||||
|
dGeomDestroy(m_pCollisionShape);
|
||||||
|
dBodyDestroy(m_pRigidBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::SyncWithEntity()
|
||||||
|
{
|
||||||
|
if (!m_pEntity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Vec3 position = m_pEntity->m_position;
|
||||||
|
dBodySetPosition(m_pRigidBody, position.x, position.y, position.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::SyncEntity()
|
||||||
|
{
|
||||||
|
if (!m_pEntity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const dReal* pPos = dBodyGetPosition(m_pRigidBody);
|
||||||
|
m_pEntity->m_position.x = pPos[0];
|
||||||
|
m_pEntity->m_position.y = pPos[1];
|
||||||
|
m_pEntity->m_position.z = pPos[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
float PhysicsObject::GetFriction() const
|
||||||
|
{
|
||||||
|
return m_Friction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::SetFriction(float friction)
|
||||||
|
{
|
||||||
|
m_Friction = friction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::SetLinearVelocity(const Vec3& vel)
|
||||||
|
{
|
||||||
|
m_LinearVelocity = vel;
|
||||||
|
dBodySetLinearVel(m_pRigidBody, vel.x, vel.y, vel.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 PhysicsObject::GetLinearVelocity() const
|
||||||
|
{
|
||||||
|
const dReal* vel = dBodyGetLinearVel(m_pRigidBody);
|
||||||
|
return Vec3( vel[0], vel[1], vel[2] );
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsObject::SetGravity(const Vec3& gravityVector)
|
||||||
|
{
|
||||||
|
m_Gravity = gravityVector;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 PhysicsObject::GetGravity()
|
||||||
|
{
|
||||||
|
return m_Gravity;
|
||||||
|
}
|
54
src/engine/physics/physics_object.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#ifndef PHYSICS_OBJECT_H
|
||||||
|
#define PHYSICS_OBJECT_H
|
||||||
|
|
||||||
|
#include "physics/physics_world.h"
|
||||||
|
|
||||||
|
class GameObject;
|
||||||
|
|
||||||
|
class PhysicsObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PhysicsObject();
|
||||||
|
~PhysicsObject();
|
||||||
|
|
||||||
|
void CreateTriMesh(const Vec3* vertices, const int verticesCount, const uint32_t* indices, const int indicesCount);
|
||||||
|
void CreatePlayer();
|
||||||
|
void CreateSimpleBox();
|
||||||
|
void CreateSimpleBox_Kinematic();
|
||||||
|
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
|
inline dGeomID GetShape() { return (m_pCollisionShape); }
|
||||||
|
inline dGeomID const GetShape() const { return (m_pCollisionShape); }
|
||||||
|
|
||||||
|
inline dBodyID GetBody() { return (m_pRigidBody); }
|
||||||
|
inline dBodyID const GetBody() const { return (m_pRigidBody); }
|
||||||
|
|
||||||
|
inline void SetEntity(GameObject* pEntity) { m_pEntity = pEntity; }
|
||||||
|
inline GameObject* GetEntity() { return (m_pEntity); }
|
||||||
|
inline GameObject const* GetEntity() const { return (m_pEntity); }
|
||||||
|
|
||||||
|
void SyncWithEntity ();
|
||||||
|
void SyncEntity ();
|
||||||
|
|
||||||
|
float GetFriction () const;
|
||||||
|
void SetFriction (float friction);
|
||||||
|
void SetLinearVelocity (const Vec3& vel);
|
||||||
|
Vec3 GetLinearVelocity () const;
|
||||||
|
|
||||||
|
void SetGravity (const Vec3& gravityVector);
|
||||||
|
Vec3 GetGravity ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
GameObject* m_pEntity;
|
||||||
|
dTriMeshDataID m_pTriMesh;
|
||||||
|
dGeomID m_pCollisionShape;
|
||||||
|
dBodyID m_pRigidBody;
|
||||||
|
|
||||||
|
float m_Friction;
|
||||||
|
Vec3 m_Gravity;
|
||||||
|
|
||||||
|
Vec3 m_LinearVelocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !PHYSICS_OBJECT_H
|
1
src/engine/physics/physics_render.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "render/debugrender.h"
|
5
src/engine/physics/physics_render.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#ifndef PHYSICSDEBUGDRAW_H
|
||||||
|
#define PHYSICSDEBUGDRAW_H
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
171
src/engine/physics/physics_world.cpp
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "utils/maths.h"
|
||||||
|
#include "render/debugrender.h"
|
||||||
|
#include "physics_world.h"
|
||||||
|
#include "physics_render.h"
|
||||||
|
#include "physics_object.h"
|
||||||
|
#include "game/game_object.h"
|
||||||
|
|
||||||
|
#include <ode/collision_trimesh.h>
|
||||||
|
|
||||||
|
static void odeNearCollisionCallback(void* _this, dGeomID id1, dGeomID id2)
|
||||||
|
{
|
||||||
|
PhysicsWorld* physWorld = (PhysicsWorld*)_this;
|
||||||
|
return physWorld->NearCollisionCallback(id1, id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsWorld* g_PhysicsWorld = nullptr;
|
||||||
|
|
||||||
|
PhysicsWorld::PhysicsWorld()
|
||||||
|
{
|
||||||
|
m_dynamicsWorld = nullptr;
|
||||||
|
m_space = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
PhysicsWorld::~PhysicsWorld()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsWorld::Create()
|
||||||
|
{
|
||||||
|
m_dynamicsWorld = dWorldCreate();
|
||||||
|
m_space = dHashSpaceCreate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsWorld::Destroy()
|
||||||
|
{
|
||||||
|
dSpaceDestroy(m_space);
|
||||||
|
dWorldDestroy(m_dynamicsWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsWorld::Update(float deltaTime)
|
||||||
|
{
|
||||||
|
dSpaceCollide(m_space, this, &odeNearCollisionCallback);
|
||||||
|
dWorldQuickStep(m_dynamicsWorld, 1);
|
||||||
|
|
||||||
|
|
||||||
|
//dWorldStep(m_dynamicsWorld, 0.05);
|
||||||
|
//dWorldQuickStep(m_dynamicsWorld, stepSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsWorld::DebugDraw()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_objects.size(); i++)
|
||||||
|
{
|
||||||
|
PhysicsObject* obj = m_objects[i];
|
||||||
|
if (dGeomID geom = obj->GetShape())
|
||||||
|
{
|
||||||
|
int type = dGeomGetClass(geom);
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
|
||||||
|
//case dSphereClass:
|
||||||
|
//case dBoxClass:
|
||||||
|
//case dTriMeshClass:
|
||||||
|
//{
|
||||||
|
// //float rad = dGeomSphereGetRadius(geom);
|
||||||
|
// //GLUquadric* q = gluNewQuadric();
|
||||||
|
// //gluSphere(q, rad, 8, 8); break;
|
||||||
|
//}
|
||||||
|
case dBoxClass:
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dTriMeshClass:
|
||||||
|
{
|
||||||
|
// not supported yet
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case dSphereClass:
|
||||||
|
{
|
||||||
|
float rad = dGeomSphereGetRadius(geom);
|
||||||
|
|
||||||
|
glm::mat4 m = obj->GetEntity()->GetModelMatrix();
|
||||||
|
m = glm::scale(m, glm::vec3(RadtoDeg(rad)));
|
||||||
|
|
||||||
|
g_debugRender->DrawEllipse(m, Vec3(0.5f, 0.5f, 1.0f));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
printf(" UNKNOWN OBJECT CLASS!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dWorldID PhysicsWorld::GetWorld()
|
||||||
|
{
|
||||||
|
return m_dynamicsWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
dSpaceID PhysicsWorld::GetSpace()
|
||||||
|
{
|
||||||
|
return m_space;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsWorld::AddObject(PhysicsObject* object)
|
||||||
|
{
|
||||||
|
std::vector<PhysicsObject*>::iterator it = std::find(
|
||||||
|
m_objects.begin(),
|
||||||
|
m_objects.end(),
|
||||||
|
object
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(it == m_objects.end());
|
||||||
|
|
||||||
|
m_objects.push_back(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsWorld::RemoveObject(PhysicsObject* object)
|
||||||
|
{
|
||||||
|
std::vector<PhysicsObject*>::iterator it = std::find(
|
||||||
|
m_objects.begin(),
|
||||||
|
m_objects.end(),
|
||||||
|
object
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(it != m_objects.end());
|
||||||
|
|
||||||
|
m_objects.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsWorld::SetGravity(const Vec3& gravityVector)
|
||||||
|
{
|
||||||
|
dWorldSetGravity(m_dynamicsWorld, gravityVector.x, gravityVector.y, gravityVector.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 PhysicsWorld::GetGravity()
|
||||||
|
{
|
||||||
|
dVector3 g;
|
||||||
|
dWorldGetGravity(m_dynamicsWorld, g);
|
||||||
|
return Vec3(g[0], g[1], g[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsWorld::NearCollisionCallback(dGeomID id1, dGeomID id2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsInit()
|
||||||
|
{
|
||||||
|
dInitODE2(0);
|
||||||
|
|
||||||
|
g_PhysicsWorld = new PhysicsWorld();
|
||||||
|
g_PhysicsWorld->Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PhysicsShutdown()
|
||||||
|
{
|
||||||
|
if (g_PhysicsWorld)
|
||||||
|
{
|
||||||
|
g_PhysicsWorld->Destroy();
|
||||||
|
|
||||||
|
delete g_PhysicsWorld;
|
||||||
|
g_PhysicsWorld = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
dCloseODE();
|
||||||
|
}
|
46
src/engine/physics/physics_world.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef PHYSICS_WORLD_H
|
||||||
|
#define PHYSICS_WORLD_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#define dDOUBLE
|
||||||
|
#include <ode/ode.h>
|
||||||
|
|
||||||
|
class PhysicsObject;
|
||||||
|
|
||||||
|
class PhysicsWorld
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PhysicsWorld();
|
||||||
|
~PhysicsWorld();
|
||||||
|
|
||||||
|
void Create();
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
|
void Update(float deltaTime);
|
||||||
|
void DebugDraw();
|
||||||
|
|
||||||
|
dWorldID GetWorld();
|
||||||
|
dSpaceID GetSpace();
|
||||||
|
|
||||||
|
void AddObject(PhysicsObject* object);
|
||||||
|
void RemoveObject(PhysicsObject* object);
|
||||||
|
|
||||||
|
void SetGravity(const Vec3& gravityVector);
|
||||||
|
Vec3 GetGravity();
|
||||||
|
|
||||||
|
void NearCollisionCallback(dGeomID id1, dGeomID id2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<PhysicsObject*> m_objects;
|
||||||
|
|
||||||
|
dWorldID m_dynamicsWorld;
|
||||||
|
dSpaceID m_space;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PhysicsWorld* g_PhysicsWorld;
|
||||||
|
|
||||||
|
void PhysicsInit();
|
||||||
|
void PhysicsShutdown();
|
||||||
|
|
||||||
|
#endif // !PHYSICS_WORLD_H
|
52
src/engine/render/color.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#ifndef _COLOR_H_
|
||||||
|
#define _COLOR_H_
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//#define MAKE_ARGB(a,r,g,b) \
|
||||||
|
// ((uint32_t)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)))
|
||||||
|
//#define MAKE_RGBA(r,g,b,a) MAKE_ARGB(a,r,g,b)
|
||||||
|
//#define MAKE_XRGB(r,g,b) MAKE_ARGB(0xff,r,g,b)
|
||||||
|
//
|
||||||
|
//#define GET_A(argb) (((argb&0xff000000)>>24)&0xff)
|
||||||
|
//#define GET_R(argb) (((argb&0x00ff0000)>>16)&0xff)
|
||||||
|
//#define GET_G(argb) (((argb&0x0000ff00)>>8)&0xff)
|
||||||
|
//#define GET_B(argb) ((argb&0x000000ff)&0xff)
|
||||||
|
//#define GET_COLOR(argb) \
|
||||||
|
// (Color({\
|
||||||
|
// GET_A(argb),\
|
||||||
|
// GET_R(argb),\
|
||||||
|
// GET_G(argb),\
|
||||||
|
// GET_B(argb)\
|
||||||
|
// }))
|
||||||
|
//
|
||||||
|
//namespace BasicColor
|
||||||
|
//{
|
||||||
|
// enum EBasicColor
|
||||||
|
// {
|
||||||
|
// eWhite = MAKE_XRGB(255, 255, 255),
|
||||||
|
// eBlack = MAKE_XRGB(0, 0, 0),
|
||||||
|
// eRed = MAKE_XRGB(255, 0, 0),
|
||||||
|
// eGreen = MAKE_XRGB(0, 255, 0),
|
||||||
|
// eBlue = MAKE_XRGB(0, 0, 255),
|
||||||
|
// eYellow = MAKE_XRGB(255, 255, 0),
|
||||||
|
// eCyan = MAKE_XRGB(0, 255, 255),
|
||||||
|
// eMagenta = MAKE_XRGB(255, 0, 255)
|
||||||
|
// };
|
||||||
|
//};
|
||||||
|
|
||||||
|
struct Color
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t a;
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
};
|
||||||
|
uint32_t argb;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
341
src/engine/render/debugrender.cpp
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
#include "render/debugrender.h"
|
||||||
|
#include "render/render_shared.h"
|
||||||
|
#include "render/render.h"
|
||||||
|
#include "render/renderdevice.h"
|
||||||
|
#include "render/vertexbuffer.h"
|
||||||
|
#include "render/shadersystem.h"
|
||||||
|
|
||||||
|
#include "glad/glad.h"
|
||||||
|
|
||||||
|
struct DebugVertex
|
||||||
|
{
|
||||||
|
Vec3 position;
|
||||||
|
Vec3 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
static InputLayoutDesc_t g_debugRenderLayout[] =
|
||||||
|
{
|
||||||
|
{ VERTEXATTR_VEC3, SHADERSEMANTIC_POSITION },
|
||||||
|
{ VERTEXATTR_VEC3, SHADERSEMANTIC_COLOR }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const int kEllipseVertexBufferSize = 114;
|
||||||
|
const int kEllipseIndexBufferSize = 672;
|
||||||
|
|
||||||
|
void FillVertexBuffer( VertexBuffer* _pVertexBuffer, const Vec3& _Color )
|
||||||
|
{
|
||||||
|
static Vec3 previousColor = Vec3(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
if (previousColor.x == _Color.x &&
|
||||||
|
previousColor.y == _Color.y &&
|
||||||
|
previousColor.z == _Color.z)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float vertices[] =
|
||||||
|
{
|
||||||
|
0.0000f,0.0000f,1.0000f, 0.0000f,0.3827f,0.9239f, -0.1464f,0.3536f,0.9239f,
|
||||||
|
-0.2706f,0.2706f,0.9239f, -0.3536f,0.1464f,0.9239f, -0.3827f,0.0000f,0.9239f,
|
||||||
|
-0.3536f,-0.1464f,0.9239f, -0.2706f,-0.2706f,0.9239f, -0.1464f,-0.3536f,0.9239f,
|
||||||
|
0.0000f,-0.3827f,0.9239f, 0.1464f,-0.3536f,0.9239f, 0.2706f,-0.2706f,0.9239f,
|
||||||
|
0.3536f,-0.1464f,0.9239f, 0.3827f,0.0000f,0.9239f, 0.3536f,0.1464f,0.9239f,
|
||||||
|
0.2706f,0.2706f,0.9239f, 0.1464f,0.3536f,0.9239f, 0.0000f,0.7071f,0.7071f,
|
||||||
|
-0.2706f,0.6533f,0.7071f, -0.5000f,0.5000f,0.7071f, -0.6533f,0.2706f,0.7071f,
|
||||||
|
-0.7071f,0.0000f,0.7071f, -0.6533f,-0.2706f,0.7071f, -0.5000f,-0.5000f,0.7071f,
|
||||||
|
-0.2706f,-0.6533f,0.7071f, 0.0000f,-0.7071f,0.7071f, 0.2706f,-0.6533f,0.7071f,
|
||||||
|
0.5000f,-0.5000f,0.7071f, 0.6533f,-0.2706f,0.7071f, 0.7071f,0.0000f,0.7071f,
|
||||||
|
0.6533f,0.2706f,0.7071f, 0.5000f,0.5000f,0.7071f, 0.2706f,0.6533f,0.7071f,
|
||||||
|
0.0000f,0.9239f,0.3827f, -0.3536f,0.8536f,0.3827f, -0.6533f,0.6533f,0.3827f,
|
||||||
|
-0.8536f,0.3536f,0.3827f, -0.9239f,0.0000f,0.3827f, -0.8536f,-0.3536f,0.3827f,
|
||||||
|
-0.6533f,-0.6533f,0.3827f, -0.3536f,-0.8536f,0.3827f, 0.0000f,-0.9239f,0.3827f,
|
||||||
|
0.3536f,-0.8536f,0.3827f, 0.6533f,-0.6533f,0.3827f, 0.8536f,-0.3536f,0.3827f,
|
||||||
|
0.9239f,0.0000f,0.3827f, 0.8536f,0.3536f,0.3827f, 0.6533f,0.6533f,0.3827f,
|
||||||
|
0.3536f,0.8536f,0.3827f, 0.0000f,1.0000f,0.0000f, -0.3827f,0.9239f,0.0000f,
|
||||||
|
-0.7071f,0.7071f,0.0000f, -0.9239f,0.3827f,0.0000f, -1.0000f,0.0000f,0.0000f,
|
||||||
|
-0.9239f,-0.3827f,0.0000f, -0.7071f,-0.7071f,0.0000f, -0.3827f,-0.9239f,0.0000f,
|
||||||
|
0.0000f,-1.0000f,0.0000f, 0.3827f,-0.9239f,0.0000f, 0.7071f,-0.7071f,0.0000f,
|
||||||
|
0.9239f,-0.3827f,0.0000f, 1.0000f,0.0000f,0.0000f, 0.9239f,0.3827f,0.0000f,
|
||||||
|
0.7071f,0.7071f,0.0000f, 0.3827f,0.9239f,0.0000f, 0.0000f,0.9239f,-0.3827f,
|
||||||
|
-0.3536f,0.8536f,-0.3827f, -0.6533f,0.6533f,-0.3827f, -0.8536f,0.3536f,-0.3827f,
|
||||||
|
-0.9239f,0.0000f,-0.3827f, -0.8536f,-0.3536f,-0.3827f, -0.6533f,-0.6533f,-0.3827f,
|
||||||
|
-0.3536f,-0.8536f,-0.3827f, 0.0000f,-0.9239f,-0.3827f, 0.3536f,-0.8536f,-0.3827f,
|
||||||
|
0.6533f,-0.6533f,-0.3827f, 0.8536f,-0.3536f,-0.3827f, 0.9239f,0.0000f,-0.3827f,
|
||||||
|
0.8536f,0.3536f,-0.3827f, 0.6533f,0.6533f,-0.3827f, 0.3536f,0.8536f,-0.3827f,
|
||||||
|
0.0000f,0.7071f,-0.7071f, -0.2706f,0.6533f,-0.7071f, -0.5000f,0.5000f,-0.7071f,
|
||||||
|
-0.6533f,0.2706f,-0.7071f, -0.7071f,0.0000f,-0.7071f, -0.6533f,-0.2706f,-0.7071f,
|
||||||
|
-0.5000f,-0.5000f,-0.7071f, -0.2706f,-0.6533f,-0.7071f, 0.0000f,-0.7071f,-0.7071f,
|
||||||
|
0.2706f,-0.6533f,-0.7071f, 0.5000f,-0.5000f,-0.7071f, 0.6533f,-0.2706f,-0.7071f,
|
||||||
|
0.7071f,0.0000f,-0.7071f, 0.6533f,0.2706f,-0.7071f, 0.5000f,0.5000f,-0.7071f,
|
||||||
|
0.2706f,0.6533f,-0.7071f, 0.0000f,0.3827f,-0.9239f, -0.1464f,0.3536f,-0.9239f,
|
||||||
|
-0.2706f,0.2706f,-0.9239f, -0.3536f,0.1464f,-0.9239f, -0.3827f,0.0000f,-0.9239f,
|
||||||
|
-0.3536f,-0.1464f,-0.9239f, -0.2706f,-0.2706f,-0.9239f, -0.1464f,-0.3536f,-0.9239f,
|
||||||
|
0.0000f,-0.3827f,-0.9239f, 0.1464f,-0.3536f,-0.9239f, 0.2706f,-0.2706f,-0.9239f,
|
||||||
|
0.3536f,-0.1464f,-0.9239f, 0.3827f,0.0000f,-0.9239f, 0.3536f,0.1464f,-0.9239f,
|
||||||
|
0.2706f,0.2706f,-0.9239f, 0.1464f,0.3536f,-0.9239f, 0.0000f,0.0000f,-1.0000f
|
||||||
|
};
|
||||||
|
|
||||||
|
const int vcnt = sizeof(vertices) / (sizeof(float) * 3);
|
||||||
|
DebugVertex verts[vcnt];
|
||||||
|
for (int i = 0; i < vcnt; i++) {
|
||||||
|
int k = i * 3;
|
||||||
|
|
||||||
|
verts[i].position.x = vertices[k];
|
||||||
|
verts[i].position.y = vertices[k + 1];
|
||||||
|
verts[i].position.z = vertices[k + 2];
|
||||||
|
verts[i].color = _Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugVertex* pAGPMemory = ( DebugVertex* )_pVertexBuffer->MapBuffer( BufferAccess::WRITE_ONLY );
|
||||||
|
memcpy( pAGPMemory, verts, sizeof( verts ) );
|
||||||
|
_pVertexBuffer->UnmapBuffer();
|
||||||
|
|
||||||
|
previousColor = _Color;
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexBuffer* CreateEllipseIndexBuffer()
|
||||||
|
{
|
||||||
|
uint16_t faces[224 * 3] =
|
||||||
|
{
|
||||||
|
0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,7, 0,7,8, 0,8,9, 0,9,10,
|
||||||
|
0,10,11, 0,11,12, 0,12,13, 0,13,14, 0,14,15, 0,15,16, 0,16,1, 1,17,18, 1,18,2,
|
||||||
|
2,18,19, 2,19,3, 3,19,20, 3,20,4, 4,20,21, 4,21,5, 5,21,22, 5,22,6, 6,22,23,
|
||||||
|
6,23,7, 7,23,24, 7,24,8, 8,24,25, 8,25,9, 9,25,26, 9,26,10, 10,26,27, 10,27,11,
|
||||||
|
11,27,28, 11,28,12, 12,28,29, 12,29,13, 13,29,30, 13,30,14, 14,30,31, 14,31,15, 15,31,32,
|
||||||
|
15,32,16, 16,32,17, 16,17,1, 17,33,34, 17,34,18, 18,34,35, 18,35,19, 19,35,36, 19,36,20,
|
||||||
|
20,36,37, 20,37,21, 21,37,38, 21,38,22, 22,38,39, 22,39,23, 23,39,40, 23,40,24, 24,40,41,
|
||||||
|
24,41,25, 25,41,42, 25,42,26, 26,42,43, 26,43,27, 27,43,44, 27,44,28, 28,44,45, 28,45,29,
|
||||||
|
29,45,46, 29,46,30, 30,46,47, 30,47,31, 31,47,48, 31,48,32, 32,48,33, 32,33,17, 33,49,50,
|
||||||
|
33,50,34, 34,50,51, 34,51,35, 35,51,52, 35,52,36, 36,52,53, 36,53,37, 37,53,54, 37,54,38,
|
||||||
|
38,54,55, 38,55,39, 39,55,56, 39,56,40, 40,56,57, 40,57,41, 41,57,58, 41,58,42, 42,58,59,
|
||||||
|
42,59,43, 43,59,60, 43,60,44, 44,60,61, 44,61,45, 45,61,62, 45,62,46, 46,62,63, 46,63,47,
|
||||||
|
47,63,64, 47,64,48, 48,64,49, 48,49,33, 49,65,66, 49,66,50, 50,66,67, 50,67,51, 51,67,68,
|
||||||
|
51,68,52, 52,68,69, 52,69,53, 53,69,70, 53,70,54, 54,70,71, 54,71,55, 55,71,72, 55,72,56,
|
||||||
|
56,72,73, 56,73,57, 57,73,74, 57,74,58, 58,74,75, 58,75,59, 59,75,76, 59,76,60, 60,76,77,
|
||||||
|
60,77,61, 61,77,78, 61,78,62, 62,78,79, 62,79,63, 63,79,80, 63,80,64, 64,80,65, 64,65,49,
|
||||||
|
65,81,82, 65,82,66, 66,82,83, 66,83,67, 67,83,84, 67,84,68, 68,84,85, 68,85,69, 69,85,86,
|
||||||
|
69,86,70, 70,86,87, 70,87,71, 71,87,88, 71,88,72, 72,88,89, 72,89,73, 73,89,90, 73,90,74,
|
||||||
|
74,90,91, 74,91,75, 75,91,92, 75,92,76, 76,92,93, 76,93,77, 77,93,94, 77,94,78, 78,94,95,
|
||||||
|
78,95,79, 79,95,96, 79,96,80, 80,96,81, 80,81,65, 81,97,98, 81,98,82, 82,98,99, 82,99,83,
|
||||||
|
83,99,100, 83,100,84, 84,100,101, 84,101,85, 85,101,102, 85,102,86, 86,102,103, 86,103,87, 87,103,104,
|
||||||
|
87,104,88, 88,104,105, 88,105,89, 89,105,106, 89,106,90, 90,106,107, 90,107,91, 91,107,108, 91,108,92,
|
||||||
|
92,108,109, 92,109,93, 93,109,110, 93,110,94, 94,110,111, 94,111,95, 95,111,112, 95,112,96, 96,112,97,
|
||||||
|
96,97,81, 113,98,97, 113,99,98, 113,100,99, 113,101,100, 113,102,101, 113,103,102, 113,104,103, 113,105,104,
|
||||||
|
113,106,105, 113,107,106, 113,108,107, 113,109,108, 113,110,109, 113,111,110, 113,112,111, 113,97,112
|
||||||
|
};
|
||||||
|
|
||||||
|
return g_renderDevice->CreateIndexBuffer(faces, sizeof(faces));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool g_drawDebug = false;
|
||||||
|
DebugRender* g_debugRender;
|
||||||
|
|
||||||
|
DebugRender::DebugRender()
|
||||||
|
{
|
||||||
|
m_verticesBuffer = nullptr;
|
||||||
|
m_ellipseVertexBuffer = nullptr;
|
||||||
|
m_ellipseIndexBuffer = nullptr;
|
||||||
|
m_shader = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugRender::~DebugRender()
|
||||||
|
{
|
||||||
|
m_verticesBuffer = nullptr;
|
||||||
|
m_shader = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::Initialize()
|
||||||
|
{
|
||||||
|
float points[12];
|
||||||
|
m_verticesBuffer = g_renderDevice->CreateVertexBuffer(points, sizeof(points), true);
|
||||||
|
|
||||||
|
m_ellipseVertexBuffer = g_renderDevice->CreateVertexBuffer(nullptr, kEllipseVertexBufferSize * sizeof(DebugVertex), true);
|
||||||
|
m_ellipseIndexBuffer = CreateEllipseIndexBuffer();
|
||||||
|
|
||||||
|
m_shader = g_shaderSystem->CreateShader("debug_draw",
|
||||||
|
"content/shaders/debug_draw.vs",
|
||||||
|
"content/shaders/debug_draw.ps",
|
||||||
|
g_debugRenderLayout,
|
||||||
|
sizeof(g_debugRenderLayout) / sizeof(g_debugRenderLayout[0]));
|
||||||
|
|
||||||
|
m_shader->m_stride = sizeof(DebugVertex);
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &m_vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::Shutdown()
|
||||||
|
{
|
||||||
|
glDeleteVertexArrays(1, &m_vao);
|
||||||
|
|
||||||
|
if (m_ellipseIndexBuffer) {
|
||||||
|
delete m_ellipseIndexBuffer;
|
||||||
|
m_ellipseIndexBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ellipseVertexBuffer) {
|
||||||
|
delete m_ellipseVertexBuffer;
|
||||||
|
m_ellipseVertexBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_verticesBuffer) {
|
||||||
|
delete m_verticesBuffer;
|
||||||
|
m_verticesBuffer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::DrawLine(const Vec3& from, const Vec3& to, const Vec3& color)
|
||||||
|
{
|
||||||
|
if (!g_drawDebug)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Line line;
|
||||||
|
line.from = from;
|
||||||
|
line.color0 = color;
|
||||||
|
line.to = to;
|
||||||
|
line.color1 = color;
|
||||||
|
m_lines.push_back(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::DrawBoundingBox(const BoundingBox& box, const glm::vec3& color)
|
||||||
|
{
|
||||||
|
glm::vec3 from = glm::vec3(box.min.x, box.min.y, box.min.z);
|
||||||
|
glm::vec3 to = glm::vec3(box.max.x, box.max.y, box.max.z);
|
||||||
|
|
||||||
|
glm::vec3 halfExtents = (to - from) * 0.5f;
|
||||||
|
glm::vec3 center = (to + from) * 0.5f;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
glm::vec3 edgecoord(1.f, 1.f, 1.f), pa, pb;
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
pa = glm::vec3(edgecoord[0] * halfExtents[0], edgecoord[1] * halfExtents[1],
|
||||||
|
edgecoord[2] * halfExtents[2]);
|
||||||
|
pa += center;
|
||||||
|
|
||||||
|
int othercoord = j % 3;
|
||||||
|
edgecoord[othercoord] *= -1.f;
|
||||||
|
pb = glm::vec3(edgecoord[0] * halfExtents[0], edgecoord[1] * halfExtents[1],
|
||||||
|
edgecoord[2] * halfExtents[2]);
|
||||||
|
pb += center;
|
||||||
|
|
||||||
|
DrawLine(Vec3(pa.x, pa.y, pa.z), Vec3(pb.x, pb.y, pb.z) , Vec3(color.x, color.y, color.z) );
|
||||||
|
}
|
||||||
|
|
||||||
|
edgecoord = glm::vec3(-1.f, -1.f, -1.f);
|
||||||
|
if (i < 3)
|
||||||
|
edgecoord[i] *= -1.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::DrawEllipse(const glm::mat4& trans, const Vec3& color)
|
||||||
|
{
|
||||||
|
EllipseDrawCmd drawCmd = {};
|
||||||
|
drawCmd.trans = trans;
|
||||||
|
drawCmd.color = color;
|
||||||
|
m_ellipseDrawCmd.push_back(drawCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::RenderFrame()
|
||||||
|
{
|
||||||
|
if (!g_drawDebug)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BeginDraw();
|
||||||
|
|
||||||
|
// draw lines
|
||||||
|
DrawLinesInternal();
|
||||||
|
|
||||||
|
// and clear them
|
||||||
|
m_lines.clear();
|
||||||
|
|
||||||
|
// Draw cmds
|
||||||
|
DrawCmds();
|
||||||
|
|
||||||
|
// and clear them
|
||||||
|
m_ellipseDrawCmd.clear();
|
||||||
|
|
||||||
|
EndDraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::DrawAxis(const Vec3& vec)
|
||||||
|
{
|
||||||
|
const float length = 0.2f;
|
||||||
|
DrawLine(vec, Vec3(vec.x + length, vec.y, vec.z), Vec3(1.0f, 0.0, 0.0f));
|
||||||
|
DrawLine(vec, Vec3(vec.x, vec.y + length, vec.z), Vec3(0.0f, 0.0f, 1.0f));
|
||||||
|
DrawLine(vec, Vec3(vec.x, vec.y, vec.z + length), Vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::BeginDraw()
|
||||||
|
{
|
||||||
|
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, (int*)&m_savedVao);
|
||||||
|
|
||||||
|
glBindVertexArray(m_vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::EndDraw()
|
||||||
|
{
|
||||||
|
glBindVertexArray(m_savedVao);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::DrawLinesInternal()
|
||||||
|
{
|
||||||
|
if (m_lines.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_renderDevice->SetDepthTest(true);
|
||||||
|
g_renderDevice->SetDepthWrite(true);
|
||||||
|
|
||||||
|
g_renderDevice->SetVerticesBuffer(m_verticesBuffer);
|
||||||
|
|
||||||
|
m_verticesBuffer->UpdateBuffer(m_lines.data(), m_lines.size() * sizeof(Line));
|
||||||
|
|
||||||
|
// Bind our shader
|
||||||
|
g_shaderSystem->SetShader(m_shader);
|
||||||
|
|
||||||
|
// #TODO: Fix stupid bug, when we get very far from wireframe and lines can start cliping
|
||||||
|
View view = g_renderView;
|
||||||
|
view.proj[2][3] -= 0.0001f;
|
||||||
|
|
||||||
|
glm::mat4 mv = glm::identity<glm::mat4>();
|
||||||
|
mv = view.proj * view.view;
|
||||||
|
|
||||||
|
g_shaderSystem->SetUniformMatrix(m_shader, UNIFORM_MVP_MATRIX, &mv[0]);
|
||||||
|
|
||||||
|
// draw stuff
|
||||||
|
g_renderDevice->DrawArrays(PT_LINES, 0, m_lines.size() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugRender::DrawCmds()
|
||||||
|
{
|
||||||
|
if (m_ellipseDrawCmd.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_renderDevice->SetDepthTest(true);
|
||||||
|
g_renderDevice->SetDepthWrite(true);
|
||||||
|
|
||||||
|
g_renderDevice->SetVerticesBuffer(m_ellipseVertexBuffer);
|
||||||
|
g_renderDevice->SetIndicesBuffer(m_ellipseIndexBuffer);
|
||||||
|
|
||||||
|
// Bind our shader
|
||||||
|
g_shaderSystem->SetShader(m_shader);
|
||||||
|
|
||||||
|
for (int i = 0; i < m_ellipseDrawCmd.size(); i++)
|
||||||
|
{
|
||||||
|
const EllipseDrawCmd& cmd = m_ellipseDrawCmd[i];
|
||||||
|
|
||||||
|
FillVertexBuffer(m_ellipseVertexBuffer, cmd.color);
|
||||||
|
|
||||||
|
// #TODO: Fix stupid bug, when we get very far from wireframe and lines can start cliping
|
||||||
|
View view = g_renderView;
|
||||||
|
view.proj[2][3] -= 0.0001f;
|
||||||
|
|
||||||
|
glm::mat4 mv = glm::identity<glm::mat4>();
|
||||||
|
mv = view.proj * view.view * cmd.trans;
|
||||||
|
|
||||||
|
g_shaderSystem->SetUniformMatrix(m_shader, UNIFORM_MVP_MATRIX, &mv[0]);
|
||||||
|
|
||||||
|
// draw stuff
|
||||||
|
g_renderDevice->DrawElements( PT_LINES, 672, true );
|
||||||
|
}
|
||||||
|
}
|
68
src/engine/render/debugrender.h
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#ifndef DEBUGRENDER_H
|
||||||
|
#define DEBUGRENDER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <utils/maths.h>
|
||||||
|
|
||||||
|
class VertexBuffer;
|
||||||
|
class IndexBuffer;
|
||||||
|
class Shader;
|
||||||
|
|
||||||
|
class DebugRender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DebugRender();
|
||||||
|
~DebugRender();
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void DrawAxis(const Vec3& vec);
|
||||||
|
void DrawLine(const Vec3& from, const Vec3& to, const Vec3& color);
|
||||||
|
void DrawBoundingBox(const BoundingBox& box, const glm::vec3& color);
|
||||||
|
void DrawEllipse(const glm::mat4& trans, const Vec3& color);
|
||||||
|
|
||||||
|
void RenderFrame();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void BeginDraw();
|
||||||
|
void EndDraw();
|
||||||
|
|
||||||
|
void DrawLinesInternal();
|
||||||
|
void DrawCmds();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Primitives
|
||||||
|
struct Line
|
||||||
|
{
|
||||||
|
Vec3 from;
|
||||||
|
Vec3 color0;
|
||||||
|
|
||||||
|
Vec3 to;
|
||||||
|
Vec3 color1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EllipseDrawCmd
|
||||||
|
{
|
||||||
|
glm::mat4 trans;
|
||||||
|
Vec3 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Line> m_lines;
|
||||||
|
std::vector<EllipseDrawCmd> m_ellipseDrawCmd;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VertexBuffer* m_verticesBuffer;
|
||||||
|
VertexBuffer* m_ellipseVertexBuffer;
|
||||||
|
IndexBuffer* m_ellipseIndexBuffer;
|
||||||
|
Shader* m_shader;
|
||||||
|
|
||||||
|
unsigned int m_vao;
|
||||||
|
unsigned int m_savedVao;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DebugRender* g_debugRender;
|
||||||
|
|
||||||
|
extern bool g_drawDebug;
|
||||||
|
|
||||||
|
#endif // !DEBUGRENDER_H
|
76
src/engine/render/font.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include "utils/logger.h"
|
||||||
|
#include "render/font.h"
|
||||||
|
#include "render/shader.h"
|
||||||
|
#include "render/vertexbuffer.h"
|
||||||
|
#include "render/indexbuffer.h"
|
||||||
|
#include "render/renderdevice.h"
|
||||||
|
#include "render/shadersystem.h"
|
||||||
|
#include "render/ui.h"
|
||||||
|
#include "render/texture2d.h"
|
||||||
|
#include "render/texturesmanager.h"
|
||||||
|
|
||||||
|
#include <stb_easy_font.h>
|
||||||
|
|
||||||
|
struct FontGlobals {
|
||||||
|
VertexBuffer* vb;
|
||||||
|
IndexBuffer* ib;
|
||||||
|
Shader* shader;
|
||||||
|
|
||||||
|
UIVertex* vertices = nullptr;
|
||||||
|
uint16_t* indices = nullptr;
|
||||||
|
uint16_t count = 0;
|
||||||
|
uint16_t position = 0;
|
||||||
|
uint16_t Indexposition = 0;
|
||||||
|
uint16_t currentIdx = 0;
|
||||||
|
} g_font;
|
||||||
|
|
||||||
|
void fontInit()
|
||||||
|
{
|
||||||
|
// Create vertex and index buffer
|
||||||
|
|
||||||
|
// same as ui
|
||||||
|
g_font.vb = g_renderDevice->CreateVertexBuffer( nullptr, MAX_UI_VERTICES, true );
|
||||||
|
|
||||||
|
// Create shader
|
||||||
|
|
||||||
|
InputLayoutDesc_t inputLayout[] =
|
||||||
|
{
|
||||||
|
{ VERTEXATTR_VEC2, SHADERSEMANTIC_POSITION },
|
||||||
|
{ VERTEXATTR_VEC2, SHADERSEMANTIC_TEXCOORD },
|
||||||
|
{ VERTEXATTR_VEC4, SHADERSEMANTIC_COLOR },
|
||||||
|
};
|
||||||
|
|
||||||
|
g_font.shader = g_shaderSystem->CreateShader("ui_base", "content/shaders/ui_base.vs", "content/shaders/ui_base.ps", inputLayout, sizeof(inputLayout) / sizeof(inputLayout[0]));
|
||||||
|
g_font.shader->m_stride = sizeof( UIVertex );
|
||||||
|
}
|
||||||
|
|
||||||
|
void fontShutdown()
|
||||||
|
{
|
||||||
|
delete g_font.ib;
|
||||||
|
delete g_font.vb;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned char toByteColor(const Vec4& color)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void fontDrawString(const char* text, float x, float y, float w, float h, const Vec4& color)
|
||||||
|
{
|
||||||
|
// lock buffers
|
||||||
|
|
||||||
|
UIVertex* vertices = (UIVertex*)g_font.vb->MapBuffer(BufferAccess::WRITE_ONLY);
|
||||||
|
|
||||||
|
//int num_quads = stb_easy_font_print(x, y, (char*)text, , buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
//static char buffer[99999]; // ~500 chars
|
||||||
|
//int num_quads;
|
||||||
|
|
||||||
|
//num_quads = stb_easy_font_print(x, y, (char*)text, NULL, buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
//glColor3f(r, g, b);
|
||||||
|
//glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
//glVertexPointer(2, GL_FLOAT, 16, buffer);
|
||||||
|
//glDrawArrays(GL_QUADS, 0, num_quads * 4);
|
||||||
|
//glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
}
|
10
src/engine/render/font.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef FONT_H
|
||||||
|
#define FONT_H
|
||||||
|
|
||||||
|
#include <utils/maths.h>
|
||||||
|
|
||||||
|
void fontInit();
|
||||||
|
void fontShutdown();
|
||||||
|
void fontDrawString(const char* text, float x, float y, float w, float h, const Vec4& color);
|
||||||
|
|
||||||
|
#endif // !FONT_H
|
44
src/engine/render/gl_shared.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "utils/logger.h"
|
||||||
|
#include "render/gl_shared.h"
|
||||||
|
|
||||||
|
const char *GL_ErrorString( int err )
|
||||||
|
{
|
||||||
|
switch( err )
|
||||||
|
{
|
||||||
|
case GL_STACK_OVERFLOW:
|
||||||
|
return "GL_STACK_OVERFLOW";
|
||||||
|
case GL_STACK_UNDERFLOW:
|
||||||
|
return "GL_STACK_UNDERFLOW";
|
||||||
|
case GL_INVALID_ENUM:
|
||||||
|
return "GL_INVALID_ENUM";
|
||||||
|
case GL_INVALID_VALUE:
|
||||||
|
return "GL_INVALID_VALUE";
|
||||||
|
case GL_INVALID_OPERATION:
|
||||||
|
return "GL_INVALID_OPERATION";
|
||||||
|
case GL_OUT_OF_MEMORY:
|
||||||
|
return "GL_OUT_OF_MEMORY";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL_CheckError()
|
||||||
|
{
|
||||||
|
GLenum err;
|
||||||
|
if ( (err = glGetError()) != GL_NO_ERROR )
|
||||||
|
Msg( "OpenGL Error: %s", GL_ErrorString( err ) );// Msg("OpenGL Error: %s [%s]\n", GL_ErrorString(err), GL_TargetToString(tex->target));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL_CheckErrorEx( const char* filename, int line )
|
||||||
|
{
|
||||||
|
GLenum err;
|
||||||
|
if ( (err = glGetError()) != GL_NO_ERROR )
|
||||||
|
Msg( "OpenGL Error: %s at %s:%i", GL_ErrorString( err ), filename, line );// Msg("OpenGL Error: %s [%s]\n", GL_ErrorString(err), GL_TargetToString(tex->target));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL_CheckErrorFunction(const char* expression, const char* filename, int line)
|
||||||
|
{
|
||||||
|
GLenum err;
|
||||||
|
if ( (err = glGetError()) != GL_NO_ERROR )
|
||||||
|
Msg( "OpenGL Error: %s (%s) at %s:%i", expression, GL_ErrorString( err ), filename, line );// Msg("OpenGL Error: %s [%s]\n", GL_ErrorString(err), GL_TargetToString(tex->target));
|
||||||
|
}
|
17
src/engine/render/gl_shared.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef GL_SHARED_H
|
||||||
|
#define GL_SHARED_H
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
void GL_CheckError();
|
||||||
|
void GL_CheckErrorEx(const char* filename, int line);
|
||||||
|
void GL_CheckErrorFunction(const char* expression, const char* filename, int line);
|
||||||
|
|
||||||
|
#define GL_CHECK_ERROR() \
|
||||||
|
GL_CheckErrorEx(__FILE__, __LINE__)
|
||||||
|
|
||||||
|
#define GL_CHECK_FUNC_ERROR(expr) \
|
||||||
|
expr; \
|
||||||
|
GL_CheckErrorFunction(#expr, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
#endif // !GL_SHARED_H
|
56
src/engine/render/indexbuffer.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "render/indexbuffer.h"
|
||||||
|
#include "render/gl_shared.h"
|
||||||
|
|
||||||
|
IndexBuffer::IndexBuffer(void* data, size_t size, bool isStream /*= false*/)
|
||||||
|
{
|
||||||
|
glGenBuffers(1, &m_buffer);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, isStream ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
//if (isStream) {
|
||||||
|
// Logger::msg("created dynamic index stream ...");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexBuffer::~IndexBuffer()
|
||||||
|
{
|
||||||
|
glDeleteBuffers(1, &m_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexBuffer::Bind()
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* IndexBuffer::MapBuffer(BufferAccess access)
|
||||||
|
{
|
||||||
|
GLenum accessGl = 0;
|
||||||
|
|
||||||
|
switch (access)
|
||||||
|
{
|
||||||
|
case BufferAccess::READ_ONLY:
|
||||||
|
accessGl = GL_READ_ONLY;
|
||||||
|
break;
|
||||||
|
case BufferAccess::WRITE_ONLY:
|
||||||
|
accessGl = GL_WRITE_ONLY;
|
||||||
|
break;
|
||||||
|
case BufferAccess::READ_WRITE:
|
||||||
|
accessGl = GL_READ_WRITE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bind();
|
||||||
|
|
||||||
|
void* ptr = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, accessGl);
|
||||||
|
|
||||||
|
//check_for_opengl_error();
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexBuffer::UnmapBuffer()
|
||||||
|
{
|
||||||
|
Bind();
|
||||||
|
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
||||||
|
}
|
26
src/engine/render/indexbuffer.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef INDEXOBJECT_H
|
||||||
|
#define INDEXOBJECT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "render/render_shared.h"
|
||||||
|
|
||||||
|
class RenderDevice;
|
||||||
|
|
||||||
|
class IndexBuffer
|
||||||
|
{
|
||||||
|
friend class RenderDevice;
|
||||||
|
public:
|
||||||
|
~IndexBuffer();
|
||||||
|
|
||||||
|
void* MapBuffer(BufferAccess access);
|
||||||
|
void UnmapBuffer();
|
||||||
|
|
||||||
|
void Bind();
|
||||||
|
|
||||||
|
private:
|
||||||
|
IndexBuffer(void* data, size_t size, bool isStream = false);
|
||||||
|
|
||||||
|
uint32_t m_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !INDEXOBJECT_H
|
373
src/engine/render/modelmanager.cpp
Normal file
@ -0,0 +1,373 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <utils/maths.h>
|
||||||
|
#include <utils/timer.h>
|
||||||
|
#include <filesystem/filemanager.h>
|
||||||
|
#include <input/input_system.h>
|
||||||
|
#include <render/vertexbuffer.h>
|
||||||
|
#include <render/indexbuffer.h>
|
||||||
|
#include <render/renderdevice.h>
|
||||||
|
#include <render/modelmanager.h>
|
||||||
|
#include <render/shader.h>
|
||||||
|
#include <render/shadersystem.h>
|
||||||
|
#include <render/texturesmanager.h>
|
||||||
|
#include <render/texture2d.h>
|
||||||
|
#include <render/debugrender.h>
|
||||||
|
|
||||||
|
ModelManager* g_modelManager = nullptr;
|
||||||
|
|
||||||
|
static InputLayoutDesc_t g_staticVertexLayout[] = {
|
||||||
|
{ VERTEXATTR_VEC3, SHADERSEMANTIC_POSITION },
|
||||||
|
{ VERTEXATTR_VEC3, SHADERSEMANTIC_NORMAL },
|
||||||
|
{ VERTEXATTR_VEC2, SHADERSEMANTIC_TEXCOORD },
|
||||||
|
};
|
||||||
|
|
||||||
|
static InputLayoutDesc_t g_skinnedVertexLayout[] = {
|
||||||
|
{ VERTEXATTR_VEC3, SHADERSEMANTIC_POSITION },
|
||||||
|
{ VERTEXATTR_VEC3, SHADERSEMANTIC_NORMAL },
|
||||||
|
{ VERTEXATTR_VEC2, SHADERSEMANTIC_TEXCOORD }
|
||||||
|
};
|
||||||
|
|
||||||
|
Shader* g_litShader = nullptr;
|
||||||
|
|
||||||
|
ModelManager::ModelManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelManager::~ModelManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBuffer* ModelManager::CreateVertexBuffer( void* data, int size )
|
||||||
|
{
|
||||||
|
// create vertex buffer
|
||||||
|
VertexBuffer* vb = g_renderDevice->CreateVertexBuffer( data, size );
|
||||||
|
|
||||||
|
return vb;
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexBuffer* ModelManager::CreateIndexBuffer( void* data, int size )
|
||||||
|
{
|
||||||
|
// create index buffer
|
||||||
|
IndexBuffer* ib = g_renderDevice->CreateIndexBuffer( data, size );
|
||||||
|
|
||||||
|
return ib;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* ModelManager::LoadModel(const char* filename)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_models.begin(), m_models.end(), [=](const ModelEntry& entry) { return strcmp(entry.filename, filename) == 0; });
|
||||||
|
if (it != m_models.end())
|
||||||
|
{
|
||||||
|
return it->model;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_fileManager->FileExist(filename))
|
||||||
|
{
|
||||||
|
Logger::logPrint("ModelManager::LoadModel: File '%s' not exist.", filename);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model* model = new Model();
|
||||||
|
|
||||||
|
if (strstr(filename, ".obj"))
|
||||||
|
{
|
||||||
|
model->LoadObj(filename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger::logPrint("ModelManager::LoadModel(%s): Unknowed file format '%s'",
|
||||||
|
filename, fs::getFileExtension(filename).c_str());
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelEntry entry = {};
|
||||||
|
strcpy(entry.filename, filename);
|
||||||
|
entry.model = model;
|
||||||
|
|
||||||
|
m_models.push_back(entry);
|
||||||
|
|
||||||
|
Logger::logPrint("ModelManager::LoadModel: Loaded '%s'", filename);
|
||||||
|
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
Model::Model()
|
||||||
|
{
|
||||||
|
m_data.vb = nullptr;
|
||||||
|
m_data.ib = nullptr;
|
||||||
|
m_AlbedoTexture = nullptr;
|
||||||
|
|
||||||
|
m_boundingBox.min = glm::vec3(0.0f);
|
||||||
|
m_boundingBox.max = glm::vec3(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Model::~Model()
|
||||||
|
{
|
||||||
|
m_AlbedoTexture = nullptr;
|
||||||
|
|
||||||
|
if (m_data.vb)
|
||||||
|
{
|
||||||
|
delete m_data.vb;
|
||||||
|
m_data.vb = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::LoadObj( const char* filename )
|
||||||
|
{
|
||||||
|
Msg( "Loading OBJ file %s...", filename );
|
||||||
|
|
||||||
|
std::vector<unsigned int> vertexIndices, uvIndices, normalIndices;
|
||||||
|
std::vector<glm::vec3> temp_vertices;
|
||||||
|
std::vector<glm::vec2> temp_uvs;
|
||||||
|
std::vector<glm::vec3> temp_normals;
|
||||||
|
|
||||||
|
std::vector<glm::vec3> out_vertices;
|
||||||
|
std::vector<glm::vec2> out_uvs;
|
||||||
|
std::vector<glm::vec3> out_normals;
|
||||||
|
|
||||||
|
FILE* file = fopen(filename, "r");
|
||||||
|
if (file == NULL) {
|
||||||
|
Msg("Model::LoadObj: Impossible to open the file !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
char lineHeader[128];
|
||||||
|
// read the first word of the line
|
||||||
|
int res = fscanf(file, "%s", lineHeader);
|
||||||
|
if (res == EOF)
|
||||||
|
break; // EOF = End Of File. Quit the loop.
|
||||||
|
|
||||||
|
// else : parse lineHeader
|
||||||
|
|
||||||
|
if (strcmp(lineHeader, "v") == 0) {
|
||||||
|
glm::vec3 vertex;
|
||||||
|
fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
|
||||||
|
temp_vertices.push_back(vertex);
|
||||||
|
}
|
||||||
|
else if (strcmp(lineHeader, "vt") == 0) {
|
||||||
|
glm::vec2 uv;
|
||||||
|
fscanf(file, "%f %f\n", &uv.x, &uv.y);
|
||||||
|
uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders.
|
||||||
|
temp_uvs.push_back(uv);
|
||||||
|
}
|
||||||
|
else if (strcmp(lineHeader, "vn") == 0) {
|
||||||
|
glm::vec3 normal;
|
||||||
|
fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z);
|
||||||
|
temp_normals.push_back(normal);
|
||||||
|
}
|
||||||
|
else if (strcmp(lineHeader, "f") == 0) {
|
||||||
|
std::string vertex1, vertex2, vertex3;
|
||||||
|
unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
|
||||||
|
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2]);
|
||||||
|
if (matches != 9) {
|
||||||
|
Msg("Model::LoadObj: File can't be read by our simple parser :-( Try exporting with other options");
|
||||||
|
fclose(file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vertexIndices.push_back(vertexIndex[0]);
|
||||||
|
vertexIndices.push_back(vertexIndex[1]);
|
||||||
|
vertexIndices.push_back(vertexIndex[2]);
|
||||||
|
uvIndices.push_back(uvIndex[0]);
|
||||||
|
uvIndices.push_back(uvIndex[1]);
|
||||||
|
uvIndices.push_back(uvIndex[2]);
|
||||||
|
normalIndices.push_back(normalIndex[0]);
|
||||||
|
normalIndices.push_back(normalIndex[1]);
|
||||||
|
normalIndices.push_back(normalIndex[2]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Probably a comment, eat up the rest of the line
|
||||||
|
char stupidBuffer[1000];
|
||||||
|
fgets(stupidBuffer, 1000, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each vertex of each triangle
|
||||||
|
for (unsigned int i = 0; i < vertexIndices.size(); i++) {
|
||||||
|
|
||||||
|
// Get the indices of its attributes
|
||||||
|
unsigned int vertexIndex = vertexIndices[i];
|
||||||
|
unsigned int uvIndex = uvIndices[i];
|
||||||
|
unsigned int normalIndex = normalIndices[i];
|
||||||
|
|
||||||
|
// Get the attributes thanks to the index
|
||||||
|
glm::vec3 vertex = temp_vertices[vertexIndex - 1];
|
||||||
|
glm::vec2 uv = temp_uvs[uvIndex - 1];
|
||||||
|
glm::vec3 normal = temp_normals[normalIndex - 1];
|
||||||
|
|
||||||
|
// Put the attributes in buffers
|
||||||
|
out_vertices.push_back(vertex);
|
||||||
|
out_uvs.push_back(uv);
|
||||||
|
out_normals.push_back(normal);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
// Combine in to the one array
|
||||||
|
std::vector<StaticMeshVertex> vertices;
|
||||||
|
for (unsigned int i = 0; i < vertexIndices.size(); i++)
|
||||||
|
{
|
||||||
|
// Get the indices of its attributes
|
||||||
|
unsigned int vertexIndex = vertexIndices[i];
|
||||||
|
unsigned int uvIndex = uvIndices[i];
|
||||||
|
unsigned int normalIndex = normalIndices[i];
|
||||||
|
|
||||||
|
// Get the attributes thanks to the index
|
||||||
|
glm::vec3 vertex = temp_vertices[vertexIndex - 1];
|
||||||
|
glm::vec2 uv = temp_uvs[uvIndex - 1];
|
||||||
|
glm::vec3 normal = temp_normals[normalIndex - 1];
|
||||||
|
|
||||||
|
StaticMeshVertex vtx = {};
|
||||||
|
vtx.position =vertex;
|
||||||
|
vtx.normal = normal;
|
||||||
|
vtx.texcoord = uv;
|
||||||
|
vertices.push_back(vtx);
|
||||||
|
|
||||||
|
m_boundingBox.min = glm::min(m_boundingBox.min, vertex);
|
||||||
|
m_boundingBox.max = glm::max(m_boundingBox.max, vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_data.vb = g_modelManager->CreateVertexBuffer(vertices.data(), (int)sizeof(StaticMeshVertex) * (int)vertices.size());
|
||||||
|
m_data.vbcount = vertices.size();
|
||||||
|
|
||||||
|
std::string mtlfilename = fs::getFileNameWithoutExtension(filename);
|
||||||
|
mtlfilename += ".mtl";
|
||||||
|
LoadMtl(mtlfilename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::LoadMtl( const char* filename )
|
||||||
|
{
|
||||||
|
Msg("Loading MTL file %s...", filename);
|
||||||
|
|
||||||
|
FILE* file = fopen(filename, "r");
|
||||||
|
if (file == NULL) {
|
||||||
|
Msg("Model::LoadObj: Impossible to open the file !");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
char lineHeader[128];
|
||||||
|
// read the first word of the line
|
||||||
|
int res = fscanf(file, "%s", lineHeader);
|
||||||
|
if (res == EOF)
|
||||||
|
break; // EOF = End Of File. Quit the loop.
|
||||||
|
|
||||||
|
if (strcmp(lineHeader, "map_Kd") == 0) {
|
||||||
|
char stupidBuffer[1000];
|
||||||
|
fgets(stupidBuffer, 1000, file);
|
||||||
|
|
||||||
|
const char* textureFilename = stupidBuffer + 1;
|
||||||
|
m_AlbedoTexture = g_texturesManager->LoadTexture2D(textureFilename, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (strcmp(lineHeader, "v") == 0) {
|
||||||
|
// glm::vec3 vertex;
|
||||||
|
// fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z);
|
||||||
|
// temp_vertices.push_back(vertex);
|
||||||
|
//}
|
||||||
|
//else {
|
||||||
|
// // Probably a comment, eat up the rest of the line
|
||||||
|
// char stupidBuffer[1000];
|
||||||
|
// fgets(stupidBuffer, 1000, file);
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::LoadIQM( const char* filename )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::Draw( const glm::mat4& model, bool isTransparent /*= false*/ )
|
||||||
|
{
|
||||||
|
if (!g_litShader)
|
||||||
|
{
|
||||||
|
g_litShader = g_shaderSystem->CreateShader("lit_generic", "content/shaders/lit_generic.vs", "content/shaders/lit_generic.ps",
|
||||||
|
g_staticVertexLayout, sizeof(g_staticVertexLayout) / sizeof(g_staticVertexLayout[0]));
|
||||||
|
|
||||||
|
g_litShader->m_stride = sizeof(StaticMeshVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_renderDevice->SetDepthTest(true);
|
||||||
|
g_renderDevice->SetDepthWrite(true);
|
||||||
|
|
||||||
|
if (isTransparent)
|
||||||
|
{
|
||||||
|
// Enable blending
|
||||||
|
g_renderDevice->SetBlending(true);
|
||||||
|
g_renderDevice->SetBlendingFunction(BF_SRC_ALPHA, BF_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
glm::vec4 color = glm::vec4(1.f, 1.f, 1.f, .5f);
|
||||||
|
g_shaderSystem->SetUniformFloat4( g_litShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr( color ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_renderDevice->SetBlending(false);
|
||||||
|
|
||||||
|
glm::vec4 color = glm::vec4(1.f, 1.f, 1.f, 1.f);
|
||||||
|
g_shaderSystem->SetUniformFloat4( g_litShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr( color ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
g_renderDevice->SetVerticesBuffer(m_data.vb);
|
||||||
|
|
||||||
|
g_shaderSystem->SetShader(g_litShader);
|
||||||
|
g_shaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MODEL_MATRIX, &model[0] );
|
||||||
|
|
||||||
|
//static float test = 0.0f;
|
||||||
|
//test += g_systemTimer->GetDelta() * 6.0f;
|
||||||
|
|
||||||
|
//glm::mat4 model = glm::mat4(1.0f);
|
||||||
|
|
||||||
|
//int32_t x = 0, y = 0;
|
||||||
|
//g_inputSystem->GetMousePosition(&x, &y);
|
||||||
|
//
|
||||||
|
//glm::mat4 model = glm::mat4(1.0f);
|
||||||
|
//model = glm::rotate(model, test, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
//
|
||||||
|
//float realY = (float)g_renderView.height - (float)y - 1;
|
||||||
|
//
|
||||||
|
//glm::vec4 viewport = glm::vec4(0.0f, 0.0f, (float)g_renderView.width, (float)g_renderView.height);
|
||||||
|
//glm::vec3 pos = glm::unProject(
|
||||||
|
// glm::vec3((float)x, realY, 0.0f),
|
||||||
|
// model,
|
||||||
|
// g_renderView.proj,
|
||||||
|
// viewport);
|
||||||
|
//
|
||||||
|
//pos *= 50.0f;
|
||||||
|
//
|
||||||
|
//model = glm::translate(model, pos);
|
||||||
|
|
||||||
|
glm::mat4 mvp = glm::identity<glm::mat4>();
|
||||||
|
mvp = g_renderView.proj * g_renderView.view * model;
|
||||||
|
g_shaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MVP_MATRIX, &mvp[0]);
|
||||||
|
|
||||||
|
g_texturesManager->SetTexture( 0, m_AlbedoTexture );
|
||||||
|
g_shaderSystem->SetUniformSampler(g_litShader, SAMPLER_ALBEDO, 0);
|
||||||
|
|
||||||
|
g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_data.vbcount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReleaseModelData(ModelData_t& data)
|
||||||
|
{
|
||||||
|
if (data.ib)
|
||||||
|
{
|
||||||
|
delete data.ib;
|
||||||
|
data.ib = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.vb)
|
||||||
|
{
|
||||||
|
delete data.vb;
|
||||||
|
data.vb = nullptr;
|
||||||
|
}
|
||||||
|
}
|
75
src/engine/render/modelmanager.h
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#ifndef MODELMANAGER_H
|
||||||
|
#define MODELMANAGER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <utils/maths.h>
|
||||||
|
|
||||||
|
class VertexBuffer;
|
||||||
|
class IndexBuffer;
|
||||||
|
class Texture2D;
|
||||||
|
|
||||||
|
struct StaticMeshVertex
|
||||||
|
{
|
||||||
|
glm::vec3 position;
|
||||||
|
glm::vec3 normal;
|
||||||
|
glm::vec2 texcoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ModelData_t
|
||||||
|
{
|
||||||
|
VertexBuffer* vb;
|
||||||
|
IndexBuffer* ib;
|
||||||
|
uint32_t vbcount;
|
||||||
|
uint32_t ibcount;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ReleaseModelData(ModelData_t& data);
|
||||||
|
|
||||||
|
class Model
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Model();
|
||||||
|
~Model();
|
||||||
|
|
||||||
|
void LoadObj( const char* filename );
|
||||||
|
void LoadMtl( const char* filename );
|
||||||
|
|
||||||
|
void LoadIQM( const char* filename );
|
||||||
|
|
||||||
|
void Draw( const glm::mat4& model, bool isTransparent = false );
|
||||||
|
|
||||||
|
BoundingBox GetBoundingBox() { return m_boundingBox; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ModelData_t m_data;
|
||||||
|
BoundingBox m_boundingBox;
|
||||||
|
Texture2D* m_AlbedoTexture;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ModelManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ModelManager();
|
||||||
|
~ModelManager();
|
||||||
|
|
||||||
|
// Buffer creation
|
||||||
|
VertexBuffer* CreateVertexBuffer( void* data, int size );
|
||||||
|
IndexBuffer* CreateIndexBuffer( void* data, int size );
|
||||||
|
|
||||||
|
Model* LoadModel(const char* filename);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ModelEntry
|
||||||
|
{
|
||||||
|
char filename[260];
|
||||||
|
Model* model;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector< ModelEntry > m_models;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ModelManager* g_modelManager;
|
||||||
|
|
||||||
|
#endif // !MODELMANAGER_H
|
396
src/engine/render/render.cpp
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <glad/glad.h>
|
||||||
|
#include <GL/wglext.h>
|
||||||
|
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <utils/win32_keys.h>
|
||||||
|
|
||||||
|
#include <render/render.h>
|
||||||
|
#include <render/renderdevice.h>
|
||||||
|
#include <render/texturesmanager.h>
|
||||||
|
#include <render/shadersystem.h>
|
||||||
|
#include <render/modelmanager.h>
|
||||||
|
#include <render/ui.h>
|
||||||
|
#include <render/debugrender.h>
|
||||||
|
|
||||||
|
#include <game/game_app.h>
|
||||||
|
|
||||||
|
#pragma comment(lib, "OpenGL32.lib")
|
||||||
|
|
||||||
|
View g_renderView;
|
||||||
|
Render* g_render = NULL;
|
||||||
|
HDC g_hDC = NULL;
|
||||||
|
HGLRC g_openglContext = NULL;
|
||||||
|
|
||||||
|
GLuint g_vao = 0;
|
||||||
|
|
||||||
|
void CreateOpenGL( HWND hWnd )
|
||||||
|
{
|
||||||
|
PIXELFORMATDESCRIPTOR pfd =
|
||||||
|
{
|
||||||
|
sizeof(PIXELFORMATDESCRIPTOR),
|
||||||
|
1,
|
||||||
|
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags
|
||||||
|
PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
|
||||||
|
32, // Colordepth of the framebuffer.
|
||||||
|
0, 0, 0, 0, 0, 0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
24, // Number of bits for the depthbuffer
|
||||||
|
8, // Number of bits for the stencilbuffer
|
||||||
|
0, // Number of Aux buffers in the framebuffer.
|
||||||
|
PFD_MAIN_PLANE,
|
||||||
|
0,
|
||||||
|
0, 0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
g_hDC = GetDC( hWnd );
|
||||||
|
int pixelFormat = ChoosePixelFormat( g_hDC, &pfd );
|
||||||
|
SetPixelFormat( g_hDC, pixelFormat, &pfd );
|
||||||
|
|
||||||
|
HGLRC tempContext = wglCreateContext( g_hDC );
|
||||||
|
wglMakeCurrent( g_hDC, tempContext );
|
||||||
|
|
||||||
|
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
|
||||||
|
assert(wglCreateContextAttribsARB);
|
||||||
|
|
||||||
|
int attribs[] =
|
||||||
|
{
|
||||||
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||||
|
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
|
||||||
|
WGL_CONTEXT_FLAGS_ARB, 0,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
g_openglContext = wglCreateContextAttribsARB( g_hDC, 0, attribs );
|
||||||
|
wglMakeCurrent( NULL, NULL );
|
||||||
|
wglDeleteContext( tempContext );
|
||||||
|
wglMakeCurrent( g_hDC, g_openglContext );
|
||||||
|
}
|
||||||
|
|
||||||
|
Render::Render() : m_window(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Render::~Render()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render::Init()
|
||||||
|
{
|
||||||
|
Msg("Initializing renderer ...");
|
||||||
|
|
||||||
|
m_window = WND_CreateWindow(0, 0, 1280, 720, "Game");
|
||||||
|
|
||||||
|
CreateOpenGL( (HWND)m_window );
|
||||||
|
|
||||||
|
gladLoadGL();
|
||||||
|
|
||||||
|
int width = 0, height = 0;
|
||||||
|
WND_GetWindowSize(m_window, &width, &height);
|
||||||
|
|
||||||
|
g_renderView.width = width;
|
||||||
|
g_renderView.height = height;
|
||||||
|
|
||||||
|
// Create render device
|
||||||
|
g_renderDevice = new RenderDevice();
|
||||||
|
|
||||||
|
// Create texture manager
|
||||||
|
g_texturesManager = new TexturesManager();
|
||||||
|
g_texturesManager->Init();
|
||||||
|
|
||||||
|
// Create shader system
|
||||||
|
g_shaderSystem = new ShaderSystem();
|
||||||
|
g_shaderSystem->Init();
|
||||||
|
|
||||||
|
// Create model manager
|
||||||
|
g_modelManager = new ModelManager();
|
||||||
|
|
||||||
|
// Create debug render
|
||||||
|
g_debugRender = new DebugRender();
|
||||||
|
g_debugRender->Initialize();
|
||||||
|
|
||||||
|
g_drawDebug = true;
|
||||||
|
|
||||||
|
// Create UI System
|
||||||
|
uiInit();
|
||||||
|
|
||||||
|
// Create global vertex array
|
||||||
|
glGenVertexArrays(1, &g_vao);
|
||||||
|
glBindVertexArray(g_vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render::Shutdown()
|
||||||
|
{
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glDeleteVertexArrays(1, &g_vao);
|
||||||
|
|
||||||
|
uiShutdown();
|
||||||
|
|
||||||
|
g_debugRender->Shutdown();
|
||||||
|
delete g_debugRender;
|
||||||
|
g_debugRender = nullptr;
|
||||||
|
|
||||||
|
delete g_modelManager;
|
||||||
|
g_modelManager = nullptr;
|
||||||
|
|
||||||
|
g_shaderSystem->Shutdown();
|
||||||
|
delete g_shaderSystem;
|
||||||
|
g_shaderSystem = nullptr;
|
||||||
|
|
||||||
|
g_texturesManager->Shutdown();
|
||||||
|
delete g_texturesManager;
|
||||||
|
g_texturesManager = nullptr;
|
||||||
|
|
||||||
|
delete g_renderDevice;
|
||||||
|
g_renderDevice = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render::BeginFrame()
|
||||||
|
{
|
||||||
|
BuildRenderView();
|
||||||
|
|
||||||
|
int width = 0, height = 0;
|
||||||
|
WND_GetWindowSize(m_window, &width, &height);
|
||||||
|
|
||||||
|
glViewport( 0, 0, width, height );
|
||||||
|
|
||||||
|
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||||
|
glClearColor( 0.5f, 0.5f, 0.5f, 1.0f );
|
||||||
|
|
||||||
|
g_renderDevice->SetBackfaceCull(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render::EndFrame()
|
||||||
|
{
|
||||||
|
// Flush debug render
|
||||||
|
g_debugRender->RenderFrame();
|
||||||
|
|
||||||
|
SwapBuffers( g_hDC );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render::DrawFrame()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Render::GetRenderWindow()
|
||||||
|
{
|
||||||
|
return m_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render::BuildRenderView()
|
||||||
|
{
|
||||||
|
if (g_renderView.fov <= 0.0f)
|
||||||
|
{
|
||||||
|
Msg("Render::BuildRenderView: FOV is zero!");
|
||||||
|
g_renderView.fov = 0.1f;//70.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = 0, height = 0;
|
||||||
|
WND_GetWindowSize(m_window, &width, &height);
|
||||||
|
|
||||||
|
if (width < 1) width = 1;
|
||||||
|
if (height < 1) height = 1;
|
||||||
|
|
||||||
|
float aspect = (float)width / (float)height;
|
||||||
|
g_renderView.proj = glm::perspectiveFov(glm::radians(g_renderView.fov), (float)width, (float)height, 0.1f, 1000.0f);
|
||||||
|
|
||||||
|
ShowCursor(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windowing
|
||||||
|
|
||||||
|
static int s_should_wrap_mouse = FALSE;
|
||||||
|
static bool s_wndclass_registered = FALSE;
|
||||||
|
static const char* s_wndclass_name = "DumbWindowClass";
|
||||||
|
|
||||||
|
int g_mousex = 0;
|
||||||
|
int g_mousey = 0;
|
||||||
|
RECT g_rect = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
// Should be implemented by library user.
|
||||||
|
void WND_Callback_Keyboard(void* window, KeyboardKeys key, int nativeKey, int action)
|
||||||
|
{
|
||||||
|
if (action)
|
||||||
|
g_inputSystem->OnKeyDown(key);
|
||||||
|
else
|
||||||
|
g_inputSystem->OnKeyUp(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
mouseButton_t GetMouseButton(UINT mouseButton)
|
||||||
|
{
|
||||||
|
switch (mouseButton)
|
||||||
|
{
|
||||||
|
case MK_LBUTTON:
|
||||||
|
return mouseButton_Left;
|
||||||
|
case MK_MBUTTON:
|
||||||
|
return mouseButton_Middle;
|
||||||
|
case MK_RBUTTON:
|
||||||
|
return mouseButton_Right;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #TODO: nameless buttons ???
|
||||||
|
return GetNamelessMouseButtonIndex(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK WND_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case WM_CLOSE:
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
WND_Callback_Keyboard(hwnd, GetKeyFromWin32((Win32Keys::Keys)wParam), (int)wParam, PRESSED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_KEYUP:
|
||||||
|
WND_Callback_Keyboard(hwnd, GetKeyFromWin32((Win32Keys::Keys)wParam), (int)wParam, UNPRESSED);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_LBUTTONDOWN:
|
||||||
|
g_inputSystem->OnMouseKeyDown(mouseButton_Left);
|
||||||
|
break;
|
||||||
|
case WM_RBUTTONDOWN:
|
||||||
|
g_inputSystem->OnMouseKeyDown(mouseButton_Right);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case WM_LBUTTONUP:
|
||||||
|
g_inputSystem->OnMouseKeyUp(mouseButton_Left);
|
||||||
|
break;
|
||||||
|
case WM_RBUTTONUP:
|
||||||
|
g_inputSystem->OnMouseKeyUp(mouseButton_Right);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_MOUSEHOVER:
|
||||||
|
ShowCursor(FALSE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_MOUSELEAVE:
|
||||||
|
ShowCursor(TRUE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
{
|
||||||
|
if (s_should_wrap_mouse)
|
||||||
|
{
|
||||||
|
GetClientRect(hwnd, &g_rect); // Get window dimension
|
||||||
|
|
||||||
|
g_rect.right -= 12; // right offset
|
||||||
|
g_rect.left += 12; // left offset
|
||||||
|
|
||||||
|
g_mousex = LOWORD(lParam); // Get mouse X pos
|
||||||
|
g_mousey = HIWORD(lParam); // Get mouse Y pos
|
||||||
|
|
||||||
|
if (g_mousex >= g_rect.right)
|
||||||
|
{
|
||||||
|
SetCursorPos(g_rect.left, g_mousey);
|
||||||
|
}
|
||||||
|
else if (g_mousex <= g_rect.left)
|
||||||
|
{
|
||||||
|
SetCursorPos(g_rect.right, g_mousey);
|
||||||
|
}
|
||||||
|
g_inputSystem->OnMouseMove(g_mousex, g_mousey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_mousex = LOWORD(lParam); // Get mouse X pos
|
||||||
|
g_mousey = HIWORD(lParam); // Get mouse Y pos
|
||||||
|
g_inputSystem->OnMouseMove(g_mousex, g_mousey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefWindowProcA(hwnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* WND_CreateWindow(int x, int y, int width, int height, const char* title)
|
||||||
|
{
|
||||||
|
if (!s_wndclass_registered)
|
||||||
|
{
|
||||||
|
WNDCLASSA wc;
|
||||||
|
memset(&wc, 0, sizeof(wc));
|
||||||
|
// wc.hIcon = LoadIconA(GetModuleHandleA(0), MAKEINTRESOURCEA(IDI_ICON1));
|
||||||
|
wc.lpfnWndProc = WND_WindowProc;
|
||||||
|
wc.hInstance = GetModuleHandleA(0);
|
||||||
|
wc.lpszClassName = s_wndclass_name;
|
||||||
|
RegisterClassA(&wc);
|
||||||
|
|
||||||
|
s_wndclass_registered = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Window Style
|
||||||
|
DWORD dwWindowStyle = WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME | WS_MAXIMIZEBOX);
|
||||||
|
|
||||||
|
// Rect
|
||||||
|
RECT rc = { 0, 0, width, height };
|
||||||
|
AdjustWindowRect(&rc, dwWindowStyle, FALSE);
|
||||||
|
|
||||||
|
HWND hWnd = CreateWindowA(s_wndclass_name, title, dwWindowStyle,
|
||||||
|
x, y, (rc.right - rc.left), (rc.bottom - rc.top),
|
||||||
|
NULL, NULL, GetModuleHandleA(0), NULL);
|
||||||
|
|
||||||
|
assert(hWnd != INVALID_HANDLE_VALUE);
|
||||||
|
|
||||||
|
ShowWindow(hWnd, SW_SHOW);
|
||||||
|
UpdateWindow(hWnd);
|
||||||
|
|
||||||
|
return hWnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WND_DestroyWindow(void* window)
|
||||||
|
{
|
||||||
|
DestroyWindow((HWND)window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WND_GetWindowSize(void* window, int* x, int* y)
|
||||||
|
{
|
||||||
|
RECT rc;
|
||||||
|
memset(&rc, 0, sizeof(rc));
|
||||||
|
|
||||||
|
GetClientRect((HWND)window, &rc);
|
||||||
|
|
||||||
|
*x = (rc.right - rc.left);
|
||||||
|
*y = (rc.bottom - rc.top);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WND_GetWindowGrab(void* window)
|
||||||
|
{
|
||||||
|
return GetFocus() == (HWND)window;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HELPER_GetWindowPos(HWND hWnd, int* x, int* y)
|
||||||
|
{
|
||||||
|
RECT rect = { NULL };
|
||||||
|
if (GetWindowRect(hWnd, &rect))
|
||||||
|
{
|
||||||
|
*x = rect.left;
|
||||||
|
*y = rect.top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WND_SetWindowSize(void* window, int x, int y)
|
||||||
|
{
|
||||||
|
int posX = 0, posY = 0;
|
||||||
|
HELPER_GetWindowPos((HWND)window, &posX, &posY);
|
||||||
|
MoveWindow((HWND)window, posX, posY, x, y, TRUE);
|
||||||
|
UpdateWindow((HWND)window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WND_SetRelativeMouseMode(int value)
|
||||||
|
{
|
||||||
|
s_should_wrap_mouse = value;
|
||||||
|
}
|
45
src/engine/render/render.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef RENDER_H
|
||||||
|
#define RENDER_H
|
||||||
|
|
||||||
|
// Render windowing management
|
||||||
|
|
||||||
|
enum KEY_ACTION
|
||||||
|
{
|
||||||
|
UNPRESSED,
|
||||||
|
PRESSED,
|
||||||
|
HOLDING
|
||||||
|
};
|
||||||
|
|
||||||
|
void* WND_CreateWindow(int x, int y, int width, int height, const char* title);
|
||||||
|
void WND_DestroyWindow(void* window);
|
||||||
|
void WND_GetWindowSize(void* window, int* x, int* y);
|
||||||
|
bool WND_GetWindowGrab(void* window);
|
||||||
|
void WND_SetWindowSize(void* window, int x, int y);
|
||||||
|
void WND_SetRelativeMouseMode(int value);
|
||||||
|
|
||||||
|
class Render
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Render();
|
||||||
|
~Render();
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void BeginFrame();
|
||||||
|
void EndFrame();
|
||||||
|
|
||||||
|
void DrawFrame();
|
||||||
|
|
||||||
|
void* GetRenderWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void BuildRenderView();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* m_window;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Render* g_render;
|
||||||
|
|
||||||
|
#endif // !RENDER_H
|
84
src/engine/render/render_shared.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// Shared header for render stuff
|
||||||
|
#ifndef RENDER_SHARED_H
|
||||||
|
#define RENDER_SHARED_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "utils/maths.h"
|
||||||
|
#include "render/color.h"
|
||||||
|
|
||||||
|
enum class BufferAccess
|
||||||
|
{
|
||||||
|
READ_ONLY,
|
||||||
|
WRITE_ONLY,
|
||||||
|
READ_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
// texture format
|
||||||
|
enum PixelFormat
|
||||||
|
{
|
||||||
|
PF_UNKNOWN,
|
||||||
|
PF_R8G8B8,
|
||||||
|
PF_R8G8B8A8,
|
||||||
|
PF_R8G8B8F,
|
||||||
|
PF_R8G8B8A8F,
|
||||||
|
|
||||||
|
// Depth formats
|
||||||
|
PF_DEPTH32F
|
||||||
|
};
|
||||||
|
|
||||||
|
// pixel format convertion
|
||||||
|
uint32_t getGLPF(PixelFormat pf);
|
||||||
|
uint32_t getGLInternalPF(PixelFormat pf);
|
||||||
|
uint32_t getGLTypePF(PixelFormat pf);
|
||||||
|
|
||||||
|
// Blending functions
|
||||||
|
enum BlendFactor
|
||||||
|
{
|
||||||
|
BF_ZERO,
|
||||||
|
BF_ONE,
|
||||||
|
BF_SRC_COLOR,
|
||||||
|
BF_ONE_MINUS_SRC_COLOR,
|
||||||
|
BF_DST_COLOR,
|
||||||
|
BF_ONE_MINUS_DST_COLOR,
|
||||||
|
BF_SRC_ALPHA,
|
||||||
|
BF_ONE_MINUS_SRC_ALPHA,
|
||||||
|
BF_DST_ALPHA,
|
||||||
|
BF_ONE_MINUS_DST_ALPHA,
|
||||||
|
BF_CONSTANT_COLOR,
|
||||||
|
BF_ONE_MINUS_CONSTANT_COLOR,
|
||||||
|
BF_CONSTANT_ALPHA,
|
||||||
|
BF_ONE_MINUS_CONSTANT_ALPHA
|
||||||
|
};
|
||||||
|
|
||||||
|
// Blending factor convertion
|
||||||
|
uint32_t GetGLBlendFactor(BlendFactor factor);
|
||||||
|
|
||||||
|
// Base structure for render view (view and projection matrices, viewport settings)
|
||||||
|
struct View
|
||||||
|
{
|
||||||
|
glm::mat4 view;
|
||||||
|
glm::mat4 proj;
|
||||||
|
|
||||||
|
int x, y;
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
float fov;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global instance of render view
|
||||||
|
extern View g_renderView;
|
||||||
|
|
||||||
|
// Stretched picture vertex
|
||||||
|
struct StretchedVertex
|
||||||
|
{
|
||||||
|
Vec3 position;
|
||||||
|
Vec2 texcoord;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_STRETCH_VX 12 * sizeof(StretchedVertex)
|
||||||
|
|
||||||
|
// debugging stuff
|
||||||
|
void check_for_opengl_error();
|
||||||
|
|
||||||
|
#endif
|
202
src/engine/render/renderdevice.cpp
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// OpenGL
|
||||||
|
#include "render/gl_shared.h"
|
||||||
|
|
||||||
|
// VERTEX AND INDEX OBJECTS
|
||||||
|
#include "render/vertexbuffer.h"
|
||||||
|
#include "render/indexbuffer.h"
|
||||||
|
|
||||||
|
#include "render/rendertarget.h"
|
||||||
|
#include "render/renderdevice.h"
|
||||||
|
|
||||||
|
RenderDevice* g_renderDevice = nullptr;
|
||||||
|
|
||||||
|
RenderDevice::RenderDevice()
|
||||||
|
{
|
||||||
|
m_activeVB = nullptr;
|
||||||
|
m_activeIB = nullptr;
|
||||||
|
m_blending = false;
|
||||||
|
m_activeReadRT = nullptr;
|
||||||
|
m_activeWriteRT = nullptr;
|
||||||
|
m_backfaceCull = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderDevice::~RenderDevice()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBuffer* RenderDevice::CreateVertexBuffer(void* data, size_t size, bool isStream)
|
||||||
|
{
|
||||||
|
return new VertexBuffer(data, size, isStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexBuffer* RenderDevice::CreateIndexBuffer(void* data, size_t size, bool isStream)
|
||||||
|
{
|
||||||
|
return new IndexBuffer(data, size, isStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::SetVerticesBuffer(VertexBuffer* buffer)
|
||||||
|
{
|
||||||
|
if (buffer) {
|
||||||
|
if (m_activeVB != buffer) {
|
||||||
|
m_activeVB = buffer;
|
||||||
|
m_activeVB->Bind();
|
||||||
|
}
|
||||||
|
} else { // unbind buffer
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::SetIndicesBuffer(IndexBuffer* buffer)
|
||||||
|
{
|
||||||
|
if (buffer) {
|
||||||
|
if (m_activeIB != buffer) {
|
||||||
|
m_activeIB = buffer;
|
||||||
|
m_activeIB->Bind();
|
||||||
|
}
|
||||||
|
} else { // unbind buffer
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::SetDepthTest(bool enable)
|
||||||
|
{
|
||||||
|
enable ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::SetDepthWrite(bool enable)
|
||||||
|
{
|
||||||
|
glDepthMask(enable ? GL_TRUE : GL_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//void RenderDevice::setVertexFormat(VertexFormat* format)
|
||||||
|
//{
|
||||||
|
// assert(format);
|
||||||
|
//
|
||||||
|
// if (format->count() == 0) {
|
||||||
|
// Core::error("RenderDevice::setVertexFormat: failed to set empty vertex format");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// size_t appliedOffset = 0;
|
||||||
|
// for (VertexAttribute* it = format->begin(); it != format->end(); ++it) {
|
||||||
|
//
|
||||||
|
// GLenum data_type = get_gl_vertex_attribute_type(it->m_type);
|
||||||
|
// GLuint data_size = GLuint(get_vertex_attribute_size(it->m_type));
|
||||||
|
//
|
||||||
|
// if (appliedOffset > 0)
|
||||||
|
// glVertexAttribPointer(
|
||||||
|
// GLuint(it->m_offset),
|
||||||
|
// GLint(it->m_size),
|
||||||
|
// data_type,
|
||||||
|
// GL_FALSE,
|
||||||
|
// GLsizei(format->size() * data_size),
|
||||||
|
// (void*)(appliedOffset * sizeof(float))
|
||||||
|
// );
|
||||||
|
// else
|
||||||
|
// glVertexAttribPointer(
|
||||||
|
// GLuint(it->m_offset),
|
||||||
|
// GLint(it->m_size),
|
||||||
|
// data_type,
|
||||||
|
// GL_FALSE,
|
||||||
|
// GLsizei(format->size() * data_size),
|
||||||
|
// (void*)0
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// glEnableVertexAttribArray(GLuint(it->m_offset));
|
||||||
|
//
|
||||||
|
// appliedOffset += it->m_size;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
void RenderDevice::SetBlending(bool value)
|
||||||
|
{
|
||||||
|
if (m_blending != value) {
|
||||||
|
m_blending = value;
|
||||||
|
|
||||||
|
value ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::SetBlendingFunction(BlendFactor srcFactor, BlendFactor destFactor)
|
||||||
|
{
|
||||||
|
// Switch state if one of two blending factors was changed
|
||||||
|
if (srcFactor != m_srcBlendFactor || destFactor != m_destBlendFactor)
|
||||||
|
{
|
||||||
|
m_srcBlendFactor = srcFactor;
|
||||||
|
m_destBlendFactor = destFactor;
|
||||||
|
|
||||||
|
// push to gl state
|
||||||
|
glBlendFunc(GetGLBlendFactor(srcFactor), GetGLBlendFactor(destFactor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::SetReadRenderTarget(RenderTarget* renderTarget)
|
||||||
|
{
|
||||||
|
if (renderTarget) {
|
||||||
|
if (m_activeReadRT != renderTarget) {
|
||||||
|
m_activeReadRT = renderTarget;
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, renderTarget->m_framebuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // set default rt
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::SetWriteRenderTarget(RenderTarget* renderTarget)
|
||||||
|
{
|
||||||
|
if (renderTarget) {
|
||||||
|
if (m_activeWriteRT != renderTarget) {
|
||||||
|
m_activeWriteRT = renderTarget;
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, renderTarget->m_framebuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // set default rt
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::SetBackfaceCull(bool value)
|
||||||
|
{
|
||||||
|
if (m_backfaceCull != value) {
|
||||||
|
m_backfaceCull = value;
|
||||||
|
|
||||||
|
value ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::SetViewport(int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
glViewport(x, y, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::BlitRenderTarget(int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, TextureSurfaceType surfaceType)
|
||||||
|
{
|
||||||
|
GLbitfield mask = 0;
|
||||||
|
if (surfaceType & TST_COLOR)
|
||||||
|
mask |= GL_COLOR_BUFFER_BIT;
|
||||||
|
if (surfaceType & TST_DEPTH)
|
||||||
|
mask |= GL_DEPTH_BUFFER_BIT;
|
||||||
|
if (surfaceType & TST_STENCIL)
|
||||||
|
mask |= GL_STENCIL_BUFFER_BIT;
|
||||||
|
|
||||||
|
glBlitFramebuffer(srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, mask, GL_LINEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLenum g_glPrimitiveMode[PT_TRIANGLES + 1] = {
|
||||||
|
GL_POINTS,
|
||||||
|
GL_LINES,
|
||||||
|
GL_TRIANGLES
|
||||||
|
};
|
||||||
|
|
||||||
|
void RenderDevice::DrawArrays(PrimitiveType primType, uint32_t startOf, size_t verticesCount)
|
||||||
|
{
|
||||||
|
glDrawArrays(g_glPrimitiveMode[primType], startOf, GLsizei(verticesCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderDevice::DrawElements(PrimitiveType primType, size_t elementsCount, bool is16bitIndices)
|
||||||
|
{
|
||||||
|
glDrawElements(g_glPrimitiveMode[primType], GLsizei(elementsCount), is16bitIndices ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, NULL);
|
||||||
|
}
|
78
src/engine/render/renderdevice.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef RENDERDEVICE_H
|
||||||
|
#define RENDERDEVICE_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "render/render_shared.h"
|
||||||
|
|
||||||
|
class VertexBuffer;
|
||||||
|
class IndexBuffer;
|
||||||
|
class VertexFormat;
|
||||||
|
class RenderTarget;
|
||||||
|
|
||||||
|
enum TextureSurfaceType
|
||||||
|
{
|
||||||
|
TST_COLOR = 1 << 0,
|
||||||
|
TST_DEPTH = 1 << 1,
|
||||||
|
TST_STENCIL = 1 << 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PrimitiveType
|
||||||
|
{
|
||||||
|
PT_POINTS,
|
||||||
|
PT_LINES,
|
||||||
|
PT_TRIANGLES
|
||||||
|
};
|
||||||
|
|
||||||
|
class RenderDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RenderDevice();
|
||||||
|
~RenderDevice();
|
||||||
|
|
||||||
|
VertexBuffer* CreateVertexBuffer(void* data, size_t size, bool isStream = false);
|
||||||
|
IndexBuffer* CreateIndexBuffer(void* data, size_t size, bool isStream = false);
|
||||||
|
|
||||||
|
void SetVerticesBuffer(VertexBuffer* buffer);
|
||||||
|
void SetIndicesBuffer(IndexBuffer* buffer);
|
||||||
|
|
||||||
|
void SetDepthTest(bool enable);
|
||||||
|
void SetDepthWrite(bool enable);
|
||||||
|
|
||||||
|
//void setVertexFormat(VertexFormat* format);
|
||||||
|
|
||||||
|
void SetBlending(bool value);
|
||||||
|
void SetBlendingFunction(BlendFactor srcFactor, BlendFactor destFactor);
|
||||||
|
|
||||||
|
void SetReadRenderTarget(RenderTarget* renderTarget);
|
||||||
|
void SetWriteRenderTarget(RenderTarget* renderTarget);
|
||||||
|
|
||||||
|
void SetBackfaceCull(bool value);
|
||||||
|
|
||||||
|
void SetViewport(int x, int y, int w, int h);
|
||||||
|
|
||||||
|
// glBlitFramebuffer
|
||||||
|
void BlitRenderTarget(int srcX, int srcY, int srcWidth, int srcHeight,
|
||||||
|
int destX, int destY, int destWidth, int destHeight,
|
||||||
|
TextureSurfaceType surfaceType);
|
||||||
|
|
||||||
|
// drawing
|
||||||
|
void DrawArrays(PrimitiveType primType, uint32_t startOf, size_t verticesCount);
|
||||||
|
void DrawElements(PrimitiveType primType, size_t elementsCount, bool is16bitIndices);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VertexBuffer* m_activeVB;
|
||||||
|
IndexBuffer* m_activeIB;
|
||||||
|
|
||||||
|
RenderTarget* m_activeReadRT;
|
||||||
|
RenderTarget* m_activeWriteRT;
|
||||||
|
|
||||||
|
bool m_blending;
|
||||||
|
BlendFactor m_srcBlendFactor;
|
||||||
|
BlendFactor m_destBlendFactor;
|
||||||
|
|
||||||
|
bool m_backfaceCull;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern RenderDevice* g_renderDevice;
|
||||||
|
|
||||||
|
#endif // !RENDERDEVICE_H
|
63
src/engine/render/rendertarget.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "render/rendertarget.h"
|
||||||
|
|
||||||
|
#include "render/texturesmanager.h"
|
||||||
|
#include "render/texture2d.h"
|
||||||
|
|
||||||
|
#include "glad/glad.h"
|
||||||
|
|
||||||
|
void RenderTarget::setDefaultFramebuffer()
|
||||||
|
{
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderTarget::RenderTarget()
|
||||||
|
{
|
||||||
|
m_framebuffer = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderTarget::~RenderTarget()
|
||||||
|
{
|
||||||
|
m_framebuffer = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::create(const char* name /*= nullptr*/)
|
||||||
|
{
|
||||||
|
assert(g_texturesManager);
|
||||||
|
|
||||||
|
////////////////////////
|
||||||
|
// Create FBO
|
||||||
|
|
||||||
|
// generate frame buffer
|
||||||
|
glGenFramebuffers(1, &m_framebuffer);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::destroy()
|
||||||
|
{
|
||||||
|
GLint drawFboId;
|
||||||
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &drawFboId);
|
||||||
|
|
||||||
|
if (drawFboId == (GLint)m_framebuffer)
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
glDeleteFramebuffers(1, &m_framebuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::finialize()
|
||||||
|
{
|
||||||
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
|
assert(0 && "RenderTarget::finialize: failed to finialize framebuffer. Framebuffer is not complete");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::attachColorTexture(int slot, Texture2D* texture)
|
||||||
|
{
|
||||||
|
assert(texture && "Failed to assing nullptr texture");
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + slot, GL_TEXTURE_2D, texture->GetHandle(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::attachDepthTexture(Texture2D* texture)
|
||||||
|
{
|
||||||
|
assert(texture && "Failed to assing nullptr texture");
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture->GetHandle(), 0);
|
||||||
|
}
|
33
src/engine/render/rendertarget.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef RENDERTARGET_H
|
||||||
|
#define RENDERTARGET_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
class Texture2D;
|
||||||
|
class RenderDevice;
|
||||||
|
|
||||||
|
class RenderTarget
|
||||||
|
{
|
||||||
|
friend class RenderDevice;
|
||||||
|
public:
|
||||||
|
// #TODO: Little hack
|
||||||
|
static void setDefaultFramebuffer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
RenderTarget();
|
||||||
|
~RenderTarget();
|
||||||
|
|
||||||
|
void create(const char* name = nullptr);
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
void finialize();
|
||||||
|
|
||||||
|
void attachColorTexture(int slot, Texture2D* texture);
|
||||||
|
void attachDepthTexture(Texture2D* texture);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t m_framebuffer;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
92
src/engine/render/shader.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "render/shader.h"
|
||||||
|
#include "filesystem/filemanager.h"
|
||||||
|
#include "filesystem/stream.h"
|
||||||
|
|
||||||
|
GLuint CreateShader(GLenum shaderType, const char* filename)
|
||||||
|
{
|
||||||
|
StreamBase* stream = g_fileManager->OpenStream( filename, FileAccess::Read );
|
||||||
|
if ( !stream )
|
||||||
|
{
|
||||||
|
Msg( "CreateShader: failed to open file %s", filename );
|
||||||
|
assert( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->seek( SeekDir::End, 0 );
|
||||||
|
size_t length = stream->tell();
|
||||||
|
stream->seek( SeekDir::Begin, 0 );
|
||||||
|
|
||||||
|
std::string content;
|
||||||
|
content.resize( length + 1 );
|
||||||
|
stream->readBuffer( (void*)content.data(), length );
|
||||||
|
|
||||||
|
content[length] = '\0';
|
||||||
|
|
||||||
|
const char* contentCStr = content.c_str();
|
||||||
|
|
||||||
|
GLuint shader = glCreateShader(shaderType);
|
||||||
|
glShaderSource(shader, 1, &contentCStr, NULL);
|
||||||
|
glCompileShader(shader);
|
||||||
|
|
||||||
|
int success;
|
||||||
|
char infoLog[512];
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
glGetShaderInfoLog(shader, 512, NULL, infoLog);
|
||||||
|
Msg("Failed to compile shader %s\n%s", filename, infoLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg("created shader from file %s", filename);
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader::Shader() :
|
||||||
|
m_name(nullptr),
|
||||||
|
m_stride(0),
|
||||||
|
m_layout_count(0)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader::~Shader()
|
||||||
|
{
|
||||||
|
if (m_name)
|
||||||
|
free( (void*)m_name );
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::Create(const char* name, const char* vsfilepath, const char* psfilepath)
|
||||||
|
{
|
||||||
|
//m_name = strdup( name );
|
||||||
|
|
||||||
|
GLuint vertexShader = CreateShader(GL_VERTEX_SHADER, vsfilepath);
|
||||||
|
GLuint fragmentShader = CreateShader(GL_FRAGMENT_SHADER, psfilepath);
|
||||||
|
|
||||||
|
m_program = glCreateProgram();
|
||||||
|
glAttachShader(m_program, vertexShader);
|
||||||
|
glAttachShader(m_program, fragmentShader);
|
||||||
|
AllocateAttributes();
|
||||||
|
glLinkProgram(m_program);
|
||||||
|
|
||||||
|
glDeleteShader(vertexShader);
|
||||||
|
glDeleteShader(fragmentShader);
|
||||||
|
|
||||||
|
int success;
|
||||||
|
char infoLog[512];
|
||||||
|
glGetProgramiv(m_program, GL_LINK_STATUS, &success);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
glGetProgramInfoLog(m_program, 512, NULL, infoLog);
|
||||||
|
Msg("Failed to link program %s", infoLog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::Destroy()
|
||||||
|
{
|
||||||
|
glDeleteProgram(m_program);
|
||||||
|
}
|
98
src/engine/render/shader.h
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#ifndef SHADER_H
|
||||||
|
#define SHADER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
const int SHADERUNIFORM_MAX_COUNT = 16;
|
||||||
|
const int INPUT_LAYOUT_MAX_COUNT = 8;
|
||||||
|
|
||||||
|
enum VertexAttribute_t {
|
||||||
|
VERTEXATTR_VEC2,
|
||||||
|
VERTEXATTR_VEC3,
|
||||||
|
VERTEXATTR_VEC4,
|
||||||
|
|
||||||
|
VERTEXATTR_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ShaderSemantic_t {
|
||||||
|
SHADERSEMANTIC_POSITION,
|
||||||
|
SHADERSEMANTIC_COLOR,
|
||||||
|
SHADERSEMANTIC_TEXCOORD,
|
||||||
|
SHADERSEMANTIC_TEXCOORD0,
|
||||||
|
SHADERSEMANTIC_TEXCOORD1,
|
||||||
|
SHADERSEMANTIC_NORMAL,
|
||||||
|
SHADERSEMANTIC_TANGENT,
|
||||||
|
SHADERSEMANTIC_BITANGENT,
|
||||||
|
|
||||||
|
SHADERSEMANTIC_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ShaderUniformType_t {
|
||||||
|
SHADERUNIFORM_FLOAT,
|
||||||
|
SHADERUNIFORM_VEC2,
|
||||||
|
SHADERUNIFORM_VEC3,
|
||||||
|
SHADERUNIFORM_VEC4,
|
||||||
|
SHADERUNIFORM_MAT4,
|
||||||
|
|
||||||
|
SHADERUNIFORM_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct InputLayoutDesc_t {
|
||||||
|
VertexAttribute_t attribute;
|
||||||
|
ShaderSemantic_t semantic;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShaderUniformDesc_t {
|
||||||
|
ShaderUniformType_t type;
|
||||||
|
const char* name;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Shader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Shader();
|
||||||
|
~Shader();
|
||||||
|
|
||||||
|
void Create(const char* name, const char* vsfilepath, const char* psfilepath);
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
|
void AllocateAttributes();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// TEMP SOLUTION
|
||||||
|
ShaderUniformDesc_t m_uniform_desc[SHADERUNIFORM_MAX_COUNT];
|
||||||
|
size_t m_uniform_count;
|
||||||
|
|
||||||
|
InputLayoutDesc_t m_layouts[INPUT_LAYOUT_MAX_COUNT];
|
||||||
|
size_t m_layout_count;
|
||||||
|
|
||||||
|
GLuint m_glLayouts[INPUT_LAYOUT_MAX_COUNT];
|
||||||
|
|
||||||
|
// #TODO: REMOVE PLEASE
|
||||||
|
int m_stride;
|
||||||
|
|
||||||
|
const char* m_name;
|
||||||
|
|
||||||
|
GLuint m_program;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline int GetVertexAttributeSize( VertexAttribute_t attrib )
|
||||||
|
{
|
||||||
|
switch ( attrib )
|
||||||
|
{
|
||||||
|
case VERTEXATTR_VEC2:
|
||||||
|
return 2;
|
||||||
|
case VERTEXATTR_VEC3:
|
||||||
|
return 3;
|
||||||
|
case VERTEXATTR_VEC4:
|
||||||
|
return 4;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !SHADER_H
|
190
src/engine/render/shadersystem.cpp
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "render/shadersystem.h"
|
||||||
|
#include "render/shader.h"
|
||||||
|
#include <render/gl_shared.h>
|
||||||
|
|
||||||
|
static const char* g_uniformNameTable[UNIFORM_MAX] =
|
||||||
|
{
|
||||||
|
"u_modelMatrix",
|
||||||
|
"u_viewMatrix",
|
||||||
|
"u_projectionMatrix",
|
||||||
|
"u_modelViewProjection",
|
||||||
|
"u_customColor",
|
||||||
|
"u_sunDirection",
|
||||||
|
"u_sunColor",
|
||||||
|
"u_sunAmbientColor",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* g_samplersNameTable[SAMPLER_MAX] =
|
||||||
|
{
|
||||||
|
"u_albedoTexture",
|
||||||
|
"u_normalTexture",
|
||||||
|
"u_lightmapTexture",
|
||||||
|
};
|
||||||
|
|
||||||
|
ShaderSystem* g_shaderSystem = nullptr;
|
||||||
|
|
||||||
|
ShaderSystem::ShaderSystem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderSystem::~ShaderSystem()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderSystem::Init()
|
||||||
|
{
|
||||||
|
Msg("Initializing Shader System ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderSystem::Shutdown()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < m_shaders.size(); i++)
|
||||||
|
{
|
||||||
|
ShaderData& shaderData = m_shaders[i];
|
||||||
|
|
||||||
|
if (shaderData.shader)
|
||||||
|
{
|
||||||
|
delete shaderData.shader;
|
||||||
|
shaderData.shader = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_shaders.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader* ShaderSystem::CreateShader(const char* name, const char* vsfilepath, const char* psfilepath, InputLayoutDesc_t* inputLayout /*= nullptr*/, int inputLayoutCount/* = 0*/)
|
||||||
|
{
|
||||||
|
auto it = std::find_if(m_shaders.begin(), m_shaders.end(), [=](const ShaderData& shaderData) { return shaderData.shadername == name; });
|
||||||
|
if ( it != m_shaders.end() )
|
||||||
|
{
|
||||||
|
return it->shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
Shader* pShader = new Shader();
|
||||||
|
|
||||||
|
if ( inputLayout && inputLayoutCount > 0 )
|
||||||
|
{
|
||||||
|
memcpy( pShader->m_layouts, inputLayout, inputLayoutCount * sizeof( InputLayoutDesc_t ) );
|
||||||
|
pShader->m_layout_count = inputLayoutCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
pShader->Create( name, vsfilepath, psfilepath );
|
||||||
|
|
||||||
|
ShaderData shaderData = { name, pShader };
|
||||||
|
m_shaders.push_back(shaderData);
|
||||||
|
|
||||||
|
return pShader;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t g_vertex_attribs_sizetable[VERTEXATTR_MAX] =
|
||||||
|
{
|
||||||
|
2, // VERTEXATTR_VEC2
|
||||||
|
3, // VERTEXATTR_VEC3
|
||||||
|
4, // VERTEXATTR_VEC4
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t g_vertex_attribs_realsizetable[VERTEXATTR_MAX] =
|
||||||
|
{
|
||||||
|
8, // VERTEXATTR_VEC2
|
||||||
|
12, // VERTEXATTR_VEC3
|
||||||
|
16, // VERTEXATTR_VEC4
|
||||||
|
};
|
||||||
|
|
||||||
|
void ApplyVertexFormat(const Shader* shader, size_t stride)
|
||||||
|
{
|
||||||
|
size_t appliedOffset = 0;
|
||||||
|
for (int i = 0; i < shader->m_layout_count; i++)
|
||||||
|
{
|
||||||
|
const InputLayoutDesc_t* layoutEntry = &shader->m_layouts[i];
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(GLuint(i));
|
||||||
|
|
||||||
|
glVertexAttribPointer(GLuint(i), GLint(g_vertex_attribs_sizetable[layoutEntry->attribute]),
|
||||||
|
GL_FLOAT, GL_FALSE, static_cast<GLsizei>(stride),
|
||||||
|
(appliedOffset > 0) ? (void*)(appliedOffset * sizeof(float)) : (void*)0);
|
||||||
|
|
||||||
|
appliedOffset += g_vertex_attribs_sizetable[layoutEntry->attribute];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderSystem::SetShader(const Shader* shader)
|
||||||
|
{
|
||||||
|
assert( shader );
|
||||||
|
glUseProgram( shader->m_program );
|
||||||
|
|
||||||
|
// apply input layout
|
||||||
|
|
||||||
|
//for ( int i = 0; i < shader->m_layout_count; i++ )
|
||||||
|
//{
|
||||||
|
// const InputLayoutDesc_t& layout = shader->m_layouts[ i ];
|
||||||
|
//
|
||||||
|
// //glEnableVertexAttribArray( shader->m_glLayouts[ i ] );
|
||||||
|
// //glVertexAttribPointer( shader->m_glLayouts[ i ], GetVertexAttributeSize( layout.attribute ), GL_FLOAT, GL_FALSE, shader->m_stride, NULL );
|
||||||
|
|
||||||
|
// glEnableVertexAttribArray( i );
|
||||||
|
// glVertexAttribPointer( i, GetVertexAttributeSize( layout.attribute ), GL_FLOAT, GL_FALSE, shader->m_stride, NULL );
|
||||||
|
//}
|
||||||
|
|
||||||
|
ApplyVertexFormat( shader, shader->m_stride );
|
||||||
|
//for ( int i = 0; i < shader->m_layout_count; i++ )
|
||||||
|
//{
|
||||||
|
// const InputLayoutDesc_t& layout = shader->m_layouts[ i ];
|
||||||
|
//
|
||||||
|
// glEnableVertexAttribArray( shader->m_glLayouts[ i ] );
|
||||||
|
// glVertexAttribPointer( shader->m_glLayouts[ i ], GetVertexAttributeSize( layout.attribute ), GL_FLOAT, GL_FALSE, shader->m_stride, NULL );
|
||||||
|
//}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderSystem::SetUniformSampler(const Shader* shader, ShaderSamplers_t sampler, int index)
|
||||||
|
{
|
||||||
|
glGetError();
|
||||||
|
|
||||||
|
GLint uniformLocation = glGetUniformLocation(shader->m_program, g_samplersNameTable[sampler]);
|
||||||
|
glUniform1i(uniformLocation, static_cast<GLint>(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderSystem::SetUniformFloat4(const Shader* shader, ShaderUniform_t uniform, const void* data)
|
||||||
|
{
|
||||||
|
GLint location = glGetUniformLocation( shader->m_program, g_uniformNameTable[ uniform ] );
|
||||||
|
glUniform4fv( location, 1, ( const GLfloat* )data );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShaderSystem::SetUniformMatrix( const Shader* shader, ShaderUniform_t uniform, const void* data )
|
||||||
|
{
|
||||||
|
GLint location = glGetUniformLocation( shader->m_program, g_uniformNameTable[ uniform ] );
|
||||||
|
glUniformMatrix4fv( location, 1, GL_FALSE, ( const GLfloat* )data );
|
||||||
|
}
|
||||||
|
|
||||||
|
// #TODO: Move out
|
||||||
|
|
||||||
|
static const char* s_attributeNameTable[SHADERSEMANTIC_MAX] =
|
||||||
|
{
|
||||||
|
"a_position",//SHADERSEMANTIC_POSITION,
|
||||||
|
"a_color", //SHADERSEMANTIC_COLOR
|
||||||
|
"a_texcoord",//SHADERSEMANTIC_TEXCOORD,
|
||||||
|
"a_texcoord0", //SHADERSEMANTIC_TEXCOORD0,
|
||||||
|
"a_texcoord1",//SHADERSEMANTIC_TEXCOORD1,
|
||||||
|
"a_normal",//SHADERSEMANTIC_NORMAL,
|
||||||
|
"a_tangent",//SHADERSEMANTIC_TANGENT,
|
||||||
|
"a_bitangent"//SHADERSEMANTIC_BITANGENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
void Shader::AllocateAttributes()
|
||||||
|
{
|
||||||
|
// Allocate input layout
|
||||||
|
for ( int i = 0; i < m_layout_count; i++ )
|
||||||
|
{
|
||||||
|
const InputLayoutDesc_t& layout = m_layouts[ i ];
|
||||||
|
// Msg( "Shader::AllocateAttributes: Bind %i as %s", i, s_attributeNameTable[ layout.semantic ] );
|
||||||
|
glBindAttribLocation( m_program, i, s_attributeNameTable[ layout.semantic ] );
|
||||||
|
|
||||||
|
GL_CHECK_ERROR();
|
||||||
|
|
||||||
|
// m_glLayouts[ i ] = glGetAttribLocation( m_program, s_attributeNameTable[i] );
|
||||||
|
// assert( m_glLayouts[ i ] );
|
||||||
|
}
|
||||||
|
}
|
61
src/engine/render/shadersystem.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#ifndef SHADERSYSTEM_H
|
||||||
|
#define SHADERSYSTEM_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "render/shader.h"
|
||||||
|
|
||||||
|
enum ShaderUniform_t
|
||||||
|
{
|
||||||
|
UNIFORM_MODEL_MATRIX,
|
||||||
|
UNIFORM_VIEW_MATRIX,
|
||||||
|
UNIFORM_PROJ_MATRIX,
|
||||||
|
UNIFORM_MVP_MATRIX,
|
||||||
|
UNIFORM_CUSTOM_COLOR,
|
||||||
|
UNIFORM_SUN_DIRECTION,
|
||||||
|
UNIFORM_SUN_COLOR,
|
||||||
|
UNIFORM_SUN_AMBIENT,
|
||||||
|
|
||||||
|
UNIFORM_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ShaderSamplers_t
|
||||||
|
{
|
||||||
|
SAMPLER_ALBEDO,
|
||||||
|
SAMPLER_NORMAL,
|
||||||
|
SAMPLER_LIGHTMAP,
|
||||||
|
|
||||||
|
SAMPLER_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShaderSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShaderSystem();
|
||||||
|
~ShaderSystem();
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
Shader* CreateShader(const char* name, const char* vsfilepath, const char* psfilepath, InputLayoutDesc_t* inputLayout = nullptr, int inputLayoutCount = 0);
|
||||||
|
|
||||||
|
void SetShader(const Shader* shader);
|
||||||
|
|
||||||
|
void SetUniformSampler( const Shader* shader, ShaderSamplers_t sampler, int index );
|
||||||
|
void SetUniformFloat4( const Shader* shader, ShaderUniform_t uniform, const void* data );
|
||||||
|
void SetUniformMatrix( const Shader* shader, ShaderUniform_t uniform, const void* data );
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ShaderData
|
||||||
|
{
|
||||||
|
std::string shadername;
|
||||||
|
Shader* shader;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ShaderData> m_shaders;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ShaderSystem* g_shaderSystem;
|
||||||
|
|
||||||
|
#endif // !SHADERSYSTEM_H
|
308
src/engine/render/texture2d.cpp
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "render/texture2d.h"
|
||||||
|
#include "render/texturesmanager.h"
|
||||||
|
#include "render/gl_shared.h"
|
||||||
|
|
||||||
|
GLint getGlWrap(TextureWrap wrap);
|
||||||
|
GLint getGlTexFilter(TextureFilter filter);
|
||||||
|
|
||||||
|
Texture2D* Texture2D::Create()
|
||||||
|
{
|
||||||
|
return new Texture2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D::Texture2D()
|
||||||
|
{
|
||||||
|
m_pf = PF_UNKNOWN;
|
||||||
|
m_width = 0;
|
||||||
|
m_height = 0;
|
||||||
|
m_channels = 0;
|
||||||
|
m_handle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D::~Texture2D()
|
||||||
|
{
|
||||||
|
m_pf = PF_UNKNOWN;
|
||||||
|
m_width = 0;
|
||||||
|
m_height = 0;
|
||||||
|
m_channels = 0;
|
||||||
|
m_handle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::CreateBlackTexture(int width, int height, int channels)
|
||||||
|
{
|
||||||
|
size_t textureSize = width * height * channels;
|
||||||
|
uint8_t* data = new uint8_t[textureSize];
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)textureSize; i++) {
|
||||||
|
data[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateFromExistedData(data, width, height, channels);
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::CreateWhiteTexture(int width, int height, int channels)
|
||||||
|
{
|
||||||
|
size_t textureSize = width * height * channels;
|
||||||
|
uint8_t* data = new uint8_t[textureSize];
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)textureSize; i++) {
|
||||||
|
data[i] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateFromExistedData(data, width, height, channels);
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::CreateGrayTexture(int width, int height, int channels)
|
||||||
|
{
|
||||||
|
size_t textureSize = width * height * channels;
|
||||||
|
uint8_t* data = new uint8_t[textureSize];
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)textureSize; i++) {
|
||||||
|
data[i] = 255 / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateFromExistedData(data, width, height, channels);
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::CreateTexture_Generator(int width, int height, int channels, int color)
|
||||||
|
{
|
||||||
|
size_t textureSize = width * height * channels;
|
||||||
|
uint8_t* data = new uint8_t[textureSize];
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
m_textureFileName = "$generator_texture$";
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)textureSize; i++) {
|
||||||
|
data[i] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateFromExistedData(data, width, height, channels);
|
||||||
|
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::CreateFromExistedData(void* data, int width, int height, int channels)
|
||||||
|
{
|
||||||
|
//assert(data);
|
||||||
|
|
||||||
|
m_width = width;
|
||||||
|
m_height = height;
|
||||||
|
m_channels = channels;
|
||||||
|
|
||||||
|
glGenTextures(1, &m_handle);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_handle);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, (channels == 3) ? GL_RGB : GL_RGBA, width, height, 0, (channels == 3) ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::CreateRaw(void* data, int width, int height, PixelFormat pf)
|
||||||
|
{
|
||||||
|
m_width = width;
|
||||||
|
m_height = height;
|
||||||
|
m_channels = (pf == PF_R8G8B8) ? 3 : 4;
|
||||||
|
m_pf = pf;
|
||||||
|
|
||||||
|
glGenTextures(1, &m_handle);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_handle);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, getGLInternalPF(pf), width, height, 0, getGLInternalPF(pf), GL_UNSIGNED_BYTE, data);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
|
||||||
|
#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
|
||||||
|
|
||||||
|
void Texture2D::GenerateMipmaps()
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_handle);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
//if (g_texAnisoFilter.getValueB()) {
|
||||||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, g_texAnisoLevel.getValueI());
|
||||||
|
//}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::Bind()
|
||||||
|
{
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::setWrapS(TextureWrap wrap)
|
||||||
|
{
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getGlWrap(wrap));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::setWrapT(TextureWrap wrap)
|
||||||
|
{
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getGlWrap(wrap));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::setMin(TextureFilter filter)
|
||||||
|
{
|
||||||
|
GLint param = 0;
|
||||||
|
param = getGlTexFilter(filter);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Texture2D::setMag(TextureFilter filter)
|
||||||
|
{
|
||||||
|
GLint param = 0;
|
||||||
|
param = getGlTexFilter(filter);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint getGlWrap(TextureWrap wrap)
|
||||||
|
{
|
||||||
|
GLint param = 0;
|
||||||
|
|
||||||
|
if (wrap == TextureWrap::Repeat)
|
||||||
|
param = GL_REPEAT;
|
||||||
|
else if (wrap == TextureWrap::MirroredRepeat)
|
||||||
|
param = GL_MIRRORED_REPEAT;
|
||||||
|
else if (wrap == TextureWrap::ClampToEdge)
|
||||||
|
param = GL_CLAMP_TO_EDGE;
|
||||||
|
else if (wrap == TextureWrap::ClampToBorder)
|
||||||
|
param = GL_CLAMP_TO_BORDER;
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint getGlTexFilter(TextureFilter filter)
|
||||||
|
{
|
||||||
|
GLint param = 0;
|
||||||
|
|
||||||
|
if (filter == TextureFilter::Linear)
|
||||||
|
param = GL_LINEAR;
|
||||||
|
else if (filter == TextureFilter::Nearest)
|
||||||
|
param = GL_NEAREST;
|
||||||
|
else if (filter == TextureFilter::LinearMipmapLinear)
|
||||||
|
param = GL_LINEAR_MIPMAP_LINEAR;
|
||||||
|
else if (filter == TextureFilter::LinearMipmapNearest)
|
||||||
|
param = GL_LINEAR_MIPMAP_NEAREST;
|
||||||
|
else if (filter == TextureFilter::NearestMipmapLinear)
|
||||||
|
param = GL_NEAREST_MIPMAP_LINEAR;
|
||||||
|
else if (filter == TextureFilter::NearestMipmapNearest)
|
||||||
|
param = GL_NEAREST_MIPMAP_NEAREST;
|
||||||
|
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getGLPF(PixelFormat pf)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
//return uint32_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kirill: Remove to render_main.cpp or something else
|
||||||
|
uint32_t getGLInternalPF(PixelFormat pf)
|
||||||
|
{
|
||||||
|
switch (pf)
|
||||||
|
{
|
||||||
|
case PF_UNKNOWN:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case PF_R8G8B8:
|
||||||
|
case PF_R8G8B8F:
|
||||||
|
return GL_RGB;
|
||||||
|
|
||||||
|
case PF_R8G8B8A8:
|
||||||
|
case PF_R8G8B8A8F:
|
||||||
|
return GL_RGBA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getGLTypePF(PixelFormat pf)
|
||||||
|
{
|
||||||
|
switch (pf)
|
||||||
|
{
|
||||||
|
case PF_UNKNOWN:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case PF_R8G8B8:
|
||||||
|
case PF_R8G8B8A8:
|
||||||
|
return GL_UNSIGNED_BYTE;
|
||||||
|
|
||||||
|
case PF_R8G8B8F:
|
||||||
|
case PF_R8G8B8A8F:
|
||||||
|
return GL_FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetGLBlendFactor(BlendFactor factor)
|
||||||
|
{
|
||||||
|
switch (factor)
|
||||||
|
{
|
||||||
|
case BF_ZERO:
|
||||||
|
return GL_ZERO;
|
||||||
|
break;
|
||||||
|
case BF_ONE:
|
||||||
|
return GL_ONE;
|
||||||
|
break;
|
||||||
|
case BF_SRC_COLOR:
|
||||||
|
return GL_SRC_COLOR;
|
||||||
|
break;
|
||||||
|
case BF_ONE_MINUS_SRC_COLOR:
|
||||||
|
return GL_ONE_MINUS_SRC_COLOR;
|
||||||
|
break;
|
||||||
|
case BF_DST_COLOR:
|
||||||
|
return GL_DST_COLOR;
|
||||||
|
break;
|
||||||
|
case BF_ONE_MINUS_DST_COLOR:
|
||||||
|
return GL_ONE_MINUS_DST_COLOR;
|
||||||
|
break;
|
||||||
|
case BF_SRC_ALPHA:
|
||||||
|
return GL_SRC_ALPHA;
|
||||||
|
break;
|
||||||
|
case BF_ONE_MINUS_SRC_ALPHA:
|
||||||
|
return GL_ONE_MINUS_SRC_ALPHA;
|
||||||
|
break;
|
||||||
|
case BF_DST_ALPHA:
|
||||||
|
return GL_DST_ALPHA;
|
||||||
|
break;
|
||||||
|
case BF_ONE_MINUS_DST_ALPHA:
|
||||||
|
return GL_ONE_MINUS_DST_ALPHA;
|
||||||
|
break;
|
||||||
|
case BF_CONSTANT_COLOR:
|
||||||
|
return GL_CONSTANT_COLOR;
|
||||||
|
break;
|
||||||
|
case BF_ONE_MINUS_CONSTANT_COLOR:
|
||||||
|
return GL_ONE_MINUS_CONSTANT_COLOR;
|
||||||
|
break;
|
||||||
|
case BF_CONSTANT_ALPHA:
|
||||||
|
return GL_CONSTANT_ALPHA;
|
||||||
|
break;
|
||||||
|
case BF_ONE_MINUS_CONSTANT_ALPHA:
|
||||||
|
return GL_ONE_MINUS_CONSTANT_ALPHA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
67
src/engine/render/texture2d.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#ifndef TEXTURE2D_H
|
||||||
|
#define TEXTURE2D_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "render/render_shared.h"
|
||||||
|
|
||||||
|
enum class TextureWrap
|
||||||
|
{
|
||||||
|
Repeat,
|
||||||
|
MirroredRepeat,
|
||||||
|
ClampToEdge,
|
||||||
|
ClampToBorder
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TextureFilter
|
||||||
|
{
|
||||||
|
Nearest,
|
||||||
|
Linear,
|
||||||
|
NearestMipmapNearest,
|
||||||
|
LinearMipmapNearest,
|
||||||
|
NearestMipmapLinear,
|
||||||
|
LinearMipmapLinear
|
||||||
|
};
|
||||||
|
|
||||||
|
class TexturesManager;
|
||||||
|
|
||||||
|
class Texture2D
|
||||||
|
{
|
||||||
|
friend class TexturesManager;
|
||||||
|
public:
|
||||||
|
static Texture2D* Create();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Texture2D();
|
||||||
|
~Texture2D();
|
||||||
|
|
||||||
|
void CreateBlackTexture(int width, int height, int channels);
|
||||||
|
void CreateWhiteTexture(int width, int height, int channels);
|
||||||
|
void CreateGrayTexture(int width, int height, int channels);
|
||||||
|
void CreateTexture_Generator(int width, int height, int channels, int color);
|
||||||
|
void CreateFromExistedData(void* data, int width, int height, int channels);
|
||||||
|
void CreateFromFile(const char* filename);
|
||||||
|
|
||||||
|
void CreateRaw(void* data, int width, int height, PixelFormat pf);
|
||||||
|
|
||||||
|
void GenerateMipmaps();
|
||||||
|
|
||||||
|
void Bind();
|
||||||
|
|
||||||
|
void setWrapS(TextureWrap wrap);
|
||||||
|
void setWrapT(TextureWrap wrap);
|
||||||
|
void setMin(TextureFilter filter);
|
||||||
|
void setMag(TextureFilter filter);
|
||||||
|
|
||||||
|
uint32_t GetHandle() { return m_handle; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_textureFileName;
|
||||||
|
PixelFormat m_pf;
|
||||||
|
int m_width;
|
||||||
|
int m_height;
|
||||||
|
int m_channels;
|
||||||
|
uint32_t m_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !TEXTURE2D_H
|
194
src/engine/render/texturesmanager.cpp
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#include "utils/logger.h"
|
||||||
|
#include "filesystem/filemanager.h"
|
||||||
|
#include "render/texture2d.h"
|
||||||
|
#include "render/texturesmanager.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
#include <glad/glad.h>
|
||||||
|
|
||||||
|
// STB Image loading code
|
||||||
|
void Texture2D::CreateFromFile(const char* filename)
|
||||||
|
{
|
||||||
|
int width, height, channels;
|
||||||
|
m_textureFileName = filename;
|
||||||
|
|
||||||
|
File* file = g_fileManager->OpenFile(filename, FileAccess::Read);
|
||||||
|
|
||||||
|
file->seek(SeekDir::End, 0);
|
||||||
|
size_t imageSize = file->tell();
|
||||||
|
file->seek(SeekDir::Begin, 0);
|
||||||
|
|
||||||
|
uint8_t* fileData = (uint8_t*)malloc(imageSize);
|
||||||
|
file->read(fileData, imageSize);
|
||||||
|
|
||||||
|
g_fileManager->CloseFile(file);
|
||||||
|
|
||||||
|
uint8_t* imageData = stbi_load_from_memory(fileData, int(imageSize), &width, &height, &channels, 0);
|
||||||
|
|
||||||
|
if (imageData == NULL) {
|
||||||
|
free(fileData);
|
||||||
|
Msg("Texture loading error: %s (%s)", filename, stbi_failure_reason());
|
||||||
|
assert(imageData);
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateFromExistedData(imageData, width, height, channels);
|
||||||
|
m_textureFileName = filename;
|
||||||
|
|
||||||
|
free(fileData);
|
||||||
|
|
||||||
|
stbi_image_free(imageData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* g_texFileExtensions[] = { ".png", ".jpeg", ".jpg", ".tga", ".bmp" };
|
||||||
|
const int kTexFileExtensionsSize = sizeof(g_texFileExtensions) / sizeof(g_texFileExtensions[0]);
|
||||||
|
|
||||||
|
TexturesManager* g_texturesManager = nullptr;
|
||||||
|
|
||||||
|
TexturesManager::TexturesManager()
|
||||||
|
{
|
||||||
|
m_notex = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexturesManager::~TexturesManager()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TexturesManager::Init()
|
||||||
|
{
|
||||||
|
stbi_set_flip_vertically_on_load(true);
|
||||||
|
|
||||||
|
m_notex = LoadTexture2D("content/textures/system/notex.png", true);
|
||||||
|
if (!m_notex) {
|
||||||
|
Logger::error("TexturesManager::Init: Failed to initialize system texture! 'system/notex.png' is not exist.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TexturesManager::Shutdown()
|
||||||
|
{
|
||||||
|
if (!m_textures.empty()) {
|
||||||
|
Msg("--- unfreed textures ---");
|
||||||
|
|
||||||
|
for (std::vector<Texture2D*>::iterator it = m_textures.begin(); it != m_textures.end(); ++it) {
|
||||||
|
Msg("%s", (*it)->m_textureFileName.c_str());
|
||||||
|
delete* it;
|
||||||
|
*it = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_textures.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TexturesManager::SetTexture(int slot, Texture2D* texture)
|
||||||
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE0 + slot);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture ? texture->GetHandle() : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D* TexturesManager::CreateManual2D(const char* name, uint32_t width, uint32_t height, PixelFormat format, bool useAsRenderTarget)
|
||||||
|
{
|
||||||
|
for (std::vector<Texture2D*>::iterator it = m_textures.begin(); it != m_textures.end(); ++it) {
|
||||||
|
if ((*it)->m_textureFileName == name) {
|
||||||
|
Logger::error("TexturesManager::CreateManual2D: texture %s is already created!", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate
|
||||||
|
Texture2D* texture = Texture2D::Create();
|
||||||
|
texture->CreateRaw(nullptr, width, height, format);
|
||||||
|
texture->m_textureFileName = name;
|
||||||
|
|
||||||
|
if (useAsRenderTarget)
|
||||||
|
Msg("Created rt texture [%s]", name);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSupportedExtension(const char* filename)
|
||||||
|
{
|
||||||
|
std::string ext = fs::getFileExtension(filename);
|
||||||
|
|
||||||
|
for (int i = 0; i < kTexFileExtensionsSize; i++) {
|
||||||
|
if (ext == g_texFileExtensions[i]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D* TexturesManager::LoadTexture2D(const char* texturename, bool useMipmaps /*= false*/)
|
||||||
|
{
|
||||||
|
int texturesNbr = m_textures.size();
|
||||||
|
for (int i = 0; i < texturesNbr; i++) {
|
||||||
|
if (m_textures[i]->m_textureFileName == texturename)
|
||||||
|
return m_textures[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(texturename, "$white$") == 0) {
|
||||||
|
Texture2D* tex = Texture2D::Create();
|
||||||
|
tex->m_textureFileName = "$white$";
|
||||||
|
tex->CreateWhiteTexture(16, 16, 3);
|
||||||
|
m_textures.push_back(tex);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
if (strcmp(texturename, "$black$") == 0) {
|
||||||
|
Texture2D* tex = Texture2D::Create();
|
||||||
|
tex->m_textureFileName = "$black$";
|
||||||
|
tex->CreateBlackTexture(16, 16, 3);
|
||||||
|
m_textures.push_back(tex);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
if (strcmp(texturename, "$gray$") == 0) {
|
||||||
|
Texture2D* tex = Texture2D::Create();
|
||||||
|
tex->m_textureFileName = "$gray$";
|
||||||
|
tex->CreateGrayTexture(16, 16, 3);
|
||||||
|
m_textures.push_back(tex);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
if (strcmp(texturename, "$gray_console$") == 0) {
|
||||||
|
Texture2D* tex = Texture2D::Create();
|
||||||
|
tex->CreateTexture_Generator(16, 16, 3, 32);
|
||||||
|
m_textures.push_back(tex);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(texturename) <= 0) {
|
||||||
|
return m_notex;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string texnamebuf;
|
||||||
|
|
||||||
|
// find texture from disk
|
||||||
|
for (int i = 0; i < kTexFileExtensionsSize; i++)
|
||||||
|
{
|
||||||
|
std::string textureFilename = fs::getFileNameWithoutExtension(texturename);
|
||||||
|
textureFilename += g_texFileExtensions[i];
|
||||||
|
|
||||||
|
if (g_fileManager->FileExist(textureFilename.c_str()))
|
||||||
|
{
|
||||||
|
texnamebuf = textureFilename;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!texnamebuf.empty()) {
|
||||||
|
Texture2D* texture = Texture2D::Create();
|
||||||
|
texture->CreateFromFile(texnamebuf.c_str());
|
||||||
|
|
||||||
|
if (useMipmaps)
|
||||||
|
texture->GenerateMipmaps();
|
||||||
|
|
||||||
|
Msg("loaded %s", fs::getFilenameWithoutPathAndExtension(texturename).c_str());
|
||||||
|
m_textures.push_back(texture);
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
else if (texnamebuf.empty() && m_notex) {
|
||||||
|
Msg("not found %s", fs::getFilenameWithoutPathAndExtension(texturename).c_str());
|
||||||
|
return m_notex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
39
src/engine/render/texturesmanager.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifndef TEXTURESMANAGER_H
|
||||||
|
#define TEXTURESMANAGER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "render/render_shared.h"
|
||||||
|
|
||||||
|
class Texture2D;
|
||||||
|
|
||||||
|
class TexturesManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TexturesManager();
|
||||||
|
~TexturesManager();
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void SetTexture(int slot, Texture2D* texture);
|
||||||
|
|
||||||
|
Texture2D* CreateManual2D(
|
||||||
|
const char* name,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
PixelFormat format,
|
||||||
|
bool useAsRenderTarget = false);
|
||||||
|
|
||||||
|
Texture2D* LoadTexture2D(const char* texturename, bool useMipmaps = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Texture2D*> m_textures;
|
||||||
|
|
||||||
|
Texture2D* m_notex;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern TexturesManager* g_texturesManager;
|
||||||
|
|
||||||
|
#endif // !TEXTURESMANAGER_H
|
460
src/engine/render/ui.cpp
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cassert>
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "render/ui.h"
|
||||||
|
#include "render/vertexbuffer.h"
|
||||||
|
#include "render/indexbuffer.h"
|
||||||
|
#include "render/renderdevice.h"
|
||||||
|
#include "render/shadersystem.h"
|
||||||
|
#include "render/texturesmanager.h"
|
||||||
|
#include "render/texture2d.h"
|
||||||
|
|
||||||
|
struct DrawInfo
|
||||||
|
{
|
||||||
|
uint16_t vxcount;
|
||||||
|
uint16_t idxcount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UIGlobals {
|
||||||
|
VertexBuffer* vb;
|
||||||
|
IndexBuffer* ib;
|
||||||
|
Shader* shader;
|
||||||
|
Texture2D* activetexture = nullptr;
|
||||||
|
Texture2D* defaultTexture = nullptr;
|
||||||
|
|
||||||
|
UIVertex* vertices = nullptr;
|
||||||
|
uint16_t* indices = nullptr;
|
||||||
|
DrawInfo drawInfo[MAX_UI_VERTICES];
|
||||||
|
uint16_t count = 0;
|
||||||
|
uint16_t position = 0;
|
||||||
|
uint16_t Indexposition = 0;
|
||||||
|
uint16_t currentIdx = 0;
|
||||||
|
} g_ui;
|
||||||
|
|
||||||
|
|
||||||
|
void uiInit()
|
||||||
|
{
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Buffer and context state
|
||||||
|
|
||||||
|
// Buffer creation
|
||||||
|
g_ui.vb = g_renderDevice->CreateVertexBuffer(nullptr, MAX_UI_VERTICES, true);
|
||||||
|
g_ui.ib = g_renderDevice->CreateIndexBuffer(nullptr, MAX_UI_INDICES, true);
|
||||||
|
|
||||||
|
// Create shader
|
||||||
|
|
||||||
|
InputLayoutDesc_t inputLayout[] =
|
||||||
|
{
|
||||||
|
{ VERTEXATTR_VEC2, SHADERSEMANTIC_POSITION },
|
||||||
|
{ VERTEXATTR_VEC2, SHADERSEMANTIC_TEXCOORD },
|
||||||
|
{ VERTEXATTR_VEC4, SHADERSEMANTIC_COLOR },
|
||||||
|
};
|
||||||
|
|
||||||
|
g_ui.shader = g_shaderSystem->CreateShader("ui", "content/shaders/ui_base.vs", "content/shaders/ui_tex.ps", inputLayout, sizeof(inputLayout) / sizeof(inputLayout[0]));
|
||||||
|
g_ui.shader->m_stride = sizeof( UIVertex );
|
||||||
|
|
||||||
|
g_ui.defaultTexture = g_texturesManager->LoadTexture2D("$white$");
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiShutdown()
|
||||||
|
{
|
||||||
|
delete g_ui.ib;
|
||||||
|
delete g_ui.vb;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDumpBuffers()
|
||||||
|
{
|
||||||
|
Msg( "--- UI Vertex Buffer ---" );
|
||||||
|
|
||||||
|
g_ui.vertices = (UIVertex*)g_ui.vb->MapBuffer(BufferAccess::WRITE_ONLY);
|
||||||
|
assert(g_ui.vertices);
|
||||||
|
|
||||||
|
for ( int i = 0; i < g_ui.position; i++ )
|
||||||
|
{
|
||||||
|
Msg( "%i: POSITION = %.2f %.2f", i, g_ui.vertices[ i ].position.x, g_ui.vertices[ i ].position.y );
|
||||||
|
Msg( "%i: TEXCOORD = %.2f %.2f", i, g_ui.vertices[ i ].uv.x, g_ui.vertices[ i ].uv.y );
|
||||||
|
Msg( "%i: COLOR = %.2f %.2f %.2f %.2f", i,
|
||||||
|
g_ui.vertices[ i ].color.x,
|
||||||
|
g_ui.vertices[ i ].color.y,
|
||||||
|
g_ui.vertices[ i ].color.z,
|
||||||
|
g_ui.vertices[ i ].color.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg( "------------------------" );
|
||||||
|
|
||||||
|
g_ui.vb->UnmapBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiBeginRender()
|
||||||
|
{
|
||||||
|
g_ui.vertices = (UIVertex*)g_ui.vb->MapBuffer(BufferAccess::WRITE_ONLY);
|
||||||
|
assert(g_ui.vertices);
|
||||||
|
|
||||||
|
g_ui.indices = (uint16_t*)g_ui.ib->MapBuffer(BufferAccess::WRITE_ONLY);
|
||||||
|
assert(g_ui.indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawQuad(const Vec2& a, const Vec2& b, const Vec2& c, const Vec2& d, const Vec4& color)
|
||||||
|
{
|
||||||
|
DrawInfo& drawInfo = g_ui.drawInfo[g_ui.count];
|
||||||
|
drawInfo.vxcount = 4;
|
||||||
|
drawInfo.idxcount = 6;
|
||||||
|
|
||||||
|
g_ui.indices[g_ui.Indexposition + 0] = g_ui.currentIdx;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 1] = g_ui.currentIdx + 1;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 2] = g_ui.currentIdx + 2;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 3] = g_ui.currentIdx;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 4] = g_ui.currentIdx + 2;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 5] = g_ui.currentIdx + 3;
|
||||||
|
g_ui.vertices[g_ui.position + 0].position = a; g_ui.vertices[g_ui.position + 0].color = color;
|
||||||
|
g_ui.vertices[g_ui.position + 1].position = b; g_ui.vertices[g_ui.position + 1].color = color;
|
||||||
|
g_ui.vertices[g_ui.position + 2].position = c; g_ui.vertices[g_ui.position + 2].color = color;
|
||||||
|
g_ui.vertices[g_ui.position + 3].position = d; g_ui.vertices[g_ui.position + 3].color = color;
|
||||||
|
|
||||||
|
// texcoord
|
||||||
|
g_ui.vertices[g_ui.position + 0].uv = Vec2{ 0.0f, 1.0f };
|
||||||
|
g_ui.vertices[g_ui.position + 1].uv = Vec2{ 1.0f, 1.0f };
|
||||||
|
g_ui.vertices[g_ui.position + 2].uv = Vec2{ 1.0f, 0.0f };
|
||||||
|
g_ui.vertices[g_ui.position + 3].uv = Vec2{ 0.0f, 0.0f };
|
||||||
|
|
||||||
|
g_ui.currentIdx += 4;
|
||||||
|
g_ui.Indexposition += 6;
|
||||||
|
g_ui.position += 4;
|
||||||
|
g_ui.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float Rsqrt(float x) { return 1.0f / sqrtf(x); }
|
||||||
|
#define NORMALIZE2F_OVER_ZERO(VX,VY) { float d2 = VX*VX + VY*VY; if (d2 > 0.0f) { float inv_len = Rsqrt(d2); VX *= inv_len; VY *= inv_len; } } (void)0
|
||||||
|
|
||||||
|
void uiDrawLines(const Vec2* drawPoints, const size_t pointsCount, bool closed, const Vec4& color)
|
||||||
|
{
|
||||||
|
float thickness = 2.1f;
|
||||||
|
|
||||||
|
const int count = closed ? pointsCount : pointsCount - 1;
|
||||||
|
const int vtxCount = (count) * 4;
|
||||||
|
const int idxCount = (count) * 6;
|
||||||
|
|
||||||
|
for (int i1 = 0; i1 < count; i1++)
|
||||||
|
{
|
||||||
|
const int i2 = (i1 + 1) == pointsCount ? 0 : i1 + 1;
|
||||||
|
const Vec2& p1 = drawPoints[i1];
|
||||||
|
const Vec2& p2 = drawPoints[i2];
|
||||||
|
|
||||||
|
float dx = p2.x - p1.x;
|
||||||
|
float dy = p2.y - p1.y;
|
||||||
|
NORMALIZE2F_OVER_ZERO(dx, dy);
|
||||||
|
dx *= (thickness * 0.5f);
|
||||||
|
dy *= (thickness * 0.5f);
|
||||||
|
|
||||||
|
g_ui.vertices[g_ui.position + 0].position.x = p1.x + dy; g_ui.vertices[g_ui.position + 0].position.y = p1.y - dx; g_ui.vertices[g_ui.position + 0].color = color;
|
||||||
|
g_ui.vertices[g_ui.position + 1].position.x = p2.x + dy; g_ui.vertices[g_ui.position + 1].position.y = p2.y - dx; g_ui.vertices[g_ui.position + 1].color = color;
|
||||||
|
g_ui.vertices[g_ui.position + 2].position.x = p2.x - dy; g_ui.vertices[g_ui.position + 2].position.y = p2.y + dx; g_ui.vertices[g_ui.position + 2].color = color;
|
||||||
|
g_ui.vertices[g_ui.position + 3].position.x = p1.x - dy; g_ui.vertices[g_ui.position + 3].position.y = p1.y + dx; g_ui.vertices[g_ui.position + 3].color = color;
|
||||||
|
|
||||||
|
g_ui.indices[g_ui.Indexposition + 0] = g_ui.currentIdx;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 1] = g_ui.currentIdx + 1;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 2] = g_ui.currentIdx + 2;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 3] = g_ui.currentIdx;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 4] = g_ui.currentIdx + 2;
|
||||||
|
g_ui.indices[g_ui.Indexposition + 5] = g_ui.currentIdx + 3;
|
||||||
|
g_ui.currentIdx += 4;
|
||||||
|
g_ui.Indexposition += 6;
|
||||||
|
g_ui.position += 4;
|
||||||
|
|
||||||
|
DrawInfo& drawInfo = g_ui.drawInfo[g_ui.count];
|
||||||
|
drawInfo.vxcount = 4;
|
||||||
|
drawInfo.idxcount = 6;
|
||||||
|
g_ui.count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiDrawRect(const Vec2& position, const Vec2& size, const Vec4& color)
|
||||||
|
{
|
||||||
|
Vec2 quad[4];
|
||||||
|
quad[0] = { position.x, position.y };
|
||||||
|
quad[1] = { position.x + size.x, position.y };
|
||||||
|
quad[2] = { position.x + size.x, position.y + size.y };
|
||||||
|
quad[3] = { position.x, position.y + size.y };
|
||||||
|
uiDrawQuad(quad[0], quad[1], quad[2], quad[3], color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiSetTexture(Texture2D* texture)
|
||||||
|
{
|
||||||
|
g_ui.activetexture = texture ? texture : g_ui.defaultTexture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiSetTextureByName(const char* filename)
|
||||||
|
{
|
||||||
|
uiSetTexture( g_texturesManager->LoadTexture2D( filename ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void uiEndRender()
|
||||||
|
{
|
||||||
|
g_ui.indices = nullptr;
|
||||||
|
g_ui.vertices = nullptr;
|
||||||
|
|
||||||
|
g_ui.ib->UnmapBuffer();
|
||||||
|
g_ui.vb->UnmapBuffer();
|
||||||
|
|
||||||
|
int x = 0, y = 0, w = g_renderView.width, h = g_renderView.height;
|
||||||
|
g_renderDevice->SetViewport(x, y, w, h);
|
||||||
|
|
||||||
|
float L = x;
|
||||||
|
float R = x + w;
|
||||||
|
float T = y;
|
||||||
|
float B = y + h;
|
||||||
|
#if defined(GL_CLIP_ORIGIN)
|
||||||
|
if (!clip_origin_lower_left) { float tmp = T; T = B; B = tmp; } // Swap top and bottom if origin is upper left
|
||||||
|
#endif
|
||||||
|
const float orthoProjection[4][4] =
|
||||||
|
{
|
||||||
|
{ 2.0f / (R - L), 0.0f, 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 2.0f / (T - B), 0.0f, 0.0f },
|
||||||
|
{ 0.0f, 0.0f, -1.0f, 0.0f },
|
||||||
|
{ (R + L) / (L - R), (T + B) / (B - T), 0.0f, 1.0f },
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( g_ui.activetexture == nullptr )
|
||||||
|
g_ui.activetexture = g_ui.defaultTexture;
|
||||||
|
|
||||||
|
g_texturesManager->SetTexture( 0, g_ui.activetexture );
|
||||||
|
g_ui.activetexture->setMin(TextureFilter::Linear);
|
||||||
|
g_ui.activetexture->setMag(TextureFilter::Linear);
|
||||||
|
g_ui.activetexture->setWrapS(TextureWrap::ClampToEdge);
|
||||||
|
g_ui.activetexture->setWrapT(TextureWrap::ClampToEdge);
|
||||||
|
|
||||||
|
g_shaderSystem->SetShader( g_ui.shader );
|
||||||
|
g_shaderSystem->SetUniformMatrix( g_ui.shader, UNIFORM_PROJ_MATRIX, orthoProjection );
|
||||||
|
|
||||||
|
g_renderDevice->SetVerticesBuffer( g_ui.vb );
|
||||||
|
g_renderDevice->SetIndicesBuffer( g_ui.ib );
|
||||||
|
|
||||||
|
// Enable blending
|
||||||
|
g_renderDevice->SetBlending( true );
|
||||||
|
g_renderDevice->SetBlendingFunction( BF_SRC_ALPHA, BF_ONE_MINUS_SRC_ALPHA );
|
||||||
|
|
||||||
|
// Disable depth
|
||||||
|
g_renderDevice->SetDepthTest( false );
|
||||||
|
g_renderDevice->SetBackfaceCull( false );
|
||||||
|
|
||||||
|
g_renderDevice->DrawElements( PT_TRIANGLES, g_ui.Indexposition, true );
|
||||||
|
|
||||||
|
// Uncomment for UI VB debugging
|
||||||
|
//uiDumpBuffers();
|
||||||
|
|
||||||
|
g_ui.currentIdx = 0;
|
||||||
|
g_ui.Indexposition = 0;
|
||||||
|
g_ui.position = 0;
|
||||||
|
g_ui.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct Character {
|
||||||
|
int codePoint, x, y, width, height, originX, originY;
|
||||||
|
} Character;
|
||||||
|
|
||||||
|
typedef struct Font {
|
||||||
|
const char* name;
|
||||||
|
int size, bold, italic, width, height, characterCount;
|
||||||
|
Character* characters;
|
||||||
|
} Font;
|
||||||
|
|
||||||
|
static Character characters_Courier_New[] = {
|
||||||
|
{' ', 36, 61, 3, 3, 1, 1},
|
||||||
|
{'!', 498, 0, 10, 20, -1, 16},
|
||||||
|
{'"', 423, 43, 14, 13, 1, 16},
|
||||||
|
{'#', 160, 0, 16, 22, 2, 17},
|
||||||
|
{'$', 47, 0, 16, 23, 2, 17},
|
||||||
|
{'%', 357, 0, 16, 20, 2, 16},
|
||||||
|
{'&', 202, 24, 15, 19, 1, 15},
|
||||||
|
{'\'', 448, 43, 10, 13, -1, 16},
|
||||||
|
{'(', 111, 0, 11, 23, -2, 16},
|
||||||
|
{')', 122, 0, 11, 23, 1, 16},
|
||||||
|
{'*', 357, 43, 16, 15, 2, 16},
|
||||||
|
{'+', 392, 24, 18, 18, 3, 15},
|
||||||
|
{',', 437, 43, 11, 13, -1, 6},
|
||||||
|
{'-', 20, 61, 16, 9, 2, 10},
|
||||||
|
{'.', 474, 43, 10, 10, -1, 6},
|
||||||
|
{'/', 0, 0, 16, 24, 2, 18},
|
||||||
|
{'0', 373, 0, 16, 20, 2, 16},
|
||||||
|
{'1', 106, 24, 16, 19, 2, 16},
|
||||||
|
{'2', 122, 24, 16, 19, 2, 16},
|
||||||
|
{'3', 389, 0, 16, 20, 2, 16},
|
||||||
|
{'4', 138, 24, 16, 19, 2, 16},
|
||||||
|
{'5', 405, 0, 16, 20, 2, 16},
|
||||||
|
{'6', 453, 0, 15, 20, 1, 16},
|
||||||
|
{'7', 154, 24, 16, 19, 2, 16},
|
||||||
|
{'8', 421, 0, 16, 20, 2, 16},
|
||||||
|
{'9', 468, 0, 15, 20, 1, 16},
|
||||||
|
{':', 292, 43, 10, 16, -1, 12},
|
||||||
|
{';', 120, 43, 12, 18, 0, 12},
|
||||||
|
{'<', 297, 24, 19, 18, 4, 15},
|
||||||
|
{'=', 405, 43, 18, 13, 3, 12},
|
||||||
|
{'>', 316, 24, 19, 18, 3, 15},
|
||||||
|
{'?', 483, 0, 15, 20, 1, 16},
|
||||||
|
{'@', 232, 0, 15, 21, 2, 16},
|
||||||
|
{'A', 217, 24, 20, 18, 4, 15},
|
||||||
|
{'B', 410, 24, 18, 18, 3, 15},
|
||||||
|
{'C', 285, 0, 18, 20, 3, 16},
|
||||||
|
{'D', 428, 24, 18, 18, 3, 15},
|
||||||
|
{'E', 446, 24, 18, 18, 3, 15},
|
||||||
|
{'F', 54, 43, 17, 18, 2, 15},
|
||||||
|
{'G', 303, 0, 18, 20, 3, 16},
|
||||||
|
{'H', 464, 24, 18, 18, 3, 15},
|
||||||
|
{'I', 88, 43, 16, 18, 2, 15},
|
||||||
|
{'J', 0, 24, 18, 19, 2, 15},
|
||||||
|
{'K', 335, 24, 19, 18, 3, 15},
|
||||||
|
{'L', 482, 24, 18, 18, 3, 15},
|
||||||
|
{'M', 237, 24, 20, 18, 4, 15},
|
||||||
|
{'N', 354, 24, 19, 18, 4, 15},
|
||||||
|
{'O', 321, 0, 18, 20, 3, 16},
|
||||||
|
{'P', 71, 43, 17, 18, 2, 15},
|
||||||
|
{'Q', 142, 0, 18, 22, 3, 16},
|
||||||
|
{'R', 373, 24, 19, 18, 3, 15},
|
||||||
|
{'S', 437, 0, 16, 20, 2, 16},
|
||||||
|
{'T', 0, 43, 18, 18, 3, 15},
|
||||||
|
{'U', 18, 24, 18, 19, 3, 15},
|
||||||
|
{'V', 257, 24, 20, 18, 4, 15},
|
||||||
|
{'W', 277, 24, 20, 18, 4, 15},
|
||||||
|
{'X', 18, 43, 18, 18, 3, 15},
|
||||||
|
{'Y', 36, 43, 18, 18, 3, 15},
|
||||||
|
{'Z', 104, 43, 16, 18, 2, 15},
|
||||||
|
{'[', 63, 0, 12, 23, -1, 16},
|
||||||
|
{'\\', 16, 0, 16, 24, 2, 18},
|
||||||
|
{']', 75, 0, 12, 23, 1, 16},
|
||||||
|
{'^', 389, 43, 16, 14, 2, 17},
|
||||||
|
{'_', 0, 61, 20, 9, 4, -1},
|
||||||
|
{'`', 484, 43, 10, 10, -1, 17},
|
||||||
|
{'a', 132, 43, 18, 17, 3, 13},
|
||||||
|
{'b', 247, 0, 19, 20, 4, 16},
|
||||||
|
{'c', 186, 43, 17, 17, 2, 13},
|
||||||
|
{'d', 266, 0, 19, 20, 3, 16},
|
||||||
|
{'e', 150, 43, 18, 17, 3, 13},
|
||||||
|
{'f', 72, 24, 17, 19, 2, 16},
|
||||||
|
{'g', 214, 0, 18, 21, 3, 13},
|
||||||
|
{'h', 36, 24, 18, 19, 3, 16},
|
||||||
|
{'i', 170, 24, 16, 19, 2, 16},
|
||||||
|
{'j', 32, 0, 15, 24, 2, 16},
|
||||||
|
{'k', 54, 24, 18, 19, 3, 16},
|
||||||
|
{'l', 186, 24, 16, 19, 2, 16},
|
||||||
|
{'m', 219, 43, 20, 16, 4, 13},
|
||||||
|
{'n', 239, 43, 18, 16, 3, 13},
|
||||||
|
{'o', 168, 43, 18, 17, 3, 13},
|
||||||
|
{'p', 176, 0, 19, 21, 4, 13},
|
||||||
|
{'q', 195, 0, 19, 21, 3, 13},
|
||||||
|
{'r', 275, 43, 17, 16, 2, 13},
|
||||||
|
{'s', 203, 43, 16, 17, 2, 13},
|
||||||
|
{'t', 89, 24, 17, 19, 2, 15},
|
||||||
|
{'u', 257, 43, 18, 16, 3, 12},
|
||||||
|
{'v', 302, 43, 19, 15, 3, 12},
|
||||||
|
{'w', 321, 43, 18, 15, 3, 12},
|
||||||
|
{'x', 339, 43, 18, 15, 3, 12},
|
||||||
|
{'y', 339, 0, 18, 20, 3, 12},
|
||||||
|
{'z', 373, 43, 16, 15, 2, 12},
|
||||||
|
{'{', 87, 0, 12, 23, 0, 16},
|
||||||
|
{'|', 133, 0, 9, 23, -2, 16},
|
||||||
|
{'}', 99, 0, 12, 23, 0, 16},
|
||||||
|
{'~', 458, 43, 16, 11, 2, 11},
|
||||||
|
};
|
||||||
|
|
||||||
|
static Font font_Courier_New = { "Courier New", 20, 1, 0, 512, 128, 95, characters_Courier_New };
|
||||||
|
|
||||||
|
static Character characters_Arial[] = {
|
||||||
|
{' ', 10, 61, 3, 3, 1, 1},
|
||||||
|
{'!', 205, 34, 5, 15, 0, 14},
|
||||||
|
{'"', 202, 49, 8, 7, 1, 14},
|
||||||
|
{'#', 187, 19, 12, 15, 1, 14},
|
||||||
|
{'$', 71, 0, 12, 18, 1, 15},
|
||||||
|
{'%', 162, 0, 16, 15, 0, 14},
|
||||||
|
{'&', 208, 0, 14, 15, 1, 14},
|
||||||
|
{'\'', 210, 49, 5, 7, 1, 14},
|
||||||
|
{'(', 35, 0, 7, 19, 0, 14},
|
||||||
|
{')', 42, 0, 7, 19, 0, 14},
|
||||||
|
{'*', 193, 49, 9, 7, 1, 14},
|
||||||
|
{'+', 161, 49, 11, 10, 0, 11},
|
||||||
|
{',', 215, 49, 5, 7, 0, 3},
|
||||||
|
{'-', 246, 49, 8, 4, 1, 6},
|
||||||
|
{'.', 0, 61, 5, 4, 0, 3},
|
||||||
|
{'/', 177, 34, 7, 15, 1, 14},
|
||||||
|
{'0', 199, 19, 12, 15, 1, 14},
|
||||||
|
{'1', 184, 34, 7, 15, -1, 14},
|
||||||
|
{'2', 84, 34, 11, 15, 1, 14},
|
||||||
|
{'3', 211, 19, 12, 15, 1, 14},
|
||||||
|
{'4', 223, 19, 12, 15, 1, 14},
|
||||||
|
{'5', 235, 19, 12, 15, 1, 14},
|
||||||
|
{'6', 0, 34, 12, 15, 1, 14},
|
||||||
|
{'7', 12, 34, 12, 15, 1, 14},
|
||||||
|
{'8', 24, 34, 12, 15, 1, 14},
|
||||||
|
{'9', 36, 34, 12, 15, 1, 14},
|
||||||
|
{':', 156, 49, 5, 11, 0, 10},
|
||||||
|
{';', 223, 34, 5, 14, 0, 10},
|
||||||
|
{'<', 134, 49, 11, 11, 0, 12},
|
||||||
|
{'=', 182, 49, 11, 8, 0, 10},
|
||||||
|
{'>', 145, 49, 11, 11, 0, 12},
|
||||||
|
{'?', 95, 34, 11, 15, 1, 14},
|
||||||
|
{'@', 0, 0, 19, 19, 0, 14},
|
||||||
|
{'A', 222, 0, 14, 15, 1, 14},
|
||||||
|
{'B', 48, 34, 12, 15, 0, 14},
|
||||||
|
{'C', 236, 0, 14, 15, 0, 14},
|
||||||
|
{'D', 70, 19, 13, 15, 0, 14},
|
||||||
|
{'E', 60, 34, 12, 15, 0, 14},
|
||||||
|
{'F', 72, 34, 12, 15, 0, 14},
|
||||||
|
{'G', 0, 19, 14, 15, 0, 14},
|
||||||
|
{'H', 83, 19, 13, 15, 0, 14},
|
||||||
|
{'I', 210, 34, 5, 15, 0, 14},
|
||||||
|
{'J', 139, 34, 10, 15, 1, 14},
|
||||||
|
{'K', 96, 19, 13, 15, 0, 14},
|
||||||
|
{'L', 106, 34, 11, 15, 0, 14},
|
||||||
|
{'M', 178, 0, 15, 15, 0, 14},
|
||||||
|
{'N', 109, 19, 13, 15, 0, 14},
|
||||||
|
{'O', 193, 0, 15, 15, 0, 14},
|
||||||
|
{'P', 122, 19, 13, 15, 0, 14},
|
||||||
|
{'Q', 83, 0, 16, 16, 1, 14},
|
||||||
|
{'R', 14, 19, 14, 15, 0, 14},
|
||||||
|
{'S', 135, 19, 13, 15, 1, 14},
|
||||||
|
{'T', 148, 19, 13, 15, 1, 14},
|
||||||
|
{'U', 161, 19, 13, 15, 0, 14},
|
||||||
|
{'V', 28, 19, 14, 15, 1, 14},
|
||||||
|
{'W', 143, 0, 19, 15, 1, 14},
|
||||||
|
{'X', 42, 19, 14, 15, 1, 14},
|
||||||
|
{'Y', 56, 19, 14, 15, 1, 14},
|
||||||
|
{'Z', 174, 19, 13, 15, 1, 14},
|
||||||
|
{'[', 49, 0, 6, 19, 0, 14},
|
||||||
|
{'\\', 191, 34, 7, 15, 1, 14},
|
||||||
|
{']', 55, 0, 6, 19, 1, 14},
|
||||||
|
{'^', 172, 49, 10, 9, 1, 14},
|
||||||
|
{'_', 232, 49, 14, 4, 2, -1},
|
||||||
|
{'`', 5, 61, 5, 4, 0, 14},
|
||||||
|
{'a', 15, 49, 12, 12, 1, 11},
|
||||||
|
{'b', 117, 34, 11, 15, 0, 14},
|
||||||
|
{'c', 51, 49, 11, 12, 1, 11},
|
||||||
|
{'d', 128, 34, 11, 15, 1, 14},
|
||||||
|
{'e', 27, 49, 12, 12, 1, 11},
|
||||||
|
{'f', 169, 34, 8, 15, 1, 14},
|
||||||
|
{'g', 99, 0, 11, 16, 1, 11},
|
||||||
|
{'h', 149, 34, 10, 15, 0, 14},
|
||||||
|
{'i', 215, 34, 4, 15, 0, 14},
|
||||||
|
{'j', 61, 0, 6, 19, 2, 14},
|
||||||
|
{'k', 159, 34, 10, 15, 0, 14},
|
||||||
|
{'l', 219, 34, 4, 15, 0, 14},
|
||||||
|
{'m', 228, 34, 15, 12, 0, 11},
|
||||||
|
{'n', 106, 49, 10, 12, 0, 11},
|
||||||
|
{'o', 39, 49, 12, 12, 1, 11},
|
||||||
|
{'p', 110, 0, 11, 16, 0, 11},
|
||||||
|
{'q', 121, 0, 11, 16, 1, 11},
|
||||||
|
{'r', 126, 49, 8, 12, 0, 11},
|
||||||
|
{'s', 62, 49, 11, 12, 1, 11},
|
||||||
|
{'t', 198, 34, 7, 15, 1, 14},
|
||||||
|
{'u', 116, 49, 10, 12, 0, 11},
|
||||||
|
{'v', 73, 49, 11, 12, 1, 11},
|
||||||
|
{'w', 0, 49, 15, 12, 1, 11},
|
||||||
|
{'x', 84, 49, 11, 12, 1, 11},
|
||||||
|
{'y', 132, 0, 11, 16, 1, 11},
|
||||||
|
{'z', 95, 49, 11, 12, 1, 11},
|
||||||
|
{'{', 19, 0, 8, 19, 1, 14},
|
||||||
|
{'|', 67, 0, 4, 19, 0, 14},
|
||||||
|
{'}', 27, 0, 8, 19, 1, 14},
|
||||||
|
{'~', 220, 49, 12, 5, 1, 9},
|
||||||
|
};
|
||||||
|
|
||||||
|
static Font font_Arial = { "Arial", 18, 0, 0, 256, 128, 95, characters_Arial };
|
29
src/engine/render/ui.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/maths.h>
|
||||||
|
|
||||||
|
#define MAX_UI_VERTICES 2048 * 4
|
||||||
|
#define MAX_UI_INDICES 2048 * 4
|
||||||
|
|
||||||
|
class Texture2D;
|
||||||
|
|
||||||
|
struct UIVertex
|
||||||
|
{
|
||||||
|
Vec2 position;
|
||||||
|
Vec2 uv;
|
||||||
|
Vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
void uiInit();
|
||||||
|
void uiShutdown();
|
||||||
|
|
||||||
|
void uiBeginRender();
|
||||||
|
|
||||||
|
void uiDrawQuad(const Vec2& a, const Vec2& b, const Vec2& c, const Vec2& d, const Vec4& color);
|
||||||
|
void uiDrawLines(const Vec2* drawPoints, const size_t pointsCount, bool closed, const Vec4& color);
|
||||||
|
void uiDrawRect(const Vec2& position, const Vec2& size, const Vec4& color);
|
||||||
|
|
||||||
|
void uiSetTexture(Texture2D* texture);
|
||||||
|
void uiSetTextureByName(const char* filename);
|
||||||
|
|
||||||
|
void uiEndRender();
|
62
src/engine/render/vertexbuffer.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#include "render/vertexbuffer.h"
|
||||||
|
#include "render/gl_shared.h"
|
||||||
|
|
||||||
|
VertexBuffer::VertexBuffer(void* data, size_t size, bool isStream /*= false*/)
|
||||||
|
{
|
||||||
|
glGenBuffers(1, &m_buffer);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, size, data, isStream ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
//if (isStream) {
|
||||||
|
// Logger::msg("created dynamic vertex stream ...");
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBuffer::~VertexBuffer()
|
||||||
|
{
|
||||||
|
glDeleteBuffers(1, &m_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBuffer::Bind()
|
||||||
|
{
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* VertexBuffer::MapBuffer(BufferAccess access)
|
||||||
|
{
|
||||||
|
GLenum accessGl = 0;
|
||||||
|
|
||||||
|
switch (access)
|
||||||
|
{
|
||||||
|
case BufferAccess::READ_ONLY:
|
||||||
|
accessGl = GL_READ_ONLY;
|
||||||
|
break;
|
||||||
|
case BufferAccess::WRITE_ONLY:
|
||||||
|
accessGl = GL_WRITE_ONLY;
|
||||||
|
break;
|
||||||
|
case BufferAccess::READ_WRITE:
|
||||||
|
accessGl = GL_READ_WRITE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Bind();
|
||||||
|
|
||||||
|
void* ptr = glMapBuffer(GL_ARRAY_BUFFER, accessGl);
|
||||||
|
|
||||||
|
//check_for_opengl_error();
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBuffer::UnmapBuffer()
|
||||||
|
{
|
||||||
|
Bind();
|
||||||
|
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBuffer::UpdateBuffer(void* data, size_t size)
|
||||||
|
{
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, size, data, GL_DYNAMIC_DRAW);
|
||||||
|
GL_CHECK_ERROR();
|
||||||
|
}
|
28
src/engine/render/vertexbuffer.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#ifndef VERTEXOBJECT_H
|
||||||
|
#define VERTEXOBJECT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "render/render_shared.h"
|
||||||
|
|
||||||
|
class RenderDevice;
|
||||||
|
|
||||||
|
class VertexBuffer
|
||||||
|
{
|
||||||
|
friend class RenderDevice;
|
||||||
|
public:
|
||||||
|
~VertexBuffer();
|
||||||
|
|
||||||
|
void Bind();
|
||||||
|
|
||||||
|
void* MapBuffer(BufferAccess access);
|
||||||
|
void UnmapBuffer();
|
||||||
|
|
||||||
|
void UpdateBuffer(void* data, size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
VertexBuffer(void* data, size_t size, bool isStream = false);
|
||||||
|
|
||||||
|
uint32_t m_buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // !VERTEXOBJECT_H
|
3
src/engine/sound/sound_system.cpp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "sound_system.h"
|
||||||
|
|
||||||
|
ISoundSystem* g_soundSystem = nullptr;
|
53
src/engine/sound/sound_system.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef SOUND_SYSTEM_H
|
||||||
|
#define SOUND_SYSTEM_H
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
class ISound
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ISound () { }
|
||||||
|
|
||||||
|
virtual void play () = 0;
|
||||||
|
virtual void Stop () = 0;
|
||||||
|
virtual void Pause () = 0;
|
||||||
|
|
||||||
|
virtual bool isPlaying () const = 0;
|
||||||
|
virtual bool isPaused () const = 0;
|
||||||
|
|
||||||
|
virtual bool IsLooped () const = 0;
|
||||||
|
virtual void SetLooped (bool bLooped) = 0;
|
||||||
|
|
||||||
|
virtual float GetVolume () const = 0;
|
||||||
|
virtual void SetVolume (float fVolume) = 0;
|
||||||
|
|
||||||
|
virtual void OnFrame (float delta) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef unsigned int SoundDeviceID;
|
||||||
|
|
||||||
|
class ISoundSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ISoundSystem () { }
|
||||||
|
|
||||||
|
virtual void selectDevice (SoundDeviceID deviceId) = 0;
|
||||||
|
virtual SoundDeviceID selectedDevice () const = 0;
|
||||||
|
|
||||||
|
virtual ISound* CreateSound (const char* sSoundFile) = 0;
|
||||||
|
virtual void DestroySound (ISound*& pSound) = 0;
|
||||||
|
|
||||||
|
virtual void Update (float delta) = 0;
|
||||||
|
|
||||||
|
virtual void StopAllSounds () = 0;
|
||||||
|
virtual void PauseAllSounds () = 0;
|
||||||
|
virtual void ReleaseAllSounds() = 0;
|
||||||
|
|
||||||
|
virtual float GetMasterVolume () const = 0;
|
||||||
|
virtual void SetMasterVolume (float fVolume) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ISoundSystem* CreateSoundSystem_DirectSound(void* wndHandle);
|
||||||
|
|
||||||
|
extern ISoundSystem* g_soundSystem;
|
||||||
|
|
||||||
|
#endif
|
0
src/engine/sound/sound_system_null.cpp
Normal file
378
src/engine/sound/soundsys_dsound.cpp
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "filesystem/stream.h"
|
||||||
|
#include "filesystem/filemanager.h"
|
||||||
|
#include "sound/sound_system.h"
|
||||||
|
|
||||||
|
#undef Msg
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <mmeapi.h>
|
||||||
|
#include <dsound.h>
|
||||||
|
|
||||||
|
#pragma comment(lib, "dsound.lib")
|
||||||
|
|
||||||
|
IDirectSound8* g_DirectSound = nullptr;
|
||||||
|
IDirectSoundBuffer* g_PrimaryBuffer = nullptr;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Sound implementation
|
||||||
|
|
||||||
|
class Sound_DSound_Impl : public ISound
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sound_DSound_Impl(const char* sSoundFile);
|
||||||
|
~Sound_DSound_Impl();
|
||||||
|
|
||||||
|
void play() override;
|
||||||
|
void Stop() override;
|
||||||
|
void Pause() override;
|
||||||
|
|
||||||
|
bool isPlaying() const override;
|
||||||
|
bool isPaused() const override;
|
||||||
|
|
||||||
|
bool IsLooped() const override;
|
||||||
|
void SetLooped(bool bLooped) override;
|
||||||
|
|
||||||
|
float GetVolume() const override;
|
||||||
|
void SetVolume(float fVolume) override;
|
||||||
|
|
||||||
|
void OnFrame(float delta) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
IDirectSoundBuffer8* m_pBuffer;
|
||||||
|
bool m_IsLopped;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sound_DSound_Impl::Sound_DSound_Impl(const char* sSoundFile) : m_pBuffer(nullptr), m_IsLopped(false)
|
||||||
|
{
|
||||||
|
if (!strstr(sSoundFile, ".wav"))
|
||||||
|
Logger::error("Failed to load sound file '%s'. Only wav supported", sSoundFile);
|
||||||
|
|
||||||
|
StreamBase* pStream = g_fileManager->OpenStream( sSoundFile, FileAccess::Read );
|
||||||
|
assert( pStream );
|
||||||
|
|
||||||
|
pStream->seek(SeekDir::End, 0);
|
||||||
|
size_t length = pStream->tell();
|
||||||
|
pStream->seek(SeekDir::Begin, 0);
|
||||||
|
|
||||||
|
uint8_t* filedata = (uint8_t*)malloc(length);
|
||||||
|
pStream->readBuffer(filedata, length);
|
||||||
|
|
||||||
|
delete pStream;
|
||||||
|
pStream = nullptr;
|
||||||
|
|
||||||
|
DSBUFFERDESC bufferDesc = {};
|
||||||
|
|
||||||
|
|
||||||
|
//g_DirectSound->CreateSoundBuffer( as )
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Sound_DSound_Impl::~Sound_DSound_Impl()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound_DSound_Impl::play()
|
||||||
|
{
|
||||||
|
m_pBuffer->Play(0, 0, m_IsLopped ? DSBPLAY_LOOPING : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound_DSound_Impl::Stop()
|
||||||
|
{
|
||||||
|
m_pBuffer->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound_DSound_Impl::Pause()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sound_DSound_Impl::isPlaying() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sound_DSound_Impl::isPaused() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sound_DSound_Impl::IsLooped() const
|
||||||
|
{
|
||||||
|
return m_IsLopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound_DSound_Impl::SetLooped(bool bLooped)
|
||||||
|
{
|
||||||
|
m_IsLopped = bLooped;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Sound_DSound_Impl::GetVolume() const
|
||||||
|
{
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound_DSound_Impl::SetVolume(float fVolume)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sound_DSound_Impl::OnFrame(float delta)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//bool cSoundBuffer::SetVolume(short percent)
|
||||||
|
//{
|
||||||
|
// long Volume;
|
||||||
|
// if (m_buffer == NULL)
|
||||||
|
// return false;
|
||||||
|
//
|
||||||
|
// if (!percent)
|
||||||
|
// Volume = DSBVOLUME_MIN;
|
||||||
|
// else
|
||||||
|
// Volume = -20 * (100 - (percent % 101));
|
||||||
|
//
|
||||||
|
// if (FAILED(m_buffer->SetVolume(Volume)))
|
||||||
|
// return false; return true;
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//bool cSoundBuffer::SetPan(signed long level)
|
||||||
|
//{
|
||||||
|
// signed long Pan;
|
||||||
|
//
|
||||||
|
// if (m_buffer == NULL)
|
||||||
|
// return false;
|
||||||
|
//
|
||||||
|
// if (level < 0)
|
||||||
|
// Pan = DSBPAN_LEFT / 100 * ((-level) % 101);
|
||||||
|
// else
|
||||||
|
// Pan = DSBPAN_RIGHT / 100 * (level % 101);
|
||||||
|
//
|
||||||
|
// if (FAILED(m_buffer->SetPan(Pan)))
|
||||||
|
// return false;
|
||||||
|
//
|
||||||
|
// return true;
|
||||||
|
//}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Sound System implementation
|
||||||
|
|
||||||
|
class SoundSystem_DSound : public ISoundSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SoundSystem_DSound(HWND hWndHandle);
|
||||||
|
~SoundSystem_DSound();
|
||||||
|
|
||||||
|
void InitPrimaryBuffer();
|
||||||
|
|
||||||
|
void selectDevice(SoundDeviceID deviceId) override;
|
||||||
|
SoundDeviceID selectedDevice() const override;
|
||||||
|
|
||||||
|
ISound* CreateSound(const char* sSoundFile) override;
|
||||||
|
void DestroySound(ISound*& pSound) override;
|
||||||
|
|
||||||
|
void Update(float delta) override;
|
||||||
|
|
||||||
|
void StopAllSounds() override;
|
||||||
|
void PauseAllSounds() override;
|
||||||
|
void ReleaseAllSounds() override;
|
||||||
|
|
||||||
|
float GetMasterVolume() const override;
|
||||||
|
void SetMasterVolume(float fVolume) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector< Sound_DSound_Impl* > m_Sounds;
|
||||||
|
float m_MasterVolume;
|
||||||
|
};
|
||||||
|
|
||||||
|
SoundSystem_DSound::SoundSystem_DSound(HWND hWndHandle) :
|
||||||
|
m_MasterVolume(0.0f)
|
||||||
|
{
|
||||||
|
Logger::logPrint("Starting SOUND system ...");
|
||||||
|
|
||||||
|
HRESULT hr = DirectSoundCreate8(NULL, &g_DirectSound, NULL);
|
||||||
|
if (FAILED(hr))
|
||||||
|
Logger::error("Failed to initialize DirectSound");
|
||||||
|
|
||||||
|
// Set cooperative level to the engine window
|
||||||
|
hr = g_DirectSound->SetCooperativeLevel(hWndHandle, DSSCL_PRIORITY);
|
||||||
|
if (FAILED(hr))
|
||||||
|
Logger::error("g_DirectSound->SetCooperativeLevel(...) Failed!");
|
||||||
|
|
||||||
|
InitPrimaryBuffer();
|
||||||
|
|
||||||
|
Logger::logPrint("SoundSystem_DSound: Created device successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundSystem_DSound::~SoundSystem_DSound()
|
||||||
|
{
|
||||||
|
ReleaseAllSounds();
|
||||||
|
|
||||||
|
if (g_PrimaryBuffer)
|
||||||
|
{
|
||||||
|
g_PrimaryBuffer->Release();
|
||||||
|
g_PrimaryBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_DirectSound)
|
||||||
|
{
|
||||||
|
g_DirectSound->Release();
|
||||||
|
g_DirectSound = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundSystem_DSound::InitPrimaryBuffer()
|
||||||
|
{
|
||||||
|
// Create primary buffer.
|
||||||
|
DSBUFFERDESC dsbd;
|
||||||
|
memset(&dsbd, 0, sizeof(DSBUFFERDESC));
|
||||||
|
dsbd.dwSize = sizeof(DSBUFFERDESC);
|
||||||
|
dsbd.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
|
||||||
|
dsbd.dwBufferBytes = 0;
|
||||||
|
|
||||||
|
HRESULT hr = g_DirectSound->CreateSoundBuffer(&dsbd, &g_PrimaryBuffer, NULL);
|
||||||
|
if (FAILED(hr))
|
||||||
|
Logger::error("SoundSystem_DSound::InitPrimaryBuffer: Failed to create primary buffer");
|
||||||
|
|
||||||
|
const int bitCount = 16;
|
||||||
|
const int channelCount = 2;
|
||||||
|
const int sampleRate22k = 22050;
|
||||||
|
const int sampleRate44k = 44100;
|
||||||
|
|
||||||
|
// calculate buffer format
|
||||||
|
|
||||||
|
WAVEFORMATEX waveFormat;
|
||||||
|
memset(&waveFormat, 0, sizeof(waveFormat));
|
||||||
|
waveFormat.cbSize = sizeof(WAVEFORMATEX);
|
||||||
|
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
waveFormat.nChannels = channelCount;
|
||||||
|
waveFormat.nSamplesPerSec = sampleRate44k;
|
||||||
|
waveFormat.nBlockAlign = channelCount * bitCount / 8;
|
||||||
|
waveFormat.nAvgBytesPerSec = sampleRate44k * waveFormat.nBlockAlign;
|
||||||
|
waveFormat.wBitsPerSample = sampleRate44k;
|
||||||
|
|
||||||
|
// For safety only :)
|
||||||
|
g_PrimaryBuffer->SetFormat(&waveFormat);
|
||||||
|
g_PrimaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
|
||||||
|
|
||||||
|
Logger::logPrint("SoundSystem_DSound::InitPrimaryBuffer: Created primary buffer with %i sample rate", waveFormat.nSamplesPerSec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundSystem_DSound::selectDevice(SoundDeviceID deviceId)
|
||||||
|
{
|
||||||
|
// Stub method
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundDeviceID SoundSystem_DSound::selectedDevice() const
|
||||||
|
{
|
||||||
|
// Stub method
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SOUND Creation
|
||||||
|
|
||||||
|
ISound* SoundSystem_DSound::CreateSound(const char* sSoundFile)
|
||||||
|
{
|
||||||
|
Sound_DSound_Impl* pSoundImpl = new Sound_DSound_Impl(sSoundFile);
|
||||||
|
m_Sounds.push_back(pSoundImpl);
|
||||||
|
return pSoundImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundSystem_DSound::DestroySound(ISound*& pSound)
|
||||||
|
{
|
||||||
|
// find sound in the cache
|
||||||
|
|
||||||
|
std::vector< Sound_DSound_Impl* >::iterator it = std::find(m_Sounds.begin(), m_Sounds.end(), pSound);
|
||||||
|
if (it != m_Sounds.end())
|
||||||
|
{
|
||||||
|
m_Sounds.erase( it );
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete sound
|
||||||
|
delete pSound;
|
||||||
|
pSound = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG dsu_CalcVolume(const float Volume)
|
||||||
|
{
|
||||||
|
LONG Result = 0;
|
||||||
|
if (Volume == 0)
|
||||||
|
Result = -10000;
|
||||||
|
else
|
||||||
|
Result = -round(1000 * log(1 / Volume));
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundSystem_DSound::Update(float delta)
|
||||||
|
{
|
||||||
|
if (!g_PrimaryBuffer)
|
||||||
|
Logger::error("SoundSystem_DSound::Update: Canno't update sound system without primary buffer.");
|
||||||
|
|
||||||
|
g_PrimaryBuffer->SetVolume(dsu_CalcVolume(m_MasterVolume));
|
||||||
|
|
||||||
|
int soundsNbr = m_Sounds.size();
|
||||||
|
for (int i = 0; i < soundsNbr; i++)
|
||||||
|
{
|
||||||
|
// Sanity check
|
||||||
|
if (m_Sounds[i])
|
||||||
|
m_Sounds[i]->OnFrame( delta );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundSystem_DSound::StopAllSounds()
|
||||||
|
{
|
||||||
|
int soundsNbr = m_Sounds.size();
|
||||||
|
for (int i = 0; i < soundsNbr; i++)
|
||||||
|
{
|
||||||
|
// Sanity check
|
||||||
|
if (m_Sounds[i])
|
||||||
|
m_Sounds[i]->Stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundSystem_DSound::PauseAllSounds()
|
||||||
|
{
|
||||||
|
int soundsNbr = m_Sounds.size();
|
||||||
|
for (int i = 0; i < soundsNbr; i++)
|
||||||
|
{
|
||||||
|
// Sanity check
|
||||||
|
if (m_Sounds[i])
|
||||||
|
m_Sounds[i]->Pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundSystem_DSound::ReleaseAllSounds()
|
||||||
|
{
|
||||||
|
int soundsNbr = m_Sounds.size();
|
||||||
|
for (int i = 0; i < soundsNbr; i++)
|
||||||
|
{
|
||||||
|
if (m_Sounds[i])
|
||||||
|
{
|
||||||
|
delete m_Sounds[i];
|
||||||
|
m_Sounds[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Sounds.clear();
|
||||||
|
|
||||||
|
Logger::logPrint("SoundSystem_DSound::ReleaseAllSounds: Cleared %i sounds", soundsNbr);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SoundSystem_DSound::GetMasterVolume() const
|
||||||
|
{
|
||||||
|
return m_MasterVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundSystem_DSound::SetMasterVolume(float fVolume)
|
||||||
|
{
|
||||||
|
m_MasterVolume = fVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sound System Factory
|
||||||
|
ISoundSystem* CreateSoundSystem_DirectSound(void* wndHandle)
|
||||||
|
{
|
||||||
|
return new SoundSystem_DSound( (HWND)wndHandle );
|
||||||
|
}
|
105
src/engine/utils/logger.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include "utils/logger.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static FILE* s_logFileHandle = nullptr;
|
||||||
|
static DWORD s_logOpenTime = 0;
|
||||||
|
|
||||||
|
void logWriteMsg(const char* msg)
|
||||||
|
{
|
||||||
|
DWORD dwCurrentTime = GetTickCount() - s_logOpenTime;
|
||||||
|
|
||||||
|
static char buffer[1024];
|
||||||
|
int len = sprintf(buffer, "%02lu:%02lu.%02lu: %s",
|
||||||
|
dwCurrentTime / 60000, dwCurrentTime / 1000 % 60, dwCurrentTime % 1000 / 10, msg);
|
||||||
|
|
||||||
|
if (s_logFileHandle)
|
||||||
|
{
|
||||||
|
fwrite(buffer, sizeof(char), len, s_logFileHandle);
|
||||||
|
fflush(s_logFileHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::init()
|
||||||
|
{
|
||||||
|
s_logFileHandle = fopen("output.txt", "w");
|
||||||
|
assert(s_logFileHandle);
|
||||||
|
|
||||||
|
struct tm newtime;
|
||||||
|
__time32_t aclock;
|
||||||
|
|
||||||
|
char buffer[32];
|
||||||
|
_time32(&aclock);
|
||||||
|
_localtime32_s(&newtime, &aclock);
|
||||||
|
errno_t errNum = asctime_s(buffer, 32, &newtime);
|
||||||
|
|
||||||
|
char timeBuffer[1024];
|
||||||
|
int len = sprintf(timeBuffer, "Log started: %s", buffer);
|
||||||
|
|
||||||
|
fwrite(timeBuffer, sizeof(char), len, s_logFileHandle);
|
||||||
|
|
||||||
|
s_logOpenTime = GetTickCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::shutdown()
|
||||||
|
{
|
||||||
|
if (s_logFileHandle)
|
||||||
|
{
|
||||||
|
fclose(s_logFileHandle);
|
||||||
|
s_logFileHandle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::logPrint(const char* msg, ...)
|
||||||
|
{
|
||||||
|
static char buffer[2048 * 2];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
vsnprintf(buffer, sizeof(buffer), msg, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
strcat(buffer, "\n");
|
||||||
|
|
||||||
|
OutputDebugStringA(buffer);
|
||||||
|
|
||||||
|
// write to console
|
||||||
|
fwrite(buffer, sizeof(char), strlen(buffer), stdout);
|
||||||
|
|
||||||
|
logWriteMsg(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::error(const char* msg, ...)
|
||||||
|
{
|
||||||
|
static char buffer[2048 * 2];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
vsnprintf(buffer, sizeof(buffer), msg, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
strcat(buffer, "\n");
|
||||||
|
|
||||||
|
OutputDebugStringA(buffer);
|
||||||
|
|
||||||
|
// write to console
|
||||||
|
fwrite(buffer, sizeof(char), strlen(buffer), stdout);
|
||||||
|
|
||||||
|
logWriteMsg(buffer);
|
||||||
|
|
||||||
|
MessageBoxA(NULL, buffer, "Engine Error", MB_OK | MB_ICONERROR);
|
||||||
|
|
||||||
|
if (IsDebuggerPresent())
|
||||||
|
DebugBreak();
|
||||||
|
//else
|
||||||
|
exit(-1);
|
||||||
|
}
|
16
src/engine/utils/logger.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef LOGGER_H
|
||||||
|
#define LOGGER_H
|
||||||
|
|
||||||
|
class Logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void init();
|
||||||
|
static void shutdown();
|
||||||
|
static void logPrint(const char* msg, ...);
|
||||||
|
static void error(const char* msg, ...);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define Msg Logger::logPrint
|
||||||
|
#define LogPrint Logger::logPrint
|
||||||
|
|
||||||
|
#endif // !LOGGER_H
|
61
src/engine/utils/maths.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#include <utils/maths.h>
|
||||||
|
|
||||||
|
Vec3 g_zeroVector = Vec3(0.0f, 0.0f, 0.0f);
|
||||||
|
Vec3 g_identityVector = Vec3(1.0f, 1.0f, 1.0f);
|
||||||
|
Matrix g_identityMatrix = { 1.0f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 0.0f, 1.0f };
|
||||||
|
|
||||||
|
BoundingBox g_identityBoundingBox = { { -0.1f, -0.1f, -0.1f }, { 0.1f, 0.1f, 0.1f } };
|
||||||
|
|
||||||
|
void TransformBoundingBox(BoundingBox& bbox, const glm::mat4& model)
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// transform to center/extents box representation
|
||||||
|
glm::vec3 center = (bbox.max + bbox.min) * glm::vec3(0.5);
|
||||||
|
glm::vec3 extents = bbox.max - center;
|
||||||
|
|
||||||
|
// transform center
|
||||||
|
glm::vec3 t_center = glm::vec3(model * glm::vec4(center, 1.0));
|
||||||
|
|
||||||
|
// transform extents (take maximum)
|
||||||
|
glm::mat3 abs_mat = glm::mat3(abs(glm::vec3(model[0])), abs(glm::vec3(model[1])), abs(glm::vec3(model[2])));
|
||||||
|
glm::vec3 t_extents = abs_mat * extents;
|
||||||
|
|
||||||
|
// transform to min/max box representation
|
||||||
|
glm::vec3 tmin = t_center - t_extents;
|
||||||
|
glm::vec3 tmax = t_center + t_extents;
|
||||||
|
|
||||||
|
bbox.min = tmin;
|
||||||
|
bbox.max = tmax;
|
||||||
|
#else
|
||||||
|
|
||||||
|
glm::mat3 M(model);
|
||||||
|
|
||||||
|
// Split the transform into a translation vector (T) and a 3x3 rotation (M).
|
||||||
|
BoundingBox B = {}; // zero-volume AABB at T
|
||||||
|
for (int i = 0, j = 0; i < 3, j < 3; i++, j++)
|
||||||
|
{
|
||||||
|
float a = M[i][j] * bbox.min[j];
|
||||||
|
float b = M[i][j] * bbox.max[j];
|
||||||
|
B.min[i] += a < b ? a : b;
|
||||||
|
B.max[i] += a < b ? b : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
bbox.min = B.min;
|
||||||
|
bbox.max = B.max;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransformOBB(OBB& obb, const BoundingBox& bbox, const glm::mat4& model)
|
||||||
|
{
|
||||||
|
// transform to center/extents box representation
|
||||||
|
glm::vec3 center = (bbox.max + bbox.min) * glm::vec3(0.5);
|
||||||
|
glm::vec3 extents = bbox.max - center;
|
||||||
|
|
||||||
|
// transform center
|
||||||
|
glm::vec3 t_center = glm::vec3(model * glm::vec4(center, 1.0));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
339
src/engine/utils/maths.h
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
// maths.h - Simple mathematics library with aggressive inlining.
|
||||||
|
#ifndef MATHS_H
|
||||||
|
#define MATHS_H
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
// Define M_PI
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846 // pi
|
||||||
|
#endif // !M_PI
|
||||||
|
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtx/transform.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
#include <glm/gtx/rotate_vector.hpp>
|
||||||
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
|
||||||
|
#pragma warning( disable : 4244 )
|
||||||
|
|
||||||
|
struct Point2
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vec2
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
|
||||||
|
Vec2() : x(0.0f), y(0.0f) {}
|
||||||
|
Vec2(float _val) : x(_val), y(_val) {}
|
||||||
|
Vec2(float _x, float _y) : x(_x), y(_y) {}
|
||||||
|
|
||||||
|
// Vec2 with Vec2 operations
|
||||||
|
|
||||||
|
inline Vec2 operator+(const Vec2& rhs) const { return Vec2(x + rhs.x, y + rhs.y); }
|
||||||
|
inline Vec2 operator-(const Vec2& rhs) const { return Vec2(x - rhs.x, y - rhs.y); }
|
||||||
|
inline Vec2 operator*(const Vec2& rhs) const { return Vec2(x * rhs.x, y * rhs.y); }
|
||||||
|
inline Vec2 operator/(const Vec2& rhs) const { return Vec2(x / rhs.x, y / rhs.y); }
|
||||||
|
|
||||||
|
inline Vec2& operator+=(const Vec2& rhs) { *this = *this + rhs; return *this; }
|
||||||
|
inline Vec2& operator*=(const Vec2& rhs) { *this = *this * rhs; return *this; }
|
||||||
|
inline Vec2& operator-=(const Vec2& rhs) { *this = *this - rhs; return *this; }
|
||||||
|
inline Vec2& operator/=(const Vec2& rhs) { *this = *this / rhs; return *this; }
|
||||||
|
|
||||||
|
// Vec2 with Scalar operations
|
||||||
|
|
||||||
|
inline Vec2 operator+(const float s) const { return Vec2(x + s, y + s); }
|
||||||
|
inline Vec2 operator-(const float s) const { return Vec2(x - s, y - s); }
|
||||||
|
inline Vec2 operator*(const float s) const { return Vec2(x * s, y * s); }
|
||||||
|
inline Vec2 operator/(const float s) const { return Vec2(x / s, y / s); }
|
||||||
|
|
||||||
|
inline Vec2& operator+=(const float s) { *this = *this + s; return *this; }
|
||||||
|
inline Vec2& operator*=(const float s) { *this = *this * s; return *this; }
|
||||||
|
inline Vec2& operator-=(const float s) { *this = *this - s; return *this; }
|
||||||
|
inline Vec2& operator/=(const float s) { *this = *this / s; return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vec3
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
|
||||||
|
Vec3() : x(0.0f), y(0.0f), z(0.0f) {}
|
||||||
|
Vec3(float _val) : x(_val), y(_val), z(_val) {}
|
||||||
|
Vec3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
|
||||||
|
|
||||||
|
// Vec3 with Vec2 operations
|
||||||
|
|
||||||
|
inline Vec3 operator+(const Vec2& rhs) const { return Vec3(x + rhs.x, y + rhs.y, z); }
|
||||||
|
inline Vec3 operator-(const Vec2& rhs) const { return Vec3(x - rhs.x, y - rhs.y, z); }
|
||||||
|
inline Vec3 operator*(const Vec2& rhs) const { return Vec3(x * rhs.x, y * rhs.y, z); }
|
||||||
|
inline Vec3 operator/(const Vec2& rhs) const { return Vec3(x / rhs.x, y / rhs.y, z); }
|
||||||
|
|
||||||
|
inline Vec3& operator+=(const Vec2& rhs) { *this = *this + rhs; return *this; }
|
||||||
|
inline Vec3& operator*=(const Vec2& rhs) { *this = *this * rhs; return *this; }
|
||||||
|
inline Vec3& operator-=(const Vec2& rhs) { *this = *this - rhs; return *this; }
|
||||||
|
inline Vec3& operator/=(const Vec2& rhs) { *this = *this / rhs; return *this; }
|
||||||
|
|
||||||
|
// Vec3 with Vec3 operations
|
||||||
|
|
||||||
|
inline Vec3 operator+(const Vec3& rhs) const { return Vec3(x + rhs.x, y + rhs.y, z + rhs.z); }
|
||||||
|
inline Vec3 operator-(const Vec3& rhs) const { return Vec3(x - rhs.x, y - rhs.y, z - rhs.z); }
|
||||||
|
inline Vec3 operator*(const Vec3& rhs) const { return Vec3(x * rhs.x, y * rhs.y, z * rhs.z); }
|
||||||
|
inline Vec3 operator/(const Vec3& rhs) const { return Vec3(x / rhs.x, y / rhs.y, z / rhs.z); }
|
||||||
|
|
||||||
|
inline Vec3& operator+=(const Vec3& rhs) { *this = *this + rhs; return *this; }
|
||||||
|
inline Vec3& operator*=(const Vec3& rhs) { *this = *this * rhs; return *this; }
|
||||||
|
inline Vec3& operator-=(const Vec3& rhs) { *this = *this - rhs; return *this; }
|
||||||
|
inline Vec3& operator/=(const Vec3& rhs) { *this = *this / rhs; return *this; }
|
||||||
|
|
||||||
|
// Vec3 with Scalar operations
|
||||||
|
|
||||||
|
inline Vec3 operator+(const float s) const { return Vec3(x + s, y + s, z + s); }
|
||||||
|
inline Vec3 operator-(const float s) const { return Vec3(x - s, y - s, z - s); }
|
||||||
|
inline Vec3 operator*(const float s) const { return Vec3(x * s, y * s, z * s); }
|
||||||
|
inline Vec3 operator/(const float s) const { return Vec3(x / s, y / s, z / s); }
|
||||||
|
|
||||||
|
inline Vec3& operator+=(const float s) { *this = *this + s; return *this; }
|
||||||
|
inline Vec3& operator*=(const float s) { *this = *this * s; return *this; }
|
||||||
|
inline Vec3& operator-=(const float s) { *this = *this - s; return *this; }
|
||||||
|
inline Vec3& operator/=(const float s) { *this = *this / s; return *this; }
|
||||||
|
|
||||||
|
// Vec3 with GLM Vec3 operations (please delete someday :)
|
||||||
|
|
||||||
|
inline Vec3 operator+(const glm::vec3& rhs) const { return Vec3(x + rhs.x, y + rhs.y, z + rhs.z); }
|
||||||
|
inline Vec3 operator-(const glm::vec3& rhs) const { return Vec3(x - rhs.x, y - rhs.y, z - rhs.z); }
|
||||||
|
inline Vec3 operator*(const glm::vec3& rhs) const { return Vec3(x * rhs.x, y * rhs.y, z * rhs.z); }
|
||||||
|
inline Vec3 operator/(const glm::vec3& rhs) const { return Vec3(x / rhs.x, y / rhs.y, z / rhs.z); }
|
||||||
|
|
||||||
|
inline Vec3& operator+=(const glm::vec3& rhs) { *this = *this + rhs; return *this; }
|
||||||
|
inline Vec3& operator*=(const glm::vec3& rhs) { *this = *this * rhs; return *this; }
|
||||||
|
inline Vec3& operator-=(const glm::vec3& rhs) { *this = *this - rhs; return *this; }
|
||||||
|
inline Vec3& operator/=(const glm::vec3& rhs) { *this = *this / rhs; return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Vec3 g_zeroVector;
|
||||||
|
extern Vec3 g_identityVector;
|
||||||
|
|
||||||
|
struct Vec4
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
float w;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Vec3 operator+(const float s, const Vec3& v)
|
||||||
|
{
|
||||||
|
return Vec3(s + v.x, s + v.y, s + v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 operator-(const float s, const Vec3& v)
|
||||||
|
{
|
||||||
|
return Vec3(s - v.x, s - v.y, s - v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 operator*(const float s, const Vec3& v)
|
||||||
|
{
|
||||||
|
return Vec3(s * v.x, s * v.y, s * v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 operator/(const float s, const Vec3& v)
|
||||||
|
{
|
||||||
|
return Vec3(s / v.x, s / v.y, s / v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float lerp(float f, float a, float b)
|
||||||
|
{
|
||||||
|
return a * (1.0 - f) + (b * f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 lerp(float f, const Vec3& a, const Vec3& b)
|
||||||
|
{
|
||||||
|
return a * (1.0 - f) + (b * f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool GetBoxIntersection2D(const Vec2& boxAmins, const Vec2& boxAmaxs,
|
||||||
|
const Vec2& boxBmins, const Vec2& boxBmaxs)
|
||||||
|
{
|
||||||
|
float xMin1 = boxAmins.x;
|
||||||
|
float yMin1 = boxAmins.y;
|
||||||
|
|
||||||
|
float xMax1 = boxAmaxs.x;
|
||||||
|
float yMax1 = boxAmaxs.y;
|
||||||
|
|
||||||
|
float xMin2 = boxBmins.x;
|
||||||
|
float yMin2 = boxBmins.y;
|
||||||
|
|
||||||
|
float xMax2 = boxBmaxs.x;
|
||||||
|
float yMax2 = boxBmaxs.y;
|
||||||
|
|
||||||
|
if (xMin1 < xMax2 || xMax1 > xMin2)
|
||||||
|
return false;
|
||||||
|
if (yMin1 < yMax2 || yMax1 > yMin2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float DegtoRad(float _deg)
|
||||||
|
{
|
||||||
|
return _deg * M_PI / 180.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float RadtoDeg(float _rad)
|
||||||
|
{
|
||||||
|
return _rad / M_PI * 180.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 sub(const Vec3& _a, const Vec3& _b)
|
||||||
|
{
|
||||||
|
return Vec3(_a.x - _b.x, _a.y - _b.y, _a.z - _b.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 sub(const Vec3 _a, float _b)
|
||||||
|
{
|
||||||
|
return Vec3(_a.x - _b, _a.y - _b, _a.z - _b);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 mul(const Vec3& _a, const Vec3& _b)
|
||||||
|
{
|
||||||
|
return Vec3(_a.x * _b.x, _a.y * _b.y, _a.z * _b.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 mul(const Vec3& _a, float _b)
|
||||||
|
{
|
||||||
|
return Vec3(_a.x * _b, _a.y * _b, _a.z * _b);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float dot(const Vec3& _a, const Vec3& _b)
|
||||||
|
{
|
||||||
|
return _a.x * _b.x + _a.y * _b.y + _a.z * _b.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float length(const Vec3& _a)
|
||||||
|
{
|
||||||
|
return sqrt(dot(_a, _a));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 normalize(const Vec3& _a)
|
||||||
|
{
|
||||||
|
const float invLen = 1.0f / length(_a);
|
||||||
|
const Vec3 result = mul(_a, invLen);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 cross(const Vec3& _a, const Vec3& _b)
|
||||||
|
{
|
||||||
|
return Vec3(_a.y * _b.z - _a.z * _b.y, _a.z * _b.x - _a.x * _b.z, _a.x * _b.y - _a.y * _b.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matrix class
|
||||||
|
struct Matrix
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
float _11, _12, _13, _14;
|
||||||
|
float _21, _22, _23, _24;
|
||||||
|
float _31, _32, _33, _34;
|
||||||
|
float _41, _42, _43, _44;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
Vec3 i; float _14_;
|
||||||
|
Vec3 j; float _24_;
|
||||||
|
Vec3 k; float _34_;
|
||||||
|
Vec3 c; float _44_;
|
||||||
|
};
|
||||||
|
float m[4][4];
|
||||||
|
};
|
||||||
|
|
||||||
|
float* data() const { return (float*)this; }
|
||||||
|
float* operator()()const{ return (float*)this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
extern Matrix g_identityMatrix;
|
||||||
|
|
||||||
|
inline Matrix MakePerspective(float fovy, float aspect, float znear, float zfar)
|
||||||
|
{
|
||||||
|
Matrix M = {};
|
||||||
|
|
||||||
|
float f = 1.f / tanf(fovy / 2.f),
|
||||||
|
A = (zfar + znear) / (znear - zfar),
|
||||||
|
B = (2.f * zfar * znear) / (znear - zfar);
|
||||||
|
|
||||||
|
M._11 = f / aspect; M._12 = 0.f; M._13 = 0.f; M._14 = 0.f;
|
||||||
|
M._21 = 0.f; M._22 = f; M._23 = 0.f; M._24 = 0.f;
|
||||||
|
M._31 = 0.f; M._32 = 0.f; M._33 = A; M._34 = B;
|
||||||
|
M._41 = 0.f; M._42 = 0.f; M._43 = -1.f; M._44 = 0.f;
|
||||||
|
|
||||||
|
return M;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BoundingBox
|
||||||
|
{
|
||||||
|
glm::vec3 min;
|
||||||
|
glm::vec3 max;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OBB
|
||||||
|
{
|
||||||
|
BoundingBox bbox;
|
||||||
|
glm::mat4 rot;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern BoundingBox g_identityBoundingBox;
|
||||||
|
|
||||||
|
void TransformBoundingBox(BoundingBox& bbox, const glm::mat4& model);
|
||||||
|
void TransformOBB(OBB& obb, const BoundingBox& bbox, const glm::mat4& model);
|
||||||
|
|
||||||
|
inline bool GetBBoxIntersection3D(const BoundingBox& boxA, const BoundingBox& boxB)
|
||||||
|
{
|
||||||
|
return ((boxA.max.x >= boxB.min.x) && (boxA.min.x <= boxB.max.x) &&
|
||||||
|
(boxA.max.z >= boxB.min.z) && (boxA.min.z <= boxB.max.z) &&
|
||||||
|
(boxA.max.y >= boxB.min.y) && (boxA.min.y <= boxB.max.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool RayBoxIntersection(const Vec3& ray_pos, const Vec3& ray_dir, BoundingBox& box, float& tmin)
|
||||||
|
{
|
||||||
|
float lo = ray_dir.x * (box.min.x - ray_pos.x);
|
||||||
|
float hi = ray_dir.x * (box.max.x - ray_pos.x);
|
||||||
|
|
||||||
|
float tmax;
|
||||||
|
tmin = fminf(lo, hi);
|
||||||
|
tmax = fmaxf(lo, hi);
|
||||||
|
|
||||||
|
float lo1 = ray_dir.y * (box.min.y - ray_pos.y);
|
||||||
|
float hi1 = ray_dir.y * (box.max.y - ray_pos.y);
|
||||||
|
|
||||||
|
tmin = fmaxf(tmin, fminf(lo1, hi1));
|
||||||
|
tmax = fminf(tmax, fmaxf(lo1, hi1));
|
||||||
|
|
||||||
|
float lo2 = ray_dir.z * (box.min.z - ray_pos.z);
|
||||||
|
float hi2 = ray_dir.z * (box.max.z - ray_pos.z);
|
||||||
|
|
||||||
|
tmin = fmaxf(tmin, fminf(lo2, hi2));
|
||||||
|
tmax = fminf(tmax, fmaxf(lo2, hi2));
|
||||||
|
|
||||||
|
return (tmin <= tmax) && (tmax > 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GLM Stuff
|
||||||
|
|
||||||
|
inline glm::vec3 ToGlm(const Vec3& v)
|
||||||
|
{
|
||||||
|
return glm::vec3(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vec3 ToEngine(const glm::vec3& v)
|
||||||
|
{
|
||||||
|
return Vec3(v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !MATHS_H
|
183
src/engine/utils/objectmanager.cpp
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "utils/objectmanager.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
|
||||||
|
ObjectManager g_ObjectManager;
|
||||||
|
|
||||||
|
ObjectManager::ObjectManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectManager::~ObjectManager()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectManager::Register( const RuntimeClass* _pRuntimeClass, IObjectConstructor* _pObjectConstructor )
|
||||||
|
{
|
||||||
|
// Find already registered object.
|
||||||
|
|
||||||
|
std::vector<ObjectRegistryEntry>::iterator it = std::find_if(
|
||||||
|
m_objectRegistry.begin(),
|
||||||
|
m_objectRegistry.end(),
|
||||||
|
[=]( const ObjectRegistryEntry& objectEntry )
|
||||||
|
{
|
||||||
|
return objectEntry.pRuntimeClass == _pRuntimeClass;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert( it == m_objectRegistry.end() );
|
||||||
|
|
||||||
|
ObjectRegistryEntry entry = {};
|
||||||
|
entry.pRuntimeClass = _pRuntimeClass;
|
||||||
|
entry.pObjectConstructor = _pObjectConstructor;
|
||||||
|
|
||||||
|
m_objectRegistry.push_back( entry );
|
||||||
|
|
||||||
|
Msg( "ObjectManager: Registered object %s", _pRuntimeClass->m_classname );
|
||||||
|
}
|
||||||
|
|
||||||
|
IObjectBase* ObjectManager::Create( const RuntimeClass* _pRuntimeClass )
|
||||||
|
{
|
||||||
|
// Find already registered object.
|
||||||
|
std::vector<ObjectRegistryEntry>::iterator it = std::find_if(
|
||||||
|
m_objectRegistry.begin(),
|
||||||
|
m_objectRegistry.end(),
|
||||||
|
[=]( const ObjectRegistryEntry& objectEntry )
|
||||||
|
{
|
||||||
|
return objectEntry.pRuntimeClass == _pRuntimeClass;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert( it != m_objectRegistry.end() );
|
||||||
|
|
||||||
|
IObjectConstructor* pObjectConstructor = it->pObjectConstructor;
|
||||||
|
assert( pObjectConstructor );
|
||||||
|
|
||||||
|
IObjectBase* pObject = pObjectConstructor->Create();
|
||||||
|
assert( pObject );
|
||||||
|
|
||||||
|
// Add reference
|
||||||
|
//pObject->AddRef();
|
||||||
|
|
||||||
|
return pObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
IObjectBase* ObjectManager::CreateByName( const char* _pClassName )
|
||||||
|
{
|
||||||
|
// Find already registered object.
|
||||||
|
std::vector<ObjectRegistryEntry>::iterator it = std::find_if(
|
||||||
|
m_objectRegistry.begin(),
|
||||||
|
m_objectRegistry.end(),
|
||||||
|
[=]( const ObjectRegistryEntry& objectEntry )
|
||||||
|
{
|
||||||
|
return strcmp( objectEntry.pRuntimeClass->Name(), _pClassName ) == 0;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assert( it != m_objectRegistry.end() );
|
||||||
|
|
||||||
|
IObjectConstructor* pObjectConstructor = it->pObjectConstructor;
|
||||||
|
assert( pObjectConstructor );
|
||||||
|
|
||||||
|
IObjectBase* pObject = pObjectConstructor->Create();
|
||||||
|
assert( pObject );
|
||||||
|
|
||||||
|
// Add reference
|
||||||
|
pObject->AddRef();
|
||||||
|
|
||||||
|
return pObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////
|
||||||
|
// Object System Test
|
||||||
|
|
||||||
|
class TestObject1 : public IObjectBase
|
||||||
|
{
|
||||||
|
DECLARE_RTTI_ROOT( TestObject1 );
|
||||||
|
public:
|
||||||
|
TestObject1();
|
||||||
|
virtual ~TestObject1();
|
||||||
|
|
||||||
|
virtual void Foo();
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_RTTI_ROOT( TestObject1 );
|
||||||
|
|
||||||
|
TestObject1::TestObject1()
|
||||||
|
{
|
||||||
|
Msg( "TestObject1: ctor called" );
|
||||||
|
}
|
||||||
|
|
||||||
|
TestObject1::~TestObject1()
|
||||||
|
{
|
||||||
|
Msg( "TestObject1: dtor called" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestObject1::Foo()
|
||||||
|
{
|
||||||
|
Msg( "TestObject1::Foo() called" );
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestObject2 : public TestObject1
|
||||||
|
{
|
||||||
|
DECLARE_RTTI(TestObject2, TestObject1);
|
||||||
|
public:
|
||||||
|
TestObject2();
|
||||||
|
~TestObject2();
|
||||||
|
|
||||||
|
void Foo() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_RTTI(TestObject2, TestObject1);
|
||||||
|
|
||||||
|
TestObject2::TestObject2()
|
||||||
|
{
|
||||||
|
Msg("TestObject2: ctor called");
|
||||||
|
}
|
||||||
|
|
||||||
|
TestObject2::~TestObject2()
|
||||||
|
{
|
||||||
|
Msg("TestObject2: dtor called");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestObject2::Foo()
|
||||||
|
{
|
||||||
|
Msg("TestObject2::Foo() called");
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestTPtr()
|
||||||
|
{
|
||||||
|
TPtr< TestObject1 > testObjectPtr = CreateObject<TestObject1>();
|
||||||
|
testObjectPtr->Foo();
|
||||||
|
|
||||||
|
TPtr< TestObject2 > testObject2 = CreateObject<TestObject2>();
|
||||||
|
testObject2->Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectSystemTest()
|
||||||
|
{
|
||||||
|
RegisterObject< TestObject1 >();
|
||||||
|
RegisterObject< TestObject2 >();
|
||||||
|
|
||||||
|
Msg( "Creating object" );
|
||||||
|
|
||||||
|
IObjectBase* pObject = g_ObjectManager.Create( RUNTIME_CLASS( TestObject1 ) );
|
||||||
|
pObject->AddRef();
|
||||||
|
|
||||||
|
if ( TestObject1* pTestObject = DynamicCast< TestObject1 >( pObject ) )
|
||||||
|
{
|
||||||
|
Msg( "DynamicCast for TestObject1 was successful" );
|
||||||
|
|
||||||
|
pTestObject->Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg( "Releasing object" );
|
||||||
|
|
||||||
|
pObject->Release();
|
||||||
|
|
||||||
|
TestTPtr();
|
||||||
|
|
||||||
|
}
|
348
src/engine/utils/objectmanager.h
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
#ifndef objectmanagerH_included
|
||||||
|
#define objectmanagerH_included
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <utils/rtti.h>
|
||||||
|
#include <utils/refcount.h>
|
||||||
|
|
||||||
|
// #TODO: Make IRefCount or templated class for AddRef\Release and Ref Counting implementation
|
||||||
|
|
||||||
|
// \brief Base interface for all objects.
|
||||||
|
class IObjectBase : public RefCount
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Virtual destructor
|
||||||
|
virtual ~IObjectBase() {}
|
||||||
|
|
||||||
|
// Get RuntimeClass.
|
||||||
|
virtual const RuntimeClass* GetRuntimeClass() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// \brief Dynamic Cast
|
||||||
|
template < typename T >
|
||||||
|
T* DynamicCast( IObjectBase* _pObject )
|
||||||
|
{
|
||||||
|
const RuntimeClass* pRuntimeClass = RUNTIME_CLASS( T );
|
||||||
|
|
||||||
|
if ( _pObject->GetRuntimeClass()->IsKindOf( pRuntimeClass ) )
|
||||||
|
return static_cast< T* >( _pObject );
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class _NoAddRefReleaseOnTPtr : public T
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
virtual uint64_t AddRef() = 0;
|
||||||
|
virtual uint64_t Release() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TPtrBase provides the basis for all other smart pointers
|
||||||
|
// The other smartpointers add their own constructors and operators
|
||||||
|
template <class T>
|
||||||
|
class TPtrBase
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
TPtrBase()
|
||||||
|
{
|
||||||
|
p = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TPtrBase(T* lp)
|
||||||
|
{
|
||||||
|
p = lp;
|
||||||
|
if (p != NULL)
|
||||||
|
p->AddRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef T _PtrClass;
|
||||||
|
|
||||||
|
~TPtrBase()
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
p->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T* () const
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator*() const
|
||||||
|
{
|
||||||
|
assert(p != NULL);
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
//The assert on operator& usually indicates a bug. If this is really
|
||||||
|
//what is needed, however, take the address of the p member explicitly.
|
||||||
|
T** operator&()
|
||||||
|
{
|
||||||
|
assert(p == NULL);
|
||||||
|
return &p;
|
||||||
|
}
|
||||||
|
|
||||||
|
_NoAddRefReleaseOnTPtr<T>* operator->() const
|
||||||
|
{
|
||||||
|
assert(p != NULL);
|
||||||
|
return (_NoAddRefReleaseOnTPtr<T>*)p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!() const
|
||||||
|
{
|
||||||
|
return (p == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(T* pT) const
|
||||||
|
{
|
||||||
|
return p < pT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(T* pT) const
|
||||||
|
{
|
||||||
|
return !operator==(pT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(T* pT) const
|
||||||
|
{
|
||||||
|
return p == pT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the interface and set to NULL
|
||||||
|
void Release()
|
||||||
|
{
|
||||||
|
T* pTemp = p;
|
||||||
|
if (pTemp)
|
||||||
|
{
|
||||||
|
p = NULL;
|
||||||
|
pTemp->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two objects for equivalence
|
||||||
|
bool IsEqualObject(IObjectBase* pOther)
|
||||||
|
{
|
||||||
|
if (p == NULL && pOther == NULL)
|
||||||
|
return true; // They are both NULL objects
|
||||||
|
|
||||||
|
if (p == NULL || pOther == NULL)
|
||||||
|
return false; // One is NULL the other is not
|
||||||
|
|
||||||
|
return p->GetRuntimeClass()->IsKindOf( pOther->GetRuntimeClass() );
|
||||||
|
|
||||||
|
/* CComPtr<IUnknown> punk1;
|
||||||
|
CComPtr<IUnknown> punk2;
|
||||||
|
p->QueryInterface(__uuidof(IUnknown), (void**)&punk1);
|
||||||
|
pOther->QueryInterface(__uuidof(IUnknown), (void**)&punk2);
|
||||||
|
return punk1 == punk2;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attach to an existing interface (does not AddRef)
|
||||||
|
void Attach(T* p2) throw()
|
||||||
|
{
|
||||||
|
if (p)
|
||||||
|
p->Release();
|
||||||
|
|
||||||
|
p = p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detach the interface (does not Release)
|
||||||
|
T* Detach() throw()
|
||||||
|
{
|
||||||
|
T* pt = p;
|
||||||
|
p = NULL;
|
||||||
|
return pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CopyTo(T** ppT)
|
||||||
|
{
|
||||||
|
assert(ppT != NULL);
|
||||||
|
if (ppT == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*ppT = p;
|
||||||
|
if (p)
|
||||||
|
p->AddRef();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//template <class Q>
|
||||||
|
//bool QueryInterface(__deref_out_opt Q** pp) const throw()
|
||||||
|
//{
|
||||||
|
// assert(pp != NULL);
|
||||||
|
//
|
||||||
|
// const RuntimeClass* pRuntimeClass = RUNTIME_CLASS( Q );
|
||||||
|
// if ( pRuntimeClass->IsKindOf( pRuntimeClass ) )
|
||||||
|
// return (Q*)p;
|
||||||
|
|
||||||
|
// return p->QueryInterface(__uuidof(Q), (void**)pp);
|
||||||
|
//}
|
||||||
|
|
||||||
|
T* p;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline IObjectBase* TPtrAssign(IObjectBase** pp, IObjectBase* lp)
|
||||||
|
{
|
||||||
|
if (pp == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (lp != NULL)
|
||||||
|
lp->AddRef();
|
||||||
|
|
||||||
|
if (*pp)
|
||||||
|
(*pp)->Release();
|
||||||
|
|
||||||
|
*pp = lp;
|
||||||
|
return lp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class TPtr : public TPtrBase<T>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TPtr()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TPtr(T* lp) : TPtrBase<T>(lp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TPtr(__in const TPtr<T>& lp) : TPtrBase<T>(lp.p)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator=(T* lp)
|
||||||
|
{
|
||||||
|
if (*this != lp)
|
||||||
|
{
|
||||||
|
return static_cast<T*>(TPtrAssign((IObjectBase**)&p, lp));
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//template <typename Q>
|
||||||
|
//T* operator=(__in const TPtr<Q>& lp)
|
||||||
|
//{
|
||||||
|
// if (!IsEqualObject(lp))
|
||||||
|
// {
|
||||||
|
// return static_cast<T*>(AtlComQIPtrAssign((IUnknown**)&p, lp, __uuidof(T)));
|
||||||
|
// }
|
||||||
|
// return *this;
|
||||||
|
//}
|
||||||
|
|
||||||
|
T* operator=(__in const TPtr<T>& lp)
|
||||||
|
{
|
||||||
|
if (*this != lp)
|
||||||
|
{
|
||||||
|
return static_cast<T*>(TPtrAssign((IObjectBase**)&p, lp));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// \brief Dynamic Cast
|
||||||
|
template < typename T >
|
||||||
|
TPtr< T >* DynamicCast( TPtr< IObjectBase >& _pObject )
|
||||||
|
{
|
||||||
|
const RuntimeClass* pRuntimeClass = RUNTIME_CLASS( T );
|
||||||
|
|
||||||
|
if ( _pObject->GetRuntimeClass()->IsKindOf( pRuntimeClass ) )
|
||||||
|
return TPtr< T >( static_cast< T* >( _pObject ) );
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// \brief Interface for ObjectConstructor
|
||||||
|
class IObjectConstructor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~IObjectConstructor() {}
|
||||||
|
|
||||||
|
// Create object
|
||||||
|
virtual IObjectBase* Create() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// \brief A helper class for creating object from inplace new.
|
||||||
|
template <typename T>
|
||||||
|
class ObjectConstructor : public IObjectConstructor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Singleton
|
||||||
|
static ObjectConstructor* GetInstance();
|
||||||
|
|
||||||
|
public:
|
||||||
|
IObjectBase* Create() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline ObjectConstructor<T>* ObjectConstructor<T>::GetInstance()
|
||||||
|
{
|
||||||
|
static ObjectConstructor<T> s_Instance;
|
||||||
|
return &s_Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline IObjectBase* ObjectConstructor<T>::Create()
|
||||||
|
{
|
||||||
|
return new T();
|
||||||
|
}
|
||||||
|
|
||||||
|
// \brief The Object Manager. Store all Runtime Classes and create refcount objects
|
||||||
|
class ObjectManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ObjectManager();
|
||||||
|
~ObjectManager();
|
||||||
|
|
||||||
|
// Register IObjectBase to the object manager
|
||||||
|
void Register( const RuntimeClass* _pRuntimeClass, IObjectConstructor* _pObjectConstructor );
|
||||||
|
|
||||||
|
// Create object
|
||||||
|
IObjectBase* Create( const RuntimeClass* _pRuntimeClass );
|
||||||
|
IObjectBase* CreateByName( const char* _pClassName );
|
||||||
|
|
||||||
|
// Templated version of Create
|
||||||
|
template < typename T >
|
||||||
|
T* Create();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct ObjectRegistryEntry
|
||||||
|
{
|
||||||
|
const RuntimeClass* pRuntimeClass;
|
||||||
|
IObjectConstructor* pObjectConstructor;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ObjectRegistryEntry> m_objectRegistry;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< typename T >
|
||||||
|
inline T* ObjectManager::Create()
|
||||||
|
{
|
||||||
|
return Create(RUNTIME_CLASS(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern ObjectManager g_ObjectManager;
|
||||||
|
|
||||||
|
// Helper function for registering object
|
||||||
|
template < typename T >
|
||||||
|
void RegisterObject()
|
||||||
|
{
|
||||||
|
g_ObjectManager.Register( RUNTIME_CLASS( T ), ObjectConstructor< T >::GetInstance() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function for creating object
|
||||||
|
template < typename T >
|
||||||
|
TPtr< T > CreateObject()
|
||||||
|
{
|
||||||
|
IObjectBase* pObject = g_ObjectManager.Create( RUNTIME_CLASS( T ) );
|
||||||
|
return TPtr< T >( ( T* )pObject );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !objectmanagerH_included
|
45
src/engine/utils/refcount.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef REFCOUNT_H
|
||||||
|
#define REFCOUNT_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
class RefCount
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Virtual destructor
|
||||||
|
virtual ~RefCount() {}
|
||||||
|
|
||||||
|
// Add reference
|
||||||
|
uint64_t AddRef();
|
||||||
|
|
||||||
|
// Release (remove reference and destroy object at zero reference's)
|
||||||
|
uint64_t Release();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Ref counting
|
||||||
|
uint64_t m_RefCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline uint64_t RefCount::AddRef()
|
||||||
|
{
|
||||||
|
++m_RefCount;
|
||||||
|
return m_RefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t RefCount::Release()
|
||||||
|
{
|
||||||
|
assert(m_RefCount > 0);
|
||||||
|
--m_RefCount;
|
||||||
|
|
||||||
|
if (m_RefCount == 0)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_RefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
23
src/engine/utils/rtti.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "rtti.h"
|
||||||
|
|
||||||
|
RuntimeClass::RuntimeClass(const char* classname) : m_classname(classname), m_baseRuntimeClass(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeClass::RuntimeClass(const char* classname, const RuntimeClass* baseTypeInfo) : m_classname(classname), m_baseRuntimeClass(baseTypeInfo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RuntimeClass::IsKindOf(const RuntimeClass* typeInfo) const
|
||||||
|
{
|
||||||
|
for (const RuntimeClass* it = this; it != nullptr; it = it->m_baseRuntimeClass)
|
||||||
|
if (it == typeInfo)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* RuntimeClass::Name() const
|
||||||
|
{
|
||||||
|
return m_classname;
|
||||||
|
}
|
43
src/engine/utils/rtti.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef RTTI_H
|
||||||
|
#define RTTI_H
|
||||||
|
|
||||||
|
struct RuntimeClass
|
||||||
|
{
|
||||||
|
RuntimeClass(const char* classname);
|
||||||
|
RuntimeClass(const char* classname, const RuntimeClass* baseTypeInfo);
|
||||||
|
|
||||||
|
bool IsKindOf(const RuntimeClass* typeInfo) const;
|
||||||
|
|
||||||
|
const char* Name() const;
|
||||||
|
|
||||||
|
const RuntimeClass* m_baseRuntimeClass;
|
||||||
|
const char* m_classname;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DECLARE_RTTI_ROOT(typeName) \
|
||||||
|
public: \
|
||||||
|
static const RuntimeClass s_runtimeClass; \
|
||||||
|
static const RuntimeClass* GetStaticRuntimeClass() { return &s_runtimeClass; } \
|
||||||
|
virtual const RuntimeClass* GetRuntimeClass() const { return GetStaticRuntimeClass(); }
|
||||||
|
|
||||||
|
#define DECLARE_RTTI(typeName, baseTypeName) \
|
||||||
|
public: \
|
||||||
|
static const RuntimeClass s_runtimeClass; \
|
||||||
|
static const RuntimeClass* GetStaticRuntimeClass() { return &s_runtimeClass; } \
|
||||||
|
virtual const RuntimeClass* GetRuntimeClass() const { return GetStaticRuntimeClass(); }
|
||||||
|
|
||||||
|
#define IMPLEMENT_RTTI_ROOT(typeName) \
|
||||||
|
const RuntimeClass typeName::s_runtimeClass(#typeName, nullptr)
|
||||||
|
|
||||||
|
#define IMPLEMENT_RTTI(typeName, baseTypeName) \
|
||||||
|
const RuntimeClass typeName::s_runtimeClass(#typeName, baseTypeName::GetStaticRuntimeClass())
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
const RuntimeClass* GetRuntimeClass()
|
||||||
|
{
|
||||||
|
return T::GetStaticRuntimeClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RUNTIME_CLASS(typeName) (typeName::GetStaticRuntimeClass())
|
||||||
|
|
||||||
|
#endif //!RTTI_H
|
14
src/engine/utils/string.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include <stdarg.h>
|
||||||
|
#include "utils/string.h"
|
||||||
|
|
||||||
|
const char* va(const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
static char buffer[4096];
|
||||||
|
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsnprintf(buffer, sizeof(buffer), fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
10
src/engine/utils/string.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef UTILS_STRING_H
|
||||||
|
#define UTILS_STRING_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
typedef std::string String;
|
||||||
|
|
||||||
|
const char* va(const char* fmt, ...);
|
||||||
|
|
||||||
|
#endif // !UTILS_STRING_H
|
65
src/engine/utils/timer.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include "timer.h"
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32)
|
||||||
|
class SystemTimerWin32 : public SystemTimer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void Update();
|
||||||
|
|
||||||
|
float GetTime();
|
||||||
|
float GetDelta();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LARGE_INTEGER m_frequency;
|
||||||
|
LARGE_INTEGER m_startTime;
|
||||||
|
LARGE_INTEGER m_endTime;
|
||||||
|
|
||||||
|
float m_floatFrequency;
|
||||||
|
float m_deltaTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SystemTimerWin32 s_system_timer_win32;
|
||||||
|
SystemTimer* g_systemTimer = (SystemTimer*)&s_system_timer_win32;
|
||||||
|
|
||||||
|
void SystemTimerWin32::Init()
|
||||||
|
{
|
||||||
|
QueryPerformanceFrequency(&m_frequency);
|
||||||
|
m_floatFrequency = (float)m_frequency.QuadPart;
|
||||||
|
|
||||||
|
QueryPerformanceCounter(&m_startTime);
|
||||||
|
m_startTime = m_endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemTimerWin32::Shutdown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemTimerWin32::Update()
|
||||||
|
{
|
||||||
|
QueryPerformanceCounter(&m_startTime);
|
||||||
|
m_deltaTime = static_cast<float>(m_startTime.QuadPart - m_endTime.QuadPart) / m_frequency.QuadPart;
|
||||||
|
|
||||||
|
if (m_deltaTime > 10.0f)
|
||||||
|
m_deltaTime = 0.0f;
|
||||||
|
|
||||||
|
m_endTime = m_startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
float SystemTimerWin32::GetTime()
|
||||||
|
{
|
||||||
|
LARGE_INTEGER time;
|
||||||
|
QueryPerformanceCounter(&time);
|
||||||
|
return static_cast<float>(time.QuadPart / m_frequency.QuadPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SystemTimerWin32::GetDelta()
|
||||||
|
{
|
||||||
|
return m_deltaTime;
|
||||||
|
}
|
||||||
|
#endif // WIN32
|