본문 바로가기
LibGdx

libgdx - Convert c ++ bullet file to libgdx file - 1( terrainDemo )

by ses jeon 2019. 12. 14.

Let's port the terrainDemo with reference to basicDemo porting in the previous chapter.

1
2
3
4
5
6
7
8
9
10
11
12
#include "TerrainDemo.h"
#include "GlutStuff.h"
 
int main(int argc,char** argv)
{
    DemoApplication * demo = btCreateTerrainDemo();
    btAssert(demo && "failed to create terrain demo object");
 
        return glutmain(argc, argv, 800600,
        "Terrain Demo. http://www.continuousphysics.com/Bullet/phpBB2/",
        demo);
}
cs

btCreateTerrainDemo () is executed instead of initPhysics. Follow the source.

The world setting is different. This part does not have prior knowledge of the bullet wrapper reference. Originally it was where btDbvtBroadphase ();

..... 추가

 

I'm changing 1- gravity, creating 2-btHeightFiledData, and 3- btHeightFiledTerrainShape.
I think you need to understand the new btHeightFiledData, btHeightFieldTerrainShape. Other work flows are no different from the dynamic world settings.

First, let's check the other terrainDemo part.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// creates a radially-varying heightfield
static void
setRadial
(
byte_t * grid,
int bytesPerElement,
PHY_ScalarType type,
float phase = 0.0
)
{
    btAssert(grid);
    btAssert(bytesPerElement > 0);
 
    // min/max
    float period = 0.5 / s_gridSpacing;
    float floor = 0.0;
    float min_r = 3.0 * sqrt(s_gridSpacing);
    float magnitude = 50.0 * sqrt(s_gridSpacing);
 
    // pick a base_phase such that phase = 0 results in max height
    //   (this way, if you create a heightfield with phase = 0,
    //    you can rely on the min/max heights that result)
    float base_phase = (0.5 * SIMD_PI) - (period * min_r);
    phase += base_phase;
 
    // center of grid
    float cx = 0.5 * s_gridSize * s_gridSpacing;
    float cy = cx;        // assume square grid
    byte_t * p = grid;
    for (int i = 0; i < s_gridSize; ++i) {
        float x = i * s_gridSpacing;
        for (int j = 0; j < s_gridSize; ++j) {
            float y = j * s_gridSpacing;
 
            float dx = x - cx;
            float dy = y - cy;
 
            float r = sqrt((dx * dx) + (dy * dy));
 
            float z = period;
            if (r < min_r) {
                r = min_r;
            }
            z = (1.0 / r) * sin(period * r + phase);
            if (z > period) {
                z = period;
            } else if (z < -period) {
                z = -period;
            }
            z = floor + magnitude * z;
 
            convertFromFloat(p, z, type);
            p += bytesPerElement;
        }
    }
}
cs

It is said to create radial change terrain. We can infer that we take a grid of bype_t * type that we don't know yet and change it. The last part can be read as changing p (since it's a grid) and shifting it by the data size.

convertFromFloat(p, z, type);

p += bytesPerElement;

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// creates a random, fractal heightfield
static void
setFractal
(
byte_t * grid,
int bytesPerElement,
PHY_ScalarType type,
int step
)
{
    btAssert(grid);
    btAssert(bytesPerElement > 0);
    btAssert(step > 0);
    btAssert(step < s_gridSize);
 
    int newStep = step / 2;
//    std::cerr << "Computing grid with step = " << step << ": before\n";
//    dumpGrid(grid, bytesPerElement, type, step + 1);
 
    // special case: starting (must set four corners)
    if (s_gridSize - 1 == step) {
        // pick a non-zero (possibly negative) base elevation for testing
        float base = randomHeight(step / 2);
 
        convertFromFloat(grid, base, type);
        convertFromFloat(grid + step * bytesPerElement, base, type);
        convertFromFloat(grid + step * s_gridSize * bytesPerElement, base, type);
        convertFromFloat(grid + (step * s_gridSize + step) * bytesPerElement, base, type);
    }
 
    // determine elevation of each corner
    float c00 = convertToFloat(grid, type);
    float c01 = convertToFloat(grid + step * bytesPerElement, type);
    float c10 = convertToFloat(grid + (step * s_gridSize) * bytesPerElement, type);
    float c11 = convertToFloat(grid + (step * s_gridSize + step) * bytesPerElement, type);
 
    // set top middle
    updateHeight(grid + newStep * bytesPerElement, 0.5 * (c00 + c01) + randomHeight(step), type);
 
    // set left middle
    updateHeight(grid + (newStep * s_gridSize) * bytesPerElement, 0.5 * (c00 + c10) + randomHeight(step), type);
 
    // set right middle
    updateHeight(grid + (newStep * s_gridSize + step) * bytesPerElement, 0.5 * (c01 + c11) + randomHeight(step), type);
 
    // set bottom middle
    updateHeight(grid + (step * s_gridSize + newStep) * bytesPerElement, 0.5 * (c10 + c11) + randomHeight(step), type);
 
    // set middle
    updateHeight(grid + (newStep * s_gridSize + newStep) * bytesPerElement, 0.25 * (c00 + c01 + c10 + c11) + randomHeight(step), type);
 
//    std::cerr << "Computing grid with step = " << step << ": after\n";
//    dumpGrid(grid, bytesPerElement, type, step + 1);
 
    // terminate?
    if (newStep < 2) {
        return;
    }
 
    // recurse
    setFractal(grid, bytesPerElement, type, newStep);
    setFractal(grid + newStep * bytesPerElement, bytesPerElement, type, newStep);
    setFractal(grid + (newStep * s_gridSize) * bytesPerElement, bytesPerElement, type, newStep);
    setFractal(grid + ((newStep * s_gridSize) + newStep) * bytesPerElement, bytesPerElement, type, newStep);
}
cs

