Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
587 lines (495 sloc) 16.4 KB
/* ______ ___ ___
* /\ _ \ /\_ \ /\_ \
* \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
* \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
* \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
* \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
* \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
* /\____/
* \_/__/
*
* Core primitive addon functions.
*
*
* By Pavel Sountsov.
*
* See readme.txt for copyright information.
*/
#include "allegro5/allegro.h"
#include "allegro5/allegro_primitives.h"
#include "allegro5/platform/alplatf.h"
#include "allegro5/internal/aintern.h"
#include "allegro5/internal/aintern_bitmap.h"
#include "allegro5/internal/aintern_exitfunc.h"
#include "allegro5/internal/aintern_pixels.h"
#include "allegro5/internal/aintern_prim.h"
#include "allegro5/internal/aintern_prim_directx.h"
#include "allegro5/internal/aintern_prim_opengl.h"
#include "allegro5/internal/aintern_prim_soft.h"
#include <math.h>
#ifdef ALLEGRO_CFG_OPENGL
#include "allegro5/allegro_opengl.h"
#endif
#ifndef ALLEGRO_DIRECT3D
#define ALLEGRO_DIRECT3D ALLEGRO_DIRECT3D_INTERNAL
#endif
ALLEGRO_DEBUG_CHANNEL("primitives")
static bool addon_initialized = false;
/* Function: al_init_primitives_addon
*/
bool al_init_primitives_addon(void)
{
bool ret = true;
ret &= _al_init_d3d_driver();
addon_initialized = ret;
_al_add_exit_func(al_shutdown_primitives_addon, "primitives_shutdown");
return ret;
}
/* Function: al_shutdown_primitives_addon
*/
void al_shutdown_primitives_addon(void)
{
_al_shutdown_d3d_driver();
addon_initialized = false;
}
/* Function: al_draw_prim
*/
int al_draw_prim(const void* vtxs, const ALLEGRO_VERTEX_DECL* decl,
ALLEGRO_BITMAP* texture, int start, int end, int type)
{
ALLEGRO_BITMAP *target;
int ret = 0;
ASSERT(addon_initialized);
ASSERT(vtxs);
ASSERT(end >= start);
ASSERT(start >= 0);
ASSERT(type >= 0 && type < ALLEGRO_PRIM_NUM_TYPES);
target = al_get_target_bitmap();
/* In theory, if we ever get a camera concept for this addon, the transformation into
* view space should occur here
*/
if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP ||
(texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP) ||
_al_pixel_format_is_compressed(al_get_bitmap_format(target))) {
ret = _al_draw_prim_soft(texture, vtxs, decl, start, end, type);
} else {
int flags = al_get_display_flags(_al_get_bitmap_display(target));
if (flags & ALLEGRO_OPENGL) {
ret = _al_draw_prim_opengl(target, texture, vtxs, decl, start, end, type);
} else if (flags & ALLEGRO_DIRECT3D) {
ret = _al_draw_prim_directx(target, texture, vtxs, decl, start, end, type);
}
}
return ret;
}
/* Function: al_draw_indexed_prim
*/
int al_draw_indexed_prim(const void* vtxs, const ALLEGRO_VERTEX_DECL* decl,
ALLEGRO_BITMAP* texture, const int* indices, int num_vtx, int type)
{
ALLEGRO_BITMAP *target;
int ret = 0;
ASSERT(addon_initialized);
ASSERT(vtxs);
ASSERT(indices);
ASSERT(num_vtx > 0);
ASSERT(type >= 0 && type < ALLEGRO_PRIM_NUM_TYPES);
target = al_get_target_bitmap();
/* In theory, if we ever get a camera concept for this addon, the transformation into
* view space should occur here
*/
if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP ||
(texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP) ||
_al_pixel_format_is_compressed(al_get_bitmap_format(target))) {
ret = _al_draw_prim_indexed_soft(texture, vtxs, decl, indices, num_vtx, type);
} else {
int flags = al_get_display_flags(_al_get_bitmap_display(target));
if (flags & ALLEGRO_OPENGL) {
ret = _al_draw_prim_indexed_opengl(target, texture, vtxs, decl, indices, num_vtx, type);
} else if (flags & ALLEGRO_DIRECT3D) {
ret = _al_draw_prim_indexed_directx(target, texture, vtxs, decl, indices, num_vtx, type);
}
}
return ret;
}
int _al_bitmap_region_is_locked(ALLEGRO_BITMAP* bmp, int x1, int y1, int w, int h)
{
ASSERT(bmp);
if (!al_is_bitmap_locked(bmp))
return 0;
if (x1 + w > bmp->lock_x && y1 + h > bmp->lock_y && x1 < bmp->lock_x + bmp->lock_w && y1 < bmp->lock_y + bmp->lock_h)
return 1;
return 0;
}
/* Function: al_get_allegro_primitives_version
*/
uint32_t al_get_allegro_primitives_version(void)
{
return ALLEGRO_VERSION_INT;
}
/* Function: al_create_vertex_decl
*/
ALLEGRO_VERTEX_DECL* al_create_vertex_decl(const ALLEGRO_VERTEX_ELEMENT* elements, int stride)
{
ALLEGRO_VERTEX_DECL* ret;
ALLEGRO_DISPLAY* display;
ALLEGRO_VERTEX_ELEMENT* e;
int flags;
ASSERT(addon_initialized);
ret = al_malloc(sizeof(ALLEGRO_VERTEX_DECL));
ret->elements = al_calloc(1, sizeof(ALLEGRO_VERTEX_ELEMENT) * ALLEGRO_PRIM_ATTR_NUM);
while(elements->attribute) {
#ifdef ALLEGRO_CFG_OPENGLES
if (elements->storage == ALLEGRO_PRIM_HALF_FLOAT_2 ||
elements->storage == ALLEGRO_PRIM_HALF_FLOAT_4) {
ALLEGRO_WARN("This platform does not support ALLEGRO_PRIM_HALF_FLOAT_2 or ALLEGRO_PRIM_HALF_FLOAT_4.\n");
goto fail;
}
#endif
ret->elements[elements->attribute] = *elements;
elements++;
}
e = &ret->elements[ALLEGRO_PRIM_POSITION];
if (e->attribute) {
if (e->storage != ALLEGRO_PRIM_FLOAT_2 &&
e->storage != ALLEGRO_PRIM_FLOAT_3 &&
e->storage != ALLEGRO_PRIM_SHORT_2) {
ALLEGRO_WARN("Invalid storage for ALLEGRO_PRIM_POSITION.\n");
goto fail;
}
}
e = &ret->elements[ALLEGRO_PRIM_TEX_COORD];
if(!e->attribute)
e = &ret->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL];
if (e->attribute) {
if (e->storage != ALLEGRO_PRIM_FLOAT_2 &&
e->storage != ALLEGRO_PRIM_SHORT_2) {
ALLEGRO_WARN("Invalid storage for %s.\n", ret->elements[ALLEGRO_PRIM_TEX_COORD].attribute ? "ALLEGRO_PRIM_TEX_COORD" : "ALLEGRO_PRIM_TEX_COORD_PIXEL");
goto fail;
}
}
display = al_get_current_display();
flags = al_get_display_flags(display);
if (flags & ALLEGRO_DIRECT3D) {
_al_set_d3d_decl(display, ret);
}
ret->stride = stride;
return ret;
fail:
al_free(ret->elements);
al_free(ret);
return NULL;
}
/* Function: al_destroy_vertex_decl
*/
void al_destroy_vertex_decl(ALLEGRO_VERTEX_DECL* decl)
{
al_free(decl->elements);
/*
* TODO: Somehow free the d3d_decl
*/
al_free(decl);
}
/* Function: al_create_vertex_buffer
*/
ALLEGRO_VERTEX_BUFFER* al_create_vertex_buffer(ALLEGRO_VERTEX_DECL* decl,
const void* initial_data, int num_vertices, int flags)
{
ALLEGRO_VERTEX_BUFFER* ret;
int display_flags = al_get_display_flags(al_get_current_display());
ASSERT(addon_initialized);
ret = al_calloc(1, sizeof(ALLEGRO_VERTEX_BUFFER));
ret->common.size = num_vertices;
ret->common.write_only = !(flags & ALLEGRO_PRIM_BUFFER_READWRITE);
ret->decl = decl;
#if defined ALLEGRO_IPHONE || defined ALLEGRO_ANDROID
if (flags & ALLEGRO_PRIM_BUFFER_READWRITE)
goto fail;
#endif
if (display_flags & ALLEGRO_OPENGL) {
if (_al_create_vertex_buffer_opengl(ret, initial_data, num_vertices, flags))
return ret;
}
else if (display_flags & ALLEGRO_DIRECT3D) {
if (_al_create_vertex_buffer_directx(ret, initial_data, num_vertices, flags))
return ret;
}
/* Silence the warning */
goto fail;
fail:
al_free(ret);
return 0;
}
/* Function: al_create_index_buffer
*/
ALLEGRO_INDEX_BUFFER* al_create_index_buffer(int index_size,
const void* initial_data, int num_indices, int flags)
{
ALLEGRO_INDEX_BUFFER* ret;
int display_flags = al_get_display_flags(al_get_current_display());
ASSERT(addon_initialized);
ASSERT(index_size == 2 || index_size == 4);
ret = al_calloc(1, sizeof(ALLEGRO_INDEX_BUFFER));
ret->common.size = num_indices;
ret->common.write_only = !(flags & ALLEGRO_PRIM_BUFFER_READWRITE);
ret->index_size = index_size;
#if defined ALLEGRO_IPHONE || defined ALLEGRO_ANDROID
if (flags & ALLEGRO_PRIM_BUFFER_READWRITE)
goto fail;
#endif
#if defined ALLEGRO_IPHONE
if (index_size == 4)
goto fail;
#endif
if (display_flags & ALLEGRO_OPENGL) {
if (_al_create_index_buffer_opengl(ret, initial_data, num_indices, flags))
return ret;
}
else if (display_flags & ALLEGRO_DIRECT3D) {
if (_al_create_index_buffer_directx(ret, initial_data, num_indices, flags))
return ret;
}
/* Silence the warning */
goto fail;
fail:
al_free(ret);
return NULL;
}
/* Function: al_destroy_vertex_buffer
*/
void al_destroy_vertex_buffer(ALLEGRO_VERTEX_BUFFER* buffer)
{
int flags = al_get_display_flags(al_get_current_display());
ASSERT(addon_initialized);
if (buffer == 0)
return;
al_unlock_vertex_buffer(buffer);
if (flags & ALLEGRO_OPENGL) {
_al_destroy_vertex_buffer_opengl(buffer);
}
else if (flags & ALLEGRO_DIRECT3D) {
_al_destroy_vertex_buffer_directx(buffer);
}
al_free(buffer);
}
/* Function: al_destroy_index_buffer
*/
void al_destroy_index_buffer(ALLEGRO_INDEX_BUFFER* buffer)
{
int flags = al_get_display_flags(al_get_current_display());
ASSERT(addon_initialized);
if (buffer == 0)
return;
al_unlock_index_buffer(buffer);
if (flags & ALLEGRO_OPENGL) {
_al_destroy_index_buffer_opengl(buffer);
}
else if (flags & ALLEGRO_DIRECT3D) {
_al_destroy_index_buffer_directx(buffer);
}
al_free(buffer);
}
/* The sizes are in bytes here */
static bool lock_buffer_common(ALLEGRO_BUFFER_COMMON* common, int offset, int length, int flags)
{
if (common->is_locked || (common->write_only && flags != ALLEGRO_LOCK_WRITEONLY))
return false;
common->lock_offset = offset;
common->lock_length = length;
common->lock_flags = flags;
common->is_locked = true;
return true;
}
/* Function: al_lock_vertex_buffer
*/
void* al_lock_vertex_buffer(ALLEGRO_VERTEX_BUFFER* buffer, int offset,
int length, int flags)
{
int stride;
int disp_flags = al_get_display_flags(al_get_current_display());
ASSERT(buffer);
ASSERT(addon_initialized);
if (offset + length > buffer->common.size)
return NULL;
stride = buffer->decl ? buffer->decl->stride : (int)sizeof(ALLEGRO_VERTEX);
if (!lock_buffer_common(&buffer->common, offset * stride, length * stride, flags))
return NULL;
if (disp_flags & ALLEGRO_OPENGL) {
return _al_lock_vertex_buffer_opengl(buffer);
}
else if (disp_flags & ALLEGRO_DIRECT3D) {
return _al_lock_vertex_buffer_directx(buffer);
}
else {
return NULL;
}
}
/* Function: al_lock_index_buffer
*/
void* al_lock_index_buffer(ALLEGRO_INDEX_BUFFER* buffer, int offset,
int length, int flags)
{
int disp_flags = al_get_display_flags(al_get_current_display());
ASSERT(buffer);
ASSERT(addon_initialized);
if (offset + length > buffer->common.size)
return NULL;
if (!lock_buffer_common(&buffer->common, offset * buffer->index_size, length * buffer->index_size, flags))
return NULL;
if (disp_flags & ALLEGRO_OPENGL) {
return _al_lock_index_buffer_opengl(buffer);
}
else if (disp_flags & ALLEGRO_DIRECT3D) {
return _al_lock_index_buffer_directx(buffer);
}
else {
return NULL;
}
}
/* Function: al_unlock_vertex_buffer
*/
void al_unlock_vertex_buffer(ALLEGRO_VERTEX_BUFFER* buffer)
{
int flags = al_get_display_flags(al_get_current_display());
ASSERT(buffer);
ASSERT(addon_initialized);
if (!buffer->common.is_locked)
return;
buffer->common.is_locked = false;
if (flags & ALLEGRO_OPENGL) {
_al_unlock_vertex_buffer_opengl(buffer);
}
else if (flags & ALLEGRO_DIRECT3D) {
_al_unlock_vertex_buffer_directx(buffer);
}
}
/* Function: al_unlock_index_buffer
*/
void al_unlock_index_buffer(ALLEGRO_INDEX_BUFFER* buffer)
{
int flags = al_get_display_flags(al_get_current_display());
ASSERT(buffer);
ASSERT(addon_initialized);
if (!buffer->common.is_locked)
return;
buffer->common.is_locked = false;
if (flags & ALLEGRO_OPENGL) {
_al_unlock_index_buffer_opengl(buffer);
}
else if (flags & ALLEGRO_DIRECT3D) {
_al_unlock_index_buffer_directx(buffer);
}
}
/* Software fallback for buffer drawing */
int _al_draw_buffer_common_soft(ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_BITMAP* texture, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type)
{
void* vtx;
int num_primitives = 0;
int num_vtx = end - start;
int vtx_lock_start = index_buffer ? 0 : start;
int vtx_lock_len = index_buffer ? al_get_vertex_buffer_size(vertex_buffer) : num_vtx;
if (vertex_buffer->common.write_only || (index_buffer && index_buffer->common.write_only)) {
return 0;
}
vtx = al_lock_vertex_buffer(vertex_buffer, vtx_lock_start, vtx_lock_len, ALLEGRO_LOCK_READONLY);
ASSERT(vtx);
if (index_buffer) {
void* idx;
int* int_idx = NULL;
int ii;
idx = al_lock_index_buffer(index_buffer, start, num_vtx, ALLEGRO_LOCK_READONLY);
ASSERT(idx);
if (index_buffer->index_size != 4) {
int_idx = al_malloc(num_vtx * sizeof(int));
for (ii = 0; ii < num_vtx; ii++) {
int_idx[ii] = ((unsigned short*)idx)[ii];
}
idx = int_idx;
}
num_primitives = _al_draw_prim_indexed_soft(texture, vtx, vertex_buffer->decl, idx, num_vtx, type);
al_unlock_index_buffer(index_buffer);
al_free(int_idx);
}
else {
num_primitives = _al_draw_prim_soft(texture, vtx, vertex_buffer->decl, 0, num_vtx, type);
}
al_unlock_vertex_buffer(vertex_buffer);
return num_primitives;
}
/* Function: al_draw_vertex_buffer
*/
int al_draw_vertex_buffer(ALLEGRO_VERTEX_BUFFER* vertex_buffer,
ALLEGRO_BITMAP* texture, int start, int end, int type)
{
ALLEGRO_BITMAP *target;
int ret = 0;
ASSERT(addon_initialized);
ASSERT(end >= start);
ASSERT(start >= 0);
ASSERT(end <= al_get_vertex_buffer_size(vertex_buffer));
ASSERT(type >= 0 && type < ALLEGRO_PRIM_NUM_TYPES);
ASSERT(vertex_buffer);
ASSERT(!vertex_buffer->common.is_locked);
target = al_get_target_bitmap();
if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP ||
(texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP) ||
_al_pixel_format_is_compressed(al_get_bitmap_format(target))) {
ret = _al_draw_buffer_common_soft(vertex_buffer, texture, NULL, start, end, type);
} else {
int flags = al_get_display_flags(al_get_current_display());
if (flags & ALLEGRO_OPENGL) {
ret = _al_draw_vertex_buffer_opengl(target, texture, vertex_buffer, start, end, type);
}
else if (flags & ALLEGRO_DIRECT3D) {
ret = _al_draw_vertex_buffer_directx(target, texture, vertex_buffer, start, end, type);
}
}
return ret;
}
/* Function: al_draw_indexed_buffer
*/
int al_draw_indexed_buffer(ALLEGRO_VERTEX_BUFFER* vertex_buffer,
ALLEGRO_BITMAP* texture, ALLEGRO_INDEX_BUFFER* index_buffer,
int start, int end, int type)
{
ALLEGRO_BITMAP *target;
int ret = 0;
ASSERT(addon_initialized);
ASSERT(end >= start);
ASSERT(start >= 0);
ASSERT(end <= al_get_index_buffer_size(index_buffer));
ASSERT(type >= 0 && type < ALLEGRO_PRIM_NUM_TYPES);
ASSERT(vertex_buffer);
ASSERT(!vertex_buffer->common.is_locked);
ASSERT(index_buffer);
ASSERT(!index_buffer->common.is_locked);
target = al_get_target_bitmap();
if (al_get_bitmap_flags(target) & ALLEGRO_MEMORY_BITMAP ||
(texture && al_get_bitmap_flags(texture) & ALLEGRO_MEMORY_BITMAP) ||
_al_pixel_format_is_compressed(al_get_bitmap_format(target))) {
ret = _al_draw_buffer_common_soft(vertex_buffer, texture, index_buffer, start, end, type);
} else {
int flags = al_get_display_flags(al_get_current_display());
if (flags & ALLEGRO_OPENGL) {
ret = _al_draw_indexed_buffer_opengl(target, texture, vertex_buffer, index_buffer, start, end, type);
}
else if (flags & ALLEGRO_DIRECT3D) {
ret = _al_draw_indexed_buffer_directx(target, texture, vertex_buffer, index_buffer, start, end, type);
}
}
return ret;
}
/* Function: al_get_vertex_buffer_size
*/
int al_get_vertex_buffer_size(ALLEGRO_VERTEX_BUFFER* buffer)
{
ASSERT(buffer);
return buffer->common.size;
}
/* Function: al_get_index_buffer_size
*/
int al_get_index_buffer_size(ALLEGRO_INDEX_BUFFER* buffer)
{
ASSERT(buffer);
return buffer->common.size;
}
You can’t perform that action at this time.