src/ascension/scene.h

Sun, 06 Oct 2024 20:49:43 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 06 Oct 2024 20:49:43 +0200
changeset 75
0ce353485509
parent 73
cfa1d05754ac
permissions
-rw-r--r--

revert introduction of high level ucx trees and stick to the low level API

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * Copyright 2023 Mike Becker. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ASCENSION_SCENE_H
#define ASCENSION_SCENE_H

#include "datatypes.h"
#include "transform.h"
#include "camera.h"
#include "texture.h"

#include <cx/list.h>

typedef struct AscSceneNode AscSceneNode;

typedef void(*asc_scene_free_func)(AscSceneNode*);
typedef void(*asc_scene_update_func)(AscSceneNode*);

enum AscRenderGroup {
    ASC_RENDER_GROUP_SPRITE_OPAQUE,
    ASC_RENDER_GROUP_SPRITE_BLEND,
    ASC_RENDER_GROUP_COUNT
};

struct AscSceneNode {
    AscSceneNode *parent;
    AscSceneNode *prev;
    AscSceneNode *next;
    AscSceneNode *children;
    AscSceneNode *last_child;
    CxList *behaviors;
    asc_scene_free_func free_func;
    asc_scene_update_func update_func;
    unsigned depth; // TODO: do we really need this bullshit?
    asc_vec3f position;
    asc_vec3f rotation;
    asc_vec3f scale;
    asc_transform transform;
    asc_transform world_transform;
    enum AscRenderGroup render_group;
    /**
     * Custom flags for this node.
     * The #ASC_SCENE_NODE_FLAGS_MASK bits are reserved for general flags.
     */
    uint32_t flags;
};

typedef struct AscSprite {
    AscSceneNode data;
    AscTexture tex;
} AscSprite;

/**
 * The reserved bits for general flags.
 */
#define ASC_SCENE_NODE_FLAGS_MASK             0xFF000000
/**
 * Set when a graphics update is needed in this frame.
 */
#define ASC_SCENE_NODE_UPDATE_GRAPHICS        0x01000000
/**
 * Set when a graphics updated happened last frame.
 */
#define ASC_SCENE_NODE_GRAPHICS_UPDATED       0x10000000
/**
 * Set when a transform update is needed in this frame.
 */
#define ASC_SCENE_NODE_UPDATE_TRANSFORM       0x02000000
/**
 * Set when a transform update happened last frame.
 */
#define ASC_SCENE_NODE_TRANSFORM_UPDATED      0x20000000
/**
 * Set when the node is not supposed to be shown on screen.
 */
#define ASC_SCENE_NODE_HIDDEN                 0x80000000

/**
 * Draws the scene with the specified root node.
 *
 * @param root the root node of the scene graph
 * @param viewport the window viewport the scene shall be drawn to
 * @param camera the camera to obtain the view and projection matrix from
 */
__attribute__((__nonnull__))
void asc_scene_draw(AscSceneNode *root, asc_recti viewport, AscCamera *camera);

/**
 * Creates an empty node that may serve as a container for other nodes.
 *
 * The free_func of this node will be a simple free().
 *
 * @return the new node
 */
AscSceneNode *asc_scene_node_empty(void);

/**
 * Unlinks the node from its parent and frees the entire subtree.
 *
 * The free_func of this node and all child nodes is called, starting
 * with the leaf nodes and terminating with \p node.
 *
 * @param node the node to unlink
 */
void asc_scene_node_free(AscSceneNode *node);

/**
 * Links a node to a (new) parent.
 *
 * @param parent the (new) parent
 * @param node the node to link
 */
__attribute__((__nonnull__))
void asc_scene_node_link(
        AscSceneNode *restrict parent,
        AscSceneNode *restrict node
);

/**
 * Unlinks a node from its parent.
 *
 * This might be useful to temporarily remove a subtree from a scene.
 * To permanently remove the node use asc_scene_node_free().
 *
 * @param node the node to unlink
 */
__attribute__((__nonnull__))
void asc_scene_node_unlink(AscSceneNode *node);

/**
 * Adds a behavior function to the node.
 *
 * A behavior function MUST NOT be added more than once to the same node.
 * This will not be checked.
 *
 * @param node the node
 * @param behavior the behavior function
 */
__attribute__((__nonnull__))
void asc_scene_add_behavior(
        AscSceneNode *node,
        asc_scene_update_func behavior
);

/**
 * Removes a behavior function from the node.
 *
 * If the behavior function is not attached to this node, this function
 * does nothing.
 *
 * @param node the node
 * @param behavior the behavior function
 */
__attribute__((__nonnull__))
void asc_scene_remove_behavior(
        AscSceneNode *node,
        asc_scene_update_func behavior
);

__attribute__((__nonnull__))
void asc_node_update(AscSceneNode *node);

__attribute__((__nonnull__))
void asc_node_update_transform(AscSceneNode *node);


__attribute__((__nonnull__)) static inline
void asc_set_position(AscSceneNode *node, float x, float y, float z) {
    node->position.x = x;
    node->position.y = y;
    node->position.z = z;
    asc_node_update_transform(node);
}

__attribute__((__nonnull__)) static inline
void asc_set_position2d(AscSceneNode *node, int x, int y) {
    node->position.x = (float)x;
    node->position.y = (float)y;
    node->position.z = 0.f;
    asc_node_update_transform(node);
}

__attribute__((__nonnull__)) static inline
asc_vec2i asc_get_position2d(AscSceneNode *node) {
    return (asc_vec2i) {(int) node->position.x, (int) node->position.y};
}

__attribute__((__nonnull__)) static inline
void asc_set_scale(AscSceneNode *node, float width, float height, float depth) {
    node->scale.width = width;
    node->scale.height = height;
    node->scale.depth = depth;
    asc_node_update_transform(node);
}

__attribute__((__nonnull__)) static inline
void asc_set_scale2d(AscSceneNode *node, int width, int height) {
    node->scale.width = (float)width;
    node->scale.height = (float)height;
    node->scale.depth = 1.f;
    asc_node_update_transform(node);
}

__attribute__((__nonnull__)) static inline
asc_vec2i asc_get_scale2d(AscSceneNode *node) {
    return (asc_vec2i) {(int) node->scale.width, (int) node->scale.height};
}

#endif // ASCENSION_SCENE_H

mercurial