mirror of
https://github.com/Karaka-Management/cOMS.git
synced 2026-01-11 11:18:40 +00:00
588 lines
18 KiB
C
588 lines
18 KiB
C
/**
|
|
* Jingga
|
|
*
|
|
* @copyright Jingga
|
|
* @license OMS License 2.0
|
|
* @version 1.0.0
|
|
* @link https://jingga.app
|
|
*/
|
|
#ifndef TOS_GPUAPI_RENDER_UTILS_H
|
|
#define TOS_GPUAPI_RENDER_UTILS_H
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include "../stdlib/Types.h"
|
|
#include "../utils/StringUtils.h"
|
|
#include "../math/matrix/MatrixFloat32.h"
|
|
#include "../font/Font.h"
|
|
#include "../object/Vertex.h"
|
|
#include "../ui/UITheme.h"
|
|
#include "../ui/UIElement.h"
|
|
#include "../ui/UIAlignment.h"
|
|
|
|
// @performance Create improved vertex generation for components (input + button, chat, ...) where we don't use as many
|
|
// degenerate triangle
|
|
|
|
// @todo in many places we use ->value_int. We should load it as a value_float and also define it as float in the theme.
|
|
// This way we wouldn't have to convert the value
|
|
|
|
inline
|
|
void vertex_degenerate_create(
|
|
Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex,
|
|
f32 x, f32 y
|
|
) {
|
|
// Degenerate triangles
|
|
// They are alternating every loop BUT since we use references they look the same in code
|
|
// WARNING: Before using we must make sure that the 0 index is defined
|
|
// The easiest way is to just define a "degenerate" starting point
|
|
vertices[*index] = {{vertices[*index - 1].position.x, vertices[*index - 1].position.y, zindex}, {0, 0}, 0};
|
|
++(*index);
|
|
|
|
vertices[*index] = {{x, y, zindex}, {0, 0}, 0};
|
|
++(*index);
|
|
}
|
|
|
|
inline
|
|
void vertex_line_create(
|
|
Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex,
|
|
f32 x1, f32 y1, f32 x2, f32 y2, f32 thickness, int32 align_h, int32 align_v,
|
|
f32 color_index = 0, f32 tex_x1 = 0.0f, f32 tex_y1 = 0.0f, f32 tex_x2 = 0.0f, f32 tex_y2 = 0.0f
|
|
) {
|
|
if (align_h == UI_ALIGN_H_RIGHT) {
|
|
x1 -= thickness;
|
|
x2 -= thickness;
|
|
} else if (align_h == UI_ALIGN_H_CENTER) {
|
|
x1 -= thickness / 2;
|
|
x2 -= thickness / 2;
|
|
}
|
|
|
|
if (align_v == UI_ALIGN_V_TOP) {
|
|
y1 -= thickness;
|
|
y2 -= thickness;
|
|
} else if (align_v == UI_ALIGN_V_CENTER) {
|
|
y1 -= thickness / 2;
|
|
y2 -= thickness / 2;
|
|
}
|
|
|
|
f32 n1 = -(y2 - y1);
|
|
f32 n2 = x2 - x1;
|
|
f32 n_ = oms_rsqrt(n2 * n2 + n1 * n1);
|
|
f32 norm1 = n1 * n_;
|
|
f32 norm2 = n2 * n_;
|
|
|
|
vertex_degenerate_create(vertices, index, zindex, x1, y1);
|
|
|
|
int32 idx = *index;
|
|
|
|
vertices[idx++] = {{x1, y1, zindex}, {tex_x1, tex_y1}, color_index};
|
|
vertices[idx++] = {{x1 + thickness * norm1, y1 + thickness * norm2, zindex}, {tex_x1, tex_y2}, color_index};
|
|
vertices[idx++] = {{x2, y2, zindex}, {tex_x2, tex_y1}, color_index};
|
|
vertices[idx++] = {{x2 + thickness * norm1, y2 + thickness * norm2, zindex}, {tex_x2, tex_y2}, color_index};
|
|
|
|
*index = idx;
|
|
}
|
|
|
|
// @performance Do we really want to create the UI as one continuous mesh?
|
|
// Individual meshes without degenerates might be faster
|
|
inline
|
|
void vertex_rect_create(
|
|
Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex,
|
|
f32 x, f32 y, f32 width, f32 height, int32 align_h, int32 align_v,
|
|
f32 color_index = 0, f32 tex_x1 = 0.0f, f32 tex_y1 = 0.0f, f32 tex_x2 = 0.0f, f32 tex_y2 = 0.0f
|
|
) {
|
|
if (align_h == UI_ALIGN_H_RIGHT) {
|
|
x -= width;
|
|
} else if (align_h == UI_ALIGN_H_CENTER) {
|
|
x -= width / 2;
|
|
}
|
|
|
|
if (align_v == UI_ALIGN_V_TOP) {
|
|
y -= height;
|
|
} else if (align_v == UI_ALIGN_V_CENTER) {
|
|
y -= height / 2;
|
|
}
|
|
|
|
vertex_degenerate_create(vertices, index, zindex, x, y);
|
|
|
|
f32 y_height = y + height;
|
|
f32 x_width = x + width;
|
|
|
|
// Rectangle
|
|
int32 idx = *index;
|
|
|
|
vertices[idx++] = {{x, y, zindex}, {tex_x1, tex_y1}, color_index};
|
|
vertices[idx++] = {{x, y_height, zindex}, {tex_x1, tex_y2}, color_index};
|
|
vertices[idx++] = {{x_width, y, zindex}, {tex_x2, tex_y1}, color_index};
|
|
vertices[idx++] = {{x_width, y_height, zindex}, {tex_x2, tex_y2}, color_index};
|
|
|
|
*index = idx;
|
|
}
|
|
|
|
// @todo also allow background -> we can benefit from reduced vertex count
|
|
// All we have to do is add 3 more vertices (= inside vertices)
|
|
inline
|
|
void vertex_rect_border_create(
|
|
Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex,
|
|
f32 x, f32 y, f32 width, f32 height, f32 thickness, int32 align_h, int32 align_v,
|
|
f32 color_index = 0, f32 tex_x1 = 0.0f, f32 tex_y1 = 0.0f, f32 tex_x2 = 0.0f, f32 tex_y2 = 0.0f
|
|
) {
|
|
if (align_h == UI_ALIGN_H_RIGHT) {
|
|
x -= width;
|
|
} else if (align_h == UI_ALIGN_H_CENTER) {
|
|
x -= width / 2;
|
|
}
|
|
|
|
if (align_v == UI_ALIGN_V_TOP) {
|
|
y -= height;
|
|
} else if (align_v == UI_ALIGN_V_CENTER) {
|
|
y -= height / 2;
|
|
}
|
|
|
|
vertex_degenerate_create(vertices, index, zindex, x, y);
|
|
|
|
// @bug While this works for the whole rectangle it doesn't work for individual borders
|
|
// @todo We need a version where you can define individual borders
|
|
|
|
f32 y_height = y + height;
|
|
f32 y_thickness = y + thickness;
|
|
f32 x_width = x + width;
|
|
f32 x_thickness = x + thickness;
|
|
|
|
// Rectangle
|
|
// Top border
|
|
vertices[*index].position.x = x;
|
|
vertices[*index].position.y = y;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x1;
|
|
vertices[*index].tex_coord.y = tex_y1;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
vertices[*index].position.x = x;
|
|
vertices[*index].position.y = y_thickness;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x1;
|
|
vertices[*index].tex_coord.y = tex_y2;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
vertices[*index].position.x = x_width;
|
|
vertices[*index].position.y = y;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x2;
|
|
vertices[*index].tex_coord.y = tex_y1;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
vertices[*index].position.x = x_width;
|
|
vertices[*index].position.y = y_thickness;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x2;
|
|
vertices[*index].tex_coord.y = tex_y2;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
// Right border
|
|
vertices[*index].position.x = x_width - thickness;
|
|
vertices[*index].position.y = y_thickness;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x2;
|
|
vertices[*index].tex_coord.y = tex_y2;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
vertices[*index].position.x = x_width;
|
|
vertices[*index].position.y = y_height;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x1;
|
|
vertices[*index].tex_coord.y = tex_y2;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
vertices[*index].position.x = x_width - thickness;
|
|
vertices[*index].position.y = y_height;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x2;
|
|
vertices[*index].tex_coord.y = tex_y1;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
// Bottom border
|
|
vertices[*index].position.x = x_width - thickness;
|
|
vertices[*index].position.y = y_height - thickness;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x2;
|
|
vertices[*index].tex_coord.y = tex_y2;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
vertices[*index].position.x = x;
|
|
vertices[*index].position.y = y_height;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x1;
|
|
vertices[*index].tex_coord.y = tex_y2;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
vertices[*index].position.x = x;
|
|
vertices[*index].position.y = y_height - thickness;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x2;
|
|
vertices[*index].tex_coord.y = tex_y1;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
// Left border
|
|
vertices[*index].position.x = x_thickness;
|
|
vertices[*index].position.y = y_height - thickness;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x2;
|
|
vertices[*index].tex_coord.y = tex_y2;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
vertices[*index].position.x = x;
|
|
vertices[*index].position.y = y_thickness;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x1;
|
|
vertices[*index].tex_coord.y = tex_y2;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
|
|
vertices[*index].position.x = x_thickness;
|
|
vertices[*index].position.y = y_thickness;
|
|
vertices[*index].position.z = zindex;
|
|
vertices[*index].tex_coord.x = tex_x2;
|
|
vertices[*index].tex_coord.y = tex_y1;
|
|
vertices[*index].color = color_index;
|
|
++(*index);
|
|
}
|
|
|
|
void vertex_input(Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex,
|
|
f32 x, f32 y, f32 width, f32 height, int32 align_h, int32 align_v,
|
|
f32 color_index = 0, f32 tex_x1 = 0.0f, f32 tex_y1 = 0.0f, f32 tex_x2 = 0.0f, f32 tex_y2 = 0.0f
|
|
)
|
|
{
|
|
vertex_rect_border_create(
|
|
vertices, index, zindex,
|
|
x, y, width, height, 1, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM,
|
|
12, 0.0f, 0.0f
|
|
);
|
|
|
|
vertex_rect_create(
|
|
vertices, index, zindex,
|
|
x + 1, y + 1, width - 2, height - 2, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM,
|
|
14, 0.0f, 0.0f
|
|
);
|
|
}
|
|
|
|
static inline
|
|
f32 text_calculate_dimensions_height(
|
|
const Font* __restrict font, const char* __restrict text, f32 scale, int32 length
|
|
) {
|
|
f32 line_height = font->line_height * scale;
|
|
f32 y = line_height;
|
|
|
|
// @todo remember to restrict to width/height if value > 0 -> force width to remain below certain value
|
|
|
|
for (int32 i = 0; i < length; ++i) {
|
|
if (text[i] == '\n') {
|
|
y += line_height;
|
|
}
|
|
}
|
|
|
|
return y;
|
|
}
|
|
|
|
static inline
|
|
f32 text_calculate_dimensions_width(
|
|
const Font* __restrict font, const char* __restrict text, bool is_ascii, f32 scale, int32 length
|
|
) {
|
|
f32 x = 0;
|
|
f32 offset_x = 0;
|
|
|
|
// @todo remember to restrict to width/height if value > 0 -> force width to remain below certain value
|
|
|
|
for (int32 i = 0; i < length; ++i) {
|
|
int32 character = is_ascii ? text[i] : utf8_get_char_at(text, i);
|
|
|
|
if (character == '\n') {
|
|
x = OMS_MAX(x, offset_x);
|
|
offset_x = 0;
|
|
|
|
continue;
|
|
}
|
|
|
|
Glyph* glyph = font_glyph_find(font, character);
|
|
if (!glyph) {
|
|
continue;
|
|
}
|
|
|
|
offset_x += (glyph->metrics.width + glyph->metrics.offset_x + glyph->metrics.advance_x) * scale;
|
|
}
|
|
|
|
return OMS_MAX(x, offset_x);
|
|
}
|
|
|
|
static inline
|
|
void text_calculate_dimensions(
|
|
f32* __restrict width, f32* __restrict height,
|
|
const Font* __restrict font, const char* __restrict text, bool is_ascii, f32 scale, int32 length
|
|
) {
|
|
f32 line_height = font->line_height * scale;
|
|
f32 x = 0;
|
|
f32 y = line_height;
|
|
|
|
f32 offset_x = 0;
|
|
|
|
// @todo remember to restrict to width/height if value > 0 -> force width to remain below certain value
|
|
|
|
for (int32 i = 0; i < length; ++i) {
|
|
int32 character = is_ascii ? text[i] : utf8_get_char_at(text, i);
|
|
|
|
if (character == '\n') {
|
|
x = OMS_MAX(x, offset_x);
|
|
y += line_height;
|
|
|
|
offset_x = 0;
|
|
|
|
continue;
|
|
}
|
|
|
|
Glyph* glyph = font_glyph_find(font, character);
|
|
if (!glyph) {
|
|
continue;
|
|
}
|
|
|
|
offset_x += (glyph->metrics.width + glyph->metrics.offset_x + glyph->metrics.advance_x) * scale;
|
|
}
|
|
|
|
*width = OMS_MAX(x, offset_x);
|
|
*height = y;
|
|
}
|
|
|
|
// @todo implement shadow (offset + angle + diffuse) or should this be a shader only thing? if so this would be a problem for us since we are handling text in the same shader as simple shapes
|
|
// we might want to implement distance field font atlas
|
|
// @todo We should be able to cut off text at an arbitrary position, not just at a line_height incremental
|
|
// we could probably get the MIN of the glyph height and the remaining window height
|
|
v2_f32 vertex_text_create(
|
|
Vertex3DTextureColorIndex* __restrict vertices, uint32* __restrict index, f32 zindex,
|
|
f32 x, f32 y, f32 width, f32 height, int32 align_h, int32 align_v,
|
|
const Font* __restrict font, const char* __restrict text, f32 size, f32 color_index = 0
|
|
) {
|
|
int32 length = utf8_strlen(text);
|
|
bool is_ascii = (int32) strlen(text) == length;
|
|
f32 scale = size / font->size;
|
|
|
|
// If we do a different alignment we need to pre-calculate the width and height
|
|
if (align_h != 0 || align_v != 0) {
|
|
if (align_h != 0 && align_v != 0) {
|
|
text_calculate_dimensions(&width, &height, font, text, is_ascii, scale, length);
|
|
} else if (align_h != 0) {
|
|
width = text_calculate_dimensions_width(font, text, is_ascii, scale, length);
|
|
} else {
|
|
height = text_calculate_dimensions_height(font, text, scale, length);
|
|
}
|
|
|
|
if (align_h == UI_ALIGN_H_RIGHT) {
|
|
x -= width;
|
|
} else if (align_h == UI_ALIGN_H_CENTER) {
|
|
x -= width / 2;
|
|
}
|
|
|
|
if (align_v == UI_ALIGN_V_TOP) {
|
|
y -= height;
|
|
} else if (align_v == UI_ALIGN_V_CENTER) {
|
|
y -= height / 2;
|
|
}
|
|
}
|
|
|
|
f32 line_height_scaled = font->line_height * scale;
|
|
|
|
f32 rendered_width = 0;
|
|
f32 rendered_height = line_height_scaled;
|
|
|
|
f32 offset_x = x;
|
|
for (int32 i = 0; i < length; ++i) {
|
|
int32 character = is_ascii ? text[i] : utf8_get_char_at(text, i);
|
|
if (character == '\n') {
|
|
rendered_height += line_height_scaled;
|
|
rendered_width = OMS_MAX(rendered_width, offset_x - x);
|
|
|
|
y -= line_height_scaled;
|
|
offset_x = x;
|
|
|
|
continue;
|
|
}
|
|
|
|
Glyph* glyph = font_glyph_find(font, character);
|
|
if (!glyph) {
|
|
continue;
|
|
}
|
|
|
|
f32 offset_y = y + glyph->metrics.offset_y * scale;
|
|
offset_x += glyph->metrics.offset_x * scale;
|
|
|
|
// @performance Consider to handle whitespaces just by offsetting
|
|
vertex_rect_create(
|
|
vertices, index, zindex,
|
|
offset_x, offset_y, glyph->metrics.width * scale, glyph->metrics.height * scale, UI_ALIGN_H_LEFT, UI_ALIGN_V_BOTTOM,
|
|
color_index, glyph->coords.x1, glyph->coords.y1, glyph->coords.x2, glyph->coords.y2
|
|
);
|
|
|
|
offset_x += (glyph->metrics.width + glyph->metrics.advance_x) * scale;
|
|
}
|
|
|
|
// @question How and where to cut off text out of view (here or somewhere else)
|
|
// We could just prepare the entire text here but then decide what to render later?
|
|
// @todo If width or height (usually just width) > 0 we use those values for automatic wrapping
|
|
// This way we can ensure no overflow easily
|
|
// @todo implement line alignment, currently only total alignment is considered
|
|
|
|
return {rendered_width, rendered_height};
|
|
}
|
|
|
|
inline
|
|
void entity_world_space(f32* world_space, const f32* local_space, const f32* model_mat)
|
|
{
|
|
mat4vec4_mult(model_mat, local_space, world_space);
|
|
}
|
|
|
|
inline
|
|
void entity_view_space(f32* view_space, const f32* world_space, const f32* view_mat)
|
|
{
|
|
mat4vec4_mult(view_mat, world_space, view_space);
|
|
}
|
|
|
|
inline
|
|
void entity_clip_space(f32* clip_space, const f32* view_space, const f32* projection_mat)
|
|
{
|
|
mat4vec4_mult(projection_mat, view_space, clip_space);
|
|
}
|
|
|
|
inline
|
|
void entity_clip_space_mat(f32* result_mat, const f32* model_mat, const f32* view_mat, const f32* projection_mat)
|
|
{
|
|
f32 temp[16];
|
|
mat4mat4_mult(projection_mat, view_mat, temp);
|
|
mat4mat4_mult(temp, model_mat, result_mat);
|
|
}
|
|
|
|
/**
|
|
* Create the matrix used to transform from local space to clip space
|
|
*
|
|
* This allows us to transform multiple objects with the same matrix
|
|
*
|
|
* Vclip = Mprojection * Mview * Mmodel * Vlocal
|
|
*/
|
|
void entity_clip_space_mat_sse(f32* result_mat, const f32* model_mat, const f32* view_mat, const f32* projection_mat)
|
|
{
|
|
__m128 temp[4];
|
|
|
|
__m128 a[4];
|
|
__m128 b[4];
|
|
|
|
a[0] = _mm_load_ps(projection_mat);
|
|
a[1] = _mm_load_ps(&projection_mat[4]);
|
|
a[2] = _mm_load_ps(&projection_mat[8]);
|
|
a[3] = _mm_load_ps(&projection_mat[12]);
|
|
|
|
b[0] = _mm_load_ps(view_mat);
|
|
b[1] = _mm_load_ps(&view_mat[4]);
|
|
b[2] = _mm_load_ps(&view_mat[8]);
|
|
b[3] = _mm_load_ps(&view_mat[12]);
|
|
_MM_TRANSPOSE4_PS(b[0], b[1], b[2], b[3]);
|
|
|
|
mat4mat4_mult_sse(a, b, temp);
|
|
|
|
a[0] = temp[0];
|
|
a[1] = temp[1];
|
|
a[2] = temp[2];
|
|
a[3] = temp[3];
|
|
|
|
b[0] = _mm_load_ps(model_mat);
|
|
b[1] = _mm_load_ps(&model_mat[4]);
|
|
b[2] = _mm_load_ps(&model_mat[8]);
|
|
b[3] = _mm_load_ps(&model_mat[12]);
|
|
_MM_TRANSPOSE4_PS(b[0], b[1], b[2], b[3]);
|
|
|
|
mat4mat4_mult_sse(a, b, temp);
|
|
_mm_store_ps(&result_mat[0], temp[0]);
|
|
_mm_store_ps(&result_mat[4], temp[1]);
|
|
_mm_store_ps(&result_mat[8], temp[2]);
|
|
_mm_store_ps(&result_mat[12], temp[3]);
|
|
}
|
|
|
|
inline
|
|
void entity_clip_space_from_local(f32* clip_space, const f32* local_space, const f32* mat)
|
|
{
|
|
mat4vec4_mult(mat, local_space, clip_space);
|
|
}
|
|
|
|
inline
|
|
void entity_clip_space_from_local_sse(f32* clip_space, const f32* local_space, const f32* mat)
|
|
{
|
|
mat4vec4_mult_sse(mat, local_space, clip_space);
|
|
}
|
|
|
|
/*
|
|
inline
|
|
void entity_screen_space(f32* screen_space, const f32* clip_space, const f32* viewport_mat)
|
|
{
|
|
// @todo implement
|
|
}
|
|
*/
|
|
|
|
inline
|
|
void entity_world_space_sse(f32* world_space, const f32* local_space, const f32* model_mat)
|
|
{
|
|
mat4vec4_mult_sse(model_mat, local_space, world_space);
|
|
}
|
|
|
|
inline
|
|
void entity_view_space_sse(f32* view_space, const f32* world_space, const f32* view_mat)
|
|
{
|
|
mat4vec4_mult_sse(view_mat, world_space, view_space);
|
|
}
|
|
|
|
inline
|
|
void entity_clip_space_sse(f32* clip_space, const f32* view_space, const f32* projection_mat)
|
|
{
|
|
mat4vec4_mult_sse(projection_mat, view_space, clip_space);
|
|
}
|
|
|
|
/*
|
|
inline
|
|
void entity_screen_space_sse(f32* screen_space, const f32* clip_space, const f32* viewport_mat)
|
|
{
|
|
// @todo implement
|
|
}
|
|
*/
|
|
|
|
inline
|
|
void entity_world_space_sse(__m128* world_space, const __m128* local_space, const __m128* model_mat)
|
|
{
|
|
mat4vec4_mult_sse(model_mat, local_space, world_space);
|
|
}
|
|
|
|
inline
|
|
void entity_view_space_sse(__m128* view_space, const __m128* world_space, const __m128* view_mat)
|
|
{
|
|
mat4vec4_mult_sse(view_mat, world_space, view_space);
|
|
}
|
|
|
|
inline
|
|
void entity_clip_space_sse(__m128* clip_space, const __m128* view_space, const __m128* projection_mat)
|
|
{
|
|
mat4vec4_mult_sse(projection_mat, view_space, clip_space);
|
|
}
|
|
|
|
/*
|
|
inline
|
|
void entity_screen_space_sse(__m128* screen_space, const __m128* clip_space, const __m128* viewport_mat)
|
|
{
|
|
// @todo implement
|
|
}
|
|
*/
|
|
|
|
#endif |