Creates a random fractal height field.

setRadial () and setFractal () This doesn't know exactly what it does, but it can be expected to transform the grid data anyway. When you run the example, the ground is moving, so it seems to be the same.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
static byte_t *
getRawHeightfieldData
(
eTerrainModel model,
PHY_ScalarType type,
btScalar& minHeight,
btScalar& maxHeight
)
{
//    std::cerr << "\nRegenerating terrain\n";
//    std::cerr << "  model = " << model << "\n";
//    std::cerr << "  type = " << type << "\n";
 
    long nElements = ((long) s_gridSize) * s_gridSize;
//    std::cerr << "  nElements = " << nElements << "\n";
 
    int bytesPerElement = getByteSize(type);
//    std::cerr << "  bytesPerElement = " << bytesPerElement << "\n";
    btAssert(bytesPerElement > 0 && "bad bytes per element");
 
    long nBytes = nElements * bytesPerElement;
//    std::cerr << "  nBytes = " << nBytes << "\n";
    byte_t * raw = new byte_t[nBytes];
    btAssert(raw && "out of memory");
 
    // reseed randomization every 30 seconds
//    srand(time(NULL) / 30);
 
    // populate based on model
    switch (model) {
    case eRadial:
        setRadial(raw, bytesPerElement, type);
        break;
 
    case eFractal:
        for (int i = 0; i < nBytes; i++)
        {
            raw[i] = 0;
        }
        setFractal(raw, bytesPerElement, type, s_gridSize - 1);
        break;
 
    default:
        btAssert(!"bad model type");
    }
 
    if (0) {
        // inside if(0) so it keeps compiling but isn't
        //     exercised and doesn't cause warnings
//        std::cerr << "final grid:\n";
        dumpGrid(raw, bytesPerElement, type, s_gridSize - 1);
    }
 
    // find min/max
    for (int i = 0; i < s_gridSize; ++i) {
        for (int j = 0; j < s_gridSize; ++j) {
            float z = getGridHeight(raw, i, j, type);
//            std::cerr << "i=" << i << ", j=" << j << ": z=" << z << "\n";
 
            // update min/max
            if (!&& !j) {
                minHeight = z;
                maxHeight = z;
            } else {
                if (z < minHeight) {
                    minHeight = z;
                }
                if (z > maxHeight) {
                    maxHeight = z;
                }
            }
        }
    }
 
    if (maxHeight < -minHeight) {
        maxHeight = -minHeight;
    }
    if (minHeight > -maxHeight) {
        minHeight = -maxHeight;
    }
 
//    std::cerr << "  minHeight = " << minHeight << "\n";
//    std::cerr << "  maxHeight = " << maxHeight << "\n";
 
    return raw;
}
cs

getRawHeightfieldData (), yes it seems to be a function that creates heightFieldData directly. But no data is received. You can see that it creates an empty data array called raw. By creating this, it seems to create terrain randomly with the above two functions.

We have looked at the main functions. Now, use your imagination to port the code above to libgdx / java, modify it, and see the value.

This part of drawOpenGL in GL_ShapeDrawer.cpp ..-> Move while watching getShapeType ()

By the way, getShapeType () did not find anything special. Then let's follow the same from the first world setting.