features.txt should be updated.
Marek On Sat, Sep 8, 2018 at 12:31 AM Timothy Arceri <tarc...@itsqueeze.com> wrote: > > From: Chris Forbes <chr...@ijw.co.nz> > > Allows the legacy matrix stacks to be manipulated without disturbing the > matrix mode selector. > > Signed-off-by: Chris Forbes <chr...@ijw.co.nz> > --- > src/mesa/main/matrix.c | 370 +++++++++++++++++++++++++++++++++++------ > src/mesa/main/matrix.h | 46 +++++ > 2 files changed, 363 insertions(+), 53 deletions(-) > > diff --git a/src/mesa/main/matrix.c b/src/mesa/main/matrix.c > index bd38c1d8496..ea0a3bd537f 100644 > --- a/src/mesa/main/matrix.c > +++ b/src/mesa/main/matrix.c > @@ -116,25 +116,53 @@ _mesa_Frustum( GLdouble left, GLdouble right, > { > GET_CURRENT_CONTEXT(ctx); > > - FLUSH_VERTICES(ctx, 0); > - > if (nearval <= 0.0 || > farval <= 0.0 || > nearval == farval || > left == right || > - top == bottom) > - { > + top == bottom) { > _mesa_error( ctx, GL_INVALID_VALUE, "glFrustum" ); > return; > } > > + FLUSH_VERTICES(ctx, 0); > _math_matrix_frustum( ctx->CurrentStack->Top, > - (GLfloat) left, (GLfloat) right, > - (GLfloat) bottom, (GLfloat) top, > + (GLfloat) left, (GLfloat) right, > + (GLfloat) bottom, (GLfloat) top, > (GLfloat) nearval, (GLfloat) farval ); > ctx->NewState |= ctx->CurrentStack->DirtyFlag; > } > > +void GLAPIENTRY > +_mesa_MatrixFrustumEXT( GLenum matrixMode, > + GLdouble left, GLdouble right, > + GLdouble bottom, GLdouble top, > + GLdouble nearval, GLdouble farval ) > +{ > + GET_CURRENT_CONTEXT(ctx); > + struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode); > + > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, "glMatrixFrustumEXT(mode)"); > + return; > + } > + > + if (nearval <= 0.0 || > + farval <= 0.0 || > + nearval == farval || > + left == right || > + top == bottom) { > + _mesa_error(ctx, GL_INVALID_VALUE, "glMatrixFrustumEXT"); > + return; > + } > + > + FLUSH_VERTICES(ctx, 0); > + _math_matrix_frustum(stack->Top, > + (GLfloat) left, (GLfloat) right, > + (GLfloat) bottom, (GLfloat) top, > + (GLfloat) nearval, (GLfloat) farval); > + ctx->NewState |= stack->DirtyFlag; > +} > > /** > * Apply an orthographic projection matrix. > @@ -159,27 +187,54 @@ _mesa_Ortho( GLdouble left, GLdouble right, > { > GET_CURRENT_CONTEXT(ctx); > > - FLUSH_VERTICES(ctx, 0); > - > if (MESA_VERBOSE & VERBOSE_API) > _mesa_debug(ctx, "glOrtho(%f, %f, %f, %f, %f, %f)\n", > left, right, bottom, top, nearval, farval); > > if (left == right || > bottom == top || > - nearval == farval) > - { > + nearval == farval) { > _mesa_error( ctx, GL_INVALID_VALUE, "glOrtho" ); > return; > } > > + FLUSH_VERTICES(ctx, 0); > _math_matrix_ortho( ctx->CurrentStack->Top, > - (GLfloat) left, (GLfloat) right, > - (GLfloat) bottom, (GLfloat) top, > + (GLfloat) left, (GLfloat) right, > + (GLfloat) bottom, (GLfloat) top, > (GLfloat) nearval, (GLfloat) farval ); > ctx->NewState |= ctx->CurrentStack->DirtyFlag; > } > > +void GLAPIENTRY > +_mesa_MatrixOrthoEXT( GLenum matrixMode, > + GLdouble left, GLdouble right, > + GLdouble bottom, GLdouble top, > + GLdouble nearval, GLdouble farval ) > +{ > + GET_CURRENT_CONTEXT(ctx); > + struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode); > + > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, "glMatrixOrthoEXT(mode)"); > + return; > + } > + > + if (left == right || > + bottom == top || > + nearval == farval) { > + _mesa_error(ctx, GL_INVALID_VALUE, "glMatrixOrthoEXT"); > + return; > + } > + > + FLUSH_VERTICES(ctx, 0); > + _math_matrix_ortho(stack->Top, > + (GLfloat) left, (GLfloat) right, > + (GLfloat) bottom, (GLfloat) top, > + (GLfloat) nearval, (GLfloat) farval); > + ctx->NewState |= stack->DirtyFlag; > +} > + > /** > * Set the current matrix stack. > * > @@ -211,38 +266,21 @@ _mesa_MatrixMode( GLenum mode ) > } > } > > - > -/** > - * Push the current matrix stack. > - * > - * \sa glPushMatrix(). > - * > - * Verifies the current matrix stack is not full, and duplicates the top-most > - * matrix in the stack. > - * Marks __struct gl_contextRec::NewState with the stack dirty flag. > - */ > -void GLAPIENTRY > -_mesa_PushMatrix( void ) > +static void > +push_matrix(struct gl_context *ctx, struct gl_matrix_stack *stack, > + GLenum matrixMode, const char *func) > { > - GET_CURRENT_CONTEXT(ctx); > - struct gl_matrix_stack *stack = ctx->CurrentStack; > - > - if (MESA_VERBOSE&VERBOSE_API) > - _mesa_debug(ctx, "glPushMatrix %s\n", > - _mesa_enum_to_string(ctx->Transform.MatrixMode)); > - > if (stack->Depth + 1 >= stack->MaxDepth) { > if (ctx->Transform.MatrixMode == GL_TEXTURE) { > - _mesa_error(ctx, GL_STACK_OVERFLOW, > - "glPushMatrix(mode=GL_TEXTURE, unit=%d)", > - ctx->Texture.CurrentUnit); > - } > - else { > - _mesa_error(ctx, GL_STACK_OVERFLOW, "glPushMatrix(mode=%s)", > - _mesa_enum_to_string(ctx->Transform.MatrixMode)); > + _mesa_error(ctx, GL_STACK_OVERFLOW, "%s(mode=GL_TEXTURE, unit=%d)", > + func, ctx->Texture.CurrentUnit); > + } else { > + _mesa_error(ctx, GL_STACK_OVERFLOW, "%s(mode=%s)", > + func, _mesa_enum_to_string(matrixMode)); > } > return; > } > + > if (stack->Depth + 1 >= stack->StackSize) { > unsigned new_stack_size = stack->StackSize * 2; > unsigned i; > @@ -250,7 +288,7 @@ _mesa_PushMatrix( void ) > sizeof(*new_stack) * new_stack_size); > > if (!new_stack) { > - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glPushMatrix()"); > + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); > return; > } > > @@ -268,12 +306,60 @@ _mesa_PushMatrix( void ) > ctx->NewState |= stack->DirtyFlag; > } > > +/** > + * Push the current matrix stack. > + * > + * \sa glPushMatrix(). > + * > + * Verifies the current matrix stack is not full, and duplicates the top-most > + * matrix in the stack. > + * Marks __struct gl_contextRec::NewState with the stack dirty flag. > + */ > +void GLAPIENTRY > +_mesa_PushMatrix( void ) > +{ > + GET_CURRENT_CONTEXT(ctx); > + struct gl_matrix_stack *stack = ctx->CurrentStack; > + > + if (MESA_VERBOSE&VERBOSE_API) > + _mesa_debug(ctx, "glPushMatrix %s\n", > + _mesa_enum_to_string(ctx->Transform.MatrixMode)); > + > + push_matrix(ctx, stack, ctx->Transform.MatrixMode, "glPushMatrix"); > +} > + > +void GLAPIENTRY > +_mesa_MatrixPushEXT( GLenum matrixMode ) > +{ > + GET_CURRENT_CONTEXT(ctx); > + struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode); > + ASSERT_OUTSIDE_BEGIN_END(ctx); > + > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, "glMatrixPushEXT(mode)"); > + return; > + } > + > + push_matrix(ctx, stack, matrixMode, "glMatrixPushEXT"); > +} > + > +static GLboolean > +pop_matrix( struct gl_context *ctx, struct gl_matrix_stack *stack ) > +{ > + if (stack->Depth == 0) > + return GL_FALSE; > + > + stack->Depth--; > + stack->Top = &(stack->Stack[stack->Depth]); > + ctx->NewState |= stack->DirtyFlag; > + return GL_TRUE; > +} > > /** > * Pop the current matrix stack. > * > * \sa glPopMatrix(). > - * > + * > * Flushes the vertices, verifies the current matrix stack is not empty, and > * moves the stack head down. > * Marks __struct gl_contextRec::NewState with the dirty stack flag. > @@ -290,21 +376,41 @@ _mesa_PopMatrix( void ) > _mesa_debug(ctx, "glPopMatrix %s\n", > _mesa_enum_to_string(ctx->Transform.MatrixMode)); > > - if (stack->Depth == 0) { > + if (!pop_matrix(ctx, stack)) { > if (ctx->Transform.MatrixMode == GL_TEXTURE) { > - _mesa_error(ctx, GL_STACK_UNDERFLOW, > + _mesa_error(ctx, GL_STACK_UNDERFLOW, > "glPopMatrix(mode=GL_TEXTURE, unit=%d)", > ctx->Texture.CurrentUnit); > } > else { > - _mesa_error(ctx, GL_STACK_UNDERFLOW, "glPopMatrix(mode=%s)", > + _mesa_error(ctx, GL_STACK_UNDERFLOW, "glPopMatrix(mode=%s)", > _mesa_enum_to_string(ctx->Transform.MatrixMode)); > } > + } > +} > + > +void GLAPIENTRY > +_mesa_MatrixPopEXT( GLenum matrixMode ) > +{ > + GET_CURRENT_CONTEXT(ctx); > + struct gl_matrix_stack *stack = get_named_matrix_stack(ctx, matrixMode); > + > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, "glMatrixPopEXT(mode)"); > return; > } > - stack->Depth--; > - stack->Top = &(stack->Stack[stack->Depth]); > - ctx->NewState |= stack->DirtyFlag; > + > + if (!pop_matrix(ctx, stack)) { > + if (matrixMode == GL_TEXTURE) { > + _mesa_error(ctx, GL_STACK_UNDERFLOW, > + "glMatrixPopEXT(mode=GL_TEXTURE, unit=%d)", > + ctx->Texture.CurrentUnit); > + } > + else { > + _mesa_error(ctx, GL_STACK_UNDERFLOW, "glMatrixPopEXT(mode=%s)", > + _mesa_enum_to_string(matrixMode)); > + } > + } > } > > > @@ -331,6 +437,24 @@ _mesa_LoadIdentity( void ) > ctx->NewState |= ctx->CurrentStack->DirtyFlag; > } > > +void GLAPIENTRY > +_mesa_MatrixLoadIdentityEXT( GLenum matrixMode ) > +{ > + struct gl_matrix_stack *stack; > + GET_CURRENT_CONTEXT(ctx); > + stack = get_named_matrix_stack(ctx, matrixMode); > + > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, > + "glMatrixLoadIdentityEXT(mode)\n"); > + return; > + } > + > + FLUSH_VERTICES(ctx, 0); > + _math_matrix_set_identity( stack->Top ); > + ctx->NewState |= stack->DirtyFlag; > +} > + > > /** > * Replace the current matrix with a given matrix. > @@ -364,6 +488,33 @@ _mesa_LoadMatrixf( const GLfloat *m ) > } > > > +/** > + * Replace the named matrix with a given matrix. > + * > + * \param matrixMode matrix to replace > + * \param m matrix > + * > + * \sa glLoadMatrixf(). > + */ > +void GLAPIENTRY > +_mesa_MatrixLoadfEXT( GLenum matrixMode, const GLfloat *m ) > +{ > + struct gl_matrix_stack *stack; > + GET_CURRENT_CONTEXT(ctx); > + if (!m) return; > + > + stack = get_named_matrix_stack(ctx, matrixMode); > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, > + "glMatrixLoadfEXT(matrixMode)"); > + return; > + } > + > + FLUSH_VERTICES(ctx, 0); > + _math_matrix_loadf(stack->Top, m); > + ctx->NewState |= stack->DirtyFlag; > +} > + > /** > * Multiply the current matrix with a given matrix. > * > @@ -393,6 +544,24 @@ _mesa_MultMatrixf( const GLfloat *m ) > ctx->NewState |= ctx->CurrentStack->DirtyFlag; > } > > +void GLAPIENTRY > +_mesa_MatrixMultfEXT( GLenum matrixMode, const GLfloat *m ) > +{ > + struct gl_matrix_stack *stack; > + GET_CURRENT_CONTEXT(ctx); > + if (!m) return; > + > + stack = get_named_matrix_stack(ctx, matrixMode); > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, > + "glMatrixMultfEXT(matrixMode)"); > + return; > + } > + > + FLUSH_VERTICES(ctx, 0); > + _math_matrix_mul_floats(stack->Top, m); > + ctx->NewState |= stack->DirtyFlag; > +} > > /** > * Multiply the current matrix with a rotation matrix. > @@ -420,6 +589,25 @@ _mesa_Rotatef( GLfloat angle, GLfloat x, GLfloat y, > GLfloat z ) > } > } > > +void GLAPIENTRY > +_mesa_MatrixRotatefEXT( GLenum matrixMode, GLfloat angle, GLfloat x, GLfloat > y, GLfloat z ) > +{ > + struct gl_matrix_stack *stack; > + GET_CURRENT_CONTEXT(ctx); > + if (angle == 0.0f) return; > + > + stack = get_named_matrix_stack(ctx, matrixMode); > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, > + "glMatrixRotatefEXT(matrixMode)"); > + return; > + } > + > + FLUSH_VERTICES(ctx, 0); > + _math_matrix_rotate(stack->Top, angle, x, y, z); > + ctx->NewState |= stack->DirtyFlag; > +} > + > > /** > * Multiply the current matrix with a general scaling matrix. > @@ -444,6 +632,24 @@ _mesa_Scalef( GLfloat x, GLfloat y, GLfloat z ) > ctx->NewState |= ctx->CurrentStack->DirtyFlag; > } > > +void GLAPIENTRY > +_mesa_MatrixScalefEXT( GLenum matrixMode, GLfloat x, GLfloat y, GLfloat z ) > +{ > + struct gl_matrix_stack *stack; > + GET_CURRENT_CONTEXT(ctx); > + > + stack = get_named_matrix_stack(ctx, matrixMode); > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, > + "glMatrixScalefEXT(matrixMode)"); > + return; > + } > + > + FLUSH_VERTICES(ctx, 0); > + _math_matrix_scale(stack->Top, x, y, z); > + ctx->NewState |= stack->DirtyFlag; > +} > + > > /** > * Multiply the current matrix with a translation matrix. > @@ -468,7 +674,25 @@ _mesa_Translatef( GLfloat x, GLfloat y, GLfloat z ) > ctx->NewState |= ctx->CurrentStack->DirtyFlag; > } > > - > +void GLAPIENTRY > +_mesa_MatrixTranslatefEXT( GLenum matrixMode, GLfloat x, GLfloat y, GLfloat > z ) > +{ > + struct gl_matrix_stack *stack; > + GET_CURRENT_CONTEXT(ctx); > + > + stack = get_named_matrix_stack(ctx, matrixMode); > + if (!stack) { > + _mesa_error(ctx, GL_INVALID_ENUM, > + "glMatrixTranslatefEXT(matrixMode)"); > + return; > + } > + > + FLUSH_VERTICES(ctx, 0); > + _math_matrix_translate(stack->Top, x, y, z); > + ctx->NewState |= stack->DirtyFlag; > +} > + > + > void GLAPIENTRY > _mesa_LoadMatrixd( const GLdouble *m ) > { > @@ -480,6 +704,17 @@ _mesa_LoadMatrixd( const GLdouble *m ) > _mesa_LoadMatrixf(f); > } > > +void GLAPIENTRY > +_mesa_MatrixLoaddEXT( GLenum matrixMode, const GLdouble *m ) > +{ > + GLint i; > + GLfloat f[16]; > + if (!m) return; > + for (i = 0; i < 16; i++) > + f[i] = (GLfloat) m[i]; > + _mesa_MatrixLoadfEXT(matrixMode, f); > +} > + > void GLAPIENTRY > _mesa_MultMatrixd( const GLdouble *m ) > { > @@ -491,6 +726,16 @@ _mesa_MultMatrixd( const GLdouble *m ) > _mesa_MultMatrixf( f ); > } > > +void GLAPIENTRY > +_mesa_MatrixMultdEXT( GLenum matrixMode, const GLdouble *m ) > +{ > + GLint i; > + GLfloat f[16]; > + if (!m) return; > + for (i = 0; i < 16; i++) > + f[i] = (GLfloat) m[i]; > + _mesa_MatrixMultfEXT(matrixMode, f); > +} > > void GLAPIENTRY > _mesa_Rotated( GLdouble angle, GLdouble x, GLdouble y, GLdouble z ) > @@ -498,6 +743,14 @@ _mesa_Rotated( GLdouble angle, GLdouble x, GLdouble y, > GLdouble z ) > _mesa_Rotatef((GLfloat) angle, (GLfloat) x, (GLfloat) y, (GLfloat) z); > } > > +void GLAPIENTRY > +_mesa_MatrixRotatedEXT( GLenum matrixMode, GLdouble angle, > + GLdouble x, GLdouble y, GLdouble z ) > +{ > + _mesa_MatrixRotatefEXT(matrixMode, (GLfloat) angle, > + (GLfloat) x, (GLfloat) y, (GLfloat) z); > +} > + > > void GLAPIENTRY > _mesa_Scaled( GLdouble x, GLdouble y, GLdouble z ) > @@ -505,6 +758,12 @@ _mesa_Scaled( GLdouble x, GLdouble y, GLdouble z ) > _mesa_Scalef((GLfloat) x, (GLfloat) y, (GLfloat) z); > } > > +void GLAPIENTRY > +_mesa_MatrixScaledEXT( GLenum matrixMode, GLdouble x, GLdouble y, GLdouble z > ) > +{ > + _mesa_MatrixScalefEXT(matrixMode, (GLfloat) x, (GLfloat) y, (GLfloat) z); > +} > + > > void GLAPIENTRY > _mesa_Translated( GLdouble x, GLdouble y, GLdouble z ) > @@ -512,6 +771,11 @@ _mesa_Translated( GLdouble x, GLdouble y, GLdouble z ) > _mesa_Translatef((GLfloat) x, (GLfloat) y, (GLfloat) z); > } > > +void GLAPIENTRY > +_mesa_MatrixTranslatedEXT( GLenum matrixMode, GLdouble x, GLdouble y, > GLdouble z ) > +{ > + _mesa_MatrixTranslatefEXT(matrixMode, (GLfloat) x, (GLfloat) y, (GLfloat) > z); > +} > > void GLAPIENTRY > _mesa_LoadTransposeMatrixf( const GLfloat *m ) > @@ -566,7 +830,7 @@ _mesa_MultTransposeMatrixd( const GLdouble *m ) > * > * Calls _math_matrix_analyse() with the top-matrix of the projection matrix > * stack, and recomputes user clip positions if necessary. > - * > + * > * \note This routine references __struct gl_contextRec::Tranform attribute > * values to compute userclip positions in clip space, but is only called on > * _NEW_PROJECTION. The _mesa_ClipPlane() function keeps these values up to > @@ -652,7 +916,7 @@ void _mesa_update_modelview_project( struct gl_context > *ctx, GLuint new_state ) > * \param stack matrix stack. > * \param maxDepth maximum stack depth. > * \param dirtyFlag dirty flag. > - * > + * > * Allocates an array of \p maxDepth elements for the matrix stack and calls > * _math_matrix_ctr() for each element to initialize it. > */ > @@ -676,9 +940,9 @@ init_matrix_stack( struct gl_matrix_stack *stack, > > /** > * Free matrix stack. > - * > + * > * \param stack matrix stack. > - * > + * > * Calls _math_matrix_dtr() for each element of the matrix stack and > * frees the array. > */ > @@ -734,7 +998,7 @@ void _mesa_init_matrix( struct gl_context * ctx ) > > /** > * Free the context matrix data. > - * > + * > * \param ctx GL context. > * > * Frees each of the matrix stacks and the combined modelview-projection > @@ -756,7 +1020,7 @@ void _mesa_free_matrix_data( struct gl_context *ctx ) > } > > > -/** > +/** > * Initialize the context transform attribute group. > * > * \param ctx GL context. > diff --git a/src/mesa/main/matrix.h b/src/mesa/main/matrix.h > index 8eee67ca386..78f4cb5a6dc 100644 > --- a/src/mesa/main/matrix.h > +++ b/src/mesa/main/matrix.h > @@ -96,6 +96,52 @@ _mesa_MultTransposeMatrixf( const GLfloat *m ); > extern void GLAPIENTRY > _mesa_MultTransposeMatrixd( const GLdouble *m ); > > +extern void GLAPIENTRY > +_mesa_MatrixLoadfEXT( GLenum matrixMode, const GLfloat *m ); > + > +extern void GLAPIENTRY > +_mesa_MatrixLoaddEXT( GLenum matrixMode, const GLdouble *m ); > + > +extern void GLAPIENTRY > +_mesa_MatrixMultfEXT( GLenum matrixMode, const GLfloat *m ); > + > +extern void GLAPIENTRY > +_mesa_MatrixMultdEXT( GLenum matrixMode, const GLdouble *m ); > + > +extern void GLAPIENTRY > +_mesa_MatrixLoadIdentityEXT( GLenum matrixMode ); > + > +extern void GLAPIENTRY > +_mesa_MatrixRotatefEXT( GLenum matrixMode, GLfloat angle, GLfloat x, GLfloat > y, GLfloat z ); > + > +extern void GLAPIENTRY > +_mesa_MatrixRotatedEXT( GLenum matrixMode, GLdouble angle, GLdouble x, > GLdouble y, GLdouble z ); > + > +extern void GLAPIENTRY > +_mesa_MatrixScalefEXT( GLenum matrixMode, GLfloat x, GLfloat y, GLfloat z ); > + > +extern void GLAPIENTRY > +_mesa_MatrixScaledEXT( GLenum matrixMode, GLdouble x, GLdouble y, GLdouble z > ); > + > +extern void GLAPIENTRY > +_mesa_MatrixTranslatefEXT( GLenum matrixMode, GLfloat x, GLfloat y, GLfloat > z ); > + > +extern void GLAPIENTRY > +_mesa_MatrixTranslatedEXT( GLenum matrixMode, GLdouble x, GLdouble y, > GLdouble z ); > + > +extern void GLAPIENTRY > +_mesa_MatrixOrthoEXT( GLenum matrixMode, GLdouble l, GLdouble r, GLdouble b, > GLdouble t, > + GLdouble n, GLdouble f ); > + > +extern void GLAPIENTRY > +_mesa_MatrixFrustumEXT( GLenum matrixMode, GLdouble l, GLdouble r, GLdouble > b, GLdouble t, > + GLdouble n, GLdouble f ); > + > +extern void GLAPIENTRY > +_mesa_MatrixPushEXT( GLenum matrixMode ); > + > +extern void GLAPIENTRY > +_mesa_MatrixPopEXT( GLenum matrixMode ); > > extern void > _mesa_init_matrix( struct gl_context * ctx ); > -- > 2.17.1 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev