Merge branch 'master' of ssh://git.openclonk.org/openclonk
|
@ -11,7 +11,7 @@
|
|||
# To redistribute this file separately, substitute the full license texts
|
||||
# for the above references.
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.10)
|
||||
cmake_minimum_required (VERSION 3.0.2)
|
||||
project (openclonk CXX C)
|
||||
|
||||
# CMP0054: Only interpret if() arguments as variables or keywords when unquoted
|
||||
|
@ -55,9 +55,6 @@ separate_arguments(OC_EXE_LINKER_FLAGS_DEBUG)
|
|||
|
||||
CHECK_CXX_COMPILER_FLAG("-std=gnu++14" USE_GCC_STD_14)
|
||||
if(USE_GCC_STD_14)
|
||||
if(OC_CXX_FLAGS MATCHES \\-std=gnu\\+\\+0x)
|
||||
list(REMOVE_ITEM OC_CXX_FLAGS "-std=gnu++0x")
|
||||
endif()
|
||||
list(APPEND OC_CXX_FLAGS "-std=gnu++14")
|
||||
endif()
|
||||
|
||||
|
@ -1142,7 +1139,7 @@ endif()
|
|||
|
||||
if(GTK3_FOUND AND GTK3_gtksourceview_FOUND)
|
||||
add_executable(mape ${MAPE_BASE_SOURCES} ${MAPE_SOURCES})
|
||||
set_property(TARGET mape APPEND PROPERTY COMPILE_FLAGS ${GTK3_COMPILE_DEFINITIONS})
|
||||
target_compile_options(mape PRIVATE ${GTK3_COMPILE_DEFINITIONS} ${GTK3_gtksourceview_COMPILE_DEFINITIONS})
|
||||
target_include_directories(mape PRIVATE ${GTK3_INCLUDE_DIRS} ${GTK3_gtksourceview_INCLUDE_DIRS})
|
||||
target_link_libraries(mape
|
||||
${GTK3_LIBRARIES}
|
||||
|
@ -1172,18 +1169,8 @@ if(WIN32)
|
|||
target_link_libraries(c4script ws2_32)
|
||||
endif()
|
||||
|
||||
if(NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.10")
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG>)
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
|
||||
else()
|
||||
# CMake started supporting generator expressions in 2.8.10. Earlier
|
||||
# versions pass most of this through unmodified, which confuses make.
|
||||
# Once we stop supporting old versions of CMake, this case can be removed.
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG)
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELEASE NDEBUG)
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_RELWITHDEBINFO NDEBUG)
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_MINSIZEREL NDEBUG)
|
||||
endif()
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:_DEBUG>)
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<NOT:$<CONFIG:Debug>>:NDEBUG>)
|
||||
|
||||
# This expands some variables in Info.plist as a side-effect. XCode might then
|
||||
# expand a second time, using the same syntax. Try not to get confused by this!
|
||||
|
@ -1493,9 +1480,4 @@ set(CPACK_PACKAGE_VERSION_MINOR "${C4XVER2}")
|
|||
set(CPACK_PACKAGE_FILE_NAME "openclonk-${C4XVER1}.${C4XVER2}")
|
||||
set(CPACK_SOURCE_PACKAGE_FILE_NAME "openclonk-src-${C4XVER1}.${C4XVER2}")
|
||||
set(CPACK_SOURCE_GENERATOR "TGZ;ZIP")
|
||||
# Somebody who uses Debian/Ubuntu should set this
|
||||
#set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libgcc1, libx11, libXrandr, libXpm, libGLEW, libGL, libpng, libSDL-1.2, libSDL_mixer-1.2, gtk2, libjpeg, zlib")
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "libc6, libgcc1, libx11, libXrandr, libXpm, libGLEW, libGL, libpng, libSDL-1.2, libSDL_mixer-1.2, gtk2, libjpeg, zlib")
|
||||
|
||||
include(CPack)
|
||||
|
|
|
@ -27,10 +27,10 @@ Martin Strohmeier (K-Pone)
|
|||
Tobias Zwick (Newton)
|
||||
|
||||
<Thanks to our package maintainers>
|
||||
Benedict Etzel (B_E), Phillip Kern (pkern), Kevin Zheng and more
|
||||
Benedict Etzel (B_E), Philipp Kern (pkern), Kevin Zheng and more
|
||||
|
||||
<Special Thanks to Contributors>
|
||||
Martin Adam (Win), Florian Graier (Nachtfalter), Mark Haßelbusch (Marky), Merten Ehmig (pluto), Benjamin Herr (Loriel), Armin Schäfer, Pyrit, Philip Holzmann (Batman), Alexander Semeniuk (AlteredARMOR), Andriel, Peewee, Oliver Schneider (ker), Fabian Pietsch, Manuel Rieke (MrBeast), Felix Riese (Fungiform), Carl-Philip Hänsch (Carli), Sebastian Rühl, Gurkenglas and many more:
|
||||
Luchs, Asmageddon, mizipzor, Tim Blume, Apfelclonk, Sven-Hendrik Haase, Lauri Niskanen (Ape), Daniel Theuke (ST-DDT), Russell, Stan, TomyLobo, Clonkine, Koronis, Johannes Nixdorf (mixi), grgecko, Dominik Bayerl, Misty de Meo, Lorenz Schwittmann, hasufell, Jan Heberer, dylanstrategie, Checkmaty, Faby
|
||||
|
||||
Also, big thanks to Matthes Bender and all those who contributed to previous Clonk titles for the passion they put into the game and for agreeing to make Clonk open source.
|
||||
Also, big thanks to Matthes Bender and all those who contributed to previous Clonk titles for the passion they put into the game and for agreeing to make Clonk open source.
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
/**
|
||||
/*
|
||||
Hot Ice
|
||||
Ice islands above a lava lake
|
||||
|
||||
@authors Sven2
|
||||
*/
|
||||
|
||||
static g_player_spawn_positions;
|
||||
static g_map_width;
|
||||
|
||||
// Called be the engine: draw the complete map here.
|
||||
public func InitializeMap(proplist map)
|
||||
{
|
||||
|
@ -12,35 +15,77 @@ public func InitializeMap(proplist map)
|
|||
// Map type 1: Only many small islands
|
||||
var t = SCENPAR_MapType;
|
||||
var w = map.Wdt, h=map.Hgt;
|
||||
g_map_width = w;
|
||||
|
||||
// Bottom lava lake
|
||||
map->Draw("^DuroLava", nil, [0,h*4/5,w,h/5]);
|
||||
|
||||
// Big island
|
||||
if (t == 0)
|
||||
{
|
||||
var island = { Algo=MAPALGO_Polygon, X=[0,w,w*6/8,w*2/8], Y=[h*4/10,h*4/10,h*7/10,h*7/10] };
|
||||
island = { Algo=MAPALGO_Turbulence, Op=island, Amplitude=[0, 8] };
|
||||
map->Draw("^Ice-ice2", island, [w/10,h*13/20,w*8/10,h*3/20]);
|
||||
}
|
||||
|
||||
// Small islands
|
||||
var n_islands = [12,37][t];
|
||||
while(n_islands--)
|
||||
{
|
||||
var y = h*2/10 + Random(h*(3+t*2)/10);
|
||||
var x = w*1/10 + Random(w*8/10);
|
||||
var szx = t*Random(3);
|
||||
var szy = 1+t*Random(Random(2));
|
||||
map->Draw("^Ice-ice2", nil, [x-szx,y,1+2*szx,szy]);
|
||||
}
|
||||
|
||||
// Alternate texctures
|
||||
var icealt_tex = { Algo=MAPALGO_RndChecker, Wdt=2, Hgt=3 };
|
||||
icealt_tex = { Algo=MAPALGO_Turbulence, Op=icealt_tex };
|
||||
icealt_tex = { Algo=MAPALGO_And, Op=[Duplicate("Ice"), icealt_tex]};
|
||||
map->Draw("^Ice-ice3", icealt_tex);
|
||||
|
||||
if (t == 0) DrawBigIslandMap(map);
|
||||
if (t == 1) DrawSmallIslandsMap(map);
|
||||
|
||||
// Alternate texctures
|
||||
var icealt_tex = { Algo=MAPALGO_RndChecker, Wdt=2, Hgt=3 };
|
||||
icealt_tex = { Algo=MAPALGO_Turbulence, Op=icealt_tex };
|
||||
icealt_tex = { Algo=MAPALGO_And, Op=[Duplicate("Ice"), icealt_tex]};
|
||||
map->Draw("^Ice-ice", icealt_tex);
|
||||
|
||||
// Return true to tell the engine a map has been successfully created.
|
||||
return true;
|
||||
}
|
||||
|
||||
func DrawBigIslandMap(proplist map)
|
||||
{
|
||||
var w = map.Wdt, h=map.Hgt;
|
||||
// Draw one big island as the ground and some smaller islands floating above
|
||||
// Big
|
||||
var island = { Algo=MAPALGO_Polygon, X=[0,w,w*6/8,w*2/8], Y=[h*4/10,h*4/10,h*7/10,h*7/10] };
|
||||
island = { Algo=MAPALGO_Turbulence, Op=island, Amplitude=[0, 8] };
|
||||
map->Draw("^Ice-ice2", island, [w/10,h*13/20,w*8/10,h*3/20]);
|
||||
// Make sure one row of inner island is drawn because it's used for player spawns
|
||||
map->Draw("^Ice-ice2", nil, [w*3/10,h*13/20,w*4/10+1,1]);
|
||||
// Smaller floating
|
||||
var n_islands = 12;
|
||||
while(n_islands--)
|
||||
{
|
||||
var x = w*1/10 + Random(w*8/10);
|
||||
var y = h*2/10 + Random(h*3/10);
|
||||
map->Draw("^Ice-ice2", nil, [x,y,1,1]);
|
||||
}
|
||||
// Player spawns simply in middle of big island
|
||||
var plrcnt = GetStartupPlayerCount();
|
||||
g_player_spawn_positions = CreateArray(plrcnt);
|
||||
for (var i = 0; i < plrcnt; ++i)
|
||||
{
|
||||
g_player_spawn_positions[i] = [w*3/10 + i*w*4/10/(plrcnt-1), h*13/20-1];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
func DrawSmallIslandsMap(proplist map)
|
||||
{
|
||||
var w = map.Wdt, h=map.Hgt, x, y, szx, szy;
|
||||
// Islands in center of map
|
||||
var n_islands = 35;
|
||||
while(n_islands--)
|
||||
{
|
||||
y = h*3/10 + Random(h*5/10 - 3);
|
||||
var xrange = w * (y)/(h*9/10);
|
||||
x = w/2 - xrange/2 + Random(xrange);
|
||||
szx = Random(3);
|
||||
szy = 1;
|
||||
if (y > h/2) szy += Random(2); // lower islands sometimes taller
|
||||
if (Abs(x-w/2) < w/10) szx += Random(3); // central islands sometimes wider
|
||||
map->Draw("^Ice-ice2", nil, [x-szx,y,1+2*szx,szy]);
|
||||
}
|
||||
// Starting islands for player spawns
|
||||
var spawn_island_count = GetStartupPlayerCount();
|
||||
g_player_spawn_positions = CreateArray(spawn_island_count);
|
||||
for (var i = 0; i < spawn_island_count; ++i)
|
||||
{
|
||||
var x = w*2/10 + i * (w*6/10) / (spawn_island_count - 1);
|
||||
var y = Max(1, h/10) + Abs(x-w/2) * 3*h/10/w;
|
||||
map->Draw("^Ice-ice2", nil, [x,y,1,1]);
|
||||
g_player_spawn_positions[i] = [x, y-1];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -5,9 +5,10 @@ func Initialize()
|
|||
// Materials: Chests
|
||||
var i,pos;
|
||||
var ls_wdt = LandscapeWidth(), ls_hgt = LandscapeHeight();
|
||||
var top_area_hgt = ls_hgt*[50,80][SCENPAR_MapType]/100;
|
||||
var chest_area_y = ls_hgt*[0,30][SCENPAR_MapType]/100;
|
||||
var chest_area_hgt = ls_hgt/2;
|
||||
for (i=0; i<6; ++i)
|
||||
if (pos=FindLocation(Loc_InRect(0,0,ls_wdt,top_area_hgt-100), Loc_Wall(CNAT_Bottom))) // Loc_Wall adds us 100 pixels...
|
||||
if (pos=FindLocation(Loc_InRect(0,chest_area_y,ls_wdt,chest_area_hgt-100), Loc_Wall(CNAT_Bottom))) // Loc_Wall adds us 100 pixels...
|
||||
{
|
||||
var chest = CreateObjectAbove(Chest,pos.x,pos.y);
|
||||
if (chest)
|
||||
|
@ -24,27 +25,40 @@ func Initialize()
|
|||
}
|
||||
// Materials: Firestones
|
||||
for (i=0; i<30; ++i)
|
||||
if (pos=FindLocation(Loc_InRect(0,0,ls_wdt,top_area_hgt), Loc_Solid()))
|
||||
if (pos=FindLocation(Loc_InRect(0,chest_area_y,ls_wdt,chest_area_hgt), Loc_Solid()))
|
||||
if (IsFirestoneSpot(pos.x,pos.y))
|
||||
CreateObjectAbove(Firestone,pos.x,pos.y-1);
|
||||
// Some firestones in lower half. For ap type 1, more firestones in lower than upper half.
|
||||
// Some firestones and bombs in lower half. For ap type 1, more firestones in lower than upper half.
|
||||
for (i=0; i<30; ++i)
|
||||
if (pos=FindLocation(Loc_InRect(0,ls_hgt/2,ls_wdt,ls_hgt/3), Loc_Solid()))
|
||||
if (IsFirestoneSpot(pos.x,pos.y))
|
||||
CreateObjectAbove(Firestone,pos.x,pos.y-1);
|
||||
CreateObjectAbove([Firestone,IronBomb][Random(Random(3))],pos.x,pos.y-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static g_player_spawn_positions, g_map_width, g_player_spawn_index;
|
||||
|
||||
func InitializePlayer(int plr)
|
||||
{
|
||||
// everything visible
|
||||
SetFoW(false, plr);
|
||||
// player positioning. In lower area for both maps becuase starting high is an an advantage.
|
||||
// Player positioning.
|
||||
var ls_wdt = LandscapeWidth(), ls_hgt = LandscapeHeight();
|
||||
var crew = GetCrew(plr);
|
||||
var start_pos = FindLocation(Loc_InRect(ls_wdt/5,ls_hgt/2,ls_wdt*3/5,ls_hgt/3), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot));
|
||||
if (!start_pos) start_pos = FindLocation(Loc_InRect(ls_wdt/10,0,ls_wdt*8/10,ls_hgt*4/5), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot));
|
||||
if (!start_pos) start_pos = {x=Random(ls_wdt*6/10)+ls_wdt*2/10, y=ls_hgt*58/100};
|
||||
var crew = GetCrew(plr), start_pos;
|
||||
// Position by map type?
|
||||
if (g_player_spawn_positions && g_player_spawn_index < GetLength(g_player_spawn_positions))
|
||||
{
|
||||
start_pos = g_player_spawn_positions[g_player_spawn_index++];
|
||||
var map_zoom = ls_wdt / g_map_width;
|
||||
start_pos = {x=start_pos[0]*map_zoom+map_zoom/2, y=start_pos[1]*map_zoom};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start positions not defined or exhausted: Spawn in lower area for both maps becuase starting high is an an advantage.
|
||||
start_pos = FindLocation(Loc_InRect(ls_wdt/5,ls_hgt/2,ls_wdt*3/5,ls_hgt/3), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot));
|
||||
if (!start_pos) start_pos = FindLocation(Loc_InRect(ls_wdt/10,0,ls_wdt*8/10,ls_hgt*4/5), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot));
|
||||
if (!start_pos) start_pos = {x=Random(ls_wdt*6/10)+ls_wdt*2/10, y=ls_hgt*58/100};
|
||||
}
|
||||
crew->SetPosition(start_pos.x, start_pos.y-10);
|
||||
// initial material
|
||||
crew->CreateContents(Shovel);
|
||||
|
|
|
@ -386,9 +386,8 @@ func Statue_Death()
|
|||
while (i--) EliminatePlayer(GetPlayerByIndex(i, C4PT_User));
|
||||
// Statue down :(
|
||||
CastObjects(Nugget, 5, 10);
|
||||
Explode(10);
|
||||
ScheduleCall(nil, Global.GameOver, 50, 1);
|
||||
return true;
|
||||
return Explode(10);
|
||||
}
|
||||
|
||||
/* Developer commands */
|
||||
|
|
|
@ -76,14 +76,14 @@ slice(texture+5)
|
|||
// Query light texture
|
||||
vec2 lightDirCoord = lightCoord;
|
||||
|
||||
vec4 lightPx = texture2D(lightTex, lightDirCoord);
|
||||
vec4 lightPx = texture(lightTex, lightDirCoord);
|
||||
float lightBright = maxLightBrightness * max(0.0, (lightPx.a-lightDarknessLevel)/(1.0-lightDarknessLevel));
|
||||
vec3 lightDir = normalize(vec3(vec2(1.0, 1.0) - lightPx.yz * 3.0, lightDepth));
|
||||
|
||||
// Query light color texture (part of the light texture)
|
||||
vec2 lightColorCoord = lightCoord - vec2(0.0, 0.5); // subtract offset for the color texture
|
||||
|
||||
vec3 lightColor = texture2D(lightTex, lightColorCoord.st).rgb;
|
||||
vec3 lightColor = texture(lightTex, lightColorCoord.st).rgb;
|
||||
|
||||
// Normalise light colour
|
||||
#ifdef LIGHT_DEBUG_COLOR
|
||||
|
@ -93,7 +93,7 @@ slice(texture+5)
|
|||
|
||||
// Ambient light
|
||||
// Edxtra .xy since some old intel drivers return a vec3
|
||||
float ambient = texture2D(ambientTex, (ambientTransform * vec3(gl_FragCoord.xy, 1.0)).xy).r;
|
||||
float ambient = texture(ambientTex, (ambientTransform * vec3(gl_FragCoord.xy, 1.0)).xy).r;
|
||||
ambient *= ambientBrightness;
|
||||
#ifdef OC_SKY
|
||||
ambient = 0.999; // TODO: = 1.0 causes bugs?
|
||||
|
@ -144,7 +144,7 @@ slice(color+5)
|
|||
// "spotty" and allow the material to self-illuminate. The light
|
||||
// brightness overrules everything though (= FoW is last factor).
|
||||
vec3 spotLight = pow(vec3(light,light,light), matSpot);
|
||||
color.rgb = lightBright * color.rgb * (matEmit + lightColorNorm * spotLight);
|
||||
fragColor.rgb = lightBright * fragColor.rgb * (matEmit + lightColorNorm * spotLight);
|
||||
#ifdef OC_LANDSCAPE
|
||||
vec3 spotLight2 = pow(vec3(light2,light2,light2), matSpot2);
|
||||
color2.rgb = lightBright * color2.rgb * (matEmit2 + lightColorNorm * spotLight2);
|
||||
|
@ -159,18 +159,18 @@ slice(finish+5)
|
|||
float lightYDir = lightPx.b - 1.0/3.0;
|
||||
float lightXDir = lightPx.g - 1.0/3.0;
|
||||
float lightStrength = lightPx.a;
|
||||
color =
|
||||
fragColor =
|
||||
vec4(lightStrength * vec3(1.0-1.5*(max(0.0, lightYDir) + max(0.0,lightXDir)),
|
||||
1.0-1.5*(max(0.0, lightYDir) + max(0.0,-lightXDir)),
|
||||
1.0-1.5*max(0.0, -lightYDir)),
|
||||
1.0);
|
||||
#else
|
||||
color = vec4(0.0, 0.0, 0.0, 0.0); // invisible
|
||||
fragColor = vec4(0.0, 0.0, 0.0, 0.0); // invisible
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
slice(finish+10) {
|
||||
color = vec4(pow(color.rgb, gamma), color.a);
|
||||
fragColor = vec4(pow(fragColor.rgb, gamma), fragColor.a);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
|
||||
// Interpolated texture coordinates
|
||||
varying vec2 landscapeTexCoord;
|
||||
in vec2 landscapeTexCoord;
|
||||
#ifdef OC_DYNAMIC_LIGHT
|
||||
varying vec2 lightTexCoord;
|
||||
in vec2 lightTexCoord;
|
||||
#endif
|
||||
|
||||
// Input textures
|
||||
uniform sampler2D landscapeTex[2];
|
||||
uniform sampler2D scalerTex;
|
||||
uniform sampler3D materialTex;
|
||||
uniform sampler2DArray materialTex;
|
||||
|
||||
// Resolution of the landscape texture
|
||||
uniform vec2 resolution;
|
||||
|
@ -20,6 +20,8 @@ uniform sampler1D matMapTex;
|
|||
uniform float materialDepth;
|
||||
uniform vec2 materialSize;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
// Expected parameters for the scaler
|
||||
const vec2 scalerStepX = vec2(1.0 / 8.0, 0.0);
|
||||
const vec2 scalerStepY = vec2(0.0, 1.0 / 32.0);
|
||||
|
@ -28,7 +30,7 @@ const vec2 scalerPixel = vec2(scalerStepX.x, scalerStepY.y) / 3.0;
|
|||
|
||||
vec4 queryMatMap(int pix)
|
||||
{
|
||||
return texture1D(matMapTex, float(pix) / 2.0 / 256.0 + 0.5 / 2.0 / 256.0);
|
||||
return texture(matMapTex, float(pix) / 2.0 / 256.0 + 0.5 / 2.0 / 256.0);
|
||||
}
|
||||
|
||||
slice(init)
|
||||
|
@ -67,8 +69,8 @@ slice(coordinate)
|
|||
slice(texture)
|
||||
{
|
||||
// our pixel color (without/with interpolation)
|
||||
vec4 landscapePx = texture2D(landscapeTex[0], centerCoo);
|
||||
vec4 realLandscapePx = texture2D(landscapeTex[0], texCoo);
|
||||
vec4 landscapePx = texture(landscapeTex[0], centerCoo);
|
||||
vec4 realLandscapePx = texture(landscapeTex[0], texCoo);
|
||||
|
||||
// find scaler coordinate
|
||||
vec2 scalerCoo = scalerOffset + mod(pixelCoo, vec2(1.0, 1.0)) * scalerPixel;
|
||||
|
@ -77,12 +79,12 @@ slice(texture)
|
|||
scalerCoo.y += float(iScaler / 8) / 32.0;
|
||||
|
||||
// query scaler texture
|
||||
vec4 scalerPx = texture2D(scalerTex, scalerCoo);
|
||||
vec4 scalerPx = texture(scalerTex, scalerCoo);
|
||||
|
||||
// Get "second" landscape pixel
|
||||
vec2 centerCoo2 = centerCoo + fullStep * floor(vec2(-0.5, -0.5) +
|
||||
scalerPx.gb * 255.0 / 64.0);
|
||||
vec4 landscapePx2 = texture2D(landscapeTex[0], centerCoo2);
|
||||
vec4 landscapePx2 = texture(landscapeTex[0], centerCoo2);
|
||||
|
||||
}
|
||||
|
||||
|
@ -95,30 +97,31 @@ slice(texture+4)
|
|||
|
||||
slice(material)
|
||||
{
|
||||
|
||||
// Get material properties from material map
|
||||
int matMapIx = f2i(landscapePx.r);
|
||||
vec4 matMap = queryMatMap(2*matMapIx);
|
||||
vec4 matMapX = queryMatMap(2*matMapIx+1);
|
||||
float materialIx = float(f2i(matMap.a)) / 256.0 + 0.5 / materialDepth;
|
||||
float materialIx = f2i(matMap.a) / 256.0 * materialDepth;
|
||||
vec3 matEmit = matMap.rgb;
|
||||
vec3 matSpot = matMapX.rgb * 255.9f / 16.0f;
|
||||
float matAngle = matMapX.a;
|
||||
|
||||
// Query material texture pixels
|
||||
vec4 materialPx = texture3D(materialTex, vec3(materialCoo, materialIx));
|
||||
vec4 normalPx = texture3D(materialTex, vec3(materialCoo, materialIx+0.5));
|
||||
vec4 materialPx = texture(materialTex, vec3(materialCoo, materialIx));
|
||||
vec4 normalPx = texture(materialTex, vec3(materialCoo, materialIx+0.5 * materialDepth));
|
||||
// Same for second pixel
|
||||
int matMapIx2 = f2i(landscapePx2.r);
|
||||
vec4 matMap2 = queryMatMap(2*matMapIx2);
|
||||
vec4 matMapX2 = queryMatMap(2*matMapIx2+1);
|
||||
float materialIx2 = float(f2i(matMap2.a)) / 256.0 + 0.5 / materialDepth;
|
||||
float materialIx2 = f2i(matMap2.a) / 256.0 * materialDepth;
|
||||
vec3 matEmit2 = matMap2.rgb;
|
||||
vec3 matSpot2 = matMapX2.rgb * 255.9f / 16.0f;
|
||||
float matAngle2 = matMapX2.a;
|
||||
|
||||
// Query material texture pixels
|
||||
vec4 materialPx2 = texture3D(materialTex, vec3(materialCoo, materialIx2));
|
||||
vec4 normalPx2 = texture3D(materialTex, vec3(materialCoo, materialIx2+0.5));
|
||||
vec4 materialPx2 = texture(materialTex, vec3(materialCoo, materialIx2));
|
||||
vec4 normalPx2 = texture(materialTex, vec3(materialCoo, materialIx2+0.5 * materialDepth));
|
||||
}
|
||||
|
||||
slice(normal)
|
||||
|
@ -144,12 +147,11 @@ slice(normal)
|
|||
}
|
||||
|
||||
slice(color) {
|
||||
#define color gl_FragColor
|
||||
color = materialPx;
|
||||
fragColor = materialPx;
|
||||
vec4 color2 = materialPx2;
|
||||
}
|
||||
|
||||
slice(color+10) {
|
||||
// Mix second color into main color according to scaler
|
||||
color = mix(color2, color, scalerPx.r);
|
||||
fragColor = mix(color2, fragColor, scalerPx.r);
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
|
||||
// Default Vertex Shader for the landscape.
|
||||
|
||||
attribute vec2 oc_Position;
|
||||
attribute vec2 oc_LandscapeTexCoord;
|
||||
attribute vec2 oc_LightTexCoord;
|
||||
in vec2 oc_Position;
|
||||
in vec2 oc_LandscapeTexCoord;
|
||||
in vec2 oc_LightTexCoord;
|
||||
|
||||
varying vec2 landscapeTexCoord;
|
||||
out vec2 landscapeTexCoord;
|
||||
#ifdef OC_DYNAMIC_LIGHT
|
||||
varying vec2 lightTexCoord;
|
||||
out vec2 lightTexCoord;
|
||||
#endif
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
|
|
|
@ -36,12 +36,12 @@
|
|||
|
||||
#define MAX_BONE_COUNT 80
|
||||
|
||||
attribute vec3 oc_Position;
|
||||
attribute vec3 oc_Normal;
|
||||
attribute vec2 oc_TexCoord;
|
||||
in vec3 oc_Position;
|
||||
in vec3 oc_Normal;
|
||||
in vec2 oc_TexCoord;
|
||||
|
||||
varying vec3 vtxNormal;
|
||||
varying vec2 texcoord;
|
||||
out vec3 vtxNormal;
|
||||
out vec2 texcoord;
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
uniform mat4 modelviewMatrix;
|
||||
|
@ -58,12 +58,12 @@ uniform mat3x4 bones[MAX_BONE_COUNT];
|
|||
// respectively. (Or we could split it even further.)
|
||||
#define BONE_COUNT 8
|
||||
|
||||
attribute vec4 oc_BoneIndices0;
|
||||
attribute vec4 oc_BoneWeights0;
|
||||
in vec4 oc_BoneIndices0;
|
||||
in vec4 oc_BoneWeights0;
|
||||
|
||||
#if BONE_COUNT > 4
|
||||
attribute vec4 oc_BoneIndices1;
|
||||
attribute vec4 oc_BoneWeights1;
|
||||
in vec4 oc_BoneIndices1;
|
||||
in vec4 oc_BoneWeights1;
|
||||
#endif
|
||||
|
||||
#ifndef OC_WA_LOW_MAX_VERTEX_UNIFORM_COMPONENTS
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
|
||||
uniform mat3x2 lightTransform;
|
||||
|
||||
#ifdef OC_MESH
|
||||
//uniform vec4 materialAmbient;
|
||||
uniform vec4 materialDiffuse;
|
||||
uniform vec4 materialEmission;
|
||||
uniform vec4 materialSpecular;
|
||||
#endif
|
||||
|
||||
#ifdef OC_WITH_NORMALMAP
|
||||
uniform mat3 normalMatrix;
|
||||
uniform sampler2D normalTex;
|
||||
|
@ -14,50 +21,55 @@ uniform sampler2D overlayTex;
|
|||
#endif
|
||||
|
||||
#ifdef OC_MESH
|
||||
varying vec3 vtxNormal;
|
||||
varying vec2 texcoord;
|
||||
in vec3 vtxNormal;
|
||||
in vec2 texcoord;
|
||||
#endif
|
||||
|
||||
#ifndef OC_MESH
|
||||
varying vec4 vtxColor;
|
||||
in vec4 vtxColor;
|
||||
#ifdef OC_HAVE_BASE
|
||||
uniform sampler2D baseTex;
|
||||
varying vec2 texcoord;
|
||||
in vec2 texcoord;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
slice(material)
|
||||
{
|
||||
// Default material properties. TODO: Populate them?
|
||||
vec3 matEmit = vec3(0.0,0.0,0.0);
|
||||
vec3 matSpot = vec3(1.0,1.0,1.0);
|
||||
// Default material properties.
|
||||
#ifdef OC_MESH
|
||||
vec3 matEmit = vec3(0.0, 0.0, 0.0);//materialEmission.rgb;
|
||||
vec3 matSpot = vec3(1.0, 1.0, 1.0);//materialSpecular.rgb;
|
||||
#else
|
||||
vec3 matEmit = vec3(0.0, 0.0, 0.0);
|
||||
vec3 matSpot = vec3(1.0, 1.0, 1.0);
|
||||
#endif
|
||||
float matAngle = 1.0;
|
||||
}
|
||||
|
||||
slice(texture)
|
||||
{
|
||||
#define color gl_FragColor
|
||||
|
||||
#ifdef OC_MESH
|
||||
// TODO: Add emission part of the material. Note we cannot just
|
||||
// add this to the color, but it would need to be handled separately,
|
||||
// such that it is independent from the incident light direction.
|
||||
color = gl_FrontMaterial.diffuse;
|
||||
fragColor = materialDiffuse;
|
||||
#else
|
||||
|
||||
#ifdef OC_HAVE_BASE
|
||||
// Texturing: Use color from texture, modulated with vertex color
|
||||
color = vtxColor * texture2D(baseTex, texcoord);
|
||||
fragColor = vtxColor * texture(baseTex, texcoord);
|
||||
#ifdef OC_HAVE_OVERLAY
|
||||
// Get overlay color from overlay texture
|
||||
vec4 overlay = vtxColor * overlayClr * texture2D(overlayTex, texcoord);
|
||||
vec4 overlay = vtxColor * overlayClr * texture(overlayTex, texcoord);
|
||||
// Mix overlay with texture
|
||||
float alpha0 = 1.0 - (1.0 - color.a) * (1.0 - overlay.a);
|
||||
color = vec4(mix(color.rgb, overlay.rgb, overlay.a / alpha0), alpha0);
|
||||
float alpha0 = 1.0 - (1.0 - fragColor.a) * (1.0 - overlay.a);
|
||||
fragColor = vec4(mix(fragColor.rgb, overlay.rgb, overlay.a / alpha0), alpha0);
|
||||
#endif
|
||||
#else
|
||||
// No texturing: Just use color assigned to vertex
|
||||
color = vtxColor;
|
||||
fragColor = vtxColor;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@ -74,7 +86,7 @@ slice(texture+4)
|
|||
slice(normal)
|
||||
{
|
||||
#ifdef OC_WITH_NORMALMAP
|
||||
vec4 normalPx = texture2D(normalTex, texcoord);
|
||||
vec4 normalPx = texture(normalTex, texcoord);
|
||||
vec3 normalPxDir = 2.0 * (normalPx.xyz - vec3(0.5, 0.5, 0.5));
|
||||
vec3 normal = normalize(normalMatrix * normalPxDir);
|
||||
#else
|
||||
|
@ -98,8 +110,8 @@ slice(color)
|
|||
// out = (color, clrmod, 1) * (A,B,C,D,E,F,0,0,G) * (color, clrmod, 1)
|
||||
|
||||
#ifdef OC_CLRMOD_MOD2
|
||||
color = vec4(clamp(color.rgb + clrMod.rgb - 0.5, 0.0, 1.0), color.a * clrMod.a);
|
||||
fragColor = vec4(clamp(fragColor.rgb + clrMod.rgb - 0.5, 0.0, 1.0), fragColor.a * clrMod.a);
|
||||
#else
|
||||
color = color * clrMod;
|
||||
fragColor = fragColor * clrMod;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -18,17 +18,17 @@
|
|||
uniform mat4 projectionMatrix;
|
||||
uniform mat4 modelviewMatrix;
|
||||
|
||||
attribute vec2 oc_Position;
|
||||
attribute vec4 oc_Color;
|
||||
in vec2 oc_Position;
|
||||
in vec4 oc_Color;
|
||||
|
||||
#ifdef OC_HAVE_BASE
|
||||
attribute vec2 oc_TexCoord;
|
||||
in vec2 oc_TexCoord;
|
||||
#endif
|
||||
|
||||
varying vec4 vtxColor;
|
||||
out vec4 vtxColor;
|
||||
|
||||
#ifdef OC_HAVE_BASE
|
||||
varying vec2 texcoord;
|
||||
out vec2 texcoord;
|
||||
#endif
|
||||
|
||||
slice(position)
|
||||
|
|
Before Width: | Height: | Size: 292 KiB After Width: | Height: | Size: 293 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
@ -28,10 +28,8 @@ func InitializeObjects()
|
|||
|
||||
var Tree_Coniferous2003 = CreateObjectAbove(Tree_Coniferous2, 347, 565);
|
||||
var Tree_Coniferous2004 = CreateObjectAbove(Tree_Coniferous2, 422, 558);
|
||||
CreateObjectAbove(Tree_Coniferous2, 1329, 384);
|
||||
CreateObjectAbove(Tree_Coniferous2, 1364, 364);
|
||||
CreateObjectAbove(Tree_Coniferous2, 1389, 327);
|
||||
CreateObjectAbove(Tree_Coniferous2, 1295, 398);
|
||||
CreateObjectAbove(Tree_Coniferous2, 1404, 390);
|
||||
CreateObjectAbove(Tree_Coniferous2, 1290, 403);
|
||||
|
||||
CreateObject(Fern, 1331, 701);
|
||||
CreateObject(Fern, 1468, 661);
|
||||
|
@ -143,7 +141,7 @@ func InitializeObjects()
|
|||
CreateObject(Loam, 1360, 781);
|
||||
CreateObject(Loam, 1519, 721);
|
||||
CreateObject(Loam, 1348, 718);
|
||||
CreateObject(Loam, 1379, 349);
|
||||
CreateObject(Loam, 1358, 388);
|
||||
CreateObject(Loam, 559, 1120);
|
||||
CreateObject(Loam, 505, 850);
|
||||
CreateObject(Loam, 517, 858);
|
||||
|
|
|
@ -64,7 +64,7 @@ func EnsureTrees(proplist area)
|
|||
return true;
|
||||
}
|
||||
|
||||
global func FxIntWaterfallTimer(object obj, int eff)
|
||||
global func FxIntWaterfallTimer(object obj, proplist eff)
|
||||
{
|
||||
InsertMaterial(Material("Water"), 1560,840);
|
||||
ExtractLiquid(1314,901);
|
||||
|
|
|
@ -259,8 +259,8 @@ func Intro_Stop()
|
|||
if (plane)
|
||||
{
|
||||
plane->FaceLeft();
|
||||
plane->SetR(-130);
|
||||
plane->SetPosition(1387, 238);
|
||||
plane->SetR(-90);
|
||||
plane->SetPosition(1387, 345);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -7,27 +7,27 @@ Sky=Clouds2
|
|||
[Player1]
|
||||
Wealth=25
|
||||
Crew=Clonk=1
|
||||
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;
|
||||
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;Chest=1;WoodenBridge=1;
|
||||
BaseMaterial=Bread=25;
|
||||
BaseProduction=Bread=25;
|
||||
|
||||
[Player2]
|
||||
Wealth=25
|
||||
Crew=Clonk=1
|
||||
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;
|
||||
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;Chest=1;WoodenBridge=1;
|
||||
BaseMaterial=Bread=25;
|
||||
BaseProduction=Bread=25;
|
||||
|
||||
[Player3]
|
||||
Wealth=25
|
||||
Crew=Clonk=1
|
||||
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;
|
||||
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;Chest=1;WoodenBridge=1;
|
||||
BaseMaterial=Bread=25;
|
||||
BaseProduction=Bread=25;
|
||||
|
||||
[Player4]
|
||||
Wealth=25
|
||||
Crew=Clonk=1
|
||||
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;
|
||||
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;Chest=1;WoodenBridge=1;
|
||||
BaseMaterial=Bread=25;
|
||||
BaseProduction=Bread=25;
|
||||
|
|
|
@ -159,6 +159,7 @@ func Intro_11()
|
|||
{
|
||||
crew->SetPosition(g_tuesday_pos[0],-100);
|
||||
crew->SetXDir(-10); crew->SetYDir(-30);
|
||||
crew->SetAction("Tumble");
|
||||
if (!index) SetPlrView(plr, crew);
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
@ -1,6 +1,6 @@
|
|||
/* Automatically created objects file */
|
||||
|
||||
static g_flagpole, npc_dagobert, npc_tarzan, g_golden_shovel, g_golden_idol, g_last_stone_door;
|
||||
static g_flagpole, g_golden_idol, npc_dagobert, npc_tarzan, g_golden_shovel, g_last_stone_door;
|
||||
|
||||
func InitializeObjects()
|
||||
{
|
||||
|
@ -11,14 +11,20 @@ func InitializeObjects()
|
|||
CreateObjectAbove(Grass, 1564, 493);
|
||||
CreateObjectAbove(Grass, 1537, 525);
|
||||
CreateObjectAbove(Grass, 1585, 486);
|
||||
CreateObject(Grass, 1739, 429);
|
||||
CreateObjectAbove(Grass, 1739, 430);
|
||||
|
||||
var Torch001 = CreateObjectAbove(Torch, 1869, 1454);
|
||||
var Torch001 = CreateObjectAbove(Torch, 1201, 1549);
|
||||
Torch001->AttachToWall(true);
|
||||
var Torch002 = CreateObjectAbove(Torch, 562, 1126);
|
||||
var Torch002 = CreateObjectAbove(Torch, 1109, 1146);
|
||||
Torch002->AttachToWall(true);
|
||||
var Torch003 = CreateObjectAbove(Torch, 923, 1144);
|
||||
Torch003->AttachToWall(true);
|
||||
var Torch004 = CreateObjectAbove(Torch, 1869, 1454);
|
||||
Torch004->AttachToWall(true);
|
||||
var Torch005 = CreateObjectAbove(Torch, 562, 1126);
|
||||
Torch005->AttachToWall(true);
|
||||
|
||||
var Chest001 = CreateObjectAbove(Chest, 1002, 313);
|
||||
var Chest001 = CreateObject(Chest, 1002, 302);
|
||||
Chest001.Plane = 50;
|
||||
|
||||
var Column001 = CreateObjectAbove(Column, 779, 591);
|
||||
|
@ -104,10 +110,10 @@ func InitializeObjects()
|
|||
var Lichen001 = CreateObjectAbove(Lichen, 2694, 706);
|
||||
Lichen001->SetAction("Grown");
|
||||
|
||||
CreateObjectAbove(BigRock, 1301, 500);
|
||||
CreateObject(BigRock, 1301, 497);
|
||||
CreateObjectAbove(BigRock, 1207, 282);
|
||||
CreateObject(BigRock, 1291, 260);
|
||||
var Amethyst001 = CreateObjectAbove(Amethyst, 803, 583);
|
||||
var Amethyst001 = CreateObject(Amethyst, 803, 579);
|
||||
Amethyst001.Plane = 190;
|
||||
|
||||
var Chest002 = CreateObjectAbove(Chest, 515, 967);
|
||||
|
@ -139,85 +145,12 @@ func InitializeObjects()
|
|||
var Chest019 = CreateObjectAbove(Chest, 730, 135);
|
||||
var Chest020 = CreateObjectAbove(Chest, 1626, 1591);
|
||||
|
||||
var StoneDoor001 = CreateObject(StoneDoor, 940, 1132);
|
||||
StoneDoor001->SetComDir(COMD_Down);
|
||||
StoneDoor001->MakeInvincible();
|
||||
var StoneDoor002 = CreateObject(StoneDoor, 1084, 1132);
|
||||
StoneDoor002->SetComDir(COMD_Down);
|
||||
StoneDoor002->MakeInvincible();
|
||||
var StoneDoor003 = CreateObject(StoneDoor, 564, 436);
|
||||
StoneDoor003->SetComDir(COMD_Down);
|
||||
StoneDoor003->MakeInvincible();
|
||||
var StoneDoor004 = CreateObject(StoneDoor, 843, 716);
|
||||
StoneDoor004->SetComDir(COMD_Down);
|
||||
StoneDoor004->MakeInvincible();
|
||||
var StoneDoor005 = CreateObject(StoneDoor, 1058, 700);
|
||||
StoneDoor005->SetComDir(COMD_Down);
|
||||
StoneDoor005->MakeInvincible();
|
||||
var StoneDoor006 = CreateObject(StoneDoor, 1092, 1028);
|
||||
StoneDoor006->SetComDir(COMD_Down);
|
||||
StoneDoor006->MakeInvincible();
|
||||
var StoneDoor007 = CreateObject(StoneDoor, 1892, 932);
|
||||
StoneDoor007->SetComDir(COMD_Down);
|
||||
StoneDoor007->MakeInvincible();
|
||||
var StoneDoor008 = CreateObject(StoneDoor, 813, 716);
|
||||
StoneDoor008->SetComDir(COMD_Down);
|
||||
StoneDoor008->MakeInvincible();
|
||||
g_last_stone_door = CreateObject(StoneDoor, 781, 716);
|
||||
g_last_stone_door.StaticSaveVar = "g_last_stone_door";
|
||||
g_last_stone_door->SetComDir(COMD_Down);
|
||||
g_last_stone_door->SetClrModulation(0xffa0a0a0);
|
||||
var StoneDoor010 = CreateObject(StoneDoor, 692, 748);
|
||||
StoneDoor010->SetComDir(COMD_Down);
|
||||
StoneDoor010->MakeInvincible();
|
||||
var StoneDoor011 = CreateObject(StoneDoor, 684, 332);
|
||||
StoneDoor011->SetComDir(COMD_Down);
|
||||
StoneDoor011->MakeInvincible();
|
||||
|
||||
var SpinWheel001 = CreateObjectAbove(SpinWheel, 589, 457);
|
||||
SpinWheel001->SetMeshMaterial("SpinWheelGearRed", 0);
|
||||
SpinWheel001->SetStoneDoor(StoneDoor001);
|
||||
var SpinWheel002 = CreateObjectAbove(SpinWheel, 611, 456);
|
||||
SpinWheel002->SetMeshMaterial("SpinWheelGearBlue", 0);
|
||||
SpinWheel002->SetStoneDoor(StoneDoor002);
|
||||
var SpinWheel003 = CreateObjectAbove(SpinWheel, 619, 410);
|
||||
SpinWheel003->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel003->SetStoneDoor(StoneDoor003);
|
||||
var SpinWheel004 = CreateObjectAbove(SpinWheel, 1223, 1553);
|
||||
SpinWheel004->SetStoneDoor(StoneDoor005);
|
||||
var SpinWheel005 = CreateObjectAbove(SpinWheel, 1117, 1048);
|
||||
SpinWheel005->SetStoneDoor(StoneDoor006);
|
||||
var SpinWheel006 = CreateObjectAbove(SpinWheel, 2761, 690);
|
||||
SpinWheel006->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel006->SetStoneDoor(StoneDoor008);
|
||||
var SpinWheel007 = CreateObjectAbove(SpinWheel, 1850, 1463);
|
||||
SpinWheel007->SetMeshMaterial("SpinWheelGearRed", 0);
|
||||
SpinWheel007->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel007->SetStoneDoor(StoneDoor004);
|
||||
var SpinWheel008 = CreateObjectAbove(SpinWheel, 2793, 1521);
|
||||
SpinWheel008->SetMeshMaterial("SpinWheelGearRed", 0);
|
||||
SpinWheel008->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel008->SetStoneDoor(StoneDoor007);
|
||||
var SpinWheel009 = CreateObjectAbove(SpinWheel, 830, 735);
|
||||
SpinWheel009->SetStoneDoor(StoneDoor010);
|
||||
var SpinWheel010 = CreateObjectAbove(SpinWheel, 703, 352);
|
||||
SpinWheel010->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel010->SetStoneDoor(StoneDoor011);
|
||||
|
||||
CreateObjectAbove(Pump, 1027, 1152);
|
||||
|
||||
CreateObjectAbove(Sawmill, 1259, 1047);
|
||||
|
||||
var ToolsWorkshop001 = CreateObjectAbove(ToolsWorkshop, 1169, 903);
|
||||
|
||||
var Column002 = CreateObject(Column, 779, 488);
|
||||
Column002->SetR(180);
|
||||
Column002->SetClrModulation(0xffffd0d0);
|
||||
Column002->SetMeshMaterial("AncientColumn", 0);
|
||||
var Column003 = CreateObject(Column, 1419, 217);
|
||||
Column003->SetMeshMaterial("AncientColumn", 0);
|
||||
CreateObject(Column, 1386, 616);
|
||||
|
||||
CreateObjectAbove(Ruin_Windmill, 1678, 375);
|
||||
|
||||
CreateObjectAbove(Ruin_WoodenCabin, 1199, 1046);
|
||||
|
@ -225,17 +158,18 @@ func InitializeObjects()
|
|||
var Idol001 = CreateObjectAbove(Idol, 1045, 721);
|
||||
Idol001->SetMeshMaterial("IdolGrayColor", 0);
|
||||
|
||||
g_flagpole = CreateObjectAbove(Flagpole, 210, 1185);
|
||||
g_flagpole = CreateObject(Flagpole, 210, 1151);
|
||||
g_flagpole.StaticSaveVar = "g_flagpole";
|
||||
g_flagpole->SetName("Respawn");
|
||||
g_flagpole->SetNeutral(true);
|
||||
|
||||
var LotsOfCoins001 = CreateObject(LotsOfCoins, 805, 583);
|
||||
LotsOfCoins001.Plane = 200;
|
||||
|
||||
g_golden_idol = CreateObject(Idol, 824, 568);
|
||||
g_golden_idol.StaticSaveVar = "g_golden_idol";
|
||||
g_golden_idol->SetR(-4);
|
||||
g_golden_idol.Plane = 220;
|
||||
g_golden_idol.StaticSaveVar = "g_golden_idol";
|
||||
|
||||
var Lorry002 = CreateObjectAbove(Lorry, 200, 1183);
|
||||
var Lorry001 = CreateObjectAbove(Lorry, 708, 1407);
|
||||
|
@ -291,7 +225,7 @@ func InitializeObjects()
|
|||
Clonk007->SetColor(0x802000);
|
||||
Clonk007->SetName("Jane");
|
||||
Clonk007->SetSkin(1);
|
||||
npc_tarzan = CreateObjectAbove(Clonk, 754, 879);
|
||||
npc_tarzan = CreateObjectAbove(Clonk, 750, 859);
|
||||
npc_tarzan->SetXDir(3);
|
||||
npc_tarzan->SetYDir(27);
|
||||
npc_tarzan->SetColor(0x402000);
|
||||
|
@ -345,10 +279,8 @@ func InitializeObjects()
|
|||
Bone004->SetYDir(8);
|
||||
var Bone005 = CreateObject(Bone, 479, 964);
|
||||
Bone005->SetR(-51);
|
||||
Bone005->SetYDir(8);
|
||||
var Bone006 = CreateObject(Bone, 464, 965);
|
||||
Bone006->SetR(-51);
|
||||
Bone006->SetYDir(8);
|
||||
|
||||
Lorry002->CreateContents(Loam, 4);
|
||||
CreateObject(Loam, 153, 1232);
|
||||
|
@ -401,24 +333,24 @@ func InitializeObjects()
|
|||
ToolsWorkshop001->CreateContents(GoldBar);
|
||||
CreateObject(GoldBar, 72, 1463);
|
||||
CreateObject(GoldBar, 2746, 736);
|
||||
CreateObject(GoldBar, 2507, 1262);
|
||||
CreateObjectAbove(GoldBar, 2507, 1262);
|
||||
Chest020->CreateContents(GoldBar);
|
||||
var GoldBar003 = CreateObject(GoldBar, 972, 1277);
|
||||
GoldBar003->SetR(55);
|
||||
|
||||
CreateObject(Ruby, 864, 581);
|
||||
CreateObject(Ruby, 806, 583);
|
||||
CreateObjectAbove(Ruby, 849, 582);
|
||||
CreateObject(Ruby, 849, 578);
|
||||
CreateObject(Ruby, 856, 584);
|
||||
|
||||
var Amethyst002 = CreateObject(Amethyst, 793, 584);
|
||||
Amethyst002->SetR(22);
|
||||
CreateObject(Amethyst, 885, 557);
|
||||
CreateObject(Amethyst, 828, 581);
|
||||
CreateObjectAbove(Amethyst, 828, 585);
|
||||
|
||||
Lorry002->CreateContents(Dynamite, 2);
|
||||
Chest006->CreateContents(Dynamite, 3);
|
||||
CreateObjectAbove(Dynamite, 1046, 722);
|
||||
CreateObjectAbove(Dynamite, 790, 736);
|
||||
Chest005->CreateContents(Dynamite, 2);
|
||||
Chest004->CreateContents(Dynamite, 2);
|
||||
Chest002->CreateContents(Dynamite);
|
||||
|
@ -426,9 +358,14 @@ func InitializeObjects()
|
|||
Chest014->CreateContents(Dynamite, 3);
|
||||
|
||||
var Bow001 = Clonk001->CreateContents(Bow);
|
||||
Chest003->CreateContents(Bow);
|
||||
|
||||
Bow001->CreateContents(Arrow);
|
||||
Clonk001->CreateContents(Arrow);
|
||||
var Arrow001 = CreateObject(Arrow, 313, 431);
|
||||
Arrow001->SetR(90);
|
||||
var Arrow002 = CreateObject(Arrow, 313, 431);
|
||||
Arrow002->SetR(90);
|
||||
var Arrow003 = CreateObject(Arrow, 313, 431);
|
||||
Arrow003->SetR(90);
|
||||
var Arrow004 = CreateObject(Arrow, 313, 431);
|
||||
|
@ -443,13 +380,19 @@ func InitializeObjects()
|
|||
Arrow008->SetR(90);
|
||||
var Arrow009 = CreateObject(Arrow, 313, 431);
|
||||
Arrow009->SetR(90);
|
||||
var Arrow010 = CreateObject(Arrow, 313, 431);
|
||||
Arrow010->SetR(90);
|
||||
var Arrow011 = CreateObject(Arrow, 313, 431);
|
||||
Arrow011->SetR(90);
|
||||
Chest003->CreateContents(Arrow);
|
||||
|
||||
Chest021->CreateContents(Bread, 2);
|
||||
Lorry001->CreateContents(Bread, 3);
|
||||
Chest004->CreateContents(Bread);
|
||||
Chest017->CreateContents(Bread);
|
||||
Chest009->CreateContents(Bread);
|
||||
ToolsWorkshop001->CreateContents(Bread);
|
||||
Chest011->CreateContents(Bread);
|
||||
Chest012->CreateContents(Bread);
|
||||
Chest018->CreateContents(Bread);
|
||||
Chest007->CreateContents(Bread);
|
||||
Chest002->CreateContents(Bread);
|
||||
|
||||
Chest021->CreateContents(DynamiteBox, 2);
|
||||
Chest017->CreateContents(DynamiteBox, 2);
|
||||
|
@ -462,6 +405,7 @@ func InitializeObjects()
|
|||
Chest006->CreateContents(Sword);
|
||||
Clonk004->CreateContents(Sword, 2);
|
||||
Lorry001->CreateContents(Sword);
|
||||
Chest003->CreateContents(Sword);
|
||||
|
||||
CreateObjectAbove(Seaweed, 2494, 1263);
|
||||
CreateObjectAbove(Seaweed, 2508, 1263);
|
||||
|
@ -482,16 +426,16 @@ func InitializeObjects()
|
|||
CreateObjectAbove(Seaweed, 2395, 1239);
|
||||
CreateObjectAbove(Seaweed, 2396, 1239);
|
||||
CreateObjectAbove(Seaweed, 2332, 1145);
|
||||
CreateObjectAbove(Seaweed, 2407, 1246);
|
||||
CreateObject(Seaweed, 2407, 1239);
|
||||
|
||||
CreateObjectAbove(Mushroom, 1580, 759);
|
||||
CreateObjectAbove(Mushroom, 1613, 775);
|
||||
CreateObjectAbove(Mushroom, 1525, 846);
|
||||
CreateObjectAbove(Mushroom, 1612, 862);
|
||||
CreateObjectAbove(Mushroom, 1580, 758);
|
||||
CreateObjectAbove(Mushroom, 1613, 776);
|
||||
CreateObjectAbove(Mushroom, 1525, 847);
|
||||
CreateObjectAbove(Mushroom, 1612, 864);
|
||||
CreateObjectAbove(Mushroom, 1321, 895);
|
||||
CreateObjectAbove(Mushroom, 1315, 894);
|
||||
CreateObjectAbove(Mushroom, 1343, 903);
|
||||
CreateObjectAbove(Mushroom, 1347, 901);
|
||||
CreateObjectAbove(Mushroom, 1315, 895);
|
||||
CreateObjectAbove(Mushroom, 1343, 902);
|
||||
CreateObjectAbove(Mushroom, 1347, 903);
|
||||
|
||||
CreateObjectAbove(Balloon, 491, 383);
|
||||
|
||||
|
@ -552,5 +496,78 @@ func InitializeObjects()
|
|||
CreateObject(Firestone, 2161, 942);
|
||||
CreateObject(Firestone, 2073, 861);
|
||||
CreateObject(Firestone, 2064, 851);
|
||||
|
||||
var StoneDoor001 = CreateObject(StoneDoor, 940, 1132);
|
||||
StoneDoor001->SetComDir(COMD_Down);
|
||||
StoneDoor001->MakeInvincible();
|
||||
var StoneDoor002 = CreateObject(StoneDoor, 1084, 1132);
|
||||
StoneDoor002->SetComDir(COMD_Down);
|
||||
StoneDoor002->MakeInvincible();
|
||||
var StoneDoor003 = CreateObject(StoneDoor, 564, 436);
|
||||
StoneDoor003->SetComDir(COMD_Down);
|
||||
StoneDoor003->MakeInvincible();
|
||||
var StoneDoor004 = CreateObject(StoneDoor, 843, 716);
|
||||
StoneDoor004->SetComDir(COMD_Down);
|
||||
StoneDoor004->MakeInvincible();
|
||||
var StoneDoor005 = CreateObject(StoneDoor, 1058, 700);
|
||||
StoneDoor005->SetComDir(COMD_Down);
|
||||
StoneDoor005->MakeInvincible();
|
||||
var StoneDoor006 = CreateObject(StoneDoor, 1092, 1028);
|
||||
StoneDoor006->SetComDir(COMD_Down);
|
||||
StoneDoor006->MakeInvincible();
|
||||
var StoneDoor007 = CreateObject(StoneDoor, 1892, 932);
|
||||
StoneDoor007->SetComDir(COMD_Down);
|
||||
StoneDoor007->MakeInvincible();
|
||||
var StoneDoor008 = CreateObject(StoneDoor, 813, 716);
|
||||
StoneDoor008->SetComDir(COMD_Down);
|
||||
StoneDoor008->MakeInvincible();
|
||||
g_last_stone_door = CreateObject(StoneDoor, 781, 716);
|
||||
g_last_stone_door->SetComDir(COMD_Down);
|
||||
g_last_stone_door->SetClrModulation(0xffa0a0a0);
|
||||
g_last_stone_door.StaticSaveVar = "g_last_stone_door";
|
||||
var StoneDoor009 = CreateObject(StoneDoor, 692, 748);
|
||||
StoneDoor009->SetComDir(COMD_Down);
|
||||
StoneDoor009->MakeInvincible();
|
||||
var StoneDoor010 = CreateObject(StoneDoor, 684, 332);
|
||||
StoneDoor010->SetComDir(COMD_Down);
|
||||
StoneDoor010->MakeInvincible();
|
||||
|
||||
var SpinWheel001 = CreateObjectAbove(SpinWheel, 589, 457);
|
||||
SpinWheel001->SetMeshMaterial("SpinWheelGearRed", 0);
|
||||
SpinWheel001->SetStoneDoor(StoneDoor001);
|
||||
var SpinWheel002 = CreateObjectAbove(SpinWheel, 611, 456);
|
||||
SpinWheel002->SetMeshMaterial("SpinWheelGearBlue", 0);
|
||||
SpinWheel002->SetStoneDoor(StoneDoor002);
|
||||
var SpinWheel003 = CreateObjectAbove(SpinWheel, 619, 410);
|
||||
SpinWheel003->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel003->SetStoneDoor(StoneDoor003);
|
||||
var SpinWheel004 = CreateObject(SpinWheel, 1223, 1545);
|
||||
SpinWheel004->SetStoneDoor(StoneDoor005);
|
||||
var SpinWheel005 = CreateObjectAbove(SpinWheel, 1117, 1048);
|
||||
SpinWheel005->SetStoneDoor(StoneDoor006);
|
||||
var SpinWheel006 = CreateObjectAbove(SpinWheel, 2761, 690);
|
||||
SpinWheel006->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel006->SetStoneDoor(StoneDoor008);
|
||||
var SpinWheel007 = CreateObjectAbove(SpinWheel, 1850, 1463);
|
||||
SpinWheel007->SetMeshMaterial("SpinWheelGearRed", 0);
|
||||
SpinWheel007->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel007->SetStoneDoor(StoneDoor004);
|
||||
var SpinWheel008 = CreateObjectAbove(SpinWheel, 2793, 1521);
|
||||
SpinWheel008->SetMeshMaterial("SpinWheelGearRed", 0);
|
||||
SpinWheel008->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel008->SetStoneDoor(StoneDoor007);
|
||||
var SpinWheel009 = CreateObjectAbove(SpinWheel, 830, 735);
|
||||
SpinWheel009->SetStoneDoor(StoneDoor009);
|
||||
var SpinWheel010 = CreateObjectAbove(SpinWheel, 703, 352);
|
||||
SpinWheel010->SetMeshMaterial("SpinWheelBaseAlt", 1);
|
||||
SpinWheel010->SetStoneDoor(StoneDoor010);
|
||||
|
||||
var Column002 = CreateObject(Column, 779, 488);
|
||||
Column002->SetR(180);
|
||||
Column002->SetClrModulation(0xffffd0d0);
|
||||
Column002->SetMeshMaterial("AncientColumn", 0);
|
||||
var Column003 = CreateObject(Column, 1419, 217);
|
||||
Column003->SetMeshMaterial("AncientColumn", 0);
|
||||
CreateObject(Column, 1386, 616);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -21,13 +21,13 @@ func Intro_Init(object flagpole)
|
|||
// Pyrit the pilot
|
||||
this.pilot = npc_pyrit = CreateObjectAbove(Clonk, 100, 100, NO_OWNER);
|
||||
this.pilot->MakeInvincible();
|
||||
this.pilot->SetSkin(2);
|
||||
this.pilot->Enter(this.plane);
|
||||
this.pilot->SetAction("Walk");
|
||||
this.pilot->SetName("Pyrit");
|
||||
this.pilot->SetColor(0xff0000);
|
||||
this.pilot->SetDir(DIR_Left);
|
||||
this.pilot->SetObjectLayer(this.pilot);
|
||||
this.pilot->SetAlternativeSkin("MaleBrownHair");
|
||||
|
||||
// Pyit has a red hat!
|
||||
this.pilot->AttachMesh(Hat, "skeleton_head", "main", Trans_Translate(5500, 0, 0));
|
||||
|
|
|
@ -30,19 +30,19 @@
|
|||
protected func Construction()
|
||||
{
|
||||
_inherited(...);
|
||||
|
||||
SetAction("Walk");
|
||||
SetDir(Random(2));
|
||||
// Broadcast for rules
|
||||
GameCallEx("OnClonkCreation", this);
|
||||
|
||||
SetSkin(0);
|
||||
|
||||
AddEffect("IntTurn", this, 1, 1, this);
|
||||
AddEffect("IntEyes", this, 1, 35+Random(4), this);
|
||||
|
||||
AttachBackpack();
|
||||
iHandMesh = [0,0];
|
||||
|
||||
SetSkin(0);
|
||||
|
||||
SetAction("Walk");
|
||||
SetDir(Random(2));
|
||||
// Broadcast for rules
|
||||
GameCallEx("OnClonkCreation", this);
|
||||
}
|
||||
|
||||
/* When adding to the crew of a player */
|
||||
|
@ -455,28 +455,36 @@ static const CARRY_Spear = 6;
|
|||
static const CARRY_Musket = 7;
|
||||
static const CARRY_Grappler = 8;
|
||||
|
||||
func HasHandAction(sec, just_wear)
|
||||
func HasHandAction(sec, just_wear, bool force_landscape_letgo)
|
||||
{
|
||||
// Check if the clonk is currently able to use hands
|
||||
// sec: Needs both hands (e.g. CarryHeavy?)
|
||||
// just_wear: ???
|
||||
// force_landscape_letgo: Also allow from actions where hands are currently grabbing the landscape (scale, hangle)
|
||||
if(sec && fBothHanded)
|
||||
return false;
|
||||
if(just_wear)
|
||||
{
|
||||
if( HasActionProcedure() && !fHandAction ) // For wear purpose fHandAction==-1 also blocks
|
||||
if( HasActionProcedure(force_landscape_letgo) && !fHandAction ) // For wear purpose fHandAction==-1 also blocks
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( HasActionProcedure() && (!fHandAction || fHandAction == -1) )
|
||||
if( HasActionProcedure(force_landscape_letgo) && (!fHandAction || fHandAction == -1) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
func HasActionProcedure()
|
||||
func HasActionProcedure(bool force_landscape_letgo)
|
||||
{
|
||||
// Check if the clonk is currently in an action where he could use his hands
|
||||
// if force_landscape_letgo is true, also allow during scale/hangle assuming the clonk will let go
|
||||
var action = GetAction();
|
||||
if (action == "Walk" || action == "Jump" || action == "WallJump" || action == "Kneel" || action == "Ride" || action == "BridgeStand")
|
||||
return true;
|
||||
if (force_landscape_letgo) if (action == "Scale" || action == "Hangle")
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -653,7 +661,12 @@ func SetSkin(int new_skin)
|
|||
|
||||
RemoveBackpack(); //add a backpack
|
||||
AttachBackpack();
|
||||
SetAction("Jump"); //refreshes animation
|
||||
//refreshes animation (whatever that means?)
|
||||
// Go back to original action afterwards and hope
|
||||
// that noone calls SetSkin during more compex activities
|
||||
var prev_action = GetAction();
|
||||
SetAction("Jump");
|
||||
SetAction(prev_action);
|
||||
|
||||
return skin;
|
||||
}
|
||||
|
|
|
@ -220,8 +220,9 @@ private func Construction()
|
|||
text =
|
||||
{
|
||||
Target = this,
|
||||
Top = "-0.45em",
|
||||
Style = GUI_TextHCenter,
|
||||
Top = "-0.5em",
|
||||
Bottom = "0.5em",
|
||||
Style = GUI_TextHCenter | GUI_TextVCenter,
|
||||
Text = "",
|
||||
Priority = 9
|
||||
}
|
||||
|
@ -231,7 +232,6 @@ private func Construction()
|
|||
Target = this,
|
||||
Player = NO_OWNER,
|
||||
ID = crew_next_id + 3,
|
||||
Style = GUI_NoCrop,
|
||||
Top = "100%+0.6em",
|
||||
Bottom = "100%+0.85em",
|
||||
BackgroundColor = RGB(40, 40, 40),
|
||||
|
@ -826,8 +826,9 @@ private func AddCrewBar(int foreground, int background)
|
|||
text =
|
||||
{
|
||||
Target = this,
|
||||
Top = "-0.45em",
|
||||
Style = GUI_TextHCenter,
|
||||
Top = "-0.5em",
|
||||
Bottom = "0.5em",
|
||||
Style = GUI_TextHCenter | GUI_TextVCenter,
|
||||
Text = "",
|
||||
Priority = 5
|
||||
}
|
||||
|
|
|
@ -159,8 +159,8 @@ func FxIntCheckObjectsTimer(target, effect fx)
|
|||
var new_objects = FindObjects(Find_AtRect(target->GetX() - 5, target->GetY() - 10, 10, 20), container_restriction, Find_Layer(target->GetObjectLayer()),
|
||||
// Find all containers and objects with a custom menu.
|
||||
Find_Or(Find_Func("IsContainer"), Find_Func("HasInteractionMenu")),
|
||||
// Do not show objects with an extra slot though - even if they are containers. They count as items here.
|
||||
Find_Not(Find_And(Find_Category(C4D_Object), Find_Func("HasExtraSlots"))),
|
||||
// Do not show objects with an extra slot though - even if they are containers. They count as items here and can be accessed via the surroundings tab.
|
||||
Find_Not(Find_And(Find_Property("Collectible"), Find_Func("HasExtraSlot"))),
|
||||
// Show only objects that the player can see.
|
||||
Find_Func("CheckVisibility", GetOwner()),
|
||||
// Normally sorted by z-order. But some objects may have a lower priority.
|
||||
|
@ -531,7 +531,7 @@ public func OnMoveAllToClicked(int menu_id)
|
|||
for (obj in contents)
|
||||
{
|
||||
// Sanity, can actually happen if an item merges with others during the transfer etc.
|
||||
if (!obj) continue;
|
||||
if (!obj || !target) continue;
|
||||
|
||||
var collected = target->Collect(obj, true);
|
||||
if (collected)
|
||||
|
@ -750,7 +750,7 @@ func CreateMainMenu(object obj, int slot)
|
|||
{
|
||||
Priority = 1,
|
||||
Style = GUI_TextVCenter | GUI_TextHCenter,
|
||||
Bottom = "+0.75em",
|
||||
Bottom = "+1em",
|
||||
Text = menu.title,
|
||||
BackgroundColor = 0xa0000000,
|
||||
//Decoration = menu.decoration
|
||||
|
|
|
@ -193,8 +193,7 @@ public func StopDialogue()
|
|||
// clear remembered positions
|
||||
dlg_last_opt_sel = nil;
|
||||
// put on wait for a while; then reenable
|
||||
SetDialogueStatus(DLG_Status_Wait);
|
||||
ScheduleCall(this, this.SetDialogueStatus, 30, 1, DLG_Status_Stop);
|
||||
SetDialogueStatus(DLG_Status_Stop);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -245,7 +244,8 @@ public func Interact(object clonk)
|
|||
if (dlg_status == DLG_Status_Stop)
|
||||
{
|
||||
clonk->CloseMenu();
|
||||
dlg_status = DLG_Status_Active;
|
||||
dlg_status = DLG_Status_Wait;
|
||||
ScheduleCall(this, this.SetDialogueStatus, 30, 0, DLG_Status_Active);
|
||||
// Do a call on a closed dialogue as well.
|
||||
var fn_closed = Format("~Dlg_%s_Closed", dlg_name);
|
||||
if (!Call(fn_closed, clonk, dlg_target))
|
||||
|
|
|
@ -21,7 +21,7 @@ public func GetCarryTransform()
|
|||
|
||||
public func RejectUse(object clonk)
|
||||
{
|
||||
return !clonk->HasHandAction();
|
||||
return !clonk->HasHandAction(false, false, true);
|
||||
}
|
||||
|
||||
public func ControlUse(object clonk, int iX, int iY)
|
||||
|
@ -154,3 +154,4 @@ local Name = "$Name$";
|
|||
local Description = "$Description$";
|
||||
local UsageHelp = "$UsageHelp$";
|
||||
local Collectible = true;
|
||||
local ForceFreeHands = true;
|
|
@ -40,7 +40,8 @@ static const Pickaxe_SwingTime = 40;
|
|||
|
||||
public func RejectUse(object clonk)
|
||||
{
|
||||
return clonk->GetProcedure() != "WALK";
|
||||
var proc = clonk->GetProcedure();
|
||||
return proc != "WALK" && proc != "SCALE";
|
||||
}
|
||||
|
||||
func ControlUseStart(object clonk, int ix, int iy)
|
||||
|
@ -52,7 +53,10 @@ func ControlUseStart(object clonk, int ix, int iy)
|
|||
clonk->SetHandAction(1);
|
||||
clonk->UpdateAttach();
|
||||
clonk->PlayAnimation("StrikePickaxe", CLONK_ANIM_SLOT_Arms, Anim_Linear(0, 0, clonk->GetAnimationLength("StrikePickaxe"), Pickaxe_SwingTime, ANIM_Loop), Anim_Const(1000));
|
||||
AddEffect("IntPickaxe", clonk, 1, 1, this);
|
||||
var fx = AddEffect("IntPickaxe", clonk, 1, 1, this);
|
||||
if (!fx) return false;
|
||||
fx.x = ix;
|
||||
fx.y = iy;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -66,13 +70,12 @@ func ControlUseHolding(object clonk, int new_x, int new_y)
|
|||
clonk->PauseUse(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
x = new_x; y = new_y;
|
||||
var fx = GetEffect("IntPickaxe", clonk);
|
||||
if (!fx) return clonk->CancelUse();
|
||||
fx.x = new_x; fx.y = new_y;
|
||||
return true;
|
||||
}
|
||||
|
||||
local x, y;
|
||||
|
||||
func ControlUseStop(object clonk, int ix, int iy)
|
||||
{
|
||||
Reset(clonk);
|
||||
|
@ -164,28 +167,16 @@ public func DigOutObject(object obj)
|
|||
clonk->~DigOutObject(obj);
|
||||
}
|
||||
|
||||
public func FxIntPickaxeStart(object clonk, proplist effect, int temp)
|
||||
{
|
||||
if (temp)
|
||||
return FX_OK;
|
||||
// Ensure ActMap is local and writable
|
||||
if (clonk.ActMap == clonk.Prototype.ActMap) clonk.ActMap = new clonk.ActMap {};
|
||||
// Disable scaling during usage.
|
||||
effect.actmap_scale = clonk.ActMap.Scale;
|
||||
clonk.ActMap.Scale = nil;
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
public func FxIntPickaxeTimer(object clonk, proplist effect, int time)
|
||||
{
|
||||
++swingtime;
|
||||
if(swingtime >= Pickaxe_SwingTime) // Waits three seconds for animation to run (we could have a clonk swing his pick 3 times)
|
||||
{
|
||||
DoSwing(clonk,x,y);
|
||||
DoSwing(clonk,effect.x,effect.y);
|
||||
swingtime = 0;
|
||||
}
|
||||
|
||||
var angle = Angle(0,0,x,y);
|
||||
var angle = Angle(0,0,effect.x,effect.y);
|
||||
var speed = 50;
|
||||
|
||||
var iPosition = swingtime*180/Pickaxe_SwingTime;
|
||||
|
@ -196,15 +187,6 @@ public func FxIntPickaxeTimer(object clonk, proplist effect, int time)
|
|||
clonk->SetYDir(Cos(angle,-speed),100);
|
||||
}
|
||||
|
||||
public func FxIntPickaxeStop(object clonk, proplist effect, int reason, bool temp)
|
||||
{
|
||||
if (temp)
|
||||
return FX_OK;
|
||||
// Reset the clonk scaling entry in its ActMap.
|
||||
clonk.ActMap.Scale = effect.actmap_scale;
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
protected func ControlUseCancel(object clonk, int ix, int iy)
|
||||
{
|
||||
Reset(clonk);
|
||||
|
@ -246,3 +228,4 @@ local Name = "$Name$";
|
|||
local Description = "$Description$";
|
||||
local UsageHelp = "$UsageHelp$";
|
||||
local MaxPickDensity = 70; // can't pick granite
|
||||
local ForceFreeHands = true;
|
||||
|
|
|
@ -38,6 +38,8 @@ public func ControlUseStart(object clonk, int x, int y)
|
|||
DigFree(clonk->GetX(), clonk->GetY(), 10);
|
||||
}
|
||||
|
||||
ControlUseHolding(clonk, x, y); // initial coordinate setup
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ public func GetAnimationSet() { return animation_set; }
|
|||
public func RejectUse(object clonk)
|
||||
{
|
||||
// if the clonk doesn't have an action where he can use it's hands do nothing
|
||||
return !clonk->HasHandAction();
|
||||
return !clonk->HasHandAction(false, false, true);
|
||||
}
|
||||
|
||||
public func ControlUseStart(object clonk, int x, int y)
|
||||
|
@ -233,4 +233,5 @@ local Description = "$Description$";
|
|||
local UsageHelp = "$UsageHelp$";
|
||||
local Collectible = 1;
|
||||
local BlastIncinerate = 30;
|
||||
local ContactIncinerate = 5;
|
||||
local ContactIncinerate = 5;
|
||||
local ForceFreeHands = true;
|
||||
|
|
|
@ -67,7 +67,7 @@ local fAiming;
|
|||
|
||||
public func RejectUse(object clonk)
|
||||
{
|
||||
return !CanStrikeWithWeapon(clonk) || !clonk->HasHandAction();
|
||||
return !CanStrikeWithWeapon(clonk) || !clonk->HasHandAction(false, false, true);
|
||||
}
|
||||
|
||||
public func ControlUseStart(object clonk, int x, int y)
|
||||
|
@ -99,6 +99,12 @@ public func ControlUseStop(object clonk, ix, iy)
|
|||
return true;
|
||||
}
|
||||
|
||||
public func ControlUseCancel(object clonk, ix, iy)
|
||||
{
|
||||
clonk->StopAim();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback from the clonk, when he actually has stopped aiming
|
||||
public func FinishedAiming(object clonk, int angle)
|
||||
{
|
||||
|
@ -245,3 +251,4 @@ local Collectible = 1;
|
|||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local UsageHelp = "$UsageHelp$";
|
||||
local ForceFreeHands = true;
|
|
@ -65,7 +65,7 @@ protected func HoldingEnabled() { return true; }
|
|||
|
||||
public func RejectUse(object clonk)
|
||||
{
|
||||
return !clonk->HasHandAction();
|
||||
return !clonk->HasHandAction(false, false, true);
|
||||
}
|
||||
|
||||
func ControlUseStart(object clonk, int x, int y)
|
||||
|
@ -201,4 +201,5 @@ func Definition(def)
|
|||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local UsageHelp = "$UsageHelp$";
|
||||
local Collectible = 1;
|
||||
local Collectible = 1;
|
||||
local ForceFreeHands = true;
|
|
@ -28,7 +28,7 @@ func Fuse(bool explode_on_hit)
|
|||
AddEffect("FuseBurn", this, 1,1, this);
|
||||
}
|
||||
|
||||
func FxFuseBurnTimer(object bomb, int num, int timer)
|
||||
func FxFuseBurnTimer(object bomb, proplist effect, int timer)
|
||||
{
|
||||
var i = 3;
|
||||
var x = +Sin(GetR(), i);
|
||||
|
|
|
@ -16,7 +16,7 @@ public func Launch(int shooter)
|
|||
AddEffect("HitCheck", this, 1,1, nil, nil);
|
||||
}
|
||||
|
||||
protected func FxFadeTimer(object target, int num, int timer)
|
||||
protected func FxFadeTimer(object target, proplist effect, int timer)
|
||||
{
|
||||
if(timer > FlightTime()) RemoveObject();
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public func GetCarryTransform() { if(aiming == 1) return Trans_Rotate(180, 0, 0,
|
|||
|
||||
public func RejectUse(object clonk)
|
||||
{
|
||||
return !clonk->HasHandAction();
|
||||
return !clonk->HasHandAction(false, false, true);
|
||||
}
|
||||
|
||||
public func ControlUseStart(object clonk, int x, int y)
|
||||
|
@ -229,3 +229,4 @@ func Definition(def) {
|
|||
local Collectible = 1;
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local ForceFreeHands = true;
|
||||
|
|
|
@ -62,7 +62,7 @@ protected func HoldingEnabled() { return true; }
|
|||
|
||||
func RejectUse(object clonk)
|
||||
{
|
||||
return !clonk->HasHandAction();
|
||||
return !clonk->HasHandAction(false, false, true);
|
||||
}
|
||||
|
||||
func ControlUseStart(object clonk, int x, int y)
|
||||
|
@ -192,3 +192,4 @@ local Name = "$Name$";
|
|||
local Description = "$Description$";
|
||||
local UsageHelp = "$UsageHelp$";
|
||||
local Collectible = 1;
|
||||
local ForceFreeHands = true;
|
||||
|
|
|
@ -616,6 +616,9 @@ func StartUseControl(int ctrl, int x, int y, object obj)
|
|||
// but still catch command
|
||||
return true;
|
||||
}
|
||||
|
||||
// Disable climb/hangle actions for the duration of this use
|
||||
if (obj.ForceFreeHands && !GetEffect("IntControlFreeHands", this)) AddEffect("IntControlFreeHands", this, 130, 0, this);
|
||||
|
||||
obj->SetController(GetController());
|
||||
this.control.current_object = obj;
|
||||
|
@ -665,6 +668,9 @@ func StartUseDelayedControl(int ctrl, object obj)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Disable climb/hangle actions for the duration of this use
|
||||
if (obj.ForceFreeHands && !GetEffect("IntControlFreeHands", this)) AddEffect("IntControlFreeHands", this, 130, 0, this);
|
||||
|
||||
this.control.current_object = obj;
|
||||
this.control.using_type = DetermineUsageType(obj);
|
||||
this.control.alt = ctrl != CON_UseDelayed;
|
||||
|
@ -718,6 +724,8 @@ func StopUseControl(int x, int y, object obj, bool cancel)
|
|||
if (removal_helper.CommandTarget != this) continue;
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
RemoveEffect("IntControlFreeHands", this); // make sure we can climb again
|
||||
|
||||
this.control.current_object = nil;
|
||||
this.control.using_type = nil;
|
||||
|
@ -918,6 +926,31 @@ func ControlMovement2Script(int ctrl, int x, int y, int strength, bool repeat, b
|
|||
|
||||
}
|
||||
|
||||
// Effect to free/unfree hands by disabling/enabling scale and hangle procedures
|
||||
public func FxIntControlFreeHandsStart(object target, proplist fx, int temp)
|
||||
{
|
||||
// Process on non-temp as well in case scale/handle effects need to stack
|
||||
// Stop current action
|
||||
var proc = GetProcedure();
|
||||
if (proc == "SCALE" || proc == "HANGLE") SetAction("Walk");
|
||||
// Make sure ActMap is writable
|
||||
if (this.ActMap == this.Prototype.ActMap) this.ActMap = new this.ActMap{};
|
||||
// Kill scale/hangle effects
|
||||
fx.act_scale = this.ActMap.Scale;
|
||||
this.ActMap.Scale = nil;
|
||||
fx.act_hangle = this.ActMap.Hangle;
|
||||
this.ActMap.Hangle = nil;
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
public func FxIntControlFreeHandsStop(object target, proplist fx, int reason, bool temp)
|
||||
{
|
||||
// Restore scale/hangle effects (engine will handle re-grabbing walls if needed)
|
||||
if (fx.act_scale) this.ActMap.Scale = fx.act_scale;
|
||||
if (fx.act_hangle) this.ActMap.Hangle = fx.act_hangle;
|
||||
return FX_OK;
|
||||
}
|
||||
|
||||
// returns true if the clonk is able to enter a building (procedurewise)
|
||||
public func CanEnter()
|
||||
{
|
||||
|
@ -1176,11 +1209,6 @@ public func ControlJump()
|
|||
return false;
|
||||
}
|
||||
|
||||
func FxIsWallKickStart(object target, int num, bool temp)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Interaction with clonks is special:
|
||||
// * The clonk opening the menu should always have higher priority so the clonk is predictably selected on the left side even if standing behind e.g. a crate
|
||||
// * Other clonks should be behind because interaction with them is rare but having your fellow players stand in front of a building is very common
|
||||
|
|
|
@ -122,7 +122,14 @@ private func TransferInventory(object from, object to)
|
|||
while (i--)
|
||||
if (contents = from->Contents(i))
|
||||
if (contents->~IsDroppedOnDeath(from))
|
||||
{
|
||||
contents->Exit();
|
||||
}
|
||||
else
|
||||
{
|
||||
// The new clonk doesn't burn. To be consistent, also extinguish contents
|
||||
contents->Extinguish();
|
||||
}
|
||||
return to->GrabContents(from);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
/*-- Buy at flagpole --*/
|
||||
|
||||
public func Construction(...)
|
||||
{
|
||||
// This rule enables wealth display because it's annoying to not
|
||||
// know your wealth in multiplayer when many people buy/sell at
|
||||
// the flagpole)
|
||||
// Doesn't remove the display on destruction because there's no
|
||||
// refcounting for this command.
|
||||
GUI_Controller->ShowWealth();
|
||||
return _inherited(...);
|
||||
}
|
||||
|
||||
protected func Activate(int iByPlayer)
|
||||
{
|
||||
MessageWindow(GetProperty("Description"), iByPlayer);
|
||||
|
|
|
@ -3,17 +3,17 @@ uniform sampler2D normalTex;
|
|||
uniform mat3 normalMatrix;
|
||||
|
||||
#ifndef OPENCLONK
|
||||
varying vec2 texcoord;
|
||||
in vec2 texcoord;
|
||||
out vec4 fragColor;
|
||||
#define slice(x)
|
||||
#define color gl_FragColor
|
||||
void main()
|
||||
{
|
||||
color = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
fragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
#endif
|
||||
|
||||
slice(texture+1)
|
||||
{
|
||||
color = color * texture2D(basemap, texcoord);
|
||||
fragColor = fragColor * texture(basemap, texcoord);
|
||||
|
||||
#ifndef OPENCLONK
|
||||
// TODO: Could apply some default lighting here, for viewing the mesh in
|
||||
|
@ -27,7 +27,7 @@ slice(normal+1)
|
|||
// from ObjectShader.glsl. It's probably optimized out,
|
||||
// but a more elegant solution would be nice. Also maybe
|
||||
// a function in UtilShader.glsl to reduce code duplication.
|
||||
vec4 normalPx = texture2D(normalTex, texcoord);
|
||||
vec4 normalPx = texture(normalTex, texcoord);
|
||||
vec3 normalPxDir = 2.0 * (normalPx.xyz - vec3(0.5, 0.5, 0.5));
|
||||
normal = normalize(normalMatrix * normalPxDir);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
attribute vec3 oc_Position;
|
||||
attribute vec3 oc_Normal;
|
||||
attribute vec2 oc_TexCoord;
|
||||
in vec3 oc_Position;
|
||||
in vec3 oc_Normal;
|
||||
in vec2 oc_TexCoord;
|
||||
|
||||
varying vec3 vtxNormal;
|
||||
varying vec2 texcoord;
|
||||
out vec3 vtxNormal;
|
||||
out vec2 texcoord;
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
uniform mat4 modelviewMatrix;
|
||||
|
|
|
@ -23,43 +23,36 @@ func SetPaintCol(int idx)
|
|||
}
|
||||
|
||||
// Impact sound
|
||||
func Hit()
|
||||
public func Hit()
|
||||
{
|
||||
Sound("Hits::GeneralHit?");
|
||||
}
|
||||
|
||||
// Item activation
|
||||
func ControlUseStart(object clonk, int x, int y)
|
||||
public func ControlUseStart(object clonk, int x, int y)
|
||||
{
|
||||
if (Distance(0,0,x,y) > max_dist) return true;
|
||||
|
||||
x += GetX(); y += GetY();
|
||||
last_x = x; last_y = y;
|
||||
last_ldx=last_ldy=0;
|
||||
var r = Random(90), wdt = 2;
|
||||
var ldx = Sin(r, wdt), ldy = Cos(r, wdt);
|
||||
DrawMaterialQuad(paint_col, x-ldx,y-ldy, x-ldy,y+ldx, x+ldx,y+ldy, x+ldy,y-ldx, DMQ_Bridge);
|
||||
SetAction("Spraying");
|
||||
return true;
|
||||
return ControlUseHolding(clonk, x, y);
|
||||
}
|
||||
|
||||
func HoldingEnabled() { return true; }
|
||||
public func HoldingEnabled() { return true; }
|
||||
|
||||
func ControlUseHolding(object clonk, int new_x, int new_y)
|
||||
{
|
||||
new_x += GetX(); new_y += GetY();
|
||||
if (new_x==last_x && new_y == last_y) return true;
|
||||
|
||||
if (Distance(GetX(),GetY(),new_x,new_y) > max_dist)
|
||||
public func ControlUseHolding(object clonk, int new_x, int new_y)
|
||||
{
|
||||
// Out of reach? Stop spraying.
|
||||
if (Distance(0,0,new_x,new_y) > max_dist)
|
||||
{
|
||||
last_x = new_x;
|
||||
last_y = new_y;
|
||||
SetAction("Idle");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GetAction() != "Spraying") SetAction("Spraying");
|
||||
// Work in global coordinates
|
||||
new_x += GetX(); new_y += GetY();
|
||||
|
||||
// (re-)start spraying
|
||||
if (GetAction() != "Spraying") StartSpraying(clonk, new_x, new_y);
|
||||
|
||||
// Spray paint if position moved
|
||||
if (new_x==last_x && new_y == last_y) return true;
|
||||
var wdt = 2;
|
||||
var dx=new_x-last_x, dy=new_y-last_y;
|
||||
var d = Distance(dx,dy);
|
||||
|
@ -83,6 +76,19 @@ public func ControlUseCancel(object clonk, int x, int y)
|
|||
return true;
|
||||
}
|
||||
|
||||
private func StartSpraying(object clonk, int x, int y)
|
||||
{
|
||||
// Go into spray mode and place an initial blob
|
||||
last_x = x; last_y = y;
|
||||
last_ldx=last_ldy=0;
|
||||
var r = Random(90), wdt = 2;
|
||||
var ldx = Sin(r, wdt), ldy = Cos(r, wdt);
|
||||
DrawMaterialQuad(paint_col, x-ldx,y-ldy, x-ldy,y+ldx, x+ldx,y+ldy, x+ldy,y-ldx, DMQ_Bridge);
|
||||
SetAction("Spraying");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
local ActMap = {
|
||||
Spraying = {
|
||||
Prototype = Action,
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
Override screenshot functionality
|
||||
--*/
|
||||
|
||||
global func PlayerControl(int plr, int ctrl)
|
||||
global func PlayerControl(int plr, int ctrl, ...)
|
||||
{
|
||||
if (ctrl == CON_TryScreenshot)
|
||||
{
|
||||
CustomMessage(Format("$MsgCheater$", GetTaggedPlayerName(plr)));
|
||||
Sound("Error", true);
|
||||
Sound("UI::Error", true);
|
||||
//var crew = GetCursor(plr); - used for cheating
|
||||
//if (crew) crew->Punch(crew, 50);
|
||||
return true;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Makes sure the guide message is hidden when starting a dialogue and shown again when closing.
|
||||
|
||||
#appendto Dialogue
|
||||
|
||||
public func Interact(object clonk)
|
||||
{
|
||||
if (!dlg_interact || !dlg_name)
|
||||
return inherited(clonk, ...);
|
||||
var guide = FindObject(Find_ID(TutorialGuide), Find_Owner(clonk->GetOwner()));
|
||||
if (!guide)
|
||||
return inherited(clonk, ...);
|
||||
if (dlg_status == DLG_Status_Stop)
|
||||
{
|
||||
if (this.guide_was_shown)
|
||||
{
|
||||
this.guide_was_shown = false;
|
||||
guide->ShowGuide();
|
||||
}
|
||||
}
|
||||
else if (dlg_status != DLG_Status_Remove && dlg_status != DLG_Status_Wait)
|
||||
{
|
||||
if (!guide->IsHidden())
|
||||
{
|
||||
this.guide_was_shown = true;
|
||||
guide->HideGuide();
|
||||
}
|
||||
}
|
||||
return inherited(clonk, ...);
|
||||
}
|
|
@ -146,14 +146,10 @@ private func InitializeMenu()
|
|||
var prop_text =
|
||||
{
|
||||
Left = Format("0%%%s", ToEmString(10 * menu_height + text_margin)),
|
||||
Right = Format("100%%%s", ToEmString(- 5 * menu_height - text_margin)),
|
||||
// Wrap the text again to scroll only one window instead of also scrolling e.g. the portrait.
|
||||
text =
|
||||
{
|
||||
Target = this,
|
||||
ID = 2,
|
||||
Text = nil,
|
||||
}
|
||||
// 'Right' will be set on update
|
||||
Target = this,
|
||||
ID = 2,
|
||||
Text = nil,
|
||||
};
|
||||
prop_next =
|
||||
{
|
||||
|
@ -222,8 +218,17 @@ private func ShowGuideMenu(int index)
|
|||
private func UpdateGuideMenu(string guide_message, bool has_next, bool has_prev, bool has_close)
|
||||
{
|
||||
// Update the text message entry.
|
||||
prop_menu.text.text.Text = guide_message;
|
||||
GuiUpdateText(guide_message, id_menu, prop_menu.text.text.ID, this);
|
||||
prop_menu.text.Text = guide_message;
|
||||
|
||||
// Don't usually leave a margin for the text - just when actually showing buttons.
|
||||
var is_showing_buttons = has_next || has_close || has_prev;
|
||||
|
||||
var text_right_side = "100%";
|
||||
if (is_showing_buttons)
|
||||
{
|
||||
text_right_side = Format("100%-2.9em");
|
||||
}
|
||||
GuiUpdate({Right = text_right_side, Text = guide_message}, id_menu, prop_menu.text.ID, this);
|
||||
|
||||
// Update the next/close button.
|
||||
if (has_next || has_close)
|
||||
|
|
|
@ -62,6 +62,7 @@ private func InitVillageEntrance()
|
|||
var site = CreateObjectAbove(ConstructionSite, 264, 386);
|
||||
site.MeshTransformation = Trans_Mul(Trans_Rotate(RandomX(-30, 30), 0, 1, 0), Trans_Rotate(RandomX(-10, 10), 1, 0, 0));
|
||||
site->Set(Sawmill);
|
||||
site->MakeUncancellable();
|
||||
site->CreateContents(Wood, 1);
|
||||
site->CreateContents(Rock, 1);
|
||||
|
||||
|
@ -202,7 +203,7 @@ private func InitAI()
|
|||
barrel->SetFilled("Water", 300);
|
||||
npc_fireman->SetObjectLayer(npc_fireman);
|
||||
npc_fireman->SetDir(DIR_Left);
|
||||
npc_fireman->SetDialogue("Fireman", true);
|
||||
npc_fireman->SetDialogue("Fireman", false);
|
||||
npc_fireman->SetAlternativeSkin("MaleDarkHair");
|
||||
|
||||
// A builder which tells you where to place the flagpole.
|
||||
|
@ -211,7 +212,7 @@ private func InitAI()
|
|||
npc_builder->CreateContents(Hammer);
|
||||
npc_builder->SetObjectLayer(npc_builder);
|
||||
npc_builder->SetDir(DIR_Left);
|
||||
npc_builder->SetDialogue("Builder", true);
|
||||
npc_builder->SetDialogue("Builder", false);
|
||||
npc_builder->SetAlternativeSkin("Carpenter");
|
||||
|
||||
// A farmer near the grain field.
|
||||
|
@ -413,7 +414,9 @@ global func FxTutorialSawmillFinishedTimer(object target, proplist effect)
|
|||
// Notify lumberjack the sawmill is done.
|
||||
var dialogue_lumberjack = Dialogue->FindByName("Lumberjack");
|
||||
if (dialogue_lumberjack)
|
||||
dialogue_lumberjack->SetDialogueProgress(5, nil, true);
|
||||
dialogue_lumberjack->SetDialogueProgress(5, nil, false);
|
||||
Dialogue->FindByName("Fireman")->AddAttention();
|
||||
Dialogue->FindByName("Builder")->AddAttention();
|
||||
return FX_Execute_Kill;
|
||||
}
|
||||
return FX_OK;
|
||||
|
@ -456,6 +459,10 @@ global func FxTutorialPlacedFlagpoleTimer(object target, proplist effect)
|
|||
guide->ShowGuideMessage();
|
||||
var new_effect = AddEffect("TutorialTalkedToLumberjack2", nil, 100, 5);
|
||||
new_effect.plr = effect.plr;
|
||||
// Notify lumberjack that player talked to other npc's.
|
||||
var dialogue_lumberjack = Dialogue->FindByName("Lumberjack");
|
||||
if (dialogue_lumberjack)
|
||||
dialogue_lumberjack->SetDialogueProgress(6, nil, true);
|
||||
return FX_Execute_Kill;
|
||||
}
|
||||
return FX_OK;
|
||||
|
|
|
@ -35,27 +35,35 @@ public func Dlg_Lumberjack_4(object clonk)
|
|||
|
||||
public func Dlg_Lumberjack_5(object clonk)
|
||||
{
|
||||
MessageBox("$DlgLumberjackWellDone$", clonk, dlg_target);
|
||||
MessageBox("$DlgLumberjackTalkToOthers$", clonk, dlg_target);
|
||||
StopDialogue();
|
||||
SetDialogueProgress(5);
|
||||
return true;
|
||||
}
|
||||
|
||||
public func Dlg_Lumberjack_6(object clonk)
|
||||
{
|
||||
MessageBox("$DlgLumberjackFavor$", clonk, clonk);
|
||||
MessageBox("$DlgLumberjackWellDone$", clonk, dlg_target);
|
||||
return true;
|
||||
}
|
||||
|
||||
public func Dlg_Lumberjack_7(object clonk)
|
||||
{
|
||||
MessageBox("$DlgLumberjackMines$", clonk, dlg_target);
|
||||
MessageBox("$DlgLumberjackFavor$", clonk, clonk);
|
||||
return true;
|
||||
}
|
||||
|
||||
public func Dlg_Lumberjack_8(object clonk)
|
||||
{
|
||||
MessageBox("$DlgLumberjackMines$", clonk, dlg_target);
|
||||
return true;
|
||||
}
|
||||
|
||||
public func Dlg_Lumberjack_9(object clonk)
|
||||
{
|
||||
MessageBox("$DlgLumberjackLook$", clonk, clonk);
|
||||
StopDialogue();
|
||||
SetDialogueProgress(5);
|
||||
SetDialogueProgress(6);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ DlgLumberjackHello=Hallo, ich bin %s, die Holzfällerin des Dorfes.
|
|||
DlgLumberjackReply=Ich heiße %s. Du schaust traurig aus.
|
||||
DlgLumberjackSawmill=Ja, das stimmt. Mein Sägewerk wurde zerstört und ich finde keine Steine, um es wieder aufzubauen. Kannst du mir helfen?
|
||||
DlgLumberjackRock=Ja, ich werde dir Steine finden.
|
||||
DlgLumberjackTalkToOthers=Danke, vielleicht kannst du jetzt einem der anderen Dorfbewohner helfen.
|
||||
DlgLumberjackWellDone=Danke vielmals, dass du das Sägewerk aufgebaut hast. Kann ich irgendwas für dich tun?
|
||||
DlgLumberjackFavor=Tatsächlich kannst du das, ja. Ich brauche Holz, du hast nicht zufällig eine Axt?
|
||||
DlgLumberjackMines=Nein, leider nicht. Ich habe meine Axt in der Mine fallen gelassen, als ich mich während des Angriffes versteckt habe.
|
||||
|
|
|
@ -3,6 +3,7 @@ DlgLumberjackHello=Hello I am %s, the lumberjack of this small village.
|
|||
DlgLumberjackReply=My name is %s, you seem sad.
|
||||
DlgLumberjackSawmill=Yes, indeed. My sawmill got destroyed and I can't find any rock to rebuild it. Can you help me?
|
||||
DlgLumberjackRock=Yes, I'll find you some rock.
|
||||
DlgLumberjackTalkToOthers=Thank you, maybe you can help one of the other villagers now.
|
||||
DlgLumberjackWellDone=Thanks a lot, for constructing the sawmill. Can I do anything for you?
|
||||
DlgLumberjackFavor=Actually you can, I need wood, do you happen to have an axe?
|
||||
DlgLumberjackMines=No, I don't, but I have dropped my axe in the mines when I was hiding there during the attack.
|
||||
|
|
|
@ -1 +1 @@
|
|||
Sky.jpg adapted from http://commons.wikimedia.org/wiki/File:Berge_mountains.JPG (Steinsplitter CC BY-SA 3.0)
|
||||
Sky.jpg adapted from http://commons.wikimedia.org/wiki/File:Berge_mountains.JPG (Steinsplitter CC BY 3.0)
|
|
@ -1,5 +1,5 @@
|
|||
Clonkomotive
|
||||
|
||||
A once flourishing train route through Clonkomotive Canyon has been disrupted by heavy rockfall. The rockfall destroyed the necessary bridges to connect the cliffs in between the canyons, thereby disconnecting two villages on the route. You are left with the locomotive in one of the villages and now you need to rebuild the route to the other village. Luckily Nature has settled and the rockfall has become less severe.
|
||||
Einst florierte die Eisenbahnstrecke durch den Clonkomotive Canyon, doch hat ein schwerer Steinschlag die Strecke zerstört. Die Brücken über die Schluchten wurden sämtlich vernichtet und die beiden Dörfer an den Enden des Canyons sind nun ohne Verbindung. Du findest dich in einem der Dörfer wieder und stehst vor der Aufgabe, die Strecke wieder herzurichten. Glücklicherweise hat sich der Steinschlag etwas beruhigt und ein Aufbau der Strecke ist überhaupt machbar.
|
||||
|
||||
Goal: Transport the locomotive to the village on the far right.
|
||||
Ziel: Bringe die Lokomotive zum Dorf auf der rechten Seite.
|
|
@ -1,2 +1,2 @@
|
|||
Name=HeavyCrumb
|
||||
Description=Hurts Clonks and buildings!
|
||||
Name=Felsbrocken
|
||||
Description=Verletzt Clonks und beschädigt Gebäude.
|
|
@ -1,2 +1,2 @@
|
|||
Name=HeavyCrumb
|
||||
Description=Hurts Clonks and buildings!
|
||||
Name=Boulder
|
||||
Description=Hurts Clonks and damages buildings.
|
|
@ -1,4 +1,4 @@
|
|||
# Intro sequence messages
|
||||
MsgDriveTrain=We only have to drive this train to the village on the other side of these canyons.
|
||||
MsgOutOfFuel=Are we out of fuel again?!
|
||||
MsgBridgesGone=Yes, and it seems all the bridges over the canyons have been destroyed as well.
|
||||
MsgDriveTrain=Dieser Zug muss zum Dorf auf der anderen Seite des Canyons.
|
||||
MsgOutOfFuel=Ist der Treibstoff etwa wieder alle?
|
||||
MsgBridgesGone=Ja, aber die Brücken über die Schluchten sind sowieso zerstört worden.
|
|
@ -1282,8 +1282,10 @@ bool C4PlayerControl::ExecuteControlScript(int32_t iControl, C4ID idControlExtra
|
|||
{
|
||||
x = rKeyExtraData.game_x; y = rKeyExtraData.game_y;
|
||||
}
|
||||
C4Value vx = (x == C4KeyEventData::KeyPos_None) ? C4VNull : C4VInt(x);
|
||||
C4Value vy = (y == C4KeyEventData::KeyPos_None) ? C4VNull : C4VInt(y);
|
||||
// exec control function
|
||||
C4AulParSet Pars(C4VInt(iPlr), C4VInt(iControl), C4VPropList(C4Id2Def(idControlExtraData)), C4VInt(x), C4VInt(y), C4VInt(rKeyExtraData.iStrength), C4VBool(fRepeated), C4VBool(fUp));
|
||||
C4AulParSet Pars(C4VInt(iPlr), C4VInt(iControl), C4VPropList(C4Id2Def(idControlExtraData)), vx, vy, C4VInt(rKeyExtraData.iStrength), C4VBool(fRepeated), C4VBool(fUp));
|
||||
return ::ScriptEngine.GetPropList()->Call(PSF_PlayerControl, &Pars).getBool();
|
||||
}
|
||||
|
||||
|
|
|
@ -552,7 +552,7 @@ void C4ConsoleGUI::DisplayInfoText(InfoTextType type, StdStrBuf& text)
|
|||
{
|
||||
case CONSOLE_Cursor:
|
||||
gtk_statusbar_pop(GTK_STATUSBAR(state->statusBar), 0);
|
||||
gtk_statusbar_push(GTK_STATUSBAR(state->statusBar), 0, text.getData());
|
||||
if (text.getData()) gtk_statusbar_push(GTK_STATUSBAR(state->statusBar), 0, text.getData());
|
||||
return;
|
||||
case CONSOLE_FrameCounter:
|
||||
label = state->lblFrame;
|
||||
|
|
|
@ -135,6 +135,9 @@ public:
|
|||
void Win32KeepDialogsFloating(HWND hwnd = 0);
|
||||
virtual bool Win32DialogMessageHandling(MSG *msg);
|
||||
void UpdateMenuText(HMENU hMenu);
|
||||
|
||||
friend INT_PTR CALLBACK PropertyDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam);
|
||||
friend INT_PTR CALLBACK ConsoleDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -78,6 +78,16 @@ public:
|
|||
int MenuIndexViewport;
|
||||
int MenuIndexNet;
|
||||
int MenuIndexHelp;
|
||||
int property_dlg_inputarea_height;
|
||||
int property_dlg_margin;
|
||||
int property_dlg_okbutton_width;
|
||||
HWND console_handle;
|
||||
int console_default_width, console_default_height; // default (and minimum) console window size
|
||||
int console_margin; // margins between controls and from window borders
|
||||
int console_wide_margin; // larger margins around some console buttons
|
||||
int console_button_height; // height of buttons and the three control rows in the console
|
||||
int console_ok_button_width; // width of OK button to enter script commands (everyone just presses enter anyway...)
|
||||
int console_status_width; // width of frame counter and time/FPS display status boxes
|
||||
|
||||
State(C4ConsoleGUI *console)
|
||||
{
|
||||
|
@ -97,6 +107,17 @@ public:
|
|||
MenuIndexViewport = 2;
|
||||
MenuIndexNet = -1;
|
||||
MenuIndexHelp = 3;
|
||||
property_dlg_inputarea_height = 0;
|
||||
property_dlg_margin = 0;
|
||||
property_dlg_okbutton_width = 0;
|
||||
console_handle = NULL;
|
||||
console_default_width = 0;
|
||||
console_default_height = 0;
|
||||
console_margin = 0;
|
||||
console_wide_margin = 0;
|
||||
console_button_height = 0;
|
||||
console_ok_button_width = 0;
|
||||
console_status_width = 0;
|
||||
}
|
||||
|
||||
~State()
|
||||
|
@ -155,6 +176,159 @@ public:
|
|||
hSubMenu = GetSubMenu(hMenu,MenuIndexHelp);
|
||||
SetMenuItemText(hSubMenu,IDM_HELP_ABOUT,LoadResStr("IDS_MENU_ABOUT"));
|
||||
}
|
||||
|
||||
void PropertyDlgInitLayout()
|
||||
{
|
||||
// Find out desired sizes and margins of elements used in property dialogue.
|
||||
// Just remember initial layout.
|
||||
// This is easier than getting all values from Windows metrics definitions.
|
||||
RECT client_rc = { 0,0,252,101 }, button_rc = { 207,182,254,202 };
|
||||
::GetClientRect(hPropertyDlg, &client_rc);
|
||||
HWND button = ::GetDlgItem(hPropertyDlg, IDOK);
|
||||
::GetWindowRect(button, &button_rc);
|
||||
property_dlg_inputarea_height = button_rc.bottom - button_rc.top;
|
||||
property_dlg_margin = 1; // hardcoded. The elements are actually placed quite poorly in the .rc, cannot derive from it
|
||||
property_dlg_okbutton_width = button_rc.right - button_rc.left;
|
||||
}
|
||||
|
||||
void PropertyDlgUpdateSize()
|
||||
{
|
||||
// Positions unknown?
|
||||
if (!property_dlg_inputarea_height) return;
|
||||
// Reposition all child elements after size of property dialogue has changed
|
||||
RECT rc = { 0,0,0,0 };
|
||||
if (!::GetClientRect(hPropertyDlg, &rc)) return;
|
||||
int y0 = rc.bottom - property_dlg_margin - property_dlg_inputarea_height;
|
||||
// Output text box
|
||||
::SetWindowPos(::GetDlgItem(hPropertyDlg, IDC_EDITOUTPUT), NULL,
|
||||
property_dlg_margin,
|
||||
property_dlg_margin,
|
||||
rc.right - 2* property_dlg_margin,
|
||||
y0 - 2* property_dlg_margin,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// Input ComboBox
|
||||
::SetWindowPos(::GetDlgItem(hPropertyDlg, IDC_COMBOINPUT), NULL,
|
||||
property_dlg_margin,
|
||||
y0,
|
||||
rc.right - property_dlg_okbutton_width - 3*property_dlg_margin,
|
||||
property_dlg_inputarea_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// OK button
|
||||
::SetWindowPos(::GetDlgItem(hPropertyDlg, IDOK), NULL,
|
||||
rc.right - property_dlg_margin - property_dlg_okbutton_width,
|
||||
y0,
|
||||
property_dlg_okbutton_width,
|
||||
property_dlg_inputarea_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
}
|
||||
|
||||
void ConsoleInitLayout()
|
||||
{
|
||||
// Find out desired sizes and margins of elements used in console dialogue.
|
||||
// Just remember initial layout.
|
||||
// This is easier than getting all values from Windows metrics definitions.
|
||||
RECT console_rc = { 0,0,356,252 };
|
||||
::GetWindowRect(console_handle, &console_rc);
|
||||
console_default_width = console_rc.right - console_rc.left;
|
||||
console_default_height = console_rc.bottom - console_rc.top;
|
||||
console_margin = 1; // hardcoded margins
|
||||
console_wide_margin = 3;
|
||||
RECT button_rc = { 288,180,350,200 };
|
||||
::GetWindowRect(::GetDlgItem(console_handle, IDOK), &button_rc);
|
||||
console_button_height = button_rc.bottom - button_rc.top;
|
||||
console_ok_button_width = button_rc.right - button_rc.left;
|
||||
RECT status_rc = { 222,205,350,223 };
|
||||
::GetWindowRect(::GetDlgItem(console_handle, IDC_STATICTIME), &status_rc);
|
||||
console_status_width = status_rc.right - status_rc.left;
|
||||
}
|
||||
|
||||
void ConsoleUpdateSize()
|
||||
{
|
||||
// Positions unknown?
|
||||
if (!console_default_width) return;
|
||||
// Reposition all child elements after size of console dialogue has changed
|
||||
RECT rc = { 0,0,0,0 };
|
||||
if (!::GetClientRect(console_handle, &rc)) return;
|
||||
int y0 = rc.bottom - console_margin * 3 - console_button_height * 3;
|
||||
int y1 = rc.bottom - console_margin * 2 - console_button_height * 2;
|
||||
int y2 = rc.bottom - console_margin * 1 - console_button_height * 1;
|
||||
int x0 = rc.right - console_margin - console_button_height;
|
||||
// Output text box
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_EDITOUTPUT), NULL,
|
||||
console_margin,
|
||||
0,
|
||||
x0 - console_margin - console_wide_margin,
|
||||
y0 - console_margin,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// Input ComboBox
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_COMBOINPUT), NULL,
|
||||
console_margin,
|
||||
y0,
|
||||
rc.right - console_ok_button_width - console_margin * 3,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// Input OK button
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDOK), NULL,
|
||||
rc.right - console_margin - console_ok_button_width,
|
||||
y0,
|
||||
console_ok_button_width,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// Frame status bar
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_STATICFRAME), NULL,
|
||||
console_margin,
|
||||
y1,
|
||||
console_status_width,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// Play button
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_BUTTONPLAY), NULL,
|
||||
console_margin + console_status_width + console_wide_margin,
|
||||
y1,
|
||||
console_button_height,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// Halt button
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_BUTTONHALT), NULL,
|
||||
console_margin + console_status_width + console_wide_margin * 2 + console_button_height,
|
||||
y1,
|
||||
console_button_height,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// Time/FPS status bar
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_STATICTIME), NULL,
|
||||
rc.right - console_margin - console_status_width,
|
||||
y1,
|
||||
console_status_width,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// Main status bar
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_STATICCURSOR), NULL,
|
||||
console_margin,
|
||||
y2,
|
||||
rc.right - 2* console_margin,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
// Tool buttons
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_BUTTONMODEPLAY), NULL,
|
||||
x0,
|
||||
console_margin,
|
||||
console_button_height,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_BUTTONMODEEDIT), NULL,
|
||||
x0,
|
||||
console_margin * 2 + console_button_height,
|
||||
console_button_height,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
::SetWindowPos(::GetDlgItem(console_handle, IDC_BUTTONMODEDRAW), NULL,
|
||||
x0,
|
||||
console_margin * 3 + console_button_height * 2,
|
||||
console_button_height,
|
||||
console_button_height,
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER);
|
||||
}
|
||||
};
|
||||
|
||||
void C4ConsoleGUI::UpdateMenuText(HMENU hMenu) { state->UpdateMenuText(*this, hMenu); }
|
||||
|
@ -176,7 +350,7 @@ INT_PTR CALLBACK ConsoleDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lPara
|
|||
return true;
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
case WM_DESTROY:
|
||||
StoreWindowPosition(hDlg, "Main", Config.GetSubkeyPath("Console"), false);
|
||||
StoreWindowPosition(hDlg, "Main", Config.GetSubkeyPath("Console"), true);
|
||||
Application.Quit();
|
||||
return true;
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
|
@ -191,7 +365,7 @@ INT_PTR CALLBACK ConsoleDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lPara
|
|||
//------------------------------------------------------------------------------------------------------------
|
||||
case WM_INITDIALOG:
|
||||
Console.Active = true;
|
||||
SendMessage(hDlg,DM_SETDEFID,(WPARAM)IDOK,(LPARAM)0);
|
||||
SendMessage(hDlg, DM_SETDEFID, (WPARAM)IDOK, (LPARAM)0);
|
||||
Console.UpdateMenuText(GetMenu(hDlg));
|
||||
return true;
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
|
@ -203,7 +377,7 @@ INT_PTR CALLBACK ConsoleDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lPara
|
|||
case IDOK:
|
||||
// IDC_COMBOINPUT to Console.In()
|
||||
wchar_t buffer[16000];
|
||||
GetDlgItemTextW(hDlg,IDC_COMBOINPUT,buffer,16000);
|
||||
GetDlgItemTextW(hDlg, IDC_COMBOINPUT, buffer, 16000);
|
||||
if (buffer[0])
|
||||
{
|
||||
StdStrBuf in_char(buffer);
|
||||
|
@ -256,13 +430,13 @@ INT_PTR CALLBACK ConsoleDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lPara
|
|||
case IDM_VIEWPORT_NEW: Console.ViewportNew(); return true;
|
||||
}
|
||||
// New player viewport
|
||||
if (Inside((int) LOWORD(wParam),IDM_VIEWPORT_NEW1,IDM_VIEWPORT_NEW2))
|
||||
if (Inside((int)LOWORD(wParam), IDM_VIEWPORT_NEW1, IDM_VIEWPORT_NEW2))
|
||||
{
|
||||
::Viewports.CreateViewport(LOWORD(wParam)-IDM_VIEWPORT_NEW1);
|
||||
::Viewports.CreateViewport(LOWORD(wParam) - IDM_VIEWPORT_NEW1);
|
||||
return true;
|
||||
}
|
||||
// Remove player
|
||||
if (Inside((int) LOWORD(wParam),IDM_PLAYER_QUIT1,IDM_PLAYER_QUIT2))
|
||||
if (Inside((int)LOWORD(wParam), IDM_PLAYER_QUIT1, IDM_PLAYER_QUIT2))
|
||||
{
|
||||
C4Player *plr = ::Players.Get(LOWORD(wParam) - IDM_PLAYER_QUIT1);
|
||||
if (!plr) return true;
|
||||
|
@ -270,10 +444,10 @@ INT_PTR CALLBACK ConsoleDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lPara
|
|||
return true;
|
||||
}
|
||||
// Remove client
|
||||
if (Inside((int) LOWORD(wParam),IDM_NET_CLIENT1,IDM_NET_CLIENT2))
|
||||
if (Inside((int)LOWORD(wParam), IDM_NET_CLIENT1, IDM_NET_CLIENT2))
|
||||
{
|
||||
if (!::Control.isCtrlHost()) return false;
|
||||
Game.Clients.CtrlRemove(Game.Clients.getClientByID(LOWORD(wParam)-IDM_NET_CLIENT1), LoadResStr("IDS_MSG_KICKBYMENU"));
|
||||
Game.Clients.CtrlRemove(Game.Clients.getClientByID(LOWORD(wParam) - IDM_NET_CLIENT1), LoadResStr("IDS_MSG_KICKBYMENU"));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -286,7 +460,7 @@ INT_PTR CALLBACK ConsoleDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lPara
|
|||
return false;
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
case WM_COPYDATA:
|
||||
{
|
||||
{
|
||||
COPYDATASTRUCT* pcds = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||
if (pcds->dwData == WM_USER_RELOADFILE)
|
||||
{
|
||||
|
@ -297,12 +471,30 @@ INT_PTR CALLBACK ConsoleDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lPara
|
|||
Game.ReloadFile(szPath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
case WM_INPUTLANGCHANGE:
|
||||
::Application.OnKeyboardLayoutChanged();
|
||||
break;
|
||||
//------------------------------------------------------------------------------------------------------------
|
||||
// Resizing
|
||||
case WM_GETMINMAXINFO:
|
||||
// Window may not become smaller than initial size
|
||||
if (Console.state && Console.state->console_default_width)
|
||||
{
|
||||
MINMAXINFO *info = reinterpret_cast<MINMAXINFO *>(lParam);
|
||||
info->ptMinTrackSize.x = Console.state->console_default_width;
|
||||
info->ptMinTrackSize.y = Console.state->console_default_height;
|
||||
}
|
||||
return 0;
|
||||
case WM_SIZING: Console.state->ConsoleUpdateSize(); break;
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
const WINDOWPOS *data = reinterpret_cast<const WINDOWPOS *>(lParam);
|
||||
if (data && !(data->flags & SWP_NOSIZE)) Console.state->ConsoleUpdateSize();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -399,7 +591,7 @@ INT_PTR CALLBACK ToolsDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
|
|||
break;
|
||||
//----------------------------------------------------------------------------------------------
|
||||
case WM_DESTROY:
|
||||
StoreWindowPosition(hDlg, "Property", Config.GetSubkeyPath("Console"), false);
|
||||
StoreWindowPosition(hDlg, "Tools", Config.GetSubkeyPath("Console"), false);
|
||||
break;
|
||||
//----------------------------------------------------------------------------------------------
|
||||
case WM_INITDIALOG:
|
||||
|
@ -511,13 +703,22 @@ INT_PTR CALLBACK PropertyDlgProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lPar
|
|||
break;
|
||||
//------------------------------------------------------------------------------------------------
|
||||
case WM_DESTROY:
|
||||
StoreWindowPosition(hDlg, "Property", Config.GetSubkeyPath("Console"), false);
|
||||
StoreWindowPosition(hDlg, "Property", Config.GetSubkeyPath("Console"), true);
|
||||
break;
|
||||
//------------------------------------------------------------------------------------------------
|
||||
case WM_INITDIALOG:
|
||||
SendMessage(hDlg,DM_SETDEFID,(WPARAM)IDOK,(LPARAM)0);
|
||||
return true;
|
||||
//------------------------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Callbacks during/after window resizing
|
||||
case WM_SIZING: Console.state->PropertyDlgUpdateSize(); break;
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
{
|
||||
const WINDOWPOS *data = reinterpret_cast<const WINDOWPOS *>(lParam);
|
||||
if (data && !(data->flags & SWP_NOSIZE)) Console.state->PropertyDlgUpdateSize();
|
||||
break;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------
|
||||
case WM_COMMAND:
|
||||
// Evaluate command
|
||||
switch (LOWORD(wParam))
|
||||
|
@ -601,6 +802,9 @@ C4Window* C4ConsoleGUI::CreateConsoleWindow(C4AbstractApp *application)
|
|||
LocalFree(lpMsgBuf);
|
||||
return NULL;
|
||||
}
|
||||
// Remember metrics
|
||||
state->console_handle = hWindow;
|
||||
state->ConsoleInitLayout();
|
||||
// Restore window position
|
||||
RestoreWindowPosition(hWindow, "Main", Config.GetSubkeyPath("Console"));
|
||||
// Set icon
|
||||
|
@ -839,6 +1043,8 @@ bool C4ConsoleGUI::PropertyDlgOpen()
|
|||
PropertyDlgProc);
|
||||
if (!hDialog) return false;
|
||||
state->hPropertyDlg = hDialog;
|
||||
// Remember initial layout
|
||||
state->PropertyDlgInitLayout();
|
||||
// Set text
|
||||
SetWindowTextW(hDialog,LoadResStrW("IDS_DLG_PROPERTIES"));
|
||||
// Enable controls
|
||||
|
@ -957,7 +1163,7 @@ bool C4ConsoleGUI::ToolsDlgOpen(C4ToolsDlg *dlg)
|
|||
dlg->state->pPreviewWindow = new C4ConsoleGUIPreviewWindow(GetDlgItem(dlg->state->hDialog, IDC_PREVIEW));
|
||||
}
|
||||
// Show window
|
||||
RestoreWindowPosition(dlg->state->hDialog, "Property", Config.GetSubkeyPath("Console"));
|
||||
RestoreWindowPosition(dlg->state->hDialog, "Tools", Config.GetSubkeyPath("Console"));
|
||||
SetWindowPos(dlg->state->hDialog,Console.hWindow,0,0,0,0,SWP_NOSIZE | SWP_NOMOVE);
|
||||
ShowWindow(dlg->state->hDialog,SW_SHOWNOACTIVATE);
|
||||
return true;
|
||||
|
|
|
@ -185,9 +185,6 @@ bool C4Application::DoInit(int argc, char * argv[])
|
|||
pWindow->SetSize(Config.Graphics.WindowX, Config.Graphics.WindowY);
|
||||
}
|
||||
|
||||
// after initializing graphics, the particle system can check for compatibility
|
||||
::Particles.DoInit();
|
||||
|
||||
// Initialize gamepad
|
||||
if (!pGamePadControl && Config.General.GamepadEnabled)
|
||||
pGamePadControl = new C4GamePadControl();
|
||||
|
|
|
@ -378,7 +378,7 @@ void C4Viewport::Execute()
|
|||
bool draw_game = true;
|
||||
if (Player == NO_OWNER)
|
||||
if (!::Application.isEditor && !::Game.DebugMode)
|
||||
if (!::Network.isEnabled() || !::Network.Clients.GetLocal() || ::Network.Clients.GetLocal()->isObserver())
|
||||
if (!::Network.isEnabled() || !::Network.Clients.GetLocal() || !::Network.Clients.GetLocal()->isObserver())
|
||||
if (::Game.PlayerInfos.GetJoinIssuedPlayerCount() > 0) // free scrolling allowed if the scenario was started explicitely without players to inspect the landscape
|
||||
draw_game = false;
|
||||
// Draw
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace
|
|||
#undef USERPARAM_CONST
|
||||
|
||||
CStdGL::CStdGL():
|
||||
pMainCtx(0), CurrentVBO(0)
|
||||
pMainCtx(0), CurrentVBO(0), NextVAOID(VAOIDs.end())
|
||||
{
|
||||
GenericVBOs[0] = 0;
|
||||
Default();
|
||||
|
@ -220,6 +220,11 @@ bool CStdGL::PrepareSpriteShader(C4Shader& shader, const char* name, int ssc, C4
|
|||
uniformNames[C4SSU_AmbientTex] = "ambientTex";
|
||||
uniformNames[C4SSU_AmbientTransform] = "ambientTransform";
|
||||
uniformNames[C4SSU_AmbientBrightness] = "ambientBrightness";
|
||||
uniformNames[C4SSU_MaterialAmbient] = "materialAmbient"; // unused
|
||||
uniformNames[C4SSU_MaterialDiffuse] = "materialDiffuse"; // unused
|
||||
uniformNames[C4SSU_MaterialSpecular] = "materialSpecular"; // unused
|
||||
uniformNames[C4SSU_MaterialEmission] = "materialEmission"; // unused
|
||||
uniformNames[C4SSU_MaterialShininess] = "materialShininess"; // unused
|
||||
uniformNames[C4SSU_Bones] = "bones"; // unused
|
||||
uniformNames[C4SSU_CullMode] = "cullMode"; // unused
|
||||
uniformNames[C4SSU_Count] = NULL;
|
||||
|
@ -376,16 +381,6 @@ bool CStdGL::CreatePrimarySurfaces(unsigned int, unsigned int, int iColorDepth,
|
|||
{
|
||||
// store options
|
||||
bool ok = RestoreDeviceObjects();
|
||||
|
||||
// - AMD GPUs have supported OpenGL 2.1 since 2007
|
||||
// - nVidia GPUs have supported OpenGL 2.1 since 2005
|
||||
// - Intel integrated GPUs have supported OpenGL 2.1 since Clarkdale (maybe earlier).
|
||||
// And we've already been using features from OpenGL 2.1. Nobody has complained yet.
|
||||
// So checking for 2.1 support should be fine.
|
||||
if (!GLEW_VERSION_2_1)
|
||||
{
|
||||
return Error(" gl: OpenGL Version 2.1 or higher required. A better graphics driver will probably help.");
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
@ -646,21 +641,31 @@ void CStdGL::PerformMultiBlt(C4Surface* sfcTarget, DrawOperation op, const C4Blt
|
|||
glBufferSubData(GL_ARRAY_BUFFER, 0, n_vertices * sizeof(C4BltVertex), vertices);
|
||||
}
|
||||
|
||||
const GLuint position = shader_call->GetAttribute(C4SSA_Position);
|
||||
const GLuint color = shader_call->GetAttribute(C4SSA_Color);
|
||||
const GLuint texcoord = has_tex ? shader_call->GetAttribute(C4SSA_TexCoord) : 0;
|
||||
|
||||
glEnableVertexAttribArray(position);
|
||||
glEnableVertexAttribArray(color);
|
||||
|
||||
if(has_tex)
|
||||
// Choose the VAO that corresponds to the chosen VBO. Also, use one
|
||||
// that supplies texture coordinates if we have texturing enabled.
|
||||
GLuint vao;
|
||||
const unsigned int vao_index = vbo_index + (has_tex ? N_GENERIC_VBOS : 0);
|
||||
const unsigned int vao_id = GenericVAOs[vao_index];
|
||||
const bool has_vao = GetVAO(vao_id, vao);
|
||||
glBindVertexArray(vao);
|
||||
if (!has_vao)
|
||||
{
|
||||
glEnableVertexAttribArray(texcoord);
|
||||
glVertexAttribPointer(texcoord, 2, GL_FLOAT, GL_FALSE, sizeof(C4BltVertex), reinterpret_cast<const uint8_t*>(offsetof(C4BltVertex, tx)));
|
||||
}
|
||||
// Initialize VAO for this context
|
||||
const GLuint position = shader_call->GetAttribute(C4SSA_Position);
|
||||
const GLuint color = shader_call->GetAttribute(C4SSA_Color);
|
||||
const GLuint texcoord = has_tex ? shader_call->GetAttribute(C4SSA_TexCoord) : 0;
|
||||
|
||||
glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, sizeof(C4BltVertex), reinterpret_cast<const uint8_t*>(offsetof(C4BltVertex, ftx)));
|
||||
glVertexAttribPointer(color, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(C4BltVertex), reinterpret_cast<const uint8_t*>(offsetof(C4BltVertex, color)));
|
||||
glEnableVertexAttribArray(position);
|
||||
glEnableVertexAttribArray(color);
|
||||
if (has_tex)
|
||||
glEnableVertexAttribArray(texcoord);
|
||||
|
||||
|
||||
glVertexAttribPointer(position, 2, GL_FLOAT, GL_FALSE, sizeof(C4BltVertex), reinterpret_cast<const uint8_t*>(offsetof(C4BltVertex, ftx)));
|
||||
glVertexAttribPointer(color, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(C4BltVertex), reinterpret_cast<const uint8_t*>(offsetof(C4BltVertex, color)));
|
||||
if (has_tex)
|
||||
glVertexAttribPointer(texcoord, 2, GL_FLOAT, GL_FALSE, sizeof(C4BltVertex), reinterpret_cast<const uint8_t*>(offsetof(C4BltVertex, tx)));
|
||||
}
|
||||
|
||||
switch (op)
|
||||
{
|
||||
|
@ -675,10 +680,8 @@ void CStdGL::PerformMultiBlt(C4Surface* sfcTarget, DrawOperation op, const C4Blt
|
|||
break;
|
||||
}
|
||||
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
if(has_tex) glDisableVertexAttribArray(texcoord);
|
||||
glDisableVertexAttribArray(position);
|
||||
glDisableVertexAttribArray(color);
|
||||
}
|
||||
|
||||
C4Shader* CStdGL::GetSpriteShader(bool haveBase, bool haveOverlay, bool haveNormal)
|
||||
|
@ -806,6 +809,8 @@ bool CStdGL::RestoreDeviceObjects()
|
|||
GenericVBOSizes[i] = GENERIC_VBO_SIZE;
|
||||
glBindBuffer(GL_ARRAY_BUFFER, GenericVBOs[i]);
|
||||
glBufferData(GL_ARRAY_BUFFER, GenericVBOSizes[i] * sizeof(C4BltVertex), NULL, GL_STREAM_DRAW);
|
||||
GenericVAOs[i] = GenVAOID();
|
||||
GenericVAOs[i + N_GENERIC_VBOS] = GenVAOID();
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
@ -832,9 +837,13 @@ bool CStdGL::InvalidateDeviceObjects()
|
|||
|
||||
// invalidate generic VBOs
|
||||
if (GenericVBOs[0] != 0)
|
||||
{
|
||||
glDeleteBuffers(N_GENERIC_VBOS, GenericVBOs);
|
||||
GenericVBOs[0] = 0;
|
||||
CurrentVBO = 0;
|
||||
GenericVBOs[0] = 0;
|
||||
CurrentVBO = 0;
|
||||
for (unsigned int i = 0; i < N_GENERIC_VBOS * 2; ++i)
|
||||
FreeVAOID(GenericVAOs[i]);
|
||||
}
|
||||
|
||||
// invalidate shaders
|
||||
|
||||
|
@ -932,4 +941,120 @@ void CStdGL::Default()
|
|||
Workarounds.LowMaxVertexUniformCount = false;
|
||||
}
|
||||
|
||||
unsigned int CStdGL::GenVAOID()
|
||||
{
|
||||
// Generate a new VAO ID. Make them sequential so that the actual
|
||||
// VAOs in the context can be simply maintained with a lookup table.
|
||||
unsigned int id;
|
||||
if (NextVAOID == VAOIDs.begin())
|
||||
{
|
||||
// Insert at the beginning
|
||||
id = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Insert at the end, or somewhere in the middle
|
||||
std::set<unsigned int>::iterator iter = NextVAOID;
|
||||
--iter;
|
||||
|
||||
id = *iter + 1;
|
||||
}
|
||||
|
||||
// Actually insert the ID
|
||||
#ifdef NDEBUG
|
||||
std::set<unsigned int>::iterator inserted_iter = VAOIDs.insert(NextVAOID, id);
|
||||
#else
|
||||
std::pair<std::set<unsigned int>::iterator, bool> inserted = VAOIDs.insert(id);
|
||||
assert(inserted.second == true);
|
||||
std::set<unsigned int>::iterator inserted_iter = inserted.first;
|
||||
#endif
|
||||
|
||||
// Update next VAO ID: increment iterator until we find a gap
|
||||
// in the sequence.
|
||||
NextVAOID = inserted_iter;
|
||||
unsigned int prev_id = id;
|
||||
++NextVAOID;
|
||||
while(NextVAOID != VAOIDs.end() && prev_id + 1 == *NextVAOID)
|
||||
{
|
||||
prev_id = *NextVAOID;
|
||||
++NextVAOID;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void CStdGL::FreeVAOID(unsigned int vaoid)
|
||||
{
|
||||
std::set<unsigned int>::iterator iter = VAOIDs.find(vaoid);
|
||||
assert(iter != VAOIDs.end());
|
||||
|
||||
// Delete this VAO in the current context
|
||||
if (pCurrCtx)
|
||||
{
|
||||
if (vaoid < pCurrCtx->hVAOs.size() && pCurrCtx->hVAOs[vaoid] != 0)
|
||||
{
|
||||
glDeleteVertexArrays(1, &pCurrCtx->hVAOs[vaoid]);
|
||||
pCurrCtx->hVAOs[vaoid] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// For all other contexts, mark it to be deleted as soon as we select
|
||||
// that context. Otherwise we would need to do a lot of context
|
||||
// switching at this point.
|
||||
for (std::list<CStdGLCtx*>::iterator iter = CStdGLCtx::contexts.begin(); iter != CStdGLCtx::contexts.end(); ++iter)
|
||||
{
|
||||
CStdGLCtx* ctx = *iter;
|
||||
if (ctx != pCurrCtx && vaoid < ctx->hVAOs.size() && ctx->hVAOs[vaoid] != 0)
|
||||
if (std::find(ctx->VAOsToBeDeleted.begin(), ctx->VAOsToBeDeleted.end(), vaoid) == ctx->VAOsToBeDeleted.end())
|
||||
ctx->VAOsToBeDeleted.push_back(vaoid);
|
||||
}
|
||||
|
||||
// Delete the VAO ID from our list of VAO IDs in use
|
||||
// If the Next VAO ID is 1, then no matter what we delete we don't need
|
||||
// to update anything. If it is not at the beginning, then move it to the
|
||||
// gap we just created if it was at a higher place, to make sure we keep
|
||||
// the numbers as sequential as possible.
|
||||
unsigned int nextVaoID = 1;
|
||||
if (NextVAOID != VAOIDs.begin())
|
||||
{
|
||||
std::set<unsigned int>::iterator next_vao_iter = NextVAOID;
|
||||
--next_vao_iter;
|
||||
nextVaoID = *next_vao_iter + 1;
|
||||
}
|
||||
|
||||
assert(vaoid != nextVaoID);
|
||||
|
||||
if (vaoid < nextVaoID || iter == NextVAOID)
|
||||
NextVAOID = VAOIDs.erase(iter);
|
||||
else
|
||||
VAOIDs.erase(iter);
|
||||
}
|
||||
|
||||
bool CStdGL::GetVAO(unsigned int vaoid, GLuint& vao)
|
||||
{
|
||||
assert(pCurrCtx != NULL);
|
||||
|
||||
if (vaoid >= pCurrCtx->hVAOs.size())
|
||||
{
|
||||
// Resize the VAO array so that all generated VAO IDs fit
|
||||
// in it, and not only the one requested in this call.
|
||||
// We hope to get away with fewer reallocations this way.
|
||||
assert(VAOIDs.find(vaoid) != VAOIDs.end());
|
||||
std::set<unsigned int>::iterator iter = VAOIDs.end();
|
||||
--iter;
|
||||
|
||||
pCurrCtx->hVAOs.resize(*iter + 1);
|
||||
}
|
||||
|
||||
if (pCurrCtx->hVAOs[vaoid] == 0)
|
||||
{
|
||||
glGenVertexArrays(1, &pCurrCtx->hVAOs[vaoid]);
|
||||
vao = pCurrCtx->hVAOs[vaoid];
|
||||
return false;
|
||||
}
|
||||
|
||||
vao = pCurrCtx->hVAOs[vaoid];
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // USE_CONSOLE
|
||||
|
|
|
@ -68,6 +68,12 @@ enum C4SS_Uniforms
|
|||
C4SSU_AmbientTransform, // C4SSC_LIGHT
|
||||
C4SSU_AmbientBrightness, // C4SSC_LIGHT
|
||||
|
||||
C4SSU_MaterialAmbient, // for meshes
|
||||
C4SSU_MaterialDiffuse, // for meshes
|
||||
C4SSU_MaterialSpecular, // for meshes
|
||||
C4SSU_MaterialEmission, // for meshes
|
||||
C4SSU_MaterialShininess, // for meshes
|
||||
|
||||
C4SSU_Bones, // for meshes
|
||||
C4SSU_CullMode, // for meshes
|
||||
|
||||
|
@ -99,7 +105,7 @@ class CStdGLCtx
|
|||
{
|
||||
public:
|
||||
CStdGLCtx(); // ctor
|
||||
~CStdGLCtx() { Clear(); }; // dtor
|
||||
~CStdGLCtx() { Clear(); } // dtor
|
||||
|
||||
void Clear(); // clear objects
|
||||
|
||||
|
@ -130,6 +136,15 @@ protected:
|
|||
/*GLXContext*/void * ctx;
|
||||
#endif
|
||||
|
||||
// Global list of all OpenGL contexts in use
|
||||
static std::list<CStdGLCtx*> contexts;
|
||||
std::list<CStdGLCtx*>::iterator this_context;
|
||||
|
||||
// VAOs available on this context
|
||||
std::vector<GLuint> hVAOs;
|
||||
// VAOs to be deleted the next time this context is being made current.
|
||||
std::vector<unsigned int> VAOsToBeDeleted;
|
||||
|
||||
friend class CStdGL;
|
||||
friend class C4Surface;
|
||||
};
|
||||
|
@ -188,8 +203,31 @@ protected:
|
|||
GLuint GenericVBOs[N_GENERIC_VBOS];
|
||||
unsigned int GenericVBOSizes[N_GENERIC_VBOS];
|
||||
unsigned int CurrentVBO;
|
||||
// We need twice as much VAOs, since the sprite rendering routines work
|
||||
// both with and without textures (in which case we either need texture
|
||||
// coordinates or not).
|
||||
unsigned int GenericVAOs[N_GENERIC_VBOS * 2];
|
||||
|
||||
// VAO IDs currently in use.
|
||||
std::set<unsigned int> VAOIDs;
|
||||
std::set<unsigned int>::iterator NextVAOID;
|
||||
|
||||
public:
|
||||
// Create a new (unique) VAO ID. A VAO ID is a number that identifies
|
||||
// a certain VAO across all OpenGL contexts. This indirection is needed
|
||||
// because, unlike most other GL state, VAOs are not shared between
|
||||
// OpenGL contexts.
|
||||
unsigned int GenVAOID();
|
||||
|
||||
// Free the given VAO ID, i.e. it can be re-used for new VAOs. This causes
|
||||
// the VAO associated with this ID to be deleted in all OpenGL contexts.
|
||||
void FreeVAOID(unsigned int vaoid);
|
||||
|
||||
// Return a VAO with the given vao ID in the "vao" output variable.
|
||||
// If the function returns false, the VAO was newly created, otherwise
|
||||
// an existing VAO is returned.
|
||||
bool GetVAO(unsigned int vaoid, GLuint& vao);
|
||||
|
||||
// General
|
||||
void Clear();
|
||||
void Default();
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
|
||||
#ifndef USE_CONSOLE
|
||||
|
||||
static const int REQUESTED_GL_CTX_MAJOR = 3;
|
||||
static const int REQUESTED_GL_CTX_MINOR = 2;
|
||||
|
||||
std::list<CStdGLCtx*> CStdGLCtx::contexts;
|
||||
|
||||
void CStdGLCtx::SelectCommon()
|
||||
{
|
||||
pGL->pCurrCtx = this;
|
||||
|
@ -32,6 +37,22 @@ void CStdGLCtx::SelectCommon()
|
|||
glDepthFunc(GL_LESS);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_BLEND);
|
||||
// Delete pending VAOs
|
||||
std::vector<GLuint> toBeDeleted;
|
||||
if (!VAOsToBeDeleted.empty())
|
||||
{
|
||||
for (unsigned int i = 0; i < VAOsToBeDeleted.size(); ++i)
|
||||
{
|
||||
if (VAOsToBeDeleted[i] < hVAOs.size() && hVAOs[VAOsToBeDeleted[i]] != 0)
|
||||
{
|
||||
toBeDeleted.push_back(hVAOs[VAOsToBeDeleted[i]]);
|
||||
hVAOs[VAOsToBeDeleted[i]] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
glDeleteVertexArrays(toBeDeleted.size(), &toBeDeleted[0]);
|
||||
VAOsToBeDeleted.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void CStdGLCtx::Reinitialize()
|
||||
|
@ -214,6 +235,7 @@ bool CStdGLCtx::InitGlew(HINSTANCE hInst)
|
|||
else
|
||||
{
|
||||
// init extensions
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if(err != GLEW_OK)
|
||||
{
|
||||
|
@ -239,7 +261,7 @@ bool CStdGLCtx::InitGlew(HINSTANCE hInst)
|
|||
return glewInitialized;
|
||||
}
|
||||
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0), hDC(0) { }
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0), hDC(0), this_context(contexts.end()) { }
|
||||
|
||||
void CStdGLCtx::Clear()
|
||||
{
|
||||
|
@ -250,6 +272,12 @@ void CStdGLCtx::Clear()
|
|||
hDC=0;
|
||||
}
|
||||
pWindow = 0; hWindow = NULL;
|
||||
|
||||
if (this_context != contexts.end())
|
||||
{
|
||||
contexts.erase(this_context);
|
||||
this_context = contexts.end();
|
||||
}
|
||||
}
|
||||
|
||||
bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *pApp, HWND hWindow)
|
||||
|
@ -305,17 +333,23 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *pApp, HWND hWindow)
|
|||
else
|
||||
{
|
||||
// create context
|
||||
if (Config.Graphics.DebugOpenGL && wglCreateContextAttribsARB)
|
||||
if (wglCreateContextAttribsARB)
|
||||
{
|
||||
const int attribs[] = {
|
||||
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
|
||||
WGL_CONTEXT_FLAGS_ARB, Config.Graphics.DebugOpenGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB, REQUESTED_GL_CTX_MAJOR,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB, REQUESTED_GL_CTX_MINOR,
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
0
|
||||
};
|
||||
DebugLog(" gl: Creating debug context.");
|
||||
|
||||
if (Config.Graphics.DebugOpenGL)
|
||||
DebugLog(" gl: Creating debug context.");
|
||||
hrc = wglCreateContextAttribsARB(hDC, 0, attribs);
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugLog(" gl: wglCreateContextAttribsARB not available; creating default context.");
|
||||
hrc = wglCreateContext(hDC);
|
||||
}
|
||||
|
||||
|
@ -335,6 +369,7 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *pApp, HWND hWindow)
|
|||
// After selecting the new context, we have to reinitialize GLEW to
|
||||
// update its function pointers - the driver may elect to expose
|
||||
// different extensions depending on the context attributes
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if (err != GLEW_OK)
|
||||
{
|
||||
|
@ -342,6 +377,8 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *pApp, HWND hWindow)
|
|||
pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
|
||||
return false;
|
||||
}
|
||||
|
||||
this_context = contexts.insert(contexts.end(), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -417,7 +454,7 @@ void InitGLXPointers()
|
|||
}
|
||||
}
|
||||
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0), ctx(0) { }
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0), ctx(0), this_context(contexts.end()) { }
|
||||
|
||||
void CStdGLCtx::Clear()
|
||||
{
|
||||
|
@ -429,6 +466,12 @@ void CStdGLCtx::Clear()
|
|||
ctx = 0;
|
||||
}
|
||||
pWindow = 0;
|
||||
|
||||
if (this_context != contexts.end())
|
||||
{
|
||||
contexts.erase(this_context);
|
||||
this_context = contexts.end();
|
||||
}
|
||||
}
|
||||
|
||||
bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
|
||||
|
@ -448,6 +491,7 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
|
|||
GLXContext dummy_ctx = glXCreateContext(dpy, vis_info, 0, True);
|
||||
XFree(vis_info);
|
||||
glXMakeCurrent(dpy, pWindow->renderwnd, dummy_ctx);
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if (err != GLEW_OK)
|
||||
{
|
||||
|
@ -456,7 +500,10 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
|
|||
|
||||
// Create Context with sharing (if this is the main context, our ctx will be 0, so no sharing)
|
||||
const int attribs[] = {
|
||||
GLX_CONTEXT_MAJOR_VERSION_ARB, REQUESTED_GL_CTX_MAJOR,
|
||||
GLX_CONTEXT_MINOR_VERSION_ARB, REQUESTED_GL_CTX_MINOR,
|
||||
GLX_CONTEXT_FLAGS_ARB, (Config.Graphics.DebugOpenGL ? GLX_CONTEXT_DEBUG_BIT_ARB : 0),
|
||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
||||
None
|
||||
};
|
||||
GLXContext share_context = (pGL->pMainCtx != this) ? static_cast<GLXContext>(pGL->pMainCtx->ctx) : 0;
|
||||
|
@ -479,12 +526,15 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
|
|||
if (!ctx) return pGL->Error(" gl: Unable to create context");
|
||||
if (!Select(true)) return pGL->Error(" gl: Unable to select context");
|
||||
// init extensions
|
||||
glewExperimental = GL_TRUE;
|
||||
err = glewInit();
|
||||
if (GLEW_OK != err)
|
||||
{
|
||||
// Problem: glewInit failed, something is seriously wrong.
|
||||
return pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
|
||||
}
|
||||
|
||||
this_context = contexts.insert(contexts.end(), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -538,11 +588,17 @@ bool CStdGLCtx::PageFlip()
|
|||
|
||||
#elif defined(USE_SDL_MAINLOOP)
|
||||
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0) { }
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0), this_context(contexts.end()) { }
|
||||
|
||||
void CStdGLCtx::Clear()
|
||||
{
|
||||
pWindow = 0;
|
||||
|
||||
if (this_context != contexts.end())
|
||||
{
|
||||
contexts.erase(this_context);
|
||||
this_context = contexts.end();
|
||||
}
|
||||
}
|
||||
|
||||
bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
|
||||
|
@ -554,12 +610,15 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
|
|||
// No luck at all?
|
||||
if (!Select(true)) return pGL->Error(" gl: Unable to select context");
|
||||
// init extensions
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if (GLEW_OK != err)
|
||||
{
|
||||
// Problem: glewInit failed, something is seriously wrong.
|
||||
return pGL->Error(reinterpret_cast<const char*>(glewGetErrorString(err)));
|
||||
}
|
||||
|
||||
this_context = contexts.insert(contexts.end(), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -478,6 +478,8 @@ static NSOpenGLContext* MainContext;
|
|||
+ (NSOpenGLContext*) createContext:(CStdGLCtx*) pMainCtx
|
||||
{
|
||||
std::vector<NSOpenGLPixelFormatAttribute> attribs;
|
||||
attribs.push_back(NSOpenGLPFAOpenGLProfile);
|
||||
attribs.push_back(NSOpenGLProfileVersion3_2Core);
|
||||
attribs.push_back(NSOpenGLPFADepthSize);
|
||||
attribs.push_back(16);
|
||||
if (!Application.isEditor && Config.Graphics.MultiSampling > 0)
|
||||
|
@ -495,10 +497,9 @@ static NSOpenGLContext* MainContext;
|
|||
}
|
||||
attribs.push_back(NSOpenGLPFANoRecovery);
|
||||
//attribs.push_back(NSOpenGLPFADoubleBuffer);
|
||||
attribs.push_back(NSOpenGLPFAWindow);
|
||||
//attribs.push_back(NSOpenGLPFAWindow); // cannot create a core profile with this
|
||||
attribs.push_back(0);
|
||||
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:&attribs[0]];
|
||||
|
||||
NSOpenGLContext* result = [[NSOpenGLContext alloc] initWithFormat:format shareContext:pMainCtx ? pMainCtx->objectiveCObject<NSOpenGLContext>() : nil];
|
||||
if (!MainContext)
|
||||
MainContext = result;
|
||||
|
@ -555,13 +556,19 @@ static NSOpenGLContext* MainContext;
|
|||
|
||||
#pragma mark CStdGLCtx: Initialization
|
||||
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0) {}
|
||||
CStdGLCtx::CStdGLCtx(): pWindow(0), this_context(contexts.end()) {}
|
||||
|
||||
void CStdGLCtx::Clear()
|
||||
{
|
||||
Deselect();
|
||||
setObjectiveCObject(nil);
|
||||
pWindow = 0;
|
||||
|
||||
if (this_context != contexts.end())
|
||||
{
|
||||
contexts.erase(this_context);
|
||||
this_context = contexts.end();
|
||||
}
|
||||
}
|
||||
|
||||
void C4Window::EnumerateMultiSamples(std::vector<int>& samples) const
|
||||
|
@ -582,6 +589,7 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
|
|||
// No luck at all?
|
||||
if (!Select(true)) return pGL->Error(" gl: Unable to select context");
|
||||
// init extensions
|
||||
glewExperimental = GL_TRUE; // Init GL 3.0+ function pointers
|
||||
GLenum err = glewInit();
|
||||
if (GLEW_OK != err)
|
||||
{
|
||||
|
@ -594,6 +602,8 @@ bool CStdGLCtx::Init(C4Window * pWindow, C4AbstractApp *)
|
|||
{
|
||||
[controller.openGLView setContext:ctx];
|
||||
}
|
||||
|
||||
this_context = contexts.insert(contexts.end(), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,8 @@ namespace
|
|||
////////////////////////////////////////////
|
||||
StdStrBuf Texture2DToCode(int index, bool hasTextureAnimation)
|
||||
{
|
||||
if (hasTextureAnimation) return FormatString("texture2D(oc_Texture%d, (oc_TextureMatrix%d * vec4(texcoord, 0.0, 1.0)).xy)", index, index);
|
||||
return FormatString("texture2D(oc_Texture%d, texcoord)", index);
|
||||
if (hasTextureAnimation) return FormatString("texture(oc_Texture%d, (oc_TextureMatrix%d * vec4(texcoord, 0.0, 1.0)).xy)", index, index);
|
||||
return FormatString("texture(oc_Texture%d, texcoord)", index);
|
||||
}
|
||||
|
||||
StdStrBuf TextureUnitSourceToCode(int index, StdMeshMaterialTextureUnit::BlendOpSourceType source, const float manualColor[3], float manualAlpha, bool hasTextureAnimation)
|
||||
|
@ -123,17 +123,17 @@ namespace
|
|||
case StdMeshMaterialPass::DF_AlwaysFail:
|
||||
return StdStrBuf("discard;");
|
||||
case StdMeshMaterialPass::DF_Less:
|
||||
return FormatString("if (!(color.a < %f)) discard;", pass.AlphaRejectionValue);
|
||||
return FormatString("if (!(fragColor.a < %f)) discard;", pass.AlphaRejectionValue);
|
||||
case StdMeshMaterialPass::DF_LessEqual:
|
||||
return FormatString("if (!(color.a <= %f)) discard;", pass.AlphaRejectionValue);
|
||||
return FormatString("if (!(fragColor.a <= %f)) discard;", pass.AlphaRejectionValue);
|
||||
case StdMeshMaterialPass::DF_Equal:
|
||||
return FormatString("if (!(color.a == %f)) discard;", pass.AlphaRejectionValue);
|
||||
return FormatString("if (!(fragColor.a == %f)) discard;", pass.AlphaRejectionValue);
|
||||
case StdMeshMaterialPass::DF_NotEqual:
|
||||
return FormatString("if (!(color.a != %f)) discard;", pass.AlphaRejectionValue);
|
||||
return FormatString("if (!(fragColor.a != %f)) discard;", pass.AlphaRejectionValue);
|
||||
case StdMeshMaterialPass::DF_Greater:
|
||||
return FormatString("if (!(color.a > %f)) discard;", pass.AlphaRejectionValue);
|
||||
return FormatString("if (!(fragColor.a > %f)) discard;", pass.AlphaRejectionValue);
|
||||
case StdMeshMaterialPass::DF_GreaterEqual:
|
||||
return FormatString("if (!(color.a >= %f)) discard;", pass.AlphaRejectionValue);
|
||||
return FormatString("if (!(fragColor.a >= %f)) discard;", pass.AlphaRejectionValue);
|
||||
default:
|
||||
assert(false);
|
||||
return StdStrBuf();
|
||||
|
@ -238,10 +238,10 @@ namespace
|
|||
"\n"
|
||||
"slice(texture)\n"
|
||||
"{\n"
|
||||
" vec4 diffuse = color;\n"
|
||||
" vec4 diffuse = fragColor;\n"
|
||||
" vec4 currentColor = diffuse;\n"
|
||||
" %s\n"
|
||||
" color = currentColor;\n"
|
||||
" fragColor = currentColor;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"slice(finish)\n"
|
||||
|
@ -614,7 +614,10 @@ namespace
|
|||
|
||||
bool using_shared_vertices = instance.GetSubMesh().GetVertices().empty();
|
||||
GLuint vbo = mesh_instance.GetMesh().GetVBO();
|
||||
size_t buffer_offset = using_shared_vertices ? 0 : instance.GetSubMesh().GetOffsetInBuffer();
|
||||
GLuint ibo = mesh_instance.GetIBO();
|
||||
unsigned int vaoid = mesh_instance.GetVAOID();
|
||||
size_t vertex_buffer_offset = using_shared_vertices ? 0 : instance.GetSubMesh().GetOffsetInVBO();
|
||||
size_t index_buffer_offset = instance.GetSubMesh().GetOffsetInIBO(); // note this is constant
|
||||
|
||||
// Cook the bone transform matrixes into something that OpenGL can use. This could be moved into RenderMeshImpl.
|
||||
// Or, even better, we could upload them into a UBO, but Intel doesn't support them prior to Sandy Bridge.
|
||||
|
@ -666,13 +669,6 @@ namespace
|
|||
else
|
||||
glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
|
||||
|
||||
// Set material properties
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, pass.Ambient);
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pass.Diffuse);
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, pass.Specular);
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, pass.Emissive);
|
||||
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, pass.Shininess);
|
||||
|
||||
glFrontFace(parity ? GL_CW : GL_CCW);
|
||||
if(mesh_instance.GetCompletion() < 1.0f)
|
||||
{
|
||||
|
@ -734,6 +730,14 @@ namespace
|
|||
call.SetUniformMatrix4x4(C4SSU_ModelViewMatrix, modelviewMatrix);
|
||||
call.SetUniformMatrix3x3Transpose(C4SSU_NormalMatrix, normalMatrixTranspose);
|
||||
|
||||
|
||||
// Upload material properties
|
||||
call.SetUniform4fv(C4SSU_MaterialAmbient, 1, pass.Ambient);
|
||||
call.SetUniform4fv(C4SSU_MaterialDiffuse, 1, pass.Diffuse);
|
||||
call.SetUniform4fv(C4SSU_MaterialSpecular, 1, pass.Specular);
|
||||
call.SetUniform4fv(C4SSU_MaterialEmission, 1, pass.Emissive);
|
||||
call.SetUniform1f(C4SSU_MaterialShininess, pass.Shininess);
|
||||
|
||||
// Upload the current bone transformation matrixes (if there are any)
|
||||
if (!bones.empty())
|
||||
{
|
||||
|
@ -743,24 +747,39 @@ namespace
|
|||
glUniformMatrix4x3fv(shader->GetUniform(C4SSU_Bones), bones.size(), GL_TRUE, &bones[0].m[0][0]);
|
||||
}
|
||||
|
||||
// Bind the vertex data of the mesh
|
||||
GLuint vao;
|
||||
const bool has_vao = pGL->GetVAO(vaoid, vao);
|
||||
glBindVertexArray(vao);
|
||||
if (!has_vao)
|
||||
{
|
||||
// Bind the vertex data of the mesh
|
||||
// Note this relies on the fact that all vertex
|
||||
// attributes for all shaders are at the same
|
||||
// locations.
|
||||
// TODO: And this fails if the mesh changes
|
||||
// from a material with texture to one without
|
||||
// or vice versa.
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
#define VERTEX_OFFSET(field) reinterpret_cast<const uint8_t *>(offsetof(StdMeshVertex, field))
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_Position), 3, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), buffer_offset + VERTEX_OFFSET(x));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_Normal), 3, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), buffer_offset + VERTEX_OFFSET(nx));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_TexCoord), 2, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), buffer_offset + VERTEX_OFFSET(u));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_BoneWeights0), 4, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), buffer_offset + VERTEX_OFFSET(bone_weight));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_BoneWeights1), 4, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), buffer_offset + VERTEX_OFFSET(bone_weight) + 4 * sizeof(std::remove_all_extents<decltype(StdMeshVertex::bone_weight)>::type));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_BoneIndices0), 4, GL_SHORT, GL_FALSE, sizeof(StdMeshVertex), buffer_offset + VERTEX_OFFSET(bone_index));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_BoneIndices1), 4, GL_SHORT, GL_FALSE, sizeof(StdMeshVertex), buffer_offset + VERTEX_OFFSET(bone_index) + 4 * sizeof(std::remove_all_extents<decltype(StdMeshVertex::bone_index)>::type));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_Position));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_Normal));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_TexCoord));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_BoneWeights0));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_BoneWeights1));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_BoneIndices0));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_BoneIndices1));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_Position), 3, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), VERTEX_OFFSET(x));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_Normal), 3, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), VERTEX_OFFSET(nx));
|
||||
if (shader->GetAttribute(C4SSA_TexCoord) != -1)
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_TexCoord), 2, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), VERTEX_OFFSET(u));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_BoneWeights0), 4, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), VERTEX_OFFSET(bone_weight));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_BoneWeights1), 4, GL_FLOAT, GL_FALSE, sizeof(StdMeshVertex), VERTEX_OFFSET(bone_weight) + 4 * sizeof(std::remove_all_extents<decltype(StdMeshVertex::bone_weight)>::type));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_BoneIndices0), 4, GL_SHORT, GL_FALSE, sizeof(StdMeshVertex), VERTEX_OFFSET(bone_index));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4SSA_BoneIndices1), 4, GL_SHORT, GL_FALSE, sizeof(StdMeshVertex), VERTEX_OFFSET(bone_index) + 4 * sizeof(std::remove_all_extents<decltype(StdMeshVertex::bone_index)>::type));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_Position));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_Normal));
|
||||
if (shader->GetAttribute(C4SSA_TexCoord) != -1)
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_TexCoord));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_BoneWeights0));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_BoneWeights1));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_BoneIndices0));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4SSA_BoneIndices1));
|
||||
#undef VERTEX_OFFSET
|
||||
}
|
||||
|
||||
// Bind textures
|
||||
for (unsigned int j = 0; j < pass.TextureUnits.size(); ++j)
|
||||
|
@ -821,15 +840,10 @@ namespace
|
|||
}
|
||||
|
||||
size_t vertex_count = 3 * instance.GetNumFaces();
|
||||
glDrawElements(GL_TRIANGLES, vertex_count, GL_UNSIGNED_INT, instance.GetFaces());
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4SSA_Position));
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4SSA_Normal));
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4SSA_TexCoord));
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4SSA_BoneWeights0));
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4SSA_BoneWeights1));
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4SSA_BoneIndices0));
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4SSA_BoneIndices1));
|
||||
assert (vertex_buffer_offset % sizeof(StdMeshVertex) == 0);
|
||||
size_t base_vertex = vertex_buffer_offset / sizeof(StdMeshVertex);
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, vertex_count, GL_UNSIGNED_INT, reinterpret_cast<void*>(index_buffer_offset), base_vertex);
|
||||
glBindVertexArray(0);
|
||||
call.Finish();
|
||||
|
||||
if(!pass.DepthCheck)
|
||||
|
@ -869,14 +883,9 @@ namespace
|
|||
for (; attach_iter != instance.AttachedMeshesEnd() && ((*attach_iter)->GetFlags() & StdMeshInstance::AM_DrawBefore); ++attach_iter)
|
||||
RenderAttachedMesh(projectionMatrix, modelviewMatrix, *attach_iter, dwModClr, dwBlitMode, dwPlayerColor, pFoW, clipRect, outRect, parity);
|
||||
|
||||
GLint modes[2];
|
||||
// Check if we should draw in wireframe or normal mode
|
||||
if(dwBlitMode & C4GFXBLIT_WIREFRAME)
|
||||
{
|
||||
// save old mode
|
||||
glGetIntegerv(GL_POLYGON_MODE, modes);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
// Render each submesh
|
||||
for (unsigned int i = 0; i < mesh.GetNumSubMeshes(); ++i)
|
||||
|
@ -884,10 +893,7 @@ namespace
|
|||
|
||||
// reset old mode to prevent rendering errors
|
||||
if(dwBlitMode & C4GFXBLIT_WIREFRAME)
|
||||
{
|
||||
glPolygonMode(GL_FRONT, modes[0]);
|
||||
glPolygonMode(GL_BACK, modes[1]);
|
||||
}
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
// Render non-AM_DrawBefore attached meshes
|
||||
for (; attach_iter != instance.AttachedMeshesEnd(); ++attach_iter)
|
||||
|
|
|
@ -55,7 +55,7 @@ bool C4FacetSurface::Create(int iWdt, int iHgt, int iWdt2, int iHgt2)
|
|||
Clear();
|
||||
// Create surface
|
||||
Face.Default();
|
||||
if (!Face.Create(iWdt,iHgt,false,0,0)) return false;
|
||||
if (!Face.Create(iWdt,iHgt)) return false;
|
||||
// Set facet
|
||||
if (iWdt2==C4FCT_Full) iWdt2=Face.Wdt; if (iWdt2==C4FCT_Height) iWdt2=Face.Hgt; if (iWdt2==C4FCT_Width) iWdt2=Face.Wdt;
|
||||
if (iHgt2==C4FCT_Full) iHgt2=Face.Hgt; if (iHgt2==C4FCT_Height) iHgt2=Face.Hgt; if (iHgt2==C4FCT_Width) iHgt2=Face.Wdt;
|
||||
|
|
|
@ -311,7 +311,7 @@ bool CStdFont::AddSurface()
|
|||
psfcFontData = pNewSfcs;
|
||||
C4Surface *sfcNew = psfcFontData[iNumFontSfcs] = new C4Surface();
|
||||
++iNumFontSfcs;
|
||||
if (iSfcSizes) if (!sfcNew->Create(iSfcSizes, iSfcSizes,false,0,0)) return false;
|
||||
if (iSfcSizes) if (!sfcNew->Create(iSfcSizes, iSfcSizes)) return false;
|
||||
// If old surface was locked, unlock it and lock the new one in its stead
|
||||
if (sfcCurrent && sfcCurrent->IsLocked())
|
||||
{
|
||||
|
|
|
@ -289,7 +289,7 @@ void C4Shader::Clear()
|
|||
#ifndef USE_CONSOLE
|
||||
if (!hProg) return;
|
||||
// Need to be detached, then deleted
|
||||
glDeleteObjectARB(hProg);
|
||||
glDeleteProgram(hProg);
|
||||
hProg = 0;
|
||||
// Clear uniform data
|
||||
Uniforms.clear();
|
||||
|
@ -313,43 +313,46 @@ bool C4Shader::Init(const char *szWhat, const char **szUniforms, const char **sz
|
|||
|
||||
#ifndef USE_CONSOLE
|
||||
// Attempt to create shaders
|
||||
const GLint hVert = Create(GL_VERTEX_SHADER_ARB,
|
||||
FormatString("%s vertex shader", szWhat).getData(),
|
||||
VertexShader.getData());
|
||||
const GLint hFrag = Create(GL_FRAGMENT_SHADER_ARB,
|
||||
FormatString("%s fragment shader", szWhat).getData(),
|
||||
FragmentShader.getData());
|
||||
const GLuint hVert = Create(GL_VERTEX_SHADER,
|
||||
FormatString("%s vertex shader", szWhat).getData(),
|
||||
VertexShader.getData());
|
||||
const GLuint hFrag = Create(GL_FRAGMENT_SHADER,
|
||||
FormatString("%s fragment shader", szWhat).getData(),
|
||||
FragmentShader.getData());
|
||||
|
||||
if(!hFrag || !hVert)
|
||||
{
|
||||
if (hVert) glDeleteObjectARB(hVert);
|
||||
if (hFrag) glDeleteShader(hFrag);
|
||||
if (hVert) glDeleteShader(hVert);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Link program
|
||||
const GLint hNewProg = glCreateProgramObjectARB();
|
||||
const GLuint hNewProg = glCreateProgram();
|
||||
#ifdef GL_KHR_debug
|
||||
if (glObjectLabel)
|
||||
glObjectLabel(GL_PROGRAM, hNewProg, -1, szWhat);
|
||||
#endif
|
||||
glAttachObjectARB(hNewProg, hVert);
|
||||
glAttachObjectARB(hNewProg, hFrag);
|
||||
glLinkProgramARB(hNewProg);
|
||||
glAttachShader(hNewProg, hVert);
|
||||
glAttachShader(hNewProg, hFrag);
|
||||
glLinkProgram(hNewProg);
|
||||
// Delete vertex and fragment shader after we linked the program
|
||||
glDeleteObjectARB(hFrag);
|
||||
glDeleteObjectARB(hVert);
|
||||
glDeleteShader(hFrag);
|
||||
glDeleteShader(hVert);
|
||||
|
||||
// Link successful?
|
||||
DumpInfoLog(FormatString("%s shader program", szWhat).getData(), hNewProg);
|
||||
if(GetObjectStatus(hNewProg, GL_OBJECT_LINK_STATUS_ARB) != 1) {
|
||||
glDeleteObjectARB(hNewProg);
|
||||
DumpInfoLog(FormatString("%s shader program", szWhat).getData(), hNewProg, true);
|
||||
GLint status;
|
||||
glGetProgramiv(hNewProg, GL_LINK_STATUS, &status);
|
||||
if(status != GL_TRUE) {
|
||||
glDeleteProgram(hNewProg);
|
||||
ShaderLogF(" gl: Failed to link %s shader!", szWhat);
|
||||
return false;
|
||||
}
|
||||
ShaderLogF(" gl: %s shader linked successfully", szWhat);
|
||||
|
||||
// Everything successful, delete old shader
|
||||
if (hProg != 0) glDeleteObjectARB(hProg);
|
||||
if (hProg != 0) glDeleteProgram(hProg);
|
||||
hProg = hNewProg;
|
||||
|
||||
// Allocate uniform and attribute arrays
|
||||
|
@ -368,13 +371,13 @@ bool C4Shader::Init(const char *szWhat, const char **szUniforms, const char **sz
|
|||
// Get uniform and attribute locations. Note this is expected to fail for a few of them
|
||||
// because the respective uniforms got optimized out!
|
||||
for (int i = 0; i < iUniformCount; i++) {
|
||||
Uniforms[i].address = glGetUniformLocationARB(hProg, szUniforms[i]);
|
||||
Uniforms[i].address = glGetUniformLocation(hProg, szUniforms[i]);
|
||||
Uniforms[i].name = szUniforms[i];
|
||||
ShaderLogF("Uniform %s = %d", szUniforms[i], Uniforms[i].address);
|
||||
}
|
||||
|
||||
for (int i = 0; i < iAttributeCount; i++) {
|
||||
Attributes[i].address = glGetAttribLocationARB(hProg, szAttributes[i]);
|
||||
Attributes[i].address = glGetAttribLocation(hProg, szAttributes[i]);
|
||||
Attributes[i].name = szAttributes[i];
|
||||
ShaderLogF("Attribute %s = %d", szAttributes[i], Attributes[i].address);
|
||||
}
|
||||
|
@ -465,15 +468,15 @@ StdStrBuf C4Shader::Build(const ShaderSliceList &Slices, bool fDebug)
|
|||
StdStrBuf Buf;
|
||||
#ifndef USE_CONSOLE
|
||||
GLint iMaxFrags = 0, iMaxVerts = 0;
|
||||
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, &iMaxFrags);
|
||||
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &iMaxVerts);
|
||||
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &iMaxFrags);
|
||||
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &iMaxVerts);
|
||||
#else
|
||||
int iMaxFrags = INT_MAX, iMaxVerts = INT_MAX;
|
||||
#endif
|
||||
Buf.Format("#version %d\n"
|
||||
"#define MAX_FRAGMENT_UNIFORM_COMPONENTS %d\n"
|
||||
"#define MAX_VERTEX_UNIFORM_COMPONENTS %d\n",
|
||||
C4Shader_Version, iMaxFrags, iMaxVerts);
|
||||
"#define MAX_FRAGMENT_UNIFORM_COMPONENTS %d\n"
|
||||
"#define MAX_VERTEX_UNIFORM_COMPONENTS %d\n",
|
||||
C4Shader_Version, iMaxFrags, iMaxVerts);
|
||||
|
||||
// Put slices
|
||||
int iPos = -1, iNextPos = -1;
|
||||
|
@ -516,56 +519,56 @@ StdStrBuf C4Shader::Build(const ShaderSliceList &Slices, bool fDebug)
|
|||
}
|
||||
|
||||
#ifndef USE_CONSOLE
|
||||
GLhandleARB C4Shader::Create(GLenum iShaderType, const char *szWhat, const char *szShader)
|
||||
GLuint C4Shader::Create(GLenum iShaderType, const char *szWhat, const char *szShader)
|
||||
{
|
||||
// Create shader
|
||||
GLhandleARB hShader = glCreateShaderObjectARB(iShaderType);
|
||||
GLuint hShader = glCreateShader(iShaderType);
|
||||
#ifdef GL_KHR_debug
|
||||
if (glObjectLabel)
|
||||
glObjectLabel(GL_SHADER, hShader, -1, szWhat);
|
||||
#endif
|
||||
|
||||
// Compile
|
||||
glShaderSourceARB(hShader, 1, &szShader, 0);
|
||||
glCompileShaderARB(hShader);
|
||||
glShaderSource(hShader, 1, &szShader, 0);
|
||||
glCompileShader(hShader);
|
||||
|
||||
// Dump any information to log
|
||||
DumpInfoLog(szWhat, hShader);
|
||||
DumpInfoLog(szWhat, hShader, false);
|
||||
|
||||
// Success?
|
||||
if(GetObjectStatus(hShader, GL_OBJECT_COMPILE_STATUS_ARB) == 1)
|
||||
int status;
|
||||
glGetShaderiv(hShader, GL_COMPILE_STATUS, &status);
|
||||
if (status == GL_TRUE)
|
||||
return hShader;
|
||||
|
||||
// Did not work :/
|
||||
glDeleteObjectARB(hShader);
|
||||
glDeleteShader(hShader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void C4Shader::DumpInfoLog(const char *szWhat, GLhandleARB hShader)
|
||||
void C4Shader::DumpInfoLog(const char *szWhat, GLuint hShader, bool forProgram)
|
||||
{
|
||||
// Get length of info line
|
||||
int iLength = 0;
|
||||
glGetObjectParameterivARB(hShader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &iLength);
|
||||
GLint iLength = 0;
|
||||
if (forProgram)
|
||||
glGetProgramiv(hShader, GL_INFO_LOG_LENGTH, &iLength);
|
||||
else
|
||||
glGetShaderiv(hShader, GL_INFO_LOG_LENGTH, &iLength);
|
||||
if(iLength <= 1) return;
|
||||
|
||||
// Allocate buffer, get data
|
||||
char *pBuf = new char [iLength + 1];
|
||||
std::vector<char> buf(iLength + 1);
|
||||
int iActualLength = 0;
|
||||
glGetInfoLogARB(hShader, iLength, &iActualLength, pBuf);
|
||||
if (forProgram)
|
||||
glGetProgramInfoLog(hShader, iLength, &iActualLength, &buf[0]);
|
||||
else
|
||||
glGetShaderInfoLog(hShader, iLength, &iActualLength, &buf[0]);
|
||||
if(iActualLength > iLength || iActualLength <= 0) return;
|
||||
|
||||
// Terminate, log
|
||||
pBuf[iActualLength] = '\0';
|
||||
buf[iActualLength] = '\0';
|
||||
ShaderLogF(" gl: Compiling %s:", szWhat);
|
||||
ShaderLog(pBuf);
|
||||
delete[] pBuf;
|
||||
}
|
||||
|
||||
int C4Shader::GetObjectStatus(GLhandleARB hObj, GLenum type)
|
||||
{
|
||||
int iStatus = 0;
|
||||
glGetObjectParameterivARB(hObj, type, &iStatus);
|
||||
return iStatus;
|
||||
ShaderLog(&buf[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -605,7 +608,7 @@ void C4ShaderCall::Start()
|
|||
const_cast<C4Shader *>(pShader)->Refresh();
|
||||
|
||||
// Activate shader
|
||||
glUseProgramObjectARB(pShader->hProg);
|
||||
glUseProgram(pShader->hProg);
|
||||
fStarted = true;
|
||||
}
|
||||
|
||||
|
@ -613,7 +616,7 @@ void C4ShaderCall::Finish()
|
|||
{
|
||||
// Remove shader
|
||||
if (fStarted) {
|
||||
glUseProgramObjectARB(0);
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
iUnits = 0;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "C4Surface.h"
|
||||
|
||||
// Shader version
|
||||
const int C4Shader_Version = 120; // GLSL 1.20 / OpenGL 2.1
|
||||
const int C4Shader_Version = 150; // GLSL 1.50 / OpenGL 3.2
|
||||
|
||||
// Maximum number of texture coordinates
|
||||
const int C4Shader_MaxTexCoords = 8;
|
||||
|
@ -77,7 +77,7 @@ private:
|
|||
|
||||
#ifndef USE_CONSOLE
|
||||
// shaders
|
||||
GLhandleARB hProg;
|
||||
GLuint hProg;
|
||||
// shader variables
|
||||
struct Variable { int address; const char* name; };
|
||||
std::vector<Variable> Uniforms;
|
||||
|
@ -151,9 +151,8 @@ private:
|
|||
StdStrBuf Build(const ShaderSliceList &Slices, bool fDebug = false);
|
||||
|
||||
#ifndef USE_CONSOLE
|
||||
GLhandleARB Create(GLenum iShaderType, const char *szWhat, const char *szShader);
|
||||
void DumpInfoLog(const char *szWhat, GLhandleARB hShader);
|
||||
int GetObjectStatus(GLhandleARB hObj, GLenum type);
|
||||
GLuint Create(GLenum iShaderType, const char *szWhat, const char *szShader);
|
||||
void DumpInfoLog(const char *szWhat, GLuint hShader, bool forProgram);
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
@ -186,35 +185,35 @@ public:
|
|||
// something could be done about it.
|
||||
void SetUniform1i(int iUniform, int iX) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform1iARB(pShader->GetUniform(iUniform), iX);
|
||||
glUniform1i(pShader->GetUniform(iUniform), iX);
|
||||
}
|
||||
void SetUniform1f(int iUniform, float gX) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform1fARB(pShader->GetUniform(iUniform), gX);
|
||||
glUniform1f(pShader->GetUniform(iUniform), gX);
|
||||
}
|
||||
void SetUniform2f(int iUniform, float gX, float gY) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform2fARB(pShader->GetUniform(iUniform), gX, gY);
|
||||
glUniform2f(pShader->GetUniform(iUniform), gX, gY);
|
||||
}
|
||||
void SetUniform1iv(int iUniform, int iLength, const int *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform1ivARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
glUniform1iv(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
void SetUniform1fv(int iUniform, int iLength, const float *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform1fvARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
glUniform1fv(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
void SetUniform2fv(int iUniform, int iLength, const float *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform2fvARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
glUniform2fv(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
void SetUniform3fv(int iUniform, int iLength, const float *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform3fvARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
glUniform3fv(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
void SetUniform4fv(int iUniform, int iLength, const float *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform4fvARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
glUniform4fv(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
|
||||
// Matrices are in row-major order
|
||||
|
@ -235,7 +234,7 @@ public:
|
|||
|
||||
void SetUniformMatrix4x4fv(int iUniform, int iLength, const float* pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniformMatrix4fvARB(pShader->GetUniform(iUniform), iLength, GL_TRUE, pVals);
|
||||
glUniformMatrix4fv(pShader->GetUniform(iUniform), iLength, GL_TRUE, pVals);
|
||||
}
|
||||
|
||||
void SetUniformMatrix3x3(int iUniform, const StdMeshMatrix& matrix)
|
||||
|
@ -267,14 +266,14 @@ public:
|
|||
if (pShader->HaveUniform(iUniform))
|
||||
{
|
||||
const float mat[16] = { matrix(0, 0), matrix(1, 0), matrix(2, 0), 0.0f, matrix(0, 1), matrix(1, 1), matrix(2, 1), 0.0f, matrix(0, 2), matrix(1, 2), matrix(2, 2), 0.0f, matrix(0, 3), matrix(1, 3), matrix(2, 3), 1.0f };
|
||||
glUniformMatrix4fvARB(pShader->GetUniform(iUniform), 1, GL_FALSE, mat);
|
||||
glUniformMatrix4fv(pShader->GetUniform(iUniform), 1, GL_FALSE, mat);
|
||||
}
|
||||
}
|
||||
|
||||
void SetUniformMatrix4x4(int iUniform, const StdProjectionMatrix& matrix)
|
||||
{
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniformMatrix4fvARB(pShader->GetUniform(iUniform), 1, GL_TRUE, matrix.data());
|
||||
glUniformMatrix4fv(pShader->GetUniform(iUniform), 1, GL_TRUE, matrix.data());
|
||||
}
|
||||
|
||||
void Start();
|
||||
|
|
|
@ -51,7 +51,7 @@ C4Surface::C4Surface(int iWdt, int iHgt, int iFlags) : fIsBackground(false)
|
|||
{
|
||||
Default();
|
||||
// create
|
||||
Create(iWdt, iHgt, false, 0, iFlags);
|
||||
Create(iWdt, iHgt, iFlags);
|
||||
}
|
||||
|
||||
C4Surface::C4Surface(C4AbstractApp * pApp, C4Window * pWindow):
|
||||
|
@ -94,7 +94,6 @@ void C4Surface::Default()
|
|||
pWindow=NULL;
|
||||
ClrByOwnerClr=0;
|
||||
iTexSize=iTexX=iTexY=0;
|
||||
fIsRenderTarget=false;
|
||||
fIsBackground=false;
|
||||
#ifdef _DEBUG
|
||||
dbg_idx = NULL;
|
||||
|
@ -172,7 +171,7 @@ void C4Surface::Clip(int iX, int iY, int iX2, int iY2)
|
|||
ClipX2=Clamp(iX2,0,Wdt-1); ClipY2=Clamp(iY2,0,Hgt-1);
|
||||
}
|
||||
|
||||
bool C4Surface::Create(int iWdt, int iHgt, bool fIsRenderTarget, int MaxTextureSize, int iFlags)
|
||||
bool C4Surface::Create(int iWdt, int iHgt, int iFlags)
|
||||
{
|
||||
Clear(); Default();
|
||||
// check size
|
||||
|
@ -187,9 +186,8 @@ bool C4Surface::Create(int iWdt, int iHgt, bool fIsRenderTarget, int MaxTextureS
|
|||
Format=pGL->sfcFmt;
|
||||
#endif
|
||||
byBytesPP=pDraw->byByteCnt;
|
||||
this->fIsRenderTarget = fIsRenderTarget;
|
||||
// create textures
|
||||
if (!CreateTextures(MaxTextureSize, iFlags)) { Clear(); return false; }
|
||||
if (!CreateTextures(iFlags)) { Clear(); return false; }
|
||||
// update clipping
|
||||
NoClip();
|
||||
// success
|
||||
|
@ -203,7 +201,7 @@ bool C4Surface::Copy(C4Surface &fromSfc)
|
|||
// Default to other surface's color depth
|
||||
Default();
|
||||
// Create surface (TODO: copy flags)
|
||||
if (!Create(fromSfc.Wdt, fromSfc.Hgt, false, 0, 0)) return false;
|
||||
if (!Create(fromSfc.Wdt, fromSfc.Hgt)) return false;
|
||||
// Blit copy
|
||||
if (!pDraw->BlitSurface(&fromSfc, this, 0, 0, false))
|
||||
{ Clear(); return false; }
|
||||
|
@ -211,39 +209,16 @@ bool C4Surface::Copy(C4Surface &fromSfc)
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
int GetNeedTexSize(int Size)
|
||||
{
|
||||
int iNeedSize = Size;
|
||||
|
||||
#ifndef USE_CONSOLE
|
||||
if (!pGL || !GLEW_ARB_texture_non_power_of_two)
|
||||
#endif
|
||||
{
|
||||
int n=0;
|
||||
while ((1<<++n) < iNeedSize) {}
|
||||
iNeedSize = 1<<n;
|
||||
}
|
||||
|
||||
return iNeedSize;
|
||||
}
|
||||
}
|
||||
|
||||
bool C4Surface::CreateTextures(int MaxTextureSize, int Flags)
|
||||
bool C4Surface::CreateTextures(int Flags)
|
||||
{
|
||||
// free previous
|
||||
FreeTextures();
|
||||
iTexSize=std::min(GetNeedTexSize(std::max(Wdt, Hgt)), pDraw->MaxTexSize);
|
||||
if (MaxTextureSize)
|
||||
iTexSize=std::min(iTexSize, MaxTextureSize);
|
||||
iTexSize=std::min(std::max(Wdt, Hgt), pDraw->MaxTexSize);
|
||||
// get the number of textures needed for this size
|
||||
iTexX=(Wdt-1)/iTexSize +1;
|
||||
iTexY=(Hgt-1)/iTexSize +1;
|
||||
// get mem for texture array
|
||||
textures.reserve(iTexX * iTexY);
|
||||
// cvan't be render target if it's not a single surface
|
||||
if (!IsSingleSurface()) fIsRenderTarget = false;
|
||||
// create textures
|
||||
for (int y = 0; y < iTexY; ++y)
|
||||
{
|
||||
|
@ -251,8 +226,8 @@ bool C4Surface::CreateTextures(int MaxTextureSize, int Flags)
|
|||
{
|
||||
int sizeX = iTexSize;
|
||||
int sizeY = iTexSize;
|
||||
if(x == iTexX-1) sizeX = GetNeedTexSize( (Wdt - 1) % iTexSize + 1);
|
||||
if(y == iTexY-1) sizeY = GetNeedTexSize( (Hgt - 1) % iTexSize + 1);
|
||||
if(x == iTexX-1) sizeX = (Wdt - 1) % iTexSize + 1;
|
||||
if(y == iTexY-1) sizeY = (Hgt - 1) % iTexSize + 1;
|
||||
|
||||
textures.emplace_back(sizeX, sizeY, Flags);
|
||||
|
||||
|
@ -337,7 +312,7 @@ bool C4Surface::CreateColorByOwner(C4Surface *pBySurface)
|
|||
if (!pBySurface) return false;
|
||||
if (pBySurface->textures.empty()) return false;
|
||||
// create in same size
|
||||
if (!Create(pBySurface->Wdt, pBySurface->Hgt, false, 0, 0)) return false;
|
||||
if (!Create(pBySurface->Wdt, pBySurface->Hgt)) return false;
|
||||
// copy scale
|
||||
Scale = pBySurface->Scale;
|
||||
// set main surface
|
||||
|
@ -421,7 +396,7 @@ bool C4Surface::ReadBMP(CStdStream &hGroup, int iFlags)
|
|||
}
|
||||
|
||||
// Create and lock surface
|
||||
if (!Create(BitmapInfo.Info.biWidth,BitmapInfo.Info.biHeight, false, 0, iFlags)) return false;
|
||||
if (!Create(BitmapInfo.Info.biWidth,BitmapInfo.Info.biHeight, iFlags)) return false;
|
||||
if (!Lock()) { Clear(); return false; }
|
||||
|
||||
// create line buffer
|
||||
|
@ -729,6 +704,8 @@ bool C4Surface::SetPixDw(int iX, int iY, DWORD dwClr)
|
|||
uint16_t wClr=ClrDw2W(dwClr);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, iX, iY, 1, 1, GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, &wClr);
|
||||
}
|
||||
const bool fMipMap = (pTexRef->iFlags & C4SF_MipMap) != 0;
|
||||
if (fMipMap) glGenerateMipmap(GL_TEXTURE_2D);
|
||||
return true;
|
||||
}
|
||||
// Otherwise, make sure that the texlock covers the new pixel
|
||||
|
@ -968,8 +945,8 @@ void C4TexRef::CreateTexture()
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, fTileable ? GL_REPEAT : GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, fMipMap ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR);
|
||||
if (fMipMap) glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, iSizeX, iSizeY, 0, GL_BGRA, pDraw->byByteCnt == 2 ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
||||
if (fMipMap) glGenerateMipmap(GL_TEXTURE_2D);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1038,6 +1015,10 @@ void C4TexRef::Unlock()
|
|||
assert(pGL->pMainCtx);
|
||||
pGL->pMainCtx->Select();
|
||||
}
|
||||
|
||||
const bool fTileable = (iFlags & C4SF_Tileable) != 0;
|
||||
const bool fMipMap = (iFlags & C4SF_MipMap) != 0;
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// reuse the existing texture
|
||||
|
@ -1047,6 +1028,7 @@ void C4TexRef::Unlock()
|
|||
GL_BGRA, pDraw->byByteCnt == 2 ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_INT_8_8_8_8_REV, texLock.pBits);
|
||||
|
||||
delete[] static_cast<unsigned char*>(texLock.pBits); texLock.pBits=NULL;
|
||||
if (fMipMap) glGenerateMipmap(GL_TEXTURE_2D);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ public:
|
|||
int iTexSize; // size of textures
|
||||
int iTexX, iTexY; // number of textures in x/y-direction
|
||||
int ClipX,ClipY,ClipX2,ClipY2;
|
||||
bool fIsRenderTarget; // set for surfaces to be used as offscreen render targets
|
||||
bool fIsBackground; // background surfaces fill unused pixels with black, rather than transparency - must be set prior to loading
|
||||
#ifdef _DEBUG
|
||||
int *dbg_idx;
|
||||
|
@ -127,7 +126,7 @@ public:
|
|||
bool SetPixDw(int iX, int iY, DWORD dwCol); // set pix in surface only
|
||||
bool SetPixAlpha(int iX, int iY, BYTE byAlpha); // adjust alpha value of pixel
|
||||
bool BltPix(int iX, int iY, C4Surface *sfcSource, int iSrcX, int iSrcY, bool fTransparency); // blit pixel from source to this surface (assumes clipped coordinates!)
|
||||
bool Create(int iWdt, int iHgt, bool fIsRenderTarget, int MaxTextureSize, int iFlags);
|
||||
bool Create(int iWdt, int iHgt, int iFlags = 0);
|
||||
bool Copy(C4Surface &fromSfc);
|
||||
bool CreateColorByOwner(C4Surface *pBySurface); // create ColorByOwner-surface
|
||||
bool SetAsClrByOwnerOf(C4Surface *pOfSurface); // assume that ColorByOwner-surface has been created, and just assign it; fails if the size doesn't match
|
||||
|
@ -163,7 +162,7 @@ public:
|
|||
private:
|
||||
void MapBytes(BYTE *bpMap);
|
||||
bool ReadBytes(BYTE **lpbpData, void *bpTarget, int iSize);
|
||||
bool CreateTextures(int MaxTextureSize, int iFlags); // create ppTex-array
|
||||
bool CreateTextures(int iFlags); // create ppTex-array
|
||||
void FreeTextures(); // free ppTex-array if existant
|
||||
|
||||
bool GetTexAtImpl(C4TexRef **ppTexRef, int &rX, int &rY);
|
||||
|
|
|
@ -162,7 +162,7 @@ bool C4Surface::ReadPNG(CStdStream &hGroup, int iFlags)
|
|||
// abort if loading wasn't successful
|
||||
if (!fSuccess) return false;
|
||||
// create surface(s) - do not create an 8bit-buffer!
|
||||
if (!Create(png.iWdt, png.iHgt, false, 0, iFlags)) return false;
|
||||
if (!Create(png.iWdt, png.iHgt, iFlags)) return false;
|
||||
// lock for writing data
|
||||
if (!Lock()) return false;
|
||||
if (textures.empty())
|
||||
|
@ -342,7 +342,7 @@ bool C4Surface::ReadJPEG(CStdStream &hGroup, int iFlags)
|
|||
jpeg_start_decompress(&cinfo);
|
||||
|
||||
// create surface(s) - do not create an 8bit-buffer!
|
||||
if (!Create(cinfo.output_width, cinfo.output_height, false, 0, iFlags)) return false;
|
||||
if (!Create(cinfo.output_width, cinfo.output_height, iFlags)) return false;
|
||||
// JSAMPLEs per row in output buffer
|
||||
row_stride = cinfo.output_width * cinfo.output_components;
|
||||
// Make a one-row-high sample array that will go away at jpeg_destroy_decompress
|
||||
|
@ -377,7 +377,7 @@ bool C4Surface::ReadJPEG(CStdStream &hGroup, int iFlags)
|
|||
|
||||
bool C4Surface::ReadJPEG(CStdStream &, int) {
|
||||
// Dummy surface
|
||||
if (!Create(1, 1, false, 1, 0)) return false;
|
||||
if (!Create(1, 1)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -368,10 +368,8 @@ void CPNGFile::WaitForSaves()
|
|||
first = false;
|
||||
#ifdef HAVE_WINTHREAD
|
||||
Sleep(100);
|
||||
#elif defined (__APPLE__)
|
||||
#else
|
||||
sched_yield();
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
pthread_yield();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -322,7 +322,6 @@ namespace C4GameLobby
|
|||
else if (eToState == CDS_Countdown)
|
||||
{
|
||||
StartSoundEffect("Fire::Fuse");
|
||||
StartSoundEffect("Structures::Elevator::Moving", true);
|
||||
}
|
||||
if (eToState == CDS_Countdown || eToState == CDS_LongCountdown)
|
||||
{
|
||||
|
@ -373,7 +372,7 @@ namespace C4GameLobby
|
|||
{
|
||||
// first countdown message
|
||||
OnLog(Pkt.GetCountdownMsg(!fWasCountdown).getData(), C4GUI_LogFontClr2);
|
||||
StartSoundEffect("Hits::Materials::Wood::WoodHit*");
|
||||
StartSoundEffect("UI::Tick");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -831,7 +831,7 @@ bool C4KeyboardInput::DoInput(const C4KeyCodeEx &InKey, C4KeyEventType InEvent,
|
|||
{
|
||||
// store last-key-info
|
||||
LastKeyExtraData.iStrength = (iStrength >= 0) ? iStrength : ((InEvent != KEYEV_Up) * 100);
|
||||
LastKeyExtraData.game_x = LastKeyExtraData.game_y = LastKeyExtraData.vp_x = LastKeyExtraData.vp_y = 0;
|
||||
LastKeyExtraData.game_x = LastKeyExtraData.game_y = LastKeyExtraData.vp_x = LastKeyExtraData.vp_y = C4KeyEventData::KeyPos_None;
|
||||
// check all key events generated by this key: First the keycode itself, then any more generic key events like KEY_Any
|
||||
const int32_t iKeyRangeMax = 5;
|
||||
int32_t iKeyRangeCnt=0, j;
|
||||
|
|
|
@ -225,9 +225,10 @@ private:
|
|||
// extra data associated with a key event
|
||||
struct C4KeyEventData
|
||||
{
|
||||
enum { KeyPos_None = 0x7fffff }; // value used to denote invalid/none key positions
|
||||
int32_t iStrength; // pressure between 0 and 100 (100 for nomal keypress)
|
||||
int32_t game_x,game_y, vp_x,vp_y; // position for mouse event, landscape+viewport coordinates
|
||||
C4KeyEventData() : iStrength(0), game_x(0), game_y(0), vp_x(0), vp_y(0) {}
|
||||
C4KeyEventData() : iStrength(0), game_x(KeyPos_None), game_y(KeyPos_None), vp_x(KeyPos_None), vp_y(KeyPos_None) {}
|
||||
C4KeyEventData(int32_t iStrength, int32_t game_x, int32_t game_y, int32_t vp_x, int32_t vp_y) : iStrength(iStrength), game_x(game_x), game_y(game_y),vp_x(vp_x),vp_y(vp_y) {}
|
||||
void CompileFunc(StdCompiler *pComp);
|
||||
bool operator ==(const struct C4KeyEventData &cmp) const;
|
||||
|
|
|
@ -1694,13 +1694,22 @@ bool C4ScriptGuiWindow::UpdateLayout(C4TargetFacet &cgo, float parentWidth, floa
|
|||
// If this window contains text, we auto-fit to the text height;
|
||||
// but we only break text when the window /would/ crop it otherwise.
|
||||
StdCopyStrBuf *strBuf = props[C4ScriptGuiWindowPropertyName::text].GetStrBuf();
|
||||
int minRequiredTextHeight = 0;
|
||||
if (strBuf && !(style & C4ScriptGuiWindowStyleFlag::NoCrop))
|
||||
{
|
||||
StdStrBuf sText;
|
||||
int32_t textHgt = ::GraphicsResource.FontRegular.BreakMessage(strBuf->getData(), rcBounds.Wdt, &sText, true);
|
||||
const int32_t rawTextHeight = ::GraphicsResource.FontRegular.BreakMessage(strBuf->getData(), rcBounds.Wdt, &sText, true);
|
||||
// enable auto scroll
|
||||
if (textHgt > rcBounds.Hgt)
|
||||
rcBounds.Hgt = textHgt;
|
||||
if (rawTextHeight - 1 > rcBounds.Hgt)
|
||||
{
|
||||
// If we need to scroll, we will also have to add a scrollbar that takes up some width.
|
||||
// Recalculate the actual height, taking into account the scrollbar.
|
||||
// This is not done in the calculation earlier, because then e.g. a 2x1em field could not contain two letters
|
||||
// but would immediately add a linebreak.
|
||||
// In the case that this window auto-resizes (FitChildren), the small additional margin to the bottom should not matter much.
|
||||
const int32_t actualTextHeight = ::GraphicsResource.FontRegular.BreakMessage(strBuf->getData(), rcBounds.Wdt - pScrollBar->rcBounds.Wdt, &sText, true);
|
||||
minRequiredTextHeight = actualTextHeight;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateChildLayout(cgo, width, height);
|
||||
|
@ -1716,7 +1725,7 @@ bool C4ScriptGuiWindow::UpdateLayout(C4TargetFacet &cgo, float parentWidth, floa
|
|||
|
||||
// check if we need a scroll-bar
|
||||
int32_t topMostChild = 0;
|
||||
int32_t bottomMostChild = 0;
|
||||
int32_t bottomMostChild = minRequiredTextHeight;
|
||||
for (Element * element : *this)
|
||||
{
|
||||
C4ScriptGuiWindow *child = static_cast<C4ScriptGuiWindow*>(element);
|
||||
|
@ -1843,12 +1852,18 @@ bool C4ScriptGuiWindow::Draw(C4TargetFacet &cgo, int32_t player, C4Rect *current
|
|||
{
|
||||
StdStrBuf sText;
|
||||
int alignment = ALeft;
|
||||
// If we are showing a scrollbar, we need to leave a bit of space for it so that it doesn't overlap the text.
|
||||
const int scrollbarXOffset = pScrollBar->IsVisible() ? pScrollBar->rcBounds.Wdt : 0;
|
||||
const int scrollbarScroll = pScrollBar->IsVisible() ? this->GetScrollY() : 0;
|
||||
const int actualDrawingWidth = outDrawWdt - scrollbarXOffset;
|
||||
|
||||
// If we are set to NoCrop, the message will be split by string-defined line breaks only.
|
||||
int allowedTextWidth = outDrawWdt;
|
||||
int allowedTextWidth = actualDrawingWidth;
|
||||
|
||||
if (style & C4ScriptGuiWindowStyleFlag::NoCrop)
|
||||
allowedTextWidth = std::numeric_limits<int>::max();
|
||||
int32_t textHgt = ::GraphicsResource.FontRegular.BreakMessage(strBuf->getData(), allowedTextWidth, &sText, true);
|
||||
float textYOffset = 0.0f, textXOffset = 0.0f;
|
||||
float textYOffset = static_cast<float>(-scrollbarScroll), textXOffset = 0.0f;
|
||||
if (style & C4ScriptGuiWindowStyleFlag::TextVCenter)
|
||||
textYOffset = float(outDrawHgt) / 2.0f - float(textHgt) / 2.0f;
|
||||
else if (style & C4ScriptGuiWindowStyleFlag::TextBottom)
|
||||
|
@ -1857,7 +1872,7 @@ bool C4ScriptGuiWindow::Draw(C4TargetFacet &cgo, int32_t player, C4Rect *current
|
|||
{
|
||||
int wdt, hgt;
|
||||
::GraphicsResource.FontRegular.GetTextExtent(sText.getData(), wdt, hgt, true);
|
||||
textXOffset = float(outDrawWdt) / 2.0f;
|
||||
textXOffset = float(actualDrawingWidth) / 2.0f;
|
||||
alignment = ACenter;
|
||||
}
|
||||
else if (style & C4ScriptGuiWindowStyleFlag::TextRight)
|
||||
|
@ -1865,7 +1880,7 @@ bool C4ScriptGuiWindow::Draw(C4TargetFacet &cgo, int32_t player, C4Rect *current
|
|||
alignment = ARight;
|
||||
int wdt, hgt;
|
||||
::GraphicsResource.FontRegular.GetTextExtent(sText.getData(), wdt, hgt, true);
|
||||
textXOffset = float(outDrawWdt);
|
||||
textXOffset = float(actualDrawingWidth);
|
||||
}
|
||||
pDraw->TextOut(sText.getData(), ::GraphicsResource.FontRegular, 1.0, cgo.Surface, outDrawX + textXOffset, outDrawY + textYOffset, 0xffffffff, alignment);
|
||||
}
|
||||
|
@ -1896,20 +1911,13 @@ bool C4ScriptGuiWindow::GetClippingRect(int32_t &left, int32_t &top, int32_t &ri
|
|||
if (IsRoot() || (style & C4ScriptGuiWindowStyleFlag::NoCrop))
|
||||
return false;
|
||||
|
||||
if (pScrollBar->IsVisible())
|
||||
{
|
||||
left = rcBounds.x;
|
||||
top = rcBounds.y;
|
||||
right = rcBounds.Wdt + left;
|
||||
bottom = rcBounds.Hgt + top;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*const int32_t &style = props[C4ScriptGuiWindowPropertyName::style].GetInt();
|
||||
if (!isMainWindow && !(style & C4ScriptGuiWindowStyleFlag::NoCrop))
|
||||
return static_cast<C4ScriptGuiWindow*>(GetParent())->GetClippingRect(left, top, right, bottom);
|
||||
*/
|
||||
return false;
|
||||
// Other windows always clip their children.
|
||||
// This implicitly clips childrens' text to the parent size, too.
|
||||
left = rcBounds.x;
|
||||
top = rcBounds.y;
|
||||
right = rcBounds.Wdt + left;
|
||||
bottom = rcBounds.Hgt + top;
|
||||
return true;
|
||||
}
|
||||
|
||||
void C4ScriptGuiWindow::SetTag(C4String *tag)
|
||||
|
|
|
@ -54,8 +54,10 @@ const char *const SEPERATOR_TEXTURE = "--SEP--";
|
|||
C4LandscapeRenderGL::C4LandscapeRenderGL()
|
||||
{
|
||||
ZeroMem(Surfaces, sizeof(Surfaces));
|
||||
ZeroMem(hMaterialTexture, sizeof(hMaterialTexture));
|
||||
hMaterialTexture = 0;
|
||||
hVBO = 0;
|
||||
hVAOIDNoLight = 0;
|
||||
hVAOIDLight = 0;
|
||||
}
|
||||
|
||||
C4LandscapeRenderGL::~C4LandscapeRenderGL()
|
||||
|
@ -142,12 +144,26 @@ void C4LandscapeRenderGL::Clear()
|
|||
delete Surfaces[i];
|
||||
Surfaces[i] = NULL;
|
||||
}
|
||||
if (hMaterialTexture) glDeleteTextures(1, &hMaterialTexture);
|
||||
hMaterialTexture = 0;
|
||||
|
||||
glDeleteTextures(C4LR_MipMapCount, hMaterialTexture);
|
||||
std::fill_n(hMaterialTexture, C4LR_MipMapCount, 0);
|
||||
if (hVBO != 0)
|
||||
{
|
||||
glDeleteBuffers(1, &hVBO);
|
||||
hVBO = 0;
|
||||
}
|
||||
|
||||
glDeleteBuffers(1, &hVBO);
|
||||
hVBO = 0;
|
||||
if (hVAOIDLight != 0)
|
||||
{
|
||||
pGL->FreeVAOID(hVAOIDLight);
|
||||
hVAOIDLight = 0;
|
||||
}
|
||||
|
||||
if (hVAOIDNoLight != 0)
|
||||
{
|
||||
pGL->FreeVAOID(hVAOIDNoLight);
|
||||
hVAOIDNoLight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool C4LandscapeRenderGL::InitLandscapeTexture()
|
||||
|
@ -166,7 +182,7 @@ bool C4LandscapeRenderGL::InitLandscapeTexture()
|
|||
for(int i = 0; i < C4LR_SurfaceCount; i++)
|
||||
{
|
||||
Surfaces[i] = new C4Surface();
|
||||
if(!Surfaces[i]->Create(iSfcWdt, iSfcHgt, false, 0, 0))
|
||||
if(!Surfaces[i]->Create(iSfcWdt, iSfcHgt))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -181,9 +197,7 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
|||
AddTexturesFromMap(pTexs);
|
||||
|
||||
// Determine depth to use
|
||||
iMaterialTextureDepth = 1;
|
||||
while(iMaterialTextureDepth < 2*int32_t(MaterialTextureMap.size()))
|
||||
iMaterialTextureDepth <<= 1;
|
||||
iMaterialTextureDepth = 2*MaterialTextureMap.size();
|
||||
int32_t iNormalDepth = iMaterialTextureDepth / 2;
|
||||
|
||||
// Find the largest texture
|
||||
|
@ -197,15 +211,16 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
|||
|
||||
// Get size for our textures. We might be limited by hardware
|
||||
int iTexWdt = pRefSfc->Wdt, iTexHgt = pRefSfc->Hgt;
|
||||
GLint iMaxTexSize;
|
||||
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &iMaxTexSize);
|
||||
GLint iMaxTexSize, iMaxTexLayers;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &iMaxTexSize);
|
||||
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &iMaxTexLayers);
|
||||
if (iTexWdt > iMaxTexSize || iTexHgt > iMaxTexSize)
|
||||
{
|
||||
iTexWdt = std::min(iTexWdt, iMaxTexSize);
|
||||
iTexHgt = std::min(iTexHgt, iMaxTexSize);
|
||||
LogF(" gl: Material textures too large, GPU only supports %dx%d! Cropping might occur!", iMaxTexSize, iMaxTexSize);
|
||||
}
|
||||
if(iMaterialTextureDepth >= iMaxTexSize)
|
||||
if(iMaterialTextureDepth >= iMaxTexLayers)
|
||||
{
|
||||
LogF(" gl: Too many material textures! GPU only supports 3D texture depth of %d!", iMaxTexSize);
|
||||
return false;
|
||||
|
@ -288,70 +303,34 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
|||
// Clear error error(s?)
|
||||
while(glGetError()) {}
|
||||
|
||||
// Alloc 3D textures
|
||||
glEnable(GL_TEXTURE_3D);
|
||||
glGenTextures(C4LR_MipMapCount, hMaterialTexture);
|
||||
|
||||
// Generate textures (mipmaps too!)
|
||||
// Alloc 2D texture array
|
||||
glGenTextures(1, &hMaterialTexture);
|
||||
|
||||
// Generate textures
|
||||
int iSizeSum = 0;
|
||||
BYTE *pLastData = new BYTE [iSize / 4];
|
||||
for(int iMMLevel = 0; iMMLevel < C4LR_MipMapCount; iMMLevel++)
|
||||
{
|
||||
|
||||
// Scale the texture down for mip-mapping
|
||||
if(iMMLevel) {
|
||||
BYTE *pOut = pData;
|
||||
BYTE *pIn[4] = {
|
||||
pLastData, pLastData + iBytesPP,
|
||||
pLastData + iBytesPP * iTexWdt, pLastData + iBytesPP * iTexWdt + iBytesPP
|
||||
};
|
||||
for (int i = 0; i < iMaterialTextureDepth; ++i)
|
||||
for (int y = 0; y < iTexHgt / 2; ++y)
|
||||
{
|
||||
for (int x = 0; x < iTexWdt / 2; ++x)
|
||||
{
|
||||
for (int j = 0; j < iBytesPP; j++)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
s += *pIn[0]++; s += 3 * *pIn[1]++; s += 3 * *pIn[2]++; s += *pIn[3]++;
|
||||
*pOut++ = BYTE(s / 8);
|
||||
}
|
||||
pIn[0] += iBytesPP; pIn[1] += iBytesPP; pIn[2] += iBytesPP; pIn[3] += iBytesPP;
|
||||
}
|
||||
pIn[0] += iBytesPP * iTexWdt; pIn[1] += iBytesPP * iTexWdt;
|
||||
pIn[2] += iBytesPP * iTexWdt; pIn[3] += iBytesPP * iTexWdt;
|
||||
}
|
||||
iTexWdt /= 2; iTexHgt /= 2;
|
||||
}
|
||||
|
||||
// Select texture
|
||||
glBindTexture(GL_TEXTURE_3D, hMaterialTexture[iMMLevel]);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
// Select texture
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, hMaterialTexture);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// We fully expect to tile these
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
// We fully expect to tile these
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
|
||||
// Make it happen!
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, 4, iTexWdt, iTexHgt, iMaterialTextureDepth, 0, GL_BGRA,
|
||||
iBytesPP == 2 ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
pData);
|
||||
// Make it happen!
|
||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, iTexWdt, iTexHgt, iMaterialTextureDepth, 0, GL_BGRA,
|
||||
iBytesPP == 2 ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
pData);
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
|
||||
|
||||
// Exchange buffers
|
||||
BYTE *tmp = pLastData;
|
||||
pLastData = pData;
|
||||
pData = tmp;
|
||||
|
||||
// Statistics
|
||||
iSizeSum += iTexWdt * iTexHgt * iMaterialTextureDepth * iBytesPP;
|
||||
}
|
||||
// Statistics
|
||||
iSizeSum += iTexWdt * iTexHgt * iMaterialTextureDepth * iBytesPP;
|
||||
|
||||
// Dispose of data
|
||||
delete [] pData;
|
||||
delete [] pLastData;
|
||||
glDisable(GL_TEXTURE_3D);
|
||||
|
||||
// Check whether we were successful
|
||||
if(int err = glGetError())
|
||||
|
@ -361,10 +340,9 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
|||
}
|
||||
|
||||
// Announce the good news
|
||||
LogF(" gl: Texturing uses %d slots at %dx%d, %d levels (%d MB total)",
|
||||
LogF(" gl: Texturing uses %d slots at %dx%d (%d MB total)",
|
||||
static_cast<int>(MaterialTextureMap.size()),
|
||||
iMaterialWidth, iMaterialHeight,
|
||||
C4LR_MipMapCount,
|
||||
iSizeSum / 1000000);
|
||||
|
||||
return true;
|
||||
|
@ -634,13 +612,6 @@ bool C4LandscapeRenderGL::LoadShader(C4GroupSet *pGroups, C4Shader& shader, cons
|
|||
|
||||
bool C4LandscapeRenderGL::LoadShaders(C4GroupSet *pGroups)
|
||||
{
|
||||
// No support?
|
||||
if(!GLEW_ARB_fragment_program)
|
||||
{
|
||||
Log(" gl: no shader support!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// First, clear out all existing shaders
|
||||
ClearShaders();
|
||||
|
||||
|
@ -677,6 +648,11 @@ bool C4LandscapeRenderGL::InitVBO()
|
|||
glBindBuffer(GL_ARRAY_BUFFER, hVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(float), NULL, GL_STREAM_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
// Also allocate the VAO IDs
|
||||
assert(hVAOIDLight == 0);
|
||||
assert(hVAOIDNoLight == 0);
|
||||
hVAOIDLight = pGL->GenVAOID();
|
||||
hVAOIDNoLight = pGL->GenVAOID();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1033,13 +1009,7 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion *Ligh
|
|||
}
|
||||
if(ShaderCall.AllocTexUnit(C4LRU_MaterialTex))
|
||||
{
|
||||
// Decide which mip-map level to use
|
||||
double z = 0.5; int iMM = 0;
|
||||
while(pGL->Zoom < z * ::Game.C4S.Landscape.MaterialZoom && iMM + 1 <C4LR_MipMapCount)
|
||||
{ z /= 2; iMM++; }
|
||||
glBindTexture(GL_TEXTURE_3D, hMaterialTexture[iMM]);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, hMaterialTexture);
|
||||
}
|
||||
if(ShaderCall.AllocTexUnit(C4LRU_MatMapTex))
|
||||
{
|
||||
|
@ -1120,27 +1090,30 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion *Ligh
|
|||
glBindBuffer(GL_ARRAY_BUFFER, hVBO);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, nFloats * sizeof(float), vtxData);
|
||||
|
||||
// Setup state
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4LRA_Position));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4LRA_LandscapeTexCoord));
|
||||
|
||||
glVertexAttribPointer(shader->GetAttribute(C4LRA_Position), 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glVertexAttribPointer(shader->GetAttribute(C4LRA_LandscapeTexCoord), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(8 * sizeof(float)));
|
||||
|
||||
if (Light)
|
||||
// Bind VAO
|
||||
unsigned int vaoid = Light ? hVAOIDLight : hVAOIDNoLight;
|
||||
GLuint vao;
|
||||
const bool has_vao = pGL->GetVAO(vaoid, vao);
|
||||
glBindVertexArray(vao);
|
||||
if (!has_vao)
|
||||
{
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4LRA_LightTexCoord));
|
||||
glVertexAttribPointer(shader->GetAttribute(C4LRA_LightTexCoord), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(16 * sizeof(float)));
|
||||
// Setup state
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4LRA_Position));
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4LRA_LandscapeTexCoord));
|
||||
if (Light)
|
||||
glEnableVertexAttribArray(shader->GetAttribute(C4LRA_LightTexCoord));
|
||||
|
||||
glVertexAttribPointer(shader->GetAttribute(C4LRA_Position), 2, GL_FLOAT, GL_FALSE, 0, 0);
|
||||
glVertexAttribPointer(shader->GetAttribute(C4LRA_LandscapeTexCoord), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(8 * sizeof(float)));
|
||||
if (Light)
|
||||
glVertexAttribPointer(shader->GetAttribute(C4LRA_LightTexCoord), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(16 * sizeof(float)));
|
||||
}
|
||||
|
||||
// Do the blit
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
// Reset state
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4LRA_Position));
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4LRA_LandscapeTexCoord));
|
||||
if (Light)
|
||||
glDisableVertexAttribArray(shader->GetAttribute(C4LRA_LightTexCoord));
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
ShaderCall.Finish();
|
||||
|
|
|
@ -72,9 +72,6 @@ const int C4LR_BytesPerPx = 3;
|
|||
const int C4LR_BytesPerSurface = 4;
|
||||
const int C4LR_SurfaceCount = (C4LR_ByteCount + C4LR_BytesPerSurface - 1) / C4LR_BytesPerSurface;
|
||||
|
||||
// How many mip-map levels should be used at maximum?
|
||||
const int C4LR_MipMapCount = 6;
|
||||
|
||||
class C4Landscape; class C4TextureMap;
|
||||
|
||||
class C4LandscapeRender
|
||||
|
@ -122,10 +119,13 @@ private:
|
|||
static const char *UniformNames[];
|
||||
// VBO for landscape vertex data
|
||||
GLuint hVBO;
|
||||
// VAO IDs for rendering landscape w/ and w/o light
|
||||
unsigned int hVAOIDNoLight;
|
||||
unsigned int hVAOIDLight;
|
||||
|
||||
// 3D texture of material textures
|
||||
GLuint hMaterialTexture[C4LR_MipMapCount];
|
||||
// material texture positions in 3D texture
|
||||
// 2D texture array of material textures
|
||||
GLuint hMaterialTexture;
|
||||
// material texture positions in texture array
|
||||
std::vector<StdCopyStrBuf> MaterialTextureMap;
|
||||
// depth of material texture in layers
|
||||
int32_t iMaterialTextureDepth;
|
||||
|
|
|
@ -38,7 +38,7 @@ bool C4LandscapeRenderClassic::ReInit(int32_t iWidth, int32_t iHeight)
|
|||
delete Surface32; Surface32 = NULL;
|
||||
Surface32 = new C4Surface();
|
||||
// without shaders, the FoW is only as detailed as the landscape has tiles.
|
||||
if (!Surface32->Create(iWidth, iHeight, false, 0, 0))
|
||||
if (!Surface32->Create(iWidth, iHeight))
|
||||
return false;
|
||||
// Safe back info
|
||||
this->iWidth = iWidth;
|
||||
|
|
|
@ -967,16 +967,6 @@ bool C4ParticleChunk::Exec(C4Object *obj, float timeDelta)
|
|||
return particleCount > 0;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#undef glGenVertexArrays
|
||||
#undef glBindVertexArray
|
||||
#undef glDeleteVertexArrays
|
||||
|
||||
#define glGenVertexArrays glGenVertexArraysAPPLE
|
||||
#define glBindVertexArray glBindVertexArrayAPPLE
|
||||
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
|
||||
#endif
|
||||
|
||||
void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj, C4ShaderCall& call, int texUnit, const StdProjectionMatrix& modelview)
|
||||
{
|
||||
if (particleCount == 0) return;
|
||||
|
@ -1021,66 +1011,46 @@ void C4ParticleChunk::Draw(C4TargetFacet cgo, C4Object *obj, C4ShaderCall& call,
|
|||
glObjectLabel(GL_BUFFER, drawingDataVertexBufferObject, -1, "<particles>/VBO");
|
||||
#endif
|
||||
|
||||
// generate new vertex arrays object
|
||||
if (!Particles.useVAOWorkaround)
|
||||
{
|
||||
glGenVertexArrays(1, &drawingDataVertexArraysObject);
|
||||
assert (drawingDataVertexArraysObject != 0 && "Could not generate OpenGL vertex arrays object.");
|
||||
|
||||
// set up the vertex array structure once
|
||||
glBindVertexArray(drawingDataVertexArraysObject);
|
||||
|
||||
#ifdef GL_KHR_debug
|
||||
if (glObjectLabel)
|
||||
glObjectLabel(GL_VERTEX_ARRAY, drawingDataVertexArraysObject, -1, "<particles>/VAO");
|
||||
#endif
|
||||
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4SSA_Position));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4SSA_Color));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4SSA_TexCoord));
|
||||
glVertexAttribPointer(call.GetAttribute(C4SSA_Position), 2, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<GLvoid*>(offsetof(C4Particle::DrawingData::Vertex, x)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4SSA_TexCoord), 2, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<GLvoid*>(offsetof(C4Particle::DrawingData::Vertex, u)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4SSA_Color), 4, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<GLvoid*>(offsetof(C4Particle::DrawingData::Vertex, r)));
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
// generate new VAO ID
|
||||
drawingDataVertexArraysObject = pGL->GenVAOID();
|
||||
assert (drawingDataVertexArraysObject != 0 && "Could not generate a VAO ID.");
|
||||
}
|
||||
|
||||
assert ((Particles.useVAOWorkaround || drawingDataVertexArraysObject != 0) && "No vertex arrays object has been created yet.");
|
||||
assert ((drawingDataVertexBufferObject != 0) && "No buffer object has been created yet.");
|
||||
|
||||
// bind the VBO and push the new vertex data
|
||||
// this has to be done before binding the vertex arrays object
|
||||
// Push the new vertex data
|
||||
glBindBuffer(GL_ARRAY_BUFFER, drawingDataVertexBufferObject);
|
||||
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(C4Particle::DrawingData::Vertex) * particleCount, &vertexCoordinates[0], GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// bind VAO and set correct state
|
||||
if (!Particles.useVAOWorkaround)
|
||||
{
|
||||
glBindVertexArray(drawingDataVertexArraysObject);
|
||||
}
|
||||
else
|
||||
// set up the vertex array structure
|
||||
GLuint vao;
|
||||
const bool has_vao = pGL->GetVAO(drawingDataVertexArraysObject, vao);
|
||||
glBindVertexArray(vao);
|
||||
|
||||
assert ((drawingDataVertexBufferObject != 0) && "No buffer object has been created yet.");
|
||||
assert ((drawingDataVertexArraysObject != 0) && "No vertex arrays object has been created yet.");
|
||||
|
||||
if (!has_vao)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, drawingDataVertexBufferObject);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ::Particles.GetIBO());
|
||||
#ifdef GL_KHR_debug
|
||||
if (glObjectLabel)
|
||||
glObjectLabel(GL_VERTEX_ARRAY, vao, -1, "<particles>/VAO");
|
||||
#endif
|
||||
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4SSA_Position));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4SSA_Color));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4SSA_TexCoord));
|
||||
glVertexAttribPointer(call.GetAttribute(C4SSA_Position), 2, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<GLvoid*>(offsetof(C4Particle::DrawingData::Vertex, x)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4SSA_TexCoord), 2, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<GLvoid*>(offsetof(C4Particle::DrawingData::Vertex, u)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4SSA_Color), 4, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<GLvoid*>(offsetof(C4Particle::DrawingData::Vertex, r)));
|
||||
}
|
||||
|
||||
if (!Particles.usePrimitiveRestartIndexWorkaround)
|
||||
{
|
||||
glDrawElements(GL_TRIANGLE_STRIP, static_cast<GLsizei> (5 * particleCount), GL_UNSIGNED_INT, ::Particles.GetPrimitiveRestartArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
glMultiDrawElements(GL_TRIANGLE_STRIP, ::Particles.GetMultiDrawElementsCountArray(), GL_UNSIGNED_INT, const_cast<const GLvoid**>(::Particles.GetMultiDrawElementsIndexArray()), static_cast<GLsizei> (particleCount));
|
||||
}
|
||||
glDrawElements(GL_TRIANGLE_STRIP, static_cast<GLsizei> (5 * particleCount), GL_UNSIGNED_INT, 0);
|
||||
|
||||
// reset buffer data
|
||||
if (!Particles.useVAOWorkaround)
|
||||
{
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
bool C4ParticleChunk::IsOfType(C4ParticleDef *def, uint32_t _blitMode, uint32_t _attachment) const
|
||||
|
@ -1093,7 +1063,7 @@ void C4ParticleChunk::ClearBufferObjects()
|
|||
if (drawingDataVertexBufferObject != 0) // the value 0 as a buffer index is reserved and will never be returned by glGenBuffers
|
||||
glDeleteBuffers(1, &drawingDataVertexBufferObject);
|
||||
if (drawingDataVertexArraysObject != 0)
|
||||
glDeleteVertexArrays(1, &drawingDataVertexArraysObject);
|
||||
pGL->FreeVAOID(drawingDataVertexArraysObject);
|
||||
|
||||
drawingDataVertexArraysObject = 0;
|
||||
drawingDataVertexBufferObject = 0;
|
||||
|
@ -1158,11 +1128,8 @@ void C4ParticleList::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
pDraw->DeactivateBlitModulation();
|
||||
pDraw->ResetBlitMode();
|
||||
|
||||
if (!Particles.usePrimitiveRestartIndexWorkaround)
|
||||
{
|
||||
glPrimitiveRestartIndex(0xffffffff);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
}
|
||||
glPrimitiveRestartIndex(0xffffffff);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
|
||||
// enable shader
|
||||
C4ShaderCall call(pGL->GetSpriteShader(true, false, false));
|
||||
|
@ -1176,16 +1143,6 @@ void C4ParticleList::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
// texture unit. Will be used for each particle chunk to bind
|
||||
// their texture to this unit.
|
||||
const GLint texUnit = call.AllocTexUnit(C4SSU_BaseTex);
|
||||
// Texture coordinates are always associated to texture unit 0, since
|
||||
// there is only one set of texture coordinates
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
|
||||
if (Particles.useVAOWorkaround)
|
||||
{
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4SSA_Position));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4SSA_Color));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4SSA_TexCoord));
|
||||
}
|
||||
|
||||
accessMutex.Enter();
|
||||
|
||||
|
@ -1206,17 +1163,7 @@ void C4ParticleList::Draw(C4TargetFacet cgo, C4Object *obj)
|
|||
|
||||
accessMutex.Leave();
|
||||
|
||||
if (Particles.useVAOWorkaround)
|
||||
{
|
||||
glDisableVertexAttribArray(call.GetAttribute(C4SSA_Position));
|
||||
glDisableVertexAttribArray(call.GetAttribute(C4SSA_Color));
|
||||
glDisableVertexAttribArray(call.GetAttribute(C4SSA_TexCoord));
|
||||
}
|
||||
|
||||
if (!Particles.usePrimitiveRestartIndexWorkaround)
|
||||
{
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
}
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
}
|
||||
|
||||
void C4ParticleList::Clear()
|
||||
|
@ -1286,8 +1233,8 @@ C4ParticleSystem::C4ParticleSystem() : frameCounterAdvancedEvent(false)
|
|||
{
|
||||
currentSimulationTime = 0;
|
||||
globalParticles = 0;
|
||||
usePrimitiveRestartIndexWorkaround = false;
|
||||
useVAOWorkaround = false;
|
||||
ibo = 0;
|
||||
ibo_size = 0;
|
||||
}
|
||||
|
||||
C4ParticleSystem::~C4ParticleSystem()
|
||||
|
@ -1296,30 +1243,6 @@ C4ParticleSystem::~C4ParticleSystem()
|
|||
|
||||
calculationThread.SignalStop();
|
||||
CalculateNextStep();
|
||||
|
||||
for (std::vector<uint32_t *>::iterator iter = multiDrawElementsIndexArray.begin(); iter != multiDrawElementsIndexArray.end(); ++iter)
|
||||
delete[] (*iter);
|
||||
}
|
||||
|
||||
void C4ParticleSystem::DoInit()
|
||||
{
|
||||
// we use features that are only supported from 3.1 upwards. Check whether the graphics card supports that and - if not - use workarounds
|
||||
if (!GLEW_VERSION_3_1 || (glPrimitiveRestartIndex == 0))
|
||||
{
|
||||
usePrimitiveRestartIndexWorkaround = true;
|
||||
LogSilent("WARNING (particle system): Your graphics card does not support glPrimitiveRestartIndex - a (slower) fallback will be used!");
|
||||
}
|
||||
|
||||
assert (glGenBuffers != 0 && "Your graphics card does not seem to support buffer objects.");
|
||||
useVAOWorkaround = false;
|
||||
|
||||
#ifndef USE_WIN32_WINDOWS
|
||||
// Every window in developers' mode has an own OpenGL context at the moment. Certain objects are not shared between contexts.
|
||||
// In that case we can just use the slower workaround without VAOs to allow the developer to view particles in every viewport.
|
||||
// The best solution would obviously be to make all windows use a single OpenGL context. This has to be considered as a workaround.
|
||||
if (Application.isEditor)
|
||||
useVAOWorkaround = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void C4ParticleSystem::ExecuteCalculation()
|
||||
|
@ -1345,8 +1268,6 @@ void C4ParticleSystem::ExecuteCalculation()
|
|||
particleListAccessMutex.Leave();
|
||||
}
|
||||
}
|
||||
#else // ifdef USE_CONSOLE
|
||||
void C4ParticleSystem::DoInit() {}
|
||||
#endif
|
||||
|
||||
C4ParticleList *C4ParticleSystem::GetNewParticleList(C4Object *forObject)
|
||||
|
@ -1492,59 +1413,31 @@ void C4ParticleSystem::Create(C4ParticleDef *of_def, C4ParticleValueProvider &x,
|
|||
|
||||
void C4ParticleSystem::PreparePrimitiveRestartIndices(uint32_t forAmount)
|
||||
{
|
||||
if (!usePrimitiveRestartIndexWorkaround)
|
||||
// prepare array with indices, separated by special primitive restart index
|
||||
const uint32_t PRI = 0xffffffff;
|
||||
size_t neededAmount = 5 * forAmount;
|
||||
|
||||
if (ibo == 0) glGenBuffers(1, &ibo);
|
||||
|
||||
if (ibo_size < neededAmount * sizeof(GLuint))
|
||||
{
|
||||
// prepare array with indices, separated by special primitive restart index
|
||||
const uint32_t PRI = 0xffffffff;
|
||||
size_t neededAmount = 5 * forAmount;
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
|
||||
if (primitiveRestartIndices.size() < neededAmount)
|
||||
std::vector<GLuint> ibo_data;
|
||||
ibo_data.reserve(neededAmount);
|
||||
|
||||
unsigned int index = 0;
|
||||
for (unsigned int i = 0; i < neededAmount; ++i)
|
||||
{
|
||||
uint32_t oldValue = 0;
|
||||
|
||||
if (primitiveRestartIndices.size() > 2)
|
||||
{
|
||||
oldValue = primitiveRestartIndices[primitiveRestartIndices.size()-1];
|
||||
if (oldValue == PRI)
|
||||
oldValue = primitiveRestartIndices[primitiveRestartIndices.size()-2];
|
||||
++oldValue;
|
||||
}
|
||||
size_t oldSize = primitiveRestartIndices.size();
|
||||
primitiveRestartIndices.resize(neededAmount);
|
||||
|
||||
for (size_t i = oldSize; i < neededAmount; ++i)
|
||||
{
|
||||
if (((i+1) % 5 == 0) && (i != 0))
|
||||
{
|
||||
primitiveRestartIndices[i] = PRI;
|
||||
}
|
||||
else
|
||||
{
|
||||
primitiveRestartIndices[i] = oldValue++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// prepare arrays for glMultiDrawElements
|
||||
if (multiDrawElementsCountArray.size() <= forAmount)
|
||||
{
|
||||
multiDrawElementsCountArray.resize(forAmount, 4);
|
||||
if ((i+1) % 5 == 0)
|
||||
ibo_data.push_back(PRI);
|
||||
else
|
||||
ibo_data.push_back(index++);
|
||||
}
|
||||
|
||||
if (multiDrawElementsIndexArray.size() <= forAmount)
|
||||
{
|
||||
uint32_t oldSize = multiDrawElementsIndexArray.size();
|
||||
multiDrawElementsIndexArray.resize(forAmount);
|
||||
|
||||
for (; oldSize < forAmount; ++oldSize)
|
||||
{
|
||||
multiDrawElementsIndexArray[oldSize] = new uint32_t[4];
|
||||
for (uint32_t i = 0; i < 4; ++i)
|
||||
multiDrawElementsIndexArray[oldSize][i] = 4 * oldSize + i;
|
||||
}
|
||||
}
|
||||
ibo_size = neededAmount * sizeof(GLuint);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibo_size, &ibo_data[0], GL_STATIC_DRAW);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1552,6 +1445,9 @@ void C4ParticleSystem::PreparePrimitiveRestartIndices(uint32_t forAmount)
|
|||
void C4ParticleSystem::Clear()
|
||||
{
|
||||
#ifndef USE_CONSOLE
|
||||
if (ibo != 0) glDeleteBuffers(1, &ibo);
|
||||
ibo = 0; ibo_size = 0;
|
||||
|
||||
currentSimulationTime = 0;
|
||||
ClearAllParticles();
|
||||
#endif
|
||||
|
|
|
@ -343,7 +343,7 @@ private:
|
|||
|
||||
// OpenGL optimizations
|
||||
GLuint drawingDataVertexBufferObject;
|
||||
GLuint drawingDataVertexArraysObject;
|
||||
unsigned int drawingDataVertexArraysObject;
|
||||
void ClearBufferObjects();
|
||||
|
||||
// delete the particle at indexTo. If possible, replace it with the particle at indexFrom to keep the particles tighly packed
|
||||
|
@ -445,10 +445,8 @@ class C4ParticleSystem
|
|||
|
||||
private:
|
||||
// contains an array with indices for vertices, separated by a primitive restart index
|
||||
std::vector<uint32_t> primitiveRestartIndices;
|
||||
// these are fallbacks for if primitiveRestartIndex is not supported by the graphics card
|
||||
std::vector<GLsizei> multiDrawElementsCountArray;
|
||||
std::vector<uint32_t *> multiDrawElementsIndexArray;
|
||||
GLuint ibo;
|
||||
size_t ibo_size;
|
||||
std::list<C4ParticleList> particleLists;
|
||||
|
||||
CStdCSec particleListAccessMutex;
|
||||
|
@ -475,7 +473,6 @@ public:
|
|||
frameCounterAdvancedEvent.Set();
|
||||
#endif
|
||||
}
|
||||
void DoInit();
|
||||
// resets the internal state of the particle system and unloads all definitions
|
||||
void Clear();
|
||||
void DrawGlobalParticles(C4TargetFacet cgo)
|
||||
|
@ -502,17 +499,9 @@ public:
|
|||
C4ParticleSystemDefinitionList definitions;
|
||||
|
||||
#ifndef USE_CONSOLE
|
||||
// on some graphics card, glPrimitiveRestartIndex might not be supported
|
||||
bool usePrimitiveRestartIndexWorkaround;
|
||||
GLsizei *GetMultiDrawElementsCountArray() { return &multiDrawElementsCountArray[0]; }
|
||||
GLvoid **GetMultiDrawElementsIndexArray() { return reinterpret_cast<GLvoid**> (&multiDrawElementsIndexArray[0]); }
|
||||
|
||||
// if true, OpenGL VAOs will not be used (instead the slower direct calls will be made)
|
||||
bool useVAOWorkaround;
|
||||
|
||||
// usually, the following methods are used for drawing
|
||||
GLuint GetIBO() const { return ibo; }
|
||||
void PreparePrimitiveRestartIndices(uint32_t forSize);
|
||||
void *GetPrimitiveRestartArray() { return (void*)&primitiveRestartIndices[0]; }
|
||||
|
||||
// creates a new particle
|
||||
void Create(C4ParticleDef *of_def, C4ParticleValueProvider &x, C4ParticleValueProvider &y, C4ParticleValueProvider &speedX, C4ParticleValueProvider &speedY, C4ParticleValueProvider &lifetime, C4PropList *properties, int amount = 1, C4Object *object=NULL);
|
||||
|
|
|
@ -34,9 +34,9 @@ C4Shader *C4FoW::GetFramebufShader()
|
|||
// this is about how to utilise old frame buffer data in the lights texture.
|
||||
// Or put in other words: This shader is responsible for fading lights out.
|
||||
const char* FramebufVertexShader =
|
||||
"attribute vec2 oc_Position;\n"
|
||||
"attribute vec2 oc_TexCoord;\n"
|
||||
"varying vec2 texcoord;\n"
|
||||
"in vec2 oc_Position;\n"
|
||||
"in vec2 oc_TexCoord;\n"
|
||||
"out vec2 texcoord;\n"
|
||||
"uniform mat4 projectionMatrix;\n"
|
||||
"\n"
|
||||
"slice(position)\n"
|
||||
|
@ -50,12 +50,13 @@ C4Shader *C4FoW::GetFramebufShader()
|
|||
"}";
|
||||
|
||||
const char* FramebufFragmentShader =
|
||||
"varying vec2 texcoord;\n"
|
||||
"in vec2 texcoord;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"out vec4 fragColor;\n"
|
||||
"\n"
|
||||
"slice(color)\n"
|
||||
"{\n"
|
||||
" gl_FragColor = texture2D(tex, texcoord);\n"
|
||||
" fragColor = texture(tex, texcoord);\n"
|
||||
"}";
|
||||
|
||||
FramebufShader.AddVertexSlices("built-in FoW framebuf shader", FramebufVertexShader);
|
||||
|
@ -90,9 +91,9 @@ C4Shader *C4FoW::GetRenderShader()
|
|||
{
|
||||
// Create the render shader. Fairly simple pass-through.
|
||||
const char* RenderVertexShader =
|
||||
"attribute vec2 oc_Position;\n"
|
||||
"attribute vec4 oc_Color;\n"
|
||||
"varying vec4 vtxColor;\n"
|
||||
"in vec2 oc_Position;\n"
|
||||
"in vec4 oc_Color;\n"
|
||||
"out vec4 vtxColor;\n"
|
||||
"uniform mat4 projectionMatrix;\n"
|
||||
"uniform vec2 vertexOffset;\n"
|
||||
"\n"
|
||||
|
@ -107,11 +108,12 @@ C4Shader *C4FoW::GetRenderShader()
|
|||
"}";
|
||||
|
||||
const char* RenderFragmentShader =
|
||||
"varying vec4 vtxColor;\n"
|
||||
"in vec4 vtxColor;\n"
|
||||
"out vec4 fragColor;\n"
|
||||
"\n"
|
||||
"slice(color)\n"
|
||||
"{\n"
|
||||
" gl_FragColor = vtxColor;\n"
|
||||
" fragColor = vtxColor;\n"
|
||||
"}";
|
||||
|
||||
RenderShader.AddVertexSlices("built-in FoW render shader", RenderVertexShader);
|
||||
|
|
|
@ -109,14 +109,20 @@ void C4FoWDrawTriangulator::Reset()
|
|||
}
|
||||
|
||||
C4FoWDrawLightTextureStrategy::C4FoWDrawLightTextureStrategy(const C4FoWLight* light)
|
||||
: light(light), region(NULL), vbo_size(0)
|
||||
: light(light), region(NULL), vbo_size(0), ibo_size(0)
|
||||
{
|
||||
glGenBuffers(1, &vbo);
|
||||
glGenBuffers(2, bo);
|
||||
vaoids[0] = pGL->GenVAOID();
|
||||
vaoids[1] = pGL->GenVAOID();
|
||||
vaoids[2] = pGL->GenVAOID();
|
||||
}
|
||||
|
||||
C4FoWDrawLightTextureStrategy::~C4FoWDrawLightTextureStrategy()
|
||||
{
|
||||
glDeleteBuffers(1, &vbo);
|
||||
glDeleteBuffers(2, bo);
|
||||
pGL->FreeVAOID(vaoids[2]);
|
||||
pGL->FreeVAOID(vaoids[1]);
|
||||
pGL->FreeVAOID(vaoids[0]);
|
||||
}
|
||||
|
||||
void C4FoWDrawLightTextureStrategy::Begin(const C4FoWRegion* regionPar)
|
||||
|
@ -129,6 +135,9 @@ void C4FoWDrawLightTextureStrategy::End(C4ShaderCall& call)
|
|||
// If we have nothing to draw (e.g. directly after initialization), abort early.
|
||||
if (vertices.empty()) return;
|
||||
|
||||
const GLuint vbo = bo[0];
|
||||
const GLuint ibo = bo[1];
|
||||
|
||||
// Upload vertices
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
if (vbo_size < vertices.size())
|
||||
|
@ -140,6 +149,20 @@ void C4FoWDrawLightTextureStrategy::End(C4ShaderCall& call)
|
|||
{
|
||||
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(Vertex), &vertices[0]);
|
||||
}
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
// Upload indices
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
if (ibo_size < triangulator.GetNIndices())
|
||||
{
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangulator.GetNIndices() * 3 * sizeof(GLuint), triangulator.GetIndices(), GL_DYNAMIC_DRAW);
|
||||
ibo_size = triangulator.GetNIndices();
|
||||
}
|
||||
else
|
||||
{
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, triangulator.GetNIndices() * 3 * sizeof(GLuint), triangulator.GetIndices());
|
||||
}
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
// Region dimensions
|
||||
const float width = region->getSurfaceWidth();
|
||||
|
@ -154,10 +177,18 @@ void C4FoWDrawLightTextureStrategy::End(C4ShaderCall& call)
|
|||
glScissor(0, height, width, height);
|
||||
|
||||
// Setup state for 1st pass
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Position));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Color));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Position), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, x)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Color), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, r1)));
|
||||
GLuint vao1, vao2, vao3;
|
||||
const bool has_vao1 = pGL->GetVAO(vaoids[0], vao1);
|
||||
glBindVertexArray(vao1);
|
||||
if (!has_vao1)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Position));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Color));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Position), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, x)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Color), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, r1)));
|
||||
}
|
||||
|
||||
// Set up blend equation, see C4FoWDrawLightTextureStrategy::DrawVertex
|
||||
// for details.
|
||||
|
@ -165,31 +196,51 @@ void C4FoWDrawLightTextureStrategy::End(C4ShaderCall& call)
|
|||
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
|
||||
|
||||
// Render 1st pass
|
||||
glDrawElements(GL_TRIANGLES, triangulator.GetNIndices(), GL_UNSIGNED_INT, triangulator.GetIndices());
|
||||
glDrawElements(GL_TRIANGLES, triangulator.GetNIndices(), GL_UNSIGNED_INT, 0);
|
||||
|
||||
// Prepare state for 2nd pass
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
//glBlendFunc(GL_ONE, GL_ONE);
|
||||
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Color), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, r2)));
|
||||
|
||||
const bool has_vao2 = pGL->GetVAO(vaoids[1], vao2);
|
||||
glBindVertexArray(vao2);
|
||||
if (!has_vao2)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Position));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Color));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Position), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, x)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Color), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, r2)));
|
||||
}
|
||||
|
||||
// Render 2nd pass
|
||||
glDrawElements(GL_TRIANGLES, triangulator.GetNIndices(), GL_UNSIGNED_INT, triangulator.GetIndices());
|
||||
glDrawElements(GL_TRIANGLES, triangulator.GetNIndices(), GL_UNSIGNED_INT, 0);
|
||||
|
||||
// Prepare state for 3rd pass (color pass)
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBlendEquation(GL_FUNC_ADD);
|
||||
glScissor(0, 0, width, height);
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Color), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, r3)));
|
||||
y_offset[1] = height;
|
||||
call.SetUniform2fv(C4FoWRSU_VertexOffset, 1, y_offset);
|
||||
|
||||
const bool has_vao3 = pGL->GetVAO(vaoids[2], vao3);
|
||||
glBindVertexArray(vao3);
|
||||
if (!has_vao3)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Position));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Color));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Position), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, x)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Color), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, r3)));
|
||||
}
|
||||
|
||||
// Render 3rd pass
|
||||
glDrawElements(GL_TRIANGLES, triangulator.GetNIndices(), GL_UNSIGNED_INT, triangulator.GetIndices());
|
||||
glDrawElements(GL_TRIANGLES, triangulator.GetNIndices(), GL_UNSIGNED_INT, 0);
|
||||
|
||||
// Reset GL state
|
||||
glDisableVertexAttribArray(call.GetAttribute(C4FoWRSA_Position));
|
||||
glDisableVertexAttribArray(call.GetAttribute(C4FoWRSA_Color));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
|
||||
// Assume the capacity stays the same:
|
||||
|
@ -283,14 +334,16 @@ void C4FoWDrawLightTextureStrategy::DrawLightVertex(float x, float y)
|
|||
}
|
||||
|
||||
C4FoWDrawWireframeStrategy::C4FoWDrawWireframeStrategy(const C4FoWLight* light, const C4TargetFacet *screen) :
|
||||
light(light), screen(screen), vbo_size(0)
|
||||
light(light), screen(screen), vbo_size(0), ibo_size(0)
|
||||
{
|
||||
glGenBuffers(1, &vbo);
|
||||
glGenBuffers(2, bo);
|
||||
vaoid = pGL->GenVAOID();
|
||||
}
|
||||
|
||||
C4FoWDrawWireframeStrategy::~C4FoWDrawWireframeStrategy()
|
||||
{
|
||||
glDeleteBuffers(1, &vbo);
|
||||
glDeleteBuffers(2, bo);
|
||||
pGL->FreeVAOID(vaoid);
|
||||
}
|
||||
|
||||
void C4FoWDrawWireframeStrategy::Begin(const C4FoWRegion* region)
|
||||
|
@ -302,6 +355,9 @@ void C4FoWDrawWireframeStrategy::End(C4ShaderCall& call)
|
|||
// If we have nothing to draw (e.g. directly after initialization), abort early.
|
||||
if (vertices.empty()) return;
|
||||
|
||||
const GLuint vbo = bo[0];
|
||||
const GLuint ibo = bo[1];
|
||||
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
// Upload vertices
|
||||
|
@ -316,22 +372,40 @@ void C4FoWDrawWireframeStrategy::End(C4ShaderCall& call)
|
|||
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(Vertex), &vertices[0]);
|
||||
}
|
||||
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Position));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Color));
|
||||
// Upload indices
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
if (ibo_size < triangulator.GetNIndices())
|
||||
{
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangulator.GetNIndices() * 3 * sizeof(GLuint), triangulator.GetIndices(), GL_STREAM_DRAW);
|
||||
ibo_size = triangulator.GetNIndices();
|
||||
}
|
||||
else
|
||||
{
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, triangulator.GetNIndices() * 3 * sizeof(GLuint), triangulator.GetIndices());
|
||||
}
|
||||
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Position), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, x)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Color), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, r)));
|
||||
GLuint vao;
|
||||
const bool has_vao = pGL->GetVAO(vaoid, vao);
|
||||
glBindVertexArray(vao);
|
||||
if (!has_vao)
|
||||
{
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Position));
|
||||
glEnableVertexAttribArray(call.GetAttribute(C4FoWRSA_Color));
|
||||
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Position), 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, x)));
|
||||
glVertexAttribPointer(call.GetAttribute(C4FoWRSA_Color), 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<const uint8_t*>(offsetof(Vertex, r)));
|
||||
}
|
||||
|
||||
// Set Y offset for vertex
|
||||
const float y_offset[] = { 0.0f, 0.0f };
|
||||
call.SetUniform2fv(C4FoWRSU_VertexOffset, 1, y_offset);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, triangulator.GetNIndices(), GL_UNSIGNED_INT, triangulator.GetIndices());
|
||||
glDrawElements(GL_TRIANGLES, triangulator.GetNIndices(), GL_UNSIGNED_INT, 0);
|
||||
|
||||
// Reset GL state
|
||||
glDisableVertexAttribArray(call.GetAttribute(C4FoWRSA_Position));
|
||||
glDisableVertexAttribArray(call.GetAttribute(C4FoWRSA_Color));
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
// Assume the capacity stays the same:
|
||||
|
|
|
@ -139,9 +139,11 @@ private:
|
|||
float r3, g3, b3, a3; // color for third pass
|
||||
};
|
||||
|
||||
GLuint vbo;
|
||||
GLuint bo[2];
|
||||
std::vector<Vertex> vertices;
|
||||
unsigned int vbo_size;
|
||||
unsigned int ibo_size;
|
||||
unsigned int vaoids[3]; // Three VAOs for the three passes
|
||||
};
|
||||
|
||||
/** This draw strategy is the debug draw strategy (press Ctrl+F7,...) that
|
||||
|
@ -170,9 +172,12 @@ private:
|
|||
const C4FoWLight* light;
|
||||
const C4TargetFacet* screen;
|
||||
|
||||
GLuint vbo;
|
||||
GLuint bo[2];
|
||||
GLuint ibo;
|
||||
std::vector<Vertex> vertices;
|
||||
unsigned int vbo_size;
|
||||
unsigned int ibo_size;
|
||||
unsigned int vaoid;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,7 +21,7 @@ C4FoWRegion::C4FoWRegion(C4FoW *pFoW, C4Player *pPlayer)
|
|||
: pFoW(pFoW)
|
||||
, pPlayer(pPlayer)
|
||||
#ifndef USE_CONSOLE
|
||||
, hFrameBufDraw(0), hFrameBufRead(0), hVBO(0)
|
||||
, hFrameBufDraw(0), hFrameBufRead(0), hVBO(0), vaoid(0)
|
||||
#endif
|
||||
, Region(0,0,0,0), OldRegion(0,0,0,0)
|
||||
, pSurface(new C4Surface), pBackSurface(new C4Surface)
|
||||
|
@ -33,13 +33,17 @@ C4FoWRegion::~C4FoWRegion()
|
|||
{
|
||||
#ifndef USE_CONSOLE
|
||||
if (hFrameBufDraw) {
|
||||
glDeleteFramebuffersEXT(1, &hFrameBufDraw);
|
||||
glDeleteFramebuffersEXT(1, &hFrameBufRead);
|
||||
glDeleteFramebuffers(1, &hFrameBufDraw);
|
||||
glDeleteFramebuffers(1, &hFrameBufRead);
|
||||
}
|
||||
|
||||
if (hVBO) {
|
||||
glDeleteBuffers(1, &hVBO);
|
||||
}
|
||||
|
||||
if (vaoid) {
|
||||
pGL->FreeVAOID(vaoid);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -67,9 +71,9 @@ bool C4FoWRegion::BindFramebuf()
|
|||
// Create the new surfaces
|
||||
std::unique_ptr<C4Surface> pNewSurface(new C4Surface);
|
||||
std::unique_ptr<C4Surface> pNewBackSurface(new C4Surface);
|
||||
if (!pNewSurface->Create(iWdt, iHgt, false, 0, 0))
|
||||
if (!pNewSurface->Create(iWdt, iHgt))
|
||||
return false;
|
||||
if (!pNewBackSurface->Create(iWdt, iHgt, false, 0, 0))
|
||||
if (!pNewBackSurface->Create(iWdt, iHgt))
|
||||
return false;
|
||||
|
||||
// Copy over old content. This avoids flicker in already
|
||||
|
@ -124,28 +128,28 @@ bool C4FoWRegion::BindFramebuf()
|
|||
// Generate frame buffer object
|
||||
if (!hFrameBufDraw)
|
||||
{
|
||||
glGenFramebuffersEXT(1, &hFrameBufDraw);
|
||||
glGenFramebuffersEXT(1, &hFrameBufRead);
|
||||
glGenFramebuffers(1, &hFrameBufDraw);
|
||||
glGenFramebuffers(1, &hFrameBufRead);
|
||||
}
|
||||
|
||||
// Bind current texture to frame buffer
|
||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, hFrameBufDraw);
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, hFrameBufRead);
|
||||
glFramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER_EXT,
|
||||
GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, hFrameBufDraw);
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, hFrameBufRead);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
pSurface->textures[0].texName, 0);
|
||||
if (!pBackSurface->textures.empty())
|
||||
glFramebufferTexture2DEXT(GL_READ_FRAMEBUFFER_EXT,
|
||||
GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER,
|
||||
GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
pBackSurface->textures[0].texName, 0);
|
||||
|
||||
// Check status, unbind if something was amiss
|
||||
GLenum status1 = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT),
|
||||
status2 = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
|
||||
if (status1 != GL_FRAMEBUFFER_COMPLETE_EXT ||
|
||||
(pBackSurface && status2 != GL_FRAMEBUFFER_COMPLETE_EXT))
|
||||
GLenum status1 = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER),
|
||||
status2 = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
|
||||
if (status1 != GL_FRAMEBUFFER_COMPLETE ||
|
||||
(pBackSurface && status2 != GL_FRAMEBUFFER_COMPLETE))
|
||||
{
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -283,6 +287,9 @@ bool C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
|
|||
glGenBuffers(1, &hVBO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, hVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vtxData), vtxData, GL_STREAM_DRAW);
|
||||
|
||||
assert(vaoid == 0);
|
||||
vaoid = pGL->GenVAOID();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -301,22 +308,27 @@ bool C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
|
|||
brightBlend = 1.0f / 16.0f; // Intensity more slowly
|
||||
glBlendColor(0.0f,normalBlend,normalBlend,brightBlend);
|
||||
|
||||
glEnableVertexAttribArray(pShader->GetAttribute(C4FoWFSA_Position));
|
||||
glEnableVertexAttribArray(pShader->GetAttribute(C4FoWFSA_TexCoord));
|
||||
glVertexAttribPointer(pShader->GetAttribute(C4FoWFSA_Position), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(8 * sizeof(float)));
|
||||
glVertexAttribPointer(pShader->GetAttribute(C4FoWFSA_TexCoord), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(0));
|
||||
GLuint vao;
|
||||
const bool has_vao = pGL->GetVAO(vaoid, vao);
|
||||
glBindVertexArray(vao);
|
||||
if (!has_vao)
|
||||
{
|
||||
glEnableVertexAttribArray(pShader->GetAttribute(C4FoWFSA_Position));
|
||||
glEnableVertexAttribArray(pShader->GetAttribute(C4FoWFSA_TexCoord));
|
||||
glVertexAttribPointer(pShader->GetAttribute(C4FoWFSA_Position), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(8 * sizeof(float)));
|
||||
glVertexAttribPointer(pShader->GetAttribute(C4FoWFSA_TexCoord), 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<const uint8_t*>(0));
|
||||
}
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glDisableVertexAttribArray(pShader->GetAttribute(C4FoWFSA_Position));
|
||||
glDisableVertexAttribArray(pShader->GetAttribute(C4FoWFSA_TexCoord));
|
||||
glBindVertexArray(0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
|
||||
Call.Finish();
|
||||
}
|
||||
|
||||
// Done!
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
pDraw->RestorePrimaryClipper();
|
||||
|
||||
OldRegion = Region;
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
#ifndef USE_CONSOLE
|
||||
GLuint hFrameBufDraw, hFrameBufRead;
|
||||
GLuint hVBO;
|
||||
unsigned int vaoid;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
#include "C4Include.h"
|
||||
#include <C4DrawGL.h>
|
||||
#include <StdMesh.h>
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -545,14 +546,14 @@ std::vector<int> StdMeshSkeleton::GetMatchingBones(const StdMeshSkeleton& child_
|
|||
}
|
||||
|
||||
StdSubMesh::StdSubMesh() :
|
||||
Material(NULL), buffer_offset(0)
|
||||
Material(NULL), vertex_buffer_offset(0), index_buffer_offset(0)
|
||||
{
|
||||
}
|
||||
|
||||
StdMesh::StdMesh() :
|
||||
Skeleton(new StdMeshSkeleton)
|
||||
#ifndef USE_CONSOLE
|
||||
, vbo(0)
|
||||
, vbo(0), ibo(0), vaoid(0)
|
||||
#endif
|
||||
{
|
||||
BoundingBox.x1 = BoundingBox.y1 = BoundingBox.z1 = 0.0f;
|
||||
|
@ -563,8 +564,12 @@ StdMesh::StdMesh() :
|
|||
StdMesh::~StdMesh()
|
||||
{
|
||||
#ifndef USE_CONSOLE
|
||||
if (ibo)
|
||||
glDeleteBuffers(1, &ibo);
|
||||
if (vbo)
|
||||
glDeleteBuffers(1, &vbo);
|
||||
if (vaoid)
|
||||
pGL->FreeVAOID(vaoid);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -574,6 +579,11 @@ void StdMesh::PostInit()
|
|||
// Order submeshes so that opaque submeshes come before non-opaque ones
|
||||
std::sort(SubMeshes.begin(), SubMeshes.end(), StdMeshSubMeshVisibilityCmpPred());
|
||||
UpdateVBO();
|
||||
UpdateIBO();
|
||||
|
||||
// Allocate a VAO ID as well
|
||||
assert(vaoid == 0);
|
||||
vaoid = pGL->GenVAOID();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -621,7 +631,7 @@ void StdMesh::UpdateVBO()
|
|||
for (auto &submesh : SubMeshes)
|
||||
{
|
||||
// Store the offset, so the render code can use it later
|
||||
submesh.buffer_offset = cursor - buffer;
|
||||
submesh.vertex_buffer_offset = cursor - buffer;
|
||||
|
||||
if (submesh.Vertices.empty()) continue;
|
||||
size_t vertices_size = sizeof(submesh.Vertices[0]) * submesh.Vertices.size();
|
||||
|
@ -632,6 +642,28 @@ void StdMesh::UpdateVBO()
|
|||
// Unbind the buffer so following rendering calls do not use it
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
void StdMesh::UpdateIBO()
|
||||
{
|
||||
assert(ibo == 0);
|
||||
if (ibo != 0)
|
||||
glDeleteBuffers(1, &ibo);
|
||||
glGenBuffers(1, &ibo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
|
||||
size_t total_faces = 0;
|
||||
for (auto &submesh : SubMeshes)
|
||||
total_faces += submesh.GetNumFaces();
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, total_faces * 3 * sizeof(GLuint), NULL, GL_STATIC_DRAW);
|
||||
size_t offset = 0;
|
||||
for (auto &submesh : SubMeshes)
|
||||
{
|
||||
submesh.index_buffer_offset = offset * 3 * sizeof(GLuint);
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, submesh.index_buffer_offset, submesh.GetNumFaces() * 3 * sizeof(GLuint), &submesh.Faces[0]);
|
||||
offset += submesh.GetNumFaces();
|
||||
}
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
StdSubMeshInstance::StdSubMeshInstance(StdMeshInstance& instance, const StdSubMesh& submesh, float completion):
|
||||
|
@ -1055,6 +1087,9 @@ StdMeshInstance::StdMeshInstance(const StdMesh& mesh, float completion):
|
|||
BoneTransforms(Mesh->GetSkeleton().GetNumBones(), StdMeshMatrix::Identity()),
|
||||
SubMeshInstances(Mesh->GetNumSubMeshes()), AttachParent(NULL),
|
||||
BoneTransformsDirty(false)
|
||||
#ifndef USE_CONSOLE
|
||||
, ibo(0), vaoid(0)
|
||||
#endif
|
||||
{
|
||||
// Create submesh instances
|
||||
for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
|
||||
|
@ -1069,6 +1104,11 @@ StdMeshInstance::StdMeshInstance(const StdMesh& mesh, float completion):
|
|||
|
||||
StdMeshInstance::~StdMeshInstance()
|
||||
{
|
||||
#ifndef USE_CONSOLE
|
||||
if (ibo) glDeleteBuffers(1, &ibo);
|
||||
if (vaoid) pGL->FreeVAOID(vaoid);
|
||||
#endif
|
||||
|
||||
// If we are attached then detach from parent
|
||||
if (AttachParent)
|
||||
AttachParent->Parent->DetachMesh(AttachParent->Number);
|
||||
|
@ -1094,6 +1134,9 @@ void StdMeshInstance::SetFaceOrdering(FaceOrdering ordering)
|
|||
for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
|
||||
SubMeshInstances[i]->SetFaceOrdering(*this, Mesh->GetSubMesh(i), ordering);
|
||||
|
||||
// Faces have been reordered: upload new order to GPU
|
||||
UpdateIBO();
|
||||
|
||||
// Update attachments (only own meshes for now... others might be displayed both attached and non-attached...)
|
||||
// still not optimal.
|
||||
for (AttachedMeshIter iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
|
||||
|
@ -1108,6 +1151,9 @@ void StdMeshInstance::SetFaceOrderingForClrModulation(uint32_t clrmod)
|
|||
for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
|
||||
SubMeshInstances[i]->SetFaceOrderingForClrModulation(*this, Mesh->GetSubMesh(i), clrmod);
|
||||
|
||||
// Faces have been reordered: upload new order to GPU
|
||||
UpdateIBO();
|
||||
|
||||
// Update attachments (only own meshes for now... others might be displayed both attached and non-attached...)
|
||||
// still not optimal.
|
||||
for (AttachedMeshIter iter = AttachChildren.begin(); iter != AttachChildren.end(); ++iter)
|
||||
|
@ -1125,6 +1171,9 @@ void StdMeshInstance::SetCompletion(float completion)
|
|||
// full pool.
|
||||
for(unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
|
||||
SubMeshInstances[i]->LoadFacesForCompletion(*this, Mesh->GetSubMesh(i), completion);
|
||||
|
||||
// Faces have been reordered: upload new order to GPU
|
||||
UpdateIBO();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1534,6 +1583,9 @@ void StdMeshInstance::ReorderFaces(StdMeshMatrix* global_trans)
|
|||
}
|
||||
|
||||
// TODO: Also reorder submeshes, attached meshes and include AttachTransformation for attached meshes...
|
||||
|
||||
// Faces have been reordered: upload new order to GPU
|
||||
UpdateIBO();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1860,3 +1912,69 @@ void StdMeshInstance::SetBoneTransformsDirty(bool value)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef USE_CONSOLE
|
||||
void StdMeshInstance::UpdateIBO()
|
||||
{
|
||||
// First, find out whether we have fixed face ordering or not
|
||||
bool all_submeshes_fixed = true;
|
||||
for (StdSubMeshInstance* inst : SubMeshInstances)
|
||||
{
|
||||
all_submeshes_fixed = (inst->GetFaceOrdering() == StdSubMeshInstance::FO_Fixed);
|
||||
if (!all_submeshes_fixed) break;
|
||||
|
||||
// If true, submesh is 100% complete
|
||||
all_submeshes_fixed = inst->GetNumFaces() == inst->GetSubMesh().GetNumFaces();
|
||||
if (!all_submeshes_fixed) break;
|
||||
}
|
||||
|
||||
// If the face ordering is fixed, then we don't need a custom
|
||||
// IBO. This is typically the case for all meshes without transparency
|
||||
// and 100% completion.
|
||||
if (all_submeshes_fixed)
|
||||
{
|
||||
if (ibo) glDeleteBuffers(1, &ibo);
|
||||
if (vaoid) pGL->FreeVAOID(vaoid);
|
||||
ibo = 0; vaoid = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have a custom face ordering, or we render only a subset
|
||||
// of our faces. Create a custom IBO and upload the index
|
||||
// data.
|
||||
if (ibo == 0)
|
||||
{
|
||||
// This is required, because the IBO binding is part
|
||||
// of the VAO state. If we create a new IBO we cannot
|
||||
// keep using any old VAO. But we always create and
|
||||
// destroy them together, so we can assert here.
|
||||
assert(vaoid == 0);
|
||||
|
||||
size_t total_faces = 0;
|
||||
for (unsigned int i = 0; i < Mesh->GetNumSubMeshes(); ++i)
|
||||
total_faces += Mesh->GetSubMesh(i).GetNumFaces();
|
||||
|
||||
glGenBuffers(1, &ibo);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
|
||||
// TODO: Optimize mode. In many cases this is still fairly static.
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, total_faces * 3 * sizeof(GLuint), NULL, GL_STREAM_DRAW);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
||||
}
|
||||
|
||||
for (StdSubMeshInstance* inst : SubMeshInstances)
|
||||
{
|
||||
assert(inst->GetNumFaces() <= inst->GetSubMesh().GetNumFaces());
|
||||
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, inst->GetSubMesh().GetOffsetInIBO(), inst->GetNumFaces() * 3 * sizeof(GLuint), &inst->Faces[0]);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
if (vaoid == 0)
|
||||
vaoid = pGL->GenVAOID();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -165,14 +165,16 @@ public:
|
|||
const StdMeshMaterial& GetMaterial() const { return *Material; }
|
||||
|
||||
// Return the offset into the backing vertex buffer where this SubMesh's data starts
|
||||
size_t GetOffsetInBuffer() const { return buffer_offset; }
|
||||
size_t GetOffsetInVBO() const { return vertex_buffer_offset; }
|
||||
size_t GetOffsetInIBO() const { return index_buffer_offset; }
|
||||
|
||||
private:
|
||||
StdSubMesh();
|
||||
|
||||
std::vector<Vertex> Vertices; // Empty if we use shared vertices
|
||||
std::vector<StdMeshFace> Faces;
|
||||
size_t buffer_offset;
|
||||
size_t vertex_buffer_offset;
|
||||
size_t index_buffer_offset;
|
||||
|
||||
const StdMeshMaterial* Material;
|
||||
};
|
||||
|
@ -203,6 +205,8 @@ public:
|
|||
|
||||
#ifndef USE_CONSOLE
|
||||
GLuint GetVBO() const { return vbo; }
|
||||
GLuint GetIBO() const { return ibo; }
|
||||
unsigned int GetVAOID() const { return vaoid; }
|
||||
#endif
|
||||
|
||||
void SetLabel(const std::string &label) { Label = label; }
|
||||
|
@ -210,7 +214,10 @@ public:
|
|||
private:
|
||||
#ifndef USE_CONSOLE
|
||||
GLuint vbo;
|
||||
GLuint ibo;
|
||||
unsigned int vaoid;
|
||||
void UpdateVBO();
|
||||
void UpdateIBO();
|
||||
#endif
|
||||
|
||||
StdMesh(const StdMesh& other); // non-copyable
|
||||
|
@ -265,7 +272,7 @@ protected:
|
|||
|
||||
const StdSubMesh *base;
|
||||
// Faces sorted according to current face ordering
|
||||
std::vector<StdMeshFace> Faces; // TODO: Indices could also be stored on GPU in a vbo (element index array). Should be done in a next step if at all.
|
||||
std::vector<StdMeshFace> Faces;
|
||||
|
||||
const StdMeshMaterial* Material;
|
||||
|
||||
|
@ -602,7 +609,16 @@ public:
|
|||
|
||||
const StdMesh& GetMesh() const { return *Mesh; }
|
||||
|
||||
#ifndef USE_CONSOLE
|
||||
GLuint GetIBO() const { return ibo ? ibo : Mesh->GetIBO(); }
|
||||
unsigned int GetVAOID() const { return vaoid ? vaoid : Mesh->GetVAOID(); }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifndef USE_CONSOLE
|
||||
void UpdateIBO();
|
||||
#endif
|
||||
|
||||
AttachedMesh* AttachMeshImpl(StdMeshInstance& instance, AttachedMesh::Denumerator* denumerator, const StdStrBuf& parent_bone, const StdStrBuf& child_bone, const StdMeshMatrix& transformation, uint32_t flags, bool own_child, unsigned int new_attach_number);
|
||||
|
||||
template<typename IteratorType, typename FuncObj>
|
||||
|
@ -633,6 +649,15 @@ protected:
|
|||
AttachedMesh* AttachParent;
|
||||
|
||||
bool BoneTransformsDirty;
|
||||
|
||||
#ifndef USE_CONSOLE
|
||||
// private instance index buffer, and a VAO that is bound to it
|
||||
// instead of the mesh's. We use a private IBO when we use custom
|
||||
// face ordering. Otherwise, when we use the default face ordering,
|
||||
// these members are 0 and we use the mesh's IBO and VAO instead.
|
||||
GLuint ibo;
|
||||
unsigned int vaoid;
|
||||
#endif
|
||||
private:
|
||||
StdMeshInstance(const StdMeshInstance& other); // noncopyable
|
||||
StdMeshInstance& operator=(const StdMeshInstance& other); // noncopyable
|
||||
|
|
|
@ -878,6 +878,11 @@ bool StdMeshMaterialProgram::CompileShader(StdMeshMaterialLoader& loader, C4Shad
|
|||
uniformNames[C4SSU_AmbientTex] = "ambientTex";
|
||||
uniformNames[C4SSU_AmbientTransform] = "ambientTransform";
|
||||
uniformNames[C4SSU_AmbientBrightness] = "ambientBrightness";
|
||||
uniformNames[C4SSU_MaterialAmbient] = "materialAmbient";
|
||||
uniformNames[C4SSU_MaterialDiffuse] = "materialDiffuse";
|
||||
uniformNames[C4SSU_MaterialSpecular] = "materialSpecular";
|
||||
uniformNames[C4SSU_MaterialEmission] = "materialEmission";
|
||||
uniformNames[C4SSU_MaterialShininess] = "materialShininess";
|
||||
uniformNames[C4SSU_Bones] = "bones";
|
||||
uniformNames[C4SSU_CullMode] = "cullMode";
|
||||
for (unsigned int i = 0; i < ParameterNames.size(); ++i)
|
||||
|
|
|
@ -96,7 +96,7 @@ END
|
|||
|
||||
IDD_CONSOLE DIALOGEX 0, 0, 232, 127
|
||||
STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION |
|
||||
WS_SYSMENU
|
||||
WS_SYSMENU | WS_THICKFRAME
|
||||
EXSTYLE WS_EX_CONTROLPARENT
|
||||
CAPTION "CONSOLE"
|
||||
MENU IDR_CONSOLEMENU
|
||||
|
@ -121,7 +121,7 @@ BEGIN
|
|||
END
|
||||
|
||||
IDD_PROPERTIES DIALOGEX 0, 0, 168, 62
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_THICKFRAME
|
||||
CAPTION "PROPERTIES"
|
||||
FONT 8, "MS Sans Serif", 0, 0, 0x1
|
||||
BEGIN
|
||||
|
|
|
@ -828,7 +828,7 @@ C4AulBCC *C4AulExec::Call(C4AulFunc *pFunc, C4Value *pReturn, C4Value *pPars, C4
|
|||
pContext = pCurCtx->Obj;
|
||||
}
|
||||
|
||||
pFunc->CheckParTypes(pPars);
|
||||
pFunc->CheckParTypes(pPars, true);
|
||||
|
||||
// Script function?
|
||||
C4AulScriptFunc *pSFunc = pFunc->SFunc();
|
||||
|
|
|
@ -61,14 +61,24 @@ StdStrBuf C4AulFunc::GetFullName()
|
|||
return r;
|
||||
}
|
||||
|
||||
void C4AulFunc::CheckParTypes(const C4Value pPars[]) const {
|
||||
bool C4AulFunc::CheckParTypes(const C4Value pPars[], bool fPassErrors) const {
|
||||
// Convert parameters (typecheck)
|
||||
const C4V_Type *pTypes = GetParType();
|
||||
int parcount = GetParCount();
|
||||
for (int i = 0; i < parcount; i++) {
|
||||
if (!pPars[i].CheckParConversion(pTypes[i]))
|
||||
throw C4AulExecError(FormatString("call to \"%s\" parameter %d: passed %s, but expected %s",
|
||||
GetName(), i + 1, pPars[i].GetTypeName(), GetC4VName(pTypes[i])
|
||||
).getData());
|
||||
{
|
||||
C4AulExecError e(FormatString(
|
||||
"call to \"%s\" parameter %d: passed %s, but expected %s",
|
||||
GetName(), i + 1, pPars[i].GetTypeName(), GetC4VName(pTypes[i])).getData());
|
||||
if (fPassErrors)
|
||||
throw e;
|
||||
else
|
||||
{
|
||||
e.show();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -79,10 +79,14 @@ public:
|
|||
virtual C4V_Type GetRetType() const = 0;
|
||||
C4Value Exec(C4PropList * p = NULL, C4AulParSet *pPars = NULL, bool fPassErrors=false)
|
||||
{
|
||||
// Every parameter type allows conversion from nil, so no parameters are always allowed
|
||||
if (!pPars)
|
||||
return Exec(p, C4AulParSet().Par, fPassErrors);
|
||||
if (!CheckParTypes(pPars->Par, fPassErrors)) return C4Value();
|
||||
return Exec(p, pPars->Par, fPassErrors);
|
||||
}
|
||||
virtual C4Value Exec(C4PropList * p, C4Value pPars[], bool fPassErrors=false) = 0;
|
||||
void CheckParTypes(const C4Value pPars[]) const;
|
||||
bool CheckParTypes(const C4Value pPars[], bool fPassErrors) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -349,7 +349,6 @@ static C4Value FnCall(C4PropList * _this, C4Value * Pars)
|
|||
}
|
||||
if (!fn)
|
||||
throw C4AulExecError(FormatString("Call: no function %s", Pars[0].GetDataString().getData()).getData());
|
||||
fn->CheckParTypes(ParSet.Par);
|
||||
return fn->Exec(_this, &ParSet, true);
|
||||
}
|
||||
|
||||
|
|