Beispiel #1
0
static int physics_thread_main(void* arg)
{
    GLFWwindow* window = arg;

    for (;;)
    {
        mtx_lock(&thread_sync.particles_lock);

        // Wait for particle drawing to be done
        while (!glfwWindowShouldClose(window) &&
               thread_sync.p_frame > thread_sync.d_frame)
        {
            struct timespec ts;
            clock_gettime(CLOCK_REALTIME, &ts);
            ts.tv_nsec += 100000000;
            cnd_timedwait(&thread_sync.d_done, &thread_sync.particles_lock, &ts);
        }

        if (glfwWindowShouldClose(window))
            break;

        // Update particles
        particle_engine(thread_sync.t, thread_sync.dt);

        // Update frame counter
        thread_sync.p_frame++;

        // Unlock mutex and signal drawing thread
        mtx_unlock(&thread_sync.particles_lock);
        cnd_signal(&thread_sync.p_done);
    }

    return 0;
}
int cnd_wait(cnd_t *c, mtx_t *m)
{
	/* Calling cnd_timedwait with a null pointer is an extension.
	 * It is convenient here to avoid duplication of the logic
	 * for return values. */
	return cnd_timedwait(c, m, 0);
}
int cnd_timedwait_abs (cnd_t *cnd, mtx_t *mtx, const struct timespec *tspec) {
        if (tspec->tv_sec == RD_POLL_INFINITE)
                return cnd_wait(cnd, mtx);
        else if (tspec->tv_sec == RD_POLL_NOWAIT)
                return thrd_timedout;

        return cnd_timedwait(cnd, mtx, tspec);
}
COND_RESULT Condition_Wait(COND_HANDLE handle, LOCK_HANDLE lock, int timeout_milliseconds)
{
    COND_RESULT result;
    // Codes_SRS_CONDITION_18_004: [ Condition_Wait shall return COND_INVALID_ARG if handle is NULL ]
    // Codes_SRS_CONDITION_18_005: [ Condition_Wait shall return COND_INVALID_ARG if lock is NULL and timeout_milliseconds is 0 ]
    // Codes_SRS_CONDITION_18_006: [ Condition_Wait shall return COND_INVALID_ARG if lock is NULL and timeout_milliseconds is not 0 ]
    if (handle == NULL || lock == NULL)
    {
        result = COND_INVALID_ARG;
    }
    else
    {
        if (timeout_milliseconds > 0)
        {
            struct xtime tm;
            int wait_result;
            time_t now = get_time(NULL);

            // Codes_SRS_CONDITION_18_013: [ Condition_Wait shall accept relative timeouts ]
            tm.sec = (unsigned long)get_difftime(now, (time_t)0) + (timeout_milliseconds / 1000);
            tm.nsec = (timeout_milliseconds % 1000) * 1000000L;
            wait_result = cnd_timedwait((cnd_t *)handle, (mtx_t*)lock, &tm);
            if (wait_result == thrd_timedout)
            {
                // Codes_SRS_CONDITION_18_011: [ Condition_Wait shall return COND_TIMEOUT if the condition is NOT triggered and timeout_milliseconds is not 0 ]
                result = COND_TIMEOUT;
            }
            else if (wait_result == thrd_success)
            {
                // Codes_SRS_CONDITION_18_012: [ Condition_Wait shall return COND_OK if the condition is triggered and timeout_milliseconds is not 0 ]
                result = COND_OK;
            }
            else
            {
                LogError("Failed to Condition_Wait\r\n");
                result = COND_ERROR;
            }
        }
        else
        {
            if (cnd_wait((cnd_t*)handle, (mtx_t *)lock) != thrd_success)
            {
                LogError("Failed to cnd_wait\r\n");
                result = COND_ERROR;
            }
            else
            {
                // Codes_SRS_CONDITION_18_010: [ Condition_Wait shall return COND_OK if the condition is triggered and timeout_milliseconds is 0 ]
                result = COND_OK;
            }
        }
    }
    return result;
}
Beispiel #5
0
int     _RTL_FUNC cnd_wait(cnd_t *cond, mtx_t *mtx)
{
    switch(__mtxThisThread(mtx))
    {
        default:
            return thrd_error;
        case thrd_success:
            return cnd_timedwait(cond, mtx, -1);
        case thrd_busy:
            abort();
            // never gets here
            return thrd_error;
    }
}
int cnd_timedwait_ms(cnd_t *cnd, mtx_t *mtx, int timeout_ms) {
        if (timeout_ms == -1 /* INFINITE*/)
                return cnd_wait(cnd, mtx);
#if defined(_TTHREAD_WIN32_)
        return _cnd_timedwait_win32(cnd, mtx, (DWORD)timeout_ms);
#else
        struct timeval tv;
        struct timespec ts;

        gettimeofday(&tv, NULL);
        ts.tv_sec = tv.tv_sec;
        ts.tv_nsec = tv.tv_usec * 1000;

        ts.tv_sec  += timeout_ms / 1000;
        ts.tv_nsec += (timeout_ms % 1000) * 1000000;

        if (ts.tv_nsec >= 1000000000) {
                ts.tv_sec++;
                ts.tv_nsec -= 1000000000;
        }

        return cnd_timedwait(cnd, mtx, &ts);
#endif
}
Beispiel #7
0
static void draw_particles(GLFWwindow* window, double t, float dt)
{
    int i, particle_count;
    Vertex vertex_array[BATCH_PARTICLES * PARTICLE_VERTS];
    Vertex* vptr;
    float alpha;
    GLuint rgba;
    Vec3 quad_lower_left, quad_lower_right;
    GLfloat mat[16];
    PARTICLE* pptr;

    // Here comes the real trick with flat single primitive objects (s.c.
    // "billboards"): We must rotate the textured primitive so that it
    // always faces the viewer (is coplanar with the view-plane).
    // We:
    //   1) Create the primitive around origo (0,0,0)
    //   2) Rotate it so that it is coplanar with the view plane
    //   3) Translate it according to the particle position
    // Note that 1) and 2) is the same for all particles (done only once).

    // Get modelview matrix. We will only use the upper left 3x3 part of
    // the matrix, which represents the rotation.
    glGetFloatv(GL_MODELVIEW_MATRIX, mat);

    // 1) & 2) We do it in one swift step:
    // Although not obvious, the following six lines represent two matrix/
    // vector multiplications. The matrix is the inverse 3x3 rotation
    // matrix (i.e. the transpose of the same matrix), and the two vectors
    // represent the lower left corner of the quad, PARTICLE_SIZE/2 *
    // (-1,-1,0), and the lower right corner, PARTICLE_SIZE/2 * (1,-1,0).
    // The upper left/right corners of the quad is always the negative of
    // the opposite corners (regardless of rotation).
    quad_lower_left.x = (-PARTICLE_SIZE / 2) * (mat[0] + mat[1]);
    quad_lower_left.y = (-PARTICLE_SIZE / 2) * (mat[4] + mat[5]);
    quad_lower_left.z = (-PARTICLE_SIZE / 2) * (mat[8] + mat[9]);
    quad_lower_right.x = (PARTICLE_SIZE / 2) * (mat[0] - mat[1]);
    quad_lower_right.y = (PARTICLE_SIZE / 2) * (mat[4] - mat[5]);
    quad_lower_right.z = (PARTICLE_SIZE / 2) * (mat[8] - mat[9]);

    // Don't update z-buffer, since all particles are transparent!
    glDepthMask(GL_FALSE);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE);

    // Select particle texture
    if (!wireframe)
    {
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, particle_tex_id);
    }

    // Set up vertex arrays. We use interleaved arrays, which is easier to
    // handle (in most situations) and it gives a linear memeory access
    // access pattern (which may give better performance in some
    // situations). GL_T2F_C4UB_V3F means: 2 floats for texture coords,
    // 4 ubytes for color and 3 floats for vertex coord (in that order).
    // Most OpenGL cards / drivers are optimized for this format.
    glInterleavedArrays(GL_T2F_C4UB_V3F, 0, vertex_array);

    // Wait for particle physics thread to be done
    mtx_lock(&thread_sync.particles_lock);
    while (!glfwWindowShouldClose(window) &&
            thread_sync.p_frame <= thread_sync.d_frame)
    {
        struct timespec ts;
        clock_gettime(CLOCK_REALTIME, &ts);
        ts.tv_nsec += 100000000;
        cnd_timedwait(&thread_sync.p_done, &thread_sync.particles_lock, &ts);
    }

    // Store the frame time and delta time for the physics thread
    thread_sync.t = t;
    thread_sync.dt = dt;

    // Update frame counter
    thread_sync.d_frame++;

    // Loop through all particles and build vertex arrays.
    particle_count = 0;
    vptr = vertex_array;
    pptr = particles;

    for (i = 0;  i < MAX_PARTICLES;  i++)
    {
        if (pptr->active)
        {
            // Calculate particle intensity (we set it to max during 75%
            // of its life, then it fades out)
            alpha =  4.f * pptr->life;
            if (alpha > 1.f)
                alpha = 1.f;

            // Convert color from float to 8-bit (store it in a 32-bit
            // integer using endian independent type casting)
            ((GLubyte*) &rgba)[0] = (GLubyte)(pptr->r * 255.f);
            ((GLubyte*) &rgba)[1] = (GLubyte)(pptr->g * 255.f);
            ((GLubyte*) &rgba)[2] = (GLubyte)(pptr->b * 255.f);
            ((GLubyte*) &rgba)[3] = (GLubyte)(alpha * 255.f);

            // 3) Translate the quad to the correct position in modelview
            // space and store its parameters in vertex arrays (we also
            // store texture coord and color information for each vertex).

            // Lower left corner
            vptr->s    = 0.f;
            vptr->t    = 0.f;
            vptr->rgba = rgba;
            vptr->x    = pptr->x + quad_lower_left.x;
            vptr->y    = pptr->y + quad_lower_left.y;
            vptr->z    = pptr->z + quad_lower_left.z;
            vptr ++;

            // Lower right corner
            vptr->s    = 1.f;
            vptr->t    = 0.f;
            vptr->rgba = rgba;
            vptr->x    = pptr->x + quad_lower_right.x;
            vptr->y    = pptr->y + quad_lower_right.y;
            vptr->z    = pptr->z + quad_lower_right.z;
            vptr ++;

            // Upper right corner
            vptr->s    = 1.f;
            vptr->t    = 1.f;
            vptr->rgba = rgba;
            vptr->x    = pptr->x - quad_lower_left.x;
            vptr->y    = pptr->y - quad_lower_left.y;
            vptr->z    = pptr->z - quad_lower_left.z;
            vptr ++;

            // Upper left corner
            vptr->s    = 0.f;
            vptr->t    = 1.f;
            vptr->rgba = rgba;
            vptr->x    = pptr->x - quad_lower_right.x;
            vptr->y    = pptr->y - quad_lower_right.y;
            vptr->z    = pptr->z - quad_lower_right.z;
            vptr ++;

            // Increase count of drawable particles
            particle_count ++;
        }

        // If we have filled up one batch of particles, draw it as a set
        // of quads using glDrawArrays.
        if (particle_count >= BATCH_PARTICLES)
        {
            // The first argument tells which primitive type we use (QUAD)
            // The second argument tells the index of the first vertex (0)
            // The last argument is the vertex count
            glDrawArrays(GL_QUADS, 0, PARTICLE_VERTS * particle_count);
            particle_count = 0;
            vptr = vertex_array;
        }

        // Next particle
        pptr++;
    }

    // We are done with the particle data
    mtx_unlock(&thread_sync.particles_lock);
    cnd_signal(&thread_sync.d_done);

    // Draw final batch of particles (if any)
    glDrawArrays(GL_QUADS, 0, PARTICLE_VERTS * particle_count);

    // Disable vertex arrays (Note: glInterleavedArrays implicitly called
    // glEnableClientState for vertex, texture coord and color arrays)
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_COLOR_ARRAY);

    glDisable(GL_TEXTURE_2D);
    glDisable(GL_BLEND);

    glDepthMask(GL_TRUE);
}